gsd-pi 2.34.0 → 2.35.0-dev.30eec3f

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 (500) hide show
  1. package/dist/cli.js +7 -2
  2. package/dist/resource-loader.d.ts +1 -1
  3. package/dist/resource-loader.js +13 -1
  4. package/dist/resources/extensions/async-jobs/await-tool.js +0 -2
  5. package/dist/resources/extensions/async-jobs/job-manager.js +0 -6
  6. package/dist/resources/extensions/bg-shell/output-formatter.js +1 -19
  7. package/dist/resources/extensions/bg-shell/process-manager.js +0 -4
  8. package/dist/resources/extensions/bg-shell/types.js +0 -2
  9. package/dist/resources/extensions/context7/index.js +5 -0
  10. package/dist/resources/extensions/get-secrets-from-user.js +2 -30
  11. package/dist/resources/extensions/google-search/index.js +5 -0
  12. package/dist/resources/extensions/gsd/auto-dispatch.js +43 -1
  13. package/dist/resources/extensions/gsd/auto-loop.js +10 -1
  14. package/dist/resources/extensions/gsd/auto-recovery.js +35 -0
  15. package/dist/resources/extensions/gsd/auto-start.js +35 -2
  16. package/dist/resources/extensions/gsd/auto.js +59 -4
  17. package/dist/resources/extensions/gsd/changelog.js +162 -0
  18. package/dist/resources/extensions/gsd/commands-bootstrap.js +1 -0
  19. package/dist/resources/extensions/gsd/commands-handlers.js +2 -2
  20. package/dist/resources/extensions/gsd/commands-inspect.js +10 -3
  21. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +5 -1
  22. package/dist/resources/extensions/gsd/commands.js +8 -1
  23. package/dist/resources/extensions/gsd/docs/preferences-reference.md +10 -0
  24. package/dist/resources/extensions/gsd/doctor-checks.js +113 -5
  25. package/dist/resources/extensions/gsd/doctor-environment.js +26 -17
  26. package/dist/resources/extensions/gsd/doctor-proactive.js +22 -0
  27. package/dist/resources/extensions/gsd/doctor.js +36 -0
  28. package/dist/resources/extensions/gsd/files.js +11 -2
  29. package/dist/resources/extensions/gsd/gitignore.js +54 -7
  30. package/dist/resources/extensions/gsd/guided-flow.js +5 -3
  31. package/dist/resources/extensions/gsd/health-widget-core.js +96 -0
  32. package/dist/resources/extensions/gsd/health-widget.js +97 -46
  33. package/dist/resources/extensions/gsd/index.js +10 -1
  34. package/dist/resources/extensions/gsd/migrate-external.js +55 -2
  35. package/dist/resources/extensions/gsd/paths.js +74 -7
  36. package/dist/resources/extensions/gsd/post-unit-hooks.js +4 -1
  37. package/dist/resources/extensions/gsd/preferences-validation.js +54 -1
  38. package/dist/resources/extensions/gsd/preferences.js +2 -0
  39. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
  40. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
  41. package/dist/resources/extensions/gsd/roadmap-mutations.js +55 -0
  42. package/dist/resources/extensions/gsd/session-lock.js +26 -2
  43. package/dist/resources/extensions/gsd/templates/plan.md +8 -0
  44. package/dist/resources/extensions/gsd/worktree-resolver.js +12 -0
  45. package/dist/resources/extensions/mcp-client/index.js +2 -1
  46. package/dist/resources/extensions/remote-questions/remote-command.js +2 -22
  47. package/dist/resources/extensions/shared/mod.js +1 -1
  48. package/dist/resources/extensions/shared/sanitize.js +30 -0
  49. package/dist/resources/extensions/subagent/index.js +6 -14
  50. package/dist/resources/skills/create-gsd-extension/references/events-reference.md +4 -4
  51. package/package.json +2 -1
  52. package/packages/native/dist/native.d.ts +0 -2
  53. package/packages/native/dist/native.js +0 -2
  54. package/packages/native/src/native.ts +0 -3
  55. package/packages/pi-agent-core/dist/agent-loop.d.ts +14 -0
  56. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  57. package/packages/pi-agent-core/dist/agent-loop.js +24 -27
  58. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  59. package/packages/pi-agent-core/dist/agent.d.ts +1 -0
  60. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  61. package/packages/pi-agent-core/dist/agent.js +11 -22
  62. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  63. package/packages/pi-agent-core/dist/proxy.d.ts +1 -25
  64. package/packages/pi-agent-core/dist/proxy.d.ts.map +1 -1
  65. package/packages/pi-agent-core/dist/proxy.js +3 -9
  66. package/packages/pi-agent-core/dist/proxy.js.map +1 -1
  67. package/packages/pi-agent-core/src/agent-loop.ts +30 -27
  68. package/packages/pi-agent-core/src/agent.ts +12 -23
  69. package/packages/pi-agent-core/src/proxy.ts +3 -9
  70. package/packages/pi-ai/dist/api-registry.d.ts +0 -2
  71. package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
  72. package/packages/pi-ai/dist/api-registry.js +0 -10
  73. package/packages/pi-ai/dist/api-registry.js.map +1 -1
  74. package/packages/pi-ai/dist/providers/anthropic.d.ts +0 -8
  75. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  76. package/packages/pi-ai/dist/providers/anthropic.js +1 -1
  77. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  78. package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
  79. package/packages/pi-ai/dist/providers/azure-openai-responses.js +5 -41
  80. package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
  81. package/packages/pi-ai/dist/providers/github-copilot-headers.d.ts +0 -1
  82. package/packages/pi-ai/dist/providers/github-copilot-headers.d.ts.map +1 -1
  83. package/packages/pi-ai/dist/providers/github-copilot-headers.js +1 -1
  84. package/packages/pi-ai/dist/providers/github-copilot-headers.js.map +1 -1
  85. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts +1 -43
  86. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
  87. package/packages/pi-ai/dist/providers/google-gemini-cli.js +2 -2
  88. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  89. package/packages/pi-ai/dist/providers/google-shared.d.ts +0 -4
  90. package/packages/pi-ai/dist/providers/google-shared.d.ts.map +1 -1
  91. package/packages/pi-ai/dist/providers/google-shared.js +1 -1
  92. package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
  93. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  94. package/packages/pi-ai/dist/providers/openai-completions.js +10 -73
  95. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  96. package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
  97. package/packages/pi-ai/dist/providers/openai-responses.js +9 -80
  98. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  99. package/packages/pi-ai/dist/providers/openai-shared.d.ts +65 -0
  100. package/packages/pi-ai/dist/providers/openai-shared.d.ts.map +1 -0
  101. package/packages/pi-ai/dist/providers/openai-shared.js +146 -0
  102. package/packages/pi-ai/dist/providers/openai-shared.js.map +1 -0
  103. package/packages/pi-ai/dist/providers/register-builtins.d.ts +0 -1
  104. package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
  105. package/packages/pi-ai/dist/providers/register-builtins.js +1 -1
  106. package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
  107. package/packages/pi-ai/dist/utils/event-stream.d.ts +0 -2
  108. package/packages/pi-ai/dist/utils/event-stream.d.ts.map +1 -1
  109. package/packages/pi-ai/dist/utils/event-stream.js +0 -4
  110. package/packages/pi-ai/dist/utils/event-stream.js.map +1 -1
  111. package/packages/pi-ai/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
  112. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js +7 -135
  113. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js.map +1 -1
  114. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
  115. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js +7 -135
  116. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js.map +1 -1
  117. package/packages/pi-ai/dist/utils/oauth/google-oauth-utils.d.ts +46 -0
  118. package/packages/pi-ai/dist/utils/oauth/google-oauth-utils.d.ts.map +1 -0
  119. package/packages/pi-ai/dist/utils/oauth/google-oauth-utils.js +160 -0
  120. package/packages/pi-ai/dist/utils/oauth/google-oauth-utils.js.map +1 -0
  121. package/packages/pi-ai/dist/utils/overflow.d.ts +0 -4
  122. package/packages/pi-ai/dist/utils/overflow.d.ts.map +1 -1
  123. package/packages/pi-ai/dist/utils/overflow.js +0 -6
  124. package/packages/pi-ai/dist/utils/overflow.js.map +1 -1
  125. package/packages/pi-ai/dist/utils/validation.d.ts +0 -8
  126. package/packages/pi-ai/dist/utils/validation.d.ts.map +1 -1
  127. package/packages/pi-ai/dist/utils/validation.js +0 -14
  128. package/packages/pi-ai/dist/utils/validation.js.map +1 -1
  129. package/packages/pi-ai/src/api-registry.ts +0 -12
  130. package/packages/pi-ai/src/providers/anthropic.ts +1 -1
  131. package/packages/pi-ai/src/providers/azure-openai-responses.ts +11 -45
  132. package/packages/pi-ai/src/providers/github-copilot-headers.ts +1 -1
  133. package/packages/pi-ai/src/providers/google-gemini-cli.ts +2 -2
  134. package/packages/pi-ai/src/providers/google-shared.ts +1 -1
  135. package/packages/pi-ai/src/providers/openai-completions.ts +16 -86
  136. package/packages/pi-ai/src/providers/openai-responses.ts +16 -96
  137. package/packages/pi-ai/src/providers/openai-shared.ts +193 -0
  138. package/packages/pi-ai/src/providers/register-builtins.ts +1 -1
  139. package/packages/pi-ai/src/utils/event-stream.ts +0 -5
  140. package/packages/pi-ai/src/utils/oauth/google-antigravity.ts +14 -162
  141. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.ts +13 -161
  142. package/packages/pi-ai/src/utils/oauth/google-oauth-utils.ts +201 -0
  143. package/packages/pi-ai/src/utils/overflow.ts +1 -8
  144. package/packages/pi-ai/src/utils/validation.ts +0 -15
  145. package/packages/pi-coding-agent/dist/config.d.ts +0 -9
  146. package/packages/pi-coding-agent/dist/config.d.ts.map +1 -1
  147. package/packages/pi-coding-agent/dist/config.js +4 -8
  148. package/packages/pi-coding-agent/dist/config.js.map +1 -1
  149. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +16 -63
  150. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  151. package/packages/pi-coding-agent/dist/core/agent-session.js +104 -641
  152. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  153. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +0 -1
  154. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  155. package/packages/pi-coding-agent/dist/core/auth-storage.js +4 -35
  156. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  157. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  158. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js +5 -43
  159. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  161. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +11 -69
  162. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  163. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts +40 -0
  164. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts.map +1 -1
  165. package/packages/pi-coding-agent/dist/core/compaction/utils.js +78 -0
  166. package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
  167. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts +77 -0
  168. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -0
  169. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +331 -0
  170. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -0
  171. package/packages/pi-coding-agent/dist/core/export-html/ansi-to-html.d.ts +0 -4
  172. package/packages/pi-coding-agent/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  173. package/packages/pi-coding-agent/dist/core/export-html/ansi-to-html.js +1 -1
  174. package/packages/pi-coding-agent/dist/core/export-html/ansi-to-html.js.map +1 -1
  175. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +2 -2
  176. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  177. package/packages/pi-coding-agent/dist/core/extensions/index.js +1 -1
  178. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +15 -5
  180. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/extensions/runner.js +129 -256
  182. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +49 -42
  184. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/extensions/types.js +2 -21
  186. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/keybindings.d.ts +0 -8
  188. package/packages/pi-coding-agent/dist/core/keybindings.d.ts.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/keybindings.js +2 -2
  190. package/packages/pi-coding-agent/dist/core/keybindings.js.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/lock-utils.d.ts +39 -0
  192. package/packages/pi-coding-agent/dist/core/lock-utils.d.ts.map +1 -0
  193. package/packages/pi-coding-agent/dist/core/lock-utils.js +89 -0
  194. package/packages/pi-coding-agent/dist/core/lock-utils.js.map +1 -0
  195. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +0 -17
  196. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  197. package/packages/pi-coding-agent/dist/core/lsp/client.js +3 -62
  198. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  199. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts +1 -1
  200. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -1
  201. package/packages/pi-coding-agent/dist/core/lsp/config.js +2 -6
  202. package/packages/pi-coding-agent/dist/core/lsp/config.js.map +1 -1
  203. package/packages/pi-coding-agent/dist/core/lsp/edits.d.ts +0 -5
  204. package/packages/pi-coding-agent/dist/core/lsp/edits.d.ts.map +1 -1
  205. package/packages/pi-coding-agent/dist/core/lsp/edits.js +1 -1
  206. package/packages/pi-coding-agent/dist/core/lsp/edits.js.map +1 -1
  207. package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
  208. package/packages/pi-coding-agent/dist/core/lsp/index.js +52 -107
  209. package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts +0 -1
  211. package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts.map +1 -1
  212. package/packages/pi-coding-agent/dist/core/lsp/lspmux.js +3 -22
  213. package/packages/pi-coding-agent/dist/core/lsp/lspmux.js.map +1 -1
  214. package/packages/pi-coding-agent/dist/core/lsp/types.d.ts +0 -1
  215. package/packages/pi-coding-agent/dist/core/lsp/types.d.ts.map +1 -1
  216. package/packages/pi-coding-agent/dist/core/lsp/types.js +0 -28
  217. package/packages/pi-coding-agent/dist/core/lsp/types.js.map +1 -1
  218. package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts +1 -6
  219. package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts.map +1 -1
  220. package/packages/pi-coding-agent/dist/core/lsp/utils.js +1 -28
  221. package/packages/pi-coding-agent/dist/core/lsp/utils.js.map +1 -1
  222. package/packages/pi-coding-agent/dist/core/messages.d.ts +0 -8
  223. package/packages/pi-coding-agent/dist/core/messages.d.ts.map +1 -1
  224. package/packages/pi-coding-agent/dist/core/messages.js +5 -5
  225. package/packages/pi-coding-agent/dist/core/messages.js.map +1 -1
  226. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +0 -3
  227. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  228. package/packages/pi-coding-agent/dist/core/model-registry.js +1 -3
  229. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  230. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts +1 -26
  231. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  232. package/packages/pi-coding-agent/dist/core/model-resolver.js +3 -59
  233. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  234. package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  235. package/packages/pi-coding-agent/dist/core/package-manager.js +2 -4
  236. package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  237. package/packages/pi-coding-agent/dist/core/prompt-templates.d.ts +0 -17
  238. package/packages/pi-coding-agent/dist/core/prompt-templates.d.ts.map +1 -1
  239. package/packages/pi-coding-agent/dist/core/prompt-templates.js +2 -2
  240. package/packages/pi-coding-agent/dist/core/prompt-templates.js.map +1 -1
  241. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +2 -4
  242. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  243. package/packages/pi-coding-agent/dist/core/resource-loader.js +46 -60
  244. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  245. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +87 -0
  246. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -0
  247. package/packages/pi-coding-agent/dist/core/retry-handler.js +295 -0
  248. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -0
  249. package/packages/pi-coding-agent/dist/core/session-manager.d.ts +0 -5
  250. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  251. package/packages/pi-coding-agent/dist/core/session-manager.js +5 -32
  252. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  253. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +8 -12
  254. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  255. package/packages/pi-coding-agent/dist/core/settings-manager.js +78 -168
  256. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  257. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  258. package/packages/pi-coding-agent/dist/core/skills.js +1 -3
  259. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  260. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  261. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  262. package/packages/pi-coding-agent/dist/index.js +1 -1
  263. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  264. package/packages/pi-coding-agent/dist/migrations.d.ts +0 -16
  265. package/packages/pi-coding-agent/dist/migrations.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/migrations.js +2 -2
  267. package/packages/pi-coding-agent/dist/migrations.js.map +1 -1
  268. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector-search.d.ts +0 -2
  269. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  270. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector-search.js +2 -2
  271. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  272. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.d.ts +1 -1
  273. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  274. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.js +9 -26
  275. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.js.map +1 -1
  276. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  277. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +1 -13
  278. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  279. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-render-utils.d.ts +44 -0
  280. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-render-utils.d.ts.map +1 -0
  281. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-render-utils.js +61 -0
  282. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-render-utils.js.map +1 -0
  283. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  284. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-selector.js +6 -9
  285. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-selector.js.map +1 -1
  286. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +1 -24
  287. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  288. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +50 -512
  289. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  290. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts +71 -0
  291. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -0
  292. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +514 -0
  293. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -0
  294. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +65 -4
  295. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  296. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +6 -23
  297. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  298. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts +12 -0
  299. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -0
  300. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +175 -0
  301. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -0
  302. package/packages/pi-coding-agent/dist/modes/interactive/utils/shorten-path.d.ts +6 -0
  303. package/packages/pi-coding-agent/dist/modes/interactive/utils/shorten-path.d.ts.map +1 -0
  304. package/packages/pi-coding-agent/dist/modes/interactive/utils/shorten-path.js +15 -0
  305. package/packages/pi-coding-agent/dist/modes/interactive/utils/shorten-path.js.map +1 -0
  306. package/packages/pi-coding-agent/dist/modes/print-mode.d.ts.map +1 -1
  307. package/packages/pi-coding-agent/dist/modes/print-mode.js +2 -30
  308. package/packages/pi-coding-agent/dist/modes/print-mode.js.map +1 -1
  309. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  310. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +2 -28
  311. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  312. package/packages/pi-coding-agent/dist/modes/shared/command-context-actions.d.ts +19 -0
  313. package/packages/pi-coding-agent/dist/modes/shared/command-context-actions.d.ts.map +1 -0
  314. package/packages/pi-coding-agent/dist/modes/shared/command-context-actions.js +45 -0
  315. package/packages/pi-coding-agent/dist/modes/shared/command-context-actions.js.map +1 -0
  316. package/packages/pi-coding-agent/dist/utils/changelog.d.ts +0 -4
  317. package/packages/pi-coding-agent/dist/utils/changelog.d.ts.map +1 -1
  318. package/packages/pi-coding-agent/dist/utils/changelog.js +1 -1
  319. package/packages/pi-coding-agent/dist/utils/changelog.js.map +1 -1
  320. package/packages/pi-coding-agent/dist/utils/clipboard-image.d.ts +0 -1
  321. package/packages/pi-coding-agent/dist/utils/clipboard-image.d.ts.map +1 -1
  322. package/packages/pi-coding-agent/dist/utils/clipboard-image.js +1 -1
  323. package/packages/pi-coding-agent/dist/utils/clipboard-image.js.map +1 -1
  324. package/packages/pi-coding-agent/dist/utils/error.d.ts +5 -0
  325. package/packages/pi-coding-agent/dist/utils/error.d.ts.map +1 -0
  326. package/packages/pi-coding-agent/dist/utils/error.js +7 -0
  327. package/packages/pi-coding-agent/dist/utils/error.js.map +1 -0
  328. package/packages/pi-coding-agent/dist/utils/photon.d.ts +0 -19
  329. package/packages/pi-coding-agent/dist/utils/photon.d.ts.map +1 -1
  330. package/packages/pi-coding-agent/dist/utils/photon.js +1 -120
  331. package/packages/pi-coding-agent/dist/utils/photon.js.map +1 -1
  332. package/packages/pi-coding-agent/dist/utils/tools-manager.d.ts +0 -1
  333. package/packages/pi-coding-agent/dist/utils/tools-manager.d.ts.map +1 -1
  334. package/packages/pi-coding-agent/dist/utils/tools-manager.js +1 -1
  335. package/packages/pi-coding-agent/dist/utils/tools-manager.js.map +1 -1
  336. package/packages/pi-coding-agent/package.json +1 -1
  337. package/packages/pi-coding-agent/src/config.ts +5 -10
  338. package/packages/pi-coding-agent/src/core/agent-session.ts +117 -745
  339. package/packages/pi-coding-agent/src/core/auth-storage.ts +4 -38
  340. package/packages/pi-coding-agent/src/core/compaction/branch-summarization.ts +7 -53
  341. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +14 -74
  342. package/packages/pi-coding-agent/src/core/compaction/utils.ts +100 -0
  343. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +424 -0
  344. package/packages/pi-coding-agent/src/core/export-html/ansi-to-html.ts +1 -1
  345. package/packages/pi-coding-agent/src/core/extensions/index.ts +1 -21
  346. package/packages/pi-coding-agent/src/core/extensions/runner.ts +119 -256
  347. package/packages/pi-coding-agent/src/core/extensions/types.ts +50 -69
  348. package/packages/pi-coding-agent/src/core/keybindings.ts +2 -2
  349. package/packages/pi-coding-agent/src/core/lock-utils.ts +113 -0
  350. package/packages/pi-coding-agent/src/core/lsp/client.ts +3 -73
  351. package/packages/pi-coding-agent/src/core/lsp/config.ts +2 -10
  352. package/packages/pi-coding-agent/src/core/lsp/edits.ts +1 -1
  353. package/packages/pi-coding-agent/src/core/lsp/index.ts +83 -152
  354. package/packages/pi-coding-agent/src/core/lsp/lspmux.ts +3 -23
  355. package/packages/pi-coding-agent/src/core/lsp/types.ts +0 -29
  356. package/packages/pi-coding-agent/src/core/lsp/utils.ts +1 -33
  357. package/packages/pi-coding-agent/src/core/messages.ts +5 -5
  358. package/packages/pi-coding-agent/src/core/model-registry.ts +0 -2
  359. package/packages/pi-coding-agent/src/core/model-resolver.ts +3 -77
  360. package/packages/pi-coding-agent/src/core/package-manager.ts +1 -4
  361. package/packages/pi-coding-agent/src/core/prompt-templates.ts +2 -2
  362. package/packages/pi-coding-agent/src/core/resource-loader.ts +56 -69
  363. package/packages/pi-coding-agent/src/core/retry-handler.ts +359 -0
  364. package/packages/pi-coding-agent/src/core/session-manager.ts +5 -34
  365. package/packages/pi-coding-agent/src/core/settings-manager.ts +87 -166
  366. package/packages/pi-coding-agent/src/core/skills.ts +1 -4
  367. package/packages/pi-coding-agent/src/index.ts +1 -7
  368. package/packages/pi-coding-agent/src/migrations.ts +2 -2
  369. package/packages/pi-coding-agent/src/modes/interactive/components/session-selector-search.ts +2 -2
  370. package/packages/pi-coding-agent/src/modes/interactive/components/session-selector.ts +17 -29
  371. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +1 -13
  372. package/packages/pi-coding-agent/src/modes/interactive/components/tree-render-utils.ts +81 -0
  373. package/packages/pi-coding-agent/src/modes/interactive/components/tree-selector.ts +14 -19
  374. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +50 -561
  375. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +653 -0
  376. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +7 -26
  377. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +196 -0
  378. package/packages/pi-coding-agent/src/modes/interactive/utils/shorten-path.ts +14 -0
  379. package/packages/pi-coding-agent/src/modes/print-mode.ts +2 -30
  380. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -28
  381. package/packages/pi-coding-agent/src/modes/shared/command-context-actions.ts +53 -0
  382. package/packages/pi-coding-agent/src/utils/changelog.ts +1 -1
  383. package/packages/pi-coding-agent/src/utils/clipboard-image.ts +1 -1
  384. package/packages/pi-coding-agent/src/utils/error.ts +6 -0
  385. package/packages/pi-coding-agent/src/utils/photon.ts +0 -137
  386. package/packages/pi-coding-agent/src/utils/tools-manager.ts +1 -1
  387. package/packages/pi-tui/dist/components/editor.d.ts +0 -10
  388. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  389. package/packages/pi-tui/dist/components/editor.js +1 -1
  390. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  391. package/packages/pi-tui/dist/components/markdown.d.ts +5 -0
  392. package/packages/pi-tui/dist/components/markdown.d.ts.map +1 -1
  393. package/packages/pi-tui/dist/components/markdown.js +25 -31
  394. package/packages/pi-tui/dist/components/markdown.js.map +1 -1
  395. package/packages/pi-tui/dist/keys.d.ts +0 -4
  396. package/packages/pi-tui/dist/keys.d.ts.map +1 -1
  397. package/packages/pi-tui/dist/keys.js +94 -162
  398. package/packages/pi-tui/dist/keys.js.map +1 -1
  399. package/packages/pi-tui/dist/overlay-layout.d.ts +55 -0
  400. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -0
  401. package/packages/pi-tui/dist/overlay-layout.js +288 -0
  402. package/packages/pi-tui/dist/overlay-layout.js.map +1 -0
  403. package/packages/pi-tui/dist/tui.d.ts +0 -22
  404. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  405. package/packages/pi-tui/dist/tui.js +6 -272
  406. package/packages/pi-tui/dist/tui.js.map +1 -1
  407. package/packages/pi-tui/dist/utils.d.ts +0 -7
  408. package/packages/pi-tui/dist/utils.d.ts.map +1 -1
  409. package/packages/pi-tui/dist/utils.js +0 -44
  410. package/packages/pi-tui/dist/utils.js.map +1 -1
  411. package/packages/pi-tui/src/components/editor.ts +1 -1
  412. package/packages/pi-tui/src/components/markdown.ts +25 -29
  413. package/packages/pi-tui/src/keys.ts +94 -173
  414. package/packages/pi-tui/src/overlay-layout.ts +372 -0
  415. package/packages/pi-tui/src/tui.ts +11 -312
  416. package/packages/pi-tui/src/utils.ts +0 -43
  417. package/pkg/dist/core/export-html/ansi-to-html.d.ts +0 -4
  418. package/pkg/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  419. package/pkg/dist/core/export-html/ansi-to-html.js +1 -1
  420. package/pkg/dist/core/export-html/ansi-to-html.js.map +1 -1
  421. package/pkg/dist/modes/interactive/theme/theme.d.ts +65 -4
  422. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  423. package/pkg/dist/modes/interactive/theme/theme.js +6 -23
  424. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  425. package/pkg/dist/modes/interactive/theme/themes.d.ts +12 -0
  426. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -0
  427. package/pkg/dist/modes/interactive/theme/themes.js +175 -0
  428. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -0
  429. package/pkg/package.json +1 -1
  430. package/src/resources/extensions/async-jobs/await-tool.ts +0 -2
  431. package/src/resources/extensions/async-jobs/job-manager.ts +0 -7
  432. package/src/resources/extensions/bg-shell/output-formatter.ts +0 -17
  433. package/src/resources/extensions/bg-shell/process-manager.ts +0 -4
  434. package/src/resources/extensions/bg-shell/types.ts +0 -12
  435. package/src/resources/extensions/context7/index.ts +7 -0
  436. package/src/resources/extensions/get-secrets-from-user.ts +2 -35
  437. package/src/resources/extensions/google-search/index.ts +7 -0
  438. package/src/resources/extensions/gsd/auto-dispatch.ts +49 -1
  439. package/src/resources/extensions/gsd/auto-loop.ts +11 -1
  440. package/src/resources/extensions/gsd/auto-recovery.ts +39 -0
  441. package/src/resources/extensions/gsd/auto-start.ts +42 -2
  442. package/src/resources/extensions/gsd/auto.ts +61 -3
  443. package/src/resources/extensions/gsd/changelog.ts +213 -0
  444. package/src/resources/extensions/gsd/commands-bootstrap.ts +1 -0
  445. package/src/resources/extensions/gsd/commands-handlers.ts +2 -2
  446. package/src/resources/extensions/gsd/commands-inspect.ts +10 -3
  447. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +5 -1
  448. package/src/resources/extensions/gsd/commands.ts +9 -1
  449. package/src/resources/extensions/gsd/docs/preferences-reference.md +10 -0
  450. package/src/resources/extensions/gsd/doctor-checks.ts +107 -5
  451. package/src/resources/extensions/gsd/doctor-environment.ts +26 -16
  452. package/src/resources/extensions/gsd/doctor-proactive.ts +24 -0
  453. package/src/resources/extensions/gsd/doctor-types.ts +9 -1
  454. package/src/resources/extensions/gsd/doctor.ts +35 -0
  455. package/src/resources/extensions/gsd/files.ts +12 -2
  456. package/src/resources/extensions/gsd/gitignore.ts +54 -7
  457. package/src/resources/extensions/gsd/guided-flow.ts +5 -3
  458. package/src/resources/extensions/gsd/health-widget-core.ts +129 -0
  459. package/src/resources/extensions/gsd/health-widget.ts +103 -59
  460. package/src/resources/extensions/gsd/index.ts +10 -1
  461. package/src/resources/extensions/gsd/migrate-external.ts +47 -2
  462. package/src/resources/extensions/gsd/paths.ts +73 -7
  463. package/src/resources/extensions/gsd/post-unit-hooks.ts +5 -1
  464. package/src/resources/extensions/gsd/preferences-validation.ts +54 -1
  465. package/src/resources/extensions/gsd/preferences.ts +2 -0
  466. package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
  467. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
  468. package/src/resources/extensions/gsd/roadmap-mutations.ts +66 -0
  469. package/src/resources/extensions/gsd/session-lock.ts +29 -2
  470. package/src/resources/extensions/gsd/templates/plan.md +8 -0
  471. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +46 -0
  472. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +98 -2
  473. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +59 -3
  474. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +20 -0
  475. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +214 -0
  476. package/src/resources/extensions/gsd/tests/health-widget.test.ts +158 -0
  477. package/src/resources/extensions/gsd/tests/paths.test.ts +113 -0
  478. package/src/resources/extensions/gsd/tests/preferences.test.ts +40 -2
  479. package/src/resources/extensions/gsd/tests/test-utils.ts +165 -0
  480. package/src/resources/extensions/gsd/tests/validate-directory.test.ts +15 -0
  481. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +2 -0
  482. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +32 -0
  483. package/src/resources/extensions/gsd/worktree-resolver.ts +11 -0
  484. package/src/resources/extensions/mcp-client/index.ts +2 -1
  485. package/src/resources/extensions/remote-questions/remote-command.ts +2 -23
  486. package/src/resources/extensions/shared/mod.ts +1 -1
  487. package/src/resources/extensions/shared/sanitize.ts +36 -0
  488. package/src/resources/extensions/subagent/index.ts +6 -12
  489. package/src/resources/skills/create-gsd-extension/references/events-reference.md +4 -4
  490. package/dist/resources/extensions/shared/wizard-ui.js +0 -478
  491. package/packages/pi-coding-agent/dist/modes/interactive/theme/dark.json +0 -85
  492. package/packages/pi-coding-agent/dist/modes/interactive/theme/light.json +0 -84
  493. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.json +0 -335
  494. package/packages/pi-coding-agent/src/modes/interactive/theme/dark.json +0 -85
  495. package/packages/pi-coding-agent/src/modes/interactive/theme/light.json +0 -84
  496. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.json +0 -335
  497. package/pkg/dist/modes/interactive/theme/dark.json +0 -85
  498. package/pkg/dist/modes/interactive/theme/light.json +0 -84
  499. package/pkg/dist/modes/interactive/theme/theme-schema.json +0 -335
  500. package/src/resources/extensions/shared/wizard-ui.ts +0 -551
@@ -10,7 +10,8 @@
10
10
  */
11
11
 
12
12
  import { readdirSync, existsSync, realpathSync, Dirent } from "node:fs";
13
- import { join } from "node:path";
13
+ import { join, dirname, normalize } from "node:path";
14
+ import { spawnSync } from "node:child_process";
14
15
  import { nativeScanGsdTree, type GsdTreeEntry } from "./native-parser-bridge.js";
15
16
  import { DIR_CACHE_MAX } from "./constants.js";
16
17
 
@@ -277,15 +278,80 @@ const LEGACY_GSD_ROOT_FILES: Record<GSDRootFileKey, string> = {
277
278
  KNOWLEDGE: "knowledge.md",
278
279
  };
279
280
 
281
+ // ─── GSD Root Discovery ───────────────────────────────────────────────────────
282
+
283
+ const gsdRootCache = new Map<string, string>();
284
+
285
+ /** Exported for tests only — do not call in production code. */
286
+ export function _clearGsdRootCache(): void {
287
+ gsdRootCache.clear();
288
+ }
289
+
290
+ /**
291
+ * Resolve the `.gsd` directory for a given project base path.
292
+ *
293
+ * Probe order:
294
+ * 1. basePath/.gsd — fast path (common case)
295
+ * 2. git rev-parse root — handles cwd-is-a-subdirectory
296
+ * 3. Walk up from basePath — handles moved .gsd in an ancestor (bounded by git root)
297
+ * 4. basePath/.gsd — creation fallback (init scenario)
298
+ *
299
+ * Result is cached per basePath for the process lifetime.
300
+ */
280
301
  export function gsdRoot(basePath: string): string {
281
- const local = join(basePath, ".gsd");
282
- try {
283
- const resolved = realpathSync(local);
284
- if (resolved !== local) return resolved; // symlink resolved
285
- } catch { /* doesn't exist yet — fall through */ }
286
- return local; // backwards compat: unmigrated projects
302
+ const cached = gsdRootCache.get(basePath);
303
+ if (cached) return cached;
304
+
305
+ const result = probeGsdRoot(basePath);
306
+ gsdRootCache.set(basePath, result);
307
+ return result;
287
308
  }
288
309
 
310
+ function probeGsdRoot(rawBasePath: string): string {
311
+ // 1. Fast path — check the input path directly
312
+ const local = join(rawBasePath, ".gsd");
313
+ if (existsSync(local)) return local;
314
+
315
+ // Resolve symlinks so path comparisons work correctly across platforms
316
+ // (e.g. macOS /var → /private/var). Use rawBasePath as fallback if not resolvable.
317
+ let basePath: string;
318
+ try { basePath = realpathSync.native(rawBasePath); } catch { basePath = rawBasePath; }
319
+
320
+ // 2. Git root anchor — used as both probe target and walk-up boundary
321
+ // Only walk if we're inside a git project — prevents escaping into
322
+ // unrelated filesystem territory when running outside any repo.
323
+ let gitRoot: string | null = null;
324
+ try {
325
+ const out = spawnSync("git", ["rev-parse", "--show-toplevel"], {
326
+ cwd: basePath,
327
+ encoding: "utf-8",
328
+ });
329
+ if (out.status === 0) {
330
+ const r = out.stdout.trim();
331
+ if (r) gitRoot = normalize(r);
332
+ }
333
+ } catch { /* git not available */ }
334
+
335
+ if (gitRoot) {
336
+ const candidate = join(gitRoot, ".gsd");
337
+ if (existsSync(candidate)) return candidate;
338
+ }
339
+
340
+ // 3. Walk up from basePath to the git root (only if we are in a subdirectory)
341
+ if (gitRoot && basePath !== gitRoot) {
342
+ let cur = dirname(basePath);
343
+ while (cur !== basePath) {
344
+ const candidate = join(cur, ".gsd");
345
+ if (existsSync(candidate)) return candidate;
346
+ if (cur === gitRoot) break;
347
+ basePath = cur;
348
+ cur = dirname(cur);
349
+ }
350
+ }
351
+
352
+ // 4. Fallback for init/creation
353
+ return local;
354
+ }
289
355
  export function milestonesDir(basePath: string): string {
290
356
  return join(gsdRoot(basePath), "milestones");
291
357
  }
@@ -149,11 +149,15 @@ function dequeueNextHook(basePath: string): HookDispatchResult | null {
149
149
 
150
150
  // Build the prompt with variable substitution
151
151
  const [mid, sid, tid] = triggerUnitId.split("/");
152
- const prompt = config.prompt
152
+ let prompt = config.prompt
153
153
  .replace(/\{milestoneId\}/g, mid ?? "")
154
154
  .replace(/\{sliceId\}/g, sid ?? "")
155
155
  .replace(/\{taskId\}/g, tid ?? "");
156
156
 
157
+ // Inject browser safety instruction for hooks that may use browser tools (#1345).
158
+ // Vite HMR and other persistent connections prevent networkidle from resolving.
159
+ prompt += "\n\n**Browser tool safety:** Do NOT use `browser_wait_for` with `condition: \"network_idle\"` — it hangs indefinitely when dev servers keep persistent connections (Vite HMR, WebSocket). Use `selector_visible`, `text_visible`, or `delay` instead.";
160
+
157
161
  return {
158
162
  hookName: config.name,
159
163
  prompt,
@@ -33,9 +33,24 @@ export function validatePreferences(preferences: GSDPreferences): {
33
33
  const validated: GSDPreferences = {};
34
34
 
35
35
  // ─── Unknown Key Detection ──────────────────────────────────────────
36
+ // Common key migration hints for pi-level settings that don't map to GSD prefs
37
+ const KEY_MIGRATION_HINTS: Record<string, string> = {
38
+ taskIsolation: 'use "git.isolation" instead (values: worktree, branch, none)',
39
+ task_isolation: 'use "git.isolation" instead (values: worktree, branch, none)',
40
+ isolation: 'use "git.isolation" instead (values: worktree, branch, none)',
41
+ manage_gitignore: 'use "git.manage_gitignore" instead',
42
+ auto_push: 'use "git.auto_push" instead',
43
+ main_branch: 'use "git.main_branch" instead',
44
+ };
45
+
36
46
  for (const key of Object.keys(preferences)) {
37
47
  if (!KNOWN_PREFERENCE_KEYS.has(key)) {
38
- warnings.push(`unknown preference key "${key}" — ignored`);
48
+ const hint = KEY_MIGRATION_HINTS[key];
49
+ if (hint) {
50
+ warnings.push(`unknown preference key "${key}" — ${hint}`);
51
+ } else {
52
+ warnings.push(`unknown preference key "${key}" — ignored`);
53
+ }
39
54
  }
40
55
  }
41
56
 
@@ -586,5 +601,43 @@ export function validatePreferences(preferences: GSDPreferences): {
586
601
  }
587
602
  }
588
603
 
604
+ // ─── Auto Visualize ─────────────────────────────────────────────────
605
+ if (preferences.auto_visualize !== undefined) {
606
+ if (typeof preferences.auto_visualize === "boolean") {
607
+ validated.auto_visualize = preferences.auto_visualize;
608
+ } else {
609
+ errors.push("auto_visualize must be a boolean");
610
+ }
611
+ }
612
+
613
+ // ─── Auto Report ────────────────────────────────────────────────────
614
+ if (preferences.auto_report !== undefined) {
615
+ if (typeof preferences.auto_report === "boolean") {
616
+ validated.auto_report = preferences.auto_report;
617
+ } else {
618
+ errors.push("auto_report must be a boolean");
619
+ }
620
+ }
621
+
622
+ // ─── Compression Strategy ───────────────────────────────────────────
623
+ if (preferences.compression_strategy !== undefined) {
624
+ const validStrategies = new Set(["truncate", "compress"]);
625
+ if (typeof preferences.compression_strategy === "string" && validStrategies.has(preferences.compression_strategy)) {
626
+ validated.compression_strategy = preferences.compression_strategy as GSDPreferences["compression_strategy"];
627
+ } else {
628
+ errors.push(`compression_strategy must be one of: truncate, compress`);
629
+ }
630
+ }
631
+
632
+ // ─── Context Selection ──────────────────────────────────────────────
633
+ if (preferences.context_selection !== undefined) {
634
+ const validModes = new Set(["full", "smart"]);
635
+ if (typeof preferences.context_selection === "string" && validModes.has(preferences.context_selection)) {
636
+ validated.context_selection = preferences.context_selection as GSDPreferences["context_selection"];
637
+ } else {
638
+ errors.push(`context_selection must be one of: full, smart`);
639
+ }
640
+ }
641
+
589
642
  return { preferences: validated, errors, warnings };
590
643
  }
@@ -252,6 +252,8 @@ function mergePreferences(base: GSDPreferences, override: GSDPreferences): GSDPr
252
252
  search_provider: override.search_provider ?? base.search_provider,
253
253
  compression_strategy: override.compression_strategy ?? base.compression_strategy,
254
254
  context_selection: override.context_selection ?? base.context_selection,
255
+ auto_visualize: override.auto_visualize ?? base.auto_visualize,
256
+ auto_report: override.auto_report ?? base.auto_report,
255
257
  };
256
258
  }
257
259
 
@@ -28,6 +28,8 @@ Then:
28
28
 
29
29
  **Important:** Do NOT skip the success criteria and definition of done verification (steps 3-4). The milestone summary must reflect actual verified outcomes, not assumed success. If any criterion was not met, document it clearly in the summary and do not mark the milestone as passing verification.
30
30
 
31
+ **File system safety:** When scanning milestone directories for evidence, use `ls` or `find` to list directory contents first — never pass a directory path (e.g. `tasks/`, `slices/`) directly to the `read` tool. The `read` tool only accepts file paths, not directories.
32
+
31
33
  **You MUST write `{{milestoneSummaryPath}}` AND update PROJECT.md before finishing.**
32
34
 
33
35
  When done, say: "Milestone {{milestoneId}} complete."
@@ -67,4 +67,6 @@ If verdict is `needs-remediation`:
67
67
 
68
68
  **You MUST write `{{validationPath}}` before finishing.**
69
69
 
70
+ **File system safety:** When scanning milestone directories for evidence, use `ls` or `find` to list directory contents first — never pass a directory path (e.g. `tasks/`, `slices/`) directly to the `read` tool. The `read` tool only accepts file paths, not directories.
71
+
70
72
  When done, say: "Milestone {{milestoneId}} validation complete — verdict: <verdict>."
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Roadmap Mutations — shared utilities for modifying roadmap checkbox state.
3
+ *
4
+ * Extracts the duplicated "flip slice checkbox" pattern that existed in
5
+ * doctor.ts, mechanical-completion.ts, and auto-recovery.ts.
6
+ */
7
+
8
+ import { readFileSync } from "node:fs";
9
+ import { atomicWriteSync } from "./atomic-write.js";
10
+ import { resolveMilestoneFile } from "./paths.js";
11
+ import { clearParseCache } from "./files.js";
12
+
13
+ /**
14
+ * Mark a slice as done ([x]) in the milestone roadmap.
15
+ * Idempotent — no-op if already checked or if the slice isn't found.
16
+ *
17
+ * @returns true if the roadmap was modified, false if no change was needed
18
+ */
19
+ export function markSliceDoneInRoadmap(basePath: string, mid: string, sid: string): boolean {
20
+ const roadmapFile = resolveMilestoneFile(basePath, mid, "ROADMAP");
21
+ if (!roadmapFile) return false;
22
+
23
+ let content: string;
24
+ try {
25
+ content = readFileSync(roadmapFile, "utf-8");
26
+ } catch {
27
+ return false;
28
+ }
29
+
30
+ const updated = content.replace(
31
+ new RegExp(`^(\\s*-\\s+)\\[ \\]\\s+\\*\\*${sid}:`, "m"),
32
+ `$1[x] **${sid}:`,
33
+ );
34
+
35
+ if (updated === content) return false;
36
+
37
+ atomicWriteSync(roadmapFile, updated);
38
+ clearParseCache();
39
+ return true;
40
+ }
41
+
42
+ /**
43
+ * Mark a task as done ([x]) in the slice plan.
44
+ * Idempotent — no-op if already checked or if the task isn't found.
45
+ *
46
+ * @returns true if the plan was modified, false if no change was needed
47
+ */
48
+ export function markTaskDoneInPlan(basePath: string, planPath: string, tid: string): boolean {
49
+ let content: string;
50
+ try {
51
+ content = readFileSync(planPath, "utf-8");
52
+ } catch {
53
+ return false;
54
+ }
55
+
56
+ const updated = content.replace(
57
+ new RegExp(`^(\\s*-\\s+)\\[ \\]\\s+\\*\\*${tid}:`, "m"),
58
+ `$1[x] **${tid}:`,
59
+ );
60
+
61
+ if (updated === content) return false;
62
+
63
+ atomicWriteSync(planPath, updated);
64
+ clearParseCache();
65
+ return true;
66
+ }
@@ -57,9 +57,19 @@ let _lockCompromised: boolean = false;
57
57
  /** Whether we've already registered a process.on('exit') handler. */
58
58
  let _exitHandlerRegistered: boolean = false;
59
59
 
60
+ /** Snapshotted lock file path — captured at acquireSessionLock time to avoid
61
+ * gsdRoot() resolving differently in worktree vs project root contexts (#1363). */
62
+ let _snapshotLockPath: string | null = null;
63
+
64
+ /** Timestamp when the session lock was acquired — used to detect false-positive
65
+ * onCompromised events from event loop stalls within the stale window (#1362). */
66
+ let _lockAcquiredAt: number = 0;
67
+
60
68
  const LOCK_FILE = "auto.lock";
61
69
 
62
70
  function lockPath(basePath: string): string {
71
+ // If we have a snapshotted path from acquisition, use it for consistency
72
+ if (_snapshotLockPath) return _snapshotLockPath;
63
73
  return join(gsdRoot(basePath), LOCK_FILE);
64
74
  }
65
75
 
@@ -198,8 +208,19 @@ export function acquireSessionLock(basePath: string): SessionLockResult {
198
208
  onCompromised: () => {
199
209
  // proper-lockfile detected mtime drift (system sleep, event loop stall, etc.).
200
210
  // Default handler throws inside setTimeout — an uncaught exception that crashes
201
- // or corrupts process state. Instead, set a flag so validateSessionLock() can
202
- // detect the compromise gracefully on the next dispatch cycle.
211
+ // or corrupts process state.
212
+ //
213
+ // False-positive suppression (#1362): If we're still within the stale window
214
+ // (30 min since acquisition), the mtime mismatch is from an event loop stall
215
+ // during a long LLM call — not a real takeover. Log and continue.
216
+ const elapsed = Date.now() - _lockAcquiredAt;
217
+ if (elapsed < 1_800_000) {
218
+ process.stderr.write(
219
+ `[gsd] Lock heartbeat mismatch after ${Math.round(elapsed / 1000)}s — event loop stall, continuing.\n`,
220
+ );
221
+ return; // Suppress false positive
222
+ }
223
+ // Past the stale window — this is a real compromise
203
224
  _lockCompromised = true;
204
225
  _releaseFunction = null;
205
226
  },
@@ -209,6 +230,8 @@ export function acquireSessionLock(basePath: string): SessionLockResult {
209
230
  _lockedPath = basePath;
210
231
  _lockPid = process.pid;
211
232
  _lockCompromised = false;
233
+ _lockAcquiredAt = Date.now();
234
+ _snapshotLockPath = lp; // Snapshot the resolved path for consistent access (#1363)
212
235
 
213
236
  // Safety net: clean up lock dir on process exit if _releaseFunction
214
237
  // wasn't called (e.g., normal exit after clean completion) (#1245).
@@ -245,6 +268,8 @@ export function acquireSessionLock(basePath: string): SessionLockResult {
245
268
  _lockedPath = basePath;
246
269
  _lockPid = process.pid;
247
270
  _lockCompromised = false;
271
+ _lockAcquiredAt = Date.now();
272
+ _snapshotLockPath = lp; // Snapshot for retry path too (#1363)
248
273
 
249
274
  // Safety net — uses centralized handler to avoid double-registration
250
275
  ensureExitHandler(gsdDir);
@@ -394,6 +419,8 @@ export function releaseSessionLock(basePath: string): void {
394
419
  _lockedPath = null;
395
420
  _lockPid = 0;
396
421
  _lockCompromised = false;
422
+ _lockAcquiredAt = 0;
423
+ _snapshotLockPath = null;
397
424
  }
398
425
 
399
426
  /**
@@ -113,6 +113,14 @@
113
113
  - Tasks execute sequentially in order (T01, T02, T03, ...)
114
114
  - est: is informational (e.g. 30m, 1h, 2h) and optional
115
115
 
116
+ Verify field rules:
117
+ - MUST be a mechanically executable command: `npm test`, `grep -q "pattern" file`, `test -f path`
118
+ - For content/document tasks: verify file existence, section count, YAML validity, or word count
119
+ NOT exact phrasing, specific formulas, or "zero TBD" aspirational criteria
120
+ - If no command can verify the output, write: "Manual review — file exists and is non-empty"
121
+ - BAD: "Sections 3.1 and 3.2 exist with exact formulas. Zero TBD/TODO."
122
+ - GOOD: `grep -c "^## " doc.md` returns >= 4 (4+ sections), `! grep -q "TBD\|TODO" doc.md`
123
+
116
124
  Integration closure rule:
117
125
  - At least one slice in any multi-boundary milestone should perform real composition/wiring, not just contract hardening
118
126
  - For the final assembly slice, verification must exercise the real entrypoint or runtime path
@@ -0,0 +1,46 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import fs from "node:fs";
6
+
7
+ import { handleInspect } from "../commands-inspect.ts";
8
+ import { closeDatabase, openDatabase } from "../gsd-db.ts";
9
+
10
+ test("/gsd inspect opens existing database when it was not yet opened in session", async () => {
11
+ closeDatabase();
12
+
13
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "gsd-inspect-db-"));
14
+ const prevCwd = process.cwd();
15
+
16
+ try {
17
+ const gsdDir = path.join(tmp, ".gsd");
18
+ fs.mkdirSync(gsdDir, { recursive: true });
19
+ const dbPath = path.join(gsdDir, "gsd.db");
20
+
21
+ assert.equal(openDatabase(dbPath), true);
22
+ closeDatabase();
23
+
24
+ process.chdir(tmp);
25
+
26
+ const notifications: Array<{ message: string; level: string }> = [];
27
+ const ctx = {
28
+ ui: {
29
+ notify(message: string, level: string) {
30
+ notifications.push({ message, level });
31
+ },
32
+ },
33
+ } as any;
34
+
35
+ await handleInspect(ctx);
36
+
37
+ assert.equal(notifications.length, 1);
38
+ assert.equal(notifications[0].level, "info");
39
+ assert.match(notifications[0].message, /=== GSD Database Inspect ===/);
40
+ assert.doesNotMatch(notifications[0].message, /No GSD database available/);
41
+ } finally {
42
+ process.chdir(prevCwd);
43
+ closeDatabase();
44
+ fs.rmSync(tmp, { recursive: true, force: true });
45
+ }
46
+ });
@@ -2,9 +2,10 @@
2
2
  * doctor-git.test.ts — Integration tests for doctor git health checks.
3
3
  *
4
4
  * Creates real temp git repos with deliberate broken state, runs runGSDDoctor,
5
- * and asserts correct detection and fixing of all 4 git issue codes:
5
+ * and asserts correct detection and fixing of git issue codes:
6
6
  * orphaned_auto_worktree, stale_milestone_branch,
7
- * corrupt_merge_state, tracked_runtime_files
7
+ * corrupt_merge_state, tracked_runtime_files,
8
+ * integration_branch_missing, worktree_directory_orphaned
8
9
  */
9
10
 
10
11
  import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, realpathSync } from "node:fs";
@@ -299,6 +300,101 @@ async function main(): Promise<void> {
299
300
  console.log("\n=== none-mode skips stale branch (skipped on Windows) ===");
300
301
  }
301
302
 
303
+ // ─── Test: Integration branch missing ──────────────────────────────
304
+ if (process.platform !== "win32") {
305
+ console.log("\n=== integration_branch_missing ===");
306
+ {
307
+ const dir = createRepoWithActiveMilestone();
308
+ cleanups.push(dir);
309
+
310
+ // Write integration branch metadata for M001 pointing to a non-existent branch
311
+ const metaPath = join(dir, ".gsd", "milestones", "M001", "M001-META.json");
312
+ writeFileSync(metaPath, JSON.stringify({ integrationBranch: "feat/does-not-exist" }, null, 2));
313
+
314
+ const detect = await runGSDDoctor(dir);
315
+ const missingBranchIssues = detect.issues.filter(i => i.code === "integration_branch_missing");
316
+ assertTrue(missingBranchIssues.length > 0, "detects missing integration branch");
317
+ assertTrue(
318
+ missingBranchIssues[0]?.message.includes("feat/does-not-exist"),
319
+ "message includes the missing branch name",
320
+ );
321
+ assertEq(missingBranchIssues[0]?.fixable, false, "integration_branch_missing is not auto-fixable");
322
+ assertEq(missingBranchIssues[0]?.severity, "error", "severity is error");
323
+ }
324
+ } else {
325
+ console.log("\n=== integration_branch_missing (skipped on Windows) ===");
326
+ }
327
+
328
+ // ─── Test: Integration branch present — no false positive ──────────
329
+ if (process.platform !== "win32") {
330
+ console.log("\n=== integration_branch_missing (no false positive) ===");
331
+ {
332
+ const dir = createRepoWithActiveMilestone();
333
+ cleanups.push(dir);
334
+
335
+ // Write integration branch metadata for M001 pointing to "main" (which exists)
336
+ const metaPath = join(dir, ".gsd", "milestones", "M001", "M001-META.json");
337
+ writeFileSync(metaPath, JSON.stringify({ integrationBranch: "main" }, null, 2));
338
+
339
+ const detect = await runGSDDoctor(dir);
340
+ const missingBranchIssues = detect.issues.filter(i => i.code === "integration_branch_missing");
341
+ assertEq(missingBranchIssues.length, 0, "existing integration branch NOT flagged");
342
+ }
343
+ } else {
344
+ console.log("\n=== integration_branch_missing (no false positive — skipped on Windows) ===");
345
+ }
346
+
347
+ // ─── Test: Orphaned worktree directory ─────────────────────────────
348
+ if (process.platform !== "win32") {
349
+ console.log("\n=== worktree_directory_orphaned ===");
350
+ {
351
+ const dir = createRepoWithActiveMilestone();
352
+ cleanups.push(dir);
353
+
354
+ // Create a worktrees/ dir with an entry that is NOT in git worktree list
355
+ const orphanDir = join(dir, ".gsd", "worktrees", "orphan-feature");
356
+ mkdirSync(orphanDir, { recursive: true });
357
+ writeFileSync(join(orphanDir, "some-file.txt"), "leftover content\n");
358
+
359
+ const detect = await runGSDDoctor(dir);
360
+ const orphanDirIssues = detect.issues.filter(i => i.code === "worktree_directory_orphaned");
361
+ assertTrue(orphanDirIssues.length > 0, "detects orphaned worktree directory");
362
+ assertTrue(
363
+ orphanDirIssues[0]?.message.includes("orphan-feature"),
364
+ "message includes the orphaned directory name",
365
+ );
366
+ assertTrue(orphanDirIssues[0]?.fixable === true, "worktree_directory_orphaned is fixable");
367
+
368
+ const fixed = await runGSDDoctor(dir, { fix: true });
369
+ assertTrue(
370
+ fixed.fixesApplied.some(f => f.includes("removed orphaned worktree directory")),
371
+ "fix removes orphaned worktree directory",
372
+ );
373
+ assertTrue(!existsSync(orphanDir), "orphaned directory removed after fix");
374
+ }
375
+ } else {
376
+ console.log("\n=== worktree_directory_orphaned (skipped on Windows) ===");
377
+ }
378
+
379
+ // ─── Test: Registered worktree NOT flagged as orphaned ─────────────
380
+ if (process.platform !== "win32") {
381
+ console.log("\n=== worktree_directory_orphaned (registered worktree not flagged) ===");
382
+ {
383
+ const dir = createRepoWithActiveMilestone();
384
+ cleanups.push(dir);
385
+
386
+ // Create a real registered worktree under .gsd/worktrees/
387
+ mkdirSync(join(dir, ".gsd", "worktrees"), { recursive: true });
388
+ run("git worktree add -b worktree/feature-1 .gsd/worktrees/feature-1", dir);
389
+
390
+ const detect = await runGSDDoctor(dir);
391
+ const orphanDirIssues = detect.issues.filter(i => i.code === "worktree_directory_orphaned");
392
+ assertEq(orphanDirIssues.length, 0, "registered worktree NOT flagged as orphaned");
393
+ }
394
+ } else {
395
+ console.log("\n=== worktree_directory_orphaned (registered worktree not flagged — skipped on Windows) ===");
396
+ }
397
+
302
398
  // ─── Test 9: none-mode still detects corrupt merge state ───────────
303
399
  console.log("\n=== none-mode keeps corrupt merge state ===");
304
400
  {
@@ -2,9 +2,9 @@
2
2
  * doctor-runtime.test.ts — Tests for doctor runtime health checks.
3
3
  *
4
4
  * Tests detection and auto-fix of:
5
- * stale_crash_lock, orphaned_completed_units, stale_hook_state,
6
- * activity_log_bloat, state_file_missing, state_file_stale,
7
- * gitignore_missing_patterns
5
+ * stale_crash_lock, stranded_lock_directory, orphaned_completed_units,
6
+ * stale_hook_state, activity_log_bloat, state_file_missing,
7
+ * state_file_stale, gitignore_missing_patterns
8
8
  */
9
9
 
10
10
  import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, readFileSync, realpathSync } from "node:fs";
@@ -290,6 +290,62 @@ node_modules/
290
290
  assertEq(content.length, 0, "all orphaned keys removed");
291
291
  }
292
292
 
293
+ // ─── Test: Stranded lock directory detection & fix ────────────────
294
+ // Skip on Windows: proper-lockfile uses advisory file locking on Windows,
295
+ // not the directory-based mechanism. The .gsd.lock/ directory pattern is
296
+ // a POSIX-specific lockfile implementation detail.
297
+ if (process.platform !== "win32") {
298
+ console.log("\n=== stranded_lock_directory ===");
299
+ {
300
+ const dir = createMinimalProject();
301
+ cleanups.push(dir);
302
+
303
+ // Create the proper-lockfile lock directory without a live lock holder.
304
+ // The lock dir sits at <parent of .gsd>/.gsd.lock (i.e., <basePath>/.gsd.lock).
305
+ const lockDir = join(dir, ".gsd.lock");
306
+ mkdirSync(lockDir, { recursive: true });
307
+
308
+ const detect = await runGSDDoctor(dir);
309
+ const strandedIssues = detect.issues.filter(i => i.code === "stranded_lock_directory");
310
+ assertTrue(strandedIssues.length > 0, "detects stranded lock directory");
311
+ assertTrue(strandedIssues[0]?.message.includes("lock directory"), "message describes stranded lock directory");
312
+ assertTrue(strandedIssues[0]?.fixable === true, "stranded lock dir is fixable");
313
+
314
+ const fixed = await runGSDDoctor(dir, { fix: true });
315
+ assertTrue(
316
+ fixed.fixesApplied.some(f => f.includes("removed stranded lock directory")),
317
+ "fix removes stranded lock directory",
318
+ );
319
+ assertTrue(!existsSync(lockDir), "lock directory removed after fix");
320
+ }
321
+
322
+ // ─── Test: Stranded lock dir with live lock holder — NOT flagged ───
323
+ console.log("\n=== stranded_lock_directory (live holder not flagged) ===");
324
+ {
325
+ const dir = createMinimalProject();
326
+ cleanups.push(dir);
327
+
328
+ // Create lock dir + auto.lock with PID 1 (init/launchd — always alive, never our own PID)
329
+ const lockDir = join(dir, ".gsd.lock");
330
+ mkdirSync(lockDir, { recursive: true });
331
+ const liveLockData = {
332
+ pid: 1,
333
+ startedAt: new Date().toISOString(),
334
+ unitType: "execute-task",
335
+ unitId: "M001/S01/T01",
336
+ unitStartedAt: new Date().toISOString(),
337
+ completedUnits: 1,
338
+ };
339
+ writeFileSync(join(dir, ".gsd", "auto.lock"), JSON.stringify(liveLockData, null, 2));
340
+
341
+ const detect = await runGSDDoctor(dir);
342
+ const strandedIssues = detect.issues.filter(i => i.code === "stranded_lock_directory");
343
+ assertEq(strandedIssues.length, 0, "live lock holder: stranded_lock_directory NOT detected");
344
+ }
345
+ } else {
346
+ console.log("\n=== stranded_lock_directory (skipped on Windows) ===");
347
+ }
348
+
293
349
  } finally {
294
350
  for (const dir of cleanups) {
295
351
  try { rmSync(dir, { recursive: true, force: true }); } catch { /* ignore */ }
@@ -0,0 +1,20 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import fs from "node:fs";
6
+
7
+ import { loadFile } from "../files.ts";
8
+
9
+ test("loadFile returns null for directory paths instead of throwing EISDIR", async () => {
10
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "gsd-loadfile-eisdir-"));
11
+ const dirPath = path.join(tmp, "tasks");
12
+ fs.mkdirSync(dirPath);
13
+
14
+ try {
15
+ const result = await loadFile(dirPath);
16
+ assert.equal(result, null);
17
+ } finally {
18
+ fs.rmSync(tmp, { recursive: true, force: true });
19
+ }
20
+ });