@ai-dossier/sched 0.2.0 → 0.3.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 +85 -17
- package/dist/dispatch.d.ts +128 -0
- package/dist/dispatch.d.ts.map +1 -0
- package/dist/dispatch.js +300 -0
- package/dist/dispatch.js.map +1 -0
- package/dist/engine.d.ts +111 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +936 -0
- package/dist/engine.js.map +1 -0
- package/dist/enqueue.d.ts +38 -0
- package/dist/enqueue.d.ts.map +1 -0
- package/dist/enqueue.js +222 -0
- package/dist/enqueue.js.map +1 -0
- package/dist/groundtruth.d.ts +135 -0
- package/dist/groundtruth.d.ts.map +1 -0
- package/dist/groundtruth.js +259 -0
- package/dist/groundtruth.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +101 -0
- package/dist/index.js.map +1 -0
- package/dist/journal.d.ts +32 -0
- package/dist/journal.d.ts.map +1 -0
- package/dist/journal.js +113 -0
- package/dist/journal.js.map +1 -0
- package/dist/persist.d.ts +54 -0
- package/dist/persist.d.ts.map +1 -0
- package/dist/persist.js +348 -0
- package/dist/persist.js.map +1 -0
- package/dist/project.d.ts +41 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.js +124 -0
- package/dist/project.js.map +1 -0
- package/dist/readiness.d.ts +43 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +102 -0
- package/dist/readiness.js.map +1 -0
- package/dist/scheduler.d.ts +78 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +191 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/state.d.ts +40 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +391 -0
- package/dist/state.js.map +1 -0
- package/dist/status.d.ts +44 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +82 -0
- package/dist/status.js.map +1 -0
- package/dist/teardown.d.ts +57 -0
- package/dist/teardown.d.ts.map +1 -0
- package/dist/teardown.js +242 -0
- package/dist/teardown.js.map +1 -0
- package/dist/types.d.ts +253 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +91 -0
- package/dist/types.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@ai-dossier/sched)
|
|
4
4
|
|
|
5
5
|
Deterministic scheduler core for dossier batch cycles — queue, worker slots, typed state
|
|
6
|
-
machines, crash-safe persistence,
|
|
7
|
-
processes, verifying their completion against ground truth,
|
|
8
|
-
stall/escalation ladder
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
machines, crash-safe persistence, the **dispatch engine** (#464: spawning agent
|
|
7
|
+
processes, verifying their completion against ground truth, mechanizing the
|
|
8
|
+
stall/escalation ladder), and since #468 the **PR watcher + tail work** (parked-PR
|
|
9
|
+
watching, script-based teardown, cheap-tier report dispatch — retiring the fleet
|
|
10
|
+
pattern of re-dispatching a full-cycle run for the tail). The scheduler itself **never
|
|
11
|
+
invokes an LLM** — it spawns the agent process the operator configured and reconciles
|
|
12
|
+
the durable record (`ai-dossier runstate` / `gh` / `git`) that the spawned run leaves
|
|
13
|
+
behind.
|
|
11
14
|
|
|
12
15
|
Design: RFC-0001 *Batch Cycles* §B/C.1/D (the RFC lives on branch `docs/batch-cycles-rfc`,
|
|
13
16
|
not yet merged to `main`; the §D state machines are frozen verbatim into the types below).
|
|
@@ -17,14 +20,14 @@ this state machine makes impossible to forget.
|
|
|
17
20
|
|
|
18
21
|
## CLI surface
|
|
19
22
|
|
|
20
|
-
Consumed through the monorepo CLI (`@ai-dossier/cli` ≥ 0.
|
|
23
|
+
Consumed through the monorepo CLI (`@ai-dossier/cli` ≥ 0.19.0):
|
|
21
24
|
|
|
22
25
|
```bash
|
|
23
26
|
ai-dossier sched enqueue --issues 101,105..109 --deps 100 --tier strong # flags
|
|
24
27
|
ai-dossier sched enqueue --from-manifest batch-prep.json # batch-prep output
|
|
25
|
-
ai-dossier sched start # the dispatch engine: spawn, verify, escalate (Ctrl-C stops it)
|
|
28
|
+
ai-dossier sched start # the dispatch engine: spawn, verify, escalate, watch parked PRs (Ctrl-C stops it)
|
|
26
29
|
ai-dossier sched start --once # a single reconcile+refill tick (cron-style)
|
|
27
|
-
ai-dossier sched status # queue
|
|
30
|
+
ai-dossier sched status # queue (+pr/cleanup), parked PRs, slots, batches, blocked/failed
|
|
28
31
|
ai-dossier sched pause # stop NEW assignments; live units keep running
|
|
29
32
|
ai-dossier sched resume
|
|
30
33
|
ai-dossier sched abandon --issue 42 --reason "operator abort"
|
|
@@ -91,13 +94,26 @@ import {
|
|
|
91
94
|
parseManifest, // batch-prep JSON → EnqueueInput[]
|
|
92
95
|
computeAssignments, // pure: fill idle slots with runnable units, bounded by max_slots
|
|
93
96
|
runnableUnits, // pure: which units may run right now (dep-gated)
|
|
94
|
-
tick, // one engine cycle: reconcile + verify + refill + spawn
|
|
97
|
+
tick, // one engine cycle: reconcile + verify + refill + spawn,
|
|
98
|
+
// and since #468: park-watch, teardown, report dispatch
|
|
95
99
|
runLoop, // the sched start loop (tick, sleep, repeat)
|
|
96
|
-
type TickResult, // what one tick did (spawned/
|
|
97
|
-
|
|
100
|
+
type TickResult, // what one tick did (spawned/parked/merge-accepted/report-dispatched/
|
|
101
|
+
// teardown/completed/redispatched/failed/blocked)
|
|
102
|
+
type EngineDeps, // inject everything the engine touches (store/journal/spawn/ground
|
|
103
|
+
// truth/clock/repoDir/teardownExec)
|
|
98
104
|
createSpawnDeps, // real detached-spawn process I/O
|
|
99
|
-
createExecGroundTruth, // runstate/gh/git ground truth via subprocesses (injectable exec)
|
|
100
|
-
|
|
105
|
+
createExecGroundTruth, // runstate/gh/git ground truth via subprocesses (injectable exec);
|
|
106
|
+
// since #468 also gh pr view PR state + setup info from comments
|
|
107
|
+
resolveDispatch, // config → resolved command/prompt/report-prompt/tier-models/timers
|
|
108
|
+
buildReportPrompt, // report-agent prompt ({issue}/{pr}/{cleanup} substituted)
|
|
109
|
+
reportTierFor, // report (re)dispatch tier after N escalations
|
|
110
|
+
isParkedMilestone, // ship-phase awaiting-merge + pr= → the park signal
|
|
111
|
+
prOfMilestone, // a milestone's pr= key as a positive integer
|
|
112
|
+
parsePrViewJson, // gh pr view --json → PR truth (mergedAt/mergeable/blocked label)
|
|
113
|
+
parseSetupInfo, // gh issue view --json comments → teardown inputs
|
|
114
|
+
runTeardown, // #468 script teardown for a merged unit (pool return / worktree remove)
|
|
115
|
+
isSafeWorktree, // worktree-path containment check (CWE-22)
|
|
116
|
+
TEARDOWN_TIMEOUT_MS, // teardown subprocess timeout (120 s)
|
|
101
117
|
Journal, // append-only events.jsonl
|
|
102
118
|
transitionIssue, transitionBatch, transitionSlot, // typed §D transitions
|
|
103
119
|
TRANSITIONS, // the transition tables themselves (for previews)
|
|
@@ -119,7 +135,8 @@ fake agents and stub ground truth; no LLM calls anywhere.
|
|
|
119
135
|
```
|
|
120
136
|
~/.dossier/sched/<project>/
|
|
121
137
|
├── state.json # hot operational truth — atomic tmp+fsync+rename writes;
|
|
122
|
-
├── config.json # durable intent: max_slots, stall_timeout_ms, reconcile_interval_ms,
|
|
138
|
+
├── config.json # durable intent: max_slots, stall_timeout_ms, reconcile_interval_ms,
|
|
139
|
+
│ # pr_poll_interval_ms, dispatch (incl. report_prompt)
|
|
123
140
|
├── events.jsonl # append-only event journal (the operator's flight recorder)
|
|
124
141
|
├── runs/ # per-unit agent output logs (issue-<n>.log)
|
|
125
142
|
└── .sched-lock/ # cross-process directory mutex (pid; stolen from dead holders)
|
|
@@ -133,14 +150,63 @@ fake agents and stub ground truth; no LLM calls anywhere.
|
|
|
133
150
|
- **Corrupt state is loud**: `load()` throws `CorruptStateError` naming the file —
|
|
134
151
|
never a silent queue reset. `state.json` is deletable and rebuildable from GitHub,
|
|
135
152
|
which remains the system of record.
|
|
136
|
-
- **Schema**: state/config files from #460 (schema 1.0.0)
|
|
137
|
-
automatically (slot `branch`/`last_head
|
|
153
|
+
- **Schema**: state/config files from #460 (schema 1.0.0) and #464 (1.1.0) load and
|
|
154
|
+
migrate to 1.2.0 automatically (slot `branch`/`last_head`, entry `pr`/`cleanup`,
|
|
155
|
+
and state-level `last_pr_poll_at` backfill to null).
|
|
138
156
|
- **`max_slots`** bounds live units (`assigned | running | recovering`); dependency
|
|
139
157
|
edges gate readiness — an issue with an unmerged dependency, and a batch behind an
|
|
140
158
|
unmerged batch, are never runnable.
|
|
141
159
|
- **Pause** stops new assignments only; abandon routes through the typed failure rails
|
|
142
160
|
(`evicted → requeued{full}` for batch members — nothing green is discarded).
|
|
143
161
|
|
|
162
|
+
## The PR watcher + tail work (#468)
|
|
163
|
+
|
|
164
|
+
Dispatched runs park their PR on `auto-merge` (detached ship mode — the default
|
|
165
|
+
prompt instructs it) and exit. The engine owns everything after the park:
|
|
166
|
+
|
|
167
|
+
1. **Park detection (AC1)** — an agent exit whose latest milestone is the ship
|
|
168
|
+
phase's `awaiting-merge` (with `pr=`) is a VERIFIED park, not an unverified
|
|
169
|
+
exit: the entry moves to `parked`, the slot is released (a waiting unit
|
|
170
|
+
consumes zero slots), and the watcher takes over.
|
|
171
|
+
2. **PR watching (AC1)** — parked PRs are polled every `pr_poll_interval_ms`
|
|
172
|
+
(default 150 s — "every 2–3 min", persisted `last_pr_poll_at` so a restart
|
|
173
|
+
honors the cadence; checked on each reconcile tick when due, so a
|
|
174
|
+
`reconcile_interval_ms` longer than the interval slows the effective cadence)
|
|
175
|
+
via `gh pr view --json state,mergedAt,mergeable,labels`.
|
|
176
|
+
A merge is accepted only when state is MERGED **and** `mergedAt` is non-null
|
|
177
|
+
**and** the issue is closed — never inferred from an agent exit. An
|
|
178
|
+
unreachable poll pauses the watcher (decision 2, option A).
|
|
179
|
+
3. **Failure states (AC3)** — `CONFLICTING`, closed-unmerged, or the
|
|
180
|
+
`auto-merge-blocked` label fail the unit with the reason and block its
|
|
181
|
+
TRANSITIVE dependents. The engine never merges anything itself.
|
|
182
|
+
4. **Gating on MERGE, not park (AC4)** — `parked` is not a satisfied status:
|
|
183
|
+
dependents stay blocked until the merge lands (`parked → shipped`).
|
|
184
|
+
5. **Teardown as a script (AC2)** — on merge, the run's setup milestone
|
|
185
|
+
(recovered once from the issue's comments — collaborator-authored only, and
|
|
186
|
+
the worktree path must pass a containment check before any destructive
|
|
187
|
+
subprocess) chooses the script: pool-claimed worktrees run
|
|
188
|
+
`worktree-pool return --path <wt> --json` (the pool's own self-check is the
|
|
189
|
+
verification); cold worktrees run
|
|
190
|
+
`git worktree remove --force <wt>` with a path-gone check. Both are
|
|
191
|
+
verify-first idempotent; a failed step records `cleanup=failed-<step>` on
|
|
192
|
+
the entry and in the journal — degradation, never unit failure.
|
|
193
|
+
6. **Report dispatch (AC2)** — once teardown is recorded (when a slot is
|
|
194
|
+
free — a waiting report consumes zero slots), a **mechanical-tier** report
|
|
195
|
+
agent is spawned with the report-phase prompt (`dispatch.report_prompt`;
|
|
196
|
+
`{issue}`/`{pr}`/`{cleanup}` substituted — the cleanup status rides into
|
|
197
|
+
the report). It completes like any agent; a report that stalls climbs the
|
|
198
|
+
same ladder (mechanical → mid → strong, cap 2), and at the cap the unit
|
|
199
|
+
completes (`done`, reason `report-escalation-cap`) with a `report-failed`
|
|
200
|
+
journal event — the work is merged, so dependents are never re-blocked.
|
|
201
|
+
The full-cycle tail-run pattern (re-dispatching a whole run for
|
|
202
|
+
teardown+report) is retired.
|
|
203
|
+
|
|
204
|
+
`sched status` shows parked PRs (zero slots, with the last poll's age), a
|
|
205
|
+
`pr` column and a `cleanup` column on the queue; every watcher decision lands
|
|
206
|
+
in `events.jsonl` (`pr-parked`, `merge-accepted`, `pr-watch-failed`,
|
|
207
|
+
`pr-watch-waiting`, `teardown-done`/`teardown-failed`, `report-dispatched`,
|
|
208
|
+
`report-failed`, `ground-truth-unreachable`).
|
|
209
|
+
|
|
144
210
|
## Development
|
|
145
211
|
|
|
146
212
|
```bash
|
|
@@ -152,4 +218,6 @@ npm test # vitest — state machines, persistence, crash/restart, engine
|
|
|
152
218
|
|
|
153
219
|
No network, no GitHub in unit tests — persistence tests run on temp directories; the
|
|
154
220
|
integration tests spawn fake-agent fixtures against a scratch git repo with stubbed
|
|
155
|
-
ground truth.
|
|
221
|
+
ground truth. The #468 integration tests run the full detached-ship tail
|
|
222
|
+
(park → watch → merge → REAL worktree removal → report) end-to-end, including a
|
|
223
|
+
sched restart mid-watch.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent dispatch machinery (#464, AC1 — "a runnable queue unit is dispatched
|
|
3
|
+
* as a spawned agent process … with `--model` per its tier; pid + phase +
|
|
4
|
+
* last-progress timestamp tracked in state.json"; RFC-0001 §C.1 "spawns agent
|
|
5
|
+
* processes via the existing `run` machinery").
|
|
6
|
+
*
|
|
7
|
+
* The command is a template (default `claude -p --output-format json --model
|
|
8
|
+
* {model}` — the same headless invocation `ai-dossier run` builds in
|
|
9
|
+
* cli/src/helpers.ts) with `{model}`/`{issue}` placeholders; the prompt
|
|
10
|
+
* travels on stdin exactly like the run machinery's headless path. Children
|
|
11
|
+
* spawn DETACHED and unref'd: an agent must survive a sched crash (RFC F.10 —
|
|
12
|
+
* restart reconciles by pid, it never owns the agent's lifetime).
|
|
13
|
+
*
|
|
14
|
+
* All process I/O is injectable (`SpawnDeps`) so tests spawn fake agents, and
|
|
15
|
+
* the package itself never invokes an LLM — it spawns a process the operator
|
|
16
|
+
* configured.
|
|
17
|
+
*/
|
|
18
|
+
import { type ModelTier, type SchedConfig } from './types';
|
|
19
|
+
/** Default tier → model mapping (claude aliases; override in config.json). */
|
|
20
|
+
export declare const DEFAULT_TIER_MODELS: Readonly<Record<ModelTier, string>>;
|
|
21
|
+
/** Default headless agent command template (claude, the run machinery's first choice). */
|
|
22
|
+
export declare const DEFAULT_DISPATCH_COMMAND: readonly string[];
|
|
23
|
+
/** opencode equivalent (the run machinery's second agent, #459). */
|
|
24
|
+
export declare const OPENCODE_DISPATCH_COMMAND: readonly string[];
|
|
25
|
+
/**
|
|
26
|
+
* Default prompt sent on the child's stdin. Detached ship mode (#468): the
|
|
27
|
+
* agent parks the PR on `auto-merge` and STOPS — the scheduler's PR watcher
|
|
28
|
+
* owns the merge wait and dispatches teardown + report as tail work. The
|
|
29
|
+
* fleet pattern of re-dispatching a full-cycle run for the tail is retired.
|
|
30
|
+
* Operators wanting attached runs (agent drives to the final report itself)
|
|
31
|
+
* override `dispatch.prompt` in config.json.
|
|
32
|
+
*/
|
|
33
|
+
export declare const DEFAULT_PROMPT_TEMPLATE: string;
|
|
34
|
+
/**
|
|
35
|
+
* Default prompt for the report agent dispatched after a merged PR (#468
|
|
36
|
+
* AC2) — a cheap-tier run of the report phase only, never a full cycle.
|
|
37
|
+
*/
|
|
38
|
+
export declare const DEFAULT_REPORT_PROMPT_TEMPLATE: string;
|
|
39
|
+
/** Fully-resolved dispatch settings the engine runs with. */
|
|
40
|
+
export interface ResolvedDispatch {
|
|
41
|
+
/** Command template with `{model}`/`{issue}` placeholders. */
|
|
42
|
+
command: string[];
|
|
43
|
+
/** Prompt template with `{issue}` placeholder. */
|
|
44
|
+
prompt: string;
|
|
45
|
+
/** Report-agent prompt template with `{issue}`/`{pr}`/`{cleanup}` placeholders (#468). */
|
|
46
|
+
reportPrompt: string;
|
|
47
|
+
/** Model per tier; null means "no model flag" (the command's `--model {model}` pair drops). */
|
|
48
|
+
tierModels: Record<ModelTier, string | null>;
|
|
49
|
+
stallTimeoutMs: number;
|
|
50
|
+
reconcileIntervalMs: number;
|
|
51
|
+
/** Parked-PR poll interval (#468 AC1, default 150 s — "every 2–3 min"). */
|
|
52
|
+
prPollIntervalMs: number;
|
|
53
|
+
}
|
|
54
|
+
/** Resolve engine dispatch settings from the (possibly sparse) config. */
|
|
55
|
+
export declare function resolveDispatch(config: SchedConfig): ResolvedDispatch;
|
|
56
|
+
/**
|
|
57
|
+
* Build the concrete agent argv for one dispatch: substitute `{issue}` and
|
|
58
|
+
* `{model}`. When the tier's model is null, the `{model}` item AND its
|
|
59
|
+
* immediately-preceding flag (e.g. `--model`) drop together — a command never
|
|
60
|
+
* carries a flag whose value is missing.
|
|
61
|
+
*/
|
|
62
|
+
export declare function buildAgentCommand(template: readonly string[], tier: ModelTier, issue: number, tierModels: Readonly<Record<ModelTier, string | null>>): string[];
|
|
63
|
+
/** Build the child's stdin prompt for one dispatch. */
|
|
64
|
+
export declare function buildPrompt(template: string, issue: number): string;
|
|
65
|
+
/** Build the report agent's stdin prompt (#468): `{issue}`/`{pr}`/`{cleanup}` substituted. */
|
|
66
|
+
export declare function buildReportPrompt(template: string, issue: number, pr: number, cleanup: string): string;
|
|
67
|
+
/** One tier stronger on the ladder, or null at the top (RFC-0001 §C.1). */
|
|
68
|
+
export declare function escalateTier(tier: ModelTier): ModelTier | null;
|
|
69
|
+
/**
|
|
70
|
+
* The tier for a report-agent (re)dispatch after `recoveries` escalations
|
|
71
|
+
* (#468): reports start cheap (mechanical) and climb the same ladder —
|
|
72
|
+
* mechanical → mid → strong — with null past the top. The engine's
|
|
73
|
+
* `ESCALATION_CAP` check fails the unit before that null is reached.
|
|
74
|
+
*/
|
|
75
|
+
export declare function reportTierFor(recoveries: number): ModelTier | null;
|
|
76
|
+
export interface SpawnDeps {
|
|
77
|
+
/**
|
|
78
|
+
* Spawn a detached agent process and return its pid. `logFile` receives the
|
|
79
|
+
* child's combined stdout/stderr (agents outlive sched, so their output
|
|
80
|
+
* cannot stay in this process's pipes). Throws synchronously when the
|
|
81
|
+
* process cannot be spawned (missing binary, unwritable log dir).
|
|
82
|
+
*/
|
|
83
|
+
spawn(cmd: string[], prompt: string, logFile: string): number;
|
|
84
|
+
/**
|
|
85
|
+
* Signal a pid; returns false when it was already dead (or not ours).
|
|
86
|
+
* `expectedStart` (the persisted `/proc` start-time) enables the pid-reuse
|
|
87
|
+
* guard: a pid whose start-time no longer matches was reused by an
|
|
88
|
+
* unrelated process and is never signalled.
|
|
89
|
+
*/
|
|
90
|
+
kill(pid: number, expectedStart?: number): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Whether a pid is alive (best-effort). `expectedStart` applies the same
|
|
93
|
+
* pid-reuse guard as `kill`.
|
|
94
|
+
*/
|
|
95
|
+
isAlive(pid: number, expectedStart?: number): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* `/proc/<pid>/stat` start-time (field 22) of a pid, when the platform
|
|
98
|
+
* exposes it (Linux); null elsewhere. The engine persists this at spawn so
|
|
99
|
+
* pid identity survives engine restarts (decision 1, option C).
|
|
100
|
+
*/
|
|
101
|
+
processStart(pid: number): number | null;
|
|
102
|
+
}
|
|
103
|
+
/** `issue:464` → `issue-464` (filesystem-safe unit ids for log file names). */
|
|
104
|
+
export declare function unitLogName(unit: string): string;
|
|
105
|
+
/** Poll cadence bounds for `sleep`'s stop-check interval (engine loop). */
|
|
106
|
+
export declare const STOP_POLL_MIN_MS = 100;
|
|
107
|
+
export declare const STOP_POLL_MAX_MS = 1000;
|
|
108
|
+
/**
|
|
109
|
+
* `/proc/<pid>/stat` start-time (field 22, clock ticks since boot) — stable
|
|
110
|
+
* process identity for the lifetime of the pid, so a recycled pid is
|
|
111
|
+
* detectable. Null when /proc is unavailable (macOS/Windows) or the process
|
|
112
|
+
* is gone.
|
|
113
|
+
*/
|
|
114
|
+
export declare function procStartTime(pid: number): number | null;
|
|
115
|
+
/**
|
|
116
|
+
* Real process I/O: detached spawn with output to a log file, unref'd.
|
|
117
|
+
*
|
|
118
|
+
* Pid-reuse guard (decision 1, option C — hybrid): every pid this instance
|
|
119
|
+
* spawns is recorded with its `/proc` start-time; `kill`/`isAlive` accept the
|
|
120
|
+
* start-time persisted in state.json and refuse a pid whose current
|
|
121
|
+
* start-time no longer matches (it was reused by an unrelated process — the
|
|
122
|
+
* agent we spawned is already dead, so skipping the signal loses nothing).
|
|
123
|
+
* On platforms without /proc the guard degrades to best-effort, and pids
|
|
124
|
+
* without a recorded start-time (e.g. from pre-decision state files) stay
|
|
125
|
+
* best-effort everywhere.
|
|
126
|
+
*/
|
|
127
|
+
export declare function createSpawnDeps(cwd?: string): SpawnDeps;
|
|
128
|
+
//# sourceMappingURL=dispatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"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"}
|
package/dist/dispatch.js
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Agent dispatch machinery (#464, AC1 — "a runnable queue unit is dispatched
|
|
4
|
+
* as a spawned agent process … with `--model` per its tier; pid + phase +
|
|
5
|
+
* last-progress timestamp tracked in state.json"; RFC-0001 §C.1 "spawns agent
|
|
6
|
+
* processes via the existing `run` machinery").
|
|
7
|
+
*
|
|
8
|
+
* The command is a template (default `claude -p --output-format json --model
|
|
9
|
+
* {model}` — the same headless invocation `ai-dossier run` builds in
|
|
10
|
+
* cli/src/helpers.ts) with `{model}`/`{issue}` placeholders; the prompt
|
|
11
|
+
* travels on stdin exactly like the run machinery's headless path. Children
|
|
12
|
+
* spawn DETACHED and unref'd: an agent must survive a sched crash (RFC F.10 —
|
|
13
|
+
* restart reconciles by pid, it never owns the agent's lifetime).
|
|
14
|
+
*
|
|
15
|
+
* All process I/O is injectable (`SpawnDeps`) so tests spawn fake agents, and
|
|
16
|
+
* the package itself never invokes an LLM — it spawns a process the operator
|
|
17
|
+
* configured.
|
|
18
|
+
*/
|
|
19
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
22
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
23
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
24
|
+
}
|
|
25
|
+
Object.defineProperty(o, k2, desc);
|
|
26
|
+
}) : (function(o, m, k, k2) {
|
|
27
|
+
if (k2 === undefined) k2 = k;
|
|
28
|
+
o[k2] = m[k];
|
|
29
|
+
}));
|
|
30
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
31
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
32
|
+
}) : function(o, v) {
|
|
33
|
+
o["default"] = v;
|
|
34
|
+
});
|
|
35
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
36
|
+
var ownKeys = function(o) {
|
|
37
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
38
|
+
var ar = [];
|
|
39
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
40
|
+
return ar;
|
|
41
|
+
};
|
|
42
|
+
return ownKeys(o);
|
|
43
|
+
};
|
|
44
|
+
return function (mod) {
|
|
45
|
+
if (mod && mod.__esModule) return mod;
|
|
46
|
+
var result = {};
|
|
47
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
48
|
+
__setModuleDefault(result, mod);
|
|
49
|
+
return result;
|
|
50
|
+
};
|
|
51
|
+
})();
|
|
52
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
+
exports.STOP_POLL_MAX_MS = exports.STOP_POLL_MIN_MS = exports.DEFAULT_REPORT_PROMPT_TEMPLATE = exports.DEFAULT_PROMPT_TEMPLATE = exports.OPENCODE_DISPATCH_COMMAND = exports.DEFAULT_DISPATCH_COMMAND = exports.DEFAULT_TIER_MODELS = void 0;
|
|
54
|
+
exports.resolveDispatch = resolveDispatch;
|
|
55
|
+
exports.buildAgentCommand = buildAgentCommand;
|
|
56
|
+
exports.buildPrompt = buildPrompt;
|
|
57
|
+
exports.buildReportPrompt = buildReportPrompt;
|
|
58
|
+
exports.escalateTier = escalateTier;
|
|
59
|
+
exports.reportTierFor = reportTierFor;
|
|
60
|
+
exports.unitLogName = unitLogName;
|
|
61
|
+
exports.procStartTime = procStartTime;
|
|
62
|
+
exports.createSpawnDeps = createSpawnDeps;
|
|
63
|
+
const node_child_process_1 = require("node:child_process");
|
|
64
|
+
const fs = __importStar(require("node:fs"));
|
|
65
|
+
const path = __importStar(require("node:path"));
|
|
66
|
+
const project_1 = require("./project");
|
|
67
|
+
const types_1 = require("./types");
|
|
68
|
+
/** Default tier → model mapping (claude aliases; override in config.json). */
|
|
69
|
+
exports.DEFAULT_TIER_MODELS = {
|
|
70
|
+
mechanical: 'haiku',
|
|
71
|
+
mid: 'sonnet',
|
|
72
|
+
strong: 'opus',
|
|
73
|
+
};
|
|
74
|
+
/** Default headless agent command template (claude, the run machinery's first choice). */
|
|
75
|
+
exports.DEFAULT_DISPATCH_COMMAND = [
|
|
76
|
+
'claude',
|
|
77
|
+
'-p',
|
|
78
|
+
'--output-format',
|
|
79
|
+
'json',
|
|
80
|
+
'--model',
|
|
81
|
+
'{model}',
|
|
82
|
+
];
|
|
83
|
+
/** opencode equivalent (the run machinery's second agent, #459). */
|
|
84
|
+
exports.OPENCODE_DISPATCH_COMMAND = [
|
|
85
|
+
'opencode',
|
|
86
|
+
'run',
|
|
87
|
+
'--format',
|
|
88
|
+
'json',
|
|
89
|
+
'--model',
|
|
90
|
+
'{model}',
|
|
91
|
+
];
|
|
92
|
+
/**
|
|
93
|
+
* Default prompt sent on the child's stdin. Detached ship mode (#468): the
|
|
94
|
+
* agent parks the PR on `auto-merge` and STOPS — the scheduler's PR watcher
|
|
95
|
+
* owns the merge wait and dispatches teardown + report as tail work. The
|
|
96
|
+
* fleet pattern of re-dispatching a full-cycle run for the tail is retired.
|
|
97
|
+
* Operators wanting attached runs (agent drives to the final report itself)
|
|
98
|
+
* override `dispatch.prompt` in config.json.
|
|
99
|
+
*/
|
|
100
|
+
exports.DEFAULT_PROMPT_TEMPLATE = 'Run the full-cycle-issue workflow for GitHub issue #{issue} in this repository.\n\n' +
|
|
101
|
+
'Begin by fetching the workflow: ai-dossier run imboard-ai/git/full-cycle-issue --pull\n\n' +
|
|
102
|
+
'Then execute it for issue #{issue} in detached ship mode (ship_mode=detached), following every ' +
|
|
103
|
+
'phase (gate, setup, plan, implement, review) without asking questions, until Phase 5 parks the ' +
|
|
104
|
+
'PR: apply the auto-merge label, post the awaiting-merge milestone, and STOP. Do not wait for ' +
|
|
105
|
+
'the merge, do not run teardown or report — the scheduler watches the PR and dispatches those.';
|
|
106
|
+
/**
|
|
107
|
+
* Default prompt for the report agent dispatched after a merged PR (#468
|
|
108
|
+
* AC2) — a cheap-tier run of the report phase only, never a full cycle.
|
|
109
|
+
*/
|
|
110
|
+
exports.DEFAULT_REPORT_PROMPT_TEMPLATE = 'Run the report phase for GitHub issue #{issue} in this repository.\n\n' +
|
|
111
|
+
'Begin by fetching the workflow: ai-dossier run imboard-ai/git/report-issue --pull\n\n' +
|
|
112
|
+
'The work is DONE: pull request #{pr} is merged (merge commit via `gh pr view {pr}`), the issue ' +
|
|
113
|
+
'is closed, and the worktree is already torn down (cleanup status: {cleanup}). Do not ' +
|
|
114
|
+
're-implement, re-review, or re-ship anything — produce the final report for issue #{issue} and ' +
|
|
115
|
+
'post its runstate milestone.';
|
|
116
|
+
/** Resolve engine dispatch settings from the (possibly sparse) config. */
|
|
117
|
+
function resolveDispatch(config) {
|
|
118
|
+
const dispatch = config.dispatch ?? {};
|
|
119
|
+
const tierModels = {
|
|
120
|
+
mechanical: dispatch.tier_models?.mechanical ?? exports.DEFAULT_TIER_MODELS.mechanical,
|
|
121
|
+
mid: dispatch.tier_models?.mid ?? exports.DEFAULT_TIER_MODELS.mid,
|
|
122
|
+
strong: dispatch.tier_models?.strong ?? exports.DEFAULT_TIER_MODELS.strong,
|
|
123
|
+
};
|
|
124
|
+
return {
|
|
125
|
+
command: dispatch.command ?? [...exports.DEFAULT_DISPATCH_COMMAND],
|
|
126
|
+
prompt: dispatch.prompt ?? exports.DEFAULT_PROMPT_TEMPLATE,
|
|
127
|
+
reportPrompt: dispatch.report_prompt ?? exports.DEFAULT_REPORT_PROMPT_TEMPLATE,
|
|
128
|
+
tierModels,
|
|
129
|
+
stallTimeoutMs: config.stall_timeout_ms ?? types_1.DEFAULT_STALL_TIMEOUT_MS,
|
|
130
|
+
reconcileIntervalMs: config.reconcile_interval_ms ?? types_1.DEFAULT_RECONCILE_INTERVAL_MS,
|
|
131
|
+
prPollIntervalMs: config.pr_poll_interval_ms ?? types_1.DEFAULT_PR_POLL_INTERVAL_MS,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Build the concrete agent argv for one dispatch: substitute `{issue}` and
|
|
136
|
+
* `{model}`. When the tier's model is null, the `{model}` item AND its
|
|
137
|
+
* immediately-preceding flag (e.g. `--model`) drop together — a command never
|
|
138
|
+
* carries a flag whose value is missing.
|
|
139
|
+
*/
|
|
140
|
+
function buildAgentCommand(template, tier, issue, tierModels) {
|
|
141
|
+
const model = tierModels[tier] ?? null;
|
|
142
|
+
const argv = [];
|
|
143
|
+
for (const item of template) {
|
|
144
|
+
if (item === '{model}') {
|
|
145
|
+
if (model === null) {
|
|
146
|
+
// Drop the preceding flag along with the placeholder.
|
|
147
|
+
if (argv.length > 0 && argv[argv.length - 1].startsWith('--'))
|
|
148
|
+
argv.pop();
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
argv.push(model);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
argv.push(item.replaceAll('{issue}', String(issue)));
|
|
155
|
+
}
|
|
156
|
+
return argv;
|
|
157
|
+
}
|
|
158
|
+
/** Build the child's stdin prompt for one dispatch. */
|
|
159
|
+
function buildPrompt(template, issue) {
|
|
160
|
+
return template.replaceAll('{issue}', String(issue));
|
|
161
|
+
}
|
|
162
|
+
/** Build the report agent's stdin prompt (#468): `{issue}`/`{pr}`/`{cleanup}` substituted. */
|
|
163
|
+
function buildReportPrompt(template, issue, pr, cleanup) {
|
|
164
|
+
return template
|
|
165
|
+
.replaceAll('{issue}', String(issue))
|
|
166
|
+
.replaceAll('{pr}', String(pr))
|
|
167
|
+
.replaceAll('{cleanup}', cleanup);
|
|
168
|
+
}
|
|
169
|
+
/** One tier stronger on the ladder, or null at the top (RFC-0001 §C.1). */
|
|
170
|
+
function escalateTier(tier) {
|
|
171
|
+
return types_1.TIER_LADDER[tier];
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* The tier for a report-agent (re)dispatch after `recoveries` escalations
|
|
175
|
+
* (#468): reports start cheap (mechanical) and climb the same ladder —
|
|
176
|
+
* mechanical → mid → strong — with null past the top. The engine's
|
|
177
|
+
* `ESCALATION_CAP` check fails the unit before that null is reached.
|
|
178
|
+
*/
|
|
179
|
+
function reportTierFor(recoveries) {
|
|
180
|
+
return types_1.TIER_ORDER[recoveries] ?? null;
|
|
181
|
+
}
|
|
182
|
+
/** `issue:464` → `issue-464` (filesystem-safe unit ids for log file names). */
|
|
183
|
+
function unitLogName(unit) {
|
|
184
|
+
return (0, project_1.sanitizeSlug)(unit);
|
|
185
|
+
}
|
|
186
|
+
/** Poll cadence bounds for `sleep`'s stop-check interval (engine loop). */
|
|
187
|
+
exports.STOP_POLL_MIN_MS = 100;
|
|
188
|
+
exports.STOP_POLL_MAX_MS = 1000;
|
|
189
|
+
/**
|
|
190
|
+
* `/proc/<pid>/stat` start-time (field 22, clock ticks since boot) — stable
|
|
191
|
+
* process identity for the lifetime of the pid, so a recycled pid is
|
|
192
|
+
* detectable. Null when /proc is unavailable (macOS/Windows) or the process
|
|
193
|
+
* is gone.
|
|
194
|
+
*/
|
|
195
|
+
function procStartTime(pid) {
|
|
196
|
+
try {
|
|
197
|
+
const stat = fs.readFileSync(`/proc/${pid}/stat`, 'utf-8');
|
|
198
|
+
// comm (field 2) is parenthesized and may contain spaces — everything
|
|
199
|
+
// after the LAST ')' is fields 3..N, space-separated.
|
|
200
|
+
const close = stat.lastIndexOf(')');
|
|
201
|
+
if (close === -1)
|
|
202
|
+
return null;
|
|
203
|
+
const fields = stat.slice(close + 2).split(' ');
|
|
204
|
+
// field 22 (starttime) -> index 19 in the post-comm array (field 3 = index 0)
|
|
205
|
+
const start = Number.parseInt(fields[19] ?? '', 10);
|
|
206
|
+
return Number.isInteger(start) && start >= 0 ? start : null;
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Real process I/O: detached spawn with output to a log file, unref'd.
|
|
214
|
+
*
|
|
215
|
+
* Pid-reuse guard (decision 1, option C — hybrid): every pid this instance
|
|
216
|
+
* spawns is recorded with its `/proc` start-time; `kill`/`isAlive` accept the
|
|
217
|
+
* start-time persisted in state.json and refuse a pid whose current
|
|
218
|
+
* start-time no longer matches (it was reused by an unrelated process — the
|
|
219
|
+
* agent we spawned is already dead, so skipping the signal loses nothing).
|
|
220
|
+
* On platforms without /proc the guard degrades to best-effort, and pids
|
|
221
|
+
* without a recorded start-time (e.g. from pre-decision state files) stay
|
|
222
|
+
* best-effort everywhere.
|
|
223
|
+
*/
|
|
224
|
+
function createSpawnDeps(cwd) {
|
|
225
|
+
/** Pids spawned by THIS instance -> their /proc start-time (Linux). */
|
|
226
|
+
const spawnedStarts = new Map();
|
|
227
|
+
/** True when `pid` plausibly still names the process we recorded. */
|
|
228
|
+
function matchesRecordedStart(pid, expectedStart) {
|
|
229
|
+
const expected = expectedStart ?? spawnedStarts.get(pid);
|
|
230
|
+
if (expected === undefined)
|
|
231
|
+
return true; // no recorded identity — best-effort
|
|
232
|
+
const current = procStartTime(pid);
|
|
233
|
+
if (current === null)
|
|
234
|
+
return true; // /proc unavailable (non-Linux) or a race — best-effort
|
|
235
|
+
return current === expected;
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
spawn(cmd, prompt, logFile) {
|
|
239
|
+
fs.mkdirSync(path.dirname(logFile), { recursive: true, mode: 0o700 });
|
|
240
|
+
const out = fs.openSync(logFile, 'a', 0o600);
|
|
241
|
+
try {
|
|
242
|
+
const child = (0, node_child_process_1.spawn)(cmd[0], cmd.slice(1), {
|
|
243
|
+
...(cwd ? { cwd } : {}),
|
|
244
|
+
detached: true,
|
|
245
|
+
stdio: ['pipe', out, out],
|
|
246
|
+
});
|
|
247
|
+
// Spawn failures surface synchronously via the pid check below; the
|
|
248
|
+
// async 'error' event must never crash the engine (ENOENT), and an
|
|
249
|
+
// agent exiting before reading stdin must never crash it either (EPIPE).
|
|
250
|
+
child.on('error', (err) => {
|
|
251
|
+
process.stderr.write(`⚠ sched: spawn '${cmd[0]}' failed: ${err.message}\n`);
|
|
252
|
+
});
|
|
253
|
+
if (child.stdin !== null) {
|
|
254
|
+
child.stdin.on('error', () => { });
|
|
255
|
+
child.stdin.write(prompt);
|
|
256
|
+
child.stdin.end();
|
|
257
|
+
}
|
|
258
|
+
child.unref();
|
|
259
|
+
if (child.pid === undefined) {
|
|
260
|
+
throw new Error(`failed to spawn '${cmd[0]}' — is it on PATH? (command: ${cmd.join(' ')})`);
|
|
261
|
+
}
|
|
262
|
+
const start = procStartTime(child.pid);
|
|
263
|
+
if (start !== null)
|
|
264
|
+
spawnedStarts.set(child.pid, start);
|
|
265
|
+
return child.pid;
|
|
266
|
+
}
|
|
267
|
+
finally {
|
|
268
|
+
// The child holds its own dups of the fd; the parent's copy must close.
|
|
269
|
+
fs.closeSync(out);
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
kill(pid, expectedStart) {
|
|
273
|
+
if (!matchesRecordedStart(pid, expectedStart)) {
|
|
274
|
+
spawnedStarts.delete(pid);
|
|
275
|
+
return false; // reused pid — the agent we spawned is already gone
|
|
276
|
+
}
|
|
277
|
+
try {
|
|
278
|
+
process.kill(pid, 'SIGTERM');
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
spawnedStarts.delete(pid);
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
isAlive(pid, expectedStart) {
|
|
287
|
+
try {
|
|
288
|
+
process.kill(pid, 0);
|
|
289
|
+
return matchesRecordedStart(pid, expectedStart);
|
|
290
|
+
}
|
|
291
|
+
catch (err) {
|
|
292
|
+
return err.code === 'EPERM';
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
processStart(pid) {
|
|
296
|
+
return procStartTime(pid);
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"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"}
|