sdd-pipeline 1.2.4 → 1.2.7
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/bin/sdd.cjs +201 -0
- package/lib/bmad/index.js +20 -3
- package/lib/bundle/.claude/commands/sdd-check.md +153 -0
- package/lib/bundle/.claude/commands/sdd-cook.md +149 -167
- package/lib/bundle/.claude/commands/sdd-task-status.md +97 -27
- package/lib/bundle/bin/sdd.cjs +201 -0
- package/lib/bundle/bin/sdd.js +159 -0
- package/lib/bundle/commands/sdd-task-status.ps1 +82 -22
- package/lib/bundle/lib/bmad/confidence.js +129 -0
- package/lib/bundle/lib/bmad/index.js +157 -0
- package/lib/bundle/lib/bmad/problem-first.js +91 -0
- package/lib/bundle/lib/bmad/questions.js +110 -0
- package/lib/bundle/lib/bmad/synthesis.js +109 -0
- package/lib/bundle/lib/config.js +35 -0
- package/lib/bundle/lib/init.js +204 -0
- package/lib/bundle/lib/sanitize.js +10 -0
- package/lib/bundle/run-converge.ps1 +288 -42
- package/lib/bundle/skills/sdd-tasks/SKILL.md +259 -0
- package/lib/init.js +108 -32
- package/package.json +8 -8
- package/bin/sdd.js +0 -70
- package/lib/bmad.js +0 -54
package/lib/init.js
CHANGED
|
@@ -3,6 +3,19 @@ const fs = require('fs')
|
|
|
3
3
|
|
|
4
4
|
const BUNDLE_DIR = path.join(__dirname, 'bundle')
|
|
5
5
|
|
|
6
|
+
// All command files to copy
|
|
7
|
+
const CMD_FILES = [
|
|
8
|
+
'sdd.md', // Unified entry point
|
|
9
|
+
'sdd-bmad.md', // Phase 0: BMAD
|
|
10
|
+
'sdd-spec.md', // Phase 2: SPEC
|
|
11
|
+
'sdd-tasks.md', // Phase 3: TASKS
|
|
12
|
+
'sdd-cook.md', // Phase 4: COOK + Implement (unified)
|
|
13
|
+
'sdd-converge.md', // Phase 5: CONVERGE
|
|
14
|
+
'sdd-check.md', // Real-time validation
|
|
15
|
+
'sdd-task-status.md', // Task status update
|
|
16
|
+
'sdd-init.md' // Initialization
|
|
17
|
+
]
|
|
18
|
+
|
|
6
19
|
const FILES = [
|
|
7
20
|
'.sdd/config.json',
|
|
8
21
|
'.sdd/smoke-test.ps1',
|
|
@@ -20,7 +33,7 @@ const FILES = [
|
|
|
20
33
|
'run-converge.ps1',
|
|
21
34
|
]
|
|
22
35
|
|
|
23
|
-
const DIRS = ['.sdd', 'templates', 'converge', 'commands', 'extensions']
|
|
36
|
+
const DIRS = ['.sdd', 'templates', 'converge', 'commands', 'extensions', 'sdd', 'skills']
|
|
24
37
|
|
|
25
38
|
function ensureDir(dir) {
|
|
26
39
|
if (!fs.existsSync(dir)) {
|
|
@@ -32,11 +45,35 @@ function copyFile(src, dest) {
|
|
|
32
45
|
ensureDir(path.dirname(dest))
|
|
33
46
|
if (fs.existsSync(dest)) {
|
|
34
47
|
console.log(` [SKIP] ${dest} already exists`)
|
|
48
|
+
return false
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const content = fs.readFileSync(src, 'utf8')
|
|
52
|
+
fs.writeFileSync(dest, content, 'utf8')
|
|
53
|
+
console.log(` [COPY] ${dest}`)
|
|
54
|
+
return true
|
|
55
|
+
} catch (err) {
|
|
56
|
+
console.log(` [WARN] Failed to copy ${src}: ${err.message}`)
|
|
57
|
+
return false
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function copyDirRecursive(src, dest) {
|
|
62
|
+
ensureDir(dest)
|
|
63
|
+
if (!fs.existsSync(src)) {
|
|
64
|
+
console.log(` [WARN] Source directory not found: ${src}`)
|
|
35
65
|
return
|
|
36
66
|
}
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
67
|
+
const entries = fs.readdirSync(src, { withFileTypes: true })
|
|
68
|
+
for (const entry of entries) {
|
|
69
|
+
const srcPath = path.join(src, entry.name)
|
|
70
|
+
const destPath = path.join(dest, entry.name)
|
|
71
|
+
if (entry.isDirectory()) {
|
|
72
|
+
copyDirRecursive(srcPath, destPath)
|
|
73
|
+
} else {
|
|
74
|
+
copyFile(srcPath, destPath)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
40
77
|
}
|
|
41
78
|
|
|
42
79
|
function run() {
|
|
@@ -45,13 +82,17 @@ function run() {
|
|
|
45
82
|
|
|
46
83
|
if (!fs.existsSync(BUNDLE_DIR)) {
|
|
47
84
|
console.error('ERROR: Bundle directory not found. Is the package installed correctly?')
|
|
85
|
+
console.error('Try: npm install -g sdd-pipeline')
|
|
48
86
|
process.exit(1)
|
|
49
87
|
}
|
|
50
88
|
|
|
89
|
+
// Ensure output directories exist
|
|
51
90
|
for (const dir of DIRS) {
|
|
52
91
|
ensureDir(dir)
|
|
53
92
|
}
|
|
54
93
|
|
|
94
|
+
// Copy config files
|
|
95
|
+
console.log('Copying config files...')
|
|
55
96
|
for (const file of FILES) {
|
|
56
97
|
const src = path.join(BUNDLE_DIR, file)
|
|
57
98
|
const dest = path.join(process.cwd(), file)
|
|
@@ -62,18 +103,37 @@ function run() {
|
|
|
62
103
|
}
|
|
63
104
|
}
|
|
64
105
|
|
|
65
|
-
//
|
|
106
|
+
// Copy Claude Code commands
|
|
107
|
+
console.log('')
|
|
108
|
+
console.log('Copying Claude Code commands...')
|
|
66
109
|
ensureDir('.claude/commands')
|
|
67
|
-
|
|
68
|
-
for (const cmd of
|
|
110
|
+
let cmdCopied = 0
|
|
111
|
+
for (const cmd of CMD_FILES) {
|
|
69
112
|
const src = path.join(BUNDLE_DIR, '.claude/commands', cmd)
|
|
70
113
|
const dest = path.join(process.cwd(), '.claude/commands', cmd)
|
|
71
114
|
if (fs.existsSync(src)) {
|
|
72
|
-
copyFile(src, dest)
|
|
115
|
+
if (copyFile(src, dest)) {
|
|
116
|
+
cmdCopied++
|
|
117
|
+
}
|
|
118
|
+
} else {
|
|
119
|
+
// Try alternative path for npm package
|
|
120
|
+
const altSrc = path.join(BUNDLE_DIR, '.claude', 'commands', cmd)
|
|
121
|
+
if (fs.existsSync(altSrc)) {
|
|
122
|
+
if (copyFile(altSrc, dest)) {
|
|
123
|
+
cmdCopied++
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
console.log(` [WARN] Command not found: ${cmd}`)
|
|
127
|
+
}
|
|
73
128
|
}
|
|
74
129
|
}
|
|
130
|
+
if (cmdCopied === 0) {
|
|
131
|
+
console.log(' [INFO] No new commands copied (all exist)')
|
|
132
|
+
}
|
|
75
133
|
|
|
76
|
-
//
|
|
134
|
+
// Copy GitHub workflows
|
|
135
|
+
console.log('')
|
|
136
|
+
console.log('Copying GitHub workflows...')
|
|
77
137
|
ensureDir('.github/workflows')
|
|
78
138
|
const workflowSrc = path.join(BUNDLE_DIR, '.github/workflows/converge.yml')
|
|
79
139
|
const workflowDest = path.join(process.cwd(), '.github/workflows/converge.yml')
|
|
@@ -81,15 +141,24 @@ function run() {
|
|
|
81
141
|
copyFile(workflowSrc, workflowDest)
|
|
82
142
|
}
|
|
83
143
|
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
if (fs.existsSync(
|
|
89
|
-
|
|
144
|
+
// Copy commands directory
|
|
145
|
+
console.log('')
|
|
146
|
+
console.log('Copying standalone commands...')
|
|
147
|
+
const commandsDir = path.join(BUNDLE_DIR, 'commands')
|
|
148
|
+
if (fs.existsSync(commandsDir)) {
|
|
149
|
+
const entries = fs.readdirSync(commandsDir, { withFileTypes: true })
|
|
150
|
+
for (const entry of entries) {
|
|
151
|
+
if (entry.isFile()) {
|
|
152
|
+
const src = path.join(commandsDir, entry.name)
|
|
153
|
+
const dest = path.join(process.cwd(), 'commands', entry.name)
|
|
154
|
+
copyFile(src, dest)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
90
157
|
}
|
|
91
158
|
|
|
92
|
-
//
|
|
159
|
+
// Copy extensions
|
|
160
|
+
console.log('')
|
|
161
|
+
console.log('Copying extensions...')
|
|
93
162
|
for (const ext of ['sdd-api', 'sdd-frontend', 'sdd-backend']) {
|
|
94
163
|
const extDir = path.join(BUNDLE_DIR, 'extensions', ext)
|
|
95
164
|
if (fs.existsSync(extDir)) {
|
|
@@ -104,25 +173,32 @@ function run() {
|
|
|
104
173
|
copyFile(extReadmeSrc, extReadmeDest)
|
|
105
174
|
}
|
|
106
175
|
|
|
176
|
+
// Copy skills directory (for Phase 4 implementation)
|
|
177
|
+
console.log('')
|
|
178
|
+
console.log('Copying skills...')
|
|
179
|
+
const skillsDir = path.join(BUNDLE_DIR, 'skills')
|
|
180
|
+
if (fs.existsSync(skillsDir)) {
|
|
181
|
+
copyDirRecursive(skillsDir, path.join(process.cwd(), 'skills'))
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Create sdd/ directory structure if not exists
|
|
185
|
+
ensureDir('sdd/tasks')
|
|
186
|
+
ensureDir('sdd/converge')
|
|
187
|
+
|
|
107
188
|
console.log('')
|
|
108
189
|
console.log('[OK] SDD pipeline initialized.')
|
|
109
190
|
console.log('')
|
|
110
|
-
console.log('
|
|
111
|
-
console.log('
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
copyDirRecursive(srcPath, destPath)
|
|
122
|
-
} else {
|
|
123
|
-
copyFile(srcPath, destPath)
|
|
124
|
-
}
|
|
125
|
-
}
|
|
191
|
+
console.log('Directory structure:')
|
|
192
|
+
console.log(' skills/ # Implementation skills (Phase 4)')
|
|
193
|
+
console.log(' .claude/commands/ # Claude Code commands')
|
|
194
|
+
console.log(' sdd/ # Generated artifacts')
|
|
195
|
+
console.log('')
|
|
196
|
+
console.log('Next steps:')
|
|
197
|
+
console.log(' 1. claude "/sdd-bmad <your feature idea>" # Interactive (recommended)')
|
|
198
|
+
console.log(' 2. sdd bmad "<idea>" # Fast mode (lower confidence)')
|
|
199
|
+
console.log('')
|
|
200
|
+
console.log('For best results, install Claude Code:')
|
|
201
|
+
console.log(' npm install -g @anthropic-ai/claude-code')
|
|
126
202
|
}
|
|
127
203
|
|
|
128
204
|
module.exports = { run }
|
package/package.json
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sdd-pipeline",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.7",
|
|
4
4
|
"description": "Spec-Driven Development pipeline for Claude Code CLI — transforms raw feature requests into validated, shipped code through a self-correcting converge loop",
|
|
5
|
+
"type": "commonjs",
|
|
5
6
|
"bin": {
|
|
6
|
-
"sdd": "bin/sdd.
|
|
7
|
+
"sdd": "bin/sdd.cjs"
|
|
7
8
|
},
|
|
8
9
|
"files": [
|
|
9
10
|
"bin/",
|
|
10
|
-
"lib/
|
|
11
|
-
"lib/config.js",
|
|
12
|
-
"lib/init.js",
|
|
13
|
-
"lib/sanitize.js",
|
|
14
|
-
"lib/bmad/",
|
|
11
|
+
"lib/",
|
|
15
12
|
"lib/bundle/"
|
|
16
13
|
],
|
|
17
14
|
"engines": {
|
|
@@ -26,5 +23,8 @@
|
|
|
26
23
|
"specification",
|
|
27
24
|
"development"
|
|
28
25
|
],
|
|
29
|
-
"license": "MIT"
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"scripts": {
|
|
28
|
+
"test": "node test/run.js"
|
|
29
|
+
}
|
|
30
30
|
}
|
package/bin/sdd.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// sdd — Spec-Driven Development CLI
|
|
3
|
-
|
|
4
|
-
const path = require('path')
|
|
5
|
-
const fs = require('fs')
|
|
6
|
-
const init = require('../lib/init')
|
|
7
|
-
const bmad = require('../lib/bmad/index')
|
|
8
|
-
const config = require('../lib/config')
|
|
9
|
-
|
|
10
|
-
const args = process.argv.slice(2)
|
|
11
|
-
const cmd = args[0]
|
|
12
|
-
|
|
13
|
-
switch (cmd) {
|
|
14
|
-
case 'init':
|
|
15
|
-
init.run()
|
|
16
|
-
break
|
|
17
|
-
case 'bmad':
|
|
18
|
-
// Non-interactive mode: run BMAD with just the feature description
|
|
19
|
-
const input = args.slice(1).join(' ')
|
|
20
|
-
if (!input) {
|
|
21
|
-
console.error('Usage: sdd bmad <feature description>')
|
|
22
|
-
process.exit(1)
|
|
23
|
-
}
|
|
24
|
-
// Initialize BMAD session
|
|
25
|
-
const session = bmad.init(input)
|
|
26
|
-
// Generate brief with minimal answers
|
|
27
|
-
const result = bmad.generateBrief()
|
|
28
|
-
console.log(`[OK] BMAD-brief.md created.`)
|
|
29
|
-
console.log(`Confidence: ${result.confidence.score}/100 — ${result.confidence.level}`)
|
|
30
|
-
break
|
|
31
|
-
case 'spec':
|
|
32
|
-
console.log('Run: claude "/sdd-spec" to generate SPEC.md')
|
|
33
|
-
break
|
|
34
|
-
case 'tasks':
|
|
35
|
-
console.log('Run: claude "/sdd-tasks" to generate TASKS.md')
|
|
36
|
-
break
|
|
37
|
-
case 'converge':
|
|
38
|
-
console.log('Run: pwsh run-converge.ps1 -Strict to run converge')
|
|
39
|
-
break
|
|
40
|
-
case 'status':
|
|
41
|
-
config.printStatus()
|
|
42
|
-
break
|
|
43
|
-
case 'help':
|
|
44
|
-
default:
|
|
45
|
-
if (cmd && cmd !== 'help') {
|
|
46
|
-
console.error(`Unknown command: ${cmd}\n`)
|
|
47
|
-
}
|
|
48
|
-
console.log(`
|
|
49
|
-
sdd — Spec-Driven Development CLI
|
|
50
|
-
|
|
51
|
-
Output Structure:
|
|
52
|
-
sdd/ # All generated artifacts
|
|
53
|
-
brief.md # Phase 0: BMAD brief
|
|
54
|
-
SPEC.md # Phase 2: Specification
|
|
55
|
-
tasks/ # Phase 3: Task directories
|
|
56
|
-
converge/ # Phase 5: Validation reports
|
|
57
|
-
|
|
58
|
-
Usage:
|
|
59
|
-
sdd init Initialize SDD pipeline
|
|
60
|
-
sdd bmad <desc> Phase 0: Interactive brainstorm
|
|
61
|
-
sdd status Show pipeline status
|
|
62
|
-
sdd help Show this help
|
|
63
|
-
|
|
64
|
-
Full pipeline (requires Claude Code):
|
|
65
|
-
claude "/sdd-spec" Phase 2: Generate SPEC.md
|
|
66
|
-
claude "/sdd-tasks" Phase 3: Generate tasks
|
|
67
|
-
claude "/sdd-cook" Phase 4: Execute tasks
|
|
68
|
-
pwsh run-converge.ps1 Phase 5: Validate
|
|
69
|
-
`)
|
|
70
|
-
}
|
package/lib/bmad.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BMAD CLI entry point — delegates to lib/bmad/index.js (non-interactive)
|
|
3
|
-
* or to the PowerShell command (interactive via Claude Code).
|
|
4
|
-
*
|
|
5
|
-
* Non-interactive: sdd bmad "input"
|
|
6
|
-
* → Uses Node.js module (this file) for quick brief generation.
|
|
7
|
-
*
|
|
8
|
-
* Interactive: Claude Code /sdd-bmad "input"
|
|
9
|
-
* → Uses .claude/commands/sdd-bmad.md which runs the full 9-question interview.
|
|
10
|
-
*
|
|
11
|
-
* Both paths produce the same BMAD-brief.md output format.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const { spawn } = require('child_process')
|
|
15
|
-
const path = require('path')
|
|
16
|
-
|
|
17
|
-
const args = process.argv.slice(2)
|
|
18
|
-
const input = args.join(' ')
|
|
19
|
-
|
|
20
|
-
if (!input) {
|
|
21
|
-
console.error('Usage: sdd bmad <feature description>')
|
|
22
|
-
console.error('Example: sdd bmad "landing page for my SaaS product"')
|
|
23
|
-
console.error('')
|
|
24
|
-
console.error('For interactive mode (9-question interview), use Claude Code:')
|
|
25
|
-
console.error(' claude "/sdd-bmad landing page for my SaaS"')
|
|
26
|
-
process.exit(1)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Delegate to PowerShell command for interactive experience
|
|
30
|
-
const cmdPath = path.join(__dirname, '.claude', 'commands', 'sdd-bmad.md')
|
|
31
|
-
|
|
32
|
-
const ps = spawn('pwsh', ['-NoProfile', '-File', cmdPath, input], {
|
|
33
|
-
stdio: 'inherit',
|
|
34
|
-
shell: false,
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
ps.on('error', (err) => {
|
|
38
|
-
// PowerShell not available — fall back to Node.js module
|
|
39
|
-
console.warn('[sdd-bmad] PowerShell not available, using non-interactive mode.')
|
|
40
|
-
const bmad = require('./bmad/index')
|
|
41
|
-
const session = bmad.init(input)
|
|
42
|
-
const { confidence } = bmad.generateBrief()
|
|
43
|
-
console.log('[OK] BMAD-brief.md created.')
|
|
44
|
-
console.log(`Confidence: ${confidence.score}/100 — ${confidence.level}`)
|
|
45
|
-
console.log('')
|
|
46
|
-
if (confidence.score < 70) {
|
|
47
|
-
console.log('Tip: Use Claude Code "/sdd-bmad" for interactive mode with 9 questions.')
|
|
48
|
-
}
|
|
49
|
-
console.log('Next: claude "/sdd-spec" to generate SPEC.md')
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
ps.on('close', (code) => {
|
|
53
|
-
process.exit(code || 0)
|
|
54
|
-
})
|