ladder-mcp 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,115 +1,215 @@
1
- # Changelog
2
-
3
- All notable changes to Ladder_mcp are documented here. Format loosely follows
4
- [Keep a Changelog](https://keepachangelog.com/); this project uses
5
- [Semantic Versioning](https://semver.org/).
6
-
7
- ## [1.0.2] - 2026-06-28
8
-
9
- Security and robustness patch release addressing findings from an external
10
- adversarial review of `src/`.
11
-
12
- ### Fixed
13
-
14
- - **`isAuthenticated` false-positive on corrupt credentials** (`environment.ts`):
15
- a credentials file that exists but is unreadable or invalid JSON was previously
16
- reported as authenticated. It now fails closed and returns `false`, satisfying
17
- NFR-5 honest diagnostics.
18
- - **Unbounded `stdout`/`stderr` capture in `runKimi`** (`kimi-runner.ts`): CLI
19
- output is now accumulated through `appendCapped` with a hard ceiling
20
- (`MAX_CAPTURE_CHARS`), preventing memory exhaustion on runaway output.
21
- - **Unvalidated `max_output_tokens` and `work_dir`** (`input-validation.ts`):
22
- non-finite, zero, or negative token counts are clamped to the default budget;
23
- `work_dir` must be an absolute path to an existing directory before Kimi is
24
- spawned. Used by `kimi_analyze` and `kimi_resume`.
25
-
26
- ### Security
27
-
28
- - **Arbitrary command persisted to `mcp.json`** (`kimi-mcp-config.ts`):
29
- `kimi_generate_mcp_config` now validates `command` against an allow-list of
30
- `node`, `npx`, or an absolute path to an existing file. Other values (e.g.
31
- `powershell`) are rejected and nothing is written.
32
-
33
- ## [1.0.1] - 2026-06-28
34
-
35
- Bug-fix release. Issues found by exercising all 20 tools live against a real
36
- Kimi CLI (the mock-only unit tests had missed them).
37
-
38
- ### Fixed
39
-
40
- - **ACP responses lost spaces** (`kimi_chat`): streamed token chunks were each
41
- trimmed and newline-joined, so `"Two plus two equals four."` came back as
42
- `"Twoplustwoequalsfour."`. Text fragments are now concatenated as-is and only
43
- the final string is trimmed. (CLI tools `kimi_analyze`/`kimi_resume` were never
44
- affected.)
45
- - **`kimi_export_session` silently no-op'd** while reporting `ok: true`: when no
46
- session id was given, `kimi export` defaults to the most recent session and asks
47
- `Export previous session …? [Y/n]` a prompt that `-y` does not suppress in Kimi
48
- CLI 0.20.1, so with stdin closed it exited 0 without writing. The tool now
49
- resolves the most recent session id itself and passes it explicitly (skipping the
50
- prompt), always passes `-y`, and verifies the output file exists before reporting
51
- success.
52
-
53
- ### Changed
54
-
55
- - `kimi_acp_sessions` now accepts `limit` (default 20) and `work_dir` filters,
56
- for parity with `kimi_list_sessions`; previously it dumped every ACP session
57
- across all projects in one response.
58
-
59
- ## [1.0.0] - 2026-06-27
60
-
61
- First release. Windows-first MCP bridge for Kimi Code CLI v24, rebuilt in a
62
- fresh `./src` application (package `ladder-mcp`). Logic is ported from the
63
- read-only `kimi-code-mcp/` reference; the legacy `CacheManager`/warmup layer is
64
- not carried over.
65
-
66
- ### Added v1 core (Epics 1-3)
67
-
68
- - Robust environment resolver (`environment.ts`): discovers `kimi.exe` via PATH
69
- and `~/.kimi-code/bin/`, resolves the `~/.kimi-code/` catalog, credentials and
70
- version with no hardcoded POSIX paths; no silent fallback to legacy `~/.kimi/`.
71
- - CLI adapter (`kimi-runner.ts`): correct Kimi CLI v24 arguments
72
- (`-p`, `--output-format stream-json`, `-S`, `-C`, `--auto`), `stream-json`
73
- parsing, native session resume, Windows process-tree termination on timeout.
74
- - API adapter (`kimi-api.ts`): contextless `kimi_query` / `kimi_verify` reading
75
- key/endpoint from `KIMICODE_API_KEY` or `~/.kimi-code/config.toml`.
76
- - Six v1 MCP tools: `kimi_analyze`, `kimi_query`, `kimi_verify`, `kimi_resume`,
77
- `kimi_list_sessions`, `kimi_status`.
78
-
79
- ### Added vNext expansion (Epic 4)
80
-
81
- - **CLI admin & capabilities** (`transports/cli-admin.ts`): `kimi_capabilities`,
82
- `kimi_doctor`, `kimi_provider_list`, `kimi_export_session`,
83
- `kimi_visualize_session`. Export requires an explicit `output_path`, is
84
- confined to the working directory, and excludes the global diagnostic log by
85
- default.
86
- - **ACP MVP over stdio** (`transports/acp.ts`): JSON-RPC client for `kimi acp`
87
- with newline-delimited and `Content-Length` framing; `kimi_chat`,
88
- `kimi_acp_sessions`, `kimi_cancel`.
89
- - **Background task lifecycle** (`task-store.ts`): in-process task store with
90
- `kimi_chat background=true`, `kimi_task_status`, `kimi_task_output`,
91
- `kimi_task_cancel`.
92
- - **Kimi-hosted MCP config + read-only desktop probes**
93
- (`kimi-mcp-config.ts`, `desktop-work.ts`): `kimi_generate_mcp_config`,
94
- `kimi_desktop_status`, `kimi_budget_probe`. Desktop access is
95
- experimental/read-only — no token-store reads, no web-auth replay, no desktop
96
- Work task submission.
97
-
98
- ### Security & robustness (adversarial review)
99
-
100
- Hardened against path traversal/TOCTOU on export, writes under the read-only
101
- reference tree, unbounded ACP frame/task memory, process crash on malformed ACP
102
- JSON, non-idempotent task cancellation, and UTF-8 byte-boundary truncation.
103
-
104
- The remaining lower-risk review findings (W1-W12) were also resolved before
105
- release: raw ACP response-id matching (no `NaN` coercion), bounded ACP update
106
- buffer, clamped ACP request timeouts, smaller buffers for parallel capability
107
- probes, a timeout around task cancel hooks, a size cap on the desktop status
108
- probe body, validated `kimi_chat` timeout input, and `kimi_cancel` rejecting
109
- ambiguous task_id+session_id calls. Regression tests added (49 total).
110
-
111
- ### Known limitations
112
-
113
- - Windows 11 only (NFR-1); POSIX branches are not a target.
114
-
115
- [1.0.0]: https://semver.org/
1
+ # Changelog
2
+
3
+ All notable changes to Ladder_mcp are documented here. Format loosely follows
4
+ [Keep a Changelog](https://keepachangelog.com/); this project uses
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [1.1.0] - 2026-06-28
8
+
9
+ Breaking tool-surface redesign: the MCP tool list is now an intent-first set of
10
+ 6 default tools, with niche/admin features gated behind `LADDER_EXPERIMENTAL=1`.
11
+
12
+ ### Changed
13
+
14
+ - `src/index.ts` now registers 6 default tools: `kimi_code`, `kimi_ask`,
15
+ `kimi_sessions`, `kimi_tasks`, `kimi_status`, `kimi_setup`.
16
+ - `kimi_code` folds `kimi_analyze`, `kimi_resume`, and `kimi_chat`. It defaults to
17
+ `transport='cli'` (validated `work_dir` via `validateWorkDir`) and supports
18
+ `edit`, `background`, `session_id`, and `new_session`.
19
+ - `kimi_ask` folds `kimi_query` and `kimi_verify`; providing `context` switches to
20
+ verify mode.
21
+ - `kimi_sessions` folds `kimi_list_sessions` and `kimi_acp_sessions` behind the
22
+ `source` parameter (`cli`, `acp`, `all`).
23
+ - `kimi_tasks` action-dispatches `status`, `output`, and `cancel` (including ACP
24
+ session cancellation via `session_id`).
25
+ - `kimi_status` detail-switches between `basic` and `full`; `full` adds
26
+ capabilities, doctor, and provider list. `isError` is now true whenever a
27
+ remediation is required.
28
+ - `kimi_setup` renames `kimi_generate_mcp_config` and resolves the default server
29
+ command from `process.execPath`.
30
+
31
+ ### Removed
32
+
33
+ The 20-tool default surface is replaced by the 6 tools above. The following tool
34
+ names are no longer registered by default:
35
+
36
+ - `kimi_analyze`, `kimi_resume`, `kimi_chat`
37
+ - `kimi_query`, `kimi_verify`
38
+ - `kimi_list_sessions`, `kimi_acp_sessions`
39
+ - `kimi_task_status`, `kimi_task_output`, `kimi_task_cancel`, `kimi_cancel`
40
+ - `kimi_capabilities`, `kimi_doctor`, `kimi_provider_list`
41
+ - `kimi_generate_mcp_config`
42
+
43
+ ### Migration
44
+
45
+ | Old tool | New |
46
+ |---|---|
47
+ | `kimi_analyze` | `kimi_code` (edit=false) |
48
+ | `kimi_resume` | `kimi_code` (session_id set) |
49
+ | `kimi_chat` | `kimi_code` (transport='acp') |
50
+ | `kimi_query` | `kimi_ask` |
51
+ | `kimi_verify` | `kimi_ask` (context/role set) |
52
+ | `kimi_list_sessions` | `kimi_sessions` (source='cli') |
53
+ | `kimi_acp_sessions` | `kimi_sessions` (source='acp') |
54
+ | `kimi_task_status` | `kimi_tasks` (action='status') |
55
+ | `kimi_task_output` | `kimi_tasks` (action='output') |
56
+ | `kimi_task_cancel` | `kimi_tasks` (action='cancel') |
57
+ | `kimi_cancel` | `kimi_tasks` (action='cancel', task_id or session_id) |
58
+ | `kimi_status` | `kimi_status` |
59
+ | `kimi_capabilities` | `kimi_status` (detail='full') |
60
+ | `kimi_doctor` | `kimi_status` (detail='full') |
61
+ | `kimi_provider_list` | `kimi_status` (detail='full') |
62
+ | `kimi_generate_mcp_config` | `kimi_setup` |
63
+ | `kimi_export_session` | experimental (unchanged name) |
64
+ | `kimi_visualize_session` | experimental |
65
+ | `kimi_desktop_status` | experimental |
66
+ | `kimi_budget_probe` | experimental |
67
+
68
+ The 4 experimental tools (`kimi_export_session`, `kimi_visualize_session`,
69
+ `kimi_desktop_status`, `kimi_budget_probe`) now register only when
70
+ `process.env.LADDER_EXPERIMENTAL === '1'`.
71
+
72
+ ### Added
73
+
74
+ - **Bidirectional ACP transport** (`transports/acp.ts`): the bridge now answers the
75
+ agent's client-bound JSON-RPC requests, so file edits and permission flows over
76
+ ACP complete instead of hanging. Includes auto-approved `session/request_permission`
77
+ and a `fs/read_text_file`/`fs/write_text_file`/`fs/read_directory` proxy.
78
+ - **Live-progress visibility**: long-running `kimi_code` work surfaces progress —
79
+ background tasks grow a timestamped log, foreground calls emit MCP
80
+ `notifications/progress`, and a stall watchdog flags silent hangs. Token streams
81
+ are coalesced so the log is readable.
82
+ - **Single-source versioning** (`version.ts`) read from `package.json`, plus
83
+ `release:patch/minor/major` scripts and a `preversion` typecheck+test gate.
84
+
85
+ ### Security
86
+
87
+ - **ACP fs proxy is sandboxed** to the session `work_dir` with realpath-based
88
+ containment (blocks symlink/junction escape, case-folding bypass, drive-relative
89
+ and UNC paths); fails closed when the work dir is unset. Permission auto-approve
90
+ fails closed when no single-use option is offered. File reads are size-capped.
91
+ - **`assertSafeCommand`** (`kimi-mcp-config.ts`) rejects PATH-resolved bare
92
+ `node`/`npx`, accepting only `process.execPath` or an absolute existing file;
93
+ `assertWritableProjectTarget` uses realpath containment instead of substring match.
94
+
95
+ ### Fixed
96
+
97
+ - Process-tree termination on Windows (`taskkill /T /F`) for ACP close/cancel and
98
+ `runKimi` timeout, with awaited exit so callers don't race a dying tree.
99
+ - Timeouts in `runKimi` and `runKimiApi` are clamped; `timeout_ms` tool args must be
100
+ positive integers.
101
+ - `parseKimiStreamJson` tolerates leading whitespace; resume-hint extraction is
102
+ fuzzier; `contentToText` keeps placeholders for non-text parts.
103
+ - `task-store` no longer appends to terminal tasks; `runKimi` preserves both stdout
104
+ and stderr on failure; disk-discovered sessions recover their real `work_dir`.
105
+ - Capped the `readBodyCapped` non-streaming fallback (`desktop-work.ts`).
106
+
107
+ ## [1.0.2] - 2026-06-28
108
+
109
+ Security and robustness patch release addressing findings from an external
110
+ adversarial review of `src/`.
111
+
112
+ ### Fixed
113
+
114
+ - **`isAuthenticated` false-positive on corrupt credentials** (`environment.ts`):
115
+ a credentials file that exists but is unreadable or invalid JSON was previously
116
+ reported as authenticated. It now fails closed and returns `false`, satisfying
117
+ NFR-5 honest diagnostics.
118
+ - **Unbounded `stdout`/`stderr` capture in `runKimi`** (`kimi-runner.ts`): CLI
119
+ output is now accumulated through `appendCapped` with a hard ceiling
120
+ (`MAX_CAPTURE_CHARS`), preventing memory exhaustion on runaway output.
121
+ - **Unvalidated `max_output_tokens` and `work_dir`** (`input-validation.ts`):
122
+ non-finite, zero, or negative token counts are clamped to the default budget;
123
+ `work_dir` must be an absolute path to an existing directory before Kimi is
124
+ spawned. Used by `kimi_analyze` and `kimi_resume`.
125
+
126
+ ### Security
127
+
128
+ - **Arbitrary command persisted to `mcp.json`** (`kimi-mcp-config.ts`):
129
+ `kimi_generate_mcp_config` now validates `command` against an allow-list of
130
+ `node`, `npx`, or an absolute path to an existing file. Other values (e.g.
131
+ `powershell`) are rejected and nothing is written.
132
+
133
+ ## [1.0.1] - 2026-06-28
134
+
135
+ Bug-fix release. Issues found by exercising all 20 tools live against a real
136
+ Kimi CLI (the mock-only unit tests had missed them).
137
+
138
+ ### Fixed
139
+
140
+ - **ACP responses lost spaces** (`kimi_chat`): streamed token chunks were each
141
+ trimmed and newline-joined, so `"Two plus two equals four."` came back as
142
+ `"Twoplustwoequalsfour."`. Text fragments are now concatenated as-is and only
143
+ the final string is trimmed. (CLI tools `kimi_analyze`/`kimi_resume` were never
144
+ affected.)
145
+ - **`kimi_export_session` silently no-op'd** while reporting `ok: true`: when no
146
+ session id was given, `kimi export` defaults to the most recent session and asks
147
+ `Export previous session …? [Y/n]` — a prompt that `-y` does not suppress in Kimi
148
+ CLI 0.20.1, so with stdin closed it exited 0 without writing. The tool now
149
+ resolves the most recent session id itself and passes it explicitly (skipping the
150
+ prompt), always passes `-y`, and verifies the output file exists before reporting
151
+ success.
152
+
153
+ ### Changed
154
+
155
+ - `kimi_acp_sessions` now accepts `limit` (default 20) and `work_dir` filters,
156
+ for parity with `kimi_list_sessions`; previously it dumped every ACP session
157
+ across all projects in one response.
158
+
159
+ ## [1.0.0] - 2026-06-27
160
+
161
+ First release. Windows-first MCP bridge for Kimi Code CLI v24, rebuilt in a
162
+ fresh `./src` application (package `ladder-mcp`). Logic is ported from the
163
+ read-only `kimi-code-mcp/` reference; the legacy `CacheManager`/warmup layer is
164
+ not carried over.
165
+
166
+ ### Added — v1 core (Epics 1-3)
167
+
168
+ - Robust environment resolver (`environment.ts`): discovers `kimi.exe` via PATH
169
+ and `~/.kimi-code/bin/`, resolves the `~/.kimi-code/` catalog, credentials and
170
+ version with no hardcoded POSIX paths; no silent fallback to legacy `~/.kimi/`.
171
+ - CLI adapter (`kimi-runner.ts`): correct Kimi CLI v24 arguments
172
+ (`-p`, `--output-format stream-json`, `-S`, `-C`, `--auto`), `stream-json`
173
+ parsing, native session resume, Windows process-tree termination on timeout.
174
+ - API adapter (`kimi-api.ts`): contextless `kimi_query` / `kimi_verify` reading
175
+ key/endpoint from `KIMICODE_API_KEY` or `~/.kimi-code/config.toml`.
176
+ - Six v1 MCP tools: `kimi_analyze`, `kimi_query`, `kimi_verify`, `kimi_resume`,
177
+ `kimi_list_sessions`, `kimi_status`.
178
+
179
+ ### Added — vNext expansion (Epic 4)
180
+
181
+ - **CLI admin & capabilities** (`transports/cli-admin.ts`): `kimi_capabilities`,
182
+ `kimi_doctor`, `kimi_provider_list`, `kimi_export_session`,
183
+ `kimi_visualize_session`. Export requires an explicit `output_path`, is
184
+ confined to the working directory, and excludes the global diagnostic log by
185
+ default.
186
+ - **ACP MVP over stdio** (`transports/acp.ts`): JSON-RPC client for `kimi acp`
187
+ with newline-delimited and `Content-Length` framing; `kimi_chat`,
188
+ `kimi_acp_sessions`, `kimi_cancel`.
189
+ - **Background task lifecycle** (`task-store.ts`): in-process task store with
190
+ `kimi_chat background=true`, `kimi_task_status`, `kimi_task_output`,
191
+ `kimi_task_cancel`.
192
+ - **Kimi-hosted MCP config + read-only desktop probes**
193
+ (`kimi-mcp-config.ts`, `desktop-work.ts`): `kimi_generate_mcp_config`,
194
+ `kimi_desktop_status`, `kimi_budget_probe`. Desktop access is
195
+ experimental/read-only — no token-store reads, no web-auth replay, no desktop
196
+ Work task submission.
197
+
198
+ ### Security & robustness (adversarial review)
199
+
200
+ Hardened against path traversal/TOCTOU on export, writes under the read-only
201
+ reference tree, unbounded ACP frame/task memory, process crash on malformed ACP
202
+ JSON, non-idempotent task cancellation, and UTF-8 byte-boundary truncation.
203
+
204
+ The remaining lower-risk review findings (W1-W12) were also resolved before
205
+ release: raw ACP response-id matching (no `NaN` coercion), bounded ACP update
206
+ buffer, clamped ACP request timeouts, smaller buffers for parallel capability
207
+ probes, a timeout around task cancel hooks, a size cap on the desktop status
208
+ probe body, validated `kimi_chat` timeout input, and `kimi_cancel` rejecting
209
+ ambiguous task_id+session_id calls. Regression tests added (49 total).
210
+
211
+ ### Known limitations
212
+
213
+ - Windows 11 only (NFR-1); POSIX branches are not a target.
214
+
215
+ [1.0.0]: https://semver.org/
@@ -7,8 +7,16 @@ export const MAX_PROBE_BODY_BYTES = 256 * 1024;
7
7
  // The surrounding AbortController still bounds total time.
8
8
  export async function readBodyCapped(response) {
9
9
  const reader = response.body?.getReader();
10
- if (!reader)
11
- return { text: await response.text(), truncated: false };
10
+ if (!reader) {
11
+ // The body is not streamable; still cap the returned text so a non-streaming
12
+ // response cannot return an unbounded body.
13
+ const text = await response.text();
14
+ const bytes = Buffer.byteLength(text, 'utf-8');
15
+ if (bytes > MAX_PROBE_BODY_BYTES) {
16
+ return { text: Buffer.from(text, 'utf-8').subarray(0, MAX_PROBE_BODY_BYTES).toString('utf-8'), truncated: true };
17
+ }
18
+ return { text, truncated: false };
19
+ }
12
20
  const decoder = new TextDecoder();
13
21
  let text = '';
14
22
  let total = 0;