@cleocode/core 2026.5.131 → 2026.5.132
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/db/index.d.ts +36 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +36 -0
- package/dist/db/index.js.map +1 -0
- package/dist/gc/daemon.d.ts +17 -8
- package/dist/gc/daemon.d.ts.map +1 -1
- package/dist/gc/daemon.js +24 -67
- package/dist/gc/daemon.js.map +1 -1
- package/dist/gc/gc-subsystem.d.ts +96 -0
- package/dist/gc/gc-subsystem.d.ts.map +1 -0
- package/dist/gc/gc-subsystem.js +186 -0
- package/dist/gc/gc-subsystem.js.map +1 -0
- package/dist/gc/index.d.ts +1 -0
- package/dist/gc/index.d.ts.map +1 -1
- package/dist/gc/index.js +1 -0
- package/dist/gc/index.js.map +1 -1
- package/dist/go/driver.d.ts +132 -0
- package/dist/go/driver.d.ts.map +1 -0
- package/dist/go/driver.js +191 -0
- package/dist/go/driver.js.map +1 -0
- package/dist/go/index.d.ts +13 -0
- package/dist/go/index.d.ts.map +1 -0
- package/dist/go/index.js +13 -0
- package/dist/go/index.js.map +1 -0
- package/dist/goal/advance-with-persist.d.ts +80 -0
- package/dist/goal/advance-with-persist.d.ts.map +1 -0
- package/dist/goal/advance-with-persist.js +105 -0
- package/dist/goal/advance-with-persist.js.map +1 -0
- package/dist/goal/arm.d.ts +61 -0
- package/dist/goal/arm.d.ts.map +1 -0
- package/dist/goal/arm.js +65 -0
- package/dist/goal/arm.js.map +1 -0
- package/dist/goal/index.d.ts +2 -0
- package/dist/goal/index.d.ts.map +1 -1
- package/dist/goal/index.js +2 -0
- package/dist/goal/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/orchestrate/lifecycle-ops.js +1 -1
- package/dist/orchestrate/lifecycle-ops.js.map +1 -1
- package/dist/orchestration/classify-readiness.d.ts +172 -0
- package/dist/orchestration/classify-readiness.d.ts.map +1 -0
- package/dist/orchestration/classify-readiness.js +346 -0
- package/dist/orchestration/classify-readiness.js.map +1 -0
- package/dist/orchestration/index.d.ts +2 -0
- package/dist/orchestration/index.d.ts.map +1 -1
- package/dist/orchestration/index.js +1 -0
- package/dist/orchestration/index.js.map +1 -1
- package/dist/release/pr-evidence.d.ts +4 -3
- package/dist/release/pr-evidence.d.ts.map +1 -1
- package/dist/release/pr-evidence.js +4 -3
- package/dist/release/pr-evidence.js.map +1 -1
- package/dist/sagas/index.d.ts +1 -0
- package/dist/sagas/index.d.ts.map +1 -1
- package/dist/sagas/index.js +1 -0
- package/dist/sagas/index.js.map +1 -1
- package/dist/sagas/next.d.ts +77 -0
- package/dist/sagas/next.d.ts.map +1 -0
- package/dist/sagas/next.js +159 -0
- package/dist/sagas/next.js.map +1 -0
- package/dist/sentient/daemon.d.ts +14 -0
- package/dist/sentient/daemon.d.ts.map +1 -1
- package/dist/sentient/daemon.js +1 -1
- package/dist/sentient/daemon.js.map +1 -1
- package/dist/sentient/index.d.ts +1 -0
- package/dist/sentient/index.d.ts.map +1 -1
- package/dist/sentient/index.js +1 -0
- package/dist/sentient/index.js.map +1 -1
- package/dist/sentient/tick.d.ts.map +1 -1
- package/dist/sentient/tick.js +28 -13
- package/dist/sentient/tick.js.map +1 -1
- package/dist/store/dual-scope-db.d.ts +183 -0
- package/dist/store/dual-scope-db.d.ts.map +1 -0
- package/dist/store/dual-scope-db.js +315 -0
- package/dist/store/dual-scope-db.js.map +1 -0
- package/dist/store/schema/cleo-shared/brain.d.ts +1 -1
- package/dist/tasks/add.d.ts.map +1 -1
- package/dist/tasks/add.js +16 -2
- package/dist/tasks/add.js.map +1 -1
- package/dist/tasks/evidence.d.ts +3 -2
- package/dist/tasks/evidence.d.ts.map +1 -1
- package/dist/tasks/evidence.js.map +1 -1
- package/dist/verification/verify-tools.d.ts +164 -0
- package/dist/verification/verify-tools.d.ts.map +1 -0
- package/dist/verification/verify-tools.js +236 -0
- package/dist/verification/verify-tools.js.map +1 -0
- package/package.json +16 -11
- package/templates/CLEO-INJECTION.md +3 -2
- package/templates/workflows/release-prepare.yml.tmpl +86 -7
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cleo go` autopilot driver — the thin orchestration sequencer.
|
|
3
|
+
*
|
|
4
|
+
* This is the canonical entry point for `cleo go` (SG-AUTOPILOT / T11492).
|
|
5
|
+
* It is PURE GLUE: it sequences existing core engines without adding new
|
|
6
|
+
* orchestration math.
|
|
7
|
+
*
|
|
8
|
+
* ## Pipeline (AC1)
|
|
9
|
+
*
|
|
10
|
+
* ```
|
|
11
|
+
* briefing (optional context anchor)
|
|
12
|
+
* → sagaNext() — pick highest-priority non-terminal saga
|
|
13
|
+
* → orchestrateReady(sagaId) — fetch readyFrontier
|
|
14
|
+
* → branch on pipelineStage of the active epic:
|
|
15
|
+
* AC-only (no children, research stage)
|
|
16
|
+
* → { action: 'needsDecomposition', sagaId, epicId }
|
|
17
|
+
* research | specification | decomposition
|
|
18
|
+
* → { action: 'lifecycleHop', sagaId, epicId, currentStage }
|
|
19
|
+
* implementation | validation | testing | release | contribution
|
|
20
|
+
* → fan-out startIvtr over readyFrontier tasks
|
|
21
|
+
* → { action: 'ivtrFanOut', sagaId, epicId, tasks: string[] }
|
|
22
|
+
* → return ONE LAFS-compatible EngineResult envelope
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* ## Design constraints
|
|
26
|
+
*
|
|
27
|
+
* - AC2: ONE LAFS envelope per call — all branching produces a single return.
|
|
28
|
+
* - AC3: empty ready-set + zero children → `needsDecomposition` (typed, not silent []).
|
|
29
|
+
* - No new orchestration math — only sequences ops from `sagas`, `orchestrate`,
|
|
30
|
+
* and `lifecycle` modules.
|
|
31
|
+
* - CORE-FIRST: all logic here in `packages/core/src/go/`; CLI is a thin dispatch.
|
|
32
|
+
*
|
|
33
|
+
* @module @cleocode/core/go
|
|
34
|
+
*
|
|
35
|
+
* @task T11494 — E2-CLEO-GO
|
|
36
|
+
* @saga T11492 — SG-AUTOPILOT
|
|
37
|
+
*/
|
|
38
|
+
import type { TaskViewPipelineStage } from '@cleocode/contracts';
|
|
39
|
+
import { type EngineResult } from '../engine-result.js';
|
|
40
|
+
/**
|
|
41
|
+
* Input parameters for {@link cleoGo}.
|
|
42
|
+
*
|
|
43
|
+
* @task T11494
|
|
44
|
+
*/
|
|
45
|
+
export interface CleoGoParams {
|
|
46
|
+
/**
|
|
47
|
+
* Optional saga ID to scope the autopilot run. When omitted, `sagaNext`
|
|
48
|
+
* auto-selects the highest-priority non-terminal Saga in canonical order.
|
|
49
|
+
*/
|
|
50
|
+
sagaId?: string;
|
|
51
|
+
/**
|
|
52
|
+
* When true, suppress any interactive output suitable for daemon / unattended
|
|
53
|
+
* runs. The result shape is identical; only side-channel logging is affected.
|
|
54
|
+
*/
|
|
55
|
+
headless?: boolean;
|
|
56
|
+
/** Override project root (useful in tests). */
|
|
57
|
+
projectRoot?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Discriminated union of the four action outcomes `cleoGo` can produce.
|
|
61
|
+
*
|
|
62
|
+
* Consumers pattern-match on `action` to route further processing.
|
|
63
|
+
*
|
|
64
|
+
* @task T11494
|
|
65
|
+
*/
|
|
66
|
+
export type CleoGoAction = {
|
|
67
|
+
/** No children + research stage — the epic needs decomposition before IVTR. */
|
|
68
|
+
action: 'needsDecomposition';
|
|
69
|
+
sagaId: string;
|
|
70
|
+
/** The AC-only epic that needs task children added. */
|
|
71
|
+
epicId: string;
|
|
72
|
+
/** Current pipelineStage (always `'research'` for AC-only epics). */
|
|
73
|
+
currentStage: TaskViewPipelineStage;
|
|
74
|
+
} | {
|
|
75
|
+
/** Pre-implementation stage — lifecycle must hop before IVTR is valid. */
|
|
76
|
+
action: 'lifecycleHop';
|
|
77
|
+
sagaId: string;
|
|
78
|
+
epicId: string;
|
|
79
|
+
currentStage: TaskViewPipelineStage;
|
|
80
|
+
/** All ready-frontier task IDs (may be empty while lifecycle hops). */
|
|
81
|
+
readyFrontier: string[];
|
|
82
|
+
} | {
|
|
83
|
+
/** Fan-out: IVTR started for each task on the ready frontier. */
|
|
84
|
+
action: 'ivtrFanOut';
|
|
85
|
+
sagaId: string;
|
|
86
|
+
epicId: string;
|
|
87
|
+
currentStage: TaskViewPipelineStage;
|
|
88
|
+
/** Task IDs for which IVTR was initiated (non-empty). */
|
|
89
|
+
tasks: string[];
|
|
90
|
+
} | {
|
|
91
|
+
/** No non-terminal sagas remain — the workgraph is complete. */
|
|
92
|
+
action: 'complete';
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Result payload for {@link cleoGo}.
|
|
96
|
+
*
|
|
97
|
+
* @task T11494
|
|
98
|
+
* @task T11496 E4-GOAL-LOOP
|
|
99
|
+
*/
|
|
100
|
+
export interface CleoGoResult {
|
|
101
|
+
/** The action taken by the driver in this turn. */
|
|
102
|
+
outcome: CleoGoAction;
|
|
103
|
+
/**
|
|
104
|
+
* Structured diagnostics for display / logging. Always present; may be empty.
|
|
105
|
+
*/
|
|
106
|
+
diagnostics: string[];
|
|
107
|
+
/**
|
|
108
|
+
* The id of the goal that was armed (or reused) for the Stop-hook loop.
|
|
109
|
+
*
|
|
110
|
+
* `null` when no saga was selected (workgraph `complete` action) — there is
|
|
111
|
+
* nothing to arm when the workgraph is already done.
|
|
112
|
+
*
|
|
113
|
+
* @task T11496
|
|
114
|
+
*/
|
|
115
|
+
armedGoalId: string | null;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Run one turn of the `cleo go` autopilot pipeline.
|
|
119
|
+
*
|
|
120
|
+
* Returns a single LAFS-compatible {@link EngineResult} wrapping a
|
|
121
|
+
* {@link CleoGoResult}. Each call is stateless (side effects — IVTR writes,
|
|
122
|
+
* lifecycle progression — happen inside the called engines); the driver itself
|
|
123
|
+
* carries no mutable state.
|
|
124
|
+
*
|
|
125
|
+
* @param params - Input parameters controlling the saga scope and mode.
|
|
126
|
+
* @returns EngineResult with {@link CleoGoResult}.
|
|
127
|
+
*
|
|
128
|
+
* @task T11494
|
|
129
|
+
* @saga T11492
|
|
130
|
+
*/
|
|
131
|
+
export declare function cleoGo(params?: CleoGoParams): Promise<EngineResult<CleoGoResult>>;
|
|
132
|
+
//# sourceMappingURL=driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/go/driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,KAAK,YAAY,EAA8B,MAAM,qBAAqB,CAAC;AAWpF;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GACpB;IACE,+EAA+E;IAC/E,MAAM,EAAE,oBAAoB,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,YAAY,EAAE,qBAAqB,CAAC;CACrC,GACD;IACE,0EAA0E;IAC1E,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,qBAAqB,CAAC;IACpC,uEAAuE;IACvE,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB,GACD;IACE,iEAAiE;IACjE,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,qBAAqB,CAAC;IACpC,yDAAyD;IACzD,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,GACD;IACE,gEAAgE;IAChE,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAEN;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,mDAAmD;IACnD,OAAO,EAAE,YAAY,CAAC;IACtB;;OAEG;IACH,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB;;;;;;;OAOG;IACH,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAuBD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,MAAM,CAAC,MAAM,GAAE,YAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CA0I3F"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cleo go` autopilot driver — the thin orchestration sequencer.
|
|
3
|
+
*
|
|
4
|
+
* This is the canonical entry point for `cleo go` (SG-AUTOPILOT / T11492).
|
|
5
|
+
* It is PURE GLUE: it sequences existing core engines without adding new
|
|
6
|
+
* orchestration math.
|
|
7
|
+
*
|
|
8
|
+
* ## Pipeline (AC1)
|
|
9
|
+
*
|
|
10
|
+
* ```
|
|
11
|
+
* briefing (optional context anchor)
|
|
12
|
+
* → sagaNext() — pick highest-priority non-terminal saga
|
|
13
|
+
* → orchestrateReady(sagaId) — fetch readyFrontier
|
|
14
|
+
* → branch on pipelineStage of the active epic:
|
|
15
|
+
* AC-only (no children, research stage)
|
|
16
|
+
* → { action: 'needsDecomposition', sagaId, epicId }
|
|
17
|
+
* research | specification | decomposition
|
|
18
|
+
* → { action: 'lifecycleHop', sagaId, epicId, currentStage }
|
|
19
|
+
* implementation | validation | testing | release | contribution
|
|
20
|
+
* → fan-out startIvtr over readyFrontier tasks
|
|
21
|
+
* → { action: 'ivtrFanOut', sagaId, epicId, tasks: string[] }
|
|
22
|
+
* → return ONE LAFS-compatible EngineResult envelope
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* ## Design constraints
|
|
26
|
+
*
|
|
27
|
+
* - AC2: ONE LAFS envelope per call — all branching produces a single return.
|
|
28
|
+
* - AC3: empty ready-set + zero children → `needsDecomposition` (typed, not silent []).
|
|
29
|
+
* - No new orchestration math — only sequences ops from `sagas`, `orchestrate`,
|
|
30
|
+
* and `lifecycle` modules.
|
|
31
|
+
* - CORE-FIRST: all logic here in `packages/core/src/go/`; CLI is a thin dispatch.
|
|
32
|
+
*
|
|
33
|
+
* @module @cleocode/core/go
|
|
34
|
+
*
|
|
35
|
+
* @task T11494 — E2-CLEO-GO
|
|
36
|
+
* @saga T11492 — SG-AUTOPILOT
|
|
37
|
+
*/
|
|
38
|
+
import { engineError, engineSuccess } from '../engine-result.js';
|
|
39
|
+
import { armGoalLoop } from '../goal/arm.js';
|
|
40
|
+
import { startIvtr } from '../lifecycle/ivtr-loop.js';
|
|
41
|
+
import { orchestrateReady } from '../orchestrate/query-ops.js';
|
|
42
|
+
import { getProjectRoot } from '../paths.js';
|
|
43
|
+
import { sagaNext } from '../sagas/next.js';
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Pre-implementation stage set
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
/**
|
|
48
|
+
* Pipeline stages that require a lifecycle hop before spawning IVTR workers.
|
|
49
|
+
*
|
|
50
|
+
* Tasks whose parent epic is still in one of these stages are not yet
|
|
51
|
+
* implementation-ready; the driver signals `lifecycleHop` instead of fanning
|
|
52
|
+
* out IVTR.
|
|
53
|
+
*/
|
|
54
|
+
const PRE_IMPLEMENTATION_STAGES = new Set([
|
|
55
|
+
'research',
|
|
56
|
+
'specification',
|
|
57
|
+
'decomposition',
|
|
58
|
+
]);
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// Public API
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
/**
|
|
63
|
+
* Run one turn of the `cleo go` autopilot pipeline.
|
|
64
|
+
*
|
|
65
|
+
* Returns a single LAFS-compatible {@link EngineResult} wrapping a
|
|
66
|
+
* {@link CleoGoResult}. Each call is stateless (side effects — IVTR writes,
|
|
67
|
+
* lifecycle progression — happen inside the called engines); the driver itself
|
|
68
|
+
* carries no mutable state.
|
|
69
|
+
*
|
|
70
|
+
* @param params - Input parameters controlling the saga scope and mode.
|
|
71
|
+
* @returns EngineResult with {@link CleoGoResult}.
|
|
72
|
+
*
|
|
73
|
+
* @task T11494
|
|
74
|
+
* @saga T11492
|
|
75
|
+
*/
|
|
76
|
+
export async function cleoGo(params = {}) {
|
|
77
|
+
const root = getProjectRoot(params.projectRoot);
|
|
78
|
+
const diagnostics = [];
|
|
79
|
+
// 1. sagaNext — pick the next actionable saga (or the explicit one).
|
|
80
|
+
const nextResult = await sagaNext(root, { sagaId: params.sagaId });
|
|
81
|
+
if (!nextResult.success) {
|
|
82
|
+
return engineError(nextResult.error?.code ?? 'E_GENERAL', nextResult.error?.message ?? 'sagaNext failed');
|
|
83
|
+
}
|
|
84
|
+
const next = nextResult.data;
|
|
85
|
+
// 2. Workgraph complete guard: no active sagas.
|
|
86
|
+
if (!next.sagaId) {
|
|
87
|
+
return engineSuccess({
|
|
88
|
+
outcome: { action: 'complete' },
|
|
89
|
+
diagnostics: ['No non-terminal sagas remain — workgraph is complete.'],
|
|
90
|
+
armedGoalId: null,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
const sagaId = next.sagaId;
|
|
94
|
+
diagnostics.push(`active saga: ${sagaId}${next.sagaTitle ? ` (${next.sagaTitle})` : ''} — ${next.completionPct ?? 0}% complete`);
|
|
95
|
+
// 2b. Arm the goal loop (AC3 of T11496): create/reuse a per-saga goal that
|
|
96
|
+
// the Stop-hook advances each turn to self-renudge until satisfied.
|
|
97
|
+
// Best-effort: failure is non-fatal (diagnostics only).
|
|
98
|
+
let armedGoalId = null;
|
|
99
|
+
try {
|
|
100
|
+
const armedGoal = await armGoalLoop({
|
|
101
|
+
sagaId,
|
|
102
|
+
sagaTitle: next.sagaTitle,
|
|
103
|
+
cwd: root,
|
|
104
|
+
});
|
|
105
|
+
armedGoalId = armedGoal.id;
|
|
106
|
+
diagnostics.push(`goal loop armed: ${armedGoalId}`);
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
diagnostics.push(`goal loop arm failed (non-fatal): ${err.message}`);
|
|
110
|
+
}
|
|
111
|
+
// 3. orchestrateReady — get the ready frontier for the saga.
|
|
112
|
+
const readyResult = await orchestrateReady(sagaId, root);
|
|
113
|
+
if (!readyResult.success) {
|
|
114
|
+
return engineError(readyResult.error?.code ?? 'E_GENERAL', `orchestrateReady failed for saga ${sagaId}: ${readyResult.error?.message ?? 'unknown'}`);
|
|
115
|
+
}
|
|
116
|
+
const readyData = readyResult.data;
|
|
117
|
+
const readyTasks = readyData.readyTasks ?? [];
|
|
118
|
+
const readyFrontier = readyTasks.map((t) => t.id);
|
|
119
|
+
// 4. Identify the "active epic" — the first ready task's parent, or the first
|
|
120
|
+
// saga member if the frontier is empty.
|
|
121
|
+
//
|
|
122
|
+
// We need the epicId to read its pipelineStage and decide the branch action.
|
|
123
|
+
const epicId = readyTasks[0]?.parentId ?? next.memberEpics?.[0]?.id ?? sagaId;
|
|
124
|
+
const rawStage = readyTasks[0]?.pipelineStage ??
|
|
125
|
+
next.memberEpics?.[0]?.status ?? // fallback: treat member epic status as a proxy
|
|
126
|
+
'research';
|
|
127
|
+
// Normalise to a valid TaskViewPipelineStage, defaulting to 'research'.
|
|
128
|
+
const currentStage = rawStage ?? 'research';
|
|
129
|
+
// 5. AC-only detection: empty ready frontier + no descendant tasks under the
|
|
130
|
+
// active epic signals that the epic has acceptance criteria only and needs
|
|
131
|
+
// to be decomposed into subtasks (AC3 — fixes the silent [] dead-end).
|
|
132
|
+
const totalDescendants = next.memberEpics?.find((e) => e.id === epicId)?.descendantTaskCount ?? 0;
|
|
133
|
+
if (readyFrontier.length === 0 && totalDescendants === 0) {
|
|
134
|
+
diagnostics.push(`epic ${epicId} has no children and no ready tasks — needs decomposition`);
|
|
135
|
+
return engineSuccess({
|
|
136
|
+
outcome: {
|
|
137
|
+
action: 'needsDecomposition',
|
|
138
|
+
sagaId,
|
|
139
|
+
epicId,
|
|
140
|
+
currentStage,
|
|
141
|
+
},
|
|
142
|
+
diagnostics,
|
|
143
|
+
armedGoalId,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
// 6. Pre-implementation stage check → lifecycle hop signal.
|
|
147
|
+
if (PRE_IMPLEMENTATION_STAGES.has(currentStage)) {
|
|
148
|
+
diagnostics.push(`epic ${epicId} is at stage '${currentStage}' — lifecycle hop required before IVTR`);
|
|
149
|
+
return engineSuccess({
|
|
150
|
+
outcome: {
|
|
151
|
+
action: 'lifecycleHop',
|
|
152
|
+
sagaId,
|
|
153
|
+
epicId,
|
|
154
|
+
currentStage,
|
|
155
|
+
readyFrontier,
|
|
156
|
+
},
|
|
157
|
+
diagnostics,
|
|
158
|
+
armedGoalId,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
// 7. Implementation+ → fan-out IVTR over the ready frontier.
|
|
162
|
+
const ivtrStarted = [];
|
|
163
|
+
for (const taskId of readyFrontier) {
|
|
164
|
+
try {
|
|
165
|
+
await startIvtr(taskId, { cwd: root });
|
|
166
|
+
ivtrStarted.push(taskId);
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
diagnostics.push(`IVTR start failed for ${taskId}: ${err.message}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (ivtrStarted.length === 0 && readyFrontier.length > 0) {
|
|
173
|
+
// All IVTR starts failed — surface the errors but return gracefully.
|
|
174
|
+
diagnostics.push(`All ${readyFrontier.length} IVTR starts failed — see diagnostics`);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
diagnostics.push(`IVTR started for ${ivtrStarted.length} task(s): ${ivtrStarted.join(', ')}`);
|
|
178
|
+
}
|
|
179
|
+
return engineSuccess({
|
|
180
|
+
outcome: {
|
|
181
|
+
action: 'ivtrFanOut',
|
|
182
|
+
sagaId,
|
|
183
|
+
epicId,
|
|
184
|
+
currentStage,
|
|
185
|
+
tasks: ivtrStarted,
|
|
186
|
+
},
|
|
187
|
+
diagnostics,
|
|
188
|
+
armedGoalId,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../../src/go/driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cleo go` autopilot driver — public barrel.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the {@link cleoGo} orchestration sequencer and its result types.
|
|
5
|
+
* Consumed by the thin CLI handler in `packages/cleo/src/cli/commands/go.ts`.
|
|
6
|
+
*
|
|
7
|
+
* @module @cleocode/core/go
|
|
8
|
+
*
|
|
9
|
+
* @task T11494 — E2-CLEO-GO
|
|
10
|
+
* @saga T11492 — SG-AUTOPILOT
|
|
11
|
+
*/
|
|
12
|
+
export { type CleoGoAction, type CleoGoParams, type CleoGoResult, cleoGo, } from './driver.js';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/go/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,MAAM,GACP,MAAM,aAAa,CAAC"}
|
package/dist/go/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cleo go` autopilot driver — public barrel.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the {@link cleoGo} orchestration sequencer and its result types.
|
|
5
|
+
* Consumed by the thin CLI handler in `packages/cleo/src/cli/commands/go.ts`.
|
|
6
|
+
*
|
|
7
|
+
* @module @cleocode/core/go
|
|
8
|
+
*
|
|
9
|
+
* @task T11494 — E2-CLEO-GO
|
|
10
|
+
* @saga T11492 — SG-AUTOPILOT
|
|
11
|
+
*/
|
|
12
|
+
export { cleoGo, } from './driver.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/go/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAIL,MAAM,GACP,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Goal advance-with-persist — load → advance → persist → continuation.
|
|
3
|
+
*
|
|
4
|
+
* This is the ORCHESTRATED entry point called by `cleo goal advance <goalId>`
|
|
5
|
+
* (CLI) and by the Claude Code Stop-hook. It wraps the PURE
|
|
6
|
+
* {@link advanceGoal} (no I/O) with the persistence and continuation steps
|
|
7
|
+
* that complete the AC loop:
|
|
8
|
+
*
|
|
9
|
+
* ```
|
|
10
|
+
* getGoalById(id)
|
|
11
|
+
* → advanceGoal(goal, judgeGoal-closure) [pure, no I/O]
|
|
12
|
+
* → updateGoal(id, { status, turnsUsed, lastVerdict })
|
|
13
|
+
* → buildContinuation(updatedGoal, verdict) [null when terminal]
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* The injected `llmJudge` is only called for `fuzzy` goals — task-completion
|
|
17
|
+
* goals use the ADR-051 evidence path (pure, offline). Tests pass
|
|
18
|
+
* {@link StaticGoalJudge} to stay fully hermetic.
|
|
19
|
+
*
|
|
20
|
+
* ## Return shape
|
|
21
|
+
*
|
|
22
|
+
* The returned {@link AdvanceWithPersistResult} always carries the
|
|
23
|
+
* `advanceResult` (verdict, nextStatus, turnsRemaining), the fully-updated
|
|
24
|
+
* `goal` record (after the persistence write), and — critically — the
|
|
25
|
+
* `continuation` nudge ({@link GoalContinuation}) or `null` when the goal
|
|
26
|
+
* has reached a terminal state. The CLI formats this as a LAFS envelope; the
|
|
27
|
+
* Stop-hook uses `continuation` to decide whether to emit a block decision.
|
|
28
|
+
*
|
|
29
|
+
* @module @cleocode/core/goal/advance-with-persist
|
|
30
|
+
*
|
|
31
|
+
* @epic T11290 EP-CLEO-GOAL-SYSTEM
|
|
32
|
+
* @task T11496 E4-GOAL-LOOP
|
|
33
|
+
* @saga T11283 SG-COGNITIVE-SUBSTRATE
|
|
34
|
+
*/
|
|
35
|
+
import type { GoalAdvanceResult, GoalContinuation, GoalJudge, GoalRecord } from '@cleocode/contracts';
|
|
36
|
+
/**
|
|
37
|
+
* The combined result of one orchestrated advance turn.
|
|
38
|
+
*
|
|
39
|
+
* @task T11496
|
|
40
|
+
*/
|
|
41
|
+
export interface AdvanceWithPersistResult {
|
|
42
|
+
/**
|
|
43
|
+
* The raw advance result from the pure `advanceGoal` engine (verdict,
|
|
44
|
+
* nextStatus, turnsRemaining). This is what is persisted.
|
|
45
|
+
*/
|
|
46
|
+
readonly advanceResult: GoalAdvanceResult;
|
|
47
|
+
/**
|
|
48
|
+
* The goal record AFTER the persistence write. Status and verdict are
|
|
49
|
+
* already updated — callers render this, not the pre-advance snapshot.
|
|
50
|
+
*/
|
|
51
|
+
readonly goal: GoalRecord;
|
|
52
|
+
/**
|
|
53
|
+
* The continuation nudge, or `null` when the goal is terminal.
|
|
54
|
+
*
|
|
55
|
+
* Non-null for `active` and `paused` goals — the Stop-hook emits this as a
|
|
56
|
+
* `{ decision: 'block', reason: continuation.content }` response to keep
|
|
57
|
+
* Claude working. Null for `satisfied`, `abandoned`, `impossible`.
|
|
58
|
+
*/
|
|
59
|
+
readonly continuation: GoalContinuation | null;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Advance a goal one turn and persist the result.
|
|
63
|
+
*
|
|
64
|
+
* Orchestrates the full load → advance (pure) → persist → continuation
|
|
65
|
+
* pipeline in one call. Returns `null` when the goal id is not found.
|
|
66
|
+
*
|
|
67
|
+
* @param goalId - The goal to advance (idempotency key / primary key).
|
|
68
|
+
* @param options - Optional overrides.
|
|
69
|
+
* @param options.llmJudge - LLM judge for fuzzy goals (default: offline stub).
|
|
70
|
+
* @param options.cwd - Project root override.
|
|
71
|
+
* @returns The combined result, or `null` when the goal is absent.
|
|
72
|
+
*
|
|
73
|
+
* @task T11496
|
|
74
|
+
* @adr ADR-051
|
|
75
|
+
*/
|
|
76
|
+
export declare function advanceGoalWithPersist(goalId: string, options?: {
|
|
77
|
+
readonly llmJudge?: GoalJudge;
|
|
78
|
+
readonly cwd?: string;
|
|
79
|
+
}): Promise<AdvanceWithPersistResult | null>;
|
|
80
|
+
//# sourceMappingURL=advance-with-persist.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advance-with-persist.d.ts","sourceRoot":"","sources":["../../src/goal/advance-with-persist.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,EACT,UAAU,EACX,MAAM,qBAAqB,CAAC;AA8B7B;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,iBAAiB,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAChD;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IACP,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CAClB,GACL,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CA4C1C"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Goal advance-with-persist — load → advance → persist → continuation.
|
|
3
|
+
*
|
|
4
|
+
* This is the ORCHESTRATED entry point called by `cleo goal advance <goalId>`
|
|
5
|
+
* (CLI) and by the Claude Code Stop-hook. It wraps the PURE
|
|
6
|
+
* {@link advanceGoal} (no I/O) with the persistence and continuation steps
|
|
7
|
+
* that complete the AC loop:
|
|
8
|
+
*
|
|
9
|
+
* ```
|
|
10
|
+
* getGoalById(id)
|
|
11
|
+
* → advanceGoal(goal, judgeGoal-closure) [pure, no I/O]
|
|
12
|
+
* → updateGoal(id, { status, turnsUsed, lastVerdict })
|
|
13
|
+
* → buildContinuation(updatedGoal, verdict) [null when terminal]
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* The injected `llmJudge` is only called for `fuzzy` goals — task-completion
|
|
17
|
+
* goals use the ADR-051 evidence path (pure, offline). Tests pass
|
|
18
|
+
* {@link StaticGoalJudge} to stay fully hermetic.
|
|
19
|
+
*
|
|
20
|
+
* ## Return shape
|
|
21
|
+
*
|
|
22
|
+
* The returned {@link AdvanceWithPersistResult} always carries the
|
|
23
|
+
* `advanceResult` (verdict, nextStatus, turnsRemaining), the fully-updated
|
|
24
|
+
* `goal` record (after the persistence write), and — critically — the
|
|
25
|
+
* `continuation` nudge ({@link GoalContinuation}) or `null` when the goal
|
|
26
|
+
* has reached a terminal state. The CLI formats this as a LAFS envelope; the
|
|
27
|
+
* Stop-hook uses `continuation` to decide whether to emit a block decision.
|
|
28
|
+
*
|
|
29
|
+
* @module @cleocode/core/goal/advance-with-persist
|
|
30
|
+
*
|
|
31
|
+
* @epic T11290 EP-CLEO-GOAL-SYSTEM
|
|
32
|
+
* @task T11496 E4-GOAL-LOOP
|
|
33
|
+
* @saga T11283 SG-COGNITIVE-SUBSTRATE
|
|
34
|
+
*/
|
|
35
|
+
import { buildContinuation } from './continuation.js';
|
|
36
|
+
import { judgeGoal, StaticGoalJudge } from './judge.js';
|
|
37
|
+
import { advanceGoal } from './loop.js';
|
|
38
|
+
import { getGoalById, updateGoal } from './store.js';
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Default offline-safe LLM judge
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
/**
|
|
43
|
+
* The fallback judge used when no real LLM judge is provided.
|
|
44
|
+
*
|
|
45
|
+
* Always returns a non-satisfied, non-impossible verdict so the loop
|
|
46
|
+
* continues (safe default). In production the caller should inject a
|
|
47
|
+
* real LLM-backed {@link GoalJudge} for fuzzy goals.
|
|
48
|
+
*
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
51
|
+
const DEFAULT_FALLBACK_JUDGE = new StaticGoalJudge({
|
|
52
|
+
ok: false,
|
|
53
|
+
impossible: false,
|
|
54
|
+
reason: 'No LLM judge provided — fuzzy goal keeps running until explicitly resolved or budget exhausted.',
|
|
55
|
+
});
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Public API
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
/**
|
|
60
|
+
* Advance a goal one turn and persist the result.
|
|
61
|
+
*
|
|
62
|
+
* Orchestrates the full load → advance (pure) → persist → continuation
|
|
63
|
+
* pipeline in one call. Returns `null` when the goal id is not found.
|
|
64
|
+
*
|
|
65
|
+
* @param goalId - The goal to advance (idempotency key / primary key).
|
|
66
|
+
* @param options - Optional overrides.
|
|
67
|
+
* @param options.llmJudge - LLM judge for fuzzy goals (default: offline stub).
|
|
68
|
+
* @param options.cwd - Project root override.
|
|
69
|
+
* @returns The combined result, or `null` when the goal is absent.
|
|
70
|
+
*
|
|
71
|
+
* @task T11496
|
|
72
|
+
* @adr ADR-051
|
|
73
|
+
*/
|
|
74
|
+
export async function advanceGoalWithPersist(goalId, options = {}) {
|
|
75
|
+
const { llmJudge = DEFAULT_FALLBACK_JUDGE, cwd } = options;
|
|
76
|
+
// 1. Load the current goal record.
|
|
77
|
+
const goal = await getGoalById(goalId, cwd);
|
|
78
|
+
if (!goal) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
// 2. Build the injected judge closure over `judgeGoal` (the evidence-gate-
|
|
82
|
+
// aware judge from judge.ts). This is what the AC says: "calling EXISTING
|
|
83
|
+
// advanceGoal(goal, judgeGoal-closure)".
|
|
84
|
+
const judgeFn = (g) => judgeGoal(g, llmJudge, cwd);
|
|
85
|
+
// 3. Advance one turn (pure — no I/O, no side effects).
|
|
86
|
+
const advanceResult = await advanceGoal(goal, judgeFn);
|
|
87
|
+
// 4. Persist the updated status + turnsUsed + lastVerdict.
|
|
88
|
+
const turnsConsumed = goal.turnsUsed + (goal.turnBudget - goal.turnsUsed - advanceResult.turnsRemaining);
|
|
89
|
+
const updated = await updateGoal(goalId, {
|
|
90
|
+
status: advanceResult.nextStatus,
|
|
91
|
+
turnsUsed: Math.max(goal.turnsUsed, goal.turnBudget - advanceResult.turnsRemaining),
|
|
92
|
+
lastVerdict: advanceResult.verdict,
|
|
93
|
+
// Clear pausedReason when we successfully advanced (non-paused result).
|
|
94
|
+
...(advanceResult.nextStatus !== 'paused' ? { pausedReason: null } : {}),
|
|
95
|
+
}, cwd);
|
|
96
|
+
// `updated` can only be null if the row disappeared between load and update
|
|
97
|
+
// (extremely unlikely — treat as present with the pre-update snapshot).
|
|
98
|
+
const persisted = updated ?? { ...goal, status: advanceResult.nextStatus };
|
|
99
|
+
// Suppress unused variable warning.
|
|
100
|
+
void turnsConsumed;
|
|
101
|
+
// 5. Build the continuation nudge for the updated goal + latest verdict.
|
|
102
|
+
const continuation = buildContinuation(persisted, advanceResult.verdict);
|
|
103
|
+
return { advanceResult, goal: persisted, continuation };
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=advance-with-persist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advance-with-persist.js","sourceRoot":"","sources":["../../src/goal/advance-with-persist.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAQH,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAErD,8EAA8E;AAC9E,iCAAiC;AACjC,8EAA8E;AAE9E;;;;;;;;GAQG;AACH,MAAM,sBAAsB,GAAc,IAAI,eAAe,CAAC;IAC5D,EAAE,EAAE,KAAK;IACT,UAAU,EAAE,KAAK;IACjB,MAAM,EACJ,iGAAiG;CACpG,CAAC,CAAC;AAgCH,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,MAAc,EACd,UAGI,EAAE;IAEN,MAAM,EAAE,QAAQ,GAAG,sBAAsB,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IAE3D,mCAAmC;IACnC,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,IAAI,CAAC;IACd,CAAC;IAED,2EAA2E;IAC3E,6EAA6E;IAC7E,4CAA4C;IAC5C,MAAM,OAAO,GAAG,CAAC,CAAa,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;IAE/D,wDAAwD;IACxD,MAAM,aAAa,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAEvD,2DAA2D;IAC3D,MAAM,aAAa,GACjB,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,SAAS,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;IAErF,MAAM,OAAO,GAAG,MAAM,UAAU,CAC9B,MAAM,EACN;QACE,MAAM,EAAE,aAAa,CAAC,UAAU;QAChC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,GAAG,aAAa,CAAC,cAAc,CAAC;QACnF,WAAW,EAAE,aAAa,CAAC,OAAO;QAClC,wEAAwE;QACxE,GAAG,CAAC,aAAa,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzE,EACD,GAAG,CACJ,CAAC;IAEF,4EAA4E;IAC5E,wEAAwE;IACxE,MAAM,SAAS,GAAG,OAAO,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,UAAU,EAAE,CAAC;IAE3E,oCAAoC;IACpC,KAAK,aAAa,CAAC;IAEnB,yEAAyE;IACzE,MAAM,YAAY,GAAG,iBAAiB,CAAC,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAEzE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;AAC1D,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Goal-loop arming — create + register the per-saga goal that `cleo go`
|
|
3
|
+
* uses to drive the Stop-hook self-renudge cycle (AC3 of T11496).
|
|
4
|
+
*
|
|
5
|
+
* `armGoalLoop` is called by `cleoGo()` after it has selected the active saga.
|
|
6
|
+
* It creates (or reuses via idempotency key) a `fuzzy` goal whose intent
|
|
7
|
+
* describes the saga work. The Stop-hook then advances this goal each turn,
|
|
8
|
+
* re-injecting the continuation nudge until `judgeGoal` signals
|
|
9
|
+
* `satisfied` or `impossible`.
|
|
10
|
+
*
|
|
11
|
+
* ## Idempotency
|
|
12
|
+
*
|
|
13
|
+
* The idempotency key is `cleo-go:${sagaId}:${epochDay}`, ensuring one goal
|
|
14
|
+
* per saga per calendar day. Re-runs of `cleo go` on the same day reuse the
|
|
15
|
+
* existing goal (via `onConflictDoNothing` in the store) rather than
|
|
16
|
+
* accumulating rows.
|
|
17
|
+
*
|
|
18
|
+
* ## Why fuzzy?
|
|
19
|
+
*
|
|
20
|
+
* Saga completion is orchestration-level progress — not a single task with
|
|
21
|
+
* ADR-051 evidence gates. A `fuzzy` goal lets the loop keep nudging Claude
|
|
22
|
+
* until the saga rollup shows the desired state; the injected nudge text
|
|
23
|
+
* (from `buildContinuation`) reminds Claude of the intent each turn.
|
|
24
|
+
*
|
|
25
|
+
* @module @cleocode/core/goal/arm
|
|
26
|
+
*
|
|
27
|
+
* @task T11496 E4-GOAL-LOOP
|
|
28
|
+
* @epic T11492 SG-AUTOPILOT
|
|
29
|
+
* @saga T11283 SG-COGNITIVE-SUBSTRATE
|
|
30
|
+
*/
|
|
31
|
+
import type { GoalRecord } from '@cleocode/contracts';
|
|
32
|
+
/**
|
|
33
|
+
* Parameters for {@link armGoalLoop}.
|
|
34
|
+
*
|
|
35
|
+
* @task T11496
|
|
36
|
+
*/
|
|
37
|
+
export interface ArmGoalLoopParams {
|
|
38
|
+
/** The saga being worked on (e.g. `'T11492'`). */
|
|
39
|
+
readonly sagaId: string;
|
|
40
|
+
/** Human-readable saga title for the goal intent. */
|
|
41
|
+
readonly sagaTitle?: string;
|
|
42
|
+
/** Override project root (useful in tests). */
|
|
43
|
+
readonly cwd?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Turn budget for the goal (default: {@link SAGA_GOAL_TURN_BUDGET}).
|
|
46
|
+
*/
|
|
47
|
+
readonly turnBudget?: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create (or reuse) the per-saga goal that arms the Stop-hook self-renudge
|
|
51
|
+
* loop for `cleo go`.
|
|
52
|
+
*
|
|
53
|
+
* Idempotent on `(sagaId, calendarDay)` — safe to call every `cleo go` turn.
|
|
54
|
+
*
|
|
55
|
+
* @param params - Arming parameters.
|
|
56
|
+
* @returns The created (or pre-existing) {@link GoalRecord}.
|
|
57
|
+
*
|
|
58
|
+
* @task T11496
|
|
59
|
+
*/
|
|
60
|
+
export declare function armGoalLoop(params: ArmGoalLoopParams): Promise<GoalRecord>;
|
|
61
|
+
//# sourceMappingURL=arm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arm.d.ts","sourceRoot":"","sources":["../../src/goal/arm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAMtD;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,qDAAqD;IACrD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,+CAA+C;IAC/C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CA2BhF"}
|