claude-spp 0.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.
Files changed (47) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.md +147 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +164 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/config/loader.d.ts +29 -0
  8. package/dist/config/loader.d.ts.map +1 -0
  9. package/dist/config/loader.js +81 -0
  10. package/dist/config/loader.js.map +1 -0
  11. package/dist/config/schema.d.ts +84 -0
  12. package/dist/config/schema.d.ts.map +1 -0
  13. package/dist/config/schema.js +104 -0
  14. package/dist/config/schema.js.map +1 -0
  15. package/dist/git/history.d.ts +55 -0
  16. package/dist/git/history.d.ts.map +1 -0
  17. package/dist/git/history.js +376 -0
  18. package/dist/git/history.js.map +1 -0
  19. package/dist/hooks/file-matcher.d.ts +22 -0
  20. package/dist/hooks/file-matcher.d.ts.map +1 -0
  21. package/dist/hooks/file-matcher.js +86 -0
  22. package/dist/hooks/file-matcher.js.map +1 -0
  23. package/dist/hooks/index.d.ts +4 -0
  24. package/dist/hooks/index.d.ts.map +1 -0
  25. package/dist/hooks/index.js +4 -0
  26. package/dist/hooks/index.js.map +1 -0
  27. package/dist/hooks/pre-tool-use.d.ts +35 -0
  28. package/dist/hooks/pre-tool-use.d.ts.map +1 -0
  29. package/dist/hooks/pre-tool-use.js +132 -0
  30. package/dist/hooks/pre-tool-use.js.map +1 -0
  31. package/dist/hooks/system-prompt.d.ts +9 -0
  32. package/dist/hooks/system-prompt.d.ts.map +1 -0
  33. package/dist/hooks/system-prompt.js +88 -0
  34. package/dist/hooks/system-prompt.js.map +1 -0
  35. package/dist/index.d.ts +8 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +13 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/init.d.ts +25 -0
  40. package/dist/init.d.ts.map +1 -0
  41. package/dist/init.js +274 -0
  42. package/dist/init.js.map +1 -0
  43. package/dist/stats.d.ts +40 -0
  44. package/dist/stats.d.ts.map +1 -0
  45. package/dist/stats.js +146 -0
  46. package/dist/stats.js.map +1 -0
  47. package/package.json +41 -0
package/dist/stats.js ADDED
@@ -0,0 +1,146 @@
1
+ import { loadConfig, isSppInitialized } from "./config/loader.js";
2
+ import { getEffectiveRatio, getCurrentMode, getStatsWindowCutoff, STATS_WINDOW_LABELS, TRACKING_MODE_LABELS, } from "./config/schema.js";
3
+ import { getLineCountsWithWindow, getCommitInfo } from "./git/history.js";
4
+ /**
5
+ * Calculate the current human work ratio from line counts
6
+ * Returns 1.0 if no work has been done yet (human is at 100% until Claude does something)
7
+ */
8
+ export function calculateRatio(humanLines, claudeLines) {
9
+ const total = humanLines + claudeLines;
10
+ if (total === 0) {
11
+ return 1.0; // No work yet, human is at 100%
12
+ }
13
+ return humanLines / total;
14
+ }
15
+ /**
16
+ * Check if the human work ratio meets the target
17
+ */
18
+ export function isRatioHealthy(humanLines, claudeLines, targetRatio) {
19
+ return calculateRatio(humanLines, claudeLines) >= targetRatio;
20
+ }
21
+ /**
22
+ * Get current SPP statistics
23
+ */
24
+ export function getStats(projectPath) {
25
+ if (!isSppInitialized(projectPath)) {
26
+ return { initialized: false };
27
+ }
28
+ const config = loadConfig(projectPath);
29
+ const statsWindow = config.statsWindow ?? "oneWeek";
30
+ const trackingMode = config.trackingMode ?? "commits";
31
+ const targetRatio = getEffectiveRatio(config);
32
+ const mode = getCurrentMode(config);
33
+ // Get counts for ratio calculation
34
+ // Filter by trackingStartCommit (if set) and statsWindow cutoff
35
+ const statsWindowCutoff = getStatsWindowCutoff(statsWindow);
36
+ const lineCounts = getLineCountsWithWindow(projectPath, {
37
+ since: statsWindowCutoff,
38
+ afterCommit: config.trackingStartCommit,
39
+ });
40
+ // Calculate ratio based on tracking mode
41
+ const humanValue = trackingMode === "commits" ? lineCounts.humanCommits : lineCounts.humanLines;
42
+ const claudeValue = trackingMode === "commits" ? lineCounts.claudeCommits : lineCounts.claudeLines;
43
+ const currentRatio = calculateRatio(humanValue, claudeValue);
44
+ const ratioHealthy = isRatioHealthy(humanValue, claudeValue, targetRatio);
45
+ return {
46
+ initialized: true,
47
+ enabled: config.enabled,
48
+ mode,
49
+ targetRatio,
50
+ currentRatio,
51
+ ratioHealthy,
52
+ statsWindow,
53
+ trackingMode,
54
+ lines: lineCounts,
55
+ };
56
+ }
57
+ /**
58
+ * Format stats for display
59
+ */
60
+ export function formatStats(stats) {
61
+ if (!stats.initialized) {
62
+ return "SPP is not initialized in this project. Run `spp init` to get started.";
63
+ }
64
+ const trackingMode = stats.trackingMode ?? "commits";
65
+ const target = stats.targetRatio ?? 0;
66
+ const ratio = stats.currentRatio ?? 1;
67
+ const windowLabel = stats.statsWindow ? STATS_WINDOW_LABELS[stats.statsWindow] : "All time";
68
+ const trackingLabel = TRACKING_MODE_LABELS[trackingMode];
69
+ // Get values based on tracking mode for catch-up calculation
70
+ const humanValue = trackingMode === "commits"
71
+ ? (stats.lines?.humanCommits ?? 0)
72
+ : (stats.lines?.humanLines ?? 0);
73
+ const claudeValue = trackingMode === "commits"
74
+ ? (stats.lines?.claudeCommits ?? 0)
75
+ : (stats.lines?.claudeLines ?? 0);
76
+ const unit = trackingMode === "commits" ? "commits" : "lines";
77
+ // Build status line
78
+ let statusLine;
79
+ if (claudeValue + humanValue === 0) {
80
+ statusLine = `βœ… πŸ’ No ${trackingMode} tracked yet. Go commit some code and check again.`;
81
+ }
82
+ else if (stats.ratioHealthy) {
83
+ statusLine = `βœ… πŸ’ Human coding on target. Current: ${(ratio * 100).toFixed(0)}% Target: ${(target * 100).toFixed(0)}%. Keep up the great work!`;
84
+ }
85
+ else {
86
+ // Calculate how many more commits/lines needed to catch up
87
+ const total = humanValue + claudeValue;
88
+ if (target >= 1) {
89
+ statusLine = `⚠️ πŸ™‰ Human coding below target. Current: ${(ratio * 100).toFixed(0)}% Target: ${(target * 100).toFixed(0)}%. Claude has written ${claudeValue} ${unit}.`;
90
+ }
91
+ else {
92
+ const needed = Math.ceil((target * total - humanValue) / (1 - target));
93
+ statusLine = `⚠️ πŸ™‰ Human coding below target. Current: ${(ratio * 100).toFixed(0)}% Target: ${(target * 100).toFixed(0)}%. Write ${needed} more ${unit} to catch up. You can do it!`;
94
+ }
95
+ }
96
+ // Format counts with alignment
97
+ const humanLinesStr = String(stats.lines?.humanLines ?? 0);
98
+ const claudeLinesStr = String(stats.lines?.claudeLines ?? 0);
99
+ const humanCommitsStr = String(stats.lines?.humanCommits ?? 0);
100
+ const claudeCommitsStr = String(stats.lines?.claudeCommits ?? 0);
101
+ const maxLines = Math.max(humanLinesStr.length, claudeLinesStr.length);
102
+ const maxCommits = Math.max(humanCommitsStr.length, claudeCommitsStr.length);
103
+ // Build aligned table (no borders)
104
+ const labelWidth = 10;
105
+ const modeValue = `${stats.mode?.name} (${stats.mode?.description})`;
106
+ // Determine tracking window display
107
+ // If trackingStartCommit is set and within the stats window, show commit info instead
108
+ const config = loadConfig(process.cwd());
109
+ let trackingValue = `${trackingLabel} (${windowLabel})`;
110
+ if (config.trackingStartCommit) {
111
+ const commitInfo = getCommitInfo(process.cwd(), config.trackingStartCommit);
112
+ if (commitInfo) {
113
+ const statsWindowCutoff = getStatsWindowCutoff(stats.statsWindow ?? "oneWeek");
114
+ // If no cutoff (allTime) or commit is within the window, show commit info
115
+ if (!statsWindowCutoff || commitInfo.date >= statsWindowCutoff) {
116
+ const truncatedTitle = commitInfo.title.length > 16
117
+ ? commitInfo.title.substring(0, 16) + "..."
118
+ : commitInfo.title;
119
+ const dateStr = commitInfo.date.toLocaleDateString();
120
+ trackingValue = `${trackingLabel} since: ${commitInfo.shortHash} "${truncatedTitle}" ${dateStr}`;
121
+ }
122
+ }
123
+ }
124
+ const lines = [
125
+ "",
126
+ statusLine,
127
+ "",
128
+ ` ${"Mode".padEnd(labelWidth)} ${modeValue}`,
129
+ ` ${"Tracking".padEnd(labelWidth)} ${trackingValue}`,
130
+ "",
131
+ ` ${"Human".padEnd(labelWidth)} ${humanCommitsStr.padStart(maxCommits)} commits ${humanLinesStr.padStart(maxLines)} lines`,
132
+ ` ${"Claude".padEnd(labelWidth)} ${claudeCommitsStr.padStart(maxCommits)} commits ${claudeLinesStr.padStart(maxLines)} lines`,
133
+ "",
134
+ ];
135
+ if (!stats.enabled) {
136
+ const config = loadConfig(process.cwd());
137
+ let pauseMsg = "SPP is disabled";
138
+ if (config.pausedUntil) {
139
+ const pausedUntilDate = new Date(config.pausedUntil);
140
+ pauseMsg = `⏸️ SPP enforcement is paused until ${pausedUntilDate.toLocaleString()}. Claude may write code freely. Run 'spp resume' to unpause.`;
141
+ }
142
+ lines.splice(1, 0, pauseMsg, "");
143
+ }
144
+ return lines.join("\n");
145
+ }
146
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../src/stats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAc,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GAIrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE1E;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,UAAkB,EAAE,WAAmB;IACpE,MAAM,KAAK,GAAG,UAAU,GAAG,WAAW,CAAC;IACvC,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,OAAO,GAAG,CAAC,CAAC,gCAAgC;IAC9C,CAAC;IACD,OAAO,UAAU,GAAG,KAAK,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,UAAkB,EAAE,WAAmB,EAAE,WAAmB;IACzF,OAAO,cAAc,CAAC,UAAU,EAAE,WAAW,CAAC,IAAI,WAAW,CAAC;AAChE,CAAC;AAwBD;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,WAAmB;IAC1C,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,EAAE,CAAC;QACnC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;IAChC,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACvC,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,SAAS,CAAC;IACpD,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,IAAI,SAAS,CAAC;IACtD,MAAM,WAAW,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAEpC,mCAAmC;IACnC,gEAAgE;IAChE,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC;IAC5D,MAAM,UAAU,GAAG,uBAAuB,CAAC,WAAW,EAAE;QACtD,KAAK,EAAE,iBAAiB;QACxB,WAAW,EAAE,MAAM,CAAC,mBAAmB;KACxC,CAAC,CAAC;IAEH,yCAAyC;IACzC,MAAM,UAAU,GAAG,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;IAChG,MAAM,WAAW,GAAG,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC;IACnG,MAAM,YAAY,GAAG,cAAc,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IAC7D,MAAM,YAAY,GAAG,cAAc,CAAC,UAAU,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;IAE1E,OAAO;QACL,WAAW,EAAE,IAAI;QACjB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,IAAI;QACJ,WAAW;QACX,YAAY;QACZ,YAAY;QACZ,WAAW;QACX,YAAY;QACZ,KAAK,EAAE,UAAU;KAClB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,KAAkB;IAC5C,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QACvB,OAAO,wEAAwE,CAAC;IAClF,CAAC;IAED,MAAM,YAAY,GAAG,KAAK,CAAC,YAAY,IAAI,SAAS,CAAC;IACrD,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,IAAI,CAAC,CAAC;IACtC,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IAC5F,MAAM,aAAa,GAAG,oBAAoB,CAAC,YAAY,CAAC,CAAC;IAEzD,6DAA6D;IAC7D,MAAM,UAAU,GAAG,YAAY,KAAK,SAAS;QAC3C,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,YAAY,IAAI,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,UAAU,IAAI,CAAC,CAAC,CAAC;IACnC,MAAM,WAAW,GAAG,YAAY,KAAK,SAAS;QAC5C,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,aAAa,IAAI,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,WAAW,IAAI,CAAC,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;IAE9D,oBAAoB;IACpB,IAAI,UAAkB,CAAC;IACvB,IAAI,WAAW,GAAG,UAAU,KAAK,CAAC,EAAE,CAAC;QACnC,UAAU,GAAG,WAAW,YAAY,oDAAoD,CAAC;IAC3F,CAAC;SAAM,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;QAC9B,UAAU,GAAG,yCAAyC,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAC;IACnJ,CAAC;SAAM,CAAC;QACN,2DAA2D;QAC3D,MAAM,KAAK,GAAG,UAAU,GAAG,WAAW,CAAC;QACvC,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;YAChB,UAAU,GAAG,6CAA6C,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB,WAAW,IAAI,IAAI,GAAG,CAAC;QAC1K,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;YACvE,UAAU,GAAG,8CAA8C,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,MAAM,SAAS,IAAI,8BAA8B,CAAC;QACzL,CAAC;IACH,CAAC;IAED,+BAA+B;IAC/B,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,UAAU,IAAI,CAAC,CAAC,CAAC;IAC3D,MAAM,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,WAAW,IAAI,CAAC,CAAC,CAAC;IAC7D,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,YAAY,IAAI,CAAC,CAAC,CAAC;IAC/D,MAAM,gBAAgB,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,aAAa,IAAI,CAAC,CAAC,CAAC;IACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACvE,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAE7E,mCAAmC;IACnC,MAAM,UAAU,GAAG,EAAE,CAAC;IACtB,MAAM,SAAS,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,KAAK,KAAK,CAAC,IAAI,EAAE,WAAW,GAAG,CAAC;IAErE,oCAAoC;IACpC,sFAAsF;IACtF,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACzC,IAAI,aAAa,GAAG,GAAG,aAAa,KAAK,WAAW,GAAG,CAAC;IAExD,IAAI,MAAM,CAAC,mBAAmB,EAAE,CAAC;QAC/B,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,mBAAmB,CAAC,CAAC;QAC5E,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,KAAK,CAAC,WAAW,IAAI,SAAS,CAAC,CAAC;YAC/E,0EAA0E;YAC1E,IAAI,CAAC,iBAAiB,IAAI,UAAU,CAAC,IAAI,IAAI,iBAAiB,EAAE,CAAC;gBAC/D,MAAM,cAAc,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,GAAG,EAAE;oBACjD,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK;oBAC3C,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC;gBACrB,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBACrD,aAAa,GAAG,GAAG,aAAa,WAAW,UAAU,CAAC,SAAS,KAAK,cAAc,KAAK,OAAO,EAAE,CAAC;YACnG,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAa;QACtB,EAAE;QACF,UAAU;QACV,EAAE;QACF,KAAK,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,SAAS,EAAE;QAC7C,KAAK,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,aAAa,EAAE;QACrD,EAAE;QACF,KAAK,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,eAAe,CAAC,QAAQ,CAAC,UAAU,CAAC,cAAc,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ;QAC7H,KAAK,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,gBAAgB,CAAC,QAAQ,CAAC,UAAU,CAAC,cAAc,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ;QAChI,EAAE;KACH,CAAC;IAEF,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACnB,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QACzC,IAAI,QAAQ,GAAG,iBAAiB,CAAC;QACjC,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YACvB,MAAM,eAAe,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YACrD,QAAQ,GAAG,uCAAuC,eAAe,CAAC,cAAc,EAAE,8DAA8D,CAAC;QACnJ,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "claude-spp",
3
+ "version": "0.1.0",
4
+ "description": "Claude Code plugin for maintaining programming skills through guided learning",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "spp": "./dist/cli.js"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "lint": "eslint src",
18
+ "test": "vitest run",
19
+ "test:watch": "vitest",
20
+ "test:coverage": "vitest run --coverage"
21
+ },
22
+ "keywords": [
23
+ "claude",
24
+ "claude-code",
25
+ "learning",
26
+ "teaching",
27
+ "programming"
28
+ ],
29
+ "author": "",
30
+ "license": "MIT",
31
+ "dependencies": {
32
+ "commander": "^14.0.2",
33
+ "zod": "^3.22.4"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^20.10.0",
37
+ "tsx": "^4.7.0",
38
+ "typescript": "^5.3.0",
39
+ "vitest": "^1.0.0"
40
+ }
41
+ }