@viren/claude-code-dashboard 0.0.6 → 0.0.8
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 +2 -0
- package/generate-dashboard.mjs +251 -619
- package/package.json +1 -1
- package/src/analysis.mjs +19 -12
- package/src/assembler.mjs +4 -1
- package/src/cli.mjs +7 -2
- package/src/constants.mjs +39 -1
- package/src/demo.mjs +269 -248
- package/src/mcp.mjs +97 -2
- package/src/pipeline.mjs +596 -0
- package/src/sections.mjs +50 -2
- package/template/dashboard.css +78 -0
- package/template/dashboard.js +18 -0
package/package.json
CHANGED
package/src/analysis.mjs
CHANGED
|
@@ -90,22 +90,29 @@ export function detectTechStack(repoDir) {
|
|
|
90
90
|
return { stacks: [...stacks] };
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
export function
|
|
94
|
-
if (
|
|
93
|
+
export function classifyDrift(commitCount) {
|
|
94
|
+
if (commitCount === null || commitCount === undefined || commitCount < 0) {
|
|
95
|
+
return { level: "unknown", commitsSince: 0 };
|
|
96
|
+
}
|
|
97
|
+
const n = Math.max(0, Number(commitCount) || 0);
|
|
98
|
+
if (n === 0) return { level: "synced", commitsSince: 0 };
|
|
99
|
+
if (n <= 5) return { level: "low", commitsSince: n };
|
|
100
|
+
if (n <= 20) return { level: "medium", commitsSince: n };
|
|
101
|
+
return { level: "high", commitsSince: n };
|
|
102
|
+
}
|
|
95
103
|
|
|
96
|
-
|
|
104
|
+
/** Count commits since config was last updated. Returns null if unknown. */
|
|
105
|
+
export function getGitRevCount(repoDir, configTimestamp) {
|
|
106
|
+
if (!configTimestamp) return null;
|
|
97
107
|
const countStr = gitCmd(repoDir, "rev-list", "--count", `--since=${configTimestamp}`, "HEAD");
|
|
98
|
-
if (!countStr) return
|
|
99
|
-
|
|
108
|
+
if (!countStr) return null;
|
|
100
109
|
const parsed = Number(countStr);
|
|
101
|
-
if (!Number.isFinite(parsed)) return
|
|
102
|
-
|
|
103
|
-
|
|
110
|
+
if (!Number.isFinite(parsed)) return null;
|
|
111
|
+
return Math.max(0, parsed - 1); // -1 to exclude the config commit itself
|
|
112
|
+
}
|
|
104
113
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (commitsSince <= 20) return { level: "medium", commitsSince };
|
|
108
|
-
return { level: "high", commitsSince };
|
|
114
|
+
export function computeDrift(repoDir, configTimestamp) {
|
|
115
|
+
return classifyDrift(getGitRevCount(repoDir, configTimestamp));
|
|
109
116
|
}
|
|
110
117
|
|
|
111
118
|
export function findExemplar(stack, configuredRepos) {
|
package/src/assembler.mjs
CHANGED
|
@@ -47,6 +47,9 @@ export function generateDashboardHtml(data) {
|
|
|
47
47
|
mcpSummary,
|
|
48
48
|
mcpPromotions,
|
|
49
49
|
formerMcpServers,
|
|
50
|
+
recommendedMcpServers,
|
|
51
|
+
availableMcpServers,
|
|
52
|
+
registryTotal,
|
|
50
53
|
consolidationGroups,
|
|
51
54
|
usageAnalytics,
|
|
52
55
|
ccusageData,
|
|
@@ -90,7 +93,7 @@ export function generateDashboardHtml(data) {
|
|
|
90
93
|
const tabOverview = `${overviewCommands}\n ${insightsHtml}\n ${chainsHtml}\n ${consolidationHtml}`;
|
|
91
94
|
|
|
92
95
|
// Skills & MCP tab
|
|
93
|
-
const tabSkillsMcp = `${renderSkillsCard(globalSkills)}\n ${renderMcpCard(mcpSummary, mcpPromotions, formerMcpServers)}`;
|
|
96
|
+
const tabSkillsMcp = `${renderSkillsCard(globalSkills)}\n ${renderMcpCard(mcpSummary, mcpPromotions, formerMcpServers, recommendedMcpServers, availableMcpServers, registryTotal)}`;
|
|
94
97
|
|
|
95
98
|
// Analytics tab
|
|
96
99
|
const insightsReportHtml = renderInsightsReportCard(insightsReport);
|
package/src/cli.mjs
CHANGED
|
@@ -15,6 +15,7 @@ export function parseArgs(argv) {
|
|
|
15
15
|
anonymize: false,
|
|
16
16
|
demo: false,
|
|
17
17
|
completions: false,
|
|
18
|
+
offline: false,
|
|
18
19
|
};
|
|
19
20
|
let i = 2; // skip node + script
|
|
20
21
|
if (argv[2] === "init") {
|
|
@@ -46,6 +47,7 @@ Options:
|
|
|
46
47
|
--watch Regenerate on file changes
|
|
47
48
|
--diff Show changes since last generation
|
|
48
49
|
--anonymize Anonymize all data for shareable export
|
|
50
|
+
--offline Skip network fetches (registry, etc.)
|
|
49
51
|
--demo Generate dashboard with sample data (no scanning)
|
|
50
52
|
--completions Output shell completion script for bash/zsh
|
|
51
53
|
--version, -v Show version
|
|
@@ -113,6 +115,9 @@ Config file: ~/.claude/dashboard.conf
|
|
|
113
115
|
case "--anonymize":
|
|
114
116
|
args.anonymize = true;
|
|
115
117
|
break;
|
|
118
|
+
case "--offline":
|
|
119
|
+
args.offline = true;
|
|
120
|
+
break;
|
|
116
121
|
case "--demo":
|
|
117
122
|
args.demo = true;
|
|
118
123
|
break;
|
|
@@ -133,11 +138,11 @@ export function generateCompletions() {
|
|
|
133
138
|
# eval "$(claude-code-dashboard --completions)"
|
|
134
139
|
if [ -n "$ZSH_VERSION" ]; then
|
|
135
140
|
_claude_code_dashboard() {
|
|
136
|
-
local -a opts; opts=(init lint --output --open --no-open --json --catalog --quiet --watch --diff --anonymize --demo --completions --help --version)
|
|
141
|
+
local -a opts; opts=(init lint --output --open --no-open --json --catalog --quiet --watch --diff --anonymize --offline --demo --completions --help --version)
|
|
137
142
|
if (( CURRENT == 2 )); then _describe 'option' opts; fi
|
|
138
143
|
}; compdef _claude_code_dashboard claude-code-dashboard
|
|
139
144
|
elif [ -n "$BASH_VERSION" ]; then
|
|
140
|
-
_claude_code_dashboard() { COMPREPLY=( $(compgen -W "init lint --output --open --no-open --json --catalog --quiet --watch --diff --anonymize --demo --completions --help --version" -- "\${COMP_WORDS[COMP_CWORD]}") ); }
|
|
145
|
+
_claude_code_dashboard() { COMPREPLY=( $(compgen -W "init lint --output --open --no-open --json --catalog --quiet --watch --diff --anonymize --offline --demo --completions --help --version" -- "\${COMP_WORDS[COMP_CWORD]}") ); }
|
|
141
146
|
complete -F _claude_code_dashboard claude-code-dashboard
|
|
142
147
|
fi`);
|
|
143
148
|
process.exit(0);
|
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.
|
|
4
|
+
export const VERSION = "0.0.8";
|
|
5
5
|
export const REPO_URL = "https://github.com/VirenMohindra/claude-code-dashboard";
|
|
6
6
|
|
|
7
7
|
export const HOME = homedir();
|
|
@@ -98,6 +98,44 @@ export const SKILL_CATEGORIES = {
|
|
|
98
98
|
"project-specific": ["storybook", "react-native"],
|
|
99
99
|
};
|
|
100
100
|
|
|
101
|
+
export const MCP_REGISTRY_URL =
|
|
102
|
+
"https://api.anthropic.com/mcp-registry/v0/servers?visibility=commercial&limit=100";
|
|
103
|
+
export const MCP_REGISTRY_TTL_MS = 24 * 60 * 60 * 1000; // 24h
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Maps detected tech stacks and description keywords to relevant MCP server slugs.
|
|
107
|
+
* Used by the pipeline to compute MCP recommendations.
|
|
108
|
+
*
|
|
109
|
+
* Keys: tech stack names (matching STACK_FILES values) or lowercase keywords
|
|
110
|
+
* found in repo descriptions.
|
|
111
|
+
* Values: array of MCP server slugs from the Anthropic registry.
|
|
112
|
+
*/
|
|
113
|
+
export const MCP_STACK_HINTS = {
|
|
114
|
+
// Stack-based (keys match STACK_FILES values)
|
|
115
|
+
next: ["vercel", "figma"],
|
|
116
|
+
react: ["figma"],
|
|
117
|
+
python: ["sentry"],
|
|
118
|
+
go: ["sentry"],
|
|
119
|
+
rust: ["sentry"],
|
|
120
|
+
java: ["sentry"],
|
|
121
|
+
expo: ["figma"],
|
|
122
|
+
|
|
123
|
+
// Keyword-based (matched against lowercased repo descriptions)
|
|
124
|
+
supabase: ["supabase"],
|
|
125
|
+
stripe: ["stripe"],
|
|
126
|
+
vercel: ["vercel"],
|
|
127
|
+
sentry: ["sentry"],
|
|
128
|
+
notion: ["notion"],
|
|
129
|
+
linear: ["linear"],
|
|
130
|
+
jira: ["atlassian"],
|
|
131
|
+
confluence: ["atlassian"],
|
|
132
|
+
slack: ["slack"],
|
|
133
|
+
figma: ["figma"],
|
|
134
|
+
github: ["github"],
|
|
135
|
+
huggingface: ["hugging-face"],
|
|
136
|
+
"hugging face": ["hugging-face"],
|
|
137
|
+
};
|
|
138
|
+
|
|
101
139
|
export const CATEGORY_ORDER = [
|
|
102
140
|
"workflow",
|
|
103
141
|
"code-quality",
|