domain-driver 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +159 -145
  2. package/dist/cli.js +208 -0
  3. package/dist/commands/action.js +118 -0
  4. package/dist/commands/component.js +18 -19
  5. package/dist/commands/container.js +10 -31
  6. package/dist/commands/controller.js +85 -0
  7. package/dist/commands/feature.js +59 -51
  8. package/dist/commands/hints.js +28 -0
  9. package/dist/commands/hook.js +10 -111
  10. package/dist/commands/repository.js +17 -115
  11. package/dist/commands/resolve.js +61 -0
  12. package/dist/commands/schema.js +22 -69
  13. package/dist/commands/service.js +15 -113
  14. package/dist/commands/sides.js +34 -0
  15. package/dist/commands/target.js +32 -0
  16. package/dist/commands/types.js +9 -17
  17. package/dist/commands/update.js +148 -0
  18. package/dist/commands/write.js +66 -0
  19. package/dist/index.js +8 -122
  20. package/dist/init/content.js +73 -0
  21. package/dist/init/init.js +66 -0
  22. package/dist/init/markers.js +21 -0
  23. package/dist/postinstall.js +80 -0
  24. package/dist/stack/detect.js +125 -0
  25. package/dist/stack/profiles/nest.js +18 -0
  26. package/dist/stack/profiles/next-frontend.js +28 -0
  27. package/dist/stack/profiles/next-fullstack.js +44 -0
  28. package/dist/stack/profiles/node.js +17 -0
  29. package/dist/stack/profiles/react.js +19 -0
  30. package/dist/stack/registry.js +63 -0
  31. package/dist/stack/types.js +24 -0
  32. package/dist/templates/actions.js +68 -0
  33. package/dist/templates/backend/server-repository.js +22 -0
  34. package/dist/templates/context.js +52 -0
  35. package/dist/templates/controllers/express.js +60 -0
  36. package/dist/templates/controllers/fastify.js +54 -0
  37. package/dist/templates/controllers/generic.js +30 -0
  38. package/dist/templates/controllers/hono.js +52 -0
  39. package/dist/templates/controllers/nest.js +63 -0
  40. package/dist/templates/controllers/next-action-route.js +40 -0
  41. package/dist/templates/controllers/next-route.js +62 -0
  42. package/dist/templates/controllers/node.js +46 -0
  43. package/dist/templates/controllers/shape.js +28 -0
  44. package/dist/templates/frontend/client-repository.js +38 -0
  45. package/dist/templates/frontend/component.js +18 -0
  46. package/dist/templates/frontend/container.js +28 -0
  47. package/{src/commands/hook.ts → dist/templates/frontend/hook.js} +28 -41
  48. package/dist/templates/frontend/page.js +26 -0
  49. package/dist/templates/nest/dto.js +12 -0
  50. package/dist/templates/nest/injectable.js +4 -0
  51. package/dist/templates/nest/module.js +41 -0
  52. package/dist/templates/service.js +40 -0
  53. package/dist/templates/shared/schema.js +13 -0
  54. package/dist/templates/shared/types.js +12 -0
  55. package/dist/templates/signatures.js +15 -0
  56. package/dist/update/cache.js +80 -0
  57. package/dist/update/check.js +47 -0
  58. package/dist/update/install-mode.js +96 -0
  59. package/dist/update/package-manager.js +99 -0
  60. package/dist/update/registry.js +77 -0
  61. package/dist/update/version.js +70 -0
  62. package/dist/utils/alias.js +80 -0
  63. package/dist/utils/fs.js +70 -0
  64. package/dist/utils/imports.js +61 -0
  65. package/dist/utils/naming.js +31 -0
  66. package/dist/utils/paths.js +44 -0
  67. package/package.json +27 -6
  68. package/scripts/postinstall.js +7 -0
  69. package/.github/workflows/publish.yml +0 -28
  70. package/dist/utils.js +0 -132
  71. package/src/__tests__/utils.test.ts +0 -128
  72. package/src/commands/__tests__/feature.test.ts +0 -85
  73. package/src/commands/__tests__/imports.test.ts +0 -115
  74. package/src/commands/__tests__/individual.test.ts +0 -137
  75. package/src/commands/component.ts +0 -33
  76. package/src/commands/container.ts +0 -42
  77. package/src/commands/feature.ts +0 -74
  78. package/src/commands/repository.ts +0 -95
  79. package/src/commands/schema.ts +0 -47
  80. package/src/commands/service.ts +0 -93
  81. package/src/commands/types.ts +0 -25
  82. package/src/index.ts +0 -126
  83. package/src/utils.ts +0 -115
  84. package/tsconfig.json +0 -13
  85. package/vitest.config.ts +0 -7
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # domain-driver 🚀
2
2
 
3
- A CLI scaffolding tool for domain-driven development in Next.js. Generate feature folder structures instantly — like Laravel's `php artisan make` but for Next.js.
3
+ A CLI scaffolding tool for domain-driven feature folders. Like Laravel's `php artisan make`, but for Next.js, React, Node, and NestJS projects. It detects your stack and generates only the layers that stack needs, one file per action.
4
4
 
5
5
  ---
6
6
 
@@ -13,249 +13,263 @@ npm install -g domain-driver
13
13
  Or use without installing:
14
14
 
15
15
  ```bash
16
- npx domain-driver make:feature <n>
16
+ npx domain-driver make:feature <feature>[/<Entity>]
17
17
  ```
18
18
 
19
19
  ---
20
20
 
21
- ## Commands
22
-
23
- ### `make:feature`
21
+ ## Stack detection
24
22
 
25
- Scaffold a full feature folder structure.
23
+ Every command reads your `package.json` once and prints the stack it found before writing anything:
26
24
 
27
- ```bash
28
- domain-driver make:feature <n>
29
- domain-driver make:feature <n> -a
30
25
  ```
26
+ Stack: next-fullstack (detected)
27
+ ```
28
+
29
+ | Stack | Detected when | Features live in |
30
+ |---|---|---|
31
+ | `nest` | `@nestjs/core` is a dependency | `src/<feature>` |
32
+ | `next-fullstack` | `next` is a dependency and `app/api`, `src/app/api`, `pages/api`, or `src/pages/api` exists | `app/<feature>` or `src/app/<feature>` |
33
+ | `next-frontend` | `next` is a dependency, no api directory | `app/<feature>` or `src/app/<feature>` |
34
+ | `react` | `react` is a dependency, `next` is not | `src/features/<feature>` or `features/<feature>` |
35
+ | `node` | none of the above | `src/features/<feature>` or `features/<feature>` |
31
36
 
32
- The `-a` flag scaffolds all files inside each folder automatically.
37
+ For `node`, the tool also picks up Express, Fastify, or Hono and shapes the controllers accordingly. With none of them present it generates framework-agnostic controller classes.
38
+
39
+ Override detection with `--stack`:
33
40
 
34
41
  ```bash
35
- domain-driver make:feature coffee-type # folders + .gitkeep only
36
- domain-driver make:feature coffee-type -a # folders + all files
42
+ domain-driver --stack nest make:feature cat -a
37
43
  ```
38
44
 
39
45
  ---
40
46
 
41
- ### `make:component`
42
-
43
- Scaffold a component inside an existing feature. Defaults to `client` if no type is specified.
47
+ ## What each stack generates
44
48
 
45
- ```bash
46
- domain-driver make:component <feature> <n>
47
- domain-driver make:component <feature> <n> client
48
- domain-driver make:component <feature> <n> server
49
- ```
49
+ | Layer | next-fullstack | next-frontend | react | node | nest |
50
+ |---|---|---|---|---|---|
51
+ | `page.tsx` | yes | yes | | | |
52
+ | components | client + server | client + server | flat | | |
53
+ | containers, hooks | yes | yes | yes | | |
54
+ | client services + repositories (fetch) | `client/` | top level | top level | | |
55
+ | server services + repositories (database stubs) | `server/` | | | yes | yes |
56
+ | controllers | `app/api/<feature>/` route handlers | | | five files + routes file | five files |
57
+ | module | | | | | yes |
58
+ | DTOs (`nestjs-zod`) | | | | | yes |
59
+ | schemas (Zod), types | yes | yes | yes | yes | yes |
50
60
 
51
- ```bash
52
- domain-driver make:component coffee-type CoffeeTypeList
53
- domain-driver make:component coffee-type CoffeeTypeForm client
54
- domain-driver make:component coffee-type CoffeeTypeCard server
55
- ```
61
+ Every layer that has actions gets one file per action: `List`, `Show`, `Create`, `Update`, `Delete`. Saving a cat means `CreateCat.controller.ts`, `CreateCat.service.ts`, `CreateCat.repository.ts`, and `CreateCat.schema.ts`.
56
62
 
57
63
  ---
58
64
 
59
- ### `make:container`
65
+ ## Commands
60
66
 
61
- Scaffold a smart container component inside an existing feature.
67
+ Every layer command takes one target, `<feature>/<Name>`: the feature folder on the left, the name used inside the files on the right. `users/User` reads as "User inside users".
62
68
 
63
- ```bash
64
- domain-driver make:container <feature> <n>
65
- ```
69
+ ### `make:feature`
66
70
 
67
71
  ```bash
68
- domain-driver make:container coffee-type CoffeeTypeContainer
72
+ domain-driver make:feature users # folders + .gitkeep, plus page.tsx (Next) or the module (Nest)
73
+ domain-driver make:feature users/User -a # every layer for the detected stack, entity User
69
74
  ```
70
75
 
71
- ---
72
-
73
- ### `make:hook`
76
+ Feature names must be kebab-case. Without `/Entity`, the entity is the PascalCase feature name (`users` becomes `Users`).
74
77
 
75
- Scaffold a custom hook inside an existing feature.
78
+ ### `make:action`
76
79
 
77
80
  ```bash
78
- domain-driver make:hook <feature> <n>
81
+ domain-driver make:action users/User findActiveUsers
82
+ domain-driver make:action users/User archiveUser --with-input --returns one
79
83
  ```
80
84
 
81
- ```bash
82
- domain-driver make:hook coffee-type useCoffeeType
83
- ```
85
+ Scaffolds a bespoke operation as its own files, so it never lands inside `ShowUser` or `ListUser`. The action name is used as-is for file and class names: `FindActiveUsers.service.ts`, `FindActiveUsersService`, handler `findActiveUsersController`, route `/find-active-users`. Include the noun in the name (`archiveUser`, not `archive`).
84
86
 
85
- ---
87
+ | Option | Effect |
88
+ |---|---|
89
+ | `--with-input` | writes `ArchiveUser.schema.ts` (and the Nest DTO), the service takes `data`, the controller is a `POST` with body validation |
90
+ | `--returns list` | `Promise<User[]>` (default) |
91
+ | `--returns one` | `Promise<User>` |
92
+ | `--returns void` | `Promise<void>`, controller responds 204 |
86
93
 
87
- ### `make:service`
94
+ | Stack | Files written |
95
+ |---|---|
96
+ | `node` | service, repository, controller for the detected framework, plus the line to add above the `/:id` routes in `<feature>.routes.ts` printed |
97
+ | `nest` | injectable service and repository, `@Controller` class, DTO with input, plus the classes to register printed, with the controller listed before `Show<Entity>Controller` |
98
+ | `next-fullstack` | server service and repository, client service and repository, `app/api/<feature>/<slug>/route.ts` |
99
+ | `next-frontend`, `react` | client service and repository calling `/api/<feature>/<slug>` |
88
100
 
89
- Scaffold a set of single-responsibility service files inside an existing feature.
101
+ ### `make:controller`
90
102
 
91
103
  ```bash
92
- domain-driver make:service <feature> <n>
104
+ domain-driver make:controller users/User
93
105
  ```
94
106
 
107
+ Node: five controllers plus `<feature>.routes.ts` for Express, Fastify, or Hono. Nest: five single-action controllers. Next.js fullstack: `app/api/<feature>/route.ts` and `app/api/<feature>/[id]/route.ts`. Not available on frontend-only stacks.
108
+
109
+ ### `make:service` and `make:repository`
110
+
95
111
  ```bash
96
- domain-driver make:service coffee-type CoffeeType
112
+ domain-driver make:service users/User [--side client|server|both]
113
+ domain-driver make:repository users/User [--side client|server|both]
97
114
  ```
98
115
 
99
- Generates:
116
+ `--side` matters on `next-fullstack`, where both sides exist. Default is `both`.
100
117
 
101
- ```
102
- app/coffee-type/services/
103
- ├── ListCoffeeType.service.ts
104
- ├── ShowCoffeeType.service.ts
105
- ├── CreateCoffeeType.service.ts
106
- ├── UpdateCoffeeType.service.ts
107
- └── DeleteCoffeeType.service.ts
108
- ```
118
+ ### `make:schema`
109
119
 
110
- ---
120
+ ```bash
121
+ domain-driver make:schema users/User
122
+ ```
111
123
 
112
- ### `make:repository`
124
+ Writes `CreateUser.schema.ts` and `UpdateUser.schema.ts`. On Nest it also writes the matching DTO classes derived with `createZodDto` from `nestjs-zod`.
113
125
 
114
- Scaffold a set of single-responsibility repository files inside an existing feature.
126
+ ### `make:types`, `make:component`, `make:container`, `make:hook`
115
127
 
116
128
  ```bash
117
- domain-driver make:repository <feature> <n>
129
+ domain-driver make:types users/User
130
+ domain-driver make:component users/UserCard [client|server]
131
+ domain-driver make:container users/UserContainer
132
+ domain-driver make:hook users/useUser
118
133
  ```
119
134
 
135
+ Component, container, and hook commands fail with a clear message on backend stacks, and `server` components are rejected on React.
136
+
137
+ ### `init`
138
+
120
139
  ```bash
121
- domain-driver make:repository coffee-type CoffeeType
140
+ domain-driver init
122
141
  ```
123
142
 
124
- Generates:
143
+ Writes agent guidance into the current project so coding agents scaffold with domain-driver instead of hand-writing layers:
125
144
 
126
- ```
127
- app/coffee-type/repositories/
128
- ├── ListCoffeeType.repository.ts
129
- ├── ShowCoffeeType.repository.ts
130
- ├── CreateCoffeeType.repository.ts
131
- ├── UpdateCoffeeType.repository.ts
132
- └── DeleteCoffeeType.repository.ts
133
- ```
145
+ - `AGENTS.md` and `CLAUDE.md` get a section between `<!-- domain-driver:start -->` and `<!-- domain-driver:end -->`. Existing content outside the markers is never touched; the section is created, refreshed in place, or left alone.
146
+ - `.claude/skills/domain-driver/SKILL.md` is a Claude Code skill owned by the tool.
134
147
 
135
- ---
148
+ Running `init` twice reports `unchanged`. Re-run it after upgrading domain-driver.
136
149
 
137
- ### `make:schema`
150
+ **On install.** A local `npm install domain-driver` in a project runs `init` automatically. It does nothing when `CI` is set, for global installs, when there is no `package.json` in the installing project, or when domain-driver installs itself. Files are written to the directory you ran npm install from, which in a workspace is the repository root. Opt out with `npm install --ignore-scripts`, or delete the marked section afterwards.
151
+
152
+ ---
138
153
 
139
- Scaffold Zod schemas for create and update operations inside an existing feature.
154
+ ## Example: `make:feature coffee-type -a` on Node with Express
140
155
 
141
- ```bash
142
- domain-driver make:schema <feature> <n>
143
156
  ```
144
-
145
- ```bash
146
- domain-driver make:schema coffee-type CoffeeType
157
+ src/features/coffee-type/
158
+ ├── coffee-type.routes.ts
159
+ ├── controllers/
160
+ │ ├── ListCoffeeType.controller.ts
161
+ │ ├── ShowCoffeeType.controller.ts
162
+ │ ├── CreateCoffeeType.controller.ts
163
+ │ ├── UpdateCoffeeType.controller.ts
164
+ │ └── DeleteCoffeeType.controller.ts
165
+ ├── services/ (five files)
166
+ ├── repositories/ (five files, database-agnostic stubs)
167
+ ├── schemas/
168
+ │ ├── CreateCoffeeType.schema.ts
169
+ │ └── UpdateCoffeeType.schema.ts
170
+ └── types/
171
+ └── CoffeeType.types.ts
147
172
  ```
148
173
 
149
- Generates:
174
+ Mount the routes with `app.use('/coffee-type', coffeeTypeRoutes)`. Then `make:action coffee-type/CoffeeType findActive` adds `FindActive.controller.ts`, `FindActive.service.ts`, `FindActive.repository.ts`, and prints `router.get('/find-active', findActiveController);` for the routes file.
175
+
176
+ ## Example: `make:feature coffee-type -a` on NestJS
150
177
 
151
178
  ```
152
- app/coffee-type/schemas/
153
- ├── CreateCoffeeType.schema.ts
154
- └── UpdateCoffeeType.schema.ts
179
+ src/coffee-type/
180
+ ├── coffee-type.module.ts registers 5 controllers and 10 providers
181
+ ├── controllers/ five @Controller('coffee-type') classes
182
+ ├── services/ five @Injectable() services
183
+ ├── repositories/ five @Injectable() repositories
184
+ ├── dto/
185
+ │ ├── CreateCoffeeType.dto.ts
186
+ │ └── UpdateCoffeeType.dto.ts
187
+ ├── schemas/
188
+ └── types/
155
189
  ```
156
190
 
191
+ Install `nestjs-zod` and register `ZodValidationPipe` as `APP_PIPE` once in your `AppModule`. The tool prints this hint when the package is missing.
192
+
157
193
  ---
158
194
 
159
- ## What `make:feature -a` generates
195
+ ## Philosophy
160
196
 
161
- Running `domain-driver make:feature coffee-type -a` creates the full structure:
197
+ Everything for a feature lives in one folder, and every file does one thing.
162
198
 
163
- ```
164
- app/
165
- └── coffee-type/
166
- ├── components/
167
- │ ├── server/
168
- │ └── client/
169
- │ └── CoffeeType.tsx
170
- ├── containers/
171
- │ └── CoffeeTypeContainer.tsx
172
- ├── hooks/
173
- │ └── useCoffeeType.ts
174
- ├── services/
175
- │ ├── ListCoffeeType.service.ts
176
- │ ├── ShowCoffeeType.service.ts
177
- │ ├── CreateCoffeeType.service.ts
178
- │ ├── UpdateCoffeeType.service.ts
179
- │ └── DeleteCoffeeType.service.ts
180
- ├── repositories/
181
- │ ├── ListCoffeeType.repository.ts
182
- │ ├── ShowCoffeeType.repository.ts
183
- │ ├── CreateCoffeeType.repository.ts
184
- │ ├── UpdateCoffeeType.repository.ts
185
- │ └── DeleteCoffeeType.repository.ts
186
- ├── schemas/
187
- │ ├── CreateCoffeeType.schema.ts
188
- │ └── UpdateCoffeeType.schema.ts
189
- └── page.tsx
190
- ```
199
+ - **repositories** — data access only. Client-side repositories call your API; server-side repositories call your database.
200
+ - **services** — business logic, one class per action.
201
+ - **controllers** — HTTP in, service call, HTTP out, one file per action.
202
+ - **hooks** — React state and side effects, calls services.
203
+ - **containers** — wire hooks into UI.
204
+ - **components** — presentational UI.
205
+ - **schemas** — Zod validation for create and update; the update body never carries the id, it comes from the path.
206
+ - **types** — the entity interface.
207
+
208
+ Server-side repositories throw a clear not-implemented error until you wire your ORM. Compiling code that fails loudly beats a fake store that looks like it works.
191
209
 
192
210
  ---
193
211
 
194
- ## Philosophy
212
+ ## Updating
195
213
 
196
- This tool follows a strict **domain-driven** folder structure where everything related to a feature lives together. No more hunting across `/components`, `/hooks`, and `/services` top-level folders.
214
+ Every command checks the registry at most once a day and, when a newer release exists, prints one line after its output:
197
215
 
198
- The layer responsibilities are:
216
+ ```
217
+ ℹ️ domain-driver 0.3.0 is available (you have 0.2.0). Run: domain-driver update
218
+ ```
219
+
220
+ ```bash
221
+ domain-driver update # detects how it was installed, runs your package manager, refreshes the guidance
222
+ domain-driver update --dry-run # show the command it would run
223
+ domain-driver update --check # only report whether a newer version exists
224
+ ```
199
225
 
200
- - **repositories** data fetching only, no business logic
201
- - **services** — business logic, calls repositories
202
- - **hooks** React state and side effects, calls services
203
- - **containers** — wire hooks into UI, no direct data fetching
204
- - **components** pure presentational UI, no data dependencies
205
- - **schemas** — Zod validation for create and update operations
226
+ Local installs use the package manager the project uses (npm, pnpm, yarn, or bun, from the `packageManager` field or the lockfile). Global installs use `npm install -g`. Running through `npx` needs no update: `npx domain-driver@latest` always fetches the newest.
227
+
228
+ The check is skipped in CI (any `CI` value other than empty, `0`, or `false`), when output is not a terminal, when `DOMAIN_DRIVER_NO_UPDATE_CHECK` is set (same value rule), or when `NO_UPDATE_NOTIFIER` is set to anything.
229
+
230
+ The cache lives in `~/.cache/domain-driver` (or `$XDG_CACHE_HOME/domain-driver`); `DOMAIN_DRIVER_CACHE_DIR` overrides it.
206
231
 
207
232
  ---
208
233
 
209
- ## Requirements
234
+ ## Upgrading from 0.1.0
210
235
 
211
- - Node.js 18+
236
+ Every layer command now takes a single `<feature>/<Name>` target instead of separate feature and name arguments, for example `make:schema users User` becomes `make:schema users/User`. `make:feature users -a` still works and names the entity `Users`; write `users/User` if you want a different entity name.
212
237
 
213
238
  ---
214
239
 
215
- ## Framework Support
240
+ ## Requirements
216
241
 
217
- This tool is optimised for **Next.js App Router** projects. All files are scaffolded into the `app/` directory following Next.js conventions (`page.tsx`, server/client component separation, etc.).
242
+ - Node.js 18+
218
243
 
219
- If no `app/` directory exists, it will be created automatically. This means the tool can also be used in any project where an `app/<feature>` folder structure makes sense.
244
+ ---
220
245
 
221
246
  ## Local Development
222
247
 
223
248
  ```bash
224
- # Clone the repo
225
249
  git clone https://github.com/IsaacHatilima/domain-driver
226
250
  cd domain-driver
227
-
228
- # Install dependencies
229
251
  npm install
230
-
231
- # Build
232
252
  npm run build
233
-
234
- # Link globally for local testing
235
253
  npm link
236
-
237
- # Test it
238
- domain-driver make:feature test-feature
239
- domain-driver make:feature test-feature -a
254
+ npm test
255
+ npm run test:coverage
240
256
  ```
241
257
 
242
258
  ---
243
259
 
244
260
  ## Roadmap
245
261
 
246
- - [x] `make:feature` scaffold feature folder structure
247
- - [x] `make:feature -a` scaffold feature with all files
248
- - [x] `make:component` scaffold a component
249
- - [x] `make:container` scaffold a container
250
- - [x] `make:hook` scaffold a custom hook
251
- - [x] `make:service`scaffold single-responsibility services
252
- - [x] `make:repository` scaffold single-responsibility repositories
253
- - [x] `make:schema` scaffold Zod schemas
254
- - [ ] Interactive mode — prompt for name if not provided
255
- - [ ] Config file — customize folder structure per project
262
+ - [x] Stack detection for Next.js, React, Node, and NestJS
263
+ - [x] `make:controller` with Express, Fastify, Hono, Nest, and Next route handlers
264
+ - [x] Per-action files in every layer
265
+ - [x] Bespoke actions with make:action
266
+ - [x] Agent guidance with init and a guarded postinstall
267
+ - [ ] Config file override stack and feature root per project
268
+ - [ ] Configurable API base URL for client repositories
269
+ - [ ] ORM-aware server repositories
256
270
 
257
271
  ---
258
272
 
259
273
  ## License
260
274
 
261
- MIT
275
+ MIT
package/dist/cli.js ADDED
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.defaultCliDeps = defaultCliDeps;
37
+ exports.createProgram = createProgram;
38
+ // src/cli.ts
39
+ const commander_1 = require("commander");
40
+ const os = __importStar(require("os"));
41
+ const action_1 = require("./commands/action");
42
+ const component_1 = require("./commands/component");
43
+ const container_1 = require("./commands/container");
44
+ const controller_1 = require("./commands/controller");
45
+ const feature_1 = require("./commands/feature");
46
+ const hints_1 = require("./commands/hints");
47
+ const hook_1 = require("./commands/hook");
48
+ const repository_1 = require("./commands/repository");
49
+ const schema_1 = require("./commands/schema");
50
+ const service_1 = require("./commands/service");
51
+ const sides_1 = require("./commands/sides");
52
+ const target_1 = require("./commands/target");
53
+ const types_1 = require("./commands/types");
54
+ const update_1 = require("./commands/update");
55
+ const init_1 = require("./init/init");
56
+ const detect_1 = require("./stack/detect");
57
+ const types_2 = require("./stack/types");
58
+ const actions_1 = require("./templates/actions");
59
+ const check_1 = require("./update/check");
60
+ const registry_1 = require("./update/registry");
61
+ const version_1 = require("./update/version");
62
+ const SKIP_DETECTION = new Set(['init', 'update']);
63
+ function defaultCliDeps() {
64
+ return {
65
+ env: process.env,
66
+ isTTY: process.stdout.isTTY === true,
67
+ homedir: os.homedir(),
68
+ now: Date.now,
69
+ fetchImpl: registry_1.nodeFetch,
70
+ current: (0, version_1.currentVersion)(),
71
+ updateDeps: update_1.defaultUpdateDeps,
72
+ log: (line) => console.log(line),
73
+ };
74
+ }
75
+ function createProgram(deps) {
76
+ const program = new commander_1.Command();
77
+ program
78
+ .name('domain-driver')
79
+ .description('CLI scaffolding tool for domain-driven feature folders in Next.js, React, Node, and NestJS projects')
80
+ .version(deps.current)
81
+ .option('--stack <name>', `Override stack detection (${types_2.STACK_NAMES.join(', ')})`);
82
+ let pendingNotice = Promise.resolve(null);
83
+ program.hook('preAction', (_thisCommand, actionCommand) => {
84
+ const name = actionCommand.name();
85
+ if ((0, check_1.shouldCheck)(deps.env, deps.isTTY, name)) {
86
+ pendingNotice = (0, check_1.checkForUpdate)({
87
+ env: deps.env,
88
+ homedir: deps.homedir,
89
+ now: deps.now,
90
+ fetchImpl: deps.fetchImpl,
91
+ current: deps.current,
92
+ });
93
+ }
94
+ if (SKIP_DETECTION.has(name))
95
+ return;
96
+ const { stack } = program.opts();
97
+ deps.log((0, detect_1.describeStack)((0, detect_1.detectStack)(stack)));
98
+ });
99
+ program.hook('postAction', async () => {
100
+ const notice = await pendingNotice;
101
+ if (notice !== null)
102
+ deps.log(notice);
103
+ });
104
+ program
105
+ .command('make:feature <target>')
106
+ .description('Scaffold a feature folder for the detected stack (<feature> or <feature>/<Entity>)')
107
+ .option('-a, --all', 'Scaffold all files inside each folder')
108
+ .action(async (target, options) => {
109
+ const { feature, entity } = (0, target_1.parseFeatureTarget)(target);
110
+ await (0, feature_1.makeFeature)(feature, options.all ?? false, entity ?? undefined);
111
+ });
112
+ program
113
+ .command('make:component <target>')
114
+ .description('Scaffold a component inside an existing feature (<feature>/<Name>)')
115
+ .argument('[type]', 'Component type: client or server', 'client')
116
+ .action((target, type) => {
117
+ const { feature, name } = (0, target_1.parseTarget)(target);
118
+ (0, component_1.makeComponent)(feature, name, (0, component_1.parseComponentType)(type));
119
+ });
120
+ program
121
+ .command('make:container <target>')
122
+ .description('Scaffold a smart container component inside an existing feature (<feature>/<Name>)')
123
+ .action((target) => {
124
+ const { feature, name } = (0, target_1.parseTarget)(target);
125
+ (0, container_1.makeContainer)(feature, name);
126
+ });
127
+ program
128
+ .command('make:hook <target>')
129
+ .description('Scaffold a custom hook inside an existing feature (<feature>/<useName>)')
130
+ .action((target) => {
131
+ const { feature, name } = (0, target_1.parseTarget)(target);
132
+ (0, hook_1.makeHook)(feature, name);
133
+ });
134
+ program
135
+ .command('make:service <target>')
136
+ .description('Scaffold single-responsibility service files inside an existing feature (<feature>/<Entity>)')
137
+ .option('--side <side>', 'client, server, or both', 'both')
138
+ .action((target, options) => {
139
+ const { feature, name } = (0, target_1.parseTarget)(target);
140
+ const wrote = (0, service_1.makeService)(feature, name, (0, sides_1.parseSide)(options.side));
141
+ if (wrote)
142
+ (0, hints_1.hintRegisterInModule)(feature, (0, hints_1.standardClassNames)(name, 'Service'));
143
+ });
144
+ program
145
+ .command('make:repository <target>')
146
+ .description('Scaffold single-responsibility repository files inside an existing feature (<feature>/<Entity>)')
147
+ .option('--side <side>', 'client, server, or both', 'both')
148
+ .action((target, options) => {
149
+ const { feature, name } = (0, target_1.parseTarget)(target);
150
+ const wrote = (0, repository_1.makeRepository)(feature, name, (0, sides_1.parseSide)(options.side));
151
+ if (wrote)
152
+ (0, hints_1.hintRegisterInModule)(feature, (0, hints_1.standardClassNames)(name, 'Repository'));
153
+ });
154
+ program
155
+ .command('make:controller <target>')
156
+ .description('Scaffold single-responsibility controllers or route handlers inside an existing feature (<feature>/<Entity>)')
157
+ .action((target) => {
158
+ const { feature, name } = (0, target_1.parseTarget)(target);
159
+ const wrote = (0, controller_1.makeController)(feature, name);
160
+ if (wrote)
161
+ (0, hints_1.hintRegisterInModule)(feature, (0, hints_1.standardClassNames)(name, 'Controller'));
162
+ });
163
+ program
164
+ .command('make:action <target> <action>')
165
+ .description('Scaffold a bespoke action as its own service, repository, and controller (<feature>/<Entity> <actionName>)')
166
+ .option('--with-input', 'The action takes a request body validated by a Zod schema', false)
167
+ .option('--returns <kind>', 'list, one, or void', 'list')
168
+ .action((target, action, options) => {
169
+ const { feature, name } = (0, target_1.parseTarget)(target);
170
+ const returns = (0, action_1.parseReturns)(options.returns);
171
+ const wrote = (0, action_1.makeAction)(feature, name, action, { withInput: options.withInput, returns });
172
+ if (wrote) {
173
+ const { pascal } = (0, actions_1.actionCase)(action);
174
+ (0, hints_1.hintRegisterInModule)(feature, [`${pascal}Controller`, `${pascal}Service`, `${pascal}Repository`], `list ${pascal}Controller before Show${name}Controller in controllers`);
175
+ }
176
+ });
177
+ program
178
+ .command('make:schema <target>')
179
+ .description('Scaffold Zod schemas (and Nest DTOs) for create and update operations (<feature>/<Entity>)')
180
+ .action((target) => {
181
+ const { feature, name } = (0, target_1.parseTarget)(target);
182
+ (0, schema_1.makeSchema)(feature, name);
183
+ });
184
+ program
185
+ .command('make:types <target>')
186
+ .description('Scaffold a types file inside an existing feature (<feature>/<Entity>)')
187
+ .action((target) => {
188
+ const { feature, name } = (0, target_1.parseTarget)(target);
189
+ (0, types_1.makeTypes)(feature, name);
190
+ });
191
+ program
192
+ .command('init')
193
+ .description('Write agent guidance into this project: AGENTS.md, CLAUDE.md, and .claude/skills/domain-driver/SKILL.md')
194
+ .action(() => {
195
+ for (const result of (0, init_1.runInit)(process.cwd())) {
196
+ console.log(`${init_1.INIT_ICONS[result.status]} ${result.file} ${result.status}`);
197
+ }
198
+ });
199
+ program
200
+ .command('update')
201
+ .description('Update domain-driver with your package manager, then refresh the agent guidance')
202
+ .option('--dry-run', 'Print the command without running it', false)
203
+ .option('--check', 'Only report whether a newer version exists', false)
204
+ .action(async (options) => {
205
+ await (0, update_1.runUpdate)(options, deps.updateDeps());
206
+ });
207
+ return program;
208
+ }