@nebulit/embuilder 0.1.39

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 (212) hide show
  1. package/README.md +254 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +138 -0
  4. package/package.json +49 -0
  5. package/templates/.claude/hooks/QUICKSTART.md +256 -0
  6. package/templates/.claude/hooks/README.md +533 -0
  7. package/templates/.claude/hooks/analyze-commit.sh +22 -0
  8. package/templates/.claude/hooks/analyze-commit.ts +518 -0
  9. package/templates/.claude/hooks/analyzers/README.md +198 -0
  10. package/templates/.claude/hooks/analyzers/code-quality-checker.ts +154 -0
  11. package/templates/.claude/hooks/analyzers/code-quality.md +54 -0
  12. package/templates/.claude/hooks/analyzers/commit-blocker-example.ts.disabled +110 -0
  13. package/templates/.claude/hooks/analyzers/commit-policy.md +49 -0
  14. package/templates/.claude/hooks/analyzers/event-model-validator.md +49 -0
  15. package/templates/.claude/hooks/analyzers/event-model-validator.ts +169 -0
  16. package/templates/.claude/hooks/analyzers/example-logger.ts +70 -0
  17. package/templates/.claude/hooks/analyzers/slice-scope-validator.md +81 -0
  18. package/templates/.claude/hooks/check-review-result.sh +47 -0
  19. package/templates/.claude/hooks/prepare-review.sh +34 -0
  20. package/templates/.claude/hooks/review-agent-prompt.md +42 -0
  21. package/templates/.claude/hooks/run-review-agent.sh +124 -0
  22. package/templates/.claude/settings.local.json +37 -0
  23. package/templates/.claude/skills/help/README.md +84 -0
  24. package/templates/.claude/skills/help/SKILL.md +393 -0
  25. package/templates/.claude/skills/help/templates/demo-config.json +6753 -0
  26. package/templates/.claude/skills/sample-slices/SKILL.md +8 -0
  27. package/templates/.claude/skills/sample-slices/templates/.slices/Library/addbook/code-slice.json +124 -0
  28. package/templates/.claude/skills/sample-slices/templates/.slices/Library/addbook/slice.json +255 -0
  29. package/templates/.claude/skills/sample-slices/templates/.slices/Library/availablebooks/slice.json +107 -0
  30. package/templates/.claude/skills/sample-slices/templates/.slices/index.json +20 -0
  31. package/templates/.claude/skills/sample-slices/templates/Cart/additem/slice.json +979 -0
  32. package/templates/.claude/skills/sample-slices/templates/Cart/archiveitem/slice.json +529 -0
  33. package/templates/.claude/skills/sample-slices/templates/Cart/cartitems/slice.json +1072 -0
  34. package/templates/.claude/skills/sample-slices/templates/Cart/cartwithproducts/slice.json +394 -0
  35. package/templates/.claude/skills/sample-slices/templates/Cart/changedprices/slice.json +88 -0
  36. package/templates/.claude/skills/sample-slices/templates/Cart/changeinventory/slice.json +264 -0
  37. package/templates/.claude/skills/sample-slices/templates/Cart/changeprice/slice.json +308 -0
  38. package/templates/.claude/skills/sample-slices/templates/Cart/clearcart/slice.json +358 -0
  39. package/templates/.claude/skills/sample-slices/templates/Cart/inventories/slice.json +203 -0
  40. package/templates/.claude/skills/sample-slices/templates/Cart/publishcart/slice.json +876 -0
  41. package/templates/.claude/skills/sample-slices/templates/Cart/removeitem/slice.json +560 -0
  42. package/templates/.claude/skills/sample-slices/templates/Cart/submitcart/slice.json +708 -0
  43. package/templates/.claude/skills/sample-slices/templates/Cart/submittedcartdata/slice.json +399 -0
  44. package/templates/.claude/skills/sample-slices/templates/index.json +108 -0
  45. package/templates/.claude/skills/slice-automation/SKILL.md +49 -0
  46. package/templates/.claude/skills/slice-state-change/SKILL.md +369 -0
  47. package/templates/.claude/skills/slice-state-change/templates/AddLocation/AddLocation.test.ts.sample +76 -0
  48. package/templates/.claude/skills/slice-state-change/templates/AddLocation/AddLocationCommand.ts.sample +84 -0
  49. package/templates/.claude/skills/slice-state-change/templates/AddLocation/routes.ts.sample +73 -0
  50. package/templates/.claude/skills/slice-state-change/templates/README.md +46 -0
  51. package/templates/.claude/skills/slice-state-view/SKILL.md +336 -0
  52. package/templates/.claude/skills/slice-state-view/templates/Locations/Locations.test.ts.sample +84 -0
  53. package/templates/.claude/skills/slice-state-view/templates/Locations/LocationsProjection.ts.sample +50 -0
  54. package/templates/.claude/skills/slice-state-view/templates/Locations/routes.ts.sample +46 -0
  55. package/templates/.claude/skills/slice-state-view/templates/README.md +109 -0
  56. package/templates/.claude/skills/slice-state-view/templates/Tables/Tables.test.ts.sample +104 -0
  57. package/templates/.claude/skills/slice-state-view/templates/Tables/TablesProjection.ts.sample +59 -0
  58. package/templates/.claude/skills/slice-state-view/templates/Tables/routes.ts.sample +46 -0
  59. package/templates/.claude/skills/slice-state-view/templates/V2__tables.sql +7 -0
  60. package/templates/.claude/skills/slice-state-view/templates/V8__locations.sql +7 -0
  61. package/templates/.claude/skills/test-analyzer/SKILL.md +373 -0
  62. package/templates/.claude/skills/test-analyzer/examples/specification-format.md +143 -0
  63. package/templates/.claude/skills/test-analyzer/examples/state-change-example.md +111 -0
  64. package/templates/.claude/skills/test-analyzer/examples/state-view-example.md +122 -0
  65. package/templates/AGENTS.md +110 -0
  66. package/templates/Claude.md +58 -0
  67. package/templates/README.md +178 -0
  68. package/templates/backend/.env +9 -0
  69. package/templates/backend/BACKEND_AUTH_SETUP.md +183 -0
  70. package/templates/backend/SWAGGER.md +213 -0
  71. package/templates/backend/eslint.config.mjs +31 -0
  72. package/templates/backend/flyway.conf +17 -0
  73. package/templates/backend/package.json +44 -0
  74. package/templates/backend/prd.json.example +64 -0
  75. package/templates/backend/public/assets/images/banner.png +0 -0
  76. package/templates/backend/public/assets/logo.png +0 -0
  77. package/templates/backend/public/file.svg +4 -0
  78. package/templates/backend/public/globe.svg +12 -0
  79. package/templates/backend/public/next.svg +6 -0
  80. package/templates/backend/public/vercel.svg +3 -0
  81. package/templates/backend/public/window.svg +5 -0
  82. package/templates/backend/server.ts +129 -0
  83. package/templates/backend/setup-env.sh +50 -0
  84. package/templates/backend/src/common/assertions.ts +6 -0
  85. package/templates/backend/src/common/db.ts +1 -0
  86. package/templates/backend/src/common/loadPostgresEventstore.ts +16 -0
  87. package/templates/backend/src/common/parseEndpoint.ts +51 -0
  88. package/templates/backend/src/common/replay.ts +9 -0
  89. package/templates/backend/src/common/routes.ts +19 -0
  90. package/templates/backend/src/common/testHelpers.ts +53 -0
  91. package/templates/backend/src/core/readmodel.ts +28 -0
  92. package/templates/backend/src/core/types.ts +26 -0
  93. package/templates/backend/src/process/process.ts +53 -0
  94. package/templates/backend/src/supabase/LoginHandler.ts +36 -0
  95. package/templates/backend/src/supabase/ProtectedPageProps.ts +21 -0
  96. package/templates/backend/src/supabase/README.md +171 -0
  97. package/templates/backend/src/supabase/api.ts +63 -0
  98. package/templates/backend/src/supabase/authMiddleware.ts +53 -0
  99. package/templates/backend/src/supabase/component.ts +12 -0
  100. package/templates/backend/src/supabase/requireUser.ts +72 -0
  101. package/templates/backend/src/supabase/serverProps.ts +25 -0
  102. package/templates/backend/src/supabase/staticProps.ts +10 -0
  103. package/templates/backend/src/swagger.ts +34 -0
  104. package/templates/backend/src/util/assertions.ts +6 -0
  105. package/templates/backend/supabase/config.toml +295 -0
  106. package/templates/backend/supabase/migrations/20260121155918593_catalogentries.sql.sample +23 -0
  107. package/templates/backend/supabase/seed.sql +1 -0
  108. package/templates/backend/tsconfig.json +31 -0
  109. package/templates/frontend/.env.development +3 -0
  110. package/templates/frontend/AGENTS.md +7 -0
  111. package/templates/frontend/README.md +73 -0
  112. package/templates/frontend/components.json +20 -0
  113. package/templates/frontend/eslint.config.js +26 -0
  114. package/templates/frontend/index.html +18 -0
  115. package/templates/frontend/package-lock.json +8347 -0
  116. package/templates/frontend/package.json +94 -0
  117. package/templates/frontend/postcss.config.js +6 -0
  118. package/templates/frontend/public/favicon.ico +0 -0
  119. package/templates/frontend/public/logo.png +0 -0
  120. package/templates/frontend/public/placeholder.svg +1 -0
  121. package/templates/frontend/public/robots.txt +14 -0
  122. package/templates/frontend/src/App.css +42 -0
  123. package/templates/frontend/src/App.tsx +47 -0
  124. package/templates/frontend/src/components/NavLink.tsx +28 -0
  125. package/templates/frontend/src/components/ProtectedRoute.tsx +24 -0
  126. package/templates/frontend/src/components/calendar/Calendar.tsx +302 -0
  127. package/templates/frontend/src/components/layout/DashboardLayout.tsx +21 -0
  128. package/templates/frontend/src/components/layout/Header.tsx +45 -0
  129. package/templates/frontend/src/components/layout/Sidebar.tsx +82 -0
  130. package/templates/frontend/src/components/tables/ReservationTemplates.tsx +189 -0
  131. package/templates/frontend/src/components/ui/accordion.tsx +52 -0
  132. package/templates/frontend/src/components/ui/alert-dialog.tsx +104 -0
  133. package/templates/frontend/src/components/ui/alert.tsx +43 -0
  134. package/templates/frontend/src/components/ui/aspect-ratio.tsx +5 -0
  135. package/templates/frontend/src/components/ui/avatar.tsx +38 -0
  136. package/templates/frontend/src/components/ui/badge.tsx +29 -0
  137. package/templates/frontend/src/components/ui/breadcrumb.tsx +90 -0
  138. package/templates/frontend/src/components/ui/button.tsx +47 -0
  139. package/templates/frontend/src/components/ui/calendar.tsx +54 -0
  140. package/templates/frontend/src/components/ui/card.tsx +43 -0
  141. package/templates/frontend/src/components/ui/carousel.tsx +224 -0
  142. package/templates/frontend/src/components/ui/chart.tsx +303 -0
  143. package/templates/frontend/src/components/ui/checkbox.tsx +26 -0
  144. package/templates/frontend/src/components/ui/collapsible.tsx +9 -0
  145. package/templates/frontend/src/components/ui/command.tsx +132 -0
  146. package/templates/frontend/src/components/ui/context-menu.tsx +178 -0
  147. package/templates/frontend/src/components/ui/dialog.tsx +95 -0
  148. package/templates/frontend/src/components/ui/drawer.tsx +87 -0
  149. package/templates/frontend/src/components/ui/dropdown-menu.tsx +179 -0
  150. package/templates/frontend/src/components/ui/form.tsx +129 -0
  151. package/templates/frontend/src/components/ui/hover-card.tsx +27 -0
  152. package/templates/frontend/src/components/ui/input-otp.tsx +61 -0
  153. package/templates/frontend/src/components/ui/input.tsx +22 -0
  154. package/templates/frontend/src/components/ui/label.tsx +17 -0
  155. package/templates/frontend/src/components/ui/menubar.tsx +207 -0
  156. package/templates/frontend/src/components/ui/navigation-menu.tsx +120 -0
  157. package/templates/frontend/src/components/ui/pagination.tsx +81 -0
  158. package/templates/frontend/src/components/ui/popover.tsx +29 -0
  159. package/templates/frontend/src/components/ui/progress.tsx +23 -0
  160. package/templates/frontend/src/components/ui/radio-group.tsx +36 -0
  161. package/templates/frontend/src/components/ui/resizable.tsx +37 -0
  162. package/templates/frontend/src/components/ui/scroll-area.tsx +38 -0
  163. package/templates/frontend/src/components/ui/select.tsx +143 -0
  164. package/templates/frontend/src/components/ui/separator.tsx +20 -0
  165. package/templates/frontend/src/components/ui/sheet.tsx +107 -0
  166. package/templates/frontend/src/components/ui/sidebar.tsx +637 -0
  167. package/templates/frontend/src/components/ui/skeleton.tsx +7 -0
  168. package/templates/frontend/src/components/ui/slider.tsx +23 -0
  169. package/templates/frontend/src/components/ui/sonner.tsx +27 -0
  170. package/templates/frontend/src/components/ui/stat-card.tsx +44 -0
  171. package/templates/frontend/src/components/ui/switch.tsx +27 -0
  172. package/templates/frontend/src/components/ui/table.tsx +72 -0
  173. package/templates/frontend/src/components/ui/tabs.tsx +53 -0
  174. package/templates/frontend/src/components/ui/textarea.tsx +21 -0
  175. package/templates/frontend/src/components/ui/toast.tsx +111 -0
  176. package/templates/frontend/src/components/ui/toaster.tsx +24 -0
  177. package/templates/frontend/src/components/ui/toggle-group.tsx +49 -0
  178. package/templates/frontend/src/components/ui/toggle.tsx +37 -0
  179. package/templates/frontend/src/components/ui/tooltip.tsx +28 -0
  180. package/templates/frontend/src/components/ui/use-toast.ts +3 -0
  181. package/templates/frontend/src/contexts/AuthContext.tsx +94 -0
  182. package/templates/frontend/src/contexts/RefreshContext.tsx +236 -0
  183. package/templates/frontend/src/hooks/api/index.ts +2 -0
  184. package/templates/frontend/src/hooks/api/useLocations.ts +15 -0
  185. package/templates/frontend/src/hooks/use-mobile.tsx +19 -0
  186. package/templates/frontend/src/hooks/use-toast.ts +186 -0
  187. package/templates/frontend/src/hooks/useApiContext.ts +11 -0
  188. package/templates/frontend/src/index.css +118 -0
  189. package/templates/frontend/src/integrations/supabase/client.ts +9 -0
  190. package/templates/frontend/src/lib/api-client.ts +136 -0
  191. package/templates/frontend/src/lib/api.ts +1028 -0
  192. package/templates/frontend/src/lib/utils.ts +6 -0
  193. package/templates/frontend/src/main.tsx +5 -0
  194. package/templates/frontend/src/pages/Auth.tsx +408 -0
  195. package/templates/frontend/src/pages/Dashboard.tsx +168 -0
  196. package/templates/frontend/src/pages/Menus.tsx +224 -0
  197. package/templates/frontend/src/pages/NotFound.tsx +24 -0
  198. package/templates/frontend/src/pages/Register.tsx +285 -0
  199. package/templates/frontend/src/test/example.test.ts +0 -0
  200. package/templates/frontend/src/test/setup.ts +15 -0
  201. package/templates/frontend/src/types/index.ts +8 -0
  202. package/templates/frontend/src/vite-env.d.ts +1 -0
  203. package/templates/frontend/tailwind.config.ts +101 -0
  204. package/templates/frontend/tsconfig.app.json +31 -0
  205. package/templates/frontend/tsconfig.json +16 -0
  206. package/templates/frontend/tsconfig.node.json +22 -0
  207. package/templates/frontend/vite.config.ts +21 -0
  208. package/templates/frontend/vitest.config.ts +16 -0
  209. package/templates/init.sh +1 -0
  210. package/templates/prompt.md +139 -0
  211. package/templates/ralph.sh +120 -0
  212. package/templates/server.mjs +505 -0
@@ -0,0 +1,533 @@
1
+ # Git Commit Pre-Tool-Call Hook
2
+
3
+ This hook system analyzes workspace changes before git commits and provides the diff information to registered analyzer scripts.
4
+
5
+ ## How It Works
6
+
7
+ 1. **Hook Configuration**: The hook is configured in `.claude/settings.local.json` under the `hooks.PreToolUse` section
8
+ 2. **Trigger**: Runs automatically before any `git commit` command executed by Claude
9
+ 3. **Analysis**: Executes the main hook script (`analyze-commit.sh`) which:
10
+ - Captures git diff (both staged and unstaged changes)
11
+ - Creates a JSON payload with diff information
12
+ - Passes the payload to all registered analyzer scripts
13
+ 4. **Analyzers**: Custom TypeScript scripts process the diff and provide feedback
14
+
15
+ ## Configuration
16
+
17
+ The hook is configured in `.claude/settings.local.json`:
18
+
19
+ ```json
20
+ {
21
+ "hooks": {
22
+ "PreToolUse": [
23
+ {
24
+ "matcher": "Bash(*git commit*)",
25
+ "hooks": [
26
+ {
27
+ "type": "command",
28
+ "command": ".claude/hooks/analyze-commit.sh",
29
+ "statusMessage": "Analyzing changes before commit"
30
+ }
31
+ ]
32
+ }
33
+ ]
34
+ }
35
+ }
36
+ ```
37
+
38
+ ### Configuration Options
39
+
40
+ - **matcher**: Pattern to match tool calls (e.g., `"Bash(*git commit*)"` for git commits)
41
+ - **type**: Hook type (`"command"` for shell commands)
42
+ - **command**: Path to the hook script
43
+ - **statusMessage**: Message displayed while hook runs
44
+
45
+ ## Hook Payload
46
+
47
+ The hook provides a JSON payload to analyzer scripts via stdin:
48
+
49
+ ```json
50
+ {
51
+ "event": "pre-commit",
52
+ "timestamp": "2026-02-23T12:00:00Z",
53
+ "repository": "/path/to/repo",
54
+ "branch": "main",
55
+ "staged_diff": "diff content...",
56
+ "unstaged_diff": "diff content...",
57
+ "changed_files": ["file1.ts", "file2.ts"],
58
+ "stats": {
59
+ "staged_files": 2,
60
+ "has_staged_changes": true,
61
+ "has_unstaged_changes": false
62
+ }
63
+ }
64
+ ```
65
+
66
+ ## Creating Analyzer Scripts
67
+
68
+ Analyzer scripts are placed in `.claude/hooks/analyzers/` and can be written in:
69
+ - **TypeScript** (`.ts` files) - Recommended
70
+ - **Bash** (executable scripts)
71
+
72
+ ### TypeScript Analyzer Example
73
+
74
+ ```typescript
75
+ #!/usr/bin/env node
76
+
77
+ import { readFileSync } from 'fs';
78
+
79
+ interface HookData {
80
+ event: string;
81
+ timestamp: string;
82
+ repository: string;
83
+ branch: string;
84
+ staged_diff: string;
85
+ unstaged_diff: string;
86
+ changed_files: string[];
87
+ stats: {
88
+ staged_files: number;
89
+ has_staged_changes: boolean;
90
+ has_unstaged_changes: boolean;
91
+ };
92
+ }
93
+
94
+ interface AnalyzerResult {
95
+ approved: boolean;
96
+ reason?: string;
97
+ }
98
+
99
+ async function main() {
100
+ // Read JSON data from stdin
101
+ const input = readFileSync(0, 'utf-8');
102
+ const data: HookData = JSON.parse(input);
103
+
104
+ // Your analysis logic here
105
+ console.log('Analyzing commit...');
106
+ console.log(`Files changed: ${data.changed_files.length}`);
107
+
108
+ // Perform checks, validations, etc.
109
+ const hasIssues = false; // Your logic here
110
+
111
+ // IMPORTANT: Always return approval status as JSON on the last line
112
+ const result: AnalyzerResult = {
113
+ approved: !hasIssues,
114
+ reason: hasIssues ? 'Issues found' : 'All checks passed'
115
+ };
116
+
117
+ console.log('\n' + JSON.stringify(result));
118
+ }
119
+
120
+ main();
121
+ ```
122
+
123
+ ### Requirements for TypeScript Analyzers
124
+
125
+ TypeScript analyzers require either `tsx` or `ts-node`:
126
+
127
+ ```bash
128
+ # Install tsx (recommended - faster)
129
+ npm install -g tsx
130
+
131
+ # Or install ts-node
132
+ npm install -g ts-node
133
+ ```
134
+
135
+ ## Approval Mechanism
136
+
137
+ **IMPORTANT**: Analyzers must return a JSON result indicating approval status:
138
+
139
+ ```typescript
140
+ interface AnalyzerResult {
141
+ approved: boolean; // true = allow commit, false = block commit
142
+ reason?: string; // Optional explanation
143
+ }
144
+ ```
145
+
146
+ ### How It Works
147
+
148
+ 1. **Analyzer runs** and performs its checks
149
+ 2. **Analyzer outputs** any informational messages (logs, warnings, etc.)
150
+ 3. **Analyzer returns** JSON approval status as the **last line** of output:
151
+ ```json
152
+ {"approved": true, "reason": "All checks passed"}
153
+ ```
154
+ 4. **Hook script** parses the JSON and:
155
+ - If `approved: false` → **BLOCKS the commit** and shows the reason
156
+ - If `approved: true` → **Allows the commit** to proceed
157
+
158
+ ### Example: Approving Commits
159
+
160
+ ```typescript
161
+ // Analysis passed - approve the commit
162
+ const result: AnalyzerResult = {
163
+ approved: true,
164
+ reason: 'Code quality checks passed'
165
+ };
166
+ console.log('\n' + JSON.stringify(result));
167
+ ```
168
+
169
+ ### Example: Blocking Commits
170
+
171
+ ```typescript
172
+ // Critical issue found - block the commit
173
+ if (hasSecrets) {
174
+ const result: AnalyzerResult = {
175
+ approved: false,
176
+ reason: 'Potential secrets detected - verify no credentials are committed'
177
+ };
178
+ console.log('\n' + JSON.stringify(result));
179
+ return;
180
+ }
181
+ ```
182
+
183
+ ### What Happens When Blocked
184
+
185
+ When any analyzer returns `approved: false`, the commit is blocked:
186
+
187
+ ```bash
188
+ ❌ Commit BLOCKED by analyzers:
189
+
190
+ • code-quality-checker.ts: Potential secrets detected
191
+ • commit-blocker.ts: Direct commits to main not allowed
192
+
193
+ 💡 Fix the issues above and try again
194
+ ```
195
+
196
+ The git commit command will **fail** and Claude will need to fix the issues before trying again.
197
+
198
+ ## Built-in Analyzers
199
+
200
+ ### 1. example-logger.ts
201
+ Simple logger that displays commit statistics and changed files.
202
+
203
+ **What it does:**
204
+ - Shows branch name
205
+ - Lists changed files
206
+ - Displays staged/unstaged status
207
+
208
+ **Approval:** Always approves (informational only)
209
+
210
+ ### 2. code-quality-checker.ts
211
+ Checks for common code quality issues.
212
+
213
+ **Checks for:**
214
+ - Console.log statements
215
+ - Debugger statements
216
+ - TODO/FIXME comments
217
+ - Potential secrets (API keys, passwords)
218
+
219
+ **Approval:**
220
+ - ✅ Approves: Normal warnings (console.log, TODO, etc.)
221
+ - ❌ Blocks: Potential secrets detected
222
+
223
+ ### 3. event-model-validator.ts
224
+ Validates event model slice conventions.
225
+
226
+ **Validates:**
227
+ - Event names use past-tense convention
228
+ - Test files are updated with logic changes
229
+ - Slice structure follows patterns
230
+
231
+ **Approval:** Always approves (provides warnings but doesn't block)
232
+
233
+ ### 4. commit-blocker-example.ts.disabled
234
+ Example showing how to block commits (disabled by default).
235
+
236
+ **Blocks commits when:**
237
+ - Direct commits to main branch
238
+ - Too many files changed (>50)
239
+ - Critical files changed without tests
240
+ - package.json changed without lockfile update
241
+
242
+ **Enable:** Rename to `commit-blocker-example.ts` to activate
243
+
244
+ ## Enabling/Disabling Analyzers
245
+
246
+ ### Enable an Analyzer
247
+ Simply ensure the `.ts` file exists in `.claude/hooks/analyzers/`:
248
+
249
+ ```bash
250
+ # Already enabled by default:
251
+ .claude/hooks/analyzers/example-logger.ts
252
+ .claude/hooks/analyzers/code-quality-checker.ts
253
+ .claude/hooks/analyzers/event-model-validator.ts
254
+ ```
255
+
256
+ ### Disable an Analyzer
257
+ Remove or rename the file:
258
+
259
+ ```bash
260
+ # Disable by renaming
261
+ mv .claude/hooks/analyzers/example-logger.ts \
262
+ .claude/hooks/analyzers/example-logger.ts.disabled
263
+
264
+ # Or delete
265
+ rm .claude/hooks/analyzers/example-logger.ts
266
+ ```
267
+
268
+ ## Creating Custom Analyzers
269
+
270
+ ### Step 1: Create a new TypeScript file
271
+
272
+ ```bash
273
+ touch .claude/hooks/analyzers/my-analyzer.ts
274
+ ```
275
+
276
+ ### Step 2: Implement your analyzer
277
+
278
+ ```typescript
279
+ #!/usr/bin/env node
280
+
281
+ import { readFileSync } from 'fs';
282
+
283
+ interface HookData {
284
+ event: string;
285
+ staged_diff: string;
286
+ changed_files: string[];
287
+ // ... other fields
288
+ }
289
+
290
+ async function main() {
291
+ const input = readFileSync(0, 'utf-8');
292
+ const data: HookData = JSON.parse(input);
293
+
294
+ // Your custom logic
295
+ console.log('🔍 My Custom Analysis:');
296
+
297
+ // Example: Check if package.json changed
298
+ if (data.changed_files.includes('package.json')) {
299
+ console.log(' ⚠️ package.json changed - remember to run npm install');
300
+ }
301
+ }
302
+
303
+ main();
304
+ ```
305
+
306
+ ### Step 3: Test your analyzer
307
+
308
+ ```bash
309
+ # Test manually
310
+ echo '{"event":"pre-commit","changed_files":["package.json"],"staged_diff":"..."}' | \
311
+ tsx .claude/hooks/analyzers/my-analyzer.ts
312
+ ```
313
+
314
+ ## Advanced Usage
315
+
316
+ ### Blocking Commits Based on Conditions
317
+
318
+ Analyzers can block commits by returning `approved: false`. Here are common patterns:
319
+
320
+ #### Block Direct Commits to Protected Branches
321
+
322
+ ```typescript
323
+ if (data.branch === 'main' || data.branch === 'production') {
324
+ const result: AnalyzerResult = {
325
+ approved: false,
326
+ reason: `Direct commits to ${data.branch} are not allowed - use pull requests`
327
+ };
328
+ console.log('\n' + JSON.stringify(result));
329
+ return;
330
+ }
331
+ ```
332
+
333
+ #### Block Commits Without Tests
334
+
335
+ ```typescript
336
+ const hasLogicChanges = data.changed_files.some(f =>
337
+ f.endsWith('Handler.ts') || f.endsWith('Command.ts')
338
+ );
339
+
340
+ const hasTestChanges = data.changed_files.some(f => f.endsWith('.test.ts'));
341
+
342
+ if (hasLogicChanges && !hasTestChanges) {
343
+ const result: AnalyzerResult = {
344
+ approved: false,
345
+ reason: 'Logic files changed but no tests updated - add tests'
346
+ };
347
+ console.log('\n' + JSON.stringify(result));
348
+ return;
349
+ }
350
+ ```
351
+
352
+ #### Block Commits Based on Diff Content
353
+
354
+ ```typescript
355
+ const lines = data.staged_diff.split('\n');
356
+ const addedLines = lines.filter(l => l.startsWith('+'));
357
+
358
+ // Block if forbidden patterns found
359
+ const hasForbiddenPattern = addedLines.some(line =>
360
+ /eval\(/.test(line) || /dangerouslySetInnerHTML/.test(line)
361
+ );
362
+
363
+ if (hasForbiddenPattern) {
364
+ const result: AnalyzerResult = {
365
+ approved: false,
366
+ reason: 'Forbidden patterns detected (eval, dangerouslySetInnerHTML)'
367
+ };
368
+ console.log('\n' + JSON.stringify(result));
369
+ return;
370
+ }
371
+ ```
372
+
373
+ ### Accessing Additional Git Information
374
+
375
+ ```typescript
376
+ import { execSync } from 'child_process';
377
+
378
+ // Get commit author
379
+ const author = execSync('git config user.name').toString().trim();
380
+
381
+ // Get recent commits
382
+ const log = execSync('git log -5 --oneline').toString();
383
+
384
+ // Check if file exists in previous commit
385
+ const fileExists = execSync('git ls-tree -r HEAD --name-only | grep myfile.ts').toString();
386
+ ```
387
+
388
+ ### Analyzing Specific File Types
389
+
390
+ ```typescript
391
+ // Only analyze TypeScript files
392
+ const tsFiles = data.changed_files.filter(f => f.endsWith('.ts'));
393
+
394
+ if (tsFiles.length === 0) {
395
+ console.log(' ℹ️ No TypeScript files changed');
396
+ return;
397
+ }
398
+
399
+ // Analyze each TypeScript file
400
+ for (const file of tsFiles) {
401
+ // Extract changes for this specific file
402
+ const fileDiff = extractFileDiff(data.staged_diff, file);
403
+ // ... analyze
404
+ }
405
+ ```
406
+
407
+ ## Troubleshooting
408
+
409
+ ### Hook not running
410
+ 1. Check `.claude/settings.local.json` has the correct hook configuration
411
+ 2. Verify the hook script is executable: `chmod +x .claude/hooks/analyze-commit.sh`
412
+ 3. Check Claude Code permissions allow the hook to run
413
+
414
+ ### TypeScript analyzers not running
415
+ 1. Install tsx or ts-node: `npm install -g tsx`
416
+ 2. Verify TypeScript files are in `.claude/hooks/analyzers/`
417
+ 3. Check for syntax errors in your TypeScript files
418
+
419
+ ### Analyzer fails silently
420
+ 1. Test manually: `echo '{}' | tsx .claude/hooks/analyzers/your-analyzer.ts`
421
+ 2. Add error handling in your analyzer
422
+ 3. Check the JSON payload format matches your interface
423
+
424
+ ## Best Practices
425
+
426
+ 1. **Keep analyzers fast** - They run on every commit
427
+ 2. **Use clear output** - Emoji and formatting help readability
428
+ 3. **Always return approval status** - Return JSON with `approved: true/false`
429
+ 4. **Block only critical issues** - Use `approved: false` sparingly
430
+ 5. **Provide clear reasons** - Explain why a commit was blocked
431
+ 6. **Test independently** - Test analyzers outside the hook first
432
+ 7. **Handle errors gracefully** - Catch exceptions and return approval
433
+ 8. **Document your analyzers** - Add comments explaining what they check
434
+
435
+ ### When to Block vs Warn
436
+
437
+ **Block (`approved: false`) when:**
438
+ - Secrets/credentials detected
439
+ - Direct commits to protected branches
440
+ - Critical files changed without tests
441
+ - Security vulnerabilities introduced
442
+ - Build will definitely fail
443
+
444
+ **Warn (`approved: true`) when:**
445
+ - Code quality issues (console.log, TODOs)
446
+ - Style violations
447
+ - Missing documentation
448
+ - Potential improvements
449
+ - Non-critical concerns
450
+
451
+ ## Examples
452
+
453
+ ### Check for Breaking Changes
454
+
455
+ ```typescript
456
+ async function main() {
457
+ const input = readFileSync(0, 'utf-8');
458
+ const data: HookData = JSON.parse(input);
459
+
460
+ // Check if public API files changed
461
+ const apiFiles = data.changed_files.filter(f =>
462
+ f.includes('/api/') || f.includes('/public/')
463
+ );
464
+
465
+ if (apiFiles.length > 0) {
466
+ console.log('⚠️ Public API files changed:');
467
+ apiFiles.forEach(f => console.log(` - ${f}`));
468
+ console.log('💡 Consider updating CHANGELOG.md');
469
+ }
470
+ }
471
+ ```
472
+
473
+ ### Enforce Commit Size Limits
474
+
475
+ ```typescript
476
+ async function main() {
477
+ const input = readFileSync(0, 'utf-8');
478
+ const data: HookData = JSON.parse(input);
479
+
480
+ const MAX_FILES = 20;
481
+
482
+ if (data.changed_files.length > MAX_FILES) {
483
+ console.error(`❌ Too many files changed (${data.changed_files.length} > ${MAX_FILES})`);
484
+ console.error('💡 Consider breaking this into smaller commits');
485
+ process.exit(1); // Block commit
486
+ }
487
+ }
488
+ ```
489
+
490
+ ### Integration with External Tools
491
+
492
+ ```typescript
493
+ import { execSync } from 'child_process';
494
+
495
+ async function main() {
496
+ const input = readFileSync(0, 'utf-8');
497
+ const data: HookData = JSON.parse(input);
498
+
499
+ // Run external linter
500
+ try {
501
+ execSync('npm run lint', { stdio: 'inherit' });
502
+ console.log('✅ Linting passed');
503
+ } catch (error) {
504
+ console.error('❌ Linting failed');
505
+ process.exit(1);
506
+ }
507
+ }
508
+ ```
509
+
510
+ ## Future Enhancements
511
+
512
+ Potential improvements to the hook system:
513
+
514
+ - Support for post-commit hooks
515
+ - Parallel execution of analyzers
516
+ - Configuration file for analyzer settings
517
+ - Built-in caching for faster analysis
518
+ - Integration with CI/CD pipelines
519
+ - Automatic fix suggestions
520
+
521
+ ## Contributing
522
+
523
+ To add your custom analyzer to the built-in set:
524
+
525
+ 1. Create your analyzer in `.claude/hooks/analyzers/`
526
+ 2. Test thoroughly
527
+ 3. Document what it checks
528
+ 4. Consider making it configurable
529
+ 5. Share with the team
530
+
531
+ ## License
532
+
533
+ These hooks are part of the EMBuilder toolkit and follow the same MIT license.
@@ -0,0 +1,22 @@
1
+ #!/bin/bash
2
+
3
+ # Git Commit Pre-Tool-Call Hook (Bash Wrapper)
4
+ # This is a minimal wrapper that calls the TypeScript implementation
5
+
6
+ # Get the directory where this script is located
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+
9
+ # Check if tsx is available
10
+ if command -v tsx &> /dev/null; then
11
+ tsx "$SCRIPT_DIR/analyze-commit.ts"
12
+ exit $?
13
+ elif command -v ts-node &> /dev/null; then
14
+ ts-node "$SCRIPT_DIR/analyze-commit.ts"
15
+ exit $?
16
+ else
17
+ echo "❌ Error: tsx or ts-node not found"
18
+ echo " Install with: npm install -g tsx"
19
+ echo ""
20
+ echo " Allowing commit to proceed (fail-safe mode)"
21
+ exit 0
22
+ fi