@dzhechkov/harness-core 0.8.30 → 0.8.31
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/.dz-manifest.json +233 -93
- package/README.md +269 -0
- package/dist/agentdb-index.d.ts +45 -0
- package/dist/agentdb-index.d.ts.map +1 -1
- package/dist/agentdb-index.js +345 -85
- package/dist/agentdb-index.js.map +1 -1
- package/dist/agentdb-reindex-marker.d.ts +170 -0
- package/dist/agentdb-reindex-marker.d.ts.map +1 -0
- package/dist/agentdb-reindex-marker.js +293 -0
- package/dist/agentdb-reindex-marker.js.map +1 -0
- package/dist/agentdb-snapshot-rotation.d.ts +169 -0
- package/dist/agentdb-snapshot-rotation.d.ts.map +1 -0
- package/dist/agentdb-snapshot-rotation.js +322 -0
- package/dist/agentdb-snapshot-rotation.js.map +1 -0
- package/dist/agentdb-snapshot.d.ts +126 -0
- package/dist/agentdb-snapshot.d.ts.map +1 -0
- package/dist/agentdb-snapshot.js +195 -0
- package/dist/agentdb-snapshot.js.map +1 -0
- package/dist/apply-leg.d.ts +202 -0
- package/dist/apply-leg.d.ts.map +1 -0
- package/dist/apply-leg.js +975 -0
- package/dist/apply-leg.js.map +1 -0
- package/dist/book-kb.d.ts.map +1 -1
- package/dist/book-kb.js +57 -1
- package/dist/book-kb.js.map +1 -1
- package/dist/brain.d.ts +3 -0
- package/dist/brain.d.ts.map +1 -1
- package/dist/brain.js +1 -1
- package/dist/brain.js.map +1 -1
- package/dist/cadence.d.ts +30 -1
- package/dist/cadence.d.ts.map +1 -1
- package/dist/cadence.js +66 -2
- package/dist/cadence.js.map +1 -1
- package/dist/guard.d.ts +14 -0
- package/dist/guard.d.ts.map +1 -1
- package/dist/guard.js +36 -0
- package/dist/guard.js.map +1 -1
- package/dist/index.d.ts +23 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -5
- package/dist/index.js.map +1 -1
- package/dist/integration-probe-worker.d.ts.map +1 -1
- package/dist/integration-probe-worker.js +4 -6
- package/dist/integration-probe-worker.js.map +1 -1
- package/dist/integrations-verify.d.ts.map +1 -1
- package/dist/integrations-verify.js +3 -1
- package/dist/integrations-verify.js.map +1 -1
- package/dist/managed-hooks.d.ts +11 -2
- package/dist/managed-hooks.d.ts.map +1 -1
- package/dist/managed-hooks.js +33 -7
- package/dist/managed-hooks.js.map +1 -1
- package/dist/mutation-gate.d.ts +35 -1
- package/dist/mutation-gate.d.ts.map +1 -1
- package/dist/mutation-gate.js +49 -9
- package/dist/mutation-gate.js.map +1 -1
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +94 -0
- package/dist/operations.js.map +1 -1
- package/dist/patterns.d.ts.map +1 -1
- package/dist/patterns.js +23 -4
- package/dist/patterns.js.map +1 -1
- package/dist/repository-origin.d.ts +1 -1
- package/dist/repository-origin.d.ts.map +1 -1
- package/dist/repository-origin.js +7 -1
- package/dist/repository-origin.js.map +1 -1
- package/dist/round-exec.d.ts +41 -0
- package/dist/round-exec.d.ts.map +1 -0
- package/dist/round-exec.js +45 -0
- package/dist/round-exec.js.map +1 -0
- package/dist/round.d.ts +109 -0
- package/dist/round.d.ts.map +1 -0
- package/dist/round.js +148 -0
- package/dist/round.js.map +1 -0
- package/dist/run-records.d.ts +8 -0
- package/dist/run-records.d.ts.map +1 -1
- package/dist/run-records.js +69 -3
- package/dist/run-records.js.map +1 -1
- package/dist/setup.d.ts +8 -0
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +166 -3
- package/dist/setup.js.map +1 -1
- package/dist/sqlite-read-helpers.d.ts +60 -0
- package/dist/sqlite-read-helpers.d.ts.map +1 -0
- package/dist/sqlite-read-helpers.js +118 -0
- package/dist/sqlite-read-helpers.js.map +1 -0
- package/dist/statusline.d.ts +20 -3
- package/dist/statusline.d.ts.map +1 -1
- package/dist/statusline.js +40 -7
- package/dist/statusline.js.map +1 -1
- package/dist/store-counts.d.ts +30 -0
- package/dist/store-counts.d.ts.map +1 -1
- package/dist/store-counts.js +189 -0
- package/dist/store-counts.js.map +1 -1
- package/dist/usage.d.ts +55 -0
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js +184 -33
- package/dist/usage.js.map +1 -1
- package/dist/vector-tier.d.ts +18 -1
- package/dist/vector-tier.d.ts.map +1 -1
- package/dist/vector-tier.js +26 -2
- package/dist/vector-tier.js.map +1 -1
- package/package.json +6 -6
- package/sbom.json +442 -92
- package/src/agentdb-index.ts +315 -32
- package/src/agentdb-reindex-marker.ts +330 -0
- package/src/agentdb-snapshot-rotation.ts +393 -0
- package/src/agentdb-snapshot.ts +222 -0
- package/src/apply-leg.ts +1046 -0
- package/src/book-kb.ts +64 -1
- package/src/brain.ts +11 -2
- package/src/cadence.ts +87 -2
- package/src/guard.ts +46 -0
- package/src/index.ts +58 -5
- package/src/integration-probe-worker.ts +4 -6
- package/src/integrations-verify.ts +3 -1
- package/src/managed-hooks.ts +32 -7
- package/src/mutation-gate.ts +87 -8
- package/src/operations.ts +89 -0
- package/src/patterns.ts +23 -4
- package/src/repository-origin.ts +7 -1
- package/src/round-exec.ts +85 -0
- package/src/round.ts +228 -0
- package/src/run-records.ts +77 -2
- package/src/setup.ts +198 -3
- package/src/sqlite-read-helpers.ts +128 -0
- package/src/statusline.ts +57 -9
- package/src/store-counts.ts +245 -1
- package/src/usage.ts +243 -29
- package/src/vector-tier.ts +45 -4
package/dist/round.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A focused work round. The module owns decisions only: callers inject observed state, time,
|
|
3
|
+
* lesson ids, ledger writing/reading and pid liveness. In particular, this file never imports a
|
|
4
|
+
* filesystem or process API; the CLI owns `.dz/rounds/` and the witnessed ledger writer.
|
|
5
|
+
*/
|
|
6
|
+
const ROUND_OUTCOMES = ['shipped', 'refuted', 'blocked', 'abandoned'];
|
|
7
|
+
function nonEmpty(value) {
|
|
8
|
+
return typeof value === 'string' && value.trim() !== '';
|
|
9
|
+
}
|
|
10
|
+
function validSlug(value) {
|
|
11
|
+
return /^[a-z0-9][a-z0-9._-]*$/i.test(value);
|
|
12
|
+
}
|
|
13
|
+
function validCount(value) {
|
|
14
|
+
return value === undefined || (Number.isInteger(value) && value >= 0);
|
|
15
|
+
}
|
|
16
|
+
export function openRound(input) {
|
|
17
|
+
if (!validSlug(input.slug) || !Number.isInteger(input.round) || input.round < 1 || !nonEmpty(input.topic)) {
|
|
18
|
+
return { ok: false, exit: 2, reason: 'нужны безопасный --slug, положительный --round и непустой --topic' };
|
|
19
|
+
}
|
|
20
|
+
const runOwner = input.ownerKind === 'run';
|
|
21
|
+
if (!Number.isFinite(Date.parse(input.startedAt)) || !Number.isInteger(input.ownerPid)
|
|
22
|
+
|| (runOwner ? input.ownerPid !== 0 || !nonEmpty(input.ownerRun) : input.ownerPid < 1)
|
|
23
|
+
|| (!runOwner && input.ownerKind !== 'explicit' && input.ownerKind !== 'parent')) {
|
|
24
|
+
return { ok: false, exit: 2, reason: 'время начала или pid круга недопустимы' };
|
|
25
|
+
}
|
|
26
|
+
const state = {
|
|
27
|
+
slug: input.slug,
|
|
28
|
+
round: input.round,
|
|
29
|
+
topic: input.topic.trim(),
|
|
30
|
+
startedAt: input.startedAt,
|
|
31
|
+
pid: input.ownerPid,
|
|
32
|
+
ownerKind: input.ownerKind,
|
|
33
|
+
...(runOwner ? { ownerRun: input.ownerRun.trim() } : {}),
|
|
34
|
+
...(nonEmpty(input.run) ? { run: input.run.trim() } : {}),
|
|
35
|
+
recalled: [...input.recalled],
|
|
36
|
+
};
|
|
37
|
+
let existingOwnerAlive = input.existingOwnerAlive;
|
|
38
|
+
if (input.existing?.ownerKind === 'run' && input.force) {
|
|
39
|
+
try {
|
|
40
|
+
existingOwnerAlive = nonEmpty(input.existing.ownerRun) ? input.isRunAlive(input.existing.ownerRun) : null;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
existingOwnerAlive = null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (input.existing !== null && input.force && existingOwnerAlive === false) {
|
|
47
|
+
return { ok: true, archiveExisting: true, state };
|
|
48
|
+
}
|
|
49
|
+
if (input.existing !== null && input.force) {
|
|
50
|
+
return {
|
|
51
|
+
ok: false,
|
|
52
|
+
exit: 1,
|
|
53
|
+
reason: input.existing.ownerKind === 'run'
|
|
54
|
+
? `круг открыт живым прогоном ${input.existing.ownerRun ?? 'unknown'}, --force не перезаписывает живой круг`
|
|
55
|
+
: `круг открыт живым процессом ${input.existing.pid}, --force не перезаписывает живой круг`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (input.existing !== null)
|
|
59
|
+
return { ok: false, exit: 1, reason: 'круг уже открыт' };
|
|
60
|
+
return { ok: true, archiveExisting: false, state };
|
|
61
|
+
}
|
|
62
|
+
export function closeRound(input, io) {
|
|
63
|
+
if (!ROUND_OUTCOMES.includes(input.outcome)) {
|
|
64
|
+
return { ok: false, exit: 2, reason: '--outcome: shipped | refuted | blocked | abandoned' };
|
|
65
|
+
}
|
|
66
|
+
if (!validCount(input.tokens) || !validCount(input.agents)) {
|
|
67
|
+
return { ok: false, exit: 2, reason: '--tokens и --agents должны быть целыми числами не меньше нуля' };
|
|
68
|
+
}
|
|
69
|
+
const lessons = [...new Set(input.lessons ?? [])];
|
|
70
|
+
const noNewKnowledge = input.noNewKnowledge?.trim() ?? '';
|
|
71
|
+
if (lessons.length === 0 && noNewKnowledge === '') {
|
|
72
|
+
return { ok: false, exit: 1, reason: 'урок не назван: передайте --lesson teach:<id> или --no-new-knowledge "<почему>"' };
|
|
73
|
+
}
|
|
74
|
+
if (lessons.length > 0 && noNewKnowledge !== '') {
|
|
75
|
+
return { ok: false, exit: 1, reason: '--lesson и --no-new-knowledge взаимоисключающие' };
|
|
76
|
+
}
|
|
77
|
+
const known = new Set(input.knownLessonIds);
|
|
78
|
+
const missing = lessons.find((id) => !/^teach:[a-z0-9]+$/i.test(id) || !known.has(id));
|
|
79
|
+
if (missing !== undefined)
|
|
80
|
+
return { ok: false, exit: 1, reason: `урок не найден: ${missing}` };
|
|
81
|
+
const startedMs = Date.parse(input.state.startedAt);
|
|
82
|
+
const closedMs = Date.parse(input.closedAt);
|
|
83
|
+
if (!Number.isFinite(startedMs) || !Number.isFinite(closedMs) || closedMs < startedMs) {
|
|
84
|
+
return { ok: false, exit: 1, reason: 'длительность круга не установлена: время состояния недопустимо' };
|
|
85
|
+
}
|
|
86
|
+
const compactTs = new Date(closedMs).toISOString().replace(/[-:.]/g, '');
|
|
87
|
+
const marker = `round-${input.state.slug}-${input.state.round}-${compactTs}`;
|
|
88
|
+
const note = input.note?.trim() ?? '';
|
|
89
|
+
const row = {
|
|
90
|
+
slug: input.state.slug,
|
|
91
|
+
stage: 'round',
|
|
92
|
+
tier: null,
|
|
93
|
+
coder: nonEmpty(input.coder) ? input.coder.trim() : null,
|
|
94
|
+
reviewer: nonEmpty(input.reviewer) ? input.reviewer.trim() : null,
|
|
95
|
+
lead: null,
|
|
96
|
+
minutes: input.noCost === true ? null : Math.floor((closedMs - startedMs) / 60_000),
|
|
97
|
+
agents: input.noCost === true ? null : input.agents ?? null,
|
|
98
|
+
tokens: input.noCost === true ? null : input.tokens ?? null,
|
|
99
|
+
grade: null,
|
|
100
|
+
outcome: input.outcome,
|
|
101
|
+
reason: nonEmpty(input.reason) ? input.reason.trim() : null,
|
|
102
|
+
round: input.state.round,
|
|
103
|
+
lessons,
|
|
104
|
+
noNewKnowledge: noNewKnowledge === '' ? null : noNewKnowledge,
|
|
105
|
+
note: note === '' ? marker : `${marker} | ${note}`,
|
|
106
|
+
date: null,
|
|
107
|
+
...(input.noCost === true ? { costIn: 'stages' } : {}),
|
|
108
|
+
...(nonEmpty(input.stateId) ? { stateId: input.stateId } : {}),
|
|
109
|
+
};
|
|
110
|
+
try {
|
|
111
|
+
io.writeLedger(row);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return { ok: false, exit: 1, reason: 'строка не найдена — круг НЕ закрыт (писатель отказал)' };
|
|
115
|
+
}
|
|
116
|
+
let tail = '';
|
|
117
|
+
try {
|
|
118
|
+
tail = io.readLedgerTail();
|
|
119
|
+
}
|
|
120
|
+
catch { /* unreadable is absence of a receipt */ }
|
|
121
|
+
if (!tail.includes(marker)) {
|
|
122
|
+
return { ok: false, exit: 1, reason: 'строка не найдена — круг НЕ закрыт' };
|
|
123
|
+
}
|
|
124
|
+
return { ok: true, row, marker };
|
|
125
|
+
}
|
|
126
|
+
export function listRounds(states, input) {
|
|
127
|
+
if (!Number.isFinite(input.now) || !Number.isFinite(input.olderThanMinutes) || input.olderThanMinutes < 0)
|
|
128
|
+
return [];
|
|
129
|
+
const rows = [];
|
|
130
|
+
for (const state of states) {
|
|
131
|
+
const startedMs = Date.parse(state.startedAt);
|
|
132
|
+
if (!Number.isFinite(startedMs))
|
|
133
|
+
continue;
|
|
134
|
+
const ageMinutes = Math.max(0, Math.floor((input.now - startedMs) / 60_000));
|
|
135
|
+
if (ageMinutes <= input.olderThanMinutes)
|
|
136
|
+
continue;
|
|
137
|
+
let pidAlive = null;
|
|
138
|
+
try {
|
|
139
|
+
pidAlive = state.ownerKind === 'run'
|
|
140
|
+
? input.isRunAlive(state.ownerRun ?? '')
|
|
141
|
+
: input.isPidAlive(state.pid);
|
|
142
|
+
}
|
|
143
|
+
catch { /* an unavailable probe is unknown */ }
|
|
144
|
+
rows.push({ state, ageMinutes, pidAlive });
|
|
145
|
+
}
|
|
146
|
+
return rows.sort((a, b) => b.ageMinutes - a.ageMinutes || a.state.slug.localeCompare(b.state.slug) || a.state.round - b.state.round);
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=round.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"round.js","sourceRoot":"","sources":["../src/round.ts"],"names":[],"mappings":"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"}
|
package/dist/run-records.d.ts
CHANGED
|
@@ -57,6 +57,14 @@ export declare function decideRecordWrite(input: {
|
|
|
57
57
|
targetHasPair?: boolean;
|
|
58
58
|
/** Stamped INTO the object before serialising — never rewritten in the shell afterwards (FR-7). */
|
|
59
59
|
timestamp?: string | null;
|
|
60
|
+
/**
|
|
61
|
+
* ledger-stage-minutes FR-2/FR-3: the `ts` of the LAST ledger row that shares this row's `runId`,
|
|
62
|
+
* found by the CALLER (the CLI reads the file; this function stays pure). Absent/null means "no
|
|
63
|
+
* such row, or it had no `ts`" — both collapse to the same honest `unavailable`, never a guess.
|
|
64
|
+
*/
|
|
65
|
+
previousRowTs?: string | null;
|
|
66
|
+
/** The runId this row WILL carry after write-time resolution, when the payload itself has none. */
|
|
67
|
+
effectiveRunId?: string | null;
|
|
60
68
|
/** Who ran it. Supplied by the CALLER, which lives outside the workflow sandbox and can see the
|
|
61
69
|
* host; absent stays absent (see the stamping comment below). */
|
|
62
70
|
runnerId?: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-records.d.ts","sourceRoot":"","sources":["../src/run-records.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,eAAe,CAAC;AAEpD,MAAM,MAAM,aAAa;AACvB,gDAAgD;AAC9C,SAAS;AACX,+EAA+E;GAC7E,WAAW;AACb,yEAAyE;GACvE,SAAS;AACX,yEAAyE;GACvE,SAAS;AACX,kGAAkG;GAChG,cAAc,CAAC;AAEnB,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,2FAA2F;AAC3F,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAoD5C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,IAAI,EAAE,UAAU,CAAC;IACjB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,+FAA+F;IAC/F,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,kGAAkG;IAClG,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gGAAgG;IAChG,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0CAA0C;IAC1C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,mGAAmG;IACnG,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;sEACkE;IAClE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"run-records.d.ts","sourceRoot":"","sources":["../src/run-records.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,eAAe,CAAC;AAEpD,MAAM,MAAM,aAAa;AACvB,gDAAgD;AAC9C,SAAS;AACX,+EAA+E;GAC7E,WAAW;AACb,yEAAyE;GACvE,SAAS;AACX,yEAAyE;GACvE,SAAS;AACX,kGAAkG;GAChG,cAAc,CAAC;AAEnB,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,2FAA2F;AAC3F,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAoD5C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,IAAI,EAAE,UAAU,CAAC;IACjB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,+FAA+F;IAC/F,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,kGAAkG;IAClG,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gGAAgG;IAChG,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0CAA0C;IAC1C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,mGAAmG;IACnG,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,mGAAmG;IACnG,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;sEACkE;IAClE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,cAAc,CAyKjB;AAED,gHAAgH;AAChH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,cAAc,CAoB9F;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,MAAM,CAE5F"}
|
package/dist/run-records.js
CHANGED
|
@@ -117,15 +117,13 @@ export function decideRecordWrite(input) {
|
|
|
117
117
|
// inside an already-serialised document — text surgery on a structured value, and the exact place
|
|
118
118
|
// a payload containing that literal token could corrupt itself.
|
|
119
119
|
const stamped = { ...obj };
|
|
120
|
+
const isGap = (v) => v === null || v === undefined || (typeof v === 'string' && v.trim() === '');
|
|
120
121
|
if (input.timestamp != null && input.timestamp !== '') {
|
|
121
122
|
// An EMPTY STRING is a gap, not a value. Stamping only over null/undefined let
|
|
122
123
|
// `"date":""` through as `written` (cross-family review, 2026-08-21) — a row that looks recorded
|
|
123
124
|
// and carries no date.
|
|
124
|
-
const isGap = (v) => v === null || v === undefined || (typeof v === 'string' && v.trim() === '');
|
|
125
125
|
if (kind === 'ledger' && isGap(stamped['date']))
|
|
126
126
|
stamped['date'] = input.timestamp.slice(0, 10);
|
|
127
|
-
if (kind === 'training-pair' && isGap(stamped['ts']))
|
|
128
|
-
stamped['ts'] = input.timestamp;
|
|
129
127
|
}
|
|
130
128
|
// WHO ran this. Stamped HERE and nowhere else, for a structural reason: the workflow lives in a
|
|
131
129
|
// sandbox with no host, no process and no clock, so it cannot name its own runner — but this
|
|
@@ -138,9 +136,77 @@ export function decideRecordWrite(input) {
|
|
|
138
136
|
// because a fabricated identity is worse than a missing one for anything that later joins on it.
|
|
139
137
|
// A blank supplied id is a gap too: `' '` sneaking in as a value would join later as a distinct
|
|
140
138
|
// runner made of spaces — the same class of harm as inventing 'unknown'.
|
|
139
|
+
//
|
|
140
|
+
// Stamped BEFORE `ts` below (fix-round-1/AM-n, cross-family review B): a runnerId this call itself
|
|
141
|
+
// adds is still an ESTABLISHED field, from the runnerId feature that shipped before
|
|
142
|
+
// ledger-stage-minutes — NFR-1's "new fields land after everything else" is a promise about the
|
|
143
|
+
// fields THIS feature introduces (`ts`, `minutesSincePrev`, `minutesSource`), not about the order
|
|
144
|
+
// decideRecordWrite happens to run its own blocks in. The original order stamped `ts` first, so a
|
|
145
|
+
// freshly-added runnerId landed AFTER it — an object key order a `--full-qe-extended` Codex review
|
|
146
|
+
// (grade B) caught by diffing `Object.keys` against the documented convention.
|
|
141
147
|
if (kind === 'ledger' && isRunnerGap(stamped['runnerId']) && !isRunnerGap(input.runnerId)) {
|
|
142
148
|
stamped['runnerId'] = input.runnerId.trim();
|
|
143
149
|
}
|
|
150
|
+
if (input.timestamp != null && input.timestamp !== '') {
|
|
151
|
+
// FR-1 (ledger-stage-minutes): every ledger row also gets the FULL ISO instant it was recorded,
|
|
152
|
+
// next to `date` — `date` alone cannot answer "how long between two rows of this run", `ts` can.
|
|
153
|
+
//
|
|
154
|
+
// fix-round-1/AM-n (cross-family review B): `ts` is ALWAYS the instant of THIS write, never a
|
|
155
|
+
// value the payload happened to bring in — the delta below measures from `ts`, and a caller-
|
|
156
|
+
// supplied instant (stale, forged, or simply wrong) would silently become "now" for that
|
|
157
|
+
// measurement. The original `isGap` check let a non-empty payload `ts` survive untouched, which
|
|
158
|
+
// is exactly the value a clock-skewed or replayed payload could poison. No data is discarded: a
|
|
159
|
+
// real payload `ts` is kept, renamed to `payloadTs`, so the row still says what the caller claimed
|
|
160
|
+
// — just not under the name the delta trusts.
|
|
161
|
+
if (kind === 'ledger') {
|
|
162
|
+
const payloadTs = stamped['ts'];
|
|
163
|
+
// Lead edit after re-review (Codex B): never clobber a `payloadTs` the caller already carries,
|
|
164
|
+
// and re-insert `ts` so it lands LAST even when the payload brought its own `ts` key
|
|
165
|
+
// (assigning an existing property keeps its old insertion position).
|
|
166
|
+
if (!isGap(payloadTs) && isGap(stamped['payloadTs']))
|
|
167
|
+
stamped['payloadTs'] = payloadTs;
|
|
168
|
+
delete stamped['ts'];
|
|
169
|
+
stamped['ts'] = input.timestamp;
|
|
170
|
+
}
|
|
171
|
+
if (kind === 'training-pair' && isGap(stamped['ts']))
|
|
172
|
+
stamped['ts'] = input.timestamp;
|
|
173
|
+
}
|
|
174
|
+
// FR-2 (ledger-stage-minutes): the writer cannot measure a stage's full duration — the workflow
|
|
175
|
+
// sandbox has no clock (`Date.now()` is banned there for resume-safety) — but it DOES know the
|
|
176
|
+
// moment of every write and the run each write belongs to. For an `auto:true` row that carries a
|
|
177
|
+
// `runId`, the gap since the PREVIOUS row of the same run is a real, partial measurement, and it
|
|
178
|
+
// gets its own named field and source rather than being folded into (or mistaken for) `minutes`
|
|
179
|
+
// — "a claim exactly as strong as its inputs" (lesson, repeated 2026-08-25/2026-09-12): a partial
|
|
180
|
+
// quantity is reported as itself, tagged with where it came from, never smuggled into a field that
|
|
181
|
+
// implies the whole. `minutes` is left untouched by this block — it stays whatever the payload
|
|
182
|
+
// already carried (null for every auto row today).
|
|
183
|
+
if (kind === 'ledger') {
|
|
184
|
+
const runIdVal = stamped['runId'];
|
|
185
|
+
// Lead edit after re-review (Codex B): the pipeline's own rows carry NO runId in the payload —
|
|
186
|
+
// the CLI resolves it at write time (`resolved-at-write`) — so the caller may hand the resolved
|
|
187
|
+
// id in as `effectiveRunId`; the delta is measurable for those rows too.
|
|
188
|
+
const effectiveRunId = typeof input.effectiveRunId === 'string' && input.effectiveRunId.trim() !== '' ? input.effectiveRunId : null;
|
|
189
|
+
const hasRunId = (typeof runIdVal === 'string' && runIdVal.trim() !== '') || effectiveRunId !== null;
|
|
190
|
+
if (stamped['auto'] === true && hasRunId) {
|
|
191
|
+
const nowTs = typeof stamped['ts'] === 'string' && stamped['ts'].trim() !== '' ? stamped['ts'] : null;
|
|
192
|
+
const prevTs = typeof input.previousRowTs === 'string' && input.previousRowTs.trim() !== '' ? input.previousRowTs : null;
|
|
193
|
+
let minutesSincePrev = null;
|
|
194
|
+
let minutesSource = 'unavailable';
|
|
195
|
+
if (nowTs !== null && prevTs !== null) {
|
|
196
|
+
const nowMs = Date.parse(nowTs);
|
|
197
|
+
const prevMs = Date.parse(prevTs);
|
|
198
|
+
// Absence of a receipt is not success: an unparseable timestamp or a previous row that is
|
|
199
|
+
// somehow LATER than this one (clock skew, out-of-order backfill) must not be reported as a
|
|
200
|
+
// measured value — it stays `unavailable`, never a fabricated or negative minute count.
|
|
201
|
+
if (Number.isFinite(nowMs) && Number.isFinite(prevMs) && nowMs >= prevMs) {
|
|
202
|
+
minutesSincePrev = Math.round(((nowMs - prevMs) / 60000) * 10) / 10;
|
|
203
|
+
minutesSource = 'ledger-ts-delta';
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
stamped['minutesSincePrev'] = minutesSincePrev;
|
|
207
|
+
stamped['minutesSource'] = minutesSource;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
144
210
|
let line;
|
|
145
211
|
try {
|
|
146
212
|
line = JSON.stringify(stamped);
|
package/dist/run-records.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-records.js","sourceRoot":"","sources":["../src/run-records.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAiCrE,2FAA2F;AAC3F,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAE5C,0EAA0E;AAC1E,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,OAAO,CAAU,CAAC;AACnD,6FAA6F;AAC7F,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAU,CAAC;AAEpE,MAAM,MAAM,GAAG,CAAC,MAAc,EAAkB,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AAE1H,qGAAqG;AACrG,MAAM,IAAI,GAAG,CAAC,OAAgC,EAAE,MAAc,EAAkB,EAAE,CAAC,CAAC;IAClF,OAAO;IACP,IAAI,EAAE,CAAC;IACP,MAAM;IACN,QAAQ,EAAE,KAAK;IACf,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,SAAS,aAAa,CAAC,IAAgB,EAAE,OAAgC;IACvE,kGAAkG;IAClG,8FAA8F;IAC9F,oFAAoF;IACpF,IAAI,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,OAAO,IAAI,QAAQ,IAAI,OAAO,EAAE,CAAC;QACnE,kGAAkG;QAClG,iGAAiG;QACjG,oEAAoE;QACpE,OAAO,0FAA0F,CAAC;IACpG,CAAC;IACD,IAAI,IAAI,KAAK,eAAe,IAAI,QAAQ,IAAI,OAAO,IAAI,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC,EAAE,CAAC;QAC7E,OAAO,sFAAsF,CAAC;IAChG,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,aAAa,CAAC;IACrE,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC7B,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI;YAAE,OAAO,KAAK,IAAI,2CAA2C,KAAK,IAAI,CAAC;QACxG,6FAA6F;QAC7F,+FAA+F;QAC/F,4DAA4D;QAC5D,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,KAAK,IAAI,0BAA0B,KAAK,IAAI,CAAC;QAClG,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,IAAI,0BAA0B,KAAK,kBAAkB,CAAC;QAC1G,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAW,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxF,OAAO,KAAK,IAAI,0BAA0B,KAAK,mBAAmB,CAAC;QACrE,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,2FAA2F;AAC3F,SAAS,WAAW,CAAC,CAAU;IAC7B,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,
|
|
1
|
+
{"version":3,"file":"run-records.js","sourceRoot":"","sources":["../src/run-records.ts"],"names":[],"mappings":"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"}
|
package/dist/setup.d.ts
CHANGED
|
@@ -29,6 +29,14 @@ export interface SetupOptions {
|
|
|
29
29
|
readonly force?: boolean | undefined;
|
|
30
30
|
/** Also deploy the operating-instructions "driver" skill + agent docs. */
|
|
31
31
|
readonly installDriver?: boolean | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Absolute directory holding the BUILT harness-core modules, baked into the generated apply-leg
|
|
34
|
+
* hooks as the first resolve candidate (ADR-001 Decision 2, feature `setup-installs-apply-leg`).
|
|
35
|
+
* The CLI computes this from ITS OWN `@dzhechkov/harness-core` resolution (the installation
|
|
36
|
+
* actually running `dz setup`); when core's own `runSetup` is called without it (e.g. a direct
|
|
37
|
+
* programmatic call, or a test), it falls back to resolving ITSELF via {@link harnessCoreDistDir}.
|
|
38
|
+
*/
|
|
39
|
+
readonly coreDistDir?: string | undefined;
|
|
32
40
|
}
|
|
33
41
|
/** Setup result. */
|
|
34
42
|
export interface SetupResult {
|
package/dist/setup.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AA2BH,2BAA2B;AAC3B,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,CAAC;AAEhD,qBAAqB;AACrB,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACrC,0EAA0E;IAC1E,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7C;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,oBAAoB;AACpB,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,2BAA2B;AAC3B,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAY5G;AAWD;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CA+FjE;AAED,0FAA0F;AAC1F,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED,kEAAkE;AAClE;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAInD;AAED,MAAM,WAAW,mBAAmB;IAClC,sFAAsF;IACtF,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,+FAA+F;IAC/F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,mBAAmB,CAmCrB;AAgCD,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CA+CvF;AAkYD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,WAAW,CA8ZxD"}
|
package/dist/setup.js
CHANGED
|
@@ -16,11 +16,14 @@
|
|
|
16
16
|
* @packageDocumentation
|
|
17
17
|
*/
|
|
18
18
|
import { existsSync, mkdirSync, writeFileSync, readFileSync, rmSync } from 'node:fs';
|
|
19
|
-
import { basename, dirname, join } from 'node:path';
|
|
19
|
+
import { basename, dirname, isAbsolute, join, relative } from 'node:path';
|
|
20
20
|
import { execSync, spawnSync } from 'node:child_process';
|
|
21
21
|
import { mergeManagedHookEntries } from './managed-hooks.js';
|
|
22
22
|
import { CLAUDE_DESTRUCTIVE_HOOK_COMMAND, CLAUDE_DESTRUCTIVE_HOOK_MATCHER, CLAUDE_DESTRUCTIVE_HOOK_RELPATH, generateClaudeDestructiveHook, isDzManagedHookBody, } from './claude-hooks-assets.js';
|
|
23
23
|
import { applyIntegrationFragments, IntegrationApplyError } from './integration-apply.js';
|
|
24
|
+
import { harnessCoreDistDir } from './harness-core-location.js';
|
|
25
|
+
import { ensureAgentdbSchema } from './agentdb-index.js';
|
|
26
|
+
import { APPLY_LEG_VERSION, applyLegHookEntries, applyLegVersionOf, bakedCoreDistDirOf, embedDaemonSource, recallHookSource, hookCommandInvokes, } from './apply-leg.js';
|
|
24
27
|
/**
|
|
25
28
|
* Absolute path to the store the generated session-hook writer opens NATIVELY (better-sqlite3).
|
|
26
29
|
* It is the writer's own file: the agentdb MCP server must never be pointed at it — see
|
|
@@ -323,7 +326,12 @@ export function generateHooksConfig(projectRoot, backend) {
|
|
|
323
326
|
// Use a RELATIVE path (Claude Code runs hooks from the project root): interpolating the absolute
|
|
324
327
|
// ${dzDir} into a single-quoted JS literal inside shell double-quotes breaks on Windows backslash
|
|
325
328
|
// paths (\U, \b…) and on any path containing a quote. `.dz/sessions.jsonl` sidesteps all of it.
|
|
326
|
-
|
|
329
|
+
// AM-5 (dz-harness-hub issue #10 defect 5): `mkdirSync('.dz',{recursive:true})` FIRST —
|
|
330
|
+
// `appendFileSync` throws ENOENT when `.dz/` has been removed (a fresh checkout with `.dz`
|
|
331
|
+
// gitignored, or a user who deleted it) or when custom `settings.json` runs hooks from a cwd
|
|
332
|
+
// where the directory was never created; `mkdirSync` with `recursive:true` is a no-op when the
|
|
333
|
+
// directory already exists, so this is free on the common path.
|
|
334
|
+
const jsonlCmd = (event) => `node -e "const fs=require('fs');fs.mkdirSync('.dz',{recursive:true});const d=new Date().toISOString();fs.appendFileSync('.dz/sessions.jsonl',JSON.stringify({event:'${event}',ts:d,backend:'jsonl'})+'\\n')"`;
|
|
327
335
|
// Matcher-less PreCompact mirrors the agentdb backend so long-session bookkeeping stays reliable
|
|
328
336
|
// even without a vector store (jsonl has no consolidator — this is just an honest marker row).
|
|
329
337
|
return JSON.stringify({
|
|
@@ -421,7 +429,14 @@ function installAgentdbLocally(projectRoot) {
|
|
|
421
429
|
// 'pipe') avoids execSync's 1 MB maxBuffer aborting the child on npm's verbose output.
|
|
422
430
|
// --save-exact: agentdb is alpha; a semver range would let a later `npm update` drift the
|
|
423
431
|
// local copy away from the version the MCP registration pins (audit gap G7).
|
|
424
|
-
|
|
432
|
+
//
|
|
433
|
+
// better-sqlite3@^11 (AM-2, dz-harness-hub issue #10 defect 1, MEASURED Node 20.20.2 with no
|
|
434
|
+
// `make` on PATH): an unpinned `npm install better-sqlite3` resolved 12.11.1, which ships no
|
|
435
|
+
// prebuilt binary for Node 20's ABI 115 — the install fell through to a node-gyp source build
|
|
436
|
+
// and failed on a machine with no C toolchain. `agentdb` itself requests `^11.8.1`, which DOES
|
|
437
|
+
// publish an ABI-115 prebuild, so pinning the range here costs nothing agentdb wasn't already
|
|
438
|
+
// going to resolve to, and buys a working install on a bare Node 20/22 host.
|
|
439
|
+
execSync('npm install agentdb better-sqlite3@^11 --save-exact --no-audit --no-fund --loglevel=error', {
|
|
425
440
|
cwd: projectRoot,
|
|
426
441
|
stdio: 'ignore',
|
|
427
442
|
timeout: 300000,
|
|
@@ -557,6 +572,144 @@ function installDriverDocs(projectRoot, force) {
|
|
|
557
572
|
parts.push(`skipped ${skipped.join(', ')}`);
|
|
558
573
|
return parts.join('; ') || 'no changes';
|
|
559
574
|
}
|
|
575
|
+
/**
|
|
576
|
+
* Install the apply-leg (recall hook + embed daemon) — ADR-001 Decision 1, feature
|
|
577
|
+
* `setup-installs-apply-leg`. The third self-learning leg (COLLECT/RANK are Steps 4/2 of
|
|
578
|
+
* `runSetup`; APPLY is this one) lived only as hand-committed files in this hub's OWN
|
|
579
|
+
* `.claude/helpers/` — a consumer's `dz setup --memory agentdb` wrote session hooks and a memory
|
|
580
|
+
* store but never a `UserPromptSubmit` recall hook at all (00_complexity_assessment.md, MEASURED
|
|
581
|
+
* 2026-09-12).
|
|
582
|
+
*
|
|
583
|
+
* WHY THIS RUNS ITS WORK BEFORE "Configure hooks", even though the STEP is reported after it
|
|
584
|
+
* (`runSetup` calls this first, then pushes the returned step once "Configure hooks" has run).
|
|
585
|
+
* "Configure hooks" owns SessionStart too (the session-hook writer's own entry) via
|
|
586
|
+
* `mergeManagedHookEntries`'s drop-its-own-managed-entries/reappend-at-tail algorithm — a call that
|
|
587
|
+
* is perfectly stable in isolation, but which REORDERS a genuinely foreign SessionStart entry
|
|
588
|
+
* relative to its own the FIRST time one coexists (kept-foreign-entries-in-place, then append fresh
|
|
589
|
+
* own at the tail — stable only once the foreign entry is already positioned before it). Running
|
|
590
|
+
* this step's ADDITIVE-ONLY write first establishes that stable [foreign, own] layout on the VERY
|
|
591
|
+
* FIRST run, so "Configure hooks" never has anything to reorder on any later run — MEASURED: with
|
|
592
|
+
* the write ordered the other way, a repeat `runSetup` flips `SessionStart`'s two entries back and
|
|
593
|
+
* forth forever and neither step ever reports `skipped`, breaking the pre-existing
|
|
594
|
+
* `setup.test.ts` "PreCompact merge is idempotent" contract (FR-6) this feature must not touch.
|
|
595
|
+
*
|
|
596
|
+
* ADDITIVE-ONLY, deliberately NOT `mergeManagedHookEntries`: this step never needs to REPLACE a
|
|
597
|
+
* stale command text (the two commands `applyLegHookEntries()` emits do not change without an
|
|
598
|
+
* `APPLY_LEG_VERSION` bump, and a version bump is about the FILE content, not the hook command) —
|
|
599
|
+
* it only needs "is our command already referenced under this event, anywhere, in any position?".
|
|
600
|
+
* That question is order-independent, so it can never itself be a source of reordering, and it is
|
|
601
|
+
* exactly what keeps "Configure hooks" stable once the first run has established the layout above.
|
|
602
|
+
*/
|
|
603
|
+
function applyLegStepResult(opts, backend) {
|
|
604
|
+
if (opts.noHooks)
|
|
605
|
+
return { name: 'Install apply-leg', status: 'skipped', detail: '--no-hooks' };
|
|
606
|
+
if (backend !== 'agentdb') {
|
|
607
|
+
return {
|
|
608
|
+
name: 'Install apply-leg',
|
|
609
|
+
status: 'skipped',
|
|
610
|
+
detail: "apply-leg needs --memory agentdb (embed daemon requires agentdb's transformers)",
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
try {
|
|
614
|
+
const coreDistDir = opts.coreDistDir ?? harnessCoreDistDir();
|
|
615
|
+
// Re-review Codex (B) finding: the hub's own portable `null` marker must survive an ordinary
|
|
616
|
+
// `dz setup` run INSIDE the hub — when harness-core resolves to a path inside THIS project's
|
|
617
|
+
// `packages/@dzhechkov/harness-core`, the checkout is the monorepo itself and the helper is
|
|
618
|
+
// baked portable (`null` → runtime `<project>/packages/...` candidate), never an absolute path
|
|
619
|
+
// that would dirty the committed twin and break the twins test in any other clone.
|
|
620
|
+
const monorepoCoreDist = join(opts.projectRoot, 'packages', '@dzhechkov', 'harness-core', 'dist');
|
|
621
|
+
const relToMonorepo = relative(monorepoCoreDist, coreDistDir);
|
|
622
|
+
const insideMonorepo = relToMonorepo === '' || (!relToMonorepo.startsWith('..') && !isAbsolute(relToMonorepo));
|
|
623
|
+
const bakeTarget = insideMonorepo ? null : coreDistDir;
|
|
624
|
+
const helpersDir = join(opts.projectRoot, '.claude', 'helpers');
|
|
625
|
+
const recallHookPath = join(helpersDir, 'recall-hook.cjs');
|
|
626
|
+
const embedDaemonPath = join(helpersDir, 'dz-embed-daemon.mjs');
|
|
627
|
+
const settingsPath = join(opts.projectRoot, '.claude', 'settings.json');
|
|
628
|
+
const deployedRecallContent = existsSync(recallHookPath) ? readFileSync(recallHookPath, 'utf-8') : undefined;
|
|
629
|
+
const deployedEmbedContent = existsSync(embedDaemonPath) ? readFileSync(embedDaemonPath, 'utf-8') : undefined;
|
|
630
|
+
const deployedRecallVersion = deployedRecallContent !== undefined ? applyLegVersionOf(deployedRecallContent) : -1;
|
|
631
|
+
const deployedEmbedVersion = deployedEmbedContent !== undefined ? applyLegVersionOf(deployedEmbedContent) : -1;
|
|
632
|
+
// MEDIUM finding "переезд ядра" (fix round 1): a version-only staleness check misses the case
|
|
633
|
+
// where npm/nvm RELOCATED the installed harness-core without any template change — the deployed
|
|
634
|
+
// file still stamps the current APPLY_LEG_VERSION, but its baked `CORE_DIST_DIR` now points at a
|
|
635
|
+
// path that no longer exists, and `loadCoreModule` degrades to permanent silence rather than an
|
|
636
|
+
// error nothing else would ever surface. Comparing the BAKED path against the CURRENT one closes
|
|
637
|
+
// that gap independently of the version stamp.
|
|
638
|
+
const deployedCoreDistDir = deployedRecallContent !== undefined ? bakedCoreDistDirOf(deployedRecallContent) : undefined;
|
|
639
|
+
// Re-review Codex (B) finding: a path-staleness rewrite must never DOWNGRADE a helper that a
|
|
640
|
+
// newer CLI already deployed — only a file at or below the current version is ours to rewrite.
|
|
641
|
+
const recallDistDirStale = deployedRecallContent !== undefined
|
|
642
|
+
&& deployedRecallVersion <= APPLY_LEG_VERSION
|
|
643
|
+
&& deployedCoreDistDir !== bakeTarget;
|
|
644
|
+
let wroteHelpers = false;
|
|
645
|
+
if (deployedRecallVersion === -1 || opts.force || deployedRecallVersion < APPLY_LEG_VERSION || recallDistDirStale) {
|
|
646
|
+
mkdirSync(helpersDir, { recursive: true });
|
|
647
|
+
writeFileSync(recallHookPath, recallHookSource(bakeTarget), { mode: 0o755 });
|
|
648
|
+
wroteHelpers = true;
|
|
649
|
+
}
|
|
650
|
+
if (deployedEmbedVersion === -1 || opts.force || deployedEmbedVersion < APPLY_LEG_VERSION) {
|
|
651
|
+
mkdirSync(helpersDir, { recursive: true });
|
|
652
|
+
writeFileSync(embedDaemonPath, embedDaemonSource(), { mode: 0o755 });
|
|
653
|
+
wroteHelpers = true;
|
|
654
|
+
}
|
|
655
|
+
// ADD-IF-MISSING, per event: FR-2's literal contract — "ours is added only if no command of
|
|
656
|
+
// the event already contains OUR entry". Never removes or reorders an existing entry (foreign
|
|
657
|
+
// OR our own) — see the WHY above for why that matters here.
|
|
658
|
+
//
|
|
659
|
+
// MEDIUM finding "совпадение подстроки в чужой команде" (fix round 1): the substring probe used
|
|
660
|
+
// to be the bare filename (`recall-hook.cjs`), so a foreign command that merely MENTIONS the
|
|
661
|
+
// filename (e.g. `echo recall-hook.cjs`) was indistinguishable from our own entry and silently
|
|
662
|
+
// blocked ours from ever being added. "Ours is already present" now means either an EXACT match
|
|
663
|
+
// of the command we would emit, or the command containing our full relative PATH
|
|
664
|
+
// (`.claude/helpers/<file>`, the same marker `applyLegStatus` structurally looks for) — a bare
|
|
665
|
+
// filename mention under any other wrapper text no longer counts.
|
|
666
|
+
const entries = applyLegHookEntries();
|
|
667
|
+
const existingSettings = existsSync(settingsPath)
|
|
668
|
+
? JSON.parse(readFileSync(settingsPath, 'utf-8'))
|
|
669
|
+
: {};
|
|
670
|
+
const hooks = { ...(existingSettings['hooks'] ?? {}) };
|
|
671
|
+
let hooksAdded = false;
|
|
672
|
+
const addIfMissing = (event, ownCommand, markerPath, entry) => {
|
|
673
|
+
const current = Array.isArray(hooks[event]) ? hooks[event] : [];
|
|
674
|
+
const alreadyPresent = current.some((e) => commandsOf(e).some((cmd) => cmd === ownCommand || hookCommandInvokes(cmd, markerPath)));
|
|
675
|
+
if (alreadyPresent)
|
|
676
|
+
return;
|
|
677
|
+
hooks[event] = [...current, entry];
|
|
678
|
+
hooksAdded = true;
|
|
679
|
+
};
|
|
680
|
+
addIfMissing('UserPromptSubmit', entries.userPromptSubmit.hooks[0]?.command ?? '', '.claude/helpers/recall-hook.cjs', entries.userPromptSubmit);
|
|
681
|
+
addIfMissing('SessionStart', entries.sessionStart.hooks[0]?.command ?? '', '.claude/helpers/dz-embed-daemon.mjs', entries.sessionStart);
|
|
682
|
+
if (hooksAdded) {
|
|
683
|
+
existingSettings['hooks'] = hooks;
|
|
684
|
+
mkdirSync(dirname(settingsPath), { recursive: true });
|
|
685
|
+
writeFileSync(settingsPath, JSON.stringify(existingSettings, null, 2));
|
|
686
|
+
}
|
|
687
|
+
// AM-4 (dz-harness-hub issue #10 defect 4): create the empty AgentDB-schema store now, so a
|
|
688
|
+
// lesson taught before the first session's SessionEnd/PreCompact writer has ever run still has
|
|
689
|
+
// somewhere to mirror into — see `ensureAgentdbSchema`'s own doc for the full mechanism. Never
|
|
690
|
+
// touches an EXISTING store (never re-opens a populated db on every routine re-run); "creates a
|
|
691
|
+
// store" is a claim about a store that did not exist.
|
|
692
|
+
const dbPath = join(opts.projectRoot, '.dz', 'agentdb.db');
|
|
693
|
+
let schemaDetail = '';
|
|
694
|
+
if (!existsSync(dbPath)) {
|
|
695
|
+
const schemaResult = ensureAgentdbSchema(opts.projectRoot);
|
|
696
|
+
schemaDetail = schemaResult.ok ? '; empty agentdb.db created' : `; agentdb.db NOT created (${schemaResult.error ?? 'unknown error'})`;
|
|
697
|
+
}
|
|
698
|
+
const changed = wroteHelpers || hooksAdded;
|
|
699
|
+
return {
|
|
700
|
+
name: 'Install apply-leg',
|
|
701
|
+
status: changed ? 'done' : 'skipped',
|
|
702
|
+
detail: (changed ? `Apply-leg: installed v${APPLY_LEG_VERSION}` : `Apply-leg: current (v${APPLY_LEG_VERSION})`) + schemaDetail,
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
catch (err) {
|
|
706
|
+
return {
|
|
707
|
+
name: 'Install apply-leg',
|
|
708
|
+
status: 'error',
|
|
709
|
+
detail: `could not install apply-leg: ${err instanceof Error ? err.message : String(err)}`,
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
}
|
|
560
713
|
export function runSetup(opts) {
|
|
561
714
|
const steps = [];
|
|
562
715
|
const dzDir = join(opts.projectRoot, '.dz');
|
|
@@ -649,6 +802,12 @@ export function runSetup(opts) {
|
|
|
649
802
|
steps.push({ name: 'Initialize patterns.jsonl', status: 'skipped', detail: 'already exists' });
|
|
650
803
|
}
|
|
651
804
|
}
|
|
805
|
+
// Step 4.6: Install apply-leg — the WORK happens here (before "Configure hooks" writes
|
|
806
|
+
// SessionStart), so a foreign SessionStart entry is already in place before that step's own
|
|
807
|
+
// merge ever sees it; see `applyLegStepResult`'s doc for why order matters. The STEP is reported
|
|
808
|
+
// further down, after "Configure hooks" pushes its own, so the printed order still reads as
|
|
809
|
+
// "collect → rank → apply".
|
|
810
|
+
const applyLegStep = applyLegStepResult(opts, backend);
|
|
652
811
|
// Step 5: Configure hooks (write to .claude/settings.json) — EVENT-LEVEL merge (gap G2):
|
|
653
812
|
// dz-generated entries (recognized by signature, incl. the broken legacy `agentdb add` hooks
|
|
654
813
|
// this feature fixes) are replaced in place WITHOUT --force; the user's own hooks and every
|
|
@@ -823,6 +982,10 @@ export function runSetup(opts) {
|
|
|
823
982
|
else {
|
|
824
983
|
steps.push({ name: 'Configure hooks', status: 'skipped', detail: '--no-hooks' });
|
|
825
984
|
}
|
|
985
|
+
// Step 5.6: Install apply-leg — report pushed AFTER "Configure hooks" below (for a report order
|
|
986
|
+
// that reads naturally), but see `applyLegStepResult()` above `runSetup` for why the WRITE itself
|
|
987
|
+
// happens BEFORE it.
|
|
988
|
+
steps.push(applyLegStep);
|
|
826
989
|
// Step 5.5: Register agentdb MCP through the SAME ownership-aware transaction used by `dz init`.
|
|
827
990
|
// `.mcp.json` is the project-scope carrier Claude Code actually loads. A known historical dz
|
|
828
991
|
// agentdb shape is adopted; an ambiguous hand-authored entry is preserved and named as an error.
|