Repository navigation
Conversation
Out-of-band control surfaces for when teamclaude runs headless (systemd, container) and the interactive TUI never renders. - POST /teamclaude/switch — pin the active account by name - POST /teamclaude/threshold — change rotation cutoff (0..1), persisted - GET /ui — single-page dashboard polling /teamclaude/status every 2s - teamclaude switch <name> + teamclaude threshold <value> CLI wrappers - Pathname-based routing (handles query strings) + lazy in-memory HTML cache (per Gemini review)
Three dev-ergonomics improvements bundled together: - src/web/index.html: container queries + clamp() typography + auto-fill grid so the dashboard adapts cleanly to narrow Wave blocks. Adds .top/.name-text wrappers + ellipsis to keep long account names from blowing out the card layout. - src/server.js: remove HTML cache so /ui reads from disk every request. Dev iteration on the dashboard no longer requires a daemon restart. The 'no-store' header was already there; the in-memory cache was the actual blocker. - src/index.js: unified SIGINT/SIGTERM handler that calls server.closeAllConnections?.() before server.close() and adds a 2s safety-net setTimeout(..., 2000).unref() for hard exit. Fixes restart hang when an in-flight Claude stream was holding the socket open past systemd's TimeoutStopUSec.
Add a reset-time column to each 5h/7d quota bar so the dashboard shows when each window rolls over, not just current utilization. Reads the unified5hReset/unified7dReset (epoch-ms from Anthropic rate-limit headers) already exposed by getStatus(); falls back to legacy resetsAt. Times render compactly (HH:MM within a day, weekday otherwise) with the full timestamp on hover, and the bars grid gains a responsive variant for narrow cards. Bump to 1.0.7. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
I'm not sure the web dashboard adds much compared to the TUI, do you have a rationale for adding it? |
|
Probably a silly reason, but I run team Claude as a service for my lan. When made into a systemd service I can no longer use the tui. And also I can view the website via other hosts using the proxy on the lan. |
|
Seems like a very useful addition to me. I was actually considering building something like this myself. In my case it's because teamclaude runs as a service so I don't have any access to the TUI interface and |
|
Closing as stale: this branch conflicts with master and predates substantial changes (e.g. it assumes no automated test suite exists, which is no longer true). Please rebase and open a fresh PR if the responsive dashboard work is still desired. |
* feat(tui): fold account rows below 70 columns so usage bars wrap On a narrow terminal (a phone over a remote session, say) an account row could not hold its name, status and quota bars on one line. The list dropped every bar past the first and shrank that one to a cell or two, so the weekly and family windows vanished below 70 columns and the session bar became unreadable near 40. Below LIST_MIN a full-width list now folds each account into a heading (marker, route cells, name, type, status) and one line per quota bar, with the trailing tags wrapped a whole tag at a time beneath them. Each folded bar takes the row less a 2-column right margin (COMPACT_BAR_RIGHT_MARGIN), so it never touches the screen edge. The heading gives the name every column the rest leaves, measured in display columns, so a CJK name is cut where it reaches the type column. The smallest drawable terminal drops from 40x8 to 30x8 so the folded layout is reachable at phone widths. This ports teamcodex KarpelesLab#21 (7296e40, compact layout below 70 columns) and KarpelesLab#23 (0a34280, compact bar right margin), adapted to teamclaude's budgeted _listLayout: the layout flags `narrow`, _renderRow passes the width, and _renderAcct returns lines instead of one string. Split panes are never narrow. teamcodex KarpelesLab#12/KarpelesLab#17/KarpelesLab#18/KarpelesLab#19 are already in 1.1.22 and were not needed. At 70 columns and wider the frame is byte-identical to 1.1.22: the trailing tags moved into a list but are appended in the same order with the same separator. test/fixtures/tui-wide-frames.json holds frames recorded from the unmodified renderer, and test/tui-narrow-bars.test.js pins both sides. docs/teamcodex-port-plan.md classifies all 34 teamcodex commits for later porting; docs/evidence/ holds the real TUI.start() paint at 30-80 columns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(tui): use a neutral double-width name in the narrow-layout fixtures The width tests need an account name of East Asian Wide characters, but the one they used read like a real person's name and address. It is now '가나다라마바사-wide@example.test': seven Hangul syllables (fourteen columns) then ASCII, which still exercises the cases the tests care about. - At 40 columns the name is cut exactly where it reaches the type column. - At 30 columns a fifth syllable would straddle the edge, so it is dropped whole and its leftover column padded (a case the old name did not hit). - At 69 columns the whole name fits. The wide-frame fixture was re-recorded from the unmodified 1.1.22 renderer with the new name. The pty capture in docs/evidence was regenerated from the real TUI.start() paint. The comments that named the data Korean now describe it by width. Mutating the folded heading to measure characters instead of display columns still fails "the folded heading spends what the type and status leave on the name, in display columns". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Euisan Kim <git@san.kim> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(tui): fold account rows below 70 columns so usage bars wrap On a narrow terminal (a phone over a remote session, say) an account row could not hold its name, status and quota bars on one line. The list dropped every bar past the first and shrank that one to a cell or two, so the weekly and family windows vanished below 70 columns and the session bar became unreadable near 40. Below LIST_MIN a full-width list now folds each account into a heading (marker, route cells, name, type, status) and one line per quota bar, with the trailing tags wrapped a whole tag at a time beneath them. Each folded bar takes the row less a 2-column right margin (COMPACT_BAR_RIGHT_MARGIN), so it never touches the screen edge. The heading gives the name every column the rest leaves, measured in display columns, so a CJK name is cut where it reaches the type column. The smallest drawable terminal drops from 40x8 to 30x8 so the folded layout is reachable at phone widths. This ports teamcodex KarpelesLab#21 (7296e40, compact layout below 70 columns) and KarpelesLab#23 (0a34280, compact bar right margin), adapted to teamclaude's budgeted _listLayout: the layout flags `narrow`, _renderRow passes the width, and _renderAcct returns lines instead of one string. Split panes are never narrow. teamcodex KarpelesLab#12/KarpelesLab#17/KarpelesLab#18/KarpelesLab#19 are already in 1.1.22 and were not needed. At 70 columns and wider the frame is byte-identical to 1.1.22: the trailing tags moved into a list but are appended in the same order with the same separator. test/fixtures/tui-wide-frames.json holds frames recorded from the unmodified renderer, and test/tui-narrow-bars.test.js pins both sides. docs/teamcodex-port-plan.md classifies all 34 teamcodex commits for later porting; docs/evidence/ holds the real TUI.start() paint at 30-80 columns. * test(tui): use a neutral double-width name in the narrow-layout fixtures The width tests need an account name of East Asian Wide characters, but the one they used read like a real person's name and address. It is now '가나다라마바사-wide@example.test': seven Hangul syllables (fourteen columns) then ASCII, which still exercises the cases the tests care about. - At 40 columns the name is cut exactly where it reaches the type column. - At 30 columns a fifth syllable would straddle the edge, so it is dropped whole and its leftover column padded (a case the old name did not hit). - At 69 columns the whole name fits. The wide-frame fixture was re-recorded from the unmodified 1.1.22 renderer with the new name. The pty capture in docs/evidence was regenerated from the real TUI.start() paint. The comments that named the data Korean now describe it by width. Mutating the folded heading to measure characters instead of display columns still fails "the folded heading spends what the type and status leave on the name, in display columns". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(tui): fold account rows below 70 columns so usage bars wrap On a narrow terminal (a phone over a remote session, say) an account row could not hold its name, status and quota bars on one line. The list dropped every bar past the first and shrank that one to a cell or two, so the weekly and family windows vanished below 70 columns and the session bar became unreadable near 40. Below LIST_MIN a full-width list now folds each account into a heading (marker, route cells, name, type, status) and one line per quota bar, with the trailing tags wrapped a whole tag at a time beneath them. Each folded bar takes the row less a 2-column right margin (COMPACT_BAR_RIGHT_MARGIN), so it never touches the screen edge. The heading gives the name every column the rest leaves, measured in display columns, so a CJK name is cut where it reaches the type column. The smallest drawable terminal drops from 40x8 to 30x8 so the folded layout is reachable at phone widths. This ports teamcodex KarpelesLab#21 (7296e40, compact layout below 70 columns) and KarpelesLab#23 (0a34280, compact bar right margin), adapted to teamclaude's budgeted _listLayout: the layout flags `narrow`, _renderRow passes the width, and _renderAcct returns lines instead of one string. Split panes are never narrow. teamcodex KarpelesLab#12/KarpelesLab#17/KarpelesLab#18/KarpelesLab#19 are already in 1.1.22 and were not needed. At 70 columns and wider the frame is byte-identical to 1.1.22: the trailing tags moved into a list but are appended in the same order with the same separator. test/fixtures/tui-wide-frames.json holds frames recorded from the unmodified renderer, and test/tui-narrow-bars.test.js pins both sides. docs/teamcodex-port-plan.md classifies all 34 teamcodex commits for later porting; docs/evidence/ holds the real TUI.start() paint at 30-80 columns. * test(tui): use a neutral double-width name in the narrow-layout fixtures The width tests need an account name of East Asian Wide characters, but the one they used read like a real person's name and address. It is now '가나다라마바사-wide@example.test': seven Hangul syllables (fourteen columns) then ASCII, which still exercises the cases the tests care about. - At 40 columns the name is cut exactly where it reaches the type column. - At 30 columns a fifth syllable would straddle the edge, so it is dropped whole and its leftover column padded (a case the old name did not hit). - At 69 columns the whole name fits. The wide-frame fixture was re-recorded from the unmodified 1.1.22 renderer with the new name. The pty capture in docs/evidence was regenerated from the real TUI.start() paint. The comments that named the data Korean now describe it by width. Mutating the folded heading to measure characters instead of display columns still fails "the folded heading spends what the type and status leave on the name, in display columns". Reapplied on 1.1.23: tui-wide-frames.json re-recorded from the unmodified 1.1.23 renderer (percentage off by default since KarpelesLab#514); renderFrame takes a config, and the folded-label test checks percentage on and off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary
Brings the web dashboard (
/teamclaude/ui) to a polished, responsive state and surfaces quota reset times alongside utilization.08c80a7).↺ HH:MMwithin a day, weekday + time beyond), with the full timestamp on hover. Readsunified5hReset/unified7dReset(epoch-ms from Anthropic rate-limit headers) already exposed bygetStatus(), with a fallback to legacyresetsAt(444281e).web/index.htmlfrom disk per request (Cache-Control: no-store), so dashboard edits are live without a restart (08c80a7).Pre-Landing Review
No issues found. Verified the reset feature is wired end-to-end: backend stores reset timestamps as epoch-ms (
account-manager.js:173-174),getStatus()forwards the full quota object via spread (account-manager.js:340), and the frontendfmtReset(ms)consumes ms directly and guards null/past values. Units consistent on both sides. Secret scan clean.Test plan
package.jsondefines onlystart).http://localhost:3456/uiagainst a running proxy with active accounts and confirm reset labels render next to each bar and resize cleanly on a narrow window.Generated with Claude Code