@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
@@ -4,7 +4,7 @@
4
4
 
5
5
  const fs = require('fs');
6
6
  const path = require('path');
7
- const { output, error, planningRoot } = require('./core.cjs');
7
+ const { output, error, planningDir, withPlanningLock, CONFIG_DEFAULTS, atomicWriteFileSync } = require('./core.cjs');
8
8
  const {
9
9
  VALID_PROFILES,
10
10
  getAgentToModelMapForProfile,
@@ -15,16 +15,28 @@ const VALID_CONFIG_KEYS = new Set([
15
15
  'mode', 'granularity', 'parallelization', 'commit_docs', 'model_profile',
16
16
  'search_gitignored', 'brave_search', 'firecrawl', 'exa_search',
17
17
  'workflow.research', 'workflow.plan_check', 'workflow.verifier',
18
- 'workflow.nyquist_validation', 'workflow.ui_phase', 'workflow.ui_safety_gate',
18
+ 'workflow.nyquist_validation', 'workflow.ai_integration_phase', 'workflow.ui_phase', 'workflow.ui_safety_gate',
19
19
  'workflow.auto_advance', 'workflow.node_repair', 'workflow.node_repair_budget',
20
20
  'workflow.text_mode',
21
21
  'workflow.research_before_questions',
22
22
  'workflow.discuss_mode',
23
23
  'workflow.skip_discuss',
24
24
  'workflow._auto_chain_active',
25
- 'git.branching_strategy', 'git.phase_branch_template', 'git.milestone_branch_template', 'git.quick_branch_template',
25
+ 'workflow.use_worktrees',
26
+ 'workflow.code_review',
27
+ 'workflow.code_review_depth',
28
+ 'git.branching_strategy', 'git.base_branch', 'git.phase_branch_template', 'git.milestone_branch_template', 'git.quick_branch_template',
26
29
  'planning.commit_docs', 'planning.search_gitignored',
30
+ 'workflow.subagent_timeout',
27
31
  'hooks.context_warnings',
32
+ 'features.thinking_partner',
33
+ 'context',
34
+ 'features.global_learnings',
35
+ 'learnings.max_inject',
36
+ 'project_code', 'phase_naming',
37
+ 'manager.flags.discuss', 'manager.flags.plan', 'manager.flags.execute',
38
+ 'response_language',
39
+ 'intel.enabled',
28
40
  ]);
29
41
 
30
42
  /**
@@ -36,6 +48,12 @@ function isValidConfigKey(keyPath) {
36
48
  if (VALID_CONFIG_KEYS.has(keyPath)) return true;
37
49
  // Allow agent_skills.<agent-type> with any agent type string
38
50
  if (/^agent_skills\.[a-zA-Z0-9_-]+$/.test(keyPath)) return true;
51
+ // Allow review.models.<cli-name> for per-CLI model selection in /sdd-review
52
+ if (/^review\.models\.[a-zA-Z0-9_-]+$/.test(keyPath)) return true;
53
+ // Allow features.<feature_name> — dynamic namespace for feature flags.
54
+ // Intentionally open-ended so new flags (e.g., features.global_learnings) work
55
+ // without updating VALID_CONFIG_KEYS each time.
56
+ if (/^features\.[a-zA-Z0-9_]+$/.test(keyPath)) return true;
39
57
  return false;
40
58
  }
41
59
 
@@ -45,6 +63,11 @@ const CONFIG_KEY_SUGGESTIONS = {
45
63
  'nyquist.validation_enabled': 'workflow.nyquist_validation',
46
64
  'hooks.research_questions': 'workflow.research_before_questions',
47
65
  'workflow.research_questions': 'workflow.research_before_questions',
66
+ 'workflow.codereview': 'workflow.code_review',
67
+ 'workflow.review': 'workflow.code_review',
68
+ 'workflow.code_review_level': 'workflow.code_review_depth',
69
+ 'workflow.review_depth': 'workflow.code_review_depth',
70
+ 'review.model': 'review.models.<cli-name>',
48
71
  };
49
72
 
50
73
  function validateKnownConfigKeyPath(keyPath) {
@@ -60,7 +83,7 @@ function validateKnownConfigKeyPath(keyPath) {
60
83
  * Merges (increasing priority):
61
84
  * 1. Hardcoded defaults — every key that loadConfig() resolves, plus mode/granularity
62
85
  * 2. User-level defaults from ~/.sdd/defaults.json (if present)
63
- * 3. userChoices — the settings the user explicitly selected during /sdd:new-project
86
+ * 3. userChoices — the settings the user explicitly selected during /sdd-new-project
64
87
  *
65
88
  * Uses the canonical `git` namespace for branching keys (consistent with VALID_CONFIG_KEYS
66
89
  * and the settings workflow). loadConfig() handles both flat and nested formats, so this
@@ -101,18 +124,18 @@ function buildNewProjectConfig(userChoices) {
101
124
  }
102
125
 
103
126
  const hardcoded = {
104
- model_profile: 'balanced',
105
- commit_docs: true,
106
- parallelization: true,
107
- search_gitignored: false,
127
+ model_profile: CONFIG_DEFAULTS.model_profile,
128
+ commit_docs: CONFIG_DEFAULTS.commit_docs,
129
+ parallelization: CONFIG_DEFAULTS.parallelization,
130
+ search_gitignored: CONFIG_DEFAULTS.search_gitignored,
108
131
  brave_search: hasBraveSearch,
109
132
  firecrawl: hasFirecrawl,
110
133
  exa_search: hasExaSearch,
111
134
  git: {
112
- branching_strategy: 'none',
113
- phase_branch_template: 'sdd/phase-{phase}-{slug}',
114
- milestone_branch_template: 'sdd/{milestone}-{slug}',
115
- quick_branch_template: null,
135
+ branching_strategy: CONFIG_DEFAULTS.branching_strategy,
136
+ phase_branch_template: CONFIG_DEFAULTS.phase_branch_template,
137
+ milestone_branch_template: CONFIG_DEFAULTS.milestone_branch_template,
138
+ quick_branch_template: CONFIG_DEFAULTS.quick_branch_template,
116
139
  },
117
140
  workflow: {
118
141
  research: true,
@@ -124,14 +147,19 @@ function buildNewProjectConfig(userChoices) {
124
147
  node_repair_budget: 2,
125
148
  ui_phase: true,
126
149
  ui_safety_gate: true,
150
+ ai_integration_phase: true,
127
151
  text_mode: false,
128
152
  research_before_questions: false,
129
153
  discuss_mode: 'discuss',
130
154
  skip_discuss: false,
155
+ code_review: true,
156
+ code_review_depth: 'standard',
131
157
  },
132
158
  hooks: {
133
159
  context_warnings: true,
134
160
  },
161
+ project_code: null,
162
+ phase_naming: 'sequential',
135
163
  agent_skills: {},
136
164
  };
137
165
 
@@ -167,13 +195,13 @@ function buildNewProjectConfig(userChoices) {
167
195
  * Command: create a fully-materialized .planning/config.json for a new project.
168
196
  *
169
197
  * Accepts user-chosen settings as a JSON string (the keys the user explicitly
170
- * configured during /sdd:new-project). All remaining keys are filled from
198
+ * configured during /sdd-new-project). All remaining keys are filled from
171
199
  * hardcoded defaults and optional ~/.sdd/defaults.json.
172
200
  *
173
201
  * Idempotent: if config.json already exists, returns { created: false }.
174
202
  */
175
203
  function cmdConfigNewProject(cwd, choicesJson, raw) {
176
- const planningBase = planningRoot(cwd);
204
+ const planningBase = planningDir(cwd);
177
205
  const configPath = path.join(planningBase, 'config.json');
178
206
 
179
207
  // Idempotent: don't overwrite existing config
@@ -204,7 +232,7 @@ function cmdConfigNewProject(cwd, choicesJson, raw) {
204
232
  const config = buildNewProjectConfig(userChoices);
205
233
 
206
234
  try {
207
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
235
+ atomicWriteFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
208
236
  output({ created: true, path: '.planning/config.json' }, raw, 'created');
209
237
  } catch (err) {
210
238
  error('Failed to write config.json: ' + err.message);
@@ -218,7 +246,7 @@ function cmdConfigNewProject(cwd, choicesJson, raw) {
218
246
  * the happy path. But note that `error()` will still `exit(1)` out of the process.
219
247
  */
220
248
  function ensureConfigFile(cwd) {
221
- const planningBase = planningRoot(cwd);
249
+ const planningBase = planningDir(cwd);
222
250
  const configPath = path.join(planningBase, 'config.json');
223
251
 
224
252
  // Ensure .planning directory exists
@@ -238,7 +266,7 @@ function ensureConfigFile(cwd) {
238
266
  const config = buildNewProjectConfig({});
239
267
 
240
268
  try {
241
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
269
+ atomicWriteFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
242
270
  return { created: true, path: '.planning/config.json' };
243
271
  } catch (err) {
244
272
  error('Failed to create config.json: ' + err.message);
@@ -268,38 +296,40 @@ function cmdConfigEnsureSection(cwd, raw) {
268
296
  * the happy path. But note that `error()` will still `exit(1)` out of the process.
269
297
  */
270
298
  function setConfigValue(cwd, keyPath, parsedValue) {
271
- const configPath = path.join(planningRoot(cwd), 'config.json');
299
+ const configPath = path.join(planningDir(cwd), 'config.json');
272
300
 
273
- // Load existing config or start with empty object
274
- let config = {};
275
- try {
276
- if (fs.existsSync(configPath)) {
277
- config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
301
+ return withPlanningLock(cwd, () => {
302
+ // Load existing config or start with empty object
303
+ let config = {};
304
+ try {
305
+ if (fs.existsSync(configPath)) {
306
+ config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
307
+ }
308
+ } catch (err) {
309
+ error('Failed to read config.json: ' + err.message);
278
310
  }
279
- } catch (err) {
280
- error('Failed to read config.json: ' + err.message);
281
- }
282
311
 
283
- // Set nested value using dot notation (e.g., "workflow.research")
284
- const keys = keyPath.split('.');
285
- let current = config;
286
- for (let i = 0; i < keys.length - 1; i++) {
287
- const key = keys[i];
288
- if (current[key] === undefined || typeof current[key] !== 'object') {
289
- current[key] = {};
312
+ // Set nested value using dot notation (e.g., "workflow.research")
313
+ const keys = keyPath.split('.');
314
+ let current = config;
315
+ for (let i = 0; i < keys.length - 1; i++) {
316
+ const key = keys[i];
317
+ if (current[key] === undefined || typeof current[key] !== 'object') {
318
+ current[key] = {};
319
+ }
320
+ current = current[key];
290
321
  }
291
- current = current[key];
292
- }
293
- const previousValue = current[keys[keys.length - 1]]; // Capture previous value before overwriting
294
- current[keys[keys.length - 1]] = parsedValue;
322
+ const previousValue = current[keys[keys.length - 1]]; // Capture previous value before overwriting
323
+ current[keys[keys.length - 1]] = parsedValue;
295
324
 
296
- // Write back
297
- try {
298
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
299
- return { updated: true, key: keyPath, value: parsedValue, previousValue };
300
- } catch (err) {
301
- error('Failed to write config.json: ' + err.message);
302
- }
325
+ // Write back
326
+ try {
327
+ atomicWriteFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
328
+ return { updated: true, key: keyPath, value: parsedValue, previousValue };
329
+ } catch (err) {
330
+ error('Failed to write config.json: ' + err.message);
331
+ }
332
+ });
303
333
  }
304
334
 
305
335
  /**
@@ -317,7 +347,7 @@ function cmdConfigSet(cwd, keyPath, value, raw) {
317
347
  validateKnownConfigKeyPath(keyPath);
318
348
 
319
349
  if (!isValidConfigKey(keyPath)) {
320
- error(`Unknown config key: "${keyPath}". Valid keys: ${[...VALID_CONFIG_KEYS].sort().join(', ')}, agent_skills.<agent-type>`);
350
+ error(`Unknown config key: "${keyPath}". Valid keys: ${[...VALID_CONFIG_KEYS].sort().join(', ')}, agent_skills.<agent-type>, features.<feature_name>`);
321
351
  }
322
352
 
323
353
  // Parse value (handle booleans, numbers, and JSON arrays/objects)
@@ -329,21 +359,30 @@ function cmdConfigSet(cwd, keyPath, value, raw) {
329
359
  try { parsedValue = JSON.parse(value); } catch { /* keep as string */ }
330
360
  }
331
361
 
362
+ const VALID_CONTEXT_VALUES = ['dev', 'research', 'review'];
363
+ if (keyPath === 'context' && !VALID_CONTEXT_VALUES.includes(String(parsedValue))) {
364
+ error(`Invalid context value '${value}'. Valid values: ${VALID_CONTEXT_VALUES.join(', ')}`);
365
+ }
366
+
332
367
  const setConfigValueResult = setConfigValue(cwd, keyPath, parsedValue);
333
368
  output(setConfigValueResult, raw, `${keyPath}=${parsedValue}`);
334
369
  }
335
370
 
336
- function cmdConfigGet(cwd, keyPath, raw) {
337
- const configPath = path.join(planningRoot(cwd), 'config.json');
371
+ function cmdConfigGet(cwd, keyPath, raw, defaultValue) {
372
+ const configPath = path.join(planningDir(cwd), 'config.json');
373
+ const hasDefault = defaultValue !== undefined;
338
374
 
339
375
  if (!keyPath) {
340
- error('Usage: config-get <key.path>');
376
+ error('Usage: config-get <key.path> [--default <value>]');
341
377
  }
342
378
 
343
379
  let config = {};
344
380
  try {
345
381
  if (fs.existsSync(configPath)) {
346
382
  config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
383
+ } else if (hasDefault) {
384
+ output(defaultValue, raw, String(defaultValue));
385
+ return;
347
386
  } else {
348
387
  error('No config.json found at ' + configPath);
349
388
  }
@@ -357,12 +396,14 @@ function cmdConfigGet(cwd, keyPath, raw) {
357
396
  let current = config;
358
397
  for (const key of keys) {
359
398
  if (current === undefined || current === null || typeof current !== 'object') {
399
+ if (hasDefault) { output(defaultValue, raw, String(defaultValue)); return; }
360
400
  error(`Key not found: ${keyPath}`);
361
401
  }
362
402
  current = current[key];
363
403
  }
364
404
 
365
405
  if (current === undefined) {
406
+ if (hasDefault) { output(defaultValue, raw, String(defaultValue)); return; }
366
407
  error(`Key not found: ${keyPath}`);
367
408
  }
368
409
 
@@ -434,6 +475,7 @@ function getCmdConfigSetModelProfileResultMessage(
434
475
  }
435
476
 
436
477
  module.exports = {
478
+ VALID_CONFIG_KEYS,
437
479
  cmdConfigEnsureSection,
438
480
  cmdConfigSet,
439
481
  cmdConfigGet,