@fractalsynapse/dsh-chapters 0.0.0-stage → 0.2.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/LICENSE +14 -0
- package/README.md +76 -2
- package/cordis.patch.yml +363 -0
- package/docs/architecture.md +692 -0
- package/docs/autorun-guide.md +248 -0
- package/docs/backlog.md +2022 -0
- package/docs/contract.md +938 -0
- package/docs/development.md +990 -0
- package/docs/host-compaction-seam.md +225 -0
- package/docs/host-protected-head-ask.md +80 -0
- package/docs/knowledge-repo.md +1332 -0
- package/docs/plans-carriage.md +571 -0
- package/docs/project-state.md +642 -0
- package/docs/provider.md +98 -0
- package/docs/superpowers/plans/2026-10-17-chapters-save.md +198 -0
- package/docs/superpowers/plans/2026-11-02-chapter-removal.md +151 -0
- package/docs/superpowers/specs/2026-11-02-chapter-removal-design.md +115 -0
- package/docs/verify.md +561 -0
- package/lib/archive.d.ts +161 -0
- package/lib/archive.js +229 -0
- package/lib/archive.js.map +1 -0
- package/lib/arrival.d.ts +23 -0
- package/lib/arrival.js +125 -0
- package/lib/arrival.js.map +1 -0
- package/lib/artifact-query.d.ts +62 -0
- package/lib/artifact-query.js +187 -0
- package/lib/artifact-query.js.map +1 -0
- package/lib/attach.d.ts +46 -0
- package/lib/attach.js +120 -0
- package/lib/attach.js.map +1 -0
- package/lib/auto-save.d.ts +145 -0
- package/lib/auto-save.js +334 -0
- package/lib/auto-save.js.map +1 -0
- package/lib/aux-message.d.ts +17 -0
- package/lib/aux-message.js +20 -0
- package/lib/aux-message.js.map +1 -0
- package/lib/client.js +1419 -0
- package/lib/client.js.map +1 -0
- package/lib/codegraph.d.ts +76 -0
- package/lib/codegraph.js +190 -0
- package/lib/codegraph.js.map +1 -0
- package/lib/commands.d.ts +52 -0
- package/lib/commands.js +946 -0
- package/lib/commands.js.map +1 -0
- package/lib/compose.d.ts +30 -0
- package/lib/compose.js +185 -0
- package/lib/compose.js.map +1 -0
- package/lib/continue-core.d.ts +245 -0
- package/lib/continue-core.js +405 -0
- package/lib/continue-core.js.map +1 -0
- package/lib/diag.d.ts +55 -0
- package/lib/diag.js +186 -0
- package/lib/diag.js.map +1 -0
- package/lib/engine-core.d.ts +301 -0
- package/lib/engine-core.js +531 -0
- package/lib/engine-core.js.map +1 -0
- package/lib/engine-note.d.ts +35 -0
- package/lib/engine-note.js +32 -0
- package/lib/engine-note.js.map +1 -0
- package/lib/engine.d.ts +329 -0
- package/lib/engine.js +1179 -0
- package/lib/engine.js.map +1 -0
- package/lib/enrich-queue.d.ts +66 -0
- package/lib/enrich-queue.js +126 -0
- package/lib/enrich-queue.js.map +1 -0
- package/lib/enrich-store.d.ts +31 -0
- package/lib/enrich-store.js +103 -0
- package/lib/enrich-store.js.map +1 -0
- package/lib/enrich-wire.d.ts +163 -0
- package/lib/enrich-wire.js +353 -0
- package/lib/enrich-wire.js.map +1 -0
- package/lib/enrich.d.ts +102 -0
- package/lib/enrich.js +267 -0
- package/lib/enrich.js.map +1 -0
- package/lib/gitops.d.ts +107 -0
- package/lib/gitops.js +539 -0
- package/lib/gitops.js.map +1 -0
- package/lib/index.d.ts +241 -0
- package/lib/index.js +1162 -0
- package/lib/index.js.map +1 -0
- package/lib/indexing.d.ts +98 -0
- package/lib/indexing.js +223 -0
- package/lib/indexing.js.map +1 -0
- package/lib/injections.d.ts +90 -0
- package/lib/injections.js +165 -0
- package/lib/injections.js.map +1 -0
- package/lib/last-resort.d.ts +24 -0
- package/lib/last-resort.js +27 -0
- package/lib/last-resort.js.map +1 -0
- package/lib/log-shape.d.ts +38 -0
- package/lib/log-shape.js +93 -0
- package/lib/log-shape.js.map +1 -0
- package/lib/models-command.d.ts +74 -0
- package/lib/models-command.js +100 -0
- package/lib/models-command.js.map +1 -0
- package/lib/notice.d.ts +74 -0
- package/lib/notice.js +92 -0
- package/lib/notice.js.map +1 -0
- package/lib/plans.d.ts +154 -0
- package/lib/plans.js +315 -0
- package/lib/plans.js.map +1 -0
- package/lib/preset.d.ts +186 -0
- package/lib/preset.js +212 -0
- package/lib/preset.js.map +1 -0
- package/lib/prompt-keys.d.ts +7 -0
- package/lib/prompt-keys.js +8 -0
- package/lib/prompt-keys.js.map +1 -0
- package/lib/prompt-loop.d.ts +73 -0
- package/lib/prompt-loop.js +147 -0
- package/lib/prompt-loop.js.map +1 -0
- package/lib/prompt-push.d.ts +47 -0
- package/lib/prompt-push.js +115 -0
- package/lib/prompt-push.js.map +1 -0
- package/lib/prompt-runner.d.ts +48 -0
- package/lib/prompt-runner.js +90 -0
- package/lib/prompt-runner.js.map +1 -0
- package/lib/prompt-state.d.ts +142 -0
- package/lib/prompt-state.js +101 -0
- package/lib/prompt-state.js.map +1 -0
- package/lib/prompt.d.ts +270 -0
- package/lib/prompt.js +408 -0
- package/lib/prompt.js.map +1 -0
- package/lib/provider.d.ts +44 -0
- package/lib/provider.js +66 -0
- package/lib/provider.js.map +1 -0
- package/lib/redact.d.ts +24 -0
- package/lib/redact.js +85 -0
- package/lib/redact.js.map +1 -0
- package/lib/registry.d.ts +187 -0
- package/lib/registry.js +235 -0
- package/lib/registry.js.map +1 -0
- package/lib/removal.d.ts +159 -0
- package/lib/removal.js +556 -0
- package/lib/removal.js.map +1 -0
- package/lib/render.d.ts +97 -0
- package/lib/render.js +530 -0
- package/lib/render.js.map +1 -0
- package/lib/repair-run.d.ts +76 -0
- package/lib/repair-run.js +506 -0
- package/lib/repair-run.js.map +1 -0
- package/lib/repair.d.ts +208 -0
- package/lib/repair.js +357 -0
- package/lib/repair.js.map +1 -0
- package/lib/repo.d.ts +78 -0
- package/lib/repo.js +184 -0
- package/lib/repo.js.map +1 -0
- package/lib/rules-commands.d.ts +46 -0
- package/lib/rules-commands.js +379 -0
- package/lib/rules-commands.js.map +1 -0
- package/lib/rules.d.ts +267 -0
- package/lib/rules.js +478 -0
- package/lib/rules.js.map +1 -0
- package/lib/save-core.d.ts +72 -0
- package/lib/save-core.js +220 -0
- package/lib/save-core.js.map +1 -0
- package/lib/search.d.ts +112 -0
- package/lib/search.js +282 -0
- package/lib/search.js.map +1 -0
- package/lib/session-rules.d.ts +222 -0
- package/lib/session-rules.js +454 -0
- package/lib/session-rules.js.map +1 -0
- package/lib/signature.d.ts +45 -0
- package/lib/signature.js +199 -0
- package/lib/signature.js.map +1 -0
- package/lib/store.d.ts +156 -0
- package/lib/store.js +368 -0
- package/lib/store.js.map +1 -0
- package/lib/sync.d.ts +220 -0
- package/lib/sync.js +810 -0
- package/lib/sync.js.map +1 -0
- package/lib/tools.d.ts +113 -0
- package/lib/tools.js +1090 -0
- package/lib/tools.js.map +1 -0
- package/lib/treedx/client.d.ts +57 -0
- package/lib/treedx/client.js +82 -0
- package/lib/treedx/client.js.map +1 -0
- package/lib/treedx/provider.d.ts +39 -0
- package/lib/treedx/provider.js +479 -0
- package/lib/treedx/provider.js.map +1 -0
- package/lib/treedx/state.d.ts +27 -0
- package/lib/treedx/state.js +65 -0
- package/lib/treedx/state.js.map +1 -0
- package/lib/types.d.ts +210 -0
- package/lib/types.js +31 -0
- package/lib/types.js.map +1 -0
- package/lib/version.d.ts +9 -0
- package/lib/version.js +10 -0
- package/lib/version.js.map +1 -0
- package/lib/vocabulary.d.ts +41 -0
- package/lib/vocabulary.js +118 -0
- package/lib/vocabulary.js.map +1 -0
- package/lib/warnings.d.ts +10 -0
- package/lib/warnings.js +18 -0
- package/lib/warnings.js.map +1 -0
- package/package.json +151 -4
package/lib/diag.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one diagnostics seam for the whole plugin (#54).
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS FILE EXISTS. `DSH_CHAPTERS_ENGINE_ERRORS` was written by two copies of the same
|
|
5
|
+
* three lines — one in the realm engine, one in the subagent auto-save listener — and by
|
|
6
|
+
* NEITHER of the places that actually fail a user: the host-plane doors and the shared
|
|
7
|
+
* continuation core. Measured consequence on host 0.2.0-rc.2: `chapters-fork refused: child
|
|
8
|
+
* creation refused: format v4 message requires a producer-owned source kind` ended the entire
|
|
9
|
+
* acceptance chain, and the sink — the one artifact a human or an agent could read without a
|
|
10
|
+
* browser — captured nothing at all. A diagnostic that misses the failure it exists to record
|
|
11
|
+
* is worse than none, because it is trusted.
|
|
12
|
+
*
|
|
13
|
+
* So there is now ONE writer, called from every plane. Rules it upholds:
|
|
14
|
+
*
|
|
15
|
+
* - **Never throws, never blocks.** Diagnostics must not turn a handled failure into an
|
|
16
|
+
* unhandled one, so every filesystem touch is swallowed. The real failure keeps its path.
|
|
17
|
+
* - **Never silent when opted in.** With no sink configured, `diagnostic` is a no-op by
|
|
18
|
+
* design — but `diagnosticRequested` lets a boot-time health line say "no sink is
|
|
19
|
+
* configured", so the absence is visible rather than discovered during an incident.
|
|
20
|
+
* - **Full detail on disk, short detail on screen.** The UI text is sliced to fit; the sink
|
|
21
|
+
* gets the whole message plus the stack when there is one. Refusals that get truncated to
|
|
22
|
+
* 90 characters for the composer are exactly the ones worth reading in full later.
|
|
23
|
+
*/
|
|
24
|
+
import fs from 'node:fs';
|
|
25
|
+
/**
|
|
26
|
+
* The sink, in resolution order: `DSH_CHAPTERS_ENGINE_ERRORS` (explicit wins), then the plugin-configured
|
|
27
|
+
* default, then NO file only when the operator wrote the literal `off`.
|
|
28
|
+
*
|
|
29
|
+
* #61 changed the default from silence to a file. Every compaction finalization failure in the SAIP field
|
|
30
|
+
* data left zero trace, and door 5 logged `saved` to a logger nobody reads for three days — a sink that
|
|
31
|
+
* must be configured before it works is a sink that is not configured at the moment you need it.
|
|
32
|
+
*/
|
|
33
|
+
let configured;
|
|
34
|
+
/** Called once per plane at boot with `<store-root>/diagnostics.log` (config `diagnosticsLog`). */
|
|
35
|
+
export function configureDiagnostics(path) { configured = path; }
|
|
36
|
+
/**
|
|
37
|
+
* First door wins: the sink lives in the project whose store we are already writing to, so a session
|
|
38
|
+
* that never touches a door leaves no stray file, and a session that does gets its failures next to its
|
|
39
|
+
* chapters. Idempotent — later projects do not relocate the log mid-process.
|
|
40
|
+
*/
|
|
41
|
+
export function ensureDiagnosticsDefault(path, capBytes) {
|
|
42
|
+
if (configured === undefined)
|
|
43
|
+
configured = path;
|
|
44
|
+
if (capBytes !== undefined && Number.isFinite(capBytes) && capBytes >= 0)
|
|
45
|
+
maxBytes = capBytes;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The sink cap (#95 follow-up). The diagnostics sink defaults ON and every fix this month made it
|
|
49
|
+
* chattier — a line per enrichment no-op, per abstention, per declined relief — while `diagnostic()` was
|
|
50
|
+
* an uncapped `appendFileSync`. Loudness that costs unbounded disk is a bug the operator meets later, on
|
|
51
|
+
* someone else's machine. The cap is a declared Config key (`diagnosticsMaxBytes`); this constant is only
|
|
52
|
+
* its default. `0` (or a non-finite value) means uncapped, which stays the operator's explicit choice.
|
|
53
|
+
*/
|
|
54
|
+
export const DEFAULT_DIAGNOSTICS_MAX_BYTES = 8_388_608;
|
|
55
|
+
let maxBytes = DEFAULT_DIAGNOSTICS_MAX_BYTES;
|
|
56
|
+
/**
|
|
57
|
+
* The size decision, kept pure so a row can prove it without a filesystem: append below the cap, rotate
|
|
58
|
+
* at it. A diagnostic is NEVER dropped — the file is what makes detection count as delivery (#61a).
|
|
59
|
+
*/
|
|
60
|
+
export function sinkAction(sizeBytes, capBytes) {
|
|
61
|
+
if (!Number.isFinite(capBytes) || capBytes <= 0)
|
|
62
|
+
return 'append';
|
|
63
|
+
if (!Number.isFinite(sizeBytes) || sizeBytes < 0)
|
|
64
|
+
return 'append';
|
|
65
|
+
return sizeBytes >= capBytes ? 'rotate' : 'append';
|
|
66
|
+
}
|
|
67
|
+
/** Set the cap from plugin config; absent keeps the default. */
|
|
68
|
+
export function configureDiagnosticsCap(bytes) {
|
|
69
|
+
if (bytes !== undefined && Number.isFinite(bytes) && bytes >= 0)
|
|
70
|
+
maxBytes = bytes;
|
|
71
|
+
}
|
|
72
|
+
export const DIAGNOSTICS_OFF = 'off';
|
|
73
|
+
export function diagnosticSink() {
|
|
74
|
+
const p = process.env.DSH_CHAPTERS_ENGINE_ERRORS;
|
|
75
|
+
if (p !== undefined && p !== '')
|
|
76
|
+
return p === DIAGNOSTICS_OFF ? undefined : p;
|
|
77
|
+
return configured;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The status line: says out loud whether a failure WOULD be recorded. Discovered the hard way
|
|
81
|
+
* (#54) — an unconfigured sink is invisible until the one moment you need it, which is exactly
|
|
82
|
+
* when a human is asking "did the feature run, and what did the kernel say?".
|
|
83
|
+
*/
|
|
84
|
+
export function diagnosticStatusLine() {
|
|
85
|
+
const sink = diagnosticSink();
|
|
86
|
+
const envSet = process.env.DSH_CHAPTERS_ENGINE_ERRORS;
|
|
87
|
+
if (sink === undefined) {
|
|
88
|
+
return envSet === DIAGNOSTICS_OFF
|
|
89
|
+
// the operator chose silence — say THAT, not "you forgot to configure it"
|
|
90
|
+
? 'Diagnostics: file sink explicitly disabled (DSH_CHAPTERS_ENGINE_ERRORS=off); door/child failures reach only the profile logger'
|
|
91
|
+
: 'Diagnostics: NO SINK AT ALL — no store root was resolved, so door/child failures reach only the profile logger (this is a bug, not a setting)';
|
|
92
|
+
}
|
|
93
|
+
return `Diagnostics: sink → ${sink}${envSet !== undefined && envSet !== '' ? ' (env override)' : ''}`;
|
|
94
|
+
}
|
|
95
|
+
/** True when SOME diagnostic was written since import — for the status line's honest "no sink" arm. */
|
|
96
|
+
let everWritten = false;
|
|
97
|
+
export function diagnosticEverWritten() { return everWritten; }
|
|
98
|
+
/** Reset for tests only; production never calls it. */
|
|
99
|
+
export function resetDiagnosticStateForTests() { everWritten = false; }
|
|
100
|
+
/**
|
|
101
|
+
* Append one diagnostic record. Returns the composed line even when the write fails, so a
|
|
102
|
+
* caller can ALSO log or include it in a refusal without recomposing it.
|
|
103
|
+
*
|
|
104
|
+
* `where` is the seam that saw it (`'door:fork'`, `'realm:compaction'`, `'auto-save'`) — a
|
|
105
|
+
* timestamp and a message without an origin is how an incident report becomes a guess.
|
|
106
|
+
*/
|
|
107
|
+
function statSize(p) {
|
|
108
|
+
try {
|
|
109
|
+
return fs.statSync(p).size;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export function diagnostic(where, message, error) {
|
|
116
|
+
const line = `[${new Date().toISOString()}] [${where}] ${message}` +
|
|
117
|
+
(error === undefined ? '' : ` :: ${describe(error)}`);
|
|
118
|
+
const sink = diagnosticSink();
|
|
119
|
+
if (sink === undefined)
|
|
120
|
+
return line;
|
|
121
|
+
try {
|
|
122
|
+
// appendFileSync, not async: a refused child creation is often followed by the process
|
|
123
|
+
// tearing the session down, and a pending write can be lost exactly when it matters.
|
|
124
|
+
// The cap is checked BEFORE the write, and the write then always happens. Rotation renames the
|
|
125
|
+
// current file to `<sink>.1` (keeping one previous generation) — this is a LOG policy for a file the
|
|
126
|
+
// plugin owns; nothing under `chapters/` is ever moved or truncated by this path, and the
|
|
127
|
+
// append-only archive invariant stays where it lives.
|
|
128
|
+
if (sinkAction(statSize(sink), maxBytes) === 'rotate') {
|
|
129
|
+
try {
|
|
130
|
+
fs.renameSync(sink, sink + '.1');
|
|
131
|
+
}
|
|
132
|
+
catch { /* rotation failure must never lose the line */ }
|
|
133
|
+
}
|
|
134
|
+
fs.appendFileSync(sink, line + '\n');
|
|
135
|
+
everWritten = true;
|
|
136
|
+
}
|
|
137
|
+
catch { /* diagnostics never mask the real failure */ }
|
|
138
|
+
return line;
|
|
139
|
+
}
|
|
140
|
+
/** The full error text a sink record needs: message, then name/code/stack — in that order. */
|
|
141
|
+
export function describe(error) {
|
|
142
|
+
if (error === null || error === undefined)
|
|
143
|
+
return '(no error object)';
|
|
144
|
+
if (typeof error === 'string')
|
|
145
|
+
return error;
|
|
146
|
+
const e = error;
|
|
147
|
+
const bits = [];
|
|
148
|
+
if (typeof e.message === 'string' && e.message !== '')
|
|
149
|
+
bits.push(e.message);
|
|
150
|
+
if (typeof e.name === 'string' && e.name !== 'Error' && !bits[0]?.startsWith(e.name))
|
|
151
|
+
bits.push(`name=${e.name}`);
|
|
152
|
+
if (typeof e.code === 'string')
|
|
153
|
+
bits.push(`code=${e.code}`);
|
|
154
|
+
if (typeof e.stack === 'string' && e.stack !== '')
|
|
155
|
+
bits.push(e.stack.split('\n').slice(0, 6).join(' | '));
|
|
156
|
+
return bits.join(' :: ') || String(error);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* A logger warn PLUS the sink, for planes that have a Cordis logger. The logger alone is not
|
|
160
|
+
* enough (r19: headless profiles route `ctx.logger` where nobody can see it), and the sink
|
|
161
|
+
* alone loses the operator channel — so do both, in that order.
|
|
162
|
+
*/
|
|
163
|
+
/**
|
|
164
|
+
* The same delivery as `diagnosticWarn`, at INFO — for an OBSERVATION the field needs on disk
|
|
165
|
+
* without anyone reading it as a failure. #78 is the reason this exists: the acceptance suite had
|
|
166
|
+
* always been the caller of `compactIfNeeded`, so "did the host invoke context relief at all?"
|
|
167
|
+
* had no answer in any artifact. A line in the sink answers it, and `info` keeps it out of the
|
|
168
|
+
* warning vocabulary the composer and `/chapters-status` use.
|
|
169
|
+
*/
|
|
170
|
+
export function diagnosticNote(logger, where, message) {
|
|
171
|
+
const line = diagnostic(where, message);
|
|
172
|
+
try {
|
|
173
|
+
logger?.info?.(line);
|
|
174
|
+
}
|
|
175
|
+
catch { /* a hostile logger must not eat the diagnostic */ }
|
|
176
|
+
return line;
|
|
177
|
+
}
|
|
178
|
+
export function diagnosticWarn(logger, where, message, error) {
|
|
179
|
+
const line = diagnostic(where, message, error);
|
|
180
|
+
try {
|
|
181
|
+
logger?.warn?.(line);
|
|
182
|
+
}
|
|
183
|
+
catch { /* a hostile logger must not eat the diagnostic */ }
|
|
184
|
+
return line;
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=diag.js.map
|
package/lib/diag.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diag.js","sourceRoot":"","sources":["../src/diag.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine core — the deterministic logic behind ChaptersCompactionEngine, as
|
|
3
|
+
* pure functions over minimal structural types. NO cordis, NO @deepseek-ai
|
|
4
|
+
* imports: this file runs under `node --test` with no harness, which is where
|
|
5
|
+
* the two scariest engine-path bugs get caught — a lost TOC bullet (silently
|
|
6
|
+
* unreachable chapter) and a mis-resolved citation (wrong text archived).
|
|
7
|
+
*
|
|
8
|
+
* The correlation model (docs/host-compaction-seam.md + FINDINGS § Phase 0b):
|
|
9
|
+
* summarize() — sees region CONTENT (no seqs); reserves numbers keyed by the
|
|
10
|
+
* OPEN transaction's compactionId (found by scanning the log:
|
|
11
|
+
* the last `compaction/start` without a matching `end` — the
|
|
12
|
+
* durable lock guarantees uniqueness) and emits the TOC text
|
|
13
|
+
* citing deterministic paths.
|
|
14
|
+
* finalize() — post-commit, from authoritative CompactionResult.shadowedSeqs,
|
|
15
|
+
* renders bodies from the DURABLE LOG, following each
|
|
16
|
+
* `tool/result` replacement's `sourceEventSeqs` chain back to
|
|
17
|
+
* the pre-prune original. Never from summarize's input.
|
|
18
|
+
*
|
|
19
|
+
* Checkpoint merge-forward: the next compaction's span usually includes the
|
|
20
|
+
* previous checkpoint node (r12 measured it). Its TOC bullets are extracted
|
|
21
|
+
* and re-emitted; an embedded LLM-style summary (a host `basic` checkpoint
|
|
22
|
+
* from before this engine was mounted) is carried verbatim ONCE — honest,
|
|
23
|
+
* bounded, and never silently dropped.
|
|
24
|
+
*/
|
|
25
|
+
import type { ChapterRange, RenderedChapter } from './types.ts';
|
|
26
|
+
import type { ChapterRecord } from './archive.ts';
|
|
27
|
+
import type { PlanChapter, SessionState } from './registry.ts';
|
|
28
|
+
/** provider tag written into `compaction/summary` — our event-scan discriminator. */
|
|
29
|
+
export declare const CHAPTERS_PROVIDER = "dsh-chapters";
|
|
30
|
+
export declare const DETERMINISTIC_MODEL = "deterministic";
|
|
31
|
+
/** Framing tags the host's summarizer wraps checkpoints in (compaction-basic summarizer.ts:21-22). */
|
|
32
|
+
export declare const SUMMARY_OPEN_TAG = "<compacted-summary>";
|
|
33
|
+
export declare const SUMMARY_CLOSE_TAG = "</compacted-summary>";
|
|
34
|
+
/** One TOC bullet, as re-parsed from prior checkpoints — the accumulation unit. */
|
|
35
|
+
export interface TocBullet {
|
|
36
|
+
title: string;
|
|
37
|
+
path: string;
|
|
38
|
+
summary: string;
|
|
39
|
+
}
|
|
40
|
+
export interface EngineConfig {
|
|
41
|
+
/** Workspace cwd, so a resolved-absolute store root still yields workspace-relative records (#69). */
|
|
42
|
+
workspaceCwd?: string | undefined;
|
|
43
|
+
/** Workspace-relative archive root; must be reachable by the `read` tool. */
|
|
44
|
+
artifactStoreRoot: string;
|
|
45
|
+
/**
|
|
46
|
+
* #85: where approved rules and the knowledge pool are read from when a notice is composed.
|
|
47
|
+
* Defaults to the historical `.dsh-knowledge` for real installs; an e2e boot pins it per port,
|
|
48
|
+
* because a tape is a claim about ONE world and a fixed path inside the developer's repo is not
|
|
49
|
+
* part of that world.
|
|
50
|
+
*/
|
|
51
|
+
knowledgeMirrorDir: string;
|
|
52
|
+
/** Lines of the chapter index a continuation notice lists; 0 lists all of them. Keeps the notice's SIZE
|
|
53
|
+
* settled so a leg parked on the compaction boundary can be captured and replayed (#56). */
|
|
54
|
+
noticeIndexCap: number;
|
|
55
|
+
/** #87: how much of the newest human turn the summary carries verbatim when relief
|
|
56
|
+
* shadows the turn that asked it. A cap, never a silent cut — the block says how much was left. */
|
|
57
|
+
openRequestCarryMaxChars: number;
|
|
58
|
+
/** #78 A: the survivability switch. See `docs/host-compaction-seam.md` § the last-resort deferral. */
|
|
59
|
+
lastResortArtifact: boolean;
|
|
60
|
+
/** Diagnostics sink size cap in bytes; 0 = uncapped (docs/verify.md, #61a). */
|
|
61
|
+
diagnosticsMaxBytes: number;
|
|
62
|
+
chapterTokenTarget: number;
|
|
63
|
+
toolResultDeferFloorTokens: number;
|
|
64
|
+
/** Composer tunables (record §4.2/§12) — same register, same defaults as the host plugin's. */
|
|
65
|
+
mergeThreshold: number;
|
|
66
|
+
chapterLimit: number;
|
|
67
|
+
/** #61 Amendment A — the seventh archive moment (see auto-save.ts `shouldForceChildArchive`). */
|
|
68
|
+
childAutoArchive?: boolean | undefined;
|
|
69
|
+
childAutoArchiveMinTurns?: number | undefined;
|
|
70
|
+
/** Arrival-time artifacting floor (architecture.md amendment 2026-09-19):
|
|
71
|
+
* tool results at/above this many estimated tokens are stored as artifacts
|
|
72
|
+
* and replaced by reference stubs BEFORE the next request is composed. */
|
|
73
|
+
toolResultArtifactTokens: number;
|
|
74
|
+
/** Verbatim plan characters printed in a chapter's Plans block (plans-carriage § 2).
|
|
75
|
+
* The full plan is ALWAYS artifact-backed, so this is display economy, not data. */
|
|
76
|
+
planInlineChars: number;
|
|
77
|
+
/** Above this many estimated tokens a tool-call ARGUMENT is artifact-backed and the
|
|
78
|
+
* inline text is a bounded head. 0 = off (default): enabling it changes chapter
|
|
79
|
+
* bytes, hence the model tapes — a deployment opts in deliberately. */
|
|
80
|
+
callArgArtifactTokens: number;
|
|
81
|
+
/** Elicit a plot note with one bounded call when the model wrote none. */
|
|
82
|
+
elicitedPlot: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Carry the operative session plan into every in-place checkpoint (the PLOT
|
|
85
|
+
* mechanism, applied to plans — docs/plans-carriage.md § 9). Shadowing can hide the
|
|
86
|
+
* chapter that holds a plan; a directive that survives only in a file the agent may
|
|
87
|
+
* never open is a directive it drifts from.
|
|
88
|
+
*/
|
|
89
|
+
plansInCheckpoint: boolean;
|
|
90
|
+
/** Bounded plan characters carried in the checkpoint text; the archive keeps all. */
|
|
91
|
+
planCheckpointChars: number;
|
|
92
|
+
}
|
|
93
|
+
export declare const ENGINE_CONFIG_DEFAULTS: EngineConfig;
|
|
94
|
+
export interface SummarizeInputLike {
|
|
95
|
+
readonly tools?: readonly unknown[];
|
|
96
|
+
readonly messages: readonly EngineMessage[];
|
|
97
|
+
}
|
|
98
|
+
export interface EngineMessage {
|
|
99
|
+
readonly role: string;
|
|
100
|
+
readonly content?: readonly {
|
|
101
|
+
type: string;
|
|
102
|
+
text?: string;
|
|
103
|
+
}[];
|
|
104
|
+
}
|
|
105
|
+
export interface SummarizeResultLike {
|
|
106
|
+
summary: {
|
|
107
|
+
type: 'text';
|
|
108
|
+
text: string;
|
|
109
|
+
}[];
|
|
110
|
+
provider: string;
|
|
111
|
+
model: string;
|
|
112
|
+
}
|
|
113
|
+
/** The slice of `Session` the core reads. Kept small so fakes are honest. */
|
|
114
|
+
export interface EngineSession {
|
|
115
|
+
readonly id: string;
|
|
116
|
+
readonly seq: number;
|
|
117
|
+
eventAt(seq: number): EngineSessionEvent | undefined;
|
|
118
|
+
/**
|
|
119
|
+
* Present on the real host Session (a class) — `reconstructShadowedSeqs`
|
|
120
|
+
* needs them to map summarize-input messages back to log seqs. Absence of
|
|
121
|
+
* either simply means: no reconstruction, legacy single-chapter compaction.
|
|
122
|
+
*/
|
|
123
|
+
readonly surface?: {
|
|
124
|
+
readonly nodes?: readonly {
|
|
125
|
+
readonly seq: number;
|
|
126
|
+
}[];
|
|
127
|
+
};
|
|
128
|
+
deriveEventMessage?(event: EngineSessionEvent): EngineMessage | null | undefined;
|
|
129
|
+
}
|
|
130
|
+
export interface EngineSessionEvent {
|
|
131
|
+
readonly type: string;
|
|
132
|
+
readonly seq: number;
|
|
133
|
+
readonly time?: number;
|
|
134
|
+
readonly sourceEventSeqs?: readonly number[];
|
|
135
|
+
readonly data?: Record<string, unknown>;
|
|
136
|
+
}
|
|
137
|
+
/** Every `<compacted-summary>…</compacted-summary>` block in the region, in order. */
|
|
138
|
+
export declare function extractCheckpointBlocks(messages: readonly EngineMessage[]): string[];
|
|
139
|
+
/**
|
|
140
|
+
* Merge-forward: parse prior bullets out of every checkpoint block. Lines that
|
|
141
|
+
* are not our bullet format (e.g. an LLM summary produced by `basic` before
|
|
142
|
+
* this engine took over) are returned as verbatim carry-overs — dropping them
|
|
143
|
+
* would be exactly the loss this plugin exists to prevent.
|
|
144
|
+
*/
|
|
145
|
+
export declare function parseTocState(blocks: readonly string[]): {
|
|
146
|
+
bullets: TocBullet[];
|
|
147
|
+
carriedProse: string[];
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* The open transaction's compactionId: the latest `compaction/start` with no
|
|
151
|
+
* later `compaction/end` carrying the same id. The base appends the start
|
|
152
|
+
* BEFORE awaiting summarize (region.ts:211) and the durable lock admits only
|
|
153
|
+
* one open transaction per session — so a backward scan finds exactly it.
|
|
154
|
+
*/
|
|
155
|
+
export declare function findOpenCompactionId(session: EngineSession): string | null;
|
|
156
|
+
/** All OUR finalized-or-not summary events (provider-tagged), oldest first. */
|
|
157
|
+
export declare function scanChaptersSummaries(session: EngineSession): Array<{
|
|
158
|
+
compactionId: string;
|
|
159
|
+
summarySeq: number;
|
|
160
|
+
shadowedSeqs: number[];
|
|
161
|
+
}>;
|
|
162
|
+
/**
|
|
163
|
+
* Follow `tool/result` replacement chains to the first version (the un-pruned
|
|
164
|
+
* original). Only single-cited tool results qualify — a compaction checkpoint
|
|
165
|
+
* `user/message` also carries sourceEventSeqs, and following THOSE would pull
|
|
166
|
+
* lifecycle bookkeeping into chapter bodies.
|
|
167
|
+
*/
|
|
168
|
+
export declare function resolveOriginalEvent(session: EngineSession, seq: number): EngineSessionEvent | undefined;
|
|
169
|
+
export interface SummarizePlan {
|
|
170
|
+
/** TOC text for the checkpoint (what summarize returns). */
|
|
171
|
+
tocText: string;
|
|
172
|
+
/** Chapter numbers reserved during planning — attemptId `compaction:${id}`. */
|
|
173
|
+
numbers: number[];
|
|
174
|
+
/** Everything finalize needs, since finalize cannot re-derive the title. */
|
|
175
|
+
chapter: {
|
|
176
|
+
title: string;
|
|
177
|
+
summary: string;
|
|
178
|
+
path: string;
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* Topic-composed plan (r29): when the composer ran over the span, one
|
|
182
|
+
* manifest chapter per composed range — finalize renders exactly these,
|
|
183
|
+
* it never recomposes (the TOC cited them; determinism is the contract).
|
|
184
|
+
*/
|
|
185
|
+
chapters?: PlanChapter[];
|
|
186
|
+
}
|
|
187
|
+
/** Deterministic title/summary from region content. Never model-authored (invariant 4 — the model is absent). */
|
|
188
|
+
export declare function deriveIdentity(messages: readonly EngineMessage[], hasCheckpoint: boolean,
|
|
189
|
+
/**
|
|
190
|
+
* A plan submitted inside this span, when there is one (docs/plans-carriage.md
|
|
191
|
+
* § 6): the submission IS the identity of a planning chapter, and it beats the
|
|
192
|
+
* first prose line the same way a file's own header beats a guess about it.
|
|
193
|
+
* Callers that hold events pass it; the summarize path, which sees provider
|
|
194
|
+
* messages only, passes nothing and keeps the old derivation.
|
|
195
|
+
*/
|
|
196
|
+
planTitle?: string): {
|
|
197
|
+
title: string;
|
|
198
|
+
summary: string;
|
|
199
|
+
};
|
|
200
|
+
/** Workspace-relative chapter path for a reserved number. */
|
|
201
|
+
export declare const chapterPathFor: (config: EngineConfig, rootSession: string, number: number, title: string) => string;
|
|
202
|
+
/**
|
|
203
|
+
* Map the prepared summarize input back to the log seqs it was built from
|
|
204
|
+
* (the host builds region messages as `deriveEventMessage(eventAt(seq))` for
|
|
205
|
+
* the shadowed selection). Returns null — meaning "use the legacy
|
|
206
|
+
* single-chapter path" — whenever the Session lacks the mapping API, nothing
|
|
207
|
+
* matches, or MORE THAN ONE contiguous run matches (duplicate small
|
|
208
|
+
* messages are common; guessing a wrong span would cite chapters that never
|
|
209
|
+
* cover their seqs, and an honest legacy chapter beats that).
|
|
210
|
+
*/
|
|
211
|
+
export declare function reconstructShadowedSeqs(session: EngineSession, input: SummarizeInputLike): number[] | null;
|
|
212
|
+
/**
|
|
213
|
+
* The summarize-time plan: merge prior bullets, derive this span's identity,
|
|
214
|
+
* reserve numbers (attempt-keyed by the OPEN transaction's compactionId),
|
|
215
|
+
* build the TOC. Pure given the state; the caller persists the returned
|
|
216
|
+
* state change BEFORE this text can ever be cited.
|
|
217
|
+
*
|
|
218
|
+
* `composition` (r29): topic-sequential ranges from the composer (record
|
|
219
|
+
* §4.2), spanning the whole selected region head-to-tail (the adapter
|
|
220
|
+
* absorbs any strays). Present => reserve one number per chapter and cite
|
|
221
|
+
* them all; absent => the legacy single-chapter identity path, unchanged.
|
|
222
|
+
*/
|
|
223
|
+
export declare function planSummarize(session: EngineSession, state: SessionState, input: SummarizeInputLike, config: EngineConfig, reserveFn: (state: SessionState, attemptId: string, count: number) => {
|
|
224
|
+
state: SessionState;
|
|
225
|
+
numbers: number[];
|
|
226
|
+
},
|
|
227
|
+
/** Required: the caller fails loudly when no `compaction/start` is open. */
|
|
228
|
+
compactionId: string, composition?: readonly ChapterRange[] | null,
|
|
229
|
+
/** Model-authored plot note carried into this checkpoint (may be null). */
|
|
230
|
+
plot?: string | null,
|
|
231
|
+
/**
|
|
232
|
+
* The operative plan, already rendered as checkpoint prose by `carryActivePlan`
|
|
233
|
+
* (plans.ts). Carried on BOTH the composed and the legacy path, because the
|
|
234
|
+
* composed path is where real pressure compaction lands. Note the asymmetry this
|
|
235
|
+
* deliberately does NOT touch: `plot` is still only prefixed on the legacy path
|
|
236
|
+
* (`:415`), and changing that would rewrite checkpoint bytes for every plot-carrying
|
|
237
|
+
* session — i.e. the committed tapes. Plans are new, so carrying them is free.
|
|
238
|
+
*/
|
|
239
|
+
planCarry?: string | null,
|
|
240
|
+
/**
|
|
241
|
+
* #50 §7.6 — the rules block carried across this checkpoint, already rendered
|
|
242
|
+
* by the ONE builder that renders it for the notice too (`rules.buildRulesSection`).
|
|
243
|
+
* This is the hole the round exists to close: `leadSections` was
|
|
244
|
+
* `[planSection, plotSection]`, so a plan and a plot survived a compaction and a
|
|
245
|
+
* RULE did not. Null (nothing active, or the corpus unreadable) renders ZERO
|
|
246
|
+
* bytes — which is what keeps every committed plot-carrying checkpoint intact.
|
|
247
|
+
*/
|
|
248
|
+
rulesCarry?: string | null): {
|
|
249
|
+
plan: SummarizePlan;
|
|
250
|
+
state: SessionState;
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* The plot note (architecture.md amendment 2026-09-19): a short forward-
|
|
254
|
+
* maintained statement of what the agent is MID-WAY through, authored by the
|
|
255
|
+
* model itself and carried forward across every in-place checkpoint.
|
|
256
|
+
*/
|
|
257
|
+
export declare const PLOT_MARKER = "PLOT:";
|
|
258
|
+
export declare function extractPlot(messages: readonly EngineMessage[], maxChars?: number): string | null;
|
|
259
|
+
/**
|
|
260
|
+
* Post-commit: render the chapter body for one compaction from the durable
|
|
261
|
+
* log (citation-resolved), and return the record to commit. The caller writes
|
|
262
|
+
* files (via archive.writeArchive) and persists state; this stays pure over
|
|
263
|
+
* the event data so the pruner-composition rule is testable.
|
|
264
|
+
*/
|
|
265
|
+
export declare function buildFinalizedChapter(session: EngineSession, shadowedSeqs: readonly number[], plan: SummarizePlan, config: EngineConfig): RenderedChapter;
|
|
266
|
+
/**
|
|
267
|
+
* Render the manifest's chapters (r29) — authoritative ranges, no
|
|
268
|
+
* recomposition (the TOC cited them). A plan without composed chapters
|
|
269
|
+
* returns the legacy single render. Mismatch between manifest and the
|
|
270
|
+
* committed shadowed span is a LOUD error: the finalizer defers and warns,
|
|
271
|
+
* never silently archives the wrong content.
|
|
272
|
+
*/
|
|
273
|
+
export declare function buildFinalizedChapters(session: EngineSession, shadowedSeqs: readonly number[], plan: SummarizePlan, config: EngineConfig): RenderedChapter[];
|
|
274
|
+
/** The registry record shape written post-writeArchive for an engine chapter. */
|
|
275
|
+
export declare function engineRecord(plan: SummarizePlan, shadowedSeqs: readonly number[], rendered: RenderedChapter, writtenPath: string, sha256hex: string): ChapterRecord;
|
|
276
|
+
/** Numbers the plan reserved, or null when the manifest disagrees (corruption). */
|
|
277
|
+
/**
|
|
278
|
+
* Walk the provider-tagged summaries of one session and finalize each that is not yet finalized,
|
|
279
|
+
* ONE AT A TIME (#59): an item whose manifest is gone is reported and skipped, never allowed to
|
|
280
|
+
* abort the items behind it. Pure over injected effects so the poison-pill case is testable without
|
|
281
|
+
* a host.
|
|
282
|
+
*/
|
|
283
|
+
export declare function scanAndFinalize(state: SessionState, summaries: readonly {
|
|
284
|
+
compactionId: string;
|
|
285
|
+
summarySeq: number;
|
|
286
|
+
shadowedSeqs: number[];
|
|
287
|
+
}[], finalizeOne: (found: {
|
|
288
|
+
compactionId: string;
|
|
289
|
+
summarySeq: number;
|
|
290
|
+
shadowedSeqs: number[];
|
|
291
|
+
}) => Promise<void>, onSkip?: (reason: {
|
|
292
|
+
compactionId: string;
|
|
293
|
+
reason: string;
|
|
294
|
+
}, error: unknown) => void): Promise<{
|
|
295
|
+
done: string[];
|
|
296
|
+
skipped: Array<{
|
|
297
|
+
compactionId: string;
|
|
298
|
+
reason: string;
|
|
299
|
+
}>;
|
|
300
|
+
}>;
|
|
301
|
+
export declare function assertReservationMatchesPlan(state: SessionState, compactionId: string, plan: SummarizePlan): boolean;
|