@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
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consistent sqlite snapshot + restore for the pre-reindex undo point (feature
|
|
3
|
+
* `snapshot-wal-consistency`, FR-1..FR-4; fix round AM-1..AM-4).
|
|
4
|
+
*
|
|
5
|
+
* A WAL-mode sqlite database's committed data can live in TWO files: the main `dbFile` and its
|
|
6
|
+
* `-wal` sidecar (frames not yet checkpointed into the main file). The snapshot this module
|
|
7
|
+
* replaces was a bare `copyFileSync(dbFile, backupPath)` — one file, no `-wal` — so a reindex that
|
|
8
|
+
* ran while any writer held the WAL open (autocheckpoint disabled, or simply a live connection
|
|
9
|
+
* between commits) copied a "backup" that was MISSING committed rows. MEASURED (scratch repro,
|
|
10
|
+
* 2026-09-13, `node` + real `better-sqlite3`): a schema + one row checkpointed, then a second row
|
|
11
|
+
* inserted on a connection kept open (`wal_autocheckpoint = 0`) — `copyFileSync` alone yields a
|
|
12
|
+
* backup with 1 row; `VACUUM INTO` on a fresh read-only connection to the SAME live db yields 2.
|
|
13
|
+
* The live db's main file hash and `-wal` size are unchanged before/after the `VACUUM INTO` (the
|
|
14
|
+
* read-only connection never checkpoints or writes) — the safety property NFR-2 names.
|
|
15
|
+
*
|
|
16
|
+
* {@link snapshotSqliteDatabase} (FR-1/FR-2) takes the snapshot through `VACUUM INTO` on a fresh
|
|
17
|
+
* READ-ONLY connection — one self-contained output file with every committed transaction, WAL
|
|
18
|
+
* frames included. If `VACUUM INTO` cannot run (older sqlite, a locked/foreign file, no free disk)
|
|
19
|
+
* — or a caller forces it for a test — it falls back to copying `dbFile` plus its `-wal` sibling
|
|
20
|
+
* (present and non-empty) to `backupPath`/`backupPath-wal`; still strictly better than the old
|
|
21
|
+
* single-file copy, and the fallback is never silent: `method`/`note` name it honestly so a report
|
|
22
|
+
* downstream (`reindexAgentdbRows`'s `snapshotMethod`) never claims a guarantee it did not get.
|
|
23
|
+
*
|
|
24
|
+
* **AM-1 (fix round).** Codex review, Grade C: reusing a `backupPath` left a stale `-wal`/`-shm`
|
|
25
|
+
* sidecar from an EARLIER, unrelated snapshot family sitting next to the new one; `restoreSqliteSnapshot`
|
|
26
|
+
* used to decide whether to restore `-wal` by checking whether `backupPath-wal` merely EXISTS, so that
|
|
27
|
+
* stale sidecar could ride along onto a `vacuum-into` restore that never produced a matching `-wal` of
|
|
28
|
+
* its own. Fixed two ways: `snapshotSqliteDatabase` now clears any `backupPath-wal`/`-shm` sidecar
|
|
29
|
+
* BEFORE either strategy writes anything, and again right after a successful `VACUUM INTO` (whose
|
|
30
|
+
* output is one self-contained file and must never be shadowed); `restoreSqliteSnapshot` now takes the
|
|
31
|
+
* `method` the caller already knows and restores `-wal` ONLY when `method === 'copy+wal'` — never by
|
|
32
|
+
* re-deriving it from file presence.
|
|
33
|
+
*
|
|
34
|
+
* **AM-2 (fix round).** The old WAL-size probe was `existsSync` + best-effort `statSync` inside a
|
|
35
|
+
* `catch { walSize = 0 }` — ANY stat failure (`EACCES`, `EIO`, a raced deletion) was silently read as
|
|
36
|
+
* "no WAL", so a snapshot could report the honest-sounding `method: 'copy'` while actually having
|
|
37
|
+
* skipped a WAL it could not even check. {@link statSizeIfExists} now calls `statSync` directly and
|
|
38
|
+
* treats only a confirmed `ENOENT` as "does not exist" — every other error propagates and aborts the
|
|
39
|
+
* whole snapshot, so `reindexAgentdbRows` reports "snapshot failed", never a falsely-successful `copy`.
|
|
40
|
+
*
|
|
41
|
+
* **AM-4 (fix round).** `snapshotSqliteDatabase` used to happily write into (overwrite) an existing
|
|
42
|
+
* `backupPath`, silently discarding whatever it held — including, combined with AM-1's stale-sidecar
|
|
43
|
+
* bug, a backup that looked complete but carried a wrong-generation `-wal`. It now refuses up front
|
|
44
|
+
* (before `VACUUM INTO` or any copy) when `backupPath` already exists and is non-empty.
|
|
45
|
+
*
|
|
46
|
+
* {@link restoreSqliteSnapshot} (FR-4) is the paired rollback. MEASURED (same repro): copying the
|
|
47
|
+
* old main file back over `dbFile` WITHOUT removing a `-wal` left over from the aborted operation
|
|
48
|
+
* — reopening the "restored" db returned ZERO rows, not the restored one, because sqlite replayed
|
|
49
|
+
* the stale WAL frames (a since-superseded DELETE) on top of the reverted main file. Removing
|
|
50
|
+
* `dbFile-wal`/`dbFile-shm` as part of the restore fixed this: the reopened db then returned
|
|
51
|
+
* exactly the restored row. The caller MUST close its own write connection to `dbFile` before
|
|
52
|
+
* calling this — restoring a file sqlite still holds open is undefined behaviour.
|
|
53
|
+
*
|
|
54
|
+
* **AM-3 (fix round).** `restoreSqliteSnapshot` used to return `void` — a failing `copyFileSync`/
|
|
55
|
+
* `rmSync` inside it threw straight out of the best-effort `rollback()` wrapper in
|
|
56
|
+
* `agentdb-index.ts`, which swallowed it in an empty `catch` and reported nothing: "absence of a
|
|
57
|
+
* receipt is not success" applies to a rollback exactly as much as to a forward operation. It now
|
|
58
|
+
* returns `{ ok: true } | { ok: false, error }` so the caller can name a failed rollback as failed,
|
|
59
|
+
* never as restored.
|
|
60
|
+
*
|
|
61
|
+
* @packageDocumentation
|
|
62
|
+
*/
|
|
63
|
+
import { copyFileSync, existsSync, rmSync, statSync } from 'node:fs';
|
|
64
|
+
/** Escape `path` as a single-quoted sqlite string literal (double any embedded `'`). */
|
|
65
|
+
function sqlQuote(path) {
|
|
66
|
+
return `'${path.replace(/'/g, "''")}'`;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* AM-2: the size of `path`, or `undefined` when it does not exist — but ONLY on a confirmed
|
|
70
|
+
* `ENOENT`. Any other stat error (`EACCES`, `EIO`, a raced deletion mid-call, …) propagates to the
|
|
71
|
+
* caller instead of being folded into "does not exist": a snapshot that cannot even determine
|
|
72
|
+
* whether a `-wal` sidecar exists must abort, not silently report the weaker `copy` method as if it
|
|
73
|
+
* had made an informed choice.
|
|
74
|
+
*/
|
|
75
|
+
function statSizeIfExists(path) {
|
|
76
|
+
try {
|
|
77
|
+
return statSync(path).size;
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
if (err?.code === 'ENOENT')
|
|
81
|
+
return undefined;
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* AM-4: refuse to snapshot into an existing, non-empty `backupPath` — silently overwriting it would
|
|
87
|
+
* discard whatever it held (possibly itself a valid undo point) with no trace. An existing but EMPTY
|
|
88
|
+
* file is not a real prior snapshot and is allowed through untouched.
|
|
89
|
+
*/
|
|
90
|
+
function assertBackupTargetFree(backupPath) {
|
|
91
|
+
const size = statSizeIfExists(backupPath);
|
|
92
|
+
if (size !== undefined && size > 0) {
|
|
93
|
+
throw new Error(`snapshot target exists and is non-empty: ${backupPath}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* AM-1: remove any `-wal`/`-shm` sidecar already sitting at `backupPath` — a leftover from an
|
|
98
|
+
* earlier, unrelated snapshot family that happened to reuse this name. Called BEFORE either strategy
|
|
99
|
+
* below writes anything, and again immediately after a successful `VACUUM INTO` (whose output is one
|
|
100
|
+
* self-contained file that must never be shadowed by a stale sidecar from a previous attempt at the
|
|
101
|
+
* same path).
|
|
102
|
+
*/
|
|
103
|
+
function clearBackupSidecars(backupPath) {
|
|
104
|
+
rmSync(`${backupPath}-wal`, { force: true });
|
|
105
|
+
rmSync(`${backupPath}-shm`, { force: true });
|
|
106
|
+
}
|
|
107
|
+
function copyWithWal(dbFile, backupPath, note) {
|
|
108
|
+
// AM-2: statSync directly; only a confirmed ENOENT means "no -wal to copy" — any other stat error
|
|
109
|
+
// propagates out of this function (and out of snapshotSqliteDatabase) as a thrown exception.
|
|
110
|
+
// Lead edit after re-review: the stat runs BEFORE the main file is copied, so a stat failure leaves
|
|
111
|
+
// no half-written target behind (which AM-4 would otherwise refuse on the retry).
|
|
112
|
+
const walSize = statSizeIfExists(`${dbFile}-wal`) ?? 0;
|
|
113
|
+
copyFileSync(dbFile, backupPath);
|
|
114
|
+
if (walSize > 0) {
|
|
115
|
+
copyFileSync(`${dbFile}-wal`, `${backupPath}-wal`);
|
|
116
|
+
return { method: 'copy+wal', note };
|
|
117
|
+
}
|
|
118
|
+
return { method: 'copy', note };
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Take a consistent snapshot of `dbFile` into `backupPath` (FR-1/FR-2). Default: open `dbFile`
|
|
122
|
+
* READ-ONLY and run `VACUUM INTO <backupPath>` — one output file holding every committed
|
|
123
|
+
* transaction (including `-wal` frames), with no write to the live database (NFR-2 — MEASURED:
|
|
124
|
+
* main-file hash and `-wal` size are unchanged across the call). On any failure — an older sqlite
|
|
125
|
+
* without `VACUUM INTO`, a locked file, no disk space — or when `opts.strategy` forces it (tests),
|
|
126
|
+
* falls back to `copyFileSync(dbFile, backupPath)` plus a copy of `dbFile-wal` to `backupPath-wal`
|
|
127
|
+
* when the WAL sibling exists and is non-empty; `method` is `'copy+wal'` when the sibling was
|
|
128
|
+
* copied, `'copy'` when there was none to copy. `note` names the fallback reason (FR-2) — set even
|
|
129
|
+
* for a forced-strategy test call, so a caller never has to guess why the fast path was skipped.
|
|
130
|
+
* The read-only connection opened for `VACUUM INTO` is always closed before returning.
|
|
131
|
+
*
|
|
132
|
+
* Throws (no snapshot taken, or an incomplete one left in a fully-cleared state) when: `backupPath`
|
|
133
|
+
* already names an existing, non-empty file (AM-4); or a `-wal` stat probe hits a non-ENOENT error
|
|
134
|
+
* (AM-2, inside the fallback path). Never silently overwrites, never mis-reports a lesser guarantee
|
|
135
|
+
* as a stronger one.
|
|
136
|
+
*/
|
|
137
|
+
export function snapshotSqliteDatabase(Database, dbFile, backupPath, opts = {}) {
|
|
138
|
+
assertBackupTargetFree(backupPath); // AM-4 — before any write, on either strategy
|
|
139
|
+
clearBackupSidecars(backupPath); // AM-1 — clean slate before either strategy writes anything
|
|
140
|
+
if (opts.strategy === 'copy+wal') {
|
|
141
|
+
return copyWithWal(dbFile, backupPath, 'snapshotStrategy=copy+wal forced by caller');
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
const db = new Database(dbFile, { readonly: true });
|
|
145
|
+
try {
|
|
146
|
+
db.exec(`VACUUM INTO ${sqlQuote(backupPath)}`);
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
db.close();
|
|
150
|
+
}
|
|
151
|
+
clearBackupSidecars(backupPath); // AM-1 — VACUUM INTO's output never has a matching -wal of its own
|
|
152
|
+
return { method: 'vacuum-into' };
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
return copyWithWal(dbFile, backupPath, `VACUUM INTO failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Restore `dbFile` from a snapshot taken by {@link snapshotSqliteDatabase} (FR-4). The caller MUST
|
|
160
|
+
* close its write connection to `dbFile` BEFORE calling this — this restore is a plain file copy,
|
|
161
|
+
* not a sqlite-mediated rollback, and a live handle can reintroduce exactly the frames being undone.
|
|
162
|
+
*
|
|
163
|
+
* `method` is the EXACT {@link SnapshotMethod} the paired `snapshotSqliteDatabase` call returned
|
|
164
|
+
* (AM-1) — never re-derived from whether `backupPath-wal` happens to exist on disk, which a stale
|
|
165
|
+
* sidecar from an unrelated earlier snapshot at the same path could satisfy. Copies `backupPath`
|
|
166
|
+
* over `dbFile`; when `method === 'copy+wal'`, also restores `backupPath-wal` to `dbFile-wal`.
|
|
167
|
+
* Otherwise (`'vacuum-into'` or `'copy'`, neither of which produced a matching `-wal` of its own) any
|
|
168
|
+
* LIVE `dbFile-wal` — left over from the operation being undone — is removed instead: MEASURED,
|
|
169
|
+
* leaving it in place made a reopened "restored" db replay that WAL's frames (a since-superseded
|
|
170
|
+
* write) on top of the reverted main file, returning zero rows instead of the restored set.
|
|
171
|
+
* `dbFile-shm` is always removed — its offsets are valid only for the `-wal` that no longer matches.
|
|
172
|
+
*
|
|
173
|
+
* Returns `{ ok: true }`, or `{ ok: false, error }` (AM-3) when any step throws — a caller that
|
|
174
|
+
* reported a failed restore as a successful one would leave the store worse than before rollback was
|
|
175
|
+
* attempted, with nothing on record to say so.
|
|
176
|
+
*/
|
|
177
|
+
export function restoreSqliteSnapshot(dbFile, backupPath, method) {
|
|
178
|
+
try {
|
|
179
|
+
if (!existsSync(backupPath))
|
|
180
|
+
return { ok: false, error: `snapshot missing at ${backupPath}` };
|
|
181
|
+
copyFileSync(backupPath, dbFile);
|
|
182
|
+
if (method === 'copy+wal') {
|
|
183
|
+
copyFileSync(`${backupPath}-wal`, `${dbFile}-wal`);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
rmSync(`${dbFile}-wal`, { force: true });
|
|
187
|
+
}
|
|
188
|
+
rmSync(`${dbFile}-shm`, { force: true });
|
|
189
|
+
return { ok: true };
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=agentdb-snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentdb-snapshot.js","sourceRoot":"","sources":["../src/agentdb-snapshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apply-leg module (feature `setup-installs-apply-leg`, ADR-001 Decisions 1 and 2).
|
|
3
|
+
*
|
|
4
|
+
* The self-learning loop has three legs — COLLECT (session hooks → store), RANK (`dz teach` /
|
|
5
|
+
* `dz recall` / `dz consolidate`), APPLY (a `UserPromptSubmit` hook injects learned lessons back
|
|
6
|
+
* into the prompt via a resident embedding daemon). `dz setup` shipped the first two legs; the
|
|
7
|
+
* third lived ONLY as hand-committed files in this hub's own `.claude/helpers/` — a consumer who
|
|
8
|
+
* ran `dz setup --target claude-code --memory agentdb` got session hooks and a memory store, but no
|
|
9
|
+
* recall injection at all (00_complexity_assessment.md, MEASURED 2026-09-12: clean scratch installs
|
|
10
|
+
* on 0.8.10 and 0.8.22, with and without `--memory agentdb`, wrote no `UserPromptSubmit` entry).
|
|
11
|
+
*
|
|
12
|
+
* This module is the SOURCE of that third leg: the two helper files as versioned template
|
|
13
|
+
* generators (the same shape as `AGENTDB_WRITER_VERSION`/`generateAgentdbWriter` in `setup.ts`),
|
|
14
|
+
* the hook-registry entries `runSetup` merges into `settings.json`, and `applyLegStatus` — the ONE
|
|
15
|
+
* measurement `dz doctor` and `dz parity` both read, so neither can drift into declaring the leg
|
|
16
|
+
* present from a static capability table again (ADR-001 Decision 3, the "приборы врут" defect).
|
|
17
|
+
*
|
|
18
|
+
* Decision 2 (why `coreDistDir` is baked in, first candidate): a hook file lives in a CONSUMER
|
|
19
|
+
* project's `.claude/helpers/`, where `require('@dzhechkov/harness-core')` cannot resolve — Node
|
|
20
|
+
* resolves a bare specifier upward from the file, and the package is not above it in a global
|
|
21
|
+
* install. The old hard-coded `/usr/lib/node_modules/...` candidate assumed one specific npm
|
|
22
|
+
* prefix; a project set up from an nvm or `/usr/local` install found nothing. The fix mirrors
|
|
23
|
+
* `claude-hooks-assets.ts`'s destructive-guard hook: bake the INSTALLING copy's absolute `dist`
|
|
24
|
+
* directory into the generated body as the FIRST candidate (proven first at C-5), keep the
|
|
25
|
+
* project-local candidates as fallbacks for a consumer that vendors its own harness-core.
|
|
26
|
+
*
|
|
27
|
+
* @packageDocumentation
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* Version stamped into BOTH generated helper files as `// dz-apply-leg-version: N` (line 2, right
|
|
31
|
+
* after the shebang). Bump on ANY change to {@link recallHookSource} or {@link embedDaemonSource}'s
|
|
32
|
+
* output — `runSetup` regenerates a deployed helper whose stamp is older, without requiring
|
|
33
|
+
* `--force` (the same self-healing contract as `AGENTDB_WRITER_VERSION`).
|
|
34
|
+
*
|
|
35
|
+
* Bumped 2→3 (fix round 1, review Codex C, MEDIUM finding "hub twins непереносимы"):
|
|
36
|
+
* `recallHookSource`'s `loadCoreModule` candidate list is now built with a conditional spread so a
|
|
37
|
+
* `null` `coreDistDir` (the hub's own portable marker, C-6/finding-6) degrades cleanly to the
|
|
38
|
+
* project-relative fallbacks — the generated BYTES changed for every caller, hub and consumer alike.
|
|
39
|
+
*/
|
|
40
|
+
export declare const APPLY_LEG_VERSION = 3;
|
|
41
|
+
/**
|
|
42
|
+
* Parse the `dz-apply-leg-version` stamp from a deployed helper file. Unlike
|
|
43
|
+
* `writerVersionOf` (which floors an absent stamp at `0`), this returns `-1` for "no stamp at
|
|
44
|
+
* all" per the plan contract (T1) — `0` is reserved for a future explicit `version 0` helper, and
|
|
45
|
+
* collapsing "never installed" into the same number as "installed at v0" would make
|
|
46
|
+
* `applyLegStatus` unable to tell the two apart.
|
|
47
|
+
*/
|
|
48
|
+
export declare function applyLegVersionOf(content: string): number;
|
|
49
|
+
/**
|
|
50
|
+
* Read back the `coreDistDir` baked into a deployed `recall-hook.cjs` by {@link recallHookSource}
|
|
51
|
+
* (fix round 1, review Codex C, MEDIUM finding "переезд ядра"): `undefined` when the file carries no
|
|
52
|
+
* recognisable `const CORE_DIST_DIR = …;` line at all (e.g. a pre-feature or hand-edited file),
|
|
53
|
+
* `null` for the hub's own portable marker, otherwise the baked absolute path. `runSetup` compares
|
|
54
|
+
* this against the CURRENT `coreDistDir` so a project whose npm/nvm relocated `harness-core` gets
|
|
55
|
+
* its helper rewritten even when {@link APPLY_LEG_VERSION} did not change — a version-only staleness
|
|
56
|
+
* check missed exactly this case (MEASURED: a stale baked path degrades the hook to permanent
|
|
57
|
+
* silence, never a thrown error, so nothing else would ever surface it).
|
|
58
|
+
*/
|
|
59
|
+
export declare function bakedCoreDistDirOf(content: string): string | null | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* Generate `.claude/helpers/recall-hook.cjs`. `coreDistDir` is baked in as the FIRST resolve
|
|
62
|
+
* candidate in `loadCoreModule` (Decision 2, AC-6/C-5) — an absolute path, supplied by the
|
|
63
|
+
* installer (`dz setup`'s CLI caller resolves its own installed `@dzhechkov/harness-core`).
|
|
64
|
+
*
|
|
65
|
+
* `coreDistDir === null` is the HUB's OWN portable marker (fix round 1, review Codex C, MEDIUM
|
|
66
|
+
* finding "hub twins непереносимы"): a checked-in file that bakes an ABSOLUTE checkout path fails
|
|
67
|
+
* the twins byte-identity test in every clone but the one it was generated from. The hub instead
|
|
68
|
+
* regenerates its two `.claude/helpers/*` files with `null`, which renders `const CORE_DIST_DIR =
|
|
69
|
+
* null;` and — since `loadCoreModule`'s candidate list below SKIPS a falsy `CORE_DIST_DIR` — falls
|
|
70
|
+
* straight through to the project-relative fallback candidates, the SAME `<project>/packages/
|
|
71
|
+
* @dzhechkov/harness-core/dist/<file>` path the hub's own `coreDistDir` would have baked anyway
|
|
72
|
+
* (`PROJECT` resolves from `CLAUDE_PROJECT_DIR`/`cwd()` at hook RUNTIME, not at generation time, so
|
|
73
|
+
* it is correct in any clone). A real consumer install still gets its installer's absolute path
|
|
74
|
+
* baked in as before — this is additive, not a behavior change for that case.
|
|
75
|
+
*
|
|
76
|
+
* Behaviourally identical to the pre-existing hand-committed hub file except for: the version
|
|
77
|
+
* stamp (new, line 2) and the candidate list in `loadCoreModule` (baked path first when present,
|
|
78
|
+
* `/usr/lib/...` dropped — FR-3).
|
|
79
|
+
*/
|
|
80
|
+
export declare function recallHookSource(coreDistDir: string | null): string;
|
|
81
|
+
/** `setTimeout`'s delay argument is a 32-bit signed int in Node — see {@link resolveIdleMs}. */
|
|
82
|
+
export declare const IDLE_MS_INT32_MAX = 2147483647;
|
|
83
|
+
/** Result of resolving a raw `DZ_EMBED_IDLE_MS` value into the daemon's actual idle-exit timer. */
|
|
84
|
+
export interface ResolvedIdleMs {
|
|
85
|
+
/** `null` ⇒ the idle exit is disabled outright (0/NaN/negative). Otherwise the clamped ms value. */
|
|
86
|
+
readonly value: number | null;
|
|
87
|
+
/** True ⇒ `value` was clamped down from a raw value above {@link IDLE_MS_INT32_MAX}. */
|
|
88
|
+
readonly clamped: boolean;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Pure mirror of the `IDLE_MS` resolution inlined into {@link embedDaemonSource}'s generated body
|
|
92
|
+
* (AM-10, dz-harness-hub issue #10 defect 7). Extracted (fix round 1, review Codex C, LOW finding)
|
|
93
|
+
* so the clamp/disable rule is unit-testable directly — the review noted the only prior proof was a
|
|
94
|
+
* LIVE process observed via its first stderr log line, which shows the log fired but not that the
|
|
95
|
+
* underlying arithmetic is right for every input class.
|
|
96
|
+
*
|
|
97
|
+
* A template string cannot `import` this function into the daemon's own runtime (it is generated
|
|
98
|
+
* text, not compiled code), so {@link embedDaemonSource} keeps its OWN copy of the same three rules —
|
|
99
|
+
* `apply-leg-twins.test.ts` pins the generated body to the same `IDLE_MS_INT32_MAX` constant this
|
|
100
|
+
* module exports, so the two cannot drift apart silently.
|
|
101
|
+
*/
|
|
102
|
+
export declare function resolveIdleMs(raw: number): ResolvedIdleMs;
|
|
103
|
+
/**
|
|
104
|
+
* Generate `.claude/helpers/dz-embed-daemon.mjs`. Behaviourally identical to the pre-existing
|
|
105
|
+
* hand-committed hub file except for: the version stamp (new, line 2) and `resolveDeps()`, which
|
|
106
|
+
* now tries `@huggingface/transformers` before falling back to `@xenova/transformers` — AM-3,
|
|
107
|
+
* dz-harness-hub issue #10 defect 3: `agentdb >= 3.0.0-alpha` depends on the former, and an older
|
|
108
|
+
* agentdb install still carries the latter, so probing only one name silently starved the daemon
|
|
109
|
+
* on either side of that agentdb version boundary.
|
|
110
|
+
*/
|
|
111
|
+
export declare function embedDaemonSource(): string;
|
|
112
|
+
/** One Claude Code hook-registry entry in the matcher-group shape (no matcher — session/prompt events don't need one). */
|
|
113
|
+
export interface ApplyLegHookEntry {
|
|
114
|
+
readonly hooks: readonly {
|
|
115
|
+
readonly type: 'command';
|
|
116
|
+
readonly command: string;
|
|
117
|
+
}[];
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The two hook-registry entries `runSetup` merges into `.claude/settings.json` (FR-1). Commands
|
|
121
|
+
* match the hub's own `.claude/settings.json` verbatim (`grep`-diffed against it at authoring time):
|
|
122
|
+
* the recall hook is invoked with a swallowed non-zero exit (`|| true`) so a broken hook body never
|
|
123
|
+
* fails a prompt, and the embed daemon is spawned detached via `nohup` + a backgrounding `sh -c`
|
|
124
|
+
* so `SessionStart` never waits on model load.
|
|
125
|
+
*/
|
|
126
|
+
export declare function applyLegHookEntries(): {
|
|
127
|
+
readonly userPromptSubmit: ApplyLegHookEntry;
|
|
128
|
+
readonly sessionStart: ApplyLegHookEntry;
|
|
129
|
+
};
|
|
130
|
+
/** Version + presence of one deployed helper file. */
|
|
131
|
+
export interface ApplyLegHelperStatus {
|
|
132
|
+
readonly path: string;
|
|
133
|
+
readonly exists: boolean;
|
|
134
|
+
/** {@link applyLegVersionOf} of the deployed file; `-1` when absent, unstamped, or unreadable. */
|
|
135
|
+
readonly version: number;
|
|
136
|
+
/** True only when the file EXISTS but could not be read (EISDIR, EACCES, …) — distinct from absent. */
|
|
137
|
+
readonly unreadable?: boolean;
|
|
138
|
+
}
|
|
139
|
+
/** Whether a hook-registry entry naming this helper was found in `.claude/settings.json`. */
|
|
140
|
+
export interface ApplyLegHookPresence {
|
|
141
|
+
readonly present: boolean;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Why {@link ApplyLegStatus.installed} is `false`. Absent when `installed` is `true`.
|
|
145
|
+
* - `'missing-helpers'` — at least one helper FILE does not exist.
|
|
146
|
+
* - `'stale-version'` — both helpers exist and are readable, but at least one carries a
|
|
147
|
+
* `dz-apply-leg-version` below {@link APPLY_LEG_VERSION}.
|
|
148
|
+
* - `'hooks-missing'` — both helpers exist and are current, but `.claude/settings.json` does not
|
|
149
|
+
* structurally wire one or both of them under the right event (fix round 1, HIGH finding 1).
|
|
150
|
+
* - `'unreadable'` — a helper file EXISTS but could not be read (fix round 1, Q3 finding): reported
|
|
151
|
+
* distinctly rather than silently folding into `missing-helpers`, which would tell a consumer to
|
|
152
|
+
* re-run `dz setup` when the real problem is a broken/permission-denied file in the way.
|
|
153
|
+
*/
|
|
154
|
+
export type ApplyLegNotInstalledReason = 'missing-helpers' | 'stale-version' | 'hooks-missing' | 'unreadable';
|
|
155
|
+
/** The ONE measurement `dz doctor` and `dz parity` both read (ADR-001 Decision 3) — never a static capability declaration. */
|
|
156
|
+
export interface ApplyLegStatus {
|
|
157
|
+
/**
|
|
158
|
+
* True only when BOTH helper files exist, are READABLE, are at {@link APPLY_LEG_VERSION} or newer,
|
|
159
|
+
* AND both hook entries are structurally wired under the correct event — a partial or stale install
|
|
160
|
+
* is not installed (fix round 1, HIGH findings 1 and 2).
|
|
161
|
+
*/
|
|
162
|
+
readonly installed: boolean;
|
|
163
|
+
/** Present exactly when `installed` is `false` — see {@link ApplyLegNotInstalledReason}. */
|
|
164
|
+
readonly reason?: ApplyLegNotInstalledReason;
|
|
165
|
+
readonly helpers: {
|
|
166
|
+
readonly recallHook: ApplyLegHelperStatus;
|
|
167
|
+
readonly embedDaemon: ApplyLegHelperStatus;
|
|
168
|
+
};
|
|
169
|
+
readonly hooks: {
|
|
170
|
+
readonly userPromptSubmit: ApplyLegHookPresence;
|
|
171
|
+
readonly sessionStart: ApplyLegHookPresence;
|
|
172
|
+
};
|
|
173
|
+
/** From `.dz/config.json`'s `memory.backend`; `'unknown'` when absent/unreadable/unrecognised. */
|
|
174
|
+
readonly backend: 'agentdb' | 'jsonl' | 'unknown';
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* ONE definition of "this command invokes our helper", shared by the installer (`setup.ts`
|
|
178
|
+
* `addIfMissing`) and the diagnostics (`applyLegStatus`) so they can never disagree (re-review
|
|
179
|
+
* Codex, third pass). A bare mention (`echo .claude/helpers/recall-hook.cjs`) is not an invocation:
|
|
180
|
+
* the helper path must follow a `node` word — directly, or inside the daemon's
|
|
181
|
+
* `sh -c 'nohup node "…"'` spawn. Forward slashes only: every command dz writes uses them.
|
|
182
|
+
*/
|
|
183
|
+
export declare function hookCommandInvokes(command: string, markerPath: string): boolean;
|
|
184
|
+
/**
|
|
185
|
+
* Measure the apply leg's actual state in `root` — plain `fs` reads, no injection (mirrors
|
|
186
|
+
* `writerVersionOf`'s own read style): a diagnostic that needed dependency injection to be testable
|
|
187
|
+
* would be a diagnostic nobody could point at a REAL project either. Never throws (fix round 1, Q3):
|
|
188
|
+
* an unreadable helper is a named fact in the return value, not an exception that would otherwise
|
|
189
|
+
* blow through `dz doctor`'s outer try/catch (silence) or crash `dz parity` outright.
|
|
190
|
+
*/
|
|
191
|
+
export declare function applyLegStatus(root: string): ApplyLegStatus;
|
|
192
|
+
/**
|
|
193
|
+
* Human remedy text shared VERBATIM between `dz doctor` and `dz parity` for the two reasons this
|
|
194
|
+
* fix round adds machinery for (fix round 1, HIGH finding 2 / Q3 finding 7): `stale-version` and
|
|
195
|
+
* `unreadable`. Both instruments read the SAME {@link ApplyLegStatus}; routing them through the same
|
|
196
|
+
* text-producing function is what makes "тексты совпадают по причине" a structural guarantee rather
|
|
197
|
+
* than two hand-written strings that happen to agree today. The `missing-helpers`/`hooks-missing`
|
|
198
|
+
* wording is deliberately NOT unified here — `dz doctor` and `dz parity` already carried different
|
|
199
|
+
* (pre-existing, tested) phrasing for that case before this fix round, and unifying it was not asked.
|
|
200
|
+
*/
|
|
201
|
+
export declare function applyLegReasonMessage(status: ApplyLegStatus): string;
|
|
202
|
+
//# sourceMappingURL=apply-leg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-leg.d.ts","sourceRoot":"","sources":["../src/apply-leg.ts"],"names":[],"mappings":"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"}
|