@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/README.md
CHANGED
|
@@ -15,6 +15,10 @@ including `execSync(` and `execFile(`, and fails when the list and census differ
|
|
|
15
15
|
whitespace-collapsed text matches exactly (case-sensitive), optionally within one metadata domain,
|
|
16
16
|
and reports whether that existing lesson is quarantined.
|
|
17
17
|
|
|
18
|
+
Карантин: источник правды — лексический стор; зеркало — проекция; `dz vector reindex`
|
|
19
|
+
пересобирает зеркало из лексических записей и восстанавливает паритет меток. Прямая правка
|
|
20
|
+
зеркала не меняет авторитетное состояние и при следующем перестроении будет утрачена.
|
|
21
|
+
|
|
18
22
|
`countLearningStoreRowsReadonly()` reports the mirror as TWO figures, deliberately not one.
|
|
19
23
|
`vectorRows` stays the whole mirror (lessons + backlog ideas + book units) because the store guard
|
|
20
24
|
reads it as an integrity signal against a recorded high-water mark; narrowing it would present a
|
|
@@ -246,6 +250,10 @@ compatibility path.
|
|
|
246
250
|
|
|
247
251
|
### Mutation registry: entry-scoped refusal and declared gaps
|
|
248
252
|
|
|
253
|
+
Every new mutable registry entry must carry an `observed` count measured by running
|
|
254
|
+
`dz mutation-gate --only <id>`. Legacy entries without that field are tracked as debt: the current
|
|
255
|
+
ceiling lives in `test/observed-debt-ceiling.json` and may move only downward.
|
|
256
|
+
|
|
249
257
|
Run outcomes distinguish **green**, **tests-failed**, **runner-infrastructure**, and
|
|
250
258
|
**unknown-nonzero**. The existing API keeps its names: the exit code identifies green;
|
|
251
259
|
`classifyRunFailure(output)` classifies nonzero runs as `assertions` (tests-failed),
|
|
@@ -520,6 +528,52 @@ protection by making at least one named test red; each
|
|
|
520
528
|
protection, when deleted from the source, turns at least one named test red. Design record:
|
|
521
529
|
`features/destructive-command-guard/03_adr/001-narrow-by-decidability.md`.
|
|
522
530
|
|
|
531
|
+
## Apply-leg module (`apply-leg.ts`) — the third self-learning leg, shipped by `dz setup`
|
|
532
|
+
|
|
533
|
+
Self-learning is COLLECT (session hooks → store) → RANK (`dz teach`/`dz recall`/`dz consolidate`) →
|
|
534
|
+
APPLY (a `UserPromptSubmit` hook injects ranked lessons back into the next prompt). Before this
|
|
535
|
+
module, `runSetup` shipped the first two legs; the third existed only as two hand-committed files
|
|
536
|
+
in this repo's own `.claude/helpers/` — every OTHER project that ran `dz setup --memory agentdb`
|
|
537
|
+
got collection and ranking but never automatic recall injection (MEASURED 2026-09-12: a clean
|
|
538
|
+
scratch install on 0.8.10/0.8.22, with or without `--memory agentdb`, wrote no `UserPromptSubmit`
|
|
539
|
+
hook entry at all).
|
|
540
|
+
|
|
541
|
+
`apply-leg.ts` is the versioned SOURCE of that leg, in the same shape `AGENTDB_WRITER_VERSION`/
|
|
542
|
+
`generateAgentdbWriter` already used for the session-hook writer:
|
|
543
|
+
|
|
544
|
+
- `APPLY_LEG_VERSION` / `applyLegVersionOf(content)` — the `// dz-apply-leg-version: N` stamp
|
|
545
|
+
(line 2 of both generated files) and its parser. Unlike `writerVersionOf` (floors an absent stamp
|
|
546
|
+
at `0`), `applyLegVersionOf` returns `-1` for "never installed" so `applyLegStatus` can tell that
|
|
547
|
+
apart from "installed at v0".
|
|
548
|
+
- `recallHookSource(coreDistDir)` / `embedDaemonSource()` — the two generated files, byte-for-byte
|
|
549
|
+
identical to the pre-existing hand-committed hub copies except for the version stamp and (recall
|
|
550
|
+
hook only) the resolve-candidate list. `coreDistDir` is baked in as the FIRST candidate
|
|
551
|
+
`loadCoreModule` tries — an absolute path the CALLER resolves (the installing CLI's own
|
|
552
|
+
`@dzhechkov/harness-core`, or the hub's own `harnessCoreDistDir()` for its own copies) — replacing
|
|
553
|
+
a hard-coded `/usr/lib/node_modules/...` guess that failed on any other npm prefix (nvm,
|
|
554
|
+
`/usr/local`, a differently-rooted global install).
|
|
555
|
+
- `applyLegHookEntries()` — the exact `UserPromptSubmit`/`SessionStart` hook-registry entries
|
|
556
|
+
`runSetup` merges into `.claude/settings.json` (a swallowed non-zero exit on the recall hook so a
|
|
557
|
+
broken body never blocks a prompt; a detached `nohup` spawn for the daemon so `SessionStart` never
|
|
558
|
+
waits on the ~1.5 s model load).
|
|
559
|
+
- `applyLegStatus(root)` — the ONE measurement `dz doctor` and `dz parity` both read: do both helper
|
|
560
|
+
files exist, at what version, and does `settings.json` actually reference them? Neither surface
|
|
561
|
+
may declare the leg "installed" from a static capability table again (ADR-001 Decision 3) — a
|
|
562
|
+
project with `memory.backend=agentdb` configured and nothing else gets a NAMED red row from
|
|
563
|
+
`dz doctor` (`apply-leg installed`, `ok:false`) and a `manual` cell from `dz parity`, never a
|
|
564
|
+
silent `✓`.
|
|
565
|
+
|
|
566
|
+
`runSetup`'s "Install apply-leg" step (agentdb backend only — jsonl reports `skipped` with the
|
|
567
|
+
named reason: the embed daemon needs agentdb's transitive transformers dependency) also creates an
|
|
568
|
+
EMPTY, schema-only `.dz/agentdb.db` via `ensureAgentdbSchema` (`agentdb-index.ts`, reusing
|
|
569
|
+
`REASONING_BANK_SCHEMA` verbatim — never a second, duplicated schema string) when the file does not
|
|
570
|
+
already exist, so `dz teach` has somewhere to mirror into before any session has ever ended.
|
|
571
|
+
|
|
572
|
+
The hub regenerates its OWN `.claude/helpers/recall-hook.cjs`/`dz-embed-daemon.mjs` from this same
|
|
573
|
+
generator (with the hub's own `coreDistDir`, via `harnessCoreDistDir()`) — a twins test
|
|
574
|
+
(`test/apply-leg-twins.test.ts`) keeps the two byte-identical, the same discipline `feature-adr`'s
|
|
575
|
+
workflow twins test applies to its own generated scripts.
|
|
576
|
+
|
|
523
577
|
## Run a plan without the Claude host
|
|
524
578
|
|
|
525
579
|
`runWorkflow` (`workflow-run.ts`) is the PURE scheduler behind `dz workflow run`: it INTERPRETS a
|
|
@@ -708,6 +762,221 @@ rule is forced SOFT even under hostile HARD configuration, and observations do n
|
|
|
708
762
|
the verdict reducer. Source comments, comment density, and prose classification are outside this
|
|
709
763
|
decision domain: justification is neither scored nor offered as a trimming target.
|
|
710
764
|
|
|
765
|
+
## Reads from a read-only-mounted store (ADR-001, `store-readonly-reads`)
|
|
766
|
+
|
|
767
|
+
`dz recall`, `dz recall --books`, and `dz brain query`/`dz brain ground` read the pattern store
|
|
768
|
+
(`patterns.sqlite`) and the book KB (`books.sqlite`) through `@dzhechkov/memory`'s
|
|
769
|
+
`openSqliteReadOnly` ladder rather than the writer's `SqliteBackend.open`/`openDb`. Observable
|
|
770
|
+
consequences: these commands now work when their store's directory is mounted read-only (e.g. a
|
|
771
|
+
sandboxed runtime) — falling back to a temporary copy when the file cannot be opened in place —
|
|
772
|
+
and, on the common case (a writable directory), the read no longer runs `CREATE TABLE`/FTS-rebuild
|
|
773
|
+
DDL on every invocation. `recallPatterns`/`loadStorePatternsSync` keep their existing
|
|
774
|
+
graceful-empty contract on any open failure (they fall through to the JSON store); `dz recall
|
|
775
|
+
--books` keeps its throw-vs-`{error}` distinction (an unreadable store still exits non-zero naming
|
|
776
|
+
the cause — see `books-recall-honesty` coverage in `book-kb.ts`). A residual (`readonly-residuals`):
|
|
777
|
+
the post-open `busy_timeout` pragma on both readonly wrappers now goes through
|
|
778
|
+
`applyReadonlyPragmas`, which closes the connection and cleans up a tmp-copy before rethrowing if
|
|
779
|
+
the pragma itself throws, instead of leaking both on that failure; and `recallPatterns`/
|
|
780
|
+
`loadStorePatternsSync` distinguish "native `better-sqlite3` unavailable" (silent JSON fallback,
|
|
781
|
+
unchanged) from "the store file itself is unreadable" (corrupt file, permission failure), printing
|
|
782
|
+
one `dz: <path> unreadable (<cause>) — falling back to the JSON store` line on stderr per process in
|
|
783
|
+
the second case, so a broken store no longer looks like plain "fewer lessons".
|
|
784
|
+
|
|
785
|
+
## Consistent pre-reindex snapshot + rollback (`agentdb-snapshot.ts`)
|
|
786
|
+
|
|
787
|
+
The pre-reindex snapshot `reindexAgentdbRows` takes before every reindex used to be a bare
|
|
788
|
+
`copyFileSync(dbFile, backupPath)` — one file, no `-wal` sidecar. A WAL-mode sqlite database can
|
|
789
|
+
hold committed rows in `-wal` that never reached the main file (autocheckpoint disabled, or simply
|
|
790
|
+
a writer connection still open between commits), so copying only the main file silently drops them
|
|
791
|
+
— the "undo point" a rollback relies on could already be missing exactly the rows a rollback is
|
|
792
|
+
meant to restore. MEASURED (scratch repro, 2026-09-13, real `better-sqlite3`): a schema + one row
|
|
793
|
+
checkpointed, then a second row inserted on a connection kept open (`wal_autocheckpoint = 0`) —
|
|
794
|
+
`copyFileSync` alone produces a backup with 1 row; `VACUUM INTO` on a fresh read-only connection to
|
|
795
|
+
the SAME live db produces 2.
|
|
796
|
+
|
|
797
|
+
- `snapshotSqliteDatabase(Database, dbFile, backupPath, opts?)` — default strategy: opens `dbFile`
|
|
798
|
+
READ-ONLY and runs `VACUUM INTO '<backupPath>'` (the path is escaped as a single-quoted sqlite
|
|
799
|
+
string literal). One output file, every committed transaction including `-wal` frames, and the
|
|
800
|
+
live database is untouched — MEASURED: the main file's hash and the `-wal` file's size are
|
|
801
|
+
identical before and after the call. On any failure (older sqlite without `VACUUM INTO`, a
|
|
802
|
+
locked/foreign file, no free disk) — or when `opts.strategy: 'copy+wal'` forces it — falls back to
|
|
803
|
+
`copyFileSync(dbFile, backupPath)` plus a copy of `dbFile-wal` to `backupPath-wal` when the WAL
|
|
804
|
+
sibling exists and is non-empty. The outcome always names how it actually happened:
|
|
805
|
+
`{ method: 'vacuum-into' | 'copy+wal' | 'copy', note?: string }` — `note` carries the fallback
|
|
806
|
+
reason, so a caller/report never claims a stronger guarantee than it got. **Refuses an existing,
|
|
807
|
+
non-empty `backupPath` before any write** (fix round AM-4, Codex review Grade C) — throws
|
|
808
|
+
`snapshot target exists and is non-empty: <path>` rather than silently clobbering whatever the
|
|
809
|
+
path already held; the target is left byte-identical. Also clears any `backupPath-wal`/`-shm`
|
|
810
|
+
sidecar BEFORE either strategy writes anything, and again right after a successful `VACUUM INTO`
|
|
811
|
+
(AM-1) — a leftover sidecar from an earlier, unrelated snapshot family reusing the same path must
|
|
812
|
+
never sit next to (and later be mistaken for part of) a fresh snapshot. The `-wal` size probe now
|
|
813
|
+
calls `statSync` directly and treats only a confirmed `ENOENT` as "no WAL, method: copy" (AM-2) —
|
|
814
|
+
any other stat error (`EACCES`, `EIO`, a raced deletion) aborts the whole snapshot with a thrown
|
|
815
|
+
exception instead of silently degrading to a weaker, falsely-honest-looking `copy`.
|
|
816
|
+
- `restoreSqliteSnapshot(dbFile, backupPath, method)` — the paired rollback. `method` is the EXACT
|
|
817
|
+
`SnapshotMethod` the paired `snapshotSqliteDatabase` call returned (AM-1, fix round) — never
|
|
818
|
+
re-derived from whether `backupPath-wal` happens to exist on disk, which a stale sidecar from an
|
|
819
|
+
unrelated earlier snapshot at the same path could satisfy and cause the wrong generation of `-wal`
|
|
820
|
+
to be restored. Copies `backupPath` over `dbFile`; when `method === 'copy+wal'`, also restores
|
|
821
|
+
`backupPath-wal` to `dbFile-wal` — otherwise (`'vacuum-into'` or `'copy'`) removes any LIVE
|
|
822
|
+
`dbFile-wal` instead. MEASURED: skipping that removal leaves a reopened "restored" db replaying
|
|
823
|
+
the stale WAL's frames (a since-superseded write) on top of the reverted main file — rows come
|
|
824
|
+
back EMPTY instead of the restored set. `dbFile-shm` is always removed (its offsets are only valid
|
|
825
|
+
for the `-wal` that no longer matches). **The caller must close its write connection to `dbFile`
|
|
826
|
+
before calling this** — it is a plain file copy, not a sqlite-mediated rollback, and a live handle
|
|
827
|
+
can reintroduce exactly the frames being undone. Returns `{ ok: true }` or `{ ok: false, error }`
|
|
828
|
+
(AM-3, fix round) — a failing restore (e.g. the destination path unwritable) is reported, never
|
|
829
|
+
silently swallowed as if the rollback had succeeded.
|
|
830
|
+
|
|
831
|
+
`reindexAgentdbRows` wires both in: sqlite now resolves (`require.resolve('better-sqlite3')` +
|
|
832
|
+
dynamic `import`) BEFORE any snapshot is attempted, so an unavailable dependency aborts with
|
|
833
|
+
`DEPS_MISSING` and no new `pre-reindex-*` file on disk (previously a snapshot could be taken and
|
|
834
|
+
then immediately discarded by a deps-missing error — a mixed-signal failure). `opts.backupPath`,
|
|
835
|
+
when given, must resolve INSIDE `dirname(dbFile)` (AM-5, fix round — checked via `resolve` +
|
|
836
|
+
`relative`, so neither a `..`-escaping relative path nor a foreign absolute path can steer the
|
|
837
|
+
snapshot outside the db's own directory); violating it aborts with no snapshot attempted at all. The
|
|
838
|
+
result gains `snapshotMethod?` / `snapshotNote?`, named whenever a snapshot ran (including when a
|
|
839
|
+
LATER best-effort step, like copying the sibling embed-manifest, fails) — "absence of a receipt is
|
|
840
|
+
not success". On a reindex failure, the result also gains `rollback: 'restored' | 'failed'` and
|
|
841
|
+
`rollbackError?` (AM-3, fix round) — `rollback()` now closes over `restoreSqliteSnapshot`'s
|
|
842
|
+
`{ ok, error }` outcome instead of a bare `copyFileSync` it used to fire-and-forget, and a failed
|
|
843
|
+
restore is folded into the top-level `error` string as `"<reindex error>; rollback failed: <why>"`
|
|
844
|
+
rather than reported as if the rollback had quietly succeeded. `rollback()` only ever runs after
|
|
845
|
+
every write connection this function opened has already been closed (the DELETE's own
|
|
846
|
+
`finally { db.close() }`, and `indexPatternsToAgentdb`'s own). Test:
|
|
847
|
+
`opts.snapshotStrategy?: 'vacuum-into' | 'copy+wal'` forces the fallback path for deterministic
|
|
848
|
+
coverage of `method: 'copy+wal'` without needing an actually-broken sqlite.
|
|
849
|
+
|
|
850
|
+
## Pre-reindex snapshot rotation (`agentdb-snapshot-rotation.ts`)
|
|
851
|
+
|
|
852
|
+
`reindexAgentdbRows` (`agentdb-index.ts`) copies the store to `<db>.pre-reindex-<ms>.bak` (+
|
|
853
|
+
`.embed-manifest.json`/`-shm`/`-wal` siblings) before every reindex, as an undo point — and nothing
|
|
854
|
+
had ever pruned them: 13 snapshots / 50 MB observed on the owner's own hub. `agentdb-snapshot-rotation.ts`
|
|
855
|
+
is the fix, split PURE/effect (NFR-2):
|
|
856
|
+
|
|
857
|
+
- `listPreReindexSnapshots(dbFile)` — reads the directory next to `dbFile`, groups matches of the
|
|
858
|
+
STRICT regex `^<basename>\.pre-reindex-(\d+)\.bak(\.embed-manifest\.json|-shm|-wal)?$` into
|
|
859
|
+
families by their `<ms>` timestamp. Nothing else in the directory is a candidate — `agentdb.db.bak`
|
|
860
|
+
and `other.pre-reindex-1.bak` next to `agentdb.db` are left alone. Symlinks are never followed and
|
|
861
|
+
never rotated (`lstatSync`, never `stat`): a matching NAME that resolves to a symlink is excluded
|
|
862
|
+
entirely, not "rotated by its link size". An orphaned sibling with no `.bak` (e.g. a lone `-shm`)
|
|
863
|
+
still forms its own one-file family under its own `<ms>`.
|
|
864
|
+
- `planSnapshotRotation(families, { keep, protectMs, now, graceMs })` — pure decision, zero fs: the
|
|
865
|
+
newest `keep` families survive; the family just created by THIS call (`protectMs`) is rescued even
|
|
866
|
+
beyond `keep` and even at `keep=0` — the boundary case named by the requirement — but is NOT
|
|
867
|
+
double-counted when it already falls inside the top-`keep` slice (the ordinary case, since a fresh
|
|
868
|
+
backup is normally the newest family already). **Grace period (fix-round AM-3):** ANY family
|
|
869
|
+
younger than `graceMs` (default 10 minutes; `ms > now - graceMs`) is rescued too, even past `keep`
|
|
870
|
+
— a snapshot from a DIFFERENT process/run than the one calling this must never look "old" just
|
|
871
|
+
because nobody named it via `protectMs`. There is no CLI flag to shorten or disable it; `now`/
|
|
872
|
+
`graceMs` exist only so tests can be deterministic.
|
|
873
|
+
- `rotatePreReindexSnapshots(dbFile, { keep = 3, protectPath })` — the fs-effect wrapper: list, plan,
|
|
874
|
+
`unlinkSync` each file of every removed family. Three fix-round hardenings, all closing a real
|
|
875
|
+
Codex-review Grade-D finding:
|
|
876
|
+
- **`keep` is validated before anything is read or deleted** (AM-1): `Number.isSafeInteger(keep)
|
|
877
|
+
&& keep >= 0`, else the call returns `{ kept: [], removed: [], errors: ['invalid keep: …'] }` and
|
|
878
|
+
touches nothing. The bug this closes: `Math.max(0, NaN)` is `NaN`, and `sorted.slice(0, NaN)` is
|
|
879
|
+
`[]` — an EMPTY kept slice, so a `NaN`/negative `keep` used to delete every existing family.
|
|
880
|
+
- **A scan error blocks deletion, not just gets logged** (AM-4): a `readdirSync`/`lstatSync`
|
|
881
|
+
failure other than ENOENT lands in `report.scanErrors: string[]` and this call removes NOTHING —
|
|
882
|
+
an incomplete candidate list can never be safely read as "these are all the old ones".
|
|
883
|
+
- **Within a family, siblings unlink first and `.bak` last, and only if every sibling
|
|
884
|
+
succeeded** (AM-2): a failed sibling unlink leaves the `.bak` — the one file that alone still
|
|
885
|
+
proves the snapshot existed — in place, and names the family's `<ms>` in
|
|
886
|
+
`report.partialFamilies: number[]`, rather than guessing the family is gone.
|
|
887
|
+
- A per-file failure still lands in `report.errors[]` and never stops the rest of the rotation or
|
|
888
|
+
the caller's own success — "no receipt is not success", so every removed file is named, never
|
|
889
|
+
just counted.
|
|
890
|
+
- An absurd `<ms>` in a matching filename (not a safe non-negative integer, or beyond `Date`'s
|
|
891
|
+
representable `±8.64e15`) is never grouped into a candidate family (AM-5) — it never reaches
|
|
892
|
+
`new Date(ms)`, which throws `RangeError` past that bound.
|
|
893
|
+
|
|
894
|
+
`reindexAgentdbRows` calls this automatically on its SUCCESS path only (`opts.keepSnapshots ?? 3`),
|
|
895
|
+
adding a `snapshots?: SnapshotRotationReport` field to its result; an `error` return never rotates
|
|
896
|
+
anything (old snapshots may be the only working copy left at that moment). `reindexBrainVectors`
|
|
897
|
+
(`brain.ts`) forwards the same field verbatim, so `dz brain reindex` reports it too.
|
|
898
|
+
|
|
899
|
+
For rotation WITHOUT running a reindex — the owner's hub forbids a live reindex there today, and
|
|
900
|
+
had 13 unrotated snapshots regardless — see `dz brain snapshots [--keep N] [--prune]` in the CLI
|
|
901
|
+
README.
|
|
902
|
+
|
|
903
|
+
## Snapshot lock + reindex-in-progress marker (`agentdb-reindex-marker.ts`)
|
|
904
|
+
|
|
905
|
+
**Recovery-required marker (lead edit after Codex re-review, 2026-09-13).** When a reindex fails AND its rollback
|
|
906
|
+
fails too, the marker is rewritten (owner token, atomic tmp+rename) with `requiresRecovery: true`. Such a marker never
|
|
907
|
+
expires: rotation keeps protecting its family and prints a note, and every new reindex of that store is refused with
|
|
908
|
+
`recovery required: … restore <snapshot> manually, then remove marker <path>`. Every marker mutation (create, stale
|
|
909
|
+
replacement, clear, recovery flag) runs under the same `agentdb-snapshot` lock, so compare-and-delete cannot
|
|
910
|
+
interleave with another owner. A snapshot that throws inside the locked section clears its own marker before the
|
|
911
|
+
error propagates.
|
|
912
|
+
|
|
913
|
+
Snapshot creation (`reindexAgentdbRows`), rotation (`rotatePreReindexSnapshots`) and restore
|
|
914
|
+
(`restoreSqliteSnapshot` via rollback) are three writers of ONE directory — before this feature they
|
|
915
|
+
had NO mutual exclusion, and only the 10-minute grace period above stood between a concurrent
|
|
916
|
+
`rotate --keep 0` and the very snapshot family a live reindex was relying on as its undo point.
|
|
917
|
+
|
|
918
|
+
- `withAgentdbSnapshotLock(dbFile, fn, opts?)` — a thin, `dbFile`-addressed wrapper over
|
|
919
|
+
`withNamedLockSync`: the lock lives at `<dirname(dbFile)>/.dz/locks/agentdb-snapshot.lock`, a pure
|
|
920
|
+
function of the database's OWN directory, never of `process.cwd()` — a project store and the home
|
|
921
|
+
brain each get their own lock. All three snapshot writers now run their file operations
|
|
922
|
+
(`VACUUM INTO`/copy, unlink, restore) under this lock; a `NamedLockTimeoutError` propagates as an
|
|
923
|
+
explicit `error` (`reindexAgentdbRows`: `"snapshot lock busy: …"`, no snapshot, no db change;
|
|
924
|
+
`rotatePreReindexSnapshots`: `{ removed: [], errors: ['lock busy: …'] }`) — never a silent skip.
|
|
925
|
+
The critical section stays SHORT and SYNCHRONOUS by design: re-embedding (the network/CPU-bound
|
|
926
|
+
part of a reindex) runs OUTSIDE the lock, exactly as the store-lock/named-lock lesson requires.
|
|
927
|
+
- **The lock is never acquired twice in one call stack** (NFR-2): `rotatePreReindexSnapshotsUnlocked`
|
|
928
|
+
is the pure fs-effect primitive with no lock of its own; the PUBLIC `rotatePreReindexSnapshots`
|
|
929
|
+
wraps it in one lock acquisition, and `reindexAgentdbRows`'s own success-path rotation wraps it in
|
|
930
|
+
its OWN separate acquisition — never through the public wrapper, which would try to take the same
|
|
931
|
+
named lock a second time while the first was still logically "in flight" for this call.
|
|
932
|
+
- `writeReindexMarker(dbFile, { ms, pid, startedAt, backupPath? })` / `clearReindexMarker(dbFile,
|
|
933
|
+
token)` — a `<dbFile>.reindex-inprogress.json` marker written at the start of `reindexAgentdbRows`,
|
|
934
|
+
INSIDE the same locked critical section as the snapshot itself (never before the lock is even
|
|
935
|
+
attempted, so a busy lock leaves the directory byte-identical — no snapshot AND no marker). Removed
|
|
936
|
+
in `finally` on every path EXCEPT one (below). `ms` is recomputed from the actual `backupPath`'s
|
|
937
|
+
filename, not from whatever internal counter built the default one — a non-standard `backupPath`
|
|
938
|
+
(no `.pre-reindex-<n>.bak` suffix) names no family, so the marker carries `ms: null` plus the
|
|
939
|
+
literal `backupPath` for an operator to identify it by.
|
|
940
|
+
- **Marker OWNERSHIP (fix-round, 2026-09-13).** `writeReindexMarker` creates the file EXCLUSIVELY
|
|
941
|
+
(`openSync(path, 'wx')`) and stamps it with a random 16-hex-char `token`. A LIVE marker already at
|
|
942
|
+
that path — a genuinely concurrent reindex of the SAME store — refuses the call outright:
|
|
943
|
+
`{ ok: false, error: 'reindex already in progress (marker <path>)' }`, with NO snapshot ever taken
|
|
944
|
+
for the refused attempt (nothing was deleted, so there is nothing to roll back). A marker at or past
|
|
945
|
+
the TTL is replaced. `clearReindexMarker` is compare-and-delete: it removes the marker ONLY when the
|
|
946
|
+
caller's `token` matches the one on disk — a process can never tear down a marker it does not own —
|
|
947
|
+
returning `{ cleared: false, reason }` otherwise (an absent marker is treated as an idempotent
|
|
948
|
+
`{ cleared: true }`).
|
|
949
|
+
- **A rollback that cannot re-take the lock leaves the marker in place (fix-round, 2026-09-13).** If
|
|
950
|
+
the forward reindex fails and needs to roll back, and the rollback's OWN lock re-acquisition times
|
|
951
|
+
out, the marker is deliberately NOT cleared — its family may be the only intact copy of the
|
|
952
|
+
pre-reindex state, and clearing the marker would let a concurrent `dz brain snapshots --prune`
|
|
953
|
+
delete it out from under an operator who has not yet acted. The returned `error` names BOTH paths
|
|
954
|
+
explicitly (`"…; snapshot at <backupPath> was not confirmed restored; marker at <path> is left in
|
|
955
|
+
place — requires manual recovery"`), and `rollback: 'failed'` / `rollbackError` surface the
|
|
956
|
+
underlying reason (typically `lock busy: …`). Recovery is manual: inspect the snapshot at the named
|
|
957
|
+
path, restore it by hand if needed, then remove the marker file directly.
|
|
958
|
+
- `readLiveReindexMarkers(dbFile, now?)` — a marker younger than `REINDEX_MARKER_TTL_MS` (60 min)
|
|
959
|
+
rescues its `ms` from rotation, even at `keep=0` and `graceMs=0` (a `ms: null` marker protects
|
|
960
|
+
nothing — there is no family to protect); a marker at or past the TTL is abandoned — removal is
|
|
961
|
+
attempted and the outcome is reported HONESTLY in the rotation report's `notes: string[]` field:
|
|
962
|
+
`"… ignored and removed"` only once the removal actually succeeded, `"… ignored, removal failed:
|
|
963
|
+
<err>"` when it did not (fix-round, 2026-09-13 — the previous wording always said "removed" even
|
|
964
|
+
when the underlying `rmSync` failed). **`pid` is recorded for operator debugging only and is NEVER
|
|
965
|
+
consulted for liveness** — the same "pid is not authority" lesson `store-lock.ts`/`named-lock.ts`
|
|
966
|
+
already encode for lock staleness; a marker with an obviously-dead `pid` and a fresh `startedAt` is
|
|
967
|
+
still treated as live.
|
|
968
|
+
- **Stale threshold: 5 minutes (fix-round, 2026-09-13).** `withAgentdbSnapshotLock` defaults
|
|
969
|
+
`staleMs` to `AGENTDB_SNAPSHOT_LOCK_STALE_MS` (300 000 ms) rather than named-lock's ordinary 30s
|
|
970
|
+
default — MEASURED: `VACUUM INTO` on an 8.45 MB agentdb store took 96 ms, so 5 minutes leaves
|
|
971
|
+
roughly 3000x headroom while staying inside named-lock's own 600 000 ms environment-override
|
|
972
|
+
ceiling. **A database whose snapshot genuinely takes longer than 5 minutes needs external
|
|
973
|
+
coordination** (a bigger default is not the fix); a caller doing something unusual may still pass
|
|
974
|
+
its own `staleMs`.
|
|
975
|
+
- **`rotatePreReindexSnapshotsUnlocked` is package-internal only (fix-round, 2026-09-13).** It is no
|
|
976
|
+
longer exported from this package's public barrel — the public rotation API is
|
|
977
|
+
`rotatePreReindexSnapshots`, which always takes the snapshot lock. Exporting the unlocked primitive
|
|
978
|
+
would hand outside callers a way to rotate with no mutual exclusion at all.
|
|
979
|
+
|
|
711
980
|
## Status
|
|
712
981
|
|
|
713
982
|
`dz guard check --op publish` now warns when either release line disagrees with the core/CLI package versions, and a registry-confirmed live core or CLI publish synchronizes the first such line in both release READMEs: each README is rewritten atomically; the pair is not one transaction (dry-run and bump-only never write them).
|
package/dist/agentdb-index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @packageDocumentation
|
|
13
13
|
*/
|
|
14
|
+
import { type SnapshotRotationReport } from './agentdb-snapshot-rotation.js';
|
|
15
|
+
import { type SnapshotMethod } from './agentdb-snapshot.js';
|
|
14
16
|
/** One record to index. `text` is stored as `approach` AND embedded (`${taskType}: ${text}`). */
|
|
15
17
|
export interface AgentdbRow {
|
|
16
18
|
readonly taskType: string;
|
|
@@ -29,6 +31,33 @@ export interface AgentdbIndexResult {
|
|
|
29
31
|
}
|
|
30
32
|
/** Resolve the shared store path: explicit opt → AGENTDB_PATH env → `<project>/.dz/agentdb.db`. */
|
|
31
33
|
export declare function resolveAgentdbPath(projectRoot: string, dbPath?: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Create (or verify) an EMPTY AgentDB-schema store at `resolveAgentdbPath(projectRoot, dbPath)`,
|
|
36
|
+
* without indexing any rows (AM-4, feature `setup-installs-apply-leg`, dz-harness-hub issue #10
|
|
37
|
+
* defect 4).
|
|
38
|
+
*
|
|
39
|
+
* WHY THIS EXISTS: before this, `.dz/agentdb.db` came into being only as a side effect of the
|
|
40
|
+
* SessionEnd/PreCompact writer's first `dz consolidate` — so a project that had run
|
|
41
|
+
* `dz setup --memory agentdb` but not yet completed one full session had `memory.backend=agentdb`
|
|
42
|
+
* configured with NO database file at all, and any lesson taught in that window before the first
|
|
43
|
+
* consolidate had nothing to mirror into (the apply leg's daemon reads THIS file — see
|
|
44
|
+
* `dz-embed-daemon.mjs`). `dz setup`'s "Install apply-leg" step now calls this directly so the
|
|
45
|
+
* store exists from the moment setup finishes, not from the moment a session happens to end.
|
|
46
|
+
*
|
|
47
|
+
* SYNCHRONOUS deliberately: `runSetup` is a synchronous function (a `child_process.execSync`
|
|
48
|
+
* install already precedes every write it does), and creating an empty schema needs only
|
|
49
|
+
* `better-sqlite3` — never the async `EmbeddingService` {@link indexPatternsToAgentdb} loads for a
|
|
50
|
+
* real write. Reuses {@link REASONING_BANK_SCHEMA} verbatim — the ONE schema string every writer in
|
|
51
|
+
* this module execs — so this path can never drift into declaring a second, competing schema.
|
|
52
|
+
*
|
|
53
|
+
* Best-effort, like every setup step: a project without `better-sqlite3` installed yet (or one
|
|
54
|
+
* whose native binary is unusable) gets `{ok:false, error}` and setup reports it in the step detail
|
|
55
|
+
* rather than throwing — the writer/daemon still self-heal on the next session either way.
|
|
56
|
+
*/
|
|
57
|
+
export declare function ensureAgentdbSchema(projectRoot: string, dbPath?: string): {
|
|
58
|
+
readonly ok: boolean;
|
|
59
|
+
readonly error?: string;
|
|
60
|
+
};
|
|
32
61
|
/**
|
|
33
62
|
* Index `rows` into the shared AgentDB vector store. Returns `{indexed:0}` for an empty input and
|
|
34
63
|
* `{indexed:0, error}` when `agentdb`/`better-sqlite3` cannot be resolved from the project.
|
|
@@ -192,6 +221,12 @@ export declare function reindexAgentdbRows(projectRoot: string, rows: readonly A
|
|
|
192
221
|
dbPath?: string;
|
|
193
222
|
taskTypes?: readonly string[];
|
|
194
223
|
backupPath?: string;
|
|
224
|
+
keepSnapshots?: number;
|
|
225
|
+
/** Force the fallback snapshot path — test-only injection for AC-2 (FR-2). */
|
|
226
|
+
snapshotStrategy?: 'vacuum-into' | 'copy+wal';
|
|
227
|
+
/** agentdb-snapshot-lock: test/tuning-only override for the snapshot-lock acquisition deadline
|
|
228
|
+
* — omitted, the lock uses its ordinary default timeout. */
|
|
229
|
+
lockTimeoutMs?: number;
|
|
195
230
|
}): Promise<{
|
|
196
231
|
reembedded: number;
|
|
197
232
|
model?: string;
|
|
@@ -200,5 +235,15 @@ export declare function reindexAgentdbRows(projectRoot: string, rows: readonly A
|
|
|
200
235
|
error?: string;
|
|
201
236
|
/** Task types left in the OLD embedding space because this reindex does not own them. */
|
|
202
237
|
staleTaskTypes?: string[];
|
|
238
|
+
/** Pre-reindex snapshot rotation outcome — present ONLY on a successful reindex (FR-6). */
|
|
239
|
+
snapshots?: SnapshotRotationReport;
|
|
240
|
+
/** How the pre-reindex snapshot was actually taken — always named when a snapshot ran (FR-2). */
|
|
241
|
+
snapshotMethod?: SnapshotMethod;
|
|
242
|
+
/** Present only for a fallback method — the reason `vacuum-into` did not run (FR-2). */
|
|
243
|
+
snapshotNote?: string;
|
|
244
|
+
/** AM-3: present whenever a rollback was attempted — 'restored' is the only success signal. */
|
|
245
|
+
rollback?: 'restored' | 'failed';
|
|
246
|
+
/** AM-3: present only when `rollback === 'failed'` — why the restore did not fully complete. */
|
|
247
|
+
rollbackError?: string;
|
|
203
248
|
}>;
|
|
204
249
|
//# sourceMappingURL=agentdb-index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentdb-index.d.ts","sourceRoot":"","sources":["../src/agentdb-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;
|
|
1
|
+
{"version":3,"file":"agentdb-index.d.ts","sourceRoot":"","sources":["../src/agentdb-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAUH,OAAO,EAAqC,KAAK,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAChH,OAAO,EAAiD,KAAK,cAAc,EAAuB,MAAM,uBAAuB,CAAC;AAehI,iGAAiG;AACjG,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+FAA+F;IAC/F,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,iDAAiD;AACjD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAaD,mGAAmG;AACnG,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAI/E;AAuBD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAiB3H;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,SAAS,UAAU,EAAE,EAC3B,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7B,OAAO,CAAC,kBAAkB,CAAC,CAmF7B;AAMD;;;GAGG;AACH;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,sCAAuC,CAAC;AAG1E;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,oDAAqD,CAAC;AAWtF,6DAA6D;AAC7D,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,kGAAkG;IAClG,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,wGAAwG;AACxG,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,EAAE,CAAC;IAClC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAID;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAgC9E;AA2DD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,MAAM,CAYzE;AAaD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAClG,OAAO,CAAC,mBAAmB,CAAC,CAmD9B;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAO,GAC5D,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC,CAyBxD;AAED;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7B;IAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CA6CxC;AAMD,wEAAwE;AACxE,MAAM,WAAW,gBAAgB;IAC/B,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,mFAAmF;IACnF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7C;AAcD;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,SAAS,gBAAgB,EAAE,EACjC,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAwE/C;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7B;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAmCrC;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAO,GAC5D;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CA2CrC;AAED,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9C;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAuCpC;AAED,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,SAAS,UAAU,EAAE,EAC3B,IAAI,GAAE;IACJ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,aAAa,GAAG,UAAU,CAAC;IAC9C;gEAC4D;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC;CACnB,GACL,OAAO,CAAC;IACT,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,2FAA2F;IAC3F,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,iGAAiG;IACjG,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,wFAAwF;IACxF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;IACjC,gGAAgG;IAChG,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC,CAyRD"}
|