gm-orchestrator 0.10.0 → 0.12.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 +135 -1
- package/dist/cli/index.js +5 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/core/heartbeat.d.ts +33 -0
- package/dist/core/heartbeat.d.ts.map +1 -0
- package/dist/core/heartbeat.js +138 -0
- package/dist/core/heartbeat.js.map +1 -0
- package/dist/core/orchestrator.d.ts +7 -1
- package/dist/core/orchestrator.d.ts.map +1 -1
- package/dist/core/orchestrator.js +75 -25
- package/dist/core/orchestrator.js.map +1 -1
- package/dist/core/post-task-hooks.d.ts +21 -0
- package/dist/core/post-task-hooks.d.ts.map +1 -0
- package/dist/core/post-task-hooks.js +67 -0
- package/dist/core/post-task-hooks.js.map +1 -0
- package/dist/core/prompt-builder.d.ts +1 -0
- package/dist/core/prompt-builder.d.ts.map +1 -1
- package/dist/core/prompt-builder.js +9 -0
- package/dist/core/prompt-builder.js.map +1 -1
- package/dist/core/scheduler.d.ts +4 -1
- package/dist/core/scheduler.d.ts.map +1 -1
- package/dist/core/scheduler.js +2 -0
- package/dist/core/scheduler.js.map +1 -1
- package/dist/core/task-utils.d.ts +5 -0
- package/dist/core/task-utils.d.ts.map +1 -1
- package/dist/core/task-utils.js +20 -5
- package/dist/core/task-utils.js.map +1 -1
- package/dist/core/types.d.ts +69 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/infra/claude-runner.d.ts +1 -1
- package/dist/infra/claude-runner.d.ts.map +1 -1
- package/dist/infra/claude-runner.js +3 -3
- package/dist/infra/claude-runner.js.map +1 -1
- package/dist/infra/config.d.ts.map +1 -1
- package/dist/infra/config.js +4 -0
- package/dist/infra/config.js.map +1 -1
- package/dist/infra/gm-client.d.ts +7 -1
- package/dist/infra/gm-client.d.ts.map +1 -1
- package/dist/infra/gm-client.js +3 -0
- package/dist/infra/gm-client.js.map +1 -1
- package/dist/infra/hook-runner.d.ts +9 -0
- package/dist/infra/hook-runner.d.ts.map +1 -0
- package/dist/infra/hook-runner.js +37 -0
- package/dist/infra/hook-runner.js.map +1 -0
- package/dist/server/api.d.ts +3 -3
- package/dist/server/api.d.ts.map +1 -1
- package/dist/server/api.js +49 -9
- package/dist/server/api.js.map +1 -1
- package/dist/server/runner-service.d.ts +1 -0
- package/dist/server/runner-service.d.ts.map +1 -1
- package/dist/server/runner-service.js +11 -9
- package/dist/server/runner-service.js.map +1 -1
- package/dist/ui/assets/{index-BralPefk.js → index-CV3c6w1g.js} +91 -86
- package/dist/ui/assets/index-Dd1YlJOi.css +1 -0
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/ui/assets/index-RLyz4r_Z.css +0 -1
package/README.md
CHANGED
|
@@ -72,7 +72,7 @@ The primary interface. Opens automatically at `http://localhost:4242`.
|
|
|
72
72
|
|
|
73
73
|
### Dashboard
|
|
74
74
|
Overview of your project: task queue sorted by priority, epics, done count for today.
|
|
75
|
-
One click to start a sprint or select an epic.
|
|
75
|
+
One click to start a sprint or select an epic. Choose the Claude model (Sonnet, Opus, Haiku) from the dropdown before starting.
|
|
76
76
|
|
|
77
77
|
### Sprint Runner
|
|
78
78
|
Live view while work is in progress:
|
|
@@ -196,7 +196,141 @@ Resolved in order — later sources override earlier:
|
|
|
196
196
|
| `pauseMs` | `number` | `2000` | Pause between tasks |
|
|
197
197
|
| `maxRetries` | `number` | `1` | Retries on timeout/error |
|
|
198
198
|
| `claudeArgs` | `string[]` | `[]` | Extra args for `claude --print` |
|
|
199
|
+
| `model` | `string` | | Claude model override (e.g. `claude-sonnet-4-6`) |
|
|
199
200
|
| `dryRun` | `boolean` | `false` | Preview prompts, don't run |
|
|
201
|
+
| `postTaskHooks` | `PostTaskHook[]` | `[]` | Verification commands run after each task (see [Post-task verification hooks](#post-task-verification-hooks)) |
|
|
202
|
+
| `heartbeat` | `HeartbeatConfig` | | Heartbeat / zombie recovery settings (see [Crash recovery](#crash-recovery-heartbeat)) |
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Task dependencies
|
|
207
|
+
|
|
208
|
+
The orchestrator respects task blockers when choosing which task to run next.
|
|
209
|
+
A task whose blockers are unresolved is **skipped** regardless of its priority.
|
|
210
|
+
|
|
211
|
+
### Marking a blocker
|
|
212
|
+
|
|
213
|
+
Use `tasks_link` with `kind="blocks"`:
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
tasks_link(fromId="U13", toId="U7", kind="blocks")
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
This means **U13 blocks U7** — the orchestrator will not start U7 until U13 reaches `done` (or `cancelled`).
|
|
220
|
+
|
|
221
|
+
**Concrete example:** task U13 creates a lock helper used by U7 and U9. Link U13→U7 and U13→U9 with `kind="blocks"` so the orchestrator picks U13 first, even if U7 and U9 have higher priority.
|
|
222
|
+
|
|
223
|
+
### Link kinds
|
|
224
|
+
|
|
225
|
+
GraphMemory supports four link kinds between tasks:
|
|
226
|
+
|
|
227
|
+
| Kind | Effect on orchestrator |
|
|
228
|
+
|------|----------------------|
|
|
229
|
+
| `blocks` | **Enforced.** Target task is skipped until the source is terminal (`done` / `cancelled`). Checked by `areBlockersResolved(task)`. |
|
|
230
|
+
| `prefers_after` | **Soft.** Target task is deprioritised while the source is still active, but **not blocked**. If the source is cancelled or stuck, the target can still run. Useful for "ideally A before B" without a hard gate. |
|
|
231
|
+
| `subtask_of` | Structural only — groups tasks under a parent. Does **not** affect scheduling order. |
|
|
232
|
+
| `related_to` | Informational only — no effect on scheduling. |
|
|
233
|
+
|
|
234
|
+
### Cancelled blockers
|
|
235
|
+
|
|
236
|
+
A blocker in `cancelled` state is treated as **resolved**, same as `done`. Semantically, "this work is not going to happen" is equivalent to "this work is already accomplished" from the dependent task's perspective. Cancelling a blocker unblocks everything downstream — no ghost-blocked tasks stalling forever.
|
|
237
|
+
|
|
238
|
+
### Cross-project blockers
|
|
239
|
+
|
|
240
|
+
For multi-project setups, a blocker can live in a different GraphMemory project. Pass `targetProjectId` when linking:
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
tasks_link(fromId="U-API-1", toId="U6", kind="blocks", targetProjectId="MixPlacesEcommerce")
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
This means **U-API-1 in the current project blocks U6 in `MixPlacesEcommerce`**. The orchestrator resolves blocker status across all configured projects, so you can run multiple epics in parallel and let the scheduler interleave tasks based on real-time readiness — no need to sequence epics by hand.
|
|
247
|
+
|
|
248
|
+
### Programmatic check
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
import { areBlockersResolved } from 'gm-orchestrator';
|
|
252
|
+
|
|
253
|
+
// Returns true when every task linked with kind="blocks" is done or cancelled
|
|
254
|
+
areBlockersResolved(task); // boolean
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Post-task verification hooks
|
|
260
|
+
|
|
261
|
+
After a task is marked `done`, the orchestrator can run user-configurable verification commands before accepting the `done` state. This provides a hard gate on quality — "task done = runtime verified" is enforced mechanically, not by convention.
|
|
262
|
+
|
|
263
|
+
Hooks run **in the orchestrator process**, not inside the spawned Claude session. A failing session cannot skip its own verification.
|
|
264
|
+
|
|
265
|
+
### Configuration
|
|
266
|
+
|
|
267
|
+
```json
|
|
268
|
+
{
|
|
269
|
+
"postTaskHooks": [
|
|
270
|
+
{
|
|
271
|
+
"name": "make-verify",
|
|
272
|
+
"command": "make verify",
|
|
273
|
+
"cwd": "/path/to/project",
|
|
274
|
+
"timeoutMs": 600000,
|
|
275
|
+
"onFailure": "block"
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"name": "lint",
|
|
279
|
+
"command": "npm run lint",
|
|
280
|
+
"onFailure": "warn"
|
|
281
|
+
}
|
|
282
|
+
]
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
| Field | Type | Description |
|
|
287
|
+
|-------|------|-------------|
|
|
288
|
+
| `name` | `string` | Human-readable label for logs. |
|
|
289
|
+
| `command` | `string` | Shell command to execute. |
|
|
290
|
+
| `cwd` | `string` | Working directory (default: `process.cwd()`). |
|
|
291
|
+
| `timeoutMs` | `number` | Timeout in ms (default: 600000 = 10 min). |
|
|
292
|
+
| `onFailure` | `'block' \| 'warn'` | `block` halts the sprint, `warn` logs and continues. |
|
|
293
|
+
|
|
294
|
+
### On failure (`onFailure: "block"`)
|
|
295
|
+
|
|
296
|
+
1. Task is moved back from `done` to `in_progress`
|
|
297
|
+
2. An `auto-verify-failed` tag is added
|
|
298
|
+
3. Last 50 lines of stdout/stderr are attached to `task.metadata.verifyFailures`
|
|
299
|
+
4. The sprint halts — orchestrator does **not** pick the next task until the user intervenes
|
|
300
|
+
|
|
301
|
+
Hooks run sequentially in the order declared. Multiple hooks per project (e.g. lint + build + test as separate entries) are supported.
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Crash recovery (heartbeat)
|
|
306
|
+
|
|
307
|
+
If the orchestrator process dies mid-task (OS reboot, OOM, pkill), the task is left stuck in `in_progress` forever. Heartbeats give the orchestrator a way to tell live work from zombie state.
|
|
308
|
+
|
|
309
|
+
While a task is running, the orchestrator writes `metadata.runId` and `metadata.heartbeatAt` on a 30s interval. On startup, it scans all `in_progress` tasks: any task with a stale heartbeat (older than 2× the interval) or no heartbeat at all is treated as a zombie and recovered according to the configured policy.
|
|
310
|
+
|
|
311
|
+
### Configuration
|
|
312
|
+
|
|
313
|
+
```json
|
|
314
|
+
{
|
|
315
|
+
"heartbeat": {
|
|
316
|
+
"intervalMs": 30000,
|
|
317
|
+
"staleThresholdMs": 60000,
|
|
318
|
+
"zombiePolicy": "reset-to-todo"
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
| Field | Default | Description |
|
|
324
|
+
|-------|---------|-------------|
|
|
325
|
+
| `intervalMs` | `30000` | How often to write heartbeat metadata. |
|
|
326
|
+
| `staleThresholdMs` | `2 × intervalMs` | Age threshold for zombie detection. |
|
|
327
|
+
| `zombiePolicy` | `reset-to-todo` | `reset-to-todo`, `move-to-review`, or `cancel`. |
|
|
328
|
+
|
|
329
|
+
`reset-to-todo` is the safe default: the zombie task goes back in the queue and will be re-picked with a fresh Claude session. Given per-task isolation, redoing the work is usually fine.
|
|
330
|
+
|
|
331
|
+
### Idempotency (double-spawn safety)
|
|
332
|
+
|
|
333
|
+
Each run gets a unique `runId` UUID, exposed to the spawned Claude session via the `ORCHESTRATOR_RUN_ID` environment variable and written to `task.metadata.runId`. Before making destructive changes, a well-behaved subagent can call `tasks_get` and compare `metadata.runId` to its own `ORCHESTRATOR_RUN_ID` — if they differ, another run has superseded this one and it should exit cleanly. This protects against race conditions between two orchestrator instances or restarts that happen during the narrow window between "pick task" and "move to in_progress".
|
|
200
334
|
|
|
201
335
|
---
|
|
202
336
|
|
package/dist/cli/index.js
CHANGED
|
@@ -199,11 +199,16 @@ async function main() {
|
|
|
199
199
|
projectId: activeProj?.projectId ?? '',
|
|
200
200
|
...(activeProj?.apiKey !== undefined && { apiKey: activeProj.apiKey }),
|
|
201
201
|
});
|
|
202
|
+
// Lazy-import HookRunner only when hooks are configured
|
|
203
|
+
const hookRunner = config.postTaskHooks?.length
|
|
204
|
+
? new (await import('../infra/hook-runner.js')).HookRunner()
|
|
205
|
+
: undefined;
|
|
202
206
|
const ports = {
|
|
203
207
|
gm,
|
|
204
208
|
runner: new ClaudeRunner(),
|
|
205
209
|
poller: new TaskPoller(gm),
|
|
206
210
|
logger: consoleLogger,
|
|
211
|
+
...(hookRunner ? { hookRunner } : {}),
|
|
207
212
|
};
|
|
208
213
|
if (effectiveCommand === 'status') {
|
|
209
214
|
const [todo, inProgress, done] = await Promise.all([
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { GraphMemoryPort, HeartbeatConfig } from './types.js';
|
|
2
|
+
import type { Logger } from '../infra/logger.js';
|
|
3
|
+
export declare const HEARTBEAT_DEFAULTS: HeartbeatConfig;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve heartbeat config by merging user overrides with defaults.
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveHeartbeatConfig(partial?: Partial<HeartbeatConfig>): HeartbeatConfig;
|
|
8
|
+
export interface HeartbeatHandle {
|
|
9
|
+
/** Unique run ID for this session. */
|
|
10
|
+
runId: string;
|
|
11
|
+
/** Stop the heartbeat interval and clear metadata from the task. */
|
|
12
|
+
stop(): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Start a heartbeat for a running task.
|
|
16
|
+
*
|
|
17
|
+
* - Writes `metadata.runId` and `metadata.heartbeatAt` immediately.
|
|
18
|
+
* - Updates `metadata.heartbeatAt` every `intervalMs`.
|
|
19
|
+
* - `stop()` clears the interval and removes heartbeat metadata.
|
|
20
|
+
*/
|
|
21
|
+
export declare function startHeartbeat(taskId: string, gm: GraphMemoryPort, config: HeartbeatConfig, logger: Logger): HeartbeatHandle;
|
|
22
|
+
/**
|
|
23
|
+
* Detect and recover zombie tasks on startup.
|
|
24
|
+
*
|
|
25
|
+
* Scans all `in_progress` tasks. If a task has heartbeat metadata
|
|
26
|
+
* and `heartbeatAt` is older than `staleThresholdMs`, it's a zombie.
|
|
27
|
+
* Tasks with no heartbeat metadata but `in_progress` status are also
|
|
28
|
+
* treated as zombies (pre-heartbeat era or metadata was lost).
|
|
29
|
+
*
|
|
30
|
+
* Returns the list of recovered task IDs.
|
|
31
|
+
*/
|
|
32
|
+
export declare function recoverZombieTasks(gm: GraphMemoryPort, config: HeartbeatConfig, logger: Logger): Promise<string[]>;
|
|
33
|
+
//# sourceMappingURL=heartbeat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../../src/core/heartbeat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EAIhB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAIjD,eAAO,MAAM,kBAAkB,EAAE,eAIhC,CAAC;AAEF;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GACjC,eAAe,CAQjB;AAID,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,eAAe,EACnB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,GACb,eAAe,CAqCjB;AAID;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,eAAe,EACnB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,EAAE,CAAC,CA4CnB"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
// ─── Defaults ────────────────────────────────────────────────────────────
|
|
3
|
+
export const HEARTBEAT_DEFAULTS = {
|
|
4
|
+
intervalMs: 30_000,
|
|
5
|
+
staleThresholdMs: 60_000,
|
|
6
|
+
zombiePolicy: 'reset-to-todo',
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Resolve heartbeat config by merging user overrides with defaults.
|
|
10
|
+
*/
|
|
11
|
+
export function resolveHeartbeatConfig(partial) {
|
|
12
|
+
return {
|
|
13
|
+
intervalMs: partial?.intervalMs ?? HEARTBEAT_DEFAULTS.intervalMs,
|
|
14
|
+
staleThresholdMs: partial?.staleThresholdMs ??
|
|
15
|
+
(partial?.intervalMs ? partial.intervalMs * 2 : HEARTBEAT_DEFAULTS.staleThresholdMs),
|
|
16
|
+
zombiePolicy: partial?.zombiePolicy ?? HEARTBEAT_DEFAULTS.zombiePolicy,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Start a heartbeat for a running task.
|
|
21
|
+
*
|
|
22
|
+
* - Writes `metadata.runId` and `metadata.heartbeatAt` immediately.
|
|
23
|
+
* - Updates `metadata.heartbeatAt` every `intervalMs`.
|
|
24
|
+
* - `stop()` clears the interval and removes heartbeat metadata.
|
|
25
|
+
*/
|
|
26
|
+
export function startHeartbeat(taskId, gm, config, logger) {
|
|
27
|
+
const runId = randomUUID();
|
|
28
|
+
let stopped = false;
|
|
29
|
+
const writeMeta = async () => {
|
|
30
|
+
if (stopped)
|
|
31
|
+
return;
|
|
32
|
+
const meta = { runId, heartbeatAt: Date.now() };
|
|
33
|
+
try {
|
|
34
|
+
await gm.updateTask(taskId, {
|
|
35
|
+
metadata: { runId: meta.runId, heartbeatAt: meta.heartbeatAt },
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
logger.warn(`Heartbeat write failed for ${taskId}: ${String(err)}`);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
// Initial write
|
|
43
|
+
void writeMeta();
|
|
44
|
+
const timer = setInterval(() => void writeMeta(), config.intervalMs);
|
|
45
|
+
return {
|
|
46
|
+
runId,
|
|
47
|
+
async stop() {
|
|
48
|
+
if (stopped)
|
|
49
|
+
return;
|
|
50
|
+
stopped = true;
|
|
51
|
+
clearInterval(timer);
|
|
52
|
+
// Clear heartbeat metadata so it's not mistaken for a zombie
|
|
53
|
+
try {
|
|
54
|
+
await gm.updateTask(taskId, {
|
|
55
|
+
metadata: { runId: null, heartbeatAt: null },
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
logger.warn(`Heartbeat clear failed for ${taskId}: ${String(err)}`);
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// ─── Zombie recovery ─────────────────────────────────────────────────────
|
|
65
|
+
/**
|
|
66
|
+
* Detect and recover zombie tasks on startup.
|
|
67
|
+
*
|
|
68
|
+
* Scans all `in_progress` tasks. If a task has heartbeat metadata
|
|
69
|
+
* and `heartbeatAt` is older than `staleThresholdMs`, it's a zombie.
|
|
70
|
+
* Tasks with no heartbeat metadata but `in_progress` status are also
|
|
71
|
+
* treated as zombies (pre-heartbeat era or metadata was lost).
|
|
72
|
+
*
|
|
73
|
+
* Returns the list of recovered task IDs.
|
|
74
|
+
*/
|
|
75
|
+
export async function recoverZombieTasks(gm, config, logger) {
|
|
76
|
+
const now = Date.now();
|
|
77
|
+
const recovered = [];
|
|
78
|
+
let inProgressTasks;
|
|
79
|
+
try {
|
|
80
|
+
inProgressTasks = await gm.listTasks({ status: 'in_progress' });
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
logger.error(`Zombie recovery: failed to list in_progress tasks: ${String(err)}`);
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
for (const task of inProgressTasks) {
|
|
87
|
+
const heartbeatAt = task.metadata?.['heartbeatAt'];
|
|
88
|
+
// If there's a recent heartbeat, it's alive — skip
|
|
89
|
+
if (typeof heartbeatAt === 'number' && now - heartbeatAt < config.staleThresholdMs) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
// This task is a zombie — either stale heartbeat or no heartbeat at all
|
|
93
|
+
const age = typeof heartbeatAt === 'number'
|
|
94
|
+
? `${Math.round((now - heartbeatAt) / 1000)}s ago`
|
|
95
|
+
: 'no heartbeat';
|
|
96
|
+
logger.warn(`Zombie detected: "${task.title}" (${task.id}) — last heartbeat: ${age}`);
|
|
97
|
+
try {
|
|
98
|
+
await applyZombiePolicy(task, config.zombiePolicy, gm, logger);
|
|
99
|
+
recovered.push(task.id);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
logger.error(`Zombie recovery failed for ${task.id}: ${String(err)}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (recovered.length) {
|
|
106
|
+
logger.info(`Zombie recovery: ${recovered.length} task(s) recovered with policy "${config.zombiePolicy}"`);
|
|
107
|
+
}
|
|
108
|
+
else if (inProgressTasks.length === 0) {
|
|
109
|
+
logger.info('Zombie recovery: no in_progress tasks found');
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
logger.info(`Zombie recovery: ${inProgressTasks.length} in_progress task(s) are all alive`);
|
|
113
|
+
}
|
|
114
|
+
return recovered;
|
|
115
|
+
}
|
|
116
|
+
async function applyZombiePolicy(task, policy, gm, logger) {
|
|
117
|
+
// Clear heartbeat metadata regardless of policy
|
|
118
|
+
await gm.updateTask(task.id, {
|
|
119
|
+
metadata: { runId: null, heartbeatAt: null },
|
|
120
|
+
});
|
|
121
|
+
switch (policy) {
|
|
122
|
+
case 'reset-to-todo':
|
|
123
|
+
logger.info(` → resetting "${task.title}" to todo`);
|
|
124
|
+
await gm.moveTask(task.id, 'todo');
|
|
125
|
+
break;
|
|
126
|
+
case 'cancel':
|
|
127
|
+
logger.info(` → cancelling "${task.title}"`);
|
|
128
|
+
await gm.moveTask(task.id, 'cancelled');
|
|
129
|
+
break;
|
|
130
|
+
case 'move-to-review':
|
|
131
|
+
// Move to cancelled with a note — there's no "review" status,
|
|
132
|
+
// so we cancel + tag for human inspection
|
|
133
|
+
logger.info(` → cancelling "${task.title}" for review (zombie)`);
|
|
134
|
+
await gm.moveTask(task.id, 'cancelled');
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=heartbeat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heartbeat.js","sourceRoot":"","sources":["../../src/core/heartbeat.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GraphMemoryPort, ClaudeRunnerPort, TaskPollerPort, OrchestratorConfig, SprintStats, CrossProjectResolver, CrossProjectTask } from './types.js';
|
|
1
|
+
import type { GraphMemoryPort, ClaudeRunnerPort, TaskPollerPort, HookRunnerPort, OrchestratorConfig, SprintStats, CrossProjectResolver, CrossProjectTask } from './types.js';
|
|
2
2
|
import type { Logger } from '../infra/logger.js';
|
|
3
3
|
interface Ports {
|
|
4
4
|
gm: GraphMemoryPort;
|
|
@@ -11,6 +11,12 @@ interface Ports {
|
|
|
11
11
|
* When provided, `findNextRunnable` will check blockers in other projects.
|
|
12
12
|
*/
|
|
13
13
|
crossProjectResolver?: CrossProjectResolver;
|
|
14
|
+
/**
|
|
15
|
+
* Optional hook runner for post-task verification.
|
|
16
|
+
* When provided along with config.postTaskHooks, hooks are executed
|
|
17
|
+
* after a task is marked done — before the orchestrator accepts completion.
|
|
18
|
+
*/
|
|
19
|
+
hookRunner?: HookRunnerPort;
|
|
14
20
|
}
|
|
15
21
|
/**
|
|
16
22
|
* Orchestrates a full sprint: runs all todo/in_progress tasks in priority
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/core/orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,WAAW,EAGX,oBAAoB,EACpB,gBAAgB,EACjB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/core/orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,WAAW,EAGX,oBAAoB,EACpB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAKpB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEjD,UAAU,KAAK;IACb,EAAE,EAAE,eAAe,CAAC;IACpB,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C;;;;OAIG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC7B,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,WAAW,CAAC,CAgEtB;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAC3B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,WAAW,CAAC,CAkEtB;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,MAAM,EAAE,EACjB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,WAAW,CAAC,CAyDtB;AA6JD;;;;GAIG;AACH,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,QAAQ,CAAC,EACvC,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,eAAe,EACjD,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC;IAAE,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAAC,KAAK,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAAC,CAmC/F"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { getActiveProject } from './types.js';
|
|
2
2
|
import { sortByPriority, areBlockersResolved, areBlockersResolvedAsync } from './task-utils.js';
|
|
3
|
+
import { startHeartbeat, resolveHeartbeatConfig } from './heartbeat.js';
|
|
4
|
+
import { runPostTaskHooks, handleVerifyFailure } from './post-task-hooks.js';
|
|
3
5
|
/**
|
|
4
6
|
* Orchestrates a full sprint: runs all todo/in_progress tasks in priority
|
|
5
7
|
* order, respecting blockers, retrying on failure, until none remain.
|
|
@@ -47,10 +49,16 @@ export async function runSprint(ports, config) {
|
|
|
47
49
|
return stats;
|
|
48
50
|
}
|
|
49
51
|
const result = await runOneTask(next, ports, config);
|
|
50
|
-
await handleResult(result, next, {
|
|
52
|
+
const halt = await handleResult(result, next, {
|
|
51
53
|
gm, logger, stats, failedIds, retryCounts,
|
|
52
54
|
maxRetries: config.maxRetries,
|
|
53
55
|
});
|
|
56
|
+
if (halt) {
|
|
57
|
+
logger.warn('Sprint halted due to verification failure');
|
|
58
|
+
stats.durationMs = Date.now() - startTime;
|
|
59
|
+
logStats(logger, stats);
|
|
60
|
+
return stats;
|
|
61
|
+
}
|
|
54
62
|
await sleep(config.pauseMs);
|
|
55
63
|
}
|
|
56
64
|
}
|
|
@@ -97,10 +105,16 @@ export async function runEpic(epicId, ports, config) {
|
|
|
97
105
|
return stats;
|
|
98
106
|
}
|
|
99
107
|
const result = await runOneTask(next, ports, config);
|
|
100
|
-
await handleResult(result, next, {
|
|
108
|
+
const halt = await handleResult(result, next, {
|
|
101
109
|
gm, logger, stats, failedIds, retryCounts,
|
|
102
110
|
maxRetries: config.maxRetries,
|
|
103
111
|
});
|
|
112
|
+
if (halt) {
|
|
113
|
+
logger.warn('Epic halted due to verification failure');
|
|
114
|
+
stats.durationMs = Date.now() - startTime;
|
|
115
|
+
logStats(logger, stats);
|
|
116
|
+
return stats;
|
|
117
|
+
}
|
|
104
118
|
await sleep(config.pauseMs);
|
|
105
119
|
}
|
|
106
120
|
}
|
|
@@ -146,10 +160,14 @@ export async function runTasks(taskIds, ports, config) {
|
|
|
146
160
|
if (failedIds.has(task.id))
|
|
147
161
|
continue;
|
|
148
162
|
const result = await runOneTask(task, ports, config);
|
|
149
|
-
await handleResult(result, task, {
|
|
163
|
+
const halt = await handleResult(result, task, {
|
|
150
164
|
gm, logger, stats, failedIds, retryCounts,
|
|
151
165
|
maxRetries: config.maxRetries,
|
|
152
166
|
});
|
|
167
|
+
if (halt) {
|
|
168
|
+
logger.warn('Task run halted due to verification failure');
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
153
171
|
await sleep(config.pauseMs);
|
|
154
172
|
}
|
|
155
173
|
stats.durationMs = Date.now() - startTime;
|
|
@@ -181,7 +199,8 @@ async function findNextRunnable(queue, logger, resolver) {
|
|
|
181
199
|
}
|
|
182
200
|
return null;
|
|
183
201
|
}
|
|
184
|
-
async function runOneTask(task,
|
|
202
|
+
async function runOneTask(task, ports, config) {
|
|
203
|
+
const { gm, runner, poller, logger, signal } = ports;
|
|
185
204
|
logger.task(task);
|
|
186
205
|
// Mark in_progress (idempotent)
|
|
187
206
|
if (task.status !== 'in_progress') {
|
|
@@ -194,40 +213,70 @@ async function runOneTask(task, { gm, runner, poller, logger, signal }, config)
|
|
|
194
213
|
await gm.moveTask(task.id, 'done').catch(() => { });
|
|
195
214
|
return 'dry_run';
|
|
196
215
|
}
|
|
197
|
-
//
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
216
|
+
// Start heartbeat for crash recovery
|
|
217
|
+
const hbConfig = resolveHeartbeatConfig(config.heartbeat);
|
|
218
|
+
const heartbeat = startHeartbeat(task.id, gm, hbConfig, logger);
|
|
219
|
+
try {
|
|
220
|
+
// Spawn Claude Code session (fire and forget — poller drives completion)
|
|
221
|
+
const sessionPromise = runner.run(task, config, heartbeat.runId).catch((e) => {
|
|
222
|
+
logger.warn(`Claude session error: ${String(e)}`);
|
|
223
|
+
});
|
|
224
|
+
// Poll GraphMemory until task reaches terminal state
|
|
225
|
+
const pollResult = await poller.waitForCompletion(task.id, {
|
|
226
|
+
timeoutMs: config.timeoutMs,
|
|
227
|
+
...(signal ? { signal } : {}),
|
|
228
|
+
});
|
|
229
|
+
await sessionPromise; // let process clean up
|
|
230
|
+
if (pollResult === 'timeout') {
|
|
231
|
+
logger.error(`Timeout: "${task.title}" (${task.id})`);
|
|
232
|
+
return 'timeout';
|
|
233
|
+
}
|
|
234
|
+
if (pollResult === 'done') {
|
|
235
|
+
// Run post-task verification hooks (if configured)
|
|
236
|
+
const hooks = config.postTaskHooks;
|
|
237
|
+
if (hooks?.length && ports.hookRunner) {
|
|
238
|
+
logger.info(`Running ${hooks.length} post-task hook(s) for "${task.title}"`);
|
|
239
|
+
const report = await runPostTaskHooks(hooks, ports.hookRunner, logger);
|
|
240
|
+
if (!report.passed) {
|
|
241
|
+
await handleVerifyFailure(task, report, gm, logger);
|
|
242
|
+
return 'verify_failed';
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
logger.success(`Done: "${task.title}"`);
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
logger.warn(`Cancelled: "${task.title}"`);
|
|
249
|
+
}
|
|
250
|
+
return pollResult;
|
|
213
251
|
}
|
|
214
|
-
|
|
215
|
-
|
|
252
|
+
finally {
|
|
253
|
+
// Always stop the heartbeat — whether success, failure, or abort
|
|
254
|
+
await heartbeat.stop();
|
|
216
255
|
}
|
|
217
|
-
return pollResult;
|
|
218
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* Processes a task run result. Returns true if the sprint/epic should halt
|
|
259
|
+
* (e.g. on verify_failed — don't continue to next task).
|
|
260
|
+
*/
|
|
219
261
|
async function handleResult(result, task, ctx) {
|
|
220
262
|
const { gm, logger, stats, failedIds, retryCounts, maxRetries } = ctx;
|
|
221
263
|
if (result === 'done' || result === 'dry_run') {
|
|
222
264
|
stats.done++;
|
|
223
265
|
logger.taskResult(task, 'done');
|
|
224
|
-
return;
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
if (result === 'verify_failed') {
|
|
269
|
+
stats.errors++;
|
|
270
|
+
failedIds.add(task.id);
|
|
271
|
+
logger.taskResult(task, 'verify_failed');
|
|
272
|
+
logger.error(`Halting — post-task verification failed for "${task.title}" (${task.id})`);
|
|
273
|
+
return true; // halt the sprint/epic
|
|
225
274
|
}
|
|
226
275
|
if (result === 'cancelled') {
|
|
227
276
|
stats.cancelled++;
|
|
228
277
|
failedIds.add(task.id);
|
|
229
278
|
logger.taskResult(task, 'cancelled');
|
|
230
|
-
return;
|
|
279
|
+
return false;
|
|
231
280
|
}
|
|
232
281
|
// timeout | error
|
|
233
282
|
const retries = retryCounts.get(task.id) ?? 0;
|
|
@@ -245,6 +294,7 @@ async function handleResult(result, task, ctx) {
|
|
|
245
294
|
logger.error(`Giving up on: ${task.id}`);
|
|
246
295
|
await gm.moveTask(task.id, 'cancelled').catch(() => { });
|
|
247
296
|
}
|
|
297
|
+
return false;
|
|
248
298
|
}
|
|
249
299
|
/**
|
|
250
300
|
* Collect tasks for a cross-project epic.
|