@cleocode/contracts 2026.5.61 → 2026.5.63
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__/llm-config-schema.test.d.ts +20 -0
- package/dist/__tests__/llm-config-schema.test.d.ts.map +1 -0
- package/dist/__tests__/llm-config-schema.test.js +121 -0
- package/dist/__tests__/llm-config-schema.test.js.map +1 -0
- 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 +116 -5
- 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 +12 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/operations/llm.d.ts +380 -0
- package/dist/operations/llm.d.ts.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__/llm-config-schema.test.ts +135 -0
- package/src/__tests__/nexus-scope-map.test.ts +183 -0
- package/src/branch-lock.ts +11 -0
- package/src/config.ts +122 -5
- 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 +82 -2
- package/src/operations/llm.ts +437 -0
- 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.63",
|
|
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.63"
|
|
86
86
|
},
|
|
87
87
|
"scripts": {
|
|
88
88
|
"build": "tsc -b --force && node scripts/emit-schemas.mjs",
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema roundtrip tests for the extended `LlmConfig` shape.
|
|
3
|
+
*
|
|
4
|
+
* Asserts that:
|
|
5
|
+
*
|
|
6
|
+
* 1. A literal `LlmConfig` object containing the new `default`, `roles`, and
|
|
7
|
+
* the legacy `daemon` fields typechecks and survives a JSON
|
|
8
|
+
* serialize/deserialize cycle without structural loss.
|
|
9
|
+
* 2. All five `RoleName` values (`extraction`, `consolidation`, `derivation`,
|
|
10
|
+
* `hygiene`, `judgement`) are accepted as keys of `roles`.
|
|
11
|
+
* 3. Omitting `default` and/or `roles` still typechecks (both are optional).
|
|
12
|
+
*
|
|
13
|
+
* These tests guard the Phase 2 schema extension of
|
|
14
|
+
* T-LLM-CRED-CENTRALIZATION against accidental regressions.
|
|
15
|
+
*
|
|
16
|
+
* @task T9256
|
|
17
|
+
* @epic T-LLM-CRED-CENTRALIZATION
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { describe, expect, it } from 'vitest';
|
|
21
|
+
import type { LlmConfig, LlmDefaultConfig, LlmRoleConfig, RoleName } from '../config.js';
|
|
22
|
+
|
|
23
|
+
describe('LlmConfig — Phase 2 schema extension (T9256)', () => {
|
|
24
|
+
it('accepts a fully-populated config with default, roles, and legacy daemon', () => {
|
|
25
|
+
const cfg: LlmConfig = {
|
|
26
|
+
daemon: { provider: 'anthropic', model: 'claude-sonnet-4-6' },
|
|
27
|
+
providers: {
|
|
28
|
+
anthropic: { apiKey: 'sk-test-anthropic' },
|
|
29
|
+
openai: { apiKey: 'sk-test-openai' },
|
|
30
|
+
},
|
|
31
|
+
default: { provider: 'anthropic', model: 'claude-sonnet-4-6' },
|
|
32
|
+
roles: {
|
|
33
|
+
extraction: {
|
|
34
|
+
provider: 'anthropic',
|
|
35
|
+
model: 'claude-haiku-4-5',
|
|
36
|
+
credentialLabel: 'ext-key',
|
|
37
|
+
},
|
|
38
|
+
consolidation: {
|
|
39
|
+
provider: 'openai',
|
|
40
|
+
model: 'gpt-4o',
|
|
41
|
+
},
|
|
42
|
+
derivation: {
|
|
43
|
+
provider: 'gemini',
|
|
44
|
+
model: 'gemini-2.5-pro',
|
|
45
|
+
},
|
|
46
|
+
hygiene: {
|
|
47
|
+
provider: 'moonshot',
|
|
48
|
+
model: 'kimi-k2',
|
|
49
|
+
},
|
|
50
|
+
judgement: {
|
|
51
|
+
provider: 'anthropic',
|
|
52
|
+
model: 'claude-opus-4-7',
|
|
53
|
+
credentialLabel: 'judge-key',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const roundtripped: LlmConfig = JSON.parse(JSON.stringify(cfg));
|
|
59
|
+
expect(roundtripped).toEqual(cfg);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('preserves structural identity across JSON serialize/deserialize', () => {
|
|
63
|
+
const cfg: LlmConfig = {
|
|
64
|
+
default: { provider: 'anthropic', model: 'claude-sonnet-4-6' },
|
|
65
|
+
roles: {
|
|
66
|
+
extraction: { provider: 'anthropic', model: 'claude-haiku-4-5' },
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const serialized = JSON.stringify(cfg);
|
|
71
|
+
const parsed = JSON.parse(serialized) as LlmConfig;
|
|
72
|
+
|
|
73
|
+
expect(parsed.default).toEqual(cfg.default);
|
|
74
|
+
expect(parsed.roles).toEqual(cfg.roles);
|
|
75
|
+
expect(parsed.roles?.extraction?.provider).toBe('anthropic');
|
|
76
|
+
expect(parsed.roles?.extraction?.model).toBe('claude-haiku-4-5');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('accepts all five RoleName values as keys of roles', () => {
|
|
80
|
+
const roleNames: readonly RoleName[] = [
|
|
81
|
+
'extraction',
|
|
82
|
+
'consolidation',
|
|
83
|
+
'derivation',
|
|
84
|
+
'hygiene',
|
|
85
|
+
'judgement',
|
|
86
|
+
] as const;
|
|
87
|
+
|
|
88
|
+
// Build a `roles` map populated with one entry per role name. The TS
|
|
89
|
+
// compiler enforces that only valid `RoleName` keys appear here — any
|
|
90
|
+
// typo would be a compile-time error.
|
|
91
|
+
const roles: Partial<Record<RoleName, LlmRoleConfig>> = {};
|
|
92
|
+
for (const name of roleNames) {
|
|
93
|
+
roles[name] = { provider: 'anthropic', model: 'claude-sonnet-4-6' };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const cfg: LlmConfig = { roles };
|
|
97
|
+
expect(Object.keys(cfg.roles ?? {})).toHaveLength(5);
|
|
98
|
+
for (const name of roleNames) {
|
|
99
|
+
expect(cfg.roles?.[name]?.provider).toBe('anthropic');
|
|
100
|
+
expect(cfg.roles?.[name]?.model).toBe('claude-sonnet-4-6');
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('typechecks when default and roles are both omitted', () => {
|
|
105
|
+
const cfg: LlmConfig = {
|
|
106
|
+
daemon: { provider: 'anthropic', model: 'claude-sonnet-4-6' },
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
expect(cfg.default).toBeUndefined();
|
|
110
|
+
expect(cfg.roles).toBeUndefined();
|
|
111
|
+
expect(cfg.daemon?.provider).toBe('anthropic');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('typechecks an empty LlmConfig (all fields optional)', () => {
|
|
115
|
+
const cfg: LlmConfig = {};
|
|
116
|
+
expect(cfg).toEqual({});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('allows a role entry without an optional credentialLabel', () => {
|
|
120
|
+
const role: LlmRoleConfig = {
|
|
121
|
+
provider: 'openai',
|
|
122
|
+
model: 'gpt-4o-mini',
|
|
123
|
+
};
|
|
124
|
+
expect(role.credentialLabel).toBeUndefined();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('allows LlmDefaultConfig with only provider + model (no credential)', () => {
|
|
128
|
+
const def: LlmDefaultConfig = {
|
|
129
|
+
provider: 'anthropic',
|
|
130
|
+
model: 'claude-sonnet-4-6',
|
|
131
|
+
};
|
|
132
|
+
expect(def.provider).toBe('anthropic');
|
|
133
|
+
expect(def.model).toBe('claude-sonnet-4-6');
|
|
134
|
+
});
|
|
135
|
+
});
|
|
@@ -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
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* @task T5710
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import type { ModelTransport } from './operations/llm.js';
|
|
13
|
+
|
|
12
14
|
/** Output format options. */
|
|
13
15
|
export type OutputFormat = 'json' | 'text' | 'jsonl' | 'markdown' | 'table';
|
|
14
16
|
|
|
@@ -282,7 +284,11 @@ export interface BrainTieringConfig {
|
|
|
282
284
|
export interface BrainLlmExtractionConfig {
|
|
283
285
|
/** Enable LLM-driven extraction gate (default: true). */
|
|
284
286
|
enabled: boolean;
|
|
285
|
-
/**
|
|
287
|
+
/**
|
|
288
|
+
* Anthropic model to use for extraction. Default lives in
|
|
289
|
+
* `@cleocode/core/llm/role-resolver` (`IMPLICIT_FALLBACK_MODEL`) so the
|
|
290
|
+
* literal stays in a single source location (T9255 grep guard).
|
|
291
|
+
*/
|
|
286
292
|
model: string;
|
|
287
293
|
/** Minimum importance score (0.0–1.0) below which extractions are dropped (default: 0.6). */
|
|
288
294
|
minImportance: number;
|
|
@@ -325,10 +331,11 @@ export interface BrainConfig {
|
|
|
325
331
|
* LLM-driven extraction gate settings.
|
|
326
332
|
* When enabled and ANTHROPIC_API_KEY is present, session transcripts are
|
|
327
333
|
* processed by an LLM to extract typed structured memories instead of the
|
|
328
|
-
* legacy keyword regex. Defaults are enabled: true and model
|
|
329
|
-
*
|
|
334
|
+
* legacy keyword regex. Defaults are enabled: true and model defaults to
|
|
335
|
+
* the centralised implicit fallback (cheap Haiku class) defined in
|
|
336
|
+
* `@cleocode/core/llm/role-resolver` so extraction cost stays bounded.
|
|
330
337
|
*
|
|
331
|
-
* @defaultValue { enabled: true, model:
|
|
338
|
+
* @defaultValue { enabled: true, model: IMPLICIT_FALLBACK_MODEL, minImportance: 0.6, maxExtractions: 7, maxTranscriptChars: 60000 }
|
|
332
339
|
*/
|
|
333
340
|
llmExtraction?: BrainLlmExtractionConfig;
|
|
334
341
|
}
|
|
@@ -381,7 +388,7 @@ export interface DaemonLLMConfig {
|
|
|
381
388
|
* LLM provider transport used by daemon loops.
|
|
382
389
|
* @defaultValue 'anthropic'
|
|
383
390
|
*/
|
|
384
|
-
provider:
|
|
391
|
+
provider: ModelTransport;
|
|
385
392
|
/**
|
|
386
393
|
* Full model identifier for the selected provider.
|
|
387
394
|
* @defaultValue 'claude-sonnet-4-6'
|
|
@@ -389,14 +396,85 @@ export interface DaemonLLMConfig {
|
|
|
389
396
|
model: string;
|
|
390
397
|
}
|
|
391
398
|
|
|
399
|
+
/**
|
|
400
|
+
* Canonical model transport identifier — re-export of {@link ModelTransport}
|
|
401
|
+
* from `operations/llm.ts` so config-layer types stay in lock-step with the
|
|
402
|
+
* operations layer with no risk of drift.
|
|
403
|
+
*
|
|
404
|
+
* Previously declared as a separate string-literal union; collapsed in the
|
|
405
|
+
* T-LLM-CRED Phase 2 DRY/SOLID review (P1-2). Adding a new transport now
|
|
406
|
+
* requires editing only `operations/llm.ts`.
|
|
407
|
+
*
|
|
408
|
+
* @task T-LLM-CRED-CENTRALIZATION Phase 2 — DRY review P1-2
|
|
409
|
+
*/
|
|
410
|
+
export type LlmTransport = ModelTransport;
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Logical LLM role name used by role-aware resolvers (BRAIN, sentient, etc.).
|
|
414
|
+
*
|
|
415
|
+
* Each role can pin its own provider + model + credential label, with
|
|
416
|
+
* resolution falling back to `LlmConfig.default` and finally to the legacy
|
|
417
|
+
* `LlmConfig.daemon` block.
|
|
418
|
+
*
|
|
419
|
+
* @task T-LLM-CRED-CENTRALIZATION Phase 2 (T9256)
|
|
420
|
+
*/
|
|
421
|
+
export type RoleName = 'extraction' | 'consolidation' | 'derivation' | 'hygiene' | 'judgement';
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Canonical default LLM target for unscoped (non-role) calls.
|
|
425
|
+
*
|
|
426
|
+
* Replaces the role previously played by `LlmConfig.daemon`. The `daemon`
|
|
427
|
+
* field stays as a deprecated alias for one release cycle to give downstream
|
|
428
|
+
* consumers time to migrate.
|
|
429
|
+
*
|
|
430
|
+
* @task T-LLM-CRED-CENTRALIZATION Phase 2 (T9256)
|
|
431
|
+
*/
|
|
432
|
+
export interface LlmDefaultConfig {
|
|
433
|
+
/** LLM provider transport for the default model. */
|
|
434
|
+
provider: LlmTransport;
|
|
435
|
+
/** Full model identifier for the selected provider. */
|
|
436
|
+
model: string;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Per-role LLM configuration entry.
|
|
441
|
+
*
|
|
442
|
+
* Each role may optionally pin to a specific credential label (matching a
|
|
443
|
+
* `CredentialResult.label`) so that, e.g., the `extraction` role can use a
|
|
444
|
+
* different Anthropic API key than `judgement` without changing the global
|
|
445
|
+
* default.
|
|
446
|
+
*
|
|
447
|
+
* @task T-LLM-CRED-CENTRALIZATION Phase 2 (T9256)
|
|
448
|
+
*/
|
|
449
|
+
export interface LlmRoleConfig {
|
|
450
|
+
/** LLM provider transport for this role. */
|
|
451
|
+
provider: LlmTransport;
|
|
452
|
+
/** Full model identifier for the selected provider. */
|
|
453
|
+
model: string;
|
|
454
|
+
/**
|
|
455
|
+
* Optional credential label to pin this role to a specific credential
|
|
456
|
+
* entry resolved by `resolveCredentials()`. When omitted, the role
|
|
457
|
+
* inherits the default credential resolution order.
|
|
458
|
+
*/
|
|
459
|
+
credentialLabel?: string;
|
|
460
|
+
}
|
|
461
|
+
|
|
392
462
|
/**
|
|
393
463
|
* Top-level LLM configuration block inside CleoConfig.
|
|
394
464
|
*
|
|
395
465
|
* Stored at `llm` in config.json.
|
|
466
|
+
*
|
|
467
|
+
* Resolution order for role-scoped calls:
|
|
468
|
+
* `roles[role]` → `default` → `daemon` (legacy).
|
|
396
469
|
*/
|
|
397
470
|
export interface LlmConfig {
|
|
398
471
|
/**
|
|
399
472
|
* Daemon LLM settings (provider + model for background loops).
|
|
473
|
+
*
|
|
474
|
+
* @deprecated Use `default` instead. Retained as a fallback alias for
|
|
475
|
+
* one release cycle (T-LLM-CRED-CENTRALIZATION Phase 2 · T9256). New
|
|
476
|
+
* code must read `default` first and only fall through to `daemon` when
|
|
477
|
+
* `default` is absent.
|
|
400
478
|
* @defaultValue { provider: 'anthropic', model: 'claude-sonnet-4-6' }
|
|
401
479
|
*/
|
|
402
480
|
daemon?: DaemonLLMConfig;
|
|
@@ -405,6 +483,23 @@ export interface LlmConfig {
|
|
|
405
483
|
* Keys are provider names: 'anthropic' | 'openai' | 'gemini' | 'moonshot'.
|
|
406
484
|
*/
|
|
407
485
|
providers?: Record<string, LlmProviderEntry>;
|
|
486
|
+
/**
|
|
487
|
+
* Canonical default LLM for unscoped calls. Replaces the role previously
|
|
488
|
+
* played by `daemon`, which stays as a deprecated alias for one release
|
|
489
|
+
* cycle.
|
|
490
|
+
*
|
|
491
|
+
* @task T-LLM-CRED-CENTRALIZATION Phase 2 (T9256)
|
|
492
|
+
*/
|
|
493
|
+
default?: LlmDefaultConfig;
|
|
494
|
+
/**
|
|
495
|
+
* Per-role LLM overrides. Each role optionally pins to a credential
|
|
496
|
+
* label.
|
|
497
|
+
*
|
|
498
|
+
* Resolution order: `roles[role]` → `default` → `daemon` (legacy).
|
|
499
|
+
*
|
|
500
|
+
* @task T-LLM-CRED-CENTRALIZATION Phase 2 (T9256)
|
|
501
|
+
*/
|
|
502
|
+
roles?: Partial<Record<RoleName, LlmRoleConfig>>;
|
|
408
503
|
}
|
|
409
504
|
|
|
410
505
|
/** SignalDock transport mode. */
|
|
@@ -505,6 +600,28 @@ export interface CleoConfig {
|
|
|
505
600
|
* @task T1828
|
|
506
601
|
*/
|
|
507
602
|
decisions?: DecisionsConfig;
|
|
603
|
+
/**
|
|
604
|
+
* Briefing pipeline settings (T1904 / BBTT-W2-3).
|
|
605
|
+
*
|
|
606
|
+
* @defaultValue undefined
|
|
607
|
+
*/
|
|
608
|
+
briefing?: BriefingConfig;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Configuration for the `cleo briefing` pipeline (T1904 / BBTT-W2-3).
|
|
613
|
+
*/
|
|
614
|
+
export interface BriefingConfig {
|
|
615
|
+
/**
|
|
616
|
+
* Whether `cleo briefing` opportunistically triggers a dream cycle after
|
|
617
|
+
* computing the briefing response.
|
|
618
|
+
*
|
|
619
|
+
* The dream cycle is always subject to its own 5-minute cooldown guard and
|
|
620
|
+
* never blocks the briefing response.
|
|
621
|
+
*
|
|
622
|
+
* @defaultValue true
|
|
623
|
+
*/
|
|
624
|
+
opportunisticDream?: boolean;
|
|
508
625
|
}
|
|
509
626
|
|
|
510
627
|
/**
|
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. */
|