@ucsandman/legcli 0.14.0 → 0.15.1

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 CHANGED
@@ -1,5 +1,119 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.15.1 (2026-09-19)
4
+
5
+ Your own Claude Code status line comes back.
6
+
7
+ - **Your status line runs first.** `leg claude` passes a `statusLine` through
8
+ `--settings`, and that key replaces yours rather than merging. Leg has
9
+ always read your `statusLine` command, but it only ever used its `padding`;
10
+ the command itself never ran, so on a build that honours a `--settings`
11
+ status line you saw Leg's row instead of your own. The command is now kept
12
+ on the session record and Leg's status-line hook runs it with the same JSON
13
+ Claude Code sends, printing its rows above Leg's one line. Reported by a
14
+ baton user on Discord. Claude Code 2.1.278 on Windows still shows its
15
+ built-in status line in place of any custom one passed this way, so the 5h
16
+ and 7d numbers keep coming from the usage endpoint (docs/faq.md).
17
+
18
+ ## 0.15.0 (2026-09-18)
19
+
20
+ A second login keeps the conversation, and the runtime does less work per
21
+ minute.
22
+
23
+ - **A hand-off to your other claude login keeps the conversation.** `leg
24
+ accounts add claude <name>` now junctions Claude Code's `projects` store
25
+ into the account beside the harness directories, so the second login sees
26
+ the same conversations and the same auto-memory as the first. At a weekly
27
+ or Fable wall the terminal moves to that login with `claude --resume <id>`
28
+ under its `CLAUDE_CONFIG_DIR` and no bundle prompt, and the timeline says
29
+ `claude/fable → claude/work (kept the conversation)`. One rule decides it
30
+ for the terminal and for the board's picker (`keepsConversation` in
31
+ `src/usage.mjs`): a same-login downshift, or another login whose home can
32
+ see the transcript file, checked at the switch. An account made by an
33
+ older Leg gets the junction the next time it starts. `leg history` lists a
34
+ junctioned store once. codex still takes the bundle across logins.
35
+ - **`leg digest`: what happened while you were away.** The default window is
36
+ 8 hours (`--since 2d`, `--since 30m`, an ISO time; `--json`; `GET
37
+ /api/digest?since=` on the board, owner only). The first line is the volume
38
+ it was read from, then what needs you (a live terminal waiting on a
39
+ question, a card parked for a human, a failed card, a lost terminal, in
40
+ that order), then one block per repository with every terminal, card and
41
+ landing that moved and the events worth a line, and last the walls
42
+ standing now. Read only, over the records already on disk; a window with
43
+ nothing in it says so with its counts.
44
+ - **The runtime does less work per minute, measured before and after.** A
45
+ profiler (`fs` and `child_process` counters plus `--cpu-prof`) sat on every
46
+ path first; the numbers are medians on one Windows 11 box, Node 24, with a
47
+ fake agent, an isolated `LEG_HOME` and a board on 4800–4899, and every
48
+ change carries a test that was seen failing without it.
49
+ - `leg --version` and every other command loaded 68 modules before `main()`
50
+ ran. `bin/leg.mjs` now imports each command group inside its own branch,
51
+ `src/limits.mjs` loads its fixture tree on first use, and the launcher
52
+ asks a new leaf (`src/scheduler-status.mjs`) whether the scheduler runs
53
+ instead of pulling in the orchestrator. `leg --version`: 127 → 52 ms
54
+ wall, 79 → 0 ms CPU after Node's own boot, 254 → 4 fs calls, 68 → 1
55
+ project module; `leg sessions ls` 116 → 75 ms; `leg card ls` 117 → 70 ms
56
+ (`test/cli-lazy.test.mjs`).
57
+ - An idle terminal spawned 59.5 git processes a minute (six per poll round)
58
+ and blocked its own event loop 4.4–10.3 s of every minute doing it. One
59
+ `git status --porcelain=v2 --branch` (`src/git.mjs`) now carries the
60
+ head, the branch, the dirty list and the upstream's own ahead count:
61
+ 10.9 git processes a minute, 2.1 s of git wall time, terminal CPU 1.7 →
62
+ 0.1 s a minute (`test/git-status.test.mjs`, `test/attach-perf.test.mjs`).
63
+ - The first `leg <agent>` of the day waited for the board it had just
64
+ started (polling `/api/health` for about a second) before the agent got
65
+ its first instruction. The agent starts at once and the wait runs behind
66
+ it; a session that exits within a second still claims the board's
67
+ pidfile before it goes. Time to the agent on that launch: 1,220 → 261 ms.
68
+ - The two-minute bundle checkpoint ran the python CLI synchronously inside
69
+ the poll tick, freezing limit detection and every board button for as
70
+ long as it took (up to its 120 s timeout). It runs beside the tick now,
71
+ one at a time, and the hand-off save waits for a checkpoint still
72
+ writing.
73
+ - `installedAgents()` ran `<agent> --version` for every agent on `PATH` at
74
+ every launch (an 8 s budget each); the answer is kept for a day in
75
+ `$LEG_HOME/installed.json`, keyed by the resolved bin. A `LEG_<AGENT>_BIN`
76
+ override is never cached.
77
+ - An idle board with 43 terminals and one page open rebuilt the whole
78
+ sessions view every 10 s whether or not a byte had changed: 7,294 fs
79
+ calls, 8 git processes and 1.1 CPU seconds a minute for nothing. The
80
+ health tick now asks the same stat fingerprint the watcher asks, runs the
81
+ liveness pass itself (a runner that died moves no file), and pushes only
82
+ when the answer changed; a card that starts or stops waiting on a human
83
+ forces the one push the fingerprint cannot see. Idle: 7,294 → 4,824 fs
84
+ calls, 8.2 → 0 git processes, 1.14 → 0.54 CPU seconds and 6 → 0 sessions
85
+ pushes a minute (what remains is the liveness pass and the scheduler's
86
+ own tick). One
87
+ sessions view also read the usage files 143 times (once per rung per
88
+ terminal, then again for capacity and the accounts panel) and probed three
89
+ paths per terminal for a synthesis file; one reader per view and one
90
+ `readdir` per checkout: `/api/sessions` 53 → 34 ms, 511 → 212 fs calls per
91
+ answer, and each row drops seven runner-bookkeeping fields nothing on the
92
+ board read (8% off every push; `GET /api/sessions/<id>` keeps the whole
93
+ record).
94
+ - A cold `/api/worktrees` ran up to forty git processes on the board's one
95
+ event loop: 9–25 s in which no stylesheet, click or SSE frame was served.
96
+ The list is gathered through `execFile`, four at a time, one refresh per
97
+ query, and a caller that arrives while a refresh runs gets the last list.
98
+ Worst `/api/health` during a cold call: 11.8 → 3.2 s; the rest is the
99
+ history index's synchronous `listHistory`, still open. `/api/trunk`
100
+ (polled every 2 s by the floor) is cached 15 s and cleared by any card
101
+ change or landing: 27.5 → 0.5 ms. A terminal's detail drawer ran one `git
102
+ ls-files` per file it touched every 3 s; one process for the list: 1,247 →
103
+ 305 ms.
104
+ - `updateSession` takes the lock budget `run.json` already had (250 tries, a
105
+ 10 s steal) instead of running unlocked after 1.2 s; `control.json` is
106
+ cleared under its lock at exit; `src/handoff.mjs` takes `scrub` from
107
+ `src/redact.mjs` instead of the card runner; the 12-leg stop names the
108
+ bundle and `leg resume` instead of promising a hand-off a fresh launch
109
+ never performed.
110
+ - **The README's hand-off step 3 said one bundle per leg.** The code has
111
+ written one bundle per session, updated in place, since 0.2.0; the sentence
112
+ now says so. `docs/concepts.md` and the `src/sessions.mjs` header also said
113
+ the runner was the only writer of `session.json`; the usage poller, the
114
+ claude hooks and a board action patch it too, under one lock, and both now
115
+ say that.
116
+
3
117
  ## 0.14.0 (2026-09-18)
4
118
 
5
119
  The 14-day trial is back.
package/README.md CHANGED
@@ -179,12 +179,20 @@ presenting it as current.
179
179
  3. **Bundle.** Leg writes structured notes (task, the last messages from the
180
180
  transcript, `git diff --stat`, dirty files, files edited this session, recent
181
181
  commits, why it stopped) and runs `context-handoff-bundle save --repo-local`
182
- with one slug per leg; each save writes its own timestamped bundle next to
183
- the last one. A checkpoint of the same bundle is taken every two minutes
184
- while the session is active. If the session maintained `.leg/SYNTHESIS-<session-id>.md`,
182
+ with one slug per session, updated in place (`--update <slug>`) at every
183
+ checkpoint, about every two minutes while the session is active, and at
184
+ every warning, limit and hand-off. If the session maintained `.leg/SYNTHESIS-<session-id>.md`,
185
185
  Leg inlines it into the resume file as a `## Synthesis` section ahead of the raw dump.
186
- 4. **Switch.** The agent process is stopped, the terminal is restored, and the
187
- next option starts in the same terminal with a short pointer prompt:
186
+ 4. **Switch.** The agent process is stopped and the terminal is restored. Two
187
+ claude destinations keep the conversation itself instead of the bundle: a
188
+ weaker model on the same login (`claude --resume <id> --model <alias>`),
189
+ and another claude login you added with `leg accounts add`, which sees the
190
+ same transcript through the `projects` junction the account carries
191
+ (`claude --resume <id>` under that login's `CLAUDE_CONFIG_DIR`). A weekly
192
+ or Fable wall on one login then continues on the other with the
193
+ conversation it already had, and the timeline says `kept the
194
+ conversation`. Every other rung starts in the same terminal with a short
195
+ pointer prompt:
188
196
  read `.leg/RESUME-<session-id>.md` (the `context-handoff-bundle load`
189
197
  output, the `## Synthesis` section if present, and the reason for the switch),
190
198
  check `git status` and `git diff`, continue, do not ask the human to restate
@@ -361,6 +369,23 @@ it prints how much it read beside the answer (`14 terminals and 3 cards, 812
361
369
  events read`) so an empty trail cannot be mistaken for a quiet week. Owner
362
370
  only: the trail names repositories and people.
363
371
 
372
+ ### What happened while you were away
373
+
374
+ `leg digest` (default window 8 hours; `--since 2d`, `--since 30m`, or an ISO
375
+ time; `--json` for the record; `GET /api/digest?since=` on the board, owner
376
+ only) is the trail read the other way round: grouped by repository, what
377
+ needs you first. The first line is the volume it was read from (`3
378
+ terminals, 2 cards, 1 landing, 412 events read (66 sessions and 9 cards on
379
+ disk)`), then `needs you`: a live terminal waiting on a question, a card
380
+ parked for a human, a card that failed, a terminal that was lost, in that
381
+ order and each with how long ago. Then one block per repository: every
382
+ terminal that moved in the window with its login and model, state, turns,
383
+ files, commits ahead and the events worth a line (a wall, a hand-off and
384
+ whether it kept the conversation, an all-out wait, the end), every card with
385
+ its last event, every landing with who pressed Land, and last the walls
386
+ standing right now with their reset times. Nothing new is recorded; a window
387
+ with nothing in it says so with its counts.
388
+
364
389
  ## The board
365
390
 
366
391
  `leg <agent>` opens it; `leg open` reopens it; `leg down` stops it.
@@ -445,19 +470,30 @@ matrix (which agents list, show messages, continue) and every file read are in
445
470
 
446
471
  Optional. `leg accounts add claude work` creates
447
472
  `~/.leg/accounts/claude/work`, junctions your `hooks`, `skills`, `agents`,
448
- `commands`, `plugins`, `rules`, `scripts`, `output-styles` and `tools` into it,
449
- copies `settings.json`, `CLAUDE.md` and the status-line scripts (refreshed from
450
- your real `~/.claude` before every launch), and prints one line to paste:
473
+ `commands`, `plugins`, `rules`, `scripts`, `output-styles`, `tools` and
474
+ `projects` into it, copies `settings.json`, `CLAUDE.md` and the status-line
475
+ scripts (refreshed from your real `~/.claude` before every launch), and prints
476
+ one line to paste:
451
477
 
452
478
  ```
453
479
  $env:CLAUDE_CONFIG_DIR='C:\Users\you\.leg\accounts\claude\work'; claude auth login
454
480
  ```
455
481
 
482
+ `projects` is Claude Code's conversation store, so the second login sees the
483
+ same conversations and the same auto-memory as the first, and a hand-off from
484
+ one login to the other keeps the conversation: the terminal moves to `work`
485
+ with `claude --resume <id>` and no bundle prompt. That is the whole point of a
486
+ second 20x login when the Fable or the weekly window on the first one is out.
487
+ An account made by an older Leg gets the junction the next time it starts.
488
+ Claude Code writes that directory; Leg only reads it.
489
+
456
490
  Same for codex (`CODEX_HOME`; `config.toml`, `AGENTS.md`, `skills`, `prompts`,
457
- `rules`, `plugins`, `agents`, `hooks`, `memories` shared). agy 1.2.0 has no
458
- config-directory override, so it stays one account. Only the login lives in
459
- the account directory; `leg accounts rm` removes the junctions and the
460
- directory and never touches your real home.
491
+ `rules`, `plugins`, `agents`, `hooks`, `memories` shared; a codex hand-off
492
+ still takes the bundle, because `codex resume` under a second `CODEX_HOME`
493
+ has not been observed). agy 1.2.0 has no config-directory override, so it
494
+ stays one account. Only the login lives in the account directory;
495
+ `leg accounts rm` removes the junctions and the directory and never touches
496
+ your real home.
461
497
 
462
498
  The terms, as published (effective dates below):
463
499
 
@@ -537,6 +573,8 @@ leg history [ls] [--provider p] [--repo r] [--search q] [--managed|--external] [
537
573
  every conversation on this machine, Leg's own and the agents' own (read only)
538
574
  leg history show <id> [--messages n] [--json] | continue <id> [agent args…] | refresh [--full] | providers
539
575
  leg worktrees [--repo <path>] [--no-dirty] [--json] every checkout: git's, Leg's, the conversations' (read only)
576
+ leg digest [--since 8h|2d|<iso>] [--json] what happened while you were away: needs-you first, then every
577
+ terminal, card, landing and wall in the window, by repository (read only)
540
578
  leg accounts ls logins and their 5h/7d usage
541
579
  leg accounts add <claude|codex|grok> <name> | rm <agent> <name> | terms
542
580
  leg harness status|inspect|check|explain|history [--json] the portable harness, read-only
@@ -714,7 +752,7 @@ Leg is commercial software under the [Leg License Agreement](LICENSE).
714
752
  It ships as readable JavaScript so you can see what it does on your machine,
715
753
  and you may modify it for your own use, but not redistribute it or work
716
754
  around the license check. Versions 0.2.0 and 0.3.0 were published under MIT
717
- and remain available. The version in this source tree is 0.14.0; see
755
+ and remain available. The version in this source tree is 0.15.0; see
718
756
  [npm](https://www.npmjs.com/package/legcli) for published versions and
719
757
  [CHANGELOG.md](CHANGELOG.md) for release notes.
720
758