@fractalsynapse/dsh-chapters 0.0.0-stage → 0.2.21
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 -3
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Artifact query surface (arrival-time artifacting plan, Phase 3): pure,
|
|
3
|
+
* bounded readers over content-addressed artifact files. The point of this
|
|
4
|
+
* module is that a stored blob is USEFUL without ever being loaded whole —
|
|
5
|
+
* toc/search/read are the small-block windows the RLM result calls an
|
|
6
|
+
* 'external environment', implemented with files and line numbers instead
|
|
7
|
+
* of a code sandbox. Every function is deterministic and refuses rather
|
|
8
|
+
* than silently clipping (bounds reported, never applied by truncation
|
|
9
|
+
* without a flag).
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
/** Rough token estimate consistent with the est-token convention elsewhere (chars/4). */
|
|
14
|
+
const estTokens = (s) => Math.ceil(s.length / 4);
|
|
15
|
+
/**
|
|
16
|
+
* Resolve a user/model-supplied reference to an absolute artifact path INSIDE
|
|
17
|
+
* the store. Accepts a 64-hex sha, 'artifacts/xx/<sha>.txt', or an absolute
|
|
18
|
+
* path. Throws on anything escaping the store — this tool is read-only, the
|
|
19
|
+
* containment is the whole security story.
|
|
20
|
+
*/
|
|
21
|
+
export function resolveArtifactPath(storeDir, ref) {
|
|
22
|
+
const clean = ref.trim();
|
|
23
|
+
if (/^[0-9a-f]{64}$/.test(clean))
|
|
24
|
+
return path.join(storeDir, 'artifacts', clean.slice(0, 2), `${clean}.txt`);
|
|
25
|
+
const abs = path.isAbsolute(clean) ? path.normalize(clean) : path.normalize(path.join(storeDir, clean));
|
|
26
|
+
const root = path.resolve(storeDir);
|
|
27
|
+
if (abs !== root && !abs.startsWith(root + path.sep))
|
|
28
|
+
throw new Error(`artifact reference escapes the store: ${ref}`);
|
|
29
|
+
return abs;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Markdown heading map with 1-based line numbers — a 300-page book arrives
|
|
33
|
+
* with its own table of contents (fenced code blocks are skipped so '#
|
|
34
|
+
* comments' inside them never masquerade as headings).
|
|
35
|
+
*/
|
|
36
|
+
export function buildToc(text, maxEntries = 400) {
|
|
37
|
+
const entries = [];
|
|
38
|
+
let inFence = false;
|
|
39
|
+
let fenceMarker = '';
|
|
40
|
+
let lineNo = 0;
|
|
41
|
+
for (const line of text.split('\n')) {
|
|
42
|
+
lineNo++;
|
|
43
|
+
const fence = /^\s{0,3}(`{3,}|~{3,})/.test(line);
|
|
44
|
+
if (fence) {
|
|
45
|
+
const marker = line.trim().slice(0, 3);
|
|
46
|
+
if (!inFence) {
|
|
47
|
+
inFence = true;
|
|
48
|
+
fenceMarker = marker[0];
|
|
49
|
+
}
|
|
50
|
+
else if (marker[0] === fenceMarker) {
|
|
51
|
+
inFence = false;
|
|
52
|
+
}
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (inFence)
|
|
56
|
+
continue;
|
|
57
|
+
const m = /^(#{1,6})\s+(.*)$/.exec(line);
|
|
58
|
+
if (m === null)
|
|
59
|
+
continue;
|
|
60
|
+
if (entries.length >= maxEntries)
|
|
61
|
+
return { entries, truncated: true };
|
|
62
|
+
entries.push({ line: lineNo, depth: m[1].length, title: m[2].trim().slice(0, 120) });
|
|
63
|
+
}
|
|
64
|
+
return { entries, truncated: false };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Case-insensitive query over lines: regex when it compiles, literal phrase
|
|
68
|
+
* otherwise. Matches expand to ±context lines and overlapping windows merge;
|
|
69
|
+
* the pack stops at maxTokens and REPORTS what it left behind.
|
|
70
|
+
*/
|
|
71
|
+
export function searchArtifact(text, query, opts = {}) {
|
|
72
|
+
const maxTokens = opts.maxTokens ?? 400;
|
|
73
|
+
const context = opts.contextLines ?? 2;
|
|
74
|
+
const lines = text.split('\n');
|
|
75
|
+
let re = null;
|
|
76
|
+
try {
|
|
77
|
+
re = new RegExp(query, 'i');
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
re = null;
|
|
81
|
+
}
|
|
82
|
+
const hit = (l) => re !== null ? re.test(l) : l.toLowerCase().includes(query.trim().toLowerCase());
|
|
83
|
+
const matched = [];
|
|
84
|
+
for (let i = 0; i < lines.length; i++)
|
|
85
|
+
if (hit(lines[i]))
|
|
86
|
+
matched.push(i);
|
|
87
|
+
const blocks = [];
|
|
88
|
+
let used = 0;
|
|
89
|
+
for (const idx of matched) {
|
|
90
|
+
const start = Math.max(0, idx - context);
|
|
91
|
+
const end = Math.min(lines.length - 1, idx + context);
|
|
92
|
+
const last = blocks[blocks.length - 1];
|
|
93
|
+
if (last !== undefined && start <= last.end + 1) {
|
|
94
|
+
if (end > last.end) {
|
|
95
|
+
const add = lines.slice(last.end + 1, end + 1).map((l, k) => `${last.end + 2 + k}: ${l.slice(0, 400)}`).join('\n');
|
|
96
|
+
const addTokens = estTokens(add);
|
|
97
|
+
if (used + addTokens > maxTokens)
|
|
98
|
+
break;
|
|
99
|
+
last.lines.push(...lines.slice(last.end + 1, end + 1).map((l, k) => `${last.end + 2 + k}: ${l.slice(0, 400)}`));
|
|
100
|
+
last.end = end;
|
|
101
|
+
used += addTokens;
|
|
102
|
+
}
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
const chunk = lines.slice(start, end + 1).map((l, k) => `${start + k + 1}: ${l.slice(0, 400)}`);
|
|
106
|
+
const tokens = estTokens(chunk.join('\n'));
|
|
107
|
+
if (used + tokens > maxTokens)
|
|
108
|
+
break;
|
|
109
|
+
blocks.push({ start: start + 1, end: end + 1, lines: chunk });
|
|
110
|
+
used += tokens;
|
|
111
|
+
}
|
|
112
|
+
const lastIncluded = blocks.length === 0 ? -1 : blocks[blocks.length - 1].end - 1;
|
|
113
|
+
const remaining = matched.filter((i) => i > lastIncluded).length;
|
|
114
|
+
return { total: matched.length, blocks, truncated: remaining > 0, remaining };
|
|
115
|
+
}
|
|
116
|
+
/** Exact line window (1-based inclusive), capped per call; bounds reported. */
|
|
117
|
+
export function readLines(text, offset, limit, hardCap = 400) {
|
|
118
|
+
const lines = text.split('\n');
|
|
119
|
+
const start = Math.max(1, Math.floor(offset));
|
|
120
|
+
const want = Math.max(1, Math.floor(limit));
|
|
121
|
+
const take = Math.min(want, hardCap);
|
|
122
|
+
const end = Math.min(lines.length, start + take - 1);
|
|
123
|
+
return { start, end, of: lines.length, lines: lines.slice(start - 1, end).map((l, k) => `${start + k}: ${l.slice(0, 1000)}`) };
|
|
124
|
+
}
|
|
125
|
+
/** Load an artifact with a size guard; returns text + totals for the pack. */
|
|
126
|
+
export function loadArtifact(absPath) {
|
|
127
|
+
const st = fs.statSync(absPath);
|
|
128
|
+
return { text: fs.readFileSync(absPath, 'utf8'), bytes: st.size, lines: 0 };
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Store-first, mirror-second resolution (measured 2026-09-28, treeseed pool
|
|
132
|
+
* audit): chapters cite 'artifacts/aa/<sha>.txt' — on another machine the blob
|
|
133
|
+
* lives in the knowledge MIRROR (artifacts/<projectKey>/aa/<sha>.txt, one dir
|
|
134
|
+
* per linked project), not the local store. Returns the absolute path of the
|
|
135
|
+
* first existing match, or null. Containment holds on BOTH roots; '..' can
|
|
136
|
+
* never escape.
|
|
137
|
+
*/
|
|
138
|
+
export function resolveArtifactWithMirror(storeDir, ref, mirrorDir) {
|
|
139
|
+
const primary = resolveArtifactPath(storeDir, ref); // still throws on escapes
|
|
140
|
+
if (fs.existsSync(primary))
|
|
141
|
+
return primary;
|
|
142
|
+
const clean = ref.trim();
|
|
143
|
+
// tail = the aa/<sha>.txt portion under artifacts/, whatever the ref form
|
|
144
|
+
const tail = /^[0-9a-f]{64}$/.test(clean)
|
|
145
|
+
? path.join(clean.slice(0, 2), `${clean}.txt`)
|
|
146
|
+
: (() => {
|
|
147
|
+
const m = clean.replace(/^\.\//, '').match(/artifacts[/\\](.+\.txt)$/);
|
|
148
|
+
return m?.[1] ?? null;
|
|
149
|
+
})();
|
|
150
|
+
if (tail === null || tail.split(/[\\/]/).includes('..'))
|
|
151
|
+
return null;
|
|
152
|
+
// Session trees FIRST (measured 2026-10-09, plans-carriage): a chapter defers a
|
|
153
|
+
// result — or a plan's full text — to `artifacts/<aa>/<sha>.txt`, and
|
|
154
|
+
// archive.writeArchive writes it under the ANCESTRY TREE directory
|
|
155
|
+
// (<storeRoot>/<rootSession>/artifacts/…), not the store root where arrival
|
|
156
|
+
// stubs live. Before this, every such citation pointed at a path
|
|
157
|
+
// chapters_artifact could not resolve, so 'every byte remains retrievable'
|
|
158
|
+
// held only on the machine and directory layout that happened to match.
|
|
159
|
+
if (fs.existsSync(storeDir)) {
|
|
160
|
+
for (const entry of fs.readdirSync(storeDir, { withFileTypes: true })) {
|
|
161
|
+
if (!entry.isDirectory() || entry.name.startsWith('.'))
|
|
162
|
+
continue;
|
|
163
|
+
const cand = path.join(storeDir, entry.name, 'artifacts', tail);
|
|
164
|
+
const root = path.resolve(storeDir);
|
|
165
|
+
const resolved = path.resolve(cand);
|
|
166
|
+
if (resolved !== root && !resolved.startsWith(root + path.sep))
|
|
167
|
+
continue;
|
|
168
|
+
if (fs.existsSync(cand))
|
|
169
|
+
return cand;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const artRoot = path.join(mirrorDir, 'artifacts');
|
|
173
|
+
if (!fs.existsSync(artRoot))
|
|
174
|
+
return null;
|
|
175
|
+
for (const key of fs.readdirSync(artRoot, { withFileTypes: true })) {
|
|
176
|
+
if (!key.isDirectory())
|
|
177
|
+
continue;
|
|
178
|
+
const cand = path.join(artRoot, key.name, tail);
|
|
179
|
+
const root = path.resolve(artRoot);
|
|
180
|
+
if (path.resolve(cand) !== root && !path.resolve(cand).startsWith(root + path.sep))
|
|
181
|
+
continue;
|
|
182
|
+
if (fs.existsSync(cand))
|
|
183
|
+
return cand;
|
|
184
|
+
}
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=artifact-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-query.js","sourceRoot":"","sources":["../src/artifact-query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAI5B,yFAAyF;AACzF,MAAM,SAAS,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;AAEhE;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAgB,EAAE,GAAW;IAC/D,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAA;IACxB,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,MAAM,CAAC,CAAA;IAC5G,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAA;IACvG,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IACnC,IAAI,GAAG,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,GAAG,EAAE,CAAC,CAAA;IACrH,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,UAAU,GAAG,GAAG;IACrD,MAAM,OAAO,GAAe,EAAE,CAAA;IAC9B,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,IAAI,WAAW,GAAG,EAAE,CAAA;IACpB,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,MAAM,EAAE,CAAA;QACR,MAAM,KAAK,GAAG,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAChD,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;YACtC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAAC,OAAO,GAAG,IAAI,CAAC;gBAAC,WAAW,GAAG,MAAM,CAAC,CAAC,CAAW,CAAA;YAAC,CAAC;iBAC9D,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,WAAW,EAAE,CAAC;gBAAC,OAAO,GAAG,KAAK,CAAA;YAAC,CAAC;YACvD,SAAQ;QACV,CAAC;QACD,IAAI,OAAO;YAAE,SAAQ;QACrB,MAAM,CAAC,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACxC,IAAI,CAAC,KAAK,IAAI;YAAE,SAAQ;QACxB,IAAI,OAAO,CAAC,MAAM,IAAI,UAAU;YAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAA;QACrE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;IACxF,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAA;AACtC,CAAC;AAID;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAY,EAAE,KAAa,EAAE,OAAsD,EAAE;IAErF,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,GAAG,CAAA;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,IAAI,CAAC,CAAA;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,EAAE,GAAkB,IAAI,CAAA;IAC5B,IAAI,CAAC;QAAC,EAAE,GAAG,IAAI,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,EAAE,GAAG,IAAI,CAAA;IAAC,CAAC;IACvD,MAAM,GAAG,GAAG,CAAC,CAAS,EAAW,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAA;IACnH,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC1E,MAAM,MAAM,GAAkB,EAAE,CAAA;IAChC,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,CAAA;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,CAAA;QACrD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;QACtC,IAAI,IAAI,KAAK,SAAS,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;YAChD,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACnB,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBAClH,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,CAAA;gBAChC,IAAI,IAAI,GAAG,SAAS,GAAG,SAAS;oBAAE,MAAK;gBACvC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;gBAC/G,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;gBACd,IAAI,IAAI,SAAS,CAAA;YACnB,CAAC;YACD,SAAQ;QACV,CAAC;QACD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;QAC/F,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QAC1C,IAAI,IAAI,GAAG,MAAM,GAAG,SAAS;YAAE,MAAK;QACpC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAA;QAC7D,IAAI,IAAI,MAAM,CAAA;IAChB,CAAC;IACD,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,GAAG,GAAG,CAAC,CAAA;IAClF,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,MAAM,CAAA;IAChE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,CAAC,EAAE,SAAS,EAAE,CAAA;AAC/E,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,MAAc,EAAE,KAAa,EAAE,OAAO,GAAG,GAAG;IAClF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;IAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IACpC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,CAAA;IACpD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAA;AAChI,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;IAC/B,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAA;AAC7E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAAgB,EAAE,GAAW,EAAE,SAAiB;IACxF,MAAM,OAAO,GAAG,mBAAmB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA,CAAC,0BAA0B;IAC7E,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAA;IAC1C,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAA;IACxB,0EAA0E;IAC1E,MAAM,IAAI,GAAkB,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC;QACtD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,MAAM,CAAC;QAC9C,CAAC,CAAC,CAAC,GAAG,EAAE;YACJ,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAA;YACtE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAA;QACvB,CAAC,CAAC,EAAE,CAAA;IACR,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACpE,gFAAgF;IAChF,sEAAsE;IACtE,mEAAmE;IACnE,4EAA4E;IAC5E,iEAAiE;IACjE,2EAA2E;IAC3E,wEAAwE;IACxE,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACtE,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAQ;YAChE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,CAAA;YAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;YACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;YACnC,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC;gBAAE,SAAQ;YACxE,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;gBAAE,OAAO,IAAI,CAAA;QACtC,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAA;IACjD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAA;IACxC,KAAK,MAAM,GAAG,IAAI,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACnE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE;YAAE,SAAQ;QAChC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QAClC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC;YAAE,SAAQ;QAC5F,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;IACtC,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
|
package/lib/attach.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attaching a created child to the workspace — the loud version (#54).
|
|
3
|
+
*
|
|
4
|
+
* One step, five ways it can fail, and only one of them silent. AGENTS records that
|
|
5
|
+
* `workspaceRegistry.createCanonical(cwd)` → `attachSession(id)` is precisely what makes a
|
|
6
|
+
* programmatic session APPEAR in the UI ("an unattached session was the whole explanation
|
|
7
|
+
* for round 6's 'not listed'"), yet the door called it through two optional chains inside a
|
|
8
|
+
* `catch` that only warned the profile logger. On host 0.2.0-rc.2 the result is a child that
|
|
9
|
+
* is created, durable, present in `session_projcache` — and absent from the sidebar after a
|
|
10
|
+
* reload, while the door reports success. Silence in a required step is the bug; this module
|
|
11
|
+
* is the fix.
|
|
12
|
+
*
|
|
13
|
+
* The rule it encodes: **verify the user-visible fact, not the absence of a throw.** A
|
|
14
|
+
* successful `attachSession()` proves the method exists, not that the session is listed —
|
|
15
|
+
* so the check is "does this child appear in `sessionQuery.listSessions()`", polled briefly
|
|
16
|
+
* because the workspace catches up asynchronously.
|
|
17
|
+
*/
|
|
18
|
+
export interface AttachPorts {
|
|
19
|
+
/** the host's `workspaceRegistry` service, as far as it was resolved */
|
|
20
|
+
workspaceRegistry: unknown;
|
|
21
|
+
/** the host's `sessionQuery` service; absent ⇒ listing cannot be verified, said out loud */
|
|
22
|
+
sessionQuery: unknown;
|
|
23
|
+
/** the host's `sessionController` service; its `list()` is the surface the BROWSER reads.
|
|
24
|
+
* Absent ⇒ the gateway half of the verification is UNVERIFIED, said out loud. */
|
|
25
|
+
sessionController?: unknown;
|
|
26
|
+
/** the diagnostics seam (`src/diag.ts`): sink + logger, never throws */
|
|
27
|
+
diagnostic(where: string, message: string, error?: unknown): void;
|
|
28
|
+
childId: string;
|
|
29
|
+
cwd: string;
|
|
30
|
+
/** test seams; production uses the defaults */
|
|
31
|
+
pollIntervalMs?: number;
|
|
32
|
+
pollBudgetMs?: number;
|
|
33
|
+
}
|
|
34
|
+
export interface AttachOutcome {
|
|
35
|
+
/** the workspace actually took the session */
|
|
36
|
+
attached: boolean;
|
|
37
|
+
/** it appears in the session list. `undefined` = UNVERIFIABLE, which is NOT `true`. */
|
|
38
|
+
listed: boolean | undefined;
|
|
39
|
+
/** it appears in the GATEWAY list the browser renders and opens from. `undefined` = unverified.
|
|
40
|
+
* Written as `| undefined` deliberately: this repo compiles with
|
|
41
|
+
* `exactOptionalPropertyTypes`, where `?: boolean` forbids assigning undefined. */
|
|
42
|
+
gatewayListed?: boolean | undefined;
|
|
43
|
+
/** user-visible words for anything short of attached+listed — these reach the door result */
|
|
44
|
+
warnings: string[];
|
|
45
|
+
}
|
|
46
|
+
export declare function attachCreatedChild(ports: AttachPorts): Promise<AttachOutcome>;
|
package/lib/attach.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attaching a created child to the workspace — the loud version (#54).
|
|
3
|
+
*
|
|
4
|
+
* One step, five ways it can fail, and only one of them silent. AGENTS records that
|
|
5
|
+
* `workspaceRegistry.createCanonical(cwd)` → `attachSession(id)` is precisely what makes a
|
|
6
|
+
* programmatic session APPEAR in the UI ("an unattached session was the whole explanation
|
|
7
|
+
* for round 6's 'not listed'"), yet the door called it through two optional chains inside a
|
|
8
|
+
* `catch` that only warned the profile logger. On host 0.2.0-rc.2 the result is a child that
|
|
9
|
+
* is created, durable, present in `session_projcache` — and absent from the sidebar after a
|
|
10
|
+
* reload, while the door reports success. Silence in a required step is the bug; this module
|
|
11
|
+
* is the fix.
|
|
12
|
+
*
|
|
13
|
+
* The rule it encodes: **verify the user-visible fact, not the absence of a throw.** A
|
|
14
|
+
* successful `attachSession()` proves the method exists, not that the session is listed —
|
|
15
|
+
* so the check is "does this child appear in `sessionQuery.listSessions()`", polled briefly
|
|
16
|
+
* because the workspace catches up asynchronously.
|
|
17
|
+
*/
|
|
18
|
+
const shape = (v) => {
|
|
19
|
+
if (v === null)
|
|
20
|
+
return 'null';
|
|
21
|
+
if (v === undefined)
|
|
22
|
+
return 'undefined';
|
|
23
|
+
if (typeof v !== 'object')
|
|
24
|
+
return typeof v;
|
|
25
|
+
const keys = Object.keys(v).slice(0, 6);
|
|
26
|
+
return `${Array.isArray(v) ? 'array' : 'object'}{${keys.join(',')}}`;
|
|
27
|
+
};
|
|
28
|
+
export async function attachCreatedChild(ports) {
|
|
29
|
+
const warnings = [];
|
|
30
|
+
const registry = ports.workspaceRegistry;
|
|
31
|
+
if (typeof registry?.createCanonical !== 'function') {
|
|
32
|
+
const reason = `child ${ports.childId} could NOT be attached to the workspace: no "workspaceRegistry" service (or it exposes no createCanonical) — it may never appear in the sidebar`;
|
|
33
|
+
ports.diagnostic('attach:workspaceRegistry', reason, `resolved=${shape(ports.workspaceRegistry)}`);
|
|
34
|
+
return { attached: false, listed: undefined, warnings: [reason] };
|
|
35
|
+
}
|
|
36
|
+
let workspace;
|
|
37
|
+
try {
|
|
38
|
+
workspace = await registry.createCanonical(ports.cwd);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
const reason = `child ${ports.childId} could NOT be attached: createCanonical("${ports.cwd}") failed: ${String(error?.message ?? error)}`;
|
|
42
|
+
ports.diagnostic('attach:createCanonical', reason, error);
|
|
43
|
+
return { attached: false, listed: undefined, warnings: [reason] };
|
|
44
|
+
}
|
|
45
|
+
if (typeof workspace?.attachSession !== 'function') {
|
|
46
|
+
// THE 0.2.x hypothesis: the host reshaped this return. Before this module the optional
|
|
47
|
+
// chain made it a no-op with no word said; now it is a named, diagnosable mismatch.
|
|
48
|
+
const reason = `child ${ports.childId} could NOT be attached: createCanonical returned no "attachSession" method (got ${shape(workspace)}) — the host workspace API changed shape; the child is durable but may not appear in the sidebar`;
|
|
49
|
+
ports.diagnostic('attach:attachSession', reason, `workspace=${shape(workspace)}`);
|
|
50
|
+
return { attached: false, listed: undefined, warnings: [reason] };
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
await workspace.attachSession(ports.childId);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
const reason = `child ${ports.childId} attach was refused: ${String(error?.message ?? error)}`;
|
|
57
|
+
ports.diagnostic('attach:attachSession', reason, error);
|
|
58
|
+
return { attached: false, listed: undefined, warnings: [reason] };
|
|
59
|
+
}
|
|
60
|
+
// Attached. Now the part the throw can't tell us: is it actually LISTED?
|
|
61
|
+
const sq = ports.sessionQuery;
|
|
62
|
+
if (typeof sq?.listSessions !== 'function') {
|
|
63
|
+
return {
|
|
64
|
+
attached: true,
|
|
65
|
+
listed: undefined,
|
|
66
|
+
warnings: [`child ${ports.childId} attached, but its listing is UNVERIFIED — no sessionQuery service to ask`],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const intervalMs = ports.pollIntervalMs ?? 150;
|
|
70
|
+
const budgetMs = ports.pollBudgetMs ?? 1500;
|
|
71
|
+
const deadline = Date.now() + budgetMs;
|
|
72
|
+
for (;;) {
|
|
73
|
+
let ids = [];
|
|
74
|
+
try {
|
|
75
|
+
ids = (await sq.listSessions() ?? []).map((r) => r?.header?.id ?? '');
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
// a failed LOOKUP is not a failed session — say which one happened
|
|
79
|
+
const reason = `child ${ports.childId} attached, but its listing could not be verified: sessionQuery.listSessions failed: ${String(error?.message ?? error)}`;
|
|
80
|
+
ports.diagnostic('attach:verify', reason, error);
|
|
81
|
+
return { attached: true, listed: undefined, warnings: [reason] };
|
|
82
|
+
}
|
|
83
|
+
if (ids.includes(ports.childId)) {
|
|
84
|
+
// Listed by PERSISTENCE is not the same claim as listed to the BROWSER. The gateway's
|
|
85
|
+
// `sessionController.list()` is the surface the client renders and can `open()` against,
|
|
86
|
+
// and on 0.2.0-rc.2 a plugin-created child was present in one and absent from the other
|
|
87
|
+
// (measured: the door's roster note said `MISSING, 1 sessions` while `listSessions`
|
|
88
|
+
// listed it) — so a single boolean would have called that a success.
|
|
89
|
+
const sc = ports.sessionController;
|
|
90
|
+
if (typeof sc?.list !== 'function') {
|
|
91
|
+
// Silence here is what cost a round of the 0.2.x hunt: "no warning" got read as "the
|
|
92
|
+
// gateway lists it". An unverified surface is a STATE and must be delivered as one.
|
|
93
|
+
const reason = `child ${ports.childId} is listed in the durable session corpus, but its presence in the gateway (browser) session list could not be verified — no "sessionController" service to ask`;
|
|
94
|
+
ports.diagnostic('attach:gatewayList', reason, `resolved=${shape(ports.sessionController)}`);
|
|
95
|
+
return { attached: true, listed: true, gatewayListed: undefined, warnings: [reason] };
|
|
96
|
+
}
|
|
97
|
+
let gids = [];
|
|
98
|
+
try {
|
|
99
|
+
gids = (await sc.list() ?? []).map((r) => r?.sessionId ?? r?.header?.id ?? '');
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
const reason = `child ${ports.childId} is listed, but the gateway session list could not be verified: ${String(error?.message ?? error)}`;
|
|
103
|
+
ports.diagnostic('attach:gatewayList', reason, error);
|
|
104
|
+
return { attached: true, listed: true, gatewayListed: undefined, warnings: [reason] };
|
|
105
|
+
}
|
|
106
|
+
if (gids.includes(ports.childId))
|
|
107
|
+
return { attached: true, listed: true, gatewayListed: true, warnings: [] };
|
|
108
|
+
const reason = `child ${ports.childId} is in the durable session list but NOT in the gateway's session list (sessionController.list returned ${String(gids.length)} sessions) — the browser cannot show or open it, so the door will not be able to switch`;
|
|
109
|
+
ports.diagnostic('attach:gatewayList', reason, `gateway=${gids.slice(0, 4).join(',')}`);
|
|
110
|
+
return { attached: true, listed: true, gatewayListed: false, warnings: [reason] };
|
|
111
|
+
}
|
|
112
|
+
if (Date.now() + intervalMs > deadline) {
|
|
113
|
+
const reason = `child ${ports.childId} was attached but does not appear in the session list within ${String(budgetMs)}ms (${String(ids.length)} sessions listed) — the archive is durable; the sidebar may not show it`;
|
|
114
|
+
ports.diagnostic('attach:verify', reason, `listed=${ids.slice(0, 4).join(',')}`);
|
|
115
|
+
return { attached: true, listed: false, warnings: [reason] };
|
|
116
|
+
}
|
|
117
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=attach.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach.js","sourceRoot":"","sources":["../src/attach.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { type SaveSessionConfig } from './save-core.ts';
|
|
2
|
+
import { type SessionEventLike } from './types.ts';
|
|
3
|
+
import type { RegistryStore } from './store.ts';
|
|
4
|
+
/** What `subagent/end` carries — the published `SubagentRunEndInfo` subset we read. */
|
|
5
|
+
export interface SubagentEndInfoLike {
|
|
6
|
+
/** The child agent's id — a durable session id for local (in-process) runs. */
|
|
7
|
+
id?: string;
|
|
8
|
+
runId?: string;
|
|
9
|
+
provider?: string;
|
|
10
|
+
stopReason?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AutoSaveChildHeader {
|
|
13
|
+
id?: string;
|
|
14
|
+
cwd?: string;
|
|
15
|
+
parentSession?: string;
|
|
16
|
+
origin?: string;
|
|
17
|
+
agentPreset?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface AutoSaveChildView {
|
|
20
|
+
events: SessionEventLike[];
|
|
21
|
+
header: AutoSaveChildHeader;
|
|
22
|
+
}
|
|
23
|
+
export interface AutoSaveDeps {
|
|
24
|
+
/** The preset id a child must carry to be archived (CHAPTERS_PRESET_ID in production). */
|
|
25
|
+
presetId: string;
|
|
26
|
+
/** Synchronous live read at emit time (host `agents.get(id)`); undefined when gone. */
|
|
27
|
+
liveChild: (sessionId: string) => AutoSaveChildView | undefined;
|
|
28
|
+
/** Durable fallback when the live handle is gone; undefined when unreadable. */
|
|
29
|
+
durableChild?: ((sessionId: string) => Promise<AutoSaveChildView | undefined>) | undefined;
|
|
30
|
+
/** The archive itself — saveSession in production, injected for containment tests. */
|
|
31
|
+
save: (child: AutoSaveChildView) => Promise<{
|
|
32
|
+
archived: number;
|
|
33
|
+
skipped: string | null;
|
|
34
|
+
warnings: string[];
|
|
35
|
+
}>;
|
|
36
|
+
warn: (message: string) => void;
|
|
37
|
+
/** Observability seam: what each settlement decided. Outcome vocabulary pinned by tests. */
|
|
38
|
+
onSettled?: ((sessionId: string, outcome: string) => void) | undefined;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The listener factory. Pure against injected reads — the real pipeline is wired
|
|
42
|
+
* by `wireSubagentAutoSave` below, and both are covered by
|
|
43
|
+
* tests/{unit,integration} rows. The callback itself is SYNCHRONOUS on the
|
|
44
|
+
* snapshot (that is the race-avoidance), chained asynchronously per child.
|
|
45
|
+
*/
|
|
46
|
+
export declare function makeSubagentEndListener(deps: AutoSaveDeps): (info: SubagentEndInfoLike) => void;
|
|
47
|
+
/** A minimal slice of the host ctx the wiring reads (structural, cordis-free). */
|
|
48
|
+
export interface AutoSaveCtx {
|
|
49
|
+
get?(name: string): unknown;
|
|
50
|
+
logger?: {
|
|
51
|
+
info?(m: string): void;
|
|
52
|
+
warn?(m: string): void;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export interface AutoSaveWiring extends SaveSessionConfig {
|
|
56
|
+
presetId: string;
|
|
57
|
+
/** §5 sync scheduler: every archive is a push point. */
|
|
58
|
+
scheduler?: {
|
|
59
|
+
schedule(cwd: string, reason: string): void;
|
|
60
|
+
} | undefined;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Bind the listener to the host-plane services: `agents` for the live read,
|
|
64
|
+
* `sessionQuery` for the durable fallback, `saveSession` for the archive.
|
|
65
|
+
* Returns the callback to register with `ctx.on('subagent/end', …)`.
|
|
66
|
+
*
|
|
67
|
+
* ENRICHMENT DELIBERATELY ABSENT: settlement never runs the annotator — a
|
|
68
|
+
* ten-child fanout must not fire ten LLM drains; new chapters are pending work
|
|
69
|
+
* for the idle/afterPush ladders exactly like a `/chapters-save` that skipped
|
|
70
|
+
* the manual nudge. A test pins that nothing here calls runNow.
|
|
71
|
+
*/
|
|
72
|
+
/**
|
|
73
|
+
* The ONE payload-bearing durable read (docs/contract.md § Durable reads, issue #58).
|
|
74
|
+
*
|
|
75
|
+
* Door 5 needs it because a continuable child is disposed before `subagent/end`; the repair door
|
|
76
|
+
* (`/chapters-repair`, #60) needs the same thing because re-deriving a chapter is worthless if the read
|
|
77
|
+
* returns metadata rows. Two copies of "read the log" is how 12 children were archived as empty shells
|
|
78
|
+
* and the seam still looked alive: `listEvents` succeeds, returns 10 correctly-typed
|
|
79
|
+
* `SessionEventRecord`s, and none of them has `data`. So this function is exported and pinned by a
|
|
80
|
+
* source-shape row that fails if a door starts reading the log by hand again.
|
|
81
|
+
*/
|
|
82
|
+
export declare function readDurableSession(get: (name: string) => unknown, sessionId: string, onError?: (message: string) => void): Promise<AutoSaveChildView | undefined>;
|
|
83
|
+
/**
|
|
84
|
+
* The seventh archive moment (#61, Amendment A): **a rooted child that has never archived.**
|
|
85
|
+
*
|
|
86
|
+
* Door 5 is keyed on `origin: 'subagent'`. A `ch-*` continuation child is NOT a subagent — its header
|
|
87
|
+
* says `origin: user` with a `parentSession` — so no moment was watching it at all. The field case was
|
|
88
|
+
* `ch-dc3be3ab`: 2,363 events, 414 tool calls, 2 completed turns, `chapters: []`, `reservations: {}`.
|
|
89
|
+
* Not a failed archive: one never attempted. Its knowledge sits in the log and is invisible to every
|
|
90
|
+
* search on the machine, which is precisely what this plugin exists to prevent.
|
|
91
|
+
*
|
|
92
|
+
* This is the PURE gate — the listener below only does I/O, so the decision is testable (and reviewable)
|
|
93
|
+
* without a host.
|
|
94
|
+
*/
|
|
95
|
+
export declare function shouldForceChildArchive(input: {
|
|
96
|
+
header: {
|
|
97
|
+
origin?: string;
|
|
98
|
+
agentPreset?: string;
|
|
99
|
+
parentSession?: string;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Lineage, from ANY of its three real sources — measured 2026-10-22, because the first version of
|
|
103
|
+
* this gate asked the KERNEL HEADER and silently missed the field case: `ch-dc3be3ab` carries
|
|
104
|
+
* `parentSession: NONE, origin: undefined`. Lineage lives in (a) the registry row, which
|
|
105
|
+
* `chapters_continue` writes via `linkChild` at continue-core.ts:520, (b) the header, when the host
|
|
106
|
+
* sets one, and (c) the id itself — `ch-${newId()}` is minted by continue-core.ts:501, so the prefix
|
|
107
|
+
* is OUR OWN durable claim that this session is a continuation child. A row that never archived can
|
|
108
|
+
* still carry the link, and a session with no row at all still carries the prefix.
|
|
109
|
+
*/
|
|
110
|
+
lineageParent?: string | null | undefined;
|
|
111
|
+
chapterCount: number;
|
|
112
|
+
lastArchivedSeq: number;
|
|
113
|
+
anchor: number;
|
|
114
|
+
completedTurnsAboveWatermark: number;
|
|
115
|
+
minTurns: number;
|
|
116
|
+
enabled: boolean;
|
|
117
|
+
}): {
|
|
118
|
+
fire: boolean;
|
|
119
|
+
reason: string;
|
|
120
|
+
};
|
|
121
|
+
export interface ChildArchiveCtx {
|
|
122
|
+
logger?: {
|
|
123
|
+
warn?: (m: string) => void;
|
|
124
|
+
info?: (m: string) => void;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export interface ChildArchiveDeps {
|
|
128
|
+
ctx: ChildArchiveCtx;
|
|
129
|
+
/** A getter, not a value: the realm's store opens asynchronously and once (#61). */
|
|
130
|
+
store: () => Promise<RegistryStore>;
|
|
131
|
+
wiring: AutoSaveWiring;
|
|
132
|
+
/** config `childAutoArchive`, default true — the operator can close this door. */
|
|
133
|
+
enabled: boolean;
|
|
134
|
+
/** config `childAutoArchiveMinTurns`, default 4 — the lag that re-arms it after the first save. */
|
|
135
|
+
minTurns: number;
|
|
136
|
+
onArchived?: (id: string, records: number) => void;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The listener. Save-only — creates NO session and compacts NO surface, so the "no
|
|
140
|
+
* continuation-creating actions mid-step" rule is not engaged (the same reasoning that let door 5
|
|
141
|
+
* exist). Fires only on `turn/end`, reads the LIVE session's own payload-bearing events, and is
|
|
142
|
+
* watermark-idempotent: a re-run finds `nothing-new` and writes nothing.
|
|
143
|
+
*/
|
|
144
|
+
export declare function makeChildArchiveListener(deps: ChildArchiveDeps): (session: unknown, event: unknown) => void;
|
|
145
|
+
export declare function wireSubagentAutoSave(ctx: AutoSaveCtx, store: RegistryStore, wiring: AutoSaveWiring): (info: SubagentEndInfoLike) => void;
|