@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,351 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Tutorial Runner - Visual Interactive Tutorial for Everything Claude Code
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* node scripts/tutorial-runner.js # Show status and current lesson
|
|
7
|
+
* node scripts/tutorial-runner.js <lesson> # Go to specific lesson (0-14)
|
|
8
|
+
* node scripts/tutorial-runner.js status # Show progress status
|
|
9
|
+
* node scripts/tutorial-runner.js reset # Reset all progress
|
|
10
|
+
* node scripts/tutorial-runner.js complete <num> # Mark lesson as complete
|
|
11
|
+
* node scripts/tutorial-runner.js certificate # Show completion certificate
|
|
12
|
+
* node scripts/tutorial-runner.js stats # Show usage statistics
|
|
13
|
+
* node scripts/tutorial-runner.js --accessible # Disable colors for accessibility
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const progress = require('./lib/tutorial-progress');
|
|
19
|
+
const renderer = require('./lib/tutorial-renderer');
|
|
20
|
+
const metrics = require('./lib/tutorial-metrics');
|
|
21
|
+
|
|
22
|
+
// Lessons directory
|
|
23
|
+
const LESSONS_DIR = path.join(__dirname, '..', 'skills', 'tutorial', 'lessons');
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Generate a unique certificate ID.
|
|
27
|
+
* @returns {string} Certificate ID
|
|
28
|
+
*/
|
|
29
|
+
function generateCertificateId() {
|
|
30
|
+
const date = new Date();
|
|
31
|
+
const year = date.getFullYear();
|
|
32
|
+
const random = Math.random().toString(36).substring(2, 6).toUpperCase();
|
|
33
|
+
return `ECC-${year}-${random}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Load lesson content from file.
|
|
38
|
+
* @param {number} lessonNum - Lesson number
|
|
39
|
+
* @returns {string|null} Lesson content or null
|
|
40
|
+
*/
|
|
41
|
+
function loadLessonContent(lessonNum) {
|
|
42
|
+
const lesson = progress.getLessonInfo(lessonNum);
|
|
43
|
+
if (!lesson) return null;
|
|
44
|
+
|
|
45
|
+
const filePath = path.join(LESSONS_DIR, lesson.file);
|
|
46
|
+
if (!fs.existsSync(filePath)) return null;
|
|
47
|
+
|
|
48
|
+
return fs.readFileSync(filePath, 'utf8');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Extract commands from lesson content.
|
|
53
|
+
* @param {string} content - Lesson markdown content
|
|
54
|
+
* @returns {Array<string>} Array of command names
|
|
55
|
+
*/
|
|
56
|
+
function extractCommands(content) {
|
|
57
|
+
const commands = [];
|
|
58
|
+
const regex = /\/(\w+[-\w]*)/g;
|
|
59
|
+
let match;
|
|
60
|
+
while ((match = regex.exec(content)) !== null) {
|
|
61
|
+
const cmd = `/${match[1]}`;
|
|
62
|
+
if (!commands.includes(cmd)) {
|
|
63
|
+
commands.push(cmd);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return commands.slice(0, 5); // Limit to 5 for display
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Show tutorial status.
|
|
71
|
+
*/
|
|
72
|
+
async function showStatus() {
|
|
73
|
+
await renderer.init();
|
|
74
|
+
|
|
75
|
+
const state = progress.loadProgress();
|
|
76
|
+
|
|
77
|
+
console.log('');
|
|
78
|
+
console.log(renderer.renderBanner());
|
|
79
|
+
console.log('');
|
|
80
|
+
console.log(renderer.renderProgressBar(state.completedLessons.length, progress.TOTAL_LESSONS));
|
|
81
|
+
console.log('');
|
|
82
|
+
console.log(renderer.renderLessonList(state, progress.LESSONS));
|
|
83
|
+
console.log('');
|
|
84
|
+
|
|
85
|
+
if (progress.isComplete(state)) {
|
|
86
|
+
console.log(renderer.renderSuccess('Tutorial complete!'));
|
|
87
|
+
console.log(' Terminal: node scripts/tutorial-runner.js certificate');
|
|
88
|
+
console.log(' Claude Code: /tutorial certificate');
|
|
89
|
+
} else {
|
|
90
|
+
console.log('Next lesson:');
|
|
91
|
+
console.log(` Terminal: node scripts/tutorial-runner.js ${state.currentLesson}`);
|
|
92
|
+
console.log(` Claude Code: /tutorial ${state.currentLesson}`);
|
|
93
|
+
}
|
|
94
|
+
console.log('');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Show a specific lesson.
|
|
99
|
+
* @param {number} lessonNum - Lesson number
|
|
100
|
+
*/
|
|
101
|
+
async function showLesson(lessonNum) {
|
|
102
|
+
await renderer.init();
|
|
103
|
+
|
|
104
|
+
const lesson = progress.getLessonInfo(lessonNum);
|
|
105
|
+
if (!lesson) {
|
|
106
|
+
console.error(
|
|
107
|
+
renderer.renderError(
|
|
108
|
+
`Invalid lesson number: ${lessonNum}. Valid: 0-${progress.TOTAL_LESSONS - 1}`
|
|
109
|
+
)
|
|
110
|
+
);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Record metrics
|
|
115
|
+
metrics.recordLessonStart(lessonNum);
|
|
116
|
+
|
|
117
|
+
const state = progress.setCurrentLesson(lessonNum);
|
|
118
|
+
|
|
119
|
+
console.log('');
|
|
120
|
+
console.log(renderer.renderBanner());
|
|
121
|
+
console.log('');
|
|
122
|
+
console.log(renderer.renderProgressBar(state.completedLessons.length, progress.TOTAL_LESSONS));
|
|
123
|
+
console.log('');
|
|
124
|
+
console.log(renderer.renderLessonHeader(lesson));
|
|
125
|
+
console.log('');
|
|
126
|
+
|
|
127
|
+
const content = loadLessonContent(lessonNum);
|
|
128
|
+
if (content) {
|
|
129
|
+
// Output styled lesson content
|
|
130
|
+
console.log(renderer.renderLessonContent(content));
|
|
131
|
+
} else {
|
|
132
|
+
console.log(`Lesson file not found: ${lesson.file}`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
console.log('');
|
|
136
|
+
console.log('To mark complete:');
|
|
137
|
+
console.log(` Terminal: node scripts/tutorial-runner.js complete ${lessonNum}`);
|
|
138
|
+
console.log(' Claude Code: (automatic when exercise completed)');
|
|
139
|
+
console.log('');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Mark a lesson as complete.
|
|
144
|
+
* @param {number} lessonNum - Lesson number
|
|
145
|
+
*/
|
|
146
|
+
async function completeLesson(lessonNum) {
|
|
147
|
+
await renderer.init();
|
|
148
|
+
|
|
149
|
+
const lesson = progress.getLessonInfo(lessonNum);
|
|
150
|
+
if (!lesson) {
|
|
151
|
+
console.error(renderer.renderError(`Invalid lesson number: ${lessonNum}`));
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Record metrics
|
|
156
|
+
metrics.recordLessonEnd(lessonNum);
|
|
157
|
+
|
|
158
|
+
const state = progress.completeLesson(lessonNum);
|
|
159
|
+
|
|
160
|
+
const content = loadLessonContent(lessonNum);
|
|
161
|
+
const commands = content ? extractCommands(content) : [];
|
|
162
|
+
|
|
163
|
+
const nextLesson = lessonNum < progress.TOTAL_LESSONS ? lessonNum + 1 : null;
|
|
164
|
+
|
|
165
|
+
console.log('');
|
|
166
|
+
console.log(renderer.renderCompletionBadge(lesson, commands, nextLesson));
|
|
167
|
+
console.log('');
|
|
168
|
+
|
|
169
|
+
if (progress.isComplete(state)) {
|
|
170
|
+
metrics.markComplete();
|
|
171
|
+
console.log(renderer.renderSuccess('Congratulations! You completed all lessons!'));
|
|
172
|
+
console.log('Get your certificate:');
|
|
173
|
+
console.log(' Terminal: node scripts/tutorial-runner.js certificate');
|
|
174
|
+
console.log(' Claude Code: /tutorial certificate');
|
|
175
|
+
}
|
|
176
|
+
console.log('');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Reset all progress.
|
|
181
|
+
*/
|
|
182
|
+
async function resetProgress() {
|
|
183
|
+
await renderer.init();
|
|
184
|
+
|
|
185
|
+
progress.resetProgress();
|
|
186
|
+
console.log('');
|
|
187
|
+
console.log(renderer.renderSuccess('Tutorial progress has been reset.'));
|
|
188
|
+
console.log('Start from beginning:');
|
|
189
|
+
console.log(' Terminal: node scripts/tutorial-runner.js 0');
|
|
190
|
+
console.log(' Claude Code: /tutorial 0');
|
|
191
|
+
console.log('');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Show completion certificate.
|
|
196
|
+
*/
|
|
197
|
+
async function showCertificate() {
|
|
198
|
+
await renderer.init();
|
|
199
|
+
|
|
200
|
+
const state = progress.loadProgress();
|
|
201
|
+
|
|
202
|
+
if (!progress.isComplete(state)) {
|
|
203
|
+
console.error(renderer.renderError('Tutorial not complete. Complete all 15 lessons first.'));
|
|
204
|
+
console.log('');
|
|
205
|
+
console.log(renderer.renderProgressBar(state.completedLessons.length, progress.TOTAL_LESSONS));
|
|
206
|
+
console.log('');
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const certId = generateCertificateId();
|
|
211
|
+
|
|
212
|
+
console.log('');
|
|
213
|
+
console.log(renderer.renderCertificate(state, certId));
|
|
214
|
+
console.log('');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Show resume prompt (for session-start hook).
|
|
219
|
+
*/
|
|
220
|
+
async function showResumePrompt() {
|
|
221
|
+
await renderer.init();
|
|
222
|
+
|
|
223
|
+
if (!progress.hasProgress()) {
|
|
224
|
+
return; // No progress to show
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const state = progress.loadProgress();
|
|
228
|
+
|
|
229
|
+
if (progress.isComplete(state)) {
|
|
230
|
+
return; // Already complete
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
console.log('');
|
|
234
|
+
console.log(renderer.renderResumePrompt(state));
|
|
235
|
+
console.log('');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Show usage statistics.
|
|
240
|
+
*/
|
|
241
|
+
async function showStats() {
|
|
242
|
+
await renderer.init();
|
|
243
|
+
|
|
244
|
+
if (!metrics.hasMetrics()) {
|
|
245
|
+
console.log('');
|
|
246
|
+
console.log('No metrics data yet. Start a lesson to begin tracking.');
|
|
247
|
+
console.log('');
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const stats = metrics.getStats();
|
|
252
|
+
|
|
253
|
+
console.log('');
|
|
254
|
+
console.log('Tutorial Statistics:');
|
|
255
|
+
console.log('');
|
|
256
|
+
console.log(` Total time: ${stats.totalTime}`);
|
|
257
|
+
console.log(` Sessions: ${stats.totalSessions}`);
|
|
258
|
+
console.log(` Lessons visited: ${stats.lessonsVisited}/${progress.TOTAL_LESSONS}`);
|
|
259
|
+
|
|
260
|
+
if (stats.mostVisited) {
|
|
261
|
+
const lessonInfo = progress.getLessonInfo(stats.mostVisited);
|
|
262
|
+
console.log(
|
|
263
|
+
` Most visited: Lesson ${stats.mostVisited}: ${lessonInfo.title} (${stats.mostVisitedCount} visits)`
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
console.log(` Avg per lesson: ${stats.averageTimePerLesson}`);
|
|
268
|
+
console.log('');
|
|
269
|
+
|
|
270
|
+
if (stats.completedAt) {
|
|
271
|
+
const completedDate = new Date(stats.completedAt).toLocaleDateString();
|
|
272
|
+
console.log(` Completed: ${completedDate}`);
|
|
273
|
+
console.log('');
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Show per-lesson breakdown if there's data
|
|
277
|
+
if (Object.keys(stats.lessonMetrics).length > 0) {
|
|
278
|
+
console.log(' Per-lesson breakdown:');
|
|
279
|
+
for (const [lessonNum, data] of Object.entries(stats.lessonMetrics)) {
|
|
280
|
+
const lessonInfo = progress.getLessonInfo(parseInt(lessonNum, 10));
|
|
281
|
+
const timeStr = metrics.formatTime(data.totalTimeMs);
|
|
282
|
+
console.log(` Lesson ${lessonNum}: ${data.visits} visit(s), ${timeStr}`);
|
|
283
|
+
}
|
|
284
|
+
console.log('');
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Main entry point.
|
|
290
|
+
*/
|
|
291
|
+
async function main() {
|
|
292
|
+
const args = process.argv.slice(2).filter((a) => !a.startsWith('--'));
|
|
293
|
+
|
|
294
|
+
if (args.length === 0) {
|
|
295
|
+
await showStatus();
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const command = args[0].toLowerCase();
|
|
300
|
+
|
|
301
|
+
switch (command) {
|
|
302
|
+
case 'status':
|
|
303
|
+
await showStatus();
|
|
304
|
+
break;
|
|
305
|
+
|
|
306
|
+
case 'reset':
|
|
307
|
+
await resetProgress();
|
|
308
|
+
break;
|
|
309
|
+
|
|
310
|
+
case 'certificate':
|
|
311
|
+
case 'cert':
|
|
312
|
+
await showCertificate();
|
|
313
|
+
break;
|
|
314
|
+
|
|
315
|
+
case 'complete':
|
|
316
|
+
if (!args[1]) {
|
|
317
|
+
console.error('Usage: node scripts/tutorial-runner.js complete <lesson-number>');
|
|
318
|
+
process.exit(1);
|
|
319
|
+
}
|
|
320
|
+
await completeLesson(parseInt(args[1], 10));
|
|
321
|
+
break;
|
|
322
|
+
|
|
323
|
+
case 'resume':
|
|
324
|
+
await showResumePrompt();
|
|
325
|
+
break;
|
|
326
|
+
|
|
327
|
+
case 'stats':
|
|
328
|
+
case 'metrics':
|
|
329
|
+
await showStats();
|
|
330
|
+
break;
|
|
331
|
+
|
|
332
|
+
default: {
|
|
333
|
+
// Assume it's a lesson number
|
|
334
|
+
const lessonNum = parseInt(command, 10);
|
|
335
|
+
if (isNaN(lessonNum) || lessonNum < 0 || lessonNum >= progress.TOTAL_LESSONS) {
|
|
336
|
+
console.error(`Invalid command or lesson number: ${command}`);
|
|
337
|
+
console.error(`Valid lessons: 0-${progress.TOTAL_LESSONS - 1}`);
|
|
338
|
+
console.error('Commands: status, reset, complete <n>, certificate, stats');
|
|
339
|
+
process.exit(1);
|
|
340
|
+
}
|
|
341
|
+
await showLesson(lessonNum);
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Run
|
|
348
|
+
main().catch((err) => {
|
|
349
|
+
console.error('Error:', err.message);
|
|
350
|
+
process.exit(1);
|
|
351
|
+
});
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Master Validation Orchestrator
|
|
4
|
+
* Runs all validation phases in sequence with proper error handling.
|
|
5
|
+
*/
|
|
6
|
+
const { spawn } = require('child_process');
|
|
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 quickMode = args.includes('--quick');
|
|
14
|
+
const verbose = args.includes('--verbose');
|
|
15
|
+
const continueOnError = args.includes('--continue');
|
|
16
|
+
|
|
17
|
+
// ANSI colors
|
|
18
|
+
const colors = {
|
|
19
|
+
reset: '\x1b[0m',
|
|
20
|
+
green: '\x1b[32m',
|
|
21
|
+
red: '\x1b[31m',
|
|
22
|
+
yellow: '\x1b[33m',
|
|
23
|
+
blue: '\x1b[34m',
|
|
24
|
+
dim: '\x1b[2m',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function log(message, color = 'reset') {
|
|
28
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function header(message) {
|
|
32
|
+
console.log('\n' + '='.repeat(60));
|
|
33
|
+
log(message, 'blue');
|
|
34
|
+
console.log('='.repeat(60));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Run a command and return a promise
|
|
39
|
+
*/
|
|
40
|
+
function runCommand(command, args = [], options = {}) {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
const startTime = Date.now();
|
|
43
|
+
const proc = spawn(command, args, {
|
|
44
|
+
cwd: ROOT,
|
|
45
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
46
|
+
shell: true,
|
|
47
|
+
...options,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
let stdout = '';
|
|
51
|
+
let stderr = '';
|
|
52
|
+
|
|
53
|
+
if (!verbose && proc.stdout) {
|
|
54
|
+
proc.stdout.on('data', (data) => {
|
|
55
|
+
stdout += data.toString();
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!verbose && proc.stderr) {
|
|
60
|
+
proc.stderr.on('data', (data) => {
|
|
61
|
+
stderr += data.toString();
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
proc.on('close', (code) => {
|
|
66
|
+
const duration = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
67
|
+
if (code === 0) {
|
|
68
|
+
resolve({ success: true, duration, stdout, stderr });
|
|
69
|
+
} else {
|
|
70
|
+
reject({ success: false, code, duration, stdout, stderr });
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
proc.on('error', (err) => {
|
|
75
|
+
reject({ success: false, error: err.message, stdout, stderr });
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Validation phases
|
|
82
|
+
*/
|
|
83
|
+
const phases = [
|
|
84
|
+
{
|
|
85
|
+
name: 'Environment Check',
|
|
86
|
+
command: 'npm',
|
|
87
|
+
args: ['run', 'verify:quick'],
|
|
88
|
+
required: true,
|
|
89
|
+
quick: true,
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'Plugin Structure Validation',
|
|
93
|
+
command: 'npm',
|
|
94
|
+
args: ['run', 'validate'],
|
|
95
|
+
required: true,
|
|
96
|
+
quick: true,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'Full Test Suite',
|
|
100
|
+
command: 'npm',
|
|
101
|
+
args: ['test'],
|
|
102
|
+
required: true,
|
|
103
|
+
quick: false,
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'ESLint Check',
|
|
107
|
+
command: 'npm',
|
|
108
|
+
args: ['run', 'lint'],
|
|
109
|
+
required: true,
|
|
110
|
+
quick: false,
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: 'Prettier Format Check',
|
|
114
|
+
command: 'npm',
|
|
115
|
+
args: ['run', 'format'],
|
|
116
|
+
required: true,
|
|
117
|
+
quick: false,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'Markdown Link Validation',
|
|
121
|
+
command: 'node',
|
|
122
|
+
args: ['tests/structure/links.test.js'],
|
|
123
|
+
required: true,
|
|
124
|
+
quick: false,
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: 'Documentation Freshness',
|
|
128
|
+
command: 'node',
|
|
129
|
+
args: ['scripts/doc-freshness.js'],
|
|
130
|
+
required: false,
|
|
131
|
+
quick: false,
|
|
132
|
+
},
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
async function main() {
|
|
136
|
+
log('\n\u2728 CloudStream Claude Code - Enterprise Validation\n', 'blue');
|
|
137
|
+
log(`Mode: ${quickMode ? 'Quick' : 'Full'}`, 'dim');
|
|
138
|
+
log(`Continue on error: ${continueOnError ? 'Yes' : 'No'}`, 'dim');
|
|
139
|
+
|
|
140
|
+
const results = [];
|
|
141
|
+
let hasFailure = false;
|
|
142
|
+
|
|
143
|
+
for (const phase of phases) {
|
|
144
|
+
// Skip non-quick phases in quick mode
|
|
145
|
+
if (quickMode && !phase.quick) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
header(`Phase: ${phase.name}`);
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const result = await runCommand(phase.command, phase.args);
|
|
153
|
+
log(`\u2713 ${phase.name} passed (${result.duration}s)`, 'green');
|
|
154
|
+
results.push({ phase: phase.name, success: true, duration: result.duration });
|
|
155
|
+
} catch (err) {
|
|
156
|
+
log(`\u2717 ${phase.name} failed`, 'red');
|
|
157
|
+
if (!verbose && err.stderr) {
|
|
158
|
+
console.log(colors.dim + err.stderr.slice(0, 500) + colors.reset);
|
|
159
|
+
}
|
|
160
|
+
results.push({ phase: phase.name, success: false, duration: err.duration });
|
|
161
|
+
|
|
162
|
+
if (phase.required) {
|
|
163
|
+
hasFailure = true;
|
|
164
|
+
if (!continueOnError) {
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Summary
|
|
172
|
+
header('Validation Summary');
|
|
173
|
+
|
|
174
|
+
const passed = results.filter((r) => r.success).length;
|
|
175
|
+
const failed = results.filter((r) => !r.success).length;
|
|
176
|
+
const totalTime = results.reduce((sum, r) => sum + parseFloat(r.duration || 0), 0).toFixed(1);
|
|
177
|
+
|
|
178
|
+
for (const result of results) {
|
|
179
|
+
const icon = result.success ? '\u2713' : '\u2717';
|
|
180
|
+
const color = result.success ? 'green' : 'red';
|
|
181
|
+
log(` ${icon} ${result.phase} (${result.duration}s)`, color);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.log('\n' + '-'.repeat(40));
|
|
185
|
+
log(`Passed: ${passed}`, 'green');
|
|
186
|
+
if (failed > 0) log(`Failed: ${failed}`, 'red');
|
|
187
|
+
log(`Total time: ${totalTime}s`, 'dim');
|
|
188
|
+
|
|
189
|
+
if (hasFailure) {
|
|
190
|
+
log('\n\u2717 Validation FAILED', 'red');
|
|
191
|
+
process.exit(1);
|
|
192
|
+
} else {
|
|
193
|
+
log('\n\u2713 All validations PASSED', 'green');
|
|
194
|
+
process.exit(0);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
main().catch((err) => {
|
|
199
|
+
console.error('Unexpected error:', err);
|
|
200
|
+
process.exit(1);
|
|
201
|
+
});
|