@ucsandman/legcli 0.7.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/CHANGELOG.md +560 -0
- package/LICENSE +58 -0
- package/NOTICE +4 -0
- package/README.md +558 -0
- package/bin/fake-agent.mjs +143 -0
- package/bin/leg.mjs +449 -0
- package/docs/DECISIONS.md +119 -0
- package/docs/DEMO.md +214 -0
- package/docs/DEVIATIONS.md +182 -0
- package/docs/ERRORS.md +326 -0
- package/docs/README.md +40 -0
- package/docs/REUSE.md +289 -0
- package/docs/ROADMAP-v2.md +55 -0
- package/docs/VOCABULARY.md +243 -0
- package/docs/adapters.md +300 -0
- package/docs/board-guide.md +579 -0
- package/docs/cli-contracts.md +401 -0
- package/docs/concepts.md +426 -0
- package/docs/configuration.md +220 -0
- package/docs/faq.md +206 -0
- package/docs/getting-started.md +251 -0
- package/docs/real-run.md +80 -0
- package/docs/review-2026-09-14.md +72 -0
- package/docs/screenshots/board-400px.png +0 -0
- package/docs/screenshots/board-details-open.png +0 -0
- package/docs/screenshots/board-done.png +0 -0
- package/docs/screenshots/board-drawer.png +0 -0
- package/docs/screenshots/board-empty.png +0 -0
- package/docs/screenshots/board-handoff.png +0 -0
- package/docs/screenshots/board-running.png +0 -0
- package/docs/screenshots/demo-1-claude-running.png +0 -0
- package/docs/screenshots/demo-2-limit-hit.png +0 -0
- package/docs/screenshots/demo-3-handoff-bundle.png +0 -0
- package/docs/screenshots/demo-4-codex-running.png +0 -0
- package/docs/screenshots/demo-5-done.png +0 -0
- package/docs/screenshots/floor-final-1280.png +0 -0
- package/docs/screenshots/floor-final-400.png +0 -0
- package/docs/screenshots/floor-landing.png +0 -0
- package/docs/screenshots/floor.png +0 -0
- package/docs/screenshots/share-guest-1280.png +0 -0
- package/docs/screenshots/share-owner-1280.png +0 -0
- package/docs/screenshots/terminals-1280.png +0 -0
- package/docs/screenshots/thumb-done.jpg +0 -0
- package/docs/screenshots/thumb-handoff-details.jpg +0 -0
- package/docs/screenshots/thumb-limit-hit.jpg +0 -0
- package/docs/screenshots/youtube-thumbnail.jpg +0 -0
- package/fixtures/limits/agy/agy-resource-exhausted.json +11 -0
- package/fixtures/limits/claude/claude-budget-limit.json +11 -0
- package/fixtures/limits/claude/claude-max-turns.json +11 -0
- package/fixtures/limits/claude/claude-model-limit.json +11 -0
- package/fixtures/limits/claude/claude-session-limit.json +11 -0
- package/fixtures/limits/claude/claude-weekly-limit.json +11 -0
- package/fixtures/limits/codex/codex-quota-exceeded.json +11 -0
- package/fixtures/limits/codex/codex-rate-limit-exceeded.json +11 -0
- package/fixtures/limits/codex/codex-skills-notice.json +11 -0
- package/fixtures/limits/codex/codex-usage-limit-reached.json +11 -0
- package/fixtures/limits/codex/codex-usage-limit.json +11 -0
- package/fixtures/limits/generic/generic-429.json +11 -0
- package/fixtures/limits/generic/generic-overloaded.json +11 -0
- package/fixtures/limits/generic/generic-quota.json +11 -0
- package/fixtures/limits/generic/generic-rate-limit.json +11 -0
- package/fixtures/limits/generic/generic-resource-exhausted.json +11 -0
- package/fixtures/limits/generic/generic-usage-limit.json +11 -0
- package/fixtures/limits/grok/grok-not-logged-in.json +11 -0
- package/fixtures/limits/negative/auth-source-set.json +11 -0
- package/fixtures/limits/negative/compile-error.json +11 -0
- package/fixtures/limits/negative/empty-stdout-exit-0.json +11 -0
- package/fixtures/live/agy/attempt-1-scratch-workspace.out.log +1 -0
- package/fixtures/live/agy/cmd.txt +1 -0
- package/fixtures/live/agy/err.log +0 -0
- package/fixtures/live/agy/out.log +1 -0
- package/fixtures/live/agy/parsed.json +5 -0
- package/fixtures/live/agy/run.json +18 -0
- package/fixtures/live/agy/supervisor.log +2 -0
- package/fixtures/live/claude/cmd.txt +1 -0
- package/fixtures/live/claude/err.log +0 -0
- package/fixtures/live/claude/limit-rate_limit.json +21 -0
- package/fixtures/live/claude/out.log +1 -0
- package/fixtures/live/claude/parsed.json +11 -0
- package/fixtures/live/claude/run.json +18 -0
- package/fixtures/live/claude/supervisor.log +2 -0
- package/fixtures/live/codex/cmd.txt +1 -0
- package/fixtures/live/codex/err.log +1 -0
- package/fixtures/live/codex/last.md +2 -0
- package/fixtures/live/codex/limit-usage_limit_exceeded.json +25 -0
- package/fixtures/live/codex/out.log +8 -0
- package/fixtures/live/codex/parsed.json +15 -0
- package/fixtures/live/codex/run.json +18 -0
- package/fixtures/live/codex/supervisor.log +2 -0
- package/fixtures/live/grok/cmd.txt +1 -0
- package/fixtures/live/grok/err.log +32 -0
- package/fixtures/live/grok/out.log +7 -0
- package/fixtures/live/grok/parsed.json +5 -0
- package/fixtures/live/grok/run.json +18 -0
- package/fixtures/live/grok/supervisor.log +2 -0
- package/fixtures/verified.json +34 -0
- package/package.json +68 -0
- package/scripts/board-shots.mjs +69 -0
- package/scripts/build-docs-site.mjs +308 -0
- package/scripts/check-claims.mjs +150 -0
- package/scripts/clean-clone-check.sh +42 -0
- package/scripts/license-sign.mjs +23 -0
- package/scripts/limits-table.mjs +38 -0
- package/scripts/live-limits.mjs +36 -0
- package/scripts/privacy-check.mjs +63 -0
- package/scripts/probe.mjs +92 -0
- package/scripts/seed-fake-cards.mjs +34 -0
- package/scripts/seed-floor-board.mjs +69 -0
- package/scripts/seed-wes-board.mjs +91 -0
- package/scripts/stripe-setup.mjs +99 -0
- package/scripts/vercel-env.mjs +40 -0
- package/src/accounts.mjs +119 -0
- package/src/adapters/agy.mjs +56 -0
- package/src/adapters/claude.mjs +54 -0
- package/src/adapters/codex.mjs +73 -0
- package/src/adapters/common.mjs +32 -0
- package/src/adapters/fake.mjs +48 -0
- package/src/adapters/grok.mjs +51 -0
- package/src/adapters/index.mjs +27 -0
- package/src/adapters/resolve.mjs +40 -0
- package/src/attach.mjs +592 -0
- package/src/auth.mjs +85 -0
- package/src/board/board.css +543 -0
- package/src/board/board.js +1307 -0
- package/src/board/favicon.svg +1 -0
- package/src/board/floor.html +127 -0
- package/src/board/floor.js +670 -0
- package/src/board/fonts/OFL-atkinson-hyperlegible-next.txt +93 -0
- package/src/board/fonts/OFL-azeret-mono.txt +94 -0
- package/src/board/fonts/atkinson-board.woff2 +0 -0
- package/src/board/fonts/azeret-board.woff2 +0 -0
- package/src/board/index.html +251 -0
- package/src/board/sessions.js +1451 -0
- package/src/bundle.mjs +103 -0
- package/src/cards.mjs +114 -0
- package/src/chain.mjs +264 -0
- package/src/commands.mjs +79 -0
- package/src/contract.mjs +73 -0
- package/src/env.mjs +19 -0
- package/src/fsx.mjs +72 -0
- package/src/git-snapshot.mjs +152 -0
- package/src/handoff.mjs +171 -0
- package/src/hook.mjs +49 -0
- package/src/land.mjs +106 -0
- package/src/launcher.mjs +272 -0
- package/src/leases.mjs +86 -0
- package/src/ledger.mjs +369 -0
- package/src/license.mjs +168 -0
- package/src/limits.mjs +97 -0
- package/src/live-capture.mjs +69 -0
- package/src/mergequeue.mjs +225 -0
- package/src/orchestrator.mjs +365 -0
- package/src/pipeline.mjs +100 -0
- package/src/preferences.mjs +47 -0
- package/src/presets.mjs +23 -0
- package/src/ratelimit.mjs +49 -0
- package/src/redact.mjs +47 -0
- package/src/resume.mjs +354 -0
- package/src/runner.mjs +438 -0
- package/src/scheduler.mjs +118 -0
- package/src/server.mjs +845 -0
- package/src/session-detail.mjs +129 -0
- package/src/sessions.mjs +202 -0
- package/src/share.mjs +163 -0
- package/src/stations/agent.mjs +42 -0
- package/src/stations/build.mjs +9 -0
- package/src/stations/human.mjs +5 -0
- package/src/stations/land.mjs +6 -0
- package/src/stations/plan.mjs +8 -0
- package/src/stations/pr.mjs +31 -0
- package/src/stations/review.mjs +8 -0
- package/src/stations/test.mjs +27 -0
- package/src/store.mjs +90 -0
- package/src/sync/dashclaw.mjs +70 -0
- package/src/sync/index.mjs +54 -0
- package/src/sync/workboard.mjs +54 -0
- package/src/taps/agy.mjs +64 -0
- package/src/taps/claude-usage.mjs +67 -0
- package/src/taps/claude.mjs +170 -0
- package/src/taps/codex.mjs +286 -0
- package/src/trust.mjs +323 -0
- package/src/usage.mjs +179 -0
- package/src/wait.mjs +30 -0
- package/src/worktree.mjs +207 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.7.0 (2026-09-15)
|
|
4
|
+
|
|
5
|
+
- **Rebranded to Leg.** Package is now `legcli` on npm, binary command is `leg`,
|
|
6
|
+
and site domain is `https://legcli.com`.
|
|
7
|
+
- **Clean break on the binary:** The `baton` CLI binary is removed; use `leg`.
|
|
8
|
+
- **State migration and fallback:** Leg stores its state in `~/.leg` (or
|
|
9
|
+
repo-local `.leg/`), and reads from `~/.baton` (or `.baton/`) as fallback.
|
|
10
|
+
Environment variables now use the `LEG_` prefix (`LEG_PUBLIC_KEY_B64`,
|
|
11
|
+
`LEG_TRUST`, `LEG_SITE`, `LEG_CHB_BIN`, `LEG_SYNC_DASHCLAW`) with automatic
|
|
12
|
+
fallback to `BATON_*`.
|
|
13
|
+
- **License keys:** Newly issued licenses carry the `LEG-` prefix. The CLI
|
|
14
|
+
accepts both `LEG-` and legacy `BATON-` keys indefinitely. Activations normalize
|
|
15
|
+
and store the `LEG-` form.
|
|
16
|
+
|
|
17
|
+
## 0.6.1 (2026-09-15)
|
|
18
|
+
|
|
19
|
+
- **The documentation is on the web.** The repository is private and stays
|
|
20
|
+
private, which meant every "read the source", README, FAQ and changelog link
|
|
21
|
+
on the site and in the package pointed at a 404 for anyone who is not the
|
|
22
|
+
owner — the first click a stranger makes. `npm run docs` renders the public
|
|
23
|
+
subset of `docs/` plus the README and this changelog to static pages under
|
|
24
|
+
`/docs`, committed to the repo because Vercel serves `site/` with no build
|
|
25
|
+
step. CI regenerates them and fails if the committed output has drifted.
|
|
26
|
+
Working files (DECISIONS, DEVIATIONS, ERRORS, REUSE, ROADMAP-v2, DEMO) stay
|
|
27
|
+
out.
|
|
28
|
+
- **Nothing dangles at a 404.** The clone instructions in the README and
|
|
29
|
+
getting-started are replaced by where the source actually is for a buyer:
|
|
30
|
+
`$(npm root -g)/baton-agents/src`, plain `.mjs`, nothing bundled. Links to
|
|
31
|
+
files with a public home go there; links to files that only ship inside the
|
|
32
|
+
package point at the package. The README's images are now absolute URLs,
|
|
33
|
+
because npm rewrites relative image paths to `raw.githubusercontent.com`,
|
|
34
|
+
which 404s for a private repository — the hero image on the npm page had been
|
|
35
|
+
broken.
|
|
36
|
+
- **A support page**, at `/support`: one address, the refund terms, license-key
|
|
37
|
+
troubleshooting, what to put in a bug report, and the security reporting path.
|
|
38
|
+
A private repository has no issue tracker to point at, so this is the whole
|
|
39
|
+
path. `SECURITY.md` said only `0.1.x` was supported, four minor versions late,
|
|
40
|
+
and pointed at a GitHub advisory form strangers cannot reach.
|
|
41
|
+
- **The claims check themselves.** `fixtures/verified.json` pins the verified
|
|
42
|
+
CLI versions, the verification date and the test count. `npm test` now asserts
|
|
43
|
+
every public surface agrees with it, and a weekly job
|
|
44
|
+
(`npm run claims:drift`) compares the pins against what those CLIs publish
|
|
45
|
+
now, because "verified against Claude Code 2.1.268" quietly stops being true.
|
|
46
|
+
On its first run it found `llms.txt` claiming 463 tests and the landing page
|
|
47
|
+
claiming 406 while the suite reported 454, and that all three pinned CLIs had
|
|
48
|
+
already moved.
|
|
49
|
+
- **The handoff is on film.** The landing page carries the 53-second recording
|
|
50
|
+
of a real run — claude's five-hour gauge reaching 100 percent, the headline
|
|
51
|
+
turning to *at the wall*, the terminal continuing on codex — and the README
|
|
52
|
+
leads with a GIF of the same moment. `preload="none"`, so the page weight is
|
|
53
|
+
unchanged until someone presses play.
|
|
54
|
+
- **macOS is in CI.** The matrix was Ubuntu and Windows only.
|
|
55
|
+
- Removed a stray `hello-fake.txt` that a fake-agent run had committed to the
|
|
56
|
+
repository root.
|
|
57
|
+
|
|
58
|
+
## 0.6.0 (2026-09-15)
|
|
59
|
+
|
|
60
|
+
- **Removed: the 14-day trial.** Baton is bought up front, and the risk
|
|
61
|
+
reversal is a **30-day money-back guarantee** instead. A trial suits a product
|
|
62
|
+
used daily by habit; Baton's value is bursty — it pays off in the one moment a
|
|
63
|
+
limit lands mid-flow, which a fortnight of evaluation does not reliably
|
|
64
|
+
contain, and a fortnight in which it never fires reads as "meh". The buyer is
|
|
65
|
+
already paying for two or three agent subscriptions, so at $79 they are not
|
|
66
|
+
price-sensitive, they are trust-sensitive, and a trial does not answer trust.
|
|
67
|
+
`trial.json`, `TRIAL_DAYS` and the trial branch in `entitlement()` are gone;
|
|
68
|
+
`baton <agent>` without a key exits 4 and names the buy URL and the guarantee.
|
|
69
|
+
- **Fixed: the card row was never ported to the dark product surface.** `.r1`
|
|
70
|
+
through `.r4` — the card row's whole four-column layout — carried no rule in
|
|
71
|
+
`board.css`, so Background tasks rendered on browser defaults while every
|
|
72
|
+
other row had been redesigned. `.row-title` never reset the native button
|
|
73
|
+
either, which put the board's near-white text on the user agent's light-grey
|
|
74
|
+
fill and made the card title unreadable.
|
|
75
|
+
- **Fixed: a finished card named the wrong agent.** `summarize()` read its
|
|
76
|
+
adapter off `chain[card.leg]`, which is reset when a station ends, so a card
|
|
77
|
+
that handed off from one agent to the next and finished reported the agent
|
|
78
|
+
that *started* the work. A finished card also showed `--:--` where its run
|
|
79
|
+
time belongs, and now shows how long it took.
|
|
80
|
+
- **Fixed: the settings panel asked for a token no one could need.** On a
|
|
81
|
+
loopback board with share off, `src/auth.mjs` lets the request in with no
|
|
82
|
+
token at all, so the API token field is no longer drawn there. It comes back
|
|
83
|
+
for a token already stored, for a guest, for an off-loopback bind, and
|
|
84
|
+
whenever health has not answered. No message names an address the server did
|
|
85
|
+
not give: a refused or redacted health call used to print `127.0.0.1:4747` at
|
|
86
|
+
someone looking at a different machine, and the owner of a shared board was
|
|
87
|
+
told their requests were "unauthenticated" when auth had recognised them.
|
|
88
|
+
- **Fixed: three places set a flat `.chip` against other text with no gap**
|
|
89
|
+
(`claudeclaude-2fbf`, `Files2 changed`, `10:40 AMstarted`), the floor printed
|
|
90
|
+
`blocked by blocked by card "X"`, and it showed the raw key `needs_approval`
|
|
91
|
+
where the board says `needs approval`.
|
|
92
|
+
- All nineteen screenshots in `docs/screenshots/` retaken against the current
|
|
93
|
+
build. `scripts/seed-wes-board.mjs` and the new
|
|
94
|
+
`scripts/seed-floor-board.mjs` produce the fixtures they need.
|
|
95
|
+
- The landing page shows a real handoff and the real board, not only
|
|
96
|
+
recreations, and says what a second agent gets without assuming the reader
|
|
97
|
+
knows git worktrees.
|
|
98
|
+
|
|
99
|
+
## 0.5.1 (2026-09-15)
|
|
100
|
+
|
|
101
|
+
- **Fixed: "All the terminal is on claude".** The verdict's plural sentence is
|
|
102
|
+
about everything riding on one login, and with a single terminal there is no
|
|
103
|
+
"all" to make. One terminal now reads `Your terminal is on claude, and claude
|
|
104
|
+
has 1% left.` Caught by rendering the real board rather than the seeded one.
|
|
105
|
+
- The tab mark is grey, not the accent blue, and the board and the site carry
|
|
106
|
+
the same mark. The site favicon had spent the one colour that means "this is
|
|
107
|
+
the action to take" on a browser tab, and the board carried a third, older
|
|
108
|
+
mark from before the identity colours settled.
|
|
109
|
+
- **Fixed: a merge to `main` did not deploy the site.**
|
|
110
|
+
`ignoreCommand: git diff --quiet HEAD^ HEAD .` asks whether the single most
|
|
111
|
+
recent commit touched `site/`. A push is not a commit: five commits landed
|
|
112
|
+
with `site/` changed in the first, so Vercel cancelled the build and reported
|
|
113
|
+
it as a green tick. Removed; every push to `main` deploys.
|
|
114
|
+
|
|
115
|
+
## 0.5.0 (2026-09-15)
|
|
116
|
+
|
|
117
|
+
- **The board is a dark product surface, and the largest thing on it is a
|
|
118
|
+
sentence.** The instrument that shipped through 0.4.3 was built against a
|
|
119
|
+
brief in `DESIGN.md` reading "exact, unhurried, mechanical, the printed
|
|
120
|
+
operator's manual for a piece of test equipment": a saturated navy ground,
|
|
121
|
+
hairline rules as the only structure, 2px radii, no elevation, and a monospace
|
|
122
|
+
face for prose. Six rounds were built against it and all six were rejected.
|
|
123
|
+
The brief, not the execution, was the defect, and it has been rewritten. What
|
|
124
|
+
ships instead:
|
|
125
|
+
- The board opens with the finding, not the data: "All 4 terminals are on
|
|
126
|
+
claude, and claude has 5% left", at 52px, written from the live view. Under
|
|
127
|
+
it sits the age of the reading and which direction it is wrong in — "Measured
|
|
128
|
+
2h 13m ago. 4 terminals have been running since, so the real figure is higher
|
|
129
|
+
than 95 percent, never lower." A reading taken two hours ago is a floor, and
|
|
130
|
+
saying so is the whole reason to print its age.
|
|
131
|
+
- Size encodes importance. The login carrying the terminals gets a wide panel
|
|
132
|
+
lit from above with both of its gauges; a login with one fact to report gets
|
|
133
|
+
a half panel; a login that publishes no figure draws no instrument at all,
|
|
134
|
+
because an empty track reads as a measurement of zero. Previously every login
|
|
135
|
+
got an identical row, so the layout said nothing before you read it.
|
|
136
|
+
- A terminal is a row inside one panel, not a card of its own: state, where,
|
|
137
|
+
the prompt, elapsed, and its buttons in a fixed 2x2 grid so every row's
|
|
138
|
+
controls sit in the same place. Land is the primary action only when it can
|
|
139
|
+
actually run; when it is blocked the accent goes to Hand off now, because a
|
|
140
|
+
disabled control should not wear the one accent colour in the design.
|
|
141
|
+
- Finished terminals, what landed on trunk and background tasks leave the live
|
|
142
|
+
area entirely and become three counts on the ground that open on click. On a
|
|
143
|
+
real board after a day's work those were most of the list and they buried the
|
|
144
|
+
one or two terminals that were live.
|
|
145
|
+
- A fact true of every terminal is said once, at the region, instead of once
|
|
146
|
+
per row. The per-row copy stays in the DOM, visually hidden, so each Land
|
|
147
|
+
button's `aria-describedby` still resolves to its own reason.
|
|
148
|
+
- Ground `#0E1012` neutral near-black, panels raised with a 1px top highlight
|
|
149
|
+
and a shadow beneath, 16px radii, type from 13 to 52px (it ran 13 to 21,
|
|
150
|
+
which is why it read as a spreadsheet), one accent blue spent on the primary
|
|
151
|
+
action and nowhere else, and severity painted inside a gauge track rather
|
|
152
|
+
than used as the colour of a word.
|
|
153
|
+
- Measured against a board shaped like a real one — mostly `lost` and `ended`
|
|
154
|
+
terminals with long absolute paths — the page went from 3,302px to 2,107px at
|
|
155
|
+
1280 and from 6,530px to 3,937px at 400, with terminal rows from 180-277px
|
|
156
|
+
down to 135-165px.
|
|
157
|
+
- **Prompts, file lists and the trunk log stop printing machine noise.** A pasted
|
|
158
|
+
screenshot arrived in the prompt as an `<image name=... path=...>` tag carrying
|
|
159
|
+
an absolute temp path with the operator's home directory in it, and printed as
|
|
160
|
+
two lines of noise in front of the sentence; it now reads `(image)` and the
|
|
161
|
+
text. A touched file prints its basename, not 90 characters of temp path. The
|
|
162
|
+
trunk log shows what landed as a count that opens, instead of eighteen rows of
|
|
163
|
+
`git log` at the same visual weight as the live terminals.
|
|
164
|
+
- **The marketing site runs on the board's own hex values.** `site/` was a light
|
|
165
|
+
page recreating the board in a different palette, from the card anatomy the
|
|
166
|
+
board stopped having two commits earlier. Both recreations are rebuilt against
|
|
167
|
+
what the board actually renders now, the page is on the same ramp as the
|
|
168
|
+
product, emphasis between folds is elevation rather than a slab of hue, and the
|
|
169
|
+
brand mark, favicon and OG card follow. `llms.txt` and every "card" in the copy
|
|
170
|
+
corrected. A marketing page that recreates the product in a different palette
|
|
171
|
+
is a picture of a different product.
|
|
172
|
+
- `DESIGN.md` rewritten to describe what ships, opening with what it replaced and
|
|
173
|
+
why it must not come back, and covering both surfaces from one set of tokens.
|
|
174
|
+
- `README.md` and its screenshot recaptured against the board that now exists.
|
|
175
|
+
|
|
176
|
+
- **A resume pointer that cannot describe a picture that is no longer true.**
|
|
177
|
+
`.baton/RESUME.md` used to be an unowned convenience copy: written once per
|
|
178
|
+
hand-off, never touched again, with no stamp and no expiry, so a terminal that
|
|
179
|
+
exited normally left hours old text sitting there looking live. Four changes,
|
|
180
|
+
in `src/resume.mjs`:
|
|
181
|
+
- Every resume file Baton writes carries a stamp (an HTML comment, invisible
|
|
182
|
+
in rendered markdown) of the commit, branch, working-tree fingerprint and
|
|
183
|
+
live terminals it was written against. The fingerprint is a count and a
|
|
184
|
+
12-character hash of the sorted paths, never the file names, so a shared
|
|
185
|
+
board cannot leak what someone is working on.
|
|
186
|
+
- Baton owns `RESUME.md`. A session ending rewrites it to "nothing in flight",
|
|
187
|
+
naming the last hand-off, its date and where its full text still lives; the
|
|
188
|
+
board rewrites it at start for any checkout whose pointer describes a
|
|
189
|
+
terminal that is gone, or that no Baton stamped. A terminal that is still
|
|
190
|
+
running keeps its own hand-off text.
|
|
191
|
+
- `baton resume [--check] [--json] [--path <dir>]` recomputes freshness from
|
|
192
|
+
git at read time and never from the file: exit 0 current, 1 stale or
|
|
193
|
+
unstamped, 3 no pointer in this checkout. Stale still prints the body behind
|
|
194
|
+
a loud banner, because a stale hand-off beats nothing when a human chooses
|
|
195
|
+
to read it; the exit code is what scripts and hooks key on.
|
|
196
|
+
- The terminal drawer's "What happens next" section carries the same verdict,
|
|
197
|
+
recomputed on every poll.
|
|
198
|
+
- **The terminal drawer reads newest first.** The conversation and the timeline
|
|
199
|
+
both put the last thing that happened at the top, so the drawer can be left
|
|
200
|
+
open beside the work without scrolling to find the current state.
|
|
201
|
+
- **Fixed: a scrolled box in the drawer snapped back to the top every three
|
|
202
|
+
seconds.** The panel is rebuilt on every poll so relative timestamps stay
|
|
203
|
+
honest, which threw away where the reader had scrolled inside the task box, a
|
|
204
|
+
message or the timeline. Every scrollable box now carries a stable key and its
|
|
205
|
+
offset is carried across the rebuild.
|
|
206
|
+
|
|
207
|
+
## 0.4.3 (2026-09-14)
|
|
208
|
+
|
|
209
|
+
- **Choose terminal handoff order.** Settings stores the priority order copied
|
|
210
|
+
by new terminals, and each newly attached terminal can change its own order
|
|
211
|
+
while it is running. The order is absolute, not a rotation anchored on the
|
|
212
|
+
agent running now: an agent moved to the bottom (agy, say) is the last option
|
|
213
|
+
from every starting agent instead of jumping to the front of the list for the
|
|
214
|
+
agents above it. The card shows Now, the exact fallback candidates, the
|
|
215
|
+
preferred next option, and the first currently eligible option. Missing CLIs,
|
|
216
|
+
usage walls, same-agent account fallback, all-out waiting, owner controls,
|
|
217
|
+
and normal-exit behavior are unchanged. Older terminals say that a restart
|
|
218
|
+
is required and can save the next-launch default.
|
|
219
|
+
- **See what a terminal is doing.** **Details** on a terminal card (or a click
|
|
220
|
+
on its prompt) opens a drawer: the agent's last turn, the prompt the terminal
|
|
221
|
+
started from, its last eight messages, every file it changed with the line
|
|
222
|
+
counts and a diff per file, the event timeline, and the handoff order that
|
|
223
|
+
comes next. It refreshes every three seconds while open and pauses with the
|
|
224
|
+
tab or the button. Transcripts and diffs are scrubbed for secrets before they
|
|
225
|
+
leave the machine, and a terminal that belongs to another human on a shared
|
|
226
|
+
board stays refused.
|
|
227
|
+
- **The terminal is left the way the agent found it.** An agent killed by End,
|
|
228
|
+
Hand off now or the usage limit never runs its own cleanup, so its terminal
|
|
229
|
+
modes outlived it: the mouse wheel printed raw mouse reports into the shell
|
|
230
|
+
after the session ended, and a leftover scrolling region made the next leg's
|
|
231
|
+
output land on top of the lines already on screen. The restore now turns off
|
|
232
|
+
every mouse reporting mode, bracketed paste and focus events, puts cursor
|
|
233
|
+
keys, the keypad and autowrap back, resets the scrolling region without
|
|
234
|
+
moving the cursor, and clears only the dead agent's half-drawn frame.
|
|
235
|
+
- **Clearer background cards.** The New background card form leads with repo,
|
|
236
|
+
task, and a real first agent; explains its separate worktree and Run now
|
|
237
|
+
versus draft; and puts workflow, fallback, permissions, approvals, limits,
|
|
238
|
+
leases, landing, tests, titles, and labeled test/demo adapters under Advanced
|
|
239
|
+
options. Build only explicitly says it does not merge, while workflows with
|
|
240
|
+
an automatic merge say so in their labels.
|
|
241
|
+
|
|
242
|
+
## 0.4.2 (2026-09-14)
|
|
243
|
+
|
|
244
|
+
- **Automatic npm publication.** A successful push to `main` now waits for the
|
|
245
|
+
complete Ubuntu and Windows CI matrix, validates package and lock metadata,
|
|
246
|
+
and publishes only when the exact version is missing and newer than npm's
|
|
247
|
+
stable `latest`. It uses npm trusted publishing with OIDC and no repository
|
|
248
|
+
token secret; stale versions and registry errors fail closed.
|
|
249
|
+
|
|
250
|
+
## 0.4.1 (2026-09-14)
|
|
251
|
+
|
|
252
|
+
- **Codex quota and account display.** Codex usage now comes from the read-only
|
|
253
|
+
app-server `account/rateLimits/read` response, polled every 60 seconds by the
|
|
254
|
+
board and active attach. Returned 300- and 10080-minute windows map to 5h
|
|
255
|
+
and 7d; an explicit backend available answer clears an old wall. The board
|
|
256
|
+
says `<n>% used` and labels stale readings instead of implying current data.
|
|
257
|
+
- **Session and landing safety.** The board offers **Remove record** with a
|
|
258
|
+
confirmation that preserves an own worktree, branch, unmerged commits, and
|
|
259
|
+
dirty files. Normal removal remains a safe prune. Concurrent End and Hand off
|
|
260
|
+
use the session file lock; landing rejects the wrong base branch, proves a
|
|
261
|
+
merged branch before pruning, reruns tests after a retry rebase, and recovers
|
|
262
|
+
orphaned `handing_off` cards.
|
|
263
|
+
- **Board freshness and roles.** Switching from a guest token back to an owner
|
|
264
|
+
restores pipeline controls without a reload; guest tokens still reconnect the
|
|
265
|
+
terminal stream. Card-list, drawer, log, Floor, and SSE responses now reject
|
|
266
|
+
stale asynchronous completions.
|
|
267
|
+
- **Loopback board authorization.** Tokenless owner access now requires both a
|
|
268
|
+
loopback peer and a loopback `Host`, preventing DNS-rebound hostnames from
|
|
269
|
+
inheriting owner access to read and state-changing API routes.
|
|
270
|
+
- **License delivery.** Team refresh is a signed-key POST: an expired signed
|
|
271
|
+
Team key can refresh while its subscription is active, without individual-seat
|
|
272
|
+
revocation. Webhooks accept rotated Stripe `v1` signatures; Resend receives a
|
|
273
|
+
stable event-and-delivery idempotency key, retained by Resend for 24 hours.
|
|
274
|
+
|
|
275
|
+
## 0.4.0 (2026-09-11)
|
|
276
|
+
|
|
277
|
+
Baton is a paid product as of 14 September 2026: a 14-day trial, then a Personal
|
|
278
|
+
license ($79 once, 12 months of releases) or Team ($12 per seat per month,
|
|
279
|
+
adds `baton share`). The license is the Baton License Agreement (commercial, source readable);
|
|
280
|
+
0.2.0 and 0.3.0 remain published under MIT and are not deprecated.
|
|
281
|
+
|
|
282
|
+
- **License gate.** `src/license.mjs`: Ed25519-signed keys checked offline
|
|
283
|
+
against the embedded public key; a Personal key is a window over release
|
|
284
|
+
dates (`RELEASE_DATE`), a Team key expires and `baton license refresh`
|
|
285
|
+
renews it; the trial is recorded under `$BATON_HOME`. `baton <agent>` exits
|
|
286
|
+
4 once nothing is left; `baton share on` needs Team (the trial counts).
|
|
287
|
+
`baton license status|activate|deactivate|refresh`. `scripts/license-sign.mjs`
|
|
288
|
+
signs a key by hand. Ten tests.
|
|
289
|
+
- **The npm package runs.** `files` now ships `fixtures/limits` and
|
|
290
|
+
`fixtures/live`, which `src/limits.mjs` and `src/live-capture.mjs` read at
|
|
291
|
+
load; 0.3.0 from npm crashed on every command for that reason. A lessons
|
|
292
|
+
test packs the tarball and checks it.
|
|
293
|
+
- **Checkout.** Stripe payment links, a `site/api/key` function that turns a
|
|
294
|
+
paid checkout into a key (deterministic per purchase), a webhook that emails
|
|
295
|
+
it through Resend, and `site/thanks` that shows it. `scripts/stripe-setup.mjs`
|
|
296
|
+
creates the plans, links and webhook idempotently; `scripts/vercel-env.mjs`
|
|
297
|
+
pushes the secrets.
|
|
298
|
+
- **A marketing site.** `site/` holds a static page for the product (hero, the handoff played in a recreated terminal, the board and the two-session cards recreated in HTML, the changeover, what is never touched, install), with the SEO floor (title from measured search volume, description, canonical, OG image, robots.txt, sitemap.xml, llms.txt) and Vercel headers. PRODUCT.md and DESIGN.md at the root carry the brief and the design tokens; docs/DECISIONS.md records why cobalt. Not part of the npm package.
|
|
299
|
+
|
|
300
|
+
## 0.3.2 (2026-09-11)
|
|
301
|
+
|
|
302
|
+
A second adversarial review over 0.3.1, this time of the whole tree: 49
|
|
303
|
+
confirmed bugs fixed, each with a regression test seen red first (340 tests).
|
|
304
|
+
|
|
305
|
+
- **Cards no longer wedge or double-launch.** Hand off now and Reassign on a
|
|
306
|
+
running leg used to throw out of the orchestrator and leave the card in
|
|
307
|
+
`handing_off` holding a concurrency slot with no bundle; both now stop the
|
|
308
|
+
leg, write the bundle, and continue in the same driver. A card is claimed by
|
|
309
|
+
a `driver.lock` for the whole of `runCard`, so a `card run` beside the board's
|
|
310
|
+
scheduler (or two schedulers: `scheduler start` now refuses when one runs and
|
|
311
|
+
the pidfile is created atomically) can never launch two legs into one
|
|
312
|
+
worktree; `runner launch` writes `run.json` with its driver before spawning
|
|
313
|
+
the supervisor. Kill during the launching window kills the supervisor tree
|
|
314
|
+
instead of nothing. A card left running at a test or land station by a crash
|
|
315
|
+
is recovered by the scheduler. Kill or Pause during a test or land station is
|
|
316
|
+
no longer undone by the late result. A land bounce with no agent station, and
|
|
317
|
+
a red test whose only agent station comes later, fail the card instead of
|
|
318
|
+
throwing or skipping ahead. Hand off now is offered only when a next leg
|
|
319
|
+
exists. `--model <adapter>=<name>` (and a chain entry's `network`) now reach
|
|
320
|
+
the agent argv; they were dropped on the way to the runner.
|
|
321
|
+
- **The board stays up.** The test station ran the repo's suite with
|
|
322
|
+
`spawnSync` inside the board server, freezing HTTP, SSE, the scheduler and
|
|
323
|
+
the merge queue for its whole duration; it is async now. The drawer no
|
|
324
|
+
longer refetches on every log byte, the log tail refreshes when the run
|
|
325
|
+
changes, an open drawer is refetched after an SSE reconnect, and the floor
|
|
326
|
+
stops polling on a 401 and shows a way back.
|
|
327
|
+
- **No lost writes.** `run.json` and `card.json` are read-modify-written under
|
|
328
|
+
a cross-process lock (a human Kill was silently reverted by a driver's status
|
|
329
|
+
write). `withFileLock` itself treated Windows' EPERM during a sibling's
|
|
330
|
+
unlink as "give up and run unlocked": it now retries, which also closes the
|
|
331
|
+
hole in the 0.3.1 session and usage locks. `ledger sync` renames the buffer
|
|
332
|
+
before flushing so a record buffered mid-flush survives, and refuses clearly
|
|
333
|
+
when sync is off. The merge queue's turn is a file lock keyed on the
|
|
334
|
+
canonical repo root, so two spellings of one checkout, or two processes,
|
|
335
|
+
never land into it at once.
|
|
336
|
+
- **`baton share` and the launcher.** `share add sam` before `share on` no
|
|
337
|
+
longer makes the guest the owner. A non-loopback board no longer falls open
|
|
338
|
+
to everyone the moment share.json reads as off (`share off` stops the
|
|
339
|
+
listener first, and the bind is re-checked per request). Share off no longer
|
|
340
|
+
promotes a guest's live SSE stream; a stale tab repeating one rotated token
|
|
341
|
+
no longer locks the machine out; `share on|off` no longer kill every running
|
|
342
|
+
agent; `share rm` refuses to take the last owner; the SSE health frame is
|
|
343
|
+
filtered for guests; a redacted session names its branch. The pidfile is
|
|
344
|
+
confirmed by a probe, so `status` cannot report a dead board as running and
|
|
345
|
+
`down` cannot kill whatever reused the PID. Card removal with `?branch=delete`
|
|
346
|
+
no longer escalates to `git branch -D` without `?force=1`, a status check
|
|
347
|
+
that fails no longer reads as clean, and `sessions rm` refuses mid-land.
|
|
348
|
+
- **The limit path.** codex's rollout is found for a session started in the
|
|
349
|
+
local evening (the day directory is local, the filter compared UTC). agy's
|
|
350
|
+
wall is seen behind non-ASCII log lines (a byte count was used as a string
|
|
351
|
+
index) and an old wall is not re-fired by a second agy leg. After a hand-off
|
|
352
|
+
the previous agent's usage bars are cleared, the near-limit warning fires
|
|
353
|
+
again, the chain shown as "next" is recomputed, `all_out` clears after the
|
|
354
|
+
wait, an agy leg adds to the turn count, and a board Hand off with the other
|
|
355
|
+
agents walled restarts the current agent instead of waiting. The resume
|
|
356
|
+
prompt names the absolute RESUME file.
|
|
357
|
+
- Smaller: an agent-created `.env.example` is no longer dropped from a land;
|
|
358
|
+
a card whose trunk does not exist is refused at `card add` naming the repo's
|
|
359
|
+
default branch (it used to burn every land attempt); a rebase git refuses for
|
|
360
|
+
a non-conflict reason bounces `rebase-failed` with git's words, and a
|
|
361
|
+
conflicting retry is no longer reported as `trunk-moved`; `sk-` no longer
|
|
362
|
+
matches ordinary hyphenated words (a task saying "risk-free" was refused as a
|
|
363
|
+
secret); `OPENAI_BASE_URL` is stripped from agent legs; with share off and a
|
|
364
|
+
token, the rate limit is per address, not one shared bucket.
|
|
365
|
+
|
|
366
|
+
## 0.3.1 (2026-09-11)
|
|
367
|
+
|
|
368
|
+
A security and correctness pass over 0.3.0, after an adversarial review. No new
|
|
369
|
+
features; 44 fixes, all covered by the test suite (281 tests).
|
|
370
|
+
|
|
371
|
+
- **`baton share` security.** A guest could read the owner's pipeline through
|
|
372
|
+
`/api/trunk` (now on the guest deny-list) and through the SSE stream (the
|
|
373
|
+
card/removed broadcasts now carry the per-viewer filter, and every push
|
|
374
|
+
re-checks the viewer against the live roster). `share add|rotate|rm` now take
|
|
375
|
+
effect on a live board instead of after a restart: the server re-reads
|
|
376
|
+
`share.json` per request, so a removed or rotated link stops at once and a new
|
|
377
|
+
one works at once. `baton share add` before `baton share on` can no longer
|
|
378
|
+
make a guest the board's owner. A non-loopback bind also listens on 127.0.0.1
|
|
379
|
+
so the owner keeps a tokenless URL while a remote peer still needs a token.
|
|
380
|
+
Cross-origin state-changing requests are refused. New `test/share-security.test.mjs`
|
|
381
|
+
sends a missing, wrong, other-human, rotated and removed token to every route
|
|
382
|
+
including SSE.
|
|
383
|
+
- **No lost work.** Land refuses a worktree with a rebase/merge already in
|
|
384
|
+
progress (it used to commit the half-state and then abort it, deleting the
|
|
385
|
+
human's uncommitted files). Remove and `baton sessions rm` no longer drop a
|
|
386
|
+
session record while its worktree still holds unlanded commits. `git branch -d`
|
|
387
|
+
before `-D`. A Land never commits a `.env`. A git failure during a Land no
|
|
388
|
+
longer crashes the board process.
|
|
389
|
+
- **No lost writes.** `session.json` and the usage files are written under a
|
|
390
|
+
cross-process lock with a reducer form, so concurrent hooks, taps and pollers
|
|
391
|
+
stop losing files, turns and limit walls to a last-writer-wins race.
|
|
392
|
+
- **The limit path.** The handoff chooser skips agents that are not installed
|
|
393
|
+
(a missing next agent used to kill the session exit 127), the all-out wait
|
|
394
|
+
counts down to the true soonest reset including the current agent, a weekly
|
|
395
|
+
wall is no longer recorded as a 5-hour one, and agy reset durations with more
|
|
396
|
+
than one unit (`71h19m42s`) are summed, not truncated. `live-capture` now
|
|
397
|
+
redacts the home and repo paths, not only secret shapes. The env sanitizer
|
|
398
|
+
also strips the Google/Gemini keys the agy leg kept.
|
|
399
|
+
- A hung test command no longer leaves a card in `landing` forever and wedging
|
|
400
|
+
the repo's merge queue. A crash during `git worktree add` no longer orphans a
|
|
401
|
+
worktree with no card. Two sessions in one checkout get their own
|
|
402
|
+
`RESUME-<id>.md`.
|
|
403
|
+
|
|
404
|
+
## 0.3.0 (2026-09-11)
|
|
405
|
+
|
|
406
|
+
Closing the gaps against the two tweets: a limit path proved live, waiting
|
|
407
|
+
instead of quitting, collisions stopped instead of flagged, and more than one
|
|
408
|
+
human on the board.
|
|
409
|
+
|
|
410
|
+
- `baton sessions simulate-limit <id>`: a `StopFailure` `rate_limit` payload in
|
|
411
|
+
the shape Claude Code sends (marked simulated) goes through Baton's hook, so
|
|
412
|
+
the whole path runs for real (limit status, bundle, agent stopped, the next
|
|
413
|
+
agent started in the same terminal). Verified live: a haiku session handed
|
|
414
|
+
off to codex, which read `.baton/RESUME.md` on its first turn. The simulated
|
|
415
|
+
wall clears after two minutes and is never kept as evidence. agy: the
|
|
416
|
+
RESOURCE_EXHAUSTED line is appended to the session's own log. codex is
|
|
417
|
+
refused (use `handoff`).
|
|
418
|
+
- The first real claude `StopFailure` is saved with secrets scrubbed under
|
|
419
|
+
`fixtures/live/<agent>/` in a dev clone (outside a clone it goes to
|
|
420
|
+
`~/.baton/live/`, a path nothing has written yet), and the docs row for it
|
|
421
|
+
flips from docs-only to observed-live (`scripts/live-limits.mjs`). The same
|
|
422
|
+
capture is wired for codex `usage_limit_exceeded` and agy
|
|
423
|
+
`RESOURCE_EXHAUSTED`; no real payload for either has been kept yet, and
|
|
424
|
+
their rows are still docs-only.
|
|
425
|
+
- `BATON_CLAUDE_ARGS`, `BATON_CODEX_ARGS`, `BATON_AGY_ARGS`: extra arguments
|
|
426
|
+
for a leg Baton starts after a hand-off (keep a chain on cheap models).
|
|
427
|
+
- codex's card no longer shows the injected AGENTS.md block as the task.
|
|
428
|
+
- When every option is out the terminal no longer exits 3: it prints the reset
|
|
429
|
+
times, counts down to the first one, and starts that agent from the bundle
|
|
430
|
+
when it arrives (`src/wait.mjs`). The card shows `waiting for <agent> at
|
|
431
|
+
<time>`. End on the card quits with exit 3; Ctrl-C is wired to the same exit
|
|
432
|
+
(the End path is the one under test). Verified live: with codex walled for
|
|
433
|
+
80 s and agy for 200 s, a simulated limit on a haiku session waited and then
|
|
434
|
+
started codex from `.baton/RESUME.md`.
|
|
435
|
+
- A second live session in a checkout that already has one gets its own git
|
|
436
|
+
worktree, `<repo>/.baton-worktrees/<session-id>` on branch
|
|
437
|
+
`baton/<session-id>`, cut from the branch the checkout has out; the terminal
|
|
438
|
+
prints one line saying where. `--no-worktree` shares the checkout (the flag
|
|
439
|
+
never reaches the agent).
|
|
440
|
+
- **Land** on the card of a session with its own worktree sends its branch
|
|
441
|
+
through the merge queue: commit what the agent left, rebase onto the base,
|
|
442
|
+
run the tests, fast-forward only, or bounce with the reason
|
|
443
|
+
(`rebase-conflict` with the files, `tests-red` with the output tail,
|
|
444
|
+
`dirty-trunk` when the checkout has local changes the landing would
|
|
445
|
+
overwrite). The landed-on-trunk list says who landed each commit
|
|
446
|
+
(`~/.baton/landings.jsonl`). Remove takes the worktree and branch along only
|
|
447
|
+
when the worktree is clean and the branch is already on its base. Verified
|
|
448
|
+
live: three haiku sessions in a throwaway repo, the second and third in
|
|
449
|
+
worktrees both appending to README.md; Land on one ran the tests and
|
|
450
|
+
fast-forwarded main, Land on the other bounced with `rebase-conflict` on
|
|
451
|
+
README.md.
|
|
452
|
+
- `baton share`: more than one human on the board, off by default. `baton share
|
|
453
|
+
on` binds the Tailscale address (or `--bind lan`, or one you name) and gives
|
|
454
|
+
every human a name and their own token, kept as a sha256 hash and printed
|
|
455
|
+
once (`baton share rotate <name>` issues a new one). A terminal belongs to
|
|
456
|
+
the human who started it (`BATON_PERSON`). Another human's card is
|
|
457
|
+
read-only: no prompt, no file names, no paths, no limit message, no bundle,
|
|
458
|
+
no events, no logs — the agent, the branch, the usage bars and the reset
|
|
459
|
+
time still show — and one **Request handoff** button that the owner
|
|
460
|
+
approves or dismisses on their own card; the pipeline side stays the
|
|
461
|
+
owner's. The security pass: a token on every `/api` route including the
|
|
462
|
+
event stream (which is computed per viewer), 403 for a guest on anything
|
|
463
|
+
that is not theirs, a lockout after repeated wrong tokens from one address
|
|
464
|
+
and a per-human request ceiling (defaults 20 failures and 600 requests a
|
|
465
|
+
minute, `src/ratelimit.mjs`; the tests drive both at lower thresholds), and
|
|
466
|
+
tests that send a bad and a missing token to every route. Verified live
|
|
467
|
+
over Tailscale with two terminals on one machine, one wes's and one sam's:
|
|
468
|
+
sam's board redacted wes's card, and sam's **Request handoff** reached
|
|
469
|
+
wes's board (the approve-then-hand-off step is covered by tests).
|
|
470
|
+
- The merge queue runs its tests through an async spawn instead of a blocking
|
|
471
|
+
one, so a Land no longer parks the board's event loop.
|
|
472
|
+
- Fixed: a board that asks for a token answered `ensureBoard`'s health probe
|
|
473
|
+
with 401, and Baton read that as "no board" and started a second one.
|
|
474
|
+
- `/api/health` asks each adapter where its binary is instead of running the
|
|
475
|
+
bare name, so the board no longer says `codex: false` while the runner starts
|
|
476
|
+
codex fine.
|
|
477
|
+
- When the claude usage endpoint 404s, answers with something that is not JSON,
|
|
478
|
+
or changes shape, the card says `usage unknown (<why>) · the limit still
|
|
479
|
+
hands off` instead of showing empty bars; the wall still arrives through the
|
|
480
|
+
`StopFailure` hook. `BATON_CLAUDE_USAGE_URL` (or `fetchClaudeUsage({ url })`)
|
|
481
|
+
accepts an http test double.
|
|
482
|
+
- Fixed: the first dirty file on a card (and in the bundle notes) lost its
|
|
483
|
+
first letter (`EADME.md`) because the porcelain status was trimmed;
|
|
484
|
+
`.dashclaw-local/` no longer counts as a file being touched, and it joins
|
|
485
|
+
`.baton/`, `.baton-worktrees/` and `.context-handoffs/` in
|
|
486
|
+
`.git/info/exclude` so a landing never commits it.
|
|
487
|
+
- `BATON_NO_BOARD=1` runs a session without the board; a stub-agent end-to-end
|
|
488
|
+
test (`test/attach-e2e.test.mjs`) now runs `baton claude` through the hook,
|
|
489
|
+
the hand-off, the wait and the restart in CI.
|
|
490
|
+
|
|
491
|
+
## 0.2.0 (2026-09-11)
|
|
492
|
+
|
|
493
|
+
The way in is now `baton claude`, `baton codex` or `baton agy`: the normal
|
|
494
|
+
interactive agent in your terminal, with Baton alongside it. The v0.1 form,
|
|
495
|
+
pipelines, leases and merge queue stay as extras.
|
|
496
|
+
|
|
497
|
+
- `baton <agent> [args…]` starts the real interactive CLI with your settings,
|
|
498
|
+
hooks and skills; extra args pass straight through. API-key variables are
|
|
499
|
+
stripped; Baton writes its own per-session settings file
|
|
500
|
+
(`~/.baton/sessions/<id>/claude-settings.json`) and passes it with
|
|
501
|
+
`--settings`, instead of editing `~/.claude`, `~/.codex` or agy's home.
|
|
502
|
+
- The board opens once and is reused; every session in every terminal is a
|
|
503
|
+
card: agent, account, repo@branch, task, turns, files being touched, 5h/7d
|
|
504
|
+
usage, warning/limit/handoff state. Two live sessions editing the same file
|
|
505
|
+
in one repo are flagged on both cards. A "landed on trunk" list per repo.
|
|
506
|
+
Buttons: Hand off now, End, Remove.
|
|
507
|
+
- Usage tracking per agent and account. claude: Claude Code's usage endpoint
|
|
508
|
+
with the stored login (a status-line JSON route is written as a fallback;
|
|
509
|
+
on the build machine, Claude Code 2.1.268 was not seen running a custom
|
|
510
|
+
status line — see docs/adapters.md) plus the `StopFailure` `rate_limit`
|
|
511
|
+
hook. codex: the session rollout file
|
|
512
|
+
(`token_count.rate_limits`, `usage_limit_exceeded`). agy: its log
|
|
513
|
+
(`RESOURCE_EXHAUSTED`, "it resets in"); no percentage is exposed.
|
|
514
|
+
- A context-handoff-bundle per session, refreshed every two minutes and at
|
|
515
|
+
every warning/limit/handoff (`save --update <slug>`).
|
|
516
|
+
- Hand-off on limit or on request: bundle, stop the agent, restore the
|
|
517
|
+
terminal, start the next option in the same terminal from `.baton/RESUME.md`.
|
|
518
|
+
Order: other logins of the same agent, then the next agents (claude → codex
|
|
519
|
+
→ agy). When every option is out: each reset time, soonest first, then exit
|
|
520
|
+
3. (0.3.0 waits for the first reset instead.)
|
|
521
|
+
- Optional second logins: `baton accounts add <claude|codex> <name>` (config-dir
|
|
522
|
+
junctions for the shared harness, one login line to paste). Both vendors'
|
|
523
|
+
terms are in the README and are printed by `baton accounts terms`.
|
|
524
|
+
- `baton uninstall` removes only `~/.baton` (it prints what it will remove and
|
|
525
|
+
asks for confirmation).
|
|
526
|
+
- gemini removed everywhere (Google retired Gemini CLI in favour of agy).
|
|
527
|
+
- 0 runtime dependencies still. New modules: src/attach.mjs, src/sessions.mjs,
|
|
528
|
+
src/usage.mjs, src/accounts.mjs, src/bundle.mjs, src/hook.mjs, src/taps/*.
|
|
529
|
+
|
|
530
|
+
## 0.1.0 (2026-09-10)
|
|
531
|
+
|
|
532
|
+
First public release (source on GitHub; not on npm yet).
|
|
533
|
+
|
|
534
|
+
- Ported the detached runner, the append-only ledger and the git snapshot tool
|
|
535
|
+
from a private ucsandman repository (team tooling) under the same MIT license,
|
|
536
|
+
with Telegram delivery, chat identifiers and machine paths removed (see
|
|
537
|
+
NOTICE, docs/REUSE.md, docs/DEVIATIONS.md).
|
|
538
|
+
- Adapters for claude, codex, gemini and agy, each spawned as argv with a
|
|
539
|
+
sanitized child environment (subscription logins only, no YOLO flags); grok
|
|
540
|
+
written from `--help` but unregistered until a live probe passes.
|
|
541
|
+
- Limit detector built from 25 recorded signals (docs/cli-contracts.md keeps
|
|
542
|
+
the observed-live vs docs-only tag per row); DONE-marker completion contract.
|
|
543
|
+
- Handoffs through context-handoff-bundle (repo-local bundles, `load` resume
|
|
544
|
+
prompt); pipeline presets factory / build / build-land; scheduler with path
|
|
545
|
+
leases; land station as a merge queue (rebase → test → ff-only, bounce with
|
|
546
|
+
the failure in the bundle); `pr` land mode stub.
|
|
547
|
+
- Board (kanban from the pipeline, every judgment a button, detail drawer) and
|
|
548
|
+
floor view (running cards, leases, trunk lane) over a ledger-backed server
|
|
549
|
+
with SSE and a BATON_BIND / BATON_TOKEN seam.
|
|
550
|
+
- Launcher: `npm start` = `baton up` (preflight, health check, prefixed
|
|
551
|
+
redacted logs, Ctrl-C teardown), `up --dry`, `down`, `status`, `open`.
|
|
552
|
+
- Optional syncs, off by default: OpenClaw Workboard (argv) and DashClaw action
|
|
553
|
+
recording (verified live once).
|
|
554
|
+
- Demo (fake limit on the board, five screenshots) and one real run: claude
|
|
555
|
+
hit `--max-turns 2`, codex finished from the bundle, tests green in 2 m 50 s.
|
|
556
|
+
- Polish pass: a missing CLI ends the card `failed` (was stuck `running`);
|
|
557
|
+
runs re-attach after `baton down` instead of relaunching; bounce and
|
|
558
|
+
blocked chips name their reason; repo path must be a git root outside
|
|
559
|
+
BATON_HOME; SSE re-reads only the changed card; reduced-motion and contrast
|
|
560
|
+
checks; docs/VOCABULARY.md.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Leg License Agreement
|
|
2
|
+
|
|
3
|
+
Copyright 2026 Wes Sander (Practical Systems). All rights reserved.
|
|
4
|
+
|
|
5
|
+
This is a legal agreement between you and Wes Sander ("we") for the Leg
|
|
6
|
+
software, including its source files, documentation and updates ("Leg").
|
|
7
|
+
By installing or using Leg you accept it. If you do not accept it, do not
|
|
8
|
+
install or use Leg.
|
|
9
|
+
|
|
10
|
+
1. License. When you buy a license we grant you a non-exclusive,
|
|
11
|
+
non-transferable license to install and use Leg as follows.
|
|
12
|
+
Personal: one named person, on any number of machines that person uses.
|
|
13
|
+
Team: one named person per seat purchased. A Team license also covers use
|
|
14
|
+
of the shared board (leg share) by the people holding seats. A Personal
|
|
15
|
+
license covers every Leg release dated on or before the date printed in
|
|
16
|
+
the license key; releases dated after that require a renewal, and the
|
|
17
|
+
releases already covered keep working. A Team license covers releases
|
|
18
|
+
while the subscription is active.
|
|
19
|
+
|
|
20
|
+
2. Source. Leg ships as readable JavaScript so that you can inspect what it
|
|
21
|
+
does on your machine. You may read it and modify it for your own use under
|
|
22
|
+
your license. You may not publish, distribute, sublicense, rent, sell or
|
|
23
|
+
host Leg or any modified version for others, and you may not remove,
|
|
24
|
+
disable or work around the license check.
|
|
25
|
+
|
|
26
|
+
3. What is yours. Everything Leg writes for you (session notes, handoff
|
|
27
|
+
bundles, worktrees, your repositories) is yours. Leg sends nothing about
|
|
28
|
+
your work anywhere; the only network calls it makes on its own behalf are
|
|
29
|
+
to this product's site to renew a Team key, and to the agent vendors'
|
|
30
|
+
endpoints that the agent CLIs themselves use.
|
|
31
|
+
|
|
32
|
+
4. Third parties. Leg starts the coding-agent CLIs you already have and use
|
|
33
|
+
under your own accounts and their vendors' terms. You are responsible for
|
|
34
|
+
complying with those terms; see `leg accounts terms`.
|
|
35
|
+
|
|
36
|
+
5. Ownership. Leg is licensed, not sold. We keep all rights not expressly
|
|
37
|
+
granted here.
|
|
38
|
+
|
|
39
|
+
6. Money-back guarantee. Within 30 days of purchase, reply to your receipt
|
|
40
|
+
and we refund it in full. You do not have to give a reason, and you do not
|
|
41
|
+
have to have stopped using Leg before you ask.
|
|
42
|
+
|
|
43
|
+
7. No warranty. Leg is provided "as is", without warranty of any kind,
|
|
44
|
+
express or implied, including fitness for a particular purpose. Coding
|
|
45
|
+
agents act on your code; you review what they do.
|
|
46
|
+
|
|
47
|
+
8. Limitation of liability. To the extent the law allows, our total liability
|
|
48
|
+
for any claim related to Leg is limited to the amount you paid for it in
|
|
49
|
+
the 12 months before the claim, and we are not liable for indirect,
|
|
50
|
+
incidental or consequential damages.
|
|
51
|
+
|
|
52
|
+
9. Termination. This agreement ends if you breach it; on termination you
|
|
53
|
+
stop using Leg. Sections 5, 7 and 8 survive.
|
|
54
|
+
|
|
55
|
+
10. Law. This agreement is governed by the laws of the State of Ohio, USA,
|
|
56
|
+
without regard to conflict-of-law rules.
|
|
57
|
+
|
|
58
|
+
Contact: legcli@practicalsystems.io
|
package/NOTICE
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
Portions of this software (src/runner.mjs, src/ledger.mjs, src/git-snapshot.mjs
|
|
2
|
+
and their tests) were ported on 2026-09-10 from a private ucsandman repository
|
|
3
|
+
(team tooling) under the MIT license; that code is included here under the Leg License Agreement (see LICENSE), which its author also holds. Telegram delivery, chat identifiers,
|
|
4
|
+
and machine-specific paths were removed in the port.
|