@viren/claude-code-dashboard 0.0.8 → 0.0.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viren/claude-code-dashboard",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "A visual dashboard for your Claude Code configuration across all repos",
5
5
  "type": "module",
6
6
  "bin": {
package/src/assembler.mjs CHANGED
@@ -2,12 +2,13 @@ import { readFileSync } from "fs";
2
2
  import { fileURLToPath } from "url";
3
3
  import { dirname, join } from "path";
4
4
 
5
- import { esc, insightsToMarkdown } from "./helpers.mjs";
5
+ import { esc, insightsToPrompt } from "./helpers.mjs";
6
6
  import { VERSION, REPO_URL } from "./constants.mjs";
7
7
  import { renderCmd, renderRule, renderRepoCard } from "./render.mjs";
8
8
  import {
9
9
  renderSkillsCard,
10
10
  renderMcpCard,
11
+ renderMcpRecommendedCard,
11
12
  renderToolsCard,
12
13
  renderLangsCard,
13
14
  renderErrorsCard,
@@ -71,12 +72,20 @@ export function generateDashboardHtml(data) {
71
72
  <button id="refresh-btn" class="header-btn" title="Copy refresh command to clipboard" aria-label="Copy refresh command">&#8635; refresh</button>
72
73
  <button id="theme-toggle" class="theme-toggle" title="Toggle light/dark mode" aria-label="Toggle theme"><span class="theme-icon"></span></button>
73
74
  </div>
74
- <p class="sub">generated ${timestamp} · <a href="${esc(REPO_URL)}" target="_blank" rel="noopener" style="color:var(--accent);text-decoration:none">v${esc(VERSION)}</a></p>`;
75
+ <p class="sub">generated ${timestamp} · <a href="${esc(REPO_URL)}" target="_blank" rel="noopener" style="color:var(--accent);text-decoration:underline;text-underline-offset:2px">v${esc(VERSION)}</a></p>`;
75
76
 
76
77
  const statsBar = renderStatsBar(data);
77
78
 
78
- // Overview tab
79
- const overviewCommands = `<div class="top-grid">
79
+ // Home tab — actionable content first
80
+ const insightsPrompt = insightsToPrompt(insights);
81
+ const insightsHtml = renderInsightsCard(insights, insightsPrompt);
82
+ const mcpRecsHtml = renderMcpRecommendedCard(recommendedMcpServers);
83
+ const chainsHtml = renderChainsCard(chains);
84
+ const consolidationHtml = renderConsolidationCard(consolidationGroups);
85
+ const tabHome = `${insightsHtml}\n ${mcpRecsHtml}\n ${chainsHtml}\n ${consolidationHtml}`;
86
+
87
+ // Config tab — stable reference: commands, rules, skills, MCP servers
88
+ const commandsRulesHtml = `<div class="top-grid">
80
89
  <div class="card" id="section-commands" style="margin-bottom:0">
81
90
  <h2>Global Commands <span class="n">${globalCmds.length}</span></h2>
82
91
  ${globalCmds.map((c) => renderCmd(c)).join("\n ")}
@@ -86,14 +95,7 @@ export function generateDashboardHtml(data) {
86
95
  ${globalRules.map((r) => renderRule(r)).join("\n ")}
87
96
  </div>
88
97
  </div>`;
89
- const insightsMarkdown = insightsToMarkdown(insights);
90
- const insightsHtml = renderInsightsCard(insights, insightsMarkdown);
91
- const chainsHtml = renderChainsCard(chains);
92
- const consolidationHtml = renderConsolidationCard(consolidationGroups);
93
- const tabOverview = `${overviewCommands}\n ${insightsHtml}\n ${chainsHtml}\n ${consolidationHtml}`;
94
-
95
- // Skills & MCP tab
96
- const tabSkillsMcp = `${renderSkillsCard(globalSkills)}\n ${renderMcpCard(mcpSummary, mcpPromotions, formerMcpServers, recommendedMcpServers, availableMcpServers, registryTotal)}`;
98
+ const tabConfig = `${commandsRulesHtml}\n ${renderSkillsCard(globalSkills)}\n ${renderMcpCard(mcpSummary, mcpPromotions, formerMcpServers, availableMcpServers, registryTotal)}`;
97
99
 
98
100
  // Analytics tab
99
101
  const insightsReportHtml = renderInsightsReportCard(insightsReport);
@@ -146,8 +148,8 @@ export function generateDashboardHtml(data) {
146
148
  html = html.replace("/* {{JS}} */", _js);
147
149
  html = html.replace("<!-- {{HEADER}} -->", header);
148
150
  html = html.replace("<!-- {{STATS_BAR}} -->", statsBar);
149
- html = html.replace("<!-- {{TAB_OVERVIEW}} -->", tabOverview);
150
- html = html.replace("<!-- {{TAB_SKILLS_MCP}} -->", tabSkillsMcp);
151
+ html = html.replace("<!-- {{TAB_HOME}} -->", tabHome);
152
+ html = html.replace("<!-- {{TAB_CONFIG}} -->", tabConfig);
151
153
  html = html.replace("<!-- {{TAB_ANALYTICS}} -->", tabAnalytics);
152
154
  html = html.replace("<!-- {{TAB_REPOS}} -->", tabRepos);
153
155
  html = html.replace("<!-- {{TAB_REFERENCE}} -->", tabReference);
package/src/constants.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { join } from "path";
2
2
  import { homedir } from "os";
3
3
 
4
- export const VERSION = "0.0.8";
4
+ export const VERSION = "0.0.10";
5
5
  export const REPO_URL = "https://github.com/VirenMohindra/claude-code-dashboard";
6
6
 
7
7
  export const HOME = homedir();
package/src/helpers.mjs CHANGED
@@ -33,25 +33,109 @@ export function gitCmd(repoDir, ...args) {
33
33
  }
34
34
  }
35
35
 
36
- const INSIGHT_ICONS = {
37
- warning: "\u26A0\uFE0F",
38
- tip: "\u2728",
39
- promote: "\u2B06",
40
- info: "\u2139\uFE0F",
36
+ const PROMPT_GENERATORS = {
37
+ "config-drift"(meta) {
38
+ const list = meta.repos.map((r) => `- ${r.name} (${r.commitsSince} commits since last update)`);
39
+ return [
40
+ "These repos have stale CLAUDE.md files:",
41
+ ...list,
42
+ "",
43
+ "For each repo:",
44
+ "1. Read the current CLAUDE.md",
45
+ "2. Run `git log --oneline` to see what changed since the last config update",
46
+ "3. Check if new patterns, tools, or conventions were introduced that should be documented",
47
+ "4. Propose targeted additions — don't rewrite from scratch, just fill gaps",
48
+ ].join("\n");
49
+ },
50
+ "unconfigured-repos"(meta) {
51
+ if (!meta.repos.length) return "Several repos have no Claude Code configuration.";
52
+ const list = meta.repos.map((r) => `- ${r.name} (${r.techStack.join(", ")})`);
53
+ return [
54
+ "These repos have no CLAUDE.md yet:",
55
+ ...list,
56
+ "",
57
+ "Pick the one you want to configure. For that repo:",
58
+ "1. Read the project structure and config files (package.json, pyproject.toml, etc.)",
59
+ "2. Identify the build system, test framework, and linter",
60
+ "3. Generate a concise CLAUDE.md (50-100 lines) with build/test/lint commands and key conventions",
61
+ ].join("\n");
62
+ },
63
+ "mcp-promotion"(meta) {
64
+ const list = meta.servers.map((s) => `- ${s.name} (used in ${s.projectCount} projects)`);
65
+ return [
66
+ "These MCP servers are installed in multiple projects and should be promoted to global:",
67
+ ...list,
68
+ "",
69
+ "To promote a server, run:",
70
+ " claude mcp add --scope user <server-name> <config>",
71
+ "Then remove the duplicate entries from each project's .mcp.json.",
72
+ ].join("\n");
73
+ },
74
+ "mcp-redundant"(meta) {
75
+ const list = meta.servers.map((s) => `- ${s.name}: remove from ${s.projects.join(", ")}`);
76
+ return [
77
+ "These MCP servers are configured globally AND redundantly in project .mcp.json:",
78
+ ...list,
79
+ "",
80
+ "The global config already covers all projects. Remove the listed project-level entries.",
81
+ ].join("\n");
82
+ },
83
+ "mcp-recommendations"(meta) {
84
+ const list = meta.servers.map(
85
+ (s) =>
86
+ `- ${s.name} — ${s.reasons.join(", ")}` +
87
+ (s.installCommand?.trim() ? `\n ${s.installCommand.trim()}` : ""),
88
+ );
89
+ return [
90
+ "Based on your tech stacks, these MCP servers would be useful:",
91
+ ...list,
92
+ "",
93
+ "Run any install command above to add a server. Which ones interest you?",
94
+ ].join("\n");
95
+ },
96
+ "shared-skills"(meta) {
97
+ const list = meta.skills.map((s) => `- ${s.name} (relevant in ${s.repoCount} repos)`);
98
+ return [
99
+ "These skills are relevant across multiple repos and would benefit from being global:",
100
+ ...list,
101
+ "",
102
+ "To add a skill globally, copy its definition from any project's .claude/commands/ to ~/.claude/commands/.",
103
+ ].join("\n");
104
+ },
105
+ "health-quickwins"(meta) {
106
+ const list = meta.repos.map((r) => `- ${r.name} (${r.healthScore}/100): ${r.topReason}`);
107
+ return [
108
+ "These repos have easy config health improvements:",
109
+ ...list,
110
+ "",
111
+ "Pick a repo and I'll help you make the specific improvement.",
112
+ ].join("\n");
113
+ },
114
+ "insights-report"() {
115
+ return "Run `/insights` in Claude Code to generate a personalized usage report with patterns, friction points, and suggestions.";
116
+ },
41
117
  };
42
118
 
43
- /** Convert an insights array to a markdown string suitable for pasting into Claude Code. */
44
- export function insightsToMarkdown(insights) {
119
+ /** Convert insights to an actionable prompt for pasting into Claude Code. */
120
+ export function insightsToPrompt(insights) {
45
121
  if (!insights || !insights.length) return "";
46
- const lines = ["# Dashboard Insights\n"];
122
+ const sections = [];
47
123
  for (const i of insights) {
48
- const icon = INSIGHT_ICONS[i.type] || INSIGHT_ICONS.info;
49
- lines.push(`## ${icon} ${i.title}`);
50
- if (i.detail) lines.push(i.detail);
51
- if (i.action) lines.push(`**Action:** ${i.action}`);
52
- lines.push("");
124
+ const gen = i.meta?.kind && PROMPT_GENERATORS[i.meta.kind];
125
+ if (gen) {
126
+ sections.push(gen(i.meta));
127
+ } else {
128
+ const lines = [`${i.title}`];
129
+ if (i.detail) lines.push(i.detail);
130
+ if (i.action) lines.push(i.action);
131
+ sections.push(lines.join("\n"));
132
+ }
53
133
  }
54
- return lines.join("\n");
134
+ return [
135
+ "I ran the Claude Code Dashboard and found these items to address:",
136
+ ...sections.map((s, idx) => `${idx + 1}. ${s}`),
137
+ "Which of these would you like to tackle first?",
138
+ ].join("\n\n");
55
139
  }
56
140
 
57
141
  export function anonymizePath(p) {
package/src/pipeline.mjs CHANGED
@@ -446,6 +446,10 @@ export function buildDashboardData(raw) {
446
446
  .map((r) => `${r.name} (${r.drift.commitsSince} commits since config update)`)
447
447
  .join(", "),
448
448
  action: "Review and update CLAUDE.md in these repos",
449
+ meta: {
450
+ kind: "config-drift",
451
+ repos: highDriftRepos.map((r) => ({ name: r.name, commitsSince: r.drift.commitsSince })),
452
+ },
449
453
  });
450
454
  }
451
455
 
@@ -461,6 +465,10 @@ export function buildDashboardData(raw) {
461
465
  ? `Top candidates: ${withStack.map((r) => `${r.name} (${r.techStack.join(", ")})`).join(", ")}`
462
466
  : "",
463
467
  action: "Run claude-code-dashboard init --template <stack> in these repos",
468
+ meta: {
469
+ kind: "unconfigured-repos",
470
+ repos: withStack.map((r) => ({ name: r.name, techStack: r.techStack })),
471
+ },
464
472
  });
465
473
  }
466
474
  }
@@ -472,6 +480,10 @@ export function buildDashboardData(raw) {
472
480
  title: `${mcpPromotions.length} MCP server${mcpPromotions.length > 1 ? "s" : ""} could be promoted to global`,
473
481
  detail: mcpPromotions.map((p) => `${p.name} (in ${p.projects.length} projects)`).join(", "),
474
482
  action: "Add to ~/.claude/mcp_config.json for all projects",
483
+ meta: {
484
+ kind: "mcp-promotion",
485
+ servers: mcpPromotions.map((p) => ({ name: p.name, projectCount: p.projects.length })),
486
+ },
475
487
  });
476
488
  }
477
489
 
@@ -483,6 +495,10 @@ export function buildDashboardData(raw) {
483
495
  title: `${redundantMcp.length} MCP server${redundantMcp.length > 1 ? "s are" : " is"} global but also in project .mcp.json`,
484
496
  detail: redundantMcp.map((s) => `${s.name} (${s.projects.join(", ")})`).join("; "),
485
497
  action: "Remove from project .mcp.json — global config already covers all projects",
498
+ meta: {
499
+ kind: "mcp-redundant",
500
+ servers: redundantMcp.map((s) => ({ name: s.name, projects: s.projects })),
501
+ },
486
502
  });
487
503
  }
488
504
 
@@ -495,7 +511,15 @@ export function buildDashboardData(raw) {
495
511
  .slice(0, 3)
496
512
  .map((s) => `${s.name} (${s.reasons.join(", ")})`)
497
513
  .join(", "),
498
- action: "Check the Skills & MCP tab for install commands",
514
+ action: "Check the Config tab for install commands",
515
+ meta: {
516
+ kind: "mcp-recommendations",
517
+ servers: recommendedMcpServers.slice(0, 5).map((s) => ({
518
+ name: s.name,
519
+ installCommand: s.installCommand,
520
+ reasons: s.reasons,
521
+ })),
522
+ },
499
523
  });
500
524
  }
501
525
 
@@ -518,6 +542,10 @@ export function buildDashboardData(raw) {
518
542
  title: `${widelyRelevant.length} skill${widelyRelevant.length > 1 ? "s" : ""} relevant across 3+ repos`,
519
543
  detail: top.map(([name, repos]) => `${name} (${repos.length} repos)`).join(", "),
520
544
  action: "Consider adding these skills to your global config",
545
+ meta: {
546
+ kind: "shared-skills",
547
+ skills: top.map(([name, repos]) => ({ name, repoCount: repos.length })),
548
+ },
521
549
  });
522
550
  }
523
551
 
@@ -534,6 +562,14 @@ export function buildDashboardData(raw) {
534
562
  .map((r) => `${r.name} (${r.healthScore}/100): ${r.healthReasons[0]}`)
535
563
  .join("; "),
536
564
  action: "Small changes for measurable improvement",
565
+ meta: {
566
+ kind: "health-quickwins",
567
+ repos: quickWinRepos.map((r) => ({
568
+ name: r.name,
569
+ healthScore: r.healthScore,
570
+ topReason: r.healthReasons[0],
571
+ })),
572
+ },
537
573
  });
538
574
  }
539
575
 
@@ -544,6 +580,7 @@ export function buildDashboardData(raw) {
544
580
  title: "Generate your Claude Code Insights report",
545
581
  detail: "Get personalized usage patterns, friction points, and feature suggestions",
546
582
  action: "Run /insights in Claude Code",
583
+ meta: { kind: "insights-report" },
547
584
  });
548
585
  }
549
586
 
package/src/sections.mjs CHANGED
@@ -21,15 +21,33 @@ export function renderSkillsCard(globalSkills) {
21
21
  </div>`;
22
22
  }
23
23
 
24
+ export function renderMcpRecommendedCard(recommendedMcpServers) {
25
+ if (!recommendedMcpServers.length) return "";
26
+ return `<div class="card">
27
+ <h2>Recommended MCP Servers <span class="n">${recommendedMcpServers.length}</span></h2>
28
+ ${recommendedMcpServers
29
+ .map(
30
+ (s) =>
31
+ `<div class="mcp-recommended"><span class="mcp-name">${esc(s.name)}</span> <span class="mcp-rec-badge">recommended</span>` +
32
+ (s.description ? `<div class="mcp-desc">${esc(s.description)}</div>` : "") +
33
+ (s.reasons && s.reasons.length
34
+ ? `<div class="mcp-reason">${s.reasons.map((r) => esc(r)).join(", ")}</div>`
35
+ : "") +
36
+ (s.installCommand ? `<code class="mcp-install">${esc(s.installCommand)}</code>` : "") +
37
+ `</div>`,
38
+ )
39
+ .join("\n ")}
40
+ </div>`;
41
+ }
42
+
24
43
  export function renderMcpCard(
25
44
  mcpSummary,
26
45
  mcpPromotions,
27
46
  formerMcpServers,
28
- recommendedMcpServers,
29
47
  availableMcpServers,
30
48
  registryTotal,
31
49
  ) {
32
- if (!mcpSummary.length && !recommendedMcpServers.length && !availableMcpServers.length) return "";
50
+ if (!mcpSummary.length && !availableMcpServers.length) return "";
33
51
  const rows = mcpSummary
34
52
  .map((s) => {
35
53
  const disabledClass = s.disabledIn > 0 ? " mcp-disabled" : "";
@@ -69,24 +87,6 @@ export function renderMcpCard(
69
87
  })
70
88
  .join("\n ")}`
71
89
  : "";
72
- const recommendedHtml = recommendedMcpServers.length
73
- ? `<details class="mcp-section"${recommendedMcpServers.length <= 5 ? " open" : ""}>
74
- <summary class="label" style="cursor:pointer;margin-top:.75rem">Recommended <span class="cat-n">${recommendedMcpServers.length}</span></summary>
75
- ${recommendedMcpServers
76
- .map(
77
- (s) =>
78
- `<div class="mcp-recommended"><span class="mcp-name">${esc(s.name)}</span> <span class="mcp-rec-badge">recommended</span>` +
79
- (s.description ? `<div class="mcp-desc">${esc(s.description)}</div>` : "") +
80
- (s.reasons && s.reasons.length
81
- ? `<div class="mcp-reason">${s.reasons.map((r) => esc(r)).join(", ")}</div>`
82
- : "") +
83
- (s.installCommand ? `<code class="mcp-install">${esc(s.installCommand)}</code>` : "") +
84
- `</div>`,
85
- )
86
- .join("\n ")}
87
- </details>`
88
- : "";
89
-
90
90
  const availableHtml = availableMcpServers.length
91
91
  ? `<details class="mcp-section">
92
92
  <summary class="label" style="cursor:pointer;margin-top:.75rem">Available <span class="cat-n">${availableMcpServers.length}</span></summary>
@@ -112,7 +112,6 @@ export function renderMcpCard(
112
112
  ${rows}
113
113
  ${promoteHtml}
114
114
  ${formerHtml}
115
- ${recommendedHtml}
116
115
  ${availableHtml}
117
116
  ${registryNote}
118
117
  </div>`;
@@ -378,13 +377,13 @@ export function renderReferenceCard() {
378
377
  </div>`;
379
378
  }
380
379
 
381
- export function renderInsightsCard(insights, markdown) {
380
+ export function renderInsightsCard(insights, prompt) {
382
381
  if (!insights || !insights.length) return "";
383
- const mdAttr = markdown ? ` data-markdown="${esc(markdown)}"` : "";
384
- return `<div class="card insight-card"${mdAttr}>
382
+ const promptAttr = prompt ? ` data-prompt="${esc(prompt)}"` : "";
383
+ return `<div class="card insight-card"${promptAttr}>
385
384
  <div class="card-header">
386
385
  <h2>Insights <span class="n">${insights.length}</span></h2>
387
- ${markdown ? `<button class="copy-md-btn" title="Copy as Markdown">&#128203; copy markdown</button>` : ""}
386
+ ${prompt ? `<button class="copy-prompt-btn" title="Copy as a prompt for Claude Code">&#128203; copy as prompt</button>` : ""}
388
387
  </div>
389
388
  ${insights
390
389
  .map(
@@ -437,29 +436,19 @@ export function renderInsightsReportCard(insightsReport) {
437
436
  }
438
437
 
439
438
  export function renderStatsBar(data) {
440
- const {
441
- coveragePct,
442
- configuredCount,
443
- totalRepos,
444
- avgHealth,
445
- globalCmds,
446
- globalSkills,
447
- totalRepoCmds,
448
- mcpCount,
449
- driftCount,
450
- ccusageData,
451
- usageAnalytics,
452
- } = data;
439
+ const { coveragePct, configuredCount, totalRepos, avgHealth, driftCount, ccusageData } = data;
440
+ const driftStat =
441
+ driftCount > 0
442
+ ? `<div class="stat" data-nav="repos" data-section="repo-grid" title="View drifting repos" style="border-color:#f8717133"><b style="color:var(--red)">${driftCount}</b><span>Drifting Repos</span></div>`
443
+ : "";
444
+ const spendStat = ccusageData
445
+ ? `<div class="stat" data-nav="analytics" data-section="section-activity" title="View analytics" style="border-color:#4ade8033"><b style="color:var(--green)">$${Math.round(Number(ccusageData.totals.totalCost) || 0).toLocaleString()}</b><span>Total Spent</span></div>`
446
+ : "";
453
447
  return `<div class="stats">
454
448
  <div class="stat coverage" data-nav="repos" data-section="repo-grid" title="View repos"><b>${coveragePct}%</b><span>Coverage (${configuredCount}/${totalRepos})</span></div>
455
449
  <div class="stat" data-nav="repos" data-section="repo-grid" title="View repos" style="${avgHealth >= 70 ? "border-color:#4ade8033" : avgHealth >= 40 ? "border-color:#fbbf2433" : "border-color:#f8717133"}"><b style="color:${healthScoreColor(avgHealth)}">${avgHealth}</b><span>Avg Health</span></div>
456
- <div class="stat" data-nav="overview" data-section="section-commands" title="View commands"><b>${globalCmds.length}</b><span>Global Commands</span></div>
457
- <div class="stat" data-nav="skills-mcp" data-section="section-skills" title="View skills"><b>${globalSkills.length}</b><span>Skills</span></div>
458
- <div class="stat" data-nav="repos" data-section="repo-grid" title="View repos"><b>${totalRepoCmds}</b><span>Repo Commands</span></div>
459
- ${mcpCount > 0 ? `<div class="stat" data-nav="skills-mcp" data-section="section-mcp" title="View MCP servers"><b>${mcpCount}</b><span>MCP Servers</span></div>` : ""}
460
- ${driftCount > 0 ? `<div class="stat" data-nav="repos" data-section="repo-grid" title="View drifting repos" style="border-color:#f8717133"><b style="color:var(--red)">${driftCount}</b><span>Drifting Repos</span></div>` : ""}
461
- ${ccusageData ? `<div class="stat" data-nav="analytics" data-section="section-activity" title="View analytics" style="border-color:#4ade8033"><b style="color:var(--green)">$${Math.round(Number(ccusageData.totals.totalCost) || 0).toLocaleString()}</b><span>Total Spent</span></div>` : ""}
462
- ${ccusageData ? `<div class="stat" data-nav="analytics" data-section="section-activity" title="View analytics"><b>${formatTokens(ccusageData.totals.totalTokens).replace(" tokens", "")}</b><span>Total Tokens</span></div>` : ""}
463
- ${usageAnalytics.heavySessions > 0 ? `<div class="stat" data-nav="analytics" data-section="section-activity" title="View analytics"><b>${usageAnalytics.heavySessions}</b><span>Heavy Sessions</span></div>` : ""}
450
+ <div class="stat" data-nav="repos" data-section="repo-grid" title="View repos"><b>${totalRepos}</b><span>Repos</span></div>
451
+ ${driftStat}
452
+ ${spendStat}
464
453
  </div>`;
465
454
  }
@@ -4,9 +4,9 @@
4
4
  --surface2: #1a1a1a;
5
5
  --border: #262626;
6
6
  --text: #e5e5e5;
7
- --text-dim: #777;
7
+ --text-dim: #999;
8
8
  --accent: #c4956a;
9
- --accent-dim: #8b6a4a;
9
+ --accent-dim: #b08a60;
10
10
  --green: #4ade80;
11
11
  --blue: #60a5fa;
12
12
  --purple: #a78bfa;
@@ -19,7 +19,7 @@
19
19
  --surface2: #f0f0f0;
20
20
  --border: #e0e0e0;
21
21
  --text: #1a1a1a;
22
- --text-dim: #666;
22
+ --text-dim: #555;
23
23
  --accent: #9b6b47;
24
24
  --accent-dim: #b8956e;
25
25
  --green: #16a34a;
@@ -643,7 +643,7 @@ details.cmd-detail > summary::-webkit-details-marker {
643
643
  .card-header h2 {
644
644
  margin-bottom: 0;
645
645
  }
646
- .copy-md-btn {
646
+ .copy-prompt-btn {
647
647
  background: var(--surface2);
648
648
  border: 1px solid var(--border);
649
649
  border-radius: 5px;
@@ -656,7 +656,7 @@ details.cmd-detail > summary::-webkit-details-marker {
656
656
  color 0.15s;
657
657
  white-space: nowrap;
658
658
  }
659
- .copy-md-btn:hover {
659
+ .copy-prompt-btn:hover {
660
660
  border-color: var(--accent-dim);
661
661
  color: var(--text);
662
662
  }
@@ -797,7 +797,8 @@ details.cmd-detail > summary::-webkit-details-marker {
797
797
  margin-top: 0.5rem;
798
798
  font-size: 0.72rem;
799
799
  color: var(--accent);
800
- text-decoration: none;
800
+ text-decoration: underline;
801
+ text-underline-offset: 2px;
801
802
  }
802
803
  .report-link:hover {
803
804
  text-decoration: underline;
@@ -1253,7 +1254,7 @@ details.cmd-detail > summary::-webkit-details-marker {
1253
1254
  }
1254
1255
  .unconfigured-item .upath {
1255
1256
  font-size: 0.6rem;
1256
- color: #555;
1257
+ color: var(--text-dim);
1257
1258
  display: block;
1258
1259
  overflow: hidden;
1259
1260
  text-overflow: ellipsis;
@@ -13,20 +13,21 @@
13
13
 
14
14
  <!-- {{STATS_BAR}} -->
15
15
 
16
+ <main>
16
17
  <nav class="tab-nav">
17
- <button class="tab-btn active" data-tab="overview">Overview</button>
18
- <button class="tab-btn" data-tab="skills-mcp">Skills & MCP</button>
18
+ <button class="tab-btn active" data-tab="home">Home</button>
19
+ <button class="tab-btn" data-tab="config">Config</button>
19
20
  <button class="tab-btn" data-tab="analytics">Analytics</button>
20
21
  <button class="tab-btn" data-tab="repos">Repos</button>
21
22
  <button class="tab-btn" data-tab="reference">Reference</button>
22
23
  </nav>
23
24
 
24
- <div class="tab-content active" id="tab-overview">
25
- <!-- {{TAB_OVERVIEW}} -->
25
+ <div class="tab-content active" id="tab-home">
26
+ <!-- {{TAB_HOME}} -->
26
27
  </div>
27
28
 
28
- <div class="tab-content" id="tab-skills-mcp">
29
- <!-- {{TAB_SKILLS_MCP}} -->
29
+ <div class="tab-content" id="tab-config">
30
+ <!-- {{TAB_CONFIG}} -->
30
31
  </div>
31
32
 
32
33
  <div class="tab-content" id="tab-analytics">
@@ -42,6 +43,7 @@
42
43
  </div>
43
44
 
44
45
  <!-- {{FOOTER}} -->
46
+ </main>
45
47
 
46
48
  <div class="chart-tooltip" id="chart-tooltip"></div>
47
49
  <script>
@@ -133,19 +133,19 @@ function showToast(msg) {
133
133
  }, 2000);
134
134
  }
135
135
 
136
- // ── Copy Markdown button ────────────────────────────────────
137
- document.querySelectorAll(".copy-md-btn").forEach(function (btn) {
136
+ // ── Copy as Prompt button ────────────────────────────────────
137
+ document.querySelectorAll(".copy-prompt-btn").forEach(function (btn) {
138
138
  btn.addEventListener("click", function () {
139
- var card = btn.closest("[data-markdown]");
139
+ var card = btn.closest("[data-prompt]");
140
140
  if (!card) return;
141
- var md = card.dataset.markdown;
141
+ var prompt = card.dataset.prompt;
142
142
  navigator.clipboard
143
- .writeText(md)
143
+ .writeText(prompt)
144
144
  .then(function () {
145
- showToast("Markdown copied to clipboard");
145
+ showToast("Prompt copied \u2014 paste into Claude Code");
146
146
  })
147
147
  .catch(function () {
148
- showToast("Copy failed \u2014 use browser copy from the insights card");
148
+ showToast("Copy failed \u2014 try selecting the text manually");
149
149
  });
150
150
  });
151
151
  });