@crafts69guy/orchestra 0.3.0 → 0.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orch",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Orchestrator workflow: scope, implement, review, ship via specialised subagents and worktrees.",
5
5
  "author": {
6
6
  "name": "crafts69guy"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orch",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Orchestrator workflow: scope, implement, review, ship via specialised subagents and worktrees.",
5
5
  "author": {
6
6
  "name": "crafts69guy",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crafts69guy/orchestra",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Cross-harness (Claude Code + Codex) orchestration workflow plugin",
6
6
  "license": "MIT",
@@ -46,7 +46,8 @@
46
46
  "gen:codex": "node scripts/gen-codex-agents.mjs",
47
47
  "check": "npm run lint && npm run gen:codex -- --check && npm test",
48
48
  "validate": "claude plugin validate .",
49
- "eval": "sh evals/_support/run.sh"
49
+ "eval": "sh evals/_support/run.sh",
50
+ "eval:bench": "sh evals/_support/bench.sh"
50
51
  },
51
52
  "devDependencies": {
52
53
  "@biomejs/biome": "2.5.15",
@@ -10,7 +10,8 @@ Subagents: `scoper`, `implementer`, `reviewer`, `shipper`. On Claude Code call t
10
10
  - **Scoping:** run `scoper` first on non-trivial work in unfamiliar code, unless you expect to read 3 or fewer new files. Spot-check its brief.
11
11
  - **Implementation:** delegate to `implementer` when the change spans 2+ files, adds or fixes tests, or needs more than one edit-and-test cycle.
12
12
  - **Planning:** for work with 2+ separable parts, use the `plan` skill to write `.scratch/<feature>/plan.md` before implementing.
13
- - **Parallel:** when a plan has 2+ tasks with no `depends_on` between them and disjoint `files`, use the `dispatch` skill without asking, even when each task is small. Never run two writers on the same checkout.
13
+ - **Parallel:** use the `dispatch` skill without asking when a plan has 2+ independent tasks (no `depends_on` path, disjoint `files`) that are each substantial: its own module or feature needing several edit-and-test cycles, roughly 100+ changed lines. Independent small tasks go to one `implementer` as a single batched task, done in order, not to dispatch. Never run two writers on the same checkout.
14
+ Measured: dispatch was no faster on 4 tiny modules (115 s vs 118 s, +45% cost) and 21% faster on 3 large ones (+22% cost).
14
15
  - **Review:** review every implementer diff yourself and rerun its validation. Use `reviewer` (fresh context: diff, brief, acceptance criteria) for risky changes (security, concurrency, migrations, public APIs) or on request. At most 2 fix rounds.
15
16
  - **Shipping:** delegate commit, push and PR to `shipper` only after review passes and the user asked to ship.
16
17
  - **Stays with you:** scope, architecture, cross-cutting decisions, root-cause analysis, merge conflicts, escalations.
@@ -1,5 +1,5 @@
1
1
  import { spawnSync } from 'node:child_process';
2
- import { appendFileSync, existsSync, mkdirSync } from 'node:fs';
2
+ import { appendFileSync, existsSync, mkdirSync, rmdirSync } from 'node:fs';
3
3
  import { resolve } from 'node:path';
4
4
  import { parseArgs } from 'node:util';
5
5
 
@@ -122,9 +122,12 @@ export function merge(deps, cwd, feature, task, message, yes) {
122
122
  }
123
123
  if (tree.status !== 0) return fail(task, tree.stderr);
124
124
 
125
+ const yesArg = yes ? ['--yes'] : [];
126
+ // --no-remove: wt's own cleanup runs in the background and returns before the directory is
127
+ // gone (or never finishes when the caller's sandbox kills it), so remove in the foreground below.
125
128
  const r = deps.exec(
126
129
  'wt',
127
- ['-C', path, 'merge', feature, '--no-commit', ...(yes ? ['--yes'] : [])],
130
+ ['-C', path, 'merge', feature, '--no-commit', '--no-remove', ...yesArg],
128
131
  cwd,
129
132
  );
130
133
  if (r.status !== 0) {
@@ -135,6 +138,17 @@ export function merge(deps, cwd, feature, task, message, yes) {
135
138
  return { code: 2, result: { status: 'conflict', task, files } };
136
139
  }
137
140
  const commit = git(deps, cwd, 'rev-parse', feature).stdout.trim();
141
+ const left = `merged as ${commit}, but ${path} is left`;
142
+ // -D: wt judges "merged" against the default branch, but the branch is now in `feature`.
143
+ const rm = deps.exec('wt', ['remove', branch, '--foreground', '-D', ...yesArg], cwd);
144
+ if (rm.status !== 0) return fail(task, `${left}: ${rm.stderr}`);
145
+ if (deps.exists(path)) {
146
+ try {
147
+ deps.rmdir(path); // only an empty leftover: rmdir refuses a non-empty directory
148
+ } catch (e) {
149
+ return fail(task, `${left}: ${e.message}`);
150
+ }
151
+ }
138
152
  return { code: 0, result: { status: 'merged', task, commit } };
139
153
  }
140
154
 
@@ -164,5 +178,6 @@ export const realDeps = {
164
178
  exec,
165
179
  exists: existsSync,
166
180
  mkdir: (p) => mkdirSync(p, { recursive: true }),
181
+ rmdir: rmdirSync,
167
182
  append: appendFileSync,
168
183
  };
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: dispatch
3
- description: "orch workflow: run independent tasks from .scratch/<feature>/plan.md in parallel, one implementer per git worktree (worktrunk), then merge them into the feature branch one at a time."
3
+ description: "orch workflow: run independent substantial tasks from .scratch/<feature>/plan.md in parallel, one implementer per git worktree (worktrunk), then merge them into the feature branch one at a time."
4
4
  ---
5
5
 
6
6
  # Dispatch
@@ -21,8 +21,10 @@ absolute path. Use that path where the plugin's `bin/` is not on `PATH` (Codex).
21
21
 
22
22
  ## Each wave
23
23
 
24
- 1. **Pick** the ready tasks: all `depends_on` merged, `files` disjoint. At most
25
- 4 per wave; queue the rest.
24
+ 1. **Pick** the ready `substantial` tasks: all `depends_on` merged, `files`
25
+ disjoint. At most 4 per wave; queue the rest. `small` tasks are never
26
+ dispatched: run them as one batched implementer task on `F`, before any wave
27
+ that depends on them.
26
28
  2. **Create** worktrees: `orch wt new <F> <T1> <T2> …` → JSON list of
27
29
  `{task, branch, path}`.
28
30
  3. **Spawn** one implementer per task, all in the **same message** so they run
@@ -32,6 +32,7 @@ Base branch: <F> # the branch the tasks merge into
32
32
  goal: <one sentence, observable outcome>
33
33
  files: [<paths this task owns>]
34
34
  depends_on: []
35
+ size: small # or substantial (rule below)
35
36
  validate: <command that proves this task works>
36
37
  decisions: [<task-specific choices>]
37
38
  ```
@@ -43,14 +44,20 @@ Base branch: <F> # the branch the tasks merge into
43
44
  share a file. If they must, add a `depends_on` edge or merge the tasks.
44
45
  - Shared files that everyone touches (lockfiles, barrel exports, registries) go
45
46
  to one task that the others depend on.
46
- - Each task is 1 implementer-sized unit: one edit-and-test loop, not a project.
47
+ - Each task is 1 implementer-sized unit (one module or feature), not a project.
48
+ - `size` is `substantial` when the task is its own module or feature needing
49
+ several edit-and-test cycles, roughly 100+ changed lines; otherwise `small`.
47
50
  - `validate` runs inside the task's own worktree and must not need other
48
51
  unmerged tasks.
49
52
  - Don't split one feature into many tiny tasks. Separate features stay separate
50
- tasks, even when each one is small.
53
+ tasks (each can land as its own commit), but small ones are batched, not
54
+ dispatched (below).
51
55
 
52
56
  ## After writing
53
57
 
54
- Show the user the task table (id, goal, depends_on) in a few lines. If 2+ tasks
55
- are independent, continue with the `dispatch` skill; otherwise run implementers
56
- one at a time.
58
+ Show the user the task table (id, goal, size, depends_on) in a few lines. If 2+
59
+ independent tasks are `substantial`, continue with the `dispatch` skill for
60
+ them. Batch the `small` tasks into one implementer task (all of them, in order,
61
+ on the feature branch); run the rest (a lone or dependent substantial task) with
62
+ its own implementer, one at a time. Parallel worktrees only pay off when each
63
+ task is substantial.