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/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 content = fs.readFileSync(src, 'utf8')
38
- fs.writeFileSync(dest, content, 'utf8')
39
- console.log(` [COPY] ${dest}`)
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
- // Create .claude/commands/ with the command files
106
+ // Copy Claude Code commands
107
+ console.log('')
108
+ console.log('Copying Claude Code commands...')
66
109
  ensureDir('.claude/commands')
67
- const cmdFiles = ['sdd-bmad.md', 'sdd-spec.md', 'sdd-tasks.md', 'sdd-converge.md', 'sdd-init.md']
68
- for (const cmd of cmdFiles) {
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
- // Create .github/workflows/
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
- // Create commands/sdd-status.ps1
85
- ensureDir('commands')
86
- const statusSrc = path.join(BUNDLE_DIR, 'commands/sdd-status.ps1')
87
- const statusDest = path.join(process.cwd(), 'commands/sdd-status.ps1')
88
- if (fs.existsSync(statusSrc)) {
89
- copyFile(statusSrc, statusDest)
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
- // Create extensions/
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('Next: sdd bmad <your feature idea>')
111
- console.log('Or: claude "/sdd-bmad <feature>"')
112
- }
113
-
114
- function copyDirRecursive(src, dest) {
115
- ensureDir(dest)
116
- const entries = fs.readdirSync(src, { withFileTypes: true })
117
- for (const entry of entries) {
118
- const srcPath = path.join(src, entry.name)
119
- const destPath = path.join(dest, entry.name)
120
- if (entry.isDirectory()) {
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.4",
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.js"
7
+ "sdd": "bin/sdd.cjs"
7
8
  },
8
9
  "files": [
9
10
  "bin/",
10
- "lib/bmad.js",
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
- })