@cleocode/contracts 2026.5.90 → 2026.5.93

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.
Files changed (50) hide show
  1. package/dist/__tests__/docs-taxonomy.test.d.ts +16 -0
  2. package/dist/__tests__/docs-taxonomy.test.d.ts.map +1 -0
  3. package/dist/__tests__/docs-taxonomy.test.js +404 -0
  4. package/dist/__tests__/docs-taxonomy.test.js.map +1 -0
  5. package/dist/docs-taxonomy.d.ts +286 -0
  6. package/dist/docs-taxonomy.d.ts.map +1 -0
  7. package/dist/docs-taxonomy.js +489 -0
  8. package/dist/docs-taxonomy.js.map +1 -0
  9. package/dist/doctor.d.ts +120 -0
  10. package/dist/doctor.d.ts.map +1 -0
  11. package/dist/doctor.js +16 -0
  12. package/dist/doctor.js.map +1 -0
  13. package/dist/index.d.ts +9 -3
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +2 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/logger.d.ts +42 -0
  18. package/dist/logger.d.ts.map +1 -0
  19. package/dist/logger.js +14 -0
  20. package/dist/logger.js.map +1 -0
  21. package/dist/memory.d.ts +145 -2
  22. package/dist/memory.d.ts.map +1 -1
  23. package/dist/memory.js +22 -2
  24. package/dist/memory.js.map +1 -1
  25. package/dist/operations/docs.d.ts +89 -11
  26. package/dist/operations/docs.d.ts.map +1 -1
  27. package/dist/operations/docs.js +19 -12
  28. package/dist/operations/docs.js.map +1 -1
  29. package/dist/operations/session.d.ts +66 -0
  30. package/dist/operations/session.d.ts.map +1 -1
  31. package/dist/operations/validate.d.ts +32 -0
  32. package/dist/operations/validate.d.ts.map +1 -1
  33. package/dist/release/evidence-atoms.d.ts +103 -0
  34. package/dist/release/evidence-atoms.d.ts.map +1 -0
  35. package/dist/release/evidence-atoms.js +89 -0
  36. package/dist/release/evidence-atoms.js.map +1 -0
  37. package/dist/task.d.ts +43 -0
  38. package/dist/task.d.ts.map +1 -1
  39. package/package.json +2 -2
  40. package/src/__tests__/docs-taxonomy.test.ts +465 -0
  41. package/src/docs-taxonomy.ts +682 -0
  42. package/src/doctor.ts +130 -0
  43. package/src/index.ts +37 -0
  44. package/src/logger.ts +42 -0
  45. package/src/memory.ts +154 -2
  46. package/src/operations/docs.ts +92 -18
  47. package/src/operations/session.ts +71 -0
  48. package/src/operations/validate.ts +34 -0
  49. package/src/release/evidence-atoms.ts +118 -0
  50. package/src/task.ts +44 -0
@@ -0,0 +1,489 @@
1
+ /**
2
+ * Canonical Doc-Kind Taxonomy Registry (T9788).
3
+ *
4
+ * Single source of truth for the user-facing document-kind taxonomy consumed
5
+ * by `cleo docs` (add / list / publish-pr / list-types / schema). Prior to
6
+ * this module the taxonomy was duplicated across three files:
7
+ *
8
+ * - `packages/contracts/src/operations/docs.ts` — `DOCS_TYPE_VALUES` (6 kinds)
9
+ * - `packages/core/src/docs/publish-pr.ts` — `KNOWN_DOC_TYPES` (6 kinds)
10
+ * - `packages/cleo/src/dispatch/domains/docs.ts` — local mirror (6 kinds)
11
+ *
12
+ * The three copies drifted independently. T9788 consolidates them behind
13
+ * {@link DocKindRegistry} so a new kind requires editing exactly one place
14
+ * (or one config file for project-level extensions).
15
+ *
16
+ * IMPORTANT — relationship to {@link import('./docs-accessor.js').DocKind}:
17
+ * `DocKind` in `docs-accessor.ts` is the STORAGE-LAYER discriminator (which
18
+ * backing store holds the bytes — llmtxt.db vs manifest.db). The taxonomy
19
+ * here is the USER-FACING DOCUMENT CLASSIFICATION (what kind of document
20
+ * the human / agent authored). The two are intentionally distinct:
21
+ *
22
+ * - `docs-accessor.DocKind` answers "where is it stored?"
23
+ * - `docs-taxonomy.DocKindMetadata.kind` answers "what is it about?"
24
+ *
25
+ * Most user-facing docs are stored under `docs-accessor.DocKind = 'adr'` or
26
+ * `'agent-output'`; their taxonomy `kind` (this file) carries the semantic
27
+ * classification.
28
+ *
29
+ * Backward compatibility (T9788 AC8):
30
+ * - Every prior `DOCS_TYPE_VALUES` value remains in {@link BUILTIN_DOC_KINDS}.
31
+ * - Tests using literal strings `'spec'`, `'adr'`, etc. continue to pass.
32
+ * - The stored `type` column shape is unchanged (still a string).
33
+ *
34
+ * @epic T9787 (E-DOCS-TAXONOMY-V2)
35
+ * @task T9788
36
+ * @see ADR-073 §1 — Task Hierarchy Charter (sibling registry pattern)
37
+ */
38
+ import { readFileSync } from 'node:fs';
39
+ import { join } from 'node:path';
40
+ // ---------------------------------------------------------------------------
41
+ // Built-in registry (10 canonical kinds)
42
+ // ---------------------------------------------------------------------------
43
+ /**
44
+ * Canonical list of built-in document kinds.
45
+ *
46
+ * Adding a kind requires:
47
+ * 1. Append an entry here (preserving existing kinds for back-compat).
48
+ * 2. Run the contracts build — every consumer picks the new kind up.
49
+ *
50
+ * Order is preserved by {@link DocKindRegistry.list}. Built-in kinds
51
+ * always sort before extensions.
52
+ *
53
+ * @see {@link DocKindMetadata} — entry shape
54
+ */
55
+ export const BUILTIN_DOC_KINDS = [
56
+ {
57
+ kind: 'adr',
58
+ label: 'ADR',
59
+ description: 'Architectural decision record',
60
+ defaultOwnerKind: 'task',
61
+ publishDir: 'docs/adr',
62
+ requiresEntityId: true,
63
+ entityIdPattern: /^adr-\d{3,4}-[a-z0-9-]+$/,
64
+ },
65
+ {
66
+ kind: 'spec',
67
+ label: 'Spec',
68
+ description: 'Technical specification',
69
+ defaultOwnerKind: 'task',
70
+ publishDir: 'docs/spec',
71
+ requiresEntityId: false,
72
+ },
73
+ {
74
+ kind: 'research',
75
+ label: 'Research',
76
+ description: 'Investigation / research note',
77
+ defaultOwnerKind: 'task',
78
+ publishDir: 'docs/research',
79
+ requiresEntityId: false,
80
+ },
81
+ {
82
+ kind: 'handoff',
83
+ label: 'Handoff',
84
+ description: 'Session / agent handoff',
85
+ defaultOwnerKind: 'session',
86
+ publishDir: 'docs/handoff',
87
+ requiresEntityId: false,
88
+ },
89
+ {
90
+ kind: 'note',
91
+ label: 'Note',
92
+ description: 'Agent observation / informal note',
93
+ defaultOwnerKind: 'observation',
94
+ publishDir: 'docs/note',
95
+ requiresEntityId: false,
96
+ },
97
+ {
98
+ kind: 'llm-readme',
99
+ label: 'LLM README',
100
+ description: 'Machine-readable README (llms.txt)',
101
+ defaultOwnerKind: 'project',
102
+ publishDir: '.',
103
+ requiresEntityId: false,
104
+ },
105
+ {
106
+ kind: 'changeset',
107
+ label: 'Changeset',
108
+ description: 'Atomic change entry (release-note input)',
109
+ defaultOwnerKind: 'task',
110
+ publishDir: '.changeset',
111
+ requiresEntityId: true,
112
+ entityIdPattern: /^t\d+-[a-z0-9-]+$/,
113
+ },
114
+ {
115
+ kind: 'release-note',
116
+ label: 'Release Note',
117
+ description: 'Composed release notes',
118
+ defaultOwnerKind: 'project',
119
+ publishDir: 'docs/release',
120
+ requiresEntityId: true,
121
+ entityIdPattern: /^v\d{4}\.\d+\.\d+(-[a-z0-9-]+)?$/,
122
+ },
123
+ {
124
+ kind: 'plan',
125
+ label: 'Plan',
126
+ description: 'Epic / saga decomposition plan',
127
+ defaultOwnerKind: 'task',
128
+ publishDir: 'docs/plan',
129
+ requiresEntityId: false,
130
+ },
131
+ {
132
+ kind: 'rcasd',
133
+ label: 'RCASD',
134
+ description: 'Root-cause analysis + scoped delivery',
135
+ defaultOwnerKind: 'task',
136
+ publishDir: '.cleo/rcasd',
137
+ requiresEntityId: true,
138
+ entityIdPattern: /^t\d+(-.+)?$/,
139
+ },
140
+ ];
141
+ /**
142
+ * Tuple of every built-in kind id (lowercase kebab-case).
143
+ *
144
+ * Useful for `satisfies` checks and union derivation in downstream
145
+ * contracts (e.g. `operations/docs.ts`). Kept frozen.
146
+ */
147
+ export const BUILTIN_DOC_KIND_VALUES = Object.freeze(BUILTIN_DOC_KINDS.map((d) => d.kind));
148
+ // ---------------------------------------------------------------------------
149
+ // Registry class
150
+ // ---------------------------------------------------------------------------
151
+ /**
152
+ * Runtime accessor for the canonical doc-kind registry.
153
+ *
154
+ * Combines {@link BUILTIN_DOC_KINDS} with project-level extensions loaded
155
+ * from `.cleo/docs-config.json`. Built-in entries always win on collision
156
+ * — extensions cannot override a built-in kind.
157
+ *
158
+ * Usage:
159
+ * ```ts
160
+ * const registry = DocKindRegistry.load(projectRoot);
161
+ * const adr = registry.get('adr');
162
+ * const check = registry.validateSlug('adr', 'adr-001-intro');
163
+ * ```
164
+ *
165
+ * @task T9788
166
+ */
167
+ export class DocKindRegistry {
168
+ /**
169
+ * Maximum allowed length of an `entityIdPattern` source string.
170
+ *
171
+ * Caps the input surface so a malformed extension config cannot trigger
172
+ * pathological regex backtracking. 256 chars is far more than any
173
+ * realistic slug pattern (typical: 30–60 chars).
174
+ */
175
+ static SAFE_REGEX_LENGTH_LIMIT = 256;
176
+ byKind;
177
+ orderedEntries;
178
+ /**
179
+ * Construct a registry from an explicit array of entries.
180
+ *
181
+ * Most callers should use {@link DocKindRegistry.load} instead; this
182
+ * constructor is exposed for tests that want to bypass filesystem I/O.
183
+ *
184
+ * @param entries - Pre-validated doc-kind metadata (built-in + extensions).
185
+ */
186
+ constructor(entries) {
187
+ this.orderedEntries = entries;
188
+ const map = new Map();
189
+ for (const entry of entries) {
190
+ // First write wins; built-ins are passed first by `load`, so this
191
+ // automatically gives built-ins precedence over extensions.
192
+ if (!map.has(entry.kind))
193
+ map.set(entry.kind, entry);
194
+ }
195
+ this.byKind = map;
196
+ }
197
+ /**
198
+ * Load the canonical registry, merging built-ins with extensions from
199
+ * `<projectRoot>/.cleo/docs-config.json`.
200
+ *
201
+ * Missing or unreadable config file → returns the built-in-only registry.
202
+ * Malformed config (bad JSON, invalid entry, regex too long, etc.) →
203
+ * throws {@link DocKindConfigError} so the caller can surface a clear
204
+ * envelope rather than silently dropping extensions.
205
+ *
206
+ * @param projectRoot - Absolute path to the repo root.
207
+ * @throws DocKindConfigError when the config exists but is invalid.
208
+ */
209
+ static load(projectRoot) {
210
+ const configPath = join(projectRoot, '.cleo', 'docs-config.json');
211
+ let raw;
212
+ try {
213
+ raw = readFileSync(configPath, 'utf-8');
214
+ }
215
+ catch {
216
+ // No config file → built-ins only.
217
+ return new DocKindRegistry(BUILTIN_DOC_KINDS);
218
+ }
219
+ let parsed;
220
+ try {
221
+ parsed = JSON.parse(raw);
222
+ }
223
+ catch (err) {
224
+ throw new DocKindConfigError(`${configPath}: invalid JSON — ${err.message}`, configPath);
225
+ }
226
+ const config = validateDocKindConfig(parsed, configPath);
227
+ const extensions = (config.extensions ?? []).map((ext) => compileExtension(ext, configPath));
228
+ return new DocKindRegistry([...BUILTIN_DOC_KINDS, ...extensions]);
229
+ }
230
+ /**
231
+ * Build a registry from already-parsed config — bypasses filesystem I/O.
232
+ *
233
+ * Used by tests and HTTP-dispatch callers that hand-construct a config
234
+ * object instead of reading from disk.
235
+ *
236
+ * @param config - Parsed config object (or `undefined` for built-ins only).
237
+ * @param sourceLabel - Optional label used in error messages.
238
+ * @throws DocKindConfigError when the config object is invalid.
239
+ */
240
+ static fromConfig(config, sourceLabel = '<inline-config>') {
241
+ if (!config)
242
+ return new DocKindRegistry(BUILTIN_DOC_KINDS);
243
+ const validated = validateDocKindConfig(config, sourceLabel);
244
+ const extensions = (validated.extensions ?? []).map((ext) => compileExtension(ext, sourceLabel));
245
+ return new DocKindRegistry([...BUILTIN_DOC_KINDS, ...extensions]);
246
+ }
247
+ /**
248
+ * Default registry — built-in kinds only, no extensions.
249
+ *
250
+ * Suitable for code paths that never need project-level extensions
251
+ * (e.g. unit tests, library-mode consumers).
252
+ */
253
+ static builtinOnly() {
254
+ return new DocKindRegistry(BUILTIN_DOC_KINDS);
255
+ }
256
+ /** True when `kind` is registered (built-in OR extension). */
257
+ has(kind) {
258
+ return this.byKind.has(kind);
259
+ }
260
+ /** Look up metadata for a registered kind. Returns `undefined` on miss. */
261
+ get(kind) {
262
+ return this.byKind.get(kind);
263
+ }
264
+ /**
265
+ * List every registered kind, built-ins first then extensions in
266
+ * declaration order.
267
+ *
268
+ * Used by `cleo docs schema` and `cleo docs list-types`.
269
+ */
270
+ list() {
271
+ return this.orderedEntries;
272
+ }
273
+ /**
274
+ * Validate a slug against the registered pattern for `kind`.
275
+ *
276
+ * Behaviour:
277
+ * - Unknown kind → `{ ok: false, error: "unknown kind '<kind>'" }`.
278
+ * - Known kind with `requiresEntityId === false` → always `{ ok: true }`.
279
+ * - Known kind with `requiresEntityId === true` and no pattern → defensive
280
+ * `{ ok: false }` since the registry entry is internally inconsistent.
281
+ * - Known kind with pattern → tests `slug` against the pattern.
282
+ *
283
+ * @param kind - Registered kind id.
284
+ * @param slug - Slug to validate.
285
+ * @returns Pass/fail result with a human-readable error on failure.
286
+ */
287
+ validateSlug(kind, slug) {
288
+ const meta = this.byKind.get(kind);
289
+ if (!meta) {
290
+ return { ok: false, error: `unknown kind '${kind}'` };
291
+ }
292
+ if (!meta.requiresEntityId) {
293
+ return { ok: true };
294
+ }
295
+ if (!meta.entityIdPattern) {
296
+ // Defensive: registry entry marked requiresEntityId but lacks the
297
+ // pattern. Built-in entries always carry one; an extension that
298
+ // omits it is rejected at load time, so this branch is reachable
299
+ // only via the public constructor with a hand-crafted array.
300
+ return {
301
+ ok: false,
302
+ error: `kind '${kind}' requires an entityIdPattern but the registry entry omits one`,
303
+ };
304
+ }
305
+ if (!meta.entityIdPattern.test(slug)) {
306
+ return {
307
+ ok: false,
308
+ error: `slug '${slug}' does not match pattern ${meta.entityIdPattern.source} for kind '${kind}'`,
309
+ example: buildSlugExample(meta),
310
+ };
311
+ }
312
+ return { ok: true };
313
+ }
314
+ /**
315
+ * Map a kind to its `publishDir` (e.g. `'adr'` → `'docs/adr'`).
316
+ *
317
+ * Returns `undefined` for unknown kinds — callers decide whether to
318
+ * fall back to a default (e.g. `'docs/note'`) or surface an error.
319
+ */
320
+ publishDirFor(kind) {
321
+ return this.byKind.get(kind)?.publishDir;
322
+ }
323
+ }
324
+ /**
325
+ * Error thrown by {@link DocKindRegistry.load} and
326
+ * {@link DocKindRegistry.fromConfig} when the supplied config is invalid.
327
+ *
328
+ * Carries the offending source path / label so the CLI surface can render
329
+ * a `details` payload pointing the user at the right file.
330
+ */
331
+ export class DocKindConfigError extends Error {
332
+ /** Source identifier — file path on disk, or `<inline-config>` for tests. */
333
+ source;
334
+ constructor(message, source) {
335
+ super(message);
336
+ this.name = 'DocKindConfigError';
337
+ this.source = source;
338
+ }
339
+ }
340
+ // ---------------------------------------------------------------------------
341
+ // Config validation helpers
342
+ // ---------------------------------------------------------------------------
343
+ /**
344
+ * Narrow an arbitrary parsed-JSON value to {@link DocKindConfigFile}.
345
+ *
346
+ * Performs structural validation only — regex compilation happens in
347
+ * {@link compileExtension}.
348
+ *
349
+ * @internal
350
+ */
351
+ function validateDocKindConfig(raw, source) {
352
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
353
+ throw new DocKindConfigError(`${source}: top-level value must be an object`, source);
354
+ }
355
+ const obj = raw;
356
+ if (obj.extensions === undefined) {
357
+ return {};
358
+ }
359
+ if (!Array.isArray(obj.extensions)) {
360
+ throw new DocKindConfigError(`${source}: 'extensions' must be an array`, source);
361
+ }
362
+ const extensions = [];
363
+ for (let i = 0; i < obj.extensions.length; i++) {
364
+ const item = obj.extensions[i];
365
+ extensions.push(validateExtensionEntry(item, source, i));
366
+ }
367
+ return { extensions };
368
+ }
369
+ /**
370
+ * Narrow one extension entry from the parsed `extensions[]` array.
371
+ *
372
+ * @internal
373
+ */
374
+ function validateExtensionEntry(raw, source, index) {
375
+ const where = `${source} extensions[${index}]`;
376
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
377
+ throw new DocKindConfigError(`${where}: must be an object`, source);
378
+ }
379
+ const obj = raw;
380
+ const kind = requireString(obj, 'kind', where, source);
381
+ if (!/^[a-z][a-z0-9-]*$/.test(kind)) {
382
+ throw new DocKindConfigError(`${where}: 'kind' must be lowercase kebab-case (got '${kind}')`, source);
383
+ }
384
+ const builtinNames = new Set(BUILTIN_DOC_KIND_VALUES);
385
+ if (builtinNames.has(kind)) {
386
+ throw new DocKindConfigError(`${where}: kind '${kind}' shadows a built-in — built-ins cannot be overridden`, source);
387
+ }
388
+ const label = requireString(obj, 'label', where, source);
389
+ const description = requireString(obj, 'description', where, source);
390
+ const defaultOwnerKind = requireString(obj, 'defaultOwnerKind', where, source);
391
+ if (defaultOwnerKind !== 'task' &&
392
+ defaultOwnerKind !== 'session' &&
393
+ defaultOwnerKind !== 'observation' &&
394
+ defaultOwnerKind !== 'project') {
395
+ throw new DocKindConfigError(`${where}: 'defaultOwnerKind' must be task|session|observation|project (got '${defaultOwnerKind}')`, source);
396
+ }
397
+ const publishDir = requireString(obj, 'publishDir', where, source);
398
+ const requiresEntityId = obj.requiresEntityId;
399
+ if (typeof requiresEntityId !== 'boolean') {
400
+ throw new DocKindConfigError(`${where}: 'requiresEntityId' must be a boolean`, source);
401
+ }
402
+ let entityIdPattern;
403
+ if (obj.entityIdPattern !== undefined) {
404
+ if (typeof obj.entityIdPattern !== 'string') {
405
+ throw new DocKindConfigError(`${where}: 'entityIdPattern' must be a string`, source);
406
+ }
407
+ if (obj.entityIdPattern.length > DocKindRegistry.SAFE_REGEX_LENGTH_LIMIT) {
408
+ throw new DocKindConfigError(`${where}: 'entityIdPattern' exceeds ${DocKindRegistry.SAFE_REGEX_LENGTH_LIMIT} chars`, source);
409
+ }
410
+ entityIdPattern = obj.entityIdPattern;
411
+ }
412
+ if (requiresEntityId && entityIdPattern === undefined) {
413
+ throw new DocKindConfigError(`${where}: 'entityIdPattern' is required when 'requiresEntityId' is true`, source);
414
+ }
415
+ return {
416
+ kind,
417
+ label,
418
+ description,
419
+ defaultOwnerKind,
420
+ publishDir,
421
+ requiresEntityId,
422
+ ...(entityIdPattern !== undefined ? { entityIdPattern } : {}),
423
+ };
424
+ }
425
+ /**
426
+ * Compile an extension config into a `DocKindMetadata` (regex compiled,
427
+ * `isExtension` set).
428
+ *
429
+ * @internal
430
+ */
431
+ function compileExtension(ext, source) {
432
+ let entityIdPattern;
433
+ if (ext.entityIdPattern !== undefined) {
434
+ try {
435
+ entityIdPattern = new RegExp(ext.entityIdPattern);
436
+ }
437
+ catch (err) {
438
+ throw new DocKindConfigError(`${source}: invalid regex for kind '${ext.kind}': ${err.message}`, source);
439
+ }
440
+ }
441
+ return {
442
+ kind: ext.kind,
443
+ label: ext.label,
444
+ description: ext.description,
445
+ defaultOwnerKind: ext.defaultOwnerKind,
446
+ publishDir: ext.publishDir,
447
+ requiresEntityId: ext.requiresEntityId,
448
+ ...(entityIdPattern !== undefined ? { entityIdPattern } : {}),
449
+ isExtension: true,
450
+ };
451
+ }
452
+ /**
453
+ * Extract a required string field from a parsed JSON object.
454
+ *
455
+ * @internal
456
+ */
457
+ function requireString(obj, field, where, source) {
458
+ const value = obj[field];
459
+ if (typeof value !== 'string' || value.length === 0) {
460
+ throw new DocKindConfigError(`${where}: '${field}' must be a non-empty string`, source);
461
+ }
462
+ return value;
463
+ }
464
+ /**
465
+ * Build a best-effort example slug from a metadata entry's pattern.
466
+ *
467
+ * Used by {@link DocKindRegistry.validateSlug} to give the caller a
468
+ * concrete sample slug that would pass. Built-in patterns ship with
469
+ * hard-coded samples; extensions fall back to the pattern source.
470
+ *
471
+ * @internal
472
+ */
473
+ function buildSlugExample(meta) {
474
+ // Hard-coded samples for built-in kinds keep the error message friendly.
475
+ // Extensions get the raw pattern as a fallback.
476
+ switch (meta.kind) {
477
+ case 'adr':
478
+ return 'adr-001-intro';
479
+ case 'changeset':
480
+ return 't9788-docs-taxonomy';
481
+ case 'release-note':
482
+ return 'v2026.5.93';
483
+ case 'rcasd':
484
+ return 't9788-investigation';
485
+ default:
486
+ return meta.entityIdPattern?.source;
487
+ }
488
+ }
489
+ //# sourceMappingURL=docs-taxonomy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs-taxonomy.js","sourceRoot":"","sources":["../src/docs-taxonomy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Doctor domain contracts — types for `cleo doctor` worktree-orphan audit/prune.
3
+ *
4
+ * These types describe orphan `.cleo/` directories left behind under
5
+ * `<projectRoot>/.claude/worktrees/` by the T9550/T9580 SSoT bug (fixed in
6
+ * v2026.5.83) and the schema for the audit JSONL line written per prune.
7
+ *
8
+ * Consumed by:
9
+ * - `packages/core/src/doctor/worktree-orphans.ts` (scan + prune primitives)
10
+ * - `packages/cleo/src/cli/commands/doctor.ts` (CLI flags)
11
+ *
12
+ * @task T9790
13
+ * @epic T9790
14
+ */
15
+ /**
16
+ * One orphan `.cleo/` directory discovered under
17
+ * `<projectRoot>/.claude/worktrees/`.
18
+ *
19
+ * Worktrees are nested 1-3 levels deep — examples:
20
+ * - `<projectRoot>/.claude/worktrees/agent-X/.cleo/` (depth 1)
21
+ * - `<projectRoot>/.claude/worktrees/agent-X/T9220/.cleo/` (depth 2)
22
+ *
23
+ * Each entry carries full provenance so the operator can decide whether
24
+ * the orphan represents lost work before pruning.
25
+ */
26
+ export interface OrphanEntry {
27
+ /**
28
+ * The worktree root that contains the orphan — the first directory under
29
+ * `.claude/worktrees/` (e.g. `<projectRoot>/.claude/worktrees/agent-X`).
30
+ * Used as the boundary that `pruneWorktreeOrphans` validates against.
31
+ */
32
+ worktreePath: string;
33
+ /**
34
+ * Absolute path to the orphan `.cleo/` directory itself. Always lives
35
+ * under `worktreePath` (the security check rejects anything that doesn't).
36
+ */
37
+ orphanPath: string;
38
+ /**
39
+ * List of `tasks.db`, `brain.db`, `nexus.db`, or `config.json` paths
40
+ * found inside the orphan. Empty array means the orphan exists but is
41
+ * structurally empty (still pruned — it shouldn't be there at all).
42
+ */
43
+ dbFiles: string[];
44
+ /** Total byte size of the orphan tree (sum of regular file sizes). */
45
+ sizeBytes: number;
46
+ /** ISO-8601 timestamp of the most recent file modification under the orphan. */
47
+ lastModifiedAt: string;
48
+ /**
49
+ * Seconds since `lastModifiedAt` (relative to scan time). Surfaces "stale
50
+ * vs recent" without forcing the caller to compute date math.
51
+ */
52
+ ageSeconds: number;
53
+ /**
54
+ * `true` when the orphan contains more than just stray DB files — e.g. a
55
+ * full duplicate of `adrs/`, `agent-outputs/`, `rcasd/`, etc. These need
56
+ * heightened operator review before pruning.
57
+ */
58
+ isFullDuplicate: boolean;
59
+ }
60
+ /**
61
+ * Result of one prune operation. Reports the archive location, the per-entry
62
+ * outcome, and any entries rejected by the security gate.
63
+ */
64
+ export interface PruneResult {
65
+ /**
66
+ * Absolute path to the `.tar.gz` archive written before any deletion.
67
+ * `null` only when `dryRun: true` AND no archive was produced.
68
+ */
69
+ archivePath: string | null;
70
+ /** Whether this was a dry run (no archive, no rm, no audit-log line). */
71
+ dryRun: boolean;
72
+ /** Entries that were successfully pruned (or would be in dry-run mode). */
73
+ pruned: OrphanEntry[];
74
+ /**
75
+ * Entries that failed validation and were skipped. The `reason` is a
76
+ * stable machine-readable code (e.g. `path-outside-worktrees-root`,
77
+ * `path-not-found`, `rm-failed`).
78
+ */
79
+ rejected: Array<{
80
+ entry: OrphanEntry;
81
+ reason: string;
82
+ }>;
83
+ /** Total bytes archived (sum of `pruned[].sizeBytes`). */
84
+ totalSizeBytes: number;
85
+ /** ISO-8601 timestamp the prune completed. */
86
+ prunedAt: string;
87
+ }
88
+ /**
89
+ * One line appended to `.cleo/audit/worktree-prune.jsonl` per prune
90
+ * operation. Extends the existing audit-log schema (timestamp +
91
+ * worktreePath + action + agent) with the orphan-specific fields needed
92
+ * to reconstruct what was removed.
93
+ *
94
+ * Existing fields preserved for schema continuity:
95
+ * - `timestamp`, `worktreePath`, `action`, `agent`
96
+ *
97
+ * New fields for orphan prune:
98
+ * - `orphanPath`, `sizeBytes`, `dbFileCount`, `archivePath`, `dryRun`
99
+ */
100
+ export interface PruneAuditEntry {
101
+ /** ISO-8601 timestamp. */
102
+ timestamp: string;
103
+ /** Worktree root that contained the orphan. */
104
+ worktreePath: string;
105
+ /** Absolute path to the orphan `.cleo/` directory removed. */
106
+ orphanPath: string;
107
+ /** Action code — fixed to `'prune-worktree-orphan'` for this flow. */
108
+ action: 'prune-worktree-orphan';
109
+ /** Always `'cleo'` — written by `cleo doctor`. */
110
+ agent: 'cleo';
111
+ /** Byte size of the pruned tree. */
112
+ sizeBytes: number;
113
+ /** Number of DB files found in the orphan (informational). */
114
+ dbFileCount: number;
115
+ /** Absolute path to the archive. `null` only on dry-run lines. */
116
+ archivePath: string | null;
117
+ /** Whether this entry represents a dry-run plan (no actual removal). */
118
+ dryRun: boolean;
119
+ }
120
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;IAElB,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;IAElB,gFAAgF;IAChF,cAAc,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3B,yEAAyE;IACzE,MAAM,EAAE,OAAO,CAAC;IAEhB,2EAA2E;IAC3E,MAAM,EAAE,WAAW,EAAE,CAAC;IAEtB;;;;OAIG;IACH,QAAQ,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,WAAW,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAExD,0DAA0D;IAC1D,cAAc,EAAE,MAAM,CAAC;IAEvB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,eAAe;IAC9B,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,UAAU,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,MAAM,EAAE,uBAAuB,CAAC;IAChC,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,wEAAwE;IACxE,MAAM,EAAE,OAAO,CAAC;CACjB"}
package/dist/doctor.js ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Doctor domain contracts — types for `cleo doctor` worktree-orphan audit/prune.
3
+ *
4
+ * These types describe orphan `.cleo/` directories left behind under
5
+ * `<projectRoot>/.claude/worktrees/` by the T9550/T9580 SSoT bug (fixed in
6
+ * v2026.5.83) and the schema for the audit JSONL line written per prune.
7
+ *
8
+ * Consumed by:
9
+ * - `packages/core/src/doctor/worktree-orphans.ts` (scan + prune primitives)
10
+ * - `packages/cleo/src/cli/commands/doctor.ts` (CLI flags)
11
+ *
12
+ * @task T9790
13
+ * @epic T9790
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}