create-sdd-project 0.1.1
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/LICENSE +21 -0
- package/README.md +204 -0
- package/bin/cli.js +44 -0
- package/lib/config.js +106 -0
- package/lib/generator.js +313 -0
- package/lib/wizard.js +224 -0
- package/package.json +41 -0
- package/template/.claude/agents/backend-developer.md +60 -0
- package/template/.claude/agents/backend-planner.md +65 -0
- package/template/.claude/agents/code-review-specialist.md +65 -0
- package/template/.claude/agents/database-architect.md +68 -0
- package/template/.claude/agents/frontend-developer.md +68 -0
- package/template/.claude/agents/frontend-planner.md +65 -0
- package/template/.claude/agents/production-code-validator.md +102 -0
- package/template/.claude/agents/qa-engineer.md +70 -0
- package/template/.claude/agents/spec-creator.md +72 -0
- package/template/.claude/commands/.gitkeep +0 -0
- package/template/.claude/hooks/quick-scan.sh +111 -0
- package/template/.claude/settings.json +29 -0
- package/template/.claude/skills/bug-workflow/SKILL.md +108 -0
- package/template/.claude/skills/development-workflow/SKILL.md +194 -0
- package/template/.claude/skills/development-workflow/references/branching-strategy.md +59 -0
- package/template/.claude/skills/development-workflow/references/complexity-guide.md +89 -0
- package/template/.claude/skills/development-workflow/references/failure-handling.md +174 -0
- package/template/.claude/skills/development-workflow/references/pr-template.md +80 -0
- package/template/.claude/skills/development-workflow/references/sprint-init-template.md +82 -0
- package/template/.claude/skills/development-workflow/references/ticket-template.md +71 -0
- package/template/.claude/skills/development-workflow/references/workflow-example.md +87 -0
- package/template/.claude/skills/project-memory/SKILL.md +152 -0
- package/template/.claude/skills/project-memory/references/bugs_template.md +41 -0
- package/template/.claude/skills/project-memory/references/decisions_template.md +67 -0
- package/template/.claude/skills/project-memory/references/key_facts_template.md +81 -0
- package/template/.env.example +17 -0
- package/template/.gemini/agents/backend-developer.md +31 -0
- package/template/.gemini/agents/backend-planner.md +34 -0
- package/template/.gemini/agents/code-review-specialist.md +44 -0
- package/template/.gemini/agents/database-architect.md +35 -0
- package/template/.gemini/agents/frontend-developer.md +31 -0
- package/template/.gemini/agents/frontend-planner.md +34 -0
- package/template/.gemini/agents/production-code-validator.md +32 -0
- package/template/.gemini/agents/qa-engineer.md +23 -0
- package/template/.gemini/agents/spec-creator.md +24 -0
- package/template/.gemini/settings.json +5 -0
- package/template/.gemini/styles/default.md +19 -0
- package/template/AGENTS.md +67 -0
- package/template/CLAUDE.md +19 -0
- package/template/GEMINI.md +10 -0
- package/template/ai-specs/specs/backend-standards.mdc +214 -0
- package/template/ai-specs/specs/base-standards.mdc +157 -0
- package/template/ai-specs/specs/documentation-standards.mdc +68 -0
- package/template/ai-specs/specs/frontend-standards.mdc +226 -0
- package/template/docs/project_notes/bugs.md +18 -0
- package/template/docs/project_notes/decisions.md +18 -0
- package/template/docs/project_notes/key_facts.md +52 -0
- package/template/docs/project_notes/pending-improvements.md +50 -0
- package/template/docs/project_notes/sprint-0-tracker.md +66 -0
- package/template/docs/specs/api-spec.yaml +114 -0
- package/template/docs/specs/ui-components.md +77 -0
- package/template/docs/tickets/.gitkeep +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 FiveGuays
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# SDD DevFlow
|
|
2
|
+
|
|
3
|
+
**Spec-Driven Development workflow template for AI-assisted coding.**
|
|
4
|
+
|
|
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.
|
|
6
|
+
|
|
7
|
+
## What is SDD?
|
|
8
|
+
|
|
9
|
+
SDD DevFlow combines three proven practices:
|
|
10
|
+
|
|
11
|
+
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.
|
|
14
|
+
|
|
15
|
+
## What's Inside
|
|
16
|
+
|
|
17
|
+
### 9 Specialized Agents
|
|
18
|
+
|
|
19
|
+
| Agent | Role | Step |
|
|
20
|
+
|-------|------|------|
|
|
21
|
+
| `spec-creator` | Draft/update specifications | 0 |
|
|
22
|
+
| `backend-planner` / `frontend-planner` | Create implementation plans | 2 |
|
|
23
|
+
| `backend-developer` / `frontend-developer` | TDD implementation | 3 |
|
|
24
|
+
| `production-code-validator` | Pre-commit quality scan | 4 |
|
|
25
|
+
| `code-review-specialist` | Pre-merge code review | 5 |
|
|
26
|
+
| `qa-engineer` | Edge cases, spec verification | 5 |
|
|
27
|
+
| `database-architect` | Schema design, optimization | Any |
|
|
28
|
+
|
|
29
|
+
### Workflow (Steps 0–6)
|
|
30
|
+
|
|
31
|
+
```
|
|
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)
|
|
35
|
+
3. IMPLEMENT → Developer agent, TDD
|
|
36
|
+
4. FINALIZE → Tests/lint/build, validator → Commit Approval
|
|
37
|
+
5. REVIEW → PR, code review, QA → Merge Approval
|
|
38
|
+
6. COMPLETE → Clean up, update tracker
|
|
39
|
+
```
|
|
40
|
+
|
|
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 |
|
|
53
|
+
|
|
54
|
+
### 4 Autonomy Levels
|
|
55
|
+
|
|
56
|
+
Control how many human approval checkpoints are active:
|
|
57
|
+
|
|
58
|
+
| Level | Name | Human Checkpoints | Best For |
|
|
59
|
+
|-------|------|-------------------|----------|
|
|
60
|
+
| L1 | Full Control | All 5 | First sprint, learning SDD |
|
|
61
|
+
| L2 | Trusted | Plan + Merge | Normal development **(default)** |
|
|
62
|
+
| L3 | Autopilot | Merge only | Well-defined, repetitive tasks |
|
|
63
|
+
| L4 | Full Auto | None (CI/CD gates only) | Bulk simple tasks |
|
|
64
|
+
|
|
65
|
+
Quality gates (tests, lint, build, validators) **always run** regardless of level.
|
|
66
|
+
|
|
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
|
+
### Project Memory
|
|
75
|
+
|
|
76
|
+
Tracks institutional knowledge across sessions in `docs/project_notes/`:
|
|
77
|
+
|
|
78
|
+
- **sprint-X-tracker.md** — Sprint progress + Active Session (context recovery after compaction)
|
|
79
|
+
- **bugs.md** — Bug log with solutions and prevention notes
|
|
80
|
+
- **decisions.md** — Architectural Decision Records (ADRs)
|
|
81
|
+
- **key_facts.md** — Project configuration, ports, URLs, branching strategy
|
|
82
|
+
|
|
83
|
+
### Automated Hooks (Claude Code)
|
|
84
|
+
|
|
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`.
|
|
88
|
+
|
|
89
|
+
### Multi-Tool Support
|
|
90
|
+
|
|
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
|
|
94
|
+
|
|
95
|
+
## Quick Start
|
|
96
|
+
|
|
97
|
+
### 1. Copy the template
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
cp -r template/ /path/to/your-project/
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 2. Configure for your project
|
|
104
|
+
|
|
105
|
+
Look for `<!-- CONFIG: ... -->` comments in these files:
|
|
106
|
+
|
|
107
|
+
| File | What to configure |
|
|
108
|
+
|------|-------------------|
|
|
109
|
+
| `CLAUDE.md` / `GEMINI.md` | Autonomy level (1-4) |
|
|
110
|
+
| `ai-specs/specs/backend-standards.mdc` | Backend tech stack |
|
|
111
|
+
| `ai-specs/specs/frontend-standards.mdc` | Frontend tech stack |
|
|
112
|
+
| `docs/project_notes/key_facts.md` | Project name, ports, URLs, branching strategy |
|
|
113
|
+
| `docs/specs/api-spec.yaml` | Server URLs |
|
|
114
|
+
| `AGENTS.md` | Monorepo layout |
|
|
115
|
+
|
|
116
|
+
### 3. Initialize and start
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
init sprint 0
|
|
120
|
+
start task B0.1
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The workflow skill will guide you through each step with checkpoints based on your autonomy level.
|
|
124
|
+
|
|
125
|
+
## Template Structure
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
project/
|
|
129
|
+
├── AGENTS.md # Universal AI instructions (all tools)
|
|
130
|
+
├── CLAUDE.md # Claude Code config (autonomy, recovery)
|
|
131
|
+
├── GEMINI.md # Gemini config (autonomy)
|
|
132
|
+
├── .env.example # Environment variables template
|
|
133
|
+
├── .gitignore # Git ignore with secrets protection
|
|
134
|
+
│
|
|
135
|
+
├── .claude/
|
|
136
|
+
│ ├── agents/ # 9 specialized agents
|
|
137
|
+
│ ├── skills/
|
|
138
|
+
│ │ ├── development-workflow/ # Main task workflow (Steps 0-6)
|
|
139
|
+
│ │ │ └── references/ # Templates, guides, examples
|
|
140
|
+
│ │ ├── bug-workflow/ # Bug triage and resolution
|
|
141
|
+
│ │ └── project-memory/ # Memory system setup
|
|
142
|
+
│ ├── hooks/quick-scan.sh # Post-developer quality scan
|
|
143
|
+
│ ├── settings.json # Shared hooks (git-tracked)
|
|
144
|
+
│ └── settings.local.json # Personal hooks (gitignored)
|
|
145
|
+
│
|
|
146
|
+
├── .gemini/
|
|
147
|
+
│ ├── agents/ # 9 agents (Gemini format)
|
|
148
|
+
│ ├── settings.json # Gemini configuration
|
|
149
|
+
│ └── styles/default.md # Response style
|
|
150
|
+
│
|
|
151
|
+
├── ai-specs/specs/
|
|
152
|
+
│ ├── base-standards.mdc # Constitution + methodology
|
|
153
|
+
│ ├── backend-standards.mdc # Backend patterns (DDD, Express, Prisma)
|
|
154
|
+
│ ├── frontend-standards.mdc # Frontend patterns (Next.js, Tailwind, Radix)
|
|
155
|
+
│ └── documentation-standards.mdc # Documentation update rules
|
|
156
|
+
│
|
|
157
|
+
└── docs/
|
|
158
|
+
├── project_notes/ # Project memory
|
|
159
|
+
│ ├── sprint-0-tracker.md # Sprint tracker template
|
|
160
|
+
│ ├── key_facts.md # Project configuration
|
|
161
|
+
│ ├── bugs.md # Bug log
|
|
162
|
+
│ └── decisions.md # ADRs
|
|
163
|
+
├── specs/
|
|
164
|
+
│ ├── api-spec.yaml # OpenAPI spec (backend)
|
|
165
|
+
│ └── ui-components.md # Component spec (frontend)
|
|
166
|
+
└── tickets/ # Task tickets (generated by workflow)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Default Tech Stack
|
|
170
|
+
|
|
171
|
+
The template defaults to (configurable via `<!-- CONFIG -->` comments):
|
|
172
|
+
|
|
173
|
+
- **Backend**: Node.js + Express + Prisma + PostgreSQL
|
|
174
|
+
- **Frontend**: Next.js (App Router) + Tailwind CSS + Radix UI + Zustand
|
|
175
|
+
- **Shared Types**: Zod schemas in `shared/` workspace → `z.infer<>` for TypeScript types
|
|
176
|
+
- **Testing**: Jest (unit) + Playwright (e2e)
|
|
177
|
+
- **Methodology**: TDD + DDD + Spec-Driven Development
|
|
178
|
+
|
|
179
|
+
## Constitution (Immutable Principles)
|
|
180
|
+
|
|
181
|
+
These 6 principles apply to ALL tasks, ALL agents, ALL complexity levels:
|
|
182
|
+
|
|
183
|
+
1. **Spec First** — No implementation without an approved specification
|
|
184
|
+
2. **Small Tasks** — Work in baby steps, one at a time
|
|
185
|
+
3. **Test-Driven Development** — Write tests before implementation
|
|
186
|
+
4. **Type Safety** — Strict TypeScript, no `any`, runtime validation with Zod
|
|
187
|
+
5. **English Only** — All code, comments, docs, commits, and tickets in English
|
|
188
|
+
6. **Reuse Over Recreate** — Always check existing code before proposing new files
|
|
189
|
+
|
|
190
|
+
## Prerequisites
|
|
191
|
+
|
|
192
|
+
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and/or [Gemini](https://gemini.google.com/)
|
|
193
|
+
- Node.js 18+
|
|
194
|
+
- `jq` (for quick-scan hook): `brew install jq` (macOS) or `apt install jq` (Linux)
|
|
195
|
+
|
|
196
|
+
## Roadmap
|
|
197
|
+
|
|
198
|
+
- **Agent Teams**: Parallel execution of independent tasks (waiting for Claude Code Agent Teams to stabilize)
|
|
199
|
+
- **PM Agent + L5 Autonomous**: AI-driven sprint orchestration with human review at sprint boundaries
|
|
200
|
+
- **Setup Script + npx**: Interactive installer (`npx create-sdd-project`) for automated setup
|
|
201
|
+
|
|
202
|
+
## License
|
|
203
|
+
|
|
204
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const { runWizard, buildDefaultConfig } = require('../lib/wizard');
|
|
6
|
+
const { generate } = require('../lib/generator');
|
|
7
|
+
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
const projectName = args.find((a) => !a.startsWith('-'));
|
|
10
|
+
const useDefaults = args.includes('--yes') || args.includes('-y');
|
|
11
|
+
|
|
12
|
+
async function main() {
|
|
13
|
+
let config;
|
|
14
|
+
|
|
15
|
+
if (useDefaults) {
|
|
16
|
+
if (!projectName) {
|
|
17
|
+
console.error('Error: Project name required with --yes flag.');
|
|
18
|
+
console.error('Usage: create-sdd-project <project-name> --yes');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
config = buildDefaultConfig(projectName);
|
|
22
|
+
console.log(`\nCreating SDD DevFlow project with defaults in ./${projectName}...\n`);
|
|
23
|
+
} else {
|
|
24
|
+
config = await runWizard(projectName);
|
|
25
|
+
console.log(`\nCreating SDD DevFlow project in ${config.projectDir}...\n`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Check if destination already exists
|
|
29
|
+
if (fs.existsSync(config.projectDir)) {
|
|
30
|
+
const entries = fs.readdirSync(config.projectDir);
|
|
31
|
+
if (entries.length > 0) {
|
|
32
|
+
console.error(`Error: Directory ${config.projectDir} is not empty.`);
|
|
33
|
+
console.error('Please choose a different directory or remove existing files.');
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
generate(config);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
main().catch((err) => {
|
|
42
|
+
console.error('\nError:', err.message);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
});
|
package/lib/config.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const DEFAULTS = {
|
|
4
|
+
projectName: '',
|
|
5
|
+
projectDir: '',
|
|
6
|
+
description: '',
|
|
7
|
+
businessContext: '',
|
|
8
|
+
projectType: 'fullstack', // 'fullstack' | 'backend' | 'frontend'
|
|
9
|
+
backendStack: 'express-prisma-pg',
|
|
10
|
+
frontendStack: 'nextjs-tailwind-radix',
|
|
11
|
+
aiTools: 'both', // 'both' | 'claude' | 'gemini'
|
|
12
|
+
autonomyLevel: 2,
|
|
13
|
+
branching: 'github-flow',
|
|
14
|
+
backendPort: 3010,
|
|
15
|
+
frontendPort: 3000,
|
|
16
|
+
dbPort: 5432,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const PROJECT_TYPES = [
|
|
20
|
+
{ key: 'fullstack', label: 'Backend + Frontend (monorepo)', default: true },
|
|
21
|
+
{ key: 'backend', label: 'Backend only' },
|
|
22
|
+
{ key: 'frontend', label: 'Frontend only' },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const BACKEND_STACKS = [
|
|
26
|
+
{
|
|
27
|
+
key: 'express-prisma-pg',
|
|
28
|
+
label: 'Node.js + Express + Prisma + PostgreSQL',
|
|
29
|
+
default: true,
|
|
30
|
+
db: 'PostgreSQL',
|
|
31
|
+
orm: 'Prisma',
|
|
32
|
+
framework: 'Express',
|
|
33
|
+
runtime: 'Node.js',
|
|
34
|
+
dbPort: 5432,
|
|
35
|
+
databaseUrl: 'postgresql://user:password@localhost:5432/dbname',
|
|
36
|
+
needsStandardsUpdate: false,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
key: 'express-mongo-mongoose',
|
|
40
|
+
label: 'Node.js + Express + MongoDB + Mongoose',
|
|
41
|
+
db: 'MongoDB',
|
|
42
|
+
orm: 'Mongoose',
|
|
43
|
+
framework: 'Express',
|
|
44
|
+
runtime: 'Node.js',
|
|
45
|
+
dbPort: 27017,
|
|
46
|
+
databaseUrl: 'mongodb://localhost:27017/dbname',
|
|
47
|
+
needsStandardsUpdate: true,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
key: 'custom',
|
|
51
|
+
label: 'Custom (enter your own)',
|
|
52
|
+
needsStandardsUpdate: true,
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
const FRONTEND_STACKS = [
|
|
57
|
+
{
|
|
58
|
+
key: 'nextjs-tailwind-radix',
|
|
59
|
+
label: 'Next.js + Tailwind CSS + Radix UI + Zustand',
|
|
60
|
+
default: true,
|
|
61
|
+
framework: 'Next.js (App Router)',
|
|
62
|
+
styling: 'Tailwind CSS',
|
|
63
|
+
components: 'Radix UI',
|
|
64
|
+
state: 'Zustand',
|
|
65
|
+
needsStandardsUpdate: false,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
key: 'custom',
|
|
69
|
+
label: 'Custom (enter your own)',
|
|
70
|
+
needsStandardsUpdate: true,
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
const AI_TOOLS = [
|
|
75
|
+
{ key: 'both', label: 'Claude Code + Gemini', default: true },
|
|
76
|
+
{ key: 'claude', label: 'Claude Code only' },
|
|
77
|
+
{ key: 'gemini', label: 'Gemini only' },
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
const AUTONOMY_LEVELS = [
|
|
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 },
|
|
83
|
+
{ level: 3, name: 'Autopilot', desc: 'Human only approves merges (well-defined, repetitive tasks)' },
|
|
84
|
+
{ level: 4, name: 'Full Auto', desc: 'No human checkpoints, CI/CD gates only (bulk simple tasks)' },
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
const BRANCHING_STRATEGIES = [
|
|
88
|
+
{ key: 'github-flow', label: 'GitHub Flow', desc: 'main + feature branches (recommended for MVPs)', default: true },
|
|
89
|
+
{ key: 'gitflow', label: 'GitFlow', desc: 'main + develop + feature/release/hotfix branches (larger projects)' },
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
// Agent files categorized by scope
|
|
93
|
+
const FRONTEND_AGENTS = ['frontend-developer.md', 'frontend-planner.md'];
|
|
94
|
+
const BACKEND_AGENTS = ['backend-developer.md', 'backend-planner.md', 'database-architect.md'];
|
|
95
|
+
|
|
96
|
+
module.exports = {
|
|
97
|
+
DEFAULTS,
|
|
98
|
+
PROJECT_TYPES,
|
|
99
|
+
BACKEND_STACKS,
|
|
100
|
+
FRONTEND_STACKS,
|
|
101
|
+
AI_TOOLS,
|
|
102
|
+
AUTONOMY_LEVELS,
|
|
103
|
+
BRANCHING_STRATEGIES,
|
|
104
|
+
FRONTEND_AGENTS,
|
|
105
|
+
BACKEND_AGENTS,
|
|
106
|
+
};
|
package/lib/generator.js
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const {
|
|
6
|
+
BACKEND_STACKS,
|
|
7
|
+
FRONTEND_STACKS,
|
|
8
|
+
AUTONOMY_LEVELS,
|
|
9
|
+
FRONTEND_AGENTS,
|
|
10
|
+
BACKEND_AGENTS,
|
|
11
|
+
} = require('./config');
|
|
12
|
+
|
|
13
|
+
function generate(config) {
|
|
14
|
+
const templateDir = path.join(__dirname, '..', 'template');
|
|
15
|
+
const dest = config.projectDir;
|
|
16
|
+
|
|
17
|
+
// 1. Copy entire template
|
|
18
|
+
step('Copying template files');
|
|
19
|
+
fs.cpSync(templateDir, dest, { recursive: true });
|
|
20
|
+
|
|
21
|
+
// 2. Configure key_facts.md
|
|
22
|
+
step(`Configuring project: ${config.projectName}`);
|
|
23
|
+
updateKeyFacts(dest, config);
|
|
24
|
+
|
|
25
|
+
// 3. Update tech stack references
|
|
26
|
+
if (config.projectType !== 'frontend') {
|
|
27
|
+
const bPreset = config.backendPreset || BACKEND_STACKS[0];
|
|
28
|
+
step(`Setting backend: ${bPreset.label || config.customBackend || 'Custom'}`);
|
|
29
|
+
updateBackendConfig(dest, config);
|
|
30
|
+
}
|
|
31
|
+
if (config.projectType !== 'backend') {
|
|
32
|
+
const fPreset = config.frontendPreset || FRONTEND_STACKS[0];
|
|
33
|
+
step(`Setting frontend: ${fPreset.label || config.customFrontend || 'Custom'}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 4. Set autonomy level
|
|
37
|
+
step(`Setting autonomy level: L${config.autonomyLevel} (${config.autonomyName})`);
|
|
38
|
+
updateAutonomy(dest, config);
|
|
39
|
+
|
|
40
|
+
// 5. Set branching strategy
|
|
41
|
+
step(`Setting branching: ${config.branching}`);
|
|
42
|
+
updateBranching(dest, config);
|
|
43
|
+
|
|
44
|
+
// 6. Set sprint dates
|
|
45
|
+
step('Setting sprint dates to today');
|
|
46
|
+
updateSprintDates(dest);
|
|
47
|
+
|
|
48
|
+
// 7. Remove agents/specs based on project type
|
|
49
|
+
if (config.projectType === 'backend') {
|
|
50
|
+
step('Removing frontend agents (backend only)');
|
|
51
|
+
removeFrontendFiles(dest, config);
|
|
52
|
+
} else if (config.projectType === 'frontend') {
|
|
53
|
+
step('Removing backend agents (frontend only)');
|
|
54
|
+
removeBackendFiles(dest, config);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 8. Remove AI tool config if single tool selected
|
|
58
|
+
if (config.aiTools === 'claude') {
|
|
59
|
+
step('Removing Gemini config (Claude only)');
|
|
60
|
+
fs.rmSync(path.join(dest, '.gemini'), { recursive: true, force: true });
|
|
61
|
+
safeDelete(path.join(dest, 'GEMINI.md'));
|
|
62
|
+
} else if (config.aiTools === 'gemini') {
|
|
63
|
+
step('Removing Claude config (Gemini only)');
|
|
64
|
+
fs.rmSync(path.join(dest, '.claude'), { recursive: true, force: true });
|
|
65
|
+
safeDelete(path.join(dest, 'CLAUDE.md'));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Show notes
|
|
69
|
+
const notes = collectNotes(config);
|
|
70
|
+
if (notes.length > 0) {
|
|
71
|
+
console.log('');
|
|
72
|
+
notes.forEach((n) => console.log(` 📝 ${n}`));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Done
|
|
76
|
+
console.log(`\nDone! Next steps:`);
|
|
77
|
+
console.log(` cd ${path.relative(process.cwd(), dest)}`);
|
|
78
|
+
console.log(` git init && git add -A && git commit -m "chore: initialize SDD DevFlow project"`);
|
|
79
|
+
console.log(` # Open in your AI coding tool and run: init sprint 0\n`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// --- Helpers ---
|
|
83
|
+
|
|
84
|
+
function step(msg) {
|
|
85
|
+
console.log(` ✓ ${msg}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function safeDelete(filePath) {
|
|
89
|
+
try {
|
|
90
|
+
fs.unlinkSync(filePath);
|
|
91
|
+
} catch {
|
|
92
|
+
// ignore if not found
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function replaceInFile(filePath, replacements) {
|
|
97
|
+
if (!fs.existsSync(filePath)) return;
|
|
98
|
+
let content = fs.readFileSync(filePath, 'utf8');
|
|
99
|
+
for (const [search, replace] of replacements) {
|
|
100
|
+
if (search instanceof RegExp) {
|
|
101
|
+
content = content.replace(search, replace);
|
|
102
|
+
} else {
|
|
103
|
+
content = content.split(search).join(replace);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function updateKeyFacts(dest, config) {
|
|
110
|
+
const file = path.join(dest, 'docs', 'project_notes', 'key_facts.md');
|
|
111
|
+
const bPreset = config.backendPreset || BACKEND_STACKS[0];
|
|
112
|
+
const fPreset = config.frontendPreset || FRONTEND_STACKS[0];
|
|
113
|
+
|
|
114
|
+
const replacements = [
|
|
115
|
+
['[Your project name]', config.projectName],
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
// Branching
|
|
119
|
+
// The template has: github-flow <!-- Options: ... -->
|
|
120
|
+
replacements.push([
|
|
121
|
+
/github-flow <!-- Options:.*?-->/,
|
|
122
|
+
`${config.branching} <!-- Options: github-flow | gitflow — See .claude/skills/development-workflow/references/branching-strategy.md -->`,
|
|
123
|
+
]);
|
|
124
|
+
|
|
125
|
+
// Technology Stack
|
|
126
|
+
if (config.projectType !== 'frontend' && bPreset.key !== 'custom') {
|
|
127
|
+
replacements.push(['[Framework, runtime, version]', `${bPreset.framework}, ${bPreset.runtime}`]);
|
|
128
|
+
replacements.push(['[Type, host, port]', `${bPreset.db}, localhost, ${bPreset.dbPort}`]);
|
|
129
|
+
replacements.push(['[Name, version]', bPreset.orm]);
|
|
130
|
+
} else if (config.projectType !== 'frontend' && config.customBackend) {
|
|
131
|
+
replacements.push(['[Framework, runtime, version]', config.customBackend]);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (config.projectType !== 'backend' && fPreset.key !== 'custom') {
|
|
135
|
+
replacements.push(['[Framework, version]', `${fPreset.framework}, ${fPreset.styling}, ${fPreset.components}, ${fPreset.state}`]);
|
|
136
|
+
} else if (config.projectType !== 'backend' && config.customFrontend) {
|
|
137
|
+
replacements.push(['[Framework, version]', config.customFrontend]);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Ports
|
|
141
|
+
if (config.projectType !== 'frontend') {
|
|
142
|
+
replacements.push(['[e.g., 3010]', String(config.backendPort)]);
|
|
143
|
+
replacements.push(['[e.g., 5432]', bPreset.key !== 'custom' ? String(bPreset.dbPort) : '[e.g., 5432]']);
|
|
144
|
+
replacements.push(['[e.g., http://localhost:3010/api]', `http://localhost:${config.backendPort}/api`]);
|
|
145
|
+
}
|
|
146
|
+
if (config.projectType !== 'backend') {
|
|
147
|
+
replacements.push(['[e.g., 3000]', String(config.frontendPort || 3000)]);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
replaceInFile(file, replacements);
|
|
151
|
+
|
|
152
|
+
// Add business context section if provided
|
|
153
|
+
if (config.businessContext) {
|
|
154
|
+
let content = fs.readFileSync(file, 'utf8');
|
|
155
|
+
const contextSection = `\n## Project Information\n\n${config.businessContext}\n`;
|
|
156
|
+
// Insert before ## Technology Stack
|
|
157
|
+
content = content.replace('## Technology Stack', `${contextSection}\n## Technology Stack`);
|
|
158
|
+
// Add description if provided
|
|
159
|
+
if (config.description) {
|
|
160
|
+
content = content.replace(
|
|
161
|
+
`- **Project Name**: ${config.projectName}`,
|
|
162
|
+
`- **Project Name**: ${config.projectName}\n- **Description**: ${config.description}`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
fs.writeFileSync(file, content, 'utf8');
|
|
166
|
+
} else if (config.description) {
|
|
167
|
+
replaceInFile(file, [
|
|
168
|
+
[`- **Project Name**: ${config.projectName}`, `- **Project Name**: ${config.projectName}\n- **Description**: ${config.description}`],
|
|
169
|
+
]);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function updateBackendConfig(dest, config) {
|
|
174
|
+
const bPreset = config.backendPreset || BACKEND_STACKS[0];
|
|
175
|
+
|
|
176
|
+
// .env.example
|
|
177
|
+
const envFile = path.join(dest, '.env.example');
|
|
178
|
+
const replacements = [];
|
|
179
|
+
|
|
180
|
+
if (config.backendPort !== 3010) {
|
|
181
|
+
replacements.push(['PORT=3010', `PORT=${config.backendPort}`]);
|
|
182
|
+
replacements.push([
|
|
183
|
+
'NEXT_PUBLIC_API_URL=http://localhost:3010/api',
|
|
184
|
+
`NEXT_PUBLIC_API_URL=http://localhost:${config.backendPort}/api`,
|
|
185
|
+
]);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (bPreset.databaseUrl) {
|
|
189
|
+
replacements.push([
|
|
190
|
+
'DATABASE_URL=postgresql://user:password@localhost:5432/dbname',
|
|
191
|
+
`DATABASE_URL=${bPreset.databaseUrl}`,
|
|
192
|
+
]);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (replacements.length > 0) {
|
|
196
|
+
replaceInFile(envFile, replacements);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// api-spec.yaml
|
|
200
|
+
const apiSpec = path.join(dest, 'docs', 'specs', 'api-spec.yaml');
|
|
201
|
+
const apiReplacements = [
|
|
202
|
+
['title: Project API', `title: ${config.projectName} API`],
|
|
203
|
+
];
|
|
204
|
+
if (config.backendPort !== 3010) {
|
|
205
|
+
apiReplacements.push([
|
|
206
|
+
'http://localhost:3010/api',
|
|
207
|
+
`http://localhost:${config.backendPort}/api`,
|
|
208
|
+
]);
|
|
209
|
+
}
|
|
210
|
+
replaceInFile(apiSpec, apiReplacements);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function updateAutonomy(dest, config) {
|
|
214
|
+
const levelInfo = AUTONOMY_LEVELS.find((l) => l.level === config.autonomyLevel);
|
|
215
|
+
const newLine = `**Autonomy Level: ${config.autonomyLevel} (${levelInfo.name})**`;
|
|
216
|
+
|
|
217
|
+
// CLAUDE.md
|
|
218
|
+
replaceInFile(path.join(dest, 'CLAUDE.md'), [
|
|
219
|
+
[/\*\*Autonomy Level: \d+ \([^)]+\)\*\*/, newLine],
|
|
220
|
+
]);
|
|
221
|
+
|
|
222
|
+
// GEMINI.md
|
|
223
|
+
replaceInFile(path.join(dest, 'GEMINI.md'), [
|
|
224
|
+
[/\*\*Autonomy Level: \d+ \([^)]+\)\*\*/, newLine],
|
|
225
|
+
]);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function updateBranching(dest, config) {
|
|
229
|
+
// key_facts.md is already handled in updateKeyFacts
|
|
230
|
+
// Nothing else to update — branching is read from key_facts.md at runtime
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function updateSprintDates(dest) {
|
|
234
|
+
const file = path.join(dest, 'docs', 'project_notes', 'sprint-0-tracker.md');
|
|
235
|
+
const today = new Date().toISOString().split('T')[0];
|
|
236
|
+
// Calculate 2-week sprint end
|
|
237
|
+
const endDate = new Date();
|
|
238
|
+
endDate.setDate(endDate.getDate() + 14);
|
|
239
|
+
const end = endDate.toISOString().split('T')[0];
|
|
240
|
+
|
|
241
|
+
replaceInFile(file, [
|
|
242
|
+
[/\[YYYY-MM-DD\] to \[YYYY-MM-DD\]/, `${today} to ${end}`],
|
|
243
|
+
]);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function removeFrontendFiles(dest, config) {
|
|
247
|
+
// Remove frontend agents
|
|
248
|
+
for (const agent of FRONTEND_AGENTS) {
|
|
249
|
+
safeDelete(path.join(dest, '.claude', 'agents', agent));
|
|
250
|
+
safeDelete(path.join(dest, '.gemini', 'agents', agent));
|
|
251
|
+
}
|
|
252
|
+
// Remove frontend spec
|
|
253
|
+
safeDelete(path.join(dest, 'docs', 'specs', 'ui-components.md'));
|
|
254
|
+
|
|
255
|
+
// Remove frontend from .env.example
|
|
256
|
+
replaceInFile(path.join(dest, '.env.example'), [
|
|
257
|
+
[/\n# Frontend\nNEXT_PUBLIC_API_URL=.*\n/, '\n'],
|
|
258
|
+
]);
|
|
259
|
+
|
|
260
|
+
// Remove frontend from AGENTS.md project structure
|
|
261
|
+
replaceInFile(path.join(dest, 'AGENTS.md'), [
|
|
262
|
+
['├── frontend/ ← Frontend (has its own package.json)\n', ''],
|
|
263
|
+
]);
|
|
264
|
+
|
|
265
|
+
// Remove frontend tasks from sprint tracker
|
|
266
|
+
const trackerFile = path.join(dest, 'docs', 'project_notes', 'sprint-0-tracker.md');
|
|
267
|
+
replaceInFile(trackerFile, [
|
|
268
|
+
[/\n### Frontend\n\n\|.*\n\|.*\n\|.*\n/, '\n'],
|
|
269
|
+
]);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function removeBackendFiles(dest, config) {
|
|
273
|
+
// Remove backend agents + database-architect
|
|
274
|
+
for (const agent of BACKEND_AGENTS) {
|
|
275
|
+
safeDelete(path.join(dest, '.claude', 'agents', agent));
|
|
276
|
+
safeDelete(path.join(dest, '.gemini', 'agents', agent));
|
|
277
|
+
}
|
|
278
|
+
// Remove backend spec
|
|
279
|
+
safeDelete(path.join(dest, 'docs', 'specs', 'api-spec.yaml'));
|
|
280
|
+
|
|
281
|
+
// Remove backend from .env.example
|
|
282
|
+
replaceInFile(path.join(dest, '.env.example'), [
|
|
283
|
+
[/# Backend\nNODE_ENV=.*\nPORT=.*\nDATABASE_URL=.*\n\n/, ''],
|
|
284
|
+
]);
|
|
285
|
+
|
|
286
|
+
// Remove backend from AGENTS.md project structure
|
|
287
|
+
replaceInFile(path.join(dest, 'AGENTS.md'), [
|
|
288
|
+
['├── backend/ ← Backend (has its own package.json)\n', ''],
|
|
289
|
+
]);
|
|
290
|
+
|
|
291
|
+
// Remove backend tasks from sprint tracker
|
|
292
|
+
const trackerFile = path.join(dest, 'docs', 'project_notes', 'sprint-0-tracker.md');
|
|
293
|
+
replaceInFile(trackerFile, [
|
|
294
|
+
[/\n### Backend\n\n\|.*\n\|.*\n\|.*\n/, '\n'],
|
|
295
|
+
]);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function collectNotes(config) {
|
|
299
|
+
const notes = [];
|
|
300
|
+
const bPreset = config.backendPreset;
|
|
301
|
+
const fPreset = config.frontendPreset;
|
|
302
|
+
|
|
303
|
+
if (bPreset && bPreset.needsStandardsUpdate) {
|
|
304
|
+
notes.push('Update ai-specs/specs/backend-standards.mdc with your backend stack patterns.');
|
|
305
|
+
}
|
|
306
|
+
if (fPreset && fPreset.needsStandardsUpdate) {
|
|
307
|
+
notes.push('Update ai-specs/specs/frontend-standards.mdc with your frontend stack patterns.');
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return notes;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
module.exports = { generate };
|