deepseek-coordination 0.10.1 → 0.12.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/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  A dual-face Cordis plugin for DeepSeek Harness: the host half owns a coordination SQLite database, seven model-facing tools and an HTTP surface; the web half mounts five composer dropdowns, a settings catalog and the service-level takeover dialog.
6
6
 
7
- **Status: v0.10.0 (2026-10-18).** This release follows the v0.9.2 tooltip fix and lands the settings catalog, the durable file layer, the turn pipeline, phase freezes and the data-structure adoption pass. The package version, changelog and release tarball are the same tree; claims below were checked against source, not against the design documents alone.
7
+ **Status: v0.12.0 (2026-10-18).** This release adds a domain-concept layer split by ecosystem — tex, book, markdown, html, five programming languages, maven/npm and Office — plus a `kind` filter on the chain query, a directory layer, and the canonical `NodeRecord`. It builds on v0.11.0 (durable settings, DSH-owned reasoning, experimental cache proxy). The package version, changelog and release tarball are the same tree; claims below were checked against source, not against the design documents alone.
8
8
 
9
9
  | Status | Meaning in this README |
10
10
  |---|---|
@@ -60,7 +60,7 @@ Install the packed tarball, not the GitHub source:
60
60
 
61
61
  ```powershell
62
62
  npm pack
63
- dsh plugin --profile <name> add .\deepseek-coordination-0.10.0.tgz
63
+ dsh plugin --profile <name> add .\deepseek-coordination-0.12.0.tgz
64
64
  dsh --profile <name> --dump-config # expect a deepseek-coordination layer
65
65
  ```
66
66
 
@@ -159,16 +159,16 @@ The budgets live in `src/host/comprehension.ts` and the shared `ValidationBudget
159
159
 
160
160
  ### Scenes and the writing profile
161
161
 
162
- | Scene | Thinking / effort | Plan | Outline | Revision | Score | Bash | Web | Max iterations |
163
- |---|---|---|---|---|---|---|---|---|
164
- | dialogue | disabled / medium | – | – | – | – | no | yes | 1 |
165
- | writing | enabled / high | yes | yes | yes | yes | no | yes | 3 |
166
- | office | disabled / medium | yes | – | – | – | no | yes | 1 |
167
- | research | enabled / high | yes | – | – | – | no | yes | 3 |
168
- | engineering | enabled / high | yes | – | – | – | yes | yes | 3 |
169
- | iterate | enabled / high | – | – | – | yes | no | yes | 3 |
162
+ | Scene | Plan | Outline | Revision | Score | Bash | Web | Max iterations |
163
+ |---|---|---|---|---|---|---|---|
164
+ | dialogue | – | – | – | – | no | yes | 1 |
165
+ | writing | yes | yes | yes | yes | no | yes | 3 |
166
+ | office | yes | – | – | – | no | yes | 1 |
167
+ | research | yes | – | – | – | no | yes | 3 |
168
+ | engineering | yes | – | – | – | yes | yes | 3 |
169
+ | iterate | – | – | – | yes | no | yes | 3 |
170
170
 
171
- `writing` requires an outline and at least one revision round, requires a quality score, disallows bash, allows web search and caps the loop at three iterations. The pass threshold is `0.6`; `plan.ts` uses that writing threshold. The turn pipeline reads reasoning effort, the require-* flags, citation/evidence, `allowWeb` and `sandboxOnly`; `thinking`, `allowBash`, `maxIteration` and non-writing thresholds remain deferred diagnostics because no DSH port or consumer exists yet.
171
+ `writing` requires an outline and at least one revision round, requires a quality score, disallows bash, allows web search and caps the loop at three iterations. The pass threshold is `0.6`; `plan.ts` uses that writing threshold. The turn pipeline reads the require-* flags, citation/evidence, `allowWeb` and `sandboxOnly`; reasoning (`thinking`, `reasoningEffort`) belongs to DSH — the page has no row for it, and the turn records what the session's own request header carries rather than a scene literal. `allowBash`, `maxIteration` and non-writing thresholds remain deferred diagnostics because no DSH port or consumer exists yet.
172
172
 
173
173
  ## Profession lock and turn lifecycle
174
174
 
@@ -188,9 +188,40 @@ The budgets live in `src/host/comprehension.ts` and the shared `ValidationBudget
188
188
 
189
189
  Terminal turn states (`done`, `failed`, `cancelled`, `abandoned`) are irreversible. The turn hook records turn metadata and an empty prompt row; it does not mirror the DSH conversation into the coordination database.
190
190
 
191
+ ## Domain ecosystems and parsers
192
+
193
+ The file layer is not one parser with a bag of node kinds. Each system owns a module under `src/host/text/`, and the node kinds it may emit are bounded by that system's semantics. All output is body-free `NodeMetadata`: kind, explicit name/label, span and fragment coordinates — never a body, a cell value or a paragraph.
194
+
195
+ | Ecosystem | Module | Node kinds it may emit |
196
+ |---|---|---|
197
+ | tex | `tex.ts` | `definition`, `lemma`, `theorem`, `proof`, `property`, `axiom`, `corollary`, `claim`, `example`, `remark`, `calculation`, `condition` (+ `requires`/`meets` edges) |
198
+ | book | `book.ts` | `book`, `part`, `chapter`, `article`, `section`, `person`, `venue` — the only producer of `article` |
199
+ | markdown | `markup.ts` | `document`, `chapter`, `heading`, `paragraph`, `div`, `link`, `code`, `section`, `sheet`, `cell`, `range`, `condition` |
200
+ | html | `markup.ts` | `document`, `section` (`<article>` maps here), `chapter` (`<h1>`), `link`, `code` |
201
+ | js/ts | `javascript.ts` | `class`, `function`, `method`, `variable`, `interface`, `type`, `enum`, `namespace`, `importation`, `exportation`, `condition` |
202
+ | java | `java.ts` | `module`, `class`, `method`, `variable`, `importation` |
203
+ | python | `python.ts` | `class`, `function`, `method`, `variable`, `importation` |
204
+ | c/c++ | `c-family.ts` | `module`, `class`, `function`, `method`, `variable`, `importation` |
205
+ | rust | `rust.ts` | `module`, `class`, `function`, `method`, `variable`, `importation` |
206
+ | php | `php.ts` | `module`, `class`, `function`, `method`, `variable`, `importation` |
207
+ | maven | `maven.ts` | `project`, `module`, `dependency` (parent is a dependency with `label: 'parent'`) |
208
+ | npm | `npm.ts` | `project`, `dependency`, `script` (the command body is never stored) |
209
+ | office | `office.ts` | docx: `document`, `chapter`, `section`, `paragraph`, `link`; xlsx: `workbook`, `sheet`, `range`, `formula`; pptx: `document`, `slide`; pub/accdb: no nodes, one `unsupported-format` diagnostic |
210
+ | text | `sentence.ts` | `sentence` segmentation and `line` ranges (coordinates, not nodes) |
211
+
212
+ Rules that hold across every ecosystem:
213
+
214
+ - **Language nuance lives in `label`, not in new kinds.** Rust `impl` is `kind: 'class'` with `label: 'implementation'`; C++ `struct`/`enum` and PHP `trait` work the same way. `NodeKind` stays a small closed union.
215
+ - **Descriptive only.** No parser writes files, builds, installs, executes macros or reaches the network. A real "create project" is a shell command behind DSH's permission model, never a plugin tool.
216
+ - **Explicit evidence only.** A heading level is never inferred from text, a package version is never invented, and a missing relationship is reported rather than paired positionally. Malformed input returns a diagnostic and never throws.
217
+ - **Bounded.** ZIP entries ≤ 2000, uncompressed ≤ 64 MiB per entry / 256 MiB total, XML nesting ≤ 128, nodes ≤ `MAX_METADATA_NODES` (20 000), and the parser honors the token/time budgets.
218
+ - **`SUMMARY.md` resolves to `book`** through the registry's filename-first rule; `README.md` and other Markdown stay with the Markdown parser.
219
+
220
+ The graph answers "what is in this workspace" through `coordination_parse`, `coordination_describe` and `coordination_chain`. The chain query takes an optional `kind` (trimmed, case-insensitive) on every node-returning action, so "all lemmas" or "all chapters" is one call instead of a scan. Directory nodes are derived from unambiguous workspace paths and connected with `contains`/`part_of`; the invariant is **`part_of` (child→parent) exact, `contains` (parent→child) best-effort**.
221
+
191
222
  ## Settings and configuration
192
223
 
193
- The settings page is driven by `SETTINGS_CONTROLS` in `src/shared/selection.ts`: **151 controls in 13 groups, 134 writable host rows, covering 155 non-secret config leaves**. The 18 top-level config keys include `database` and `databasePath`, which are deliberately not projected or writable.
224
+ The settings page is driven by `SETTINGS_CONTROLS` in `src/shared/selection.ts`: **139 controls in 13 groups, 122 writable host rows, covering 155 config leaves**. Twelve scene leaves (`scenes.*.thinking`, `scenes.*.reasoningEffort`) stay in the schema but have no row: DSH's model page owns reasoning, and duplicating it here would create two sources of truth. The 18 top-level config keys include `database` and `databasePath`, which are deliberately not projected or writable.
194
225
 
195
226
  | Group | Defaults / scope | Write path |
196
227
  |---|---|---|
@@ -198,36 +229,59 @@ The settings page is driven by `SETTINGS_CONTROLS` in `src/shared/selection.ts`:
198
229
  | `profession` | enabled/lock/rebuild/abandon forced `true`; default mirrors `defaults.profession`; audit/errorHint `true` | Forced flags read-only; audit/errorHint host rows (audit has no consumer) |
199
230
  | `plan` | threshold `0.5`, maxRebuild `3`, 8 weights summing to 1, 8 dimension thresholds | Host rows; weights re-normalise on save |
200
231
  | `orchestration` | maxReject `2`, maxSubTask `32`, groundTruth `true`, timeout `5000 ms`, shell ground truth `false`, modelRouting `true` | Host rows; `groundTruthTimeout` has no consumer |
201
- | `cache` | enabled `true`, ttl `60000 ms`, fingerprintWindow `50`, effortWarning `true` | Host rows; `fingerprintWindow` has no consumer |
232
+ | `cache` | enabled `true`, ttl `60000 ms`, fingerprintWindow `50`, effortWarning `true` | Host rows; `enabled`/`effortWarning` gate the cache proxy decorator, `ttl` caches the model catalog, `fingerprintWindow` has no consumer |
202
233
  | `bayesian` | prior `0.5`, stopEntropy `0.05`, infoGain `0.01`, maxRoutes `12`, calibrationFloor `0.1` | Host rows; `calibrationFloor` has no consumer |
203
234
  | `comprehension` | stageTimeout `30000 ms`, searchEnabled `true`, maxEvidence `8`, highHistoryWindow `50` | Host rows |
204
235
  | `compaction` | auto `true`, soft `0.70`, hard `0.88`, reserve `2048`, recentTurns `6`, cooldown `30000 ms`, maxPerSession `20` | auto/soft/hard host rows; structural fields read-only |
205
236
  | `ui` | toolbar `true` (deprecated alias), showTooltip `true`, takeover `false`, refreshInterval `5000 ms`, compact `true`, locale `auto` | Host rows plus the two local switches; toolbar/locale read-only |
206
- | `scenes` | six scene profiles, 13 fields each; writing threshold `0.6` | Host rows; only the writing score threshold is read by `plan.ts` |
237
+ | `scenes` | six scene profiles, 9 exposed rows each (thinking/effort remain schema-only) and a writing threshold of `0.6` | Host rows; only the writing score threshold is read by `plan.ts` |
207
238
  | `parser` | enabled `true`, 1 MiB, 200k tokens, depth `256`, 2 s, cache `256`, graph 20k/100k | enabled + four limits host rows; depth and graph caps planned |
208
239
  | `chain` | depth `8`, links `50`, tokenBudget `1500` | Host rows |
209
240
  | `tools` | maxResultBytes `0` | Planned/read-only; not consumed |
210
241
  | `defaults` | profession `execution`, interaction `think`, scene `dialogue`, validation `medium`, command `none` | Host rows |
211
242
 
212
- `GET /deepseek-coordination/config` returns `{ values, defaults }`; `defaults` is `resolveConfig(undefined)`, so the page never duplicates a default literal. `POST /config` accepts a flat dotted patch such as `{ "plan.threshold": 0.7 }`, validates it against the catalog and the real Schemastery schema, applies it to the live config, re-resolves invariants (weight normalisation, alias mirror, forced flags, compaction clamps), rebuilds `TokenGovernor` when compaction changes, and best-effort persists through `ctx.settings.update`.
243
+ `GET /deepseek-coordination/config` returns `{ values, defaults }`; `defaults` is `resolveConfig(undefined)`, so the page never duplicates a default literal. `POST /config` accepts a flat dotted patch such as `{ "plan.threshold": 0.7 }`, validates it against the catalog and the real Schemastery schema, applies it to the live config, re-resolves invariants (weight normalisation, alias mirror, forced flags, compaction clamps), rebuilds `TokenGovernor` when compaction changes, and persists the applied paths.
213
244
 
214
- Persistence is explicit: `persisted: true` only when DSH accepted the settings write; otherwise the change is live for this process and the page says so. Unknown keys, `databasePath` and `database` are rejected with `INVALID_ARGUMENT`. Known but non-editable keys are reported in `ignored` and never written. `POST /config/compaction` remains as a small compatibility route for the old auto/soft/hard patch.
245
+ Persistence is the host's own override document at `<database dir>/config.overrides.json`: a flat `{ "plan.threshold": 0.7 }` map written atomically beside the coordination database and merged over the profile config on the next start. It is not DSH's `ctx.settings.update`, which only accepts `.volatile()` schemas — and a volatile node turns every parsed value into a reference wrapper this host cannot adopt without rewriting every config reader. `persisted: true` therefore means "stored in the coordination host's own document"; a write that only touched ignored rows reports `false`. Unknown keys, `databasePath` and `database` are rejected with `INVALID_ARGUMENT`. Known but non-editable keys are reported in `ignored` and never written. `POST /config/compaction` remains as a small compatibility route for the old auto/soft/hard patch.
215
246
 
216
- The page is Material UI end to end: one default-expanded `Accordion` per group, a `List` of rows, six scene tables (no scene dropdown), `Checkbox` for booleans, `RadioGroup` for enums, `Slider` for ratio-like numbers, `TextField type="number"` for counts/bytes/milliseconds, and `Chip` only for the `主机 / 本机 / 强制 / 只读 / 计划中` status plus connection state. There is no save button; controls apply on change/blur. A forced row draws a disabled control, a read-only row shows a value, and a planned row says the runtime does not read it yet. The settings nav icon is a host-shell workaround: the shell accepts only `{ id, order, label }` for a section, so the plugin decorates its nav button with a CSS mask of the Material `sync` glyph.
247
+ The page is Material UI end to end: one default-expanded `Accordion` per group, a `List` of rows, six scene tables (no scene dropdown), `Checkbox` for booleans, `RadioGroup` for enums, `TextField type="number"` for every number (weights and ratios included, rounded to the row's step for display only), and `Chip` only for the `主机 / 本机 / 强制 / 只读 / 计划中` status plus connection state. The full-access confirmation is a modal MUI `Dialog` above the tooltip layer, never an inline banner. There is no save button; controls apply on change/blur. A forced row draws a disabled control, a read-only row shows a value, and a planned row says the runtime does not read it yet. The settings nav icon is a host-shell workaround: the shell accepts only `{ id, order, label }` for a section, so the plugin decorates its nav button with a CSS mask of the Material `sync` glyph.
217
248
 
218
249
  ## Service-level takeover
219
250
 
220
251
  - With `ui.takeover` on, `TakeoverGate` listens to DSH's `approval/request` and `user-questions/request` waterfalls. It records a durable pending row, emits `takeover/pending`, and waits for a human answer delivered through the client routes.
252
+ - The listener registers with `{ prepend: true }`. DSH's own approval and question UI listens to the same waterfalls, and a listener registered later never runs once the GUI claims the request. Note that a deployment approval policy of `never` makes DSH reject before the waterfall, so no dialog can appear regardless of this switch.
221
253
  - A timeout, an aborted request signal, an explicit cancel, or plugin unload calls `next()`; the gate never turns “nobody answered” into `allowed-once` or a fabricated answer. `unavailable` is the host's fail-closed outcome and is rejected as a user decision.
222
254
  - The dialog polls `/takeover/pending` every 1 s only while the local 权限接管 switch is on, the session id is real and the document is visible. The first pending request is rendered; a `1 / N` badge appears for a queue.
223
255
  - Approval offers 仅本次允许 / 拒绝 / 取消; only `allowed-once` and `rejected` are submitted, while cancel/Esc/backdrop use the cancel route. Questions render radios for single-select, checkboxes for multi-select and optional free text; submit stays disabled until every question is answered.
224
256
  - **Both switches are needed**: host `ui.takeover` (default `false`) opens the gate; the local 权限接管 switch makes the dialog poll. With the host switch off, the gate delegates immediately and there is nothing to show.
225
257
 
258
+ ## Cache proxy (experimental, off by default)
259
+
260
+ DSH freezes a model request before any adapter sees it: `buildRequest()` deep-freezes the messages and `Object.freeze`s the request, and the `llm/stream` waterfall's fallback closes over that object. The one supported place where outgoing content can still be rebuilt is the adapter boundary, so the plugin registers an extra provider route (`coordination-proxy`) and forwards each request to the real provider after rebuilding it.
261
+
262
+ Wiring (`src/index.ts`, `src/host/proxy-adapter.ts`, `src/host/model-brand.ts`):
263
+
264
+ - `agent/request` rewrites the route to `coordination-proxy` and remembers the real one. Only allowlisted providers (`deepseek`, `deepseek-account`, `deepseek-official`) are intercepted; anything else keeps the route the harness chose.
265
+ - The adapter forwards through `ctx.llm.stream` with the real provider, so transport, retries, attribution headers and usage reporting stay with the real adapter.
266
+ - `ctx.llm.resolveModelInfo(provider, model)` supplies the host's model identity; it is classified onto a built-in cache brand (DeepSeek, OpenAI, Anthropic, Google, xAI, Moonshot, Qwen, Zhipu, Mistral, Meta, unknown) with `automaticPrefixCache`, `explicitCacheBreakpoints`, `minPrefixTokens`, `effortBreaksCache` and `stripVolatileHelps`.
267
+ - Outgoing content is decorated only when the family has an automatic prefix cache **and** `cache.enabled` is on: `CacheModule.decorate` moves fixed content first and replaces volatile fragments (ISO timestamps, UUIDs, long hex, current-time phrases) with stable placeholders. Explicit-breakpoint families (Anthropic) are never rewritten, because markers — not bytes — decide reuse there. The advisory `cacheWarning` field is stripped before forwarding.
268
+
269
+ Security model — the proxy sees every prompt, so it is built to be unable to leak:
270
+
271
+ 1. no credential access (no `ctx.credentials`, no token, no `Authorization`, no API key);
272
+ 2. no egress (the module has no imports and no `fetch`/`http`/`net`; forwarding is an in-process call);
273
+ 3. no content persistence — `proxy.log` receives structural events only (`{event, provider, model, brand, messages, chars, tools, reason}`), never prompt or answer text;
274
+ 4. provider allowlist enforced in both the routing listener and the adapter;
275
+ 5. refusal and failure messages name the route only;
276
+ 6. opt-in and reversible.
277
+
278
+ Enable it by creating `%DSH_HOME%\coordination\proxy.enable` (or `DSH_COORDINATION_PROXY=1`) and restarting. `GET /deepseek-coordination/proxy/status` reports counts and ids only: `available`, `enabled`, `decorate`, `upstream`, `model` (brand and policy), `forwards`, `refusals`. Delete the flag file and restart to return to the normal path.
279
+
226
280
  ## Auto-compaction and the token governor
227
281
 
228
282
  `TokenGovernor` estimates context (CJK-aware O(n) estimator with a bounded 256-entry memo), plans a budget against `contextWindow - reserve`, and asks DSH's `compactIfNeeded` at `agent/pre-step` when utilisation crosses a threshold. Defaults: soft `0.70`, hard `0.88`, reserve `max(2048, 8% of window)` capped at 25%, recentTurns `6`, cooldown `30 s`, `maxPerSession 20`.
229
283
 
230
- The soft threshold is editable as a 0.30–0.90 ratio; the hard threshold as 0.30–0.98 and strictly above soft. The old 60/70/80/88% values remain valid choices (`0.60`, `0.70`, `0.80`, `0.88`) even though the catalog now uses a slider rather than a four-item picker. Auto compaction is disabled by `compaction.auto=false`, but an explicit compact command is not governed by that switch.
284
+ The soft threshold is editable as a 0.30–0.90 ratio; the hard threshold as 0.30–0.98 and strictly above soft. The old 60/70/80/88% values remain valid choices (`0.60`, `0.70`, `0.80`, `0.88`) even though the catalog now edits it as a number field with 0.01 precision. Auto compaction is disabled by `compaction.auto=false`, but an explicit compact command is not governed by that switch.
231
285
 
232
286
  Fail-safe rules are deliberate: the hook never blocks the step; a missing compaction port, `null`/`undefined` result, timeout, throw, spent per-session allowance or unelapsed cooldown all become a no-op, and the agent proceeds to `next()`. The governor snaps the policy at construction, so a live settings change also rebuilds it. DSH owns the actual safe range and replacement; this plugin only decides when it is worth asking.
233
287
 
@@ -316,6 +370,7 @@ There is no `coordination_write`, `coordination_refresh`, `outline`, `findSymbol
316
370
  - File paths are workspace-relative; absolute paths, drive-rooted paths, UNC paths, `..` escapes and symlink escapes are rejected before a read. Binary/NUL/undecodable content is refused rather than guessed.
317
371
  - The turn hook records turn metadata and an empty prompt row; it does not mirror the DSH transcript. No file content is copied into the coordination database.
318
372
  - Permission presets are written to DSH immediately (full access needs a second confirmation) and are never stored in the offline localStorage copy. Offline replay covers only the five stored selection fields.
373
+ - The optional cache proxy adds no transport and no credential surface: it forwards through DSH's own `ctx.llm.stream`, traces structural counts only, and refuses providers outside its allowlist.
319
374
  - Takeover never auto-approves. Timeout, abort, cancel and unload delegate with `next()`; only a human decision delivered through the answer route settles a window.
320
375
  - Fail-closed behaviour is explicit: invalid takeover answers leave the window open; `PROFESSION_LOCKED` leaves the selection intact; parser uncertainty is `unverifiable`; graph/parse overflow is `truncated`; compaction failure is a no-op; chain `unknown` never auto-passes.
321
376
  - The coordination DB stores task/audit rows (including `prompt` and trace rows), not credentials or provider secrets. The config projection contains no DSH credential, token or provider key.
@@ -324,10 +379,10 @@ There is no `coordination_write`, `coordination_refresh`, `outline`, `findSymbol
324
379
 
325
380
  | Check | Result |
326
381
  |---|---|
327
- | `npm test` | **473 tests, 472 pass, 1 skipped (GC-only), 0 fail**, ~3.3 s on Node 24.21.0 |
382
+ | `npm test` | **615 tests, 614 pass, 1 skipped (GC-only), 0 fail**, ~3 s on Node 24.21.0 |
328
383
  | `npm run typecheck` / `npm run test:tsc` | Clean |
329
384
  | `npm run build` | Host + client bundles green; MUI `"use client"` directive warnings are non-fatal |
330
- | `npm run pack:check` | OK: `deepseek-coordination-0.10.0.tgz` (538,820 B); four runtime files present |
385
+ | `npm run pack:check` | OK: the runtime tarball carries the four shipped files |
331
386
  | Release CI | `.github/workflows/release.yml` runs typecheck, test:tsc, tests, pack:check and attaches the tarball to a `v*` GitHub Release |
332
387
 
333
388
  Parser and structure numbers are guards, not promises: a 100k-character parse test stays under 3 s; the data-structure report records B+ tree 10k inserts at 8.3/9.8 ms, skip-list 10k inserts at 6.4 ms, red-black 10k random set/delete at 13.5 ms, sparse grid 10k cells at 5.1 ms, and `hashString` 100k calls at 4.3 ms on the audit machine. The complexity audit records the ordinal `COUNT(*)` → `MAX(ordinal)` change (≈65–69 ms → ≈12–14 ms for 2,000 statements) and route ranking (2,400 → 200 posterior statements for 200 × 12 routes).
@@ -335,17 +390,18 @@ Parser and structure numbers are guards, not promises: a 100k-character parse te
335
390
  Known limitations, stated rather than hidden:
336
391
 
337
392
  1. **Durable graph is bounded.** `node`/`edge`/`snapshot` are now schema 24 and survive a new runtime; rehydration is bounded to the newest 10k nodes / 50k edges, removed symbols are not pruned, and a handle older than the rehydration window is `NOT_FOUND`.
338
- 2. **Domain extraction is parser-level; the chain projection is partial.** Book/Article/Part/Chapter/Section/Paragraph, Person/Venue, Condition, Sheet/Cell/Range, TeX proof status and CSV/TSV sheets are emitted and projected onto node cards. `partOf`/`condition` edges are not yet queryable through `coordination_chain`; xlsx/docx/pptx, Sign promotion, Lean/Coq/Isabelle status and cross-file Book composition remain deferred.
339
- 3. **The core turn pipeline is wired, the wider engines are not.** Comprehension → Organization → Plan/score and required Predict rows now run for `command=none` turns, with the scene policy applied where ports exist. Standalone Emotion/Bayesian/Cognition/Orchestration/Learning/Resource/Score, plan rebuild loops and decompose/dispatch/verify/synthesize remain library-only. `thinking`, `allowBash`, `maxIteration` and non-writing score thresholds are recorded as deferred diagnostics, not faked.
393
+ 2. **Domain extraction is parser-level; some projections are still partial.** Book/Article/Part/Chapter/Section/Paragraph, Person/Venue, Condition, Sheet/Cell/Range and TeX proof status are emitted and projected onto node cards; docx/xlsx/pptx now parse through a bounded ZIP+OOXML reader, while Publisher/Access stay explicitly unsupported. `partOf`/`condition` edges are queryable through `coordination_chain`; cross-file Book composition and Sign promotion remain deferred.
394
+ 3. **The core turn pipeline is wired, the wider engines are not.** Comprehension → Organization → Plan/score and required Predict rows now run for `command=none` turns, with the scene policy applied where ports exist. Standalone Emotion/Bayesian/Cognition/Orchestration/Learning/Resource/Score, plan rebuild loops and decompose/dispatch/verify/synthesize remain library-only. Reasoning is DSH-owned and no longer reported as a plugin gap; `allowBash`, `maxIteration` and non-writing score thresholds are still recorded as deferred diagnostics, not faked.
340
395
  4. **Configured caps are live.** `parser.maxAstDepth`, both dependency-graph caps and `tools.maxResultBytes` are consumed; parser/chain limits retune an existing runtime, and a config change no longer leaves a stale tool runtime.
341
396
  5. **Workspace root is resolved, not hard-coded.** Tool option → service root → host root → sandbox-policy root → `process.cwd()` only as the last fallback.
342
397
  6. **`parser.enabled` still needs registration.** The other file-layer limits retune live; turning the parser off fails closed immediately, but adding/removing the four tools requires the next registration (restart).
343
398
  7. **No browser E2E test.** The UI is covered by types, build, the settings-catalog tests and the takeover/bridge/integration tests; visual verification remains manual/screenshot-based.
344
399
  8. **Node engine is `>=22.13.0`.** `node:sqlite` is unflagged from 22.13.0/23.4.0; CI and this verification use 24.21.0.
345
- 9. **A profile can still record an older package spec.** Verify the installed version (`dsh --profile <name> --dump-config` or the profile's `package.json`); install the 0.10.0 tarball or link the built checkout rather than assuming a previous install was upgraded.
400
+ 9. **A profile can still record an older package spec.** Verify the installed version (`dsh --profile <name> --dump-config` or the profile's `package.json`); install the 0.11.0 tarball or link the built checkout rather than assuming a previous install was upgraded.
401
+ 10. **The cache proxy is experimental and off by default.** Its brand profiles are policy defaults, not measurements, and it only rewrites content for families with an automatic prefix cache; the observable gain on a stable session may be near zero, which is why it ships behind a flag and a status endpoint rather than enabled.
346
402
 
347
403
  ## Repository history and license
348
404
 
349
- `0.1.x` is **dsh-os**, a different OS-interaction project, no longer on the branch tip; `0.2.0` became the DSH plugin bundle; `0.3`–`0.6` moved the UI from Angular to MDUI to plain React to Material UI; `0.7`–`0.9` added the five dropdowns, i18n, profession lock, takeover, compaction, the P0 parser, the domain model and the shared data structures; `0.10.0` adds the settings catalog, the four file tools, the second data-structure pass and the verified tarball. Earlier states remain in git history and tags.
405
+ `0.1.x` is **dsh-os**, a different OS-interaction project, no longer on the branch tip; `0.2.0` became the DSH plugin bundle; `0.3`–`0.6` moved the UI from Angular to MDUI to plain React to Material UI; `0.7`–`0.9` added the five dropdowns, i18n, profession lock, takeover, compaction, the P0 parser, the domain model and the shared data structures; `0.10.0` added the settings catalog, the four file tools, the second data-structure pass and the verified tarball; `0.11.0` added durable settings, DSH-owned reasoning and the experimental cache proxy with brand profiles; `0.12.0` added the per-ecosystem domain layer, the chain `kind` filter, the directory layer and `NodeRecord`. Earlier states remain in git history and tags.
350
406
 
351
407
  MIT © 2026 Eloy Kim. See [LICENSE](LICENSE). Source: [github.com/eloyhere/deepseek-coordination](https://github.com/eloyhere/deepseek-coordination).
package/README.zh-CN.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  一个面向 DeepSeek Harness 的双端 Cordis 插件:宿主端持有协调 SQLite 数据库、7 个模型可见工具和一组 HTTP 路由;浏览器端在输入框挂载五个下拉框,并提供设置目录与服务级接管对话框。
6
6
 
7
- **当前版本:v0.10.0(2026-10-18)。** 它在 v0.9.2 的 tooltip 修复之后,加入设置目录、持久文件层、Turn 流水线、阶段冻结和数据结构采用。包版本、更新日志和发布 tarball 来自同一棵树;下文按源码核对,不以设计文档代替实现。
7
+ **当前版本:v0.12.0(2026-10-18)。** 本版新增按体系拆分的领域概念层——tex、book、markdown、html、五种编程语言、maven/npm 与 Office——并为 chain 查询加上 `kind` 过滤、加入目录层与规范 `NodeRecord`。它建立在 v0.11.0(持久设置、推理交还 DSH、实验性缓存代理)之上。包版本、更新日志和发布 tarball 来自同一棵树;下文按源码核对,不以设计文档代替实现。
8
8
 
9
9
  | 状态 | 含义 |
10
10
  |---|---|
@@ -60,7 +60,7 @@ npm pack # 先执行 prepack,生成可安装 tarball
60
60
 
61
61
  ```powershell
62
62
  npm pack
63
- dsh plugin --profile <name> add .\deepseek-coordination-0.10.0.tgz
63
+ dsh plugin --profile <name> add .\deepseek-coordination-0.12.0.tgz
64
64
  dsh --profile <name> --dump-config # 应出现 deepseek-coordination 层
65
65
  ```
66
66
 
@@ -159,16 +159,16 @@ deepseek-coordination/
159
159
 
160
160
  ### 情景与写作档
161
161
 
162
- | 情景 | 思考 / effort | 计划 | 大纲 | 修订 | 评分 | Bash | 联网 | 最大轮次 |
163
- |---|---|---|---|---|---|---|---|---|
164
- | 对话 | 关闭 / medium | – | – | – | – | 否 | 是 | 1 |
165
- | 写作 | 开启 / high | 是 | 是 | 是 | 是 | 否 | 是 | 3 |
166
- | 办公 | 关闭 / medium | 是 | – | – | – | 否 | 是 | 1 |
167
- | 研究 | 开启 / high | 是 | – | – | – | 否 | 是 | 3 |
168
- | 工程 | 开启 / high | 是 | – | – | – | 是 | 是 | 3 |
169
- | 迭代 | 开启 / high | – | – | – | 是 | 否 | 是 | 3 |
162
+ | 情景 | 计划 | 大纲 | 修订 | 评分 | Bash | 联网 | 最大轮次 |
163
+ |---|---|---|---|---|---|---|---|
164
+ | 对话 | – | – | – | – | 否 | 是 | 1 |
165
+ | 写作 | 是 | 是 | 是 | 是 | 否 | 是 | 3 |
166
+ | 办公 | 是 | – | – | – | 否 | 是 | 1 |
167
+ | 研究 | 是 | – | – | – | 否 | 是 | 3 |
168
+ | 工程 | 是 | – | – | – | 是 | 是 | 3 |
169
+ | 迭代 | – | – | – | 是 | 否 | 是 | 3 |
170
170
 
171
- “写作”要求大纲和至少一轮修订,必须有质量评分,不允许 bash,允许联网,最多三轮。通过阈值为 `0.6`,`plan.ts` 使用该写作阈值。Turn 流水线读取 reasoning effort、require-* 标志、引用/证据、`allowWeb` 与 `sandboxOnly`;`thinking`、`allowBash`、`maxIteration` 和非写作阈值仍是没有 DSH 端口/消费者的延迟诊断项。
171
+ “写作”要求大纲和至少一轮修订,必须有质量评分,不允许 bash,允许联网,最多三轮。通过阈值为 `0.6`,`plan.ts` 使用该写作阈值。Turn 流水线读取 require-* 标志、引用/证据、`allowWeb` 与 `sandboxOnly`;推理(`thinking`、`reasoningEffort`)归 DSH 所有——页面没有对应行,Turn 记录的是会话自身请求头里的值,而不是情景字面量。`allowBash`、`maxIteration` 和非写作阈值仍是没有 DSH 端口/消费者的延迟诊断项。
172
172
 
173
173
  ## 职能锁定与 Turn 生命周期
174
174
 
@@ -188,9 +188,40 @@ deepseek-coordination/
188
188
 
189
189
  `done`、`failed`、`cancelled`、`abandoned` 是不可逆终态。Turn 钩子只记录 Turn 元数据和一条空 prompt 行,不把 DSH 对话镜像进协调库。
190
190
 
191
+ ## 领域体系与解析器
192
+
193
+ 文件层不是一个解析器加一堆节点类型。每个体系在 `src/host/text/` 下拥有独立模块,它能产出的节点类型由该体系的语义限定。所有输出都是 body-free 的 `NodeMetadata`:kind、显式 name/label、span 与 fragment 坐标——绝不包含正文、单元格值或段落内容。
194
+
195
+ | 体系 | 模块 | 可产出的节点 |
196
+ |---|---|---|
197
+ | tex | `tex.ts` | `definition`、`lemma`、`theorem`、`proof`、`property`、`axiom`、`corollary`、`claim`、`example`、`remark`、`calculation`、`condition`(含 `requires`/`meets` 边) |
198
+ | book | `book.ts` | `book`、`part`、`chapter`、`article`、`section`、`person`、`venue`——`article` 的唯一产出者 |
199
+ | markdown | `markup.ts` | `document`、`chapter`、`heading`、`paragraph`、`div`、`link`、`code`、`section`、`sheet`、`cell`、`range`、`condition` |
200
+ | html | `markup.ts` | `document`、`section`(`<article>` 映射于此)、`chapter`(`<h1>`)、`link`、`code` |
201
+ | js/ts | `javascript.ts` | `class`、`function`、`method`、`variable`、`interface`、`type`、`enum`、`namespace`、`importation`、`exportation`、`condition` |
202
+ | java | `java.ts` | `module`、`class`、`method`、`variable`、`importation` |
203
+ | python | `python.ts` | `class`、`function`、`method`、`variable`、`importation` |
204
+ | c/c++ | `c-family.ts` | `module`、`class`、`function`、`method`、`variable`、`importation` |
205
+ | rust | `rust.ts` | `module`、`class`、`function`、`method`、`variable`、`importation` |
206
+ | php | `php.ts` | `module`、`class`、`function`、`method`、`variable`、`importation` |
207
+ | maven | `maven.ts` | `project`、`module`、`dependency`(parent 是 `label: 'parent'` 的 dependency) |
208
+ | npm | `npm.ts` | `project`、`dependency`、`script`(命令体永不入库) |
209
+ | office | `office.ts` | docx:`document`、`chapter`、`section`、`paragraph`、`link`;xlsx:`workbook`、`sheet`、`range`、`formula`;pptx:`document`、`slide`;pub/accdb:无节点,只出一条 `unsupported-format` 诊断 |
210
+ | text | `sentence.ts` | `sentence` 切分与 `line` 区间(坐标,不是节点) |
211
+
212
+ 跨体系恒定规则:
213
+
214
+ - **语言细分放 `label`,不新增 kind。** Rust 的 `impl` 是 `kind: 'class'` + `label: 'implementation'`;C++ 的 `struct`/`enum`、PHP 的 `trait` 同理。`NodeKind` 保持为小而封闭的联合。
215
+ - **只描述、不操作。** 任何解析器都不写文件、不构建、不安装、不执行宏、不联网。"创建项目"若真需要,是 DSH 权限模型下的 shell 命令,绝不是插件工具。
216
+ - **只认显式证据。** 不从正文推断标题层级、不编造版本号、缺失关系只报告不按位置配对;异常输入返回诊断且绝不抛异常。
217
+ - **有界。** ZIP 条目 ≤ 2000、单条解压 ≤ 64 MiB、总计 ≤ 256 MiB、XML 嵌套 ≤ 128、节点 ≤ `MAX_METADATA_NODES`(20 000),并遵守 token/时间预算。
218
+ - **`SUMMARY.md` 由 book 解析器处理**(文件名优先规则);`README.md` 等仍走 Markdown。
219
+
220
+ 图通过 `coordination_parse`、`coordination_describe`、`coordination_chain` 回答"工作区里有什么"。chain 查询在所有返回节点的动作上支持可选 `kind`(去空格、大小写不敏感),因此"所有 lemma""所有 chapter"是一次调用而不是全量扫描。目录节点从无歧义的工作区路径派生并以 `contains`/`part_of` 连接;不变量是**`part_of`(子→父)精确、`contains`(父→子)尽力而为**。
221
+
191
222
  ## 设置与配置
192
223
 
193
- 设置页由 `src/shared/selection.ts` 的 `SETTINGS_CONTROLS` 生成:**13 组、151 个控件、134 个可写宿主行,覆盖 155 个非秘密配置叶子**。18 个顶层配置键包含 `database` 与 `databasePath`,这两个键故意不投影、不可写。
224
+ 设置页由 `src/shared/selection.ts` 的 `SETTINGS_CONTROLS` 生成:**13 组、139 个控件、122 个可写宿主行,覆盖 155 个配置叶子**。其中 12 个情景叶子(`scenes.*.thinking`、`scenes.*.reasoningEffort`)留在 schema 里但没有对应行:推理由 DSH 的模型页负责,这里再放一套会形成两个真相来源。18 个顶层配置键包含 `database` 与 `databasePath`,这两个键故意不投影、不可写。
194
225
 
195
226
  | 组 | 默认值 / 范围 | 写入路径 |
196
227
  |---|---|---|
@@ -198,36 +229,59 @@ deepseek-coordination/
198
229
  | `profession` | enabled/lock/rebuild/abandon 强制 `true`;default 镜像 `defaults.profession`;audit/errorHint `true` | 强制项只读;audit/errorHint 为宿主行(audit 无消费者) |
199
230
  | `plan` | threshold `0.5`、maxRebuild `3`、8 个权重和为 1、8 个维度阈值 | 宿主行;保存后权重重新归一 |
200
231
  | `orchestration` | maxReject `2`、maxSubTask `32`、groundTruth `true`、timeout `5000 ms`、shell ground truth `false`、modelRouting `true` | 宿主行;`groundTruthTimeout` 无消费者 |
201
- | `cache` | enabled `true`、ttl `60000 ms`、fingerprintWindow `50`、effortWarning `true` | 宿主行;`fingerprintWindow` 无消费者 |
232
+ | `cache` | enabled `true`、ttl `60000 ms`、fingerprintWindow `50`、effortWarning `true` | 宿主行;`enabled`/`effortWarning` 控制缓存代理的改写开关,`ttl` 用于模型目录缓存,`fingerprintWindow` 无消费者 |
202
233
  | `bayesian` | prior `0.5`、stopEntropy `0.05`、infoGain `0.01`、maxRoutes `12`、calibrationFloor `0.1` | 宿主行;`calibrationFloor` 无消费者 |
203
234
  | `comprehension` | stageTimeout `30000 ms`、searchEnabled `true`、maxEvidence `8`、highHistoryWindow `50` | 宿主行 |
204
235
  | `compaction` | auto `true`、soft `0.70`、hard `0.88`、reserve `2048`、recentTurns `6`、cooldown `30000 ms`、maxPerSession `20` | auto/soft/hard 为宿主行;结构字段只读 |
205
236
  | `ui` | toolbar `true`(废弃别名)、showTooltip `true`、takeover `false`、refreshInterval `5000 ms`、compact `true`、locale `auto` | 宿主行 + 两个本机开关;toolbar/locale 只读 |
206
- | `scenes` | 六个情景各 13 个字段;写作阈值 `0.6` | 宿主行;只有写作评分阈值被 `plan.ts` 读取 |
237
+ | `scenes` | 六个情景各 9 个可编辑行(思考/effort 仅保留在 schema);写作阈值 `0.6` | 宿主行;只有写作评分阈值被 `plan.ts` 读取 |
207
238
  | `parser` | enabled `true`、1 MiB、200k tokens、depth `256`、2 s、cache `256`、graph 20k/100k | enabled + 四个上限为宿主行;depth 与 graph 上限仍是计划 |
208
239
  | `chain` | depth `8`、links `50`、tokenBudget `1500` | 宿主行 |
209
240
  | `tools` | maxResultBytes `0` | 计划/只读;未被消费 |
210
241
  | `defaults` | 职能 `execution`、交互 `think`、情景 `dialogue`、验证 `medium`、命令 `none` | 宿主行 |
211
242
 
212
- `GET /deepseek-coordination/config` 返回 `{ values, defaults }`;`defaults` 来自 `resolveConfig(undefined)`,页面不复制默认字面量。`POST /config` 接收扁平点路径补丁(如 `{ "plan.threshold": 0.7 }`),按目录和真实 Schemastery schema 校验,写入活动配置,重新执行不变量(权重归一、别名镜像、强制开关、压缩阈值夹取),在压缩变化时重建 `TokenGovernor`,最后尽力通过 `ctx.settings.update` 持久化。
243
+ `GET /deepseek-coordination/config` 返回 `{ values, defaults }`;`defaults` 来自 `resolveConfig(undefined)`,页面不复制默认字面量。`POST /config` 接收扁平点路径补丁(如 `{ "plan.threshold": 0.7 }`),按目录和真实 Schemastery schema 校验,写入活动配置,重新执行不变量(权重归一、别名镜像、强制开关、压缩阈值夹取),在压缩变化时重建 `TokenGovernor`,最后持久化实际写入的路径。
213
244
 
214
- 持久化是显式的:只有 DSH 接受设置写入时 `persisted` 才为 true;否则修改只在当前进程生效,页面会如实说明。未知键、`databasePath`、`database` 会以 `INVALID_ARGUMENT` 拒绝;已知但不可写的键进入 `ignored`,绝不写入。`POST /config/compaction` 保留为旧的 auto/soft/hard 兼容小路由。
245
+ 持久化落在宿主自己的覆盖文档 `<数据库目录>/config.overrides.json`:一个扁平的 `{ "plan.threshold": 0.7 }` 映射,原子写在协调数据库旁边,下次启动时覆盖在 profile 配置之上。这里没有用 DSH 的 `ctx.settings.update`——它只接受 `.volatile()` schema,而 volatile 节点会把每个解析值变成引用包装,本宿主无法在不重写所有配置读取的前提下接受。因此 `persisted: true` 表示“已存入协调宿主自己的文档”;只命中 `ignored` 行的写入返回 `false`。未知键、`databasePath`、`database` 会以 `INVALID_ARGUMENT` 拒绝;已知但不可写的键进入 `ignored`,绝不写入。`POST /config/compaction` 保留为旧的 auto/soft/hard 兼容小路由。
215
246
 
216
- 设置页整体使用 Material UI:每组一个默认展开的 `Accordion`,行放在 `List` 中;六个情景各一张 `Table`(页面没有情景下拉框);布尔用 `Checkbox`,枚举用 `RadioGroup`,比例型数字用 `Slider`,计数/字节/毫秒用 `TextField type="number"`;`Chip` 只表示 `主机 / 本机 / 强制 / 只读 / 计划中` 状态和连接状态。没有保存按钮,控件在 change/blur 时提交。强制行画禁用控件,只读行显示值,计划行明确说明当前运行时尚未读取。设置导航图标是宿主 shell 的限制所致:section 只接受 `{ id, order, label }`,插件只能用 CSS mask 给导航按钮补一个 Material `sync` 图标。
247
+ 设置页整体使用 Material UI:每组一个默认展开的 `Accordion`,行放在 `List` 中;六个情景各一张 `Table`(页面没有情景下拉框);布尔用 `Checkbox`,枚举用 `RadioGroup`,**所有数字都用 `TextField type="number"`(含权重与比例,显示时按该行 step 取整)**;`Chip` 只表示 `主机 / 本机 / 强制 / 只读 / 计划中` 状态和连接状态。完全权限确认是一个位于 tooltip 层之上的 MUI `Dialog` 模态框,不再是内联色块。没有保存按钮,控件在 change/blur 时提交。强制行画禁用控件,只读行显示值,计划行明确说明当前运行时尚未读取。设置导航图标是宿主 shell 的限制所致:section 只接受 `{ id, order, label }`,插件只能用 CSS mask 给导航按钮补一个 Material `sync` 图标。
217
248
 
218
249
  ## 服务级接管
219
250
 
220
251
  - 打开 `ui.takeover` 后,`TakeoverGate` 监听 DSH 的 `approval/request` 与 `user-questions/request` 瀑布。它写一条持久 pending 行、发出 `takeover/pending`,等待客户端路由送来人工答案。
252
+ - 监听器用 `{ prepend: true }` 注册。DSH 自己的审批/提问 UI 监听同一个瀑布,注册晚的监听器在 GUI 认领请求后永远不会执行。注意:部署的审批策略为 `never` 时,DSH 在进入瀑布之前就直接拒绝,此时无论开关如何都不会出现对话框。
221
253
  - 超时、请求 signal 中止、显式取消或插件卸载都会调用 `next()`;闸门绝不把“没人回答”变成 `allowed-once` 或编造的问题答案。`unavailable` 是宿主 fail-closed 的结果,不作为用户决定接受。
222
254
  - 对话框只在以下条件同时成立时每 1 秒轮询 `/takeover/pending`:本机“权限接管”开关打开、session id 真实、页面可见。它渲染第一条 pending 请求;队列多于一条时显示 `1 / N` 徽标。
223
255
  - 审批提供 仅本次允许 / 拒绝 / 取消;只提交 `allowed-once` 与 `rejected`,取消/Esc/点背景走 cancel 路由。提问按单选渲染 radio、多选渲染 checkbox,并允许每题自由文本;所有问题答完前提交按钮禁用。
224
256
  - **两个开关都需要**:宿主 `ui.takeover`(默认 `false`)负责打开闸门,本机“权限接管”负责让对话框轮询。宿主开关关闭时闸门立即委托,没有窗口可显示。
225
257
 
258
+ ## 缓存代理(实验性,默认关闭)
259
+
260
+ DSH 在任何 adapter 看到请求之前就把它冻结了:`buildRequest()` 深冻结消息并 `Object.freeze` 请求,而 `llm/stream` 瀑布的兜底闭包持有这个对象。唯一还能重建出站内容的位置是 adapter 边界,所以插件注册一个额外 provider 路由(`coordination-proxy`),把每个请求重建后转发给真实 provider。
261
+
262
+ 接线(`src/index.ts`、`src/host/proxy-adapter.ts`、`src/host/model-brand.ts`):
263
+
264
+ - `agent/request` 把路由改成 `coordination-proxy` 并记住真实路由。只有白名单内的 provider(`deepseek`、`deepseek-account`、`deepseek-official`)会被拦截,其他 provider 保持宿主选择的路由。
265
+ - adapter 用真实 provider 调 `ctx.llm.stream` 转发,传输、重试、归因头和用量统计仍由真实 adapter 负责。
266
+ - `ctx.llm.resolveModelInfo(provider, model)` 提供宿主的模型身份,再分类到内置缓存品牌(DeepSeek、OpenAI、Anthropic、Google、xAI、Moonshot、Qwen、Zhipu、Mistral、Meta、未知),带 `automaticPrefixCache`、`explicitCacheBreakpoints`、`minPrefixTokens`、`effortBreaksCache`、`stripVolatileHelps`。
267
+ - 只有当该家族有自动前缀缓存**且** `cache.enabled` 打开时才改写出站内容:`CacheModule.decorate` 把固定内容前置,并把易变片段(ISO 时间戳、UUID、长 hex、"当前时间"措辞)替换为稳定占位符。显式断点家族(Anthropic)永不改写,因为那里决定复用率的是标记而不是字节。仅供 UI 的 `cacheWarning` 字段会在转发前剥掉。
268
+
269
+ 安全模型——代理能看到所有 prompt,因此设计成无法成为泄露通道:
270
+
271
+ 1. 不接触凭据(无 `ctx.credentials`、无 token、无 `Authorization`、无 API key);
272
+ 2. 无出网能力(模块零 import,没有 `fetch`/`http`/`net`;转发是进程内调用);
273
+ 3. 不落盘内容——`proxy.log` 只收结构化事件(`{event, provider, model, brand, messages, chars, tools, reason}`),绝无 prompt 或回答正文;
274
+ 4. 白名单在路由监听器和 adapter 双侧强制;
275
+ 5. 拒绝/失败信息只报路由名;
276
+ 6. 默认关闭、可逆。
277
+
278
+ 启用方式:创建 `%DSH_HOME%\coordination\proxy.enable`(或 `DSH_COORDINATION_PROXY=1`)后重启。`GET /deepseek-coordination/proxy/status` 只报告计数与标识:`available`、`enabled`、`decorate`、`upstream`、`model`(品牌与策略)、`forwards`、`refusals`。删掉开关文件重启即回到普通链路。
279
+
226
280
  ## 自动压缩与 Token 治理器
227
281
 
228
282
  `TokenGovernor` 估算上下文(CJK 感知的 O(n) 估算器,带 256 项有界 memo),按 `contextWindow - reserve` 规划预算,并在 `agent/pre-step` 利用率越过阈值时请求 DSH 的 `compactIfNeeded`。默认:soft `0.70`、hard `0.88`、reserve `max(2048, 窗口的 8%)` 且不超过窗口 25%、recentTurns `6`、cooldown `30 s`、maxPerSession `20`。
229
283
 
230
- soft 阈值可按 0.30–0.90 的比例编辑;hard 为 0.30–0.98,且必须严格高于 soft。旧界面里的 60/70/80/88% 仍是合法取值(`0.60`、`0.70`、`0.80`、`0.88`),只是目录页现在用 slider,而不是四项选择器。`compaction.auto=false` 只关闭自动压缩,不约束显式 compact 命令。
284
+ soft 阈值可按 0.30–0.90 的比例编辑;hard 为 0.30–0.98,且必须严格高于 soft。旧界面里的 60/70/80/88% 仍是合法取值(`0.60`、`0.70`、`0.80`、`0.88`),只是目录页现在用 0.01 精度的数字输入框,而不是四项选择器。`compaction.auto=false` 只关闭自动压缩,不约束显式 compact 命令。
231
285
 
232
286
  失败封闭是刻意设计:钩子绝不阻塞 step;压缩 port 缺失、返回 `null`/`undefined`、超时、抛错、每会话额度用尽或 cooldown 未到,全部按 no-op 处理,agent 继续执行 `next()`。治理器在构造时快照策略,所以设置热更新会同时重建它。实际安全范围和替换由 DSH 负责,本插件只决定何时值得请求。
233
287
 
@@ -316,6 +370,7 @@ P0 解析器是词法级、确定性的:JS/TS/JSX(import/export/`require`/
316
370
  - 文件路径必须是工作区相对路径;绝对路径、盘符路径、UNC、`..` 逃逸与符号链接逃逸在读取前拒绝。二进制/NUL/不可解码内容直接拒绝,不猜。
317
371
  - Turn 钩子只写 Turn 元数据和一条空 prompt 行,不镜像 DSH 对话,也不把文件内容复制进协调库。
318
372
  - 权限预设立即写给 DSH(完全权限需二次确认),从不进入离线 localStorage;离线重放只覆盖五个已存选择字段。
373
+ - 可选的缓存代理不新增传输层和凭据面:它通过 DSH 自己的 `ctx.llm.stream` 转发,只记录结构化计数,并拒绝白名单之外的 provider。
319
374
  - 接管绝不自动批准。超时、中止、取消、卸载都以 `next()` 委托;只有通过 answer 路由送达的人工决定才会结算窗口。
320
375
  - 失败封闭是明确的:非法接管答案保持窗口;`PROFESSION_LOCKED` 不改选择;解析不确定标 `unverifiable`;解析/图溢出标 `truncated`;压缩失败是 no-op;Chain 的 `unknown` 不会自动通过。
321
376
  - 协调库保存任务/审计行(包括 `prompt` 与追踪行),不保存凭据或 provider secret。配置投影中没有 DSH 凭据、token 或 provider key。
@@ -324,10 +379,10 @@ P0 解析器是词法级、确定性的:JS/TS/JSX(import/export/`require`/
324
379
 
325
380
  | 检查 | 结果 |
326
381
  |---|---|
327
- | `npm test` | **473 tests,472 pass,1 skipped(仅 GC),0 fail**,Node 24.21.0 上约 3.3 s |
382
+ | `npm test` | **615 tests,614 pass,1 skipped(仅 GC),0 fail**,Node 24.21.0 上约 3 s |
328
383
  | `npm run typecheck` / `npm run test:tsc` | 通过 |
329
384
  | `npm run build` | 宿主 + 客户端 bundle 通过;MUI 的 `"use client"` directive 警告不致命 |
330
- | `npm run pack:check` | OK:`deepseek-coordination-0.10.0.tgz`(538,820 B),四个运行时文件齐全 |
385
+ | `npm run pack:check` | OK:运行时 tarball 含四个发布文件 |
331
386
  | 发布 CI | `.github/workflows/release.yml` 运行 typecheck、test:tsc、测试、pack:check,并在 `v*` Release 附上 tarball |
332
387
 
333
388
  解析器与结构的数字是守卫,不是承诺:100k 字符解析测试保持在 3 秒内;数据结构报告记录 B+ 树 10k 插入 8.3/9.8 ms、skip list 10k 插入 6.4 ms、红黑树 10k 随机 set/delete 13.5 ms、稀疏网格 10k 单元 5.1 ms、`hashString` 100k 次 4.3 ms;复杂度审计记录 Turn 序号从 `COUNT(*)` 改为 `MAX(ordinal)`(2,000 条语句约 65–69 ms → 约 12–14 ms)以及路由排序(200 × 12 条路由的 2,400 次 posterior 查询降到 200 次)。
@@ -335,17 +390,18 @@ P0 解析器是词法级、确定性的:JS/TS/JSX(import/export/`require`/
335
390
  已知限制,直接列出而不是隐藏:
336
391
 
337
392
  1. **持久图有边界。** `node`/`edge`/`snapshot` 已是 schema 24,跨运行时保留;但重水化只取最新 10k 节点 / 50k 边,删除的符号不会清理,超出窗口的旧 handle 返回 `NOT_FOUND`。
338
- 2. **领域提取在解析器层,关系链投影仍不完整。** Book/Article/Part/Chapter/Section/Paragraph、Person/Venue、Condition、Sheet/Cell/Range、TeX 证明状态和 CSV/TSV 表格已产出并投影到节点卡;`partOf`/`condition` 边还不能通过 `coordination_chain` 查询。xlsx/docx/pptx、Sign 提升、Lean/Coq/Isabelle 状态和跨文件 Book 组合仍未实现。
393
+ 2. **领域提取在解析器层,部分投影仍不完整。** Book/Article/Part/Chapter/Section/Paragraph、Person/Venue、Condition、Sheet/Cell/Range、TeX 证明状态和 CSV/TSV 表格已产出并投影到节点卡;docx/xlsx/pptx 现在通过有界 ZIP+OOXML 读取器解析,Publisher/Access 明确不支持。`partOf`/`condition` 边已可通过 `coordination_chain` 查询;跨文件 Book 组合与 Sign 提升仍未实现。
339
394
  3. **核心 Turn 流水线已接线,更宽的引擎没有。** `command=none` 的 Turn 会运行 Comprehension → Organization → Plan/score,以及需要的 Predict 行;有端口的 scene 策略会生效。独立 Emotion/Bayesian/Cognition/Orchestration/Learning/Resource/Score、计划重建循环和 decompose/dispatch/verify/synthesize 仍是库级。`thinking`、`allowBash`、`maxIteration` 和非写作阈值记录为延迟诊断,不伪造。
340
395
  4. **配置上限已生效。** `parser.maxAstDepth`、两个依赖图上限和 `tools.maxResultBytes` 都有消费者;parser/chain 上限会 retune 已存在运行时,不再留下陈旧运行时。
341
396
  5. **工作区根已解析,不再硬编码。** 工具参数 → service 根 → host 根 → sandbox policy 根 → 最后才回退 `process.cwd()`。
342
397
  6. **`parser.enabled` 仍需重新注册。** 其他文件层上限会即时 retune;关闭 parser 会立即失败关闭,但从工具列表增删四个工具仍要等下一次注册(重启)。
343
398
  7. **没有浏览器 E2E。** UI 由类型、构建、settings-catalog 测试以及 takeover/bridge/集成测试覆盖;视觉验证仍是人工/截图。
344
399
  8. **Node 引擎为 `>=22.13.0`。** `node:sqlite` 从 22.13.0/23.4.0 起不再需要实验开关;CI 与本次验证使用 24.21.0。
345
- 9. **profile 里可能仍记录着旧的包 spec。** 请核对实际安装的版本(`dsh --profile <name> --dump-config` 或 profile 的 `package.json`);安装 0.10.0 tarball 或链接已构建的 checkout,不要假定上一次安装已被升级。
400
+ 9. **profile 里可能仍记录着旧的包 spec。** 请核对实际安装的版本(`dsh --profile <name> --dump-config` 或 profile 的 `package.json`);安装 0.11.0 tarball 或链接已构建的 checkout,不要假定上一次安装已被升级。
401
+ 10. **缓存代理是实验性的、默认关闭。** 品牌 profile 是策略默认值而不是实测值,且只对自动前缀缓存的家族改内容;在已经稳定的会话上收益可能接近零——这正是它藏在开关和状态端点后面的原因。
346
402
 
347
403
  ## 仓库历史与许可
348
404
 
349
- `0.1.x` 是另一个项目 **dsh-os**,已不在分支顶端;`0.2.0` 变成 DSH 插件 bundle;`0.3`–`0.6` 的 UI 从 Angular 经 MDUI、纯 React 迁到 Material UI;`0.7`–`0.9` 加入五个下拉框、i18n、职能锁定、接管、压缩、P0 解析器、领域模型和共享数据结构;`0.10.0` 加入设置目录、四个文件工具、第二轮数据结构采用和可验证 tarball。旧状态仍在 git 历史和 tag 中。
405
+ `0.1.x` 是另一个项目 **dsh-os**,已不在分支顶端;`0.2.0` 变成 DSH 插件 bundle;`0.3`–`0.6` 的 UI 从 Angular 经 MDUI、纯 React 迁到 Material UI;`0.7`–`0.9` 加入五个下拉框、i18n、职能锁定、接管、压缩、P0 解析器、领域模型和共享数据结构;`0.10.0` 加入设置目录、四个文件工具、第二轮数据结构采用和可验证 tarball;`0.11.0` 加入持久设置、推理交还 DSH,以及带品牌策略的实验性缓存代理;`0.12.0` 加入按体系拆分的领域层、chain `kind` 过滤、目录层与 `NodeRecord`。旧状态仍在 git 历史和 tag 中。
350
406
 
351
407
  MIT © 2026 Eloy Kim。见 [LICENSE](LICENSE)。源码:[github.com/eloyhere/deepseek-coordination](https://github.com/eloyhere/deepseek-coordination)。