@cleocode/contracts 2026.5.95 → 2026.5.97

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 (121) hide show
  1. package/dist/__tests__/enums.test.d.ts +14 -0
  2. package/dist/__tests__/enums.test.d.ts.map +1 -0
  3. package/dist/__tests__/enums.test.js +75 -0
  4. package/dist/__tests__/enums.test.js.map +1 -0
  5. package/dist/__tests__/jobs.test.d.ts +11 -0
  6. package/dist/__tests__/jobs.test.d.ts.map +1 -0
  7. package/dist/__tests__/jobs.test.js +48 -0
  8. package/dist/__tests__/jobs.test.js.map +1 -0
  9. package/dist/__tests__/memory-wire-shapes.test.d.ts +19 -0
  10. package/dist/__tests__/memory-wire-shapes.test.d.ts.map +1 -0
  11. package/dist/__tests__/memory-wire-shapes.test.js +119 -0
  12. package/dist/__tests__/memory-wire-shapes.test.js.map +1 -0
  13. package/dist/__tests__/operation-def.test.d.ts +20 -0
  14. package/dist/__tests__/operation-def.test.d.ts.map +1 -0
  15. package/dist/__tests__/operation-def.test.js +111 -0
  16. package/dist/__tests__/operation-def.test.js.map +1 -0
  17. package/dist/__tests__/provenance.test.d.ts +18 -0
  18. package/dist/__tests__/provenance.test.d.ts.map +1 -0
  19. package/dist/__tests__/provenance.test.js +142 -0
  20. package/dist/__tests__/provenance.test.js.map +1 -0
  21. package/dist/__tests__/scaffold-diagnostics.test.d.ts +19 -0
  22. package/dist/__tests__/scaffold-diagnostics.test.d.ts.map +1 -0
  23. package/dist/__tests__/scaffold-diagnostics.test.js +70 -0
  24. package/dist/__tests__/scaffold-diagnostics.test.js.map +1 -0
  25. package/dist/dispatch/identity.d.ts +72 -0
  26. package/dist/dispatch/identity.d.ts.map +1 -0
  27. package/dist/dispatch/identity.js +72 -0
  28. package/dist/dispatch/identity.js.map +1 -0
  29. package/dist/dispatch/operation-def.d.ts +92 -0
  30. package/dist/dispatch/operation-def.d.ts.map +1 -0
  31. package/dist/dispatch/operation-def.js +31 -0
  32. package/dist/dispatch/operation-def.js.map +1 -0
  33. package/dist/doctor.d.ts +52 -0
  34. package/dist/doctor.d.ts.map +1 -1
  35. package/dist/doctor.js +7 -0
  36. package/dist/doctor.js.map +1 -1
  37. package/dist/enums.d.ts +123 -0
  38. package/dist/enums.d.ts.map +1 -0
  39. package/dist/enums.js +139 -0
  40. package/dist/enums.js.map +1 -0
  41. package/dist/index.d.ts +16 -3
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +4 -0
  44. package/dist/index.js.map +1 -1
  45. package/dist/jobs.d.ts +39 -0
  46. package/dist/jobs.d.ts.map +1 -0
  47. package/dist/jobs.js +19 -0
  48. package/dist/jobs.js.map +1 -0
  49. package/dist/memory/budgeted.d.ts +67 -0
  50. package/dist/memory/budgeted.d.ts.map +1 -0
  51. package/dist/memory/budgeted.js +17 -0
  52. package/dist/memory/budgeted.js.map +1 -0
  53. package/dist/memory/fetch.d.ts +58 -0
  54. package/dist/memory/fetch.d.ts.map +1 -0
  55. package/dist/memory/fetch.js +19 -0
  56. package/dist/memory/fetch.js.map +1 -0
  57. package/dist/memory/observe.d.ts +158 -0
  58. package/dist/memory/observe.d.ts.map +1 -0
  59. package/dist/memory/observe.js +46 -0
  60. package/dist/memory/observe.js.map +1 -0
  61. package/dist/memory/search.d.ts +137 -0
  62. package/dist/memory/search.d.ts.map +1 -0
  63. package/dist/memory/search.js +22 -0
  64. package/dist/memory/search.js.map +1 -0
  65. package/dist/memory/timeline.d.ts +89 -0
  66. package/dist/memory/timeline.d.ts.map +1 -0
  67. package/dist/memory/timeline.js +22 -0
  68. package/dist/memory/timeline.js.map +1 -0
  69. package/dist/operations/focus.d.ts +199 -0
  70. package/dist/operations/focus.d.ts.map +1 -0
  71. package/dist/operations/focus.js +15 -0
  72. package/dist/operations/focus.js.map +1 -0
  73. package/dist/operations/index.d.ts +1 -0
  74. package/dist/operations/index.d.ts.map +1 -1
  75. package/dist/operations/index.js +1 -0
  76. package/dist/operations/index.js.map +1 -1
  77. package/dist/operations/session.d.ts +54 -0
  78. package/dist/operations/session.d.ts.map +1 -1
  79. package/dist/operations/tasks.d.ts +38 -0
  80. package/dist/operations/tasks.d.ts.map +1 -1
  81. package/dist/operations/worktree.d.ts +138 -1
  82. package/dist/operations/worktree.d.ts.map +1 -1
  83. package/dist/provenance.d.ts +257 -0
  84. package/dist/provenance.d.ts.map +1 -0
  85. package/dist/provenance.js +42 -0
  86. package/dist/provenance.js.map +1 -0
  87. package/dist/release/plan.d.ts +7 -7
  88. package/dist/scaffold-diagnostics.d.ts +110 -0
  89. package/dist/scaffold-diagnostics.d.ts.map +1 -0
  90. package/dist/scaffold-diagnostics.js +28 -0
  91. package/dist/scaffold-diagnostics.js.map +1 -0
  92. package/dist/session.d.ts +37 -0
  93. package/dist/session.d.ts.map +1 -1
  94. package/dist/session.js.map +1 -1
  95. package/dist/tasks/archive.d.ts +3 -3
  96. package/package.json +42 -2
  97. package/src/__tests__/enums.test.ts +114 -0
  98. package/src/__tests__/jobs.test.ts +76 -0
  99. package/src/__tests__/memory-wire-shapes.test.ts +371 -0
  100. package/src/__tests__/operation-def.test.ts +185 -0
  101. package/src/__tests__/provenance.test.ts +259 -0
  102. package/src/__tests__/scaffold-diagnostics.test.ts +137 -0
  103. package/src/dispatch/identity.ts +109 -0
  104. package/src/dispatch/operation-def.ts +102 -0
  105. package/src/doctor.ts +62 -0
  106. package/src/enums.ts +144 -0
  107. package/src/index.ts +89 -2
  108. package/src/jobs.ts +45 -0
  109. package/src/memory/budgeted.ts +75 -0
  110. package/src/memory/fetch.ts +66 -0
  111. package/src/memory/observe.ts +176 -0
  112. package/src/memory/search.ts +145 -0
  113. package/src/memory/timeline.ts +100 -0
  114. package/src/operations/focus.ts +226 -0
  115. package/src/operations/index.ts +1 -0
  116. package/src/operations/session.ts +56 -0
  117. package/src/operations/tasks.ts +40 -0
  118. package/src/operations/worktree.ts +149 -1
  119. package/src/provenance.ts +335 -0
  120. package/src/scaffold-diagnostics.ts +119 -0
  121. package/src/session.ts +37 -0
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Structural-equivalence tests for the provenance graph contracts.
3
+ *
4
+ * These tests pin the literal shapes of the 16 provenance/release/BRAIN
5
+ * unions promoted in Phase 0c (T9955) so that accidental narrowing or
6
+ * widening produces a compile-time failure during `tsc -b` in the CI gate.
7
+ *
8
+ * The compile-time assertions use the conditional-equality trick
9
+ * (`Equals<A, B>`) so any structural drift produces a TS2322 or TS2344 at
10
+ * build time. The runtime `expect` shape sanity check below is a thin
11
+ * smoke verification that representative literals satisfy each union — it
12
+ * does NOT exercise behavior (these are pure type contracts with no
13
+ * runtime).
14
+ *
15
+ * @since SG-ARCH-SOLID Saga T9831 · E-CONTRACTS-FOUNDATION T9832 · T9955 (Phase 0c)
16
+ */
17
+
18
+ import { describe, expect, it } from 'vitest';
19
+ import type {
20
+ BrainReleaseLinkType,
21
+ CommitConventionalType,
22
+ CommitFileChangeType,
23
+ CommitLinkKind,
24
+ CommitLinkSource,
25
+ PrLinkKind,
26
+ PrLinkSource,
27
+ PrState,
28
+ ReleaseArtifactType,
29
+ ReleaseChangeType,
30
+ ReleaseChannel,
31
+ ReleaseClassifiedBy,
32
+ ReleaseImpact,
33
+ ReleaseKind,
34
+ ReleaseScheme,
35
+ ReleaseStatus,
36
+ } from '../provenance.js';
37
+
38
+ // ─── Compile-time structural-equality helpers ───────────────────────
39
+
40
+ /** Resolve to `1` IFF `A` and `B` are mutually assignable; `2` otherwise. */
41
+ type Equals<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? 1 : 2;
42
+
43
+ /** Compile-time assert that `T` resolves to `1`. */
44
+ type AssertEquals1<T extends 1> = T;
45
+
46
+ // ─── PrState pin ────────────────────────────────────────────────────
47
+
48
+ type _PrStateShape = 'open' | 'closed' | 'merged';
49
+ type _AssertPrStatePinned = AssertEquals1<Equals<PrState, _PrStateShape>>;
50
+
51
+ // ─── CommitLinkKind pin ─────────────────────────────────────────────
52
+
53
+ type _CommitLinkKindShape = 'implements' | 'fixes' | 'refactors' | 'tests' | 'docs' | 'reverts';
54
+ type _AssertCommitLinkKindPinned = AssertEquals1<Equals<CommitLinkKind, _CommitLinkKindShape>>;
55
+
56
+ // ─── ReleaseStatus pin (unified — admits both pipelines) ────────────
57
+
58
+ type _ReleaseStatusShape =
59
+ | 'planned'
60
+ | 'pr-opened'
61
+ | 'pr-merged'
62
+ | 'published'
63
+ | 'reconciled'
64
+ | 'prepared'
65
+ | 'committed'
66
+ | 'tagged'
67
+ | 'pushed'
68
+ | 'rolled_back'
69
+ | 'failed'
70
+ | 'cancelled';
71
+ type _AssertReleaseStatusPinned = AssertEquals1<Equals<ReleaseStatus, _ReleaseStatusShape>>;
72
+
73
+ // ─── ReleaseChangeType pin (12-value taxonomy) ──────────────────────
74
+
75
+ type _ReleaseChangeTypeShape =
76
+ | 'feature'
77
+ | 'enhancement'
78
+ | 'bug'
79
+ | 'hotfix'
80
+ | 'security'
81
+ | 'breaking'
82
+ | 'refactor'
83
+ | 'docs'
84
+ | 'chore'
85
+ | 'revert'
86
+ | 'deprecation'
87
+ | 'infrastructure';
88
+ type _AssertReleaseChangeTypePinned = AssertEquals1<
89
+ Equals<ReleaseChangeType, _ReleaseChangeTypeShape>
90
+ >;
91
+
92
+ // ─── ReleaseArtifactType pin ────────────────────────────────────────
93
+
94
+ type _ReleaseArtifactTypeShape =
95
+ | 'npm'
96
+ | 'cargo'
97
+ | 'docker'
98
+ | 'pypi'
99
+ | 'github-release'
100
+ | 'binary'
101
+ | 'github-tag';
102
+ type _AssertReleaseArtifactTypePinned = AssertEquals1<
103
+ Equals<ReleaseArtifactType, _ReleaseArtifactTypeShape>
104
+ >;
105
+
106
+ // ─── BrainReleaseLinkType pin ───────────────────────────────────────
107
+
108
+ type _BrainReleaseLinkTypeShape = 'approved-by' | 'documented-in' | 'derived-from' | 'observed-in';
109
+ type _AssertBrainReleaseLinkTypePinned = AssertEquals1<
110
+ Equals<BrainReleaseLinkType, _BrainReleaseLinkTypeShape>
111
+ >;
112
+
113
+ // ─── Runtime constructibility smoke ─────────────────────────────────
114
+
115
+ describe('provenance contracts', () => {
116
+ it('PrState union covers exactly the 3 GitHub PR states', () => {
117
+ const all: PrState[] = ['open', 'closed', 'merged'];
118
+ expect(all).toHaveLength(3);
119
+ });
120
+
121
+ it('PrLinkSource enumerates all 5 discovery sources', () => {
122
+ const all: PrLinkSource[] = ['pr-title', 'pr-body', 'branch-name', 'commit-trailer', 'manual'];
123
+ expect(all).toHaveLength(5);
124
+ });
125
+
126
+ it('PrLinkKind extends CommitLinkKind with the "tracks" addition', () => {
127
+ const commit: CommitLinkKind = 'implements';
128
+ const pr: PrLinkKind = commit; // every commit-link-kind is a valid pr-link-kind
129
+ expect(pr).toBe('implements');
130
+ const tracks: PrLinkKind = 'tracks';
131
+ expect(tracks).toBe('tracks');
132
+ });
133
+
134
+ it('CommitConventionalType enumerates the canonical CC prefixes plus "breaking"', () => {
135
+ const ccs: CommitConventionalType[] = [
136
+ 'feat',
137
+ 'fix',
138
+ 'chore',
139
+ 'docs',
140
+ 'refactor',
141
+ 'test',
142
+ 'build',
143
+ 'ci',
144
+ 'perf',
145
+ 'revert',
146
+ 'breaking',
147
+ ];
148
+ expect(ccs).toHaveLength(11);
149
+ expect(ccs).toContain('breaking');
150
+ });
151
+
152
+ it('CommitLinkSource and CommitLinkKind are independent unions', () => {
153
+ const src: CommitLinkSource = 'commit-trailer';
154
+ const kind: CommitLinkKind = 'implements';
155
+ expect(src).toBe('commit-trailer');
156
+ expect(kind).toBe('implements');
157
+ });
158
+
159
+ it('CommitFileChangeType matches the git status letter codes', () => {
160
+ const codes: CommitFileChangeType[] = ['A', 'M', 'D', 'R', 'C'];
161
+ expect(codes).toHaveLength(5);
162
+ });
163
+
164
+ it('ReleaseScheme enumerates calver/semver/calver-suffix', () => {
165
+ const schemes: ReleaseScheme[] = ['calver', 'semver', 'calver-suffix'];
166
+ expect(schemes).toHaveLength(3);
167
+ });
168
+
169
+ it('ReleaseChannel enumerates the provenance-layer channels', () => {
170
+ const channels: ReleaseChannel[] = ['latest', 'beta', 'dev', 'hotfix'];
171
+ expect(channels).toHaveLength(4);
172
+ });
173
+
174
+ it('ReleaseKind enumerates regular/hotfix/prerelease', () => {
175
+ const kinds: ReleaseKind[] = ['regular', 'hotfix', 'prerelease'];
176
+ expect(kinds).toHaveLength(3);
177
+ });
178
+
179
+ it('ReleaseStatus admits BOTH new-pipeline and legacy-pipeline statuses', () => {
180
+ const newPipeline: ReleaseStatus[] = [
181
+ 'planned',
182
+ 'pr-opened',
183
+ 'pr-merged',
184
+ 'published',
185
+ 'reconciled',
186
+ ];
187
+ const legacyPipeline: ReleaseStatus[] = ['prepared', 'committed', 'tagged', 'pushed'];
188
+ const terminals: ReleaseStatus[] = ['rolled_back', 'failed', 'cancelled'];
189
+ expect(newPipeline).toHaveLength(5);
190
+ expect(legacyPipeline).toHaveLength(4);
191
+ expect(terminals).toHaveLength(3);
192
+ });
193
+
194
+ it('ReleaseChangeType enumerates the 12 CLEO change types', () => {
195
+ const types: ReleaseChangeType[] = [
196
+ 'feature',
197
+ 'enhancement',
198
+ 'bug',
199
+ 'hotfix',
200
+ 'security',
201
+ 'breaking',
202
+ 'refactor',
203
+ 'docs',
204
+ 'chore',
205
+ 'revert',
206
+ 'deprecation',
207
+ 'infrastructure',
208
+ ];
209
+ expect(types).toHaveLength(12);
210
+ });
211
+
212
+ it('ReleaseImpact enumerates the 4 semver-bump assessments', () => {
213
+ const impacts: ReleaseImpact[] = ['major', 'minor', 'patch', 'none'];
214
+ expect(impacts).toHaveLength(4);
215
+ });
216
+
217
+ it('ReleaseClassifiedBy enumerates auto/manual/approved provenance', () => {
218
+ const provenance: ReleaseClassifiedBy[] = ['auto', 'manual', 'approved'];
219
+ expect(provenance).toHaveLength(3);
220
+ });
221
+
222
+ it('ReleaseArtifactType enumerates the 7 supported artifact archetypes', () => {
223
+ const types: ReleaseArtifactType[] = [
224
+ 'npm',
225
+ 'cargo',
226
+ 'docker',
227
+ 'pypi',
228
+ 'github-release',
229
+ 'binary',
230
+ 'github-tag',
231
+ ];
232
+ expect(types).toHaveLength(7);
233
+ });
234
+
235
+ it('BrainReleaseLinkType enumerates the 4 BRAIN↔release semantics', () => {
236
+ const links: BrainReleaseLinkType[] = [
237
+ 'approved-by',
238
+ 'documented-in',
239
+ 'derived-from',
240
+ 'observed-in',
241
+ ];
242
+ expect(links).toHaveLength(4);
243
+ });
244
+
245
+ // The five `_Assert…Pinned` aliases above will fail compilation if any
246
+ // shape drifts. The following references prevent unused-locals
247
+ // diagnostics from removing them.
248
+ it('compile-time pins are wired (no-op at runtime)', () => {
249
+ const pinned: [
250
+ _AssertPrStatePinned,
251
+ _AssertCommitLinkKindPinned,
252
+ _AssertReleaseStatusPinned,
253
+ _AssertReleaseChangeTypePinned,
254
+ _AssertReleaseArtifactTypePinned,
255
+ _AssertBrainReleaseLinkTypePinned,
256
+ ] = [1, 1, 1, 1, 1, 1];
257
+ expect(pinned).toEqual([1, 1, 1, 1, 1, 1]);
258
+ });
259
+ });
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Structural-equivalence tests for the scaffold-diagnostics contracts.
3
+ *
4
+ * These tests pin the field shapes of {@link ScaffoldResult},
5
+ * {@link CheckStatus}, {@link CheckResult}, and {@link HookCheckResult}
6
+ * so accidental narrowing or widening triggers a compile-time failure
7
+ * during `tsc -b` in the CI gate.
8
+ *
9
+ * The compile-time assertions use the conditional-equality trick
10
+ * (`Equals<A, B>`) so any structural drift produces a TS2322 or TS2344
11
+ * at build time. The runtime `expect` shape sanity check below is a
12
+ * thin smoke verification that constructible literals satisfy each
13
+ * interface — it does NOT exercise behavior (these are pure type
14
+ * contracts with no runtime).
15
+ *
16
+ * @since SG-ARCH-SOLID Saga T9831 · E-CONTRACTS-FOUNDATION T9832 (Phase 0a)
17
+ */
18
+
19
+ import { describe, expect, it } from 'vitest';
20
+ import type {
21
+ CheckResult,
22
+ CheckStatus,
23
+ HookCheckResult,
24
+ ScaffoldResult,
25
+ } from '../scaffold-diagnostics.js';
26
+
27
+ // ─── Compile-time structural-equality helpers ───────────────────────
28
+
29
+ /** Resolve to `1` IFF `A` and `B` are mutually assignable; `2` otherwise. */
30
+ type Equals<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? 1 : 2;
31
+
32
+ /** Compile-time assert that `T` resolves to `1`. */
33
+ type AssertEquals1<T extends 1> = T;
34
+
35
+ // ─── ScaffoldResult shape pin ───────────────────────────────────────
36
+
37
+ type _ScaffoldResultShape = {
38
+ action: 'created' | 'repaired' | 'skipped';
39
+ path: string;
40
+ details?: string;
41
+ };
42
+
43
+ type _AssertScaffoldResultPinned = AssertEquals1<Equals<ScaffoldResult, _ScaffoldResultShape>>;
44
+
45
+ // ─── CheckStatus shape pin ──────────────────────────────────────────
46
+
47
+ type _CheckStatusShape = 'passed' | 'failed' | 'warning' | 'info';
48
+
49
+ type _AssertCheckStatusPinned = AssertEquals1<Equals<CheckStatus, _CheckStatusShape>>;
50
+
51
+ // ─── CheckResult shape pin ──────────────────────────────────────────
52
+
53
+ type _CheckResultShape = {
54
+ id: string;
55
+ category: string;
56
+ status: CheckStatus;
57
+ message: string;
58
+ details: Record<string, unknown>;
59
+ fix: string | null;
60
+ };
61
+
62
+ type _AssertCheckResultPinned = AssertEquals1<Equals<CheckResult, _CheckResultShape>>;
63
+
64
+ // ─── HookCheckResult shape pin ──────────────────────────────────────
65
+
66
+ type _HookCheckResultShape = {
67
+ hook: string;
68
+ installed: boolean;
69
+ current: boolean;
70
+ sourcePath: string;
71
+ installedPath: string;
72
+ };
73
+
74
+ type _AssertHookCheckResultPinned = AssertEquals1<Equals<HookCheckResult, _HookCheckResultShape>>;
75
+
76
+ // ─── Runtime constructibility smoke ─────────────────────────────────
77
+
78
+ describe('scaffold-diagnostics contracts', () => {
79
+ it('ScaffoldResult is constructible with the canonical shape', () => {
80
+ const r: ScaffoldResult = { action: 'created', path: '/tmp/x' };
81
+ expect(r.action).toBe('created');
82
+ expect(r.path).toBe('/tmp/x');
83
+ expect(r.details).toBeUndefined();
84
+ });
85
+
86
+ it('ScaffoldResult accepts the optional details field', () => {
87
+ const r: ScaffoldResult = {
88
+ action: 'repaired',
89
+ path: '/tmp/y',
90
+ details: 'rewrote stale entry',
91
+ };
92
+ expect(r.details).toBe('rewrote stale entry');
93
+ });
94
+
95
+ it('CheckResult is constructible with the canonical shape', () => {
96
+ const r: CheckResult = {
97
+ id: 'cleo_structure',
98
+ category: 'scaffold',
99
+ status: 'passed',
100
+ message: 'All subdirs present',
101
+ details: { missing: [] },
102
+ fix: null,
103
+ };
104
+ expect(r.status).toBe('passed');
105
+ expect(r.fix).toBeNull();
106
+ });
107
+
108
+ it('CheckStatus union covers exactly the 4 documented values', () => {
109
+ const statuses: CheckStatus[] = ['passed', 'failed', 'warning', 'info'];
110
+ expect(statuses).toHaveLength(4);
111
+ });
112
+
113
+ it('HookCheckResult is constructible with the canonical shape', () => {
114
+ const r: HookCheckResult = {
115
+ hook: 'pre-commit',
116
+ installed: true,
117
+ current: false,
118
+ sourcePath: '/pkg/templates/git-hooks/pre-commit',
119
+ installedPath: '/proj/.git/hooks/pre-commit',
120
+ };
121
+ expect(r.installed).toBe(true);
122
+ expect(r.current).toBe(false);
123
+ });
124
+
125
+ // The four `_Assert…Pinned` aliases above will fail compilation if
126
+ // any shape drifts. The following references prevent unused-locals
127
+ // diagnostics from removing them.
128
+ it('compile-time pins are wired (no-op at runtime)', () => {
129
+ const pinned: [
130
+ _AssertScaffoldResultPinned,
131
+ _AssertCheckStatusPinned,
132
+ _AssertCheckResultPinned,
133
+ _AssertHookCheckResultPinned,
134
+ ] = [1, 1, 1, 1];
135
+ expect(pinned).toEqual([1, 1, 1, 1]);
136
+ });
137
+ });
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Dispatch identity contracts.
3
+ *
4
+ * Canonical home for the three primitive identity types every dispatch
5
+ * operation is keyed on:
6
+ *
7
+ * - {@link Gateway} — CQRS read vs write classification
8
+ * - {@link Tier} — progressive-disclosure tier (0/1/2)
9
+ * - {@link CanonicalDomain} — the closed set of dispatch domains
10
+ *
11
+ * Promoted to `@cleocode/contracts` in Phase 0b of the SG-ARCH-SOLID
12
+ * Saga (T9831 · E-CONTRACTS-FOUNDATION T9832 · T9954) alongside
13
+ * {@link OperationDef} / {@link Resolution}. Originally defined in
14
+ * `packages/cleo/src/dispatch/types.ts` (lines 16, 27, 58, 86). The
15
+ * `packages/cleo` definition is now a re-export shim — every consumer
16
+ * continues to compile unchanged.
17
+ *
18
+ * `CANONICAL_DOMAINS` remains the runtime SSoT — adding/removing a
19
+ * domain still requires editing the array here exactly as before.
20
+ *
21
+ * @since SG-ARCH-SOLID Saga T9831 · E-CONTRACTS-FOUNDATION T9832 · T9954 (Phase 0b)
22
+ */
23
+
24
+ // ── Gateway ──────────────────────────────────────────────────────────
25
+
26
+ /**
27
+ * CQRS gateway: read-only queries vs state-modifying mutations.
28
+ *
29
+ * Originally defined in `packages/cleo/src/dispatch/types.ts:16`.
30
+ *
31
+ * @since SG-ARCH-SOLID Saga T9831 · E-CONTRACTS-FOUNDATION T9832 · T9954 (Phase 0b)
32
+ */
33
+ export type Gateway = 'query' | 'mutate';
34
+
35
+ // ── Tier ─────────────────────────────────────────────────────────────
36
+
37
+ /**
38
+ * Progressive disclosure tier.
39
+ *
40
+ * - `0` — tasks + session (~80% of agents)
41
+ * - `1` — + memory + check (~15% of agents)
42
+ * - `2` — + pipeline + orchestrate + tools + admin + nexus (~5%)
43
+ *
44
+ * Originally defined in `packages/cleo/src/dispatch/types.ts:27`.
45
+ *
46
+ * @since SG-ARCH-SOLID Saga T9831 · E-CONTRACTS-FOUNDATION T9832 · T9954 (Phase 0b)
47
+ */
48
+ export type Tier = 0 | 1 | 2;
49
+
50
+ // ── CanonicalDomain ──────────────────────────────────────────────────
51
+
52
+ /**
53
+ * The closed set of dispatch canonical-domain names.
54
+ *
55
+ * T964: `conduit` promoted to first-class domain (supersedes ADR-042 Decision 1).
56
+ * CONDUIT is agent-to-agent messaging and is semantically disjoint from
57
+ * ORCHESTRATE (wave planning + spawn-prompt generation). The original
58
+ * "exactly 10 canonical domains" invariant that justified folding CONDUIT
59
+ * under ORCHESTRATE has been broken multiple times (intelligence, diagnostics,
60
+ * docs, playbook); promoting CONDUIT aligns registry with wire-format, CLI,
61
+ * and core module structure at zero behavior cost.
62
+ *
63
+ * T1726: `sentient` and `release` promoted to first-class domains. Both were
64
+ * reachable via the CLI and had registered DomainHandlers but were absent from
65
+ * CANONICAL_DOMAINS, making them invisible to SDK consumers via OPERATIONS.
66
+ *
67
+ * Originally defined in `packages/cleo/src/dispatch/types.ts:58`.
68
+ *
69
+ * @since SG-ARCH-SOLID Saga T9831 · E-CONTRACTS-FOUNDATION T9832 · T9954 (Phase 0b)
70
+ */
71
+ export const CANONICAL_DOMAINS = [
72
+ 'tasks',
73
+ 'session',
74
+ 'memory',
75
+ 'check',
76
+ 'pipeline',
77
+ 'orchestrate',
78
+ 'tools',
79
+ 'admin',
80
+ 'nexus',
81
+ 'sticky',
82
+ 'intelligence',
83
+ 'diagnostics',
84
+ 'docs',
85
+ 'playbook',
86
+ 'conduit',
87
+ 'sentient',
88
+ 'release',
89
+ 'llm',
90
+ // T9528: provenance-graph maintenance verbs (backfill, verify, repair).
91
+ 'provenance',
92
+ // T9536: `cleo upgrade workflows` — re-render release-pipeline workflow
93
+ // templates + 3-way merge with `.workflow-overrides.yml`.
94
+ 'upgrade',
95
+ // T9546/T9547: 'cleo worktree list/prune/force-unlock' — worktree lifecycle.
96
+ 'worktree',
97
+ // T9973: 'cleo focus <id>' — single-envelope task orientation (8 calls → 1).
98
+ 'focus',
99
+ ] as const;
100
+
101
+ /**
102
+ * One of the canonical dispatch domain names.
103
+ *
104
+ * Derived as a string-literal union from {@link CANONICAL_DOMAINS} so
105
+ * adding/removing a domain in the array automatically updates the type.
106
+ *
107
+ * @since SG-ARCH-SOLID Saga T9831 · E-CONTRACTS-FOUNDATION T9832 · T9954 (Phase 0b)
108
+ */
109
+ export type CanonicalDomain = (typeof CANONICAL_DOMAINS)[number];
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Dispatch operation-def contracts.
3
+ *
4
+ * Canonical home for the {@link OperationDef} and {@link Resolution}
5
+ * interfaces that describe a single dispatchable CQRS operation and the
6
+ * result of resolving one from the operation registry.
7
+ *
8
+ * Promoted to `@cleocode/contracts` in Phase 0b of the SG-ARCH-SOLID Saga
9
+ * (T9831 · E-CONTRACTS-FOUNDATION T9832 · T9954). Originally defined in
10
+ * `packages/cleo/src/dispatch/registry.ts` (lines 14-41 / 43-53). The
11
+ * `packages/cleo` definition is now a re-export shim — every consumer of
12
+ * `OperationDef` / `Resolution` continues to compile unchanged.
13
+ *
14
+ * This promotion unblocks E-CLI-BOUNDARY (T9833) — the registry data
15
+ * relocation can now move {@link OPERATIONS} into `@cleocode/contracts`
16
+ * (or split it without changing the type's canonical home) without
17
+ * crossing a circular dependency.
18
+ *
19
+ * NOT promoted (intentional — different concern):
20
+ * - `OPERATIONS: OperationDef[]` — the registry data itself remains in
21
+ * `packages/cleo/src/dispatch/registry.ts` and is the subject of the
22
+ * follow-up E-CLI-BOUNDARY epic.
23
+ * - The helper functions (`resolve`, `validateRequiredParams`,
24
+ * `getByDomain`, `getByGateway`, `getByTier`, `getActiveDomains`,
25
+ * `getCounts`, `deriveGatewayMatrix`, `getGatewayDomains`) — they
26
+ * operate on the data and remain colocated with it.
27
+ *
28
+ * @since SG-ARCH-SOLID Saga T9831 · E-CONTRACTS-FOUNDATION T9832 · T9954 (Phase 0b)
29
+ */
30
+
31
+ import type { ParamDef } from '../operations/params.js';
32
+ import type { CanonicalDomain, Gateway, Tier } from './identity.js';
33
+
34
+ // Re-export the upstream identity types so consumers can pull every
35
+ // dispatch-related shape from a single subpath without having to know
36
+ // which leaf file each type lives in.
37
+ export type { CanonicalDomain, Gateway, ParamDef, Tier };
38
+
39
+ // ── OperationDef ─────────────────────────────────────────────────────
40
+
41
+ /**
42
+ * Definition of a single dispatchable operation.
43
+ *
44
+ * Each entry in the operation registry (currently in
45
+ * `packages/cleo/src/dispatch/registry.ts`'s `OPERATIONS` array)
46
+ * conforms to this interface. The dispatcher uses these definitions to
47
+ * (1) route a {@link CanonicalDomain} + operation-name + {@link Gateway}
48
+ * triple to its handler, (2) validate that all required parameters are
49
+ * present, and (3) emit dispatch-validation telemetry.
50
+ *
51
+ * Originally defined in `packages/cleo/src/dispatch/registry.ts:14-41`.
52
+ *
53
+ * @since SG-ARCH-SOLID Saga T9831 · E-CONTRACTS-FOUNDATION T9832 · T9954 (Phase 0b)
54
+ */
55
+ export interface OperationDef {
56
+ /** The CQRS gateway ('query' or 'mutate'). */
57
+ gateway: Gateway;
58
+ /** The canonical domain this operation belongs to. */
59
+ domain: CanonicalDomain;
60
+ /** The specific operation name (e.g. 'show', 'skill.list'). */
61
+ operation: string;
62
+ /** Brief description of what the operation does. */
63
+ description: string;
64
+ /** Agent progressive-disclosure tier (0=basic, 1=memory/check, 2=full). */
65
+ tier: Tier;
66
+ /** Whether the operation is safe to retry. */
67
+ idempotent: boolean;
68
+ /** Whether this operation requires an active session. */
69
+ sessionRequired: boolean;
70
+ /** List of parameter keys that MUST be present in the request. */
71
+ requiredParams: string[];
72
+ /**
73
+ * Fully-described parameter list. Replaces `requiredParams` when populated.
74
+ * Empty array = "no declared params" (not "no params accepted").
75
+ * Optional during T4897 migration — defaults to [] when absent.
76
+ * @see T4897 for progressive migration
77
+ */
78
+ params?: ParamDef[];
79
+ }
80
+
81
+ // ── Resolution ───────────────────────────────────────────────────────
82
+
83
+ /**
84
+ * Resolution output for a dispatch request.
85
+ *
86
+ * Returned by the `resolve(gateway, domain, operation)` helper in the
87
+ * operation registry. Bundles the resolved {@link OperationDef} with the
88
+ * already-typed `domain` + `operation` strings so downstream consumers
89
+ * don't have to re-narrow them.
90
+ *
91
+ * Originally defined in `packages/cleo/src/dispatch/registry.ts:43-53`.
92
+ *
93
+ * @since SG-ARCH-SOLID Saga T9831 · E-CONTRACTS-FOUNDATION T9832 · T9954 (Phase 0b)
94
+ */
95
+ export interface Resolution {
96
+ /** The canonical domain. */
97
+ domain: CanonicalDomain;
98
+ /** The operation name. */
99
+ operation: string;
100
+ /** The definition of the matched operation. */
101
+ def: OperationDef;
102
+ }
package/src/doctor.ts CHANGED
@@ -5,12 +5,19 @@
5
5
  * `<projectRoot>/.claude/worktrees/` by the T9550/T9580 SSoT bug (fixed in
6
6
  * v2026.5.83) and the schema for the audit JSONL line written per prune.
7
7
  *
8
+ * Also contains the comprehensive worktree audit types (T9808) covering:
9
+ * - Orphan `.cleo/` dirs inside ANY git worktree (not just .claude/worktrees/)
10
+ * - Worktrees outside the canonical XDG location
11
+ * - Rogue `.cleo/worktrees/` DIRECTORY (council D009 — only .json sentinel allowed)
12
+ *
8
13
  * Consumed by:
9
14
  * - `packages/core/src/doctor/worktree-orphans.ts` (scan + prune primitives)
10
15
  * - `packages/cleo/src/cli/commands/doctor.ts` (CLI flags)
11
16
  *
12
17
  * @task T9790
18
+ * @task T9808
13
19
  * @epic T9790
20
+ * @epic T9808
14
21
  */
15
22
 
16
23
  /**
@@ -96,6 +103,61 @@ export interface PruneResult {
96
103
  prunedAt: string;
97
104
  }
98
105
 
106
+ // ============================================================================
107
+ // Comprehensive Worktree Audit (T9808 — council D009)
108
+ // ============================================================================
109
+
110
+ /**
111
+ * Anomaly kinds surfaced by {@link auditWorktreeOrphansComprehensive}.
112
+ *
113
+ * - `orphan-cleo-dir`: a `.cleo/` directory found inside a git worktree path
114
+ * (any worktree, not just those under `.claude/worktrees/`)
115
+ * - `non-canonical-location`: a worktree exists outside the canonical XDG
116
+ * path (`~/.local/share/cleo/worktrees/<projectHash>/<taskId>/`)
117
+ * - `rogue-worktrees-directory`: `.cleo/worktrees/` exists as a DIRECTORY
118
+ * (council D009: only a `.json` sentinel file is permitted there)
119
+ */
120
+ export type WorktreeAnomalyKind =
121
+ | 'orphan-cleo-dir'
122
+ | 'non-canonical-location'
123
+ | 'rogue-worktrees-directory';
124
+
125
+ /**
126
+ * One anomaly surfaced by the comprehensive worktree audit.
127
+ */
128
+ export interface WorktreeAnomaly {
129
+ /** Machine-readable anomaly type. */
130
+ kind: WorktreeAnomalyKind;
131
+ /**
132
+ * Absolute path of the affected location.
133
+ * - For `orphan-cleo-dir`: path to the offending `.cleo/` directory.
134
+ * - For `non-canonical-location`: path to the non-canonical worktree root.
135
+ * - For `rogue-worktrees-directory`: path to the `.cleo/worktrees/` directory.
136
+ */
137
+ path: string;
138
+ /** Human-readable description including suggested remediation. */
139
+ description: string;
140
+ /**
141
+ * The git worktree path that triggered this anomaly (from `git worktree list`),
142
+ * or `null` for anomalies not tied to a specific worktree entry.
143
+ */
144
+ worktreePath: string | null;
145
+ }
146
+
147
+ /**
148
+ * Result returned by {@link auditWorktreeOrphansComprehensive}.
149
+ */
150
+ export interface ComprehensiveAuditResult {
151
+ /** Absolute path to the project root that was audited. */
152
+ projectRoot: string;
153
+ /** Canonical XDG worktrees root for this project (expected location). */
154
+ canonicalWorktreesRoot: string;
155
+ /** All anomalies detected. Sorted by `kind` then `path`. */
156
+ anomalies: WorktreeAnomaly[];
157
+ /** Total anomaly count. Non-zero triggers exit code 2. */
158
+ count: number;
159
+ }
160
+
99
161
  /**
100
162
  * One line appended to `.cleo/audit/worktree-prune.jsonl` per prune
101
163
  * operation. Extends the existing audit-log schema (timestamp +