@ucsandman/legcli 0.11.0 → 0.12.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +142 -0
  2. package/README.md +95 -65
  3. package/bin/leg.mjs +123 -14
  4. package/docs/DECISIONS.md +10 -0
  5. package/docs/DEMO.md +20 -14
  6. package/docs/DEVIATIONS.md +1 -0
  7. package/docs/ERRORS.md +41 -0
  8. package/docs/ROADMAP-v2.md +50 -5
  9. package/docs/VOCABULARY.md +27 -0
  10. package/docs/board-guide.md +401 -66
  11. package/docs/cli-contracts.md +199 -5
  12. package/docs/concepts.md +167 -19
  13. package/docs/configuration.md +58 -0
  14. package/docs/faq.md +21 -5
  15. package/docs/getting-started.md +15 -11
  16. package/docs/redesign-2026-09-17.md +477 -0
  17. package/docs/screenshots/background-1280.png +0 -0
  18. package/docs/screenshots/board-400px.png +0 -0
  19. package/docs/screenshots/board-details-open.png +0 -0
  20. package/docs/screenshots/board-drawer.png +0 -0
  21. package/docs/screenshots/board-handoff.png +0 -0
  22. package/docs/screenshots/board-running.png +0 -0
  23. package/docs/screenshots/capacity-drawer-1280.png +0 -0
  24. package/docs/screenshots/settings-ladder-1280.png +0 -0
  25. package/docs/screenshots/terminals-1280.png +0 -0
  26. package/fixtures/limits/claude/claude-fable-limit.json +11 -0
  27. package/fixtures/limits/claude/claude-model-limit.json +1 -1
  28. package/fixtures/limits/claude/claude-session-limit.json +1 -1
  29. package/fixtures/limits/claude/claude-weekly-limit.json +1 -1
  30. package/fixtures/live/claude/resume-model-probe.json +20 -0
  31. package/fixtures/live/claude/usage-oauth.json +87 -0
  32. package/fixtures/verified.json +1 -1
  33. package/package.json +3 -2
  34. package/scripts/seed-fake-cards.mjs +59 -6
  35. package/scripts/seed-wes-board.mjs +81 -12
  36. package/src/accounts.mjs +6 -1
  37. package/src/attach.mjs +328 -46
  38. package/src/audit.mjs +1 -1
  39. package/src/board/board.css +119 -9
  40. package/src/board/board.js +482 -106
  41. package/src/board/index.html +67 -7
  42. package/src/board/sessions.js +1347 -117
  43. package/src/buckets.mjs +101 -0
  44. package/src/cards.mjs +9 -1
  45. package/src/chain.mjs +13 -0
  46. package/src/hook.mjs +7 -1
  47. package/src/ledger.mjs +10 -2
  48. package/src/orchestrator.mjs +13 -4
  49. package/src/preferences.mjs +214 -5
  50. package/src/scheduler.mjs +24 -1
  51. package/src/server.mjs +546 -47
  52. package/src/sessions.mjs +17 -1
  53. package/src/taps/claude-usage.mjs +91 -2
  54. package/src/taps/claude.mjs +144 -5
  55. package/src/taps/codex.mjs +23 -3
  56. package/src/usage.mjs +407 -12
@@ -39,8 +39,20 @@
39
39
  <p id="verdict-sub"></p>
40
40
  </section>
41
41
 
42
- <section class="logins" id="accounts" aria-label="Logins"></section>
43
- <p class="head-caption" id="head-caption">Times are local.</p>
42
+ <!-- Usage is a property of the work, not a region of its own. The strip is
43
+ one band: a token per login carrying the bucket that will actually stop
44
+ it. The panels are not rewritten, they move intact behind the disclosure
45
+ at the end of the strip, with every gauge, notch and spoken sentence. -->
46
+ <section class="capacity" aria-label="Capacity by login">
47
+ <div class="capacity-strip">
48
+ <div class="cap-tokens" id="capacity-tokens"></div>
49
+ <button type="button" class="btn btn-secondary disclosure cap-open" id="capacity-toggle" aria-expanded="false" aria-controls="capacity-drawer">Capacity and models &gt;</button>
50
+ </div>
51
+ <div class="drawer capacity-drawer" id="capacity-drawer" hidden>
52
+ <section class="logins" id="accounts" aria-label="Logins"></section>
53
+ <p class="head-caption" id="head-caption">Times are local.</p>
54
+ </div>
55
+ </section>
44
56
 
45
57
  <section class="region-terminals" aria-labelledby="terminals-head">
46
58
  <div class="section-head">
@@ -58,6 +70,22 @@
58
70
  <p class="empty-line" hidden>No terminal is running. Start one in any repo: <code>leg claude</code>, <code>leg codex</code> or <code>leg agy</code>. It appears here within a second of the agent's first turn.</p>
59
71
  </section>
60
72
 
73
+ <!-- C.1: a card is a terminal you are not sitting at. Live cards are rows
74
+ here, directly under Terminals; finished ones fall into the ledger
75
+ cell below instead of piling up as rows. -->
76
+ <section class="region-background" id="background" aria-labelledby="background-head" hidden>
77
+ <div class="section-head">
78
+ <h2 id="background-head">Background</h2>
79
+ <p class="region-meta" role="status" aria-atomic="true"></p>
80
+ </div>
81
+ <!-- the live card rows are `.row`: the four-cell grid whose `.r4
82
+ .row-actions` block is written against the terminal rows, so the two
83
+ row kinds line up. `.card-list` is the gap between them, the same
84
+ container the cards drawer uses. -->
85
+ <div class="card-list" id="background-grid"></div>
86
+ <div id="card-entry" hidden></div>
87
+ </section>
88
+
61
89
  <!-- Finished terminals, what landed, and what is queued are all history or
62
90
  background. They sit on the ground rather than on a panel, because a
63
91
  raised surface here would compete with the terminals that are live. -->
@@ -151,13 +179,33 @@
151
179
  first request there is no address above to point at. -->
152
180
  <p class="field-help">Stored in this browser's localStorage and sent as a bearer token with every request. Clear the field to sign out.</p>
153
181
  </div>
182
+ <!-- The fallback ladder (docs/redesign-2026-09-17.md B.3). A rung is a
183
+ destination, not an agent: claude/opus and claude/sonnet are two
184
+ separate steps down before Leg leaves the login at all. The ids are
185
+ the ones the order editor used, because the same save button, status
186
+ span and list container do the same job for the longer shape. -->
154
187
  <fieldset class="default-order" id="default-order" hidden>
155
- <legend>New terminal handoff order</legend>
156
- <p class="field-help">Used by terminals started after you save.</p>
188
+ <legend>New terminal handoff ladder</legend>
189
+ <p class="field-help">Each rung is an agent, a login and a model. Leg walks down from the top and takes the first rung that is open. Used by terminals started after you save; a running terminal keeps the copy it started with, and Details on its row edits that one.</p>
157
190
  <div id="default-order-list"></div>
158
- <button type="button" class="btn btn-secondary" id="default-order-save">Save default</button>
191
+ <div class="ladder-policy" id="ladder-spend"></div>
192
+ <fieldset class="ladder-policy" id="ladder-climb"></fieldset>
193
+ <div class="ladder-policy" id="ladder-reserve"></div>
194
+ <button type="button" class="btn btn-secondary" id="default-order-save">Save ladder</button>
159
195
  <span class="field-status" id="default-order-status" aria-live="polite"></span>
160
196
  </fieldset>
197
+ <!-- Where a terminal that is waiting on a human says so when the board is
198
+ not the window you are looking at. The tab badge needs no toggle: it
199
+ needs no permission and costs nothing, so it is always on. -->
200
+ <fieldset class="notify" id="notify-settings" hidden>
201
+ <legend>Notifications</legend>
202
+ <p class="field-help">The tab title says <code>(1) Leg</code> and the favicon gains a dot whenever a terminal is waiting on you. That one is always on.</p>
203
+ <label class="notify-toggle" for="notify-terminal"><input type="checkbox" id="notify-terminal"> Terminal toast when a terminal waits on you</label>
204
+ <p class="field-help">Claude Code only, through its Notification hook: the toast reaches the window the agent is already running in.</p>
205
+ <label class="notify-toggle" for="notify-board"><input type="checkbox" id="notify-board"> Browser notification when a terminal waits on you</label>
206
+ <p class="field-help" id="notify-board-help"></p>
207
+ <span class="field-status" id="notify-status" aria-live="polite"></span>
208
+ </fieldset>
161
209
  <!-- Who did what, across every terminal and every card. The owner's, like
162
210
  the rest of this panel: the trail names repositories and people. It
163
211
  loads when asked rather than on every board render. -->
@@ -196,8 +244,11 @@
196
244
  <div class="detail-inner" id="session-drawer-content"></div>
197
245
  </div>
198
246
 
199
- <dialog id="new-card-dialog" aria-label="New card">
200
- <h2 class="dialog-title">New background card</h2>
247
+ <!-- the announced name is the heading on screen: an aria-label here would be a
248
+ second name for one thing, and the one a voice-control user says out loud
249
+ is the one they can read -->
250
+ <dialog id="new-card-dialog" aria-labelledby="new-card-dialog-title">
251
+ <h2 class="dialog-title" id="new-card-dialog-title">More settings</h2>
201
252
  <p class="dialog-intro">An agent works without an interactive terminal in a separate git worktree. The default Build workflow stops with changes in that worktree and does not merge them.</p>
202
253
  <form id="new-card-form">
203
254
  <div class="form-error" id="new-card-error" hidden></div>
@@ -296,6 +347,15 @@
296
347
  </form>
297
348
  </dialog>
298
349
 
350
+ <!-- D14: every binding clicks a button that is already on a row, so this map is
351
+ the list of those buttons and nothing else can drift from it. sessions.js
352
+ fills it from the same table the key handler reads. -->
353
+ <div class="keymap" id="keymap" role="dialog" aria-label="Keyboard shortcuts" hidden>
354
+ <h3 class="drawer-head">Keyboard</h3>
355
+ <dl class="keymap-list" id="keymap-list"></dl>
356
+ <button type="button" class="btn btn-secondary" id="keymap-close">Close</button>
357
+ </div>
358
+
299
359
  <div class="sysmsg" id="toast" aria-live="polite"></div>
300
360
 
301
361
  <script src="board.js" defer></script>