@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.
- package/README.md +254 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +138 -0
- package/package.json +49 -0
- package/templates/.claude/hooks/QUICKSTART.md +256 -0
- package/templates/.claude/hooks/README.md +533 -0
- package/templates/.claude/hooks/analyze-commit.sh +22 -0
- package/templates/.claude/hooks/analyze-commit.ts +518 -0
- package/templates/.claude/hooks/analyzers/README.md +198 -0
- package/templates/.claude/hooks/analyzers/code-quality-checker.ts +154 -0
- package/templates/.claude/hooks/analyzers/code-quality.md +54 -0
- package/templates/.claude/hooks/analyzers/commit-blocker-example.ts.disabled +110 -0
- package/templates/.claude/hooks/analyzers/commit-policy.md +49 -0
- package/templates/.claude/hooks/analyzers/event-model-validator.md +49 -0
- package/templates/.claude/hooks/analyzers/event-model-validator.ts +169 -0
- package/templates/.claude/hooks/analyzers/example-logger.ts +70 -0
- package/templates/.claude/hooks/analyzers/slice-scope-validator.md +81 -0
- package/templates/.claude/hooks/check-review-result.sh +47 -0
- package/templates/.claude/hooks/prepare-review.sh +34 -0
- package/templates/.claude/hooks/review-agent-prompt.md +42 -0
- package/templates/.claude/hooks/run-review-agent.sh +124 -0
- package/templates/.claude/settings.local.json +37 -0
- package/templates/.claude/skills/help/README.md +84 -0
- package/templates/.claude/skills/help/SKILL.md +393 -0
- package/templates/.claude/skills/help/templates/demo-config.json +6753 -0
- package/templates/.claude/skills/sample-slices/SKILL.md +8 -0
- package/templates/.claude/skills/sample-slices/templates/.slices/Library/addbook/code-slice.json +124 -0
- package/templates/.claude/skills/sample-slices/templates/.slices/Library/addbook/slice.json +255 -0
- package/templates/.claude/skills/sample-slices/templates/.slices/Library/availablebooks/slice.json +107 -0
- package/templates/.claude/skills/sample-slices/templates/.slices/index.json +20 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/additem/slice.json +979 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/archiveitem/slice.json +529 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/cartitems/slice.json +1072 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/cartwithproducts/slice.json +394 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/changedprices/slice.json +88 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/changeinventory/slice.json +264 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/changeprice/slice.json +308 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/clearcart/slice.json +358 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/inventories/slice.json +203 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/publishcart/slice.json +876 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/removeitem/slice.json +560 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/submitcart/slice.json +708 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/submittedcartdata/slice.json +399 -0
- package/templates/.claude/skills/sample-slices/templates/index.json +108 -0
- package/templates/.claude/skills/slice-automation/SKILL.md +49 -0
- package/templates/.claude/skills/slice-state-change/SKILL.md +369 -0
- package/templates/.claude/skills/slice-state-change/templates/AddLocation/AddLocation.test.ts.sample +76 -0
- package/templates/.claude/skills/slice-state-change/templates/AddLocation/AddLocationCommand.ts.sample +84 -0
- package/templates/.claude/skills/slice-state-change/templates/AddLocation/routes.ts.sample +73 -0
- package/templates/.claude/skills/slice-state-change/templates/README.md +46 -0
- package/templates/.claude/skills/slice-state-view/SKILL.md +336 -0
- package/templates/.claude/skills/slice-state-view/templates/Locations/Locations.test.ts.sample +84 -0
- package/templates/.claude/skills/slice-state-view/templates/Locations/LocationsProjection.ts.sample +50 -0
- package/templates/.claude/skills/slice-state-view/templates/Locations/routes.ts.sample +46 -0
- package/templates/.claude/skills/slice-state-view/templates/README.md +109 -0
- package/templates/.claude/skills/slice-state-view/templates/Tables/Tables.test.ts.sample +104 -0
- package/templates/.claude/skills/slice-state-view/templates/Tables/TablesProjection.ts.sample +59 -0
- package/templates/.claude/skills/slice-state-view/templates/Tables/routes.ts.sample +46 -0
- package/templates/.claude/skills/slice-state-view/templates/V2__tables.sql +7 -0
- package/templates/.claude/skills/slice-state-view/templates/V8__locations.sql +7 -0
- package/templates/.claude/skills/test-analyzer/SKILL.md +373 -0
- package/templates/.claude/skills/test-analyzer/examples/specification-format.md +143 -0
- package/templates/.claude/skills/test-analyzer/examples/state-change-example.md +111 -0
- package/templates/.claude/skills/test-analyzer/examples/state-view-example.md +122 -0
- package/templates/AGENTS.md +110 -0
- package/templates/Claude.md +58 -0
- package/templates/README.md +178 -0
- package/templates/backend/.env +9 -0
- package/templates/backend/BACKEND_AUTH_SETUP.md +183 -0
- package/templates/backend/SWAGGER.md +213 -0
- package/templates/backend/eslint.config.mjs +31 -0
- package/templates/backend/flyway.conf +17 -0
- package/templates/backend/package.json +44 -0
- package/templates/backend/prd.json.example +64 -0
- package/templates/backend/public/assets/images/banner.png +0 -0
- package/templates/backend/public/assets/logo.png +0 -0
- package/templates/backend/public/file.svg +4 -0
- package/templates/backend/public/globe.svg +12 -0
- package/templates/backend/public/next.svg +6 -0
- package/templates/backend/public/vercel.svg +3 -0
- package/templates/backend/public/window.svg +5 -0
- package/templates/backend/server.ts +129 -0
- package/templates/backend/setup-env.sh +50 -0
- package/templates/backend/src/common/assertions.ts +6 -0
- package/templates/backend/src/common/db.ts +1 -0
- package/templates/backend/src/common/loadPostgresEventstore.ts +16 -0
- package/templates/backend/src/common/parseEndpoint.ts +51 -0
- package/templates/backend/src/common/replay.ts +9 -0
- package/templates/backend/src/common/routes.ts +19 -0
- package/templates/backend/src/common/testHelpers.ts +53 -0
- package/templates/backend/src/core/readmodel.ts +28 -0
- package/templates/backend/src/core/types.ts +26 -0
- package/templates/backend/src/process/process.ts +53 -0
- package/templates/backend/src/supabase/LoginHandler.ts +36 -0
- package/templates/backend/src/supabase/ProtectedPageProps.ts +21 -0
- package/templates/backend/src/supabase/README.md +171 -0
- package/templates/backend/src/supabase/api.ts +63 -0
- package/templates/backend/src/supabase/authMiddleware.ts +53 -0
- package/templates/backend/src/supabase/component.ts +12 -0
- package/templates/backend/src/supabase/requireUser.ts +72 -0
- package/templates/backend/src/supabase/serverProps.ts +25 -0
- package/templates/backend/src/supabase/staticProps.ts +10 -0
- package/templates/backend/src/swagger.ts +34 -0
- package/templates/backend/src/util/assertions.ts +6 -0
- package/templates/backend/supabase/config.toml +295 -0
- package/templates/backend/supabase/migrations/20260121155918593_catalogentries.sql.sample +23 -0
- package/templates/backend/supabase/seed.sql +1 -0
- package/templates/backend/tsconfig.json +31 -0
- package/templates/frontend/.env.development +3 -0
- package/templates/frontend/AGENTS.md +7 -0
- package/templates/frontend/README.md +73 -0
- package/templates/frontend/components.json +20 -0
- package/templates/frontend/eslint.config.js +26 -0
- package/templates/frontend/index.html +18 -0
- package/templates/frontend/package-lock.json +8347 -0
- package/templates/frontend/package.json +94 -0
- package/templates/frontend/postcss.config.js +6 -0
- package/templates/frontend/public/favicon.ico +0 -0
- package/templates/frontend/public/logo.png +0 -0
- package/templates/frontend/public/placeholder.svg +1 -0
- package/templates/frontend/public/robots.txt +14 -0
- package/templates/frontend/src/App.css +42 -0
- package/templates/frontend/src/App.tsx +47 -0
- package/templates/frontend/src/components/NavLink.tsx +28 -0
- package/templates/frontend/src/components/ProtectedRoute.tsx +24 -0
- package/templates/frontend/src/components/calendar/Calendar.tsx +302 -0
- package/templates/frontend/src/components/layout/DashboardLayout.tsx +21 -0
- package/templates/frontend/src/components/layout/Header.tsx +45 -0
- package/templates/frontend/src/components/layout/Sidebar.tsx +82 -0
- package/templates/frontend/src/components/tables/ReservationTemplates.tsx +189 -0
- package/templates/frontend/src/components/ui/accordion.tsx +52 -0
- package/templates/frontend/src/components/ui/alert-dialog.tsx +104 -0
- package/templates/frontend/src/components/ui/alert.tsx +43 -0
- package/templates/frontend/src/components/ui/aspect-ratio.tsx +5 -0
- package/templates/frontend/src/components/ui/avatar.tsx +38 -0
- package/templates/frontend/src/components/ui/badge.tsx +29 -0
- package/templates/frontend/src/components/ui/breadcrumb.tsx +90 -0
- package/templates/frontend/src/components/ui/button.tsx +47 -0
- package/templates/frontend/src/components/ui/calendar.tsx +54 -0
- package/templates/frontend/src/components/ui/card.tsx +43 -0
- package/templates/frontend/src/components/ui/carousel.tsx +224 -0
- package/templates/frontend/src/components/ui/chart.tsx +303 -0
- package/templates/frontend/src/components/ui/checkbox.tsx +26 -0
- package/templates/frontend/src/components/ui/collapsible.tsx +9 -0
- package/templates/frontend/src/components/ui/command.tsx +132 -0
- package/templates/frontend/src/components/ui/context-menu.tsx +178 -0
- package/templates/frontend/src/components/ui/dialog.tsx +95 -0
- package/templates/frontend/src/components/ui/drawer.tsx +87 -0
- package/templates/frontend/src/components/ui/dropdown-menu.tsx +179 -0
- package/templates/frontend/src/components/ui/form.tsx +129 -0
- package/templates/frontend/src/components/ui/hover-card.tsx +27 -0
- package/templates/frontend/src/components/ui/input-otp.tsx +61 -0
- package/templates/frontend/src/components/ui/input.tsx +22 -0
- package/templates/frontend/src/components/ui/label.tsx +17 -0
- package/templates/frontend/src/components/ui/menubar.tsx +207 -0
- package/templates/frontend/src/components/ui/navigation-menu.tsx +120 -0
- package/templates/frontend/src/components/ui/pagination.tsx +81 -0
- package/templates/frontend/src/components/ui/popover.tsx +29 -0
- package/templates/frontend/src/components/ui/progress.tsx +23 -0
- package/templates/frontend/src/components/ui/radio-group.tsx +36 -0
- package/templates/frontend/src/components/ui/resizable.tsx +37 -0
- package/templates/frontend/src/components/ui/scroll-area.tsx +38 -0
- package/templates/frontend/src/components/ui/select.tsx +143 -0
- package/templates/frontend/src/components/ui/separator.tsx +20 -0
- package/templates/frontend/src/components/ui/sheet.tsx +107 -0
- package/templates/frontend/src/components/ui/sidebar.tsx +637 -0
- package/templates/frontend/src/components/ui/skeleton.tsx +7 -0
- package/templates/frontend/src/components/ui/slider.tsx +23 -0
- package/templates/frontend/src/components/ui/sonner.tsx +27 -0
- package/templates/frontend/src/components/ui/stat-card.tsx +44 -0
- package/templates/frontend/src/components/ui/switch.tsx +27 -0
- package/templates/frontend/src/components/ui/table.tsx +72 -0
- package/templates/frontend/src/components/ui/tabs.tsx +53 -0
- package/templates/frontend/src/components/ui/textarea.tsx +21 -0
- package/templates/frontend/src/components/ui/toast.tsx +111 -0
- package/templates/frontend/src/components/ui/toaster.tsx +24 -0
- package/templates/frontend/src/components/ui/toggle-group.tsx +49 -0
- package/templates/frontend/src/components/ui/toggle.tsx +37 -0
- package/templates/frontend/src/components/ui/tooltip.tsx +28 -0
- package/templates/frontend/src/components/ui/use-toast.ts +3 -0
- package/templates/frontend/src/contexts/AuthContext.tsx +94 -0
- package/templates/frontend/src/contexts/RefreshContext.tsx +236 -0
- package/templates/frontend/src/hooks/api/index.ts +2 -0
- package/templates/frontend/src/hooks/api/useLocations.ts +15 -0
- package/templates/frontend/src/hooks/use-mobile.tsx +19 -0
- package/templates/frontend/src/hooks/use-toast.ts +186 -0
- package/templates/frontend/src/hooks/useApiContext.ts +11 -0
- package/templates/frontend/src/index.css +118 -0
- package/templates/frontend/src/integrations/supabase/client.ts +9 -0
- package/templates/frontend/src/lib/api-client.ts +136 -0
- package/templates/frontend/src/lib/api.ts +1028 -0
- package/templates/frontend/src/lib/utils.ts +6 -0
- package/templates/frontend/src/main.tsx +5 -0
- package/templates/frontend/src/pages/Auth.tsx +408 -0
- package/templates/frontend/src/pages/Dashboard.tsx +168 -0
- package/templates/frontend/src/pages/Menus.tsx +224 -0
- package/templates/frontend/src/pages/NotFound.tsx +24 -0
- package/templates/frontend/src/pages/Register.tsx +285 -0
- package/templates/frontend/src/test/example.test.ts +0 -0
- package/templates/frontend/src/test/setup.ts +15 -0
- package/templates/frontend/src/types/index.ts +8 -0
- package/templates/frontend/src/vite-env.d.ts +1 -0
- package/templates/frontend/tailwind.config.ts +101 -0
- package/templates/frontend/tsconfig.app.json +31 -0
- package/templates/frontend/tsconfig.json +16 -0
- package/templates/frontend/tsconfig.node.json +22 -0
- package/templates/frontend/vite.config.ts +21 -0
- package/templates/frontend/vitest.config.ts +16 -0
- package/templates/init.sh +1 -0
- package/templates/prompt.md +139 -0
- package/templates/ralph.sh +120 -0
- package/templates/server.mjs +505 -0
package/README.md
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
# EMBuilder
|
|
2
|
+
|
|
3
|
+
Event-Model driven development toolkit for Claude Code. Generate code slices from event model specifications using simple slash commands.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Super simple - install from GitHub Packages:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx @dilgerma/embuilder install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
That's it! The skills are now available in Claude Code.
|
|
14
|
+
|
|
15
|
+
### Manual Installation (Alternative)
|
|
16
|
+
|
|
17
|
+
If you want to install from a local directory:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cd /path/to/embuilder
|
|
21
|
+
npm install
|
|
22
|
+
npm run build
|
|
23
|
+
npm link
|
|
24
|
+
embuilder install
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## What This Does
|
|
28
|
+
|
|
29
|
+
This package adds powerful skills to Claude Code for event-model driven development:
|
|
30
|
+
|
|
31
|
+
### Event Model Skills
|
|
32
|
+
- `/automation-slice` - Generate automation slices (background processes with CRON)
|
|
33
|
+
- `/state-change-slice` - Generate command handlers (business logic)
|
|
34
|
+
- `/state-view-slice` - Generate read models/projections (queries and views)
|
|
35
|
+
|
|
36
|
+
### Configuration Skills
|
|
37
|
+
- `/fetch-config` - Fetch config.json from your event model app (localhost:3001)
|
|
38
|
+
|
|
39
|
+
### Yeoman Generator Skills
|
|
40
|
+
- `/gen-skeleton` - Generate a Supabase backend skeleton app
|
|
41
|
+
- `/gen-state-change` - Generate state change slices from config.json
|
|
42
|
+
- `/gen-state-view` - Generate state view slices from config.json
|
|
43
|
+
- `/gen-automation` - Generate automation slices from config.json
|
|
44
|
+
- `/gen-ui` - Set up a React UI project with shadcn/ui and Supabase
|
|
45
|
+
|
|
46
|
+
All based on your event model specifications and configuration!
|
|
47
|
+
|
|
48
|
+
## Quick Start
|
|
49
|
+
|
|
50
|
+
### From GitHub Packages
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npx @dilgerma/embuilder install
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### From Local Directory
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
./install.sh
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Using the Skills
|
|
63
|
+
|
|
64
|
+
In Claude Code, just type one of these commands:
|
|
65
|
+
|
|
66
|
+
**Event Model Skills:**
|
|
67
|
+
```
|
|
68
|
+
/state-change-slice # Generate a command handler
|
|
69
|
+
/state-view-slice # Generate a read model
|
|
70
|
+
/automation-slice # Generate a background automation
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Configuration:**
|
|
74
|
+
```
|
|
75
|
+
/fetch-config # Fetch config from event model app
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Yeoman Generator Skills:**
|
|
79
|
+
```
|
|
80
|
+
/gen-skeleton # Generate Supabase backend skeleton
|
|
81
|
+
/gen-state-change # Generate state change slices from config
|
|
82
|
+
/gen-state-view # Generate state view slices from config
|
|
83
|
+
/gen-automation # Generate automation slices from config
|
|
84
|
+
/gen-ui # Set up React UI project
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Claude will:
|
|
88
|
+
- Guide you through the generation process
|
|
89
|
+
- Find your event model or config.json
|
|
90
|
+
- Generate TypeScript code following best practices
|
|
91
|
+
- Create tests automatically
|
|
92
|
+
- Run the tests to verify everything works
|
|
93
|
+
|
|
94
|
+
## Skills Overview
|
|
95
|
+
|
|
96
|
+
### Event Model Skills
|
|
97
|
+
|
|
98
|
+
#### `/automation-slice`
|
|
99
|
+
Builds background automations that:
|
|
100
|
+
- Read from TODO lists (work queues)
|
|
101
|
+
- Fire commands on a CRON schedule
|
|
102
|
+
- Process items automatically
|
|
103
|
+
|
|
104
|
+
**Use case:** Auto-confirm invitations, process checkouts, send notifications
|
|
105
|
+
|
|
106
|
+
#### `/state-change-slice`
|
|
107
|
+
Builds command handlers that:
|
|
108
|
+
- Accept commands (user actions)
|
|
109
|
+
- Validate against current state
|
|
110
|
+
- Emit events (facts about what happened)
|
|
111
|
+
|
|
112
|
+
**Use case:** Register clerk, activate feature, submit timesheet
|
|
113
|
+
|
|
114
|
+
#### `/state-view-slice`
|
|
115
|
+
Builds read models that:
|
|
116
|
+
- Subscribe to events
|
|
117
|
+
- Build queryable views
|
|
118
|
+
- Support UI and reporting
|
|
119
|
+
|
|
120
|
+
**Use case:** Active shifts dashboard, clerk directory, event calendar
|
|
121
|
+
|
|
122
|
+
### Yeoman Generator Skills
|
|
123
|
+
|
|
124
|
+
#### `/gen-skeleton`
|
|
125
|
+
Generates a complete Supabase backend skeleton app:
|
|
126
|
+
- Event store setup
|
|
127
|
+
- Basic project structure
|
|
128
|
+
- Common utilities and helpers
|
|
129
|
+
- Supabase configuration
|
|
130
|
+
|
|
131
|
+
**Use case:** Bootstrap a new event-sourced application
|
|
132
|
+
|
|
133
|
+
#### `/gen-state-change`, `/gen-state-view`, `/gen-automation`
|
|
134
|
+
Generate slices from your `config.json` file:
|
|
135
|
+
- Reads slice definitions from config
|
|
136
|
+
- Generates complete TypeScript implementations
|
|
137
|
+
- Creates API routes and tests
|
|
138
|
+
- Works with Yeoman's template system
|
|
139
|
+
|
|
140
|
+
**Use case:** Generate code from pre-defined slice configurations
|
|
141
|
+
|
|
142
|
+
#### `/gen-ui`
|
|
143
|
+
Sets up a modern React UI project:
|
|
144
|
+
- Vite + React + TypeScript
|
|
145
|
+
- shadcn/ui component library (Radix UI + Tailwind)
|
|
146
|
+
- Supabase client integration
|
|
147
|
+
- React Router and React Query
|
|
148
|
+
- Full suite of pre-built UI components
|
|
149
|
+
|
|
150
|
+
**Use case:** Quickly scaffold a frontend for your Supabase backend
|
|
151
|
+
|
|
152
|
+
## Event Model Structure
|
|
153
|
+
|
|
154
|
+
Your event model (JSON) typically defines:
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"commands": [
|
|
159
|
+
{
|
|
160
|
+
"title": "Register Clerk",
|
|
161
|
+
"fields": [
|
|
162
|
+
{"name": "clerkId", "type": "UUID"},
|
|
163
|
+
{"name": "name", "type": "String"}
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
],
|
|
167
|
+
"events": [
|
|
168
|
+
{
|
|
169
|
+
"title": "Clerk Registered",
|
|
170
|
+
"fields": [...]
|
|
171
|
+
}
|
|
172
|
+
],
|
|
173
|
+
"processors": [...],
|
|
174
|
+
"readmodels": [...]
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Generated Code Structure
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
src/slices/{slice-name}/
|
|
182
|
+
āāā CommandHandler.ts # Business logic (state-change)
|
|
183
|
+
āāā Projection.ts # Read model (state-view)
|
|
184
|
+
āāā processor.ts # CRON automation (automation)
|
|
185
|
+
āāā routes.ts # HTTP API endpoints
|
|
186
|
+
āāā {SliceName}.test.ts # Automated tests
|
|
187
|
+
āāā ui/ # UI components (optional)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Commands
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# Install skills only
|
|
194
|
+
npx @dilgerma/embuilder install
|
|
195
|
+
|
|
196
|
+
# Install skills + template files (ralph.sh, AGENTS.md, Claude.md, prompt.md)
|
|
197
|
+
npx @dilgerma/embuilder install --with-templates
|
|
198
|
+
|
|
199
|
+
# Uninstall
|
|
200
|
+
npx @dilgerma/embuilder uninstall
|
|
201
|
+
|
|
202
|
+
# Check status
|
|
203
|
+
npx @dilgerma/embuilder status
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Template Files
|
|
207
|
+
|
|
208
|
+
When you use `--with-templates`, you get:
|
|
209
|
+
|
|
210
|
+
- **`ralph.sh`** - Autonomous agent loop for continuous development
|
|
211
|
+
- **`AGENTS.md`** - Track learnings and patterns from development
|
|
212
|
+
- **`Claude.md`** - Project-specific configuration for Claude Code
|
|
213
|
+
- **`prompt.md`** - Agent instructions for automated development
|
|
214
|
+
- **`.claude/hooks/`** - Pre-commit hooks that analyze git diffs before commits
|
|
215
|
+
- Includes built-in analyzers for code quality and event model validation
|
|
216
|
+
- Extensible with custom TypeScript analyzers
|
|
217
|
+
|
|
218
|
+
These files enable the full event-model driven development workflow with autonomous agents.
|
|
219
|
+
|
|
220
|
+
### Git Commit Hooks
|
|
221
|
+
|
|
222
|
+
The template includes a pre-commit hook system that automatically analyzes changes before commits:
|
|
223
|
+
|
|
224
|
+
**Built-in Analyzers:**
|
|
225
|
+
- **Code Quality Checker** - Detects console.log, debugger statements, TODOs, and potential secrets
|
|
226
|
+
- **Event Model Validator** - Ensures event naming conventions and slice structure
|
|
227
|
+
- **Logger** - Displays commit statistics and changed files
|
|
228
|
+
|
|
229
|
+
**Features:**
|
|
230
|
+
- Written in TypeScript for type safety
|
|
231
|
+
- Extensible - add your own analyzers
|
|
232
|
+
- Non-blocking by default
|
|
233
|
+
- Integrates seamlessly with Claude Code
|
|
234
|
+
|
|
235
|
+
See `.claude/hooks/README.md` for full documentation on creating custom analyzers.
|
|
236
|
+
|
|
237
|
+
## Philosophy
|
|
238
|
+
|
|
239
|
+
This toolkit follows **event-model driven development**:
|
|
240
|
+
|
|
241
|
+
1. **Design first** - Define your event model (events, commands, aggregates)
|
|
242
|
+
2. **Generate code** - Use Claude skills to generate implementation
|
|
243
|
+
3. **Test automatically** - Generated code includes tests
|
|
244
|
+
4. **Iterate quickly** - Change the model, regenerate
|
|
245
|
+
|
|
246
|
+
## Requirements
|
|
247
|
+
|
|
248
|
+
- Node.js 18+
|
|
249
|
+
- Claude Code CLI
|
|
250
|
+
- TypeScript knowledge (for understanding generated code)
|
|
251
|
+
|
|
252
|
+
## License
|
|
253
|
+
|
|
254
|
+
MIT
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { dirname, join } from 'path';
|
|
5
|
+
import { existsSync, chmodSync, cpSync, rmSync, readdirSync, statSync } from 'fs';
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = dirname(__filename);
|
|
8
|
+
const program = new Command();
|
|
9
|
+
const SKILLS_DIR = join(process.cwd(), '.claude', 'skills');
|
|
10
|
+
program
|
|
11
|
+
.name('embuilder')
|
|
12
|
+
.description('EMBuilder - Event-Model driven development toolkit for Claude Code')
|
|
13
|
+
.version('0.1.22');
|
|
14
|
+
program
|
|
15
|
+
.command('install')
|
|
16
|
+
.description('Install event-model skills into Claude Code')
|
|
17
|
+
.option('--with-templates', 'Also copy template files (ralph.sh, AGENTS.md, Claude.md, prompt.md, README.md) and generators to current directory')
|
|
18
|
+
.action((options) => {
|
|
19
|
+
console.log('š¦ Installing EMBuilder...\n');
|
|
20
|
+
try {
|
|
21
|
+
// Copy template files if requested
|
|
22
|
+
console.log('\nš Copying all templates to current directory...');
|
|
23
|
+
const templatesSource = join(__dirname, '..', 'templates');
|
|
24
|
+
const targetDir = process.cwd();
|
|
25
|
+
if (!existsSync(templatesSource)) {
|
|
26
|
+
console.error('ā Templates directory not found!');
|
|
27
|
+
console.error(` Expected location: ${templatesSource}`);
|
|
28
|
+
console.error(` Package location: ${__dirname}`);
|
|
29
|
+
console.error('');
|
|
30
|
+
console.error('This might be caused by:');
|
|
31
|
+
console.error(' 1. Old cached version - try: npx --yes @dilgerma/embuilder@latest install --with-templates');
|
|
32
|
+
console.error(' 2. Package not published correctly - reinstall with: npm install -g @dilgerma/embuilder@latest');
|
|
33
|
+
console.error('');
|
|
34
|
+
console.error('If the problem persists, please report at:');
|
|
35
|
+
console.error(' https://github.com/dilgerma/embuilder/issues');
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
// Copy everything from templates/ to current directory
|
|
39
|
+
try {
|
|
40
|
+
// Read all items in templates directory and copy each one
|
|
41
|
+
// We copy items individually instead of the entire directory to have better control
|
|
42
|
+
const items = readdirSync(templatesSource);
|
|
43
|
+
for (const item of items) {
|
|
44
|
+
const sourcePath = join(templatesSource, item);
|
|
45
|
+
const targetPath = join(targetDir, item);
|
|
46
|
+
// Skip node_modules if present
|
|
47
|
+
if (item === 'node_modules') {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const stat = statSync(sourcePath);
|
|
52
|
+
if (stat.isDirectory()) {
|
|
53
|
+
// For directories, copy with filter to skip node_modules
|
|
54
|
+
cpSync(sourcePath, targetPath, {
|
|
55
|
+
recursive: true,
|
|
56
|
+
filter: (source) => {
|
|
57
|
+
// Get the relative path from the source directory to avoid matching
|
|
58
|
+
// 'node_modules' in the npx cache path itself
|
|
59
|
+
const relativePath = source.replace(sourcePath, '');
|
|
60
|
+
return !relativePath.includes('node_modules');
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
// For files, copy directly
|
|
66
|
+
cpSync(sourcePath, targetPath);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (itemError) {
|
|
70
|
+
console.error(` ā Error copying ${item}:`, itemError?.message);
|
|
71
|
+
}
|
|
72
|
+
// Verify this item was copied
|
|
73
|
+
if (!existsSync(targetPath)) {
|
|
74
|
+
console.error(` ā Failed to copy: ${item}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (copyError) {
|
|
79
|
+
console.error(' ā Error during copy:', copyError);
|
|
80
|
+
throw copyError;
|
|
81
|
+
}
|
|
82
|
+
// Verify files were actually copied
|
|
83
|
+
const copiedFiles = existsSync(join(targetDir, 'README.md'));
|
|
84
|
+
// Make ralph.sh executable if it exists
|
|
85
|
+
const ralphPath = join(targetDir, 'ralph.sh');
|
|
86
|
+
if (existsSync(ralphPath)) {
|
|
87
|
+
chmodSync(ralphPath, 0o755);
|
|
88
|
+
console.log(' ā Made ralph.sh executable');
|
|
89
|
+
}
|
|
90
|
+
if (!copiedFiles) {
|
|
91
|
+
console.error(' ā Files were not copied! This is a bug.');
|
|
92
|
+
console.error(' Please report this at: https://github.com/dilgerma/embuilder/issues');
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
console.log(' ā All template files and directories copied');
|
|
96
|
+
console.log(' - README.md, Claude.md, AGENTS.md, prompt.md, ralph.sh');
|
|
97
|
+
console.log(' - .claude/ directory with skills and generators');
|
|
98
|
+
console.log(' - All other template contents');
|
|
99
|
+
console.log('\nš Templates copied! You can now:');
|
|
100
|
+
console.log(' - Read README.md for detailed usage instructions');
|
|
101
|
+
console.log(' - Edit Claude.md with project-specific settings');
|
|
102
|
+
console.log(' - Run ./ralph.sh for automated development loops');
|
|
103
|
+
console.log(' - Track learnings in AGENTS.md');
|
|
104
|
+
console.log(' - Use skills in .claude/skills/ for code generation');
|
|
105
|
+
console.log('\nā
Installation complete with templates!');
|
|
106
|
+
console.log("\nš”Want to initialize the project? Just run this command:");
|
|
107
|
+
console.log("\ndocker run -v $PWD:/workspace nebulit/generators");
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
console.error('ā Installation failed:', error);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
program
|
|
115
|
+
.command('uninstall')
|
|
116
|
+
.description('Remove event-model skills from Claude Code')
|
|
117
|
+
.action(() => {
|
|
118
|
+
if (existsSync(SKILLS_DIR)) {
|
|
119
|
+
rmSync(SKILLS_DIR, { recursive: true, force: true });
|
|
120
|
+
console.log('ā
EMBuilder skills uninstalled');
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
console.log('ā¹ļø Skills not currently installed');
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
program
|
|
127
|
+
.command('status')
|
|
128
|
+
.description('Check installation status')
|
|
129
|
+
.action(() => {
|
|
130
|
+
console.log('EMBuilder Skills Status\n');
|
|
131
|
+
console.log(`Installation path: ${SKILLS_DIR}`);
|
|
132
|
+
console.log(`Installed: ${existsSync(SKILLS_DIR) ? 'ā
Yes' : 'ā No'}`);
|
|
133
|
+
if (existsSync(SKILLS_DIR)) {
|
|
134
|
+
const skillsSource = join(__dirname, '..', 'skills');
|
|
135
|
+
console.log(`Source: ${skillsSource}`);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nebulit/embuilder",
|
|
3
|
+
"version": "0.1.39",
|
|
4
|
+
"description": "Event-model driven development toolkit for Claude Code",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"embuilder": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc && chmod +x dist/cli.js",
|
|
11
|
+
"dev": "tsc --watch",
|
|
12
|
+
"prepublishOnly": "npm run build"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"claude",
|
|
16
|
+
"claude-code",
|
|
17
|
+
"event-model",
|
|
18
|
+
"code-generation",
|
|
19
|
+
"ddd",
|
|
20
|
+
"event-sourcing",
|
|
21
|
+
"event-driven",
|
|
22
|
+
"cqrs",
|
|
23
|
+
"yeoman-generator"
|
|
24
|
+
],
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"templates",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/dilgerma/embuilder.git"
|
|
33
|
+
},
|
|
34
|
+
"author": "Martin Dilger",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"commander": "^12.0.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^20.0.0",
|
|
44
|
+
"typescript": "^5.0.0"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=18.0.0"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# Git Commit Hooks - Quick Start
|
|
2
|
+
|
|
3
|
+
This guide gets you up and running with git commit hooks in 5 minutes.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
If you installed EMBuilder with `--with-templates`, the hooks are already set up!
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx @dilgerma/embuilder install --with-templates
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Prerequisites
|
|
14
|
+
|
|
15
|
+
Install `tsx` to run TypeScript analyzers:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g tsx
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## What You Get
|
|
22
|
+
|
|
23
|
+
When Claude commits code, these analyzers run automatically:
|
|
24
|
+
|
|
25
|
+
### 1. Code Quality Checker
|
|
26
|
+
Warns about:
|
|
27
|
+
- `console.log` statements
|
|
28
|
+
- `debugger` statements
|
|
29
|
+
- TODO/FIXME comments
|
|
30
|
+
- Potential secrets (API keys, passwords)
|
|
31
|
+
|
|
32
|
+
### 2. Event Model Validator
|
|
33
|
+
Validates:
|
|
34
|
+
- Event names use past-tense
|
|
35
|
+
- Tests are updated with logic changes
|
|
36
|
+
- Slice structure follows conventions
|
|
37
|
+
|
|
38
|
+
### 3. Example Logger
|
|
39
|
+
Shows:
|
|
40
|
+
- Branch name
|
|
41
|
+
- Files changed
|
|
42
|
+
- Staged/unstaged status
|
|
43
|
+
|
|
44
|
+
## Try It Out
|
|
45
|
+
|
|
46
|
+
1. **Make a change and commit**
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
echo "console.log('test')" >> test.ts
|
|
50
|
+
git add test.ts
|
|
51
|
+
git commit -m "test commit"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
2. **See the hook in action**
|
|
55
|
+
|
|
56
|
+
You'll see output like:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
š Running git diff analyzers...
|
|
60
|
+
ā Running analyzer: code-quality-checker.ts
|
|
61
|
+
š Code Quality Analysis:
|
|
62
|
+
ā ļø Warnings:
|
|
63
|
+
- Found 1 console.log statement(s) - consider removing debug code
|
|
64
|
+
ā
Analyzers completed
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Customizing
|
|
68
|
+
|
|
69
|
+
### Disable an analyzer
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Rename to disable
|
|
73
|
+
mv .claude/hooks/analyzers/example-logger.ts \
|
|
74
|
+
.claude/hooks/analyzers/example-logger.ts.disabled
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Create your own analyzer
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Create new analyzer
|
|
81
|
+
cat > .claude/hooks/analyzers/my-check.ts << 'EOF'
|
|
82
|
+
#!/usr/bin/env node
|
|
83
|
+
import { readFileSync } from 'fs';
|
|
84
|
+
|
|
85
|
+
interface HookData {
|
|
86
|
+
changed_files: string[];
|
|
87
|
+
staged_diff: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function main() {
|
|
91
|
+
const data: HookData = JSON.parse(readFileSync(0, 'utf-8'));
|
|
92
|
+
|
|
93
|
+
console.log('š My Custom Check:');
|
|
94
|
+
|
|
95
|
+
// Check if package.json changed
|
|
96
|
+
if (data.changed_files.includes('package.json')) {
|
|
97
|
+
console.log(' ā ļø package.json changed - remember to run npm install');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
main();
|
|
102
|
+
EOF
|
|
103
|
+
|
|
104
|
+
# Test it
|
|
105
|
+
echo '{"changed_files":["package.json"],"staged_diff":""}' | \
|
|
106
|
+
tsx .claude/hooks/analyzers/my-check.ts
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Advanced Configuration
|
|
110
|
+
|
|
111
|
+
Edit `.claude/settings.local.json` to customize:
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"hooks": {
|
|
116
|
+
"PreToolUse": [
|
|
117
|
+
{
|
|
118
|
+
"matcher": "Bash(*git commit*)",
|
|
119
|
+
"hooks": [
|
|
120
|
+
{
|
|
121
|
+
"type": "command",
|
|
122
|
+
"command": ".claude/hooks/analyze-commit.sh",
|
|
123
|
+
"statusMessage": "Analyzing changes before commit",
|
|
124
|
+
"timeout": 30
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Common Use Cases
|
|
134
|
+
|
|
135
|
+
### Enforce Commit Message Format
|
|
136
|
+
|
|
137
|
+
Create `.claude/hooks/analyzers/commit-msg-validator.ts`:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { readFileSync } from 'fs';
|
|
141
|
+
import { execSync } from 'child_process';
|
|
142
|
+
|
|
143
|
+
async function main() {
|
|
144
|
+
// Get the last commit message from git
|
|
145
|
+
const msg = execSync('git log -1 --pretty=%B').toString().trim();
|
|
146
|
+
|
|
147
|
+
// Check format: "type: description"
|
|
148
|
+
const pattern = /^(feat|fix|docs|style|refactor|test|chore):\s.{10,}$/;
|
|
149
|
+
|
|
150
|
+
if (!pattern.test(msg)) {
|
|
151
|
+
console.error('ā Invalid commit message format');
|
|
152
|
+
console.error(' Expected: "type: description" (at least 10 chars)');
|
|
153
|
+
console.error(' Types: feat, fix, docs, style, refactor, test, chore');
|
|
154
|
+
process.exit(1); // Block commit
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
console.log('ā
Commit message format valid');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
main();
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Check for Breaking Changes
|
|
164
|
+
|
|
165
|
+
Create `.claude/hooks/analyzers/breaking-changes.ts`:
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
import { readFileSync } from 'fs';
|
|
169
|
+
|
|
170
|
+
interface HookData {
|
|
171
|
+
changed_files: string[];
|
|
172
|
+
staged_diff: string;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function main() {
|
|
176
|
+
const data: HookData = JSON.parse(readFileSync(0, 'utf-8'));
|
|
177
|
+
|
|
178
|
+
// Check if public API files changed
|
|
179
|
+
const apiFiles = data.changed_files.filter(f =>
|
|
180
|
+
f.includes('/api/') ||
|
|
181
|
+
f.includes('public') ||
|
|
182
|
+
f.endsWith('types.ts')
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
if (apiFiles.length > 0) {
|
|
186
|
+
console.log('ā ļø Public API files changed:');
|
|
187
|
+
apiFiles.forEach(f => console.log(` - ${f}`));
|
|
188
|
+
console.log('\nš” Consider:');
|
|
189
|
+
console.log(' - Updating CHANGELOG.md');
|
|
190
|
+
console.log(' - Bumping version number');
|
|
191
|
+
console.log(' - Adding migration guide');
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
main();
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Run Tests Before Commit
|
|
199
|
+
|
|
200
|
+
Create `.claude/hooks/analyzers/run-tests.ts`:
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
import { execSync } from 'child_process';
|
|
204
|
+
|
|
205
|
+
async function main() {
|
|
206
|
+
console.log('š§Ŗ Running tests...');
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
execSync('npm test', { stdio: 'inherit' });
|
|
210
|
+
console.log('ā
All tests passed');
|
|
211
|
+
} catch (error) {
|
|
212
|
+
console.error('ā Tests failed - commit blocked');
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
main();
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Troubleshooting
|
|
221
|
+
|
|
222
|
+
### Hook not running?
|
|
223
|
+
|
|
224
|
+
1. Check configuration in `.claude/settings.local.json`
|
|
225
|
+
2. Verify hook script is executable:
|
|
226
|
+
```bash
|
|
227
|
+
chmod +x .claude/hooks/analyze-commit.sh
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### TypeScript errors?
|
|
231
|
+
|
|
232
|
+
1. Install tsx: `npm install -g tsx`
|
|
233
|
+
2. Check TypeScript syntax in your analyzer
|
|
234
|
+
3. Test manually:
|
|
235
|
+
```bash
|
|
236
|
+
echo '{}' | tsx .claude/hooks/analyzers/your-analyzer.ts
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Analyzer not executing?
|
|
240
|
+
|
|
241
|
+
1. Verify file is in `.claude/hooks/analyzers/`
|
|
242
|
+
2. Check file has `.ts` extension
|
|
243
|
+
3. Look for error messages in hook output
|
|
244
|
+
|
|
245
|
+
## Next Steps
|
|
246
|
+
|
|
247
|
+
- Read full documentation: `.claude/hooks/README.md`
|
|
248
|
+
- Explore built-in analyzers in `.claude/hooks/analyzers/`
|
|
249
|
+
- Share your custom analyzers with the team
|
|
250
|
+
- Configure blocking behavior for critical checks
|
|
251
|
+
|
|
252
|
+
## Help & Support
|
|
253
|
+
|
|
254
|
+
- Full docs: `.claude/hooks/README.md`
|
|
255
|
+
- Report issues: https://github.com/dilgerma/embuilder/issues
|
|
256
|
+
- Examples: See `.claude/hooks/analyzers/` directory
|