@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
package/src/doctor.ts ADDED
@@ -0,0 +1,130 @@
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
+ /**
17
+ * One orphan `.cleo/` directory discovered under
18
+ * `<projectRoot>/.claude/worktrees/`.
19
+ *
20
+ * Worktrees are nested 1-3 levels deep — examples:
21
+ * - `<projectRoot>/.claude/worktrees/agent-X/.cleo/` (depth 1)
22
+ * - `<projectRoot>/.claude/worktrees/agent-X/T9220/.cleo/` (depth 2)
23
+ *
24
+ * Each entry carries full provenance so the operator can decide whether
25
+ * the orphan represents lost work before pruning.
26
+ */
27
+ export interface OrphanEntry {
28
+ /**
29
+ * The worktree root that contains the orphan — the first directory under
30
+ * `.claude/worktrees/` (e.g. `<projectRoot>/.claude/worktrees/agent-X`).
31
+ * Used as the boundary that `pruneWorktreeOrphans` validates against.
32
+ */
33
+ worktreePath: string;
34
+
35
+ /**
36
+ * Absolute path to the orphan `.cleo/` directory itself. Always lives
37
+ * under `worktreePath` (the security check rejects anything that doesn't).
38
+ */
39
+ orphanPath: string;
40
+
41
+ /**
42
+ * List of `tasks.db`, `brain.db`, `nexus.db`, or `config.json` paths
43
+ * found inside the orphan. Empty array means the orphan exists but is
44
+ * structurally empty (still pruned — it shouldn't be there at all).
45
+ */
46
+ dbFiles: string[];
47
+
48
+ /** Total byte size of the orphan tree (sum of regular file sizes). */
49
+ sizeBytes: number;
50
+
51
+ /** ISO-8601 timestamp of the most recent file modification under the orphan. */
52
+ lastModifiedAt: string;
53
+
54
+ /**
55
+ * Seconds since `lastModifiedAt` (relative to scan time). Surfaces "stale
56
+ * vs recent" without forcing the caller to compute date math.
57
+ */
58
+ ageSeconds: number;
59
+
60
+ /**
61
+ * `true` when the orphan contains more than just stray DB files — e.g. a
62
+ * full duplicate of `adrs/`, `agent-outputs/`, `rcasd/`, etc. These need
63
+ * heightened operator review before pruning.
64
+ */
65
+ isFullDuplicate: boolean;
66
+ }
67
+
68
+ /**
69
+ * Result of one prune operation. Reports the archive location, the per-entry
70
+ * outcome, and any entries rejected by the security gate.
71
+ */
72
+ export interface PruneResult {
73
+ /**
74
+ * Absolute path to the `.tar.gz` archive written before any deletion.
75
+ * `null` only when `dryRun: true` AND no archive was produced.
76
+ */
77
+ archivePath: string | null;
78
+
79
+ /** Whether this was a dry run (no archive, no rm, no audit-log line). */
80
+ dryRun: boolean;
81
+
82
+ /** Entries that were successfully pruned (or would be in dry-run mode). */
83
+ pruned: OrphanEntry[];
84
+
85
+ /**
86
+ * Entries that failed validation and were skipped. The `reason` is a
87
+ * stable machine-readable code (e.g. `path-outside-worktrees-root`,
88
+ * `path-not-found`, `rm-failed`).
89
+ */
90
+ rejected: Array<{ entry: OrphanEntry; reason: string }>;
91
+
92
+ /** Total bytes archived (sum of `pruned[].sizeBytes`). */
93
+ totalSizeBytes: number;
94
+
95
+ /** ISO-8601 timestamp the prune completed. */
96
+ prunedAt: string;
97
+ }
98
+
99
+ /**
100
+ * One line appended to `.cleo/audit/worktree-prune.jsonl` per prune
101
+ * operation. Extends the existing audit-log schema (timestamp +
102
+ * worktreePath + action + agent) with the orphan-specific fields needed
103
+ * to reconstruct what was removed.
104
+ *
105
+ * Existing fields preserved for schema continuity:
106
+ * - `timestamp`, `worktreePath`, `action`, `agent`
107
+ *
108
+ * New fields for orphan prune:
109
+ * - `orphanPath`, `sizeBytes`, `dbFileCount`, `archivePath`, `dryRun`
110
+ */
111
+ export interface PruneAuditEntry {
112
+ /** ISO-8601 timestamp. */
113
+ timestamp: string;
114
+ /** Worktree root that contained the orphan. */
115
+ worktreePath: string;
116
+ /** Absolute path to the orphan `.cleo/` directory removed. */
117
+ orphanPath: string;
118
+ /** Action code — fixed to `'prune-worktree-orphan'` for this flow. */
119
+ action: 'prune-worktree-orphan';
120
+ /** Always `'cleo'` — written by `cleo doctor`. */
121
+ agent: 'cleo';
122
+ /** Byte size of the pruned tree. */
123
+ sizeBytes: number;
124
+ /** Number of DB files found in the orphan (informational). */
125
+ dbFileCount: number;
126
+ /** Absolute path to the archive. `null` only on dry-run lines. */
127
+ archivePath: string | null;
128
+ /** Whether this entry represents a dry-run plan (no actual removal). */
129
+ dryRun: boolean;
130
+ }
package/src/index.ts CHANGED
@@ -277,6 +277,22 @@ export type {
277
277
  StoreDocParams,
278
278
  StoreDocResult,
279
279
  } from './docs-accessor.js';
280
+ // === Canonical Doc-Kind Taxonomy Registry (T9788) ===
281
+ export type {
282
+ BuiltinDocKind,
283
+ DocKindConfigFile,
284
+ DocKindExtensionConfig,
285
+ DocKindMetadata,
286
+ SlugValidationResult,
287
+ } from './docs-taxonomy.js';
288
+ export {
289
+ BUILTIN_DOC_KIND_VALUES,
290
+ BUILTIN_DOC_KINDS,
291
+ DocKindConfigError,
292
+ DocKindRegistry,
293
+ } from './docs-taxonomy.js';
294
+ // === Doctor: Worktree-Orphan Audit + Prune Types (T9790) ===
295
+ export type { OrphanEntry, PruneAuditEntry, PruneResult } from './doctor.js';
280
296
  export type {
281
297
  EngineErrorPayload,
282
298
  EngineFailure,
@@ -499,6 +515,8 @@ export type {
499
515
  } from './llm/provider-profile.js';
500
516
  // === Phase 4 Unified Architecture (T9281 / ADR-072) — Resolved credential ===
501
517
  export type { ResolvedCredential } from './llm/resolved-credential.js';
518
+ // === Logger contract (T9766 — centralized from @cleocode/core) ===
519
+ export type { LoggerConfig } from './logger.js';
502
520
  // === ContextEngine contract (canonical home — T9304) ===
503
521
  export type { CompressedContext, ContextEngine } from './memory/context-engine.js';
504
522
  export type {
@@ -507,8 +525,14 @@ export type {
507
525
  BridgeObservation,
508
526
  BridgePattern,
509
527
  DispatchTrace,
528
+ // T9766 — BRAIN public-API records (centralized from @cleocode/core)
529
+ LearningRecord,
510
530
  MemoryBridgeConfig,
511
531
  MemoryBridgeContent,
532
+ MemoryDecisionRecord,
533
+ MemoryGraphStats,
534
+ MemorySearchHit,
535
+ PatternRecord,
512
536
  SessionSummary,
513
537
  } from './memory.js';
514
538
  export type {
@@ -985,6 +1009,9 @@ export type {
985
1009
  SessionGcResult,
986
1010
  SessionHandoffShowParams,
987
1011
  SessionHandoffShowResult,
1012
+ SessionLintParams,
1013
+ SessionLintResult,
1014
+ SessionLintViolation,
988
1015
  SessionListParams,
989
1016
  SessionListResult,
990
1017
  SessionOps,
@@ -1097,6 +1124,8 @@ export type {
1097
1124
  ComplianceMetrics,
1098
1125
  ValidateArchiveStatsParams,
1099
1126
  ValidateArchiveStatsResult,
1127
+ ValidateCanonDocsParams,
1128
+ ValidateCanonDocsResult,
1100
1129
  ValidateCanonParams,
1101
1130
  ValidateCanonResult,
1102
1131
  ValidateChainParams,
@@ -1239,6 +1268,14 @@ export type {
1239
1268
  export type { AdapterPathProvider } from './provider-paths.js';
1240
1269
  // === Release Channel ===
1241
1270
  export type { ChannelValidationResult, ReleaseChannel } from './release/channel.js';
1271
+ // === Release Evidence Atoms (T9764) ===
1272
+ export type { GhPrViewPayload, ParsedPrEvidenceAtom } from './release/evidence-atoms.js';
1273
+ export {
1274
+ ghPrViewSchema,
1275
+ PR_REQUIRED_WORKFLOWS,
1276
+ PR_REQUIRED_WORKFLOWS_ENV_VAR,
1277
+ parsedPrEvidenceAtomSchema,
1278
+ } from './release/evidence-atoms.js';
1242
1279
  // === Release GitHub PR ===
1243
1280
  export type {
1244
1281
  BranchProtectionResult,
package/src/logger.ts ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Logger configuration contract for the CLEO ecosystem.
3
+ *
4
+ * Lives in `@cleocode/contracts` so CLI bootstrap, harness adapters, and other
5
+ * consumer packages can wire pino without reaching into `@cleocode/core` for a
6
+ * type definition. The implementation (`initLogger`, `getLogger`, etc.) remains
7
+ * in `@cleocode/core/logger`.
8
+ *
9
+ * @task T9766
10
+ * @epic T9752
11
+ * @saga T9758
12
+ */
13
+
14
+ /**
15
+ * Configuration for the centralized pino logger.
16
+ *
17
+ * @remarks
18
+ * Consumed by `@cleocode/core`'s `initLogger` factory. The CLI bootstrap reads
19
+ * the corresponding `logging` section of `CleoConfig` and forwards it verbatim.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * import type { LoggerConfig } from '@cleocode/contracts';
24
+ *
25
+ * const config: LoggerConfig = {
26
+ * level: 'info',
27
+ * filePath: 'logs/cleo.log',
28
+ * maxFileSize: 10 * 1024 * 1024,
29
+ * maxFiles: 5,
30
+ * };
31
+ * ```
32
+ */
33
+ export interface LoggerConfig {
34
+ /** Pino log level (`trace` | `debug` | `info` | `warn` | `error` | `fatal`). */
35
+ level: string;
36
+ /** Path to the primary log file, relative to the `.cleo` directory. */
37
+ filePath: string;
38
+ /** Maximum bytes per log file before pino-roll rotates to a new file. */
39
+ maxFileSize: number;
40
+ /** Maximum number of rotated log files to retain before pino-roll deletes oldest. */
41
+ maxFiles: number;
42
+ }
package/src/memory.ts CHANGED
@@ -1,8 +1,28 @@
1
1
  /**
2
- * Memory bridge types for CLEO provider adapters.
3
- * Defines the shape of .cleo/memory-bridge.md content for cross-provider memory sharing.
2
+ * Memory bridge types for CLEO provider adapters and BRAIN public-API records.
3
+ *
4
+ * Two sets of types live in this file:
5
+ *
6
+ * 1. **Memory bridge types** (`MemoryBridgeContent`, `BridgeLearning`, …) — define
7
+ * the shape of `.cleo/memory-bridge.md` content for cross-provider memory
8
+ * sharing. Original home; added under T5240.
9
+ * 2. **BRAIN public-API records** (`MemorySearchHit`, `MemoryGraphStats`,
10
+ * `MemoryDecisionRecord`, `PatternRecord`, `LearningRecord`) — typed result
11
+ * shapes returned by `@cleocode/core`'s memory public API
12
+ * (`findMemoryEntries`, `getDecisions`, `getPatterns`, `getLearnings`,
13
+ * `getMemoryGraph`). Centralized here under T9766 so Studio + CLI consumers
14
+ * can depend on them without reaching into `@cleocode/core`.
15
+ *
16
+ * @remarks
17
+ * `MemoryDecisionRecord` deliberately differs in name from the session-ops
18
+ * `DecisionRecord` exported by `./operations/session.ts` to avoid a barrel-level
19
+ * name collision. The two shapes are NOT interchangeable: session-ops captures
20
+ * an audit-log entry (`sessionId`, `taskId`, `alternatives`, `timestamp`),
21
+ * whereas `MemoryDecisionRecord` captures a BRAIN graph node
22
+ * (`outcome`, `memoryTier`, `verified`, `createdAt`).
4
23
  *
5
24
  * @task T5240
25
+ * @task T9766
6
26
  */
7
27
 
8
28
  // ============================================================================
@@ -180,3 +200,135 @@ export interface BridgeObservation {
180
200
  /** Truncated summary of the observation content. */
181
201
  summary: string;
182
202
  }
203
+
204
+ // ============================================================================
205
+ // BRAIN public-API records (T9766 — centralized from @cleocode/core)
206
+ // ============================================================================
207
+
208
+ /**
209
+ * A single cross-table memory search hit returned by `findMemoryEntries`.
210
+ *
211
+ * @remarks
212
+ * Spans all four BRAIN tables (observations, decisions, patterns, learnings) and
213
+ * is what the `memory.find` dispatch operation surfaces to the CLI and Studio.
214
+ *
215
+ * @task T9766
216
+ */
217
+ export interface MemorySearchHit {
218
+ /** Entry identifier. */
219
+ id: string;
220
+ /** Source brain table. */
221
+ table: 'observations' | 'decisions' | 'patterns' | 'learnings';
222
+ /** Display title. */
223
+ title: string;
224
+ /** Short preview string (first ~160 chars of narrative/rationale/context). */
225
+ preview: string;
226
+ /** ISO 8601 creation timestamp. */
227
+ createdAt: string;
228
+ /** Quality score in [0..1] or null if not computed. */
229
+ quality: number | null;
230
+ /** Memory tier (`'short'` | `'medium'` | `'long'`). */
231
+ tier: string | null;
232
+ /** Whether the entry has been owner-verified (1 = true, 0 = false). */
233
+ verified: number;
234
+ /** Number of times this entry has been retrieved. */
235
+ citations: number;
236
+ }
237
+
238
+ /**
239
+ * Aggregate statistics for the BRAIN memory graph returned by `getMemoryGraph`.
240
+ *
241
+ * @remarks
242
+ * Used by the `memory.graph` dispatch op and Studio's `/api/memory/graph` route.
243
+ *
244
+ * @task T9766
245
+ */
246
+ export interface MemoryGraphStats {
247
+ /** Total node count. */
248
+ nodeCount: number;
249
+ /** Total edge count. */
250
+ edgeCount: number;
251
+ /** Edge type distribution. */
252
+ edgeTypeDistribution: Record<string, number>;
253
+ /** Average edges per node. */
254
+ averageEdgesPerNode: number;
255
+ }
256
+
257
+ /**
258
+ * A single decision record returned by `getDecisions`.
259
+ *
260
+ * @remarks
261
+ * **Intentionally named `MemoryDecisionRecord`** to avoid a barrel-level
262
+ * collision with the session-ops `DecisionRecord` exported by
263
+ * `./operations/session.ts`. The session-ops shape is an audit-log entry
264
+ * (`sessionId`, `taskId`, `alternatives`, `timestamp`); this shape is a BRAIN
265
+ * graph node (`outcome`, `memoryTier`, `verified`, `createdAt`).
266
+ *
267
+ * `@cleocode/core` continues to re-export this type under the legacy name
268
+ * `DecisionRecord` from its main barrel for back-compat — see
269
+ * `packages/core/src/memory/public-api.ts`.
270
+ *
271
+ * @task T9766
272
+ */
273
+ export interface MemoryDecisionRecord {
274
+ /** Decision identifier (e.g. `D-arch-001`). */
275
+ id: string;
276
+ /** Decision statement. */
277
+ decision: string;
278
+ /** Justification / rationale. */
279
+ rationale: string | null;
280
+ /** Outcome: `proposed` | `accepted` | `rejected` | `superseded`. */
281
+ outcome: string | null;
282
+ /** ISO creation timestamp. */
283
+ createdAt: string;
284
+ /** Memory tier. */
285
+ memoryTier: string | null;
286
+ /** Owner-verified flag. */
287
+ verified: number;
288
+ }
289
+
290
+ /**
291
+ * A single pattern record returned by `getPatterns`.
292
+ *
293
+ * @task T9766
294
+ */
295
+ export interface PatternRecord {
296
+ /** Pattern identifier. */
297
+ id: string;
298
+ /** Pattern description. */
299
+ pattern: string;
300
+ /** Contextual description where the pattern applies. */
301
+ context: string | null;
302
+ /** Pattern type tag. */
303
+ patternType: string | null;
304
+ /** Impact level (`'low'` | `'medium'` | `'high'`). */
305
+ impact: string | null;
306
+ /** Extraction timestamp. */
307
+ extractedAt: string;
308
+ /** Memory tier. */
309
+ memoryTier: string | null;
310
+ /** Retrieval count. */
311
+ citationCount: number;
312
+ }
313
+
314
+ /**
315
+ * A single learning record returned by `getLearnings`.
316
+ *
317
+ * @task T9766
318
+ */
319
+ export interface LearningRecord {
320
+ /** Learning identifier. */
321
+ id: string;
322
+ /** Core insight. */
323
+ insight: string;
324
+ /** Source context where the learning was extracted from. */
325
+ source: string | null;
326
+ /** Learning type tag. */
327
+ learningType: string | null;
328
+ /** Creation timestamp. */
329
+ createdAt: string;
330
+ /** Memory tier. */
331
+ memoryTier: string | null;
332
+ /** Retrieval count. */
333
+ citationCount: number;
334
+ }
@@ -29,6 +29,7 @@
29
29
  */
30
30
 
31
31
  import type { AttachmentKind } from '../attachment.js';
32
+ import { BUILTIN_DOC_KIND_VALUES, type BuiltinDocKind } from '../docs-taxonomy.js';
32
33
 
33
34
  // ============================================================================
34
35
  // Shared Attachment Types (API wire format)
@@ -54,28 +55,32 @@ export type { AttachmentKind } from '../attachment.js';
54
55
  /**
55
56
  * Allowed values for the `--type` taxonomy on `cleo docs add`.
56
57
  *
57
- * The set is closed at the CLI surface; new values require a coordinated
58
- * update to (1) {@link DOCS_TYPE_VALUES}, (2) the dispatch-layer guard, and
59
- * (3) the citty CLI flag description. The DB column itself is open (no CHECK)
60
- * so older clients reading a forward-compatible value gracefully degrade.
58
+ * As of T9788 this is derived from the canonical {@link BUILTIN_DOC_KIND_VALUES}
59
+ * in `docs-taxonomy.ts` adding a kind there automatically widens this set
60
+ * without a duplicate edit here.
61
+ *
62
+ * Project-level extensions registered through `.cleo/docs-config.json` are
63
+ * NOT included in this constant (they are runtime-only, since the
64
+ * compile-time union must stay closed). Use {@link DocKindRegistry.list}
65
+ * to enumerate built-ins plus extensions at runtime.
61
66
  *
62
67
  * @task T9637 (T-DOCS-SLUG-2)
68
+ * @task T9788 (E-DOCS-TAXONOMY-V2 — registry consolidation)
63
69
  */
64
- export const DOCS_TYPE_VALUES = [
65
- 'spec',
66
- 'adr',
67
- 'research',
68
- 'handoff',
69
- 'note',
70
- 'llm-readme',
71
- ] as const;
70
+ export const DOCS_TYPE_VALUES: ReadonlyArray<BuiltinDocKind> =
71
+ BUILTIN_DOC_KIND_VALUES as ReadonlyArray<BuiltinDocKind>;
72
72
 
73
73
  /**
74
74
  * Closed-set type alias for {@link DOCS_TYPE_VALUES}.
75
75
  *
76
+ * As of T9788 this aliases {@link BuiltinDocKind} from the canonical
77
+ * registry — the union widens automatically when a new built-in kind
78
+ * is added to {@link BUILTIN_DOC_KINDS}.
79
+ *
76
80
  * @task T9637
81
+ * @task T9788
77
82
  */
78
- export type DocsType = (typeof DOCS_TYPE_VALUES)[number];
83
+ export type DocsType = BuiltinDocKind;
79
84
 
80
85
  /**
81
86
  * Flattened wire-format attachment row returned by docs query operations.
@@ -169,16 +174,38 @@ export interface AttachmentRecord {
169
174
  // docs.list — list attachments for an owner
170
175
  // --------------------------------------------------------------------------
171
176
 
177
+ /**
178
+ * Sort key for `docs.list` results.
179
+ *
180
+ * - `newest` — descending by `createdAt` (default — most recent first).
181
+ * - `sha` — ascending by `sha256` (stable lexicographic).
182
+ * - `slug` — ascending by `slug`; entries without a slug sort last.
183
+ *
184
+ * @task T9792
185
+ */
186
+ export type DocsListOrderBy = 'newest' | 'sha' | 'slug';
187
+
188
+ /**
189
+ * Default maximum number of rows returned by `docs.list` when the caller
190
+ * does not pass an explicit `limit`. Mirrored on the CLI flag default so the
191
+ * dispatch and CLI surfaces agree on the browsing window.
192
+ *
193
+ * @task T9792
194
+ */
195
+ export const DOCS_LIST_DEFAULT_LIMIT = 50;
196
+
172
197
  /**
173
198
  * Parameters for `docs.list`.
174
199
  *
175
- * Exactly one of `task`, `session`, `observation`, or `project` must be
176
- * provided. `project=true` lists ALL attachments in the project DB
177
- * regardless of owner. `type` is an optional filter applicable to every
178
- * mode and matches the {@link DocsType} taxonomy exactly.
200
+ * Scope is auto-promoted to whole-project when no owner-scope flag is set
201
+ * (T9792). Pre-T9792 callers MUST still pass `project: true` explicitly to
202
+ * stay forward-compatible the auto-promote happens at the CLI layer.
203
+ * `type` is an optional filter applicable to every mode and matches the
204
+ * {@link DocsType} taxonomy exactly.
179
205
  *
180
206
  * @task T9637 (T-DOCS-SLUG-2 — `type` filter)
181
207
  * @task T9638 (T-DOCS-SLUG-3 — `project` scope)
208
+ * @task T9792 (E-DOCS-LIST-UX-FIX — auto-promote project scope + limit + orderBy)
182
209
  */
183
210
  export interface DocsListParams {
184
211
  /** Task identifier to list attachments for. */
@@ -199,6 +226,20 @@ export interface DocsListParams {
199
226
  * @task T9637
200
227
  */
201
228
  type?: DocsType;
229
+ /**
230
+ * Maximum number of rows to return. Defaults to
231
+ * {@link DOCS_LIST_DEFAULT_LIMIT} when omitted. Values `<= 0` are treated
232
+ * as "no limit" so agents can opt-in to the full result set explicitly.
233
+ *
234
+ * @task T9792
235
+ */
236
+ limit?: number;
237
+ /**
238
+ * Sort key for the returned rows. Defaults to `newest` when omitted.
239
+ *
240
+ * @task T9792
241
+ */
242
+ orderBy?: DocsListOrderBy;
202
243
  }
203
244
 
204
245
  /**
@@ -218,8 +259,41 @@ export interface DocsListResult {
218
259
  project?: boolean;
219
260
  /** Type taxonomy filter, echoed back from the request when provided. */
220
261
  type?: DocsType;
221
- /** Count of attachments for this owner. */
262
+ /** Count of attachments for this owner (after limit + filters). */
222
263
  count: number;
264
+ /**
265
+ * Total number of attachments matching the scope + filters BEFORE the
266
+ * `limit` window was applied. Only emitted when `limit` truncated the
267
+ * result set so consumers can distinguish "fewer than limit" from
268
+ * "limit truncated".
269
+ *
270
+ * @task T9792
271
+ */
272
+ totalCount?: number;
273
+ /**
274
+ * Effective limit applied to this response. Mirrored from the request
275
+ * (or {@link DOCS_LIST_DEFAULT_LIMIT} when the request did not set one)
276
+ * so consumers can paginate without re-deriving the default.
277
+ *
278
+ * @task T9792
279
+ */
280
+ limit?: number;
281
+ /**
282
+ * Effective sort key applied to this response. Mirrored from the request
283
+ * (or `"newest"` when the request did not set one).
284
+ *
285
+ * @task T9792
286
+ */
287
+ orderBy?: DocsListOrderBy;
288
+ /**
289
+ * Optional human-readable hint surfaced when a default behaviour kicked
290
+ * in (e.g. project scope auto-promoted because no scope was passed). The
291
+ * CLI surfaces this through `meta.hint` so JSON consumers can detect that
292
+ * a narrower invocation may have been intended.
293
+ *
294
+ * @task T9792
295
+ */
296
+ hint?: string;
223
297
  /** Attachment metadata array. */
224
298
  attachments: DocsAttachmentRow[];
225
299
  /** Current attachment backend in use. */
@@ -587,6 +587,76 @@ export interface SessionRecordAssumptionResult {
587
587
  timestamp: string;
588
588
  }
589
589
 
590
+ // session.lint — agent-accountability harness (T9797)
591
+
592
+ /**
593
+ * Parameters for `session.lint`.
594
+ *
595
+ * Scans a Claude Code-style session transcript (`*.jsonl`) for raw
596
+ * markdown writes that bypass the docs SSoT. Flags any tool call whose
597
+ * `file_path` lands under a `rawMdPaths` entry whose owning DocKind has
598
+ * `rawMdAllowed: false` in `.cleo/canon.yml`.
599
+ *
600
+ * @task T9797
601
+ */
602
+ export interface SessionLintParams {
603
+ /**
604
+ * Absolute path to the `.jsonl` transcript to scan. Required.
605
+ */
606
+ transcript: string;
607
+ }
608
+
609
+ /**
610
+ * One violation surfaced by `session.lint`.
611
+ *
612
+ * Mirrors `CanonLintViolation` from
613
+ * `packages/core/src/session/canon-lint.ts` (the SDK-level engine).
614
+ *
615
+ * @task T9797
616
+ */
617
+ export interface SessionLintViolation {
618
+ /** Session id derived from the transcript filename. */
619
+ sessionId: string;
620
+ /** Anthropic `tool_use.id` (e.g. `toolu_01ABC...`). May be empty. */
621
+ toolUseId: string;
622
+ /** Tool name — `Write`, `Edit`, or `MultiEdit`. */
623
+ tool: string;
624
+ /** Repo-relative path the agent attempted to write. */
625
+ path: string;
626
+ /** Owning DocKind id (e.g. `adr`, `note`). */
627
+ docKind: string;
628
+ /** Matching `rawMdPaths` entry (e.g. `.cleo/adrs/`). */
629
+ matchedPath: string;
630
+ /** Categorical reason — always `'raw-md-canonical'` today. */
631
+ kind: 'raw-md-canonical';
632
+ /** First 200 chars of the violating content. */
633
+ evidence: string;
634
+ /** Suggested fix command. */
635
+ fix: string;
636
+ }
637
+
638
+ /**
639
+ * Result of `session.lint`.
640
+ *
641
+ * @task T9797
642
+ */
643
+ export interface SessionLintResult {
644
+ /** Absolute transcript path that was scanned. */
645
+ transcriptPath: string;
646
+ /** Session id derived from the transcript filename. */
647
+ sessionId: string;
648
+ /** True when no violations were flagged. */
649
+ passed: boolean;
650
+ /** Number of `Write`/`Edit`/`MultiEdit` tool calls inspected. */
651
+ scanned: number;
652
+ /** Violations in transcript order. Empty when `passed === true`. */
653
+ violations: SessionLintViolation[];
654
+ /** Non-fatal warnings (e.g. JSON parse failures on isolated lines). */
655
+ warnings: string[];
656
+ /** `'enforced'` when canon.yml present, `'no-canon'` when missing. */
657
+ mode: 'enforced' | 'no-canon';
658
+ }
659
+
590
660
  // ---------------------------------------------------------------------------
591
661
  // Typed operation record (Wave D adapter — T975)
592
662
  // ---------------------------------------------------------------------------
@@ -619,4 +689,5 @@ export type SessionOps = {
619
689
  SessionRecordAssumptionParams,
620
690
  SessionRecordAssumptionResult,
621
691
  ];
692
+ readonly lint: readonly [SessionLintParams, SessionLintResult];
622
693
  };