Skip to content

Commit b968a15

Browse files
committed
Add mcode-trajectory-studio: read-only session trajectory inspection via the runtime SQLite projection
A Plugin that answers questions about mcode's own sessions: which sessions exist, what each one was for, how far it got, what the user actually asked for, what failed, and what a background task captured. Read-only, over `~/.minimax/v2/sqlite/runtime-state.sqlite` with the per-session `messages.jsonl` as a fallback. 13 MCP tools plus a loopback-only web panel, zero runtime dependencies, no build step. This commit is the plugin and everything four review rounds and a mutation sweep changed in it. The rounds, in order, each closing reproduced defects rather than named ones: 1. Symlink escapes through task and session directories; credential redaction missing the forms the runtime actually stores (JSON text, escaped JSON, a key and its separator with a quote between); the panel's Host/Origin/Sec-Fetch-Site set described as authorization when it is a CSRF fence; `readOnlyHint` wrong on the one tool that starts a listener; and a Node floor that understated what `node:sqlite` needs. 2. Structured key names (`clientSecret`, `refreshToken`, `xApiKey`) judged by exact match, so they passed a value-only sweep; `stats.workspaceDir` reaching the panel unredacted beside the field above it that was folded; record lists bounded per string and not per response; a JSONL buffer that grew until EOF before the line cap was checked; and a documented containment boundary narrowed to match what the code enforces. 3. `/api/overview` throwing `ReferenceError` for any session with a non-empty agent definition — a fixture that stubbed the definition to `null` had hidden it; an event page trimmed to the byte budget returning the store's own cursor, so records 209–999 of a 1000-record page were unreachable forever; and a byte ceiling implemented as a character count, which multibyte rows walked straight through. 4. `trajectory_tasks` advancing by rows read rather than delivered, so a byte-trimmed page answered "no more pages" with hundreds of tasks counted but unreachable; the JSONL fallback discarding `malformed` exactly when a page stopped on its look-ahead, and never adopting an all-corrupt artifact at all; a task-index look-ahead clamped back to its own cap so `capped` could never be true; `tasksOmitted` measured against the read window and published beside a `tasksTotal` it contradicted; and a list read that materialised 2,000 unbounded descriptions before egress trimming. After those, the mutation sweep and the interfaces were audited the way a caller meets them rather than the way they are written: - Every record list derives its cursor from records **delivered**, counts omissions against the **session's own total**, and says which source it read. - `trajectory_get` grew a `role` filter after measuring the question it opens. A 5,831-record session holds 11 user messages — 0.2%. Asking "what did the user say" cost one 3 MB call before and 19 KiB after. - The redaction sweep is 35× cheaper on a 4 MiB response, after one rule was found retrying the key separator 64 times per character in text with no separator anywhere. - `tools/mutation-sweep.mjs` runs all 34 mutation scripts serially and names its failure categories, because a tally nobody can reproduce is indistinguishable from a clean one. 203 mutants, 0 survivors. - `tools/browser-check.mjs` drives real Chrome over the DevTools protocol; it is kept out of the default suite because it needs a browser, and it has caught defects the unit tests could not see. The panel carries a per-process 256-bit capability in the URL fragment — never sent to the server, so never logged and never in a `Referer` — with constant-time comparison on every `/api/*` route, and `Host`/`Origin`/`Sec-Fetch-Site` as depth. Every outbound payload is swept once more at the boundary, so a field added later cannot leave unredacted. CI is scoped to this Plugin: release gates, a stub-free egress contract suite driven against the real projection, the full suite on ubuntu/macos/windows, and an engine matrix that asserts the manifest's floor and verified range instead of describing them.
1 parent 1ef5e78 commit b968a15

163 files changed

Lines changed: 45288 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
name: mcode-trajectory-studio
2+
3+
# This Plugin carries three review rounds of confidentiality, containment and
4+
# bounding fixes, and each round ended with the same finding from the reviewer:
5+
# "current tests do not cover the reproduced cases". The three fixtures that should
6+
# have caught them existed and were green.
7+
#
8+
# So this workflow does not re-run the repository's own `npm run check`, which
9+
# already covers `scripts/validate.mjs` and the whole test tree on ubuntu. It adds
10+
# the evidence that has been *claimed* rather than checked for this Plugin:
11+
#
12+
# contract The plugin-scoped gates: the release gates, then the egress contract
13+
# suite that drives every tool and every route against the real
14+
# projection instead of a stub store. The `/api/overview` 500 survived
15+
# two rounds precisely because only stub stores exercised that path, so
16+
# the stub-free suite is run as its own named step rather than folded
17+
# into a count.
18+
# suite The full Plugin suite on ubuntu, macos and windows. Cross-platform
19+
# evidence was previously a hand-run claim; the previous hand-run had
20+
# not covered three platform assumptions in the tests themselves.
21+
# engines `tools/compat-matrix.mjs` under the documented Node floor, the lowest
22+
# verified release and the current line, so the manifest's floor and
23+
# verified range are asserted rather than described. On a release
24+
# outside the verified range the only permitted skip is the FTS5 search
25+
# test, and the tool fails if anything else is skipped.
26+
#
27+
# Scope is deliberately narrow: `paths:` filters this workflow to the Plugin plus
28+
# this file, so it can never block an unrelated PR. See the note in ci.yml about
29+
# why an unscoped "validate everything" job was removed there.
30+
31+
on:
32+
pull_request:
33+
paths:
34+
- 'plugins/weekbin/mcode-trajectory-studio/**'
35+
- '.github/workflows/mcode-trajectory-studio.yml'
36+
push:
37+
branches: [main]
38+
paths:
39+
- 'plugins/weekbin/mcode-trajectory-studio/**'
40+
- '.github/workflows/mcode-trajectory-studio.yml'
41+
# Lets a maintainer, or this Plugin's author, run the same jobs outside a PR —
42+
# which is how a github-hosted green check is captured on a fork whose
43+
# fork-to-upstream PR cannot start Actions without maintainer approval.
44+
workflow_dispatch:
45+
46+
permissions:
47+
contents: read
48+
49+
jobs:
50+
contract:
51+
name: contract gates (ubuntu-latest, node 22)
52+
runs-on: ubuntu-latest
53+
timeout-minutes: 20
54+
defaults:
55+
run:
56+
working-directory: plugins/weekbin/mcode-trajectory-studio
57+
steps:
58+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
59+
with:
60+
persist-credentials: false
61+
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
62+
with:
63+
node-version: 22
64+
# No `npm ci`: the Plugin ships zero dependencies and no build step, which is
65+
# itself part of what the release gates check.
66+
- name: release gates (version, engine claims, byte units, doc anchors, egress bounds)
67+
run: node tools/release-gates.mjs
68+
- name: every tool and route, driven against the real projection
69+
run: node --test test/egress-contract.test.mjs
70+
# The browser half of this harness is manual by nature and stays out of CI.
71+
# `--smoke` is the part a machine can judge, over a real loopback socket: the
72+
# panel binds, the document is served hardened, the capability is required and
73+
# sufficient, and the planted credential does not reach the wire. Removing the
74+
# capability check makes this step fail, which is how it was verified.
75+
- name: panel smoke over a real socket
76+
run: node tools/panel-e2e.mjs --smoke
77+
78+
suite:
79+
name: suite (${{ matrix.os }}, node 22)
80+
runs-on: ${{ matrix.os }}
81+
timeout-minutes: 25
82+
strategy:
83+
fail-fast: false
84+
matrix:
85+
os: [ubuntu-latest, macos-latest, windows-latest]
86+
defaults:
87+
run:
88+
working-directory: plugins/weekbin/mcode-trajectory-studio
89+
steps:
90+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
91+
with:
92+
persist-credentials: false
93+
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
94+
with:
95+
node-version: 22
96+
# The Plugin suite creates and removes real temporary directories and opens
97+
# real SQLite projections, so it is serialised: the Windows jobs fail with
98+
# EBUSY when a fixture is unlinked while SQLite still holds the file.
99+
- name: plugin suite
100+
shell: bash
101+
run: node --test --test-concurrency=1 'test/*.test.mjs' 2>&1 | tee trajectory-suite.tap
102+
- name: preserve suite output, including failures
103+
if: always()
104+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
105+
with:
106+
name: trajectory-suite-${{ matrix.os }}
107+
path: plugins/weekbin/mcode-trajectory-studio/trajectory-suite.tap
108+
if-no-files-found: warn
109+
retention-days: 7
110+
111+
engines:
112+
name: engines (node ${{ matrix.node }})
113+
runs-on: ubuntu-latest
114+
timeout-minutes: 25
115+
strategy:
116+
fail-fast: false
117+
matrix:
118+
# 22.13.0 is the floor: node:sqlite exists, FTS5 does not. The tool requires
119+
# that the FTS5 search test is the *only* skip there.
120+
# 22.19.0 is the lowest release in the verified range, where FTS5 is present.
121+
# 24.x is the line mcode's own engines allow today.
122+
node: ['22.13.0', '22.19.0', '24']
123+
defaults:
124+
run:
125+
working-directory: plugins/weekbin/mcode-trajectory-studio
126+
steps:
127+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
128+
with:
129+
persist-credentials: false
130+
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
131+
with:
132+
node-version: ${{ matrix.node }}
133+
- name: assert the suite behaves as the manifest claims for this release
134+
run: node tools/compat-matrix.mjs
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "mcode-trajectory-studio",
3+
"version": "0.1.3",
4+
"description": "只读查看本机 MiniMax Code 会话轨迹:轮次、步骤、LLM 与工具的墙钟耗时、token 用量、工具入参与结果、上下文拆分、压缩与子代理任务,并附带一个本地交互式面板。数据取自本地运行时自身的 SQLite 投影;插件不写入任何文件、不联网、不收集遥测。面板仅监听 127.0.0.1,每个 API 路由都要求一份随进程新生成的访问凭据。需要 Node.js 22.13.0+(内置 node:sqlite 的下限),已验证范围与 mcode engines 一致:>=22.19 <23 或 >=24 <27;全文检索另需内置 SQLite 带 FTS5,22.13.0-22.18.x 与 23.x 缺失时搜索降级并告警。 / Read-only inspection of local MiniMax Code session trajectories: turns, steps, LLM and tool wall-clock time, token usage, tool arguments/results, context breakdown, compactions, sub-agent tasks, plus a local panel. Data comes from the local runtime SQLite projection; the Plugin writes no files, no network, no telemetry. The panel listens on 127.0.0.1 only and requires a per-process capability token on every API route. Requires Node.js 22.13.0+ (the built-in node:sqlite floor); the verified range matches mcode engines: >=22.19 <23 or >=24 <27. Full-text search also needs FTS5 in that bundled SQLite; absent in 22.13.0-22.18.x and 23.x, where search degrades with a warning.",
5+
"author": {
6+
"name": "weekbin",
7+
"url": "https://github.com/weekbin"
8+
},
9+
"homepage": "https://github.com/MiniMax-AI/MiniMax-Code-Plugins/tree/main/plugins/weekbin/mcode-trajectory-studio",
10+
"repository": "https://github.com/MiniMax-AI/MiniMax-Code-Plugins.git",
11+
"license": "Apache-2.0",
12+
"keywords": [
13+
"minimax-code",
14+
"mcode",
15+
"trajectory",
16+
"session",
17+
"telemetry",
18+
"sqlite",
19+
"mcp",
20+
"visualization"
21+
],
22+
"skills": [
23+
"./skills/mcode-trajectory-studio/SKILL.md"
24+
],
25+
"mcpServers": {
26+
"mcode-trajectory-studio": {
27+
"type": "stdio",
28+
"command": "node",
29+
"args": [
30+
"./server/main.mjs"
31+
],
32+
"cwd": "${PLUGIN_ROOT}"
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)