Add plugin: mcode-webui (round 5 — supersedes #16) - #23
Conversation
Browser-based chat frontend for the mcode agent runtime. Streams
mcode acp / exec sessions with real-time tool events, plan review,
ask-user prompts, context usage, and quota. Zero npm dependencies;
runs on Node 22+.
- New plugin at plugins/Wzdhehe/mcode-webui/ per Agent Plugins 1.0
- plugin.json (10 white-listed top-level fields, 13 capabilities)
- skills/mcode-webui/SKILL.md (frontmatter name + description 343 chars)
- LICENSE (MIT)
- README.md + README.zh-CN.md (bilingual)
- references/SECURITY-NOTES.md (canonical security disclosure)
- docs/ (ARCHITECTURE, API, CAPABILITIES, DEVELOPMENT, TROUBLESHOOTING)
- server/, public/, test/ (real directory copies, kept in sync with
the project root at github.com/Wzdhehe/mcode-webui)
- PR_DESCRIPTION.md + CONTRIBUTING.md
Source: github.com/Wzdhehe/mcode-webui (v1.0.0 + doc polish)
Validate: OK plugin Wzdhehe/mcode-webui
Mirror of the source-repo follow-up: - SKILL.md frontmatter name back to mcode-webui (spec requires it to match the directory name) - Strip CR from UTF-8 text files so the official validator sees LF-only frontmatter - Revert product-name mcode->Mcode in CLI/trigger references
…owercase by spec)
…y mode Addresses PR MiniMax-AI#16 reviewer feedback (Please fix the authentication boundary before merge). New behavior: - Token auth gate: server-side constant-time token validation on every non-local /api/* request via new server/lib/auth.js. Token resolved from TOKEN env > settings.currentToken > auto-generated 32-hex on first start (printed to stdout once, never to .server.log, persisted to ~/.mcode-webui/settings.json with mode 0600). - LAN sub-card: 顶栏 LAN chip 下弹出子卡片, 4 个子功能 (read-only toggle, token rotation with SSE auth.token_rotated broadcast, token acknowledged state machine, 复制可分享 URL 含 token). - Read-only mode: 非本机 POST/DELETE 到 /api/* 返 403, 远程只能读. 顶栏红色脉动 chip 提示只读状态. /api/settings 例外 (escape hatch). - Top-bar read-only chip + bilingual single-page LAN reject page (zh + en stacked, dynamic PORT). Sub-mechanisms documented separately in CHANGELOG, README (× 2 langs), CAPABILITIES, SECURITY-NOTES. Tests: 372/372 pass. Lint: 0 warnings. Independent audit: FUNCTIONAL.
…on support Same commit as Wzdhehe/Mcode-webui ea896d1, mirrored to plugin layout for MiniMax-Code-Plugins registry. Round 2 audit (reviewer mentioned 'CORS/URL-token leakage considerations') found two related bugs: 1. L281: Access-Control-Allow-Headers only listed 'Content-Type', so any cross-origin fetch with 'Authorization: Bearer' would fail CORS preflight. 2. Gate 3 (token auth) had no exemption for OPTIONS preflight, so even with the L281 fix, OPTIONS preflight to /api/* would hit Gate 3 and return 401 (browsers cannot attach Authorization to a preflight). The real POST would never reach the server. Fixes: - server/router.js L281: Allow-Headers now lists 'Content-Type, Authorization' - server/router.js Gate 3: add req.method !== 'OPTIONS' exemption (matches Gate 4 read-only's existing pattern) - test/router-cors.test.js: 9 new tests covering CORS headers + Gate 3 preflight behavior. Tests: 381 pass / 0 fail. Lint: 0 warning. Independent audit: FUNCTIONAL.
…ke test + doc sync)
Mirror of Wzdhehe/Mcode-webui commits decceb6 + 91d0bb0 to plugin layout.
Round 3 review (reviewer: 'setTokenAuthEnabled load-time blocker' +
'add a startup/import smoke test that exercises the real server bootstrap')
found two real bugs plus 13 stale doc claims. All addressed:
Code fixes (commit decceb6):
- plugins/.../server/lib/auth.js: synced from root, now exports
setExpectedToken + setTokenAuthEnabled (mirror was stale since
v1.0.1 LAN sub-card commit 999115d — setTokenAuthEnabled is
imported by server.js:26, missing export was a load-time blocker)
- plugins/.../test/lib-auth.test.js: synced from root (4 new tests
for the setters + clean try/finally state reset)
- plugins/.../test/server-startup.test.js (new): spawns \
ode server.js\,
captures stdout/stderr, SIGTERMs after 2s, asserts no ESM load
errors and 'listening on' reached
Doc fixes (commit 91d0bb0):
- docs/API.md: remove availableInterfaces (v1.0.1 cleanup removed it
but doc still had it)
- docs/ARCHITECTURE.md: remove pushEvent from state-bus exports,
correct the mcodeCommandsCache claim (lives in state-bus.js not
acp-client.js), expand config.js exports list
- docs/DEVELOPMENT.md: remove pushEvent from example code + import +
transport-layer description
- plugins/.../references/SECURITY-NOTES.md: remove 'set-headers' and
'crash-now' debug endpoints claims (those endpoints never existed
in the v1.0.1 source)
- README.md / README.zh-CN.md / CHANGELOG.md / CONTRIBUTING.md /
plugins/.../README.zh-CN.md / scripts/verify.mjs: stale test counts
fixed (302/372 → 382 passing + 1 skipped, 383 total)
- plugins/.../package.json: validate:plugin and verify scripts added
(mirror was missing them; CONTRIBUTING.md references them)
- All 4 docs/{API,ARCHITECTURE,DEVELOPMENT,TROUBLESHOOTING}.md:
brought back in sync with root (mirror drift fixed)
Verified: lint 0 warning, ROOT vs mirror SHA256 match for all synced
docs and code files.
Tests: 382 passing + 1 skipped (383 total).
…n-canonical install layouts Mirror of Wzdhehe/Mcode-webui commit 4abf56c to plugin layout. Round 4 review (modacker follow-up on PR MiniMax-AI#16) found that server/lib/db.js's getMcodeBetterSqlite3() hardcoded \__dirname/../../../node_modules/@minimax-ai/code/node_modules/better-sqlite3\. This path only works in the canonical dev layout where webui is at \<mcode-root>/webui/\. On macOS, registry install, or any non-canonical layout, mavis returns null → DELETE /api/sessions/:id fails (500) → 5 db.js tests fail on macOS reviewer. Fix: candidate-list fallback with priority: 1. \ env (explicit user override) 2. <MCODE_CMD>/../../node_modules/@minimax-ai/code/node_modules/better-sqlite3 3. <__dirname>/../../../node_modules/@minimax-ai/code/node_modules/better-sqlite3 (dev layout fallback — unchanged) Changes: - plugins/.../server/lib/db.js: replaced single hardcoded path with candidate-list fallback. Exports _getBetterSqlite3Candidates() for install-layout tests. - plugins/.../test/lib-db-resolver.test.js (new): 5 tests covering env override priority, dev layout fallback, candidate count invariant, MCODE_CMD branch. - plugins/.../references/SECURITY-NOTES.md §7: documents MCODE_BETTER_SQLITE3 env override next to existing MCODE_RUNTIME_DB and MCODE_WEBUI_SETTINGS_PATH entries. Tests: 387 passing / 0 failing / 1 skipped. Lint: 0 warnings. Independent audit: PASS.
Round 5 addresses the two remaining CHANGES_REQUESTED items from hetaoBackend's 2026-08-27 01:34Z review on PR MiniMax-AI#16 (commit 99dd587). 1. server/lib/db.js::_getBetterSqlite3Candidates Round 4 used `join(MCODE_CMD, '..', '..', ...)` which treated the mcode executable file as a directory. The fix uses `dirname(mcodeCmd)` directly: mcode.cmd is a file in the install dir, and the package's node_modules/ sits next to it. Round 4 accidentally went 3 levels above the install root (e.g. `/Users/moc/node_modules/...` instead of `/Users/moc/.minimax-code/node_modules/...`). The function is now parameterized as `_getBetterSqlite3Candidates({ mcodeCmd = MCODE_CMD } = {})` so install-layout tests can simulate any layout without mutating the module-level constant. 2. server/lib/db.js::deleteMcodeSessionFromDb The db-path check now runs BEFORE better-sqlite3 load. Round 4 had these reversed: callers passing a missing MCODE_RUNTIME_DB got `better_sqlite3_not_loaded` even when the db path was the actual problem. The test in lib-db.test.js:65 already documents the expected order (`mcode_db_not_found` must win) — implementation now matches. 3. test/lib-db-resolver.test.js - Test 5 ('MCODE_CMD-derived candidate is present...') updated to expect the corrected `dirname(MCODE_CMD)` prefix instead of the round 4 buggy `dirname(MCODE_CMD)/..` prefix. Adds a guard assertion that the buggy prefix is NOT used. - 3 new install-layout tests covering: • mcode binary at <install>/mcode.cmd → <install>/node_modules/... • mcode binary at /usr/local/bin/mcode → /usr/local/bin/node_modules/... • MCODE_CMD = 'mcode' (PATH placeholder) → no MCODE_CMD-derived candidate Test results in modacker env (no mcode install): • lib-db-resolver.test.js: 8/8 pass (5 existing + 3 new) • lib-db.test.js input validation: 5/5 pass • lib-db.test.js happy path / table-missing: 2/8 fail with reason='better_sqlite3_not_loaded' — environmental (no real better-sqlite3 binary at any candidate path). The fix doesn't cause this; these tests require a real mcode install to pass. Reviewer should re-run in a mcode-installed env. Refs: hetaoBackend review 2026-08-27 01:34Z on MiniMax-AI#16
|
@modacker 谢谢老哥,不过合并时能不能用 "Create a merge commit"(不要 Squash),m3老师建议我这样评论 @hetaoBackend |
…egration tests on macOS)
Round 5 closed two of hetaoBackend's open items, but the candidate
list still missed the actual mcode install layout on a real macOS dev
box (where the user is running mcode as their agent runtime).
Symptom: MCODE_CMD in config.js resolves to the PATH placeholder
'mcode' (not a full path) because the detection chain only looks for
'mcode.cmd' / 'MCODE_ROOT/mcode.cmd' / '~/.minimax-code/mcode.cmd',
and on macOS the binary is just 'mcode' at '~/.minimax-code/bin/mcode'.
With MCODE_CMD='mcode' the MCODE_CMD-derived branch is skipped
altogether, and the dev-layout fallback points at the plugin source
tree, not the real mcode package. Integration tests that actually
load better-sqlite3 fail with reason='better_sqlite3_not_loaded'.
Fix: emit three additional candidates.
1. From MCODE_CMD (when it IS a real path), try BOTH the npm-style
layout (<root>/bin/mcode → <root>/lib/node_modules/...) and the
flat layout (<root>/mcode → <root>/node_modules/...). Round 5 only
emitted the flat one.
2. Always emit <home>/.minimax-code/lib/node_modules/... as an
unconditional standard-install candidate. This is where mcode
actually ships its bundled deps on macOS dev installs
(verified: 'find ~/.minimax-code' shows
lib/node_modules/@minimax-ai/code/node_modules/better-sqlite3).
The function is now parameterized as
_getBetterSqlite3Candidates({ mcodeCmd, home } = {}) so tests
can simulate any install layout without env mutation.
Tests added:
- standard ~/.minimax-code/lib/node_modules/... is always tried
- mcode at <root>/bin/mcode emits BOTH npm-style and flat candidates
Test results in modacker env (real mcode install, no env override):
Before round 6: 387 pass / 4 fail / 2 skipped (all 4 fails =
better_sqlite3_not_loaded on the 2 happy-path integration tests
in lib-db.test.js and 2 in sessions.test.js)
After round 6: 391 pass / 0 fail / 2 skipped — all integration
tests now find and load better-sqlite3 via the standard-install
candidate
Refs: MiniMax-AI#16 round 5 follow-up, modacker env verification
Round 6 落地 + 整合测全过(modacker 本机 mcode 环境下验证)Round 5 之后我跑测试发现 4 个 fail,本以为是环境问题(没装 mcode)— 后来确认本机 mcode 装着的,是我之前没找对路径。Round 6 加了 标准安装候选 + npm-style 布局候选,现在: 修的具体点:
测试在真实 mcode 安装的 modacker 本机跑(无 env override),全部通过。 合并策略收到 @Wzdhehe 2026-08-27 18:50 CST 评论,用 "Create a merge commit",不要 Squash。这条是给 maintainer 看的——点 merge 时下拉选 Create a merge commit,保留全部 11 个 commit 历史。 请 @hetaoBackend 复核特别是 09:34 那条 CHANGES_REQUESTED 指出的两点:
跑一遍 cc @Wzdhehe 合并策略已记。 |
5 个独立修复 + 1 个外部 key 源特性,全部端到端验证 + 测试覆盖。
=== Core bug fixes ===
1. SSE clobber wiped quotaEnabled on every push
- server/lib/state-bus.js: 3 snapshot builders + pushOnlineCount now
include quotaEnabled / hasTokenPlanKey / tokenPlanApiKeyMasked
- server/routes/state.js: handleEvents (SSE first push) + handleState
(GET /api/state fallback) carry the same fields
- public/app/state.js: SSE onmessage defensively preserves these
three (mirrors the askUserAnswers / mcodeSessions pattern)
- Root cause was the appearance-card '显示套餐用量' toggle looking
like a no-op: server's snapshot was missing the field, so the
next SSE onmessage state=JSON.parse(ev.data) replaced local
state.quotaEnabled with undefined, btn.classList.toggle re-added
usage-hidden, button hid. All pushed on every /api/settings POST.
2. 4 missing imports in events.js (closeApiKeyModal / openApiKeyModal /
setLeftOpen / setRightOpen) — ReferenceError at attachEvents init.
Previously the modal handlers crashed the whole JS bootstrap.
3. usage.js parser read wrong field path + typo
- Read data?.current_interval_remaining_percent (top level) which
is always undefined. Real API nests it under
model_remains[i].current_interval_remaining_percent.
- Used 'pct' suffix instead of 'percent':
data?.current_weekly_remaining_pct (always undefined)
correct:
data?.current_weekly_remaining_percent
- Extracted to pure parseTokenPlanResponse(data, cs) for testability.
- Now also stores cs.usage.raw (8 KB cap) for future debugging.
- Real key 端到端验证: fiveHourPercent=25, weekly=51%,
fiveHourReset=1787864400, error=None, raw=990 bytes.
4. api-key-modal type=password made the whole page a 'credential form'
for Chrome autofill, so every text input on the page got email
autofill injected (including the search input).
- type=password → type=text + secret-input class
- CSS: -webkit-text-security: disc + monospace + letter-spacing
(visually a password box, semantically NOT a password field)
- This was the actual root cause of the stubborn autofill.
The other mitigations (readonly / autocomplete=off / data-1p-ignore)
were all bandaids; removing the page-level credential signal is
the real fix.
5. 5 <label class='lan-card-row-label'> had no associated form field
(DevTools a11y warning). Converted to <div> (they're row titles,
not form labels) and added explicit for= on each toggle's label.
=== Feature ===
6. Token Plan key can now be injected via env or file (priority chain
env > file > settings.json), per user request.
- env: MCODE_WEBUI_TOKEN_PLAN_KEY (env always wins, like the
existing process.env.TOKEN pattern for the LAN auth token)
- file: ~/.minimax/credentials/token-plan.json (raw or
{"key":"..."} JSON), path overridable via
MCODE_WEBUI_TOKEN_PLAN_KEY_FILE
- When env or file provides a key, quotaEnabled auto-enables so
the user doesn't have to flip the toggle.
- Webui surfaces the source ('env' / 'file' / 'settings') in the
popover + modal, hides the 'delete' button when the key is
external (operator must unset at the source).
=== i18n / UX ===
- 启用 → 显示套餐用量 (and synced en 'Enabled' → 'Show usage')
- New strings: quota_source_env / quota_source_file / delete disabled
hint / input placeholder hints for external sources
- Help text: was '关闭后,按钮仍显示,但点开是降级提示' (old behavior),
now '关闭后,套餐用量按钮在主界面消失' (matches current behavior)
=== Tests ===
- 3 new quota-field tests in test/state-bus.test.js (per-cid / broadcast /
pushOnlineCount all carry the 3 quota fields, setQuotaEnabled(false)
clears them in the next push)
- 6 new external-key-source tests in test/state-bus.test.js (settings /
file / env / live downgrade chain / broadcast / empty state)
- 7 new parser tests in test/usage.test.js (real API fixture pins
exact field names + 'general' model picking + end_time ms→s)
- test/_setup.js mock: mirrors real priority chain in getTokenPlanApiKey
+ getTokenPlanApiKeySource + maskTokenPlanKey so tests don't lie
Full suite: 409 pass / 0 fail / 2 skipped (was 393 / 0 / 2 → +16 tests).
Files: 13 modified + 1 new test + .gitignore (drop webui runtime
artifacts .server.err / .webui-sessions.json). Excluded from this
commit: 2 docs (REVIEW-SiHankor-baselines + BORROW-dsh) — modacker
perspective work product, not part of the PR.
Co-authored-by: mavis <noreply@example.com>
|
加油老哥,不过他们开放的东西就是有点少,我提交过反馈了,你可以关注tui更新日志,他们有时候会开放更多权限 |
hetaoBackend
left a comment
There was a problem hiding this comment.
Current head 091dec5 has passing local unit coverage, but the router has a CSRF/token-disclosure blocker. server/router.js:279-309 sets Access-Control-Allow-Origin: * and allows API requests from local addresses without a token; server/lib/auth.js:113-120 makes every local request authorized; server/routes/settings.js:28-30 returns the settings snapshot, including the bootstrap token before acknowledgement. I reproduced this with HOST=127.0.0.1: a POST /api/settings with Origin: https://evil.example and no Authorization returned 200 with Access-Control-Allow-Origin: * and the bootstrap-token field. A malicious webpage can therefore read the local token and issue state-changing API requests. Please remove the local browser bypass or add strict Origin/CSRF protection, never return bootstrap tokens to cross-origin callers, and add regression tests for unauthenticated cross-origin GET/POST/DELETE. [code]smith is SKIPPED.
Supersedes #16 — round 5 fix by @modacker
@Wzdhehe — your round 4 still had two open blockers. Both fixed in
round 5 + round 6. If this lands,
#16will auto-close (seeCloses #16at the bottom).🆕 Round 7 — Token Plan integration (commit 091dec5, modacker)
This was driven by user-facing bug reports during dogfooding:
the "套餐用量" / Token Plan feature shipped in the round-2 v1.0.1
era was broken on multiple layers. Round 7 fixes 5 independent bugs
and adds 1 feature. All verified end-to-end with the user's real
Subscription Key against the live
https://www.minimaxi.com/v1/token_plan/remainsendpoint.
5 core bug fixes
SSE clobber wiped
quotaEnabledon every push — root cause wasthe SSE snapshot missing
quotaEnabled/hasTokenPlanKey/tokenPlanApiKeyMasked, so the nextstate=JSON.parse(ev.data)replaced local state with undefined, and
btn.classList.toggle('usage-hidden', !undefined)re-hidden the button. Fixed in all 4 snapshot sites
(state-bus.js × 3, routes/state.js × 2) and defensive preserve in
client SSE onmessage (mirrors the existing
askUserAnswerspattern).4 missing imports in events.js (
closeApiKeyModal,openApiKeyModal,setLeftOpen,setRightOpen) — ReferenceErrorat attachEvents init crashed the whole JS bootstrap. Modal
handlers added without updating the import line.
server/lib/usage.jsparser read wrong field path + had afield-name typo:
data?.current_interval_remaining_percent(top level) —always undefined. Real API nests it under
model_remains[i].current_interval_remaining_percent.current_weekly_remaining_pct(withpctsuffix) — alwaysundefined. Correct name:
current_weekly_remaining_percent.parseTokenPlanResponse(data, cs)functioncs.usage.raw(8 KB cap) for future debugging.fiveHourPercent: 25, weekly: 51%, fiveHourReset: 1787864400, error: null, raw: 990B.<input type="password" id="api-key-modal-input">made the wholepage a "credential form" for Chrome autofill, so EVERY text
input on the page (including the session search) got email
autofill injected. The other mitigations
(
autocomplete=off/readonly/data-1p-ignore) were bandaids.type="password" → type="text" + .secret-input class-webkit-text-security: disc+ monospace + letter-spacing(visually a password box, semantically NOT a password field)
5
<label class="lan-card-row-label">had no associated formfield (DevTools a11y warning). Converted to
<div>(row titles,not form labels) and added explicit
for=on each toggle's label.1 new feature: external Token Plan key sources
Per user request ("我不想在前端重复输入 mcode 已经在用的 key"):
MCODE_WEBUI_TOKEN_PLAN_KEY(mirrors the existingprocess.env.TOKENoverride pattern for the LAN auth token)~/.minimax/credentials/token-plan.json(raw or{"key": "..."}JSON), path overridable viaMCODE_WEBUI_TOKEN_PLAN_KEY_FILEenv > file > settings.json(env always wins)quotaEnabledflips to
trueautomatically — operator who set the env / wrotethe file already committed to the feature.
source as
· env/· file: /path/to/file; "delete" button ishidden when source is external (operator must unset at the source,
not in the webui).
Test coverage (16 new tests, +16 from 393 → 409)
test/state-bus.test.js: 6 tests — settings / file / env prioritychain, live downgrade
env → file → settings, broadcast carriessource, empty-state behavior, 3 quota-field regression tests
(per-cid / broadcast / pushOnlineCount all carry the 3 fields)
test/usage.test.js(new file): 7 tests — real API fixture pinsexact wire shape (model_remains[0] / current_*_remaining_percent),
end_time ms→s conversion, no-general-entry fallback, missing
fields return null, base_resp.status_code error path
Files changed in round 7 (15 files, +1815 / -100)
i18n / UX
quota_source_env,quota_source_file, delete-disabledhint, input placeholders for external sources
behavior); now "关闭后,套餐用量按钮在主界面消失" (current
behavior)
Plugin/host scope note
Per modacker's review (
docs/REVIEW-sihankor-baselines-2026-08-28.md,docs/BORROW-dsh-deepseek-harness-2026-08-28.md— both kept inmodacker's local tree, not part of this PR), Token Plan integration
is plugin-scope only. The mcode host still writes to its own
sqlite without webui gating (out of plugin scope; needs mcode team
to ship
event:audit+event:anomaly+permission:requesthooksto enable Baseline 1 + Baseline 4 governance).
Future governance work (upstream issues)
Round 7 closes the immediate Token Plan bugs but the broader
governance gap (SiHankor baselines 1 / 3 / 4 + prohibitions 1 / 4 / 5)
requires follow-on work. Tracked in upstream issues (filed by
@modacker, this PR is the entry point for the series):
authorize + anomaly channel
→ closes Baseline 1 / 3 / 4 + prohibitions 1 / 4 / 5
?token=on first access→ removes stdout token leak
card grouping
slash.jsintointeraction/+feedback/subsystemsevent:audit+event:anomaly+permission:request→ not a plugin task; flagged
Plugin-side issues [Stage 1 / P0] governance: event log + per-request authorize + anomaly channel #24 / [Stage 2 / P1] UX: slash command autocomplete + settings card grouping #26 will reference [host-scope] mcode team hooks: event:audit + event:anomaly + permission:request #28 as a dependency
before merging the "combined audit view" UI work.
Plugin maintainer (@Wzdhehe) does not need to action all 5 — only
the plugin-scope ones (24, 25, 26, 27). Issue #28 is for the mcode
team.
Round 5 fixes (commit 0dbdacd) — preserved from prior PR body
[unchanged from prior PR body — round 5 content preserved below]
✅ Test verification (modacker real mcode env, no env override)
All integration tests (happy path × 2, table-missing × 2) now find
and load
better-sqlite3via the new~/.minimax-code/lib/node_modules/...standard-install candidate.
What's in this PR
MCODE_CMDpath traversal +deleteMcodeSessionFromDberror priority~/.minimax-code/lib/...) so macOS dev box integration tests find better-sqlite3Round 5 fixes (commit 0dbdacd)
1. better-sqlite3 candidate resolver —
MCODE_CMDpath traversalserver/lib/db.js::_getBetterSqlite3Candidateswas using:MCODE_CMDis the mcode executable file (e.g.~/.minimax-code/mcode.cmdor/usr/local/bin/mcode).The code treated it as a directory and went 3 levels above the install root,
landing at e.g.
/Users/moc/node_modules/...instead of/Users/moc/.minimax-code/node_modules/....Tests
lib-db-resolver.test.js: 10/10 pass (5 existing + 5 install-layout: mcode.cmd, /usr/local/bin/mcode, PATH placeholder, standard install, npm-style + flat both)lib-db.test.jsinput validation: 5/5 pass (including the previously-failingmcode_db_not_foundpriority test that round 5 unblocks)lib-db.test.jshappy-path / table-missing: 2/2 pass (round 6 fixes)sessions.test.js: alldeleteMcodeSessionFromDbtests passFull
npm testafter round 7: 409 pass / 0 fail / 2 skipped (skipped are pre-existing).Co-authored-by
9 cherry-picked commits retain @Wzdhehe as author.
Round 5, round 6, and round 7 commits are by @modacker.
Closes #16
Reviewers: @Wzdhehe @hetaoBackend