@cleocode/contracts 2026.5.61 → 2026.5.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/nexus-scope-map.test.d.ts +8 -0
- package/dist/__tests__/nexus-scope-map.test.d.ts.map +1 -0
- package/dist/__tests__/nexus-scope-map.test.js +145 -0
- package/dist/__tests__/nexus-scope-map.test.js.map +1 -0
- package/dist/branch-lock.d.ts +11 -0
- package/dist/branch-lock.d.ts.map +1 -1
- package/dist/branch-lock.js +11 -0
- package/dist/branch-lock.js.map +1 -1
- package/dist/config.d.ts +21 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/data-accessor.d.ts +2 -0
- package/dist/data-accessor.d.ts.map +1 -1
- package/dist/data-accessor.js.map +1 -1
- package/dist/engine-result.d.ts +170 -0
- package/dist/engine-result.d.ts.map +1 -0
- package/dist/engine-result.js +123 -0
- package/dist/engine-result.js.map +1 -0
- package/dist/errors.d.ts +24 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +31 -0
- package/dist/errors.js.map +1 -1
- package/dist/exit-codes.d.ts +8 -1
- package/dist/exit-codes.d.ts.map +1 -1
- package/dist/exit-codes.js +7 -0
- package/dist/exit-codes.js.map +1 -1
- package/dist/graph.d.ts +88 -0
- package/dist/graph.d.ts.map +1 -1
- package/dist/graph.js +35 -0
- package/dist/graph.js.map +1 -1
- package/dist/index.d.ts +10 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/operations/nexus-scope-map.d.ts +540 -0
- package/dist/operations/nexus-scope-map.d.ts.map +1 -0
- package/dist/operations/nexus-scope-map.js +556 -0
- package/dist/operations/nexus-scope-map.js.map +1 -0
- package/dist/operations/nexus-scope.d.ts +185 -0
- package/dist/operations/nexus-scope.d.ts.map +1 -0
- package/dist/operations/nexus-scope.js +9 -0
- package/dist/operations/nexus-scope.js.map +1 -0
- package/dist/operations/session.d.ts +79 -0
- package/dist/operations/session.d.ts.map +1 -1
- package/dist/operations/tasks.d.ts +28 -0
- package/dist/operations/tasks.d.ts.map +1 -1
- package/dist/operations/worktree.d.ts +33 -0
- package/dist/operations/worktree.d.ts.map +1 -1
- package/dist/task.d.ts +17 -2
- package/dist/task.d.ts.map +1 -1
- package/dist/task.js +11 -1
- package/dist/task.js.map +1 -1
- package/dist/tasks.d.ts +0 -2
- package/dist/tasks.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/nexus-scope-map.test.ts +183 -0
- package/src/branch-lock.ts +11 -0
- package/src/config.ts +22 -0
- package/src/data-accessor.ts +3 -0
- package/src/engine-result.ts +220 -0
- package/src/errors.ts +34 -0
- package/src/exit-codes.ts +8 -0
- package/src/graph.ts +112 -0
- package/src/index.ts +49 -2
- package/src/operations/nexus-scope-map.ts +597 -0
- package/src/operations/nexus-scope.ts +217 -0
- package/src/operations/session.ts +87 -0
- package/src/operations/tasks.ts +30 -0
- package/src/operations/worktree.ts +33 -0
- package/src/task.ts +30 -1
- package/src/tasks.ts +0 -2
package/dist/tasks.d.ts
CHANGED
|
@@ -18,8 +18,6 @@ import type { TaskPriority, TaskStatus } from './task.js';
|
|
|
18
18
|
/**
|
|
19
19
|
* RCASD-IVTR+C pipeline stage values valid for `TaskView.pipelineStage`.
|
|
20
20
|
*
|
|
21
|
-
* Mirrors `TaskViewPipelineStage` from `packages/core/src/tasks/compute-task-view.ts`.
|
|
22
|
-
*
|
|
23
21
|
* @task T1703
|
|
24
22
|
*/
|
|
25
23
|
export type TaskViewPipelineStage = 'research' | 'specification' | 'decomposition' | 'implementation' | 'validation' | 'testing' | 'release' | 'contribution';
|
package/dist/tasks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../src/tasks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAM1D
|
|
1
|
+
{"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../src/tasks.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cleocode/contracts",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.62",
|
|
4
4
|
"description": "Domain types, interfaces, and contracts for the CLEO ecosystem",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"dependencies": {
|
|
83
83
|
"zod": "^4.3.6",
|
|
84
84
|
"zod-to-json-schema": "^3.25.2",
|
|
85
|
-
"@cleocode/lafs": "2026.5.
|
|
85
|
+
"@cleocode/lafs": "2026.5.62"
|
|
86
86
|
},
|
|
87
87
|
"scripts": {
|
|
88
88
|
"build": "tsc -b --force && node scripts/emit-schemas.mjs",
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for NEXUS_SCOPE_MAP SSoT helpers and ConfidenceProvenance
|
|
3
|
+
* discriminated union utilities (T9145).
|
|
4
|
+
*
|
|
5
|
+
* @task T9145
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, expect, it } from 'vitest';
|
|
9
|
+
import { confidenceFromProvenance, provenanceFromNumeric } from '../graph.js';
|
|
10
|
+
import type { NexusOps } from '../operations/nexus.js';
|
|
11
|
+
import {
|
|
12
|
+
getNexusDescriptor,
|
|
13
|
+
listOpsByScope,
|
|
14
|
+
NEXUS_SCOPE_MAP,
|
|
15
|
+
} from '../operations/nexus-scope-map.js';
|
|
16
|
+
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// NEXUS_SCOPE_MAP completeness
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
describe('NEXUS_SCOPE_MAP completeness', () => {
|
|
22
|
+
it('contains an entry for every NexusOps key (exhaustiveness check)', () => {
|
|
23
|
+
// This test verifies the compile-time check also holds at runtime.
|
|
24
|
+
// If the TypeScript exhaustiveness check passes, this test is redundant,
|
|
25
|
+
// but it makes the intent explicit for CI reviewers.
|
|
26
|
+
const keys = Object.keys(NEXUS_SCOPE_MAP) as Array<keyof NexusOps>;
|
|
27
|
+
expect(keys.length).toBeGreaterThan(50);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('every descriptor has a non-empty description', () => {
|
|
31
|
+
for (const [key, desc] of Object.entries(NEXUS_SCOPE_MAP)) {
|
|
32
|
+
expect(
|
|
33
|
+
desc.description.length,
|
|
34
|
+
`NEXUS_SCOPE_MAP['${key}'].description must be non-empty`,
|
|
35
|
+
).toBeGreaterThan(0);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('every descriptor has a valid scope', () => {
|
|
40
|
+
const validScopes = new Set(['project', 'living-brain', 'cross', 'hybrid', 'global']);
|
|
41
|
+
for (const [key, desc] of Object.entries(NEXUS_SCOPE_MAP)) {
|
|
42
|
+
expect(
|
|
43
|
+
validScopes.has(desc.scope),
|
|
44
|
+
`NEXUS_SCOPE_MAP['${key}'].scope '${desc.scope}' is not a valid NexusScope`,
|
|
45
|
+
).toBe(true);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('every descriptor has a valid effect', () => {
|
|
50
|
+
const validEffects = new Set(['read', 'write', 'admin']);
|
|
51
|
+
for (const [key, desc] of Object.entries(NEXUS_SCOPE_MAP)) {
|
|
52
|
+
expect(
|
|
53
|
+
validEffects.has(desc.effect),
|
|
54
|
+
`NEXUS_SCOPE_MAP['${key}'].effect '${desc.effect}' is not a valid NexusEffect`,
|
|
55
|
+
).toBe(true);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('global-scope ops do not require a project', () => {
|
|
60
|
+
for (const [key, desc] of Object.entries(NEXUS_SCOPE_MAP)) {
|
|
61
|
+
if (desc.scope === 'global') {
|
|
62
|
+
expect(
|
|
63
|
+
desc.requiresProject,
|
|
64
|
+
`NEXUS_SCOPE_MAP['${key}'] has scope=global but requiresProject=true`,
|
|
65
|
+
).toBe(false);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// getNexusDescriptor helper
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
describe('getNexusDescriptor', () => {
|
|
76
|
+
it('returns the correct descriptor for a known op', () => {
|
|
77
|
+
const desc = getNexusDescriptor('status');
|
|
78
|
+
expect(desc.op).toBe('status');
|
|
79
|
+
expect(desc.scope).toBe('project');
|
|
80
|
+
expect(desc.effect).toBe('read');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('returns the correct descriptor for a global op', () => {
|
|
84
|
+
const desc = getNexusDescriptor('register');
|
|
85
|
+
expect(desc.scope).toBe('global');
|
|
86
|
+
expect(desc.effect).toBe('admin');
|
|
87
|
+
expect(desc.requiresProject).toBe(false);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('returns the correct descriptor for a hybrid op', () => {
|
|
91
|
+
const desc = getNexusDescriptor('brain-anchors');
|
|
92
|
+
expect(desc.scope).toBe('hybrid');
|
|
93
|
+
expect(desc.stores).toContain('brain');
|
|
94
|
+
expect(desc.stores).toContain('nexus-graph');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// listOpsByScope helper
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
describe('listOpsByScope', () => {
|
|
103
|
+
it('returns only project-scope ops when filtering by project', () => {
|
|
104
|
+
const ops = listOpsByScope('project');
|
|
105
|
+
expect(ops.length).toBeGreaterThan(10);
|
|
106
|
+
for (const op of ops) {
|
|
107
|
+
expect(NEXUS_SCOPE_MAP[op].scope).toBe('project');
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('returns only global-scope ops when filtering by global', () => {
|
|
112
|
+
const ops = listOpsByScope('global');
|
|
113
|
+
expect(ops.length).toBeGreaterThan(0);
|
|
114
|
+
for (const op of ops) {
|
|
115
|
+
expect(NEXUS_SCOPE_MAP[op].scope).toBe('global');
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('returns hybrid ops including brain-anchors', () => {
|
|
120
|
+
const ops = listOpsByScope('hybrid');
|
|
121
|
+
expect(ops).toContain('brain-anchors');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('returns living-brain ops including profile.view', () => {
|
|
125
|
+
const ops = listOpsByScope('living-brain');
|
|
126
|
+
expect(ops).toContain('profile.view');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
// ConfidenceProvenance helpers
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
describe('provenanceFromNumeric', () => {
|
|
135
|
+
it('maps confidence=1.0 to extracted+ast', () => {
|
|
136
|
+
const p = provenanceFromNumeric(1.0);
|
|
137
|
+
expect(p.kind).toBe('extracted');
|
|
138
|
+
if (p.kind === 'extracted') expect(p.source).toBe('ast');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('maps confidence=0.95 to extracted+legacy', () => {
|
|
142
|
+
const p = provenanceFromNumeric(0.95);
|
|
143
|
+
expect(p.kind).toBe('extracted');
|
|
144
|
+
if (p.kind === 'extracted') expect(p.source).toBe('legacy');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('maps confidence=0.85 to inferred+legacy', () => {
|
|
148
|
+
const p = provenanceFromNumeric(0.85);
|
|
149
|
+
expect(p.kind).toBe('inferred');
|
|
150
|
+
if (p.kind === 'inferred') expect(p.heuristic).toBe('legacy');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('maps confidence=0.5 to ambiguous with empty candidates', () => {
|
|
154
|
+
const p = provenanceFromNumeric(0.5);
|
|
155
|
+
expect(p.kind).toBe('ambiguous');
|
|
156
|
+
if (p.kind === 'ambiguous') expect(p.candidates).toHaveLength(0);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
describe('confidenceFromProvenance', () => {
|
|
161
|
+
it('extracted+ast → 1.0', () => {
|
|
162
|
+
expect(confidenceFromProvenance({ kind: 'extracted', source: 'ast' })).toBe(1.0);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('extracted+legacy → 0.95', () => {
|
|
166
|
+
expect(confidenceFromProvenance({ kind: 'extracted', source: 'legacy' })).toBe(0.95);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('inferred → 0.85', () => {
|
|
170
|
+
expect(confidenceFromProvenance({ kind: 'inferred', heuristic: 'heritage-map' })).toBe(0.85);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('ambiguous → 0.5', () => {
|
|
174
|
+
expect(confidenceFromProvenance({ kind: 'ambiguous', candidates: ['a', 'b'] })).toBe(0.5);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('round-trips cleanly for all three tiers', () => {
|
|
178
|
+
for (const confidence of [1.0, 0.95, 0.85, 0.5]) {
|
|
179
|
+
const recovered = confidenceFromProvenance(provenanceFromNumeric(confidence));
|
|
180
|
+
expect(recovered).toBe(confidence);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
});
|
package/src/branch-lock.ts
CHANGED
|
@@ -281,6 +281,17 @@ export const BRANCH_LOCK_ERROR_CODES = {
|
|
|
281
281
|
* the git-shim which only intercepts `git` binary calls.
|
|
282
282
|
*/
|
|
283
283
|
E_BOUNDARY_VIOLATION: 'E_BOUNDARY_VIOLATION',
|
|
284
|
+
/**
|
|
285
|
+
* T1927: the `task/<taskId>` branch already exists and contains commits that
|
|
286
|
+
* are NOT reachable from the current integration base (i.e. orphan history from
|
|
287
|
+
* a prior test fixture, aborted session, or unrelated spawn). Reusing such a
|
|
288
|
+
* branch would import garbage history on merge.
|
|
289
|
+
*
|
|
290
|
+
* Fix: delete the branch manually (`git branch -D task/<taskId>`) then
|
|
291
|
+
* re-run spawn, or pass `{ forceReset: true }` to `createWorktree` to have it
|
|
292
|
+
* reset the branch automatically.
|
|
293
|
+
*/
|
|
294
|
+
E_DIRTY_BRANCH: 'E_DIRTY_BRANCH',
|
|
284
295
|
} as const;
|
|
285
296
|
|
|
286
297
|
/** Union of all branch-lock error code strings. */
|
package/src/config.ts
CHANGED
|
@@ -505,6 +505,28 @@ export interface CleoConfig {
|
|
|
505
505
|
* @task T1828
|
|
506
506
|
*/
|
|
507
507
|
decisions?: DecisionsConfig;
|
|
508
|
+
/**
|
|
509
|
+
* Briefing pipeline settings (T1904 / BBTT-W2-3).
|
|
510
|
+
*
|
|
511
|
+
* @defaultValue undefined
|
|
512
|
+
*/
|
|
513
|
+
briefing?: BriefingConfig;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Configuration for the `cleo briefing` pipeline (T1904 / BBTT-W2-3).
|
|
518
|
+
*/
|
|
519
|
+
export interface BriefingConfig {
|
|
520
|
+
/**
|
|
521
|
+
* Whether `cleo briefing` opportunistically triggers a dream cycle after
|
|
522
|
+
* computing the briefing response.
|
|
523
|
+
*
|
|
524
|
+
* The dream cycle is always subject to its own 5-minute cooldown guard and
|
|
525
|
+
* never blocks the briefing response.
|
|
526
|
+
*
|
|
527
|
+
* @defaultValue true
|
|
528
|
+
*/
|
|
529
|
+
opportunisticDream?: boolean;
|
|
508
530
|
}
|
|
509
531
|
|
|
510
532
|
/**
|
package/src/data-accessor.ts
CHANGED
|
@@ -179,6 +179,9 @@ export interface DataAccessor {
|
|
|
179
179
|
reason?: string,
|
|
180
180
|
): Promise<void>;
|
|
181
181
|
|
|
182
|
+
/** Remove a row from the task_relations table (T9240). */
|
|
183
|
+
removeRelation(taskId: string, relatedTo: string, relationType?: string): Promise<void>;
|
|
184
|
+
|
|
182
185
|
// ---- Metadata (schema_meta KV store) ----
|
|
183
186
|
|
|
184
187
|
/** Read a typed value from the metadata store. Returns null if not found. */
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical EngineResult type — the single discriminated-union shape used by
|
|
3
|
+
* all SDK return paths, dispatch engines, and CLI domain handlers.
|
|
4
|
+
*
|
|
5
|
+
* Defined here in @cleocode/contracts so it is available to every consumer
|
|
6
|
+
* without creating a dependency on @cleocode/core. @cleocode/core re-exports
|
|
7
|
+
* these types and helpers transparently.
|
|
8
|
+
*
|
|
9
|
+
* @epic T1685 — T-CSL-RESET Wave 1: EngineResult canonicalization
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { LAFSPage } from '@cleocode/lafs';
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// RFC 9457 Problem Details — canonical definition (moved from core/errors.ts)
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* RFC 9457 Problem Details object.
|
|
20
|
+
* Structured error representation for API responses.
|
|
21
|
+
*
|
|
22
|
+
* @see https://www.rfc-editor.org/rfc/rfc9457
|
|
23
|
+
*/
|
|
24
|
+
export interface ProblemDetails {
|
|
25
|
+
/** URI reference identifying the problem type. */
|
|
26
|
+
type: string;
|
|
27
|
+
/** Short human-readable summary of the problem type. */
|
|
28
|
+
title: string;
|
|
29
|
+
/** HTTP status code. */
|
|
30
|
+
status: number;
|
|
31
|
+
/** Human-readable explanation specific to this occurrence. */
|
|
32
|
+
detail: string;
|
|
33
|
+
/** URI reference identifying the specific problem instance. */
|
|
34
|
+
instance?: string;
|
|
35
|
+
/** Extension members carrying additional problem information. */
|
|
36
|
+
extensions?: Record<string, unknown>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// EngineResult — discriminated union
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Successful engine result branch — carries `data` and optional `page`.
|
|
45
|
+
*
|
|
46
|
+
* @task T1685 — canonical home moved to contracts
|
|
47
|
+
*/
|
|
48
|
+
export interface EngineSuccess<T = unknown> {
|
|
49
|
+
readonly success: true;
|
|
50
|
+
readonly data: T;
|
|
51
|
+
readonly page?: LAFSPage;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Structured engine error payload — carries machine-readable code + human
|
|
56
|
+
* message plus optional exitCode, details, fix hint, alternative actions,
|
|
57
|
+
* and RFC 9457 problem details.
|
|
58
|
+
*
|
|
59
|
+
* @task T1707 — problemDetails field
|
|
60
|
+
* @task T1685 — canonical home moved to contracts
|
|
61
|
+
*/
|
|
62
|
+
export interface EngineErrorPayload {
|
|
63
|
+
code: string;
|
|
64
|
+
message: string;
|
|
65
|
+
exitCode?: number;
|
|
66
|
+
details?: unknown;
|
|
67
|
+
fix?: string;
|
|
68
|
+
alternatives?: Array<{ action: string; command: string }>;
|
|
69
|
+
/**
|
|
70
|
+
* RFC 9457 problem details for structured error reporting.
|
|
71
|
+
*
|
|
72
|
+
* @see ProblemDetails
|
|
73
|
+
*/
|
|
74
|
+
problemDetails?: ProblemDetails;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Failed engine result branch — carries structured `error`.
|
|
79
|
+
*
|
|
80
|
+
* @task T1685 — canonical home moved to contracts
|
|
81
|
+
*/
|
|
82
|
+
export interface EngineFailure {
|
|
83
|
+
readonly success: false;
|
|
84
|
+
readonly error: EngineErrorPayload;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Canonical EngineResult — discriminated union of success and failure.
|
|
89
|
+
*
|
|
90
|
+
* Use `result.success` to narrow:
|
|
91
|
+
* - `true` → `result.data: T` is present; `result.error` does not exist
|
|
92
|
+
* - `false` → `result.error: EngineErrorPayload` is present; `result.data` does not exist
|
|
93
|
+
*
|
|
94
|
+
* @task T1685 — canonical home moved to contracts
|
|
95
|
+
*/
|
|
96
|
+
export type EngineResult<T = unknown> = EngineSuccess<T> | EngineFailure;
|
|
97
|
+
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// Constructors
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Construct a successful EngineResult.
|
|
104
|
+
*
|
|
105
|
+
* @param data - the operation's payload
|
|
106
|
+
* @param page - optional pagination metadata
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* import { engineSuccess } from '@cleocode/contracts';
|
|
111
|
+
* return engineSuccess({ items: [], total: 0 });
|
|
112
|
+
* return engineSuccess(items, { mode: 'offset', limit: 10, offset: 0, total: 100, hasMore: true });
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export function engineSuccess<T>(data: T, page?: LAFSPage): EngineResult<T> {
|
|
116
|
+
return page ? { success: true, data, page } : { success: true, data };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Construct a failed EngineResult with structured error.
|
|
121
|
+
*
|
|
122
|
+
* @param code - stable machine-readable error code (e.g. `'E_NOT_FOUND'`)
|
|
123
|
+
* @param message - human-readable error description
|
|
124
|
+
* @param options - optional `exitCode`, `details`, `fix`, `alternatives`, `problemDetails`
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```ts
|
|
128
|
+
* import { engineError } from '@cleocode/contracts';
|
|
129
|
+
* return engineError('E_NOT_FOUND', `Task ${id} not found`, { fix: `cleo show ${id}` });
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export function engineError<T = unknown>(
|
|
133
|
+
code: string,
|
|
134
|
+
message: string,
|
|
135
|
+
options?: {
|
|
136
|
+
exitCode?: number;
|
|
137
|
+
details?: unknown;
|
|
138
|
+
fix?: string;
|
|
139
|
+
alternatives?: Array<{ action: string; command: string }>;
|
|
140
|
+
problemDetails?: ProblemDetails;
|
|
141
|
+
},
|
|
142
|
+
): EngineResult<T> {
|
|
143
|
+
return {
|
|
144
|
+
success: false,
|
|
145
|
+
error: {
|
|
146
|
+
code,
|
|
147
|
+
message,
|
|
148
|
+
...(options?.exitCode !== undefined ? { exitCode: options.exitCode } : {}),
|
|
149
|
+
...(options?.details !== undefined ? { details: options.details } : {}),
|
|
150
|
+
...(options?.fix !== undefined ? { fix: options.fix } : {}),
|
|
151
|
+
...(options?.alternatives ? { alternatives: options.alternatives } : {}),
|
|
152
|
+
...(options?.problemDetails !== undefined ? { problemDetails: options.problemDetails } : {}),
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
// unwrap() — throw-style ergonomic helper for SDK consumers
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Error thrown by {@link unwrap} when an {@link EngineResult} carries a
|
|
163
|
+
* failure. Preserves the full {@link EngineErrorPayload} shape so callers
|
|
164
|
+
* can inspect `code`, `message`, `exitCode`, `details`, `fix`,
|
|
165
|
+
* `alternatives`, and `problemDetails` after catching.
|
|
166
|
+
*
|
|
167
|
+
* @task T1725
|
|
168
|
+
*/
|
|
169
|
+
export class EngineResultError extends Error {
|
|
170
|
+
/** Machine-readable error code (e.g. `'E_NOT_FOUND'`). */
|
|
171
|
+
readonly code: string;
|
|
172
|
+
/** Numeric process exit code, if present. */
|
|
173
|
+
readonly exitCode?: number;
|
|
174
|
+
/** Structured field-level details, if present. */
|
|
175
|
+
readonly details?: unknown;
|
|
176
|
+
/** Human-readable fix hint, if present. */
|
|
177
|
+
readonly fix?: string;
|
|
178
|
+
/** Alternative actions the caller may take, if present. */
|
|
179
|
+
readonly alternatives?: Array<{ action: string; command: string }>;
|
|
180
|
+
/** RFC 9457 problem details, if present. */
|
|
181
|
+
readonly problemDetails?: ProblemDetails;
|
|
182
|
+
|
|
183
|
+
constructor(payload: EngineErrorPayload) {
|
|
184
|
+
super(payload.message);
|
|
185
|
+
this.name = 'EngineResultError';
|
|
186
|
+
this.code = payload.code;
|
|
187
|
+
if (payload.exitCode !== undefined) this.exitCode = payload.exitCode;
|
|
188
|
+
if (payload.details !== undefined) this.details = payload.details;
|
|
189
|
+
if (payload.fix !== undefined) this.fix = payload.fix;
|
|
190
|
+
if (payload.alternatives !== undefined) this.alternatives = payload.alternatives;
|
|
191
|
+
if (payload.problemDetails !== undefined) this.problemDetails = payload.problemDetails;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Unwrap an {@link EngineResult}, returning the payload data on success or
|
|
197
|
+
* throwing an {@link EngineResultError} on failure.
|
|
198
|
+
*
|
|
199
|
+
* Intended for public SDK consumers who prefer a throw-style API over the
|
|
200
|
+
* internal discriminated-union pattern. Internal dispatch code SHOULD
|
|
201
|
+
* continue using the `if (result.success)` pattern directly.
|
|
202
|
+
*
|
|
203
|
+
* @param result - an {@link EngineResult} to unwrap
|
|
204
|
+
* @returns the `data` value when `result.success` is `true`
|
|
205
|
+
* @throws {@link EngineResultError} when `result.success` is `false`
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```ts
|
|
209
|
+
* import { unwrap } from '@cleocode/contracts';
|
|
210
|
+
* const task = unwrap(await engine.getTask(id));
|
|
211
|
+
* ```
|
|
212
|
+
*
|
|
213
|
+
* @task T1725
|
|
214
|
+
*/
|
|
215
|
+
export function unwrap<T>(result: EngineResult<T>): T {
|
|
216
|
+
if (result.success) {
|
|
217
|
+
return result.data;
|
|
218
|
+
}
|
|
219
|
+
throw new EngineResultError(result.error);
|
|
220
|
+
}
|
package/src/errors.ts
CHANGED
|
@@ -199,6 +199,40 @@ export class DecisionValidatorFailedError extends Error {
|
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Thrown when a Lead session attempts to end without delegating any work.
|
|
204
|
+
*
|
|
205
|
+
* Hard gate enforcement for T9230 (ADR-070): a Lead session with
|
|
206
|
+
* `delegate_task_count=0` and `tasks_completed > 0` is a bypass attempt.
|
|
207
|
+
* Leads MUST fan out work to Workers via `delegate_task`.
|
|
208
|
+
*
|
|
209
|
+
* @codeName E_LEAD_BYPASS_DETECTED
|
|
210
|
+
* @task T9230
|
|
211
|
+
* @adr ADR-070
|
|
212
|
+
*/
|
|
213
|
+
export class LeadBypassDetectedError extends Error {
|
|
214
|
+
/** Stable LAFS error code string for envelope emission. */
|
|
215
|
+
readonly code = 'E_LEAD_BYPASS_DETECTED';
|
|
216
|
+
/** Numeric exit code aligned with {@link ExitCode.LEAD_BYPASS_DETECTED} (107). */
|
|
217
|
+
readonly exitCode = 107;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* @param tasksCompleted - Number of tasks completed in the session.
|
|
221
|
+
* @param sessionId - The session ID being ended.
|
|
222
|
+
*/
|
|
223
|
+
constructor(
|
|
224
|
+
public readonly tasksCompleted: number,
|
|
225
|
+
public readonly sessionId: string,
|
|
226
|
+
) {
|
|
227
|
+
super(
|
|
228
|
+
`E_LEAD_BYPASS_DETECTED: Lead session ${sessionId} completed ${tasksCompleted} task(s) ` +
|
|
229
|
+
`without any delegate_task call. Leads MUST fan out work to Workers (T9230 / ADR-070). ` +
|
|
230
|
+
`Set CLEO_OWNER_OVERRIDE=1 with reason to override (audited).`,
|
|
231
|
+
);
|
|
232
|
+
this.name = 'LeadBypassDetectedError';
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
202
236
|
/**
|
|
203
237
|
* Normalize any thrown value into a standardized error object.
|
|
204
238
|
*
|
package/src/exit-codes.ts
CHANGED
|
@@ -216,6 +216,14 @@ export enum ExitCode {
|
|
|
216
216
|
* @task T1828
|
|
217
217
|
*/
|
|
218
218
|
DECISION_VALIDATOR_FAILED = 106,
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Lead session attempted to end without delegating any work — `delegate_task_count=0`
|
|
222
|
+
* with `tasks_completed > 0`. Leads MUST fan out to Workers (T9230 / ADR-070).
|
|
223
|
+
* @codeName E_LEAD_BYPASS_DETECTED
|
|
224
|
+
* @task T9230
|
|
225
|
+
*/
|
|
226
|
+
LEAD_BYPASS_DETECTED = 107,
|
|
219
227
|
}
|
|
220
228
|
|
|
221
229
|
/** Check if an exit code represents an error (1-99). */
|
package/src/graph.ts
CHANGED
|
@@ -204,6 +204,118 @@ export function confidenceLabelFromNumeric(confidence: number): GraphEdgeConfide
|
|
|
204
204
|
return 'AMBIGUOUS';
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
// ---------------------------------------------------------------------------
|
|
208
|
+
// ConfidenceProvenance — structured provenance for confidence scores
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Structured provenance for an EXTRACTED confidence assignment.
|
|
213
|
+
*
|
|
214
|
+
* Used when confidence was derived from direct AST evidence (same-file
|
|
215
|
+
* lookup, import-scoped resolution) or an explicit source annotation.
|
|
216
|
+
*
|
|
217
|
+
* @since T9145
|
|
218
|
+
*/
|
|
219
|
+
export interface ExtractedProvenance {
|
|
220
|
+
/** Discriminant. */
|
|
221
|
+
readonly kind: 'extracted';
|
|
222
|
+
/**
|
|
223
|
+
* AST / static-analysis source that produced this confidence value.
|
|
224
|
+
* Examples: `"ast"`, `"import-scope"`, `"same-file"`, `"defines"`.
|
|
225
|
+
*/
|
|
226
|
+
readonly source: string;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Structured provenance for an INFERRED confidence assignment.
|
|
231
|
+
*
|
|
232
|
+
* Used when confidence was derived from resolution heuristics (cross-file
|
|
233
|
+
* type lookup, heritage-map inference, name matching).
|
|
234
|
+
*
|
|
235
|
+
* @since T9145
|
|
236
|
+
*/
|
|
237
|
+
export interface InferredProvenance {
|
|
238
|
+
/** Discriminant. */
|
|
239
|
+
readonly kind: 'inferred';
|
|
240
|
+
/**
|
|
241
|
+
* Heuristic or rule that produced this confidence value.
|
|
242
|
+
* Examples: `"heritage-map"`, `"name-match"`, `"global-tier"`.
|
|
243
|
+
*/
|
|
244
|
+
readonly heuristic: string;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Structured provenance for an AMBIGUOUS confidence assignment.
|
|
249
|
+
*
|
|
250
|
+
* Used when confidence is low because multiple candidates were found,
|
|
251
|
+
* the parent is external / unresolvable, or resolution fell to a global stub.
|
|
252
|
+
*
|
|
253
|
+
* @since T9145
|
|
254
|
+
*/
|
|
255
|
+
export interface AmbiguousProvenance {
|
|
256
|
+
/** Discriminant. */
|
|
257
|
+
readonly kind: 'ambiguous';
|
|
258
|
+
/**
|
|
259
|
+
* Candidate node IDs that competed for this resolution slot.
|
|
260
|
+
* May be empty when the ambiguity is due to an unresolvable external type.
|
|
261
|
+
*/
|
|
262
|
+
readonly candidates: ReadonlyArray<string>;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Discriminated union of structured confidence provenance variants.
|
|
267
|
+
*
|
|
268
|
+
* Replaces the bare numeric `confidence` field on {@link GraphRelation} as
|
|
269
|
+
* part of the Beta gradient deprecation (phase 0: addition, phase 1:
|
|
270
|
+
* co-existence, removal at v2026.9).
|
|
271
|
+
*
|
|
272
|
+
* **Backfill mapping** for existing records created without structured
|
|
273
|
+
* provenance:
|
|
274
|
+
* - `confidence === 1.0` → `{ kind: 'extracted', source: 'ast' }`
|
|
275
|
+
* - `confidence >= 0.90` → `{ kind: 'extracted', source: 'legacy' }`
|
|
276
|
+
* - `confidence >= 0.80` → `{ kind: 'inferred', heuristic: 'legacy' }`
|
|
277
|
+
* - `confidence < 0.80` → `{ kind: 'ambiguous', candidates: [] }`
|
|
278
|
+
*
|
|
279
|
+
* @since T9145
|
|
280
|
+
* @deprecated Numeric `confidence` on {@link GraphRelation} will be removed in v2026.9.
|
|
281
|
+
* Use `confidenceProvenance` instead. Migration: `confidenceFromProvenance()` maps back.
|
|
282
|
+
*/
|
|
283
|
+
export type ConfidenceProvenance = ExtractedProvenance | InferredProvenance | AmbiguousProvenance;
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Backfill a {@link ConfidenceProvenance} from a legacy numeric confidence value.
|
|
287
|
+
*
|
|
288
|
+
* @param confidence - Numeric confidence in range [0.0, 1.0]
|
|
289
|
+
* @returns A structured provenance record consistent with the numeric value
|
|
290
|
+
* @since T9145
|
|
291
|
+
*/
|
|
292
|
+
export function provenanceFromNumeric(confidence: number): ConfidenceProvenance {
|
|
293
|
+
if (confidence === 1.0) return { kind: 'extracted', source: 'ast' };
|
|
294
|
+
if (confidence >= 0.9) return { kind: 'extracted', source: 'legacy' };
|
|
295
|
+
if (confidence >= 0.8) return { kind: 'inferred', heuristic: 'legacy' };
|
|
296
|
+
return { kind: 'ambiguous', candidates: [] };
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Recover a numeric confidence value from a {@link ConfidenceProvenance} record.
|
|
301
|
+
*
|
|
302
|
+
* Inverse of {@link provenanceFromNumeric} for backward-compat bridging.
|
|
303
|
+
*
|
|
304
|
+
* @param provenance - Structured provenance record
|
|
305
|
+
* @returns Best-effort numeric confidence in range [0.0, 1.0]
|
|
306
|
+
* @since T9145
|
|
307
|
+
*/
|
|
308
|
+
export function confidenceFromProvenance(provenance: ConfidenceProvenance): number {
|
|
309
|
+
switch (provenance.kind) {
|
|
310
|
+
case 'extracted':
|
|
311
|
+
return provenance.source === 'ast' ? 1.0 : 0.95;
|
|
312
|
+
case 'inferred':
|
|
313
|
+
return 0.85;
|
|
314
|
+
case 'ambiguous':
|
|
315
|
+
return 0.5;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
207
319
|
// ---------------------------------------------------------------------------
|
|
208
320
|
// Relation interface
|
|
209
321
|
// ---------------------------------------------------------------------------
|