create-sdd-project 0.2.1 → 0.2.4

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 CHANGED
@@ -1,18 +1,67 @@
1
1
  # SDD DevFlow
2
2
 
3
- **Spec-Driven Development workflow template for AI-assisted coding.**
3
+ [![npm version](https://img.shields.io/npm/v/create-sdd-project)](https://www.npmjs.com/package/create-sdd-project)
4
+ [![license](https://img.shields.io/npm/l/create-sdd-project)](LICENSE)
5
+ [![node](https://img.shields.io/node/v/create-sdd-project)](package.json)
4
6
 
5
- A development methodology designed for Claude Code and Gemini that combines specialized AI agents, workflow orchestration with human checkpoints, and institutional memory. Built for creating robust, maintainable, and scalable TypeScript projects.
7
+ **Spec-Driven Development workflow for AI-assisted coding.**
8
+
9
+ A complete development methodology for Claude Code and Gemini that combines specialized AI agents, workflow orchestration with human checkpoints, and institutional memory. Works with new and existing TypeScript/JavaScript projects.
10
+
11
+ ## Quick Start
12
+
13
+ ### New Project
14
+
15
+ ```bash
16
+ npx create-sdd-project my-app
17
+ ```
18
+
19
+ The interactive wizard asks about your stack, AI tools, and autonomy level. For defaults (fullstack Express+Next.js):
20
+
21
+ ```bash
22
+ npx create-sdd-project my-app --yes
23
+ ```
24
+
25
+ ### Existing Project
26
+
27
+ ```bash
28
+ cd your-existing-project
29
+ npx create-sdd-project --init
30
+ ```
31
+
32
+ Scans your project, detects your stack and architecture, and installs SDD files adapted to your project. Never modifies existing code or overwrites existing files.
33
+
34
+ ### After Setup
35
+
36
+ Open in your AI coding tool and run:
37
+
38
+ ```
39
+ init sprint 0
40
+ start task B0.1
41
+ ```
42
+
43
+ The workflow skill guides you through each step with checkpoints based on your autonomy level.
44
+
45
+ ---
6
46
 
7
47
  ## What is SDD?
8
48
 
9
49
  SDD DevFlow combines three proven practices:
10
50
 
11
51
  1. **Spec-Driven Development** — Write specifications before code. Specs are the contract between planning and implementation.
12
- 2. **Test-Driven Development** — Red-Green-Refactor cycle for every feature. Tests define expected behavior before implementation.
13
- 3. **Human-in-the-Loop** — Strategic checkpoints (spec, ticket, plan, commit, merge) with configurable autonomy levels that reduce human intervention as trust increases.
52
+ 2. **Test-Driven Development** — Red-Green-Refactor cycle for every feature.
53
+ 3. **Human-in-the-Loop** — Strategic checkpoints with configurable autonomy levels that reduce human intervention as trust increases.
54
+
55
+ ### Why use SDD DevFlow?
56
+
57
+ - **AI agents work better with structure.** Without guardrails, AI coding assistants produce inconsistent results. SDD provides the methodology, standards, and workflow that make AI output predictable and high-quality.
58
+ - **Institutional memory across sessions.** Sprint trackers, bug logs, and decision records survive context compaction and session boundaries.
59
+ - **Scales from solo to team.** Start at L1 (full control) while learning, scale to L4 (full auto) for repetitive tasks.
60
+ - **Works with your stack.** Not opinionated about frameworks — detects and adapts to Express, Fastify, NestJS, Next.js, Nuxt, Vue, Angular, and many more.
61
+
62
+ ---
14
63
 
15
- ## What's Inside
64
+ ## What's Included
16
65
 
17
66
  ### 9 Specialized Agents
18
67
 
@@ -26,35 +75,33 @@ SDD DevFlow combines three proven practices:
26
75
  | `qa-engineer` | Edge cases, spec verification | 5 |
27
76
  | `database-architect` | Schema design, optimization | Any |
28
77
 
78
+ ### 3 Skills (Slash Commands)
79
+
80
+ | Skill | Trigger | What it does |
81
+ |-------|---------|-------------|
82
+ | `development-workflow` | `start task B0.1`, `next task`, `init sprint N` | Orchestrates the complete 7-step workflow |
83
+ | `bug-workflow` | `report bug`, `fix bug`, `hotfix needed` | Bug triage, investigation, and resolution |
84
+ | `project-memory` | `set up project memory`, `log a bug fix` | Maintains institutional knowledge |
85
+
29
86
  ### Workflow (Steps 0–6)
30
87
 
31
88
  ```
32
- 0. SPEC → spec-creator drafts specs → Spec Approval (Std/Cplx)
33
- 1. SETUP → Branch, ticket, sprint tracker → Ticket Approval (Std/Cplx)
34
- 2. PLAN → Planner creates implementation plan → Plan Approval (Std/Cplx)
89
+ 0. SPEC → spec-creator drafts specs → Spec Approval
90
+ 1. SETUP → Branch, ticket, sprint tracker → Ticket Approval
91
+ 2. PLAN → Planner creates implementation plan → Plan Approval
35
92
  3. IMPLEMENT → Developer agent, TDD
36
93
  4. FINALIZE → Tests/lint/build, validator → Commit Approval
37
94
  5. REVIEW → PR, code review, QA → Merge Approval
38
95
  6. COMPLETE → Clean up, update tracker
39
96
  ```
40
97
 
41
- **Step flow by complexity:**
42
- - **Simple**: 1 → 3 → 4 → 5 → 6
43
- - **Standard**: 0 → 1 → 2 → 3 → 4 → 5 (+QA) → 6
44
- - **Complex**: 0 → 1 (+ADR) → 2 → 3 → 4 → 5 (+QA) → 6
45
-
46
- ### 3 Complexity Tiers
47
-
48
- | Tier | Spec | Ticket | Plan | QA |
49
- |------|:----:|:------:|:----:|:--:|
50
- | Simple | Skip | Skip | Skip | Skip |
51
- | Standard | Yes | Yes | Yes | Yes |
52
- | Complex | Yes | Yes + ADR | Yes | Yes |
98
+ **By complexity:**
99
+ - **Simple** (bug fixes, small tweaks): 1 → 3 → 4 → 5 → 6
100
+ - **Standard** (features): 0 → 1 → 2 → 3 → 4 → 5 (+QA) → 6
101
+ - **Complex** (architectural changes): 0 → 1 (+ADR) → 2 → 3 → 4 → 5 (+QA) → 6
53
102
 
54
103
  ### 4 Autonomy Levels
55
104
 
56
- Control how many human approval checkpoints are active:
57
-
58
105
  | Level | Name | Human Checkpoints | Best For |
59
106
  |-------|------|-------------------|----------|
60
107
  | L1 | Full Control | All 5 | First sprint, learning SDD |
@@ -64,13 +111,6 @@ Control how many human approval checkpoints are active:
64
111
 
65
112
  Quality gates (tests, lint, build, validators) **always run** regardless of level.
66
113
 
67
- ### Branching Strategy
68
-
69
- Configurable per-project in `key_facts.md`:
70
-
71
- - **GitHub Flow** (default): `main` + `feature/*` + `hotfix/*`. Best for MVPs.
72
- - **GitFlow** (scaled): `main` + `develop` + `feature/*` + `release/*` + `hotfix/*`. For larger projects.
73
-
74
114
  ### Project Memory
75
115
 
76
116
  Tracks institutional knowledge across sessions in `docs/project_notes/`:
@@ -82,70 +122,39 @@ Tracks institutional knowledge across sessions in `docs/project_notes/`:
82
122
 
83
123
  ### Automated Hooks (Claude Code)
84
124
 
85
- - **Quick Scan** — After developer agents finish, a fast grep-based scan (~2s, no API calls) checks for debug code, secrets, and TODOs. Critical issues block; warnings pass through.
86
- - **Compaction Recovery** — After context compaction, injects a reminder to read the sprint tracker for context recovery.
87
- - **Notifications** — Personal notification hooks (macOS/Linux) in `.claude/settings.local.json`.
125
+ - **Quick Scan** — After developer agents finish, a fast grep-based scan (~2s, no API calls) checks for debug code, secrets, and TODOs
126
+ - **Compaction Recovery** — After context compaction, injects a reminder to read the sprint tracker for context recovery
88
127
 
89
128
  ### Multi-Tool Support
90
129
 
91
- - **Claude Code**: Full support with agents, skills, hooks, and settings (`.claude/`)
92
- - **Gemini**: Adapted agent format (`.gemini/`), same methodology via `ai-specs/specs/`
93
- - **Other tools**: `AGENTS.md` provides universal instructions readable by 21+ AI coding tools
130
+ | Tool | Support Level |
131
+ |------|--------------|
132
+ | **Claude Code** | Full agents, skills, hooks, settings (`.claude/`) |
133
+ | **Gemini** | Full — agents, skills, commands, settings (`.gemini/`) |
134
+ | **Other AI tools** | `AGENTS.md` provides universal instructions (Cursor, Copilot, Windsurf, etc.) |
94
135
 
95
- ## Quick Start
136
+ ---
96
137
 
97
- ### Option A: New Project (recommended)
138
+ ## `--init` Stack Detection
98
139
 
99
- ```bash
100
- npx create-sdd-project my-app
101
- ```
102
-
103
- The interactive wizard guides you through:
140
+ When running `--init` on an existing project, the scanner automatically detects:
104
141
 
105
- 1. **Project basics** name, description, business context
106
- 2. **Tech stack** — backend (Express+Prisma+PG, Express+MongoDB, or custom), frontend (Next.js+Tailwind or custom), or both
107
- 3. **Configuration** AI tools (Claude/Gemini/both), autonomy level (L1-L4), branching strategy
108
-
109
- Non-interactive mode with defaults:
110
- ```bash
111
- npx create-sdd-project my-app --yes
112
- ```
113
-
114
- ### Option B: Existing Project
115
-
116
- Add SDD DevFlow to a project that already has code:
117
-
118
- ```bash
119
- cd your-existing-project
120
- npx create-sdd-project --init
121
- ```
122
-
123
- The `--init` flag:
124
- - **Scans** your project: detects stack (Express, Next.js, Prisma, etc.), architecture (MVC, DDD, feature-based), tests, and existing docs
125
- - **Adapts** standards files to match your real architecture (not generic DDD defaults)
126
- - **Imports** existing OpenAPI/Swagger specs and references Prisma schemas
127
- - **Audits** test coverage and suggests retrofit testing tasks if coverage is low
128
- - **Never** modifies your existing code or overwrites existing files
129
-
130
- ### After setup
131
-
132
- ```
133
- # Open in your AI coding tool and run:
134
- init sprint 0
135
- start task B0.1
136
- ```
142
+ | Category | Detected |
143
+ |----------|----------|
144
+ | **Backend frameworks** | Express, Fastify, Koa, NestJS, Hapi, AdonisJS |
145
+ | **ORMs** | Prisma, Mongoose, TypeORM, Sequelize, Drizzle, Knex, MikroORM, Objection.js |
146
+ | **Databases** | PostgreSQL, MySQL, SQLite, MongoDB, SQL Server, CockroachDB (from Prisma schema, `.env`, or dependencies) |
147
+ | **Frontend frameworks** | Next.js, Nuxt, Remix, Astro, SolidJS, React, Vue, Angular, Svelte |
148
+ | **Styling** | Tailwind CSS, styled-components, Emotion, Sass |
149
+ | **Component libraries** | Radix UI, Headless UI, Material UI, Chakra UI, Ant Design |
150
+ | **State management** | Zustand, Redux, Jotai, TanStack Query, Recoil, Pinia, MobX |
151
+ | **Testing** | Jest, Vitest, Mocha (unit) + Playwright, Cypress (e2e) |
152
+ | **Architecture** | MVC, DDD, feature-based, handler-based, flat |
153
+ | **Project type** | Monorepo (workspaces, Lerna, Turbo, pnpm) or single-package |
137
154
 
138
- The workflow skill will guide you through each step with checkpoints based on your autonomy level.
155
+ Standards files are adapted to match your actual architecture not generic defaults.
139
156
 
140
- ### Manual Setup (alternative)
141
-
142
- If you prefer manual configuration, copy the template directly:
143
-
144
- ```bash
145
- cp -r template/ /path/to/your-project/
146
- ```
147
-
148
- Then look for `<!-- CONFIG: ... -->` comments in the files to customize.
157
+ ---
149
158
 
150
159
  ## Template Structure
151
160
 
@@ -155,7 +164,6 @@ project/
155
164
  ├── CLAUDE.md # Claude Code config (autonomy, recovery)
156
165
  ├── GEMINI.md # Gemini config (autonomy)
157
166
  ├── .env.example # Environment variables template
158
- ├── .gitignore # Git ignore with secrets protection
159
167
 
160
168
  ├── .claude/
161
169
  │ ├── agents/ # 9 specialized agents
@@ -165,45 +173,37 @@ project/
165
173
  │ │ ├── bug-workflow/ # Bug triage and resolution
166
174
  │ │ └── project-memory/ # Memory system setup
167
175
  │ ├── hooks/quick-scan.sh # Post-developer quality scan
168
- ├── settings.json # Shared hooks (git-tracked)
169
- │ └── settings.local.json # Personal hooks (gitignored)
176
+ └── settings.json # Shared hooks (git-tracked)
170
177
 
171
178
  ├── .gemini/
172
179
  │ ├── agents/ # 9 agents (Gemini format)
173
- │ ├── skills/
174
- │ │ ├── development-workflow/ # Main task workflow (Steps 0-6)
175
- │ │ │ └── references/ # Templates, guides, examples
176
- │ │ ├── bug-workflow/ # Bug triage and resolution
177
- │ │ └── project-memory/ # Memory system setup
180
+ │ ├── skills/ # Same 3 skills
178
181
  │ ├── commands/ # Slash command shortcuts
179
- ├── settings.json # Gemini configuration
180
- │ └── styles/default.md # Response style
182
+ └── settings.json # Gemini configuration
181
183
 
182
184
  ├── ai-specs/specs/
183
185
  │ ├── base-standards.mdc # Constitution + methodology
184
- │ ├── backend-standards.mdc # Backend patterns (DDD, Express, Prisma)
185
- │ ├── frontend-standards.mdc # Frontend patterns (Next.js, Tailwind, Radix)
186
- │ └── documentation-standards.mdc # Documentation update rules
186
+ │ ├── backend-standards.mdc # Backend patterns
187
+ │ ├── frontend-standards.mdc # Frontend patterns
188
+ │ └── documentation-standards.mdc # Documentation rules
187
189
 
188
190
  └── docs/
189
191
  ├── project_notes/ # Project memory
190
- │ ├── sprint-0-tracker.md # Sprint tracker template
191
- │ ├── key_facts.md # Project configuration
192
- │ ├── bugs.md # Bug log
193
- │ └── decisions.md # ADRs
194
- ├── specs/
195
- │ ├── api-spec.yaml # OpenAPI spec (backend)
196
- │ └── ui-components.md # Component spec (frontend)
197
- └── tickets/ # Task tickets (generated by workflow)
192
+ │ ├── sprint-0-tracker.md
193
+ │ ├── key_facts.md
194
+ │ ├── bugs.md
195
+ │ └── decisions.md
196
+ ├── specs/ # API and UI specs
197
+ └── tickets/ # Task tickets (workflow-generated)
198
198
  ```
199
199
 
200
200
  ## Default Tech Stack
201
201
 
202
- The template defaults to (configurable via `<!-- CONFIG -->` comments):
202
+ Configurable via the wizard or `<!-- CONFIG -->` comments in template files:
203
203
 
204
204
  - **Backend**: Node.js + Express + Prisma + PostgreSQL
205
205
  - **Frontend**: Next.js (App Router) + Tailwind CSS + Radix UI + Zustand
206
- - **Shared Types**: Zod schemas in `shared/` workspace → `z.infer<>` for TypeScript types
206
+ - **Shared Types**: Zod schemas with `z.infer<>` for TypeScript types
207
207
  - **Testing**: Jest (unit) + Playwright (e2e)
208
208
  - **Methodology**: TDD + DDD + Spec-Driven Development
209
209
 
@@ -224,6 +224,16 @@ These 6 principles apply to ALL tasks, ALL agents, ALL complexity levels:
224
224
  - Node.js 18+
225
225
  - `jq` (for quick-scan hook): `brew install jq` (macOS) or `apt install jq` (Linux)
226
226
 
227
+ ## Manual Setup (Alternative)
228
+
229
+ If you prefer manual configuration over the CLI wizard:
230
+
231
+ ```bash
232
+ cp -r template/ /path/to/your-project/
233
+ ```
234
+
235
+ Then look for `<!-- CONFIG: ... -->` comments in the files to customize.
236
+
227
237
  ## Roadmap
228
238
 
229
239
  - **Agent Teams**: Parallel execution of independent tasks (waiting for Claude Code Agent Teams to stabilize)
package/lib/config.js CHANGED
@@ -79,7 +79,7 @@ const AI_TOOLS = [
79
79
 
80
80
  const AUTONOMY_LEVELS = [
81
81
  { level: 1, name: 'Full Control', desc: 'Human approves every checkpoint (first sprint, learning SDD)' },
82
- { level: 2, name: 'Trusted', desc: 'Human reviews plans + merges only (default, normal development)', default: true },
82
+ { level: 2, name: 'Trusted', desc: 'Human reviews plans + merges only (normal development)', default: true },
83
83
  { level: 3, name: 'Autopilot', desc: 'Human only approves merges (well-defined, repetitive tasks)' },
84
84
  { level: 4, name: 'Full Auto', desc: 'No human checkpoints, CI/CD gates only (bulk simple tasks)' },
85
85
  ];
@@ -305,16 +305,16 @@ function adaptBackendStandards(template, scan) {
305
305
  '<!-- TODO: Review and adjust the sections below to match your project\'s conventions. -->\n<!-- This file was generated from project analysis by create-sdd-project --init. -->'
306
306
  );
307
307
 
308
- // Update globs in frontmatter
308
+ // Update globs in frontmatter — only include tsx/jsx if frontend detected
309
309
  const srcRoot = findSrcRootName(scan);
310
- const globPattern = srcRoot ? `${srcRoot}/**/*.{ts,js,tsx,jsx}` : '**/*.{ts,js,tsx,jsx}';
310
+ const exts = scan.frontend.detected ? 'ts,js,tsx,jsx' : 'ts,js';
311
+ const globPattern = srcRoot ? `${srcRoot}/**/*.{${exts}}` : `**/*.{${exts}}`;
311
312
  content = content.replace(
312
313
  /globs: \[.*?\]/,
313
314
  `globs: ["${globPattern}"]`
314
315
  );
315
316
 
316
317
  // Update Technology Stack
317
- const framework = scan.backend.framework || 'Unknown';
318
318
  const orm = scan.backend.orm;
319
319
  const db = scan.backend.db;
320
320
  const lang = scan.language === 'typescript' ? 'TypeScript' : 'JavaScript';
@@ -325,8 +325,10 @@ function adaptBackendStandards(template, scan) {
325
325
 
326
326
  let stackLines = [
327
327
  `- **Runtime**: Node.js with ${lang}`,
328
- `- **Framework**: ${framework}`,
329
328
  ];
329
+ if (scan.backend.framework) {
330
+ stackLines.push(`- **Framework**: ${scan.backend.framework}`);
331
+ }
330
332
  if (orm) {
331
333
  stackLines.push(`- **ORM**: ${orm}${db ? ` (${db})` : ''}`);
332
334
  } else if (db) {
@@ -352,21 +354,38 @@ function adaptBackendStandards(template, scan) {
352
354
  const patternLabel = patternLabels[scan.srcStructure.pattern] || 'Custom';
353
355
 
354
356
  const archStructure = buildArchitectureTree(scan);
357
+ // Robust: match any "## Architecture — <anything>" heading up to "## Naming"
355
358
  content = content.replace(
356
- /## Architecture — DDD Layered\n\n```\n[\s\S]*?```\n\n### Layer Rules\n\n[\s\S]*?(?=\n## Naming)/,
359
+ /## Architecture — [^\n]+\n\n```\n[\s\S]*?```\n\n(?:### Layer Rules\n\n[\s\S]*?)?(?=\n## Naming)/,
357
360
  `## Architecture — ${patternLabel}\n\n\`\`\`\n${archStructure}\`\`\`\n\n<!-- TODO: Add layer rules that match your project's architecture. -->\n\n`
358
361
  );
359
362
 
360
363
  // Update Database Patterns section if not Prisma
364
+ // Robust: match from "## Database Patterns" to next "## " heading
361
365
  if (!scan.backend.orm) {
362
366
  content = content.replace(
363
- /## Database Patterns\n\n### Prisma Best Practices[\s\S]*?### Repository Pattern[\s\S]*?```\n/,
364
- `## Database Patterns\n\n<!-- TODO: Add database access patterns for your project. -->\n\n`
367
+ /## Database Patterns\n\n[\s\S]*?(?=\n## )/,
368
+ `## Database Patterns\n\n<!-- TODO: Add database access patterns for your project. -->\n`
365
369
  );
366
370
  } else if (scan.backend.orm !== 'Prisma') {
367
371
  content = content.replace(
368
- /## Database Patterns\n\n### Prisma Best Practices[\s\S]*?### Repository Pattern[\s\S]*?```\n/,
369
- `## Database Patterns\n\n<!-- TODO: Add ${scan.backend.orm} best practices and patterns for your project. -->\n\n`
372
+ /## Database Patterns\n\n[\s\S]*?(?=\n## )/,
373
+ `## Database Patterns\n\n<!-- TODO: Add ${scan.backend.orm} best practices and patterns for your project. -->\n`
374
+ );
375
+ }
376
+
377
+ // Adapt Validation section based on detected validation library
378
+ if (scan.backend.validation && scan.backend.validation !== 'Zod') {
379
+ // Has a validator, but not Zod — replace with detected library name
380
+ content = content.replace(
381
+ /## Validation\n\n[\s\S]*?(?=\n## Database Patterns)/,
382
+ `## Validation\n\n- Validate all inputs at the application layer using ${scan.backend.validation}\n- Validate before executing business logic\n- Return descriptive validation errors\n\n<!-- TODO: Add ${scan.backend.validation} validation patterns for your project. -->\n\n`
383
+ );
384
+ } else if (!scan.backend.validation) {
385
+ // No validation library detected — generic guidance
386
+ content = content.replace(
387
+ /## Validation\n\n[\s\S]*?(?=\n## Database Patterns)/,
388
+ `## Validation\n\n- Validate all inputs at the application layer\n- Validate before executing business logic\n- Return descriptive validation errors\n\n<!-- TODO: Add validation patterns for your project (e.g., Zod, Joi, class-validator). -->\n\n`
370
389
  );
371
390
  }
372
391
 
@@ -444,7 +463,7 @@ function buildArchitectureTree(scan) {
444
463
  }
445
464
 
446
465
  function capitalizeFramework(name) {
447
- const map = { jest: 'Jest', vitest: 'Vitest', mocha: 'Mocha' };
466
+ const map = { jest: 'Jest', vitest: 'Vitest', mocha: 'Mocha', playwright: 'Playwright', cypress: 'Cypress' };
448
467
  return map[name] || name;
449
468
  }
450
469
 
@@ -467,15 +486,17 @@ function adaptAgentsMd(template, config, scan) {
467
486
  const tree = rootDirs.map((d) => `├── ${d.replace(/\/$/, '/')} `).join('\n');
468
487
  const treeBlock = `\`\`\`\nproject/\n${tree}\n└── docs/ ← Documentation\n\`\`\``;
469
488
 
489
+ // Robust: flexible whitespace between CONFIG comment and code block
470
490
  content = content.replace(
471
- /<!-- CONFIG: Adjust directories.*?-->\n\n```\nproject\/\n[\s\S]*?```/,
491
+ /<!-- CONFIG: Adjust directories[^>]*-->\n+```\nproject\/\n[\s\S]*?```/,
472
492
  treeBlock
473
493
  );
474
494
 
475
495
  // If not monorepo, simplify the install instructions
496
+ // Robust: match any number of table rows (not hardcoded count)
476
497
  if (!scan.isMonorepo) {
477
498
  content = content.replace(
478
- /\*\*Critical\*\*: NEVER install dependencies in the root directory\.\n\n\| Action.*\n\|.*\n\|.*\n\|.*\n\|.*\n/,
499
+ /\*\*Critical\*\*: NEVER install dependencies in the root directory\.\n\n(\|.*\n)+/,
479
500
  ''
480
501
  );
481
502
  }
@@ -494,6 +515,12 @@ function adaptAgentsMd(template, config, scan) {
494
515
  'Frontend patterns (Next.js, Tailwind, Radix)',
495
516
  `Frontend patterns (${parts.join(', ')})`
496
517
  );
518
+ } else {
519
+ // Remove frontend-standards reference for backend-only projects
520
+ content = content.replace(
521
+ /- \[Frontend Standards\].*\n/,
522
+ ''
523
+ );
497
524
  }
498
525
 
499
526
  return content;
@@ -528,9 +555,11 @@ function configureKeyFacts(template, config, scan) {
528
555
 
529
556
  // Technology Stack from scan
530
557
  if (scan.backend.detected) {
531
- const fw = scan.backend.framework || 'Unknown';
532
558
  const runtime = scan.language === 'typescript' ? 'Node.js (TypeScript)' : 'Node.js';
533
- content = content.replace('[Framework, runtime, version]', `${fw}, ${runtime}`);
559
+ const backendLabel = scan.backend.framework
560
+ ? `${scan.backend.framework}, ${runtime}`
561
+ : runtime;
562
+ content = content.replace('[Framework, runtime, version]', backendLabel);
534
563
 
535
564
  if (scan.backend.db) {
536
565
  content = content.replace('[Type, host, port]', scan.backend.db);
@@ -33,6 +33,7 @@ function formatScanSummary(scanResult) {
33
33
  const patternLabels = {
34
34
  mvc: 'MVC',
35
35
  ddd: 'DDD (Domain-Driven Design)',
36
+ layered: 'Layered (controllers + handlers + managers)',
36
37
  'feature-based': 'Feature-based',
37
38
  'handler-based': 'Handler-based',
38
39
  flat: 'Flat structure',
package/lib/prompts.js CHANGED
@@ -47,29 +47,29 @@ function askMultiline(rl, question) {
47
47
  console.log(' (Enter text below. Empty line to finish, or press Enter to skip)');
48
48
  const lines = [];
49
49
  let firstLine = true;
50
+ let done = false;
50
51
 
51
- const onLine = (line) => {
52
+ const handler = (line) => {
53
+ if (done) return;
52
54
  if (firstLine && line.trim() === '') {
53
- rl.removeListener('line', onLine);
55
+ done = true;
56
+ rl.removeListener('line', handler);
54
57
  resolve('');
55
58
  return;
56
59
  }
57
60
  firstLine = false;
58
61
  if (line.trim() === '') {
59
- rl.removeListener('line', onLine);
62
+ done = true;
63
+ rl.removeListener('line', handler);
60
64
  resolve(lines.join('\n'));
61
65
  } else {
62
66
  lines.push(line);
67
+ process.stdout.write(' > ');
63
68
  }
64
69
  };
65
70
 
66
71
  process.stdout.write(' > ');
67
- rl.on('line', (line) => {
68
- if (lines.length > 0 || line.trim() !== '') {
69
- process.stdout.write(' > ');
70
- }
71
- onLine(line);
72
- });
72
+ rl.on('line', handler);
73
73
  });
74
74
  }
75
75
 
package/lib/scanner.js CHANGED
@@ -67,11 +67,12 @@ function detectBackend(dir, pkg) {
67
67
 
68
68
  // Framework detection
69
69
  const frameworks = [
70
- { key: 'express', dep: 'express', label: 'Express' },
71
- { key: 'fastify', dep: 'fastify', label: 'Fastify' },
72
- { key: 'koa', dep: 'koa', label: 'Koa' },
73
- { key: 'nestjs', dep: '@nestjs/core', label: 'NestJS' },
74
- { key: 'hapi', dep: '@hapi/hapi', label: 'Hapi' },
70
+ { dep: 'express', label: 'Express' },
71
+ { dep: 'fastify', label: 'Fastify' },
72
+ { dep: 'koa', label: 'Koa' },
73
+ { dep: '@nestjs/core', label: 'NestJS' },
74
+ { dep: '@hapi/hapi', label: 'Hapi' },
75
+ { dep: '@adonisjs/core', label: 'AdonisJS' },
75
76
  ];
76
77
 
77
78
  for (const fw of frameworks) {
@@ -84,11 +85,14 @@ function detectBackend(dir, pkg) {
84
85
 
85
86
  // ORM detection
86
87
  const orms = [
87
- { key: 'prisma', dep: '@prisma/client', label: 'Prisma' },
88
- { key: 'mongoose', dep: 'mongoose', label: 'Mongoose' },
89
- { key: 'typeorm', dep: 'typeorm', label: 'TypeORM' },
90
- { key: 'sequelize', dep: 'sequelize', label: 'Sequelize' },
91
- { key: 'drizzle', dep: 'drizzle-orm', label: 'Drizzle' },
88
+ { dep: '@prisma/client', label: 'Prisma' },
89
+ { dep: 'mongoose', label: 'Mongoose' },
90
+ { dep: 'typeorm', label: 'TypeORM' },
91
+ { dep: 'sequelize', label: 'Sequelize' },
92
+ { dep: 'drizzle-orm', label: 'Drizzle' },
93
+ { dep: 'knex', label: 'Knex' },
94
+ { dep: '@mikro-orm/core', label: 'MikroORM' },
95
+ { dep: 'objection', label: 'Objection.js' },
92
96
  ];
93
97
 
94
98
  for (const orm of orms) {
@@ -117,6 +121,22 @@ function detectBackend(dir, pkg) {
117
121
  // Port detection
118
122
  result.port = detectPort(dir, pkg);
119
123
 
124
+ // Validation library detection
125
+ const validators = [
126
+ { dep: 'zod', label: 'Zod' },
127
+ { dep: 'joi', label: 'Joi' },
128
+ { dep: 'class-validator', label: 'class-validator' },
129
+ { dep: 'yup', label: 'Yup' },
130
+ { dep: 'ajv', label: 'Ajv' },
131
+ ];
132
+ result.validation = null;
133
+ for (const v of validators) {
134
+ if (deps[v.dep]) {
135
+ result.validation = v.label;
136
+ break;
137
+ }
138
+ }
139
+
120
140
  // If no framework but has a server-like structure, still mark as detected
121
141
  if (!result.detected && (result.orm || result.db)) {
122
142
  result.detected = true;
@@ -129,9 +149,13 @@ function detectFrontend(dir, pkg) {
129
149
  const deps = getAllDeps(pkg);
130
150
  const result = { detected: false, framework: null, styling: null, components: null, state: null };
131
151
 
132
- // Framework detection
152
+ // Framework detection (order matters — more specific first)
133
153
  const frameworks = [
134
154
  { dep: 'next', label: 'Next.js' },
155
+ { dep: 'nuxt', label: 'Nuxt' },
156
+ { dep: '@remix-run/react', label: 'Remix' },
157
+ { dep: 'astro', label: 'Astro' },
158
+ { dep: 'solid-js', label: 'SolidJS' },
135
159
  { dep: 'react', label: 'React' },
136
160
  { dep: 'vue', label: 'Vue' },
137
161
  { dep: '@angular/core', label: 'Angular' },
@@ -155,6 +179,8 @@ function detectFrontend(dir, pkg) {
155
179
  // Component libraries
156
180
  if (deps['@radix-ui/react-dialog'] || deps['@radix-ui/react-select'] || hasRadixDep(deps)) {
157
181
  result.components = 'Radix UI';
182
+ } else if (deps['@headlessui/react']) {
183
+ result.components = 'Headless UI';
158
184
  } else if (deps['@mui/material']) {
159
185
  result.components = 'Material UI';
160
186
  } else if (deps['@chakra-ui/react']) {
@@ -166,6 +192,8 @@ function detectFrontend(dir, pkg) {
166
192
  // State management
167
193
  if (deps['zustand']) result.state = 'Zustand';
168
194
  else if (deps['@reduxjs/toolkit'] || deps['redux']) result.state = 'Redux';
195
+ else if (deps['jotai']) result.state = 'Jotai';
196
+ else if (deps['@tanstack/react-query']) result.state = 'TanStack Query';
169
197
  else if (deps['recoil']) result.state = 'Recoil';
170
198
  else if (deps['pinia']) result.state = 'Pinia';
171
199
  else if (deps['mobx']) result.state = 'MobX';
@@ -280,13 +308,14 @@ function detectTests(dir, pkg) {
280
308
  const deps = getAllDeps(pkg);
281
309
  const result = {
282
310
  framework: 'none',
311
+ e2eFramework: null,
283
312
  hasConfig: false,
284
313
  testFiles: 0,
285
314
  testDirs: [],
286
315
  estimatedCoverage: 'none',
287
316
  };
288
317
 
289
- // Framework detection
318
+ // Unit test framework detection
290
319
  if (deps['jest'] || deps['@jest/core'] || deps['ts-jest'] || deps['@types/jest']) {
291
320
  result.framework = 'jest';
292
321
  } else if (deps['vitest']) {
@@ -295,11 +324,21 @@ function detectTests(dir, pkg) {
295
324
  result.framework = 'mocha';
296
325
  }
297
326
 
327
+ // E2E test framework detection (supplement, doesn't override unit framework)
328
+ result.e2eFramework = null;
329
+ if (deps['@playwright/test'] || deps['playwright']) {
330
+ result.e2eFramework = 'playwright';
331
+ } else if (deps['cypress']) {
332
+ result.e2eFramework = 'cypress';
333
+ }
334
+
298
335
  // Config files
299
336
  const configFiles = [
300
337
  'jest.config.js', 'jest.config.ts', 'jest.config.mjs', 'jest.config.cjs',
301
338
  'vitest.config.js', 'vitest.config.ts', 'vitest.config.mjs',
302
339
  '.mocharc.yml', '.mocharc.json', '.mocharc.js',
340
+ 'playwright.config.ts', 'playwright.config.js',
341
+ 'cypress.config.ts', 'cypress.config.js',
303
342
  ];
304
343
  result.hasConfig = configFiles.some((f) => fs.existsSync(path.join(dir, f)));
305
344
 
@@ -417,7 +456,10 @@ function detectDatabaseFromPrisma(dir) {
417
456
  if (fs.existsSync(schemaPath)) {
418
457
  try {
419
458
  const content = fs.readFileSync(schemaPath, 'utf8');
420
- const match = content.match(/provider\s*=\s*"(\w+)"/);
459
+ // Match provider only within a datasource block (skip generator blocks)
460
+ const dsBlock = content.match(/datasource\s+\w+\s*\{[^}]*\}/);
461
+ const providerSource = dsBlock ? dsBlock[0] : content;
462
+ const match = providerSource.match(/provider\s*=\s*"(\w+)"/);
421
463
  if (match) {
422
464
  const provider = match[1];
423
465
  const dbMap = {
@@ -444,6 +486,7 @@ function detectDatabaseFromEnv(dir) {
444
486
  if (fs.existsSync(envPath)) {
445
487
  try {
446
488
  const content = fs.readFileSync(envPath, 'utf8');
489
+ // Check DATABASE_URL
447
490
  const match = content.match(/DATABASE_URL\s*=\s*(\S+)/);
448
491
  if (match) {
449
492
  const url = match[1].replace(/["']/g, '');
@@ -452,6 +495,10 @@ function detectDatabaseFromEnv(dir) {
452
495
  if (url.startsWith('mysql://')) return 'MySQL';
453
496
  if (url.includes('sqlite')) return 'SQLite';
454
497
  }
498
+ // Check MONGODB_URI / MONGO_URI
499
+ if (/^MONGO(?:DB)?_URI\s*=/m.test(content)) return 'MongoDB';
500
+ // Check REDIS_URL
501
+ if (/^REDIS_URL\s*=/m.test(content)) return 'Redis';
455
502
  } catch { /* ignore */ }
456
503
  }
457
504
  }
@@ -466,7 +513,7 @@ function detectPort(dir, pkg) {
466
513
  if (fs.existsSync(envPath)) {
467
514
  try {
468
515
  const content = fs.readFileSync(envPath, 'utf8');
469
- const match = content.match(/^PORT\s*=\s*(\d+)/m);
516
+ const match = content.match(/^PORT\s*=\s*["']?(\d+)/m);
470
517
  if (match) return parseInt(match[1], 10);
471
518
  } catch { /* ignore */ }
472
519
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-sdd-project",
3
- "version": "0.2.1",
3
+ "version": "0.2.4",
4
4
  "description": "Create a new SDD DevFlow project with AI-assisted development workflow",
5
5
  "bin": {
6
6
  "create-sdd-project": "bin/cli.js"