@bhargavvc/sdd-cc 1.30.0 → 1.35.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.
Files changed (242) hide show
  1. package/README.ja-JP.md +144 -110
  2. package/README.ko-KR.md +143 -107
  3. package/README.md +183 -112
  4. package/README.pt-BR.md +90 -52
  5. package/README.zh-CN.md +141 -101
  6. package/agents/sdd-advisor-researcher.md +23 -0
  7. package/agents/sdd-ai-researcher.md +133 -0
  8. package/agents/sdd-code-fixer.md +516 -0
  9. package/agents/sdd-code-reviewer.md +355 -0
  10. package/agents/sdd-codebase-mapper.md +3 -3
  11. package/agents/sdd-debugger.md +17 -5
  12. package/agents/sdd-doc-verifier.md +201 -0
  13. package/agents/sdd-doc-writer.md +602 -0
  14. package/agents/sdd-domain-researcher.md +153 -0
  15. package/agents/sdd-eval-auditor.md +164 -0
  16. package/agents/sdd-eval-planner.md +154 -0
  17. package/agents/sdd-executor.md +87 -4
  18. package/agents/sdd-framework-selector.md +160 -0
  19. package/agents/sdd-intel-updater.md +314 -0
  20. package/agents/sdd-nyquist-auditor.md +1 -1
  21. package/agents/sdd-phase-researcher.md +71 -4
  22. package/agents/sdd-plan-checker.md +100 -6
  23. package/agents/sdd-planner.md +145 -206
  24. package/agents/sdd-project-researcher.md +25 -2
  25. package/agents/sdd-research-synthesizer.md +3 -3
  26. package/agents/sdd-roadmapper.md +6 -6
  27. package/agents/sdd-security-auditor.md +128 -0
  28. package/agents/sdd-ui-auditor.md +43 -3
  29. package/agents/sdd-ui-checker.md +5 -5
  30. package/agents/sdd-ui-researcher.md +27 -4
  31. package/agents/sdd-user-profiler.md +2 -2
  32. package/agents/sdd-verifier.md +142 -22
  33. package/bin/install.js +2151 -551
  34. package/commands/sdd/add-backlog.md +5 -5
  35. package/commands/sdd/add-tests.md +2 -2
  36. package/commands/sdd/ai-integration-phase.md +36 -0
  37. package/commands/sdd/analyze-dependencies.md +34 -0
  38. package/commands/sdd/audit-fix.md +33 -0
  39. package/commands/sdd/autonomous.md +7 -2
  40. package/commands/sdd/cleanup.md +5 -0
  41. package/commands/sdd/code-review-fix.md +52 -0
  42. package/commands/sdd/code-review.md +55 -0
  43. package/commands/sdd/complete-milestone.md +6 -6
  44. package/commands/sdd/debug.md +22 -9
  45. package/commands/sdd/discuss-phase.md +7 -2
  46. package/commands/sdd/do.md +1 -1
  47. package/commands/sdd/docs-update.md +48 -0
  48. package/commands/sdd/eval-review.md +32 -0
  49. package/commands/sdd/execute-phase.md +4 -0
  50. package/commands/sdd/explore.md +27 -0
  51. package/commands/sdd/fast.md +2 -2
  52. package/commands/sdd/from-sdd2.md +45 -0
  53. package/commands/sdd/help.md +2 -0
  54. package/commands/sdd/import.md +36 -0
  55. package/commands/sdd/intel.md +179 -0
  56. package/commands/sdd/join-discord.md +2 -1
  57. package/commands/sdd/manager.md +1 -0
  58. package/commands/sdd/map-codebase.md +3 -3
  59. package/commands/sdd/new-milestone.md +1 -1
  60. package/commands/sdd/new-project.md +5 -1
  61. package/commands/sdd/new-workspace.md +1 -1
  62. package/commands/sdd/next.md +2 -0
  63. package/commands/sdd/plan-milestone-gaps.md +2 -2
  64. package/commands/sdd/plan-phase.md +6 -1
  65. package/commands/sdd/plant-seed.md +1 -1
  66. package/commands/sdd/profile-user.md +1 -1
  67. package/commands/sdd/quick.md +5 -3
  68. package/commands/sdd/reapply-patches.md +230 -42
  69. package/commands/sdd/research-phase.md +3 -3
  70. package/commands/sdd/review-backlog.md +1 -0
  71. package/commands/sdd/review.md +6 -3
  72. package/commands/sdd/scan.md +26 -0
  73. package/commands/sdd/secure-phase.md +35 -0
  74. package/commands/sdd/ship.md +1 -1
  75. package/commands/sdd/thread.md +5 -5
  76. package/commands/sdd/undo.md +34 -0
  77. package/commands/sdd/verify-work.md +1 -1
  78. package/commands/sdd/workstreams.md +17 -11
  79. package/hooks/dist/sdd-check-update.js +33 -8
  80. package/hooks/dist/sdd-context-monitor.js +17 -8
  81. package/hooks/dist/sdd-phase-boundary.sh +27 -0
  82. package/hooks/dist/sdd-prompt-guard.js +1 -0
  83. package/hooks/dist/sdd-read-guard.js +82 -0
  84. package/hooks/dist/sdd-session-state.sh +33 -0
  85. package/hooks/dist/sdd-statusline.js +137 -15
  86. package/hooks/dist/sdd-validate-commit.sh +47 -0
  87. package/hooks/dist/sdd-workflow-guard.js +4 -4
  88. package/hooks/sdd-check-update.js +139 -0
  89. package/hooks/sdd-context-monitor.js +165 -0
  90. package/hooks/sdd-phase-boundary.sh +27 -0
  91. package/hooks/sdd-prompt-guard.js +97 -0
  92. package/hooks/sdd-read-guard.js +82 -0
  93. package/hooks/sdd-session-state.sh +33 -0
  94. package/hooks/sdd-statusline.js +241 -0
  95. package/hooks/sdd-validate-commit.sh +47 -0
  96. package/hooks/sdd-workflow-guard.js +94 -0
  97. package/package.json +3 -3
  98. package/scripts/build-hooks.js +18 -7
  99. package/scripts/prompt-injection-scan.sh +1 -0
  100. package/scripts/rebrand-gsd-to-sdd.sh +221 -220
  101. package/scripts/run-tests.cjs +5 -1
  102. package/scripts/sync-upstream.sh +1 -1
  103. package/sdd/bin/lib/commands.cjs +79 -17
  104. package/sdd/bin/lib/config.cjs +90 -48
  105. package/sdd/bin/lib/core.cjs +452 -87
  106. package/sdd/bin/lib/docs.cjs +267 -0
  107. package/sdd/bin/lib/frontmatter.cjs +381 -336
  108. package/sdd/bin/lib/init.cjs +110 -16
  109. package/sdd/bin/lib/intel.cjs +660 -0
  110. package/sdd/bin/lib/learnings.cjs +378 -0
  111. package/sdd/bin/lib/milestone.cjs +42 -11
  112. package/sdd/bin/lib/model-profiles.cjs +17 -15
  113. package/sdd/bin/lib/phase.cjs +367 -288
  114. package/sdd/bin/lib/profile-output.cjs +106 -10
  115. package/sdd/bin/lib/roadmap.cjs +146 -115
  116. package/sdd/bin/lib/schema-detect.cjs +238 -0
  117. package/sdd/bin/lib/sdd2-import.cjs +511 -0
  118. package/sdd/bin/lib/security.cjs +124 -3
  119. package/sdd/bin/lib/state.cjs +648 -264
  120. package/sdd/bin/lib/template.cjs +8 -4
  121. package/sdd/bin/lib/verify.cjs +209 -28
  122. package/sdd/bin/lib/workstream.cjs +7 -3
  123. package/sdd/bin/sdd-tools.cjs +184 -12
  124. package/sdd/contexts/dev.md +21 -0
  125. package/sdd/contexts/research.md +22 -0
  126. package/sdd/contexts/review.md +22 -0
  127. package/sdd/references/agent-contracts.md +79 -0
  128. package/sdd/references/ai-evals.md +156 -0
  129. package/sdd/references/ai-frameworks.md +186 -0
  130. package/sdd/references/artifact-types.md +113 -0
  131. package/sdd/references/common-bug-patterns.md +114 -0
  132. package/sdd/references/context-budget.md +49 -0
  133. package/sdd/references/continuation-format.md +25 -25
  134. package/sdd/references/domain-probes.md +125 -0
  135. package/sdd/references/few-shot-examples/plan-checker.md +73 -0
  136. package/sdd/references/few-shot-examples/verifier.md +109 -0
  137. package/sdd/references/gate-prompts.md +100 -0
  138. package/sdd/references/gates.md +70 -0
  139. package/sdd/references/git-integration.md +1 -1
  140. package/sdd/references/ios-scaffold.md +123 -0
  141. package/sdd/references/model-profile-resolution.md +2 -0
  142. package/sdd/references/model-profiles.md +24 -18
  143. package/sdd/references/planner-gap-closure.md +62 -0
  144. package/sdd/references/planner-reviews.md +39 -0
  145. package/sdd/references/planner-revision.md +87 -0
  146. package/sdd/references/planning-config.md +252 -0
  147. package/sdd/references/revision-loop.md +97 -0
  148. package/sdd/references/thinking-models-debug.md +44 -0
  149. package/sdd/references/thinking-models-execution.md +50 -0
  150. package/sdd/references/thinking-models-planning.md +62 -0
  151. package/sdd/references/thinking-models-research.md +50 -0
  152. package/sdd/references/thinking-models-verification.md +55 -0
  153. package/sdd/references/thinking-partner.md +96 -0
  154. package/sdd/references/ui-brand.md +4 -4
  155. package/sdd/references/universal-anti-patterns.md +63 -0
  156. package/sdd/references/verification-overrides.md +227 -0
  157. package/sdd/references/workstream-flag.md +56 -3
  158. package/sdd/templates/AI-SPEC.md +246 -0
  159. package/sdd/templates/DEBUG.md +1 -1
  160. package/sdd/templates/SECURITY.md +61 -0
  161. package/sdd/templates/UAT.md +4 -4
  162. package/sdd/templates/VALIDATION.md +4 -4
  163. package/sdd/templates/claude-md.md +32 -9
  164. package/sdd/templates/config.json +4 -0
  165. package/sdd/templates/debug-subagent-prompt.md +1 -1
  166. package/sdd/templates/dev-preferences.md +1 -1
  167. package/sdd/templates/discovery.md +2 -2
  168. package/sdd/templates/phase-prompt.md +1 -1
  169. package/sdd/templates/planner-subagent-prompt.md +3 -3
  170. package/sdd/templates/project.md +1 -1
  171. package/sdd/templates/research.md +1 -1
  172. package/sdd/templates/state.md +2 -2
  173. package/sdd/workflows/add-phase.md +8 -8
  174. package/sdd/workflows/add-tests.md +12 -9
  175. package/sdd/workflows/add-todo.md +5 -3
  176. package/sdd/workflows/ai-integration-phase.md +284 -0
  177. package/sdd/workflows/analyze-dependencies.md +96 -0
  178. package/sdd/workflows/audit-fix.md +157 -0
  179. package/sdd/workflows/audit-milestone.md +11 -11
  180. package/sdd/workflows/audit-uat.md +2 -2
  181. package/sdd/workflows/autonomous.md +195 -27
  182. package/sdd/workflows/check-todos.md +12 -10
  183. package/sdd/workflows/cleanup.md +2 -0
  184. package/sdd/workflows/code-review-fix.md +497 -0
  185. package/sdd/workflows/code-review.md +515 -0
  186. package/sdd/workflows/complete-milestone.md +56 -22
  187. package/sdd/workflows/diagnose-issues.md +10 -3
  188. package/sdd/workflows/discovery-phase.md +5 -3
  189. package/sdd/workflows/discuss-phase-assumptions.md +24 -6
  190. package/sdd/workflows/discuss-phase-power.md +291 -0
  191. package/sdd/workflows/discuss-phase.md +173 -21
  192. package/sdd/workflows/do.md +23 -21
  193. package/sdd/workflows/docs-update.md +1155 -0
  194. package/sdd/workflows/eval-review.md +155 -0
  195. package/sdd/workflows/execute-phase.md +594 -38
  196. package/sdd/workflows/execute-plan.md +67 -96
  197. package/sdd/workflows/explore.md +139 -0
  198. package/sdd/workflows/fast.md +5 -5
  199. package/sdd/workflows/forensics.md +2 -2
  200. package/sdd/workflows/health.md +4 -4
  201. package/sdd/workflows/help.md +122 -119
  202. package/sdd/workflows/import.md +276 -0
  203. package/sdd/workflows/inbox.md +387 -0
  204. package/sdd/workflows/insert-phase.md +7 -7
  205. package/sdd/workflows/list-phase-assumptions.md +4 -4
  206. package/sdd/workflows/list-workspaces.md +2 -2
  207. package/sdd/workflows/manager.md +35 -32
  208. package/sdd/workflows/map-codebase.md +7 -5
  209. package/sdd/workflows/milestone-summary.md +2 -2
  210. package/sdd/workflows/new-milestone.md +17 -9
  211. package/sdd/workflows/new-project.md +50 -25
  212. package/sdd/workflows/new-workspace.md +7 -5
  213. package/sdd/workflows/next.md +67 -11
  214. package/sdd/workflows/note.md +9 -7
  215. package/sdd/workflows/pause-work.md +75 -12
  216. package/sdd/workflows/plan-milestone-gaps.md +8 -8
  217. package/sdd/workflows/plan-phase.md +294 -42
  218. package/sdd/workflows/plant-seed.md +6 -3
  219. package/sdd/workflows/pr-branch.md +42 -14
  220. package/sdd/workflows/profile-user.md +9 -7
  221. package/sdd/workflows/progress.md +45 -45
  222. package/sdd/workflows/quick.md +195 -47
  223. package/sdd/workflows/remove-phase.md +6 -6
  224. package/sdd/workflows/remove-workspace.md +3 -1
  225. package/sdd/workflows/research-phase.md +2 -2
  226. package/sdd/workflows/resume-project.md +12 -12
  227. package/sdd/workflows/review.md +109 -9
  228. package/sdd/workflows/scan.md +102 -0
  229. package/sdd/workflows/secure-phase.md +166 -0
  230. package/sdd/workflows/session-report.md +2 -2
  231. package/sdd/workflows/settings.md +38 -12
  232. package/sdd/workflows/ship.md +21 -9
  233. package/sdd/workflows/stats.md +1 -1
  234. package/sdd/workflows/transition.md +23 -23
  235. package/sdd/workflows/ui-phase.md +15 -7
  236. package/sdd/workflows/ui-review.md +29 -4
  237. package/sdd/workflows/undo.md +314 -0
  238. package/sdd/workflows/update.md +171 -20
  239. package/sdd/workflows/validate-phase.md +6 -4
  240. package/sdd/workflows/verify-phase.md +210 -6
  241. package/sdd/workflows/verify-work.md +83 -9
  242. package/sdd/commands/sdd/workstreams.md +0 -63
@@ -0,0 +1,241 @@
1
+ #!/usr/bin/env node
2
+ // sdd-hook-version: {{SDD_VERSION}}
3
+ // Claude Code Statusline - SDD Edition
4
+ // Shows: model | current task (or SDD state) | directory | context usage
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const os = require('os');
9
+
10
+ // --- SDD state reader -------------------------------------------------------
11
+
12
+ /**
13
+ * Walk up from dir looking for .planning/STATE.md.
14
+ * Returns parsed state object or null.
15
+ */
16
+ function readSddState(dir) {
17
+ const home = os.homedir();
18
+ let current = dir;
19
+ for (let i = 0; i < 10; i++) {
20
+ const candidate = path.join(current, '.planning', 'STATE.md');
21
+ if (fs.existsSync(candidate)) {
22
+ try {
23
+ return parseStateMd(fs.readFileSync(candidate, 'utf8'));
24
+ } catch (e) {
25
+ return null;
26
+ }
27
+ }
28
+ const parent = path.dirname(current);
29
+ if (parent === current || current === home) break;
30
+ current = parent;
31
+ }
32
+ return null;
33
+ }
34
+
35
+ /**
36
+ * Parse STATE.md frontmatter + Phase line from body.
37
+ * Returns { status, milestone, milestoneName, phaseNum, phaseTotal, phaseName }
38
+ */
39
+ function parseStateMd(content) {
40
+ const state = {};
41
+
42
+ // YAML frontmatter between --- markers
43
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
44
+ if (fmMatch) {
45
+ for (const line of fmMatch[1].split('\n')) {
46
+ const m = line.match(/^(\w+):\s*(.+)/);
47
+ if (!m) continue;
48
+ const [, key, val] = m;
49
+ const v = val.trim().replace(/^["']|["']$/g, '');
50
+ if (key === 'status') state.status = v === 'null' ? null : v;
51
+ if (key === 'milestone') state.milestone = v === 'null' ? null : v;
52
+ if (key === 'milestone_name') state.milestoneName = v === 'null' ? null : v;
53
+ }
54
+ }
55
+
56
+ // Phase: N of M (name) or Phase: none active (...)
57
+ const phaseMatch = content.match(/^Phase:\s*(\d+)\s+of\s+(\d+)(?:\s+\(([^)]+)\))?/m);
58
+ if (phaseMatch) {
59
+ state.phaseNum = phaseMatch[1];
60
+ state.phaseTotal = phaseMatch[2];
61
+ state.phaseName = phaseMatch[3] || null;
62
+ }
63
+
64
+ // Fallback: parse Status: from body when frontmatter is absent
65
+ if (!state.status) {
66
+ const bodyStatus = content.match(/^Status:\s*(.+)/m);
67
+ if (bodyStatus) {
68
+ const raw = bodyStatus[1].trim().toLowerCase();
69
+ if (raw.includes('ready to plan') || raw.includes('planning')) state.status = 'planning';
70
+ else if (raw.includes('execut')) state.status = 'executing';
71
+ else if (raw.includes('complet') || raw.includes('archived')) state.status = 'complete';
72
+ }
73
+ }
74
+
75
+ return state;
76
+ }
77
+
78
+ /**
79
+ * Format SDD state into display string.
80
+ * Format: "v1.9 Code Quality · executing · fix-graphiti-deployment (1/5)"
81
+ * Gracefully degrades when parts are missing.
82
+ */
83
+ function formatSddState(s) {
84
+ const parts = [];
85
+
86
+ // Milestone: version + name (skip placeholder "milestone")
87
+ if (s.milestone || s.milestoneName) {
88
+ const ver = s.milestone || '';
89
+ const name = (s.milestoneName && s.milestoneName !== 'milestone') ? s.milestoneName : '';
90
+ const ms = [ver, name].filter(Boolean).join(' ');
91
+ if (ms) parts.push(ms);
92
+ }
93
+
94
+ // Status
95
+ if (s.status) parts.push(s.status);
96
+
97
+ // Phase
98
+ if (s.phaseNum && s.phaseTotal) {
99
+ const phase = s.phaseName
100
+ ? `${s.phaseName} (${s.phaseNum}/${s.phaseTotal})`
101
+ : `ph ${s.phaseNum}/${s.phaseTotal}`;
102
+ parts.push(phase);
103
+ }
104
+
105
+ return parts.join(' · ');
106
+ }
107
+
108
+ // --- stdin ------------------------------------------------------------------
109
+
110
+ function runStatusline() {
111
+ let input = '';
112
+ // Timeout guard: if stdin doesn't close within 3s (e.g. pipe issues on
113
+ // Windows/Git Bash), exit silently instead of hanging. See #775.
114
+ const stdinTimeout = setTimeout(() => process.exit(0), 3000);
115
+ process.stdin.setEncoding('utf8');
116
+ process.stdin.on('data', chunk => input += chunk);
117
+ process.stdin.on('end', () => {
118
+ clearTimeout(stdinTimeout);
119
+ try {
120
+ const data = JSON.parse(input);
121
+ const model = data.model?.display_name || 'Claude';
122
+ const dir = data.workspace?.current_dir || process.cwd();
123
+ const session = data.session_id || '';
124
+ const remaining = data.context_window?.remaining_percentage;
125
+
126
+ // Context window display (shows USED percentage scaled to usable context)
127
+ // Claude Code reserves ~16.5% for autocompact buffer, so usable context
128
+ // is 83.5% of the total window. We normalize to show 100% at that point.
129
+ const AUTO_COMPACT_BUFFER_PCT = 16.5;
130
+ let ctx = '';
131
+ if (remaining != null) {
132
+ // Normalize: subtract buffer from remaining, scale to usable range
133
+ const usableRemaining = Math.max(0, ((remaining - AUTO_COMPACT_BUFFER_PCT) / (100 - AUTO_COMPACT_BUFFER_PCT)) * 100);
134
+ const used = Math.max(0, Math.min(100, Math.round(100 - usableRemaining)));
135
+
136
+ // Write context metrics to bridge file for the context-monitor PostToolUse hook.
137
+ // The monitor reads this file to inject agent-facing warnings when context is low.
138
+ // Reject session IDs with path separators or traversal sequences to prevent
139
+ // a malicious session_id from writing files outside the temp directory.
140
+ const sessionSafe = session && !/[/\\]|\.\./.test(session);
141
+ if (sessionSafe) {
142
+ try {
143
+ const bridgePath = path.join(os.tmpdir(), `claude-ctx-${session}.json`);
144
+ const bridgeData = JSON.stringify({
145
+ session_id: session,
146
+ remaining_percentage: remaining,
147
+ used_pct: used,
148
+ timestamp: Math.floor(Date.now() / 1000)
149
+ });
150
+ fs.writeFileSync(bridgePath, bridgeData);
151
+ } catch (e) {
152
+ // Silent fail -- bridge is best-effort, don't break statusline
153
+ }
154
+ }
155
+
156
+ // Build progress bar (10 segments)
157
+ const filled = Math.floor(used / 10);
158
+ const bar = '█'.repeat(filled) + '░'.repeat(10 - filled);
159
+
160
+ // Color based on usable context thresholds
161
+ if (used < 50) {
162
+ ctx = ` \x1b[32m${bar} ${used}%\x1b[0m`;
163
+ } else if (used < 65) {
164
+ ctx = ` \x1b[33m${bar} ${used}%\x1b[0m`;
165
+ } else if (used < 80) {
166
+ ctx = ` \x1b[38;5;208m${bar} ${used}%\x1b[0m`;
167
+ } else {
168
+ ctx = ` \x1b[5;31m💀 ${bar} ${used}%\x1b[0m`;
169
+ }
170
+ }
171
+
172
+ // Current task from todos
173
+ let task = '';
174
+ const homeDir = os.homedir();
175
+ // Respect CLAUDE_CONFIG_DIR for custom config directory setups (#870)
176
+ const claudeDir = process.env.CLAUDE_CONFIG_DIR || path.join(homeDir, '.claude');
177
+ const todosDir = path.join(claudeDir, 'todos');
178
+ if (session && fs.existsSync(todosDir)) {
179
+ try {
180
+ const files = fs.readdirSync(todosDir)
181
+ .filter(f => f.startsWith(session) && f.includes('-agent-') && f.endsWith('.json'))
182
+ .map(f => ({ name: f, mtime: fs.statSync(path.join(todosDir, f)).mtime }))
183
+ .sort((a, b) => b.mtime - a.mtime);
184
+
185
+ if (files.length > 0) {
186
+ try {
187
+ const todos = JSON.parse(fs.readFileSync(path.join(todosDir, files[0].name), 'utf8'));
188
+ const inProgress = todos.find(t => t.status === 'in_progress');
189
+ if (inProgress) task = inProgress.activeForm || '';
190
+ } catch (e) {}
191
+ }
192
+ } catch (e) {
193
+ // Silently fail on file system errors - don't break statusline
194
+ }
195
+ }
196
+
197
+ // SDD state (milestone · status · phase) — shown when no todo task
198
+ const sddStateStr = task ? '' : formatSddState(readSddState(dir) || {});
199
+
200
+ // SDD update available?
201
+ // Check shared cache first (#1421), fall back to runtime-specific cache for
202
+ // backward compatibility with older sdd-check-update.js versions.
203
+ let sddUpdate = '';
204
+ const sharedCacheFile = path.join(homeDir, '.cache', 'sdd', 'sdd-update-check.json');
205
+ const legacyCacheFile = path.join(claudeDir, 'cache', 'sdd-update-check.json');
206
+ const cacheFile = fs.existsSync(sharedCacheFile) ? sharedCacheFile : legacyCacheFile;
207
+ if (fs.existsSync(cacheFile)) {
208
+ try {
209
+ const cache = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
210
+ if (cache.update_available) {
211
+ sddUpdate = '\x1b[33m⬆ /sdd-update\x1b[0m │ ';
212
+ }
213
+ if (cache.stale_hooks && cache.stale_hooks.length > 0) {
214
+ sddUpdate += '\x1b[31m⚠ stale hooks — run /sdd-update\x1b[0m │ ';
215
+ }
216
+ } catch (e) {}
217
+ }
218
+
219
+ // Output
220
+ const dirname = path.basename(dir);
221
+ const middle = task
222
+ ? `\x1b[1m${task}\x1b[0m`
223
+ : sddStateStr
224
+ ? `\x1b[2m${sddStateStr}\x1b[0m`
225
+ : null;
226
+
227
+ if (middle) {
228
+ process.stdout.write(`${sddUpdate}\x1b[2m${model}\x1b[0m │ ${middle} │ \x1b[2m${dirname}\x1b[0m${ctx}`);
229
+ } else {
230
+ process.stdout.write(`${sddUpdate}\x1b[2m${model}\x1b[0m │ \x1b[2m${dirname}\x1b[0m${ctx}`);
231
+ }
232
+ } catch (e) {
233
+ // Silent fail - don't break statusline on parse errors
234
+ }
235
+ });
236
+ }
237
+
238
+ // Export helpers for unit tests. Harmless when run as a script.
239
+ module.exports = { readSddState, parseStateMd, formatSddState };
240
+
241
+ if (require.main === module) runStatusline();
@@ -0,0 +1,47 @@
1
+ #!/bin/bash
2
+ # sdd-validate-commit.sh — PreToolUse hook: enforce Conventional Commits format
3
+ # Blocks git commit commands with non-conforming messages (exit 2).
4
+ # Allows conforming messages and all non-commit commands (exit 0).
5
+ # Uses Node.js for JSON parsing (always available in SDD projects, no jq dependency).
6
+ #
7
+ # OPT-IN: This hook is a no-op unless config.json has hooks.community: true.
8
+ # Enable with: "hooks": { "community": true } in .planning/config.json
9
+
10
+ # Check opt-in config — exit silently if not enabled
11
+ if [ -f .planning/config.json ]; then
12
+ ENABLED=$(node -e "try{const c=require('./.planning/config.json');process.stdout.write(c.hooks?.community===true?'1':'0')}catch{process.stdout.write('0')}" 2>/dev/null)
13
+ if [ "$ENABLED" != "1" ]; then exit 0; fi
14
+ else
15
+ exit 0
16
+ fi
17
+
18
+ INPUT=$(cat)
19
+
20
+ # Extract command from JSON using Node (handles escaping correctly, no jq needed)
21
+ CMD=$(echo "$INPUT" | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{process.stdout.write(JSON.parse(d).tool_input?.command||'')}catch{}})" 2>/dev/null)
22
+
23
+ # Only check git commit commands
24
+ if [[ "$CMD" =~ ^git[[:space:]]+commit ]]; then
25
+ # Extract message from -m flag
26
+ MSG=""
27
+ if [[ "$CMD" =~ -m[[:space:]]+\"([^\"]+)\" ]]; then
28
+ MSG="${BASH_REMATCH[1]}"
29
+ elif [[ "$CMD" =~ -m[[:space:]]+\'([^\']+)\' ]]; then
30
+ MSG="${BASH_REMATCH[1]}"
31
+ fi
32
+
33
+ if [ -n "$MSG" ]; then
34
+ SUBJECT=$(echo "$MSG" | head -1)
35
+ # Validate Conventional Commits format
36
+ if ! [[ "$SUBJECT" =~ ^(feat|fix|docs|style|refactor|perf|test|build|ci|chore)(\(.+\))?:[[:space:]].+ ]]; then
37
+ echo '{"decision": "block", "reason": "Commit message must follow Conventional Commits: <type>(<scope>): <subject>. Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore. Subject must be <=72 chars, lowercase, imperative mood, no trailing period."}'
38
+ exit 2
39
+ fi
40
+ if [ ${#SUBJECT} -gt 72 ]; then
41
+ echo '{"decision": "block", "reason": "Commit subject must be 72 characters or less."}'
42
+ exit 2
43
+ fi
44
+ fi
45
+ fi
46
+
47
+ exit 0
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env node
2
+ // sdd-hook-version: {{SDD_VERSION}}
3
+ // SDD Workflow Guard — PreToolUse hook
4
+ // Detects when Claude attempts file edits outside a SDD workflow context
5
+ // (no active /sdd- skill or Task subagent) and injects an advisory warning.
6
+ //
7
+ // This is a SOFT guard — it advises, not blocks. The edit still proceeds.
8
+ // The warning nudges Claude to use /sdd-quick or /sdd-fast instead of
9
+ // making direct edits that bypass state tracking.
10
+ //
11
+ // Enable via config: hooks.workflow_guard: true (default: false)
12
+ // Only triggers on Write/Edit tool calls to non-.planning/ files.
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+
17
+ let input = '';
18
+ const stdinTimeout = setTimeout(() => process.exit(0), 3000);
19
+ process.stdin.setEncoding('utf8');
20
+ process.stdin.on('data', chunk => input += chunk);
21
+ process.stdin.on('end', () => {
22
+ clearTimeout(stdinTimeout);
23
+ try {
24
+ const data = JSON.parse(input);
25
+ const toolName = data.tool_name;
26
+
27
+ // Only guard Write and Edit tool calls
28
+ if (toolName !== 'Write' && toolName !== 'Edit') {
29
+ process.exit(0);
30
+ }
31
+
32
+ // Check if we're inside a SDD workflow (Task subagent or /sdd- skill)
33
+ // Subagents have a session_id that differs from the parent
34
+ // and typically have a description field set by the orchestrator
35
+ if (data.tool_input?.is_subagent || data.session_type === 'task') {
36
+ process.exit(0);
37
+ }
38
+
39
+ // Check the file being edited
40
+ const filePath = data.tool_input?.file_path || data.tool_input?.path || '';
41
+
42
+ // Allow edits to .planning/ files (SDD state management)
43
+ if (filePath.includes('.planning/') || filePath.includes('.planning\\')) {
44
+ process.exit(0);
45
+ }
46
+
47
+ // Allow edits to common config/docs files that don't need SDD tracking
48
+ const allowedPatterns = [
49
+ /\.gitignore$/,
50
+ /\.env/,
51
+ /CLAUDE\.md$/,
52
+ /AGENTS\.md$/,
53
+ /GEMINI\.md$/,
54
+ /settings\.json$/,
55
+ ];
56
+ if (allowedPatterns.some(p => p.test(filePath))) {
57
+ process.exit(0);
58
+ }
59
+
60
+ // Check if workflow guard is enabled
61
+ const cwd = data.cwd || process.cwd();
62
+ const configPath = path.join(cwd, '.planning', 'config.json');
63
+ if (fs.existsSync(configPath)) {
64
+ try {
65
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
66
+ if (!config.hooks?.workflow_guard) {
67
+ process.exit(0); // Guard disabled (default)
68
+ }
69
+ } catch (e) {
70
+ process.exit(0);
71
+ }
72
+ } else {
73
+ process.exit(0); // No SDD project — don't guard
74
+ }
75
+
76
+ // If we get here: SDD project, guard enabled, file edit outside .planning/,
77
+ // not in a subagent context. Inject advisory warning.
78
+ const output = {
79
+ hookSpecificOutput: {
80
+ hookEventName: "PreToolUse",
81
+ additionalContext: `⚠️ WORKFLOW ADVISORY: You're editing ${path.basename(filePath)} directly without a SDD command. ` +
82
+ 'This edit will not be tracked in STATE.md or produce a SUMMARY.md. ' +
83
+ 'Consider using /sdd-fast for trivial fixes or /sdd-quick for larger changes ' +
84
+ 'to maintain project state tracking. ' +
85
+ 'If this is intentional (e.g., user explicitly asked for a direct edit), proceed normally.'
86
+ }
87
+ };
88
+
89
+ process.stdout.write(JSON.stringify(output));
90
+ } catch (e) {
91
+ // Silent fail — never block tool execution
92
+ process.exit(0);
93
+ }
94
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bhargavvc/sdd-cc",
3
- "version": "1.30.0",
3
+ "version": "1.35.0",
4
4
  "description": "A meta-prompting, context engineering and spec-driven development system for Claude Code, OpenCode, Gemini and Codex by TÂCHES.",
5
5
  "bin": {
6
6
  "sdd-cc": "bin/install.js"
@@ -10,7 +10,7 @@
10
10
  "commands",
11
11
  "sdd",
12
12
  "agents",
13
- "hooks/dist",
13
+ "hooks",
14
14
  "scripts"
15
15
  ],
16
16
  "keywords": [
@@ -36,7 +36,7 @@
36
36
  "url": "https://github.com/bhargavvc/sdd-cc/issues"
37
37
  },
38
38
  "engines": {
39
- "node": ">=20.0.0"
39
+ "node": ">=22.0.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "c8": "^11.0.0",
@@ -18,8 +18,13 @@ const HOOKS_TO_COPY = [
18
18
  'sdd-check-update.js',
19
19
  'sdd-context-monitor.js',
20
20
  'sdd-prompt-guard.js',
21
+ 'sdd-read-guard.js',
21
22
  'sdd-statusline.js',
22
- 'sdd-workflow-guard.js'
23
+ 'sdd-workflow-guard.js',
24
+ // Community hooks (bash, opt-in via .planning/config.json hooks.community)
25
+ 'sdd-session-state.sh',
26
+ 'sdd-validate-commit.sh',
27
+ 'sdd-phase-boundary.sh'
23
28
  ];
24
29
 
25
30
  /**
@@ -59,16 +64,22 @@ function build() {
59
64
  continue;
60
65
  }
61
66
 
62
- // Validate syntax before copying
63
- const syntaxError = validateSyntax(src);
64
- if (syntaxError) {
65
- console.error(`\x1b[31m✗ ${hook}: SyntaxError — ${syntaxError}\x1b[0m`);
66
- hasErrors = true;
67
- continue;
67
+ // Validate JS syntax before copying (.sh files skip — not Node.js)
68
+ if (hook.endsWith('.js')) {
69
+ const syntaxError = validateSyntax(src);
70
+ if (syntaxError) {
71
+ console.error(`\x1b[31m✗ ${hook}: SyntaxError — ${syntaxError}\x1b[0m`);
72
+ hasErrors = true;
73
+ continue;
74
+ }
68
75
  }
69
76
 
70
77
  console.log(`\x1b[32m✓\x1b[0m Copying ${hook}...`);
71
78
  fs.copyFileSync(src, dest);
79
+ // Preserve executable bit for shell scripts
80
+ if (hook.endsWith('.sh')) {
81
+ try { fs.chmodSync(dest, 0o755); } catch (e) { /* Windows */ }
82
+ }
72
83
  }
73
84
 
74
85
  if (hasErrors) {
@@ -72,6 +72,7 @@ ALLOWLIST=(
72
72
  'tests/security-scan.test.cjs'
73
73
  'tests/security.test.cjs'
74
74
  'tests/prompt-injection-scan.test.cjs'
75
+ 'tests/verify.test.cjs'
75
76
  'sdd/bin/lib/security.cjs'
76
77
  'hooks/sdd-prompt-guard.js'
77
78
  'SECURITY.md'