@treeseed/dsh-chapters 0.1.17 → 0.1.18
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/index.d.ts +16 -20
- package/lib/index.js +55 -114
- package/lib/index.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/package.json +9 -3
package/lib/preset.d.ts
CHANGED
|
@@ -1,55 +1,46 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The `chapters` agent preset
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* The `chapters` agent preset row — our implementation of the host's own
|
|
3
|
+
* `@deepseek-ai/dsh-agent-preset` declaration row, mounted from the bundle patch
|
|
4
|
+
* (`cordis.patch.yml`, row id `preset-chapters`), so the preset is a visible Loader entry
|
|
5
|
+
* exactly like `preset-standard` / `preset-ptc` rather than something a plugin does aside.
|
|
5
6
|
*
|
|
6
|
-
* WHY
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* be of type string. Received an instance of Array` at
|
|
16
|
-
* `dsh-app-boot/lib/index.js:853` (`join(packageDir, declared)`) — the host
|
|
17
|
-
* never boots.
|
|
18
|
-
* - the row itself, in ANY layer a legacy host reads:
|
|
19
|
-
* `dsh: plugin tree failed to load: ... failed to import loader entry
|
|
20
|
-
* preset-chapters (@deepseek-ai/dsh-agent-preset): Cannot find package` — a
|
|
21
|
-
* legacy host's plugin tree aborts the boot on one unresolvable row.
|
|
22
|
-
* - gating it with `disabled: !!js get('agentPresets')?.register === undefined`
|
|
23
|
-
* does not work either: the Loader evaluates `disabled` BEFORE services are
|
|
24
|
-
* mounted, so the expression is truthy on a 0.2.x host too and the row never
|
|
25
|
-
* registers (measured: `preset-v2 … failed to import`, roster without it).
|
|
7
|
+
* WHY OUR ROW AND NOT THE HOST PACKAGE DIRECTLY
|
|
8
|
+
* --------------------------------------------
|
|
9
|
+
* A preset can be unusable in two ways and both are total: one unresolvable child row makes
|
|
10
|
+
* the WHOLE preset `broken` (`mountPreset` throws on any failed row → `record.broken` →
|
|
11
|
+
* `retain()` refuses with `agent-preset/invalid`), which is the same user-visible failure as
|
|
12
|
+
* a missing preset — every chapters session stops composing while its durable log sits there
|
|
13
|
+
* intact. Measured on the stable release with a composition copy-anchored to the alpha:
|
|
14
|
+
* `@deepseek-ai/dsh-tool-schedule` is not published at 0.2.0-rc.2 at all, and the boot said
|
|
15
|
+
* `preset "chapters" is DECLARED BUT BROKEN — tool-schedule … never started`.
|
|
26
16
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* rule this module enforces anyway.
|
|
17
|
+
* So this row does what the host's does, plus drop-what-will-not-load. It also refuses to
|
|
18
|
+
* brick a host predating the mechanism: a `@deepseek-ai/dsh-agent-preset` row is
|
|
19
|
+
* unresolvable before 0.1.7-alpha.1, and ONE unresolvable row aborts a legacy plugin tree
|
|
20
|
+
* (`plugin tree failed to load: … Cannot find package`), while a row naming our own package
|
|
21
|
+
* resolves wherever our package runs. The support floor is 0.2.0, so that is now
|
|
22
|
+
* belt-and-braces rather than the reason — and it is why the row plugin is ours.
|
|
34
23
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* `
|
|
45
|
-
*
|
|
46
|
-
*
|
|
24
|
+
* WHAT IS COPIED FROM THE HOST'S PLUGIN, LINE FOR LINE
|
|
25
|
+
* ---------------------------------------------------
|
|
26
|
+
* - `static inject = ['agentPresets']` — the registry's shape, never a version test.
|
|
27
|
+
* - `static [EntryGroup.key] = true` — "preserve child expressions until their own plugins
|
|
28
|
+
* activate". Without it the Loader interpolates `!!js` against the HOST context, and
|
|
29
|
+
* `disabled: !!js process.platform === 'win32'` stops belonging to the child row that
|
|
30
|
+
* owns it.
|
|
31
|
+
* - `[Service.init]` `yield`s the registry's disposer, so Cordis owns the registration's
|
|
32
|
+
* lifetime. That also disposes of the trap the first draft fell into: calling
|
|
33
|
+
* `ctx.effect(disposer)` from `apply()` fires when the apply FIBER finishes, which
|
|
34
|
+
* un-registered the preset the instant it had been registered (measured on 0.2.0-rc.2:
|
|
35
|
+
* `register()` reported success while the roster came back without `chapters`).
|
|
47
36
|
*
|
|
48
37
|
* @module dsh-chapters/src/preset
|
|
49
38
|
*/
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
39
|
+
import { Service } from '@deepseek-ai/cordis';
|
|
40
|
+
import { EntryGroup } from '@deepseek-ai/cordis-plugin-loader';
|
|
41
|
+
import z from '@deepseek-ai/schemastery';
|
|
42
|
+
/** One mounted plugin row of a preset composition (the Loader's own shape). A group row
|
|
43
|
+
* carries its children in `config`; an ordinary row carries a config map. */
|
|
53
44
|
export interface PresetRow {
|
|
54
45
|
id: string;
|
|
55
46
|
name: string;
|
|
@@ -58,99 +49,75 @@ export interface PresetRow {
|
|
|
58
49
|
group?: boolean;
|
|
59
50
|
isolate?: Record<string, boolean>;
|
|
60
51
|
}
|
|
61
|
-
/** The
|
|
52
|
+
/** The preset definition, in the shape `AgentPresetRegistry.register()` accepts — the host
|
|
53
|
+
* plugin's own Config: id, name?, description?, order, plugins. */
|
|
62
54
|
export interface PresetDefinition {
|
|
63
55
|
id: string;
|
|
64
|
-
name
|
|
65
|
-
description
|
|
66
|
-
order
|
|
56
|
+
name?: string;
|
|
57
|
+
description?: string;
|
|
58
|
+
order?: number;
|
|
67
59
|
plugins: PresetRow[];
|
|
68
60
|
}
|
|
69
|
-
/**
|
|
70
|
-
*
|
|
71
|
-
* list denied `schedule_*` there.
|
|
72
|
-
*
|
|
73
|
-
* Measured on a real 0.2.1-alpha.4 boot: `tool-subagent` does NOT strip an unknown key —
|
|
74
|
-
* it rejects the removed one outright, and the WHOLE preset goes broken:
|
|
75
|
-
* `tool-subagent: toolFilter is no longer supported; configure persona and tool plugins
|
|
76
|
-
* in an Agent Preset and select it with agentPreset (spawn only)`
|
|
77
|
-
* while the same composition on 0.2.0-rc.2 (which still accepts `toolFilter`) mounts. So a
|
|
78
|
-
* key that one supported host accepts and the next one THROWS on is worse than dropping it:
|
|
79
|
-
* the deny list protected nothing on rc.2 (no schedule tools exist there at all) and would
|
|
80
|
-
* break every chapters session on the alpha. The general rule this incident writes down:
|
|
81
|
-
* carry only config keys EVERY supported host accepts, and let the roster line — not a
|
|
82
|
-
* file on disk — be the evidence that the composition is usable.
|
|
83
|
-
*/
|
|
84
|
-
/**
|
|
85
|
-
* The chapters preset: the host's standard coding-agent composition with EXACTLY
|
|
86
|
-
* four deltas, each one a product decision of ours.
|
|
87
|
-
*
|
|
88
|
-
* 1. `compaction-basic` → `@treeseed/dsh-chapters/engine` (thresholdRatio 0.9):
|
|
89
|
-
* the zero-inference `summarize()` — chapters from the log, no model tokens.
|
|
90
|
-
* 2. `tool-result-pruner.thresholdChars` 8192 → 1000000, deliberately dormant:
|
|
91
|
-
* chapters defer oversized results at ARCHIVE time (verbatim bodies +
|
|
92
|
-
* artifact references), never in-surface, where a prune is a prefix cliff on
|
|
93
|
-
* local hardware.
|
|
94
|
-
* 3. the persona gains the PLOT: suffix (plot carriage through in-place
|
|
95
|
-
* checkpoints) and keeps no `{{cwd}}` (see PLOT_SUFFIX).
|
|
96
|
-
* 4. `tool-ralph` mounted ENABLED — the bounded goal loop the continuation
|
|
97
|
-
* children run. The host ships it disabled; enabling it here is ours.
|
|
98
|
-
*
|
|
99
|
-
* @param platform the platform the shell-gated rows are decided against; a
|
|
100
|
-
* parameter so the rows are testable on any machine.
|
|
101
|
-
*/
|
|
102
|
-
export declare function chaptersPresetRows(platform?: NodeJS.Platform, thresholdRatio?: number): PresetRow[];
|
|
103
|
-
/** The preset identity. `config.id` is DURABLE STATE: every continuation child's
|
|
104
|
-
* log records it as `agent-preset/selected`, so renaming it orphans those
|
|
105
|
-
* sessions (`agent-preset/not-found` on open). */
|
|
61
|
+
/** The preset identity. `config.id` is DURABLE STATE: every continuation child's log
|
|
62
|
+
* records it as `agent-preset/selected`, so renaming it orphans those sessions. */
|
|
106
63
|
export declare const CHAPTERS_PRESET_ID = "chapters";
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
* failed row makes the WHOLE preset broken (`mountPreset` throws) — so it is
|
|
110
|
-
* dropped, with the reason, instead of taking every chapters session down.
|
|
64
|
+
/**
|
|
65
|
+
* Drop rows whose module cannot be imported, keeping the group structure intact.
|
|
111
66
|
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
67
|
+
* The probe is asked with the row's FULL specifier, so a package that still exists but no
|
|
68
|
+
* longer exports the subpath a row names (`…/tools`, `…/list-agents`) is caught too — those
|
|
69
|
+
* renames are what eat presets between host versions.
|
|
115
70
|
*
|
|
116
71
|
* @param rows the composition, groups included.
|
|
117
72
|
* @param resolvable asked with each row's module specifier. MUST NOT throw.
|
|
73
|
+
* @returns the composition to register, and every drop NAMED — a silent drop is how a
|
|
74
|
+
* preset loses a tool nobody notices.
|
|
118
75
|
*/
|
|
119
|
-
export declare function
|
|
76
|
+
export declare function pruneUnresolvableRows(rows: PresetRow[], resolvable: (specifier: string) => boolean): {
|
|
120
77
|
kept: PresetRow[];
|
|
121
78
|
dropped: string[];
|
|
122
79
|
};
|
|
123
|
-
/** What registering a preset can end up as. Every arm has its own log line and
|
|
124
|
-
*
|
|
80
|
+
/** What registering a preset can end up as. Every arm has its own log line and its own
|
|
81
|
+
* remedy, because the silent case is the one that cost a human hours. */
|
|
125
82
|
export type RegisterOutcome = {
|
|
126
83
|
state: 'registered';
|
|
127
|
-
}
|
|
128
|
-
/** config.installChaptersPreset=false: the operator owns the preset, we do not register. */
|
|
129
|
-
| {
|
|
130
|
-
state: 'disabled';
|
|
131
|
-
} | {
|
|
132
|
-
state: 'already-declared';
|
|
133
84
|
} | {
|
|
134
85
|
state: 'pruned';
|
|
135
86
|
dropped: string[];
|
|
87
|
+
} | {
|
|
88
|
+
state: 'already-declared';
|
|
136
89
|
} | {
|
|
137
90
|
state: 'unsupported';
|
|
138
91
|
} | {
|
|
139
92
|
state: 'failed';
|
|
140
93
|
reason: string;
|
|
141
94
|
};
|
|
142
|
-
/** The narrow surface of `ctx.get('agentPresets')` this
|
|
95
|
+
/** The narrow surface of `ctx.get('agentPresets')` this row uses. */
|
|
143
96
|
export interface PresetRegistryLike {
|
|
144
97
|
register?: (definition: PresetDefinition) => Promise<() => Promise<void>>;
|
|
145
98
|
list?: () => Promise<unknown>;
|
|
146
|
-
/**
|
|
147
|
-
*
|
|
99
|
+
/** `compositionInventory()` in `@deepseek-ai/dsh-agent-preset-registry`: every declared
|
|
100
|
+
* preset with its mounted rows and their Loader states. */
|
|
148
101
|
compositionInventory?: () => Promise<unknown>;
|
|
149
102
|
}
|
|
150
|
-
/**
|
|
103
|
+
/**
|
|
104
|
+
* Register a declared preset, dropping rows this host cannot import.
|
|
105
|
+
*
|
|
106
|
+
* Split out of the plugin class so every arm is unit-testable without a host: the caller
|
|
107
|
+
* hands in the registry surface and a resolver.
|
|
108
|
+
*
|
|
109
|
+
* @returns the outcome AND the disposer the registry hands back — the caller must keep it
|
|
110
|
+
* alive for the row's lifetime, which is what yielding it from `[Service.init]`
|
|
111
|
+
* does; nothing else has the right lifetime (see the module header).
|
|
112
|
+
*/
|
|
113
|
+
export declare function registerPrunedPreset(presets: PresetRegistryLike | undefined, definition: PresetDefinition, resolvable: (specifier: string) => boolean): Promise<{
|
|
114
|
+
outcome: RegisterOutcome;
|
|
115
|
+
disposer?: () => Promise<void>;
|
|
116
|
+
}>;
|
|
117
|
+
/** One mounted row of a live preset composition, as the host's inventory reports it.
|
|
151
118
|
* `fiberState` is the Loader's state for that row; an enabled row that is not `active`
|
|
152
119
|
* cannot serve a session, and the roster's `broken` flag reports that only for the whole
|
|
153
|
-
* mount — which is why the witness asks for the rows
|
|
120
|
+
* mount — which is why the witness asks for the rows as well. */
|
|
154
121
|
export interface InventoryRow {
|
|
155
122
|
entryId?: string;
|
|
156
123
|
moduleName?: string;
|
|
@@ -165,27 +132,55 @@ export interface InventoryEntry {
|
|
|
165
132
|
}
|
|
166
133
|
/** Find one preset in an inventory response, tolerating a missing or odd shape. */
|
|
167
134
|
export declare function inventoryEntry(raw: unknown, presetId: string): InventoryEntry | undefined;
|
|
168
|
-
/** Enabled rows of one preset that are not active. A row `pending` a host service can
|
|
169
|
-
*
|
|
135
|
+
/** Enabled rows of one preset that are not active. A row `pending` a host service can still
|
|
136
|
+
* activate later, so this is reported apart from `broken` and never as a refusal. */
|
|
170
137
|
export declare function unusableRows(entry: InventoryEntry | undefined): string[];
|
|
171
138
|
/**
|
|
172
|
-
*
|
|
173
|
-
* declaration rows, and say what happened.
|
|
139
|
+
* Whether a module specifier can be imported from THIS package's resolution family.
|
|
174
140
|
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
141
|
+
* Two limits are the host's, not ours to paper over: a RELATIVE specifier resolves without
|
|
142
|
+
* touching the filesystem (so a file-URL row would always be reported resolvable — the
|
|
143
|
+
* composition uses package specifiers only, and the drift test pins that), and a name that
|
|
144
|
+
* resolves is not yet a name that ACTIVATES, which is what the roster line reports as
|
|
145
|
+
* `DECLARED BUT BROKEN`. Never throws: an unresolvable specifier is the answer.
|
|
180
146
|
*/
|
|
181
|
-
export declare function
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
147
|
+
export declare function resolvableFromThisPackage(specifier: string): boolean;
|
|
148
|
+
/** The narrow slice of the Cordis context this row needs. */
|
|
149
|
+
interface RowCtx {
|
|
150
|
+
agentPresets: PresetRegistryLike;
|
|
151
|
+
logger?: {
|
|
152
|
+
info?: (m: string) => void;
|
|
153
|
+
warn?: (m: string) => void;
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* The declaration row. `config` IS the preset definition, exactly as the host's
|
|
158
|
+
* `AgentPreset` plugin consumes it, so a profile patch can override `preset-chapters`
|
|
159
|
+
* wholesale or `disabled: true` it — the two things a runtime registration done in
|
|
160
|
+
* `apply()` cannot offer, and the reason this is a row.
|
|
161
|
+
*/
|
|
162
|
+
export default class ChaptersPresetRow {
|
|
163
|
+
static inject: readonly ["agentPresets"];
|
|
164
|
+
/** Preserve child `!!js` expressions until their own plugins activate. */
|
|
165
|
+
static [EntryGroup.key]: boolean;
|
|
166
|
+
static Config: z<Schemastery.ObjectS<{
|
|
167
|
+
id: z<string, string>;
|
|
168
|
+
name: z<string, string>;
|
|
169
|
+
description: z<string, string>;
|
|
170
|
+
order: z<number, number>;
|
|
171
|
+
plugins: z<any[], any[]>;
|
|
172
|
+
}>, Schemastery.ObjectT<{
|
|
173
|
+
id: z<string, string>;
|
|
174
|
+
name: z<string, string>;
|
|
175
|
+
description: z<string, string>;
|
|
176
|
+
order: z<number, number>;
|
|
177
|
+
plugins: z<any[], any[]>;
|
|
178
|
+
}>>;
|
|
179
|
+
ctx: RowCtx;
|
|
180
|
+
config: PresetDefinition;
|
|
181
|
+
constructor(ctx: RowCtx, config: PresetDefinition);
|
|
182
|
+
/** Registers, then yields the disposer so Cordis owns the registration's lifetime — the
|
|
183
|
+
* host's own row plugin does exactly this (`yield await this.ctx.agentPresets.register(…)`). */
|
|
184
|
+
[Service.init](): AsyncGenerator<() => Promise<void>, void>;
|
|
185
|
+
}
|
|
186
|
+
export {};
|