zelari-code 1.25.0 → 1.27.0
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/README.md +3 -3
- package/dist/cli/app.js +5 -3
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/buildPolicy.js +1 -1
- package/dist/cli/buildPolicy.js.map +1 -1
- package/dist/cli/companion/runManager.js +2 -2
- package/dist/cli/companion/runManager.js.map +1 -1
- package/dist/cli/companion/serve.js +1 -1
- package/dist/cli/companion/serve.js.map +1 -1
- package/dist/cli/components/StatusBar.js +10 -2
- package/dist/cli/components/StatusBar.js.map +1 -1
- package/dist/cli/headless.js +17 -6
- package/dist/cli/headless.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js +16 -12
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/hooks/useSlashDispatch.js +14 -1
- package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
- package/dist/cli/kraken/executor.js +420 -0
- package/dist/cli/kraken/executor.js.map +1 -0
- package/dist/cli/kraken/graphStatus.js +114 -0
- package/dist/cli/kraken/graphStatus.js.map +1 -0
- package/dist/cli/kraken/planner.js +447 -0
- package/dist/cli/kraken/planner.js.map +1 -0
- package/dist/cli/kraken/tentacle.js +13 -0
- package/dist/cli/kraken/tentacle.js.map +1 -0
- package/dist/cli/main.bundled.js +10088 -8115
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +1 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/missionSlice.js +7 -6
- package/dist/cli/missionSlice.js.map +1 -1
- package/dist/cli/mode.js +21 -7
- package/dist/cli/mode.js.map +1 -1
- package/dist/cli/phase.js +1 -1
- package/dist/cli/runHeadless.js +105 -6
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/slashCommands.js +25 -6
- package/dist/cli/slashCommands.js.map +1 -1
- package/dist/cli/slashHandlers/krakenGraph.js +55 -0
- package/dist/cli/slashHandlers/krakenGraph.js.map +1 -0
- package/dist/cli/toolRegistry.js +49 -30
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/krakenLive.js +109 -0
- package/dist/cli/tools/krakenLive.js.map +1 -0
- package/dist/cli/tools/krakenModel.js +115 -0
- package/dist/cli/tools/krakenModel.js.map +1 -0
- package/dist/cli/tools/krakenRadio.js +95 -0
- package/dist/cli/tools/krakenRadio.js.map +1 -0
- package/dist/cli/tools/krakenWorktree.js +245 -0
- package/dist/cli/tools/krakenWorktree.js.map +1 -0
- package/dist/cli/tools/taskTool.js +315 -54
- package/dist/cli/tools/taskTool.js.map +1 -1
- package/dist/cli/workspace/composeContext.js +2 -2
- package/dist/cli/workspace/composeContext.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KrakenGraphExecutor — F3: drives a TaskGraph to convergence.
|
|
3
|
+
*
|
|
4
|
+
* Consumes the pure primitives from `@zelari/core` (getReadyNodes,
|
|
5
|
+
* selectParallelWave, isSettled/isConverged) and the F2 tentacle runner
|
|
6
|
+
* (`runTentacle`) to execute a validated `TaskGraph`:
|
|
7
|
+
* - repeatedly forms a parallel-safe "wave" of ready nodes (bounded by
|
|
8
|
+
* ZELARI_KRAKEN_MAX_PARALLEL) and runs it concurrently;
|
|
9
|
+
* - retries a failed node up to `node.maxRetries`, then spawns a `fix`
|
|
10
|
+
* node (bounded by a global fix budget) that inherits the failed
|
|
11
|
+
* node's deps/scope/acceptance; a node that still fails is left
|
|
12
|
+
* terminally `error` and does NOT abort independent branches — nodes
|
|
13
|
+
* that transitively depend on it are cascade-marked `skipped` so the
|
|
14
|
+
* graph can still settle;
|
|
15
|
+
* - merges worktree-isolated `general`/`fix` tentacles SEQUENTIALLY when
|
|
16
|
+
* a `merge` node's deps complete (Correction 4 — no concurrent merges
|
|
17
|
+
* into the same parent HEAD); on conflict the branch/worktree is kept
|
|
18
|
+
* and surfaced, never auto-resolved;
|
|
19
|
+
* - optionally gates final convergence on `run_backtest` (Level 3) when
|
|
20
|
+
* `.zelari/world/checks.json` exists and ZELARI_SCHEMA_LOOP != '0'.
|
|
21
|
+
*
|
|
22
|
+
* Also drives the F5 observability surface: the graph-level live tracker
|
|
23
|
+
* in `./graphStatus.js` (start/update/end around the scheduling loop, for
|
|
24
|
+
* the StatusBar "graph x/y · n↑" chip) alongside the `graph_*`/`node_*`
|
|
25
|
+
* radio events emitted throughout.
|
|
26
|
+
*
|
|
27
|
+
* Explicitly NOT this module's job (deferred to F6):
|
|
28
|
+
* - planning a graph from a prompt — that's `./planner.js` (F4); the
|
|
29
|
+
* executor only executes the graph it's given;
|
|
30
|
+
* - wiring into any slash command, headless flag, or `useChatTurn`.
|
|
31
|
+
*
|
|
32
|
+
* @since v0.10.x — Kraken graph engine (F3)
|
|
33
|
+
*/
|
|
34
|
+
import { getReadyNodes, isSettled, isConverged, failedNodeIds, countByStatus, selectParallelWave, } from '@zelari/core';
|
|
35
|
+
import { runTentacle, } from './tentacle.js';
|
|
36
|
+
import { mergeKrakenWorktree, } from '../tools/krakenWorktree.js';
|
|
37
|
+
import { appendKrakenRadio } from '../tools/krakenRadio.js';
|
|
38
|
+
import { runBacktest } from '../workspace/worldModel.js';
|
|
39
|
+
import { startKrakenGraphLive, updateKrakenGraphLive, endKrakenGraphLive, } from './graphStatus.js';
|
|
40
|
+
import { existsSync } from 'node:fs';
|
|
41
|
+
import path from 'node:path';
|
|
42
|
+
/** Default cap on concurrently-running tentacles across the whole graph. */
|
|
43
|
+
export const DEFAULT_MAX_PARALLEL = 12;
|
|
44
|
+
/** Default number of `fix` nodes the executor may spawn across one graph run. */
|
|
45
|
+
export const DEFAULT_FIX_BUDGET = 3;
|
|
46
|
+
export function resolveMaxParallel(env = process.env) {
|
|
47
|
+
const raw = env.ZELARI_KRAKEN_MAX_PARALLEL;
|
|
48
|
+
if (raw === undefined || raw === '')
|
|
49
|
+
return DEFAULT_MAX_PARALLEL;
|
|
50
|
+
const n = Number.parseInt(raw, 10);
|
|
51
|
+
return Number.isFinite(n) && n > 0 ? n : DEFAULT_MAX_PARALLEL;
|
|
52
|
+
}
|
|
53
|
+
export function resolveFixBudget(env = process.env) {
|
|
54
|
+
const raw = env.ZELARI_KRAKEN_FIX_BUDGET;
|
|
55
|
+
if (raw === undefined || raw === '')
|
|
56
|
+
return DEFAULT_FIX_BUDGET;
|
|
57
|
+
const n = Number.parseInt(raw, 10);
|
|
58
|
+
return Number.isFinite(n) && n >= 0 ? n : DEFAULT_FIX_BUDGET;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Default wall-clock bound per tentacle run (ms). The graph executor calls
|
|
62
|
+
* `runTentacle` directly, bypassing the `task` tool's own `timeoutMs: 300_000`
|
|
63
|
+
* enforcement (that only applies when a parent AgentHarness invokes `task`
|
|
64
|
+
* as a tool-call) — so without an executor-level bound, one stuck sub-agent
|
|
65
|
+
* (a hung bash command, a stalled fetch) hangs `execute()` forever, which
|
|
66
|
+
* hangs the whole headless process (main.ts only calls `process.exit()`
|
|
67
|
+
* after `runHeadless()`'s promise resolves), which leaves the Desktop app's
|
|
68
|
+
* "running" state stuck permanently. Matches the task tool's own budget.
|
|
69
|
+
*/
|
|
70
|
+
export const DEFAULT_NODE_TIMEOUT_MS = 300_000;
|
|
71
|
+
/** Set ZELARI_KRAKEN_NODE_TIMEOUT_MS=0 to disable (not recommended). */
|
|
72
|
+
export function resolveNodeTimeoutMs(env = process.env) {
|
|
73
|
+
const raw = env.ZELARI_KRAKEN_NODE_TIMEOUT_MS;
|
|
74
|
+
if (raw === undefined || raw === '')
|
|
75
|
+
return DEFAULT_NODE_TIMEOUT_MS;
|
|
76
|
+
const n = Number.parseInt(raw, 10);
|
|
77
|
+
return Number.isFinite(n) && n >= 0 ? n : DEFAULT_NODE_TIMEOUT_MS;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* F6 kill-switch: the `/kraken graph` slash command and `--kraken-graph`
|
|
81
|
+
* headless flag both check this before planning/executing anything. On by
|
|
82
|
+
* default, like every other Kraken env toggle (only the literal '0' turns
|
|
83
|
+
* it off — see ZELARI_SCHEMA_LOOP / ZELARI_MEMORY / ZELARI_BROWSER).
|
|
84
|
+
*/
|
|
85
|
+
export function isKrakenGraphEnabled(env = process.env) {
|
|
86
|
+
return env.ZELARI_KRAKEN_GRAPH !== '0';
|
|
87
|
+
}
|
|
88
|
+
/** Whether the optional Level-3 world-model convergence gate should run. */
|
|
89
|
+
export function isWorldModelGateEnabled(cwd, env = process.env, checksExists = defaultChecksExists) {
|
|
90
|
+
if ((env.ZELARI_SCHEMA_LOOP ?? '').trim() === '0')
|
|
91
|
+
return false;
|
|
92
|
+
return checksExists(cwd);
|
|
93
|
+
}
|
|
94
|
+
function defaultChecksExists(cwd) {
|
|
95
|
+
try {
|
|
96
|
+
return existsSync(path.join(cwd, '.zelari', 'world', 'checks.json'));
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export class KrakenGraphExecutor {
|
|
103
|
+
deps;
|
|
104
|
+
parentCwd;
|
|
105
|
+
sessionId;
|
|
106
|
+
maxParallel;
|
|
107
|
+
nodeTimeoutMs;
|
|
108
|
+
fixBudgetRemaining;
|
|
109
|
+
worldModelGateOverride;
|
|
110
|
+
runTentacleFn;
|
|
111
|
+
mergeFn;
|
|
112
|
+
backtestFn;
|
|
113
|
+
nodeRunState = new Map();
|
|
114
|
+
fixCounter = 0;
|
|
115
|
+
constructor(opts) {
|
|
116
|
+
this.deps = opts.taskToolDeps;
|
|
117
|
+
this.parentCwd = opts.parentCwd;
|
|
118
|
+
this.sessionId = opts.sessionId;
|
|
119
|
+
this.maxParallel = opts.maxParallel ?? resolveMaxParallel();
|
|
120
|
+
this.nodeTimeoutMs = opts.nodeTimeoutMs ?? resolveNodeTimeoutMs();
|
|
121
|
+
this.fixBudgetRemaining = opts.fixBudget ?? resolveFixBudget();
|
|
122
|
+
this.worldModelGateOverride = opts.worldModelGate;
|
|
123
|
+
this.runTentacleFn = opts.runTentacleFn ?? runTentacle;
|
|
124
|
+
this.mergeFn = opts.mergeFn ?? mergeKrakenWorktree;
|
|
125
|
+
this.backtestFn = opts.backtestFn ?? runBacktest;
|
|
126
|
+
}
|
|
127
|
+
/** Execute the graph in place (mutates node statuses) until it settles. */
|
|
128
|
+
async execute(graph) {
|
|
129
|
+
// Anti-explosion / self-inflicted-hang guard: cap total loop iterations
|
|
130
|
+
// at a generous multiple of the node count instead of trusting the
|
|
131
|
+
// graph to always shrink monotonically (fix-node spawns grow it).
|
|
132
|
+
const maxIterations = Math.max(64, graph.nodes.size * 8);
|
|
133
|
+
let iterations = 0;
|
|
134
|
+
startKrakenGraphLive(graph);
|
|
135
|
+
while (!isSettled(graph)) {
|
|
136
|
+
iterations += 1;
|
|
137
|
+
if (iterations > maxIterations) {
|
|
138
|
+
this.radio('graph_failed', {
|
|
139
|
+
description: 'graph executor',
|
|
140
|
+
detail: `exceeded ${maxIterations} scheduling iterations without settling`,
|
|
141
|
+
ok: false,
|
|
142
|
+
});
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
const ready = getReadyNodes(graph);
|
|
146
|
+
if (ready.length === 0) {
|
|
147
|
+
// Nothing is ready but the graph hasn't settled: some pending nodes
|
|
148
|
+
// are permanently blocked by a failed/skipped dependency. Cascade
|
|
149
|
+
// skip them so the loop can terminate.
|
|
150
|
+
const skippedAny = this.skipBlockedNodes(graph);
|
|
151
|
+
if (!skippedAny) {
|
|
152
|
+
// Nothing ready and nothing to skip — should not happen for a
|
|
153
|
+
// validated DAG, but bail out rather than spin forever.
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const wave = selectParallelWave(ready).slice(0, this.maxParallel);
|
|
159
|
+
for (const node of wave)
|
|
160
|
+
node.status = 'running';
|
|
161
|
+
const results = await Promise.all(wave.map((node) => this.runNode(node, graph)));
|
|
162
|
+
for (let i = 0; i < wave.length; i++) {
|
|
163
|
+
this.applyResult(graph, wave[i], results[i]);
|
|
164
|
+
}
|
|
165
|
+
updateKrakenGraphLive(graph);
|
|
166
|
+
}
|
|
167
|
+
let backtest;
|
|
168
|
+
const converged = isConverged(graph);
|
|
169
|
+
if (converged) {
|
|
170
|
+
const gateOn = this.worldModelGateOverride ?? isWorldModelGateEnabled(this.parentCwd);
|
|
171
|
+
if (gateOn) {
|
|
172
|
+
backtest = await this.backtestFn(this.parentCwd);
|
|
173
|
+
}
|
|
174
|
+
this.radio('graph_converged', {
|
|
175
|
+
description: 'graph executor',
|
|
176
|
+
detail: backtest ? `backtest: ${backtest.passed}/${backtest.total} passed` : undefined,
|
|
177
|
+
ok: backtest ? backtest.ok : true,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
this.radio('graph_failed', {
|
|
182
|
+
description: 'graph executor',
|
|
183
|
+
detail: `failed nodes: ${failedNodeIds(graph).join(', ') || 'none'}`,
|
|
184
|
+
ok: false,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
endKrakenGraphLive(graph, converged);
|
|
188
|
+
return {
|
|
189
|
+
graph,
|
|
190
|
+
converged,
|
|
191
|
+
failedNodeIds: failedNodeIds(graph),
|
|
192
|
+
counts: countByStatus(graph),
|
|
193
|
+
...(backtest ? { backtest } : {}),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/** Run one node: dispatch to the merge handler for `merge` nodes, else a tentacle. */
|
|
197
|
+
async runNode(node, graph) {
|
|
198
|
+
this.radio('node_start', { description: node.label, agent: node.kind });
|
|
199
|
+
if (node.kind === 'merge') {
|
|
200
|
+
return this.runMergeNode(node, graph);
|
|
201
|
+
}
|
|
202
|
+
const usesWorktree = node.kind === 'general' || node.kind === 'fix';
|
|
203
|
+
const agent = node.kind === 'fix' ? 'general' : node.kind;
|
|
204
|
+
const res = await this.withNodeTimeout(this.runTentacleFn({
|
|
205
|
+
deps: this.deps,
|
|
206
|
+
args: {
|
|
207
|
+
description: node.label,
|
|
208
|
+
prompt: node.prompt,
|
|
209
|
+
scope: node.scope,
|
|
210
|
+
acceptance: node.acceptance,
|
|
211
|
+
},
|
|
212
|
+
agent,
|
|
213
|
+
thoroughness: 'medium',
|
|
214
|
+
parentCwd: this.parentCwd,
|
|
215
|
+
sessionId: this.sessionId,
|
|
216
|
+
// Defer merge for writers so the executor controls merge ordering
|
|
217
|
+
// (Correction 4); explore/verify never create a worktree.
|
|
218
|
+
deferMerge: usesWorktree,
|
|
219
|
+
graphId: graph.id,
|
|
220
|
+
nodeId: node.id,
|
|
221
|
+
}), agent);
|
|
222
|
+
if (res.ok && usesWorktree) {
|
|
223
|
+
this.nodeRunState.set(node.id, { worktreeHandle: res.worktreeHandle });
|
|
224
|
+
}
|
|
225
|
+
return res;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Bound a tentacle run to `nodeTimeoutMs` wall-clock. On timeout, resolves
|
|
229
|
+
* to a synthetic `TentacleFailure` so the normal retry/fix/cascade-skip
|
|
230
|
+
* path handles it — this only bounds how long the EXECUTOR waits, it does
|
|
231
|
+
* not (cannot) forcibly cancel the underlying sub-agent run; the point is
|
|
232
|
+
* to guarantee `execute()` itself always settles so the caller's process
|
|
233
|
+
* can exit instead of hanging forever on one stuck node.
|
|
234
|
+
*/
|
|
235
|
+
withNodeTimeout(promise, agent) {
|
|
236
|
+
if (this.nodeTimeoutMs <= 0)
|
|
237
|
+
return promise;
|
|
238
|
+
const ms = this.nodeTimeoutMs;
|
|
239
|
+
let timer;
|
|
240
|
+
const timeout = new Promise((resolve) => {
|
|
241
|
+
timer = setTimeout(() => {
|
|
242
|
+
resolve({ ok: false, agent, error: `tentacle timed out after ${ms}ms` });
|
|
243
|
+
}, ms);
|
|
244
|
+
});
|
|
245
|
+
return Promise.race([promise, timeout]).finally(() => {
|
|
246
|
+
if (timer)
|
|
247
|
+
clearTimeout(timer);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Sequentially merge every dep node's deferred worktree (in dep order) into
|
|
252
|
+
* parent HEAD. Deps without a recorded worktree handle (worktree isolation
|
|
253
|
+
* disabled, or a read-only node) are a no-op. On conflict the branch is
|
|
254
|
+
* kept and the conflict is surfaced in the merge node's error — remaining
|
|
255
|
+
* deps still attempt to merge (independent branches shouldn't be blocked
|
|
256
|
+
* by one conflict).
|
|
257
|
+
*/
|
|
258
|
+
async runMergeNode(node, graph) {
|
|
259
|
+
const conflicts = [];
|
|
260
|
+
const merged = [];
|
|
261
|
+
for (const depId of node.deps) {
|
|
262
|
+
const state = this.nodeRunState.get(depId);
|
|
263
|
+
const handle = state?.worktreeHandle;
|
|
264
|
+
if (!handle)
|
|
265
|
+
continue; // nothing to merge for this dep
|
|
266
|
+
let result;
|
|
267
|
+
try {
|
|
268
|
+
result = await this.mergeFn(handle, {
|
|
269
|
+
message: `kraken: merge ${graph.nodes.get(depId)?.label ?? depId}`.slice(0, 200),
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
catch (err) {
|
|
273
|
+
result = {
|
|
274
|
+
ok: false,
|
|
275
|
+
merged: false,
|
|
276
|
+
committed: false,
|
|
277
|
+
conflict: true,
|
|
278
|
+
message: `merge threw: ${err instanceof Error ? err.message : String(err)}`,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
if (!result.ok) {
|
|
282
|
+
conflicts.push(`${depId}: ${result.message}`);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
merged.push(depId);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (conflicts.length > 0) {
|
|
289
|
+
return {
|
|
290
|
+
ok: false,
|
|
291
|
+
agent: 'general',
|
|
292
|
+
error: `merge: ${conflicts.length} conflict(s) — ${conflicts.join('; ')}`,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
return {
|
|
296
|
+
ok: true,
|
|
297
|
+
agent: 'general',
|
|
298
|
+
thoroughness: 'medium',
|
|
299
|
+
model: 'n/a',
|
|
300
|
+
result: merged.length > 0 ? `merged: ${merged.join(', ')}` : 'nothing to merge',
|
|
301
|
+
footer: '',
|
|
302
|
+
worktreePath: null,
|
|
303
|
+
worktreeHandle: null,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
/** Apply a tentacle result to its node: success, retry, fix-spawn, or terminal failure. */
|
|
307
|
+
applyResult(graph, node, res) {
|
|
308
|
+
if (res.ok) {
|
|
309
|
+
node.status = 'done';
|
|
310
|
+
node.result = res.result;
|
|
311
|
+
this.radio('node_end', { description: node.label, agent: node.kind, ok: true });
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
node.error = res.error;
|
|
315
|
+
if (node.retryCount < node.maxRetries) {
|
|
316
|
+
node.retryCount += 1;
|
|
317
|
+
node.status = 'pending';
|
|
318
|
+
this.radio('node_retry', {
|
|
319
|
+
description: node.label,
|
|
320
|
+
agent: node.kind,
|
|
321
|
+
detail: `retry ${node.retryCount}/${node.maxRetries}: ${res.error}`,
|
|
322
|
+
ok: false,
|
|
323
|
+
});
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (this.fixBudgetRemaining > 0 && node.kind !== 'fix') {
|
|
327
|
+
this.fixBudgetRemaining -= 1;
|
|
328
|
+
this.fixCounter += 1;
|
|
329
|
+
const fixNode = this.spawnFixNode(graph, node);
|
|
330
|
+
this.radio('node_fix', {
|
|
331
|
+
description: fixNode.label,
|
|
332
|
+
agent: fixNode.kind,
|
|
333
|
+
detail: `spawned to address failure of "${node.label}": ${res.error}`,
|
|
334
|
+
ok: false,
|
|
335
|
+
});
|
|
336
|
+
node.status = 'error';
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
// Retries and fix budget exhausted (or this was itself a fix node):
|
|
340
|
+
// terminal failure. Independent branches keep running; dependents are
|
|
341
|
+
// cascade-skipped by the scheduling loop.
|
|
342
|
+
node.status = 'error';
|
|
343
|
+
this.radio('node_end', {
|
|
344
|
+
description: node.label,
|
|
345
|
+
agent: node.kind,
|
|
346
|
+
detail: res.error,
|
|
347
|
+
ok: false,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Create a `fix` node that attempts to redo the failed node's work, wired
|
|
352
|
+
* so downstream dependents of the failed node also wait on the fix.
|
|
353
|
+
*/
|
|
354
|
+
spawnFixNode(graph, failed) {
|
|
355
|
+
const fixId = `fix-${failed.id}-${this.fixCounter}`;
|
|
356
|
+
const fixNode = {
|
|
357
|
+
id: fixId,
|
|
358
|
+
kind: 'fix',
|
|
359
|
+
label: `fix: ${failed.label}`,
|
|
360
|
+
prompt: `The previous attempt at this task failed and must be redone/repaired.\n\n` +
|
|
361
|
+
`## Original task\n${failed.prompt}\n\n` +
|
|
362
|
+
`## Failure\n${failed.error ?? 'unknown error'}`,
|
|
363
|
+
scope: failed.scope,
|
|
364
|
+
acceptance: failed.acceptance,
|
|
365
|
+
deps: [...failed.deps],
|
|
366
|
+
status: 'pending',
|
|
367
|
+
retryCount: 0,
|
|
368
|
+
maxRetries: 0,
|
|
369
|
+
// no further retries — one fix attempt per failed node in v1
|
|
370
|
+
};
|
|
371
|
+
graph.nodes.set(fixId, fixNode);
|
|
372
|
+
// Downstream dependents wait on the fix attempt INSTEAD of the failed
|
|
373
|
+
// node (not in addition to it) — the failed node never becomes `done`,
|
|
374
|
+
// so leaving it in `deps` would strand dependents forever.
|
|
375
|
+
for (const other of graph.nodes.values()) {
|
|
376
|
+
if (other.id === fixId)
|
|
377
|
+
continue;
|
|
378
|
+
if (other.deps.includes(failed.id)) {
|
|
379
|
+
other.deps = other.deps.map((d) => (d === failed.id ? fixId : d));
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return fixNode;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Mark every `pending` node whose deps include a terminally-failed or
|
|
386
|
+
* skipped node as `skipped`, transitively, so the graph can settle.
|
|
387
|
+
* Returns true if any node was newly skipped.
|
|
388
|
+
*/
|
|
389
|
+
skipBlockedNodes(graph) {
|
|
390
|
+
let changed = false;
|
|
391
|
+
let progressed = true;
|
|
392
|
+
while (progressed) {
|
|
393
|
+
progressed = false;
|
|
394
|
+
for (const node of graph.nodes.values()) {
|
|
395
|
+
if (node.status !== 'pending')
|
|
396
|
+
continue;
|
|
397
|
+
const blocked = node.deps.some((d) => {
|
|
398
|
+
const dep = graph.nodes.get(d);
|
|
399
|
+
return dep?.status === 'error' || dep?.status === 'skipped';
|
|
400
|
+
});
|
|
401
|
+
if (blocked) {
|
|
402
|
+
node.status = 'skipped';
|
|
403
|
+
changed = true;
|
|
404
|
+
progressed = true;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return changed;
|
|
409
|
+
}
|
|
410
|
+
radio(kind, fields) {
|
|
411
|
+
appendKrakenRadio(this.parentCwd, this.sessionId, {
|
|
412
|
+
kind,
|
|
413
|
+
agent: fields.agent ?? 'graph',
|
|
414
|
+
description: fields.description,
|
|
415
|
+
...(fields.detail !== undefined ? { detail: fields.detail } : {}),
|
|
416
|
+
...(fields.ok !== undefined ? { ok: fields.ok } : {}),
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../src/cli/kraken/executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kraken graph engine — observability (F5).
|
|
3
|
+
*
|
|
4
|
+
* Two independent pieces:
|
|
5
|
+
* - `formatKrakenGraphAscii` — a pure renderer of a `TaskGraph`'s topology
|
|
6
|
+
* and current node statuses (`/kraken graph` status block).
|
|
7
|
+
* - a lightweight in-process "current graph" live tracker, mirroring
|
|
8
|
+
* `krakenLive.ts`'s per-tentacle tracker but at the whole-graph level
|
|
9
|
+
* (needed for accurate pending/skipped/merge-node counts that a
|
|
10
|
+
* per-tentacle view can't see), feeding a StatusBar chip
|
|
11
|
+
* ("graph 3/8 · 2↑") the same way `formatKrakenLiveSummary` does for
|
|
12
|
+
* individual tentacles.
|
|
13
|
+
*
|
|
14
|
+
* Complements the `graph_*`/`node_*` radio events emitted by the F3
|
|
15
|
+
* executor (`src/cli/kraken/executor.ts`), which is also what drives this
|
|
16
|
+
* tracker via start/update/end calls around its scheduling loop.
|
|
17
|
+
*
|
|
18
|
+
* @since v0.10.x — Kraken graph engine (F5)
|
|
19
|
+
*/
|
|
20
|
+
import { topoLevels, countByStatus, } from '@zelari/core';
|
|
21
|
+
const STATUS_ICON = {
|
|
22
|
+
pending: '·',
|
|
23
|
+
running: '…',
|
|
24
|
+
done: '✓',
|
|
25
|
+
error: '✗',
|
|
26
|
+
skipped: '»',
|
|
27
|
+
};
|
|
28
|
+
/** Multi-line ASCII rendering of a graph's topology + current node statuses. */
|
|
29
|
+
export function formatKrakenGraphAscii(graph) {
|
|
30
|
+
const counts = countByStatus(graph);
|
|
31
|
+
const summaryParts = [`${counts.done}/${graph.nodes.size} done`];
|
|
32
|
+
if (counts.running)
|
|
33
|
+
summaryParts.push(`${counts.running} running`);
|
|
34
|
+
if (counts.error)
|
|
35
|
+
summaryParts.push(`${counts.error} failed`);
|
|
36
|
+
if (counts.skipped)
|
|
37
|
+
summaryParts.push(`${counts.skipped} skipped`);
|
|
38
|
+
const summary = `Kraken graph "${graph.id}" — ${summaryParts.join(', ')}`;
|
|
39
|
+
const levels = topoLevels(graph);
|
|
40
|
+
const lines = levels.map((ids, i) => {
|
|
41
|
+
const cells = ids.map((id) => {
|
|
42
|
+
const n = graph.nodes.get(id);
|
|
43
|
+
if (!n)
|
|
44
|
+
return `[?] ${id}`;
|
|
45
|
+
const icon = STATUS_ICON[n.status];
|
|
46
|
+
const scope = n.scope && n.scope.length > 0 ? `(${n.scope.join(',')})` : '';
|
|
47
|
+
return `[${icon}] ${n.id}${scope}`;
|
|
48
|
+
});
|
|
49
|
+
return `L${i}: ${cells.join(' ')}`;
|
|
50
|
+
});
|
|
51
|
+
if (lines.length === 0)
|
|
52
|
+
return summary;
|
|
53
|
+
return [summary, ...lines].join('\n');
|
|
54
|
+
}
|
|
55
|
+
function state() {
|
|
56
|
+
return globalThis;
|
|
57
|
+
}
|
|
58
|
+
/** Called by the executor when a graph run starts. */
|
|
59
|
+
export function startKrakenGraphLive(graph) {
|
|
60
|
+
const counts = countByStatus(graph);
|
|
61
|
+
state().__zelariKrakenGraphLive = {
|
|
62
|
+
graphId: graph.id,
|
|
63
|
+
total: graph.nodes.size,
|
|
64
|
+
pending: counts.pending,
|
|
65
|
+
running: counts.running,
|
|
66
|
+
done: counts.done,
|
|
67
|
+
error: counts.error,
|
|
68
|
+
skipped: counts.skipped,
|
|
69
|
+
startedAt: Date.now(),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** Called by the executor after each scheduling pass to refresh counts. */
|
|
73
|
+
export function updateKrakenGraphLive(graph) {
|
|
74
|
+
const live = state().__zelariKrakenGraphLive;
|
|
75
|
+
if (!live || live.graphId !== graph.id)
|
|
76
|
+
return;
|
|
77
|
+
const counts = countByStatus(graph);
|
|
78
|
+
live.total = graph.nodes.size;
|
|
79
|
+
live.pending = counts.pending;
|
|
80
|
+
live.running = counts.running;
|
|
81
|
+
live.done = counts.done;
|
|
82
|
+
live.error = counts.error;
|
|
83
|
+
live.skipped = counts.skipped;
|
|
84
|
+
}
|
|
85
|
+
/** Called by the executor once the graph settles. */
|
|
86
|
+
export function endKrakenGraphLive(graph, converged) {
|
|
87
|
+
updateKrakenGraphLive(graph);
|
|
88
|
+
const live = state().__zelariKrakenGraphLive;
|
|
89
|
+
if (!live || live.graphId !== graph.id)
|
|
90
|
+
return;
|
|
91
|
+
live.endedAt = Date.now();
|
|
92
|
+
live.converged = converged;
|
|
93
|
+
}
|
|
94
|
+
/** Clear the tracked graph (e.g. before starting a new one, or in tests). */
|
|
95
|
+
export function resetKrakenGraphLive() {
|
|
96
|
+
state().__zelariKrakenGraphLive = null;
|
|
97
|
+
}
|
|
98
|
+
/** The currently (or most recently) tracked graph's live summary, if any. */
|
|
99
|
+
export function getKrakenGraphLive() {
|
|
100
|
+
return state().__zelariKrakenGraphLive ?? null;
|
|
101
|
+
}
|
|
102
|
+
/** One-line chip for StatusBar: "graph 3/8 · 2↑" or null if no graph tracked. */
|
|
103
|
+
export function formatKrakenGraphSummary() {
|
|
104
|
+
const live = getKrakenGraphLive();
|
|
105
|
+
if (!live)
|
|
106
|
+
return null;
|
|
107
|
+
const parts = [`${live.done}/${live.total}`];
|
|
108
|
+
if (live.running)
|
|
109
|
+
parts.push(`${live.running}↑`);
|
|
110
|
+
if (live.error)
|
|
111
|
+
parts.push(`${live.error}✗`);
|
|
112
|
+
return `graph ${parts.join(' · ')}`;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=graphStatus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphStatus.js","sourceRoot":"","sources":["../../../src/cli/kraken/graphStatus.ts"],"names":[],"mappings":"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"}
|