@cstart/coldstart 2.2.13 → 2.2.15
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/dist/index-manager.d.ts +6 -0
- package/dist/index-manager.d.ts.map +1 -1
- package/dist/index-manager.js +14 -1
- package/dist/index-manager.js.map +1 -1
- package/dist/kb/cli.js +69 -49
- package/dist/kb/cli.js.map +1 -1
- package/dist/kb/durable-worklist.d.ts +18 -0
- package/dist/kb/durable-worklist.d.ts.map +1 -0
- package/dist/kb/durable-worklist.js +121 -0
- package/dist/kb/durable-worklist.js.map +1 -0
- package/dist/kb/repair.d.ts.map +1 -1
- package/dist/kb/repair.js +31 -12
- package/dist/kb/repair.js.map +1 -1
- package/dist/kb/store.d.ts.map +1 -1
- package/dist/kb/store.js +17 -3
- package/dist/kb/store.js.map +1 -1
- package/dist/kb/write-batch.d.ts +21 -0
- package/dist/kb/write-batch.d.ts.map +1 -0
- package/dist/kb/write-batch.js +77 -0
- package/dist/kb/write-batch.js.map +1 -0
- package/dist/kb/write-guide.d.ts.map +1 -1
- package/dist/kb/write-guide.js +17 -9
- package/dist/kb/write-guide.js.map +1 -1
- package/dist/kb/write.d.ts.map +1 -1
- package/dist/kb/write.js +10 -1
- package/dist/kb/write.js.map +1 -1
- package/dist/server/mcp.d.ts +8 -1
- package/dist/server/mcp.d.ts.map +1 -1
- package/dist/server/mcp.js +48 -35
- package/dist/server/mcp.js.map +1 -1
- package/hooks/capture-payload.mjs +56 -28
- package/package.json +1 -1
- package/dist/kb/session-worklist.d.ts +0 -10
- package/dist/kb/session-worklist.d.ts.map +0 -1
- package/dist/kb/session-worklist.js +0 -92
- package/dist/kb/session-worklist.js.map +0 -1
|
@@ -16,8 +16,7 @@
|
|
|
16
16
|
* (the coordinator only sees the final message — #61).
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import { readFileSync, writeFileSync } from "node:fs";
|
|
20
|
-
import { tmpdir } from "node:os";
|
|
19
|
+
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
21
20
|
import { join } from "node:path";
|
|
22
21
|
// The spec shapes are NOT written here any more. They come from the one table
|
|
23
22
|
// the write guide, the MCP tool description and `kb repair` also render from —
|
|
@@ -25,25 +24,36 @@ import { join } from "node:path";
|
|
|
25
24
|
import { shapesBlock } from "./note-shape.mjs";
|
|
26
25
|
|
|
27
26
|
/**
|
|
28
|
-
*
|
|
27
|
+
* Durable capture worklist — the checklist the agent can re-Read at any point.
|
|
29
28
|
*
|
|
30
|
-
* The
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
29
|
+
* The old design dropped the worklist in tmpdir (keyed by session id) and let
|
|
30
|
+
* `kb write --session` print a running "N of M". Two failures: the manifest was
|
|
31
|
+
* scratch that no agent ever read directly, and the whole capture PAYLOAD (this
|
|
32
|
+
* checklist + the write contract) was delivered one-shot and lost to compaction
|
|
33
|
+
* — the agent had to re-derive the note shape from memory 80 tool-calls later.
|
|
35
34
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
35
|
+
* So the pair now lives in the repo notebook, keyed by root, and holds BOTH:
|
|
36
|
+
* .worklist.json structured scope (the coverage source of truth)
|
|
37
|
+
* .worklist.md the full rendered payload — worklist + write contract
|
|
38
|
+
* The agent re-Reads the .md whenever this scrolls away; `kb write` credits and
|
|
39
|
+
* trims/clears the pair (src/kb/durable-worklist.ts) so a stale snapshot never
|
|
40
|
+
* lingers, and the next capture fire regenerates it against live freshness.
|
|
41
|
+
*
|
|
42
|
+
* CONTRACT TWIN: src/kb/durable-worklist.ts — keep the paths and the .json shape
|
|
43
|
+
* (ts, sid, files:[{path,tier,needsNote}], wrote:[]) in step. Both gitignored
|
|
44
|
+
* (src/kb/store.ts initSkeleton). One active worklist per repo (concurrent
|
|
45
|
+
* sessions last-write-wins, an accepted edge). Best-effort: capture must never
|
|
46
|
+
* fail because these could not be written.
|
|
40
47
|
*/
|
|
41
|
-
export function
|
|
42
|
-
return join(
|
|
48
|
+
export function worklistJsonPath(root) {
|
|
49
|
+
return join(root, ".coldstart", "notebook", ".worklist.json");
|
|
50
|
+
}
|
|
51
|
+
export function worklistMdPath(root) {
|
|
52
|
+
return join(root, ".coldstart", "notebook", ".worklist.md");
|
|
43
53
|
}
|
|
44
54
|
|
|
45
|
-
function
|
|
46
|
-
if (!
|
|
55
|
+
function writeDurableWorklist(root, sid, entries, mdBody) {
|
|
56
|
+
if (!root || !entries?.length) return;
|
|
47
57
|
try {
|
|
48
58
|
// needsNote: no note yet, or the note it has is stale. A file whose note is
|
|
49
59
|
// already fresh is NOT an outstanding item — counting it would make full
|
|
@@ -53,7 +63,9 @@ function recordWorklistManifest(sid, entries) {
|
|
|
53
63
|
tier: e.tier,
|
|
54
64
|
needsNote: !e.notes?.length || e.notes.some((n) => n.state === "changed" || n.state === "missing"),
|
|
55
65
|
}));
|
|
56
|
-
|
|
66
|
+
mkdirSync(join(root, ".coldstart", "notebook"), { recursive: true });
|
|
67
|
+
writeFileSync(worklistJsonPath(root), JSON.stringify({ ts: Date.now(), sid, files, wrote: [] }));
|
|
68
|
+
writeFileSync(worklistMdPath(root), mdBody);
|
|
57
69
|
} catch { /* best-effort */ }
|
|
58
70
|
}
|
|
59
71
|
|
|
@@ -101,8 +113,15 @@ function worklistLines(entries) {
|
|
|
101
113
|
return lines.join("\n");
|
|
102
114
|
}
|
|
103
115
|
|
|
104
|
-
export function buildCapturePayload(
|
|
105
|
-
|
|
116
|
+
export function buildCapturePayload(args) {
|
|
117
|
+
const payload = renderCapturePayload(args);
|
|
118
|
+
// Persist the WHOLE payload durably so the agent can re-Read it later, and the
|
|
119
|
+
// structured scope for `kb write` coverage. Best-effort; never blocks capture.
|
|
120
|
+
writeDurableWorklist(args.root, args.sid, args.entries, payload);
|
|
121
|
+
return payload;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function renderCapturePayload({ root, cli, sid, entries, envelope }) {
|
|
106
125
|
const opening = envelope === "block"
|
|
107
126
|
? "Handle capture now, then stop."
|
|
108
127
|
: envelope === "manual"
|
|
@@ -150,9 +169,10 @@ changed and what you had to understand to change it, and that is precisely the k
|
|
|
150
169
|
cold agent lacks. The default for an edited file is a note. Walk the worklist top to bottom \
|
|
151
170
|
and decide each one explicitly; do not stop at the first two or three. If you end up writing \
|
|
152
171
|
notes for well under half the [edited] files, you have under-captured — say which files you \
|
|
153
|
-
skipped and why, so the decision is visible instead of silent.
|
|
154
|
-
|
|
155
|
-
|
|
172
|
+
skipped and why, so the decision is visible instead of silent. This whole checklist (worklist \
|
|
173
|
+
+ the write contract below) is saved at \`.coldstart/notebook/.worklist.md\` — re-Read that file \
|
|
174
|
+
any time this session if this scrolls out of context. Your \`kb write\` call ends with a coverage \
|
|
175
|
+
line naming any worked file still without a note; read it back before you finish.
|
|
156
176
|
|
|
157
177
|
WORKLIST — files you actually read this session, most-worked first:
|
|
158
178
|
|
|
@@ -210,7 +230,11 @@ missing fact is a NEW flow, even in the same subsystem, even across the same fil
|
|
|
210
230
|
an unrelated fact into a nearby flow buries it: nobody searching for your fact will find that \
|
|
211
231
|
title.
|
|
212
232
|
|
|
213
|
-
WRITE —
|
|
233
|
+
WRITE — ONE call: put EVERY note as an object in a JSON array and write the array \
|
|
234
|
+
in a single \`kb write\`. Order flows before the file notes that reference them. Malformed \
|
|
235
|
+
notes are reported together (a bad note never silences a good one), and the call ends with \
|
|
236
|
+
the coverage line. Forming an array is fewer tokens than chaining, not more — same JSON, \
|
|
237
|
+
without the per-note heredoc and && glue.
|
|
214
238
|
${shapesBlock({ compact: true })}
|
|
215
239
|
"identityAliases" and "symbols" are what make a note FINDABLE and both go missing by \
|
|
216
240
|
default: a note without identityAliases is reachable only by its exact title, and agents \
|
|
@@ -227,14 +251,18 @@ however carefully you described it. Never write a flow using the file-note shape
|
|
|
227
251
|
with several of its symbols. file-hub is ONLY for grab-bag files that have no single purpose \
|
|
228
252
|
(models.py, utils, helpers) — there, knowledge lives per symbol. Touching many symbols does \
|
|
229
253
|
not make a file a hub; having no one purpose does.
|
|
230
|
-
Update = the same spec plus "id":"<id from the worklist>".
|
|
231
|
-
|
|
232
|
-
|
|
254
|
+
Update = the same spec plus "id":"<id from the worklist>". Retract a note you \
|
|
255
|
+
found wrong: {"op":"retract","id":"<id>","target":{"kind":"note"}} (as one array element).
|
|
256
|
+
cat > /tmp/notes.json <<'JSON'
|
|
257
|
+
[ {…note 1…}, {…note 2…} ]
|
|
258
|
+
JSON
|
|
259
|
+
node ${cli} kb write /tmp/notes.json --root ${root} --session ${sid} --force
|
|
260
|
+
Full shapes: run \`node ${cli} kb write --root ${root}\` with no spec — it prints the guide.
|
|
233
261
|
|
|
234
262
|
FLOW DECISION — record what you decided about FLOWS (created a new one, folded into an \
|
|
235
|
-
existing one, or none) so the flow gate can be measured. Ride it on
|
|
263
|
+
existing one, or none) so the flow gate can be measured. Ride it on the SAME batch write — it \
|
|
236
264
|
is a flag, not a second command:
|
|
237
|
-
node ${cli} kb write /tmp/
|
|
265
|
+
node ${cli} kb write /tmp/notes.json --root ${root} --session ${sid} --force \\
|
|
238
266
|
--decision <none|new|update> [--id <flow id>] --why "<one clause>"
|
|
239
267
|
Only when you wrote NO notes at all is there no write to carry it, and then run it alone:
|
|
240
268
|
node ${cli} kb flow-decision --decision none --why "<one clause>" --root ${root} --session ${sid}${tail}`;
|
package/package.json
CHANGED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/** Paths this spec puts a note on. Flow steps do NOT count: a flow verifies
|
|
2
|
-
* files, it does not give any of them the file note rule 5 asks for. */
|
|
3
|
-
export declare function specPaths(spec: unknown): string[];
|
|
4
|
-
/**
|
|
5
|
-
* Record this write against the session worklist and return the coverage line
|
|
6
|
-
* to print, or null when there is no manifest to compare against (no --session,
|
|
7
|
-
* a manual `kb write` outside capture, a session that never armed).
|
|
8
|
-
*/
|
|
9
|
-
export declare function noteCoverage(sid: string | undefined, spec: unknown): string | null;
|
|
10
|
-
//# sourceMappingURL=session-worklist.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-worklist.d.ts","sourceRoot":"","sources":["../../src/kb/session-worklist.ts"],"names":[],"mappings":"AA8CA;yEACyE;AACzE,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE,CAIjD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CA8BlF"}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Capture coverage — telling the writing agent how much of its worklist it noted.
|
|
3
|
-
*
|
|
4
|
-
* The gap this closes: the capture checklist hands the agent a worklist of every
|
|
5
|
-
* file it worked on, but `kb write` only ever sees ONE spec, so nothing could
|
|
6
|
-
* report "you wrote 8 notes for 30 worked files". The agent's own count is the
|
|
7
|
-
* one thing it cannot check — it is mid-heredoc, and under-capture is silent by
|
|
8
|
-
* construction. So the hook drops the worklist in tmpdir when it builds the
|
|
9
|
-
* capture prompt, and every `kb write --session <sid>` prints the running ratio.
|
|
10
|
-
*
|
|
11
|
-
* CONTRACT TWIN: hooks/capture-payload.mjs (worklistManifestPath) writes this
|
|
12
|
-
* file; keep the name and shape in step. Everything here is best-effort — a
|
|
13
|
-
* missing, stale or malformed manifest prints nothing and never fails a write.
|
|
14
|
-
*
|
|
15
|
-
* Local only. The manifest lives in tmpdir, never in the repo: it is scratch
|
|
16
|
-
* state for one session, not a record, and nothing about it is transmitted.
|
|
17
|
-
*/
|
|
18
|
-
import { readFileSync, writeFileSync } from 'node:fs';
|
|
19
|
-
import { tmpdir } from 'node:os';
|
|
20
|
-
import { join } from 'node:path';
|
|
21
|
-
/** Manifests older than this are a resumed/unrelated session — ignore them. */
|
|
22
|
-
const MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
23
|
-
/** Below this share of outstanding files, name the skips. */
|
|
24
|
-
const LOW_COVERAGE = 0.5;
|
|
25
|
-
const LIST_MAX = 6;
|
|
26
|
-
function manifestPath(sid) {
|
|
27
|
-
return join(tmpdir(), `coldstart-kb-worklist-${sid}.json`);
|
|
28
|
-
}
|
|
29
|
-
function load(sid) {
|
|
30
|
-
try {
|
|
31
|
-
const m = JSON.parse(readFileSync(manifestPath(sid), 'utf8'));
|
|
32
|
-
if (!Array.isArray(m?.files) || !m.files.length)
|
|
33
|
-
return null;
|
|
34
|
-
if (typeof m.ts === 'number' && Date.now() - m.ts > MAX_AGE_MS)
|
|
35
|
-
return null;
|
|
36
|
-
m.wrote = Array.isArray(m.wrote) ? m.wrote : [];
|
|
37
|
-
return m;
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
/** Paths this spec puts a note on. Flow steps do NOT count: a flow verifies
|
|
44
|
-
* files, it does not give any of them the file note rule 5 asks for. */
|
|
45
|
-
export function specPaths(spec) {
|
|
46
|
-
const s = spec;
|
|
47
|
-
if (!s || typeof s.path !== 'string')
|
|
48
|
-
return [];
|
|
49
|
-
return s.type === 'file-single' || s.type === 'file-hub' ? [s.path] : [];
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Record this write against the session worklist and return the coverage line
|
|
53
|
-
* to print, or null when there is no manifest to compare against (no --session,
|
|
54
|
-
* a manual `kb write` outside capture, a session that never armed).
|
|
55
|
-
*/
|
|
56
|
-
export function noteCoverage(sid, spec) {
|
|
57
|
-
if (!sid)
|
|
58
|
-
return null;
|
|
59
|
-
const m = load(sid);
|
|
60
|
-
if (!m)
|
|
61
|
-
return null;
|
|
62
|
-
for (const p of specPaths(spec))
|
|
63
|
-
if (!m.wrote.includes(p))
|
|
64
|
-
m.wrote.push(p);
|
|
65
|
-
try {
|
|
66
|
-
writeFileSync(manifestPath(sid), JSON.stringify(m));
|
|
67
|
-
}
|
|
68
|
-
catch { /* best-effort */ }
|
|
69
|
-
const outstanding = m.files.filter((f) => f.needsNote);
|
|
70
|
-
if (!outstanding.length)
|
|
71
|
-
return null;
|
|
72
|
-
const wrote = new Set(m.wrote);
|
|
73
|
-
const done = outstanding.filter((f) => wrote.has(f.path));
|
|
74
|
-
const left = outstanding.filter((f) => !wrote.has(f.path));
|
|
75
|
-
const already = m.files.length - outstanding.length;
|
|
76
|
-
const lines = [
|
|
77
|
-
`capture coverage: ${done.length} of ${outstanding.length} worklist files noted` +
|
|
78
|
-
(already ? ` (${already} more already had a fresh note)` : ''),
|
|
79
|
-
];
|
|
80
|
-
if (left.length) {
|
|
81
|
-
const shown = left.slice(0, LIST_MAX).map((f) => `${f.path} [${f.tier}]`).join(', ');
|
|
82
|
-
lines.push(` not noted yet: ${shown}${left.length > LIST_MAX ? `, +${left.length - LIST_MAX} more` : ''}`);
|
|
83
|
-
}
|
|
84
|
-
// The nudge fires only on the low end, and asks for a REASON rather than more
|
|
85
|
-
// notes: a deliberate skip is a fine answer, an invisible one is not. Chained
|
|
86
|
-
// writes each print this, so the last line of the block carries the real tally.
|
|
87
|
-
if (left.length && done.length / outstanding.length < LOW_COVERAGE) {
|
|
88
|
-
lines.push(' if those need no note, say which and why in your reply — an unexplained skip reads as a forgotten one.');
|
|
89
|
-
}
|
|
90
|
-
return lines.join('\n');
|
|
91
|
-
}
|
|
92
|
-
//# sourceMappingURL=session-worklist.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-worklist.js","sourceRoot":"","sources":["../../src/kb/session-worklist.ts"],"names":[],"mappings":"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"}
|