claude-mission-control 1.11.0 → 1.11.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/README.md CHANGED
@@ -26,7 +26,7 @@ Claude Code runs in a terminal. Once you have two or three sessions going, you l
26
26
 
27
27
  **Requirements:** macOS or Linux (Windows experimental, see below), Node.js ≥ 18, Claude Code.
28
28
 
29
- ![Claude Dashboard, dark mode: three live sessions, two of them waiting with the question shown, plus the pinned strip, unpushed work, and today's digest](docs/screenshots/dashboard-dark.png)
29
+ ![Claude Dashboard, dark mode: three live sessions with live cost, burn rate and context meters, two of them waiting with the question shown, plus the pinned strip, unpushed work, and today's digest](docs/screenshots/dashboard-dark.png)
30
30
 
31
31
  *Every screenshot here is demo data (`CLAUDE_DASH_DEMO=1`). The projects are invented.*
32
32
 
@@ -121,9 +121,9 @@ If something looks off, the log is at `~/Library/Logs/claude-dashboard.log`. To
121
121
  - **Project cards** — sorted by last activity. Branch chip, `●n` uncommitted changes, `↑n` unpushed commits. The sparkline is prompts per day for the last two weeks. Each session row has an `open ⬈` button that resumes the session in your terminal (new window, right directory) or imports it into the Claude desktop app when it's installed — the **Open in** selector in the header names whichever terminal you've configured (auto-detected on first run). The `⧉` button copies the `claude --resume` command instead.
122
122
  - **Header meters** — your plan and rate-limit tier (Free/Pro/Max/Enterprise/API, detected from Claude Code's local account cache), live session and weekly usage from Anthropic's usage API via your existing Claude Code sign-in, plus extra-usage spend. Set a **weekly budget** in settings and a third meter tracks estimated cost (list-price value on a subscription) against it, with one alert each at 75 / 90 / 100%. First run may show one macOS Keychain prompt — click Always Allow.
123
123
 
124
- ![Mission Control: every live session tiled side by side, each pane following its own transcript, with the waiting reason at the top of each pane and the agent team under the middle one](docs/screenshots/mission-control.png)
124
+ ![Mission Control: every live session tiled side by side, each pane following its own transcript, with cost, burn rate, context meter and tool counts in each header, the waiting reason under it, and the agent team under the middle one](docs/screenshots/mission-control.png)
125
125
 
126
- ![Transcript viewer live-following a running session: the agent team at the top, then prompts, replies as markdown, and tool calls as one-liners](docs/screenshots/transcript.png)
126
+ ![Transcript viewer on a running session with the cost panel open: value per model by input, output and cache, the subagent share, cache hit rate, context and tool calls, then the agent team and the conversation](docs/screenshots/transcript.png)
127
127
 
128
128
  - **Transcripts** — click any session title (cards, digest, search results, project drawer) to read the conversation: your prompts, Claude's replies rendered as markdown, tool calls as compact one-liners, and away-summaries highlighted. Long sessions show the newest ~1200 events. **Running sessions follow live** — a `● live` badge appears, new turns stream in every few seconds, and the view sticks to the bottom unless you've scrolled up to read.
129
129
  - **Search** — the header box searches every prompt you've ever sent plus all session titles (Enter to run, 2+ characters). Narrow with `project:name` or `since:7d` / `since:2026-08-01`. Clicking a prompt result opens the transcript scrolled to the matching turn. If the answer isn't in a prompt, **search inside full transcripts** runs the same query across the conversation bodies — slower, so it's a second click rather than the default.
@@ -143,10 +143,13 @@ If something looks off, the log is at `~/Library/Logs/claude-dashboard.log`. To
143
143
  - **Models everywhere** — every session shows which model ran it (live cards, digest, session lists), and the stats view breaks down usage per model and per project.
144
144
  - **Claude.ai chats** — import the official export from claude.ai (Settings → Privacy → Export data, then feed `conversations.json` to ⚙ settings here) and your chats become browsable (`⌘K` → Claude.ai chats) and full-text searchable next to your coding sessions. Stored slimmed in your local config dir, gitignored, never uploaded anywhere.
145
145
 
146
- ![Stats view: activity heatmap, busiest hours, weekly rhythm, 90-day spend, and per-model cost breakdowns](docs/screenshots/stats.png)
146
+ ![Stats view: activity heatmap, busiest hours, weekly rhythm, 90-day spend, per-model costs, the most expensive sessions, and models by project](docs/screenshots/stats.png)
147
147
 
148
148
  - **Project details** — click any project's name for a slide-over with its full session list, recent git commits, rendered CLAUDE.md, per-project memory files, skills/agents/commands from `.claude/`, and settings (permissions, MCP servers, allowed tools), plus the resolved **Toolset** below. Read-only; also a quick audit of which projects are missing instructions or memory. Esc closes.
149
149
  - **Toolset** — inside the project slide-over: what Claude Code would actually use in that project. Every installed plugin, every agent and skill from the project, your user dir, and enabled plugins, and every MCP server that applies, each marked on or off with where it came from and which settings scope decided it, resolved with Claude Code's own precedence (managed › local › project › user, deny beats allow, project agents shadow user agents shadow plugin agents). An amber list at the top flags things worth a look: a plugin enabled but not installed or gone stale, a deny rule naming an agent that no longer exists, a server that needs auth, a settings file that doesn't parse. The `⧉` on a row copies the exact snippet to flip it, aimed at `.claude/settings.local.json`; MCP toggles live in Claude's own registry, so that recipe tells you to run `/mcp` in a session instead (servers from a project's `.mcp.json` also honour the settings keys `enabledMcpjsonServers`, `disabledMcpjsonServers` and `enableAllProjectMcpServers`, and their recipes use those). Buttons at the foot reveal the project's settings files in Finder. Read-only — the dashboard never edits Claude configuration.
150
+
151
+ ![Toolset in the project slide-over: plugins, agents, skills and MCP servers marked on or off with their source and deciding settings scope, an amber warning for a plugin enabled but not installed, and buttons for the project's settings files](docs/screenshots/toolset.png)
152
+
150
153
  - **Plugins & MCP** — `⌘K` → Plugins & MCP (or the button in settings) lists every installed plugin with its marketplace, version, on/off state and a `stale` flag when its marketplace was refreshed after the plugin was last updated, plus every MCP server with its scope, the projects that use it, an `off` chip for servers you have disabled in a project, and an amber `needs auth` when Claude Code says so. Read-only; server secrets never reach the browser.
151
154
 
152
155
  ![Plugins & MCP inventory: plugins with on, off, stale and missing states; MCP servers with scope, projects, disabled flags and needs-auth](docs/screenshots/inventory.png)
package/lib/demo.js CHANGED
@@ -283,10 +283,30 @@ const DEMO_USAGE = {
283
283
  tools: { total: 388, errors: 0, byName: [{ name: 'Edit', count: 141, errors: 0 }, { name: 'Read', count: 122, errors: 0 }, { name: 'Bash', count: 79, errors: 0 }, { name: 'Grep', count: 46, errors: 0 }] },
284
284
  };
285
285
 
286
+ // Per-session usage, so a transcript's cost badge matches its row on the
287
+ // board (S1 Acme $24.60, S4 Data Pipeline $3.40); everything else gets the
288
+ // Blog Engine block.
289
+ const DEMO_USAGE_BY_ID = {
290
+ [S1]: {
291
+ cost: 24.6, tokens: 6_200_000, cacheHitRatio: 0.91,
292
+ byModel: [{ model: 'claude-opus-5', input: 140_000, output: 210_000, cacheRead: 5_400_000, cacheCreation: 450_000, cost: 24.6 }],
293
+ subagents: null, assumedModels: [],
294
+ context: { tokens: 412000, window: 1000000, pct: 41 },
295
+ tools: { total: 142, errors: 3, byName: [{ name: 'Read', count: 58, errors: 0 }, { name: 'Edit', count: 41, errors: 1 }, { name: 'Bash', count: 29, errors: 2 }, { name: 'Grep', count: 14, errors: 0 }] },
296
+ },
297
+ [S4]: {
298
+ cost: 3.4, tokens: 2_100_000, cacheHitRatio: 0.88,
299
+ byModel: [{ model: 'claude-sonnet-5', input: 60_000, output: 70_000, cacheRead: 1_850_000, cacheCreation: 120_000, cost: 3.4 }],
300
+ subagents: null, assumedModels: [],
301
+ context: { tokens: 186000, window: 1000000, pct: 19 },
302
+ tools: { total: 37, errors: 1, byName: [{ name: 'Bash', count: 21, errors: 1 }, { name: 'Read', count: 12, errors: 0 }, { name: 'Edit', count: 4, errors: 0 }] },
303
+ },
304
+ };
305
+
286
306
  // The usage block rides only on the initial load, like the real endpoint.
287
307
  function demoSession(id, after) {
288
308
  const t = demoSessionInner(id, after);
289
- return after ? t : { ...t, usage: DEMO_USAGE };
309
+ return after ? t : { ...t, usage: DEMO_USAGE_BY_ID[id] || DEMO_USAGE };
290
310
  }
291
311
 
292
312
  function blogSession(now, after) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-mission-control",
3
- "version": "1.11.0",
3
+ "version": "1.11.1",
4
4
  "description": "Local dashboard for Claude Code: live sessions, transcripts, costs, git status — all your projects in one place.",
5
5
  "main": "server.js",
6
6
  "bin": {
package/public/index.html CHANGED
@@ -603,10 +603,12 @@
603
603
  }
604
604
  .mc-pane.waiting { box-shadow: inset 0 2px 0 var(--warn); }
605
605
  .mc-pane-head {
606
- display: flex; align-items: center; gap: 10px;
606
+ display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px;
607
607
  padding: 8px 12px; border-bottom: 1px solid var(--line); flex: none;
608
608
  min-width: 0;
609
609
  }
610
+ .mc-pane-head .mc-proj { min-width: 0; flex: 0 1 auto; }
611
+ .mc-stats { flex: 1 0 100%; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; min-width: 0; }
610
612
  .mc-pane-head .mc-proj {
611
613
  font-family: var(--disp-font);
612
614
  text-transform: uppercase; letter-spacing: 0.05em;
@@ -2056,9 +2058,13 @@ function mcPaneHead(s) {
2056
2058
  ? `<span class="mc-meta" title="subagent transcripts · their tokens">⑂ ${s.subagents.count}${
2057
2059
  s.subagents.mtok ? ` · ${s.subagents.mtok}M tok` : ''}</span>`
2058
2060
  : '';
2061
+ // Two rows: identity and status on top, the numbers underneath, so a
2062
+ // narrow pane never pushes its status badge into the next one.
2063
+ const stats = `${s.estCost != null ? costChip(s.estCost, { cls: 'mc-meta', assumed: s.assumed, after: s.burnRate ? ` · $${s.burnRate}/h` : '' }) : ''}${contextMeter(s.context)}${s.tools ? `<span class="mc-meta" title="tool calls in this session">${s.tools.total} tools${s.tools.errors ? ` · <span class="failed">${s.tools.errors} failed</span>` : ''}</span>` : ''}${subs}`;
2059
2064
  return `<span class="mc-proj" data-session="${esc(s.sessionId)}" title="Open the full transcript">${esc(s.projectName)}</span>
2060
- ${modelChip(s.model)}${s.estCost != null ? costChip(s.estCost, { cls: 'mc-meta', assumed: s.assumed, after: s.burnRate ? ` · $${s.burnRate}/h` : '' }) : ''}${subs}${contextMeter(s.context)}${s.tools ? `<span class="mc-meta" title="tool calls in this session">${s.tools.total} tools${s.tools.errors ? ` · <span class="failed">${s.tools.errors} failed</span>` : ''}</span>` : ''}<span class="spacer"></span>
2061
- <span class="mc-meta${s.waitingMin != null ? ' overdue' : ''}">${s.waitingMin != null ? waitLabel(s.waitingMin) : elapsed(s.startedAt)}</span>${statusFlap(s, 'mc:')}`;
2065
+ ${modelChip(s.model)}<span class="spacer"></span>
2066
+ <span class="mc-meta${s.waitingMin != null ? ' overdue' : ''}">${s.waitingMin != null ? waitLabel(s.waitingMin) : elapsed(s.startedAt)}</span>${statusFlap(s, 'mc:')}${
2067
+ stats ? `<span class="mc-stats">${stats}</span>` : ''}`;
2062
2068
  }
2063
2069
 
2064
2070
  const AGENT_COLORS = { blue: '#4a90e2', green: 'var(--accent)', red: 'var(--bad)', yellow: 'var(--warn)', purple: '#a86ee0', cyan: '#2fb8c9', orange: '#e08a2f', pink: '#e06ea8', gray: 'var(--faint)', grey: 'var(--faint)' };