sddx-workflow 0.6.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.
- package/README.md +134 -0
- package/dist/cli.js +311 -0
- package/package.json +46 -0
- package/templates/CLAUDE.md +35 -0
- package/templates/claude-commands/ask.md +5 -0
- package/templates/claude-commands/assume.md +7 -0
- package/templates/claude-commands/bootstrap.md +5 -0
- package/templates/claude-commands/bugfix.md +6 -0
- package/templates/claude-commands/finish.md +5 -0
- package/templates/claude-commands/refactor.md +6 -0
- package/templates/claude-commands/review.md +5 -0
- package/templates/claude-commands/spec-new.md +4 -0
- package/templates/claude-commands/spec-plan.md +4 -0
- package/templates/claude-commands/spec-tasks.md +5 -0
- package/templates/conventions/base.md +32 -0
- package/templates/copilot-instructions.md +33 -0
- package/templates/copilot-prompts/ask.prompt.md +10 -0
- package/templates/copilot-prompts/assume.prompt.md +12 -0
- package/templates/copilot-prompts/bootstrap.prompt.md +11 -0
- package/templates/copilot-prompts/bugfix.prompt.md +12 -0
- package/templates/copilot-prompts/finish.prompt.md +10 -0
- package/templates/copilot-prompts/refactor.prompt.md +10 -0
- package/templates/copilot-prompts/review.prompt.md +10 -0
- package/templates/copilot-prompts/spec-new.prompt.md +9 -0
- package/templates/copilot-prompts/spec-plan.prompt.md +9 -0
- package/templates/copilot-prompts/spec-tasks.prompt.md +10 -0
- package/templates/cursor-rules/sddx-workflow.mdc +27 -0
- package/templates/domains/auth.md +31 -0
- package/templates/domains/email.md +30 -0
- package/templates/domains/payments.md +32 -0
- package/templates/domains/storage.md +30 -0
- package/templates/project-overview.md +31 -0
- package/templates/specs/_template/1-requirements.md +81 -0
- package/templates/specs/_template/2-plan.md +128 -0
- package/templates/specs/_template/3-tasks.md +53 -0
- package/templates/windsurf-rules/sddx-workflow.md +26 -0
- package/templates/workflow.md +285 -0
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# sddx-workflow
|
|
2
|
+
|
|
3
|
+
Spec-Driven Development CLI for AI-assisted projects. Installs a structured workflow system that guides AI agents (Claude, Cursor, Copilot) through planning, execution, and review — without letting them run loose.
|
|
4
|
+
|
|
5
|
+
Works with any project: Next.js, Python, React, Django, Go, Rails — the workflow is universal.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx sddx-workflow init
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## The problem
|
|
14
|
+
|
|
15
|
+
AI agents tend to implement without validating assumptions, refactor more than asked, and don't have a mental model of when to stop and ask for approval. This system enforces explicit ceremony levels and stop points.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Initialize in any project
|
|
23
|
+
npx sddx-workflow init
|
|
24
|
+
|
|
25
|
+
# Overwrite existing files
|
|
26
|
+
npx sddx-workflow init --force
|
|
27
|
+
|
|
28
|
+
# Add a domain file to an existing installation
|
|
29
|
+
npx sddx-workflow add domain auth
|
|
30
|
+
npx sddx-workflow add domain payments
|
|
31
|
+
npx sddx-workflow add domain storage
|
|
32
|
+
npx sddx-workflow add domain email
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Files are **copied locally** — your project owns them. No runtime dependency. Edit them freely.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## What it generates
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
.sdd/
|
|
43
|
+
workflow.md # Commands, ceremony levels, stop points
|
|
44
|
+
project-overview.md # What this app is (populated by /bootstrap)
|
|
45
|
+
conventions.md # Stack and patterns (populated by /bootstrap)
|
|
46
|
+
domains/ # Domain-specific rules (auth, payments, etc.)
|
|
47
|
+
specs/
|
|
48
|
+
_template/
|
|
49
|
+
1-requirements.md # Problem, goals, acceptance criteria (BDD)
|
|
50
|
+
2-plan.md # Technical plan — requires approval before coding
|
|
51
|
+
3-tasks.md # Atomic task checklist with TDD gate
|
|
52
|
+
CLAUDE.md # Entry point — points the agent to .sdd/
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## First thing to do after init
|
|
58
|
+
|
|
59
|
+
Run `/bootstrap` with your AI agent to populate the project context:
|
|
60
|
+
|
|
61
|
+
- **New project** — the agent interviews you with 6 targeted questions (problem, stack, non-goals, architecture decisions, domains, definition of done) and writes `.sdd/project-overview.md` and `.sdd/conventions.md`
|
|
62
|
+
- **Existing project** — run `/bootstrap --scan` and the agent reads your codebase first, infers what it can, then asks only about what the code can't answer
|
|
63
|
+
|
|
64
|
+
The agent presents a full draft for your approval before writing anything.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Workflow commands
|
|
69
|
+
|
|
70
|
+
| Command | Purpose |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `/bootstrap` | Populate project context — interview or codebase scan |
|
|
73
|
+
| `/ask` | Research and exploration — no code changes |
|
|
74
|
+
| `/assume` | Surface all assumptions before acting — stops for confirmation |
|
|
75
|
+
| `/bugfix` | Reproduce → diagnose → fix → validate |
|
|
76
|
+
| `/refactor` | Restructure without behavior change — green baseline required |
|
|
77
|
+
| `/spec-new` | Scaffold a spec folder for a feature |
|
|
78
|
+
| `/spec-plan` | Generate technical plan — **stops for approval before any code** |
|
|
79
|
+
| `/spec-tasks` | Execute plan one atomic task at a time, TDD-first |
|
|
80
|
+
| `/review` | Final audit — verifies goals, scenarios, no scope creep |
|
|
81
|
+
| `/finish` | Stage files and generate a conventional commit message for approval |
|
|
82
|
+
|
|
83
|
+
### Ceremony levels
|
|
84
|
+
|
|
85
|
+
| Change | Flow |
|
|
86
|
+
|---|---|
|
|
87
|
+
| Typo / comment | Direct |
|
|
88
|
+
| Bug | `/bugfix` → `/finish` |
|
|
89
|
+
| Refactor | `/refactor` → `/finish` |
|
|
90
|
+
| Feature | `/spec-new` → `/spec-plan` → `/spec-tasks` → `/review` → `/finish` |
|
|
91
|
+
| Architecture | `/spec-new` → `/spec-plan` (mandatory human review) → `/spec-tasks` → `/review` → `/finish` |
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Execution principles
|
|
96
|
+
|
|
97
|
+
Built into the workflow — every command enforces these:
|
|
98
|
+
|
|
99
|
+
1. **Surface assumptions** — list them before acting, not mid-execution
|
|
100
|
+
2. **Minimum code** — only what was asked; no "while I'm here" changes
|
|
101
|
+
3. **Surgical changes** — touch only what the task requires
|
|
102
|
+
4. **Verify before moving on** — define "done" before starting, not after
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Spec structure
|
|
107
|
+
|
|
108
|
+
Each feature gets a folder under `specs/<name>/` with three files:
|
|
109
|
+
|
|
110
|
+
**`1-requirements.md`** — Problem, measurable goals (G1, G2…), BDD acceptance criteria, constraints, open questions (blocking vs. non-blocking).
|
|
111
|
+
|
|
112
|
+
**`2-plan.md`** — Goals coverage, assumptions (confirmed via `/assume`), approach + tradeoffs, components affected, abort criteria, verification per task. Requires explicit approval before execution starts.
|
|
113
|
+
|
|
114
|
+
**`3-tasks.md`** — One task at a time. Each task has: test to write first (red→green), files to change, goal ID, acceptance scenario, and optional tradeoff. Completed specs move to `specs/_done/`.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Updating
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
npm version patch # bug fix: 0.1.0 → 0.1.1
|
|
122
|
+
npm version minor # new feature: 0.1.0 → 0.2.0
|
|
123
|
+
npm publish
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Users running `npx sddx-workflow init` always get the latest version automatically.
|
|
127
|
+
|
|
128
|
+
Since files are copied to your project, existing `.sdd/` files are never overwritten on update — use `--force` to explicitly replace them.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
MIT
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/cli.ts
|
|
27
|
+
var import_commander = require("commander");
|
|
28
|
+
|
|
29
|
+
// src/commands/init.ts
|
|
30
|
+
var import_path2 = __toESM(require("path"));
|
|
31
|
+
var import_fs2 = __toESM(require("fs"));
|
|
32
|
+
var import_prompts = require("@inquirer/prompts");
|
|
33
|
+
|
|
34
|
+
// src/utils.ts
|
|
35
|
+
var import_fs = __toESM(require("fs"));
|
|
36
|
+
var import_path = __toESM(require("path"));
|
|
37
|
+
var TEMPLATES_DIR = import_path.default.join(__dirname, "../templates");
|
|
38
|
+
function ensureDir(dir) {
|
|
39
|
+
if (!import_fs.default.existsSync(dir)) {
|
|
40
|
+
import_fs.default.mkdirSync(dir, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function copyTemplate(src, dest, force) {
|
|
44
|
+
const exists = import_fs.default.existsSync(dest);
|
|
45
|
+
if (exists && !force) {
|
|
46
|
+
console.log(` skip ${dest}`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
import_fs.default.copyFileSync(import_path.default.join(TEMPLATES_DIR, src), dest);
|
|
50
|
+
console.log(` ${exists ? "overwrite" : "create "} ${dest}`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/commands/init.ts
|
|
54
|
+
var CORE_FILES = [
|
|
55
|
+
{ src: "workflow.md", dest: ".sdd/workflow.md" },
|
|
56
|
+
{ src: "project-overview.md", dest: ".sdd/project-overview.md" },
|
|
57
|
+
{ src: "conventions/base.md", dest: ".sdd/conventions.md" },
|
|
58
|
+
{ src: "CLAUDE.md", dest: "CLAUDE.md" },
|
|
59
|
+
{ src: "specs/_template/1-requirements.md", dest: "specs/_template/1-requirements.md" },
|
|
60
|
+
{ src: "specs/_template/2-plan.md", dest: "specs/_template/2-plan.md" },
|
|
61
|
+
{ src: "specs/_template/3-tasks.md", dest: "specs/_template/3-tasks.md" }
|
|
62
|
+
];
|
|
63
|
+
var PROVIDERS = {
|
|
64
|
+
"claude-code": {
|
|
65
|
+
name: "Claude Code",
|
|
66
|
+
dirs: [".claude/commands"],
|
|
67
|
+
files: [
|
|
68
|
+
{ src: "claude-commands/bootstrap.md", dest: ".claude/commands/bootstrap.md" },
|
|
69
|
+
{ src: "claude-commands/ask.md", dest: ".claude/commands/ask.md" },
|
|
70
|
+
{ src: "claude-commands/assume.md", dest: ".claude/commands/assume.md" },
|
|
71
|
+
{ src: "claude-commands/bugfix.md", dest: ".claude/commands/bugfix.md" },
|
|
72
|
+
{ src: "claude-commands/refactor.md", dest: ".claude/commands/refactor.md" },
|
|
73
|
+
{ src: "claude-commands/spec-new.md", dest: ".claude/commands/spec-new.md" },
|
|
74
|
+
{ src: "claude-commands/spec-plan.md", dest: ".claude/commands/spec-plan.md" },
|
|
75
|
+
{ src: "claude-commands/spec-tasks.md", dest: ".claude/commands/spec-tasks.md" },
|
|
76
|
+
{ src: "claude-commands/review.md", dest: ".claude/commands/review.md" },
|
|
77
|
+
{ src: "claude-commands/finish.md", dest: ".claude/commands/finish.md" }
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
cursor: {
|
|
81
|
+
name: "Cursor",
|
|
82
|
+
dirs: [".cursor/rules"],
|
|
83
|
+
files: [
|
|
84
|
+
{ src: "cursor-rules/sddx-workflow.mdc", dest: ".cursor/rules/sddx-workflow.mdc" }
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
windsurf: {
|
|
88
|
+
name: "Windsurf",
|
|
89
|
+
dirs: [".windsurf/rules"],
|
|
90
|
+
files: [
|
|
91
|
+
{ src: "windsurf-rules/sddx-workflow.md", dest: ".windsurf/rules/sddx-workflow.md" }
|
|
92
|
+
]
|
|
93
|
+
},
|
|
94
|
+
copilot: {
|
|
95
|
+
name: "GitHub Copilot",
|
|
96
|
+
dirs: [".github/prompts"],
|
|
97
|
+
files: [
|
|
98
|
+
{ src: "copilot-prompts/bootstrap.prompt.md", dest: ".github/prompts/bootstrap.prompt.md" },
|
|
99
|
+
{ src: "copilot-prompts/ask.prompt.md", dest: ".github/prompts/ask.prompt.md" },
|
|
100
|
+
{ src: "copilot-prompts/assume.prompt.md", dest: ".github/prompts/assume.prompt.md" },
|
|
101
|
+
{ src: "copilot-prompts/bugfix.prompt.md", dest: ".github/prompts/bugfix.prompt.md" },
|
|
102
|
+
{ src: "copilot-prompts/refactor.prompt.md", dest: ".github/prompts/refactor.prompt.md" },
|
|
103
|
+
{ src: "copilot-prompts/spec-new.prompt.md", dest: ".github/prompts/spec-new.prompt.md" },
|
|
104
|
+
{ src: "copilot-prompts/spec-plan.prompt.md", dest: ".github/prompts/spec-plan.prompt.md" },
|
|
105
|
+
{ src: "copilot-prompts/spec-tasks.prompt.md", dest: ".github/prompts/spec-tasks.prompt.md" },
|
|
106
|
+
{ src: "copilot-prompts/review.prompt.md", dest: ".github/prompts/review.prompt.md" },
|
|
107
|
+
{ src: "copilot-prompts/finish.prompt.md", dest: ".github/prompts/finish.prompt.md" },
|
|
108
|
+
{ src: "copilot-instructions.md", dest: ".github/copilot-instructions.md" }
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
var ALL_PROVIDER_IDS = Object.keys(PROVIDERS);
|
|
113
|
+
async function selectProviders() {
|
|
114
|
+
if (!process.stdout.isTTY) {
|
|
115
|
+
return ALL_PROVIDER_IDS;
|
|
116
|
+
}
|
|
117
|
+
const selected = await (0, import_prompts.checkbox)({
|
|
118
|
+
message: "Select the AI providers to install:",
|
|
119
|
+
choices: ALL_PROVIDER_IDS.map((id) => ({
|
|
120
|
+
name: PROVIDERS[id].name,
|
|
121
|
+
value: id,
|
|
122
|
+
checked: true
|
|
123
|
+
})),
|
|
124
|
+
required: true
|
|
125
|
+
});
|
|
126
|
+
return selected;
|
|
127
|
+
}
|
|
128
|
+
async function initCommand(options) {
|
|
129
|
+
const cwd = process.cwd();
|
|
130
|
+
const { force } = options;
|
|
131
|
+
console.log("");
|
|
132
|
+
console.log(" SDD Workflow \u2014 initializing");
|
|
133
|
+
console.log("");
|
|
134
|
+
const selectedProviders = await selectProviders();
|
|
135
|
+
console.log("");
|
|
136
|
+
ensureDir(import_path2.default.join(cwd, ".sdd/domains"));
|
|
137
|
+
ensureDir(import_path2.default.join(cwd, "specs/_template"));
|
|
138
|
+
for (const id of selectedProviders) {
|
|
139
|
+
for (const dir of PROVIDERS[id].dirs) {
|
|
140
|
+
ensureDir(import_path2.default.join(cwd, dir));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const claudeExisted = import_fs2.default.existsSync(import_path2.default.join(cwd, "CLAUDE.md"));
|
|
144
|
+
for (const file of CORE_FILES) {
|
|
145
|
+
copyTemplate(file.src, import_path2.default.join(cwd, file.dest), force);
|
|
146
|
+
}
|
|
147
|
+
for (const id of selectedProviders) {
|
|
148
|
+
for (const file of PROVIDERS[id].files) {
|
|
149
|
+
copyTemplate(file.src, import_path2.default.join(cwd, file.dest), force);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const providerNames = selectedProviders.map((id) => PROVIDERS[id].name).join(", ");
|
|
153
|
+
console.log("");
|
|
154
|
+
console.log(" Done. Next steps:");
|
|
155
|
+
console.log("");
|
|
156
|
+
console.log(" 1. Run /bootstrap to populate project context (new project)");
|
|
157
|
+
console.log(" or /bootstrap --scan to let the agent analyze the codebase (existing project)");
|
|
158
|
+
if (!claudeExisted) {
|
|
159
|
+
console.log(" 2. CLAUDE.md was created \u2014 share it with your AI agent as context");
|
|
160
|
+
} else {
|
|
161
|
+
console.log(" 2. CLAUDE.md already exists \u2014 add a reference to .sdd/ files manually");
|
|
162
|
+
}
|
|
163
|
+
console.log(` 3. Slash commands are ready in: ${providerNames}. Type / to see them.
|
|
164
|
+
`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// src/commands/add.ts
|
|
168
|
+
var import_path3 = __toESM(require("path"));
|
|
169
|
+
var import_fs3 = __toESM(require("fs"));
|
|
170
|
+
var DOMAIN_MAP = {
|
|
171
|
+
auth: "domains/auth.md",
|
|
172
|
+
payments: "domains/payments.md",
|
|
173
|
+
storage: "domains/storage.md",
|
|
174
|
+
email: "domains/email.md"
|
|
175
|
+
};
|
|
176
|
+
function addCommand(type, name) {
|
|
177
|
+
const cwd = process.cwd();
|
|
178
|
+
if (type !== "domain") {
|
|
179
|
+
console.error(` error Unknown type "${type}". Available: domain`);
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
const templateSrc = DOMAIN_MAP[name];
|
|
183
|
+
if (!templateSrc) {
|
|
184
|
+
const available = Object.keys(DOMAIN_MAP).join(", ");
|
|
185
|
+
console.error(` error Unknown domain "${name}". Available: ${available}`);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
if (!import_fs3.default.existsSync(import_path3.default.join(cwd, ".sdd"))) {
|
|
189
|
+
console.error(" error .sdd/ not found. Run `npx sddx-workflow init` first.");
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
console.log("");
|
|
193
|
+
copyTemplate(templateSrc, import_path3.default.join(cwd, `.sdd/domains/${name}.md`));
|
|
194
|
+
console.log("");
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// src/commands/update.ts
|
|
198
|
+
var import_fs4 = __toESM(require("fs"));
|
|
199
|
+
var import_path4 = __toESM(require("path"));
|
|
200
|
+
var WORKFLOW_FILES = [
|
|
201
|
+
{ src: "workflow.md", dest: ".sdd/workflow.md" },
|
|
202
|
+
{ src: "claude-commands/bootstrap.md", dest: ".claude/commands/bootstrap.md" },
|
|
203
|
+
{ src: "claude-commands/ask.md", dest: ".claude/commands/ask.md" },
|
|
204
|
+
{ src: "claude-commands/assume.md", dest: ".claude/commands/assume.md" },
|
|
205
|
+
{ src: "claude-commands/bugfix.md", dest: ".claude/commands/bugfix.md" },
|
|
206
|
+
{ src: "claude-commands/refactor.md", dest: ".claude/commands/refactor.md" },
|
|
207
|
+
{ src: "claude-commands/spec-new.md", dest: ".claude/commands/spec-new.md" },
|
|
208
|
+
{ src: "claude-commands/spec-plan.md", dest: ".claude/commands/spec-plan.md" },
|
|
209
|
+
{ src: "claude-commands/spec-tasks.md", dest: ".claude/commands/spec-tasks.md" },
|
|
210
|
+
{ src: "claude-commands/review.md", dest: ".claude/commands/review.md" },
|
|
211
|
+
{ src: "claude-commands/finish.md", dest: ".claude/commands/finish.md" },
|
|
212
|
+
{ src: "cursor-rules/sddx-workflow.mdc", dest: ".cursor/rules/sddx-workflow.mdc" },
|
|
213
|
+
{ src: "windsurf-rules/sddx-workflow.md", dest: ".windsurf/rules/sddx-workflow.md" },
|
|
214
|
+
{ src: "copilot-prompts/bootstrap.prompt.md", dest: ".github/prompts/bootstrap.prompt.md" },
|
|
215
|
+
{ src: "copilot-prompts/ask.prompt.md", dest: ".github/prompts/ask.prompt.md" },
|
|
216
|
+
{ src: "copilot-prompts/assume.prompt.md", dest: ".github/prompts/assume.prompt.md" },
|
|
217
|
+
{ src: "copilot-prompts/bugfix.prompt.md", dest: ".github/prompts/bugfix.prompt.md" },
|
|
218
|
+
{ src: "copilot-prompts/refactor.prompt.md", dest: ".github/prompts/refactor.prompt.md" },
|
|
219
|
+
{ src: "copilot-prompts/spec-new.prompt.md", dest: ".github/prompts/spec-new.prompt.md" },
|
|
220
|
+
{ src: "copilot-prompts/spec-plan.prompt.md", dest: ".github/prompts/spec-plan.prompt.md" },
|
|
221
|
+
{ src: "copilot-prompts/spec-tasks.prompt.md", dest: ".github/prompts/spec-tasks.prompt.md" },
|
|
222
|
+
{ src: "copilot-prompts/review.prompt.md", dest: ".github/prompts/review.prompt.md" },
|
|
223
|
+
{ src: "copilot-prompts/finish.prompt.md", dest: ".github/prompts/finish.prompt.md" },
|
|
224
|
+
{ src: "copilot-instructions.md", dest: ".github/copilot-instructions.md" }
|
|
225
|
+
];
|
|
226
|
+
function updateCommand() {
|
|
227
|
+
const cwd = process.cwd();
|
|
228
|
+
if (!import_fs4.default.existsSync(import_path4.default.join(cwd, ".sdd"))) {
|
|
229
|
+
console.error("\n error .sdd/ not found. Run `npx sddx-workflow init` first.\n");
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
console.log("");
|
|
233
|
+
console.log(" SDD Workflow \u2014 updating workflow files");
|
|
234
|
+
console.log(" (project-overview.md, conventions.md, CLAUDE.md, and domains are yours \u2014 untouched)");
|
|
235
|
+
console.log("");
|
|
236
|
+
let updated = 0;
|
|
237
|
+
for (const file of WORKFLOW_FILES) {
|
|
238
|
+
const dest = import_path4.default.join(cwd, file.dest);
|
|
239
|
+
if (!import_fs4.default.existsSync(dest)) continue;
|
|
240
|
+
copyTemplate(file.src, dest, true);
|
|
241
|
+
updated++;
|
|
242
|
+
}
|
|
243
|
+
console.log("");
|
|
244
|
+
console.log(` Done. ${updated} file${updated !== 1 ? "s" : ""} updated.
|
|
245
|
+
`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// src/commands/status.ts
|
|
249
|
+
var import_fs5 = __toESM(require("fs"));
|
|
250
|
+
var import_path5 = __toESM(require("path"));
|
|
251
|
+
function isBootstrapped(cwd) {
|
|
252
|
+
const file = import_path5.default.join(cwd, ".sdd/project-overview.md");
|
|
253
|
+
if (!import_fs5.default.existsSync(file)) return false;
|
|
254
|
+
const lines = import_fs5.default.readFileSync(file, "utf8").split("\n");
|
|
255
|
+
return lines.some((line) => {
|
|
256
|
+
const t = line.trim();
|
|
257
|
+
return t.length > 0 && !t.startsWith("#") && !t.startsWith("<!--") && !t.startsWith("-->");
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
function readSpec(specDir) {
|
|
261
|
+
const name = import_path5.default.basename(specDir);
|
|
262
|
+
const tasksFile = import_path5.default.join(specDir, "3-tasks.md");
|
|
263
|
+
if (!import_fs5.default.existsSync(tasksFile)) {
|
|
264
|
+
return { name, planApproved: false, tasksDone: 0, tasksTotal: 0 };
|
|
265
|
+
}
|
|
266
|
+
const content = import_fs5.default.readFileSync(tasksFile, "utf8");
|
|
267
|
+
const planApproved = !content.includes("<!-- date -->");
|
|
268
|
+
const tasksDone = (content.match(/^- \[x\]/gim) ?? []).length;
|
|
269
|
+
const tasksPending = (content.match(/^- \[ \]/gim) ?? []).length;
|
|
270
|
+
return { name, planApproved, tasksDone, tasksTotal: tasksDone + tasksPending };
|
|
271
|
+
}
|
|
272
|
+
function statusCommand() {
|
|
273
|
+
const cwd = process.cwd();
|
|
274
|
+
if (!import_fs5.default.existsSync(import_path5.default.join(cwd, ".sdd"))) {
|
|
275
|
+
console.error("\n error .sdd/ not found. Run `npx sddx-workflow init` first.\n");
|
|
276
|
+
process.exit(1);
|
|
277
|
+
}
|
|
278
|
+
console.log("");
|
|
279
|
+
const bootstrapped = isBootstrapped(cwd);
|
|
280
|
+
console.log(` bootstrap ${bootstrapped ? "done" : "pending \u2014 run /bootstrap"}`);
|
|
281
|
+
const specsDir = import_path5.default.join(cwd, "specs");
|
|
282
|
+
if (!import_fs5.default.existsSync(specsDir)) {
|
|
283
|
+
console.log(" open specs 0");
|
|
284
|
+
console.log("");
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const specs = import_fs5.default.readdirSync(specsDir).filter((name) => name !== "_template" && name !== "_done").filter((name) => import_fs5.default.statSync(import_path5.default.join(specsDir, name)).isDirectory()).map((name) => readSpec(import_path5.default.join(specsDir, name)));
|
|
288
|
+
console.log(` open specs ${specs.length}`);
|
|
289
|
+
for (const spec of specs) {
|
|
290
|
+
const label = spec.name.padEnd(14);
|
|
291
|
+
if (!spec.planApproved) {
|
|
292
|
+
console.log(` ${label} awaiting approval`);
|
|
293
|
+
} else if (spec.tasksDone === spec.tasksTotal && spec.tasksTotal > 0) {
|
|
294
|
+
console.log(` ${label} ${spec.tasksDone}/${spec.tasksTotal} tasks \xB7 done`);
|
|
295
|
+
} else {
|
|
296
|
+
console.log(` ${label} ${spec.tasksDone}/${spec.tasksTotal} tasks \xB7 in progress`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
console.log("");
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// src/cli.ts
|
|
303
|
+
var import_module = require("module");
|
|
304
|
+
var pkg = (0, import_module.createRequire)(__filename)("../package.json");
|
|
305
|
+
var program = new import_commander.Command();
|
|
306
|
+
program.name("sddx-workflow").description("Spec-Driven Development CLI").version(pkg.version);
|
|
307
|
+
program.command("init").description("Initialize SDD protocol in the current project").option("--force", "Overwrite files that already exist").action(initCommand);
|
|
308
|
+
program.command("add <type> <name>").description("Add an SDD component to an existing installation").addHelpText("after", "\nExamples:\n $ sddx-workflow add domain auth\n $ sddx-workflow add domain payments").action(addCommand);
|
|
309
|
+
program.command("update").description("Update protocol files to the latest version (leaves your config files untouched)").action(updateCommand);
|
|
310
|
+
program.command("status").description("Show bootstrap status and open specs progress").action(statusCommand);
|
|
311
|
+
program.parseAsync();
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sddx-workflow",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Spec-Driven Development CLI — installs an SDD system in any project",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"sdd",
|
|
7
|
+
"spec-driven",
|
|
8
|
+
"ai",
|
|
9
|
+
"claude",
|
|
10
|
+
"cursor",
|
|
11
|
+
"cli"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/MarcosCamara01/sddx-workflow.git"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://github.com/MarcosCamara01/sddx-workflow#readme",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/MarcosCamara01/sddx-workflow/issues"
|
|
21
|
+
},
|
|
22
|
+
"bin": {
|
|
23
|
+
"sddx-workflow": "dist/cli.js"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist/",
|
|
27
|
+
"templates/"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsup && chmod +x dist/cli.js",
|
|
31
|
+
"dev": "tsup --watch",
|
|
32
|
+
"prepublishOnly": "npm run build"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@inquirer/prompts": "^8.4.2",
|
|
36
|
+
"commander": "^12.1.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^22.0.0",
|
|
40
|
+
"tsup": "^8.3.0",
|
|
41
|
+
"typescript": "^5.6.0"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Claude — Project Context
|
|
2
|
+
|
|
3
|
+
This project uses the SDD Protocol. Read these files before starting any task:
|
|
4
|
+
|
|
5
|
+
1. **[.sdd/workflow.md](.sdd/workflow.md)** — commands, ceremony levels, and stop points
|
|
6
|
+
2. **[.sdd/project-overview.md](.sdd/project-overview.md)** — what this app is, its non-goals, domains, and definition of done
|
|
7
|
+
3. **[.sdd/conventions.md](.sdd/conventions.md)** — project-specific conventions and patterns
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
| Intent | Command |
|
|
12
|
+
|---|---|
|
|
13
|
+
| Initialize project context | `/bootstrap` (new) · `/bootstrap --scan` (existing) |
|
|
14
|
+
| Explore / research | `/ask` |
|
|
15
|
+
| Surface and validate assumptions | `/assume` |
|
|
16
|
+
| Fix a confirmed bug | `/bugfix` → `/finish` |
|
|
17
|
+
| Restructure without behavior change | `/refactor` → `/finish` |
|
|
18
|
+
| New feature | `/spec-new` → `/spec-plan` → `/spec-tasks` → `/review` → `/finish` |
|
|
19
|
+
| Stage + commit after any work | `/finish` |
|
|
20
|
+
|
|
21
|
+
## Active Specs
|
|
22
|
+
|
|
23
|
+
<!-- List specs currently in progress — completed specs live in specs/_done/ and are not active context.
|
|
24
|
+
- specs/auth-refresh/ — in /spec-tasks (task 3 of 5)
|
|
25
|
+
- specs/payments-v2/ — plan pending approval
|
|
26
|
+
-->
|
|
27
|
+
|
|
28
|
+
## Domain Files
|
|
29
|
+
|
|
30
|
+
Relevant domain context lives in `.sdd/domains/`. Read the relevant domain file before working in that area.
|
|
31
|
+
|
|
32
|
+
<!-- List domains present in this project, e.g.:
|
|
33
|
+
- [.sdd/domains/auth.md](.sdd/domains/auth.md)
|
|
34
|
+
- [.sdd/domains/payments.md](.sdd/domains/payments.md)
|
|
35
|
+
-->
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Execute the /assume command defined in .sdd/workflow.md.
|
|
2
|
+
|
|
3
|
+
List every assumption being made about the task, codebase state, and technical decisions.
|
|
4
|
+
For each: what you're assuming, why, and what changes if it's wrong.
|
|
5
|
+
Stop and wait for confirmation before proceeding.
|
|
6
|
+
|
|
7
|
+
Context: $ARGUMENTS
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Execute the /bootstrap command defined in .sdd/workflow.md.
|
|
2
|
+
|
|
3
|
+
Populate .sdd/project-overview.md and .sdd/conventions.md with real project context.
|
|
4
|
+
If $ARGUMENTS contains --scan, analyze the existing codebase first before asking questions.
|
|
5
|
+
Present the full draft for approval before writing any file.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Execute the /finish command defined in .sdd/workflow.md.
|
|
2
|
+
|
|
3
|
+
Run git status and git diff. Stage all relevant files. Determine the commit type.
|
|
4
|
+
Draft a conventional commit message following the format in workflow.md.
|
|
5
|
+
Stop and present the staged files and commit message for approval before committing.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Execute the /review command defined in .sdd/workflow.md.
|
|
2
|
+
|
|
3
|
+
Audit the spec before closing. Verify all goals (G1, G2…) are satisfied, every acceptance scenario has a passing test, no out-of-scope changes were introduced, and the implementation is the simplest that meets requirements.
|
|
4
|
+
|
|
5
|
+
Spec: $ARGUMENTS
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Execute the /spec-tasks command defined in .sdd/workflow.md.
|
|
2
|
+
|
|
3
|
+
Read the approved specs/$ARGUMENTS/2-plan.md and execute tasks one at a time.
|
|
4
|
+
Write the test first (red), implement until green, run the full suite, then move to the next task.
|
|
5
|
+
Stop if tests fail or if a task reveals new scope.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Project Conventions
|
|
2
|
+
|
|
3
|
+
> Fill this out before starting any non-trivial work.
|
|
4
|
+
> The AI agent reads this file before implementing anything.
|
|
5
|
+
|
|
6
|
+
## Tech Stack
|
|
7
|
+
|
|
8
|
+
<!-- Primary technologies, frameworks, libraries, and their versions -->
|
|
9
|
+
|
|
10
|
+
## File & Folder Structure
|
|
11
|
+
|
|
12
|
+
<!-- How the project is organized. Point out anything non-obvious. -->
|
|
13
|
+
|
|
14
|
+
## Naming Conventions
|
|
15
|
+
|
|
16
|
+
<!-- Files, functions, variables, types — rules and examples -->
|
|
17
|
+
|
|
18
|
+
## Code Style
|
|
19
|
+
|
|
20
|
+
<!-- Patterns to follow, abstractions in use, preferred approaches -->
|
|
21
|
+
|
|
22
|
+
## Patterns to Avoid
|
|
23
|
+
|
|
24
|
+
<!-- Anti-patterns, deprecated approaches, things that have caused bugs before -->
|
|
25
|
+
|
|
26
|
+
## Testing
|
|
27
|
+
|
|
28
|
+
<!-- How tests are structured, what needs to be tested, coverage expectations -->
|
|
29
|
+
|
|
30
|
+
## Domain Glossary
|
|
31
|
+
|
|
32
|
+
<!-- Key terms in this project and what they mean precisely -->
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# GitHub Copilot Instructions
|
|
2
|
+
|
|
3
|
+
This project uses the SDD Protocol. Before starting any task, read:
|
|
4
|
+
|
|
5
|
+
1. `.sdd/workflow.md` — all commands, ceremony levels, and stop points
|
|
6
|
+
2. `.sdd/project-overview.md` — what this app is, its non-goals, and domains
|
|
7
|
+
3. `.sdd/conventions.md` — project-specific conventions and patterns
|
|
8
|
+
|
|
9
|
+
## Available commands
|
|
10
|
+
|
|
11
|
+
Use these slash commands in Copilot Chat (type `/` to see them):
|
|
12
|
+
|
|
13
|
+
| Command | Purpose |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `/bootstrap` | Populate project context — interview or codebase scan |
|
|
16
|
+
| `/ask` | Research only — no code changes |
|
|
17
|
+
| `/assume` | List assumptions and stop for confirmation |
|
|
18
|
+
| `/bugfix` | Reproduce → diagnose → fix → validate |
|
|
19
|
+
| `/refactor` | Restructure without behavior change |
|
|
20
|
+
| `/spec-new` | Scaffold a spec folder |
|
|
21
|
+
| `/spec-plan` | Generate technical plan — stop for approval |
|
|
22
|
+
| `/spec-tasks` | Execute plan one task at a time, TDD-first |
|
|
23
|
+
| `/review` | Final audit before closing |
|
|
24
|
+
| `/finish` | Stage files and generate commit message |
|
|
25
|
+
|
|
26
|
+
## Execution principles
|
|
27
|
+
|
|
28
|
+
1. Surface assumptions before acting — never pick an interpretation silently; if a simpler approach exists, say so and push back
|
|
29
|
+
2. Minimum code — only what was asked; no speculative flexibility, no error handling for impossible scenarios; ask "would a senior engineer say this is overcomplicated?"
|
|
30
|
+
3. Surgical changes — touch only what the task requires; match existing style; remove only orphans *your* changes created, not pre-existing dead code; every changed line must trace to the request
|
|
31
|
+
4. Verify before moving on — transform vague tasks into verifiable goals ("Fix bug" → "Write failing test, then make it pass"); define "done" before starting
|
|
32
|
+
|
|
33
|
+
Full definitions for each command are in `.sdd/workflow.md`.
|