@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,154 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Example Analyzer: Code Quality Checker
5
+ *
6
+ * This analyzer checks for common code quality issues in the diff:
7
+ * - Debug statements (console.log, debugger)
8
+ * - TODO/FIXME comments
9
+ * - Large file changes
10
+ * - Potential sensitive data (API keys, passwords)
11
+ */
12
+
13
+ import { readFileSync } from 'fs';
14
+
15
+ interface HookData {
16
+ event: string;
17
+ timestamp: string;
18
+ repository: string;
19
+ branch: string;
20
+ staged_diff: string;
21
+ unstaged_diff: string;
22
+ changed_files: string[];
23
+ stats: {
24
+ staged_files: number;
25
+ has_staged_changes: boolean;
26
+ has_unstaged_changes: boolean;
27
+ };
28
+ }
29
+
30
+ interface Issue {
31
+ severity: 'warning' | 'info';
32
+ message: string;
33
+ }
34
+
35
+ async function analyzeDiff(diff: string): Promise<Issue[]> {
36
+ const issues: Issue[] = [];
37
+ const lines = diff.split('\n');
38
+
39
+ // Only check added lines (starting with +)
40
+ const addedLines = lines.filter(line => line.startsWith('+') && !line.startsWith('+++'));
41
+
42
+ // Check for console.log statements
43
+ const consoleLogs = addedLines.filter(line => /console\.(log|debug|info|warn|error)/.test(line));
44
+ if (consoleLogs.length > 0) {
45
+ issues.push({
46
+ severity: 'warning',
47
+ message: `Found ${consoleLogs.length} console.log statement(s) - consider removing debug code`
48
+ });
49
+ }
50
+
51
+ // Check for debugger statements
52
+ const debuggers = addedLines.filter(line => /\bdebugger\b/.test(line));
53
+ if (debuggers.length > 0) {
54
+ issues.push({
55
+ severity: 'warning',
56
+ message: `Found ${debuggers.length} debugger statement(s) - remove before committing`
57
+ });
58
+ }
59
+
60
+ // Check for TODO/FIXME comments
61
+ const todos = addedLines.filter(line => /(TODO|FIXME|XXX|HACK)/i.test(line));
62
+ if (todos.length > 0) {
63
+ issues.push({
64
+ severity: 'info',
65
+ message: `Found ${todos.length} TODO/FIXME comment(s) - ensure they're tracked`
66
+ });
67
+ }
68
+
69
+ // Check for potential API keys or secrets
70
+ const potentialSecrets = addedLines.filter(line =>
71
+ /(api[_-]?key|secret|password|token|auth[_-]?key)[\s]*[:=][\s]*['"][^'"]{20,}['"]/.test(line.toLowerCase())
72
+ );
73
+ if (potentialSecrets.length > 0) {
74
+ issues.push({
75
+ severity: 'warning',
76
+ message: `āš ļø SECURITY: Found ${potentialSecrets.length} potential secret(s) - verify no credentials are committed`
77
+ });
78
+ }
79
+
80
+ return issues;
81
+ }
82
+
83
+ interface AnalyzerResult {
84
+ approved: boolean;
85
+ reason?: string;
86
+ }
87
+
88
+ async function main() {
89
+ try {
90
+ // Read JSON data from stdin
91
+ const input = readFileSync(0, 'utf-8');
92
+ const data: HookData = JSON.parse(input);
93
+
94
+ console.log('šŸ” Code Quality Analysis:');
95
+
96
+ // Analyze staged changes
97
+ const stagedIssues = await analyzeDiff(data.staged_diff);
98
+ const unstagedIssues = await analyzeDiff(data.unstaged_diff);
99
+
100
+ const allIssues = [...stagedIssues, ...unstagedIssues];
101
+
102
+ if (allIssues.length === 0) {
103
+ console.log(' āœ… No issues found');
104
+
105
+ const result: AnalyzerResult = {
106
+ approved: true,
107
+ reason: 'No code quality issues found'
108
+ };
109
+ console.log('\n' + JSON.stringify(result));
110
+ return;
111
+ }
112
+
113
+ // Group by severity
114
+ const warnings = allIssues.filter(i => i.severity === 'warning');
115
+ const infos = allIssues.filter(i => i.severity === 'info');
116
+
117
+ if (warnings.length > 0) {
118
+ console.log('\n āš ļø Warnings:');
119
+ warnings.forEach(issue => console.log(` - ${issue.message}`));
120
+ }
121
+
122
+ if (infos.length > 0) {
123
+ console.log('\n ā„¹ļø Info:');
124
+ infos.forEach(issue => console.log(` - ${issue.message}`));
125
+ }
126
+
127
+ // Check for blocking issues (potential secrets)
128
+ const hasSecrets = warnings.some(w => w.message.includes('SECURITY'));
129
+
130
+ let result: AnalyzerResult;
131
+ if (hasSecrets) {
132
+ // BLOCK commit if potential secrets found
133
+ result = {
134
+ approved: false,
135
+ reason: 'Potential secrets detected - verify no credentials are committed'
136
+ };
137
+ } else {
138
+ // Just warn but allow commit
139
+ result = {
140
+ approved: true,
141
+ reason: `Code quality warnings found (${warnings.length} warnings, ${infos.length} info)`
142
+ };
143
+ }
144
+
145
+ console.log('\n' + JSON.stringify(result));
146
+
147
+ } catch (error) {
148
+ console.error('āŒ Error in code quality checker:', error);
149
+ console.log(JSON.stringify({ approved: true, reason: 'analyzer_error' }));
150
+ process.exit(1);
151
+ }
152
+ }
153
+
154
+ main();
@@ -0,0 +1,54 @@
1
+ # Code Quality Analyzer
2
+
3
+ ## Configuration
4
+
5
+ ```yaml
6
+ name: code-quality-checker
7
+ blocking: secrets-only
8
+ priority: 1
9
+ ```
10
+
11
+ ## Prompt
12
+
13
+ You are a code quality analyzer reviewing git commit changes before they are committed.
14
+
15
+ Analyze the provided diff and check for:
16
+
17
+ 1. **Debug Code** - console.log, debugger statements, commented-out code
18
+ 2. **Security Issues** - Potential secrets, API keys, passwords, tokens hardcoded in code
19
+ 3. **Code Smells** - TODO/FIXME comments, magic numbers, overly complex code
20
+ 4. **Best Practices** - Proper error handling, appropriate variable names
21
+
22
+ ## Review Criteria
23
+
24
+ **BLOCK the commit (approved: false) if:**
25
+ - Potential secrets/credentials detected (API keys, passwords, tokens with values)
26
+ - Obvious security vulnerabilities (eval, dangerouslySetInnerHTML without sanitization)
27
+
28
+ **WARN but ALLOW (approved: true) if:**
29
+ - console.log or debugger statements found
30
+ - TODO/FIXME comments present
31
+ - Minor code quality issues
32
+
33
+ ## Response Format
34
+
35
+ Return your analysis as JSON:
36
+
37
+ ```json
38
+ {
39
+ "approved": boolean,
40
+ "reason": "Brief explanation",
41
+ "details": [
42
+ "Specific issue 1",
43
+ "Specific issue 2"
44
+ ]
45
+ }
46
+ ```
47
+
48
+ ## Input Data
49
+
50
+ You will receive:
51
+ - `staged_diff`: The git diff of staged changes
52
+ - `changed_files`: List of files being committed
53
+ - `branch`: Current git branch
54
+ - Full git context
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Example Analyzer: Commit Blocker
5
+ *
6
+ * This analyzer demonstrates how to BLOCK commits based on specific conditions.
7
+ * It's disabled by default (note the .disabled extension).
8
+ *
9
+ * To enable: Rename to commit-blocker-example.ts
10
+ */
11
+
12
+ import { readFileSync } from 'fs';
13
+
14
+ interface HookData {
15
+ event: string;
16
+ timestamp: string;
17
+ repository: string;
18
+ branch: string;
19
+ staged_diff: string;
20
+ unstaged_diff: string;
21
+ changed_files: string[];
22
+ stats: {
23
+ staged_files: number;
24
+ has_staged_changes: boolean;
25
+ has_unstaged_changes: boolean;
26
+ };
27
+ }
28
+
29
+ interface AnalyzerResult {
30
+ approved: boolean;
31
+ reason?: string;
32
+ }
33
+
34
+ async function main() {
35
+ try {
36
+ // Read JSON data from stdin
37
+ const input = readFileSync(0, 'utf-8');
38
+ const data: HookData = JSON.parse(input);
39
+
40
+ console.log('🚫 Commit Blocker Example:');
41
+
42
+ // Example 1: Block commits to main branch
43
+ if (data.branch === 'main') {
44
+ const result: AnalyzerResult = {
45
+ approved: false,
46
+ reason: 'Direct commits to main branch are not allowed'
47
+ };
48
+ console.log('\n' + JSON.stringify(result));
49
+ return;
50
+ }
51
+
52
+ // Example 2: Block commits with too many files
53
+ const MAX_FILES = 50;
54
+ if (data.changed_files.length > MAX_FILES) {
55
+ const result: AnalyzerResult = {
56
+ approved: false,
57
+ reason: `Too many files changed (${data.changed_files.length} > ${MAX_FILES}) - split into smaller commits`
58
+ };
59
+ console.log('\n' + JSON.stringify(result));
60
+ return;
61
+ }
62
+
63
+ // Example 3: Block if critical files changed without tests
64
+ const criticalFiles = data.changed_files.filter(f =>
65
+ f.includes('/api/') ||
66
+ f.includes('/core/') ||
67
+ f.endsWith('Handler.ts')
68
+ );
69
+
70
+ const testFiles = data.changed_files.filter(f => f.endsWith('.test.ts'));
71
+
72
+ if (criticalFiles.length > 0 && testFiles.length === 0) {
73
+ const result: AnalyzerResult = {
74
+ approved: false,
75
+ reason: 'Critical files changed but no test files updated - add tests first'
76
+ };
77
+ console.log(`\n Critical files: ${criticalFiles.join(', ')}`);
78
+ console.log('\n' + JSON.stringify(result));
79
+ return;
80
+ }
81
+
82
+ // Example 4: Block if package.json changed without package-lock.json
83
+ const packageJsonChanged = data.changed_files.includes('package.json');
84
+ const lockfileChanged = data.changed_files.includes('package-lock.json');
85
+
86
+ if (packageJsonChanged && !lockfileChanged) {
87
+ const result: AnalyzerResult = {
88
+ approved: false,
89
+ reason: 'package.json changed but package-lock.json not updated - run npm install'
90
+ };
91
+ console.log('\n' + JSON.stringify(result));
92
+ return;
93
+ }
94
+
95
+ // All checks passed
96
+ console.log(' āœ… All blocking checks passed');
97
+ const result: AnalyzerResult = {
98
+ approved: true,
99
+ reason: 'No blocking issues found'
100
+ };
101
+ console.log('\n' + JSON.stringify(result));
102
+
103
+ } catch (error) {
104
+ console.error('āŒ Error in commit blocker:', error);
105
+ console.log(JSON.stringify({ approved: true, reason: 'analyzer_error' }));
106
+ process.exit(1);
107
+ }
108
+ }
109
+
110
+ main();
@@ -0,0 +1,49 @@
1
+ # Commit Policy Enforcer
2
+
3
+ ## Configuration
4
+
5
+ ```yaml
6
+ name: commit-policy
7
+ blocking: true
8
+ priority: 0
9
+ ```
10
+
11
+ ## Prompt
12
+
13
+ You are a commit policy enforcer ensuring repository standards are maintained.
14
+
15
+ Review the commit and enforce these policies:
16
+
17
+ 1. **Branch Protection** - Check if direct commits to protected branches (main, production) are allowed
18
+ 2. **Commit Size** - Ensure commits aren't too large (>50 files suggests should be split)
19
+ 3. **Critical File Protection** - If critical files change (package.json, config files), ensure related files also change
20
+ 4. **Required Files** - If package.json changes, package-lock.json should also change
21
+
22
+ ## Review Criteria
23
+
24
+ **BLOCK the commit (approved: false) if:**
25
+ - Direct commit to 'main' or 'production' branch
26
+ - More than 50 files changed in a single commit
27
+ - package.json changed but package-lock.json didn't change
28
+ - Critical API files changed without corresponding test updates
29
+
30
+ **ALLOW (approved: true) otherwise**
31
+
32
+ ## Response Format
33
+
34
+ ```json
35
+ {
36
+ "approved": boolean,
37
+ "reason": "Policy check result",
38
+ "details": [
39
+ "Policy violation or approval reason"
40
+ ]
41
+ }
42
+ ```
43
+
44
+ ## Input Data
45
+
46
+ You will receive:
47
+ - `branch`: Current branch name
48
+ - `changed_files`: List and count of files
49
+ - `staged_diff`: Full diff of changes
@@ -0,0 +1,49 @@
1
+ # Event Model Validator
2
+
3
+ ## Configuration
4
+
5
+ ```yaml
6
+ name: event-model-validator
7
+ blocking: false
8
+ priority: 2
9
+ ```
10
+
11
+ ## Prompt
12
+
13
+ You are an event model architecture validator for event-sourced systems.
14
+
15
+ Review the git diff and validate that changes follow event modeling best practices:
16
+
17
+ 1. **Event Naming** - Events should be in past tense (e.g., "UserRegistered", "OrderPlaced")
18
+ 2. **Command Naming** - Commands should be imperative (e.g., "RegisterUser", "PlaceOrder")
19
+ 3. **Test Coverage** - When logic files change (CommandHandler, Projection, processor), corresponding test files should also change
20
+ 4. **Slice Structure** - Files should follow the standard slice organization pattern
21
+
22
+ ## Review Criteria
23
+
24
+ **Always ALLOW (approved: true)** - This analyzer provides guidance but doesn't block commits.
25
+
26
+ Provide warnings for:
27
+ - Event names that don't follow past-tense convention
28
+ - Missing test updates when logic changes
29
+ - Deviations from slice structure patterns
30
+
31
+ ## Response Format
32
+
33
+ ```json
34
+ {
35
+ "approved": true,
36
+ "reason": "Event model validation completed",
37
+ "details": [
38
+ "āš ļø Event 'UserRegister' should be 'UserRegistered'",
39
+ "šŸ’” Logic changed in RegisterUser slice but no test updates"
40
+ ]
41
+ }
42
+ ```
43
+
44
+ ## Input Data
45
+
46
+ You will receive:
47
+ - `staged_diff`: Changes being committed
48
+ - `changed_files`: List of modified files (check for *Command.ts, *Projection.ts, *.test.ts)
49
+ - Full repository context
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Example Analyzer: Event Model Validator
5
+ *
6
+ * This analyzer validates changes to event model slices:
7
+ * - Checks if event names follow past-tense convention
8
+ * - Validates command naming (imperative form)
9
+ * - Ensures test files are updated when logic changes
10
+ * - Verifies TypeScript files follow slice structure
11
+ */
12
+
13
+ import { readFileSync } from 'fs';
14
+
15
+ interface HookData {
16
+ event: string;
17
+ timestamp: string;
18
+ repository: string;
19
+ branch: string;
20
+ staged_diff: string;
21
+ unstaged_diff: string;
22
+ changed_files: string[];
23
+ stats: {
24
+ staged_files: number;
25
+ has_staged_changes: boolean;
26
+ has_unstaged_changes: boolean;
27
+ };
28
+ }
29
+
30
+ interface ValidationResult {
31
+ valid: boolean;
32
+ warnings: string[];
33
+ suggestions: string[];
34
+ }
35
+
36
+ function validateEventNames(diff: string): ValidationResult {
37
+ const warnings: string[] = [];
38
+ const suggestions: string[] = [];
39
+
40
+ // Look for event definitions in the diff
41
+ const eventPattern = /interface\s+(\w+Event)\s*{/g;
42
+ const lines = diff.split('\n').filter(line => line.startsWith('+'));
43
+ const content = lines.join('\n');
44
+
45
+ const matches = [...content.matchAll(eventPattern)];
46
+
47
+ for (const match of matches) {
48
+ const eventName = match[1];
49
+
50
+ // Check if event name ends with past tense indicators
51
+ const pastTenseEndings = ['ed', 'Created', 'Updated', 'Deleted', 'Activated', 'Deactivated', 'Registered', 'Confirmed'];
52
+ const hasPastTense = pastTenseEndings.some(ending => eventName.includes(ending));
53
+
54
+ if (!hasPastTense) {
55
+ warnings.push(`Event name "${eventName}" may not follow past-tense convention`);
56
+ suggestions.push(`Consider renaming to express a completed action (e.g., "${eventName}Created" or "${eventName}Updated")`);
57
+ }
58
+ }
59
+
60
+ return {
61
+ valid: warnings.length === 0,
62
+ warnings,
63
+ suggestions
64
+ };
65
+ }
66
+
67
+ function checkSliceStructure(changedFiles: string[]): ValidationResult {
68
+ const warnings: string[] = [];
69
+ const suggestions: string[] = [];
70
+
71
+ // Group files by slice
72
+ const sliceFiles = changedFiles.filter(f => f.includes('src/slices/'));
73
+
74
+ const sliceMap = new Map<string, string[]>();
75
+
76
+ for (const file of sliceFiles) {
77
+ const match = file.match(/src\/slices\/([^/]+)\//);
78
+ if (match) {
79
+ const sliceName = match[1];
80
+ if (!sliceMap.has(sliceName)) {
81
+ sliceMap.set(sliceName, []);
82
+ }
83
+ sliceMap.get(sliceName)!.push(file);
84
+ }
85
+ }
86
+
87
+ // Check if test files are included when logic changes
88
+ for (const [sliceName, files] of sliceMap.entries()) {
89
+ const hasLogicChange = files.some(f =>
90
+ f.endsWith('Command.ts') ||
91
+ f.endsWith('CommandHandler.ts') ||
92
+ f.endsWith('Projection.ts') ||
93
+ f.endsWith('processor.ts')
94
+ );
95
+
96
+ const hasTestChange = files.some(f => f.endsWith('.test.ts'));
97
+
98
+ if (hasLogicChange && !hasTestChange) {
99
+ warnings.push(`Logic changed in "${sliceName}" slice but no test file updated`);
100
+ suggestions.push(`Consider updating ${sliceName}.test.ts to cover the changes`);
101
+ }
102
+ }
103
+
104
+ return {
105
+ valid: warnings.length === 0,
106
+ warnings,
107
+ suggestions
108
+ };
109
+ }
110
+
111
+ interface AnalyzerResult {
112
+ approved: boolean;
113
+ reason?: string;
114
+ }
115
+
116
+ async function main() {
117
+ try {
118
+ // Read JSON data from stdin
119
+ const input = readFileSync(0, 'utf-8');
120
+ const data: HookData = JSON.parse(input);
121
+
122
+ console.log('šŸ—ļø Event Model Validation:');
123
+
124
+ // Validate event names
125
+ const eventValidation = validateEventNames(data.staged_diff);
126
+
127
+ // Check slice structure
128
+ const structureValidation = checkSliceStructure(data.changed_files);
129
+
130
+ const allWarnings = [...eventValidation.warnings, ...structureValidation.warnings];
131
+ const allSuggestions = [...eventValidation.suggestions, ...structureValidation.suggestions];
132
+
133
+ if (allWarnings.length === 0) {
134
+ console.log(' āœ… Event model structure looks good');
135
+
136
+ const result: AnalyzerResult = {
137
+ approved: true,
138
+ reason: 'Event model validation passed'
139
+ };
140
+ console.log('\n' + JSON.stringify(result));
141
+ return;
142
+ }
143
+
144
+ if (allWarnings.length > 0) {
145
+ console.log('\n āš ļø Validation warnings:');
146
+ allWarnings.forEach(warning => console.log(` - ${warning}`));
147
+ }
148
+
149
+ if (allSuggestions.length > 0) {
150
+ console.log('\n šŸ’” Suggestions:');
151
+ allSuggestions.forEach(suggestion => console.log(` - ${suggestion}`));
152
+ }
153
+
154
+ // Approve but provide warnings
155
+ const result: AnalyzerResult = {
156
+ approved: true,
157
+ reason: `Event model validation warnings (${allWarnings.length} warnings)`
158
+ };
159
+
160
+ console.log('\n' + JSON.stringify(result));
161
+
162
+ } catch (error) {
163
+ console.error('āŒ Error in event model validator:', error);
164
+ console.log(JSON.stringify({ approved: true, reason: 'analyzer_error' }));
165
+ process.exit(1);
166
+ }
167
+ }
168
+
169
+ main();
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Example Analyzer: Simple Logger
5
+ *
6
+ * This analyzer receives git diff information and logs basic statistics.
7
+ * It demonstrates how to parse the JSON payload and extract useful information.
8
+ * Always approves commits.
9
+ */
10
+
11
+ import { readFileSync } from 'fs';
12
+
13
+ interface HookData {
14
+ event: string;
15
+ timestamp: string;
16
+ repository: string;
17
+ branch: string;
18
+ staged_diff: string;
19
+ unstaged_diff: string;
20
+ changed_files: string[];
21
+ stats: {
22
+ staged_files: number;
23
+ has_staged_changes: boolean;
24
+ has_unstaged_changes: boolean;
25
+ };
26
+ }
27
+
28
+ interface AnalyzerResult {
29
+ approved: boolean;
30
+ reason?: string;
31
+ }
32
+
33
+ async function main() {
34
+ try {
35
+ // Read JSON data from stdin
36
+ const input = readFileSync(0, 'utf-8');
37
+ const data: HookData = JSON.parse(input);
38
+
39
+ console.log('šŸ“Š Commit Analysis:');
40
+ console.log(` Branch: ${data.branch}`);
41
+ console.log(` Files changed: ${data.changed_files.length}`);
42
+ console.log(` Has staged changes: ${data.stats.has_staged_changes}`);
43
+ console.log(` Has unstaged changes: ${data.stats.has_unstaged_changes}`);
44
+
45
+ // Log changed files
46
+ if (data.changed_files.length > 0) {
47
+ console.log('\nšŸ“ Changed files:');
48
+ data.changed_files.forEach(file => {
49
+ if (file.trim()) {
50
+ console.log(` - ${file}`);
51
+ }
52
+ });
53
+ }
54
+
55
+ // Always approve - this is just an informational analyzer
56
+ const result: AnalyzerResult = {
57
+ approved: true,
58
+ reason: 'Logger - informational only'
59
+ };
60
+
61
+ console.log('\n' + JSON.stringify(result));
62
+
63
+ } catch (error) {
64
+ console.error('āŒ Error in analyzer:', error);
65
+ console.log(JSON.stringify({ approved: true, reason: 'analyzer_error' }));
66
+ process.exit(1);
67
+ }
68
+ }
69
+
70
+ main();