gsd-pi 2.29.0-dev.953d788 → 2.29.0-dev.f08b4fe

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 (316) hide show
  1. package/README.md +24 -17
  2. package/dist/extension-registry.d.ts +63 -0
  3. package/dist/extension-registry.js +166 -0
  4. package/dist/headless.js +4 -0
  5. package/dist/loader.js +10 -1
  6. package/dist/resource-loader.js +11 -1
  7. package/dist/resources/extensions/async-jobs/extension-manifest.json +13 -0
  8. package/dist/resources/extensions/bg-shell/extension-manifest.json +14 -0
  9. package/dist/resources/extensions/bg-shell/process-manager.ts +13 -0
  10. package/dist/resources/extensions/browser-tools/extension-manifest.json +37 -0
  11. package/dist/resources/extensions/context7/extension-manifest.json +12 -0
  12. package/dist/resources/extensions/google-search/extension-manifest.json +12 -0
  13. package/dist/resources/extensions/gsd/auto-dashboard.ts +217 -65
  14. package/dist/resources/extensions/gsd/auto-dispatch.ts +32 -3
  15. package/dist/resources/extensions/gsd/auto-post-unit.ts +45 -13
  16. package/dist/resources/extensions/gsd/auto-prompts.ts +40 -17
  17. package/dist/resources/extensions/gsd/auto-recovery.ts +18 -23
  18. package/dist/resources/extensions/gsd/auto-start.ts +18 -32
  19. package/dist/resources/extensions/gsd/auto-worktree.ts +21 -182
  20. package/dist/resources/extensions/gsd/auto.ts +2 -24
  21. package/dist/resources/extensions/gsd/captures.ts +4 -10
  22. package/dist/resources/extensions/gsd/commands-extensions.ts +328 -0
  23. package/dist/resources/extensions/gsd/commands-handlers.ts +22 -2
  24. package/dist/resources/extensions/gsd/commands-logs.ts +13 -14
  25. package/dist/resources/extensions/gsd/commands-prefs-wizard.ts +44 -14
  26. package/dist/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
  27. package/dist/resources/extensions/gsd/commands.ts +108 -24
  28. package/dist/resources/extensions/gsd/dashboard-overlay.ts +2 -1
  29. package/dist/resources/extensions/gsd/detection.ts +2 -1
  30. package/dist/resources/extensions/gsd/doctor-checks.ts +49 -1
  31. package/dist/resources/extensions/gsd/doctor-types.ts +3 -1
  32. package/dist/resources/extensions/gsd/extension-manifest.json +18 -0
  33. package/dist/resources/extensions/gsd/forensics.ts +2 -2
  34. package/dist/resources/extensions/gsd/git-service.ts +3 -2
  35. package/dist/resources/extensions/gsd/gitignore.ts +9 -63
  36. package/dist/resources/extensions/gsd/gsd-db.ts +1 -165
  37. package/dist/resources/extensions/gsd/guided-flow.ts +8 -5
  38. package/dist/resources/extensions/gsd/index.ts +3 -3
  39. package/dist/resources/extensions/gsd/json-persistence.ts +16 -1
  40. package/dist/resources/extensions/gsd/md-importer.ts +3 -2
  41. package/dist/resources/extensions/gsd/mechanical-completion.ts +430 -0
  42. package/dist/resources/extensions/gsd/migrate/command.ts +3 -2
  43. package/dist/resources/extensions/gsd/migrate/writer.ts +2 -1
  44. package/dist/resources/extensions/gsd/migrate-external.ts +123 -0
  45. package/dist/resources/extensions/gsd/paths.ts +24 -2
  46. package/dist/resources/extensions/gsd/post-unit-hooks.ts +6 -5
  47. package/dist/resources/extensions/gsd/preferences-models.ts +7 -1
  48. package/dist/resources/extensions/gsd/preferences-validation.ts +2 -1
  49. package/dist/resources/extensions/gsd/preferences.ts +10 -5
  50. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
  51. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  52. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
  53. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -1
  54. package/dist/resources/extensions/gsd/prompts/workflow-start.md +28 -0
  55. package/dist/resources/extensions/gsd/queue-order.ts +10 -11
  56. package/dist/resources/extensions/gsd/repo-identity.ts +148 -0
  57. package/dist/resources/extensions/gsd/resource-version.ts +99 -0
  58. package/dist/resources/extensions/gsd/session-forensics.ts +4 -3
  59. package/dist/resources/extensions/gsd/session-status-io.ts +23 -41
  60. package/dist/resources/extensions/gsd/tests/activity-log.test.ts +2 -2
  61. package/dist/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
  62. package/dist/resources/extensions/gsd/tests/auto-recovery.test.ts +3 -3
  63. package/dist/resources/extensions/gsd/tests/auto-skip-loop.test.ts +1 -1
  64. package/dist/resources/extensions/gsd/tests/auto-worktree.test.ts +0 -58
  65. package/dist/resources/extensions/gsd/tests/doctor-runtime.test.ts +3 -4
  66. package/dist/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
  67. package/dist/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +5 -18
  68. package/dist/resources/extensions/gsd/tests/git-service.test.ts +10 -37
  69. package/dist/resources/extensions/gsd/tests/knowledge.test.ts +4 -4
  70. package/dist/resources/extensions/gsd/tests/mechanical-completion.test.ts +356 -0
  71. package/dist/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
  72. package/dist/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
  73. package/dist/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
  74. package/dist/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
  75. package/dist/resources/extensions/gsd/triage-resolution.ts +2 -1
  76. package/dist/resources/extensions/gsd/types.ts +2 -0
  77. package/dist/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
  78. package/dist/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
  79. package/dist/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
  80. package/dist/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
  81. package/dist/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
  82. package/dist/resources/extensions/gsd/workflow-templates/registry.json +85 -0
  83. package/dist/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
  84. package/dist/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
  85. package/dist/resources/extensions/gsd/workflow-templates/spike.md +69 -0
  86. package/dist/resources/extensions/gsd/workflow-templates.ts +241 -0
  87. package/dist/resources/extensions/gsd/worktree-command.ts +1 -11
  88. package/dist/resources/extensions/gsd/worktree-manager.ts +3 -2
  89. package/dist/resources/extensions/gsd/worktree.ts +42 -5
  90. package/dist/resources/extensions/mac-tools/extension-manifest.json +16 -0
  91. package/dist/resources/extensions/mcp-client/index.ts +459 -0
  92. package/dist/resources/extensions/mcporter/extension-manifest.json +12 -0
  93. package/dist/resources/extensions/remote-questions/discord-adapter.ts +8 -19
  94. package/dist/resources/extensions/remote-questions/extension-manifest.json +11 -0
  95. package/dist/resources/extensions/remote-questions/http-client.ts +76 -0
  96. package/dist/resources/extensions/remote-questions/slack-adapter.ts +11 -17
  97. package/dist/resources/extensions/remote-questions/telegram-adapter.ts +8 -19
  98. package/dist/resources/extensions/search-the-web/extension-manifest.json +13 -0
  99. package/dist/resources/extensions/slash-commands/extension-manifest.json +11 -0
  100. package/dist/resources/extensions/subagent/extension-manifest.json +13 -0
  101. package/dist/resources/extensions/ttsr/extension-manifest.json +11 -0
  102. package/dist/resources/extensions/universal-config/extension-manifest.json +13 -0
  103. package/dist/resources/extensions/voice/extension-manifest.json +12 -0
  104. package/dist/resources/skills/create-gsd-extension/SKILL.md +87 -0
  105. package/dist/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
  106. package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
  107. package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
  108. package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
  109. package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
  110. package/dist/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
  111. package/dist/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
  112. package/dist/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
  113. package/dist/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
  114. package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
  115. package/dist/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
  116. package/dist/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
  117. package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
  118. package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
  119. package/dist/resources/skills/create-gsd-extension/references/state-management.md +70 -0
  120. package/dist/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
  121. package/dist/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
  122. package/dist/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
  123. package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
  124. package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
  125. package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
  126. package/dist/resources/skills/create-skill/SKILL.md +184 -0
  127. package/dist/resources/skills/create-skill/references/api-security.md +226 -0
  128. package/dist/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
  129. package/dist/resources/skills/create-skill/references/common-patterns.md +595 -0
  130. package/dist/resources/skills/create-skill/references/core-principles.md +437 -0
  131. package/dist/resources/skills/create-skill/references/executable-code.md +175 -0
  132. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
  133. package/dist/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
  134. package/dist/resources/skills/create-skill/references/recommended-structure.md +168 -0
  135. package/dist/resources/skills/create-skill/references/skill-structure.md +372 -0
  136. package/dist/resources/skills/create-skill/references/use-xml-tags.md +466 -0
  137. package/dist/resources/skills/create-skill/references/using-scripts.md +113 -0
  138. package/dist/resources/skills/create-skill/references/using-templates.md +112 -0
  139. package/dist/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
  140. package/dist/resources/skills/create-skill/templates/router-skill.md +73 -0
  141. package/dist/resources/skills/create-skill/templates/simple-skill.md +33 -0
  142. package/dist/resources/skills/create-skill/workflows/add-reference.md +96 -0
  143. package/dist/resources/skills/create-skill/workflows/add-script.md +93 -0
  144. package/dist/resources/skills/create-skill/workflows/add-template.md +74 -0
  145. package/dist/resources/skills/create-skill/workflows/add-workflow.md +120 -0
  146. package/dist/resources/skills/create-skill/workflows/audit-skill.md +148 -0
  147. package/dist/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
  148. package/dist/resources/skills/create-skill/workflows/get-guidance.md +121 -0
  149. package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
  150. package/dist/resources/skills/create-skill/workflows/verify-skill.md +204 -0
  151. package/dist/resources/skills/react-best-practices/SKILL.md +1 -1
  152. package/package.json +1 -1
  153. package/packages/native/dist/native.d.ts +2 -0
  154. package/packages/native/dist/native.js +19 -5
  155. package/packages/native/src/native.ts +23 -9
  156. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  157. package/packages/pi-coding-agent/dist/core/extensions/loader.js +13 -0
  158. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  159. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/lsp/client.js +3 -0
  161. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  162. package/packages/pi-coding-agent/src/core/extensions/loader.ts +13 -0
  163. package/packages/pi-coding-agent/src/core/lsp/client.ts +3 -0
  164. package/src/resources/extensions/async-jobs/extension-manifest.json +13 -0
  165. package/src/resources/extensions/bg-shell/extension-manifest.json +14 -0
  166. package/src/resources/extensions/bg-shell/process-manager.ts +13 -0
  167. package/src/resources/extensions/browser-tools/extension-manifest.json +37 -0
  168. package/src/resources/extensions/context7/extension-manifest.json +12 -0
  169. package/src/resources/extensions/google-search/extension-manifest.json +12 -0
  170. package/src/resources/extensions/gsd/auto-dashboard.ts +217 -65
  171. package/src/resources/extensions/gsd/auto-dispatch.ts +32 -3
  172. package/src/resources/extensions/gsd/auto-post-unit.ts +45 -13
  173. package/src/resources/extensions/gsd/auto-prompts.ts +40 -17
  174. package/src/resources/extensions/gsd/auto-recovery.ts +18 -23
  175. package/src/resources/extensions/gsd/auto-start.ts +18 -32
  176. package/src/resources/extensions/gsd/auto-worktree.ts +21 -182
  177. package/src/resources/extensions/gsd/auto.ts +2 -24
  178. package/src/resources/extensions/gsd/captures.ts +4 -10
  179. package/src/resources/extensions/gsd/commands-extensions.ts +328 -0
  180. package/src/resources/extensions/gsd/commands-handlers.ts +22 -2
  181. package/src/resources/extensions/gsd/commands-logs.ts +13 -14
  182. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +44 -14
  183. package/src/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
  184. package/src/resources/extensions/gsd/commands.ts +108 -24
  185. package/src/resources/extensions/gsd/dashboard-overlay.ts +2 -1
  186. package/src/resources/extensions/gsd/detection.ts +2 -1
  187. package/src/resources/extensions/gsd/doctor-checks.ts +49 -1
  188. package/src/resources/extensions/gsd/doctor-types.ts +3 -1
  189. package/src/resources/extensions/gsd/extension-manifest.json +18 -0
  190. package/src/resources/extensions/gsd/forensics.ts +2 -2
  191. package/src/resources/extensions/gsd/git-service.ts +3 -2
  192. package/src/resources/extensions/gsd/gitignore.ts +9 -63
  193. package/src/resources/extensions/gsd/gsd-db.ts +1 -165
  194. package/src/resources/extensions/gsd/guided-flow.ts +8 -5
  195. package/src/resources/extensions/gsd/index.ts +3 -3
  196. package/src/resources/extensions/gsd/json-persistence.ts +16 -1
  197. package/src/resources/extensions/gsd/md-importer.ts +3 -2
  198. package/src/resources/extensions/gsd/mechanical-completion.ts +430 -0
  199. package/src/resources/extensions/gsd/migrate/command.ts +3 -2
  200. package/src/resources/extensions/gsd/migrate/writer.ts +2 -1
  201. package/src/resources/extensions/gsd/migrate-external.ts +123 -0
  202. package/src/resources/extensions/gsd/paths.ts +24 -2
  203. package/src/resources/extensions/gsd/post-unit-hooks.ts +6 -5
  204. package/src/resources/extensions/gsd/preferences-models.ts +7 -1
  205. package/src/resources/extensions/gsd/preferences-validation.ts +2 -1
  206. package/src/resources/extensions/gsd/preferences.ts +10 -5
  207. package/src/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
  208. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  209. package/src/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
  210. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -1
  211. package/src/resources/extensions/gsd/prompts/workflow-start.md +28 -0
  212. package/src/resources/extensions/gsd/queue-order.ts +10 -11
  213. package/src/resources/extensions/gsd/repo-identity.ts +148 -0
  214. package/src/resources/extensions/gsd/resource-version.ts +99 -0
  215. package/src/resources/extensions/gsd/session-forensics.ts +4 -3
  216. package/src/resources/extensions/gsd/session-status-io.ts +23 -41
  217. package/src/resources/extensions/gsd/tests/activity-log.test.ts +2 -2
  218. package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
  219. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +3 -3
  220. package/src/resources/extensions/gsd/tests/auto-skip-loop.test.ts +1 -1
  221. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +0 -58
  222. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +3 -4
  223. package/src/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
  224. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +5 -18
  225. package/src/resources/extensions/gsd/tests/git-service.test.ts +10 -37
  226. package/src/resources/extensions/gsd/tests/knowledge.test.ts +4 -4
  227. package/src/resources/extensions/gsd/tests/mechanical-completion.test.ts +356 -0
  228. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
  229. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
  230. package/src/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
  231. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
  232. package/src/resources/extensions/gsd/triage-resolution.ts +2 -1
  233. package/src/resources/extensions/gsd/types.ts +2 -0
  234. package/src/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
  235. package/src/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
  236. package/src/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
  237. package/src/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
  238. package/src/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
  239. package/src/resources/extensions/gsd/workflow-templates/registry.json +85 -0
  240. package/src/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
  241. package/src/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
  242. package/src/resources/extensions/gsd/workflow-templates/spike.md +69 -0
  243. package/src/resources/extensions/gsd/workflow-templates.ts +241 -0
  244. package/src/resources/extensions/gsd/worktree-command.ts +1 -11
  245. package/src/resources/extensions/gsd/worktree-manager.ts +3 -2
  246. package/src/resources/extensions/gsd/worktree.ts +42 -5
  247. package/src/resources/extensions/mac-tools/extension-manifest.json +16 -0
  248. package/src/resources/extensions/mcp-client/index.ts +459 -0
  249. package/src/resources/extensions/mcporter/extension-manifest.json +12 -0
  250. package/src/resources/extensions/remote-questions/discord-adapter.ts +8 -19
  251. package/src/resources/extensions/remote-questions/extension-manifest.json +11 -0
  252. package/src/resources/extensions/remote-questions/http-client.ts +76 -0
  253. package/src/resources/extensions/remote-questions/slack-adapter.ts +11 -17
  254. package/src/resources/extensions/remote-questions/telegram-adapter.ts +8 -19
  255. package/src/resources/extensions/search-the-web/extension-manifest.json +13 -0
  256. package/src/resources/extensions/slash-commands/extension-manifest.json +11 -0
  257. package/src/resources/extensions/subagent/extension-manifest.json +13 -0
  258. package/src/resources/extensions/ttsr/extension-manifest.json +11 -0
  259. package/src/resources/extensions/universal-config/extension-manifest.json +13 -0
  260. package/src/resources/extensions/voice/extension-manifest.json +12 -0
  261. package/src/resources/skills/create-gsd-extension/SKILL.md +87 -0
  262. package/src/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
  263. package/src/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
  264. package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
  265. package/src/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
  266. package/src/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
  267. package/src/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
  268. package/src/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
  269. package/src/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
  270. package/src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
  271. package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
  272. package/src/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
  273. package/src/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
  274. package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
  275. package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
  276. package/src/resources/skills/create-gsd-extension/references/state-management.md +70 -0
  277. package/src/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
  278. package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
  279. package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
  280. package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
  281. package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
  282. package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
  283. package/src/resources/skills/create-skill/SKILL.md +184 -0
  284. package/src/resources/skills/create-skill/references/api-security.md +226 -0
  285. package/src/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
  286. package/src/resources/skills/create-skill/references/common-patterns.md +595 -0
  287. package/src/resources/skills/create-skill/references/core-principles.md +437 -0
  288. package/src/resources/skills/create-skill/references/executable-code.md +175 -0
  289. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
  290. package/src/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
  291. package/src/resources/skills/create-skill/references/recommended-structure.md +168 -0
  292. package/src/resources/skills/create-skill/references/skill-structure.md +372 -0
  293. package/src/resources/skills/create-skill/references/use-xml-tags.md +466 -0
  294. package/src/resources/skills/create-skill/references/using-scripts.md +113 -0
  295. package/src/resources/skills/create-skill/references/using-templates.md +112 -0
  296. package/src/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
  297. package/src/resources/skills/create-skill/templates/router-skill.md +73 -0
  298. package/src/resources/skills/create-skill/templates/simple-skill.md +33 -0
  299. package/src/resources/skills/create-skill/workflows/add-reference.md +96 -0
  300. package/src/resources/skills/create-skill/workflows/add-script.md +93 -0
  301. package/src/resources/skills/create-skill/workflows/add-template.md +74 -0
  302. package/src/resources/skills/create-skill/workflows/add-workflow.md +120 -0
  303. package/src/resources/skills/create-skill/workflows/audit-skill.md +148 -0
  304. package/src/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
  305. package/src/resources/skills/create-skill/workflows/get-guidance.md +121 -0
  306. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
  307. package/src/resources/skills/create-skill/workflows/verify-skill.md +204 -0
  308. package/src/resources/skills/react-best-practices/SKILL.md +1 -1
  309. package/dist/resources/extensions/gsd/auto-worktree-sync.ts +0 -198
  310. package/dist/resources/extensions/gsd/tests/worktree-db-integration.test.ts +0 -205
  311. package/dist/resources/extensions/gsd/tests/worktree-db.test.ts +0 -442
  312. package/dist/resources/extensions/mcporter/index.ts +0 -525
  313. package/src/resources/extensions/gsd/auto-worktree-sync.ts +0 -198
  314. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +0 -205
  315. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +0 -442
  316. 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.
@@ -9,10 +9,10 @@
9
9
  * survives branch switches and is shared across sessions.
10
10
  */
11
11
 
12
- import { readFileSync, writeFileSync, existsSync } from "node:fs";
13
12
  import { join } from "node:path";
14
13
  import { gsdRoot } from "./paths.js";
15
14
  import { milestoneIdSort } from "./milestone-ids.js";
15
+ import { loadJsonFileOrNull, saveJsonFile } from "./json-persistence.js";
16
16
 
17
17
  // ─── Types ───────────────────────────────────────────────────────────────────
18
18
 
@@ -45,6 +45,12 @@ function queueOrderPath(basePath: string): string {
45
45
  return join(gsdRoot(basePath), "QUEUE-ORDER.json");
46
46
  }
47
47
 
48
+ // ─── Type Guards ─────────────────────────────────────────────────────────────
49
+
50
+ function isQueueOrderFile(data: unknown): data is QueueOrderFile {
51
+ return data !== null && typeof data === "object" && "order" in data! && Array.isArray((data as QueueOrderFile).order);
52
+ }
53
+
48
54
  // ─── Read / Write ────────────────────────────────────────────────────────────
49
55
 
50
56
  /**
@@ -52,15 +58,8 @@ function queueOrderPath(basePath: string): string {
52
58
  * the file is corrupt/unreadable.
53
59
  */
54
60
  export function loadQueueOrder(basePath: string): string[] | null {
55
- const p = queueOrderPath(basePath);
56
- if (!existsSync(p)) return null;
57
- try {
58
- const data: QueueOrderFile = JSON.parse(readFileSync(p, "utf-8"));
59
- if (!Array.isArray(data.order)) return null;
60
- return data.order;
61
- } catch {
62
- return null;
63
- }
61
+ const data = loadJsonFileOrNull(queueOrderPath(basePath), isQueueOrderFile);
62
+ return data?.order ?? null;
64
63
  }
65
64
 
66
65
  /**
@@ -71,7 +70,7 @@ export function saveQueueOrder(basePath: string, order: string[]): void {
71
70
  order,
72
71
  updatedAt: new Date().toISOString(),
73
72
  };
74
- writeFileSync(queueOrderPath(basePath), JSON.stringify(data, null, 2) + "\n", "utf-8");
73
+ saveJsonFile(queueOrderPath(basePath), data);
75
74
  }
76
75
 
77
76
  // ─── Sorting ─────────────────────────────────────────────────────────────────
@@ -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);
@@ -11,9 +11,6 @@
11
11
  */
12
12
 
13
13
  import {
14
- writeFileSync,
15
- readFileSync,
16
- renameSync,
17
14
  unlinkSync,
18
15
  readdirSync,
19
16
  mkdirSync,
@@ -21,6 +18,7 @@ import {
21
18
  } from "node:fs";
22
19
  import { join } from "node:path";
23
20
  import { gsdRoot } from "./paths.js";
21
+ import { loadJsonFileOrNull, writeJsonFileAtomic } from "./json-persistence.js";
24
22
 
25
23
  // ─── Types ─────────────────────────────────────────────────────────────────
26
24
 
@@ -49,9 +47,16 @@ export interface SignalMessage {
49
47
  const PARALLEL_DIR = "parallel";
50
48
  const STATUS_SUFFIX = ".status.json";
51
49
  const SIGNAL_SUFFIX = ".signal.json";
52
- const TMP_SUFFIX = ".tmp";
53
50
  const DEFAULT_STALE_TIMEOUT_MS = 30_000;
54
51
 
52
+ function isSessionStatus(data: unknown): data is SessionStatus {
53
+ return data !== null && typeof data === "object" && "milestoneId" in data && "pid" in data;
54
+ }
55
+
56
+ function isSignalMessage(data: unknown): data is SignalMessage {
57
+ return data !== null && typeof data === "object" && "signal" in data && "sentAt" in data;
58
+ }
59
+
55
60
  // ─── Helpers ───────────────────────────────────────────────────────────────
56
61
 
57
62
  function parallelDir(basePath: string): string {
@@ -86,25 +91,13 @@ function isPidAlive(pid: number): boolean {
86
91
 
87
92
  /** Write session status atomically (write to .tmp, then rename). */
88
93
  export function writeSessionStatus(basePath: string, status: SessionStatus): void {
89
- try {
90
- ensureParallelDir(basePath);
91
- const dest = statusPath(basePath, status.milestoneId);
92
- const tmp = dest + TMP_SUFFIX;
93
- writeFileSync(tmp, JSON.stringify(status, null, 2), "utf-8");
94
- renameSync(tmp, dest);
95
- } catch { /* non-fatal */ }
94
+ ensureParallelDir(basePath);
95
+ writeJsonFileAtomic(statusPath(basePath, status.milestoneId), status);
96
96
  }
97
97
 
98
98
  /** Read a specific milestone's session status. */
99
99
  export function readSessionStatus(basePath: string, milestoneId: string): SessionStatus | null {
100
- try {
101
- const p = statusPath(basePath, milestoneId);
102
- if (!existsSync(p)) return null;
103
- const raw = readFileSync(p, "utf-8");
104
- return JSON.parse(raw) as SessionStatus;
105
- } catch {
106
- return null;
107
- }
100
+ return loadJsonFileOrNull(statusPath(basePath, milestoneId), isSessionStatus);
108
101
  }
109
102
 
110
103
  /** Read all session status files from .gsd/parallel/. */
@@ -114,13 +107,10 @@ export function readAllSessionStatuses(basePath: string): SessionStatus[] {
114
107
 
115
108
  const results: SessionStatus[] = [];
116
109
  try {
117
- const entries = readdirSync(dir);
118
- for (const entry of entries) {
110
+ for (const entry of readdirSync(dir)) {
119
111
  if (!entry.endsWith(STATUS_SUFFIX)) continue;
120
- try {
121
- const raw = readFileSync(join(dir, entry), "utf-8");
122
- results.push(JSON.parse(raw) as SessionStatus);
123
- } catch { /* skip corrupt files */ }
112
+ const status = loadJsonFileOrNull(join(dir, entry), isSessionStatus);
113
+ if (status) results.push(status);
124
114
  }
125
115
  } catch { /* non-fatal */ }
126
116
  return results;
@@ -138,27 +128,19 @@ export function removeSessionStatus(basePath: string, milestoneId: string): void
138
128
 
139
129
  /** Write a signal file for a worker to consume. */
140
130
  export function sendSignal(basePath: string, milestoneId: string, signal: SessionSignal): void {
141
- try {
142
- ensureParallelDir(basePath);
143
- const dest = signalPath(basePath, milestoneId);
144
- const tmp = dest + TMP_SUFFIX;
145
- const msg: SignalMessage = { signal, sentAt: Date.now(), from: "coordinator" };
146
- writeFileSync(tmp, JSON.stringify(msg, null, 2), "utf-8");
147
- renameSync(tmp, dest);
148
- } catch { /* non-fatal */ }
131
+ ensureParallelDir(basePath);
132
+ const msg: SignalMessage = { signal, sentAt: Date.now(), from: "coordinator" };
133
+ writeJsonFileAtomic(signalPath(basePath, milestoneId), msg);
149
134
  }
150
135
 
151
136
  /** Read and delete a signal file (atomic consume). Returns null if no signal pending. */
152
137
  export function consumeSignal(basePath: string, milestoneId: string): SignalMessage | null {
153
- try {
154
- const p = signalPath(basePath, milestoneId);
155
- if (!existsSync(p)) return null;
156
- const raw = readFileSync(p, "utf-8");
157
- unlinkSync(p);
158
- return JSON.parse(raw) as SignalMessage;
159
- } catch {
160
- return null;
138
+ const p = signalPath(basePath, milestoneId);
139
+ const msg = loadJsonFileOrNull(p, isSignalMessage);
140
+ if (msg) {
141
+ try { unlinkSync(p); } catch { /* non-fatal */ }
161
142
  }
143
+ return msg;
162
144
  }
163
145
 
164
146
  // ─── Stale Detection ───────────────────────────────────────────────────────