@opslane/claude-code-game 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 (201) hide show
  1. package/dist/cli.d.ts +2 -0
  2. package/dist/cli.js +59 -0
  3. package/dist/cli.js.map +1 -0
  4. package/dist/routes/auth.d.ts +1 -0
  5. package/dist/routes/auth.js +123 -0
  6. package/dist/routes/auth.js.map +1 -0
  7. package/dist/routes/levels.d.ts +44 -0
  8. package/dist/routes/levels.js +78 -0
  9. package/dist/routes/levels.js.map +1 -0
  10. package/dist/routes/sessions.d.ts +17 -0
  11. package/dist/routes/sessions.js +303 -0
  12. package/dist/routes/sessions.js.map +1 -0
  13. package/dist/server.d.ts +2 -0
  14. package/dist/server.js +58 -0
  15. package/dist/server.js.map +1 -0
  16. package/dist/terminal.d.ts +6 -0
  17. package/dist/terminal.js +23 -0
  18. package/dist/terminal.js.map +1 -0
  19. package/dist/verification.d.ts +31 -0
  20. package/dist/verification.js +239 -0
  21. package/dist/verification.js.map +1 -0
  22. package/frontend/assets/index-CNVEnbfs.css +1 -0
  23. package/frontend/assets/index-D70xl9zu.js +27 -0
  24. package/frontend/index.html +14 -0
  25. package/frontend/vite.svg +1 -0
  26. package/keys/v1.pem +9 -0
  27. package/levels/01-context-is-everything/exercise/README.md +152 -0
  28. package/levels/01-context-is-everything/exercise/data/expenses.db +0 -0
  29. package/levels/01-context-is-everything/exercise/database.py +171 -0
  30. package/levels/01-context-is-everything/exercise/docs/FIRECRAWL_QUICKSTART.md +212 -0
  31. package/levels/01-context-is-everything/exercise/historical_data/expenses_2024_01.json +2306 -0
  32. package/levels/01-context-is-everything/exercise/historical_data/expenses_2024_02.json +2394 -0
  33. package/levels/01-context-is-everything/exercise/historical_data/expenses_2024_03.json +2251 -0
  34. package/levels/01-context-is-everything/exercise/historical_data/expenses_2024_04.json +1987 -0
  35. package/levels/01-context-is-everything/exercise/historical_data/expenses_2024_05.json +2229 -0
  36. package/levels/01-context-is-everything/exercise/main.py +97 -0
  37. package/levels/01-context-is-everything/exercise/models.py +141 -0
  38. package/levels/01-context-is-everything/exercise/pyproject.toml +52 -0
  39. package/levels/01-context-is-everything/exercise/reports.py +138 -0
  40. package/levels/01-context-is-everything/exercise/seed_data.py +91 -0
  41. package/levels/01-context-is-everything/exercise/tests/__init__.py +1 -0
  42. package/levels/01-context-is-everything/exercise/tests/conftest.py +69 -0
  43. package/levels/01-context-is-everything/exercise/tests/test_database.py +244 -0
  44. package/levels/01-context-is-everything/exercise/tests/test_models.py +240 -0
  45. package/levels/01-context-is-everything/exercise/tests/test_reports.py +190 -0
  46. package/levels/01-context-is-everything/exercise/utils.py +163 -0
  47. package/levels/01-context-is-everything/lesson.yaml +82 -0
  48. package/levels/02-claude-md/exercise/README.md +152 -0
  49. package/levels/02-claude-md/exercise/data/expenses.db +0 -0
  50. package/levels/02-claude-md/exercise/database.py +171 -0
  51. package/levels/02-claude-md/exercise/main.py +97 -0
  52. package/levels/02-claude-md/exercise/models.py +141 -0
  53. package/levels/02-claude-md/exercise/pyproject.toml +52 -0
  54. package/levels/02-claude-md/exercise/reports.py +138 -0
  55. package/levels/02-claude-md/exercise/seed_data.py +91 -0
  56. package/levels/02-claude-md/exercise/tests/__init__.py +1 -0
  57. package/levels/02-claude-md/exercise/tests/conftest.py +69 -0
  58. package/levels/02-claude-md/exercise/tests/test_database.py +244 -0
  59. package/levels/02-claude-md/exercise/tests/test_models.py +240 -0
  60. package/levels/02-claude-md/exercise/tests/test_reports.py +190 -0
  61. package/levels/02-claude-md/exercise/utils.py +163 -0
  62. package/levels/02-claude-md/lesson.yaml +60 -0
  63. package/levels/03-read-edit-verify/exercise/CLAUDE.md +15 -0
  64. package/levels/03-read-edit-verify/exercise/README.md +152 -0
  65. package/levels/03-read-edit-verify/exercise/data/expenses.db +0 -0
  66. package/levels/03-read-edit-verify/exercise/database.py +171 -0
  67. package/levels/03-read-edit-verify/exercise/main.py +97 -0
  68. package/levels/03-read-edit-verify/exercise/models.py +141 -0
  69. package/levels/03-read-edit-verify/exercise/pyproject.toml +52 -0
  70. package/levels/03-read-edit-verify/exercise/reports.py +138 -0
  71. package/levels/03-read-edit-verify/exercise/seed_data.py +91 -0
  72. package/levels/03-read-edit-verify/exercise/tests/__init__.py +1 -0
  73. package/levels/03-read-edit-verify/exercise/tests/conftest.py +69 -0
  74. package/levels/03-read-edit-verify/exercise/tests/test_database.py +244 -0
  75. package/levels/03-read-edit-verify/exercise/tests/test_models.py +240 -0
  76. package/levels/03-read-edit-verify/exercise/tests/test_reports.py +190 -0
  77. package/levels/03-read-edit-verify/exercise/utils.py +163 -0
  78. package/levels/03-read-edit-verify/lesson.yaml +60 -0
  79. package/levels/04-planning-mode/exercise/README.md +152 -0
  80. package/levels/04-planning-mode/exercise/data/expenses.db +0 -0
  81. package/levels/04-planning-mode/exercise/database.py +171 -0
  82. package/levels/04-planning-mode/exercise/main.py +97 -0
  83. package/levels/04-planning-mode/exercise/models.py +116 -0
  84. package/levels/04-planning-mode/exercise/pyproject.toml +52 -0
  85. package/levels/04-planning-mode/exercise/reports.py +138 -0
  86. package/levels/04-planning-mode/exercise/seed_data.py +91 -0
  87. package/levels/04-planning-mode/exercise/tests/__init__.py +1 -0
  88. package/levels/04-planning-mode/exercise/tests/conftest.py +69 -0
  89. package/levels/04-planning-mode/exercise/tests/test_database.py +244 -0
  90. package/levels/04-planning-mode/exercise/tests/test_expenses.db +0 -0
  91. package/levels/04-planning-mode/exercise/tests/test_models.py +240 -0
  92. package/levels/04-planning-mode/exercise/tests/test_reports.py +190 -0
  93. package/levels/04-planning-mode/exercise/utils.py +163 -0
  94. package/levels/04-planning-mode/lesson.yaml +53 -0
  95. package/levels/05-spec-driven/exercise/README.md +152 -0
  96. package/levels/05-spec-driven/exercise/data/expenses.db +0 -0
  97. package/levels/05-spec-driven/exercise/database.py +171 -0
  98. package/levels/05-spec-driven/exercise/main.py +97 -0
  99. package/levels/05-spec-driven/exercise/models.py +116 -0
  100. package/levels/05-spec-driven/exercise/pyproject.toml +52 -0
  101. package/levels/05-spec-driven/exercise/reports.py +138 -0
  102. package/levels/05-spec-driven/exercise/seed_data.py +91 -0
  103. package/levels/05-spec-driven/exercise/tests/__init__.py +1 -0
  104. package/levels/05-spec-driven/exercise/tests/conftest.py +69 -0
  105. package/levels/05-spec-driven/exercise/tests/test_database.py +244 -0
  106. package/levels/05-spec-driven/exercise/tests/test_expenses.db +0 -0
  107. package/levels/05-spec-driven/exercise/tests/test_models.py +240 -0
  108. package/levels/05-spec-driven/exercise/tests/test_reports.py +190 -0
  109. package/levels/05-spec-driven/exercise/utils.py +163 -0
  110. package/levels/05-spec-driven/lesson.yaml +53 -0
  111. package/levels/06-sub-agents/exercise/README.md +152 -0
  112. package/levels/06-sub-agents/exercise/data/expenses.db +0 -0
  113. package/levels/06-sub-agents/exercise/database.py +171 -0
  114. package/levels/06-sub-agents/exercise/main.py +97 -0
  115. package/levels/06-sub-agents/exercise/models.py +116 -0
  116. package/levels/06-sub-agents/exercise/pyproject.toml +52 -0
  117. package/levels/06-sub-agents/exercise/reports.py +63 -0
  118. package/levels/06-sub-agents/exercise/seed_data.py +91 -0
  119. package/levels/06-sub-agents/exercise/tests/__init__.py +1 -0
  120. package/levels/06-sub-agents/exercise/tests/conftest.py +69 -0
  121. package/levels/06-sub-agents/exercise/tests/test_database.py +244 -0
  122. package/levels/06-sub-agents/exercise/tests/test_models.py +240 -0
  123. package/levels/06-sub-agents/exercise/tests/test_reports.py +190 -0
  124. package/levels/06-sub-agents/exercise/utils.py +163 -0
  125. package/levels/06-sub-agents/lesson.yaml +49 -0
  126. package/levels/07-skills/exercise/README.md +152 -0
  127. package/levels/07-skills/exercise/data/expenses.db +0 -0
  128. package/levels/07-skills/exercise/database.py +171 -0
  129. package/levels/07-skills/exercise/main.py +97 -0
  130. package/levels/07-skills/exercise/models.py +116 -0
  131. package/levels/07-skills/exercise/pyproject.toml +52 -0
  132. package/levels/07-skills/exercise/reports.py +63 -0
  133. package/levels/07-skills/exercise/seed_data.py +91 -0
  134. package/levels/07-skills/exercise/tests/__init__.py +1 -0
  135. package/levels/07-skills/exercise/tests/conftest.py +69 -0
  136. package/levels/07-skills/exercise/tests/test_database.py +244 -0
  137. package/levels/07-skills/exercise/tests/test_models.py +240 -0
  138. package/levels/07-skills/exercise/tests/test_reports.py +190 -0
  139. package/levels/07-skills/exercise/utils.py +163 -0
  140. package/levels/07-skills/lesson.yaml +49 -0
  141. package/levels/08-mcp-servers/exercise/README.md +152 -0
  142. package/levels/08-mcp-servers/exercise/data/expenses.db +0 -0
  143. package/levels/08-mcp-servers/exercise/database.py +171 -0
  144. package/levels/08-mcp-servers/exercise/main.py +97 -0
  145. package/levels/08-mcp-servers/exercise/models.py +116 -0
  146. package/levels/08-mcp-servers/exercise/pyproject.toml +52 -0
  147. package/levels/08-mcp-servers/exercise/reports.py +63 -0
  148. package/levels/08-mcp-servers/exercise/seed_data.py +91 -0
  149. package/levels/08-mcp-servers/exercise/tests/__init__.py +1 -0
  150. package/levels/08-mcp-servers/exercise/tests/conftest.py +69 -0
  151. package/levels/08-mcp-servers/exercise/tests/test_database.py +244 -0
  152. package/levels/08-mcp-servers/exercise/tests/test_models.py +240 -0
  153. package/levels/08-mcp-servers/exercise/tests/test_reports.py +190 -0
  154. package/levels/08-mcp-servers/exercise/utils.py +163 -0
  155. package/levels/08-mcp-servers/lesson.yaml +59 -0
  156. package/levels/09-plugins/exercise/README.md +152 -0
  157. package/levels/09-plugins/exercise/data/expenses.db +0 -0
  158. package/levels/09-plugins/exercise/database.py +171 -0
  159. package/levels/09-plugins/exercise/main.py +97 -0
  160. package/levels/09-plugins/exercise/models.py +116 -0
  161. package/levels/09-plugins/exercise/pyproject.toml +52 -0
  162. package/levels/09-plugins/exercise/reports.py +63 -0
  163. package/levels/09-plugins/exercise/seed_data.py +91 -0
  164. package/levels/09-plugins/exercise/tests/__init__.py +1 -0
  165. package/levels/09-plugins/exercise/tests/conftest.py +69 -0
  166. package/levels/09-plugins/exercise/tests/test_database.py +244 -0
  167. package/levels/09-plugins/exercise/tests/test_models.py +240 -0
  168. package/levels/09-plugins/exercise/tests/test_reports.py +190 -0
  169. package/levels/09-plugins/exercise/utils.py +163 -0
  170. package/levels/09-plugins/lesson.yaml +51 -0
  171. package/levels/10-hooks/exercise/README.md +152 -0
  172. package/levels/10-hooks/exercise/data/expenses.db +0 -0
  173. package/levels/10-hooks/exercise/database.py +171 -0
  174. package/levels/10-hooks/exercise/main.py +97 -0
  175. package/levels/10-hooks/exercise/models.py +116 -0
  176. package/levels/10-hooks/exercise/pyproject.toml +52 -0
  177. package/levels/10-hooks/exercise/reports.py +63 -0
  178. package/levels/10-hooks/exercise/seed_data.py +91 -0
  179. package/levels/10-hooks/exercise/tests/__init__.py +1 -0
  180. package/levels/10-hooks/exercise/tests/conftest.py +69 -0
  181. package/levels/10-hooks/exercise/tests/test_database.py +244 -0
  182. package/levels/10-hooks/exercise/tests/test_models.py +240 -0
  183. package/levels/10-hooks/exercise/tests/test_reports.py +190 -0
  184. package/levels/10-hooks/exercise/utils.py +163 -0
  185. package/levels/10-hooks/lesson.yaml +58 -0
  186. package/levels/11-worktrees/exercise/README.md +152 -0
  187. package/levels/11-worktrees/exercise/data/expenses.db +0 -0
  188. package/levels/11-worktrees/exercise/database.py +171 -0
  189. package/levels/11-worktrees/exercise/main.py +97 -0
  190. package/levels/11-worktrees/exercise/models.py +116 -0
  191. package/levels/11-worktrees/exercise/pyproject.toml +52 -0
  192. package/levels/11-worktrees/exercise/reports.py +63 -0
  193. package/levels/11-worktrees/exercise/seed_data.py +91 -0
  194. package/levels/11-worktrees/exercise/tests/__init__.py +1 -0
  195. package/levels/11-worktrees/exercise/tests/conftest.py +69 -0
  196. package/levels/11-worktrees/exercise/tests/test_database.py +244 -0
  197. package/levels/11-worktrees/exercise/tests/test_models.py +240 -0
  198. package/levels/11-worktrees/exercise/tests/test_reports.py +190 -0
  199. package/levels/11-worktrees/exercise/utils.py +163 -0
  200. package/levels/11-worktrees/lesson.yaml +68 -0
  201. package/package.json +38 -0
@@ -0,0 +1,163 @@
1
+ """Utility functions for the expense tracker."""
2
+
3
+ from datetime import datetime, timedelta
4
+ from typing import Optional
5
+ import locale
6
+
7
+
8
+ def format_currency(amount: float) -> str:
9
+ """Format amount as currency.
10
+
11
+ Args:
12
+ amount: The numeric amount
13
+
14
+ Returns:
15
+ Formatted string like '$1,234.56'
16
+
17
+ Example:
18
+ >>> format_currency(1234.5)
19
+ '$1,234.50'
20
+ """
21
+ try:
22
+ locale.setlocale(locale.LC_ALL, '')
23
+ return locale.currency(amount, grouping=True)
24
+ except (locale.Error, ValueError):
25
+ # Fallback if locale not available
26
+ return f"${amount:,.2f}"
27
+
28
+
29
+ def parse_date(date_str: Optional[str]) -> Optional[datetime]:
30
+ """Parse a date string in various formats.
31
+
32
+ Supports:
33
+ - YYYY-MM-DD (2026-01-15)
34
+ - MM/DD/YYYY (01/15/2026)
35
+ - 'today'
36
+ - 'yesterday'
37
+
38
+ Args:
39
+ date_str: The date string to parse
40
+
41
+ Returns:
42
+ datetime object or None if input is None
43
+
44
+ Raises:
45
+ ValueError: If date format is not recognized
46
+
47
+ Example:
48
+ >>> parse_date('2026-01-15')
49
+ datetime(2026, 1, 15, 0, 0, 0)
50
+ >>> parse_date('today')
51
+ datetime(...) # Today at midnight
52
+ """
53
+ if not date_str:
54
+ return None
55
+
56
+ date_str = date_str.lower().strip()
57
+
58
+ # Handle relative dates
59
+ if date_str == 'today':
60
+ return datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
61
+
62
+ if date_str == 'yesterday':
63
+ return (datetime.now() - timedelta(days=1)).replace(
64
+ hour=0, minute=0, second=0, microsecond=0
65
+ )
66
+
67
+ # Try YYYY-MM-DD (ISO format)
68
+ try:
69
+ return datetime.strptime(date_str, '%Y-%m-%d')
70
+ except ValueError:
71
+ pass
72
+
73
+ # Try MM/DD/YYYY (US format)
74
+ try:
75
+ return datetime.strptime(date_str, '%m/%d/%Y')
76
+ except ValueError:
77
+ pass
78
+
79
+ # Try DD/MM/YYYY (European format)
80
+ try:
81
+ return datetime.strptime(date_str, '%d/%m/%Y')
82
+ except ValueError:
83
+ pass
84
+
85
+ raise ValueError(f"Could not parse date: {date_str}. Use YYYY-MM-DD format.")
86
+
87
+
88
+ def validate_category(category: str) -> str:
89
+ """Normalize category name.
90
+
91
+ Capitalizes first letter, strips whitespace.
92
+
93
+ Args:
94
+ category: Raw category input
95
+
96
+ Returns:
97
+ Normalized category name
98
+
99
+ Example:
100
+ >>> validate_category(' food ')
101
+ 'Food'
102
+ """
103
+ return category.strip().capitalize()
104
+
105
+
106
+ def format_date(dt: datetime) -> str:
107
+ """Format a datetime for display.
108
+
109
+ Args:
110
+ dt: The datetime to format
111
+
112
+ Returns:
113
+ Formatted string like 'Jan 15, 2026'
114
+ """
115
+ return dt.strftime('%b %d, %Y')
116
+
117
+
118
+ def format_month(month_str: str) -> str:
119
+ """Format a YYYY-MM string for display.
120
+
121
+ Args:
122
+ month_str: Month in YYYY-MM format
123
+
124
+ Returns:
125
+ Formatted string like 'January 2026'
126
+
127
+ Example:
128
+ >>> format_month('2026-01')
129
+ 'January 2026'
130
+ """
131
+ dt = datetime.strptime(month_str, '%Y-%m')
132
+ return dt.strftime('%B %Y')
133
+
134
+
135
+ # Valid categories for validation/suggestions
136
+ VALID_CATEGORIES = [
137
+ "Food",
138
+ "Transport",
139
+ "Entertainment",
140
+ "Shopping",
141
+ "Bills",
142
+ "Health",
143
+ "Education",
144
+ "Travel",
145
+ "Other"
146
+ ]
147
+
148
+
149
+ def suggest_category(partial: str) -> list[str]:
150
+ """Suggest categories matching a partial input.
151
+
152
+ Args:
153
+ partial: Partial category name
154
+
155
+ Returns:
156
+ List of matching categories
157
+
158
+ Example:
159
+ >>> suggest_category('fo')
160
+ ['Food']
161
+ """
162
+ partial_lower = partial.lower()
163
+ return [cat for cat in VALID_CATEGORIES if cat.lower().startswith(partial_lower)]
@@ -0,0 +1,68 @@
1
+ id: "worktrees"
2
+ number: 11
3
+ module: "Safety"
4
+ title: "Git Worktrees for Parallel Work"
5
+
6
+ video:
7
+ url: "https://vimeo.com/placeholder"
8
+ duration_seconds: 300
9
+
10
+ exercise:
11
+ intro: |
12
+ Worktrees let you work on multiple branches simultaneously.
13
+ You'll create a worktree, make a change, and merge it back.
14
+ objective: "Complete a full worktree workflow: create, change, merge"
15
+
16
+ intro: |
17
+ Git worktrees = multiple working directories for one repo.
18
+
19
+ Complete workflow:
20
+
21
+ 0. INITIALIZE GIT (first time only)
22
+ Type: claude
23
+ Say: "Initialize this as a git repo and commit all files"
24
+
25
+ 1. CREATE WORKTREE
26
+ Say: "Create a git worktree for a feature branch called 'add-version'
27
+ in ../add-version directory"
28
+
29
+ 2. MAKE A CHANGE (in the worktree)
30
+ Say: "In the worktree, add a --version flag to main.py that prints
31
+ 'Expense Tracker v1.0'. Then commit it."
32
+
33
+ 3. MERGE BACK TO MAIN
34
+ Say: "Switch back to main and merge the add-version branch"
35
+
36
+ 4. CLEAN UP
37
+ Say: "Remove the worktree now that we're done"
38
+
39
+ This is how you safely experiment with parallel Claude sessions!
40
+
41
+ verification:
42
+ - type: commit_exists
43
+ pattern: "version"
44
+
45
+ success: |
46
+ Congratulations! You've completed the Claude Code course!
47
+
48
+ You learned:
49
+ 1. Context is Everything - Context quality determines output
50
+ 2. CLAUDE.md - Persistent project memory
51
+ 3. Read/Edit/Verify - Core loop with self-verification
52
+ 4. Plan Mode - Think before coding
53
+ 5. Specs - Write requirements first
54
+ 6. Sub-agents - Context isolation
55
+ 7. Skills - Auto-activating commands
56
+ 8. MCP Servers - External tools
57
+ 9. Plugins - Bundled workflows
58
+ 10. Hooks - Safety guardrails
59
+ 11. Worktrees - Parallel development
60
+
61
+ The worktree workflow:
62
+ init → create → work → commit → merge → cleanup
63
+
64
+ Now go build something amazing!
65
+
66
+ limits:
67
+ max_duration_minutes: 20
68
+ max_claude_messages: 30
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@opslane/claude-code-game",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "bin": {
6
+ "claude-code-game": "./dist/cli.js"
7
+ },
8
+ "files": ["dist/", "frontend/", "levels/", "keys/"],
9
+ "engines": {
10
+ "node": ">=20.0.0"
11
+ },
12
+ "scripts": {
13
+ "prepublishOnly": "npm run build && cd ../frontend && npm install && npm run build && cd ../server && rm -rf frontend && cp -r ../frontend/dist frontend",
14
+ "build": "tsc",
15
+ "dev": "tsx watch src/cli.ts --no-open",
16
+ "start": "node dist/server.js",
17
+ "test": "vitest run"
18
+ },
19
+ "dependencies": {
20
+ "express": "^5.1.0",
21
+ "glob": "^13.0.1",
22
+ "jsonwebtoken": "^9.0.0",
23
+ "node-pty-prebuilt-multiarch": "^0.10.0",
24
+ "open": "^10.1.0",
25
+ "uuid": "^11.1.0",
26
+ "ws": "^8.18.0",
27
+ "yaml": "^2.7.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/express": "^5.0.0",
31
+ "@types/jsonwebtoken": "^9.0.0",
32
+ "@types/uuid": "^10.0.0",
33
+ "@types/ws": "^8.5.0",
34
+ "tsx": "^4.19.0",
35
+ "typescript": "^5.9.0",
36
+ "vitest": "^3.1.0"
37
+ }
38
+ }