@cloudstreamsoftware/claude-tools 1.0.0 → 1.1.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 +152 -37
- package/agents/INDEX.md +183 -0
- package/agents/architect.md +247 -0
- package/agents/build-error-resolver.md +555 -0
- package/agents/catalyst-deployer.md +132 -0
- package/agents/code-reviewer.md +121 -0
- package/agents/compliance-auditor.md +148 -0
- package/agents/creator-architect.md +395 -0
- package/agents/deluge-reviewer.md +98 -0
- package/agents/doc-updater.md +471 -0
- package/agents/e2e-runner.md +711 -0
- package/agents/planner.md +122 -0
- package/agents/refactor-cleaner.md +309 -0
- package/agents/security-reviewer.md +582 -0
- package/agents/tdd-guide.md +302 -0
- package/config/versions.json +63 -0
- package/dist/hooks/hooks.json +209 -0
- package/dist/index.js +47 -0
- package/dist/lib/asset-value.js +609 -0
- package/dist/lib/client-manager.js +300 -0
- package/dist/lib/command-matcher.js +242 -0
- package/dist/lib/cross-session-patterns.js +754 -0
- package/dist/lib/intent-classifier.js +1075 -0
- package/dist/lib/package-manager.js +374 -0
- package/dist/lib/recommendation-engine.js +597 -0
- package/dist/lib/session-memory.js +489 -0
- package/dist/lib/skill-effectiveness.js +486 -0
- package/dist/lib/skill-matcher.js +595 -0
- package/dist/lib/tutorial-metrics.js +242 -0
- package/dist/lib/tutorial-progress.js +209 -0
- package/dist/lib/tutorial-renderer.js +431 -0
- package/dist/lib/utils.js +380 -0
- package/dist/lib/verify-formatter.js +143 -0
- package/dist/lib/workflow-state.js +249 -0
- package/hooks/hooks.json +209 -0
- package/package.json +5 -1
- package/scripts/aggregate-sessions.js +290 -0
- package/scripts/branch-name-validator.js +291 -0
- package/scripts/build.js +101 -0
- package/scripts/commands/client-switch.js +231 -0
- package/scripts/deprecate-skill.js +610 -0
- package/scripts/diagnose.js +324 -0
- package/scripts/doc-freshness.js +168 -0
- package/scripts/generate-weekly-digest.js +393 -0
- package/scripts/health-check.js +270 -0
- package/scripts/hooks/credential-check.js +101 -0
- package/scripts/hooks/evaluate-session.js +81 -0
- package/scripts/hooks/pre-compact.js +66 -0
- package/scripts/hooks/prompt-analyzer.js +276 -0
- package/scripts/hooks/prompt-router.js +422 -0
- package/scripts/hooks/quality-gate-enforcer.js +371 -0
- package/scripts/hooks/session-end.js +156 -0
- package/scripts/hooks/session-start.js +195 -0
- package/scripts/hooks/skill-injector.js +333 -0
- package/scripts/hooks/suggest-compact.js +58 -0
- package/scripts/lib/asset-value.js +609 -0
- package/scripts/lib/client-manager.js +300 -0
- package/scripts/lib/command-matcher.js +242 -0
- package/scripts/lib/cross-session-patterns.js +754 -0
- package/scripts/lib/intent-classifier.js +1075 -0
- package/scripts/lib/package-manager.js +374 -0
- package/scripts/lib/recommendation-engine.js +597 -0
- package/scripts/lib/session-memory.js +489 -0
- package/scripts/lib/skill-effectiveness.js +486 -0
- package/scripts/lib/skill-matcher.js +595 -0
- package/scripts/lib/tutorial-metrics.js +242 -0
- package/scripts/lib/tutorial-progress.js +209 -0
- package/scripts/lib/tutorial-renderer.js +431 -0
- package/scripts/lib/utils.js +380 -0
- package/scripts/lib/verify-formatter.js +143 -0
- package/scripts/lib/workflow-state.js +249 -0
- package/scripts/onboard.js +363 -0
- package/scripts/quarterly-report.js +692 -0
- package/scripts/setup-package-manager.js +204 -0
- package/scripts/sync-upstream.js +391 -0
- package/scripts/test.js +108 -0
- package/scripts/tutorial-runner.js +351 -0
- package/scripts/validate-all.js +201 -0
- package/scripts/verifiers/agents.js +245 -0
- package/scripts/verifiers/config.js +186 -0
- package/scripts/verifiers/environment.js +123 -0
- package/scripts/verifiers/hooks.js +188 -0
- package/scripts/verifiers/index.js +38 -0
- package/scripts/verifiers/persistence.js +140 -0
- package/scripts/verifiers/plugin.js +215 -0
- package/scripts/verifiers/skills.js +209 -0
- package/scripts/verify-setup.js +164 -0
- package/skills/INDEX.md +157 -0
- package/skills/backend-patterns/SKILL.md +586 -0
- package/skills/backend-patterns/catalyst-patterns.md +128 -0
- package/skills/bigquery-patterns/SKILL.md +27 -0
- package/skills/bigquery-patterns/performance-optimization.md +518 -0
- package/skills/bigquery-patterns/query-patterns.md +372 -0
- package/skills/bigquery-patterns/schema-design.md +78 -0
- package/skills/cloudstream-project-template/SKILL.md +20 -0
- package/skills/cloudstream-project-template/structure.md +65 -0
- package/skills/coding-standards/SKILL.md +524 -0
- package/skills/coding-standards/deluge-standards.md +83 -0
- package/skills/compliance-patterns/SKILL.md +28 -0
- package/skills/compliance-patterns/hipaa/audit-requirements.md +251 -0
- package/skills/compliance-patterns/hipaa/baa-process.md +298 -0
- package/skills/compliance-patterns/hipaa/data-archival-strategy.md +387 -0
- package/skills/compliance-patterns/hipaa/phi-handling.md +52 -0
- package/skills/compliance-patterns/pci-dss/saq-a-requirements.md +307 -0
- package/skills/compliance-patterns/pci-dss/tokenization-patterns.md +382 -0
- package/skills/compliance-patterns/pci-dss/zoho-checkout-patterns.md +56 -0
- package/skills/compliance-patterns/soc2/access-controls.md +344 -0
- package/skills/compliance-patterns/soc2/audit-logging.md +458 -0
- package/skills/compliance-patterns/soc2/change-management.md +403 -0
- package/skills/compliance-patterns/soc2/deluge-execution-logging.md +407 -0
- package/skills/consultancy-workflows/SKILL.md +19 -0
- package/skills/consultancy-workflows/client-isolation.md +21 -0
- package/skills/consultancy-workflows/documentation-automation.md +454 -0
- package/skills/consultancy-workflows/handoff-procedures.md +257 -0
- package/skills/consultancy-workflows/knowledge-capture.md +513 -0
- package/skills/consultancy-workflows/time-tracking.md +26 -0
- package/skills/continuous-learning/SKILL.md +84 -0
- package/skills/continuous-learning/config.json +18 -0
- package/skills/continuous-learning/evaluate-session.sh +60 -0
- package/skills/continuous-learning-v2/SKILL.md +126 -0
- package/skills/continuous-learning-v2/config.json +61 -0
- package/skills/frontend-patterns/SKILL.md +635 -0
- package/skills/frontend-patterns/zoho-widget-patterns.md +103 -0
- package/skills/gcp-data-engineering/SKILL.md +36 -0
- package/skills/gcp-data-engineering/bigquery/performance-optimization.md +337 -0
- package/skills/gcp-data-engineering/dataflow/error-handling.md +496 -0
- package/skills/gcp-data-engineering/dataflow/pipeline-patterns.md +444 -0
- package/skills/gcp-data-engineering/dbt/model-organization.md +63 -0
- package/skills/gcp-data-engineering/dbt/testing-patterns.md +503 -0
- package/skills/gcp-data-engineering/medallion-architecture/bronze-layer.md +60 -0
- package/skills/gcp-data-engineering/medallion-architecture/gold-layer.md +311 -0
- package/skills/gcp-data-engineering/medallion-architecture/layer-transitions.md +517 -0
- package/skills/gcp-data-engineering/medallion-architecture/silver-layer.md +305 -0
- package/skills/gcp-data-engineering/zoho-to-gcp/data-extraction.md +543 -0
- package/skills/gcp-data-engineering/zoho-to-gcp/real-time-vs-batch.md +337 -0
- package/skills/security-review/SKILL.md +498 -0
- package/skills/security-review/compliance-checklist.md +53 -0
- package/skills/strategic-compact/SKILL.md +67 -0
- package/skills/tdd-workflow/SKILL.md +413 -0
- package/skills/tdd-workflow/zoho-testing.md +124 -0
- package/skills/tutorial/SKILL.md +249 -0
- package/skills/tutorial/docs/ACCESSIBILITY.md +169 -0
- package/skills/tutorial/lessons/00-philosophy-and-workflow.md +198 -0
- package/skills/tutorial/lessons/01-basics.md +81 -0
- package/skills/tutorial/lessons/02-training.md +86 -0
- package/skills/tutorial/lessons/03-commands.md +109 -0
- package/skills/tutorial/lessons/04-workflows.md +115 -0
- package/skills/tutorial/lessons/05-compliance.md +116 -0
- package/skills/tutorial/lessons/06-zoho.md +121 -0
- package/skills/tutorial/lessons/07-hooks-system.md +277 -0
- package/skills/tutorial/lessons/08-mcp-servers.md +316 -0
- package/skills/tutorial/lessons/09-client-management.md +215 -0
- package/skills/tutorial/lessons/10-testing-e2e.md +260 -0
- package/skills/tutorial/lessons/11-skills-deep-dive.md +272 -0
- package/skills/tutorial/lessons/12-rules-system.md +326 -0
- package/skills/tutorial/lessons/13-golden-standard-graduation.md +213 -0
- package/skills/tutorial/lessons/14-fork-setup-and-sync.md +312 -0
- package/skills/tutorial/lessons/15-living-examples-system.md +221 -0
- package/skills/tutorial/tracks/accelerated/README.md +134 -0
- package/skills/tutorial/tracks/accelerated/assessment/checkpoint-1.md +161 -0
- package/skills/tutorial/tracks/accelerated/assessment/checkpoint-2.md +175 -0
- package/skills/tutorial/tracks/accelerated/day-1-core-concepts.md +234 -0
- package/skills/tutorial/tracks/accelerated/day-2-essential-commands.md +270 -0
- package/skills/tutorial/tracks/accelerated/day-3-workflow-mastery.md +305 -0
- package/skills/tutorial/tracks/accelerated/day-4-compliance-zoho.md +304 -0
- package/skills/tutorial/tracks/accelerated/day-5-hooks-skills.md +344 -0
- package/skills/tutorial/tracks/accelerated/day-6-client-testing.md +386 -0
- package/skills/tutorial/tracks/accelerated/day-7-graduation.md +369 -0
- package/skills/zoho-patterns/CHANGELOG.md +108 -0
- package/skills/zoho-patterns/SKILL.md +446 -0
- package/skills/zoho-patterns/analytics/dashboard-patterns.md +352 -0
- package/skills/zoho-patterns/analytics/zoho-to-bigquery-pipeline.md +427 -0
- package/skills/zoho-patterns/catalyst/appsail-deployment.md +349 -0
- package/skills/zoho-patterns/catalyst/context-close-patterns.md +354 -0
- package/skills/zoho-patterns/catalyst/cron-batch-processing.md +374 -0
- package/skills/zoho-patterns/catalyst/function-patterns.md +439 -0
- package/skills/zoho-patterns/creator/form-design.md +304 -0
- package/skills/zoho-patterns/creator/publish-api-patterns.md +313 -0
- package/skills/zoho-patterns/creator/widget-integration.md +306 -0
- package/skills/zoho-patterns/creator/workflow-automation.md +253 -0
- package/skills/zoho-patterns/deluge/api-patterns.md +468 -0
- package/skills/zoho-patterns/deluge/batch-processing.md +403 -0
- package/skills/zoho-patterns/deluge/cross-app-integration.md +356 -0
- package/skills/zoho-patterns/deluge/error-handling.md +423 -0
- package/skills/zoho-patterns/deluge/syntax-reference.md +65 -0
- package/skills/zoho-patterns/integration/cors-proxy-architecture.md +426 -0
- package/skills/zoho-patterns/integration/crm-books-native-sync.md +277 -0
- package/skills/zoho-patterns/integration/oauth-token-management.md +461 -0
- package/skills/zoho-patterns/integration/zoho-flow-patterns.md +334 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Diagnose Script for Everything Claude Code
|
|
5
|
+
* Deep diagnostics for troubleshooting issues
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { getClaudeDir, getSessionsDir, readFile, findFiles, log } = require('./lib/utils');
|
|
11
|
+
|
|
12
|
+
// Status indicators
|
|
13
|
+
const OK = '[OK]';
|
|
14
|
+
const WARN = '[WARN]';
|
|
15
|
+
const FAIL = '[FAIL]';
|
|
16
|
+
|
|
17
|
+
const recommendations = [];
|
|
18
|
+
|
|
19
|
+
function padRight(str, len) {
|
|
20
|
+
return str.padEnd(len);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function addRecommendation(text) {
|
|
24
|
+
recommendations.push(text);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Configuration Checks
|
|
28
|
+
function checkJsonFile(name, filePath) {
|
|
29
|
+
if (!fs.existsSync(filePath)) {
|
|
30
|
+
return { status: WARN, message: 'Not found' };
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const content = readFile(filePath);
|
|
34
|
+
const parsed = JSON.parse(content);
|
|
35
|
+
|
|
36
|
+
// Additional validation based on file type
|
|
37
|
+
if (name === 'hooks.json' && parsed.hooks) {
|
|
38
|
+
return { status: OK, message: `Valid, ${parsed.hooks.length} hooks` };
|
|
39
|
+
}
|
|
40
|
+
if (name === 'settings.json' && parsed.mcpServers) {
|
|
41
|
+
const mcpCount = Object.keys(parsed.mcpServers).length;
|
|
42
|
+
return { status: OK, message: `Valid, ${mcpCount} MCPs` };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return { status: OK, message: 'Valid' };
|
|
46
|
+
} catch (err) {
|
|
47
|
+
addRecommendation(`Fix JSON syntax error in ${name}: ${err.message}`);
|
|
48
|
+
return { status: FAIL, message: `Invalid JSON: ${err.message.slice(0, 50)}` };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function checkConfigurations() {
|
|
53
|
+
log('Checking configurations...');
|
|
54
|
+
|
|
55
|
+
const hooksFile = path.join(process.cwd(), 'hooks', 'hooks.json');
|
|
56
|
+
const hooksResult = checkJsonFile('hooks.json', hooksFile);
|
|
57
|
+
log(` ${padRight('hooks.json:', 20)} ${hooksResult.status} ${hooksResult.message}`);
|
|
58
|
+
|
|
59
|
+
const settingsFile = path.join(getClaudeDir(), 'settings.json');
|
|
60
|
+
const settingsResult = checkJsonFile('settings.json', settingsFile);
|
|
61
|
+
log(` ${padRight('settings.json:', 20)} ${settingsResult.status} ${settingsResult.message}`);
|
|
62
|
+
|
|
63
|
+
const packageFile = path.join(process.cwd(), 'package.json');
|
|
64
|
+
const packageResult = checkJsonFile('package.json', packageFile);
|
|
65
|
+
log(` ${padRight('package.json:', 20)} ${packageResult.status} ${packageResult.message}`);
|
|
66
|
+
|
|
67
|
+
// Check if node_modules exists
|
|
68
|
+
const nodeModules = path.join(process.cwd(), 'node_modules');
|
|
69
|
+
if (!fs.existsSync(nodeModules)) {
|
|
70
|
+
log(` ${padRight('Dependencies:', 20)} ${FAIL} node_modules not found`);
|
|
71
|
+
addRecommendation('Run "npm install" to install dependencies');
|
|
72
|
+
} else {
|
|
73
|
+
log(` ${padRight('Dependencies:', 20)} ${OK} Installed`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
log('');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Permission Checks
|
|
80
|
+
function checkPermission(name, dirPath) {
|
|
81
|
+
if (!fs.existsSync(dirPath)) {
|
|
82
|
+
return { status: WARN, message: 'Does not exist' };
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const testFile = path.join(dirPath, '.diagnose-test');
|
|
86
|
+
fs.writeFileSync(testFile, 'test');
|
|
87
|
+
fs.unlinkSync(testFile);
|
|
88
|
+
return { status: OK, message: 'Writable' };
|
|
89
|
+
} catch (err) {
|
|
90
|
+
addRecommendation(`Fix permissions on ${dirPath}: ${err.code}`);
|
|
91
|
+
return { status: FAIL, message: `Not writable: ${err.code}` };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function checkPermissions() {
|
|
96
|
+
log('Checking permissions...');
|
|
97
|
+
|
|
98
|
+
const claudeDir = getClaudeDir();
|
|
99
|
+
const claudeResult = checkPermission('~/.claude/', claudeDir);
|
|
100
|
+
log(` ${padRight('~/.claude/:', 20)} ${claudeResult.status} ${claudeResult.message}`);
|
|
101
|
+
|
|
102
|
+
const memoryDir = path.join(claudeDir, 'memory');
|
|
103
|
+
const memoryResult = checkPermission('~/.claude/memory/', memoryDir);
|
|
104
|
+
log(` ${padRight('~/.claude/memory/:', 20)} ${memoryResult.status} ${memoryResult.message}`);
|
|
105
|
+
|
|
106
|
+
const skillsDir = path.join(claudeDir, 'skills');
|
|
107
|
+
const skillsResult = checkPermission('~/.claude/skills/', skillsDir);
|
|
108
|
+
log(` ${padRight('~/.claude/skills/:', 20)} ${skillsResult.status} ${skillsResult.message}`);
|
|
109
|
+
|
|
110
|
+
log('');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Recent Errors Check
|
|
114
|
+
function checkRecentErrors() {
|
|
115
|
+
log('Checking recent errors (last 24h)...');
|
|
116
|
+
|
|
117
|
+
const sessionsDir = getSessionsDir();
|
|
118
|
+
if (!fs.existsSync(sessionsDir)) {
|
|
119
|
+
log(` No sessions directory found`);
|
|
120
|
+
log('');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const recentFiles = findFiles(sessionsDir, '*.jsonl', { maxAge: 1 });
|
|
125
|
+
|
|
126
|
+
if (recentFiles.length === 0) {
|
|
127
|
+
log(` No recent sessions found`);
|
|
128
|
+
log('');
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let errorCount = 0;
|
|
133
|
+
let timeoutCount = 0;
|
|
134
|
+
let jsonErrors = 0;
|
|
135
|
+
const errorPatterns = [];
|
|
136
|
+
|
|
137
|
+
for (const file of recentFiles.slice(0, 10)) {
|
|
138
|
+
// Check last 10 sessions
|
|
139
|
+
try {
|
|
140
|
+
const content = readFile(file.path);
|
|
141
|
+
const lines = content.split('\n').filter(Boolean);
|
|
142
|
+
|
|
143
|
+
for (const line of lines) {
|
|
144
|
+
try {
|
|
145
|
+
const entry = JSON.parse(line);
|
|
146
|
+
// Look for error patterns
|
|
147
|
+
if (entry.error || (entry.type && entry.type.includes('error'))) {
|
|
148
|
+
errorCount++;
|
|
149
|
+
if (entry.error && !errorPatterns.includes(entry.error.slice(0, 50))) {
|
|
150
|
+
errorPatterns.push(entry.error.slice(0, 50));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (entry.timeout || (entry.message && entry.message.includes('timeout'))) {
|
|
154
|
+
timeoutCount++;
|
|
155
|
+
}
|
|
156
|
+
} catch {
|
|
157
|
+
jsonErrors++;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
} catch {
|
|
161
|
+
// Skip unreadable files
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (errorCount === 0 && timeoutCount === 0 && jsonErrors === 0) {
|
|
166
|
+
log(` ${OK} No errors found in recent sessions`);
|
|
167
|
+
} else {
|
|
168
|
+
if (errorCount > 0) {
|
|
169
|
+
log(` ${WARN} ${errorCount} errors found`);
|
|
170
|
+
errorPatterns.slice(0, 3).forEach((pattern) => {
|
|
171
|
+
log(` - ${pattern}...`);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
if (timeoutCount > 0) {
|
|
175
|
+
log(` ${WARN} ${timeoutCount} timeouts found`);
|
|
176
|
+
addRecommendation('Check hook timeout settings in hooks.json');
|
|
177
|
+
}
|
|
178
|
+
if (jsonErrors > 0) {
|
|
179
|
+
log(` ${WARN} ${jsonErrors} JSON parse errors in session files`);
|
|
180
|
+
addRecommendation('Some session files may be corrupted');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
log('');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// MCP Connectivity Check
|
|
188
|
+
function checkMCPs() {
|
|
189
|
+
log('Checking MCPs...');
|
|
190
|
+
|
|
191
|
+
const settingsFile = path.join(getClaudeDir(), 'settings.json');
|
|
192
|
+
if (!fs.existsSync(settingsFile)) {
|
|
193
|
+
log(` ${WARN} No settings.json found - MCPs not configured`);
|
|
194
|
+
addRecommendation('Configure MCPs in ~/.claude/settings.json');
|
|
195
|
+
log('');
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
const content = readFile(settingsFile);
|
|
201
|
+
const settings = JSON.parse(content);
|
|
202
|
+
|
|
203
|
+
if (!settings.mcpServers || Object.keys(settings.mcpServers).length === 0) {
|
|
204
|
+
log(` ${WARN} No MCPs configured`);
|
|
205
|
+
addRecommendation('Add MCP servers to ~/.claude/settings.json');
|
|
206
|
+
log('');
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
for (const [name, config] of Object.entries(settings.mcpServers)) {
|
|
211
|
+
// We can't actually test connectivity without running the MCP
|
|
212
|
+
// So we just verify the configuration looks valid
|
|
213
|
+
if (config.command || config.url) {
|
|
214
|
+
log(` ${padRight(name + ':', 20)} ${OK} Configured`);
|
|
215
|
+
} else {
|
|
216
|
+
log(` ${padRight(name + ':', 20)} ${WARN} Missing command or url`);
|
|
217
|
+
addRecommendation(`Check ${name} MCP configuration`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
} catch (err) {
|
|
221
|
+
log(` ${FAIL} Cannot parse settings.json: ${err.message}`);
|
|
222
|
+
addRecommendation('Fix JSON syntax in ~/.claude/settings.json');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
log('');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Common Misconfigurations
|
|
229
|
+
function checkCommonIssues() {
|
|
230
|
+
log('Checking common issues...');
|
|
231
|
+
|
|
232
|
+
// Check for .env file
|
|
233
|
+
const envFile = path.join(getClaudeDir(), '.env');
|
|
234
|
+
if (!fs.existsSync(envFile)) {
|
|
235
|
+
log(` ${WARN} No ~/.claude/.env file found`);
|
|
236
|
+
addRecommendation('Create ~/.claude/.env with required credentials');
|
|
237
|
+
} else {
|
|
238
|
+
log(` ${padRight('.env file:', 20)} ${OK} Found`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Check tutorial progress file
|
|
242
|
+
const milestonesFile = path.join(getClaudeDir(), 'onboarding', 'milestones.json');
|
|
243
|
+
if (fs.existsSync(milestonesFile)) {
|
|
244
|
+
try {
|
|
245
|
+
const content = readFile(milestonesFile);
|
|
246
|
+
const milestones = JSON.parse(content);
|
|
247
|
+
const completed = Object.values(milestones).filter((v) => v === true).length;
|
|
248
|
+
log(` ${padRight('Tutorial progress:', 20)} ${OK} ${completed} milestones completed`);
|
|
249
|
+
} catch {
|
|
250
|
+
log(` ${padRight('Tutorial progress:', 20)} ${WARN} Invalid milestones file`);
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
253
|
+
log(` ${padRight('Tutorial progress:', 20)} ${WARN} Not started`);
|
|
254
|
+
addRecommendation('Run /tutorial to start the tutorial');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Check git status
|
|
258
|
+
try {
|
|
259
|
+
const { execSync } = require('child_process');
|
|
260
|
+
execSync('git rev-parse --git-dir', { stdio: 'pipe' });
|
|
261
|
+
const upstream = execSync('git remote -v', { encoding: 'utf8' });
|
|
262
|
+
if (upstream.includes('upstream')) {
|
|
263
|
+
log(` ${padRight('Git upstream:', 20)} ${OK} Configured`);
|
|
264
|
+
} else {
|
|
265
|
+
log(` ${padRight('Git upstream:', 20)} ${WARN} No upstream remote`);
|
|
266
|
+
addRecommendation('Add upstream remote: git remote add upstream [central-repo-url]');
|
|
267
|
+
}
|
|
268
|
+
} catch {
|
|
269
|
+
log(` ${padRight('Git repo:', 20)} ${WARN} Not a git repository`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
log('');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function printRecommendations() {
|
|
276
|
+
log('─'.repeat(50));
|
|
277
|
+
log('');
|
|
278
|
+
|
|
279
|
+
if (recommendations.length === 0) {
|
|
280
|
+
log('DIAGNOSIS: All checks passed');
|
|
281
|
+
log('');
|
|
282
|
+
log('No issues found. System appears healthy.');
|
|
283
|
+
} else {
|
|
284
|
+
log(`DIAGNOSIS: ${recommendations.length} issue(s) found`);
|
|
285
|
+
log('');
|
|
286
|
+
log('Recommendations:');
|
|
287
|
+
recommendations.forEach((rec, i) => {
|
|
288
|
+
log(` ${i + 1}. ${rec}`);
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
log('');
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function runDiagnose(options = {}) {
|
|
296
|
+
const { config, permissions, errors, mcp } = options;
|
|
297
|
+
const runAll = !config && !permissions && !errors && !mcp;
|
|
298
|
+
|
|
299
|
+
log('');
|
|
300
|
+
log('Running diagnostics...');
|
|
301
|
+
log('');
|
|
302
|
+
|
|
303
|
+
if (runAll || config) checkConfigurations();
|
|
304
|
+
if (runAll || permissions) checkPermissions();
|
|
305
|
+
if (runAll || errors) checkRecentErrors();
|
|
306
|
+
if (runAll || mcp) checkMCPs();
|
|
307
|
+
if (runAll) checkCommonIssues();
|
|
308
|
+
|
|
309
|
+
printRecommendations();
|
|
310
|
+
|
|
311
|
+
// Exit with appropriate code for CI/CD
|
|
312
|
+
process.exit(recommendations.length > 0 ? 1 : 0);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Parse arguments
|
|
316
|
+
const args = process.argv.slice(2);
|
|
317
|
+
const options = {
|
|
318
|
+
config: args.includes('--config'),
|
|
319
|
+
permissions: args.includes('--permissions'),
|
|
320
|
+
errors: args.includes('--errors'),
|
|
321
|
+
mcp: args.includes('--mcp'),
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
runDiagnose(options);
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Documentation Freshness Checker
|
|
4
|
+
* Identifies stale documentation files that haven't been modified recently.
|
|
5
|
+
*/
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
const ROOT = path.join(__dirname, '..');
|
|
10
|
+
|
|
11
|
+
// Parse arguments
|
|
12
|
+
const args = process.argv.slice(2);
|
|
13
|
+
const failOnStale = args.find((a) => a.startsWith('--fail-on-stale='));
|
|
14
|
+
const staleThresholdDays = failOnStale ? parseInt(failOnStale.split('=')[1], 10) : 90;
|
|
15
|
+
const jsonOutput = args.includes('--json');
|
|
16
|
+
const verbose = args.includes('--verbose');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get all markdown files recursively
|
|
20
|
+
*/
|
|
21
|
+
function getMarkdownFiles(dir, files = []) {
|
|
22
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
23
|
+
for (const entry of entries) {
|
|
24
|
+
const fullPath = path.join(dir, entry.name);
|
|
25
|
+
if (entry.isDirectory()) {
|
|
26
|
+
// Skip node_modules, .git, archived
|
|
27
|
+
if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === '_archived') {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
getMarkdownFiles(fullPath, files);
|
|
31
|
+
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
32
|
+
files.push(fullPath);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return files;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Check for TODO/PLACEHOLDER markers
|
|
40
|
+
*/
|
|
41
|
+
function hasPlaceholders(content) {
|
|
42
|
+
const markers = ['TODO:', 'PLACEHOLDER', 'FIXME:', 'TBD:', 'XXX:'];
|
|
43
|
+
return markers.some((m) => content.includes(m));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get file modification date
|
|
48
|
+
*/
|
|
49
|
+
function getModDate(file) {
|
|
50
|
+
const stats = fs.statSync(file);
|
|
51
|
+
return stats.mtime;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Calculate days since modification
|
|
56
|
+
*/
|
|
57
|
+
function daysSince(date) {
|
|
58
|
+
const now = new Date();
|
|
59
|
+
const diff = now - date;
|
|
60
|
+
return Math.floor(diff / (1000 * 60 * 60 * 24));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Get all markdown files
|
|
64
|
+
const markdownFiles = getMarkdownFiles(ROOT);
|
|
65
|
+
const now = new Date();
|
|
66
|
+
|
|
67
|
+
// Analyze each file
|
|
68
|
+
const results = {
|
|
69
|
+
total: markdownFiles.length,
|
|
70
|
+
stale: [],
|
|
71
|
+
hasPlaceholders: [],
|
|
72
|
+
recent: [],
|
|
73
|
+
byAge: {
|
|
74
|
+
last7Days: 0,
|
|
75
|
+
last30Days: 0,
|
|
76
|
+
last90Days: 0,
|
|
77
|
+
older: 0,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
for (const file of markdownFiles) {
|
|
82
|
+
const relativePath = path.relative(ROOT, file);
|
|
83
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
84
|
+
const modDate = getModDate(file);
|
|
85
|
+
const days = daysSince(modDate);
|
|
86
|
+
|
|
87
|
+
// Categorize by age
|
|
88
|
+
if (days <= 7) {
|
|
89
|
+
results.byAge.last7Days++;
|
|
90
|
+
results.recent.push({ file: relativePath, days });
|
|
91
|
+
} else if (days <= 30) {
|
|
92
|
+
results.byAge.last30Days++;
|
|
93
|
+
} else if (days <= 90) {
|
|
94
|
+
results.byAge.last90Days++;
|
|
95
|
+
} else {
|
|
96
|
+
results.byAge.older++;
|
|
97
|
+
results.stale.push({
|
|
98
|
+
file: relativePath,
|
|
99
|
+
days,
|
|
100
|
+
lastModified: modDate.toISOString().split('T')[0],
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Check for placeholders
|
|
105
|
+
if (hasPlaceholders(content)) {
|
|
106
|
+
results.hasPlaceholders.push({ file: relativePath });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Sort stale by age (oldest first)
|
|
111
|
+
results.stale.sort((a, b) => b.days - a.days);
|
|
112
|
+
|
|
113
|
+
// Output results
|
|
114
|
+
if (jsonOutput) {
|
|
115
|
+
console.log(JSON.stringify(results, null, 2));
|
|
116
|
+
} else {
|
|
117
|
+
console.log('\n=== Documentation Freshness Report ===\n');
|
|
118
|
+
console.log(`Total files: ${results.total}`);
|
|
119
|
+
console.log(`\nAge Distribution:`);
|
|
120
|
+
console.log(` Last 7 days: ${results.byAge.last7Days}`);
|
|
121
|
+
console.log(` Last 30 days: ${results.byAge.last30Days}`);
|
|
122
|
+
console.log(` Last 90 days: ${results.byAge.last90Days}`);
|
|
123
|
+
console.log(` Older: ${results.byAge.older}`);
|
|
124
|
+
|
|
125
|
+
if (results.stale.length > 0) {
|
|
126
|
+
console.log(`\n\u26A0 Stale Files (>90 days):`);
|
|
127
|
+
const displayCount = verbose ? results.stale.length : Math.min(10, results.stale.length);
|
|
128
|
+
for (let i = 0; i < displayCount; i++) {
|
|
129
|
+
const { file, days, lastModified } = results.stale[i];
|
|
130
|
+
console.log(` - ${file} (${days} days old, last: ${lastModified})`);
|
|
131
|
+
}
|
|
132
|
+
if (!verbose && results.stale.length > 10) {
|
|
133
|
+
console.log(` ... and ${results.stale.length - 10} more (use --verbose to see all)`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (results.hasPlaceholders.length > 0) {
|
|
138
|
+
console.log(`\n\u26A0 Files with TODO/PLACEHOLDER markers:`);
|
|
139
|
+
for (const { file } of results.hasPlaceholders.slice(0, 10)) {
|
|
140
|
+
console.log(` - ${file}`);
|
|
141
|
+
}
|
|
142
|
+
if (results.hasPlaceholders.length > 10) {
|
|
143
|
+
console.log(` ... and ${results.hasPlaceholders.length - 10} more`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (results.recent.length > 0 && verbose) {
|
|
148
|
+
console.log(`\n\u2713 Recently Updated (last 7 days):`);
|
|
149
|
+
for (const { file, days } of results.recent.slice(0, 10)) {
|
|
150
|
+
console.log(` - ${file} (${days} days ago)`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
console.log('\n');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Exit with error if --fail-on-stale is set and there are stale files
|
|
158
|
+
if (failOnStale && results.stale.length > 0) {
|
|
159
|
+
const criticalStale = results.stale.filter((f) => f.days > staleThresholdDays);
|
|
160
|
+
if (criticalStale.length > 0) {
|
|
161
|
+
console.error(
|
|
162
|
+
`\u2717 Found ${criticalStale.length} files older than ${staleThresholdDays} days`
|
|
163
|
+
);
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
process.exit(0);
|