@cleocode/contracts 2026.5.109 → 2026.5.110
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/memory-wire-shapes.test.js.map +1 -1
- package/dist/backup-verify.d.ts +136 -0
- package/dist/backup-verify.d.ts.map +1 -0
- package/dist/backup-verify.js +29 -0
- package/dist/backup-verify.js.map +1 -0
- package/dist/db-inventory.d.ts +12 -5
- package/dist/db-inventory.d.ts.map +1 -1
- package/dist/db-inventory.js +13 -6
- package/dist/db-inventory.js.map +1 -1
- package/dist/db-inventory.json +165 -0
- package/dist/db-recovery.d.ts +141 -0
- package/dist/db-recovery.d.ts.map +1 -0
- package/dist/db-recovery.js +29 -0
- package/dist/db-recovery.js.map +1 -0
- package/dist/doctor.d.ts +453 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/memory/observe.d.ts +8 -0
- package/dist/memory/observe.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/__tests__/memory-wire-shapes.test.ts +1 -0
- package/src/backup-verify.ts +140 -0
- package/src/db-inventory.json +165 -0
- package/src/db-inventory.ts +13 -6
- package/src/db-recovery.ts +144 -0
- package/src/doctor.ts +472 -0
- package/src/index.ts +27 -0
- package/src/memory/observe.ts +8 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAyBH,2DAA2D;AAC3D,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,cAAc,GACf,MAAM,6BAA6B,CAAC;AA0DrC,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,EACvB,yBAAyB,EACzB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/memory/observe.d.ts
CHANGED
|
@@ -109,6 +109,14 @@ export interface ObserveBrainParams {
|
|
|
109
109
|
* External callers MUST NOT set this flag.
|
|
110
110
|
*/
|
|
111
111
|
_skipGate?: boolean;
|
|
112
|
+
/**
|
|
113
|
+
* T10351: Internal flag — when true, bypasses the brain writer-thread
|
|
114
|
+
* chokepoint and writes directly. Set ONLY by the writer-thread handler
|
|
115
|
+
* (`brain-writer-handlers.ts`) when re-entering observeBrain from inside
|
|
116
|
+
* the worker, so the routing doesn't recurse forever. External callers
|
|
117
|
+
* MUST NOT set this flag.
|
|
118
|
+
*/
|
|
119
|
+
_skipQueue?: boolean;
|
|
112
120
|
}
|
|
113
121
|
/**
|
|
114
122
|
* Result envelope returned by `observeBrain`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../src/memory/observe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAIzD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,8BAA8B,+DAKjC,CAAC;AAEX;;;;GAIG;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,OAAO,8BAA8B,CAAC,CAAC,MAAM,CAAC,CAAC;AAIzF;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,8FAA8F;IAC9F,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yDAAyD;IACzD,UAAU,CAAC,EAAE,0BAA0B,CAAC;IACxC,yFAAyF;IACzF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,qBAAqB,CAAC;IACzC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAClC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../src/memory/observe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAIzD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,8BAA8B,+DAKjC,CAAC;AAEX;;;;GAIG;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,OAAO,8BAA8B,CAAC,CAAC,MAAM,CAAC,CAAC;AAIzF;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,8FAA8F;IAC9F,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yDAAyD;IACzD,UAAU,CAAC,EAAE,0BAA0B,CAAC;IACxC,yFAAyF;IACzF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,qBAAqB,CAAC;IACzC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAClC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAID;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,yDAAyD;IACzD,EAAE,EAAE,MAAM,CAAC;IACX,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;CACnB;AAID;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,+BAA+B;IAC9C,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,IAAI,EAAE,gBAAgB,CAAC;CACxB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cleocode/contracts",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.110",
|
|
4
4
|
"description": "Domain types, interfaces, and contracts for the CLEO ecosystem",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -138,12 +138,13 @@
|
|
|
138
138
|
"dependencies": {
|
|
139
139
|
"zod": "^4.3.6",
|
|
140
140
|
"zod-to-json-schema": "^3.25.2",
|
|
141
|
-
"@cleocode/lafs": "2026.5.
|
|
141
|
+
"@cleocode/lafs": "2026.5.110"
|
|
142
142
|
},
|
|
143
143
|
"scripts": {
|
|
144
|
-
"build": "tsc -b --force && node scripts/emit-schemas.mjs",
|
|
145
|
-
"build:ts": "tsc -b --force",
|
|
144
|
+
"build": "tsc -b --force && node scripts/copy-assets.mjs && node scripts/emit-schemas.mjs",
|
|
145
|
+
"build:ts": "tsc -b --force && node scripts/copy-assets.mjs",
|
|
146
146
|
"build:schemas": "node scripts/emit-schemas.mjs",
|
|
147
|
+
"build:assets": "node scripts/copy-assets.mjs",
|
|
147
148
|
"typecheck": "tsc --noEmit",
|
|
148
149
|
"test": "vitest run"
|
|
149
150
|
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type contract for `cleo backup verify` — per-DB freshness + integrity walker.
|
|
3
|
+
*
|
|
4
|
+
* `cleo backup verify` walks every entry in `DB_INVENTORY` and reports, for
|
|
5
|
+
* each role, the freshest snapshot in BOTH the canonical backup directory
|
|
6
|
+
* (`.cleo/backups/sqlite/` per T10315) and the legacy backup directory
|
|
7
|
+
* (`.cleo/backups/snapshot/`, kept read-only for one deprecation window).
|
|
8
|
+
* Each snapshot is opened via the canonical chokepoint, verified with
|
|
9
|
+
* `PRAGMA integrity_check`, and surfaced as a structured envelope. Operators
|
|
10
|
+
* use the envelope to detect stale and corrupt backups before they're needed
|
|
11
|
+
* for recovery.
|
|
12
|
+
*
|
|
13
|
+
* Verdict semantics (see {@link BackupVerifyVerdict}):
|
|
14
|
+
*
|
|
15
|
+
* - `healthy` — a fresh snapshot exists (≤ 24h old) AND `integrity_check`
|
|
16
|
+
* returned `ok`.
|
|
17
|
+
* - `stale` — a snapshot exists but its mtime is > 24h old. Integrity may
|
|
18
|
+
* still be OK; the operator should run `cleo backup add` to refresh.
|
|
19
|
+
* - `corrupt` — at least one snapshot exists but the FRESH snapshot failed
|
|
20
|
+
* `integrity_check`. The legacy snapshot may still be usable as a fallback.
|
|
21
|
+
* - `missing` — no snapshot was found in EITHER the canonical or legacy
|
|
22
|
+
* directory. Recovery from snapshot is impossible.
|
|
23
|
+
*
|
|
24
|
+
* @task T10319
|
|
25
|
+
* @epic T10284
|
|
26
|
+
* @saga T10281
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Verdict roll-up for a single role.
|
|
31
|
+
*
|
|
32
|
+
* @public
|
|
33
|
+
*/
|
|
34
|
+
export type BackupVerifyVerdict = 'healthy' | 'stale' | 'corrupt' | 'missing';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Per-snapshot freshness + integrity record.
|
|
38
|
+
*
|
|
39
|
+
* @remarks
|
|
40
|
+
* Returned for both the canonical (`.cleo/backups/sqlite/`) and legacy
|
|
41
|
+
* (`.cleo/backups/snapshot/`) snapshot directories. When no snapshot exists
|
|
42
|
+
* in the corresponding directory the field on the parent
|
|
43
|
+
* {@link BackupVerifyDbReport} is `null` rather than this shape with empty
|
|
44
|
+
* fields — that lets consumers distinguish "no snapshot ever taken" from
|
|
45
|
+
* "snapshot exists but is unhealthy".
|
|
46
|
+
*
|
|
47
|
+
* @public
|
|
48
|
+
*/
|
|
49
|
+
export interface BackupVerifySnapshot {
|
|
50
|
+
/** Absolute path to the snapshot file. */
|
|
51
|
+
readonly path: string;
|
|
52
|
+
/** Snapshot mtime in epoch ms (the freshness signal). */
|
|
53
|
+
readonly mtime: number;
|
|
54
|
+
/**
|
|
55
|
+
* `true` when the snapshot file opened cleanly AND `PRAGMA integrity_check`
|
|
56
|
+
* returned the single row `ok`. `false` otherwise — see {@link error} for
|
|
57
|
+
* details.
|
|
58
|
+
*/
|
|
59
|
+
readonly integrityOK: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Snapshot file size in bytes when `stat()` succeeded; `null` when the
|
|
62
|
+
* file vanished between discovery and stat.
|
|
63
|
+
*/
|
|
64
|
+
readonly sizeBytes: number | null;
|
|
65
|
+
/**
|
|
66
|
+
* Human-readable error message when the snapshot could not be opened or
|
|
67
|
+
* its integrity check threw. `null` on success.
|
|
68
|
+
*/
|
|
69
|
+
readonly error: string | null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Per-DB report — one entry per role in `DB_INVENTORY`.
|
|
74
|
+
*
|
|
75
|
+
* @public
|
|
76
|
+
*/
|
|
77
|
+
export interface BackupVerifyDbReport {
|
|
78
|
+
/** Canonical role identifier (matches `DB_INVENTORY[i].role`). */
|
|
79
|
+
readonly role: string;
|
|
80
|
+
/** Lifecycle tier copied through from the inventory for downstream UI. */
|
|
81
|
+
readonly tier: 'project' | 'global' | 'derived';
|
|
82
|
+
/**
|
|
83
|
+
* Freshest snapshot found under `.cleo/backups/sqlite/` (canonical per
|
|
84
|
+
* T10315) — or `null` when the canonical directory has no snapshot for
|
|
85
|
+
* this role.
|
|
86
|
+
*/
|
|
87
|
+
readonly freshSnapshot: BackupVerifySnapshot | null;
|
|
88
|
+
/**
|
|
89
|
+
* Freshest snapshot found under `.cleo/backups/snapshot/` (legacy, kept
|
|
90
|
+
* read-only during the deprecation window) — or `null` when the legacy
|
|
91
|
+
* directory has no snapshot for this role.
|
|
92
|
+
*/
|
|
93
|
+
readonly legacySnapshot: BackupVerifySnapshot | null;
|
|
94
|
+
/**
|
|
95
|
+
* Hours between `Date.now()` and the freshest available snapshot's mtime
|
|
96
|
+
* (whichever of {@link freshSnapshot} / {@link legacySnapshot} is newer).
|
|
97
|
+
* `null` when {@link verdict} is `missing` — no snapshot to measure from.
|
|
98
|
+
*/
|
|
99
|
+
readonly dataLossEstimateHours: number | null;
|
|
100
|
+
/**
|
|
101
|
+
* Roll-up verdict for this role — see {@link BackupVerifyVerdict}.
|
|
102
|
+
*/
|
|
103
|
+
readonly verdict: BackupVerifyVerdict;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Aggregated counters across every role in the survey. Used by the CLI verb
|
|
108
|
+
* to drive its non-zero exit decision (`stale > 0 || corrupt > 0`).
|
|
109
|
+
*
|
|
110
|
+
* @public
|
|
111
|
+
*/
|
|
112
|
+
export interface BackupVerifySummary {
|
|
113
|
+
/** Number of roles whose verdict is `healthy`. */
|
|
114
|
+
readonly healthy: number;
|
|
115
|
+
/** Number of roles whose verdict is `stale`. */
|
|
116
|
+
readonly stale: number;
|
|
117
|
+
/** Number of roles whose verdict is `corrupt`. */
|
|
118
|
+
readonly corrupt: number;
|
|
119
|
+
/** Number of roles whose verdict is `missing`. */
|
|
120
|
+
readonly missing: number;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Envelope payload returned by `cleo backup verify` (and the underlying
|
|
125
|
+
* {@link runBackupVerify} core helper).
|
|
126
|
+
*
|
|
127
|
+
* @remarks
|
|
128
|
+
* The shape is keyed by role rather than indexed by array position so
|
|
129
|
+
* consumers can `.dbs['brain']` without scanning. The summary is provided
|
|
130
|
+
* pre-computed because the CLI exit code is driven from it — recomputing it
|
|
131
|
+
* downstream would invite drift.
|
|
132
|
+
*
|
|
133
|
+
* @public
|
|
134
|
+
*/
|
|
135
|
+
export interface BackupVerifyResult {
|
|
136
|
+
/** Per-role reports keyed by `DB_INVENTORY[i].role`. */
|
|
137
|
+
readonly dbs: Readonly<Record<string, BackupVerifyDbReport>>;
|
|
138
|
+
/** Aggregated counters used to drive the CLI exit code. */
|
|
139
|
+
readonly summary: BackupVerifySummary;
|
|
140
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schemaNote": "SSoT machine-readable inventory of every CLEO SQLite database. Consumed by T10307 fleet survey, T10310 pragma drift, T10311 migration coverage, T10312 doctor integrity, T10320 cross-DB invariants. Owned by Saga T10281 SG-BRAIN-DB-RESILIENCE / Epic T10282 E1-DB-INVENTORY (task T10305). Amend together with ADR-068 charter; the CI drift gate (forthcoming under E1) compares entries to disk reality.",
|
|
3
|
+
"$pathTokens": {
|
|
4
|
+
"<projectRoot>": "Resolved at runtime from CLEO_ROOT env var or process.cwd(). Substituted by SSoT helpers `getCleoProjectDir()` in packages/brain/src/cleo-home.ts.",
|
|
5
|
+
"$XDG_DATA_HOME": "Resolved via env-paths through `getCleoHome()` in @cleocode/paths. Linux: ~/.local/share/cleo/, macOS: ~/Library/Application Support/cleo/."
|
|
6
|
+
},
|
|
7
|
+
"entries": [
|
|
8
|
+
{
|
|
9
|
+
"role": "tasks",
|
|
10
|
+
"tier": "project",
|
|
11
|
+
"filePathTemplate": "<projectRoot>/.cleo/tasks.db",
|
|
12
|
+
"drizzleSchemaPath": "packages/core/src/store/tasks-schema.ts",
|
|
13
|
+
"migrationsDir": "packages/core/migrations/drizzle-tasks/",
|
|
14
|
+
"ownerPackage": "@cleocode/core",
|
|
15
|
+
"openedVia": "openCleoDb('tasks', cwd)",
|
|
16
|
+
"concurrency": "single-writer",
|
|
17
|
+
"privacy": "local-only",
|
|
18
|
+
"backupPath": ".cleo/backups/sqlite/tasks-YYYYMMDD-HHmmss.db",
|
|
19
|
+
"documentedIn": "ADR-068 row 1; ADR-013 §9"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"role": "brain",
|
|
23
|
+
"tier": "project",
|
|
24
|
+
"filePathTemplate": "<projectRoot>/.cleo/brain.db",
|
|
25
|
+
"drizzleSchemaPath": "packages/core/src/store/memory-schema.ts",
|
|
26
|
+
"migrationsDir": "packages/core/migrations/drizzle-brain/",
|
|
27
|
+
"ownerPackage": "@cleocode/brain",
|
|
28
|
+
"openedVia": "openCleoDb('brain', cwd)",
|
|
29
|
+
"concurrency": "single-writer",
|
|
30
|
+
"privacy": "local-only-pii",
|
|
31
|
+
"backupPath": ".cleo/backups/sqlite/brain-YYYYMMDD-HHmmss.db",
|
|
32
|
+
"documentedIn": "ADR-068 row 2; ADR-013 §9; audit §2 (P0 malformed 2026-05-23)"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"role": "conduit",
|
|
36
|
+
"tier": "project",
|
|
37
|
+
"filePathTemplate": "<projectRoot>/.cleo/conduit.db",
|
|
38
|
+
"drizzleSchemaPath": "packages/core/src/store/conduit-schema.ts",
|
|
39
|
+
"migrationsDir": "packages/core/migrations/drizzle-conduit/",
|
|
40
|
+
"ownerPackage": "@cleocode/core",
|
|
41
|
+
"openedVia": "openCleoDb('conduit', cwd)",
|
|
42
|
+
"concurrency": "single-writer",
|
|
43
|
+
"privacy": "local-only",
|
|
44
|
+
"backupPath": ".cleo/backups/sqlite/conduit-YYYYMMDD-HHmmss.db",
|
|
45
|
+
"documentedIn": "ADR-068 row 3; ADR-037 (signaldock→conduit split)"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"role": "manifest",
|
|
49
|
+
"tier": "derived",
|
|
50
|
+
"filePathTemplate": "<projectRoot>/.cleo/blobs/manifest.db",
|
|
51
|
+
"drizzleSchemaPath": "packages/core/src/store/llmtxt-blob-adapter.ts",
|
|
52
|
+
"migrationsDir": null,
|
|
53
|
+
"ownerPackage": "@cleocode/core",
|
|
54
|
+
"openedVia": "CleoBlobStore via llmtxt/blob BlobFsAdapter (no openCleoDb role registered)",
|
|
55
|
+
"concurrency": "single-writer",
|
|
56
|
+
"privacy": "local-only",
|
|
57
|
+
"backupPath": "rebuildable-from-blob-store",
|
|
58
|
+
"documentedIn": "ADR-068 row 7 (derived); schema owned by llmtxt/blob BlobFsAdapter contract"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"role": "llmtxt",
|
|
62
|
+
"tier": "project",
|
|
63
|
+
"filePathTemplate": "<projectRoot>/.cleo/llmtxt/llmtxt.db",
|
|
64
|
+
"drizzleSchemaPath": null,
|
|
65
|
+
"migrationsDir": null,
|
|
66
|
+
"ownerPackage": "@cleocode/llmtxt-core",
|
|
67
|
+
"openedVia": "openCleoDb('llmtxt', cwd) — RESERVED; opener throws 'not yet implemented' (see open-cleo-db.ts L138)",
|
|
68
|
+
"concurrency": "single-writer",
|
|
69
|
+
"privacy": "local-only-pii",
|
|
70
|
+
"backupPath": ".cleo/backups/sqlite/llmtxt-YYYYMMDD-HHmmss.db",
|
|
71
|
+
"documentedIn": "ADR-068 row 8 (reserved); audit §1.1 row 4 (live at .cleo/llmtxt/llmtxt.db)"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"role": "nexus",
|
|
75
|
+
"tier": "global",
|
|
76
|
+
"filePathTemplate": "$XDG_DATA_HOME/cleo/nexus.db",
|
|
77
|
+
"drizzleSchemaPath": "packages/core/src/store/nexus-schema.ts",
|
|
78
|
+
"migrationsDir": "packages/core/migrations/drizzle-nexus/",
|
|
79
|
+
"ownerPackage": "@cleocode/core",
|
|
80
|
+
"openedVia": "openCleoDb('nexus')",
|
|
81
|
+
"concurrency": "single-writer",
|
|
82
|
+
"privacy": "local-only-pii",
|
|
83
|
+
"backupPath": "$XDG_DATA_HOME/cleo/backups/sqlite/nexus-YYYYMMDD-HHmmss.db",
|
|
84
|
+
"documentedIn": "ADR-068 row 5"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"role": "signaldock-project",
|
|
88
|
+
"tier": "project",
|
|
89
|
+
"filePathTemplate": "<projectRoot>/.cleo/signaldock.db",
|
|
90
|
+
"drizzleSchemaPath": "packages/core/src/store/signaldock-schema.ts",
|
|
91
|
+
"migrationsDir": "packages/core/migrations/drizzle-signaldock/",
|
|
92
|
+
"ownerPackage": "@cleocode/core",
|
|
93
|
+
"openedVia": "HISTORICAL — project-tier signaldock.db was migrated into conduit.db post-T310/ADR-037. No live opener; charter row retained for migration provenance and legacy backup detection.",
|
|
94
|
+
"concurrency": "single-writer",
|
|
95
|
+
"privacy": "local-only",
|
|
96
|
+
"backupPath": ".cleo/backups/sqlite/signaldock-project-YYYYMMDD-HHmmss.db",
|
|
97
|
+
"documentedIn": "ADR-068 row 4 (stale — superseded by ADR-037); audit §1.1 (not in live project DB list)"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"role": "signaldock-global",
|
|
101
|
+
"tier": "global",
|
|
102
|
+
"filePathTemplate": "$XDG_DATA_HOME/cleo/signaldock.db",
|
|
103
|
+
"drizzleSchemaPath": "packages/core/src/store/signaldock-schema.ts",
|
|
104
|
+
"migrationsDir": "packages/core/migrations/drizzle-signaldock/",
|
|
105
|
+
"ownerPackage": "@cleocode/core",
|
|
106
|
+
"openedVia": "openCleoDb('signaldock')",
|
|
107
|
+
"concurrency": "single-writer",
|
|
108
|
+
"privacy": "local-only",
|
|
109
|
+
"backupPath": "$XDG_DATA_HOME/cleo/backups/sqlite/signaldock-global-YYYYMMDD-HHmmss.db",
|
|
110
|
+
"documentedIn": "ADR-068 row 9; ADR-037 (post-split global identity registry)"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"role": "telemetry",
|
|
114
|
+
"tier": "global",
|
|
115
|
+
"filePathTemplate": "$XDG_DATA_HOME/cleo/telemetry.db",
|
|
116
|
+
"drizzleSchemaPath": "packages/core/src/telemetry/schema.ts",
|
|
117
|
+
"migrationsDir": "packages/core/migrations/drizzle-telemetry/",
|
|
118
|
+
"ownerPackage": "@cleocode/core",
|
|
119
|
+
"openedVia": "@cleocode/core telemetry/sqlite.ts — lazy open on first event when opted-in; not yet registered as openCleoDb role",
|
|
120
|
+
"concurrency": "single-writer",
|
|
121
|
+
"privacy": "cloud-exportable-opt-in",
|
|
122
|
+
"backupPath": "$XDG_DATA_HOME/cleo/backups/sqlite/telemetry-YYYYMMDD-HHmmss.db",
|
|
123
|
+
"documentedIn": "ADR-068 row 6; T624"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"role": "skills",
|
|
127
|
+
"tier": "global",
|
|
128
|
+
"filePathTemplate": "$XDG_DATA_HOME/cleo/skills.db",
|
|
129
|
+
"drizzleSchemaPath": "packages/core/src/store/skills-schema.ts",
|
|
130
|
+
"migrationsDir": "packages/core/migrations/drizzle-skills/",
|
|
131
|
+
"ownerPackage": "@cleocode/core",
|
|
132
|
+
"openedVia": "openCleoDb('skills')",
|
|
133
|
+
"concurrency": "single-writer",
|
|
134
|
+
"privacy": "local-only",
|
|
135
|
+
"backupPath": "$XDG_DATA_HOME/cleo/backups/sqlite/skills-YYYYMMDD-HHmmss.db",
|
|
136
|
+
"documentedIn": "T9651 (initial skills.db migration); audit §1.2 row 4 — NOT yet in ADR-068 table"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"role": "global-brain",
|
|
140
|
+
"tier": "global",
|
|
141
|
+
"filePathTemplate": "$XDG_DATA_HOME/cleo/brain.db",
|
|
142
|
+
"drizzleSchemaPath": "packages/core/src/store/memory-schema.ts",
|
|
143
|
+
"migrationsDir": "packages/core/migrations/drizzle-brain/",
|
|
144
|
+
"ownerPackage": "@cleocode/brain",
|
|
145
|
+
"openedVia": "UNREGISTERED — file exists on disk (audit §1.2 row 3) but no live opener. Provenance unclear; likely orphan from a getCleoHome()-vs-project-resolution path bug. Tracked for cleanup decision under T10282/T10307.",
|
|
146
|
+
"concurrency": "single-writer",
|
|
147
|
+
"privacy": "local-only-pii",
|
|
148
|
+
"backupPath": "$XDG_DATA_HOME/cleo/backups/sqlite/global-brain-YYYYMMDD-HHmmss.db",
|
|
149
|
+
"documentedIn": "audit §1.2 row 3 — NEW per saga T10281; not in ADR-068"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"role": "global-tasks",
|
|
153
|
+
"tier": "global",
|
|
154
|
+
"filePathTemplate": "$XDG_DATA_HOME/cleo/tasks.db",
|
|
155
|
+
"drizzleSchemaPath": "packages/core/src/store/tasks-schema.ts",
|
|
156
|
+
"migrationsDir": "packages/core/migrations/drizzle-tasks/",
|
|
157
|
+
"ownerPackage": "@cleocode/core",
|
|
158
|
+
"openedVia": "UNREGISTERED — file exists on disk (audit §1.2 row 5, 4 KB) but no live opener. Provenance unclear; likely orphan from a cwd-cascade bug (T9550 class). Tracked for cleanup decision under T10282/T10307.",
|
|
159
|
+
"concurrency": "single-writer",
|
|
160
|
+
"privacy": "local-only",
|
|
161
|
+
"backupPath": "$XDG_DATA_HOME/cleo/backups/sqlite/global-tasks-YYYYMMDD-HHmmss.db",
|
|
162
|
+
"documentedIn": "audit §1.2 row 5 — NEW per saga T10281; not in ADR-068"
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
}
|
package/src/db-inventory.ts
CHANGED
|
@@ -4,10 +4,16 @@
|
|
|
4
4
|
* @remarks
|
|
5
5
|
* This module exports the typed shape and the runtime constant for every
|
|
6
6
|
* SQLite database that CLEO manages. The runtime data is sourced from the
|
|
7
|
-
* canonical JSON inventory at `packages/
|
|
7
|
+
* canonical JSON inventory at `packages/contracts/src/db-inventory.json`
|
|
8
8
|
* via ESM JSON import (`with { type: 'json' }`). The JSON file is the
|
|
9
9
|
* single source of truth; this module re-exposes it with a typed contract.
|
|
10
10
|
*
|
|
11
|
+
* The JSON file is co-located in this package (rather than referencing a
|
|
12
|
+
* sibling-package `src/` path) so that the built `dist/db-inventory.js`
|
|
13
|
+
* resolves the JSON via a relative `./db-inventory.json` import that
|
|
14
|
+
* works inside the published `@cleocode/contracts` npm tarball — sibling
|
|
15
|
+
* package `src/` directories are not shipped to consumers.
|
|
16
|
+
*
|
|
11
17
|
* Downstream consumers:
|
|
12
18
|
*
|
|
13
19
|
* - **T10307 — Fleet survey** (`cleo doctor db-substrate`) iterates `DB_INVENTORY`
|
|
@@ -23,9 +29,10 @@
|
|
|
23
29
|
* agent_id, session_id, ...).
|
|
24
30
|
*
|
|
25
31
|
* Adding a new entry to the inventory is a charter amendment — update
|
|
26
|
-
* `db-inventory.json` AND
|
|
27
|
-
* in the same PR (gated by
|
|
28
|
-
* once T10282 ships its drift
|
|
32
|
+
* `packages/contracts/src/db-inventory.json` AND
|
|
33
|
+
* `.cleo/adrs/ADR-068-cleo-database-charter.md` in the same PR (gated by
|
|
34
|
+
* `cleo check arch` Gate-4 SSoT-EXEMPT lint once T10282 ships its drift
|
|
35
|
+
* check).
|
|
29
36
|
*
|
|
30
37
|
* @see ADR-068 — CLEO Database Charter (canonical narrative)
|
|
31
38
|
* @see Saga T10281 — SG-BRAIN-DB-RESILIENCE (provenance)
|
|
@@ -37,7 +44,7 @@
|
|
|
37
44
|
* @saga T10281
|
|
38
45
|
*/
|
|
39
46
|
|
|
40
|
-
import dbInventoryData from '
|
|
47
|
+
import dbInventoryData from './db-inventory.json' with { type: 'json' };
|
|
41
48
|
|
|
42
49
|
/**
|
|
43
50
|
* Canonical role names for every SQLite database in the CLEO charter.
|
|
@@ -203,7 +210,7 @@ const rawInventory = dbInventoryData as DbInventoryFile;
|
|
|
203
210
|
* Immutable canonical inventory of every CLEO SQLite database.
|
|
204
211
|
*
|
|
205
212
|
* @remarks
|
|
206
|
-
* Sourced from `packages/
|
|
213
|
+
* Sourced from `packages/contracts/src/db-inventory.json` — the SSoT.
|
|
207
214
|
* Adding a new entry is a charter amendment per ADR-068 §"How to add a
|
|
208
215
|
* new database". The {@link db-inventory.test.ts} suite asserts:
|
|
209
216
|
*
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic CLEO database recovery contracts — generalised from the brain-only
|
|
3
|
+
* T10303/T10304 shapes so the same envelope works for every role declared in
|
|
4
|
+
* {@link DB_INVENTORY}.
|
|
5
|
+
*
|
|
6
|
+
* These types mirror {@link BrainRecoveryResult} + {@link BackupRecoverBrainResult}
|
|
7
|
+
* almost verbatim, with two adjustments:
|
|
8
|
+
*
|
|
9
|
+
* 1. `observationsRecovered: number | null` is generalised to
|
|
10
|
+
* `rowCounts: DbRecoveredRowCounts` — a `Record<tableName, number | null>`
|
|
11
|
+
* keyed by the user tables discovered in the restored DB via
|
|
12
|
+
* `sqlite_master`. Tables that fail to count surface as `null`.
|
|
13
|
+
* 2. Every envelope carries the `role: DbRole` it pertains to so envelopes from
|
|
14
|
+
* `cleo backup recover <role>` are self-describing across tools that may
|
|
15
|
+
* fan recovery out across multiple DBs.
|
|
16
|
+
*
|
|
17
|
+
* The brain-specific shapes ({@link BrainRecoveryResult},
|
|
18
|
+
* {@link BackupRecoverBrainResult}, {@link BrainRecoveredRowCounts}) remain in
|
|
19
|
+
* {@link brain.ts} as the backward-compatible surface — the brain CLI verb
|
|
20
|
+
* (`cleo backup recover brain`) still emits the same envelope it did before
|
|
21
|
+
* T10318 generalised the pipeline.
|
|
22
|
+
*
|
|
23
|
+
* @task T10318
|
|
24
|
+
* @epic T10284
|
|
25
|
+
* @saga T10281
|
|
26
|
+
* @adr ADR-068
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import type { DbRole } from './db-inventory.js';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Best-effort per-table row counts probed from a recovered CLEO database.
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* The recovery pipeline enumerates user tables in the restored DB via
|
|
36
|
+
* `sqlite_master` (excluding internal `sqlite_*` and Drizzle journal tables)
|
|
37
|
+
* and runs `SELECT COUNT(*)` on each. Tables that fail to count — for
|
|
38
|
+
* example, a missing table in a very old snapshot, or a schema/version
|
|
39
|
+
* mismatch — surface as `null` instead of throwing so the envelope always
|
|
40
|
+
* serialises cleanly.
|
|
41
|
+
*
|
|
42
|
+
* Keys are exact SQLite table names (case-sensitive). Values are non-negative
|
|
43
|
+
* integers or `null`.
|
|
44
|
+
*
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
export type DbRecoveredRowCounts = Readonly<Record<string, number | null>>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Result of a generic CLEO DB auto-recovery attempt.
|
|
51
|
+
*
|
|
52
|
+
* @remarks
|
|
53
|
+
* Returned by `recoverMalformedDb({ role, ... })` (T10318) when the chokepoint
|
|
54
|
+
* (or an operator invoking `cleo backup recover <role>`) detects malformation
|
|
55
|
+
* via `ERR_SQLITE_ERROR errcode=11` or a failing `PRAGMA integrity_check` /
|
|
56
|
+
* `PRAGMA quick_check`. The corrupt DB has been moved to a quarantine
|
|
57
|
+
* directory and the freshest validated snapshot has been copied to the
|
|
58
|
+
* canonical role path.
|
|
59
|
+
*
|
|
60
|
+
* Consumers read this structure to decide whether to re-attempt the open and
|
|
61
|
+
* to emit user-facing diagnostics with the data-loss window.
|
|
62
|
+
*
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
export interface DbRecoveryResult {
|
|
66
|
+
/** Canonical role of the database that was recovered. */
|
|
67
|
+
role: DbRole;
|
|
68
|
+
/** Absolute path to the snapshot that was restored, or `null` if recovery failed. */
|
|
69
|
+
restoredFrom: string | null;
|
|
70
|
+
/**
|
|
71
|
+
* Approximate hours between the snapshot's timestamp and the recovery
|
|
72
|
+
* event. `null` when the snapshot timestamp could not be parsed.
|
|
73
|
+
* Used in the recovery warning to make the data-loss window legible.
|
|
74
|
+
*/
|
|
75
|
+
dataLossWindowHours: number | null;
|
|
76
|
+
/**
|
|
77
|
+
* Per-table row counts probed from the restored DB. Each key is a user
|
|
78
|
+
* table name; each value is the row count, or `null` on count failure.
|
|
79
|
+
* Empty record `{}` when the restored DB has no user tables (or when
|
|
80
|
+
* the probe itself failed to open the DB).
|
|
81
|
+
*/
|
|
82
|
+
rowCounts: DbRecoveredRowCounts;
|
|
83
|
+
/** `true` if the restored DB passes `PRAGMA quick_check`. */
|
|
84
|
+
integrityOK: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Absolute path to the quarantine directory where the corrupt DB plus
|
|
87
|
+
* its `-wal`/`-shm` sidecars were moved before restore. `null` when no
|
|
88
|
+
* corrupt DB existed at the canonical path (recovery into an empty slot).
|
|
89
|
+
*/
|
|
90
|
+
quarantineDir: string | null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Envelope payload returned by `cleo backup recover <role>`.
|
|
95
|
+
*
|
|
96
|
+
* @remarks
|
|
97
|
+
* Wraps {@link DbRecoveryResult} with three CLI-only additions:
|
|
98
|
+
*
|
|
99
|
+
* - `rowsRecovered` aliases `rowCounts` to keep the envelope shape compatible
|
|
100
|
+
* with the brain-specific {@link BackupRecoverBrainResult}.
|
|
101
|
+
* - `quarantinedTo: string` is the non-nullable string form (empty string in
|
|
102
|
+
* `--dry-run` mode where no files were touched) — easier for shell scripts
|
|
103
|
+
* that pipe the envelope into `jq` and then path operations.
|
|
104
|
+
* - `dryRun: boolean` records whether the envelope is a *plan* (would-do)
|
|
105
|
+
* versus a *record* (already-done). Consumers MUST check this before
|
|
106
|
+
* treating `restoredFrom` as a post-condition.
|
|
107
|
+
*
|
|
108
|
+
* @task T10318
|
|
109
|
+
* @epic T10284
|
|
110
|
+
* @saga T10281
|
|
111
|
+
* @public
|
|
112
|
+
*/
|
|
113
|
+
export interface BackupRecoverResult {
|
|
114
|
+
/** Canonical role of the database that was (or would be) recovered. */
|
|
115
|
+
role: DbRole;
|
|
116
|
+
/**
|
|
117
|
+
* Absolute path to the snapshot that was (or would be) restored. Empty
|
|
118
|
+
* string when no snapshot was available — the envelope's caller surfaces
|
|
119
|
+
* that as a failure mode via a structured error.
|
|
120
|
+
*/
|
|
121
|
+
restoredFrom: string;
|
|
122
|
+
/** Per-table row counts probed from the restored DB (or the plan target). */
|
|
123
|
+
rowsRecovered: DbRecoveredRowCounts;
|
|
124
|
+
/**
|
|
125
|
+
* Approximate hours between the snapshot's timestamp and the recovery
|
|
126
|
+
* event. `null` when the snapshot timestamp could not be parsed (e.g.
|
|
127
|
+
* legacy `<role>.db.PRE-DUP-FIX-*` fallback artifact).
|
|
128
|
+
*/
|
|
129
|
+
dataLossWindowHours: number | null;
|
|
130
|
+
/** `true` when the restored DB passes `PRAGMA quick_check`. */
|
|
131
|
+
integrityOK: boolean;
|
|
132
|
+
/**
|
|
133
|
+
* Absolute path to the quarantine directory where the corrupt DB plus
|
|
134
|
+
* its `-wal`/`-shm` sidecars were moved. Empty string in `--dry-run`
|
|
135
|
+
* mode where no files were touched.
|
|
136
|
+
*/
|
|
137
|
+
quarantinedTo: string;
|
|
138
|
+
/**
|
|
139
|
+
* `true` when invoked with `--dry-run` — indicates the envelope is a
|
|
140
|
+
* plan, NOT a record of mutations performed. Consumers MUST check this
|
|
141
|
+
* before treating `restoredFrom` as a post-condition.
|
|
142
|
+
*/
|
|
143
|
+
dryRun: boolean;
|
|
144
|
+
}
|