gsd-antigravity-kit 2.0.1 → 2.1.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 (251) hide show
  1. package/.agent/skills/gsd/SKILL.md +26 -4
  2. package/.agent/skills/gsd/VERSION +1 -1
  3. package/.agent/skills/gsd/assets/templates/AI-SPEC.md +246 -0
  4. package/.agent/skills/gsd/assets/templates/DEBUG.md +7 -2
  5. package/.agent/skills/gsd/assets/templates/config.json +56 -48
  6. package/.agent/skills/gsd/assets/templates/research.md +40 -0
  7. package/.agent/skills/gsd/assets/templates/spec.md +307 -0
  8. package/.agent/skills/gsd/assets/templates/state.md +8 -0
  9. package/.agent/skills/gsd/bin/gsd-tools.cjs +212 -11
  10. package/.agent/skills/gsd/bin/help-manifest.json +8 -2
  11. package/.agent/skills/gsd/bin/hooks/gsd-check-update-worker.js +108 -0
  12. package/.agent/skills/gsd/bin/hooks/gsd-check-update.js +14 -89
  13. package/.agent/skills/gsd/bin/hooks/gsd-context-monitor.js +34 -5
  14. package/.agent/skills/gsd/bin/hooks/gsd-phase-boundary.sh +1 -0
  15. package/.agent/skills/gsd/bin/hooks/gsd-prompt-guard.js +1 -1
  16. package/.agent/skills/gsd/bin/hooks/gsd-read-guard.js +6 -1
  17. package/.agent/skills/gsd/bin/hooks/gsd-session-state.sh +1 -0
  18. package/.agent/skills/gsd/bin/hooks/gsd-statusline.js +150 -16
  19. package/.agent/skills/gsd/bin/hooks/gsd-validate-commit.sh +1 -0
  20. package/.agent/skills/gsd/bin/hooks/gsd-workflow-guard.js +1 -1
  21. package/.agent/skills/gsd/bin/lib/audit.cjs +757 -0
  22. package/.agent/skills/gsd/bin/lib/commands.cjs +17 -7
  23. package/.agent/skills/gsd/bin/lib/config.cjs +66 -20
  24. package/.agent/skills/gsd/bin/lib/core.cjs +212 -12
  25. package/.agent/skills/gsd/bin/lib/frontmatter.cjs +6 -8
  26. package/.agent/skills/gsd/bin/lib/graphify.cjs +494 -0
  27. package/.agent/skills/gsd/bin/lib/gsd2-import.cjs +511 -0
  28. package/.agent/skills/gsd/bin/lib/init.cjs +371 -18
  29. package/.agent/skills/gsd/bin/lib/intel.cjs +9 -30
  30. package/.agent/skills/gsd/bin/lib/milestone.cjs +18 -17
  31. package/.agent/skills/gsd/bin/lib/model-profiles.cjs +1 -0
  32. package/.agent/skills/gsd/bin/lib/phase.cjs +225 -98
  33. package/.agent/skills/gsd/bin/lib/profile-output.cjs +17 -5
  34. package/.agent/skills/gsd/bin/lib/roadmap.cjs +12 -5
  35. package/.agent/skills/gsd/bin/lib/state.cjs +394 -129
  36. package/.agent/skills/gsd/bin/lib/template.cjs +8 -4
  37. package/.agent/skills/gsd/bin/lib/uat.cjs +2 -1
  38. package/.agent/skills/gsd/bin/lib/verify.cjs +111 -42
  39. package/.agent/skills/gsd/migration_report.md +2 -2
  40. package/.agent/skills/gsd/references/agents/gsd-advisor-researcher.md +23 -0
  41. package/.agent/skills/gsd/references/agents/gsd-ai-researcher.md +133 -0
  42. package/.agent/skills/gsd/references/agents/gsd-code-fixer.md +11 -10
  43. package/.agent/skills/gsd/references/agents/gsd-code-reviewer.md +2 -2
  44. package/.agent/skills/gsd/references/agents/gsd-codebase-mapper.md +13 -2
  45. package/.agent/skills/gsd/references/agents/gsd-debug-session-manager.md +314 -0
  46. package/.agent/skills/gsd/references/agents/gsd-debugger.md +147 -76
  47. package/.agent/skills/gsd/references/agents/gsd-doc-verifier.md +1 -1
  48. package/.agent/skills/gsd/references/agents/gsd-doc-writer.md +615 -602
  49. package/.agent/skills/gsd/references/agents/gsd-domain-researcher.md +153 -0
  50. package/.agent/skills/gsd/references/agents/gsd-eval-auditor.md +175 -0
  51. package/.agent/skills/gsd/references/agents/gsd-eval-planner.md +154 -0
  52. package/.agent/skills/gsd/references/agents/gsd-executor.md +108 -38
  53. package/.agent/skills/gsd/references/agents/gsd-framework-selector.md +160 -0
  54. package/.agent/skills/gsd/references/agents/gsd-integration-checker.md +454 -443
  55. package/.agent/skills/gsd/references/agents/gsd-intel-updater.md +40 -20
  56. package/.agent/skills/gsd/references/agents/gsd-nyquist-auditor.md +187 -176
  57. package/.agent/skills/gsd/references/agents/gsd-pattern-mapper.md +335 -0
  58. package/.agent/skills/gsd/references/agents/gsd-phase-researcher.md +112 -13
  59. package/.agent/skills/gsd/references/agents/gsd-plan-checker.md +104 -10
  60. package/.agent/skills/gsd/references/agents/gsd-planner.md +125 -167
  61. package/.agent/skills/gsd/references/agents/gsd-project-researcher.md +25 -2
  62. package/.agent/skills/gsd/references/agents/gsd-research-synthesizer.md +3 -3
  63. package/.agent/skills/gsd/references/agents/gsd-roadmapper.md +12 -1
  64. package/.agent/skills/gsd/references/agents/gsd-security-auditor.md +139 -128
  65. package/.agent/skills/gsd/references/agents/gsd-ui-auditor.md +3 -3
  66. package/.agent/skills/gsd/references/agents/gsd-ui-checker.md +11 -2
  67. package/.agent/skills/gsd/references/agents/gsd-ui-researcher.md +27 -4
  68. package/.agent/skills/gsd/references/agents/gsd-verifier.md +13 -19
  69. package/.agent/skills/gsd/references/commands/atomic/add-todo.md +2 -2
  70. package/.agent/skills/gsd/references/commands/atomic/check-todos.md +2 -2
  71. package/.agent/skills/gsd/references/commands/atomic/cleanup.md +2 -2
  72. package/.agent/skills/gsd/references/commands/atomic/do.md +2 -2
  73. package/.agent/skills/gsd/references/commands/atomic/help.md +2 -2
  74. package/.agent/skills/gsd/references/commands/atomic/join-discord.md +2 -2
  75. package/.agent/skills/gsd/references/commands/atomic/note.md +2 -2
  76. package/.agent/skills/gsd/references/commands/atomic/session-report.md +2 -2
  77. package/.agent/skills/gsd/references/commands/atomic/ship.md +2 -2
  78. package/.agent/skills/gsd/references/commands/atomic/stats.md +2 -2
  79. package/.agent/skills/gsd/references/commands/atomic/thread.md +141 -41
  80. package/.agent/skills/gsd/references/commands/atomic/undo.md +2 -2
  81. package/.agent/skills/gsd/references/commands/milestone/add-backlog.md +15 -12
  82. package/.agent/skills/gsd/references/commands/milestone/audit-milestone.md +2 -2
  83. package/.agent/skills/gsd/references/commands/milestone/complete-milestone.md +2 -2
  84. package/.agent/skills/gsd/references/commands/milestone/milestone-summary.md +2 -2
  85. package/.agent/skills/gsd/references/commands/milestone/new-milestone.md +2 -2
  86. package/.agent/skills/gsd/references/commands/milestone/plan-milestone-gaps.md +2 -2
  87. package/.agent/skills/gsd/references/commands/milestone/plant-seed.md +2 -2
  88. package/.agent/skills/gsd/references/commands/milestone/review-backlog.md +4 -4
  89. package/.agent/skills/gsd/references/commands/misc/ai-integration-phase.md +38 -0
  90. package/.agent/skills/gsd/references/commands/misc/audit-fix.md +2 -2
  91. package/.agent/skills/gsd/references/commands/misc/audit-uat.md +2 -2
  92. package/.agent/skills/gsd/references/commands/misc/eval-review.md +34 -0
  93. package/.agent/skills/gsd/references/commands/misc/extract_learnings.md +24 -0
  94. package/.agent/skills/gsd/references/commands/misc/from-gsd2.md +49 -0
  95. package/.agent/skills/gsd/references/commands/misc/graphify.md +203 -0
  96. package/.agent/skills/gsd/references/commands/misc/inbox.md +40 -0
  97. package/.agent/skills/gsd/references/commands/misc/next.md +5 -3
  98. package/.agent/skills/gsd/references/commands/misc/progress.md +4 -3
  99. package/.agent/skills/gsd/references/commands/misc/sketch-wrap-up.md +33 -0
  100. package/.agent/skills/gsd/references/commands/misc/sketch.md +47 -0
  101. package/.agent/skills/gsd/references/commands/misc/spec-phase.md +64 -0
  102. package/.agent/skills/gsd/references/commands/misc/spike-wrap-up.md +33 -0
  103. package/.agent/skills/gsd/references/commands/misc/spike.md +43 -0
  104. package/.agent/skills/gsd/references/commands/misc/verify-work.md +2 -2
  105. package/.agent/skills/gsd/references/commands/phase/add-phase.md +2 -2
  106. package/.agent/skills/gsd/references/commands/phase/add-tests.md +2 -2
  107. package/.agent/skills/gsd/references/commands/phase/discuss-phase.md +5 -5
  108. package/.agent/skills/gsd/references/commands/phase/execute-phase.md +4 -4
  109. package/.agent/skills/gsd/references/commands/phase/insert-phase.md +2 -2
  110. package/.agent/skills/gsd/references/commands/phase/list-phase-assumptions.md +2 -2
  111. package/.agent/skills/gsd/references/commands/phase/plan-phase.md +3 -3
  112. package/.agent/skills/gsd/references/commands/phase/remove-phase.md +2 -2
  113. package/.agent/skills/gsd/references/commands/phase/research-phase.md +5 -5
  114. package/.agent/skills/gsd/references/commands/phase/secure-phase.md +2 -2
  115. package/.agent/skills/gsd/references/commands/phase/ui-phase.md +2 -2
  116. package/.agent/skills/gsd/references/commands/phase/ui-review.md +2 -2
  117. package/.agent/skills/gsd/references/commands/phase/validate-phase.md +2 -2
  118. package/.agent/skills/gsd/references/commands/phase/workstreams.md +9 -9
  119. package/.agent/skills/gsd/references/commands/project/analyze-dependencies.md +2 -2
  120. package/.agent/skills/gsd/references/commands/project/explore.md +2 -2
  121. package/.agent/skills/gsd/references/commands/project/import.md +2 -2
  122. package/.agent/skills/gsd/references/commands/project/intel.md +10 -10
  123. package/.agent/skills/gsd/references/commands/project/list-workspaces.md +2 -2
  124. package/.agent/skills/gsd/references/commands/project/map-codebase.md +2 -2
  125. package/.agent/skills/gsd/references/commands/project/new-project.md +2 -2
  126. package/.agent/skills/gsd/references/commands/project/new-workspace.md +2 -2
  127. package/.agent/skills/gsd/references/commands/project/remove-workspace.md +2 -2
  128. package/.agent/skills/gsd/references/commands/project/scan.md +2 -2
  129. package/.agent/skills/gsd/references/commands/system/autonomous.md +4 -3
  130. package/.agent/skills/gsd/references/commands/system/code-review-fix.md +3 -3
  131. package/.agent/skills/gsd/references/commands/system/code-review.md +3 -3
  132. package/.agent/skills/gsd/references/commands/system/debug.md +177 -100
  133. package/.agent/skills/gsd/references/commands/system/docs-update.md +2 -2
  134. package/.agent/skills/gsd/references/commands/system/fast.md +2 -2
  135. package/.agent/skills/gsd/references/commands/system/forensics.md +2 -2
  136. package/.agent/skills/gsd/references/commands/system/gsd-tools.md +153 -6
  137. package/.agent/skills/gsd/references/commands/system/health.md +2 -2
  138. package/.agent/skills/gsd/references/commands/system/manager.md +3 -3
  139. package/.agent/skills/gsd/references/commands/system/pause-work.md +2 -2
  140. package/.agent/skills/gsd/references/commands/system/pr-branch.md +2 -2
  141. package/.agent/skills/gsd/references/commands/system/profile-user.md +2 -2
  142. package/.agent/skills/gsd/references/commands/system/quick.md +127 -3
  143. package/.agent/skills/gsd/references/commands/system/reapply-patches.md +45 -6
  144. package/.agent/skills/gsd/references/commands/system/resume-work.md +2 -2
  145. package/.agent/skills/gsd/references/commands/system/review.md +6 -4
  146. package/.agent/skills/gsd/references/commands/system/set-profile.md +3 -3
  147. package/.agent/skills/gsd/references/commands/system/settings.md +2 -2
  148. package/.agent/skills/gsd/references/commands/system/update.md +2 -2
  149. package/.agent/skills/gsd/references/docs/ai-evals.md +156 -0
  150. package/.agent/skills/gsd/references/docs/ai-frameworks.md +186 -0
  151. package/.agent/skills/gsd/references/docs/artifact-types.md +18 -0
  152. package/.agent/skills/gsd/references/docs/autonomous-smart-discuss.md +277 -0
  153. package/.agent/skills/gsd/references/docs/checkpoints.md +30 -0
  154. package/.agent/skills/gsd/references/docs/common-bug-patterns.md +49 -49
  155. package/.agent/skills/gsd/references/docs/continuation-format.md +11 -7
  156. package/.agent/skills/gsd/references/docs/debugger-philosophy.md +76 -0
  157. package/.agent/skills/gsd/references/docs/decimal-phase-calculation.md +64 -64
  158. package/.agent/skills/gsd/references/docs/executor-examples.md +110 -0
  159. package/.agent/skills/gsd/references/docs/git-integration.md +4 -4
  160. package/.agent/skills/gsd/references/docs/git-planning-commit.md +40 -38
  161. package/.agent/skills/gsd/references/docs/ios-scaffold.md +123 -0
  162. package/.agent/skills/gsd/references/docs/mandatory-initial-read.md +2 -0
  163. package/.agent/skills/gsd/references/docs/phase-argument-parsing.md +61 -61
  164. package/.agent/skills/gsd/references/docs/planner-antipatterns.md +89 -0
  165. package/.agent/skills/gsd/references/docs/planner-revision.md +87 -87
  166. package/.agent/skills/gsd/references/docs/planner-source-audit.md +73 -0
  167. package/.agent/skills/gsd/references/docs/planning-config.md +33 -8
  168. package/.agent/skills/gsd/references/docs/project-skills-discovery.md +19 -0
  169. package/.agent/skills/gsd/references/docs/sketch-interactivity.md +41 -0
  170. package/.agent/skills/gsd/references/docs/sketch-theme-system.md +94 -0
  171. package/.agent/skills/gsd/references/docs/sketch-tooling.md +45 -0
  172. package/.agent/skills/gsd/references/docs/sketch-variant-patterns.md +81 -0
  173. package/.agent/skills/gsd/references/docs/tdd.md +67 -0
  174. package/.agent/skills/gsd/references/docs/universal-anti-patterns.md +5 -0
  175. package/.agent/skills/gsd/references/docs/workstream-flag.md +11 -11
  176. package/.agent/skills/gsd/references/mapping.md +1 -1
  177. package/.agent/skills/gsd/references/workflows/add-phase.md +112 -112
  178. package/.agent/skills/gsd/references/workflows/add-tests.md +6 -3
  179. package/.agent/skills/gsd/references/workflows/add-todo.md +5 -3
  180. package/.agent/skills/gsd/references/workflows/ai-integration-phase.md +284 -0
  181. package/.agent/skills/gsd/references/workflows/audit-fix.md +157 -157
  182. package/.agent/skills/gsd/references/workflows/audit-milestone.md +340 -340
  183. package/.agent/skills/gsd/references/workflows/audit-uat.md +109 -109
  184. package/.agent/skills/gsd/references/workflows/autonomous.md +20 -288
  185. package/.agent/skills/gsd/references/workflows/check-todos.md +4 -2
  186. package/.agent/skills/gsd/references/workflows/cleanup.md +3 -1
  187. package/.agent/skills/gsd/references/workflows/code-review-fix.md +497 -497
  188. package/.agent/skills/gsd/references/workflows/code-review.md +515 -515
  189. package/.agent/skills/gsd/references/workflows/complete-milestone.md +97 -24
  190. package/.agent/skills/gsd/references/workflows/diagnose-issues.md +238 -238
  191. package/.agent/skills/gsd/references/workflows/discovery-phase.md +2 -0
  192. package/.agent/skills/gsd/references/workflows/discuss-phase-assumptions.md +11 -11
  193. package/.agent/skills/gsd/references/workflows/discuss-phase.md +143 -19
  194. package/.agent/skills/gsd/references/workflows/do.md +8 -2
  195. package/.agent/skills/gsd/references/workflows/docs-update.md +5 -3
  196. package/.agent/skills/gsd/references/workflows/eval-review.md +155 -0
  197. package/.agent/skills/gsd/references/workflows/execute-phase.md +338 -54
  198. package/.agent/skills/gsd/references/workflows/execute-plan.md +80 -104
  199. package/.agent/skills/gsd/references/workflows/explore.md +3 -1
  200. package/.agent/skills/gsd/references/workflows/extract_learnings.md +232 -0
  201. package/.agent/skills/gsd/references/workflows/forensics.md +3 -3
  202. package/.agent/skills/gsd/references/workflows/health.md +2 -2
  203. package/.agent/skills/gsd/references/workflows/help.md +59 -1
  204. package/.agent/skills/gsd/references/workflows/import.md +3 -1
  205. package/.agent/skills/gsd/references/workflows/inbox.md +387 -384
  206. package/.agent/skills/gsd/references/workflows/insert-phase.md +130 -130
  207. package/.agent/skills/gsd/references/workflows/list-workspaces.md +56 -56
  208. package/.agent/skills/gsd/references/workflows/manager.md +5 -3
  209. package/.agent/skills/gsd/references/workflows/map-codebase.md +19 -5
  210. package/.agent/skills/gsd/references/workflows/milestone-summary.md +6 -6
  211. package/.agent/skills/gsd/references/workflows/new-milestone.md +63 -9
  212. package/.agent/skills/gsd/references/workflows/new-project.md +126 -22
  213. package/.agent/skills/gsd/references/workflows/new-workspace.md +6 -4
  214. package/.agent/skills/gsd/references/workflows/next.md +220 -153
  215. package/.agent/skills/gsd/references/workflows/note.md +2 -0
  216. package/.agent/skills/gsd/references/workflows/pause-work.md +11 -7
  217. package/.agent/skills/gsd/references/workflows/plan-milestone-gaps.md +273 -273
  218. package/.agent/skills/gsd/references/workflows/plan-phase.md +281 -62
  219. package/.agent/skills/gsd/references/workflows/plant-seed.md +4 -1
  220. package/.agent/skills/gsd/references/workflows/pr-branch.md +41 -13
  221. package/.agent/skills/gsd/references/workflows/profile-user.md +15 -13
  222. package/.agent/skills/gsd/references/workflows/progress.md +133 -21
  223. package/.agent/skills/gsd/references/workflows/quick.md +67 -27
  224. package/.agent/skills/gsd/references/workflows/remove-phase.md +155 -155
  225. package/.agent/skills/gsd/references/workflows/remove-workspace.md +4 -2
  226. package/.agent/skills/gsd/references/workflows/research-phase.md +3 -3
  227. package/.agent/skills/gsd/references/workflows/resume-project.md +3 -3
  228. package/.agent/skills/gsd/references/workflows/review.md +71 -8
  229. package/.agent/skills/gsd/references/workflows/scan.md +102 -102
  230. package/.agent/skills/gsd/references/workflows/secure-phase.md +7 -5
  231. package/.agent/skills/gsd/references/workflows/settings.md +24 -7
  232. package/.agent/skills/gsd/references/workflows/ship.md +71 -6
  233. package/.agent/skills/gsd/references/workflows/sketch-wrap-up.md +283 -0
  234. package/.agent/skills/gsd/references/workflows/sketch.md +263 -0
  235. package/.agent/skills/gsd/references/workflows/spec-phase.md +262 -0
  236. package/.agent/skills/gsd/references/workflows/spike-wrap-up.md +273 -0
  237. package/.agent/skills/gsd/references/workflows/spike.md +270 -0
  238. package/.agent/skills/gsd/references/workflows/stats.md +60 -60
  239. package/.agent/skills/gsd/references/workflows/transition.md +671 -671
  240. package/.agent/skills/gsd/references/workflows/ui-phase.md +33 -12
  241. package/.agent/skills/gsd/references/workflows/ui-review.md +6 -4
  242. package/.agent/skills/gsd/references/workflows/undo.md +3 -1
  243. package/.agent/skills/gsd/references/workflows/update.md +113 -2
  244. package/.agent/skills/gsd/references/workflows/validate-phase.md +7 -5
  245. package/.agent/skills/gsd/references/workflows/verify-phase.md +93 -10
  246. package/.agent/skills/gsd/references/workflows/verify-work.md +50 -10
  247. package/.agent/skills/gsd-converter/references/mapping.md +1 -1
  248. package/.agent/skills/gsd-converter/scripts/convert.py +36 -17
  249. package/.agent/skills/gsd-converter/scripts/regression_test.py +68 -33
  250. package/README.md +3 -2
  251. package/package.json +1 -1
@@ -0,0 +1,307 @@
1
+ # Phase Spec Template
2
+
3
+ Template for `.planning/phases/XX-name/{phase_num}-SPEC.md` — locks requirements before discuss-phase.
4
+
5
+ **Purpose:** Capture WHAT a phase delivers and WHY, with enough precision that requirements are falsifiable. discuss-phase reads this file and focuses on HOW to implement (skipping "what/why" questions already answered here).
6
+
7
+ **Key principle:** Every requirement must be falsifiable — you can write a test or check that proves it was met or not. Vague requirements like "improve performance" are not allowed.
8
+
9
+ **Downstream consumers:**
10
+ - `discuss-phase` — reads SPEC.md at startup; treats Requirements, Boundaries, and Acceptance Criteria as locked; skips "what/why" questions
11
+ - `gsd-planner` — reads locked requirements to constrain plan scope
12
+ - `gsd-verifier` — uses acceptance criteria as explicit pass/fail checks
13
+
14
+ ---
15
+
16
+ ## File Template
17
+
18
+ ```markdown
19
+ # Phase [X]: [Name] — Specification
20
+
21
+ **Created:** [date]
22
+ **Ambiguity score:** [score] (gate: ≤ 0.20)
23
+ **Requirements:** [N] locked
24
+
25
+ ## Goal
26
+
27
+ [One precise sentence — specific and measurable. NOT "improve X" — instead "X changes from A to B".]
28
+
29
+ ## Background
30
+
31
+ [Current state from codebase — what exists today, what's broken or missing, what triggers this work. Grounded in code reality, not abstract description.]
32
+
33
+ ## Requirements
34
+
35
+ 1. **[Short label]**: [Specific, testable statement.]
36
+ - Current: [what exists or does NOT exist today]
37
+ - Target: [what it should become after this phase]
38
+ - Acceptance: [concrete pass/fail check — how a verifier confirms this was met]
39
+
40
+ 2. **[Short label]**: [Specific, testable statement.]
41
+ - Current: [what exists or does NOT exist today]
42
+ - Target: [what it should become after this phase]
43
+ - Acceptance: [concrete pass/fail check]
44
+
45
+ [Continue for all requirements. Each must have Current/Target/Acceptance.]
46
+
47
+ ## Boundaries
48
+
49
+ **In scope:**
50
+ - [Explicit list of what this phase produces]
51
+ - [Each item is a concrete deliverable or behavior]
52
+
53
+ **Out of scope:**
54
+ - [Explicit list of what this phase does NOT do] — [brief reason why it's excluded]
55
+ - [Adjacent problems excluded from this phase] — [brief reason]
56
+
57
+ ## Constraints
58
+
59
+ [Performance, compatibility, data volume, dependency, or platform constraints.
60
+ If none: "No additional constraints beyond standard project conventions."]
61
+
62
+ ## Acceptance Criteria
63
+
64
+ - [ ] [Pass/fail criterion — unambiguous, verifiable]
65
+ - [ ] [Pass/fail criterion]
66
+ - [ ] [Pass/fail criterion]
67
+
68
+ [Every acceptance criterion must be a checkbox that resolves to PASS or FAIL.
69
+ No "should feel good", "looks reasonable", or "generally works" — those are not checkboxes.]
70
+
71
+ ## Ambiguity Report
72
+
73
+ | Dimension | Score | Min | Status | Notes |
74
+ |--------------------|-------|------|--------|------------------------------------|
75
+ | Goal Clarity | | 0.75 | | |
76
+ | Boundary Clarity | | 0.70 | | |
77
+ | Constraint Clarity | | 0.65 | | |
78
+ | Acceptance Criteria| | 0.70 | | |
79
+ | **Ambiguity** | | ≤0.20| | |
80
+
81
+ Status: ✓ = met minimum, ⚠ = below minimum (planner treats as assumption)
82
+
83
+ ## Interview Log
84
+
85
+ [Key decisions made during the Socratic interview. Format: round → question → answer → decision locked.]
86
+
87
+ | Round | Perspective | Question summary | Decision locked |
88
+ |-------|----------------|-------------------------|------------------------------------|
89
+ | 1 | Researcher | [what was asked] | [what was decided] |
90
+ | 2 | Simplifier | [what was asked] | [what was decided] |
91
+ | 3 | Boundary Keeper| [what was asked] | [what was decided] |
92
+
93
+ [If --auto mode: note "auto-selected" decisions with the reasoning Antigravity used.]
94
+
95
+ ---
96
+
97
+ *Phase: [XX-name]*
98
+ *Spec created: [date]*
99
+ *Next step: /gsd-discuss-phase [X] — implementation decisions (how to build what's specified above)*
100
+ ```
101
+
102
+ <good_examples>
103
+
104
+ **Example 1: Feature addition (Post Feed)**
105
+
106
+ ```markdown
107
+ # Phase 3: Post Feed — Specification
108
+
109
+ **Created:** 2025-01-20
110
+ **Ambiguity score:** 0.12
111
+ **Requirements:** 4 locked
112
+
113
+ ## Goal
114
+
115
+ Users can scroll through posts from accounts they follow, with new posts available after pull-to-refresh.
116
+
117
+ ## Background
118
+
119
+ The database has a `posts` table and `follows` table. No feed query or feed UI exists today. The home screen shows a placeholder "Your feed will appear here." This phase builds the feed query, API endpoint, and the feed list component.
120
+
121
+ ## Requirements
122
+
123
+ 1. **Feed query**: Returns posts from followed accounts ordered by creation time, descending.
124
+ - Current: No feed query exists — `posts` table is queried directly only from profile pages
125
+ - Target: `GET /api/feed` returns paginated posts from followed accounts, newest first, max 20 per page
126
+ - Acceptance: Query returns correct posts for a user who follows 3 accounts with known post counts; cursor-based pagination advances correctly
127
+
128
+ 2. **Feed display**: Posts display in a scrollable card list.
129
+ - Current: Home screen shows static placeholder text
130
+ - Target: Home screen renders feed cards with author, timestamp, post content, and reaction count
131
+ - Acceptance: Feed renders without error for 0 posts (empty state shown), 1 post, and 20+ posts
132
+
133
+ 3. **Pull-to-refresh**: User can refresh the feed manually.
134
+ - Current: No refresh mechanism exists
135
+ - Target: Pull-down gesture triggers refetch; new posts appear at top of list
136
+ - Acceptance: After a new post is created in test, pull-to-refresh shows the new post without full app restart
137
+
138
+ 4. **New posts indicator**: When new posts arrive, a banner appears instead of auto-scrolling.
139
+ - Current: No such mechanism
140
+ - Target: "3 new posts" banner appears when refetch returns posts newer than the oldest visible post; tapping banner scrolls to top and shows new posts
141
+ - Acceptance: Banner appears for ≥1 new post, does not appear when no new posts, tap navigates to top
142
+
143
+ ## Boundaries
144
+
145
+ **In scope:**
146
+ - Feed query (backend) — posts from followed accounts, paginated
147
+ - Feed list UI (frontend) — post cards with author, timestamp, content, reaction counts
148
+ - Pull-to-refresh gesture
149
+ - New posts indicator banner
150
+ - Empty state when user follows no one or no posts exist
151
+
152
+ **Out of scope:**
153
+ - Creating posts — that is Phase 4
154
+ - Reacting to posts — that is Phase 5
155
+ - Following/unfollowing accounts — that is Phase 2 (already done)
156
+ - Push notifications for new posts — separate backlog item
157
+
158
+ ## Constraints
159
+
160
+ - Feed query must use cursor-based pagination (not offset) — the database has 500K+ posts and offset pagination is unacceptably slow beyond page 3
161
+ - The feed card component must reuse the existing `<AvatarImage>` component from Phase 2
162
+
163
+ ## Acceptance Criteria
164
+
165
+ - [ ] `GET /api/feed` returns posts only from followed accounts (not all posts)
166
+ - [ ] `GET /api/feed` supports `cursor` parameter for pagination
167
+ - [ ] Feed renders correctly at 0, 1, and 20+ posts
168
+ - [ ] Pull-to-refresh triggers refetch
169
+ - [ ] New posts indicator appears when posts newer than current view exist
170
+ - [ ] Empty state renders when user follows no one
171
+
172
+ ## Ambiguity Report
173
+
174
+ | Dimension | Score | Min | Status | Notes |
175
+ |--------------------|-------|------|--------|----------------------------------|
176
+ | Goal Clarity | 0.92 | 0.75 | ✓ | |
177
+ | Boundary Clarity | 0.95 | 0.70 | ✓ | Explicit out-of-scope list |
178
+ | Constraint Clarity | 0.80 | 0.65 | ✓ | Cursor pagination required |
179
+ | Acceptance Criteria| 0.85 | 0.70 | ✓ | 6 pass/fail criteria |
180
+ | **Ambiguity** | 0.12 | ≤0.20| ✓ | |
181
+
182
+ ## Interview Log
183
+
184
+ | Round | Perspective | Question summary | Decision locked |
185
+ |-------|-----------------|------------------------------|-----------------------------------------|
186
+ | 1 | Researcher | What exists in posts today? | posts + follows tables exist, no feed |
187
+ | 2 | Simplifier | Minimum viable feed? | Cards + pull-refresh, no auto-scroll |
188
+ | 3 | Boundary Keeper | What's NOT this phase? | Creating posts, reactions out of scope |
189
+ | 3 | Boundary Keeper | What does done look like? | Scrollable feed with 4 card fields |
190
+
191
+ ---
192
+
193
+ *Phase: 03-post-feed*
194
+ *Spec created: 2025-01-20*
195
+ *Next step: /gsd-discuss-phase 3 — implementation decisions (card layout, loading skeleton, etc.)*
196
+ ```
197
+
198
+ **Example 2: CLI tool (Database backup)**
199
+
200
+ ```markdown
201
+ # Phase 2: Backup Command — Specification
202
+
203
+ **Created:** 2025-01-20
204
+ **Ambiguity score:** 0.15
205
+ **Requirements:** 3 locked
206
+
207
+ ## Goal
208
+
209
+ A `gsd backup` CLI command creates a reproducible database snapshot that can be restored by `gsd restore` (a separate phase).
210
+
211
+ ## Background
212
+
213
+ No backup tooling exists. The project uses PostgreSQL. Developers currently use `pg_dump` manually — there is no standardized process, no output naming convention, and no CI integration. Three incidents in the last quarter involved restoring from wrong or corrupt dumps.
214
+
215
+ ## Requirements
216
+
217
+ 1. **Backup creation**: CLI command executes a full database backup.
218
+ - Current: No `backup` subcommand exists in the CLI
219
+ - Target: `gsd backup` connects to the database (via `DATABASE_URL` env or `--db` flag), runs pg_dump, writes output to `./backups/YYYY-MM-DD_HH-MM-SS.dump`
220
+ - Acceptance: Running `gsd backup` on a test database creates a `.dump` file; running `pg_restore` on that file recreates the database without error
221
+
222
+ 2. **Network retry**: Transient network failures are retried automatically.
223
+ - Current: pg_dump fails immediately on network error
224
+ - Target: Backup retries up to 3 times with 5-second delay; 4th failure exits with code 1 and a message to stderr
225
+ - Acceptance: Simulating 2 sequential network failures causes 2 retries then success; simulating 4 failures causes exit code 1 and stderr message
226
+
227
+ 3. **Partial cleanup**: Failed backups do not leave corrupt files.
228
+ - Current: Manual pg_dump leaves partial files on failure
229
+ - Target: If backup fails after starting, the partial `.dump` file is deleted before exit
230
+ - Acceptance: After a simulated failure mid-dump, no `.dump` file exists in `./backups/`
231
+
232
+ ## Boundaries
233
+
234
+ **In scope:**
235
+ - `gsd backup` subcommand (full dump only)
236
+ - Output to `./backups/` directory (created if missing)
237
+ - Network retry (3 attempts)
238
+ - Partial file cleanup on failure
239
+
240
+ **Out of scope:**
241
+ - `gsd restore` — that is Phase 3
242
+ - Incremental backups — separate backlog item (full dump only for now)
243
+ - S3 or remote storage — separate backlog item
244
+ - Encryption — separate backlog item
245
+ - Scheduled/cron backups — separate backlog item
246
+
247
+ ## Constraints
248
+
249
+ - Must use `pg_dump` (not a custom query) — ensures compatibility with standard `pg_restore`
250
+ - `--no-retry` flag must be available for CI use (fail fast, no retries)
251
+
252
+ ## Acceptance Criteria
253
+
254
+ - [ ] `gsd backup` creates a `.dump` file in `./backups/YYYY-MM-DD_HH-MM-SS.dump` format
255
+ - [ ] `gsd backup` uses `DATABASE_URL` env var or `--db` flag for connection
256
+ - [ ] 3 retries on network failure, then exit code 1 with stderr message
257
+ - [ ] `--no-retry` flag skips retries and fails immediately on first error
258
+ - [ ] No partial `.dump` file left after a failed backup
259
+
260
+ ## Ambiguity Report
261
+
262
+ | Dimension | Score | Min | Status | Notes |
263
+ |--------------------|-------|------|--------|--------------------------------|
264
+ | Goal Clarity | 0.90 | 0.75 | ✓ | |
265
+ | Boundary Clarity | 0.95 | 0.70 | ✓ | Explicit out-of-scope list |
266
+ | Constraint Clarity | 0.75 | 0.65 | ✓ | pg_dump required |
267
+ | Acceptance Criteria| 0.80 | 0.70 | ✓ | 5 pass/fail criteria |
268
+ | **Ambiguity** | 0.15 | ≤0.20| ✓ | |
269
+
270
+ ## Interview Log
271
+
272
+ | Round | Perspective | Question summary | Decision locked |
273
+ |-------|-----------------|------------------------------|-----------------------------------------|
274
+ | 1 | Researcher | What backup tooling exists? | None — pg_dump manual only |
275
+ | 2 | Simplifier | Minimum viable backup? | Full dump only, local only |
276
+ | 3 | Boundary Keeper | What's NOT this phase? | Restore, S3, encryption excluded |
277
+ | 4 | Failure Analyst | What goes wrong on failure? | Partial files, CI fail-fast needed |
278
+
279
+ ---
280
+
281
+ *Phase: 02-backup-command*
282
+ *Spec created: 2025-01-20*
283
+ *Next step: /gsd-discuss-phase 2 — implementation decisions (progress reporting, flag design, etc.)*
284
+ ```
285
+
286
+ </good_examples>
287
+
288
+ <guidelines>
289
+ **Every requirement needs all three fields:**
290
+ - Current: grounds the requirement in reality — what exists today?
291
+ - Target: the concrete change — not "improve X" but "X becomes Y"
292
+ - Acceptance: the falsifiable check — how does a verifier confirm this?
293
+
294
+ **Ambiguity Report must reflect the actual interview.** If a dimension is below minimum, mark it ⚠ — the planner knows to treat it as an assumption rather than a locked requirement.
295
+
296
+ **Interview Log is evidence of rigor.** Don't skip it. It shows that requirements came from discovery, not assumption.
297
+
298
+ **Boundaries protect the phase from scope creep.** The out-of-scope list with reasoning is as important as the in-scope list. Future phases that touch adjacent areas can point to this SPEC.md to understand what was intentionally excluded.
299
+
300
+ **SPEC.md is a one-way door for requirements.** discuss-phase will treat these as locked. If requirements change after SPEC.md is written, the user should update SPEC.md first, then re-run discuss-phase.
301
+
302
+ **SPEC.md does NOT replace CONTEXT.md.** They serve different purposes:
303
+ - SPEC.md: what the phase delivers (requirements, boundaries, acceptance criteria)
304
+ - CONTEXT.md: how the phase will be implemented (decisions, patterns, tradeoffs)
305
+
306
+ discuss-phase generates CONTEXT.md after reading SPEC.md.
307
+ </guidelines>
@@ -66,6 +66,14 @@ None yet.
66
66
 
67
67
  None yet.
68
68
 
69
+ ## Deferred Items
70
+
71
+ Items acknowledged and carried forward from previous milestone close:
72
+
73
+ | Category | Item | Status | Deferred At |
74
+ |----------|------|--------|-------------|
75
+ | *(none)* | | | |
76
+
69
77
  ## Session Continuity
70
78
 
71
79
  Last session: [YYYY-MM-DD HH:MM]
@@ -182,6 +182,17 @@ async function main() {
182
182
  args.splice(pickIdx, 2);
183
183
  }
184
184
 
185
+ // --default <value>: for config-get, return this value instead of erroring
186
+ // when the key is absent. Allows workflows to express optional config reads
187
+ // without defensive `2>/dev/null || true` boilerplate (#1893).
188
+ const defaultIdx = args.indexOf('--default');
189
+ let defaultValue = undefined;
190
+ if (defaultIdx !== -1) {
191
+ defaultValue = args[defaultIdx + 1];
192
+ if (defaultValue === undefined) defaultValue = '';
193
+ args.splice(defaultIdx, 2);
194
+ }
195
+
185
196
  const command = args[0];
186
197
 
187
198
  if (!command) {
@@ -203,7 +214,7 @@ async function main() {
203
214
  // filesystem traversal on every invocation.
204
215
  const SKIP_ROOT_RESOLUTION = new Set([
205
216
  'generate-slug', 'current-timestamp', 'verify-path-exists',
206
- 'verify-summary', 'template', 'frontmatter',
217
+ 'verify-summary', 'template', 'frontmatter', 'detect-custom-files',
207
218
  ]);
208
219
  if (!SKIP_ROOT_RESOLUTION.has(command)) {
209
220
  cwd = findProjectRoot(cwd);
@@ -234,7 +245,7 @@ async function main() {
234
245
  }
235
246
  };
236
247
  try {
237
- await runCommand(command, args, cwd, raw);
248
+ await runCommand(command, args, cwd, raw, defaultValue);
238
249
  cleanup();
239
250
  } catch (e) {
240
251
  fs.writeSync = origWriteSync;
@@ -243,7 +254,27 @@ async function main() {
243
254
  return;
244
255
  }
245
256
 
246
- await runCommand(command, args, cwd, raw);
257
+ // Intercept stdout to transparently resolve @file: references (#1891).
258
+ // core.cjs output() writes @file:<path> when JSON > 50KB. The --pick path
259
+ // already resolves this, but the normal path wrote @file: to stdout, forcing
260
+ // every workflow to have a bash-specific `if [[ "$INIT" == @file:* ]]` check
261
+ // that breaks on PowerShell and other non-bash shells.
262
+ const origWriteSync2 = fs.writeSync;
263
+ const outChunks = [];
264
+ fs.writeSync = function (fd, data, ...rest) {
265
+ if (fd === 1) { outChunks.push(String(data)); return; }
266
+ return origWriteSync2.call(fs, fd, data, ...rest);
267
+ };
268
+ try {
269
+ await runCommand(command, args, cwd, raw, defaultValue);
270
+ } finally {
271
+ fs.writeSync = origWriteSync2;
272
+ }
273
+ let captured = outChunks.join('');
274
+ if (captured.startsWith('@file:')) {
275
+ captured = fs.readFileSync(captured.slice(6), 'utf-8');
276
+ }
277
+ origWriteSync2.call(fs, 1, captured);
247
278
  }
248
279
 
249
280
  /**
@@ -269,7 +300,7 @@ function extractField(obj, fieldPath) {
269
300
  return current;
270
301
  }
271
302
 
272
- async function runCommand(command, args, cwd, raw) {
303
+ async function runCommand(command, args, cwd, raw, defaultValue) {
273
304
  switch (command) {
274
305
  case 'state': {
275
306
  const subcommand = args[1];
@@ -323,6 +354,9 @@ async function runCommand(command, args, cwd, raw) {
323
354
  } else if (subcommand === 'sync') {
324
355
  const { verify } = parseNamedArgs(args, [], ['verify']);
325
356
  state.cmdStateSync(cwd, { verify }, raw);
357
+ } else if (subcommand === 'prune') {
358
+ const { 'keep-recent': keepRecent, 'dry-run': dryRun } = parseNamedArgs(args, ['keep-recent'], ['dry-run']);
359
+ state.cmdStatePrune(cwd, { keepRecent: keepRecent || '3', dryRun: !!dryRun }, raw);
326
360
  } else {
327
361
  state.cmdStateLoad(cwd, raw);
328
362
  }
@@ -477,7 +511,7 @@ async function runCommand(command, args, cwd, raw) {
477
511
  }
478
512
 
479
513
  case 'config-get': {
480
- config.cmdConfigGet(cwd, args[1], raw);
514
+ config.cmdConfigGet(cwd, args[1], raw, defaultValue);
481
515
  break;
482
516
  }
483
517
 
@@ -486,11 +520,21 @@ async function runCommand(command, args, cwd, raw) {
486
520
  break;
487
521
  }
488
522
 
523
+ case 'config-path': {
524
+ config.cmdConfigPath(cwd, raw);
525
+ break;
526
+ }
527
+
489
528
  case 'agent-skills': {
490
529
  init.cmdAgentSkills(cwd, args[1], raw);
491
530
  break;
492
531
  }
493
532
 
533
+ case 'skill-manifest': {
534
+ init.cmdSkillManifest(cwd, args, raw);
535
+ break;
536
+ }
537
+
494
538
  case 'history-digest': {
495
539
  commands.cmdHistoryDigest(cwd, raw);
496
540
  break;
@@ -556,6 +600,16 @@ async function runCommand(command, args, cwd, raw) {
556
600
  }
557
601
  }
558
602
  phase.cmdPhaseAdd(cwd, descArgs.join(' '), raw, customId);
603
+ } else if (subcommand === 'add-batch') {
604
+ // Accepts JSON array of descriptions via --descriptions '[...]' or positional args
605
+ const descFlagIdx = args.indexOf('--descriptions');
606
+ let descriptions;
607
+ if (descFlagIdx !== -1 && args[descFlagIdx + 1]) {
608
+ try { descriptions = JSON.parse(args[descFlagIdx + 1]); } catch (e) { error('--descriptions must be a JSON array'); }
609
+ } else {
610
+ descriptions = args.slice(2).filter(a => a !== '--raw');
611
+ }
612
+ phase.cmdPhaseAddBatch(cwd, descriptions, raw);
559
613
  } else if (subcommand === 'insert') {
560
614
  phase.cmdPhaseInsert(cwd, args[2], args.slice(3).join(' '), raw);
561
615
  } else if (subcommand === 'remove') {
@@ -564,7 +618,7 @@ async function runCommand(command, args, cwd, raw) {
564
618
  } else if (subcommand === 'complete') {
565
619
  phase.cmdPhaseComplete(cwd, args[2], raw);
566
620
  } else {
567
- error('Unknown phase subcommand. Available: next-decimal, add, insert, remove, complete');
621
+ error('Unknown phase subcommand. Available: next-decimal, add, add-batch, insert, remove, complete');
568
622
  }
569
623
  break;
570
624
  }
@@ -608,6 +662,18 @@ async function runCommand(command, args, cwd, raw) {
608
662
  break;
609
663
  }
610
664
 
665
+ case 'audit-open': {
666
+ const { auditOpenArtifacts, formatAuditReport } = require('./lib/audit.cjs');
667
+ const includeRaw = args.includes('--json');
668
+ const result = auditOpenArtifacts(cwd);
669
+ if (includeRaw) {
670
+ core.output(result, raw);
671
+ } else {
672
+ core.output(formatAuditReport(result), raw);
673
+ }
674
+ break;
675
+ }
676
+
611
677
  case 'uat': {
612
678
  const subcommand = args[1];
613
679
  const uat = require('./lib/uat.cjs');
@@ -653,13 +719,13 @@ async function runCommand(command, args, cwd, raw) {
653
719
  const includes = parseIncludeFlag(args);
654
720
  switch (workflow) {
655
721
  case 'execute-phase': {
656
- const { validate: epValidate } = parseNamedArgs(args, [], ['validate']);
657
- init.cmdInitExecutePhase(cwd, args[2], includes, raw, { validate: epValidate });
722
+ const { validate: epValidate, tdd: epTdd } = parseNamedArgs(args, [], ['validate', 'tdd']);
723
+ init.cmdInitExecutePhase(cwd, args[2], includes, raw, { validate: epValidate, tdd: epTdd });
658
724
  break;
659
725
  }
660
726
  case 'plan-phase': {
661
- const { validate: ppValidate } = parseNamedArgs(args, [], ['validate']);
662
- init.cmdInitPlanPhase(cwd, args[2], includes, raw, { validate: ppValidate });
727
+ const { validate: ppValidate, tdd: ppTdd } = parseNamedArgs(args, [], ['validate', 'tdd']);
728
+ init.cmdInitPlanPhase(cwd, args[2], includes, raw, { validate: ppValidate, tdd: ppTdd });
663
729
  break;
664
730
  }
665
731
  case 'new-project':
@@ -866,7 +932,15 @@ async function runCommand(command, args, cwd, raw) {
866
932
  core.output(intel.intelQuery(term, planningDir), raw);
867
933
  } else if (subcommand === 'status') {
868
934
  const planningDir = path.join(cwd, '.planning');
869
- core.output(intel.intelStatus(planningDir), raw);
935
+ const status = intel.intelStatus(planningDir);
936
+ if (!raw && status.files) {
937
+ for (const file of Object.values(status.files)) {
938
+ if (file.updated_at) {
939
+ file.updated_at = core.timeAgo(new Date(file.updated_at));
940
+ }
941
+ }
942
+ }
943
+ core.output(status, raw);
870
944
  } else if (subcommand === 'diff') {
871
945
  const planningDir = path.join(cwd, '.planning');
872
946
  core.output(intel.intelDiff(planningDir), raw);
@@ -893,6 +967,33 @@ async function runCommand(command, args, cwd, raw) {
893
967
  break;
894
968
  }
895
969
 
970
+ // ─── Graphify ──────────────────────────────────────────────────────────
971
+
972
+ case 'graphify': {
973
+ const graphify = require('./lib/graphify.cjs');
974
+ const subcommand = args[1];
975
+ if (subcommand === 'query') {
976
+ const term = args[2];
977
+ if (!term) error('Usage: gsd-tools graphify query <term>');
978
+ const budgetIdx = args.indexOf('--budget');
979
+ const budget = budgetIdx !== -1 ? parseInt(args[budgetIdx + 1], 10) : null;
980
+ core.output(graphify.graphifyQuery(cwd, term, { budget }), raw);
981
+ } else if (subcommand === 'status') {
982
+ core.output(graphify.graphifyStatus(cwd), raw);
983
+ } else if (subcommand === 'diff') {
984
+ core.output(graphify.graphifyDiff(cwd), raw);
985
+ } else if (subcommand === 'build') {
986
+ if (args[2] === 'snapshot') {
987
+ core.output(graphify.writeSnapshot(cwd), raw);
988
+ } else {
989
+ core.output(graphify.graphifyBuild(cwd), raw);
990
+ }
991
+ } else {
992
+ error('Unknown graphify subcommand. Available: build, query, status, diff');
993
+ }
994
+ break;
995
+ }
996
+
896
997
  // ─── Documentation ────────────────────────────────────────────────────
897
998
 
898
999
  case 'docs-init': {
@@ -928,6 +1029,106 @@ async function runCommand(command, args, cwd, raw) {
928
1029
  break;
929
1030
  }
930
1031
 
1032
+ // ─── detect-custom-files ───────────────────────────────────────────────
1033
+ // Detect user-added files inside GSD-managed directories that are not
1034
+ // tracked in gsd-file-manifest.json. Used by the update workflow to back
1035
+ // up custom files before the installer wipes those directories.
1036
+ //
1037
+ // This replaces the fragile bash pattern:
1038
+ // MANIFEST_FILES=$(node -e "require('$RUNTIME_DIR/...')" 2>/dev/null)
1039
+ // ${filepath#$RUNTIME_DIR/} # unreliable path stripping
1040
+ // which silently returns CUSTOM_COUNT=0 when $RUNTIME_DIR is unset or
1041
+ // when the stripped path does not match the manifest key format (#1997).
1042
+
1043
+ case 'detect-custom-files': {
1044
+ const configDirIdx = args.indexOf('--config-dir');
1045
+ const configDir = configDirIdx !== -1 ? args[configDirIdx + 1] : null;
1046
+ if (!configDir) {
1047
+ error('Usage: gsd-tools detect-custom-files --config-dir <path>');
1048
+ }
1049
+ const resolvedConfigDir = path.resolve(configDir);
1050
+ if (!fs.existsSync(resolvedConfigDir)) {
1051
+ error(`Config directory not found: ${resolvedConfigDir}`);
1052
+ }
1053
+
1054
+ const manifestPath = path.join(resolvedConfigDir, 'gsd-file-manifest.json');
1055
+ if (!fs.existsSync(manifestPath)) {
1056
+ // No manifest — cannot determine what is custom. Return empty list
1057
+ // (same behaviour as saveLocalPatches in install.js when no manifest).
1058
+ const out = { custom_files: [], custom_count: 0, manifest_found: false };
1059
+ process.stdout.write(JSON.stringify(out, null, 2));
1060
+ break;
1061
+ }
1062
+
1063
+ let manifest;
1064
+ try {
1065
+ manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
1066
+ } catch {
1067
+ const out = { custom_files: [], custom_count: 0, manifest_found: false, error: 'manifest parse error' };
1068
+ process.stdout.write(JSON.stringify(out, null, 2));
1069
+ break;
1070
+ }
1071
+
1072
+ const manifestKeys = new Set(Object.keys(manifest.files || {}));
1073
+
1074
+ // GSD-managed directories to scan for user-added files.
1075
+ // These are the directories the installer wipes on update.
1076
+ const GSD_MANAGED_DIRS = [
1077
+ 'get-shit-done',
1078
+ 'agents',
1079
+ path.join('commands', 'gsd'),
1080
+ 'hooks',
1081
+ // OpenCode/Kilo flat command dir
1082
+ 'command',
1083
+ // Codex/Copilot skills dir
1084
+ 'skills',
1085
+ ];
1086
+
1087
+ function walkDir(dir, baseDir) {
1088
+ const results = [];
1089
+ if (!fs.existsSync(dir)) return results;
1090
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
1091
+ const fullPath = path.join(dir, entry.name);
1092
+ if (entry.isDirectory()) {
1093
+ results.push(...walkDir(fullPath, baseDir));
1094
+ } else {
1095
+ // Use forward slashes for cross-platform manifest key compatibility
1096
+ const relPath = path.relative(baseDir, fullPath).replace(/\\/g, '/');
1097
+ results.push(relPath);
1098
+ }
1099
+ }
1100
+ return results;
1101
+ }
1102
+
1103
+ const customFiles = [];
1104
+ for (const managedDir of GSD_MANAGED_DIRS) {
1105
+ const absDir = path.join(resolvedConfigDir, managedDir);
1106
+ if (!fs.existsSync(absDir)) continue;
1107
+ for (const relPath of walkDir(absDir, resolvedConfigDir)) {
1108
+ if (!manifestKeys.has(relPath)) {
1109
+ customFiles.push(relPath);
1110
+ }
1111
+ }
1112
+ }
1113
+
1114
+ const out = {
1115
+ custom_files: customFiles,
1116
+ custom_count: customFiles.length,
1117
+ manifest_found: true,
1118
+ manifest_version: manifest.version || null,
1119
+ };
1120
+ process.stdout.write(JSON.stringify(out, null, 2));
1121
+ break;
1122
+ }
1123
+
1124
+ // ─── GSD-2 Reverse Migration ───────────────────────────────────────────
1125
+
1126
+ case 'from-gsd2': {
1127
+ const gsd2Import = require('./lib/gsd2-import.cjs');
1128
+ gsd2Import.cmdFromGsd2(args.slice(1), cwd, raw);
1129
+ break;
1130
+ }
1131
+
931
1132
  default:
932
1133
  error(`Unknown command: ${command}`);
933
1134
  }