@cloudstreamsoftware/claude-tools 1.0.0 → 1.2.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/bin/cloudstream-setup.js +16 -6
- 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,242 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Tutorial metrics collection module.
|
|
4
|
+
* Tracks local, privacy-respecting analytics for tutorial usage.
|
|
5
|
+
*
|
|
6
|
+
* Metrics are stored in ~/.claude/tutorial-metrics.json
|
|
7
|
+
* No external telemetry - data stays on your machine.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const os = require('os');
|
|
13
|
+
|
|
14
|
+
// Metrics file location
|
|
15
|
+
const METRICS_DIR = path.join(os.homedir(), '.claude');
|
|
16
|
+
const METRICS_FILE = path.join(METRICS_DIR, 'tutorial-metrics.json');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Ensure the metrics directory exists.
|
|
20
|
+
*/
|
|
21
|
+
function ensureMetricsDir() {
|
|
22
|
+
if (!fs.existsSync(METRICS_DIR)) {
|
|
23
|
+
fs.mkdirSync(METRICS_DIR, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get default metrics state.
|
|
29
|
+
* @returns {object} Default metrics object
|
|
30
|
+
*/
|
|
31
|
+
function getDefaultMetrics() {
|
|
32
|
+
return {
|
|
33
|
+
lessonMetrics: {},
|
|
34
|
+
overallMetrics: {
|
|
35
|
+
startedAt: new Date().toISOString(),
|
|
36
|
+
completedAt: null,
|
|
37
|
+
totalSessions: 0,
|
|
38
|
+
totalTimeMs: 0,
|
|
39
|
+
},
|
|
40
|
+
activeLesson: null,
|
|
41
|
+
activeLessonStartTime: null,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Load metrics from file.
|
|
47
|
+
* @returns {object} Metrics state or default if not exists
|
|
48
|
+
*/
|
|
49
|
+
function loadMetrics() {
|
|
50
|
+
try {
|
|
51
|
+
if (fs.existsSync(METRICS_FILE)) {
|
|
52
|
+
const data = fs.readFileSync(METRICS_FILE, 'utf8');
|
|
53
|
+
return JSON.parse(data);
|
|
54
|
+
}
|
|
55
|
+
} catch {
|
|
56
|
+
// If file is corrupted, start fresh
|
|
57
|
+
}
|
|
58
|
+
return getDefaultMetrics();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Save metrics to file.
|
|
63
|
+
* @param {object} metrics - Metrics state to save
|
|
64
|
+
*/
|
|
65
|
+
function saveMetrics(metrics) {
|
|
66
|
+
ensureMetricsDir();
|
|
67
|
+
fs.writeFileSync(METRICS_FILE, JSON.stringify(metrics, null, 2));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Record that a lesson was started/viewed.
|
|
72
|
+
* @param {number} lessonNum - Lesson number (1-9)
|
|
73
|
+
* @returns {object} Updated metrics
|
|
74
|
+
*/
|
|
75
|
+
function recordLessonStart(lessonNum) {
|
|
76
|
+
const metrics = loadMetrics();
|
|
77
|
+
|
|
78
|
+
// Initialize lesson metrics if needed
|
|
79
|
+
if (!metrics.lessonMetrics[lessonNum]) {
|
|
80
|
+
metrics.lessonMetrics[lessonNum] = {
|
|
81
|
+
visits: 0,
|
|
82
|
+
totalTimeMs: 0,
|
|
83
|
+
lastVisit: null,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Increment visit count
|
|
88
|
+
metrics.lessonMetrics[lessonNum].visits++;
|
|
89
|
+
metrics.lessonMetrics[lessonNum].lastVisit = new Date().toISOString();
|
|
90
|
+
|
|
91
|
+
// Track active lesson for time calculation
|
|
92
|
+
metrics.activeLesson = lessonNum;
|
|
93
|
+
metrics.activeLessonStartTime = Date.now();
|
|
94
|
+
|
|
95
|
+
saveMetrics(metrics);
|
|
96
|
+
return metrics;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Record that a lesson was completed/ended.
|
|
101
|
+
* @param {number} lessonNum - Lesson number (1-9)
|
|
102
|
+
* @returns {object} Updated metrics
|
|
103
|
+
*/
|
|
104
|
+
function recordLessonEnd(lessonNum) {
|
|
105
|
+
const metrics = loadMetrics();
|
|
106
|
+
|
|
107
|
+
// Calculate time spent if this was the active lesson
|
|
108
|
+
if (metrics.activeLesson === lessonNum && metrics.activeLessonStartTime) {
|
|
109
|
+
const timeSpent = Date.now() - metrics.activeLessonStartTime;
|
|
110
|
+
|
|
111
|
+
if (!metrics.lessonMetrics[lessonNum]) {
|
|
112
|
+
metrics.lessonMetrics[lessonNum] = {
|
|
113
|
+
visits: 1,
|
|
114
|
+
totalTimeMs: 0,
|
|
115
|
+
lastVisit: new Date().toISOString(),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
metrics.lessonMetrics[lessonNum].totalTimeMs += timeSpent;
|
|
120
|
+
metrics.overallMetrics.totalTimeMs += timeSpent;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Clear active lesson
|
|
124
|
+
metrics.activeLesson = null;
|
|
125
|
+
metrics.activeLessonStartTime = null;
|
|
126
|
+
|
|
127
|
+
saveMetrics(metrics);
|
|
128
|
+
return metrics;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Record a new session.
|
|
133
|
+
* @returns {object} Updated metrics
|
|
134
|
+
*/
|
|
135
|
+
function recordSession() {
|
|
136
|
+
const metrics = loadMetrics();
|
|
137
|
+
metrics.overallMetrics.totalSessions++;
|
|
138
|
+
saveMetrics(metrics);
|
|
139
|
+
return metrics;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Mark tutorial as completed.
|
|
144
|
+
* @returns {object} Updated metrics
|
|
145
|
+
*/
|
|
146
|
+
function markComplete() {
|
|
147
|
+
const metrics = loadMetrics();
|
|
148
|
+
metrics.overallMetrics.completedAt = new Date().toISOString();
|
|
149
|
+
saveMetrics(metrics);
|
|
150
|
+
return metrics;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Format milliseconds as human-readable time.
|
|
155
|
+
* @param {number} ms - Milliseconds
|
|
156
|
+
* @returns {string} Formatted time string
|
|
157
|
+
*/
|
|
158
|
+
function formatTime(ms) {
|
|
159
|
+
if (ms < 1000) return '< 1s';
|
|
160
|
+
|
|
161
|
+
const seconds = Math.floor(ms / 1000);
|
|
162
|
+
const minutes = Math.floor(seconds / 60);
|
|
163
|
+
const hours = Math.floor(minutes / 60);
|
|
164
|
+
|
|
165
|
+
if (hours > 0) {
|
|
166
|
+
const remainingMinutes = minutes % 60;
|
|
167
|
+
return `${hours}h ${remainingMinutes}m`;
|
|
168
|
+
}
|
|
169
|
+
if (minutes > 0) {
|
|
170
|
+
const remainingSeconds = seconds % 60;
|
|
171
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
172
|
+
}
|
|
173
|
+
return `${seconds}s`;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Get summary statistics.
|
|
178
|
+
* @returns {object} Stats object
|
|
179
|
+
*/
|
|
180
|
+
function getStats() {
|
|
181
|
+
const metrics = loadMetrics();
|
|
182
|
+
|
|
183
|
+
// Calculate most visited lesson
|
|
184
|
+
let mostVisited = null;
|
|
185
|
+
let maxVisits = 0;
|
|
186
|
+
|
|
187
|
+
for (const [lessonNum, data] of Object.entries(metrics.lessonMetrics)) {
|
|
188
|
+
if (data.visits > maxVisits) {
|
|
189
|
+
maxVisits = data.visits;
|
|
190
|
+
mostVisited = parseInt(lessonNum, 10);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Calculate average time per lesson
|
|
195
|
+
const lessonCount = Object.keys(metrics.lessonMetrics).length;
|
|
196
|
+
const avgTimeMs = lessonCount > 0 ? metrics.overallMetrics.totalTimeMs / lessonCount : 0;
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
totalTime: formatTime(metrics.overallMetrics.totalTimeMs),
|
|
200
|
+
totalTimeMs: metrics.overallMetrics.totalTimeMs,
|
|
201
|
+
totalSessions: metrics.overallMetrics.totalSessions,
|
|
202
|
+
lessonsVisited: lessonCount,
|
|
203
|
+
mostVisited: mostVisited,
|
|
204
|
+
mostVisitedCount: maxVisits,
|
|
205
|
+
averageTimePerLesson: formatTime(avgTimeMs),
|
|
206
|
+
startedAt: metrics.overallMetrics.startedAt,
|
|
207
|
+
completedAt: metrics.overallMetrics.completedAt,
|
|
208
|
+
lessonMetrics: metrics.lessonMetrics,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Reset all metrics.
|
|
214
|
+
* @returns {object} Fresh metrics state
|
|
215
|
+
*/
|
|
216
|
+
function resetMetrics() {
|
|
217
|
+
const metrics = getDefaultMetrics();
|
|
218
|
+
saveMetrics(metrics);
|
|
219
|
+
return metrics;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Check if metrics file exists.
|
|
224
|
+
* @returns {boolean} True if metrics file exists
|
|
225
|
+
*/
|
|
226
|
+
function hasMetrics() {
|
|
227
|
+
return fs.existsSync(METRICS_FILE);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
module.exports = {
|
|
231
|
+
METRICS_FILE,
|
|
232
|
+
loadMetrics,
|
|
233
|
+
saveMetrics,
|
|
234
|
+
recordLessonStart,
|
|
235
|
+
recordLessonEnd,
|
|
236
|
+
recordSession,
|
|
237
|
+
markComplete,
|
|
238
|
+
getStats,
|
|
239
|
+
resetMetrics,
|
|
240
|
+
hasMetrics,
|
|
241
|
+
formatTime,
|
|
242
|
+
};
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Tutorial progress persistence module.
|
|
4
|
+
* Manages progress state for the interactive tutorial system.
|
|
5
|
+
*
|
|
6
|
+
* Progress is stored in ~/.claude/tutorial-progress.json
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const os = require('os');
|
|
12
|
+
|
|
13
|
+
// Progress file location
|
|
14
|
+
const PROGRESS_DIR = path.join(os.homedir(), '.claude');
|
|
15
|
+
const PROGRESS_FILE = path.join(PROGRESS_DIR, 'tutorial-progress.json');
|
|
16
|
+
|
|
17
|
+
// Total lessons in the tutorial (lessons 0-14 = 15 lessons total)
|
|
18
|
+
const TOTAL_LESSONS = 15;
|
|
19
|
+
|
|
20
|
+
// Lesson metadata (lesson numbers 1-14 for display, but lesson 0 is Philosophy)
|
|
21
|
+
const LESSONS = [
|
|
22
|
+
{ num: 0, file: '00-philosophy-and-workflow.md', title: 'Philosophy & Workflow' },
|
|
23
|
+
{ num: 1, file: '01-basics.md', title: 'Core Concepts' },
|
|
24
|
+
{ num: 2, file: '02-training.md', title: 'Training Mode' },
|
|
25
|
+
{ num: 3, file: '03-commands.md', title: 'Essential Commands' },
|
|
26
|
+
{ num: 4, file: '04-workflows.md', title: 'Workflow Patterns' },
|
|
27
|
+
{ num: 5, file: '05-compliance.md', title: 'Compliance' },
|
|
28
|
+
{ num: 6, file: '06-zoho.md', title: 'Zoho Development' },
|
|
29
|
+
{ num: 7, file: '07-hooks-system.md', title: 'Hooks System' },
|
|
30
|
+
{ num: 8, file: '08-mcp-servers.md', title: 'MCP Servers' },
|
|
31
|
+
{ num: 9, file: '09-client-management.md', title: 'Client Management' },
|
|
32
|
+
{ num: 10, file: '10-testing-e2e.md', title: 'Testing & E2E' },
|
|
33
|
+
{ num: 11, file: '11-skills-deep-dive.md', title: 'Skills Deep Dive' },
|
|
34
|
+
{ num: 12, file: '12-rules-system.md', title: 'Rules System' },
|
|
35
|
+
{ num: 13, file: '13-golden-standard-graduation.md', title: 'Golden Standard Graduation' },
|
|
36
|
+
{ num: 14, file: '14-fork-setup-and-sync.md', title: 'Fork Setup & Sync' },
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Ensure the progress directory exists.
|
|
41
|
+
*/
|
|
42
|
+
function ensureProgressDir() {
|
|
43
|
+
if (!fs.existsSync(PROGRESS_DIR)) {
|
|
44
|
+
fs.mkdirSync(PROGRESS_DIR, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get default progress state.
|
|
50
|
+
* @returns {object} Default progress object
|
|
51
|
+
*/
|
|
52
|
+
function getDefaultProgress() {
|
|
53
|
+
return {
|
|
54
|
+
currentLesson: 0, // Start with lesson 0 (Philosophy)
|
|
55
|
+
completedLessons: [],
|
|
56
|
+
startedAt: new Date().toISOString(),
|
|
57
|
+
lastAccessed: new Date().toISOString(),
|
|
58
|
+
totalSessions: 1,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Load progress from file.
|
|
64
|
+
* @returns {object} Progress state or default if not exists
|
|
65
|
+
*/
|
|
66
|
+
function loadProgress() {
|
|
67
|
+
try {
|
|
68
|
+
if (fs.existsSync(PROGRESS_FILE)) {
|
|
69
|
+
const data = fs.readFileSync(PROGRESS_FILE, 'utf8');
|
|
70
|
+
const progress = JSON.parse(data);
|
|
71
|
+
// Update last accessed time
|
|
72
|
+
progress.lastAccessed = new Date().toISOString();
|
|
73
|
+
progress.totalSessions = (progress.totalSessions || 0) + 1;
|
|
74
|
+
return progress;
|
|
75
|
+
}
|
|
76
|
+
} catch {
|
|
77
|
+
// If file is corrupted, start fresh
|
|
78
|
+
}
|
|
79
|
+
return getDefaultProgress();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Save progress to file.
|
|
84
|
+
* @param {object} progress - Progress state to save
|
|
85
|
+
*/
|
|
86
|
+
function saveProgress(progress) {
|
|
87
|
+
ensureProgressDir();
|
|
88
|
+
progress.lastAccessed = new Date().toISOString();
|
|
89
|
+
fs.writeFileSync(PROGRESS_FILE, JSON.stringify(progress, null, 2));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Mark a lesson as completed.
|
|
94
|
+
* @param {number} lessonNum - Lesson number (0-14)
|
|
95
|
+
* @returns {object} Updated progress
|
|
96
|
+
*/
|
|
97
|
+
function completeLesson(lessonNum) {
|
|
98
|
+
const progress = loadProgress();
|
|
99
|
+
|
|
100
|
+
if (!progress.completedLessons.includes(lessonNum)) {
|
|
101
|
+
progress.completedLessons.push(lessonNum);
|
|
102
|
+
progress.completedLessons.sort((a, b) => a - b);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Move to next lesson if current (max lesson is TOTAL_LESSONS - 1)
|
|
106
|
+
if (lessonNum === progress.currentLesson && lessonNum < TOTAL_LESSONS - 1) {
|
|
107
|
+
progress.currentLesson = lessonNum + 1;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Check for completion
|
|
111
|
+
if (progress.completedLessons.length === TOTAL_LESSONS) {
|
|
112
|
+
progress.completedAt = new Date().toISOString();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
saveProgress(progress);
|
|
116
|
+
return progress;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Set the current lesson.
|
|
121
|
+
* @param {number} lessonNum - Lesson number (0-14)
|
|
122
|
+
* @returns {object} Updated progress
|
|
123
|
+
*/
|
|
124
|
+
function setCurrentLesson(lessonNum) {
|
|
125
|
+
if (lessonNum < 0 || lessonNum >= TOTAL_LESSONS) {
|
|
126
|
+
throw new Error(`Invalid lesson number: ${lessonNum}. Must be 0-${TOTAL_LESSONS - 1}`);
|
|
127
|
+
}
|
|
128
|
+
const progress = loadProgress();
|
|
129
|
+
progress.currentLesson = lessonNum;
|
|
130
|
+
saveProgress(progress);
|
|
131
|
+
return progress;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Reset all progress.
|
|
136
|
+
* @returns {object} Fresh progress state
|
|
137
|
+
*/
|
|
138
|
+
function resetProgress() {
|
|
139
|
+
const progress = getDefaultProgress();
|
|
140
|
+
saveProgress(progress);
|
|
141
|
+
return progress;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get completion percentage.
|
|
146
|
+
* @param {object} progress - Progress state
|
|
147
|
+
* @returns {number} Completion percentage (0-100)
|
|
148
|
+
*/
|
|
149
|
+
function getCompletionPercent(progress) {
|
|
150
|
+
return Math.round((progress.completedLessons.length / TOTAL_LESSONS) * 100);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Check if tutorial is complete.
|
|
155
|
+
* @param {object} progress - Progress state
|
|
156
|
+
* @returns {boolean} True if all lessons completed
|
|
157
|
+
*/
|
|
158
|
+
function isComplete(progress) {
|
|
159
|
+
return progress.completedLessons.length === TOTAL_LESSONS;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Get lesson info by number.
|
|
164
|
+
* @param {number} lessonNum - Lesson number (0-14)
|
|
165
|
+
* @returns {object|null} Lesson info or null
|
|
166
|
+
*/
|
|
167
|
+
function getLessonInfo(lessonNum) {
|
|
168
|
+
return LESSONS.find((l) => l.num === lessonNum) || null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Get lesson status for display.
|
|
173
|
+
* @param {object} progress - Progress state
|
|
174
|
+
* @param {number} lessonNum - Lesson number
|
|
175
|
+
* @returns {string} Status: 'completed', 'current', or 'pending'
|
|
176
|
+
*/
|
|
177
|
+
function getLessonStatus(progress, lessonNum) {
|
|
178
|
+
if (progress.completedLessons.includes(lessonNum)) {
|
|
179
|
+
return 'completed';
|
|
180
|
+
}
|
|
181
|
+
if (lessonNum === progress.currentLesson) {
|
|
182
|
+
return 'current';
|
|
183
|
+
}
|
|
184
|
+
return 'pending';
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Check if progress file exists.
|
|
189
|
+
* @returns {boolean} True if progress file exists
|
|
190
|
+
*/
|
|
191
|
+
function hasProgress() {
|
|
192
|
+
return fs.existsSync(PROGRESS_FILE);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
module.exports = {
|
|
196
|
+
TOTAL_LESSONS,
|
|
197
|
+
LESSONS,
|
|
198
|
+
PROGRESS_FILE,
|
|
199
|
+
loadProgress,
|
|
200
|
+
saveProgress,
|
|
201
|
+
completeLesson,
|
|
202
|
+
setCurrentLesson,
|
|
203
|
+
resetProgress,
|
|
204
|
+
getCompletionPercent,
|
|
205
|
+
isComplete,
|
|
206
|
+
getLessonInfo,
|
|
207
|
+
getLessonStatus,
|
|
208
|
+
hasProgress,
|
|
209
|
+
};
|