sdd-pipeline 1.0.1 → 1.0.2

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/bmad.js ADDED
@@ -0,0 +1,60 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const sanitize = require('./sanitize')
4
+
5
+ function run(description) {
6
+ if (!description) {
7
+ console.error('Usage: sdd bmad <description>')
8
+ console.error('Example: sdd bmad "landing page for my SaaS product"')
9
+ process.exit(1)
10
+ }
11
+
12
+ const sanitized = sanitize.run(description)
13
+ const date = new Date().toISOString().split('T')[0]
14
+ const expiry = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]
15
+
16
+ const content = `# BMAD Brief — [Project Name]
17
+
18
+ > Generated: ${date}. Expires: ${expiry}.
19
+
20
+ ## Input
21
+ > ${sanitized}
22
+
23
+ ## PM Perspective
24
+ **Target user:** [Who benefits most from this feature]
25
+ **User needs:** [Top 3 needs this feature addresses]
26
+ **Primary conversion action:** [What user does that matters to business]
27
+
28
+ ## Architect Perspective
29
+ **Minimum viable approach:** [One paragraph]
30
+ **Technical risks:**
31
+ | Risk | Likelihood | Impact | Mitigation |
32
+ |------|-----------|--------|------------|
33
+ | [Risk 1] | [H/M/L] | [H/M/L] | [Mitigation] |
34
+
35
+ ## UX Perspective
36
+ **First impression goal:** [Description]
37
+ **Microcopy needed:** [List]
38
+
39
+ ## Synthesis
40
+ **What we're building:** [2-3 sentences describing the feature]
41
+
42
+ **What we're NOT building:** [Explicit exclusions]
43
+ 1. [Exclusion]
44
+
45
+ ## Open Questions
46
+ | # | Question | Impact |
47
+ |---|----------|--------|
48
+ | 1 | [Question] | [Blocking?] |
49
+
50
+ ## Prompt Injection Check
51
+ - Input was sanitized before processing
52
+ - No system prompt overrides accepted
53
+ `
54
+
55
+ fs.writeFileSync('BMAD-brief.md', content, 'utf8')
56
+ console.log('[OK] BMAD-brief.md created.')
57
+ console.log('Next: claude "/sdd-spec" to generate SPEC.md')
58
+ }
59
+
60
+ module.exports = { run }
package/lib/config.js ADDED
@@ -0,0 +1,35 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+
4
+ function read() {
5
+ const configPath = path.join(process.cwd(), '.sdd/config.json')
6
+ if (!fs.existsSync(configPath)) {
7
+ return null
8
+ }
9
+ return JSON.parse(fs.readFileSync(configPath, 'utf8'))
10
+ }
11
+
12
+ function printStatus() {
13
+ const config = read()
14
+ if (!config) {
15
+ console.error('ERROR: .sdd/config.json not found. Run: sdd init')
16
+ process.exit(1)
17
+ }
18
+
19
+ const phases = ['phase0', 'phase1', 'phase2', 'phase3', 'phase4', 'phase5']
20
+ console.log('=== SDD Pipeline Status ===')
21
+ console.log(`Project: ${config.project.name}`)
22
+ console.log(`Phase: ${config.phases.current}`)
23
+ console.log(`Domain: ${config.project.domain}`)
24
+ console.log('')
25
+
26
+ for (const p of phases) {
27
+ const phaseData = config.phases[p]
28
+ const status = phaseData?.status || 'unknown'
29
+ const icon = status === 'completed' ? '[V]' : status === 'in-progress' ? '[>]' : '[ ]'
30
+ const color = status === 'completed' ? '32' : status === 'in-progress' ? '33' : '90'
31
+ console.log(` \x1b[${color}m${icon} ${p}: ${status}\x1b[0m`)
32
+ }
33
+ }
34
+
35
+ module.exports = { read, printStatus }
package/lib/init.js ADDED
@@ -0,0 +1,126 @@
1
+ const path = require('path')
2
+ const fs = require('fs')
3
+
4
+ const BUNDLE_DIR = path.join(__dirname, 'bundle')
5
+
6
+ const FILES = [
7
+ '.sdd/config.json',
8
+ '.sdd/smoke-test.ps1',
9
+ '.sdd/tool-versions.json',
10
+ 'templates/CONSTITUTION.template.md',
11
+ 'templates/SPEC.template.md',
12
+ 'templates/PLAN.template.md',
13
+ 'templates/TASKS.template.md',
14
+ 'templates/BMAD-brief.template.md',
15
+ 'templates/README.md',
16
+ 'converge/validation.md',
17
+ 'CLAUDE.md',
18
+ 'run-converge.ps1',
19
+ ]
20
+
21
+ const DIRS = ['.sdd', 'templates', 'converge', 'commands', 'extensions']
22
+
23
+ function ensureDir(dir) {
24
+ if (!fs.existsSync(dir)) {
25
+ fs.mkdirSync(dir, { recursive: true })
26
+ }
27
+ }
28
+
29
+ function copyFile(src, dest) {
30
+ ensureDir(path.dirname(dest))
31
+ if (fs.existsSync(dest)) {
32
+ console.log(` [SKIP] ${dest} already exists`)
33
+ return
34
+ }
35
+ const content = fs.readFileSync(src, 'utf8')
36
+ fs.writeFileSync(dest, content, 'utf8')
37
+ console.log(` [COPY] ${dest}`)
38
+ }
39
+
40
+ function run() {
41
+ console.log('Initializing SDD pipeline...')
42
+ console.log('')
43
+
44
+ if (!fs.existsSync(BUNDLE_DIR)) {
45
+ console.error('ERROR: Bundle directory not found. Is the package installed correctly?')
46
+ process.exit(1)
47
+ }
48
+
49
+ for (const dir of DIRS) {
50
+ ensureDir(dir)
51
+ }
52
+
53
+ for (const file of FILES) {
54
+ const src = path.join(BUNDLE_DIR, file)
55
+ const dest = path.join(process.cwd(), file)
56
+ if (fs.existsSync(src)) {
57
+ copyFile(src, dest)
58
+ } else {
59
+ console.log(` [WARN] ${src} not found in bundle`)
60
+ }
61
+ }
62
+
63
+ // Create .claude/commands/ with the command files
64
+ ensureDir('.claude/commands')
65
+ const cmdFiles = ['sdd-bmad.md', 'sdd-spec.md', 'sdd-tasks.md', 'sdd-converge.md', 'sdd-init.md']
66
+ for (const cmd of cmdFiles) {
67
+ const src = path.join(BUNDLE_DIR, '.claude/commands', cmd)
68
+ const dest = path.join(process.cwd(), '.claude/commands', cmd)
69
+ if (fs.existsSync(src)) {
70
+ copyFile(src, dest)
71
+ }
72
+ }
73
+
74
+ // Create .github/workflows/
75
+ ensureDir('.github/workflows')
76
+ const workflowSrc = path.join(BUNDLE_DIR, '.github/workflows/converge.yml')
77
+ const workflowDest = path.join(process.cwd(), '.github/workflows/converge.yml')
78
+ if (fs.existsSync(workflowSrc)) {
79
+ copyFile(workflowSrc, workflowDest)
80
+ }
81
+
82
+ // Create commands/sdd-status.ps1
83
+ ensureDir('commands')
84
+ const statusSrc = path.join(BUNDLE_DIR, 'commands/sdd-status.ps1')
85
+ const statusDest = path.join(process.cwd(), 'commands/sdd-status.ps1')
86
+ if (fs.existsSync(statusSrc)) {
87
+ copyFile(statusSrc, statusDest)
88
+ }
89
+
90
+ // Create extensions/
91
+ for (const ext of ['sdd-api', 'sdd-frontend', 'sdd-backend']) {
92
+ const extDir = path.join(BUNDLE_DIR, 'extensions', ext)
93
+ if (fs.existsSync(extDir)) {
94
+ copyDirRecursive(extDir, path.join(process.cwd(), 'extensions', ext))
95
+ }
96
+ }
97
+
98
+ // Copy extensions README
99
+ const extReadmeSrc = path.join(BUNDLE_DIR, 'extensions/README.md')
100
+ const extReadmeDest = path.join(process.cwd(), 'extensions/README.md')
101
+ if (fs.existsSync(extReadmeSrc)) {
102
+ copyFile(extReadmeSrc, extReadmeDest)
103
+ }
104
+
105
+ console.log('')
106
+ console.log('[OK] SDD pipeline initialized.')
107
+ console.log('')
108
+ console.log('Next: sdd bmad <your feature idea>')
109
+ console.log('Or: claude "/sdd-bmad <feature>"')
110
+ }
111
+
112
+ function copyDirRecursive(src, dest) {
113
+ ensureDir(dest)
114
+ const entries = fs.readdirSync(src, { withFileTypes: true })
115
+ for (const entry of entries) {
116
+ const srcPath = path.join(src, entry.name)
117
+ const destPath = path.join(dest, entry.name)
118
+ if (entry.isDirectory()) {
119
+ copyDirRecursive(srcPath, destPath)
120
+ } else {
121
+ copyFile(srcPath, destPath)
122
+ }
123
+ }
124
+ }
125
+
126
+ module.exports = { run }
@@ -0,0 +1,10 @@
1
+ // Prompt injection protection — sanitize user input before LLM embedding
2
+ function sanitize(input) {
3
+ if (!input) return ''
4
+ return input
5
+ .replace(/ignore previous|disregard|system:|<script|<\/script>/gi, '[FILTERED]')
6
+ .replace(/ignore all previous instructions/gi, '[FILTERED]')
7
+ .trim()
8
+ }
9
+
10
+ module.exports = { run: sanitize }
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "sdd-pipeline",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Spec-Driven Development pipeline for Claude Code",
5
5
  "bin": {
6
6
  "sdd": "bin/sdd.js"
7
7
  },
8
8
  "files": [
9
9
  "bin",
10
+ "lib",
10
11
  "lib/bundle"
11
12
  ],
12
13
  "engines": {