@viren/claude-code-dashboard 0.0.5 → 0.0.6

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
@@ -212,6 +212,16 @@ If no directories are listed, the entire home directory is scanned (depth 5).
212
212
  - Node.js 18+
213
213
  - Git (for freshness timestamps and drift detection)
214
214
 
215
+ ## Roadmap
216
+
217
+ Completed: v0.1 (foundation), v0.2 (intelligence layer), v0.3 (recommendations engine), v0.4 (config templates), v0.5 (control center).
218
+
219
+ **Up next:**
220
+
221
+ - [ ] Org-wide dashboard — scan multiple users' configs for team visibility
222
+
223
+ See [issues](https://github.com/VirenMohindra/claude-code-dashboard/issues) for feature requests.
224
+
215
225
  ## Privacy
216
226
 
217
227
  The generated HTML file contains:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viren/claude-code-dashboard",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
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,7 +2,7 @@ import { readFileSync } from "fs";
2
2
  import { fileURLToPath } from "url";
3
3
  import { dirname, join } from "path";
4
4
 
5
- import { esc } from "./helpers.mjs";
5
+ import { esc, insightsToMarkdown } from "./helpers.mjs";
6
6
  import { VERSION, REPO_URL } from "./constants.mjs";
7
7
  import { renderCmd, renderRule, renderRepoCard } from "./render.mjs";
8
8
  import {
@@ -64,8 +64,11 @@ export function generateDashboardHtml(data) {
64
64
  // ── Build section HTML fragments ──────────────────────────────────────────
65
65
 
66
66
  const header = `<h1>claude code dashboard</h1>
67
- <button id="theme-toggle" class="theme-toggle" title="Toggle light/dark mode" aria-label="Toggle theme"><span class="theme-icon"></span></button>
68
- <p class="sub">generated ${timestamp} · run <code>claude-code-dashboard</code> to refresh · <a href="${esc(REPO_URL)}" target="_blank" rel="noopener" style="color:var(--accent);text-decoration:none">v${esc(VERSION)}</a></p>`;
67
+ <div class="header-actions">
68
+ <button id="refresh-btn" class="header-btn" title="Copy refresh command to clipboard" aria-label="Copy refresh command">&#8635; refresh</button>
69
+ <button id="theme-toggle" class="theme-toggle" title="Toggle light/dark mode" aria-label="Toggle theme"><span class="theme-icon"></span></button>
70
+ </div>
71
+ <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>`;
69
72
 
70
73
  const statsBar = renderStatsBar(data);
71
74
 
@@ -80,7 +83,8 @@ export function generateDashboardHtml(data) {
80
83
  ${globalRules.map((r) => renderRule(r)).join("\n ")}
81
84
  </div>
82
85
  </div>`;
83
- const insightsHtml = renderInsightsCard(insights);
86
+ const insightsMarkdown = insightsToMarkdown(insights);
87
+ const insightsHtml = renderInsightsCard(insights, insightsMarkdown);
84
88
  const chainsHtml = renderChainsCard(chains);
85
89
  const consolidationHtml = renderConsolidationCard(consolidationGroups);
86
90
  const tabOverview = `${overviewCommands}\n ${insightsHtml}\n ${chainsHtml}\n ${consolidationHtml}`;
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.5";
4
+ export const VERSION = "0.0.6";
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,6 +33,27 @@ 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",
41
+ };
42
+
43
+ /** Convert an insights array to a markdown string suitable for pasting into Claude Code. */
44
+ export function insightsToMarkdown(insights) {
45
+ if (!insights || !insights.length) return "";
46
+ const lines = ["# Dashboard Insights\n"];
47
+ 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("");
53
+ }
54
+ return lines.join("\n");
55
+ }
56
+
36
57
  export function anonymizePath(p) {
37
58
  return p
38
59
  .replace(/^\/Users\/[^/]+\//, "~/")
package/src/sections.mjs CHANGED
@@ -330,10 +330,14 @@ export function renderReferenceCard() {
330
330
  </div>`;
331
331
  }
332
332
 
333
- export function renderInsightsCard(insights) {
333
+ export function renderInsightsCard(insights, markdown) {
334
334
  if (!insights || !insights.length) return "";
335
- return `<div class="card insight-card">
336
- <h2>Insights <span class="n">${insights.length}</span></h2>
335
+ const mdAttr = markdown ? ` data-markdown="${esc(markdown)}"` : "";
336
+ return `<div class="card insight-card"${mdAttr}>
337
+ <div class="card-header">
338
+ <h2>Insights <span class="n">${insights.length}</span></h2>
339
+ ${markdown ? `<button class="copy-md-btn" title="Copy as Markdown">&#128203; copy markdown</button>` : ""}
340
+ </div>
337
341
  ${insights
338
342
  .map(
339
343
  (i) =>
@@ -52,6 +52,31 @@ h1 {
52
52
  color: var(--accent);
53
53
  margin-bottom: 0.2rem;
54
54
  }
55
+ .header-actions {
56
+ position: fixed;
57
+ top: 1rem;
58
+ right: 1rem;
59
+ z-index: 100;
60
+ display: flex;
61
+ gap: 0.4rem;
62
+ align-items: center;
63
+ }
64
+ .header-btn {
65
+ background: var(--surface);
66
+ border: 1px solid var(--border);
67
+ border-radius: 8px;
68
+ padding: 0.4rem 0.6rem;
69
+ cursor: pointer;
70
+ color: var(--text-dim);
71
+ font-size: 0.75rem;
72
+ transition:
73
+ background 0.15s,
74
+ border-color 0.15s;
75
+ }
76
+ .header-btn:hover {
77
+ border-color: var(--accent-dim);
78
+ color: var(--text);
79
+ }
55
80
  .sub {
56
81
  color: var(--text-dim);
57
82
  font-size: 0.78rem;
@@ -609,6 +634,54 @@ details.cmd-detail > summary::-webkit-details-marker {
609
634
  color: var(--accent);
610
635
  }
611
636
 
637
+ .card-header {
638
+ display: flex;
639
+ align-items: center;
640
+ justify-content: space-between;
641
+ margin-bottom: 0.5rem;
642
+ }
643
+ .card-header h2 {
644
+ margin-bottom: 0;
645
+ }
646
+ .copy-md-btn {
647
+ background: var(--surface2);
648
+ border: 1px solid var(--border);
649
+ border-radius: 5px;
650
+ padding: 0.25rem 0.5rem;
651
+ font-size: 0.65rem;
652
+ color: var(--text-dim);
653
+ cursor: pointer;
654
+ transition:
655
+ border-color 0.15s,
656
+ color 0.15s;
657
+ white-space: nowrap;
658
+ }
659
+ .copy-md-btn:hover {
660
+ border-color: var(--accent-dim);
661
+ color: var(--text);
662
+ }
663
+ .copy-toast {
664
+ position: fixed;
665
+ bottom: 1.5rem;
666
+ left: 50%;
667
+ transform: translateX(-50%) translateY(20px);
668
+ background: var(--surface);
669
+ border: 1px solid var(--accent-dim);
670
+ color: var(--text);
671
+ padding: 0.5rem 1rem;
672
+ border-radius: 8px;
673
+ font-size: 0.75rem;
674
+ opacity: 0;
675
+ pointer-events: none;
676
+ transition:
677
+ opacity 0.2s,
678
+ transform 0.2s;
679
+ z-index: 200;
680
+ }
681
+ .copy-toast.visible {
682
+ opacity: 1;
683
+ transform: translateX(-50%) translateY(0);
684
+ }
612
685
  .insight-card {
613
686
  margin-bottom: 1.25rem;
614
687
  }
@@ -1133,10 +1206,6 @@ details.cmd-detail > summary::-webkit-details-marker {
1133
1206
  }
1134
1207
 
1135
1208
  .theme-toggle {
1136
- position: fixed;
1137
- top: 1rem;
1138
- right: 1rem;
1139
- z-index: 100;
1140
1209
  background: var(--surface);
1141
1210
  border: 1px solid var(--border);
1142
1211
  border-radius: 8px;
@@ -119,6 +119,52 @@ groupSelect.addEventListener("change", function () {
119
119
  });
120
120
  });
121
121
 
122
+ // ── Toast helper ────────────────────────────────────────────
123
+ var toast = document.createElement("div");
124
+ toast.className = "copy-toast";
125
+ document.body.appendChild(toast);
126
+ var toastTimer;
127
+ function showToast(msg) {
128
+ toast.textContent = msg;
129
+ toast.classList.add("visible");
130
+ clearTimeout(toastTimer);
131
+ toastTimer = setTimeout(function () {
132
+ toast.classList.remove("visible");
133
+ }, 2000);
134
+ }
135
+
136
+ // ── Copy Markdown button ────────────────────────────────────
137
+ document.querySelectorAll(".copy-md-btn").forEach(function (btn) {
138
+ btn.addEventListener("click", function () {
139
+ var card = btn.closest("[data-markdown]");
140
+ if (!card) return;
141
+ var md = card.dataset.markdown;
142
+ navigator.clipboard
143
+ .writeText(md)
144
+ .then(function () {
145
+ showToast("Markdown copied to clipboard");
146
+ })
147
+ .catch(function () {
148
+ showToast("Copy failed \u2014 use browser copy from the insights card");
149
+ });
150
+ });
151
+ });
152
+
153
+ // ── Refresh button ──────────────────────────────────────────
154
+ var refreshBtn = document.getElementById("refresh-btn");
155
+ if (refreshBtn) {
156
+ refreshBtn.addEventListener("click", function () {
157
+ navigator.clipboard
158
+ .writeText("claude-code-dashboard --open")
159
+ .then(function () {
160
+ showToast("Copied \u2014 paste in terminal to refresh");
161
+ })
162
+ .catch(function () {
163
+ showToast("Run: claude-code-dashboard --open");
164
+ });
165
+ });
166
+ }
167
+
122
168
  // Custom tooltip for heatmap cells and peak bars
123
169
  var tip = document.getElementById("chart-tooltip");
124
170
  document.addEventListener("mouseover", function (e) {