@cleocode/core 2026.6.6 → 2026.6.8
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/db/index.d.ts +5 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +5 -1
- package/dist/db/index.js.map +1 -1
- package/dist/dispatch/contracts/output-contracts.d.ts +36 -0
- package/dist/dispatch/contracts/output-contracts.d.ts.map +1 -0
- package/dist/dispatch/contracts/output-contracts.js +38 -0
- package/dist/dispatch/contracts/output-contracts.js.map +1 -0
- package/dist/dispatch/describe-operation.d.ts +98 -0
- package/dist/dispatch/describe-operation.d.ts.map +1 -0
- package/dist/dispatch/describe-operation.js +101 -0
- package/dist/dispatch/describe-operation.js.map +1 -0
- package/dist/docs/build-provenance-graph.d.ts +12 -0
- package/dist/docs/build-provenance-graph.d.ts.map +1 -1
- package/dist/docs/build-provenance-graph.js +52 -0
- package/dist/docs/build-provenance-graph.js.map +1 -1
- package/dist/docs/docs-read-model.d.ts +40 -0
- package/dist/docs/docs-read-model.d.ts.map +1 -1
- package/dist/docs/docs-read-model.js +29 -0
- package/dist/docs/docs-read-model.js.map +1 -1
- package/dist/docs/export-document.js +1794 -1235
- package/dist/docs/export-document.js.map +3 -3
- package/dist/docs/index.d.ts +4 -0
- package/dist/docs/index.d.ts.map +1 -1
- package/dist/docs/index.js +2 -0
- package/dist/docs/index.js.map +1 -1
- package/dist/docs/read-doc.d.ts +60 -0
- package/dist/docs/read-doc.d.ts.map +1 -0
- package/dist/docs/read-doc.js +188 -0
- package/dist/docs/read-doc.js.map +1 -0
- package/dist/docs/wikilinks.d.ts +119 -0
- package/dist/docs/wikilinks.d.ts.map +1 -0
- package/dist/docs/wikilinks.js +217 -0
- package/dist/docs/wikilinks.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +2 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +6 -0
- package/dist/internal.js.map +1 -1
- package/dist/llm/index.d.ts +1 -3
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +1 -2
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/model-metadata.d.ts +14 -0
- package/dist/llm/model-metadata.d.ts.map +1 -1
- package/dist/llm/model-metadata.js +23 -0
- package/dist/llm/model-metadata.js.map +1 -1
- package/dist/llm/model-runner.d.ts.map +1 -1
- package/dist/llm/model-runner.js +104 -74
- package/dist/llm/model-runner.js.map +1 -1
- package/dist/llm/plugin-facade.js +1947 -1364
- package/dist/llm/plugin-facade.js.map +3 -3
- package/dist/llm/provider-registry/builtin/anthropic.d.ts.map +1 -1
- package/dist/llm/provider-registry/builtin/anthropic.js +4 -0
- package/dist/llm/provider-registry/builtin/anthropic.js.map +1 -1
- package/dist/llm/provider-registry/builtin/gemini.d.ts.map +1 -1
- package/dist/llm/provider-registry/builtin/gemini.js +4 -0
- package/dist/llm/provider-registry/builtin/gemini.js.map +1 -1
- package/dist/llm/provider-registry/builtin/ollama.d.ts.map +1 -1
- package/dist/llm/provider-registry/builtin/ollama.js +4 -0
- package/dist/llm/provider-registry/builtin/ollama.js.map +1 -1
- package/dist/llm/provider-registry/builtin/openai.d.ts.map +1 -1
- package/dist/llm/provider-registry/builtin/openai.js +6 -0
- package/dist/llm/provider-registry/builtin/openai.js.map +1 -1
- package/dist/llm/transports/index.d.ts +5 -3
- package/dist/llm/transports/index.d.ts.map +1 -1
- package/dist/llm/transports/index.js +5 -2
- package/dist/llm/transports/index.js.map +1 -1
- package/dist/reconciliation/reconciliation-engine.d.ts.map +1 -1
- package/dist/reconciliation/reconciliation-engine.js +3 -0
- package/dist/reconciliation/reconciliation-engine.js.map +1 -1
- package/dist/release/plan.d.ts +27 -0
- package/dist/release/plan.d.ts.map +1 -1
- package/dist/release/plan.js +36 -2
- package/dist/release/plan.js.map +1 -1
- package/dist/release/provenance-fk.d.ts +74 -0
- package/dist/release/provenance-fk.d.ts.map +1 -0
- package/dist/release/provenance-fk.js +122 -0
- package/dist/release/provenance-fk.js.map +1 -0
- package/dist/release/reconcile.d.ts +2 -53
- package/dist/release/reconcile.d.ts.map +1 -1
- package/dist/release/reconcile.js +13 -93
- package/dist/release/reconcile.js.map +1 -1
- package/dist/sticky/convert.d.ts.map +1 -1
- package/dist/sticky/convert.js +3 -0
- package/dist/sticky/convert.js.map +1 -1
- package/dist/store/dual-scope-db.d.ts +83 -0
- package/dist/store/dual-scope-db.d.ts.map +1 -1
- package/dist/store/dual-scope-db.js +135 -6
- package/dist/store/dual-scope-db.js.map +1 -1
- package/dist/store/exodus/abort-events.d.ts +116 -0
- package/dist/store/exodus/abort-events.d.ts.map +1 -0
- package/dist/store/exodus/abort-events.js +130 -0
- package/dist/store/exodus/abort-events.js.map +1 -0
- package/dist/store/exodus/column-transforms.d.ts +35 -8
- package/dist/store/exodus/column-transforms.d.ts.map +1 -1
- package/dist/store/exodus/column-transforms.js +47 -13
- package/dist/store/exodus/column-transforms.js.map +1 -1
- package/dist/store/exodus/count-parity.d.ts +71 -0
- package/dist/store/exodus/count-parity.d.ts.map +1 -0
- package/dist/store/exodus/count-parity.js +124 -0
- package/dist/store/exodus/count-parity.js.map +1 -0
- package/dist/store/exodus/health.d.ts +70 -0
- package/dist/store/exodus/health.d.ts.map +1 -0
- package/dist/store/exodus/health.js +130 -0
- package/dist/store/exodus/health.js.map +1 -0
- package/dist/store/exodus/index.d.ts +4 -0
- package/dist/store/exodus/index.d.ts.map +1 -1
- package/dist/store/exodus/index.js +4 -0
- package/dist/store/exodus/index.js.map +1 -1
- package/dist/store/exodus/migrate.d.ts.map +1 -1
- package/dist/store/exodus/migrate.js +98 -31
- package/dist/store/exodus/migrate.js.map +1 -1
- package/dist/store/exodus/plan.d.ts +48 -4
- package/dist/store/exodus/plan.d.ts.map +1 -1
- package/dist/store/exodus/plan.js +67 -9
- package/dist/store/exodus/plan.js.map +1 -1
- package/dist/store/exodus/seal.d.ts +69 -0
- package/dist/store/exodus/seal.d.ts.map +1 -0
- package/dist/store/exodus/seal.js +73 -0
- package/dist/store/exodus/seal.js.map +1 -0
- package/dist/store/exodus/types.d.ts +24 -1
- package/dist/store/exodus/types.d.ts.map +1 -1
- package/dist/store/exodus/types.js.map +1 -1
- package/dist/store/exodus/verify-migration.d.ts.map +1 -1
- package/dist/store/exodus/verify-migration.js +53 -26
- package/dist/store/exodus/verify-migration.js.map +1 -1
- package/dist/store/repair-malformed-dbs.d.ts +87 -0
- package/dist/store/repair-malformed-dbs.d.ts.map +1 -0
- package/dist/store/repair-malformed-dbs.js +188 -0
- package/dist/store/repair-malformed-dbs.js.map +1 -0
- package/dist/store/schema/attachments.d.ts +133 -0
- package/dist/store/schema/attachments.d.ts.map +1 -1
- package/dist/store/schema/attachments.js +63 -0
- package/dist/store/schema/attachments.js.map +1 -1
- package/dist/tasks/add.d.ts +13 -0
- package/dist/tasks/add.d.ts.map +1 -1
- package/dist/tasks/add.js +50 -18
- package/dist/tasks/add.js.map +1 -1
- package/dist/tasks/archive.d.ts.map +1 -1
- package/dist/tasks/archive.js +12 -7
- package/dist/tasks/archive.js.map +1 -1
- package/dist/tasks/child-disposition.d.ts +66 -0
- package/dist/tasks/child-disposition.d.ts.map +1 -0
- package/dist/tasks/child-disposition.js +80 -0
- package/dist/tasks/child-disposition.js.map +1 -0
- package/dist/tasks/delete-preview.js +1 -1
- package/dist/tasks/delete-preview.js.map +1 -1
- package/dist/tasks/deletion-strategy.d.ts +21 -3
- package/dist/tasks/deletion-strategy.d.ts.map +1 -1
- package/dist/tasks/deletion-strategy.js +61 -15
- package/dist/tasks/deletion-strategy.js.map +1 -1
- package/dist/tasks/engine-wrap.d.ts +8 -0
- package/dist/tasks/engine-wrap.d.ts.map +1 -1
- package/dist/tasks/engine-wrap.js +22 -9
- package/dist/tasks/engine-wrap.js.map +1 -1
- package/dist/tasks/update.d.ts.map +1 -1
- package/dist/tasks/update.js +12 -0
- package/dist/tasks/update.js.map +1 -1
- package/migrations/drizzle-tasks/20260605000001_t11826-docs-wikilinks/migration.sql +110 -0
- package/package.json +12 -12
- package/dist/llm/transports/openai.d.ts +0 -181
- package/dist/llm/transports/openai.d.ts.map +0 -1
- package/dist/llm/transports/openai.js +0 -645
- package/dist/llm/transports/openai.js.map +0 -1
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cleo doctor repair` orchestrator — detect malformed CLEO databases and
|
|
3
|
+
* restore each from its freshest validated snapshot (T11829 · DHQ-060).
|
|
4
|
+
*
|
|
5
|
+
* ## Why this exists
|
|
6
|
+
*
|
|
7
|
+
* The corruption-resilience pipeline ALREADY existed before T11829:
|
|
8
|
+
*
|
|
9
|
+
* - {@link recoverMalformedDb} (quarantine → snapshot-restore → `quick_check`),
|
|
10
|
+
* - `autoRecoverFromBackup` (catches `"database disk image is malformed"` at
|
|
11
|
+
* open and restores the freshest VACUUM snapshot), and
|
|
12
|
+
* - the operator verb `cleo backup recover <role>` ({@link runBackupRecover}).
|
|
13
|
+
*
|
|
14
|
+
* The ONLY gap vs the DHQ-060 ask was a discoverable `cleo doctor` entry point
|
|
15
|
+
* that DETECTS corruption across the fleet and repairs only what is broken. This
|
|
16
|
+
* module is that orchestrator — it adds NO new recovery logic. It probes each
|
|
17
|
+
* role's live DB with `PRAGMA quick_check` (the same probe the pipeline runs on
|
|
18
|
+
* snapshot candidates, via {@link probeSnapshot}) and delegates every actual
|
|
19
|
+
* repair to {@link runBackupRecover} → {@link recoverMalformedDb}.
|
|
20
|
+
*
|
|
21
|
+
* ## WAL-specific corruption is covered
|
|
22
|
+
*
|
|
23
|
+
* A torn WAL frame surfaces as `"database disk image is malformed"` and makes
|
|
24
|
+
* `PRAGMA quick_check` return a non-`ok` result — so {@link probeSnapshot}
|
|
25
|
+
* detects it. The quarantine step ({@link quarantineCorruptDb}) already moves the
|
|
26
|
+
* `-wal`/`-shm` sidecars alongside the main file, so the WAL case is fully
|
|
27
|
+
* handled by the existing pipeline; this orchestrator does not need to special-case it.
|
|
28
|
+
*
|
|
29
|
+
* @module
|
|
30
|
+
* @task T11829 (DHQ-060 — `cleo doctor repair` entry point over the recovery pipeline)
|
|
31
|
+
* @epic T11833
|
|
32
|
+
* @saga T11242 (SG-DB-SUBSTRATE-V2)
|
|
33
|
+
* @see packages/core/src/store/recover-malformed-db.ts — the recovery pipeline
|
|
34
|
+
* @see packages/core/src/store/backup-recover.ts — `cleo backup recover <role>` wrapper
|
|
35
|
+
*/
|
|
36
|
+
import { existsSync } from 'node:fs';
|
|
37
|
+
import { DB_INVENTORY } from '@cleocode/contracts';
|
|
38
|
+
import { BackupRecoverError, runBackupRecover } from './backup-recover.js';
|
|
39
|
+
import { probeSnapshot, resolveRoleDbPath } from './recover-malformed-db.js';
|
|
40
|
+
/**
|
|
41
|
+
* Probe a single role's live DB and, when malformed, repair it from snapshot.
|
|
42
|
+
*
|
|
43
|
+
* Pure delegation: detection via {@link probeSnapshot} (`PRAGMA quick_check`),
|
|
44
|
+
* repair via {@link runBackupRecover}. Never throws — a recovery failure is
|
|
45
|
+
* captured in the returned record's `action: 'failed'`.
|
|
46
|
+
*
|
|
47
|
+
* @internal
|
|
48
|
+
*/
|
|
49
|
+
function repairOneRole(role, opts) {
|
|
50
|
+
const dbPath = resolveRoleDbPath(role, { projectRoot: opts.projectRoot });
|
|
51
|
+
const present = existsSync(dbPath);
|
|
52
|
+
if (!present) {
|
|
53
|
+
return {
|
|
54
|
+
role,
|
|
55
|
+
dbPath,
|
|
56
|
+
present: false,
|
|
57
|
+
healthy: true,
|
|
58
|
+
action: 'skipped',
|
|
59
|
+
restoredFrom: null,
|
|
60
|
+
quarantinedTo: null,
|
|
61
|
+
dataLossWindowHours: null,
|
|
62
|
+
detail: 'live DB file not present on disk (nothing to repair)',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// DETECT — the same `PRAGMA quick_check` the pipeline runs on snapshots. A
|
|
66
|
+
// torn WAL frame ("database disk image is malformed") fails this probe.
|
|
67
|
+
const probe = probeSnapshot(dbPath);
|
|
68
|
+
if (probe.ok) {
|
|
69
|
+
return {
|
|
70
|
+
role,
|
|
71
|
+
dbPath,
|
|
72
|
+
present: true,
|
|
73
|
+
healthy: true,
|
|
74
|
+
action: 'skipped',
|
|
75
|
+
restoredFrom: null,
|
|
76
|
+
quarantinedTo: null,
|
|
77
|
+
dataLossWindowHours: null,
|
|
78
|
+
detail: 'PRAGMA quick_check passed — DB is healthy',
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
// MALFORMED — plan or repair.
|
|
82
|
+
if (opts.dryRun === true) {
|
|
83
|
+
try {
|
|
84
|
+
// Dry-run delegates to the SAME pipeline (no mutation) for an honest plan.
|
|
85
|
+
const plan = runBackupRecover({
|
|
86
|
+
role,
|
|
87
|
+
projectRoot: opts.projectRoot,
|
|
88
|
+
logger: opts.logger,
|
|
89
|
+
dryRun: true,
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
role,
|
|
93
|
+
dbPath,
|
|
94
|
+
present: true,
|
|
95
|
+
healthy: false,
|
|
96
|
+
action: 'would-repair',
|
|
97
|
+
restoredFrom: plan.restoredFrom || null,
|
|
98
|
+
quarantinedTo: null,
|
|
99
|
+
dataLossWindowHours: plan.dataLossWindowHours,
|
|
100
|
+
detail: `malformed — would restore from ${plan.restoredFrom} (re-run without --dry-run to repair)`,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
return {
|
|
105
|
+
role,
|
|
106
|
+
dbPath,
|
|
107
|
+
present: true,
|
|
108
|
+
healthy: false,
|
|
109
|
+
action: 'failed',
|
|
110
|
+
restoredFrom: null,
|
|
111
|
+
quarantinedTo: null,
|
|
112
|
+
dataLossWindowHours: null,
|
|
113
|
+
detail: `malformed but NO valid snapshot to restore from: ${err instanceof BackupRecoverError ? err.message : String(err)}`,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// EXECUTE — quarantine + restore + verify via the existing pipeline.
|
|
118
|
+
try {
|
|
119
|
+
const result = runBackupRecover({
|
|
120
|
+
role,
|
|
121
|
+
projectRoot: opts.projectRoot,
|
|
122
|
+
logger: opts.logger,
|
|
123
|
+
dryRun: false,
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
role,
|
|
127
|
+
dbPath,
|
|
128
|
+
present: true,
|
|
129
|
+
healthy: false,
|
|
130
|
+
action: 'repaired',
|
|
131
|
+
restoredFrom: result.restoredFrom || null,
|
|
132
|
+
quarantinedTo: result.quarantinedTo || null,
|
|
133
|
+
dataLossWindowHours: result.dataLossWindowHours,
|
|
134
|
+
detail: `repaired — restored from ${result.restoredFrom}; corrupt DB quarantined at ${result.quarantinedTo}`,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
return {
|
|
139
|
+
role,
|
|
140
|
+
dbPath,
|
|
141
|
+
present: true,
|
|
142
|
+
healthy: false,
|
|
143
|
+
action: 'failed',
|
|
144
|
+
restoredFrom: null,
|
|
145
|
+
quarantinedTo: null,
|
|
146
|
+
dataLossWindowHours: null,
|
|
147
|
+
detail: `malformed — recovery FAILED: ${err instanceof BackupRecoverError ? err.message : String(err)}`,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Detect and repair malformed CLEO databases across the fleet (T11829 · DHQ-060).
|
|
153
|
+
*
|
|
154
|
+
* For each requested role (or every present role in {@link DB_INVENTORY} when none
|
|
155
|
+
* are specified) this probes the live DB with `PRAGMA quick_check` and, when
|
|
156
|
+
* corruption is found, restores the freshest validated snapshot via the existing
|
|
157
|
+
* {@link runBackupRecover} pipeline. No new recovery logic is introduced — this is
|
|
158
|
+
* the discoverable `cleo doctor repair` entry point requested by DHQ-060.
|
|
159
|
+
*
|
|
160
|
+
* @param opts - Repair inputs (project root, optional role filter, dry-run, logger).
|
|
161
|
+
* @returns A {@link DoctorRepairResult} aggregate with per-role outcomes.
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```ts
|
|
165
|
+
* const report = repairMalformedDbs({ projectRoot: '/repo', logger });
|
|
166
|
+
* if (report.failedCount > 0) process.exitCode = 1;
|
|
167
|
+
* ```
|
|
168
|
+
*
|
|
169
|
+
* @task T11829
|
|
170
|
+
* @epic T11833
|
|
171
|
+
* @saga T11242
|
|
172
|
+
* @public
|
|
173
|
+
*/
|
|
174
|
+
export function repairMalformedDbs(opts) {
|
|
175
|
+
const explicit = opts.roles !== undefined && opts.roles.length > 0;
|
|
176
|
+
const candidateRoles = explicit
|
|
177
|
+
? opts.roles
|
|
178
|
+
: DB_INVENTORY.map((e) => e.role).filter((role) => existsSync(resolveRoleDbPath(role, { projectRoot: opts.projectRoot })));
|
|
179
|
+
const roles = candidateRoles.map((role) => repairOneRole(role, opts));
|
|
180
|
+
return {
|
|
181
|
+
dryRun: opts.dryRun === true,
|
|
182
|
+
roles,
|
|
183
|
+
malformedCount: roles.filter((r) => !r.healthy).length,
|
|
184
|
+
repairedCount: roles.filter((r) => r.action === 'repaired').length,
|
|
185
|
+
failedCount: roles.filter((r) => r.action === 'failed').length,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=repair-malformed-dbs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repair-malformed-dbs.js","sourceRoot":"","sources":["../../src/store/repair-malformed-dbs.ts"],"names":[],"mappings":"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"}
|
|
@@ -391,8 +391,141 @@ export declare const attachmentRefs: import("drizzle-orm/sqlite-core").SQLiteTab
|
|
|
391
391
|
};
|
|
392
392
|
dialect: "sqlite";
|
|
393
393
|
}>;
|
|
394
|
+
/**
|
|
395
|
+
* Allowed relations for a `docs_wikilinks` edge.
|
|
396
|
+
*
|
|
397
|
+
* A wikilink is a DERIVED, slug-addressed edge between two docs (or a doc and a
|
|
398
|
+
* task) reconstructed from the authoritative provenance columns on
|
|
399
|
+
* `attachments` — there is no hand-authored edge here. The relation enumerates
|
|
400
|
+
* which source column produced the edge:
|
|
401
|
+
*
|
|
402
|
+
* - `supersedes` — `attachments.supersedes` (newer → older)
|
|
403
|
+
* - `superseded-by` — `attachments.superseded_by` (older → newer)
|
|
404
|
+
* - `related-task` — `attachments.related_tasks` JSON membership (doc → T####)
|
|
405
|
+
* - `topic` — `attachments.topics` JSON co-membership (doc ↔ doc sharing a topic)
|
|
406
|
+
*
|
|
407
|
+
* Kept slug-primary so the edge table is Obsidian-grade (vault links are
|
|
408
|
+
* slug-addressed) and survives attachment-id churn across versions.
|
|
409
|
+
*
|
|
410
|
+
* @task T11826 (Epic T11781 / Saga T11778)
|
|
411
|
+
*/
|
|
412
|
+
export declare const DOCS_WIKILINK_RELATIONS: readonly ["supersedes", "superseded-by", "related-task", "topic"];
|
|
413
|
+
/** Discriminated union of `docs_wikilinks.relation` values. */
|
|
414
|
+
export type DocsWikilinkRelation = (typeof DOCS_WIKILINK_RELATIONS)[number];
|
|
415
|
+
/**
|
|
416
|
+
* `docs_wikilinks` — DERIVED, slug-addressed edge table for the docs graph.
|
|
417
|
+
*
|
|
418
|
+
* Per the ratified Docs-SSoT model (saga T11778): `cleo.db` is the SOLE doc
|
|
419
|
+
* authority, and `docs_wikilinks` is a *minimal edge table derived from*
|
|
420
|
+
* `supersedes` + `relatedTasks` + `topics` on `attachments`. It is NOT an
|
|
421
|
+
* authoritative input surface — it is rebuilt idempotently from the provenance
|
|
422
|
+
* columns by {@link import('../../docs/wikilinks.js').rebuildDocsWikilinks}.
|
|
423
|
+
*
|
|
424
|
+
* The table makes the bidirectional backlink graph queryable in O(edges)
|
|
425
|
+
* without recomputing the BFS, which is what the Obsidian plugin (T11827)
|
|
426
|
+
* renders. `cleo docs graph` (T10164) continues to compute the provenance BFS
|
|
427
|
+
* but hydrates persisted backlinks from this table when present.
|
|
428
|
+
*
|
|
429
|
+
* Edges are slug-primary; `to_slug` carries a doc slug for `topic` /
|
|
430
|
+
* `supersedes` / `superseded-by` edges and a `T####` task id for `related-task`
|
|
431
|
+
* edges (`to_is_task = 1`). No markdown body `[[link]]` parsing is performed
|
|
432
|
+
* (AC4) — the edges derive purely from structured provenance columns.
|
|
433
|
+
*
|
|
434
|
+
* @task T11826 (Epic T11781 / Saga T11778)
|
|
435
|
+
*/
|
|
436
|
+
export declare const docsWikilinks: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
437
|
+
name: "docs_wikilinks";
|
|
438
|
+
schema: undefined;
|
|
439
|
+
columns: {
|
|
440
|
+
fromSlug: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
441
|
+
name: string;
|
|
442
|
+
tableName: "docs_wikilinks";
|
|
443
|
+
dataType: "string";
|
|
444
|
+
data: string;
|
|
445
|
+
driverParam: string;
|
|
446
|
+
notNull: true;
|
|
447
|
+
hasDefault: false;
|
|
448
|
+
isPrimaryKey: false;
|
|
449
|
+
isAutoincrement: false;
|
|
450
|
+
hasRuntimeDefault: false;
|
|
451
|
+
enumValues: [string, ...string[]];
|
|
452
|
+
baseColumn: never;
|
|
453
|
+
identity: undefined;
|
|
454
|
+
generated: undefined;
|
|
455
|
+
}, {}>;
|
|
456
|
+
toSlug: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
457
|
+
name: string;
|
|
458
|
+
tableName: "docs_wikilinks";
|
|
459
|
+
dataType: "string";
|
|
460
|
+
data: string;
|
|
461
|
+
driverParam: string;
|
|
462
|
+
notNull: true;
|
|
463
|
+
hasDefault: false;
|
|
464
|
+
isPrimaryKey: false;
|
|
465
|
+
isAutoincrement: false;
|
|
466
|
+
hasRuntimeDefault: false;
|
|
467
|
+
enumValues: [string, ...string[]];
|
|
468
|
+
baseColumn: never;
|
|
469
|
+
identity: undefined;
|
|
470
|
+
generated: undefined;
|
|
471
|
+
}, {}>;
|
|
472
|
+
relation: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
473
|
+
name: string;
|
|
474
|
+
tableName: "docs_wikilinks";
|
|
475
|
+
dataType: "string enum";
|
|
476
|
+
data: "topic" | "supersedes" | "superseded-by" | "related-task";
|
|
477
|
+
driverParam: string;
|
|
478
|
+
notNull: true;
|
|
479
|
+
hasDefault: false;
|
|
480
|
+
isPrimaryKey: false;
|
|
481
|
+
isAutoincrement: false;
|
|
482
|
+
hasRuntimeDefault: false;
|
|
483
|
+
enumValues: ["supersedes", "superseded-by", "related-task", "topic"];
|
|
484
|
+
baseColumn: never;
|
|
485
|
+
identity: undefined;
|
|
486
|
+
generated: undefined;
|
|
487
|
+
}, {}>;
|
|
488
|
+
toIsTask: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
489
|
+
name: string;
|
|
490
|
+
tableName: "docs_wikilinks";
|
|
491
|
+
dataType: "boolean";
|
|
492
|
+
data: boolean;
|
|
493
|
+
driverParam: number;
|
|
494
|
+
notNull: true;
|
|
495
|
+
hasDefault: true;
|
|
496
|
+
isPrimaryKey: false;
|
|
497
|
+
isAutoincrement: false;
|
|
498
|
+
hasRuntimeDefault: false;
|
|
499
|
+
enumValues: undefined;
|
|
500
|
+
baseColumn: never;
|
|
501
|
+
identity: undefined;
|
|
502
|
+
generated: undefined;
|
|
503
|
+
}, {}>;
|
|
504
|
+
derivedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
505
|
+
name: string;
|
|
506
|
+
tableName: "docs_wikilinks";
|
|
507
|
+
dataType: "string";
|
|
508
|
+
data: string;
|
|
509
|
+
driverParam: string;
|
|
510
|
+
notNull: true;
|
|
511
|
+
hasDefault: true;
|
|
512
|
+
isPrimaryKey: false;
|
|
513
|
+
isAutoincrement: false;
|
|
514
|
+
hasRuntimeDefault: false;
|
|
515
|
+
enumValues: [string, ...string[]];
|
|
516
|
+
baseColumn: never;
|
|
517
|
+
identity: undefined;
|
|
518
|
+
generated: undefined;
|
|
519
|
+
}, {}>;
|
|
520
|
+
};
|
|
521
|
+
dialect: "sqlite";
|
|
522
|
+
}>;
|
|
394
523
|
export type AttachmentRow = typeof attachments.$inferSelect;
|
|
395
524
|
export type NewAttachmentRow = typeof attachments.$inferInsert;
|
|
396
525
|
export type AttachmentRefRow = typeof attachmentRefs.$inferSelect;
|
|
397
526
|
export type NewAttachmentRefRow = typeof attachmentRefs.$inferInsert;
|
|
527
|
+
/** Row type for `docs_wikilinks` SELECT queries. */
|
|
528
|
+
export type DocsWikilinkRow = typeof docsWikilinks.$inferSelect;
|
|
529
|
+
/** Row type for `docs_wikilinks` INSERT operations. */
|
|
530
|
+
export type NewDocsWikilinkRow = typeof docsWikilinks.$inferInsert;
|
|
398
531
|
//# sourceMappingURL=attachments.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachments.d.ts","sourceRoot":"","sources":["../../../src/store/schema/attachments.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"attachments.d.ts","sourceRoot":"","sources":["../../../src/store/schema/attachments.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,gFAOzB,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,6BAA6B,oFAOhC,CAAC;AAEX,0DAA0D;AAC1D,MAAM,MAAM,yBAAyB,GAAG,CAAC,OAAO,6BAA6B,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvF;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+HvB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqB1B,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,uBAAuB,mEAK1B,CAAC;AAEX,+DAA+D;AAC/D,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoBzB,CAAC;AAIF,MAAM,MAAM,aAAa,GAAG,OAAO,WAAW,CAAC,YAAY,CAAC;AAC5D,MAAM,MAAM,gBAAgB,GAAG,OAAO,WAAW,CAAC,YAAY,CAAC;AAC/D,MAAM,MAAM,gBAAgB,GAAG,OAAO,cAAc,CAAC,YAAY,CAAC;AAClE,MAAM,MAAM,mBAAmB,GAAG,OAAO,cAAc,CAAC,YAAY,CAAC;AACrE,oDAAoD;AACpD,MAAM,MAAM,eAAe,GAAG,OAAO,aAAa,CAAC,YAAY,CAAC;AAChE,uDAAuD;AACvD,MAAM,MAAM,kBAAkB,GAAG,OAAO,aAAa,CAAC,YAAY,CAAC"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* @epic T760
|
|
5
5
|
* @task T796
|
|
6
6
|
*/
|
|
7
|
+
import { sql } from 'drizzle-orm';
|
|
7
8
|
import { index, integer, primaryKey, sqliteTable, text, } from 'drizzle-orm/sqlite-core';
|
|
8
9
|
/**
|
|
9
10
|
* Allowed owner-entity types for `attachment_refs.owner_type`.
|
|
@@ -196,4 +197,66 @@ export const attachmentRefs = sqliteTable('attachment_refs', {
|
|
|
196
197
|
index('idx_attachment_refs_attachment_id').on(table.attachmentId),
|
|
197
198
|
index('idx_attachment_refs_owner').on(table.ownerType, table.ownerId),
|
|
198
199
|
]);
|
|
200
|
+
/**
|
|
201
|
+
* Allowed relations for a `docs_wikilinks` edge.
|
|
202
|
+
*
|
|
203
|
+
* A wikilink is a DERIVED, slug-addressed edge between two docs (or a doc and a
|
|
204
|
+
* task) reconstructed from the authoritative provenance columns on
|
|
205
|
+
* `attachments` — there is no hand-authored edge here. The relation enumerates
|
|
206
|
+
* which source column produced the edge:
|
|
207
|
+
*
|
|
208
|
+
* - `supersedes` — `attachments.supersedes` (newer → older)
|
|
209
|
+
* - `superseded-by` — `attachments.superseded_by` (older → newer)
|
|
210
|
+
* - `related-task` — `attachments.related_tasks` JSON membership (doc → T####)
|
|
211
|
+
* - `topic` — `attachments.topics` JSON co-membership (doc ↔ doc sharing a topic)
|
|
212
|
+
*
|
|
213
|
+
* Kept slug-primary so the edge table is Obsidian-grade (vault links are
|
|
214
|
+
* slug-addressed) and survives attachment-id churn across versions.
|
|
215
|
+
*
|
|
216
|
+
* @task T11826 (Epic T11781 / Saga T11778)
|
|
217
|
+
*/
|
|
218
|
+
export const DOCS_WIKILINK_RELATIONS = [
|
|
219
|
+
'supersedes',
|
|
220
|
+
'superseded-by',
|
|
221
|
+
'related-task',
|
|
222
|
+
'topic',
|
|
223
|
+
];
|
|
224
|
+
/**
|
|
225
|
+
* `docs_wikilinks` — DERIVED, slug-addressed edge table for the docs graph.
|
|
226
|
+
*
|
|
227
|
+
* Per the ratified Docs-SSoT model (saga T11778): `cleo.db` is the SOLE doc
|
|
228
|
+
* authority, and `docs_wikilinks` is a *minimal edge table derived from*
|
|
229
|
+
* `supersedes` + `relatedTasks` + `topics` on `attachments`. It is NOT an
|
|
230
|
+
* authoritative input surface — it is rebuilt idempotently from the provenance
|
|
231
|
+
* columns by {@link import('../../docs/wikilinks.js').rebuildDocsWikilinks}.
|
|
232
|
+
*
|
|
233
|
+
* The table makes the bidirectional backlink graph queryable in O(edges)
|
|
234
|
+
* without recomputing the BFS, which is what the Obsidian plugin (T11827)
|
|
235
|
+
* renders. `cleo docs graph` (T10164) continues to compute the provenance BFS
|
|
236
|
+
* but hydrates persisted backlinks from this table when present.
|
|
237
|
+
*
|
|
238
|
+
* Edges are slug-primary; `to_slug` carries a doc slug for `topic` /
|
|
239
|
+
* `supersedes` / `superseded-by` edges and a `T####` task id for `related-task`
|
|
240
|
+
* edges (`to_is_task = 1`). No markdown body `[[link]]` parsing is performed
|
|
241
|
+
* (AC4) — the edges derive purely from structured provenance columns.
|
|
242
|
+
*
|
|
243
|
+
* @task T11826 (Epic T11781 / Saga T11778)
|
|
244
|
+
*/
|
|
245
|
+
export const docsWikilinks = sqliteTable('docs_wikilinks', {
|
|
246
|
+
/** Source doc slug (→ `attachments.slug`). Always a doc. */
|
|
247
|
+
fromSlug: text('from_slug').notNull(),
|
|
248
|
+
/** Target slug — a doc slug, or a `T####` task id when `toIsTask = 1`. */
|
|
249
|
+
toSlug: text('to_slug').notNull(),
|
|
250
|
+
/** Which provenance column produced this edge — dispatch-validated, no SQL CHECK. */
|
|
251
|
+
relation: text('relation', { enum: DOCS_WIKILINK_RELATIONS }).notNull(),
|
|
252
|
+
/** 1 when `to_slug` is a task id (`related-task` edges); 0 for doc→doc edges. */
|
|
253
|
+
toIsTask: integer('to_is_task', { mode: 'boolean' }).notNull().default(false),
|
|
254
|
+
/** ISO-8601 UTC instant this edge was last (re)derived. */
|
|
255
|
+
derivedAt: text('derived_at').notNull().default(sql `(datetime('now'))`),
|
|
256
|
+
}, (table) => [
|
|
257
|
+
primaryKey({ columns: [table.fromSlug, table.toSlug, table.relation] }),
|
|
258
|
+
index('idx_docs_wikilinks_from').on(table.fromSlug),
|
|
259
|
+
index('idx_docs_wikilinks_to').on(table.toSlug),
|
|
260
|
+
index('idx_docs_wikilinks_relation').on(table.relation),
|
|
261
|
+
]);
|
|
199
262
|
//# sourceMappingURL=attachments.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachments.js","sourceRoot":"","sources":["../../../src/store/schema/attachments.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"attachments.js","sourceRoot":"","sources":["../../../src/store/schema/attachments.ts"],"names":[],"mappings":"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"}
|
package/dist/tasks/add.d.ts
CHANGED
|
@@ -60,6 +60,19 @@ export interface AddTaskOptions {
|
|
|
60
60
|
* @task T1633
|
|
61
61
|
*/
|
|
62
62
|
forceDuplicate?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Bypass the T11811 write-time containment invariant (orphan / terminal-parent
|
|
65
|
+
* / wrong-tier rejection).
|
|
66
|
+
*
|
|
67
|
+
* MUST be set ONLY by historical data-movement paths — exodus migration,
|
|
68
|
+
* `cleo import`, restore/JSON-merge replay — which legitimately re-insert
|
|
69
|
+
* rows that predate the strict-spine rule (the fleet still carries legacy
|
|
70
|
+
* orphans). Agent-facing `cleo add` / `add-batch` MUST NOT set this; the
|
|
71
|
+
* invariant is the whole point of the guard for net-new work.
|
|
72
|
+
*
|
|
73
|
+
* @task T11811
|
|
74
|
+
*/
|
|
75
|
+
skipContainmentInvariant?: boolean;
|
|
63
76
|
}
|
|
64
77
|
/** Result of adding a task. */
|
|
65
78
|
export interface AddTaskResult {
|
package/dist/tasks/add.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/tasks/add.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAEV,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,gBAAgB,EACjB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/tasks/add.ts"],"names":[],"mappings":"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"}
|
package/dist/tasks/add.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { randomBytes } from 'node:crypto';
|
|
8
8
|
// setMetaValue now called via tx.setMetaValue inside transaction (T023)
|
|
9
|
-
import { ExitCode, isAllowedWorkGraphParentType, TASK_STATUSES } from '@cleocode/contracts';
|
|
9
|
+
import { ExitCode, isAllowedWorkGraphParentType, TASK_STATUSES, TERMINAL_TASK_STATUSES, } from '@cleocode/contracts';
|
|
10
10
|
import { loadConfig } from '../config.js';
|
|
11
11
|
import { CleoError } from '../errors.js';
|
|
12
12
|
import { resolveOrCwd } from '../paths.js';
|
|
@@ -15,7 +15,7 @@ import { requireActiveSession } from '../sessions/session-enforcement.js';
|
|
|
15
15
|
import { trackBackgroundOp } from '../store/background-ops.js';
|
|
16
16
|
import { acItemToText, applyAcPlan, buildAcRowId, buildChildProjectionAcText, buildFreshAcRows, childProjectionFreshnessFingerprint, childProjectionSourceKey, } from './ac-table.js';
|
|
17
17
|
import { createAcceptanceEnforcement } from './enforcement.js';
|
|
18
|
-
import { findEpicAncestor,
|
|
18
|
+
import { findEpicAncestor, validateChildStageCeiling, validateEpicCreation, } from './epic-enforcement.js';
|
|
19
19
|
import { resolveHierarchyPolicy } from './hierarchy-policy.js';
|
|
20
20
|
import { resolveDefaultPipelineStage, validatePipelineStage } from './pipeline-stage.js';
|
|
21
21
|
/** Normalize AC arrays once so legacy JSON, AC rows, and projections stay aligned. */
|
|
@@ -524,23 +524,34 @@ export async function addTask(options, cwd, accessor) {
|
|
|
524
524
|
fix: 'Provide --desc with a description different from the title',
|
|
525
525
|
});
|
|
526
526
|
}
|
|
527
|
-
// Orphan prevention (T101
|
|
528
|
-
//
|
|
529
|
-
//
|
|
527
|
+
// Orphan prevention (T101 → hardened by T11811 AC1).
|
|
528
|
+
//
|
|
529
|
+
// Write-time containment invariant — the strict-spine rule (owner decision 1):
|
|
530
|
+
// EVERY net-new node must attach to a parent unless it is a `saga`. Only sagas
|
|
531
|
+
// may be roots. A `task` / `subtask` / `epic` with a null/absent parent is a
|
|
532
|
+
// NET-NEW ORPHAN and is HARD-REJECTED regardless of lifecycle mode — the prior
|
|
533
|
+
// strict-mode-only gate let advisory-mode installs silently manufacture the
|
|
534
|
+
// exact orphan the doctor/CI gate then flags.
|
|
535
|
+
//
|
|
536
|
+
// Escape hatch: historical data-movement paths (exodus, import, restore replay)
|
|
537
|
+
// set `skipContainmentInvariant` so legacy rows that predate the rule are not
|
|
538
|
+
// self-blocked. Dry-run is exempt (no data is written).
|
|
539
|
+
//
|
|
540
|
+
// The effective type mirrors the later inference: an unset type with no parent
|
|
541
|
+
// resolves to `task`, so a bare `cleo add "X"` (no parent, no type) is rejected.
|
|
530
542
|
const parentId = options.parentId ?? null;
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
}
|
|
543
|
+
const effectiveRootType = options.type ?? 'task';
|
|
544
|
+
if (!options.dryRun &&
|
|
545
|
+
!options.skipContainmentInvariant &&
|
|
546
|
+
!parentId &&
|
|
547
|
+
effectiveRootType !== 'saga') {
|
|
548
|
+
issues.push({
|
|
549
|
+
field: 'parentId',
|
|
550
|
+
message: `A ${effectiveRootType} must attach to a parent — only a saga may be a root ` +
|
|
551
|
+
`(strict-spine containment, T11811). Use --parent <id> to file it under the ` +
|
|
552
|
+
`correct container (saga→epic, epic→task, task→subtask).`,
|
|
553
|
+
fix: 'cleo add "Task title" --parent T### --acceptance "AC1|AC2|AC3"',
|
|
554
|
+
});
|
|
544
555
|
}
|
|
545
556
|
// Always use accessor (SQLite canonical storage per ADR-006)
|
|
546
557
|
const dataAccessor = accessor ?? (await (await import('../store/data-accessor.js')).getTaskAccessor(cwd));
|
|
@@ -686,6 +697,27 @@ export async function addTask(options, cwd, accessor) {
|
|
|
686
697
|
details: { field: 'parentId', actual: parentId },
|
|
687
698
|
});
|
|
688
699
|
}
|
|
700
|
+
// T11811 AC1 — reject filing NET-NEW work under an IRREVERSIBLY-TERMINAL
|
|
701
|
+
// parent (`cancelled` / `archived`). A child added under such a parent is
|
|
702
|
+
// born stranded — the parent can never be auto-reopened to satisfy it.
|
|
703
|
+
//
|
|
704
|
+
// `done` is deliberately EXCLUDED: PM-Core V2 design-point 5 (saga T10538)
|
|
705
|
+
// reopens a `done` parent (and done ancestors) when a child is filed under
|
|
706
|
+
// it, so the child is NOT stranded — see the reopen logic below. Mirrors the
|
|
707
|
+
// `s !== 'done'` carve-out already in satisfies-validator.ts. Skip entirely
|
|
708
|
+
// for the historical-replay escape hatch (legacy rows reference terminals).
|
|
709
|
+
const parentIsIrreversiblyTerminal = TERMINAL_TASK_STATUSES.has(parentTask.status) && parentTask.status !== 'done';
|
|
710
|
+
if (!options.skipContainmentInvariant && parentIsIrreversiblyTerminal) {
|
|
711
|
+
throw new CleoError(ExitCode.VALIDATION_ERROR, `Cannot file new work under ${parentId}: its status is '${parentTask.status}' (terminal). ` +
|
|
712
|
+
`A child under a terminal parent is born stranded.`, {
|
|
713
|
+
fix: `Pick a non-terminal parent (cleo find), or reopen ${parentId} first (cleo restore task ${parentId}).`,
|
|
714
|
+
details: {
|
|
715
|
+
field: 'parentId',
|
|
716
|
+
expected: 'non-terminal parent (pending|active|blocked|done)',
|
|
717
|
+
actual: parentTask.status,
|
|
718
|
+
},
|
|
719
|
+
});
|
|
720
|
+
}
|
|
689
721
|
parentTaskForProjection = parentTask;
|
|
690
722
|
// Read hierarchy limits from config via policy module
|
|
691
723
|
const config = await loadConfig(cwd);
|