@welluable/orch 1.3.0 → 1.4.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 +94 -18
- package/agents/adjust.js +66 -0
- package/agents/ask.js +3 -5
- package/agents/boundaries.js +3 -4
- package/agents/code-writer.js +3 -5
- package/agents/decomposer.js +5 -5
- package/agents/index.js +2 -0
- package/agents/integrator.js +3 -4
- package/agents/planner.js +3 -5
- package/agents/quick-fix.js +3 -5
- package/agents/research.js +3 -5
- package/agents/seq-decomposer.js +58 -0
- package/agents/summary-footer.js +23 -0
- package/agents/test-critic.js +5 -6
- package/agents/test-runner.js +5 -6
- package/agents/test-writer.js +3 -5
- package/agents/triage.js +5 -6
- package/lib/agent-agn.js +4 -2
- package/lib/agent-cursor.js +4 -2
- package/lib/agent-opencode.js +177 -0
- package/lib/agent.js +150 -12
- package/lib/config.js +92 -17
- package/lib/continue.js +25 -7
- package/lib/failure-log.js +72 -0
- package/lib/file-tracker.js +68 -12
- package/lib/jobs.js +131 -6
- package/lib/notify.js +71 -0
- package/lib/resume.js +264 -0
- package/lib/seq.js +281 -0
- package/lib/stage-summary.js +24 -0
- package/lib/tool-status.js +53 -6
- package/main.js +2571 -412
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ orch: commit: a1b2c3d on orch/verbose-flag-x7q2
|
|
|
34
34
|
worktree on an `orch/<slug>` branch, so your working tree stays untouched
|
|
35
35
|
until you decide to merge.
|
|
36
36
|
- **Agent-agnostic backends.** Pick the CLI you already trust with
|
|
37
|
-
`--agent cursor|claude|agn` — orch owns the pipeline, the agent CLI does
|
|
37
|
+
`--agent cursor|claude|agn|opencode` — orch owns the pipeline, the agent CLI does
|
|
38
38
|
the reading and writing.
|
|
39
39
|
- **Readable runs.** Every stage prints a one-paragraph natural-language
|
|
40
40
|
summary of what it did; add `-v` if you also want the raw thinking/output
|
|
@@ -50,7 +50,7 @@ npm install -g @welluable/orch
|
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
Make sure an agent CLI is on your `PATH` — orch defaults to `--agent cursor`
|
|
53
|
-
(the Cursor Agent CLI, command `agent`); `claude` and `
|
|
53
|
+
(the Cursor Agent CLI, command `agent`); `claude`, `agn`, and `opencode` are also
|
|
54
54
|
supported. Pin a default with `orch config --agent <name>` so you don't need
|
|
55
55
|
`--agent` on every run (local `.orch/config` overrides global
|
|
56
56
|
`~/.orch/config`; CLI `--agent` still wins). See [Requirements](#requirements)
|
|
@@ -156,7 +156,8 @@ runs, since foreground runs already stream their output to your terminal.
|
|
|
156
156
|
▼
|
|
157
157
|
┌──────────────────────┐
|
|
158
158
|
│ agent backend adapter │
|
|
159
|
-
│ (cursor
|
|
159
|
+
│ (cursor/claude/agn/ │
|
|
160
|
+
│ opencode) │
|
|
160
161
|
└──────────────────────┘
|
|
161
162
|
```
|
|
162
163
|
|
|
@@ -174,7 +175,8 @@ agent CLI does all the actual reading and writing of files.
|
|
|
174
175
|
| `--detach` | Runs the pipeline in a background process and returns immediately, printing the run slug. Manage it with `orch list/status/pause/resume/stop/logs`. | You want to kick off a run and keep using your shell, or run several tasks concurrently. |
|
|
175
176
|
|
|
176
177
|
For `--ask`, Cursor uses `--mode ask`, Claude uses `--permission-mode plan`,
|
|
177
|
-
|
|
178
|
+
`agn` is prompt-only best-effort (it has no dedicated read-only flag), and
|
|
179
|
+
OpenCode uses `--agent plan` with `edit`/`bash` denied via `OPENCODE_PERMISSION`.
|
|
178
180
|
|
|
179
181
|
`--detach` only controls backgrounding, not whether a job record exists —
|
|
180
182
|
every non-`--dry-run` invocation gets one. Combining `--detach` with
|
|
@@ -206,24 +208,36 @@ Usage: orch [options] [command] <task...>
|
|
|
206
208
|
implementer loop; defaults to `5`, ignored with `--ask` and `--quick`.
|
|
207
209
|
- `--fan-out` — decomposes the task into parallel workers coordinated by this
|
|
208
210
|
process instead of running the single-worktree pipeline (see
|
|
209
|
-
[Fan-out](#fan-out)); rejects `--ask`/`--quick`/`--dry-run`.
|
|
211
|
+
[Fan-out](#fan-out)); rejects `--ask`/`--quick`/`--dry-run`/`--seq`.
|
|
212
|
+
- `--seq` — decomposes into ordered units, merges each into `orch/<slug>`,
|
|
213
|
+
then adjusts the near-term backlog (see
|
|
214
|
+
[Sequential multi-unit (`--seq`)](#sequential-multi-unit---seq)); rejects
|
|
215
|
+
`--fan-out`/`--ask`/`--quick`/`--dry-run`.
|
|
210
216
|
- `--max-workers <n>` — max number of parallel fan-out workers; defaults to
|
|
211
217
|
`4`; only meaningful with `--fan-out`.
|
|
218
|
+
- `--max-units <n>` — max number of sequential units; defaults to `8`; only
|
|
219
|
+
meaningful with `--seq`.
|
|
212
220
|
- `--max-concurrency <n>` — optional hard ceiling on in-flight fan-out workers
|
|
213
221
|
at once; omit to let the coordinator choose (typically the current layer's
|
|
214
222
|
size); only meaningful with `--fan-out`.
|
|
215
|
-
- `--agent <cursor|claude|agn>` — selects the backend for the whole pipeline;
|
|
223
|
+
- `--agent <cursor|claude|agn|opencode>` — selects the backend for the whole pipeline;
|
|
216
224
|
when omitted, uses local `.orch/config`, then global `~/.orch/config`, else
|
|
217
225
|
`cursor`.
|
|
226
|
+
- `--notify` / `--no-notify` — enable or disable a desktop notification when a
|
|
227
|
+
job reaches a terminal state (`done` / `failed` / `stopped` / `crashed`).
|
|
228
|
+
Default is on; config key `notify` and these flags share precedence
|
|
229
|
+
CLI > local > global > on. Dry-run never notifies.
|
|
218
230
|
- `-h, --help` — displays help for the command.
|
|
219
231
|
|
|
220
232
|
Config:
|
|
221
233
|
|
|
222
|
-
- `orch config` — prints the effective agent and
|
|
223
|
-
(local / global / default). Does not prompt.
|
|
224
|
-
- `orch config --agent <cursor|claude|agn> [--global|--local]` — writes the
|
|
234
|
+
- `orch config` — prints the effective agent and notify settings and which
|
|
235
|
+
file(s) contributed (local / global / default). Does not prompt.
|
|
236
|
+
- `orch config --agent <cursor|claude|agn|opencode> [--global|--local]` — writes the
|
|
225
237
|
default agent. Bare `--agent` (and `--global`) write `~/.orch/config`;
|
|
226
238
|
`--local` writes `<cwd>/.orch/config`. There is no `orch init`.
|
|
239
|
+
- `orch config --notify` / `--no-notify` `[--local|--global]` — set desktop
|
|
240
|
+
notify on or off without wiping `agent` (keys merge on write).
|
|
227
241
|
|
|
228
242
|
Job-control subcommands (see [Headless runs](#headless-runs)):
|
|
229
243
|
|
|
@@ -232,17 +246,21 @@ Job-control subcommands (see [Headless runs](#headless-runs)):
|
|
|
232
246
|
recently started run.
|
|
233
247
|
- `orch pause <slug>` — requests a pause at the run's next stage-boundary
|
|
234
248
|
checkpoint.
|
|
235
|
-
- `orch resume <slug>` — unpauses a paused
|
|
249
|
+
- `orch resume <slug>` — unpauses a paused/pausing run, or recovers a
|
|
250
|
+
failed/stopped/crashed complex job at its unfinished stage (thin recover +
|
|
251
|
+
reentry; see failure resume). Not the same as continue.
|
|
236
252
|
- `orch continue <slug> "new task"` — starts a new complex pipeline on a
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
worker slug, then `orch --integrate <parent>`.
|
|
253
|
+
**done** run's existing worktree/branch (same slug). Carries prior outcome
|
|
254
|
+
into research/plan. For crash recovery use `orch resume` instead. For fan-out
|
|
255
|
+
workers that finished, continue the worker slug, then `orch --integrate <parent>`.
|
|
240
256
|
- `orch stop <slug>` — sends `SIGTERM` to a running job (or reconciles a dead
|
|
241
257
|
one to `crashed`).
|
|
242
258
|
- `orch logs <slug> [-f]` — prints a run's `orch.log`; `-f` follows it until
|
|
243
259
|
the job reaches a terminal state.
|
|
244
260
|
- `orch jobs clean` — deletes every run tracked under `.orch/` in the current
|
|
245
|
-
directory, after a `y/N` confirmation prompt.
|
|
261
|
+
directory, after a `y/N` confirmation prompt. Refuses (without prompting)
|
|
262
|
+
if any job is still live (`running`/`pausing`/`paused` with an alive pid);
|
|
263
|
+
run `orch stop <slug>` first, then clean.
|
|
246
264
|
|
|
247
265
|
Examples:
|
|
248
266
|
|
|
@@ -250,12 +268,16 @@ Examples:
|
|
|
250
268
|
orch "fix the typo in the README" --agent claude
|
|
251
269
|
orch "fix the bug described in task.md" --agent cursor -v
|
|
252
270
|
orch "implement the local spec" --agent agn -v
|
|
271
|
+
orch "fix the typo in the README" --agent opencode
|
|
253
272
|
orch --ask "where is the CLI entrypoint?" --agent claude
|
|
273
|
+
orch --ask "where is package.json?" --agent opencode
|
|
254
274
|
orch --quick "fix the typo in the README" --agent claude
|
|
255
275
|
orch "noop" --dry-run --agent cursor
|
|
276
|
+
orch "noop" --dry-run --agent opencode
|
|
256
277
|
orch config
|
|
257
278
|
orch config --agent claude
|
|
258
279
|
orch config --agent agn --local
|
|
280
|
+
orch config --agent opencode
|
|
259
281
|
```
|
|
260
282
|
|
|
261
283
|
## Headless runs
|
|
@@ -279,11 +301,11 @@ directory's `.orch/`:
|
|
|
279
301
|
orch list # SLUG ROLE STATE PHASE AGENT STARTED DURATION PID
|
|
280
302
|
orch status swift-lagoon-49ea # full record: state, phase, branch, worktree, exit code, ...
|
|
281
303
|
orch pause swift-lagoon-49ea # request a pause at the next stage-boundary checkpoint
|
|
282
|
-
orch resume swift-lagoon-49ea # unpause
|
|
283
|
-
orch continue swift-lagoon-49ea "follow-up polish" # new work on
|
|
304
|
+
orch resume swift-lagoon-49ea # unpause, or recover failed/stopped/crashed
|
|
305
|
+
orch continue swift-lagoon-49ea "follow-up polish" # new work on a done run
|
|
284
306
|
orch logs swift-lagoon-49ea -f # follow orch.log until the run finishes
|
|
285
307
|
orch stop swift-lagoon-49ea # SIGTERM the run
|
|
286
|
-
orch jobs clean # delete every tracked run under .orch/ (asks to confirm)
|
|
308
|
+
orch jobs clean # delete every tracked run under .orch/ (asks to confirm; refuses if live)
|
|
287
309
|
```
|
|
288
310
|
|
|
289
311
|
Pausing is cooperative and happens at stage boundaries (before the first
|
|
@@ -414,6 +436,58 @@ Depth is capped at 1: every worker and the integration session run with
|
|
|
414
436
|
variable is already present — a worker or integration session never fans out
|
|
415
437
|
again.
|
|
416
438
|
|
|
439
|
+
## Sequential multi-unit (`--seq`)
|
|
440
|
+
|
|
441
|
+
Big features fail in one context window. orch splits them into units agents
|
|
442
|
+
can finish. `--fan-out` runs independent units in parallel; `--seq` runs
|
|
443
|
+
ordered units one-by-one, merging each into `orch/<slug>` before adjusting
|
|
444
|
+
the next.
|
|
445
|
+
|
|
446
|
+
| | `--fan-out` | `--seq` |
|
|
447
|
+
|---|---|---|
|
|
448
|
+
| Split reason | Parallel independence | Finishable unit size + order |
|
|
449
|
+
| Boundaries | Yes | **No** |
|
|
450
|
+
| Unit shape | Workers + `dependsOn` / `owns` / layers | **Flat ordered list** |
|
|
451
|
+
| Schedule | Parallel (layers / concurrency) | **Strictly one unit at a time** |
|
|
452
|
+
| Base SHA | One shared base for all workers | **Advances after each merge** |
|
|
453
|
+
| Integrate | One session at the end | **Merge + verify after every unit** |
|
|
454
|
+
| Replan | Frozen after decompose | **Hybrid adjust** after each merge |
|
|
455
|
+
|
|
456
|
+
```bash
|
|
457
|
+
orch "implement the billing module" --seq --agent claude
|
|
458
|
+
orch "implement X" --seq --max-units 6
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
```text
|
|
462
|
+
triage: complex — seq requested
|
|
463
|
+
decomposer: 5 units
|
|
464
|
+
[01-types …] done — merged into orch/wise-pine-e904
|
|
465
|
+
adjust: rewrote 02-api against tip; dropped 05-legacy-path
|
|
466
|
+
[02-api …] done — merged
|
|
467
|
+
[03-ui …] failed at code-loop / test-runner (round 3)
|
|
468
|
+
stopped: 2/5 merged; next: orch resume <unit-slug>
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
The flow, in order:
|
|
472
|
+
|
|
473
|
+
1. **Triage** runs once. If it routes to quick-fix, seq is skipped entirely —
|
|
474
|
+
triage never opts into `--seq` on its own.
|
|
475
|
+
2. **`seq-decomposer`** (no boundaries agent) emits an ordered `units[]`
|
|
476
|
+
backlog, or declines → today's single-worktree pipeline with no `seq.json`.
|
|
477
|
+
3. **Schedule** runs concurrency 1: spawn the first pending unit at the current
|
|
478
|
+
tip → wait → on failure stop the chain → on success merge into
|
|
479
|
+
`orch/<parent-slug>`, runner-first verify, advance tip, hybrid-adjust the
|
|
480
|
+
next 1–2 pending units (or drop obsolete ones), continue.
|
|
481
|
+
4. **Continue / resume.** Fix a failed unit with `orch resume <unit-slug>`,
|
|
482
|
+
then `orch --seq-continue <parent>` (or `orch resume <parent>` when paused).
|
|
483
|
+
Use `orch continue <unit-slug>` only for new follow-up work on a done unit.
|
|
484
|
+
Do not `orch continue` the coordinator.
|
|
485
|
+
|
|
486
|
+
`--max-units` (default `8`) caps both the initial backlog and adjust growth.
|
|
487
|
+
Unit children set `ORCH_SEQ_DEPTH=1` and `ORCH_FANOUT_DEPTH=1` so they cannot
|
|
488
|
+
nest `--seq` or `--fan-out`. Deliverable stays on `orch/<parent-slug>` until
|
|
489
|
+
you merge it yourself.
|
|
490
|
+
|
|
417
491
|
## Project structure
|
|
418
492
|
|
|
419
493
|
Complex runs create a run directory and a sibling worktree, reusing the
|
|
@@ -446,6 +520,7 @@ manually if that happens:
|
|
|
446
520
|
pkill -f 'agent -p' # --agent cursor
|
|
447
521
|
pkill -f 'claude ' # --agent claude, adjust to local argv
|
|
448
522
|
pkill -f 'agn ' # --agent agn
|
|
523
|
+
pkill -f 'opencode run' # --agent opencode
|
|
449
524
|
```
|
|
450
525
|
|
|
451
526
|
## Agent compatibility
|
|
@@ -455,12 +530,13 @@ pkill -f 'agn ' # --agent agn
|
|
|
455
530
|
| Cursor Agent CLI | `cursor` | Supported (builtin default) | Command `agent` on `PATH`. Override via `orch config` or `--agent`. |
|
|
456
531
|
| Claude Code CLI | `claude` | Supported | Command `claude` on `PATH`. |
|
|
457
532
|
| agn | `agn` | Supported | Requires `npm install -g @welluable/agn-cli` (`>= 0.0.12`) and `agn init`. |
|
|
533
|
+
| OpenCode CLI | `opencode` | Supported | Command `opencode` on `PATH` (`>= 1.17.18`). Install from https://opencode.ai; first-time setup: `opencode auth login`. Read-only/`--ask` uses `--agent plan` with edit/bash denied. |
|
|
458
534
|
|
|
459
535
|
## Requirements
|
|
460
536
|
|
|
461
537
|
- A modern Node.js runtime.
|
|
462
538
|
- One supported agent CLI on your `PATH`: `agent` (Cursor), `claude` (Claude
|
|
463
|
-
Code), or `
|
|
539
|
+
Code), `agn`, or `opencode` (OpenCode `>= 1.17.18`).
|
|
464
540
|
- Git, for any run that isn't `--ask` or `--quick` (worktrees and commits
|
|
465
541
|
need it).
|
|
466
542
|
|
package/agents/adjust.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { summaryTrailerInstructions } from './summary-footer.js';
|
|
2
|
+
|
|
3
|
+
function feedbackBlock(feedback) {
|
|
4
|
+
if (!Array.isArray(feedback) || feedback.length === 0) return '';
|
|
5
|
+
const violations = feedback.map((violation) => `- ${violation}`).join('\n');
|
|
6
|
+
return `
|
|
7
|
+
|
|
8
|
+
[Validation Feedback]
|
|
9
|
+
Your previous adjust result was rejected for these reasons. Fix them and
|
|
10
|
+
try again:
|
|
11
|
+
${violations}
|
|
12
|
+
[/Validation Feedback]`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function formatUnits(units) {
|
|
16
|
+
if (!Array.isArray(units) || units.length === 0) return '(none)';
|
|
17
|
+
return units
|
|
18
|
+
.map((u) => `- ${u.id}: ${u.title} — ${u.subtask}${u.sha ? ` (sha ${u.sha})` : ''}`)
|
|
19
|
+
.join('\n');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function adjustAgentArgs({
|
|
23
|
+
originalTask,
|
|
24
|
+
doneUnits,
|
|
25
|
+
pendingUnits,
|
|
26
|
+
tip,
|
|
27
|
+
cwd,
|
|
28
|
+
maxUnits,
|
|
29
|
+
feedback,
|
|
30
|
+
}) {
|
|
31
|
+
return {
|
|
32
|
+
name: 'adjust',
|
|
33
|
+
instructions: `
|
|
34
|
+
You are an Adjust Agent for a sequential orch run.
|
|
35
|
+
|
|
36
|
+
* The original task is the hard fence — do not expand product scope past it:
|
|
37
|
+
${originalTask}
|
|
38
|
+
* Current tip SHA of the integration branch: ${tip}
|
|
39
|
+
* Done units (do not rewrite or drop these):
|
|
40
|
+
${formatUnits(doneUnits)}
|
|
41
|
+
* Pending units in schedule order:
|
|
42
|
+
${formatUnits(pendingUnits)}
|
|
43
|
+
* You may rewrite at most the next two pending units' title/subtask texts
|
|
44
|
+
so they match the tip. You may drop obsolete pending units. Do not invent
|
|
45
|
+
new ids. Do not resurrect done/failed work as new ids. Respect maxUnits
|
|
46
|
+
${maxUnits} (rewrite/drop only — do not grow the backlog).
|
|
47
|
+
* Your final message MUST be valid JSON only — no markdown, no prose
|
|
48
|
+
outside JSON:
|
|
49
|
+
|
|
50
|
+
{
|
|
51
|
+
"rewrites": [
|
|
52
|
+
{ "id": "02-api", "title": "optional new title", "subtask": "optional new subtask" }
|
|
53
|
+
],
|
|
54
|
+
"drops": ["04-obsolete"]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Use empty arrays when you have no rewrites or drops.
|
|
58
|
+
* Before the summary marker below, the JSON itself must stay exactly as
|
|
59
|
+
specified above.
|
|
60
|
+
${summaryTrailerInstructions({ before: 'the JSON verdict only' })}
|
|
61
|
+
${feedbackBlock(feedback)}
|
|
62
|
+
`,
|
|
63
|
+
prompt: originalTask,
|
|
64
|
+
options: { cwd },
|
|
65
|
+
};
|
|
66
|
+
}
|
package/agents/ask.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { summaryTrailerInstructions } from './summary-footer.js';
|
|
2
|
+
|
|
1
3
|
export function askAgentArgs({ prompt, cwd }) {
|
|
2
4
|
return {
|
|
3
5
|
name: 'ask',
|
|
@@ -10,11 +12,7 @@ export function askAgentArgs({ prompt, cwd }) {
|
|
|
10
12
|
* Put the full answer in your final message.
|
|
11
13
|
* Before the summary marker below, your message should only have the
|
|
12
14
|
answer, no other text.
|
|
13
|
-
|
|
14
|
-
'<' characters, then SUMMARY, then three '>' characters, with no
|
|
15
|
-
spaces), followed by one paragraph in natural, human-readable language
|
|
16
|
-
explaining what you did in this step and what happened — no lists, no
|
|
17
|
-
headers, just prose.
|
|
15
|
+
${summaryTrailerInstructions({ before: 'the answer' })}
|
|
18
16
|
`,
|
|
19
17
|
prompt,
|
|
20
18
|
options: { cwd, readOnly: true },
|
package/agents/boundaries.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { summaryTrailerInstructions } from './summary-footer.js';
|
|
2
|
+
|
|
1
3
|
export function boundariesAgentArgs({ prompt, cwd, boundariesPath }) {
|
|
2
4
|
return {
|
|
3
5
|
name: 'boundaries',
|
|
@@ -15,10 +17,7 @@ export function boundariesAgentArgs({ prompt, cwd, boundariesPath }) {
|
|
|
15
17
|
${boundariesPath}
|
|
16
18
|
* Before the summary marker below, your message must contain only the
|
|
17
19
|
exact path: ${boundariesPath}
|
|
18
|
-
|
|
19
|
-
\`<<<SUMMARY>>>\`, followed by one paragraph in natural, human-readable
|
|
20
|
-
language explaining what you did in this step and what happened — no
|
|
21
|
-
lists, no headers, just prose.
|
|
20
|
+
${summaryTrailerInstructions({ before: `the exact path: ${boundariesPath}` })}
|
|
22
21
|
`,
|
|
23
22
|
prompt,
|
|
24
23
|
options: { cwd },
|
package/agents/code-writer.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { summaryTrailerInstructions } from './summary-footer.js';
|
|
2
|
+
|
|
1
3
|
export function codeWriterAgentArgs({
|
|
2
4
|
prompt,
|
|
3
5
|
cwd,
|
|
@@ -42,11 +44,7 @@ export function codeWriterAgentArgs({
|
|
|
42
44
|
* Do not run \`git add\`, \`git commit\`, or any other git branch/commit
|
|
43
45
|
command. Leave changes unstaged — orch commits after the pipeline finishes.
|
|
44
46
|
* Once implementation is done, the task is complete.
|
|
45
|
-
|
|
46
|
-
marker (three '<' characters, then SUMMARY, then three '>'
|
|
47
|
-
characters, with no spaces), followed by one paragraph in natural,
|
|
48
|
-
human-readable language explaining what you did in this step and
|
|
49
|
-
what happened — no lists, no headers, just prose.
|
|
47
|
+
${summaryTrailerInstructions({ before: 'your final message' })}
|
|
50
48
|
* If you changed any files, after that paragraph add a line reading
|
|
51
49
|
exactly "Files:" followed by one line per changed file formatted
|
|
52
50
|
as "<path>: <one-line description>" (e.g. "lib/agent.js: wired the
|
package/agents/decomposer.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { summaryTrailerInstructions } from './summary-footer.js';
|
|
2
|
+
|
|
1
3
|
function feedbackBlock(feedback) {
|
|
2
4
|
if (!Array.isArray(feedback) || feedback.length === 0) return '';
|
|
3
5
|
const violations = feedback.map((violation) => `- ${violation}`).join('\n');
|
|
@@ -46,11 +48,9 @@ export function decomposerAgentArgs({ prompt, cwd, boundariesOutput, maxWorkers,
|
|
|
46
48
|
"decomposable": false,
|
|
47
49
|
"why": "short reason"
|
|
48
50
|
}
|
|
49
|
-
*
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
lists, no headers, just prose. The JSON itself must stay exactly as
|
|
53
|
-
specified above, before the summary marker.
|
|
51
|
+
* Before the summary marker below, the JSON itself must stay exactly as
|
|
52
|
+
specified above.
|
|
53
|
+
${summaryTrailerInstructions({ before: 'the JSON verdict only' })}
|
|
54
54
|
|
|
55
55
|
[Boundaries Agent Output]
|
|
56
56
|
${boundariesOutput}
|
package/agents/index.js
CHANGED
|
@@ -10,3 +10,5 @@ export { testRunnerAgentArgs } from './test-runner.js';
|
|
|
10
10
|
export { integratorAgentArgs } from './integrator.js';
|
|
11
11
|
export { boundariesAgentArgs } from './boundaries.js';
|
|
12
12
|
export { decomposerAgentArgs } from './decomposer.js';
|
|
13
|
+
export { seqDecomposerAgentArgs } from './seq-decomposer.js';
|
|
14
|
+
export { adjustAgentArgs } from './adjust.js';
|
package/agents/integrator.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { summaryTrailerInstructions } from './summary-footer.js';
|
|
2
|
+
|
|
1
3
|
/** Conflict-repair-only agent for the `--integrate` driver: resolves merge conflict
|
|
2
4
|
* markers in the given files using the merge output and involved workers' subtask/area
|
|
3
5
|
* as context. Never touches git itself — orch owns the merge commit. */
|
|
@@ -26,10 +28,7 @@ export function integratorAgentArgs({ prompt, cwd, conflictedFiles, mergeOutput,
|
|
|
26
28
|
command. orch completes the merge commit itself; you only edit files.
|
|
27
29
|
* Do not report a pass/fail judgment of any kind; orch checks whether
|
|
28
30
|
the conflict markers are gone itself.
|
|
29
|
-
|
|
30
|
-
\`<<<SUMMARY>>>\`, followed by one paragraph in natural,
|
|
31
|
-
human-readable language explaining what you did in this step and
|
|
32
|
-
what happened — no lists, no headers, just prose.
|
|
31
|
+
${summaryTrailerInstructions({ before: 'your conflict-resolution work' })}
|
|
33
32
|
|
|
34
33
|
[Merge Output]
|
|
35
34
|
${mergeOutput}
|
package/agents/planner.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { summaryTrailerInstructions } from './summary-footer.js';
|
|
2
|
+
|
|
1
3
|
export function plannerAgentArgs({ prompt, cwd, researchPath, taskPath, researchOutput }) {
|
|
2
4
|
return {
|
|
3
5
|
name: 'planner',
|
|
@@ -10,11 +12,7 @@ export function plannerAgentArgs({ prompt, cwd, researchPath, taskPath, research
|
|
|
10
12
|
the exact path: ${taskPath}
|
|
11
13
|
* Before the summary marker below, your message must contain only the
|
|
12
14
|
exact path: ${taskPath}
|
|
13
|
-
|
|
14
|
-
'<' characters, then SUMMARY, then three '>' characters, with no
|
|
15
|
-
spaces), followed by one paragraph in natural, human-readable language
|
|
16
|
-
explaining what you did in this step and what happened — no lists, no
|
|
17
|
-
headers, just prose.
|
|
15
|
+
${summaryTrailerInstructions({ before: `the exact path: ${taskPath}` })}
|
|
18
16
|
|
|
19
17
|
[Research Agent Output]
|
|
20
18
|
${researchOutput}
|
package/agents/quick-fix.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { summaryTrailerInstructions } from './summary-footer.js';
|
|
2
|
+
|
|
1
3
|
export function quickFixAgentArgs({ prompt, cwd, fix_plan }) {
|
|
2
4
|
const fixPlan = fix_plan
|
|
3
5
|
? `
|
|
@@ -17,11 +19,7 @@ export function quickFixAgentArgs({ prompt, cwd, fix_plan }) {
|
|
|
17
19
|
* Apply changes in the current working tree.
|
|
18
20
|
* Do not write research.md or task.md.
|
|
19
21
|
* Do not create a git worktree.
|
|
20
|
-
|
|
21
|
-
marker (three '<' characters, then SUMMARY, then three '>'
|
|
22
|
-
characters, with no spaces), followed by one paragraph in
|
|
23
|
-
natural, human-readable language explaining what you did in this
|
|
24
|
-
step and what happened — no lists, no headers, just prose.
|
|
22
|
+
${summaryTrailerInstructions({ before: 'your final message' })}
|
|
25
23
|
* If you changed any files, after that paragraph add a line reading
|
|
26
24
|
exactly "Files:" followed by one line per changed file formatted
|
|
27
25
|
as "<path>: <one-line description>" (e.g. "README.md: documented
|
package/agents/research.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { summaryTrailerInstructions } from './summary-footer.js';
|
|
2
|
+
|
|
1
3
|
export function researchAgentArgs({ prompt, cwd, researchPath }) {
|
|
2
4
|
return {
|
|
3
5
|
name: 'research',
|
|
@@ -11,11 +13,7 @@ export function researchAgentArgs({ prompt, cwd, researchPath }) {
|
|
|
11
13
|
findings only to the exact path: ${researchPath}
|
|
12
14
|
* Before the summary marker below, your message must contain only the
|
|
13
15
|
exact path: ${researchPath}
|
|
14
|
-
|
|
15
|
-
'<' characters, then SUMMARY, then three '>' characters, with no
|
|
16
|
-
spaces), followed by one paragraph in natural, human-readable language
|
|
17
|
-
explaining what you did in this step and what happened — no lists, no
|
|
18
|
-
headers, just prose.
|
|
16
|
+
${summaryTrailerInstructions({ before: `the exact path: ${researchPath}` })}
|
|
19
17
|
`,
|
|
20
18
|
prompt,
|
|
21
19
|
options: { cwd },
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { summaryTrailerInstructions } from './summary-footer.js';
|
|
2
|
+
|
|
3
|
+
function feedbackBlock(feedback) {
|
|
4
|
+
if (!Array.isArray(feedback) || feedback.length === 0) return '';
|
|
5
|
+
const violations = feedback.map((violation) => `- ${violation}`).join('\n');
|
|
6
|
+
return `
|
|
7
|
+
|
|
8
|
+
[Validation Feedback]
|
|
9
|
+
Your previous decomposition was rejected for these reasons. Fix them and
|
|
10
|
+
try again:
|
|
11
|
+
${violations}
|
|
12
|
+
[/Validation Feedback]`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function seqDecomposerAgentArgs({ prompt, cwd, maxUnits, feedback }) {
|
|
16
|
+
return {
|
|
17
|
+
name: 'seq-decomposer',
|
|
18
|
+
instructions: `
|
|
19
|
+
You are a Seq-Decomposer Agent.
|
|
20
|
+
|
|
21
|
+
* Read the original task and decide whether the work can be split into an
|
|
22
|
+
ordered backlog of finishable units. Order is the schedule — a flat
|
|
23
|
+
list only, not a parallel dependency graph.
|
|
24
|
+
* At most ${maxUnits} units — that is a hard ceiling, not a target.
|
|
25
|
+
* Each unit object must contain only id, title, and subtask.
|
|
26
|
+
* "decomposable": false (with a "why") is a valid answer when you cannot
|
|
27
|
+
find a useful ordered split — do not force a split. That is the
|
|
28
|
+
not decomposable / decomposable: false path.
|
|
29
|
+
* Your final message MUST be valid JSON only — no markdown, no prose
|
|
30
|
+
outside JSON:
|
|
31
|
+
|
|
32
|
+
{
|
|
33
|
+
"decomposable": true,
|
|
34
|
+
"why": "short reason",
|
|
35
|
+
"units": [
|
|
36
|
+
{
|
|
37
|
+
"id": "01-types",
|
|
38
|
+
"title": "short title",
|
|
39
|
+
"subtask": "what this unit implements"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
or, when declining:
|
|
45
|
+
|
|
46
|
+
{
|
|
47
|
+
"decomposable": false,
|
|
48
|
+
"why": "short reason"
|
|
49
|
+
}
|
|
50
|
+
* Before the summary marker below, the JSON itself must stay exactly as
|
|
51
|
+
specified above.
|
|
52
|
+
${summaryTrailerInstructions({ before: 'the JSON verdict only' })}
|
|
53
|
+
${feedbackBlock(feedback)}
|
|
54
|
+
`,
|
|
55
|
+
prompt,
|
|
56
|
+
options: { cwd },
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared `<<<SUMMARY>>>` trailer instructions for every stage agent.
|
|
3
|
+
* @param {{ before?: string }} [opts]
|
|
4
|
+
*/
|
|
5
|
+
export function summaryTrailerInstructions({ before = 'required stage output' } = {}) {
|
|
6
|
+
return `
|
|
7
|
+
* Your final message MUST end with a summary trailer. After ${before}, on its
|
|
8
|
+
own line write exactly this marker (copy it verbatim — do not put it inside
|
|
9
|
+
a code fence):
|
|
10
|
+
|
|
11
|
+
\`<<<SUMMARY>>>\`
|
|
12
|
+
|
|
13
|
+
* On the next line, write one paragraph in natural, human-readable language
|
|
14
|
+
explaining what you did in this step and what happened — no lists, no headers.
|
|
15
|
+
* Shape:
|
|
16
|
+
|
|
17
|
+
<${before}>
|
|
18
|
+
<<<SUMMARY>>>
|
|
19
|
+
One short paragraph of what you did and what happened.
|
|
20
|
+
|
|
21
|
+
* Omitting the marker makes the reply invalid for this pipeline.
|
|
22
|
+
`;
|
|
23
|
+
}
|
package/agents/test-critic.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { summaryTrailerInstructions } from './summary-footer.js';
|
|
2
|
+
|
|
1
3
|
export function testCriticAgentArgs({
|
|
2
4
|
prompt,
|
|
3
5
|
cwd,
|
|
@@ -23,12 +25,9 @@ export function testCriticAgentArgs({
|
|
|
23
25
|
* Your final message MUST include a JSON verdict:
|
|
24
26
|
{"passed": true|false, "summary": "short reason", "failures": ["optional"]}
|
|
25
27
|
* Set passed: true only when verification is adequate to freeze for implementation.
|
|
26
|
-
*
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
explaining what you did in this step and what happened — no lists, no
|
|
30
|
-
headers, just prose. The JSON itself must stay exactly as specified
|
|
31
|
-
above, before the summary marker.
|
|
28
|
+
* Before the summary marker below, the JSON itself must stay exactly as
|
|
29
|
+
specified above.
|
|
30
|
+
${summaryTrailerInstructions({ before: 'the JSON verdict only' })}
|
|
32
31
|
|
|
33
32
|
[Test Writer Output]
|
|
34
33
|
${testWriterOutput}
|
package/agents/test-runner.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { summaryTrailerInstructions } from './summary-footer.js';
|
|
2
|
+
|
|
1
3
|
export function testRunnerAgentArgs({
|
|
2
4
|
prompt,
|
|
3
5
|
cwd,
|
|
@@ -22,12 +24,9 @@ export function testRunnerAgentArgs({
|
|
|
22
24
|
* Your final message MUST include a JSON verdict:
|
|
23
25
|
{"passed": true|false, "summary": "short reason", "failures": ["optional"]}
|
|
24
26
|
* Set passed: true only when the verification gate is green.
|
|
25
|
-
*
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
explaining what you did in this step and what happened — no lists, no
|
|
29
|
-
headers, just prose. The JSON itself must stay exactly as specified
|
|
30
|
-
above, before the summary marker.
|
|
27
|
+
* Before the summary marker below, the JSON itself must stay exactly as
|
|
28
|
+
specified above.
|
|
29
|
+
${summaryTrailerInstructions({ before: 'the JSON verdict only' })}
|
|
31
30
|
|
|
32
31
|
[Code Writer Output]
|
|
33
32
|
${codeWriterOutput}
|
package/agents/test-writer.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { summaryTrailerInstructions } from './summary-footer.js';
|
|
2
|
+
|
|
1
3
|
export function testWriterAgentArgs({
|
|
2
4
|
prompt,
|
|
3
5
|
cwd,
|
|
@@ -37,11 +39,7 @@ export function testWriterAgentArgs({
|
|
|
37
39
|
* Your final message must include test file paths / run command, if
|
|
38
40
|
applicable, so it can be handed to the next stage.
|
|
39
41
|
* Later rounds must address critic feedback; do not write production code.
|
|
40
|
-
|
|
41
|
-
marker (three '<' characters, then SUMMARY, then three '>'
|
|
42
|
-
characters, with no spaces), followed by one paragraph in natural,
|
|
43
|
-
human-readable language explaining what you did in this step and
|
|
44
|
-
what happened — no lists, no headers, just prose.
|
|
42
|
+
${summaryTrailerInstructions({ before: 'your final message' })}
|
|
45
43
|
* If you changed any files, after that paragraph add a line reading
|
|
46
44
|
exactly "Files:" followed by one line per changed file formatted
|
|
47
45
|
as "<path>: <one-line description>" (e.g. "test/agent.test.js:
|
package/agents/triage.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { summaryTrailerInstructions } from './summary-footer.js';
|
|
2
|
+
|
|
1
3
|
export function triageAgentArgs({ prompt, cwd }) {
|
|
2
4
|
return {
|
|
3
5
|
name: 'triage',
|
|
@@ -18,12 +20,9 @@ export function triageAgentArgs({ prompt, cwd }) {
|
|
|
18
20
|
Set "simple": true only when a quick fix in the current working tree is enough.
|
|
19
21
|
Set "simple": false when research, planning, or a worktree is needed.
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
explaining what you did in this step and what happened — no lists, no
|
|
25
|
-
headers, just prose. The JSON itself must stay exactly as specified
|
|
26
|
-
above, before the summary marker.
|
|
23
|
+
Before the summary marker below, the JSON itself must stay exactly as
|
|
24
|
+
specified above.
|
|
25
|
+
${summaryTrailerInstructions({ before: 'the JSON verdict only' })}
|
|
27
26
|
`,
|
|
28
27
|
prompt,
|
|
29
28
|
options: { cwd },
|
package/lib/agent-agn.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Agent } from './agent.js';
|
|
1
|
+
import { Agent, appendVerbose } from './agent.js';
|
|
2
2
|
import { normalizeAgnToolEvent } from './tool-status.js';
|
|
3
3
|
|
|
4
4
|
export class AgentAgn extends Agent {
|
|
@@ -24,8 +24,10 @@ export class AgentAgn extends Agent {
|
|
|
24
24
|
}
|
|
25
25
|
case 'assistant': {
|
|
26
26
|
if (event.subtype === 'delta') {
|
|
27
|
+
const text = event.text ?? '';
|
|
28
|
+
appendVerbose(text);
|
|
27
29
|
if (verbose) {
|
|
28
|
-
process.stderr.write(
|
|
30
|
+
process.stderr.write(text);
|
|
29
31
|
} else if (this.activeTools.size === 0) {
|
|
30
32
|
this.setStatus('thinking…');
|
|
31
33
|
}
|