gsd-pi 2.29.0-dev.49d972f → 2.29.0-dev.4c155ee

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 (256) hide show
  1. package/README.md +24 -17
  2. package/dist/headless.js +4 -0
  3. package/dist/resources/extensions/bg-shell/process-manager.ts +13 -0
  4. package/dist/resources/extensions/gsd/auto-dashboard.ts +217 -65
  5. package/dist/resources/extensions/gsd/auto-dispatch.ts +32 -3
  6. package/dist/resources/extensions/gsd/auto-post-unit.ts +44 -12
  7. package/dist/resources/extensions/gsd/auto-prompts.ts +40 -17
  8. package/dist/resources/extensions/gsd/auto-recovery.ts +2 -1
  9. package/dist/resources/extensions/gsd/auto-start.ts +18 -32
  10. package/dist/resources/extensions/gsd/auto-worktree.ts +21 -182
  11. package/dist/resources/extensions/gsd/auto.ts +2 -9
  12. package/dist/resources/extensions/gsd/captures.ts +4 -10
  13. package/dist/resources/extensions/gsd/commands-handlers.ts +2 -1
  14. package/dist/resources/extensions/gsd/commands-prefs-wizard.ts +44 -14
  15. package/dist/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
  16. package/dist/resources/extensions/gsd/commands.ts +55 -2
  17. package/dist/resources/extensions/gsd/detection.ts +2 -1
  18. package/dist/resources/extensions/gsd/doctor-checks.ts +49 -1
  19. package/dist/resources/extensions/gsd/doctor-types.ts +3 -1
  20. package/dist/resources/extensions/gsd/forensics.ts +2 -2
  21. package/dist/resources/extensions/gsd/git-service.ts +3 -2
  22. package/dist/resources/extensions/gsd/gitignore.ts +9 -63
  23. package/dist/resources/extensions/gsd/gsd-db.ts +1 -165
  24. package/dist/resources/extensions/gsd/guided-flow.ts +8 -5
  25. package/dist/resources/extensions/gsd/index.ts +3 -3
  26. package/dist/resources/extensions/gsd/md-importer.ts +3 -2
  27. package/dist/resources/extensions/gsd/mechanical-completion.ts +430 -0
  28. package/dist/resources/extensions/gsd/migrate/command.ts +3 -2
  29. package/dist/resources/extensions/gsd/migrate/writer.ts +2 -1
  30. package/dist/resources/extensions/gsd/migrate-external.ts +123 -0
  31. package/dist/resources/extensions/gsd/paths.ts +24 -2
  32. package/dist/resources/extensions/gsd/post-unit-hooks.ts +6 -5
  33. package/dist/resources/extensions/gsd/preferences-models.ts +7 -1
  34. package/dist/resources/extensions/gsd/preferences-validation.ts +2 -1
  35. package/dist/resources/extensions/gsd/preferences.ts +10 -5
  36. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
  37. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  38. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
  39. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -1
  40. package/dist/resources/extensions/gsd/prompts/workflow-start.md +28 -0
  41. package/dist/resources/extensions/gsd/repo-identity.ts +148 -0
  42. package/dist/resources/extensions/gsd/resource-version.ts +99 -0
  43. package/dist/resources/extensions/gsd/session-forensics.ts +4 -3
  44. package/dist/resources/extensions/gsd/tests/activity-log.test.ts +2 -2
  45. package/dist/resources/extensions/gsd/tests/auto-recovery.test.ts +3 -3
  46. package/dist/resources/extensions/gsd/tests/auto-worktree.test.ts +0 -58
  47. package/dist/resources/extensions/gsd/tests/doctor-runtime.test.ts +3 -4
  48. package/dist/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
  49. package/dist/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +5 -18
  50. package/dist/resources/extensions/gsd/tests/git-service.test.ts +10 -37
  51. package/dist/resources/extensions/gsd/tests/knowledge.test.ts +4 -4
  52. package/dist/resources/extensions/gsd/tests/mechanical-completion.test.ts +356 -0
  53. package/dist/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
  54. package/dist/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
  55. package/dist/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
  56. package/dist/resources/extensions/gsd/triage-resolution.ts +2 -1
  57. package/dist/resources/extensions/gsd/types.ts +2 -0
  58. package/dist/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
  59. package/dist/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
  60. package/dist/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
  61. package/dist/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
  62. package/dist/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
  63. package/dist/resources/extensions/gsd/workflow-templates/registry.json +85 -0
  64. package/dist/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
  65. package/dist/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
  66. package/dist/resources/extensions/gsd/workflow-templates/spike.md +69 -0
  67. package/dist/resources/extensions/gsd/workflow-templates.ts +241 -0
  68. package/dist/resources/extensions/gsd/worktree-command.ts +1 -11
  69. package/dist/resources/extensions/gsd/worktree-manager.ts +3 -2
  70. package/dist/resources/extensions/gsd/worktree.ts +42 -5
  71. package/dist/resources/extensions/mcp-client/index.ts +459 -0
  72. package/dist/resources/skills/create-gsd-extension/SKILL.md +87 -0
  73. package/dist/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
  74. package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
  75. package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
  76. package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
  77. package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
  78. package/dist/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
  79. package/dist/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
  80. package/dist/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
  81. package/dist/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
  82. package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
  83. package/dist/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
  84. package/dist/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
  85. package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
  86. package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
  87. package/dist/resources/skills/create-gsd-extension/references/state-management.md +70 -0
  88. package/dist/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
  89. package/dist/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
  90. package/dist/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
  91. package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
  92. package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
  93. package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
  94. package/dist/resources/skills/create-skill/SKILL.md +184 -0
  95. package/dist/resources/skills/create-skill/references/api-security.md +226 -0
  96. package/dist/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
  97. package/dist/resources/skills/create-skill/references/common-patterns.md +595 -0
  98. package/dist/resources/skills/create-skill/references/core-principles.md +437 -0
  99. package/dist/resources/skills/create-skill/references/executable-code.md +175 -0
  100. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
  101. package/dist/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
  102. package/dist/resources/skills/create-skill/references/recommended-structure.md +168 -0
  103. package/dist/resources/skills/create-skill/references/skill-structure.md +372 -0
  104. package/dist/resources/skills/create-skill/references/use-xml-tags.md +466 -0
  105. package/dist/resources/skills/create-skill/references/using-scripts.md +113 -0
  106. package/dist/resources/skills/create-skill/references/using-templates.md +112 -0
  107. package/dist/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
  108. package/dist/resources/skills/create-skill/templates/router-skill.md +73 -0
  109. package/dist/resources/skills/create-skill/templates/simple-skill.md +33 -0
  110. package/dist/resources/skills/create-skill/workflows/add-reference.md +96 -0
  111. package/dist/resources/skills/create-skill/workflows/add-script.md +93 -0
  112. package/dist/resources/skills/create-skill/workflows/add-template.md +74 -0
  113. package/dist/resources/skills/create-skill/workflows/add-workflow.md +120 -0
  114. package/dist/resources/skills/create-skill/workflows/audit-skill.md +148 -0
  115. package/dist/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
  116. package/dist/resources/skills/create-skill/workflows/get-guidance.md +121 -0
  117. package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
  118. package/dist/resources/skills/create-skill/workflows/verify-skill.md +204 -0
  119. package/dist/resources/skills/react-best-practices/SKILL.md +1 -1
  120. package/package.json +1 -1
  121. package/packages/native/dist/native.d.ts +2 -0
  122. package/packages/native/dist/native.js +19 -5
  123. package/packages/native/src/native.ts +23 -9
  124. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  125. package/packages/pi-coding-agent/dist/core/extensions/loader.js +13 -0
  126. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  128. package/packages/pi-coding-agent/dist/core/lsp/client.js +3 -0
  129. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  130. package/packages/pi-coding-agent/src/core/extensions/loader.ts +13 -0
  131. package/packages/pi-coding-agent/src/core/lsp/client.ts +3 -0
  132. package/src/resources/extensions/bg-shell/process-manager.ts +13 -0
  133. package/src/resources/extensions/gsd/auto-dashboard.ts +217 -65
  134. package/src/resources/extensions/gsd/auto-dispatch.ts +32 -3
  135. package/src/resources/extensions/gsd/auto-post-unit.ts +44 -12
  136. package/src/resources/extensions/gsd/auto-prompts.ts +40 -17
  137. package/src/resources/extensions/gsd/auto-recovery.ts +2 -1
  138. package/src/resources/extensions/gsd/auto-start.ts +18 -32
  139. package/src/resources/extensions/gsd/auto-worktree.ts +21 -182
  140. package/src/resources/extensions/gsd/auto.ts +2 -9
  141. package/src/resources/extensions/gsd/captures.ts +4 -10
  142. package/src/resources/extensions/gsd/commands-handlers.ts +2 -1
  143. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +44 -14
  144. package/src/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
  145. package/src/resources/extensions/gsd/commands.ts +55 -2
  146. package/src/resources/extensions/gsd/detection.ts +2 -1
  147. package/src/resources/extensions/gsd/doctor-checks.ts +49 -1
  148. package/src/resources/extensions/gsd/doctor-types.ts +3 -1
  149. package/src/resources/extensions/gsd/forensics.ts +2 -2
  150. package/src/resources/extensions/gsd/git-service.ts +3 -2
  151. package/src/resources/extensions/gsd/gitignore.ts +9 -63
  152. package/src/resources/extensions/gsd/gsd-db.ts +1 -165
  153. package/src/resources/extensions/gsd/guided-flow.ts +8 -5
  154. package/src/resources/extensions/gsd/index.ts +3 -3
  155. package/src/resources/extensions/gsd/md-importer.ts +3 -2
  156. package/src/resources/extensions/gsd/mechanical-completion.ts +430 -0
  157. package/src/resources/extensions/gsd/migrate/command.ts +3 -2
  158. package/src/resources/extensions/gsd/migrate/writer.ts +2 -1
  159. package/src/resources/extensions/gsd/migrate-external.ts +123 -0
  160. package/src/resources/extensions/gsd/paths.ts +24 -2
  161. package/src/resources/extensions/gsd/post-unit-hooks.ts +6 -5
  162. package/src/resources/extensions/gsd/preferences-models.ts +7 -1
  163. package/src/resources/extensions/gsd/preferences-validation.ts +2 -1
  164. package/src/resources/extensions/gsd/preferences.ts +10 -5
  165. package/src/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
  166. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  167. package/src/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
  168. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -1
  169. package/src/resources/extensions/gsd/prompts/workflow-start.md +28 -0
  170. package/src/resources/extensions/gsd/repo-identity.ts +148 -0
  171. package/src/resources/extensions/gsd/resource-version.ts +99 -0
  172. package/src/resources/extensions/gsd/session-forensics.ts +4 -3
  173. package/src/resources/extensions/gsd/tests/activity-log.test.ts +2 -2
  174. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +3 -3
  175. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +0 -58
  176. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +3 -4
  177. package/src/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
  178. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +5 -18
  179. package/src/resources/extensions/gsd/tests/git-service.test.ts +10 -37
  180. package/src/resources/extensions/gsd/tests/knowledge.test.ts +4 -4
  181. package/src/resources/extensions/gsd/tests/mechanical-completion.test.ts +356 -0
  182. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
  183. package/src/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
  184. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
  185. package/src/resources/extensions/gsd/triage-resolution.ts +2 -1
  186. package/src/resources/extensions/gsd/types.ts +2 -0
  187. package/src/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
  188. package/src/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
  189. package/src/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
  190. package/src/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
  191. package/src/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
  192. package/src/resources/extensions/gsd/workflow-templates/registry.json +85 -0
  193. package/src/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
  194. package/src/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
  195. package/src/resources/extensions/gsd/workflow-templates/spike.md +69 -0
  196. package/src/resources/extensions/gsd/workflow-templates.ts +241 -0
  197. package/src/resources/extensions/gsd/worktree-command.ts +1 -11
  198. package/src/resources/extensions/gsd/worktree-manager.ts +3 -2
  199. package/src/resources/extensions/gsd/worktree.ts +42 -5
  200. package/src/resources/extensions/mcp-client/index.ts +459 -0
  201. package/src/resources/skills/create-gsd-extension/SKILL.md +87 -0
  202. package/src/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
  203. package/src/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
  204. package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
  205. package/src/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
  206. package/src/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
  207. package/src/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
  208. package/src/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
  209. package/src/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
  210. package/src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
  211. package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
  212. package/src/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
  213. package/src/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
  214. package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
  215. package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
  216. package/src/resources/skills/create-gsd-extension/references/state-management.md +70 -0
  217. package/src/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
  218. package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
  219. package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
  220. package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
  221. package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
  222. package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
  223. package/src/resources/skills/create-skill/SKILL.md +184 -0
  224. package/src/resources/skills/create-skill/references/api-security.md +226 -0
  225. package/src/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
  226. package/src/resources/skills/create-skill/references/common-patterns.md +595 -0
  227. package/src/resources/skills/create-skill/references/core-principles.md +437 -0
  228. package/src/resources/skills/create-skill/references/executable-code.md +175 -0
  229. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
  230. package/src/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
  231. package/src/resources/skills/create-skill/references/recommended-structure.md +168 -0
  232. package/src/resources/skills/create-skill/references/skill-structure.md +372 -0
  233. package/src/resources/skills/create-skill/references/use-xml-tags.md +466 -0
  234. package/src/resources/skills/create-skill/references/using-scripts.md +113 -0
  235. package/src/resources/skills/create-skill/references/using-templates.md +112 -0
  236. package/src/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
  237. package/src/resources/skills/create-skill/templates/router-skill.md +73 -0
  238. package/src/resources/skills/create-skill/templates/simple-skill.md +33 -0
  239. package/src/resources/skills/create-skill/workflows/add-reference.md +96 -0
  240. package/src/resources/skills/create-skill/workflows/add-script.md +93 -0
  241. package/src/resources/skills/create-skill/workflows/add-template.md +74 -0
  242. package/src/resources/skills/create-skill/workflows/add-workflow.md +120 -0
  243. package/src/resources/skills/create-skill/workflows/audit-skill.md +148 -0
  244. package/src/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
  245. package/src/resources/skills/create-skill/workflows/get-guidance.md +121 -0
  246. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
  247. package/src/resources/skills/create-skill/workflows/verify-skill.md +204 -0
  248. package/src/resources/skills/react-best-practices/SKILL.md +1 -1
  249. package/dist/resources/extensions/gsd/auto-worktree-sync.ts +0 -199
  250. package/dist/resources/extensions/gsd/tests/worktree-db-integration.test.ts +0 -205
  251. package/dist/resources/extensions/gsd/tests/worktree-db.test.ts +0 -442
  252. package/dist/resources/extensions/mcporter/index.ts +0 -525
  253. package/src/resources/extensions/gsd/auto-worktree-sync.ts +0 -199
  254. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +0 -205
  255. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +0 -442
  256. package/src/resources/extensions/mcporter/index.ts +0 -525
@@ -254,13 +254,19 @@ export function resolveProfileDefaults(profile: TokenProfile): Partial<GSDPrefer
254
254
  subagent: "claude-sonnet-4-5-20250514",
255
255
  },
256
256
  phases: {
257
+ skip_research: true,
258
+ skip_reassess: true,
257
259
  skip_slice_research: true,
258
260
  },
259
261
  };
260
262
  case "quality":
261
263
  return {
262
264
  models: {},
263
- phases: {},
265
+ phases: {
266
+ skip_research: true,
267
+ skip_slice_research: true,
268
+ skip_reassess: true,
269
+ },
264
270
  };
265
271
  }
266
272
  }
@@ -172,9 +172,10 @@ export function validatePreferences(preferences: GSDPreferences): {
172
172
  if (p.skip_reassess !== undefined) validatedPhases.skip_reassess = !!p.skip_reassess;
173
173
  if (p.skip_slice_research !== undefined) validatedPhases.skip_slice_research = !!p.skip_slice_research;
174
174
  if (p.skip_milestone_validation !== undefined) validatedPhases.skip_milestone_validation = !!p.skip_milestone_validation;
175
+ if (p.reassess_after_slice !== undefined) validatedPhases.reassess_after_slice = !!p.reassess_after_slice;
175
176
  if ((p as any).require_slice_discussion !== undefined) (validatedPhases as any).require_slice_discussion = !!(p as any).require_slice_discussion;
176
177
  // Warn on unknown phase keys
177
- const knownPhaseKeys = new Set(["skip_research", "skip_reassess", "skip_slice_research", "skip_milestone_validation", "require_slice_discussion"]);
178
+ const knownPhaseKeys = new Set(["skip_research", "skip_reassess", "skip_slice_research", "skip_milestone_validation", "reassess_after_slice", "require_slice_discussion"]);
178
179
  for (const key of Object.keys(p)) {
179
180
  if (!knownPhaseKeys.has(key)) {
180
181
  warnings.push(`unknown phases key "${key}" — ignored`);
@@ -13,6 +13,7 @@
13
13
  import { existsSync, readFileSync } from "node:fs";
14
14
  import { homedir } from "node:os";
15
15
  import { join } from "node:path";
16
+ import { gsdRoot } from "./paths.js";
16
17
  import { parse as parseYaml } from "yaml";
17
18
  import type { PostUnitHookConfig, PreDispatchHookConfig } from "./types.js";
18
19
  import type { DynamicRoutingConfig } from "./model-router.js";
@@ -81,11 +82,15 @@ export {
81
82
 
82
83
  const GLOBAL_PREFERENCES_PATH = join(homedir(), ".gsd", "preferences.md");
83
84
  const LEGACY_GLOBAL_PREFERENCES_PATH = join(homedir(), ".pi", "agent", "gsd-preferences.md");
84
- const PROJECT_PREFERENCES_PATH = join(process.cwd(), ".gsd", "preferences.md");
85
+ function projectPreferencesPath(): string {
86
+ return join(gsdRoot(process.cwd()), "preferences.md");
87
+ }
85
88
  // Bootstrap in gitignore.ts historically created PREFERENCES.md (uppercase) by mistake.
86
89
  // Check uppercase as a fallback so those files aren't silently ignored.
87
90
  const GLOBAL_PREFERENCES_PATH_UPPERCASE = join(homedir(), ".gsd", "PREFERENCES.md");
88
- const PROJECT_PREFERENCES_PATH_UPPERCASE = join(process.cwd(), ".gsd", "PREFERENCES.md");
91
+ function projectPreferencesPathUppercase(): string {
92
+ return join(gsdRoot(process.cwd()), "PREFERENCES.md");
93
+ }
89
94
 
90
95
  export function getGlobalGSDPreferencesPath(): string {
91
96
  return GLOBAL_PREFERENCES_PATH;
@@ -96,7 +101,7 @@ export function getLegacyGlobalGSDPreferencesPath(): string {
96
101
  }
97
102
 
98
103
  export function getProjectGSDPreferencesPath(): string {
99
- return PROJECT_PREFERENCES_PATH;
104
+ return projectPreferencesPath();
100
105
  }
101
106
 
102
107
  // ─── Loading ────────────────────────────────────────────────────────────────
@@ -108,8 +113,8 @@ export function loadGlobalGSDPreferences(): LoadedGSDPreferences | null {
108
113
  }
109
114
 
110
115
  export function loadProjectGSDPreferences(): LoadedGSDPreferences | null {
111
- return loadPreferencesFile(PROJECT_PREFERENCES_PATH, "project")
112
- ?? loadPreferencesFile(PROJECT_PREFERENCES_PATH_UPPERCASE, "project");
116
+ return loadPreferencesFile(projectPreferencesPath(), "project")
117
+ ?? loadPreferencesFile(projectPreferencesPathUppercase(), "project");
113
118
  }
114
119
 
115
120
  export function loadEffectiveGSDPreferences(): LoadedGSDPreferences | null {
@@ -16,13 +16,15 @@ Summarize your understanding of the specification concretely:
16
16
  - Scope estimate (how many milestones × slices)
17
17
  - Any ambiguities or gaps you notice
18
18
 
19
- ### Step 2: Investigate
19
+ ### Step 2: Investigate (brief)
20
20
 
21
- Scout the codebase to understand what already exists:
21
+ Quickly scout the codebase to understand what already exists — spend no more than 5-6 tool calls here:
22
22
  - `ls` the project root and key directories
23
23
  - Search for relevant existing code, patterns, dependencies
24
24
  - Check library docs if needed (`resolve_library` / `get_library_docs`)
25
25
 
26
+ Then move on to writing artifacts. Do not explore exhaustively — the research phase will do deeper investigation later.
27
+
26
28
  ### Step 3: Make Decisions
27
29
 
28
30
  For any ambiguities or gaps in the specification:
@@ -91,7 +91,7 @@ Before moving to the wrap-up gate, verify you have covered:
91
91
  - options: "Yes, you got it (Recommended)", "Not quite — let me clarify"
92
92
  - **The question ID must contain `depth_verification`** (e.g. `depth_verification_confirm`) — this enables the write-gate downstream.
93
93
 
94
- **If `{{structuredQuestionsAvailable}}` is `false`:** ask in plain text: "Did I capture that correctly? Anything I missed?" Wait for confirmation before proceeding.
94
+ **If `{{structuredQuestionsAvailable}}` is `false`:** ask in plain text: "Did I capture that correctly? If not, tell me what I missed." Wait for confirmation before proceeding.
95
95
 
96
96
  If they clarify, absorb the correction and re-verify.
97
97
 
@@ -12,9 +12,33 @@ All relevant context has been preloaded below — start working immediately with
12
12
 
13
13
  ## Your Role in the Pipeline
14
14
 
15
- A **researcher agent** already explored the codebase and documented findings in the milestone research doc (inlined above, if present). It identified key files, technology choices, constraints, and risks. **Trust the research.** Your job is strategic decomposition turning findings into an ordered set of demoable slices — not re-exploration. Don't read code files the research already summarized unless something is ambiguous or missing.
15
+ You are the first deep look at this milestone. You have full tool access explore the codebase, look up docs, investigate technology choices. Your job is to understand the landscape and then strategically decompose the work into demoable slices.
16
16
 
17
- After you finish, each slice goes through its own research → plan → execute cycle. Slice researchers dive deeper into the specific area. Slice planners decompose into tasks. Executors build each task. Your roadmap sets the strategic frame for all of them.
17
+ After you finish, each slice goes through its own plan → execute cycle. Slice planners decompose into tasks. Executors build each task. Your roadmap sets the strategic frame for all of them.
18
+
19
+ ### Explore First, Then Decompose
20
+
21
+ Before decomposing, build your understanding:
22
+
23
+ 1. **Codebase exploration.** For small/familiar codebases, use `rg`, `find`, and targeted reads. For large or unfamiliar codebases, use `scout` to build a broad map efficiently before diving in.
24
+ 2. **Library docs.** Use `resolve_library` / `get_library_docs` for unfamiliar libraries — skip this for libraries already used in the codebase.
25
+ 3. **Skill Discovery ({{skillDiscoveryMode}}):**{{skillDiscoveryInstructions}}
26
+ 4. **Requirements analysis.** If `.gsd/REQUIREMENTS.md` exists, research against it. Identify which Active requirements are table stakes, likely omissions, overbuilt risks, or domain-standard behaviors.
27
+
28
+ ### Strategic Questions to Answer
29
+
30
+ - What should be proven first?
31
+ - What existing patterns should be reused?
32
+ - What boundary contracts matter?
33
+ - What constraints does the existing codebase impose?
34
+ - Are there known failure modes that should shape slice ordering?
35
+ - If requirements exist: what table stakes, expected behaviors, continuity expectations, launchability expectations, or failure-visibility expectations are missing, optional, or clearly out of scope?
36
+
37
+ ### Source Files
38
+
39
+ {{sourceFilePaths}}
40
+
41
+ If milestone research exists (inlined above), trust those findings and skip redundant exploration. If findings are significant and no research file exists yet, write `{{researchOutputPath}}`.
18
42
 
19
43
  Narrate your decomposition reasoning — why you're grouping work this way, what risks are driving the order, what verification strategy you're choosing and why. Use complete sentences rather than planner shorthand or fragmentary notes.
20
44
 
@@ -18,7 +18,21 @@ Pay particular attention to **Forward Intelligence** sections — they contain h
18
18
 
19
19
  ## Your Role in the Pipeline
20
20
 
21
- A **researcher agent** already explored the codebase and documented findings in the slice research doc (inlined above, if present). It identified key files, build order, constraints, and verification approach. **Trust the research.** Your job is decomposition — turning findings into executable tasks — not re-exploration. Don't read code files the research already summarized unless something is ambiguous or missing from its findings.
21
+ You have full tool access. Before decomposing, explore the relevant code to ground your plan in reality.
22
+
23
+ ### Verify Roadmap Assumptions
24
+
25
+ Check prior slice summaries (inlined above as dependency summaries, if present). If prior slices discovered constraints, changed approaches, or flagged fragility, adjust your plan accordingly. The roadmap description may be stale — verify it against the current codebase state.
26
+
27
+ ### Explore Slice Scope
28
+
29
+ Read the code files relevant to this slice. Confirm the roadmap's description of what exists, what needs to change, and what boundaries apply. Use `rg`, `find`, and targeted reads.
30
+
31
+ ### Source Files
32
+
33
+ {{sourceFilePaths}}
34
+
35
+ If slice research exists (inlined above), trust those findings and skip redundant exploration.
22
36
 
23
37
  After you finish, **executor agents** implement each task in isolated fresh context windows. They see only their task plan, the slice plan excerpt (goal/demo/verification), and compressed summaries of prior tasks. They do not see the research doc, the roadmap, or REQUIREMENTS.md. Everything an executor needs must be in the task plan itself — file paths, specific steps, expected inputs and outputs.
24
38
 
@@ -0,0 +1,28 @@
1
+ # Workflow Template: {{templateName}}
2
+
3
+ You are executing a **{{templateName}}** workflow (template: `{{templateId}}`).
4
+
5
+ ## Context
6
+
7
+ - **Description:** {{description}}
8
+ - **Issue reference:** {{issueRef}}
9
+ - **Date:** {{date}}
10
+ - **Branch:** {{branch}}
11
+ - **Artifact directory:** {{artifactDir}}
12
+ - **Phases:** {{phases}}
13
+ - **Complexity:** {{complexity}}
14
+
15
+ ## Workflow Definition
16
+
17
+ Follow the workflow defined below. Execute each phase in order, completing one before moving to the next. At each phase gate, confirm with the user before proceeding.
18
+
19
+ {{workflowContent}}
20
+
21
+ ## Execution Rules
22
+
23
+ 1. **Follow the phases in order.** Do not skip phases unless the workflow explicitly allows it.
24
+ 2. **Artifact discipline.** If an artifact directory is specified, write all planning/summary documents there.
25
+ 3. **Atomic commits.** Commit working code after each meaningful change. Use conventional commit format: `<type>(<scope>): <description>`.
26
+ 4. **Verify before shipping.** Run the project's test suite and build before marking the workflow complete.
27
+ 5. **Gate between phases.** After each phase, summarize what was done and ask the user to confirm before moving to the next phase.
28
+ 6. **Stay focused.** This is a {{complexity}}-complexity workflow. Match your ceremony level to the task — don't over-engineer or under-deliver.
@@ -0,0 +1,148 @@
1
+ /**
2
+ * GSD Repo Identity — external state directory primitives.
3
+ *
4
+ * Computes a stable per-repo identity hash, resolves the external
5
+ * `~/.gsd/projects/<hash>/` state directory, and manages the
6
+ * `<project>/.gsd → external` symlink.
7
+ */
8
+
9
+ import { createHash } from "node:crypto";
10
+ import { execFileSync } from "node:child_process";
11
+ import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, symlinkSync } from "node:fs";
12
+ import { homedir } from "node:os";
13
+ import { join, resolve } from "node:path";
14
+
15
+ // ─── Repo Identity ──────────────────────────────────────────────────────────
16
+
17
+ /**
18
+ * Get the git remote URL for "origin", or "" if no remote is configured.
19
+ * Uses `git config` rather than `git remote get-url` for broader compat.
20
+ */
21
+ function getRemoteUrl(basePath: string): string {
22
+ try {
23
+ return execFileSync("git", ["config", "--get", "remote.origin.url"], {
24
+ cwd: basePath,
25
+ encoding: "utf-8",
26
+ stdio: ["ignore", "pipe", "ignore"],
27
+ timeout: 5_000,
28
+ }).trim();
29
+ } catch {
30
+ return "";
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Resolve the git toplevel (real root) for the given path.
36
+ * For worktrees this returns the main repo root, not the worktree path.
37
+ */
38
+ function resolveGitRoot(basePath: string): string {
39
+ try {
40
+ return execFileSync("git", ["rev-parse", "--show-toplevel"], {
41
+ cwd: basePath,
42
+ encoding: "utf-8",
43
+ stdio: ["ignore", "pipe", "ignore"],
44
+ timeout: 5_000,
45
+ }).trim();
46
+ } catch {
47
+ return resolve(basePath);
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Compute a stable identity for a repository.
53
+ *
54
+ * SHA-256 of `${remoteUrl}\n${resolvedRoot}`, truncated to 12 hex chars.
55
+ * Deterministic: same repo always produces the same hash regardless of
56
+ * which worktree the caller is inside.
57
+ */
58
+ export function repoIdentity(basePath: string): string {
59
+ const remoteUrl = getRemoteUrl(basePath);
60
+ const root = resolveGitRoot(basePath);
61
+ const input = `${remoteUrl}\n${root}`;
62
+ return createHash("sha256").update(input).digest("hex").slice(0, 12);
63
+ }
64
+
65
+ // ─── External State Directory ───────────────────────────────────────────────
66
+
67
+ /**
68
+ * Compute the external GSD state directory for a repository.
69
+ *
70
+ * Returns `$GSD_STATE_DIR/projects/<hash>` if `GSD_STATE_DIR` is set,
71
+ * otherwise `~/.gsd/projects/<hash>`.
72
+ */
73
+ export function externalGsdRoot(basePath: string): string {
74
+ const base = process.env.GSD_STATE_DIR || join(homedir(), ".gsd");
75
+ return join(base, "projects", repoIdentity(basePath));
76
+ }
77
+
78
+ // ─── Symlink Management ─────────────────────────────────────────────────────
79
+
80
+ /**
81
+ * Ensure the `<project>/.gsd` symlink points to the external state directory.
82
+ *
83
+ * 1. mkdir -p the external dir
84
+ * 2. If `<project>/.gsd` doesn't exist → create symlink
85
+ * 3. If `<project>/.gsd` is already the correct symlink → no-op
86
+ * 4. If `<project>/.gsd` is a real directory → return as-is (migration handles later)
87
+ *
88
+ * Returns the resolved external path.
89
+ */
90
+ export function ensureGsdSymlink(projectPath: string): string {
91
+ const externalPath = externalGsdRoot(projectPath);
92
+ const localGsd = join(projectPath, ".gsd");
93
+
94
+ // Ensure external directory exists
95
+ mkdirSync(externalPath, { recursive: true });
96
+
97
+ if (!existsSync(localGsd)) {
98
+ // Nothing exists yet — create symlink
99
+ symlinkSync(externalPath, localGsd, "junction");
100
+ return externalPath;
101
+ }
102
+
103
+ try {
104
+ const stat = lstatSync(localGsd);
105
+
106
+ if (stat.isSymbolicLink()) {
107
+ // Already a symlink — verify it points to the right place
108
+ const target = realpathSync(localGsd);
109
+ if (target === externalPath) {
110
+ return externalPath; // correct symlink, no-op
111
+ }
112
+ // Symlink exists but points elsewhere — leave it for now
113
+ // (could be a custom override or stale symlink)
114
+ return target;
115
+ }
116
+
117
+ if (stat.isDirectory()) {
118
+ // Real directory — migration will handle this later.
119
+ // Return the local path so existing code still works.
120
+ return localGsd;
121
+ }
122
+ } catch {
123
+ // lstat failed — path exists but we can't stat it
124
+ }
125
+
126
+ return localGsd;
127
+ }
128
+
129
+ // ─── Worktree Detection ─────────────────────────────────────────────────────
130
+
131
+ /**
132
+ * Check if the given directory is a git worktree (not the main repo).
133
+ *
134
+ * Git worktrees have a `.git` *file* (not directory) containing a
135
+ * `gitdir:` pointer. This is git's native worktree indicator — no
136
+ * string marker parsing needed.
137
+ */
138
+ export function isInsideWorktree(cwd: string): boolean {
139
+ const gitPath = join(cwd, ".git");
140
+ try {
141
+ const stat = lstatSync(gitPath);
142
+ if (!stat.isFile()) return false;
143
+ const content = readFileSync(gitPath, "utf-8").trim();
144
+ return content.startsWith("gitdir:");
145
+ } catch {
146
+ return false;
147
+ }
148
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Resource version tracking and stale worktree detection.
3
+ *
4
+ * Staleness detection for managed GSD resources and utilities
5
+ * for escaping stale worktree cwd after milestone teardown.
6
+ */
7
+
8
+ import { existsSync, readdirSync, unlinkSync } from "node:fs";
9
+ import { loadJsonFileOrNull } from "./json-persistence.js";
10
+ import { join } from "node:path";
11
+ import { homedir } from "node:os";
12
+ import { resolveProjectRoot } from "./worktree.js";
13
+
14
+ // ─── Resource Staleness ───────────────────────────────────────────────────
15
+
16
+ /**
17
+ * Read the resource version (semver) from the managed-resources manifest.
18
+ * Uses gsdVersion instead of syncedAt so that launching a second session
19
+ * doesn't falsely trigger staleness (#804).
20
+ */
21
+ function isManifestWithVersion(data: unknown): data is { gsdVersion: string } {
22
+ return data !== null && typeof data === "object" && "gsdVersion" in data! && typeof (data as Record<string, unknown>).gsdVersion === "string";
23
+ }
24
+
25
+ export function readResourceVersion(): string | null {
26
+ const agentDir = process.env.GSD_CODING_AGENT_DIR || join(homedir(), ".gsd", "agent");
27
+ const manifestPath = join(agentDir, "managed-resources.json");
28
+ const manifest = loadJsonFileOrNull(manifestPath, isManifestWithVersion);
29
+ return manifest?.gsdVersion ?? null;
30
+ }
31
+
32
+ /**
33
+ * Check if managed resources have been updated since session start.
34
+ * Returns a warning message if stale, null otherwise.
35
+ */
36
+ export function checkResourcesStale(versionOnStart: string | null): string | null {
37
+ if (versionOnStart === null) return null;
38
+ const current = readResourceVersion();
39
+ if (current === null) return null;
40
+ if (current !== versionOnStart) {
41
+ return "GSD resources were updated since this session started. Restart gsd to load the new code.";
42
+ }
43
+ return null;
44
+ }
45
+
46
+ // ─── Stale Worktree Escape ────────────────────────────────────────────────
47
+
48
+ /**
49
+ * Detect and escape a stale worktree cwd (#608).
50
+ *
51
+ * After milestone completion + merge, the worktree directory is removed but
52
+ * the process cwd may still point inside `.gsd/worktrees/<MID>/`.
53
+ * When a new session starts, `process.cwd()` is passed as `base` to startAuto
54
+ * and all subsequent writes land in the wrong directory. This function detects
55
+ * that scenario and chdir back to the project root.
56
+ *
57
+ * Returns the corrected base path.
58
+ */
59
+ export function escapeStaleWorktree(base: string): string {
60
+ const projectRoot = resolveProjectRoot(base);
61
+ if (projectRoot === base) return base;
62
+ try {
63
+ process.chdir(projectRoot);
64
+ } catch {
65
+ return base;
66
+ }
67
+ return projectRoot;
68
+ }
69
+
70
+ /**
71
+ * Clean stale runtime unit files for completed milestones.
72
+ *
73
+ * After restart, stale runtime/units/*.json from prior milestones can
74
+ * cause deriveState to resume the wrong milestone (#887). Removes files
75
+ * for milestones that have a SUMMARY (fully complete).
76
+ */
77
+ export function cleanStaleRuntimeUnits(
78
+ gsdRootPath: string,
79
+ hasMilestoneSummary: (mid: string) => boolean,
80
+ ): number {
81
+ const runtimeUnitsDir = join(gsdRootPath, "runtime", "units");
82
+ if (!existsSync(runtimeUnitsDir)) return 0;
83
+
84
+ let cleaned = 0;
85
+ try {
86
+ for (const file of readdirSync(runtimeUnitsDir)) {
87
+ if (!file.endsWith(".json")) continue;
88
+ const midMatch = file.match(/(M\d+(?:-[a-z0-9]{6})?)/);
89
+ if (!midMatch) continue;
90
+ if (hasMilestoneSummary(midMatch[1])) {
91
+ try {
92
+ unlinkSync(join(runtimeUnitsDir, file));
93
+ cleaned++;
94
+ } catch { /* non-fatal */ }
95
+ }
96
+ }
97
+ } catch { /* non-fatal */ }
98
+ return cleaned;
99
+ }
@@ -20,6 +20,7 @@
20
20
 
21
21
  import { readFileSync, readdirSync, existsSync, statSync } from "node:fs";
22
22
  import { basename, join } from "node:path";
23
+ import { gsdRoot } from "./paths.js";
23
24
  import { truncateWithEllipsis } from "../shared/format-utils.js";
24
25
  import { nativeParseJsonlTail } from "./native-parser-bridge.js";
25
26
  import { MAX_JSONL_BYTES, parseJSONL } from "./jsonl-utils.js";
@@ -292,7 +293,7 @@ export function getDeepDiagnostic(basePath: string): string | null {
292
293
  if (mid) {
293
294
  const wtPath = getAutoWorktreePath(basePath, mid);
294
295
  if (wtPath) {
295
- const wtActivityDir = join(wtPath, ".gsd", "activity");
296
+ const wtActivityDir = join(gsdRoot(wtPath), "activity");
296
297
  trace = readLastActivityLog(wtActivityDir);
297
298
  }
298
299
  }
@@ -300,7 +301,7 @@ export function getDeepDiagnostic(basePath: string): string | null {
300
301
 
301
302
  // Fall back to root activity logs
302
303
  if (!trace || trace.toolCallCount === 0) {
303
- const activityDir = join(basePath, ".gsd", "activity");
304
+ const activityDir = join(gsdRoot(basePath), "activity");
304
305
  trace = readLastActivityLog(activityDir);
305
306
  }
306
307
 
@@ -314,7 +315,7 @@ export function getDeepDiagnostic(basePath: string): string | null {
314
315
  */
315
316
  function readActiveMilestoneId(basePath: string): string | null {
316
317
  try {
317
- const statePath = join(basePath, ".gsd", "STATE.md");
318
+ const statePath = join(gsdRoot(basePath), "STATE.md");
318
319
  if (!existsSync(statePath)) return null;
319
320
  const content = readFileSync(statePath, "utf-8");
320
321
  const match = /\*\*Active Milestone:\*\*\s*(\S+)/i.exec(content);
@@ -6,7 +6,7 @@
6
6
 
7
7
  import test from "node:test";
8
8
  import assert from "node:assert/strict";
9
- import { existsSync, mkdtempSync, mkdirSync, readdirSync, rmSync, utimesSync, writeFileSync, readFileSync } from "node:fs";
9
+ import { existsSync, mkdtempSync, mkdirSync, readdirSync, realpathSync, rmSync, utimesSync, writeFileSync, readFileSync } from "node:fs";
10
10
  import { join, dirname } from "node:path";
11
11
  import { tmpdir } from "node:os";
12
12
  import { fileURLToPath } from "node:url";
@@ -18,7 +18,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
18
18
  // ── Helpers ──────────────────────────────────────────────────────────────────
19
19
 
20
20
  function createTmpDir(): string {
21
- return mkdtempSync(join(tmpdir(), "gsd-activity-test-"));
21
+ return realpathSync(mkdtempSync(join(tmpdir(), "gsd-activity-test-")));
22
22
  }
23
23
 
24
24
  function writeActivityFile(dir: string, seq: string, name: string): string {
@@ -308,8 +308,8 @@ test("loadPersistedKeys unions keys from project root and worktree", () => {
308
308
  });
309
309
 
310
310
  test("completed-units.json set-union merge produces correct result", () => {
311
- // Verify that a manual set-union merge (as done in syncStateToProjectRoot)
312
- // correctly merges two JSON arrays of keys.
311
+ // Verify that a manual set-union merge correctly merges two JSON arrays
312
+ // of completed-unit keys.
313
313
  const projectRoot = makeTmpBase();
314
314
  const worktree = makeTmpBase();
315
315
  try {
@@ -320,7 +320,7 @@ test("completed-units.json set-union merge produces correct result", () => {
320
320
  writeFileSync(prKeysFile, JSON.stringify(["a", "b"]));
321
321
  writeFileSync(wtKeysFile, JSON.stringify(["b", "c", "d"]));
322
322
 
323
- // Perform the same merge logic used in syncStateToProjectRoot
323
+ // Perform a set-union merge of two JSON key arrays
324
324
  const srcKeys: string[] = JSON.parse(readFileSync(wtKeysFile, "utf8"));
325
325
  let dstKeys: string[] = [];
326
326
  if (existsSync(prKeysFile)) {
@@ -153,64 +153,6 @@ async function main(): Promise<void> {
153
153
  // After teardown, originalBase should be null
154
154
  assertEq(getAutoWorktreeOriginalBase(), null, "no split-brain: originalBase cleared");
155
155
 
156
- // ─── #778: reconcile plan checkboxes on re-attach ─────────────────
157
- console.log("\n=== #778: reconcile plan checkboxes on re-attach ===");
158
- {
159
- // Simulate: T01 [x] was committed to milestone branch, T02 [x] was
160
- // written to project root by syncStateToProjectRoot() but the
161
- // auto-commit crashed before it fired. On restart the worktree is
162
- // re-created from the milestone branch HEAD (T02 still [ ]).
163
- // reconcilePlanCheckboxes should forward-apply T02 [x] from the root.
164
-
165
- const planRelPath = join(".gsd", "milestones", "M004", "slices", "S01", "S01-PLAN.md");
166
- const planDir = join(tempDir, ".gsd", "milestones", "M004", "slices", "S01");
167
- const { mkdirSync: mkdir, writeFileSync: write, readFileSync: read } = await import("node:fs");
168
-
169
- // Plan on integration branch (project root): T01 [x], T02 [x]
170
- mkdir(planDir, { recursive: true });
171
- write(
172
- join(tempDir, planRelPath),
173
- "# S01 Plan\n- [x] **T01:** task one\n- [x] **T02:** task two\n- [ ] **T03:** task three\n",
174
- );
175
-
176
- // Write integration-branch plan to git so milestone branch starts from it
177
- run(`git add .`, tempDir);
178
- run(`git commit -m "add plan with T01 and T02 checked" --allow-empty`, tempDir);
179
-
180
- // Create milestone branch with only T01 [x] (simulating crash before T02 commit)
181
- const milestoneBranch = "milestone/M004";
182
- run(`git checkout -b ${milestoneBranch}`, tempDir);
183
- mkdir(planDir, { recursive: true });
184
- write(
185
- join(tempDir, planRelPath),
186
- "# S01 Plan\n- [x] **T01:** task one\n- [ ] **T02:** task two\n- [ ] **T03:** task three\n",
187
- );
188
- run(`git add .`, tempDir);
189
- run(`git commit -m "milestone: only T01 checked"`, tempDir);
190
- run(`git checkout main`, tempDir);
191
-
192
- // Restore project root plan (T01+T02 [x]) — simulates syncStateToProjectRoot
193
- write(
194
- join(tempDir, planRelPath),
195
- "# S01 Plan\n- [x] **T01:** task one\n- [x] **T02:** task two\n- [ ] **T03:** task three\n",
196
- );
197
-
198
- // Create worktree re-attached to existing milestone branch (T02 still [ ] in branch)
199
- const wtPath = createAutoWorktree(tempDir, "M004");
200
-
201
- try {
202
- const wtPlanPath = join(wtPath, planRelPath);
203
- assertTrue(existsSync(wtPlanPath), "plan file exists in worktree after re-attach");
204
-
205
- const wtPlan = read(wtPlanPath, "utf-8");
206
- assertTrue(wtPlan.includes("- [x] **T02:"), "T02 should be [x] after reconciliation (was [ ] on branch)");
207
- assertTrue(wtPlan.includes("- [x] **T01:"), "T01 stays [x]");
208
- assertTrue(wtPlan.includes("- [ ] **T03:"), "T03 stays [ ] (not in root either)");
209
- } finally {
210
- teardownAutoWorktree(tempDir, "M004");
211
- }
212
- }
213
-
214
156
  } finally {
215
157
  // Always restore cwd and clean up
216
158
  process.chdir(savedCwd);
@@ -231,15 +231,14 @@ None
231
231
  const detect = await runGSDDoctor(dir);
232
232
  const gitignoreIssues = detect.issues.filter(i => i.code === "gitignore_missing_patterns");
233
233
  assertTrue(gitignoreIssues.length > 0, "detects missing gitignore patterns");
234
- assertTrue(gitignoreIssues[0]?.message.includes(".gsd/activity/"), "message lists missing patterns");
234
+ assertTrue(gitignoreIssues[0]?.message.includes(".gsd"), "message lists missing .gsd pattern");
235
235
 
236
236
  const fixed = await runGSDDoctor(dir, { fix: true });
237
237
  assertTrue(fixed.fixesApplied.some(f => f.includes("added missing GSD runtime patterns")), "fix adds patterns");
238
238
 
239
- // Verify patterns were added
239
+ // Verify .gsd entry was added (external state symlink)
240
240
  const content = readFileSync(join(dir, ".gitignore"), "utf-8");
241
- assertTrue(content.includes(".gsd/activity/"), "gitignore now has activity pattern");
242
- assertTrue(content.includes(".gsd/auto.lock"), "gitignore now has auto.lock pattern");
241
+ assertTrue(content.includes(".gsd"), "gitignore now has .gsd entry");
243
242
  }
244
243
  } else {
245
244
  console.log("\n=== gitignore_missing_patterns (skipped on Windows) ===");