@irythill/orq 0.3.0 → 0.5.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 +55 -11
- package/README.pt-BR.md +47 -11
- package/dist/agents.js +10 -0
- package/dist/ci.js +241 -0
- package/dist/cli.js +9 -1
- package/dist/commands/agent.js +86 -13
- package/dist/commands/block.js +46 -6
- package/dist/commands/board.js +109 -18
- package/dist/commands/ci.js +48 -0
- package/dist/commands/claim.js +148 -12
- package/dist/commands/completion.js +4 -3
- package/dist/commands/gc.js +1 -1
- package/dist/commands/handoff.js +259 -0
- package/dist/commands/pick.js +19 -4
- package/dist/commands/quota.js +34 -9
- package/dist/commands/rounds.js +132 -0
- package/dist/commands/stats.js +1 -1
- package/dist/commands/verify.js +2 -0
- package/dist/commands/wait.js +2 -0
- package/dist/config.js +5 -2
- package/dist/diagnose.js +105 -0
- package/dist/identity.js +55 -0
- package/dist/notice.js +282 -0
- package/dist/pick.js +137 -11
- package/dist/quota.js +83 -21
- package/dist/roles.js +11 -2
- package/dist/rounds.js +176 -0
- package/dist/stats.js +4 -3
- package/dist/testrun.js +4 -10
- package/package.json +1 -1
- package/skills/issue/SKILL.md +48 -6
- package/skills/orq-setup/SKILL.md +1 -1
- package/templates/workspace.CLAUDE.md +8 -0
package/dist/stats.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
7
7
|
import { homedir } from "node:os";
|
|
8
8
|
import { basename, join } from "node:path";
|
|
9
|
-
const ROLE = /^(impl|fix\d*|review\d*|[a-z]+-review\d*)-?/;
|
|
9
|
+
const ROLE = /^(impl|fix\d*|review\d*|[a-z]+-review\d*|watchdog\d*)-?/;
|
|
10
10
|
const read = (f) => { try {
|
|
11
11
|
return readFileSync(f, "utf8");
|
|
12
12
|
}
|
|
@@ -115,8 +115,9 @@ export function collectRuns(ws, days) {
|
|
|
115
115
|
const name = basename(pre);
|
|
116
116
|
const rm = ROLE.exec(name);
|
|
117
117
|
const role = rm && rm[1].includes("review") ? "review"
|
|
118
|
-
:
|
|
119
|
-
: name.startsWith("
|
|
118
|
+
: rm && rm[1].startsWith("watchdog") ? "watchdog"
|
|
119
|
+
: name.startsWith("fix") || txt.includes("-R ") || txt.includes(" resume ") || txt.includes("--resume") ? "fix"
|
|
120
|
+
: name.startsWith("impl") ? "impl" : "other";
|
|
120
121
|
const out = read(`${pre}.out.md`);
|
|
121
122
|
const [neu, tot] = tokens(agent, log, read(`${pre}.id`).trim());
|
|
122
123
|
runs.push({ issue, name, agent, model, role, ok: read(done).includes("status=ok") && out.trim() !== "",
|
package/dist/testrun.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
// memory cap (src/process.ts) and read its JSON report into "<file relative to the repo> :: <full test name>" lines.
|
|
3
3
|
// The runner's own bin (node_modules/<runner>/package.json "bin") runs with this node, so Windows needs no shell;
|
|
4
4
|
// without it, npx as before. Also the background job both share (launch on a TerminalHost, queue, .pid/.done, notify).
|
|
5
|
-
import {
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
6
|
import { createWriteStream, existsSync, lstatSync, readFileSync, realpathSync, rmdirSync, rmSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { dirname, isAbsolute, join, relative } from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
import { writeAtomic } from "./fsutil.js";
|
|
10
10
|
import { m } from "./i18n.js";
|
|
11
11
|
import { acquire, release } from "./lock.js";
|
|
12
|
+
import { handoffFile, notify } from "./notice.js";
|
|
12
13
|
import { killTree, parseSize, runCapped } from "./process.js";
|
|
13
14
|
import { closeOwnTab, detectHost, launch } from "./terminal.js";
|
|
14
15
|
export const JS_EXT = /\.(ts|tsx|js|jsx|mjs|cjs|mts|cts)$/;
|
|
@@ -196,12 +197,5 @@ export async function inJob(j, label, slots, body, done) {
|
|
|
196
197
|
}
|
|
197
198
|
return st === "ok" ? 0 : 1;
|
|
198
199
|
}
|
|
199
|
-
/**
|
|
200
|
-
|
|
201
|
-
export function notify(pane, line, background = false) {
|
|
202
|
-
const local = join(dirname(CLI), "..", "setup", "herdr-notify"), cmd = existsSync(local) ? local : "herdr-notify";
|
|
203
|
-
if (background)
|
|
204
|
-
spawn(cmd, [pane, line], { detached: true, stdio: "ignore" }).unref();
|
|
205
|
-
else
|
|
206
|
-
spawnSync(cmd, [pane, line], { stdio: "inherit" });
|
|
207
|
-
}
|
|
200
|
+
/** Tell the conductor's herdr pane (src/notice.ts): returns at once, delivery runs detached with retries and a log. */
|
|
201
|
+
export { handoffFile, notify };
|
package/package.json
CHANGED
package/skills/issue/SKILL.md
CHANGED
|
@@ -30,7 +30,15 @@ Issue artifacts (prompts, notes) live in `$WS/.orquestra/<ID>/`.
|
|
|
30
30
|
## 1. Read the issue
|
|
31
31
|
- **First, claim it:** `herdr-claim -w $WS <ID>`. Exit 1 = another conductor owns it: **stop** and tell the user
|
|
32
32
|
(don't read it, don't dispatch anything). Taking it over (e.g. switching accounts) only with the user's OK:
|
|
33
|
-
`herdr-claim -w $WS -f <ID>`. Several conductors may share a workspace; `herdr-claim -w $WS -l` lists who has what
|
|
33
|
+
`herdr-claim -w $WS -f <ID>`. Several conductors may share a workspace; `herdr-claim -w $WS -l` lists who has what,
|
|
34
|
+
with each conductor's name (its herdr workspace label, e.g. "emp: orq-cms-dsgn"; outside herdr, `ORQ_CONDUCTOR_ID`).
|
|
35
|
+
- **The user names another conductor** ("take over orq-cms-dsgn's work"): never guess a pane id. Run
|
|
36
|
+
`orq claim -w $WS --from "<what they said>"` (any part of the name works). It lists that conductor's issues; exit 3 =
|
|
37
|
+
the name matches more than one conductor (show the list, ask which); exit 1 = none. With the user's OK,
|
|
38
|
+
`orq claim -w $WS --from "<name>" -f` takes them all. **Resuming** an issue someone else started: don't start over.
|
|
39
|
+
Read `$O/` first — `impl-<repo>.md`/`.out.md` (prompt, answer, `## Decisions`), `.pick` files, the last
|
|
40
|
+
`fix-<n>.md` and `review-<repo>.out.md`, `verify-<repo>.txt` — and the Plane comments, then go on from the step the
|
|
41
|
+
files show (a `.pane`/`.id` without `.done` = a child still running: `orq wait` for it instead of dispatching again).
|
|
34
42
|
- `mcp__plane__workitem` `retrieve_by_identifier` with `workitem_identifier: "<ID>"`; then `workitem_comment list`.
|
|
35
43
|
- Extract: goal, **acceptance criteria**, affected repos, links. No acceptance criteria → write a short proposal and
|
|
36
44
|
**ask the user** before dispatching.
|
|
@@ -44,6 +52,14 @@ One task per repo. Level:
|
|
|
44
52
|
- **medium** — business rule, API↔front integration, several files.
|
|
45
53
|
- **heavy** — architecture, data migration, hard/concurrency bug, security.
|
|
46
54
|
|
|
55
|
+
**Scope check, before dispatching.** Estimate the size. Split into sub-issues or sequential batches (each its own PR)
|
|
56
|
+
when it touches several unrelated areas, changes roughly >400 lines, mixes refactor with behavior change, or has
|
|
57
|
+
independent acceptance criteria.
|
|
58
|
+
- Each batch is independently testable and reviewable; dispatch in order, one implementer per batch. Record the split in
|
|
59
|
+
Plane (sub-issues or a checklist comment) before starting.
|
|
60
|
+
- Scope too big mid-run (reviews hitting `policy.max_rounds`, repeated findings, the implementer asking to change
|
|
61
|
+
scope): stop, split the remainder, don't force more rounds. `orq rounds <ID>` shows the alert; on warn/stop `orq rounds <ID> --diagnose` says why.
|
|
62
|
+
|
|
47
63
|
## 3. Pick agent and model: always `orq pick`, never by hand
|
|
48
64
|
`orq pick` decides agent, model, effort and account (user config + delivery and token history + current quota +
|
|
49
65
|
rotation). **Do not choose by preference, by a rule you read elsewhere, or by what worked last time**: run it before
|
|
@@ -51,8 +67,10 @@ EVERY dispatch (implementation, review, second opinion) and use its output verba
|
|
|
51
67
|
```bash
|
|
52
68
|
orq pick impl --level simple|medium|heavy # → e.g. -a codex -m gpt-6-sol -e low
|
|
53
69
|
orq pick review --level <level> --impl-agent <agent that implemented> # → another vendor, e.g. -a opencode -m ...
|
|
54
|
-
orq pick opinion
|
|
70
|
+
orq pick opinion --impl-agent <agent that implemented> # second opinion (e.g. Copilot), see step 5
|
|
55
71
|
```
|
|
72
|
+
More than one agent eligible for `review`/`opinion` (declared, not excluded or blocked, with a model for the role; quota is not considered) and neither `--impl-agent` nor `--impl-vendor` given → exit 2:
|
|
73
|
+
always pass one of them (`--no-record`/`--explain` do not change this).
|
|
56
74
|
The output goes straight into `herdr-agent` (`herdr-agent $(orq pick ...) -g ... -t ... -d ... -o ... -- prompt.md`).
|
|
57
75
|
- Exit 3 = no candidate (quota exhausted, no agent with that role): **stop and ask the user**.
|
|
58
76
|
- Implementer failed review twice (step 6) → pick again without it: `orq pick impl --level <level> --exclude-agent <agent>`.
|
|
@@ -108,7 +126,7 @@ tell me".
|
|
|
108
126
|
orq pick impl --level <level> > $O/impl-<repo>.pick # the fix rounds reuse it (step 6)
|
|
109
127
|
herdr-agent $(cat $O/impl-<repo>.pick) -g <group> -t "<ID> impl <repo>" -d $WT -o $O/impl-<repo> -- $O/impl-<repo>.md
|
|
110
128
|
```
|
|
111
|
-
- The Claude account (`-c`) already comes from `orq pick` (the
|
|
129
|
+
- The Claude account (`-c`) already comes from `orq pick` (one under the limit whose pace stays within it, then the least used).
|
|
112
130
|
- Full final answer in `$O/impl-<repo>.out.md`; log in `.log`; the agent's session id in `.id`.
|
|
113
131
|
- Codex's sandbox has no network: `git fetch` is yours, beforehand (above). Push/PR: yours (step 7).
|
|
114
132
|
- `herdr-agent` returns immediately (no need to background it); the child's pane is in `<prefix>.pane`
|
|
@@ -125,6 +143,9 @@ herdr-agent $(cat $O/impl-<repo>.pick) -g <group> -t "<ID> impl <repo>" -d $WT -
|
|
|
125
143
|
origin/<BASE>...HEAD`); (2) `NODE_OPTIONS=--max-old-space-size=2048 tsc --noEmit` for the project. Don't run tests".
|
|
126
144
|
Full suite only in CI (or a manual `herdr-baseline` if the user asks).
|
|
127
145
|
- An issue that changes an API contract: **API first**; consumers afterwards, with the new contract in the prompt.
|
|
146
|
+
- **A red board line / `✗` pane title = a failure you may have missed.** If you see one (or the user says notices aren't
|
|
147
|
+
arriving), run `orq notice` (delivery log) and `<prefix>.done` for that issue, then handle the failure; running
|
|
148
|
+
`orq wait`, `orq verify` or `orq agent` for the issue acknowledges it.
|
|
128
149
|
- **Never block waiting** (`herdr agent wait`, `pane wait-output`, `sleep`, `timeout`): completion arrives as a
|
|
129
150
|
`[HERDR-AGENT DONE]` line in your pane. Dispatch, report in one line and end your turn. "Done yet?" = `<prefix>.done`
|
|
130
151
|
exists (never `pgrep`).
|
|
@@ -160,7 +181,16 @@ are in the attached verify)". If the reviewer ends with `status=fail` and no ver
|
|
|
160
181
|
`jetski: ... permission` line), that is not a rejection: run `orq pick review ... --exclude-agent <it>` and redo it.
|
|
161
182
|
`--exclude-agent` applies **only to redoing that review** (save the new pick to `review-<repo>.pick`); the next
|
|
162
183
|
round reuses whoever gave the verdict. An agent that failed twice in a row with no verdict →
|
|
163
|
-
`orq block <agent> --days 1` and tell the user.
|
|
184
|
+
`orq block <agent> --days 1` and tell the user. If it stopped on a quota limit, use `orq block <agent> --quota` (until
|
|
185
|
+
the window resets; a fixed period outlives it and keeps the agent out of `orq pick` for nothing). If `orq pick` finds no
|
|
186
|
+
candidate, its output is empty and `orq agent` refuses to start: stop and tell the user.
|
|
187
|
+
**Review tools** (an agent whose `run` has no `{prompt}`/`{prompt_text}`/stdin, e.g. a CodeRabbit-like CLI with
|
|
188
|
+
`ok_exit`/`filter` in the config): same command; it ignores the prompt and the attachments and reviews the branch
|
|
189
|
+
against `{base}` itself. Read its answer like any other: `status=ok` with `rc≠0` is a verdict with findings, not a
|
|
190
|
+
failure. Its high-severity items are the blockers, still under the step 6 rule (`file:line` + concrete failure).
|
|
191
|
+
If the tool's answer opens with (or, when short, consists of) a statement that nothing was reviewed (e.g. Revtool's "Nothing to review"), `agents.<name>.no_review` (a
|
|
192
|
+
regex) makes `orq agent` end that run `status=fail`: `orq pick`'s fallback and the conductor treat it as not run,
|
|
193
|
+
same as an empty answer.
|
|
164
194
|
**Second opinion** (`orq pick opinion`, read only, same attachments): only on **heavy** issues or when reviewer and
|
|
165
195
|
implementer disagree about a blocker. It never becomes a round by itself: you weigh both answers and decide.
|
|
166
196
|
**Before dispatching:** `git -C $R fetch origin $BASE; git -C $WT merge-base --is-ancestor origin/$BASE HEAD` — if it
|
|
@@ -180,7 +210,7 @@ repo checklist.
|
|
|
180
210
|
**Only `[blocker]` items open a round.** An item tagged blocker without `file:line` and a concrete failure, or that
|
|
181
211
|
only restates a `## Decisions` choice, counts as a suggestion; when you downgrade one, say why in the Plane comment.
|
|
182
212
|
No blockers left → APPROVED, even with suggestions.
|
|
183
|
-
Blocking problems → write the list (blockers only) to `$O/fix-<n>.md` and continue the implementer's session (any agent):
|
|
213
|
+
Blocking problems → write the list (blockers only) to `$O/fix-<n>.md` (always this name; reviews `$O/review-<repo>-<n>`, never `fix<n>-<repo>` or other variants — a later conductor counts rounds by these files) and continue the implementer's session (any agent):
|
|
184
214
|
`herdr-agent $(orq pick fix --same $O/impl-<repo>.pick) -g <group> -t "<ID> fix<n> <repo>" -d $WT -o $O/impl-<repo> -R $(cat $O/impl-<repo>.id) -- $O/fix-<n>.md`.
|
|
185
215
|
A fix is a continuation: same agent, model, account and session, effort one level up (`--same` reads the implementer's
|
|
186
216
|
pick; never a new `orq pick`, never `-a` alone — without `-m` the session resumes on the CLI's default model, which
|
|
@@ -196,10 +226,18 @@ Then a new `herdr-verify` (4b) and the **round review** (step 5 with these chang
|
|
|
196
226
|
(the full `-b $BASE` diff stays, as context).
|
|
197
227
|
- The prompt asks a closed question: "for each item in fix-<n>.md: RESOLVED or NOT RESOLVED (why); then the fix diff:
|
|
198
228
|
any regression it introduced, as `[blocker]`/`[suggestion]`. Outside the fix diff, report only a blocker you missed
|
|
199
|
-
before that would break production, and say why it wasn't in the first review". Anything else is a suggestion.
|
|
229
|
+
before that would break production, and say why it wasn't in the first review". Anything else is a suggestion. A review tool can't answer that: it reviews the whole
|
|
230
|
+
branch again, so you do the matching — a finding is a blocker this round only if it is inside `fix-<n>.diff` or is a
|
|
231
|
+
NOT RESOLVED item of `fix-<n>.md`; one you already decided on (fixed, rejected or downgraded) stays decided. **Maximum: `orq config get policy.max_rounds` rounds** — `orq agent -R` refuses the next one (exit 4) and counts per session, so a renamed prefix doesn't reset it; on exit 4 stop and tell the user. With their OK run `orq rounds <ID> --diagnose` (a cheap independent agent, advisory: read its `RECOMMENDATION` — continue / split / change-implementer / ask-user — and tell the user), then `-F` (refused without a diagnosis newer than the last fix/review; `-F -F` skips that, only if the user says so); over it → `orq pick impl
|
|
200
232
|
--exclude-agent <it> > $O/impl-<repo>.pick` only with the user's OK, or stop and report. Non-blocking suggestions go into the comment; they
|
|
201
233
|
don't become a round.
|
|
202
234
|
|
|
235
|
+
## Screenshots / visual validation
|
|
236
|
+
Only when the issue asks for it. **One** attempt (a job with `--effort low`, a short prompt that says which screens and
|
|
237
|
+
where to save the images), at most ~6 images, and read them only as files you need to judge — never re-read the same
|
|
238
|
+
image. If it fails, tell the user instead of dispatching a second `shots` job. Playwright runs inside that child's
|
|
239
|
+
worktree, never as an MCP in the conductor (images in the conductor's context are re-billed every turn).
|
|
240
|
+
|
|
203
241
|
## 7. Close
|
|
204
242
|
**Commit/PR conventions belong to the repo, not to you.** The **implementer, in the worktree** (where the repo's
|
|
205
243
|
rules live) commits and writes the PR. Find and cite in the prompt, by path, whatever the repo has:
|
|
@@ -212,6 +250,10 @@ rules live) commits and writes the PR. Find and cite in the prompt, by path, wha
|
|
|
212
250
|
issue) and the answer in `$O/impl-<repo>.out.md`. Check the opened PR against the template.
|
|
213
251
|
- Plane comment (`workitem_comment create`): summary, repo(s), branch, agents and models used (`orq pick` output),
|
|
214
252
|
review result, checks that ran.
|
|
253
|
+
- **Review bots on the PR** (a GitHub App reviewer): one more input, not a new review cycle. Only a finding with
|
|
254
|
+
high severity, `file:line` and a concrete failure, not already decided in the rounds, goes into a fix round (it
|
|
255
|
+
counts towards `policy.max_rounds`); the rest goes into the Plane comment or a follow-up issue. Don't re-request the
|
|
256
|
+
bot's review to "get it clean".
|
|
215
257
|
- **CI after every push:** `gh pr checks <n>` (no `--watch`; if pending, end your turn and check on the next notice).
|
|
216
258
|
Red → `gh run view <id> --log-failed | tail -40`: error from the diff → fix round; error already on the base → create
|
|
217
259
|
a Plane issue (workspace standard) and tell the user. "Ready to merge" only with green checks or an explained failure
|
|
@@ -61,7 +61,7 @@ Offer `$ORQ/examples/irythill/config.toml` as an example, saying clearly **it is
|
|
|
61
61
|
|
|
62
62
|
## 4. Policy
|
|
63
63
|
Explain simply, then suggest the example's values and ask if they want to change any:
|
|
64
|
-
- `
|
|
64
|
+
- `quota_week` (95) and `quota_5h` (simple 90, medium 85, heavy 80): an agent at or above these % is left out.
|
|
65
65
|
- weights — already suggested by `orq setup` from the parallel tasks: `quality` (did it deliver?), `tokens` (spent
|
|
66
66
|
little?), `speed` (finished fast?), `rotation` (penalty for being picked recently, spreads the work).
|
|
67
67
|
- `max_rounds` (2) review rounds before handing back; `machine.agent_mem_max` / `test_mem_max` come from `orq setup`
|
|
@@ -11,6 +11,14 @@ rules — read the repo's own before touching it. This file only holds the map a
|
|
|
11
11
|
outside herdr; one at a time on the machine); the child does lint + `tsc` (`NODE_OPTIONS=--max-old-space-size=2048`).
|
|
12
12
|
- **Agents:** chosen by `orq-pick` from each developer's `~/.config/orq/config.toml` — nothing about models here.
|
|
13
13
|
|
|
14
|
+
## Scope
|
|
15
|
+
- Before dispatching, split big issues into sub-issues or sequential batches (one PR, one implementer each) when they touch
|
|
16
|
+
several unrelated areas, change roughly >400 lines, mix refactor with behavior change, or have independent acceptance
|
|
17
|
+
criteria. Each batch must be testable and reviewable on its own; record the split in Plane before starting.
|
|
18
|
+
- Reviews hitting `policy.max_rounds`, repeated findings or the implementer asking to change scope mean it was too big:
|
|
19
|
+
stop and split the remainder instead of forcing more rounds. `orq rounds <ID> --diagnose` asks an independent agent why
|
|
20
|
+
(advisory); `orq agent -R -F` past `max_rounds` needs that diagnosis (`-F -F` skips it, only on the user's word).
|
|
21
|
+
|
|
14
22
|
## Repositories
|
|
15
23
|
|
|
16
24
|
| Folder | What it is | Stack / PM | Group | Base | Verification | Checklist |
|