@welluable/orch 1.2.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 +110 -14
- 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 +165 -14
- package/lib/config.js +190 -0
- package/lib/continue.js +150 -0
- package/lib/failure-log.js +72 -0
- package/lib/file-tracker.js +68 -12
- package/lib/jobs.js +209 -7
- 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 +3116 -360
- 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,8 +50,11 @@ 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 `
|
|
54
|
-
supported.
|
|
53
|
+
(the Cursor Agent CLI, command `agent`); `claude`, `agn`, and `opencode` are also
|
|
54
|
+
supported. Pin a default with `orch config --agent <name>` so you don't need
|
|
55
|
+
`--agent` on every run (local `.orch/config` overrides global
|
|
56
|
+
`~/.orch/config`; CLI `--agent` still wins). See [Requirements](#requirements)
|
|
57
|
+
for details.
|
|
55
58
|
|
|
56
59
|
```bash
|
|
57
60
|
orch "fix the typo in the README"
|
|
@@ -153,7 +156,8 @@ runs, since foreground runs already stream their output to your terminal.
|
|
|
153
156
|
▼
|
|
154
157
|
┌──────────────────────┐
|
|
155
158
|
│ agent backend adapter │
|
|
156
|
-
│ (cursor
|
|
159
|
+
│ (cursor/claude/agn/ │
|
|
160
|
+
│ opencode) │
|
|
157
161
|
└──────────────────────┘
|
|
158
162
|
```
|
|
159
163
|
|
|
@@ -171,7 +175,8 @@ agent CLI does all the actual reading and writing of files.
|
|
|
171
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. |
|
|
172
176
|
|
|
173
177
|
For `--ask`, Cursor uses `--mode ask`, Claude uses `--permission-mode plan`,
|
|
174
|
-
|
|
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`.
|
|
175
180
|
|
|
176
181
|
`--detach` only controls backgrounding, not whether a job record exists —
|
|
177
182
|
every non-`--dry-run` invocation gets one. Combining `--detach` with
|
|
@@ -203,16 +208,37 @@ Usage: orch [options] [command] <task...>
|
|
|
203
208
|
implementer loop; defaults to `5`, ignored with `--ask` and `--quick`.
|
|
204
209
|
- `--fan-out` — decomposes the task into parallel workers coordinated by this
|
|
205
210
|
process instead of running the single-worktree pipeline (see
|
|
206
|
-
[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`.
|
|
207
216
|
- `--max-workers <n>` — max number of parallel fan-out workers; defaults to
|
|
208
217
|
`4`; only meaningful with `--fan-out`.
|
|
218
|
+
- `--max-units <n>` — max number of sequential units; defaults to `8`; only
|
|
219
|
+
meaningful with `--seq`.
|
|
209
220
|
- `--max-concurrency <n>` — optional hard ceiling on in-flight fan-out workers
|
|
210
221
|
at once; omit to let the coordinator choose (typically the current layer's
|
|
211
222
|
size); only meaningful with `--fan-out`.
|
|
212
|
-
- `--agent <cursor|claude|agn>` — selects the backend for the whole pipeline;
|
|
213
|
-
|
|
223
|
+
- `--agent <cursor|claude|agn|opencode>` — selects the backend for the whole pipeline;
|
|
224
|
+
when omitted, uses local `.orch/config`, then global `~/.orch/config`, else
|
|
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.
|
|
214
230
|
- `-h, --help` — displays help for the command.
|
|
215
231
|
|
|
232
|
+
Config:
|
|
233
|
+
|
|
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
|
|
237
|
+
default agent. Bare `--agent` (and `--global`) write `~/.orch/config`;
|
|
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).
|
|
241
|
+
|
|
216
242
|
Job-control subcommands (see [Headless runs](#headless-runs)):
|
|
217
243
|
|
|
218
244
|
- `orch list` — lists all runs tracked under `.orch/` in the current directory.
|
|
@@ -220,13 +246,21 @@ Job-control subcommands (see [Headless runs](#headless-runs)):
|
|
|
220
246
|
recently started run.
|
|
221
247
|
- `orch pause <slug>` — requests a pause at the run's next stage-boundary
|
|
222
248
|
checkpoint.
|
|
223
|
-
- `orch resume <slug>` —
|
|
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.
|
|
252
|
+
- `orch continue <slug> "new task"` — starts a new complex pipeline on a
|
|
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>`.
|
|
224
256
|
- `orch stop <slug>` — sends `SIGTERM` to a running job (or reconciles a dead
|
|
225
257
|
one to `crashed`).
|
|
226
258
|
- `orch logs <slug> [-f]` — prints a run's `orch.log`; `-f` follows it until
|
|
227
259
|
the job reaches a terminal state.
|
|
228
260
|
- `orch jobs clean` — deletes every run tracked under `.orch/` in the current
|
|
229
|
-
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.
|
|
230
264
|
|
|
231
265
|
Examples:
|
|
232
266
|
|
|
@@ -234,9 +268,16 @@ Examples:
|
|
|
234
268
|
orch "fix the typo in the README" --agent claude
|
|
235
269
|
orch "fix the bug described in task.md" --agent cursor -v
|
|
236
270
|
orch "implement the local spec" --agent agn -v
|
|
271
|
+
orch "fix the typo in the README" --agent opencode
|
|
237
272
|
orch --ask "where is the CLI entrypoint?" --agent claude
|
|
273
|
+
orch --ask "where is package.json?" --agent opencode
|
|
238
274
|
orch --quick "fix the typo in the README" --agent claude
|
|
239
275
|
orch "noop" --dry-run --agent cursor
|
|
276
|
+
orch "noop" --dry-run --agent opencode
|
|
277
|
+
orch config
|
|
278
|
+
orch config --agent claude
|
|
279
|
+
orch config --agent agn --local
|
|
280
|
+
orch config --agent opencode
|
|
240
281
|
```
|
|
241
282
|
|
|
242
283
|
## Headless runs
|
|
@@ -260,10 +301,11 @@ directory's `.orch/`:
|
|
|
260
301
|
orch list # SLUG ROLE STATE PHASE AGENT STARTED DURATION PID
|
|
261
302
|
orch status swift-lagoon-49ea # full record: state, phase, branch, worktree, exit code, ...
|
|
262
303
|
orch pause swift-lagoon-49ea # request a pause at the next stage-boundary checkpoint
|
|
263
|
-
orch resume swift-lagoon-49ea #
|
|
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
|
|
264
306
|
orch logs swift-lagoon-49ea -f # follow orch.log until the run finishes
|
|
265
307
|
orch stop swift-lagoon-49ea # SIGTERM the run
|
|
266
|
-
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)
|
|
267
309
|
```
|
|
268
310
|
|
|
269
311
|
Pausing is cooperative and happens at stage boundaries (before the first
|
|
@@ -394,6 +436,58 @@ Depth is capped at 1: every worker and the integration session run with
|
|
|
394
436
|
variable is already present — a worker or integration session never fans out
|
|
395
437
|
again.
|
|
396
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
|
+
|
|
397
491
|
## Project structure
|
|
398
492
|
|
|
399
493
|
Complex runs create a run directory and a sibling worktree, reusing the
|
|
@@ -426,21 +520,23 @@ manually if that happens:
|
|
|
426
520
|
pkill -f 'agent -p' # --agent cursor
|
|
427
521
|
pkill -f 'claude ' # --agent claude, adjust to local argv
|
|
428
522
|
pkill -f 'agn ' # --agent agn
|
|
523
|
+
pkill -f 'opencode run' # --agent opencode
|
|
429
524
|
```
|
|
430
525
|
|
|
431
526
|
## Agent compatibility
|
|
432
527
|
|
|
433
528
|
| Backend | `--agent` value | Status | Notes |
|
|
434
529
|
| --- | --- | --- | --- |
|
|
435
|
-
| Cursor Agent CLI | `cursor` | Supported (default) | Command `agent` on `PATH`. |
|
|
530
|
+
| Cursor Agent CLI | `cursor` | Supported (builtin default) | Command `agent` on `PATH`. Override via `orch config` or `--agent`. |
|
|
436
531
|
| Claude Code CLI | `claude` | Supported | Command `claude` on `PATH`. |
|
|
437
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. |
|
|
438
534
|
|
|
439
535
|
## Requirements
|
|
440
536
|
|
|
441
537
|
- A modern Node.js runtime.
|
|
442
538
|
- One supported agent CLI on your `PATH`: `agent` (Cursor), `claude` (Claude
|
|
443
|
-
Code), or `
|
|
539
|
+
Code), `agn`, or `opencode` (OpenCode `>= 1.17.18`).
|
|
444
540
|
- Git, for any run that isn't `--ask` or `--quick` (worktrees and commits
|
|
445
541
|
need it).
|
|
446
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
|
}
|