@treeseed/dsh-chapters 0.1.17 → 0.1.20
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/cordis.patch.yml +207 -27
- package/docs/backlog.md +12 -5
- package/docs/contract.md +20 -26
- package/docs/development.md +37 -1
- package/docs/verify.md +2 -1
- package/lib/codegraph.d.ts +76 -0
- package/lib/codegraph.js +190 -0
- package/lib/codegraph.js.map +1 -0
- package/lib/continue-core.js +6 -0
- package/lib/continue-core.js.map +1 -1
- package/lib/engine.d.ts +2 -0
- package/lib/engine.js +13 -2
- package/lib/engine.js.map +1 -1
- package/lib/enrich-wire.js +18 -1
- package/lib/enrich-wire.js.map +1 -1
- package/lib/enrich.d.ts +5 -1
- package/lib/enrich.js +12 -1
- package/lib/enrich.js.map +1 -1
- package/lib/index.d.ts +26 -20
- package/lib/index.js +70 -114
- package/lib/index.js.map +1 -1
- package/lib/indexing.d.ts +4 -0
- package/lib/indexing.js +2 -0
- package/lib/indexing.js.map +1 -1
- package/lib/preset.d.ts +122 -127
- package/lib/preset.js +156 -226
- package/lib/preset.js.map +1 -1
- package/lib/render.d.ts +4 -1
- package/lib/render.js +9 -1
- package/lib/render.js.map +1 -1
- package/lib/search.d.ts +9 -0
- package/lib/search.js +31 -1
- package/lib/search.js.map +1 -1
- package/lib/signature.d.ts +17 -0
- package/lib/signature.js +51 -1
- package/lib/signature.js.map +1 -1
- package/package.json +10 -3
package/cordis.patch.yml
CHANGED
|
@@ -10,36 +10,37 @@
|
|
|
10
10
|
# Two planes, two surfaces:
|
|
11
11
|
# HOST PLANE — the `config:` block below (defaults shown commented; set any
|
|
12
12
|
# under your profile's plugin entry).
|
|
13
|
-
# REALM PLANE — the compaction ENGINE row inside the preset's composition
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# per plane. Design record: docs/knowledge-repo.md §12.
|
|
13
|
+
# REALM PLANE — the compaction ENGINE row inside the preset's composition (the
|
|
14
|
+
# `preset-chapters` row at the foot of this file); shared names behave per
|
|
15
|
+
# plane. Design record: docs/knowledge-repo.md §12.
|
|
17
16
|
#
|
|
18
|
-
# PRESET DELIVERY —
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
17
|
+
# PRESET DELIVERY — the preset is a DECLARATION ROW, exactly like the host's own presets.
|
|
18
|
+
# `preset-chapters` (the id is the host convention `preset-<id>`) is inserted by this
|
|
19
|
+
# file, its `config` IS the preset definition (`id/name/description/order/plugins`), and
|
|
20
|
+
# because it is an ordinary Loader entry you can see it in the plugin list and the config
|
|
21
|
+
# editor, override it from your profile patch, or `disabled: true` it.
|
|
22
|
+
# Its row module is ours — '@treeseed/dsh-chapters/preset' (src/preset.ts) — not the
|
|
23
|
+
# host's '@deepseek-ai/dsh-agent-preset'. It mirrors that plugin line for line (injects
|
|
24
|
+
# `agentPresets`, preserves child `!!js` expressions, yields the registry disposer to
|
|
25
|
+
# Cordis) and adds one thing: rows this host cannot import are dropped at boot and NAMED,
|
|
26
|
+
# because a single unresolvable child row makes the WHOLE preset `broken` — which is the
|
|
27
|
+
# same user-visible failure as no preset at all (measured: `DECLARED BUT BROKEN —
|
|
28
|
+
# tool-schedule … never started` on a host where that package was never published). The
|
|
29
|
+
# host package cannot be named directly because a row that fails to import aborts the
|
|
30
|
+
# plugin tree of any host predating declaration rows; ours resolves everywhere our
|
|
31
|
+
# package runs. Support floor: 0.2.0.
|
|
32
|
+
# After activation the plugin then ASKS THE ROSTER, and the mounted rows: file presence
|
|
33
|
+
# is not preset existence, and "declared" is not "usable". The `dsh-chapters:` lines at
|
|
34
|
+
# startup say which of the four states you are in.
|
|
30
35
|
#
|
|
31
36
|
# config:
|
|
32
|
-
# # ---- identity
|
|
33
|
-
# installChaptersPreset: true #
|
|
34
|
-
# #
|
|
35
|
-
# #
|
|
36
|
-
#
|
|
37
|
-
# #
|
|
38
|
-
#
|
|
39
|
-
# compactionThresholdRatio: 0.9 # the registered preset's engine row: share of the
|
|
40
|
-
# # window that triggers a chapter checkpoint. This is
|
|
41
|
-
# # the knob a preset YAML used to carry in the home.
|
|
42
|
-
# fallbackPreset: 'chapters' # preset mounted for children when the
|
|
37
|
+
# # ---- identity -------------------------------------------------------
|
|
38
|
+
# installChaptersPreset: true # INERT since 0.1.18 — the preset is the `preset-chapters`
|
|
39
|
+
# # row above, so `disabled: true` on THAT row is the switch.
|
|
40
|
+
# # Kept so an existing profile patch still parses.
|
|
41
|
+
# compactionThresholdRatio: 0.9 # INERT since 0.1.18 for the same reason: it is
|
|
42
|
+
# # `thresholdRatio` on the preset's chapters-engine row now.
|
|
43
|
+
# # fallbackPreset: 'chapters' # preset mounted for children when the
|
|
43
44
|
# # caller's own preset cannot be resolved — and
|
|
44
45
|
# # the id the roster check looks for. This id is
|
|
45
46
|
# # DURABLE STATE: every child's log records it,
|
|
@@ -121,3 +122,182 @@
|
|
|
121
122
|
- insert:
|
|
122
123
|
- id: '@treeseed/dsh-chapters'
|
|
123
124
|
name: '@treeseed/dsh-chapters'
|
|
125
|
+
|
|
126
|
+
# ── the `chapters` agent preset — a DECLARATION ROW, exactly as @deepseek-ai/dsh-web-app
|
|
127
|
+
# ships its own presets/standard.patch.yml. Row id `preset-chapters` follows the host's
|
|
128
|
+
# `preset-<id>` convention; `config.id: chapters` is DURABLE STATE (every continuation
|
|
129
|
+
# child records it as `agent-preset/selected`, so renaming it orphans those sessions).
|
|
130
|
+
#
|
|
131
|
+
# The row's `name` is OUR plugin (`@treeseed/dsh-chapters/preset`), which mirrors
|
|
132
|
+
# @deepseek-ai/dsh-agent-preset line for line — `inject: ['agentPresets']`,
|
|
133
|
+
# `static [EntryGroup.key] = true` so child `!!js` expressions survive until the child
|
|
134
|
+
# activates, `[Service.init]` yields the registry disposer so Cordis owns its lifetime —
|
|
135
|
+
# and drops rows THIS host cannot import before registering. Why not the host package
|
|
136
|
+
# directly: a row naming @deepseek-ai/dsh-agent-preset is unresolvable on a pre-0.1.7
|
|
137
|
+
# host and an unresolvable row aborts that host's whole plugin tree, while one stale
|
|
138
|
+
# child row (e.g. @deepseek-ai/dsh-tool-schedule, unpublished at 0.2.0-rc.2) makes the
|
|
139
|
+
# ENTIRE preset `broken` — measured both ways. Same row, same visibility in
|
|
140
|
+
# `dsh --dump-default-config`/the config editor, no boot that it can brick.
|
|
141
|
+
#
|
|
142
|
+
# Four deltas from the host's own standard list, each ours deliberately:
|
|
143
|
+
# 1. compaction-basic -> chapters-engine (the zero-inference summarize())
|
|
144
|
+
# 2. tool-result-pruner.thresholdChars 8192 -> 1000000 (dormant by choice: chapters
|
|
145
|
+
# defer oversized results at ARCHIVE time; an in-surface prune is a prefix cliff
|
|
146
|
+
# on local hardware — and that plugin REJECTS unknown config keys, so the three
|
|
147
|
+
# keys below are the whole surface)
|
|
148
|
+
# 3. the PLOT: persona suffix, with NO {{cwd}} (hosts from 0.2.1-alpha.2 register only
|
|
149
|
+
# provider/model and an unregistered variable throws at prompt assembly, killing
|
|
150
|
+
# every turn of every chapters session)
|
|
151
|
+
# 4. tool-ralph ENABLED (the host standard list mounts it disabled)
|
|
152
|
+
# `noUnusedLocals`-equivalent discipline applies: keys the host dropped between versions
|
|
153
|
+
# are not carried here (toolFilter was one — alpha.4 throws on it).
|
|
154
|
+
- insert:
|
|
155
|
+
- id: preset-chapters
|
|
156
|
+
name: '@treeseed/dsh-chapters/preset'
|
|
157
|
+
config:
|
|
158
|
+
id: chapters
|
|
159
|
+
name: Chapters
|
|
160
|
+
description: Full coding agent; context relief via zero-inference chapter compaction.
|
|
161
|
+
order: 0
|
|
162
|
+
plugins:
|
|
163
|
+
- id: persona
|
|
164
|
+
name: '@deepseek-ai/dsh-persona'
|
|
165
|
+
config:
|
|
166
|
+
prefix: You are a coding agent powered by the {{model}} model.
|
|
167
|
+
suffix: "When a task spans multiple turns, end each reply with one line beginning 'PLOT:' (max 60 words — objective, current hypothesis, immediate next step). A checkpoint carries this plot forward; if it looks stale, revise it on your next plot line."
|
|
168
|
+
- id: agent-instructions
|
|
169
|
+
name: '@deepseek-ai/dsh-agent-instructions'
|
|
170
|
+
config:
|
|
171
|
+
maxBytes: 65536
|
|
172
|
+
- id: time-context
|
|
173
|
+
name: '@deepseek-ai/dsh-time-context'
|
|
174
|
+
- id: tool-bash
|
|
175
|
+
name: '@deepseek-ai/dsh-tool-bash'
|
|
176
|
+
disabled: !!js process.platform === 'win32'
|
|
177
|
+
- id: tool-pwsh
|
|
178
|
+
name: '@deepseek-ai/dsh-tool-pwsh'
|
|
179
|
+
disabled: !!js process.platform !== 'win32'
|
|
180
|
+
- id: tool-fs
|
|
181
|
+
name: '@deepseek-ai/dsh-tool-fs'
|
|
182
|
+
- id: tool-fs-search
|
|
183
|
+
name: '@deepseek-ai/dsh-tool-fs-search'
|
|
184
|
+
config:
|
|
185
|
+
sampleOverCapGlobResults: false
|
|
186
|
+
- id: tool-jobs
|
|
187
|
+
name: '@deepseek-ai/dsh-tool-jobs'
|
|
188
|
+
- id: tool-schedule
|
|
189
|
+
name: '@deepseek-ai/dsh-tool-schedule'
|
|
190
|
+
- id: skill-filesystem
|
|
191
|
+
name: '@deepseek-ai/dsh-skill-filesystem'
|
|
192
|
+
- id: tool-skill
|
|
193
|
+
name: '@deepseek-ai/dsh-tool-skill'
|
|
194
|
+
- id: command-goal
|
|
195
|
+
name: '@deepseek-ai/dsh-command-goal'
|
|
196
|
+
- id: tool-goal
|
|
197
|
+
name: '@deepseek-ai/dsh-tool-goal'
|
|
198
|
+
- id: planning
|
|
199
|
+
name: cordis:group
|
|
200
|
+
group: true
|
|
201
|
+
isolate:
|
|
202
|
+
planMode: true
|
|
203
|
+
config:
|
|
204
|
+
- id: plan-mode
|
|
205
|
+
name: '@deepseek-ai/dsh-plan-mode'
|
|
206
|
+
config:
|
|
207
|
+
section: |
|
|
208
|
+
You are in plan mode. Stay in plan mode until exit_plan_mode succeeds or the user switches the session mode. Imperative language to implement changes means plan the implementation, not execute it. A user's conversational agreement — including an answer confirming something you asked — approves nothing and does not end plan mode; fold the confirmed decision into the plan and submit it through exit_plan_mode.
|
|
209
|
+
|
|
210
|
+
Explore first. Use non-mutating reads, searches, static analysis, and checks to ground the plan in the actual repository. Do not edit or write files, change configuration, run formatters or code generation that rewrites tracked files, commit, or otherwise carry out the plan. Prefer existing functions and patterns over new machinery.
|
|
211
|
+
|
|
212
|
+
The tool catalog stays the same across modes for request-cache stability. These plan-mode rules override any later tool description or guidance that suggests using mutation tools; those tools remain listed to keep the tool catalog unchanged. Do not use todo_write to track this planning phase: it tracks implementation after an approved plan, while the plan itself belongs in exit_plan_mode.
|
|
213
|
+
|
|
214
|
+
Resolve discoverable facts by inspection. Use ask_user_question only for user-owned choices or material ambiguity that inspection cannot answer. Do not ask the user where code lives or how current behavior works when you can find out.
|
|
215
|
+
|
|
216
|
+
Make the plan decision-complete: state the goal and success criteria; group implementation changes by subsystem; identify public API, schema, and data-flow changes; cover edge cases, failure modes, tests, acceptance criteria, and explicit assumptions. Keep it concise enough to review but detailed enough that another engineer can implement it without making design decisions.
|
|
217
|
+
|
|
218
|
+
When ready, call exit_plan_mode with the complete plan markdown, starting with a # title. Make exit_plan_mode the only and final tool call in that assistant response: it presents the plan for approval, and implementation begins only in a later step after approval. Do not paste the final plan as a plain reply or ask "should I proceed?" through prose or ask_user_question. If review rejects it, incorporate the feedback and present again. If the review channel is unavailable or aborted, stay in plan mode and ask the user to switch modes manually; do not proceed with implementation.
|
|
219
|
+
- id: compaction
|
|
220
|
+
name: cordis:group
|
|
221
|
+
group: true
|
|
222
|
+
isolate:
|
|
223
|
+
compaction: true
|
|
224
|
+
toolResultPruner: true
|
|
225
|
+
config:
|
|
226
|
+
- id: chapters-engine
|
|
227
|
+
name: '@treeseed/dsh-chapters/engine'
|
|
228
|
+
config:
|
|
229
|
+
thresholdRatio: 0.9
|
|
230
|
+
- id: command-compact
|
|
231
|
+
name: '@deepseek-ai/dsh-command-compact'
|
|
232
|
+
- id: tool-result-pruner
|
|
233
|
+
name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
|
|
234
|
+
config:
|
|
235
|
+
thresholdChars: 1000000
|
|
236
|
+
headChars: 4096
|
|
237
|
+
tailChars: 1024
|
|
238
|
+
- id: delegation
|
|
239
|
+
name: cordis:group
|
|
240
|
+
group: true
|
|
241
|
+
isolate:
|
|
242
|
+
workflowEngine: true
|
|
243
|
+
config:
|
|
244
|
+
- id: tool-subagent-control
|
|
245
|
+
name: '@deepseek-ai/dsh-tool-subagent-control'
|
|
246
|
+
- id: tool-subagent-list-agents
|
|
247
|
+
name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
|
|
248
|
+
- id: tool-subagent
|
|
249
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
250
|
+
config:
|
|
251
|
+
provider: spawn
|
|
252
|
+
toolName: subagent
|
|
253
|
+
modelSelectionSettings: true
|
|
254
|
+
backgroundMode: continuable
|
|
255
|
+
- id: tool-subagent-fork
|
|
256
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
257
|
+
config:
|
|
258
|
+
provider: fork
|
|
259
|
+
toolName: subagent_fork
|
|
260
|
+
backgroundMode: continuable
|
|
261
|
+
- id: tool-subagent-codex
|
|
262
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
263
|
+
disabled: true
|
|
264
|
+
config:
|
|
265
|
+
provider: codex
|
|
266
|
+
toolName: subagent_codex
|
|
267
|
+
backgroundMode: one-shot
|
|
268
|
+
maxDepth: provider-managed
|
|
269
|
+
- id: tool-subagent-claude-code
|
|
270
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
271
|
+
disabled: true
|
|
272
|
+
config:
|
|
273
|
+
provider: claude-code
|
|
274
|
+
toolName: subagent_claude_code
|
|
275
|
+
backgroundMode: one-shot
|
|
276
|
+
maxDepth: provider-managed
|
|
277
|
+
- id: workflow-ptc
|
|
278
|
+
name: '@deepseek-ai/dsh-workflow-ptc'
|
|
279
|
+
config:
|
|
280
|
+
provider: spawn
|
|
281
|
+
- id: tool-workflow
|
|
282
|
+
name: '@deepseek-ai/dsh-tool-workflow'
|
|
283
|
+
- id: tool-ralph
|
|
284
|
+
name: '@deepseek-ai/dsh-tool-ralph'
|
|
285
|
+
config:
|
|
286
|
+
subagentProvider: spawn
|
|
287
|
+
maxRounds: 64
|
|
288
|
+
- id: tool-ask-user
|
|
289
|
+
name: '@deepseek-ai/dsh-tool-ask-user'
|
|
290
|
+
- id: tool-todo
|
|
291
|
+
name: '@deepseek-ai/dsh-tool-todo'
|
|
292
|
+
config:
|
|
293
|
+
allowParallelInProgress: true
|
|
294
|
+
- id: tool-web
|
|
295
|
+
name: '@deepseek-ai/dsh-tool-web'
|
|
296
|
+
config:
|
|
297
|
+
fetch: true
|
|
298
|
+
searchTimeoutMs: 60000
|
|
299
|
+
- id: present
|
|
300
|
+
name: '@deepseek-ai/dsh-tool-present'
|
|
301
|
+
- id: tool-plugin-manager
|
|
302
|
+
name: '@deepseek-ai/dsh-plugin-manager/tools'
|
|
303
|
+
disabled: true
|
package/docs/backlog.md
CHANGED
|
@@ -121,15 +121,22 @@ NEW host too (measured). Full record: `docs/contract.md` § Presets are declarat
|
|
|
121
121
|
|
|
122
122
|
0. **Re-anchor the e2e host, then re-distill the tapes.** `tests/e2e/boot.ts` now refuses by name
|
|
123
123
|
while `dev/dsh-host-lock` pins a pre-0.2.0 host, and the refusal lifts itself when the lock moves —
|
|
124
|
-
that is the upgrade path, not a TODO.
|
|
124
|
+
that is the upgrade path, not a TODO. `ci.yml`'s `host-capability` job reads that same lock and
|
|
125
|
+
SKIPS the acceptance job with a step-summary reason plus a `::warning::` while the pinned host
|
|
126
|
+
predates declaration rows: visibly skipped, never red-by-accident, never green-by-omission.
|
|
127
|
+
Publishing is unaffected — the release gate is the deterministic suite. The per-boot row pins (`thresholdRatio`, `enrichmentEnabled`,
|
|
125
128
|
`auto`, `elicitedPlot`, `toolResultArtifactTokens`) and the `[e2e] boot pins:` line were deleted with
|
|
126
129
|
the YAML they patched; they come back expressed as CONFIG on the registered row (`compactionThresholdRatio`
|
|
127
130
|
exists now; the rest need the same treatment). Until then the browser acceptance chain does not run, and
|
|
128
131
|
`docs/verify.md`'s P23 is retired rather than passing.
|
|
129
|
-
1. **The roster
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
1. **The roster verdict is a boot log line, and a user has no terminal.** 0.1.18 made the preset a
|
|
133
|
+
visible Loader row (`preset-chapters`) and put the mounted-row count in that line, so the
|
|
134
|
+
"is it actually usable" fact is one grep away — but it is still a grep. Candidate: surface it in
|
|
135
|
+
`/chapters-status`. Nothing else in the plugin reports health to a human today.
|
|
136
|
+
2. **`installChaptersPreset` and `compactionThresholdRatio` are accepted-and-inert** since 0.1.18 (the
|
|
137
|
+
preset is a row; the engine threshold is row config). They must be DELETED in the next minor — a key
|
|
138
|
+
that silently does nothing is its own drift — and the removal needs the same care: check no shipped
|
|
139
|
+
profile patch sets them, then drop both from `Config` and from `cordis.patch.yml`'s header.
|
|
133
140
|
2. **`compositionInventory()` is used by the dev witness only.** Making the boot check itself compare
|
|
134
141
|
mounted rows would catch a row that resolves but never activates — the `broken` flag does not always
|
|
135
142
|
cover that, and the witness proves the shape of the answer already.
|
package/docs/contract.md
CHANGED
|
@@ -369,35 +369,29 @@ running", the preset is simply absent — and a session's preset id is **durable
|
|
|
369
369
|
`agent-preset/not-found`, `dsh-agent-preset-registry/lib/index.js:596`), so every chapters session refuses
|
|
370
370
|
to OPEN while its log sits there intact.
|
|
371
371
|
|
|
372
|
-
**This bundle
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
`
|
|
372
|
+
**This bundle DOES ship the row — in its one existing patch layer, with our own row module.**
|
|
373
|
+
`cordis.patch.yml` ends with `- insert: [{id: preset-chapters, name: '@treeseed/dsh-chapters/preset',
|
|
374
|
+
config: <the preset definition>}]`, so the preset is an ordinary Loader entry: visible in the plugin
|
|
375
|
+
list and `dsh --dump-default-config`, overridable or disable-able from a profile patch, positioned by
|
|
376
|
+
`config.order`. The row module (`src/preset.ts`) mirrors `@deepseek-ai/dsh-agent-preset`'s plugin line
|
|
377
|
+
for line and adds the pruning described below. Why not the host package directly, measured on the
|
|
378
|
+
0.1.5-rc.1 closure and on 0.2.0-rc.2:
|
|
377
379
|
|
|
378
380
|
- `dsh.bundle.patch` as an **array** (what a second layer requires) dies at profile load on a pre-0.1.7
|
|
379
381
|
host: `TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received an
|
|
380
|
-
instance of Array`
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
`disabled`
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
import`, roster without it, while the same row with `disabled: !!js false` registered normally. Bare
|
|
394
|
-
`get(...)` also throws in that scope (`ctx` is bound, `get` is not).
|
|
395
|
-
|
|
396
|
-
The registration path is verified on both mechanisms with real boots: on 0.2.0-rc.2 the witness reports
|
|
397
|
-
`register: pruned, roster: present, inventoryRows: 28, unusableRows: []`; on 0.1.5-rc.1 it reports
|
|
398
|
-
and the same build on 0.1.5-rc.1 logs
|
|
399
|
-
`delivery: REFUSED — this host predates preset declaration rows (< 0.2.0)` — the tools work,
|
|
400
|
-
the preset cannot exist there, and 0.2.0 is now the support floor.
|
|
382
|
+
instance of Array` (`dsh-app-boot/lib/index.js:853`, `join(packageDir, declared)`). Array support and
|
|
383
|
+
declaration rows arrive in the SAME release, 0.1.7-alpha.1 — so one layer, still a string, is both
|
|
384
|
+
enough and the only boot-safe shape.
|
|
385
|
+
- a row naming `@deepseek-ai/dsh-agent-preset` in ANY layer a legacy host reads aborts its plugin tree:
|
|
386
|
+
`plugin tree failed to load: … failed to import loader entry … Cannot find package` (the package is
|
|
387
|
+
first published at 0.1.7-alpha.1). A row naming our own module resolves wherever our package runs.
|
|
388
|
+
- **`disabled: !!js` cannot capability-gate a root row**: the Loader evaluates `disabled` before services
|
|
389
|
+
are mounted (`cordis-plugin-loader/lib/index.js:348` → `with (ctx) { eval(expr) }`), so
|
|
390
|
+
`get('agentPresets')?.register === undefined` is true on the MODERN host too and the row never
|
|
391
|
+
registers — measured (`preset-v2 … failed to import`, roster without it, while the same row with
|
|
392
|
+
`disabled: !!js false` registered normally). Bare `get(...)` also throws there; only `ctx` is bound.
|
|
393
|
+
- and the row must be *ours* anyway for the reason below: it is the one place that can drop a child the
|
|
394
|
+
host cannot load before the mount is attempted.
|
|
401
395
|
|
|
402
396
|
Three consequences of reading the registry rather than the filesystem:
|
|
403
397
|
|
package/docs/development.md
CHANGED
|
@@ -355,7 +355,7 @@ happened in these notes before it was caught.
|
|
|
355
355
|
| `src/notice.ts` + `test/notice.test.ts` — TOC-notice builder, kernel-rejection reproduction, vocabulary pins + drift guard (Phase 0b check 5) | **done**, 10 tests |
|
|
356
356
|
| `src/registry.ts` + `src/store.ts` — pure numbering/ancestry/plan state; zod domain spec, storage-domain + node-fs adapters | **done**, 13 + 7 tests; durability witness passed |
|
|
357
357
|
| `src/engine-core.ts` + `src/engine.ts` — ChaptersCompactionEngine | **done & boot-proven** (r18/r19: realm subpath row mounts; real cascade finalizes; catch-path fix — FINDINGS § Phase 1) |
|
|
358
|
-
| preset delivery | **
|
|
358
|
+
| preset delivery | **0.1.18: the preset IS a declaration row** — `preset-chapters` in `cordis.patch.yml`, mounted by `@treeseed/dsh-chapters/preset` (`src/preset.ts`), which registers what the host can load and drops what it cannot. The `presets/chapters/` + copy-on-boot mechanism is deleted with the 0.2.0 floor. Verify.md P24 (rows + three-host boots) |
|
|
359
359
|
| `npm test` (unit + integration) | **188 passing, <2 s** — unit imports no harness services; integration runs the sync loop against a fake git driver AND a real git smart-HTTP server (git-http-backend on loopback; the git binary is test-only scaffolding, the product stays pure-JS) |
|
|
360
360
|
| 20-check verify.md pass | **r26/26b**: 18 mechanical on `.dshdev2` (refusals with numbers, tamper marks, idempotent retry, cross-boot registry + resume); human rows per verify.md evidence map |
|
|
361
361
|
| dsh-session-fork coexistence | **moot at this version** (r26a pair-boot): the example fails to boot the installed host ALONE (unguarded `webServer` read in the installed dsh-client-connection) — assumed-neutral until a version-matched pair-boot |
|
|
@@ -492,3 +492,39 @@ Two traps measured while finding that:
|
|
|
492
492
|
`src/` only).
|
|
493
493
|
|
|
494
494
|
Never fix a missing test runner by editing the tests. The suite is the contract; the runner is local.
|
|
495
|
+
|
|
496
|
+
### Verifying against a host version that is not the installed one
|
|
497
|
+
|
|
498
|
+
A preset/delivery change must be proven on EVERY host release the package claims to serve, and the
|
|
499
|
+
installed host is one data point. Recipe measured 2026-10-16 (this is how 0.1.17 was verified on
|
|
500
|
+
0.2.0-rc.2, 0.2.1-alpha.4 and the pinned 0.1.5-rc.1 in one sitting):
|
|
501
|
+
|
|
502
|
+
```bash
|
|
503
|
+
# 1. a second host, installed as its own tree — never over the running one
|
|
504
|
+
mkdir -p var/host-versions/a4 && cd var/host-versions/a4
|
|
505
|
+
echo '{"name":"a4-host","private":true,"dependencies":{"@deepseek-ai/dsh":"0.2.1-alpha.4"}}' > package.json
|
|
506
|
+
npm install --no-audit --no-fund # ~1 min, 616 packages
|
|
507
|
+
# 2. a THROWAWAY home for it (profiles/web/package.json listing the bundles + this plugin),
|
|
508
|
+
# then boot THAT bin with DSH_HOME pointed at the new home:
|
|
509
|
+
DSH_HOME=$PWD/var/a4-home DSH_CHAPTERS_WITNESS=$PWD/var/a4-home/w.json \
|
|
510
|
+
node var/host-versions/a4/node_modules/@deepseek-ai/dsh/lib/bin.js web --port 0 --no-open
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
The witness JSON is the answer — `presetRegister`, `presetDroppedRows`, `presetRoster` and
|
|
514
|
+
`presetInventoryRows`/`presetUnusableRows` say what a log line only hints at, and `presetUnusableRows: []`
|
|
515
|
+
is the assertion that the composition actually ACTIVATES rather than merely being declared.
|
|
516
|
+
|
|
517
|
+
Three traps, all paid for:
|
|
518
|
+
|
|
519
|
+
- **Never symlink a host tree into an npm-managed profile's `node_modules`.** `npm install` treats what it
|
|
520
|
+
does not recognize as extraneous and **deletes it through the link** — it ate a 500-package host closure
|
|
521
|
+
this way ("the closure is gone, `ls` returns nothing"). Copy instead (`cp -r`), or point the boot's own
|
|
522
|
+
installation anchor at the other tree and install ONLY the plugin into the profile.
|
|
523
|
+
- **`npm pack` + install-from-tarball, not `file:`-linked sources.** The artifact users get is the packed
|
|
524
|
+
`files` list; a linked working tree hides a missing `files` entry (e.g. an asset the preset needs).
|
|
525
|
+
- Boot with `timeout 45 …` and read the exit code: **124 means it stayed up** (healthy), `1` means the
|
|
526
|
+
plugin tree refused to load. A crashed boot and a slow boot both print to the same log; the code is the
|
|
527
|
+
difference between "no preset" and "no harness".
|
|
528
|
+
|
|
529
|
+
Prune after: `var/host-versions/`, the throwaway homes and `var/coverage` are all regenerable in minutes and
|
|
530
|
+
together cost ~2 GB — this repository's contract is the *measurements written down*, not their scratch.
|
package/docs/verify.md
CHANGED
|
@@ -152,7 +152,8 @@ renderer, the segmentation tool, and the child's notice.
|
|
|
152
152
|
| P10 | Artifact citations resolve wherever they were written | a chapter's `artifacts/aa/<sha>.txt` reference resolves whether the blob sits at the STORE ROOT (arrival stubs) or inside the ANCESTRY TREE (`<store>/<root>/artifacts/…`, where `writeArchive` puts deferred results and every plan) — before this fix the second form was unreadable through `chapters_artifact`, which is what "every byte remains retrievable" actually promised | `artifact-query.test.ts` rows + integration `plans-carriage.test.ts` (`resolveArtifactWithMirror` over the real tree) |
|
|
153
153
|
| P11 | The browser plane runs in the chain | `/plan <message>` → a real `exit_plan_mode` call → the host's review card opened and answered by a real CLICK → fork; asserts the submission's bytes are the artifact's bytes (or provably only-redacted), `planMode: inactive` from the fold, a `kind: plan` document on disk, and that the BRANCH child carries **no** `## Active plan` and no call-out while still citing the archive; plus a guard that no `compaction/*` entered the journey | `tests/e2e/plans.spec.ts` = chain project `plans` (13 s replay, no LLM; 3-entry tape). **Scope, learned at cost:** the continuation leg was REMOVED from this journey because a tape freezes the model's tool ARGUMENTS — my scripted upstream derived `chapters_continue` ranges from the ceiling the live segment tool reported while distilling (30 here), and the runner's session lands at 29, so `validateRanges` refused the stale input (correctly). A journey whose recorded request embeds a machine-specific seq cannot be hardware-neutral. Continuation semantics — `## Active plan`, `## Previous plans`, the seeded `plan/mode`, the checkpoint carry — are covered by the deterministic plane (`continue-plans`, `plans-engine`, `plan-documents`, the § 10 kernel probe) and the in-place path by the heavy/arrival/enrich/fanout journeys. Tape provenance: scripted upstream, see `tests/fixtures/model-tape/plans/PROVENANCE.md` |
|
|
154
154
|
|
|
155
|
-
| P23 | **Retired in 0.1.17 with the legacy copy** (support floor 0.2.0): `installChaptersPreset` and `presets/chapters/` are deleted, so there is no installed file set to half-delete. The
|
|
155
|
+
| P23 | **Retired in 0.1.17 with the legacy copy** (support floor 0.2.0): `installChaptersPreset` and `presets/chapters/` are deleted, so there is no installed file set to half-delete. The key is ACCEPTED-and-inert since 0.1.18 — removing it would make an existing profile patch fail to parse, and a bundle that will not mount is worse than a key that does nothing | see P24 |
|
|
156
|
+
| P24 | The preset is a **visible declaration row**, and the row composes on every host in range | `preset-chapters` is inserted by our own `cordis.patch.yml` with the preset definition in its `config`, mounted by `@treeseed/dsh-chapters/preset` (`src/preset.ts`) — the visible Loader entry the host's own presets are, overridable and `disabled`-able from a profile patch, with the registration's lifetime yielded to Cordis (an `apply()`-scoped disposer un-registered it: measured as `register()` succeeding with the roster WITHOUT `chapters`). Rows the host cannot import are dropped and NAMED, because one unresolvable child makes the whole preset `broken` | 15 rows in `preset-declaration.test.ts`, **each verified to fail on the mutation it guards** (ralph re-disabled, an unknown pruner key, `toolFilter` restored, `{{cwd}}` restored, the durable id renamed) — plus real boots of the packed tarball on 0.2.0-rc.2 (`roster: present`, `inventoryRows: 28`, `unusableRows: []`, tool-schedule pruned), 0.2.1-alpha.4 (`registered`, `inventoryRows: 29`, nothing pruned) and 0.1.5-rc.1 (boots; the row says the host cannot register rows) |
|
|
156
157
|
| P21 | The continuation has a **human-pulled door**, and the two doors cannot drift | `/chapters-continue` = `deterministicCommand({intent:'continue'})`, the same builder as `/chapters-fork`; only name/verbs/intent/no-directive prose differ; archive semantics identical (everything since the watermark). CLIENT SIDE, same discipline: the assistant row registers both doors from ONE runner (`src/client/doors.ts` `makeDoorRunner` + a two-row `DOOR_ACTIONS` table) — a composer-only continue left the user with a created child and no affordance | unit `continue-command.test.ts` (7 rows) incl. the **no-drift row**: same events in ⇒ same ranges, titles and plan facts out of both doors; the no-plan case, the refusal naming its own door, and approved ⇒ NOT seeded vs still-planning ⇒ seeded `['user/message','plan/mode']`. Unit `client-doors.test.ts` (7 rows) pins the two client rows (distinct id/order/label/command, the fork label frozen for the specs), that ONE child-id regex parses BOTH door wordings, that both rows fire their own command through the same body, and — by reading the server's own templates — that the reply wording the client parses is still what `deterministicCommand` emits. Browser: project `fork` asserts BOTH buttons render |
|
|
157
158
|
| P22 | The continuation shape is covered **in the browser**, on every push | the leg that a tape could not carry (§ 15) is back, driven by the command — no model request, no frozen `endSeq`; asserted from the child's durable log without switching the UI: `## Active plan`, the operative plan by title with its real verdict, `plan document:` and `chapters_artifact` citations, `## Finding things`, no seeded gate after approval, exactly one synthetic notice (invariant 2) | `tests/e2e/plans.spec.ts` project `plans` — replays in ~14 s with no LLM/GPU, eight-project chain green |
|
|
158
159
|
| P18 | Search answers **without a pool linked** — the findability audit | `buildLocalCorpus` walks the workspace store (chapters, `kind: plan` documents, rules) and answers through the SAME scorer as the mirror door (`rankEntries`), so ranking cannot drift between doors; artifacts are deliberately not indexed (they answer to `chapters_artifact`); the answer names its door ("searched this machine's store, N docs, no pool mirror") so a session never reads *this machine only* as *the whole project*; "nothing matched" (`documents>0`) is distinguished from "nothing here" (`empty`); a pool miss falls back to the local store before answering empty | unit `local-corpus.test.ts` (5) + integration `find-without-a-pool.test.ts` through the real tool wrapper — the empty answer used to be born in the wrapper, not the pure function |
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export interface SubprocessLike {
|
|
2
|
+
resolveExecutable(name: string): Promise<string>;
|
|
3
|
+
spawn(opts: {
|
|
4
|
+
argv: string[];
|
|
5
|
+
cwd: string;
|
|
6
|
+
stdio: {
|
|
7
|
+
stdin: string;
|
|
8
|
+
stdout: {
|
|
9
|
+
maxBytes: number;
|
|
10
|
+
};
|
|
11
|
+
stderr: {
|
|
12
|
+
maxBytes: number;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
graceMs: number;
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
}): {
|
|
18
|
+
done: Promise<{
|
|
19
|
+
exitCode: number;
|
|
20
|
+
}>;
|
|
21
|
+
collected: {
|
|
22
|
+
stdout?: {
|
|
23
|
+
readFrom(n: number): {
|
|
24
|
+
text: string;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
stderr?: {
|
|
28
|
+
readFrom(n: number): {
|
|
29
|
+
text: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolve the codegraph CLI executable. Returns null if unavailable.
|
|
37
|
+
* Cached after first attempt — call freely.
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolveCodegraph(subprocess: SubprocessLike | undefined): Promise<string | null>;
|
|
40
|
+
/** Reset the cached resolution (test seam only). */
|
|
41
|
+
export declare function resetCodegraphResolution(): void;
|
|
42
|
+
/** Check whether a project has a CodeGraph index at or above the given path. */
|
|
43
|
+
export declare function hasCodegraphIndex(cwd: string): boolean;
|
|
44
|
+
/** Find the nearest indexed ancestor directory. */
|
|
45
|
+
export declare function findCodegraphRoot(cwd: string): string | undefined;
|
|
46
|
+
/** Extract code-shaped tokens from text (file names, camelCase, PascalCase, snake_case). */
|
|
47
|
+
export declare function extractCodeTokens(text: string, limit?: number): string[];
|
|
48
|
+
interface RunResult {
|
|
49
|
+
text: string;
|
|
50
|
+
ok: boolean;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Run a codegraph CLI command. Returns empty text on any failure — callers
|
|
54
|
+
* treat failure as "no data", never as an error.
|
|
55
|
+
*/
|
|
56
|
+
export declare function runCodegraphQuiet(subprocess: SubprocessLike | undefined, argv: string[], cwd: string, timeoutMs: number): Promise<RunResult>;
|
|
57
|
+
/**
|
|
58
|
+
* Query CodeGraph for symbols matching a token. Returns symbol names that
|
|
59
|
+
* exist in the index. Fire-and-forget friendly — errors return [].
|
|
60
|
+
*/
|
|
61
|
+
export declare function querySymbols(subprocess: SubprocessLike | undefined, root: string, token: string, limit?: number, timeoutMs?: number): Promise<string[]>;
|
|
62
|
+
/**
|
|
63
|
+
* Extract CodeGraph symbols from a set of events by verifying code-shaped
|
|
64
|
+
* tokens against the project index. Budget: max 3 queries, 5s each.
|
|
65
|
+
* Returns [] on any failure — callers treat this as optional enrichment.
|
|
66
|
+
*/
|
|
67
|
+
export declare function extractCodegraphSymbolsFromEvents(subprocess: SubprocessLike | undefined, cwd: string, events: readonly {
|
|
68
|
+
type?: string;
|
|
69
|
+
data?: Record<string, unknown>;
|
|
70
|
+
}[], limit?: number): Promise<string[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Run codegraph explore and return the raw text output. Capped and
|
|
73
|
+
* fire-and-forget — errors return ''.
|
|
74
|
+
*/
|
|
75
|
+
export declare function exploreCodegraph(subprocess: SubprocessLike | undefined, root: string, query: string, maxChars?: number, timeoutMs?: number): Promise<string>;
|
|
76
|
+
export {};
|