Add plugin: mcode-webui (round 5 — supersedes #16) - #23
Open
modacker wants to merge 12 commits into
Open
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
11 tasks
|
@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
Author
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更新日志,他们有时候会开放更多权限 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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