ccdeck 3.43.4 → 3.44.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/README.md +69 -17
- package/THIRD_PARTY_NOTICES.md +43 -7
- package/bin/cli/commands.js +613 -0
- package/bin/cli/help.js +26 -3
- package/bin/cli/one-shot.js +2 -2
- package/bin/cli/picker.js +86 -0
- package/bin/cli/startup.js +13 -0
- package/bin/deck.js +16 -1
- package/dist/web/assets/{BrowserWatchModal-nOxhGOO4.js → BrowserWatchModal-DMIUygWz.js} +1 -1
- package/dist/web/assets/{RadioPanel-BLfpQ1Iw.js → RadioPanel-DNB_AHSs.js} +1 -1
- package/dist/web/assets/TrafficRadar-Ch0LVdSl.js +8 -0
- package/dist/web/assets/UsageHistoryModal-Du0ZkIJ1.js +1 -0
- package/dist/web/assets/app-CQIstkMF.js +318 -0
- package/dist/web/assets/app-Ch-0CYlK.css +1 -0
- package/dist/web/assets/{index-Ch4ks76J.js → index-BQbOfxbL.js} +1 -1
- package/dist/web/index.html +3 -3
- package/package.json +2 -1
- package/release-notes.json +34 -0
- package/src/server/account-notify.mjs +206 -9
- package/src/server/account-pick.mjs +160 -0
- package/src/server/account-projects.mjs +55 -15
- package/src/server/account-routes.mjs +47 -4
- package/src/server/account-watch.mjs +48 -4
- package/src/server/activity.mjs +3 -2
- package/src/server/args.mjs +112 -2
- package/src/server/autoswitch-failover.mjs +138 -0
- package/src/server/claude-accounts.mjs +115 -14
- package/src/server/claude-dir.mjs +142 -5
- package/src/server/claude-identity.mjs +23 -0
- package/src/server/cli-lines.mjs +224 -0
- package/src/server/codex-cost-usage.mjs +67 -0
- package/src/server/codex-enrichment.mjs +53 -9
- package/src/server/codex-review-policy.d.mts +4 -0
- package/src/server/codex-review-policy.mjs +11 -0
- package/src/server/codex-skills.mjs +146 -0
- package/src/server/codex-watch.mjs +5 -2
- package/src/server/cswap-auto-choice.mjs +53 -0
- package/src/server/cswap-auto-loop.mjs +100 -9
- package/src/server/deck-client.mjs +112 -0
- package/src/server/deck-prefs.mjs +16 -5
- package/src/server/event-pipeline.mjs +19 -3
- package/src/server/event-routes.mjs +15 -0
- package/src/server/exec.mjs +6 -2
- package/src/server/index.mjs +17 -1
- package/src/server/installer.mjs +149 -8
- package/src/server/lan-engine.mjs +2 -2
- package/src/server/lan-sync.mjs +3 -3
- package/src/server/lan-wire.mjs +3 -3
- package/src/server/login-guard.mjs +162 -0
- package/src/server/login-service.mjs +3 -0
- package/src/server/pinned-build.mjs +5 -0
- package/src/server/prefs-routes.mjs +4 -0
- package/src/server/request-gates.mjs +7 -0
- package/src/server/session-read-gate.mjs +5 -3
- package/src/server/session-summary.mjs +281 -0
- package/src/server/skill-hook.mjs +162 -0
- package/src/server/stop-continue-gate.d.mts +8 -0
- package/src/server/stop-continue-gate.mjs +77 -0
- package/src/server/stop-continue.mjs +544 -0
- package/src/server/stop-failure.d.mts +10 -0
- package/src/server/stop-failure.mjs +97 -0
- package/src/server/swap-log.mjs +19 -10
- package/src/server/tool-audit-report.mjs +5 -3
- package/src/server/tool-audit-routes.mjs +5 -3
- package/src/server/tool-audit-skills.mjs +82 -0
- package/src/server/tool-audit.mjs +53 -11
- package/src/server/traffic-radar-capture.mjs +10 -1
- package/src/server/traffic-radar-monitor.mjs +4 -2
- package/src/server/traffic-radar-routes.mjs +13 -0
- package/src/server/traffic-radar-service.mjs +133 -0
- package/src/server/usage-day.mjs +1 -1
- package/dist/web/assets/TrafficRadar-BFrObpjW.js +0 -1
- package/dist/web/assets/UsageHistoryModal-DCnFf1vi.js +0 -1
- package/dist/web/assets/app-BiJ8TfUl.css +0 -1
- package/dist/web/assets/app-DBsNB-2y.js +0 -312
package/README.md
CHANGED
|
@@ -98,7 +98,7 @@ The deck opens on these eight pictures the first time it runs — they are the w
|
|
|
98
98
|
| **Live DAG** | Nodes are agents and edges are spawns; each agent's latest tool calls sit beside its node and light up while they run. In-flight edges animate, settled ones dim. |
|
|
99
99
|
| **Both providers, one canvas** | Claude Code through hooks, Codex through its rollout log. The model chip (`Opus 5`, `GPT-5.5`) tells them apart. Codex child sessions are connected when their rollout records an explicit parent. Each thread keeps its own tool calls and token totals. |
|
|
100
100
|
| **Cost and quota, live** | Spend per model and per session, plus Claude and Codex quota windows as they refill. |
|
|
101
|
-
| **Tool activity** | Which tools and commands your Claude Code and Codex agents ran on this machine, over the last day or up to 90 days: how many calls, how long they took, which ones fail. Kept on this machine and nowhere else. |
|
|
101
|
+
| **Tool activity** | Which tools and commands your Claude Code and Codex agents ran on this machine, over the last day or up to 90 days: how many calls, how long they took, which ones fail — and, on its Skills tab, which skills they used, how often and when last. Kept on this machine and nowhere else. |
|
|
102
102
|
| **Double-click to inspect** | Any node opens its prompt, tool calls, token usage and timing in the side panel. A single click selects it and frames its session. |
|
|
103
103
|
| **Survives restarts** | Events are appended to this platform's log directory (see `--history` below) and replayed on open. |
|
|
104
104
|
| **Accounts without a terminal** | Sign a new Claude account in, move one or your whole set to another machine, rename, reorder, remove — from the panel. |
|
|
@@ -131,7 +131,7 @@ Everything the page lets you set apart from the music — the theme, the text si
|
|
|
131
131
|
|
|
132
132
|
**Radio**, on the right sidebar beside the character (in **More** on a phone), opens a responsive Radio Explorer with a large interactive map, station discovery and a persistent player. Filter by country, sound or language, save favorites, return to recent stations, or choose **Surprise me**. Your existing Claude FM, Lofi Girl and custom streams are under **Your streams**. Select a station to inspect it, then press Play to listen; closing Radio or hiding the character keeps it playing. Favorites, history and the last catalogue are saved in this browser. Control music directly in Radio Explorer; character settings are in **Settings › Appearance**.
|
|
133
133
|
|
|
134
|
-
**Tool activity**, on the stripe on the right below Usage history (in **More** on a phone), is a page of which tools and commands the Claude Code and Codex agents on this machine used. For the last 24 hours, 7, 30 or 90 days, and both CLIs or one, it lists each tool's calls, its total and usual time and its failures, sortable by any of them and searchable, under up to three findings worth a look: the tool that takes the most time, one that fails often, the slowest. A row opens that tool's details beside the list: who used it, its calls per day, its latest and slowest calls. A shell command counts per operation — `git status`, `git push` and `npm run build` are rows of their own — and an MCP tool under its own name. A call's time runs from the agent starting the tool to its result, so it includes any wait for your approval, and Claude Code and Codex time their tools differently. It counts what the deck captures from the first time it runs at 3.42.0 or later — earlier sessions are not read back — and it is kept apart from the canvas: Clear empties the canvas and leaves the tool history. What it keeps, and where, is in [What it touches](#what-it-touches).
|
|
134
|
+
**Tool activity**, on the stripe on the right below Usage history (in **More** on a phone), is a page of which tools and commands the Claude Code and Codex agents on this machine used. For the last 24 hours, 7, 30 or 90 days, and both CLIs or one, it lists each tool's calls, its total and usual time and its failures, sortable by any of them and searchable, under up to three findings worth a look: the tool that takes the most time, one that fails often, the slowest. A row opens that tool's details beside the list: who used it, its calls per day, its latest and slowest calls. A shell command counts per operation — `git status`, `git push` and `npm run build` are rows of their own — and an MCP tool under its own name. A call's time runs from the agent starting the tool to its result, so it includes any wait for your approval, and Claude Code and Codex time their tools differently. Its **Skills** tab, beside **Tools** at the top, lists the skills those agents used, ranked by uses, with when each last ran: a skill Claude calls, a slash command you type (only when the deck is started with `AGENTS_DECK_SKILL_HOOK=1` and every Claude Code on the machine is 2.1.116 or newer — see [How it works](#how-it-works)), a skill you pick in Codex, and one Codex picks itself, detected when it reads that skill's instructions. The same command run again in a session with the same arguments, such as a `/loop` tick, is a repeat and is left out of the count. A skill opens its details: its uses per day, the projects it ran in, and its latest uses, each linking to its session while that is still on the canvas. It counts what the deck captures from the first time it runs at 3.42.0 or later — earlier sessions are not read back — and it is kept apart from the canvas: Clear empties the canvas and leaves the tool history. What it keeps, and where, is in [What it touches](#what-it-touches).
|
|
135
135
|
|
|
136
136
|
No config file. No account. What your sessions contain — your prompts, the replies, the files they touch — is never reported anywhere. The deck does send usage reports, on by default: its version, your system, your IP address and a device fingerprint, rough counts such as how many sessions ran in a day, and the errors it hits. It has no switch for them; `AGENTS_DECK_NO_REPORTS=1` keeps them off from the first start.
|
|
137
137
|
|
|
@@ -180,7 +180,13 @@ phone. Three views keep configuration, observed traffic and saved files separate
|
|
|
180
180
|
the list. Filter by session, destination or message type, then select a message for its
|
|
181
181
|
readable overview or decoded **JSON**. Session attribution comes from IDs in
|
|
182
182
|
the captured payload; absent IDs remain unidentified, and an export containing
|
|
183
|
-
multiple session IDs is shown under each matching session.
|
|
183
|
+
multiple session IDs is shown under each matching session. **With prompt**
|
|
184
|
+
narrows the list to exports carrying prompt fields, redacted ones included,
|
|
185
|
+
and their rows preview the exported text. The overview leads with what an
|
|
186
|
+
export holds — error, prompt, response, project, tool, model, tokens, cost —
|
|
187
|
+
and keeps the rest under **All record fields**; the JSON tree can be searched
|
|
188
|
+
and collapsed. Drag the divider, or focus it and use the arrow keys, to size
|
|
189
|
+
the list.
|
|
184
190
|
- **Configuration** shows configured destinations, telemetry/content flags and
|
|
185
191
|
their sources. Enabled flags are highlighted and recognized boolean values
|
|
186
192
|
are shown as written. These are settings-file evidence, not confirmation of a
|
|
@@ -249,6 +255,13 @@ destinations are saved, never packet contents, tokens or decoded messages.
|
|
|
249
255
|
Capture contents are available through the local loopback UI, not LAN endpoints.
|
|
250
256
|
Local clients of the same server share its capture.
|
|
251
257
|
|
|
258
|
+
**Automatic monitoring** is off unless you turn it on in **Settings → Radar →
|
|
259
|
+
Monitor automatically**. On, ccdeck finds the collector itself — from Claude's
|
|
260
|
+
settings, a monitor you started, or an active IPv4 OTLP/gRPC connection on port
|
|
261
|
+
4317 — monitors it without Radar open, and retries every five seconds while
|
|
262
|
+
none is available; Monitor then hides Start and the destination picker. Off
|
|
263
|
+
stops it, and nothing is looked for or retried.
|
|
264
|
+
|
|
252
265
|
Configuration and connection sampling runs only while Radar is open and the
|
|
253
266
|
browser page is visible. A connection does not prove an upload, and absence of
|
|
254
267
|
observed traffic does not mean telemetry is disabled. Native-process sampling
|
|
@@ -310,9 +323,13 @@ Two capture paths feed one SSE stream, which feeds one canvas.
|
|
|
310
323
|
|
|
311
324
|
```
|
|
312
325
|
SessionStart · UserPromptSubmit · PreToolUse · PostToolUse · PostToolUseFailure
|
|
313
|
-
SubagentStart · SubagentStop · Stop · SessionEnd · Notification
|
|
326
|
+
SubagentStart · SubagentStop · Stop · StopFailure · SessionEnd · Notification
|
|
314
327
|
```
|
|
315
328
|
|
|
329
|
+
`StopFailure`, which Claude Code sends instead of `Stop` when a turn ends on an API error, is added only when every Claude Code the deck finds on disk is 2.1.78 or newer, read from its install rather than by running it. Older ones did not know the event, and before 2.1.101 an event name Claude Code did not know made it ignore the whole `settings.json`. When the deck cannot tell which version is installed, it leaves the entry out.
|
|
330
|
+
|
|
331
|
+
`UserPromptExpansion`, which lets Tool activity's Skills tab count the slash commands you type, is off by default, and there is no switch for it in Settings. The deck adds it only when you start it with `AGENTS_DECK_SKILL_HOOK=1` (any other value is off), and then only when every Claude Code the deck finds is 2.1.116 or newer, the first that knows the event. An install that does not say its version is asked `claude --version`; one that still does not say counts as too old. Until 2.1.101 a hook event Claude Code did not know made it ignore the whole `settings.json` without saying so, so the deck would rather count no typed commands than risk that. Turned on, it writes that one entry, and the first time it does, it keeps the `settings.json` it replaced as `agent-dag/settings.before-skill-hook.json` beside the hook, readable only by you. Off, it changes nothing in `settings.json`, with one exception: start the deck without the variable, or with an older Claude Code, after a start that added the entry, and that entry is taken back out. Nothing else is touched, and a `UserPromptExpansion` hook of your own stays. What the Skills tab records — the skill's name, the session it ran in and its project folder's name — stays on this machine (see [What it touches](#what-it-touches)).
|
|
332
|
+
|
|
316
333
|
Each one fires the bundled `hook.js`, which POSTs the event JSON to the running server. The hook is fire-and-forget with a 1-second timeout: if the deck is not running, your session is not slowed down and nothing fails.
|
|
317
334
|
|
|
318
335
|
**OpenAI Codex** — Codex CLI hooks do not fire reliably on Windows, so nothing is installed at all. The server tails Codex's own rollout files at `~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl` and reconstructs the equivalent stream — session start, prompts, tool calls, token usage, model. No hook install, no trust prompt. Set `CODEX_HOME` to override the path.
|
|
@@ -325,9 +342,9 @@ Opening Radio asks the public [Radio Browser](https://www.radio-browser.info/) d
|
|
|
325
342
|
|
|
326
343
|
It never steers an agent or edits your code, but it is not read-only either — besides the hook entry and its own event log, it manages the two tools it leans on, and it refreshes the Codex token it reads quota with, rewriting `~/.codex/auth.json` the way `codex` itself does. It also reads your browser's history, because Browser Watch is on unless you switch it off; that is its own section below, because it is the one thing here that is about you rather than about an agent.
|
|
327
344
|
|
|
328
|
-
Telemetry Radar's flag switches write to `~/.claude/settings.json` too: each puts the flag you set — `CLAUDE_CODE_ENABLE_TELEMETRY`, `OTEL_LOG_USER_PROMPTS` and the other telemetry and content flags Radar lists — in that file's `env` block, as `"1"` or `"0"`. Switching a flag off writes `"0"` rather than removing it, and `--uninstall`, which removes ccdeck's hook entries, leaves these values as you set them. Starting Radar's monitoring writes `~/.agents-deck/radar-monitor-<port>.json`: the opt-in and the destinations a deck on that port resumes, never packets or decoded messages. And the quota readings the deck takes are kept in `quota-history.json`, in its data directory (see [Uninstall](#uninstall)), for 35 days and up to 2 MB, under a hash of the account rather than its address, for the Usage panel's quota history.
|
|
345
|
+
Telemetry Radar's flag switches write to `~/.claude/settings.json` too: each puts the flag you set — `CLAUDE_CODE_ENABLE_TELEMETRY`, `OTEL_LOG_USER_PROMPTS` and the other telemetry and content flags Radar lists — in that file's `env` block, as `"1"` or `"0"`. Switching a flag off writes `"0"` rather than removing it, and `--uninstall`, which removes ccdeck's hook entries, leaves these values as you set them. Starting Radar's monitoring writes `~/.agents-deck/radar-monitor-<port>.json`: the opt-in and the destinations a deck on that port resumes, never packets or decoded messages; turning on automatic monitoring writes `radar-settings-<port>.json` beside it, the switch and the collectors it found. And the quota readings the deck takes are kept in `quota-history.json`, in its data directory (see [Uninstall](#uninstall)), for 35 days and up to 2 MB, under a hash of the account rather than its address, for the Usage panel's quota history.
|
|
329
346
|
|
|
330
|
-
Tool activity keeps its history in `tool-audit/`, in the same data directory: a file a day with a line per tool call — Claude Code or Codex, when it started and ended, whether it failed, and the tool's name or, for a shell command, its operation (`git push`, `npm run build`) — and a `settings.json` holding how long to keep it, when it started counting, and a random id for this device that nothing sends anywhere. The rest of a command line, the tool's arguments and output,
|
|
347
|
+
Tool activity keeps its history in `tool-audit/`, in the same data directory: a file a day with a line per tool call — Claude Code or Codex, when it started and ended, whether it failed, and the tool's name or, for a shell command, its operation (`git push`, `npm run build`) — with a line per skill used, holding the skill's name, the session it ran in and the name of its project folder, and a `settings.json` holding how long to keep it, when it started counting, and a random id for this device that nothing sends anywhere. The rest of a command line, the tool's or the skill's arguments and output, and paths are not saved, nor a tool call's session id, and nothing in the folder leaves the machine. It keeps 90 days unless you pick 30 or 60 under **Keep history** in **Settings › Data › Tool history**, which also shows the space it takes and has **Clear history…**; older days are deleted as they fall out. `--no-persist` does not stop it — that flag is about the events log — and `--uninstall` leaves it, `--purge` too (see [Uninstall](#uninstall)).
|
|
331
348
|
|
|
332
349
|
What does go out is short and ordinary: a ~20-byte version check against the npm registry (plus one small request to confirm a version it has not seen before), installs and daily version checks for the two tools the deck manages (claude-swap from PyPI, ccusage from npm), on an Apple Silicon Mac whose sensors stay silent one release lookup and one binary download from GitHub for `macmon`, and, while the page is open or one of the two quota notifications is on, quota reads to Anthropic and OpenAI signed with your own credentials — that is where those numbers live. While the page is open, and while the desktop app has a session running or waiting, it also reads Anthropic's and OpenAI's public status pages (`status.claude.com`, `status.openai.com`), unsigned, about every three minutes, and once a minute at most while a page is not answering, so an outage on their side shows as a chip in the topbar instead of looking like a fault on yours. While the machine panel is open, on a machine with Claude Code, it times the way to Claude every thirty seconds — a DNS lookup of `api.anthropic.com` and a TCP handshake on port 443, with nothing sent over it — for the panel's latency reading. While the Browser Watch panel is open, it looks up the address of Claude's browser relay, `bridge.claudeusercontent.com`, about every thirty seconds — a DNS query to your resolver — to tell whether a running browser holds a connection to it. The [desktop app](#desktop-app) also asks this repository's GitHub releases for its own updates. With **Local network** on, which it is unless you switch it off, the deck also announces itself to other decks on your local network over UDP (port 45317) and pairs with the ones that answer — see [Local network](#local-network). The deck also sends usage reports to `api.ccdeck.dev`: an install event (naming the ccdeck.dev page the command was copied from, when the command says so with `--ref`, which the site's copy buttons add; a page name and nothing else, sent once), an update event (saying how the new version arrived: the deck's own update, the desktop app's updater, npx, npm or a source checkout), one "active" a day, one "uninstall" when you run `ccdeck --uninstall` (which asks, at a terminal, one skippable question about why, from a short list), one "activated" when a new install's first session arrives (how long after the install, in rough buckets such as "under five minutes", and whether it was a Claude or a Codex session), one "rated" if you answer the one question the deck asks about itself after about a week of use — "How useful is ccdeck to you?", 0 to 10, which you can skip — with the number you picked and how many days you had used the deck, as a range (nothing is sent for a question you put off or leave), and the errors it runs into, with every path outside ccdeck's own code, project folder names, the machine name in every web address, every IP address and the machine name a network error carries (the loopback, such as `127.0.0.1:4317`, stays, so a local port error still reads as one), email addresses and keys scrubbed out (a line of ccdeck's own code keeps its place in the package, such as `ccdeck/src/server/tail.mjs:42`, or in the page, such as `<deck>/assets/index-abc.js:1:2345`, so the error still says where it happened). Each carries the version, your OS and CPU architecture, the channel (desktop, npm or a source checkout), your IP address and the machine's rough shape — the number of CPU cores, the amount of RAM, the locale, the shell, the terminal, and the Claude Code and Codex versions. The install, update, active, activated, rated and uninstall reports also carry the runtime and a device fingerprint (a stable hashed machine id); an error report carries neither. The first four also say whether the Claude hooks went in and Codex is being watched, with the daily "active" also carrying how many sessions, subagents and projects you ran on the last day you used the deck, that day's date, and which of the deck's own features you used that day — fixed names such as "usage history" or "account switch", a yes for each and nothing about what you did with them — plus how the deck held up and what it runs with: how long this run took to start, that day's peak memory and how many events it took in, each as a rough bucket such as "under two seconds" or "256–512 MB", the Claude and Codex plan as its category only (such as "Max 5x" or "Plus", read from the file each CLI keeps beside its login, and nothing else from it), and how many Claude accounts and paired machines the deck holds, as counts. The fingerprint is a one-way hash of stable machine traits, never those traits in the clear; everything else is coarse counts and short tokens — no path, no project name, no free text. These reports are no longer anonymous: the install id is random, but the fingerprint follows this machine and the server records the IP the report arrives from. What still never leaves is your sessions, prompts, files, project names and paths. The deck has no switch for them; `AGENTS_DECK_NO_REPORTS=1` keeps them off from the first start. While the deck runs it also sends a tiny heartbeat every few minutes, the install id and nothing else, so the count of decks running right now, and how many hours a day a deck stays open, can be seen. **Send feedback** (the topbar's Feedback button; on a phone, under More) sends what you write, and any screenshots and contact you add, to the same place, with the ccdeck version and your system (such as `darwin-arm64`), which the dialog names before you send, and, while the usage reports are on, the same device fingerprint they carry, which it does not show; `AGENTS_DECK_NO_REPORTS=1` keeps the fingerprint home and the feedback still goes. As with a report, the server records the IP address it arrives from. The people who make ccdeck read it there and may open a public issue from it, never with the contact you gave or your screenshots. `AGENTS_DECK_NO_INSTALL=1` turns off everything but the quota reads; `AGENTS_DECK_NO_DOWNLOAD=1` is the narrower version — no `uv` binary is fetched, the managed installs stay.
|
|
333
350
|
|
|
@@ -353,19 +370,20 @@ The Accounts panel reads the store [claude-swap](https://github.com/realiti4/cla
|
|
|
353
370
|
|
|
354
371
|
The deck installs that package itself, so it installs it **bounded**: `claude-swap~=0.26`, which is `>= 0.26, == 0.*`, and when PyPI can be reached the exact version it resolved rather than the range. What `cswap --version` reports afterwards has to be that version, or the deck says so and leaves the panel dark rather than driving a copy it cannot account for — this is the tool that holds your Claude logins. The daily upgrade is bounded by the same specifier, and what it left behind is written to `~/.agents-deck/cswap-upgrade.json`.
|
|
355
372
|
|
|
356
|
-
**Switch** on an account's row makes it the active one. New sessions start on it; sessions already running are not restarted, and pick it up on their next message — up to about 30 seconds later on macOS. **Auto-switch**, off until you turn it on, does the same without a press: about once a minute the deck runs claude-swap's own engine, which, once the active account passes your threshold (90% unless you choose another) of its 5-hour or 7-day window, moves Claude Code to the account with the most room left. Every account keeps its own limits; when no other account is under the threshold, nothing switches. **Custom…**, last in the threshold picker, takes any whole percent from 50 to 99 and refuses anything else under the field without saving it; the threshold is claude-swap's own setting, kept on this machine.
|
|
373
|
+
**Switch** on an account's row makes it the active one. New sessions start on it; sessions already running are not restarted, and pick it up on their next message — up to about 30 seconds later on macOS. Because every session on the machine shares that one login, the deck will not switch to an account whose saved login claude-swap has already seen refused: it asks claude-swap to read the account first when a read is due, and if the login has expired the row says so, with **Sign in again**, and nothing moves. When it cannot tell — offline, or claude-swap does not answer in time — the switch goes ahead. **Auto-switch**, off until you turn it on, does the same without a press: about once a minute the deck runs claude-swap's own engine, which, once the active account passes your threshold (90% unless you choose another) of its 5-hour or 7-day window, moves Claude Code to the account with the most room left. Every account keeps its own limits; when no other account is under the threshold, nothing switches. Auto-switch also moves Claude Code off an account whose login has expired, once Claude Code has signed it out and claude-swap's stored copy of it no longer works either, to the account with the most room under the threshold that claude-swap has not set aside and no local `cswap run` session is using; the expired one stays in the list, waiting for you to sign it in again. When Claude Code sessions stop on an expired login or a usage limit, Auto-switch runs once right away instead of waiting for its next minute, and the cards say `Stopped · login expired` or `Stopped · usage limit` until the session does something again: type `continue` in each one once a working login is active. A session running in the background (`claude --bg`, agent view) gets **Continue** on its card instead, enabled once the active account's usage reading shows a working login with room since the stop: it runs Claude Code's own [`claude stop` and `claude --resume <session> --bg`](https://code.claude.com/docs/en/sessions) in the session's folder, and the card says how that went. **Continue stopped background sessions**, in **Settings › General**, off until you turn it on, presses it for you, once per stop; a session that stops again right after is left for you. **Custom…**, last in the threshold picker, takes any whole percent from 50 to 99 and refuses anything else under the field without saving it; the threshold is claude-swap's own setting, kept on this machine.
|
|
357
374
|
|
|
358
375
|
Two choices change where Auto-switch goes, and do nothing while it is off. **Next account**, under the switch, is **Most room left** — claude-swap's own pick, and the default — or **Soonest weekly reset**: the account whose 7-day window resets soonest, as long as that is within 95 hours, so quota that is about to reset is used first. With it, the deck also moves below the threshold, to an account that resets at least an hour sooner than the one in use, and never sooner than half an hour after the last move. **Set as home**, in an account's **⋯**, marks the row with ⌂: Auto-switch takes you there, does not move you off it before the threshold, and comes back once its 5-hour window has reset. Only an account comfortably under the threshold, read in the last 15 minutes, signed in, in rotation, not set aside by claude-swap and not in use in a local `cswap run` session is moved to. An account reported as active on another paired device remains eligible for Home and Soonest weekly reset. If Home has stale readings, Auto-switch asks claude-swap to collect before choosing a weekly alternative; if Home is still unavailable afterward, it uses the alternative. A switch you make yourself is left alone until that account reaches the threshold, or until you set a home or pick a rule again. When no account fits either rule, claude-swap decides, as before. Both choices are kept on this machine.
|
|
359
376
|
|
|
360
377
|
**Account capacity**, the gauge in the panel's header, says how many accounts are ready and what their 5-hour and 7-day windows have left. Its **Reset calendar** view lays out today and the next six days, with each account's 7-day reset on the day it falls, and marks the readings that need refreshing.
|
|
361
378
|
|
|
362
|
-
**Account notifications** are
|
|
379
|
+
**Account notifications** are four switches in **Settings › Notifications** (the gear in the topbar, or `Cmd+,`; `Ctrl+,` on Windows and Linux), each on its own and none of them tied to **Notifications while closed**: they are sent whether the deck is open or not, because nothing on the page says them. The desktop app shows them as ccdeck, without a sound.
|
|
363
380
|
|
|
364
|
-
- **Account auto-switched**, on unless you turn it off. When Auto-switch moves Claude Code to another account, one notification says where to and, when the engine's own reading shows it, why: `Switched to work · personal@example.com reached 90%`, `Back on work · your home account` or `Switched to side · weekly limit resets in 1d 7h`, with an account's alias when it has one. A switch you make yourself is not announced.
|
|
381
|
+
- **Account auto-switched**, on unless you turn it off. When Auto-switch moves Claude Code to another account, one notification says where to and, when the engine's own reading shows it, why: `Switched to work · personal@example.com reached 90%`, `Back on work · your home account` or `Switched to side · weekly limit resets in 1d 7h`, with an account's alias when it has one. A switch away from an expired login says so: `Switched to work · personal@example.com's login expired, sign in again to use it`; and when no other account is ready to take over, that is said once rather than every minute. A switch you make yourself is not announced.
|
|
365
382
|
- **Quota at 90% and 100%**, off until you turn it on. When a window of the Claude or Codex account you are on reaches 90%, and once more at 100%: Claude's 5-hour, 7-day and per-model windows, and every Codex window the Usage panel shows, the extra limits included — `5-hour usage reached 90% · resets in 2h 14m`. Only the account in use is watched, not every account you have stored. When reaching it is what makes Auto-switch move the account, the switch notification says it and this one is not sent, unless the switch notification is off.
|
|
366
383
|
- **Quota reset**, off until you turn it on. When one of those windows that had reached 90% starts over: `5-hour window available again`. A window that never got that high resets without a word.
|
|
384
|
+
- **Sessions stopped on login or limit**, on unless you turn it off. When Claude Code sessions stop on an expired login or a usage limit, one notification for all of them says how many stopped and to type `continue` in each. When the Auto-switch run that follows moves the account, the switch notification says it instead, so one incident is one notification.
|
|
367
385
|
|
|
368
|
-
Each is said once per window. The deck writes what it has said to `account-notify.json`, beside its settings, so a restart does not say it again, and nothing said about one account counts for another. With either quota switch on, the deck reads the quota of the accounts in use about every two minutes even while no page is open — the same reads, through the same caches and limits, as the Usage panel's. `AGENTS_DECK_NO_NOTIFY=1` keeps all
|
|
386
|
+
Each is said once per window. The deck writes what it has said to `account-notify.json`, beside its settings, so a restart does not say it again, and nothing said about one account counts for another. With either quota switch on, the deck reads the quota of the accounts in use about every two minutes even while no page is open — the same reads, through the same caches and limits, as the Usage panel's. `AGENTS_DECK_NO_NOTIFY=1` keeps all four off.
|
|
369
387
|
|
|
370
388
|
**`+` → Sign in** runs `claude auth login`, shows you the link, and hands the result to `cswap add`. The sign-in usually completes by itself once you approve it in the browser; only when the page shows a code — as it does on a deck opened from another machine — is there one to paste back into the dialog. The account you were using **stays active** — signing in replaces the live credentials, so the previous one is switched back the moment the new one is recorded. A pasted code goes straight into the CLI's stdin on this machine; it is never stored, logged, or sent anywhere else.
|
|
371
389
|
|
|
@@ -380,10 +398,36 @@ An import adds what is missing and leaves a working account exactly as it is. Th
|
|
|
380
398
|
> [!WARNING]
|
|
381
399
|
> A share carries the **live login of every account in it, in the clear** — claude-swap's export format has no encryption, and five ticked boxes is five passwords on your clipboard. It expires ten minutes after it is made and imports refuse it after that. While it lives, treat it as those passwords: anything that can read your clipboard can read the accounts.
|
|
382
400
|
|
|
383
|
-
**Rename**, **Move to slot…** and **Remove** are on the same row menu. Removal takes two clicks and cannot be undone.
|
|
401
|
+
**Rename**, **Move to slot…** and **Remove** are on the same row menu. Removal takes two clicks and cannot be undone. Removing the active account leaves Claude Code signed in as it; when that login is the expired one, the deck moves Claude Code to the working account with the most room left that claude-swap has not set aside and no local `cswap run` session is using, or says that none could take over.
|
|
384
402
|
|
|
385
403
|
Step by step: [Switch between multiple Claude Code accounts](https://ccdeck.dev/guides/claude-accounts/) · [Copy your Claude Code login to another machine](https://ccdeck.dev/guides/move-an-account/)
|
|
386
404
|
|
|
405
|
+
## From the terminal
|
|
406
|
+
|
|
407
|
+
The Accounts panel and the session list answer from any terminal on the machine too, which is the whole of what you have when you reach it over SSH:
|
|
408
|
+
|
|
409
|
+
```
|
|
410
|
+
ccdeck accounts every Claude account, its 5h / 7d usage and resets
|
|
411
|
+
ccdeck switch work move the live login: a slot number, an email, an alias,
|
|
412
|
+
or any part of one that names a single account
|
|
413
|
+
ccdeck switch --best where Auto-switch would go: your home account or the soonest
|
|
414
|
+
weekly reset when you set one, else the most room left
|
|
415
|
+
ccdeck switch pick from a list (arrows, Enter; Esc cancels)
|
|
416
|
+
ccdeck usage the active account's limits, every lane
|
|
417
|
+
ccdeck sessions what each session is doing, the ones waiting on you first
|
|
418
|
+
ccdeck open the deck in your browser — over SSH, the line that opens it on yours
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
`swap` and `use` are other names for `switch`, `ls` for `accounts` and `ps` for `sessions`; `status`, `stop` and `logs` are `--status`, `--stop` and `--logs`. `ccdeck swap 1 2` does not exchange two slots the way claude-swap's `cswap swap` does — it says so and points you there.
|
|
422
|
+
|
|
423
|
+
**The commands ask the deck that is running.** A switch from the terminal goes through the same route as **Switch** on a row, so it waits for the same lock as the panel, Auto-switch and a sign-in in flight, the panel shows it at once, and it lands in the Projects report's history. With no deck running, `accounts`, `switch` and `usage` read and drive claude-swap's store directly; `sessions` and `open` need a deck, since sessions are what a deck watches. After a switch, the command says how many running Claude sessions move with it — all of them, from their next message.
|
|
424
|
+
|
|
425
|
+
**Over SSH**, `ccdeck open` prints the line to run on your own computer, `ssh -N -o ExitOnForwardFailure=yes -L 14317:127.0.0.1:4317 you@that-machine` (with `-p` when sshd is not on 22), and the deck then opens at `http://127.0.0.1:14317` in your own browser. Your end is not 4317, so it cannot land on a deck of your own. The deck still listens only on 127.0.0.1; the tunnel is your SSH connection.
|
|
426
|
+
|
|
427
|
+
**For scripts**, every command takes `--json` — one object on stdout with `schemaVersion` and `ok` — and `--port <n>` to name a deck. Nothing prompts without a terminal: `ccdeck switch` with no account named and no terminal is an error, not a wait. Exit codes are 0 done, 1 failed, 2 the command line was wrong (an account nothing matches, a misspelled command), and 3 no deck is running.
|
|
428
|
+
|
|
429
|
+
A misspelled command is refused — `ccdeck acounts` suggests `accounts` and starts nothing — so a typo over SSH never leaves a deck behind.
|
|
430
|
+
|
|
387
431
|
## Local network
|
|
388
432
|
|
|
389
433
|
A Claude login expires on the machine that has not used it for a while, and stays alive on the one that has. With two or three machines that is a `claude login` a week, each time on the machine you are not sitting at. **Local network** is the last section of the Claude accounts panel, and it is that chore done for you: decks on one network find each other, pair, and a login that has expired on one is copied back from another that still has it.
|
|
@@ -425,8 +469,10 @@ Step by step: [Repair expired Claude Code logins across machines](https://ccdeck
|
|
|
425
469
|
|
|
426
470
|
```
|
|
427
471
|
ccdeck [options]
|
|
472
|
+
ccdeck <command> [options] accounts, switch, usage, sessions, open — see From the terminal
|
|
428
473
|
|
|
429
|
-
-p, --port <number> Preferred port (default: 4317; fallback: random 4318–4400)
|
|
474
|
+
-p, --port <number> Preferred port (default: 4317; fallback: random 4318–4400);
|
|
475
|
+
with a command, the deck to ask
|
|
430
476
|
--no-open Don't open the browser automatically
|
|
431
477
|
--foreground Hold the terminal, the way every version before 3.20
|
|
432
478
|
did (Ctrl+C stops the deck again)
|
|
@@ -462,13 +508,16 @@ ccdeck [options]
|
|
|
462
508
|
--uninstall Remove ccdeck's hooks from settings files, and name
|
|
463
509
|
the files that still hold this deck's private key
|
|
464
510
|
--purge With --uninstall: delete those files too
|
|
511
|
+
--json With a command: one object on stdout, for scripts
|
|
512
|
+
--best With `switch`: the account Auto-switch would pick
|
|
465
513
|
-h, --help Show this help
|
|
466
514
|
-v, --version Print the version and exit
|
|
467
515
|
```
|
|
468
516
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
517
|
+
A word in first position that is not a command — [From the terminal](#from-the-terminal)
|
|
518
|
+
lists them — is refused, so `ccdeck acounts` never starts a deck. Anything else
|
|
519
|
+
on the command line is reported as an unknown option and then ignored — the deck
|
|
520
|
+
still starts, so a typo costs you a warning rather than a dashboard.
|
|
472
521
|
|
|
473
522
|
`--foreground` is there for anything that was relying on the old behaviour — a
|
|
474
523
|
wrapper script, a CI step, a supervisor of your own that starts the deck and
|
|
@@ -560,6 +609,7 @@ Environment:
|
|
|
560
609
|
| `AGENTS_DECK_CSWAP` | Full path to `cswap`, when it lives somewhere unusual |
|
|
561
610
|
| `AGENTS_DECK_CLAUDE` | Full path to the `claude` CLI |
|
|
562
611
|
| `AGENTS_DECK_CCUSAGE` | Full path to your own `ccusage`, used ahead of everything else |
|
|
612
|
+
| `AGENTS_DECK_SKILL_HOOK=1` | Add the `UserPromptExpansion` hook, so Tool activity's Skills tab counts the slash commands you type — only where every Claude Code found is 2.1.116 or newer. Off by default, and only `1` turns it on |
|
|
563
613
|
| `CLAUDE_SWAP_BACKUP` | Override the claude-swap store root the Accounts panel reads |
|
|
564
614
|
| `CCDECK_HOME` | Put everything the deck writes — its state and its log — under this directory instead of the platform default. Wins over every rule below it |
|
|
565
615
|
| `CLAUDE_CONFIG_DIR` | Override `~/.claude` — the hook entry, the event log and everything else the deck writes move with it |
|
|
@@ -605,8 +655,10 @@ platform's **data** directory, and the platform's **log** directory.
|
|
|
605
655
|
`prefs.json` is the one to delete deliberately: it holds this deck's **Local
|
|
606
656
|
network private key**, the one every deck you paired with has pinned. Leaving it
|
|
607
657
|
behind leaves that identity on the machine. (`~/.agents-deck/` holds the managed
|
|
608
|
-
tools and the deck's records about them,
|
|
609
|
-
Telemetry Radar has monitored — the destinations it resumes —
|
|
658
|
+
tools and the deck's records about them, `radar-monitor-<port>.json` once
|
|
659
|
+
Telemetry Radar has monitored — the destinations it resumes — and
|
|
660
|
+
`radar-settings-<port>.json` once its automatic monitoring has been switched,
|
|
661
|
+
but no key.)
|
|
610
662
|
|
|
611
663
|
The data directory also holds Tool activity's `tool-audit/` folder — up to 90
|
|
612
664
|
days of which tools and commands your agents ran, and how long they took — and
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -70,7 +70,7 @@ arrives with its own licence beside it. They are named for completeness, so that
|
|
|
70
70
|
"what ccdeck ships" and "what ccdeck can run" are not confused. Every one of them
|
|
71
71
|
is off under `AGENTS_DECK_NO_INSTALL=1`.
|
|
72
72
|
|
|
73
|
-
## Bundled packages (
|
|
73
|
+
## Bundled packages (27)
|
|
74
74
|
|
|
75
75
|
| Package | Version | Licence | Copyright |
|
|
76
76
|
| --- | --- | --- | --- |
|
|
@@ -92,6 +92,7 @@ is off under `AGENTS_DECK_NO_INSTALL=1`.
|
|
|
92
92
|
| `dagre` | 0.8.5 | MIT | Copyright (c) 2012-2014 Chris Pettitt |
|
|
93
93
|
| `graphlib` | 2.1.8 | MIT | Copyright (c) 2012-2014 Chris Pettitt |
|
|
94
94
|
| `hls.js` | 1.7.3 | Apache-2.0 | Copyright (c) 2017 Dailymotion (http://www.dailymotion.com) |
|
|
95
|
+
| `json-edit-react` | 2.0.4 | MIT | Copyright (c) 2024 Carl Smith |
|
|
95
96
|
| `lodash` | 4.18.1 | MIT | Copyright OpenJS Foundation and other contributors <https://openjsf.org/> |
|
|
96
97
|
| `react` | 18.3.1 | MIT | Copyright (c) Facebook, Inc. and its affiliates. |
|
|
97
98
|
| `react-dom` | 18.3.1 | MIT | Copyright (c) Facebook, Inc. and its affiliates. |
|
|
@@ -109,12 +110,16 @@ for more than a notice — a copy of the licence itself travels with the work
|
|
|
109
110
|
and it is compatible with version 3 of the GNU licences, which is the version
|
|
110
111
|
ccdeck is under.
|
|
111
112
|
|
|
112
|
-
`hls.js`
|
|
113
|
-
own chunk, `dist/web/assets/hls-*.js`,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
`hls.js` and `json-edit-react` are the two entries that are not in the page
|
|
114
|
+
every visit loads. `hls.js` is its own chunk, `dist/web/assets/hls-*.js`,
|
|
115
|
+
fetched only when somebody plays an HLS custom station in a browser without
|
|
116
|
+
native HLS (#1208). `json-edit-react` is the JSON tree in Radar's event
|
|
117
|
+
inspector and is compiled into Radar's chunk,
|
|
118
|
+
`dist/web/assets/TrafficRadar-*.js`, fetched only when somebody opens Radar; it
|
|
119
|
+
adds its own stylesheet from that JavaScript the first time it renders, so it
|
|
120
|
+
has no CSS file of its own. Both chunks are in `dist/web` like every other, and
|
|
121
|
+
so in the tarball. None of these licences is changed by ccdeck's relicensing,
|
|
122
|
+
and no copyleft obligation flows back to their authors.
|
|
118
123
|
|
|
119
124
|
### Declared but not emitted (3)
|
|
120
125
|
|
|
@@ -655,6 +660,37 @@ If the Work includes a "NOTICE" text file as part of its distribution, then any
|
|
|
655
660
|
END OF TERMS AND CONDITIONS
|
|
656
661
|
```
|
|
657
662
|
|
|
663
|
+
### 15. `json-edit-react` 2.0.4
|
|
664
|
+
|
|
665
|
+
Reproduced verbatim from `node_modules/json-edit-react/LICENSE`:
|
|
666
|
+
|
|
667
|
+
```text
|
|
668
|
+
MIT License
|
|
669
|
+
|
|
670
|
+
Copyright (c) 2024 Carl Smith
|
|
671
|
+
|
|
672
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
673
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
674
|
+
in the Software without restriction, including without limitation the rights
|
|
675
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
676
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
677
|
+
furnished to do so, subject to the following conditions:
|
|
678
|
+
|
|
679
|
+
The above copyright notice and this permission notice shall be included in all
|
|
680
|
+
copies or substantial portions of the Software.
|
|
681
|
+
|
|
682
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
683
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
684
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
685
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
686
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
687
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
688
|
+
SOFTWARE.
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
Source: https://github.com/CarlosNZ/json-edit-react. The package has no
|
|
692
|
+
dependencies of its own; React, its one peer, is §1.
|
|
693
|
+
|
|
658
694
|
## Radio world map
|
|
659
695
|
|
|
660
696
|
The radio map includes simplified country geometry from Natural Earth
|