@webappwiz/arbor 0.0.2 → 0.0.3
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 +7 -2
- package/config.d.ts +6 -0
- package/index.js +26 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -216,7 +216,7 @@ The agent's control flow runs on these.
|
|
|
216
216
|
| 6 | `lease_held` | Another agent is driving this tree. |
|
|
217
217
|
| 7 | `dirty` | Uncommitted changes. Commit before merging. |
|
|
218
218
|
| 8 | `not_found` | No such task, or not run from a task worktree. |
|
|
219
|
-
| 9 | `hook_failed` | `postCheckout` failed
|
|
219
|
+
| 9 | `hook_failed` | `postCheckout` failed (worktree still exists; fix and re-run the hook), or `postMerge` failed (the branch already landed; nothing rolled back). |
|
|
220
220
|
| 10 | `exists` | Task already exists. `arbor claim` it, or `arbor rm` first. |
|
|
221
221
|
| 11 | `orphaned` | Record with no worktree. `arbor rm` it. |
|
|
222
222
|
| 12 | `merge_failed` | Trunk could not be fast-forwarded (usually a dirty main worktree). |
|
|
@@ -239,6 +239,7 @@ export default defineConfig({
|
|
|
239
239
|
postCheckout: "bun install && cp ../../myrepo/.env .env",
|
|
240
240
|
postRewrite: "bun install", // after each rebase, before preMerge
|
|
241
241
|
preMerge: "bun test", // the last gate before the branch lands
|
|
242
|
+
postMerge: "bun install", // in the main tree, after the branch lands
|
|
242
243
|
leaseStalenessMs: 90_000,
|
|
243
244
|
mergeRetryCount: 2,
|
|
244
245
|
removedCapacity: 50, // removed names kept, so rm can say "already removed"
|
|
@@ -254,7 +255,11 @@ The hooks are named for the git events they sit around: `postCheckout` runs
|
|
|
254
255
|
once, when `add` checks the worktree out; `postRewrite` runs after every rebase
|
|
255
256
|
`merge` does; `preMerge` runs after that, and is the last thing between the
|
|
256
257
|
branch and the base. They all run through `sh -c` in the worktree with
|
|
257
|
-
`ARBOR_TASK` and `ARBOR_WORKTREE` in the environment.
|
|
258
|
+
`ARBOR_TASK` and `ARBOR_WORKTREE` in the environment. `postMerge` is the
|
|
259
|
+
exception: it runs in the main tree after the branch lands and the worktree is
|
|
260
|
+
gone (so only `ARBOR_TASK` is set), for keeping the main tree current the way
|
|
261
|
+
`postRewrite` keeps the worktree current. It reports failure but rolls nothing
|
|
262
|
+
back; the landing already happened.
|
|
258
263
|
|
|
259
264
|
Every hook is unset by default: arbor has no opinion about what a repo runs, or
|
|
260
265
|
whether it has tests at all. Configure `preMerge` and a nonzero exit rolls the
|
package/config.d.ts
CHANGED
|
@@ -22,6 +22,12 @@ export interface Config {
|
|
|
22
22
|
* rebase alone.
|
|
23
23
|
*/
|
|
24
24
|
preMerge: string | null;
|
|
25
|
+
/**
|
|
26
|
+
* Command run by `merge` in the main tree after the base fast-forwards, via
|
|
27
|
+
* `sh -c`. The branch has already landed and the worktree is gone: a nonzero
|
|
28
|
+
* exit reports the failure but rolls nothing back.
|
|
29
|
+
*/
|
|
30
|
+
postMerge: string | null;
|
|
25
31
|
/** How long since its last heartbeat before a task's lease is up for grabs. */
|
|
26
32
|
leaseStalenessMs: number;
|
|
27
33
|
/** Failed `merge` attempts a task gets before it must escalate or be removed. */
|
package/index.js
CHANGED
|
@@ -627,6 +627,21 @@ ${gated.stderr}`)
|
|
|
627
627
|
fail("usage", `landed '${task}' on ${base} (${head}) but could not discard its worktree: ${discarded.stderr || discarded.stdout}
|
|
628
628
|
Run \`arbor rm ${task}\` to clean up.`, { task });
|
|
629
629
|
}
|
|
630
|
+
if (config.postMerge) {
|
|
631
|
+
const ran = await shell.run(config.postMerge, {
|
|
632
|
+
cwd: git.root,
|
|
633
|
+
env: { ARBOR_TASK: task }
|
|
634
|
+
});
|
|
635
|
+
if (ran.exitCode !== 0) {
|
|
636
|
+
fail("hook_failed", [
|
|
637
|
+
`landed '${task}' on ${base} (${head}) but the postMerge hook failed (exit ${ran.exitCode}).`,
|
|
638
|
+
"",
|
|
639
|
+
tail(`${ran.stdout}
|
|
640
|
+
${ran.stderr}`)
|
|
641
|
+
].join(`
|
|
642
|
+
`), { task, exitCode: ran.exitCode });
|
|
643
|
+
}
|
|
644
|
+
}
|
|
630
645
|
log2.info(`${color8.green("merged")} ${task} onto ${base} (${head})
|
|
631
646
|
worktree removed, cd ${git.root}`);
|
|
632
647
|
}
|
|
@@ -846,6 +861,7 @@ function defaults(root, trunk) {
|
|
|
846
861
|
postCheckout: null,
|
|
847
862
|
postRewrite: null,
|
|
848
863
|
preMerge: null,
|
|
864
|
+
postMerge: null,
|
|
849
865
|
leaseStalenessMs: 90000,
|
|
850
866
|
mergeRetryCount: 2,
|
|
851
867
|
removedCapacity: 50,
|
|
@@ -19033,14 +19049,21 @@ function App() {
|
|
|
19033
19049
|
}, [feed]);
|
|
19034
19050
|
const { snapshot, offline } = useReactive(feed, (feed2) => ({ snapshot: feed2.snapshot, offline: feed2.offline }), ["changed"]);
|
|
19035
19051
|
const [tab, setTab] = import_react6.useState("tasks");
|
|
19052
|
+
const emoji = offline ? "⚠️" : "\\uD83C\\uDF32";
|
|
19053
|
+
import_react6.useEffect(() => {
|
|
19054
|
+
document.querySelector("link[rel=icon]")?.setAttribute("href", \`data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><text y='26' font-size='28'>\${emoji}</text></svg>\`);
|
|
19055
|
+
}, [emoji]);
|
|
19036
19056
|
return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV("div", {
|
|
19037
19057
|
className: "mx-auto max-w-6xl px-4 py-8 font-mono text-[13px]",
|
|
19038
19058
|
children: [
|
|
19039
19059
|
/* @__PURE__ */ jsx_dev_runtime2.jsxDEV("h1", {
|
|
19040
19060
|
className: "mb-4 text-base",
|
|
19041
19061
|
children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV("b", {
|
|
19042
|
-
children:
|
|
19043
|
-
|
|
19062
|
+
children: [
|
|
19063
|
+
emoji,
|
|
19064
|
+
" arbor"
|
|
19065
|
+
]
|
|
19066
|
+
}, undefined, true, undefined, this)
|
|
19044
19067
|
}, undefined, false, undefined, this),
|
|
19045
19068
|
/* @__PURE__ */ jsx_dev_runtime2.jsxDEV("nav", {
|
|
19046
19069
|
className: "mb-4 flex gap-6 text-xs uppercase tracking-widest",
|
|
@@ -19369,7 +19392,7 @@ var shell_default = `<!doctype html>
|
|
|
19369
19392
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
19370
19393
|
<title>arbor</title>
|
|
19371
19394
|
<!-- The emoji drawn as SVG inline, so there is no file for the server to
|
|
19372
|
-
serve
|
|
19395
|
+
serve. The page rewrites it to a warning when the server goes away. -->
|
|
19373
19396
|
<link
|
|
19374
19397
|
rel="icon"
|
|
19375
19398
|
href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><text y='26' font-size='28'>🌲</text></svg>"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webappwiz/arbor",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Runs several AI coding agents on one repository at once, each in its own git worktree",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Jared Johnson",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"access": "public"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"webappwiz": "^0.0.
|
|
20
|
+
"webappwiz": "^0.0.3"
|
|
21
21
|
},
|
|
22
22
|
"main": "./index.js",
|
|
23
23
|
"types": "./index.d.ts",
|