gsd-pi 2.20.0 → 2.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. package/README.md +12 -0
  2. package/dist/cli.js +21 -18
  3. package/dist/help-text.d.ts +2 -0
  4. package/dist/help-text.js +47 -0
  5. package/dist/loader.js +2 -16
  6. package/dist/mcp-server.d.ts +18 -0
  7. package/dist/mcp-server.js +53 -0
  8. package/dist/onboarding.d.ts +0 -6
  9. package/dist/onboarding.js +0 -28
  10. package/dist/resources/agents/javascript-pro.md +280 -0
  11. package/dist/resources/agents/typescript-pro.md +255 -0
  12. package/dist/resources/extensions/bg-shell/index.ts +14 -2
  13. package/dist/resources/extensions/bg-shell/utilities.ts +14 -0
  14. package/dist/resources/extensions/browser-tools/{core.js → core.ts} +329 -190
  15. package/dist/resources/extensions/gsd/auto-dashboard.ts +2 -1
  16. package/dist/resources/extensions/gsd/auto-prompts.ts +42 -1
  17. package/dist/resources/extensions/gsd/auto-worktree.ts +35 -2
  18. package/dist/resources/extensions/gsd/auto.ts +116 -10
  19. package/dist/resources/extensions/gsd/claude-import.ts +656 -0
  20. package/dist/resources/extensions/gsd/collision-diagnostics.ts +332 -0
  21. package/dist/resources/extensions/gsd/commands.ts +60 -7
  22. package/dist/resources/extensions/gsd/diff-context.ts +220 -0
  23. package/dist/resources/extensions/gsd/docs/claude-marketplace-import.md +214 -0
  24. package/dist/resources/extensions/gsd/docs/preferences-reference.md +2 -1
  25. package/dist/resources/extensions/gsd/doctor.ts +12 -4
  26. package/dist/resources/extensions/gsd/file-watcher.ts +97 -0
  27. package/dist/resources/extensions/gsd/files.ts +1 -1
  28. package/dist/resources/extensions/gsd/forensics.ts +596 -0
  29. package/dist/resources/extensions/gsd/git-service.ts +2 -1
  30. package/dist/resources/extensions/gsd/github-client.ts +235 -0
  31. package/dist/resources/extensions/gsd/gitignore.ts +1 -0
  32. package/dist/resources/extensions/gsd/marketplace-discovery.ts +507 -0
  33. package/dist/resources/extensions/gsd/mcp-server.ts +87 -0
  34. package/dist/resources/extensions/gsd/namespaced-registry.ts +467 -0
  35. package/dist/resources/extensions/gsd/namespaced-resolver.ts +307 -0
  36. package/dist/resources/extensions/gsd/plugin-importer.ts +410 -0
  37. package/dist/resources/extensions/gsd/preferences.ts +14 -3
  38. package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -1
  39. package/dist/resources/extensions/gsd/prompts/forensics.md +71 -0
  40. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  41. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
  42. package/dist/resources/extensions/gsd/prompts/system.md +12 -3
  43. package/dist/resources/extensions/gsd/roadmap-slices.ts +1 -1
  44. package/dist/resources/extensions/gsd/session-forensics.ts +5 -5
  45. package/dist/resources/extensions/gsd/tests/claude-import-tui.test.ts +351 -0
  46. package/dist/resources/extensions/gsd/tests/collision-diagnostics.test.ts +705 -0
  47. package/dist/resources/extensions/gsd/tests/context-compression.test.ts +13 -0
  48. package/dist/resources/extensions/gsd/tests/diff-context.test.ts +136 -0
  49. package/dist/resources/extensions/gsd/tests/doctor-git.test.ts +118 -0
  50. package/dist/resources/extensions/gsd/tests/marketplace-discovery.test.ts +202 -0
  51. package/dist/resources/extensions/gsd/tests/marketplace-test-fixtures.ts +91 -0
  52. package/dist/resources/extensions/gsd/tests/namespaced-registry.test.ts +1027 -0
  53. package/dist/resources/extensions/gsd/tests/namespaced-resolver.test.ts +671 -0
  54. package/dist/resources/extensions/gsd/tests/none-mode-gates.test.ts +105 -0
  55. package/dist/resources/extensions/gsd/tests/plugin-importer-live.test.ts +481 -0
  56. package/dist/resources/extensions/gsd/tests/plugin-importer.test.ts +1383 -0
  57. package/dist/resources/extensions/gsd/tests/preferences-git.test.ts +21 -2
  58. package/dist/resources/extensions/gsd/tests/preferences-schema-validation.test.ts +8 -1
  59. package/dist/resources/extensions/gsd/tests/visualizer-data.test.ts +11 -0
  60. package/dist/resources/extensions/gsd/tests/worktree-bugfix.test.ts +120 -0
  61. package/dist/resources/extensions/gsd/token-counter.ts +45 -0
  62. package/dist/resources/extensions/gsd/visualizer-data.ts +2 -2
  63. package/dist/resources/extensions/gsd/worktree-manager.ts +29 -1
  64. package/dist/resources/extensions/gsd/worktree.ts +3 -0
  65. package/dist/resources/extensions/mcporter/index.ts +90 -7
  66. package/dist/resources/extensions/search-the-web/native-search.ts +2 -0
  67. package/dist/resources/extensions/search-the-web/tool-fetch-page.ts +9 -1
  68. package/dist/resources/extensions/search-the-web/url-utils.ts +35 -1
  69. package/dist/resources/extensions/shared/terminal.ts +1 -1
  70. package/dist/resources/extensions/universal-config/discovery.ts +4 -0
  71. package/dist/resources/extensions/universal-config/format.ts +35 -4
  72. package/dist/resources/extensions/universal-config/index.ts +5 -3
  73. package/dist/resources/extensions/universal-config/scanners.ts +65 -2
  74. package/dist/resources/extensions/universal-config/tests/discovery.test.ts +9 -1
  75. package/dist/resources/extensions/universal-config/tests/format.test.ts +22 -6
  76. package/dist/resources/extensions/universal-config/tests/scanners.test.ts +18 -0
  77. package/dist/resources/extensions/universal-config/types.ts +20 -1
  78. package/dist/resources/skills/lint/SKILL.md +141 -0
  79. package/dist/resources/skills/review/SKILL.md +214 -0
  80. package/dist/resources/skills/test/SKILL.md +201 -0
  81. package/dist/tool-bootstrap.js +2 -1
  82. package/dist/wizard.js +2 -0
  83. package/package.json +12 -7
  84. package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
  85. package/packages/pi-ai/dist/providers/azure-openai-responses.js +12 -1
  86. package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
  87. package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
  88. package/packages/pi-ai/dist/providers/openai-responses.js +12 -1
  89. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  90. package/packages/pi-ai/node_modules/@smithy/node-http-handler/LICENSE +201 -0
  91. package/packages/pi-ai/node_modules/@smithy/node-http-handler/README.md +9 -0
  92. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-cjs/index.js +762 -0
  93. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/build-abort-error.js +19 -0
  94. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/constants.js +1 -0
  95. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/get-transformed-headers.js +9 -0
  96. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/index.js +3 -0
  97. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/node-http-handler.js +230 -0
  98. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/node-http2-connection-manager.js +87 -0
  99. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/node-http2-connection-pool.js +32 -0
  100. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/node-http2-handler.js +169 -0
  101. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/readable.mock.js +21 -0
  102. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/server.mock.js +88 -0
  103. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/set-connection-timeout.js +36 -0
  104. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/set-request-timeout.js +21 -0
  105. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/set-socket-keep-alive.js +22 -0
  106. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/set-socket-timeout.js +23 -0
  107. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/stream-collector/collector.js +8 -0
  108. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/stream-collector/index.js +41 -0
  109. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/stream-collector/readable.mock.js +21 -0
  110. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/timing.js +4 -0
  111. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/write-request-body.js +63 -0
  112. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/build-abort-error.d.ts +10 -0
  113. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/constants.d.ts +5 -0
  114. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/get-transformed-headers.d.ts +4 -0
  115. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/index.d.ts +3 -0
  116. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/node-http-handler.d.ts +46 -0
  117. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/node-http2-connection-manager.d.ts +24 -0
  118. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/node-http2-connection-pool.d.ts +12 -0
  119. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/node-http2-handler.d.ts +63 -0
  120. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/readable.mock.d.ts +13 -0
  121. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/server.mock.d.ts +12 -0
  122. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/set-connection-timeout.d.ts +2 -0
  123. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/set-request-timeout.d.ts +6 -0
  124. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/set-socket-keep-alive.d.ts +6 -0
  125. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/set-socket-timeout.d.ts +2 -0
  126. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/stream-collector/collector.d.ts +5 -0
  127. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/stream-collector/index.d.ts +6 -0
  128. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/stream-collector/readable.mock.d.ts +13 -0
  129. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/timing.d.ts +8 -0
  130. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/build-abort-error.d.ts +10 -0
  131. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/constants.d.ts +5 -0
  132. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/get-transformed-headers.d.ts +4 -0
  133. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/index.d.ts +3 -0
  134. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/node-http-handler.d.ts +46 -0
  135. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/node-http2-connection-manager.d.ts +24 -0
  136. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/node-http2-connection-pool.d.ts +12 -0
  137. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/node-http2-handler.d.ts +63 -0
  138. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/readable.mock.d.ts +13 -0
  139. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/server.mock.d.ts +12 -0
  140. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/set-connection-timeout.d.ts +2 -0
  141. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/set-request-timeout.d.ts +6 -0
  142. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/set-socket-keep-alive.d.ts +6 -0
  143. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/set-socket-timeout.d.ts +2 -0
  144. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/stream-collector/collector.d.ts +5 -0
  145. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/stream-collector/index.d.ts +6 -0
  146. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/stream-collector/readable.mock.d.ts +13 -0
  147. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/timing.d.ts +8 -0
  148. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/write-request-body.d.ts +12 -0
  149. package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/write-request-body.d.ts +12 -0
  150. package/packages/pi-ai/node_modules/@smithy/node-http-handler/package.json +68 -0
  151. package/packages/pi-ai/package.json +3 -0
  152. package/packages/pi-ai/pnpm-lock.yaml +2022 -0
  153. package/packages/pi-ai/src/providers/azure-openai-responses.ts +12 -1
  154. package/packages/pi-ai/src/providers/openai-responses.ts +12 -1
  155. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  156. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  157. package/packages/pi-coding-agent/dist/core/extensions/index.js +1 -1
  158. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  159. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +1 -0
  160. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  161. package/packages/pi-coding-agent/dist/core/extensions/loader.js +12 -1
  162. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  163. package/packages/pi-coding-agent/dist/core/extensions/loader.test.d.ts +2 -0
  164. package/packages/pi-coding-agent/dist/core/extensions/loader.test.d.ts.map +1 -0
  165. package/packages/pi-coding-agent/dist/core/extensions/loader.test.js +113 -0
  166. package/packages/pi-coding-agent/dist/core/extensions/loader.test.js.map +1 -0
  167. package/packages/pi-coding-agent/dist/core/extensions/project-trust.d.ts +4 -0
  168. package/packages/pi-coding-agent/dist/core/extensions/project-trust.d.ts.map +1 -0
  169. package/packages/pi-coding-agent/dist/core/extensions/project-trust.js +42 -0
  170. package/packages/pi-coding-agent/dist/core/extensions/project-trust.js.map +1 -0
  171. package/packages/pi-coding-agent/dist/core/resolve-config-value.d.ts +1 -0
  172. package/packages/pi-coding-agent/dist/core/resolve-config-value.d.ts.map +1 -1
  173. package/packages/pi-coding-agent/dist/core/resolve-config-value.js +18 -0
  174. package/packages/pi-coding-agent/dist/core/resolve-config-value.js.map +1 -1
  175. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.d.ts +2 -0
  176. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.d.ts.map +1 -0
  177. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +114 -0
  178. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -0
  179. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  180. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +8 -2
  181. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
  182. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts +2 -0
  183. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  184. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +23 -9
  185. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  186. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.d.ts +2 -0
  187. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.d.ts.map +1 -0
  188. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +67 -0
  189. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -0
  190. package/packages/pi-coding-agent/package.json +1 -1
  191. package/packages/pi-coding-agent/pnpm-lock.yaml +454 -0
  192. package/packages/pi-coding-agent/scripts/copy-assets.cjs +24 -0
  193. package/packages/pi-coding-agent/src/core/extensions/index.ts +3 -0
  194. package/packages/pi-coding-agent/src/core/extensions/loader.test.ts +141 -0
  195. package/packages/pi-coding-agent/src/core/extensions/loader.ts +14 -1
  196. package/packages/pi-coding-agent/src/core/extensions/project-trust.ts +51 -0
  197. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +132 -0
  198. package/packages/pi-coding-agent/src/core/resolve-config-value.ts +20 -0
  199. package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +7 -2
  200. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +98 -0
  201. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +24 -9
  202. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  203. package/packages/pi-tui/dist/tui.js +2 -2
  204. package/packages/pi-tui/dist/tui.js.map +1 -1
  205. package/packages/pi-tui/package.json +3 -1
  206. package/packages/pi-tui/src/tui.ts +2 -2
  207. package/src/resources/agents/javascript-pro.md +280 -0
  208. package/src/resources/agents/typescript-pro.md +255 -0
  209. package/src/resources/extensions/bg-shell/index.ts +14 -2
  210. package/src/resources/extensions/bg-shell/utilities.ts +14 -0
  211. package/src/resources/extensions/browser-tools/{core.js → core.ts} +329 -190
  212. package/src/resources/extensions/gsd/auto-dashboard.ts +2 -1
  213. package/src/resources/extensions/gsd/auto-prompts.ts +42 -1
  214. package/src/resources/extensions/gsd/auto-worktree.ts +35 -2
  215. package/src/resources/extensions/gsd/auto.ts +116 -10
  216. package/src/resources/extensions/gsd/claude-import.ts +656 -0
  217. package/src/resources/extensions/gsd/collision-diagnostics.ts +332 -0
  218. package/src/resources/extensions/gsd/commands.ts +60 -7
  219. package/src/resources/extensions/gsd/diff-context.ts +220 -0
  220. package/src/resources/extensions/gsd/docs/claude-marketplace-import.md +214 -0
  221. package/src/resources/extensions/gsd/docs/preferences-reference.md +2 -1
  222. package/src/resources/extensions/gsd/doctor.ts +12 -4
  223. package/src/resources/extensions/gsd/file-watcher.ts +97 -0
  224. package/src/resources/extensions/gsd/files.ts +1 -1
  225. package/src/resources/extensions/gsd/forensics.ts +596 -0
  226. package/src/resources/extensions/gsd/git-service.ts +2 -1
  227. package/src/resources/extensions/gsd/github-client.ts +235 -0
  228. package/src/resources/extensions/gsd/gitignore.ts +1 -0
  229. package/src/resources/extensions/gsd/marketplace-discovery.ts +507 -0
  230. package/src/resources/extensions/gsd/mcp-server.ts +87 -0
  231. package/src/resources/extensions/gsd/namespaced-registry.ts +467 -0
  232. package/src/resources/extensions/gsd/namespaced-resolver.ts +307 -0
  233. package/src/resources/extensions/gsd/plugin-importer.ts +410 -0
  234. package/src/resources/extensions/gsd/preferences.ts +14 -3
  235. package/src/resources/extensions/gsd/prompts/execute-task.md +1 -1
  236. package/src/resources/extensions/gsd/prompts/forensics.md +71 -0
  237. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  238. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  239. package/src/resources/extensions/gsd/prompts/system.md +12 -3
  240. package/src/resources/extensions/gsd/roadmap-slices.ts +1 -1
  241. package/src/resources/extensions/gsd/session-forensics.ts +5 -5
  242. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +351 -0
  243. package/src/resources/extensions/gsd/tests/collision-diagnostics.test.ts +705 -0
  244. package/src/resources/extensions/gsd/tests/context-compression.test.ts +13 -0
  245. package/src/resources/extensions/gsd/tests/diff-context.test.ts +136 -0
  246. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +118 -0
  247. package/src/resources/extensions/gsd/tests/marketplace-discovery.test.ts +202 -0
  248. package/src/resources/extensions/gsd/tests/marketplace-test-fixtures.ts +91 -0
  249. package/src/resources/extensions/gsd/tests/namespaced-registry.test.ts +1027 -0
  250. package/src/resources/extensions/gsd/tests/namespaced-resolver.test.ts +671 -0
  251. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +105 -0
  252. package/src/resources/extensions/gsd/tests/plugin-importer-live.test.ts +481 -0
  253. package/src/resources/extensions/gsd/tests/plugin-importer.test.ts +1383 -0
  254. package/src/resources/extensions/gsd/tests/preferences-git.test.ts +21 -2
  255. package/src/resources/extensions/gsd/tests/preferences-schema-validation.test.ts +8 -1
  256. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +11 -0
  257. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +120 -0
  258. package/src/resources/extensions/gsd/token-counter.ts +45 -0
  259. package/src/resources/extensions/gsd/visualizer-data.ts +2 -2
  260. package/src/resources/extensions/gsd/worktree-manager.ts +29 -1
  261. package/src/resources/extensions/gsd/worktree.ts +3 -0
  262. package/src/resources/extensions/mcporter/index.ts +90 -7
  263. package/src/resources/extensions/search-the-web/native-search.ts +2 -0
  264. package/src/resources/extensions/search-the-web/tool-fetch-page.ts +9 -1
  265. package/src/resources/extensions/search-the-web/url-utils.ts +35 -1
  266. package/src/resources/extensions/shared/terminal.ts +1 -1
  267. package/src/resources/extensions/universal-config/discovery.ts +4 -0
  268. package/src/resources/extensions/universal-config/format.ts +35 -4
  269. package/src/resources/extensions/universal-config/index.ts +5 -3
  270. package/src/resources/extensions/universal-config/scanners.ts +65 -2
  271. package/src/resources/extensions/universal-config/tests/discovery.test.ts +9 -1
  272. package/src/resources/extensions/universal-config/tests/format.test.ts +22 -6
  273. package/src/resources/extensions/universal-config/tests/scanners.test.ts +18 -0
  274. package/src/resources/extensions/universal-config/types.ts +20 -1
  275. package/src/resources/skills/lint/SKILL.md +141 -0
  276. package/src/resources/skills/review/SKILL.md +214 -0
  277. package/src/resources/skills/test/SKILL.md +201 -0
  278. package/dist/resources/extensions/browser-tools/core.d.ts +0 -205
  279. package/src/resources/extensions/browser-tools/core.d.ts +0 -205
@@ -525,6 +525,17 @@ export function resolveSkillStalenessDays(): number {
525
525
  return prefs?.preferences.skill_staleness_days ?? 60;
526
526
  }
527
527
 
528
+ /**
529
+ * Resolve the effective git isolation mode from preferences.
530
+ * Returns "worktree" (default), "branch", or "none".
531
+ */
532
+ export function getIsolationMode(): "none" | "worktree" | "branch" {
533
+ const prefs = loadEffectiveGSDPreferences()?.preferences?.git;
534
+ if (prefs?.isolation === "none") return "none";
535
+ if (prefs?.isolation === "branch") return "branch";
536
+ return "worktree"; // default
537
+ }
538
+
528
539
  /**
529
540
  * Resolve which model ID to use for a given auto-mode unit type.
530
541
  * Returns undefined if no model preference is set for this unit type.
@@ -1197,11 +1208,11 @@ export function validatePreferences(preferences: GSDPreferences): {
1197
1208
  }
1198
1209
  }
1199
1210
  if (g.isolation !== undefined) {
1200
- const validIsolation = new Set(["worktree", "branch"]);
1211
+ const validIsolation = new Set(["worktree", "branch", "none"]);
1201
1212
  if (typeof g.isolation === "string" && validIsolation.has(g.isolation)) {
1202
- git.isolation = g.isolation as "worktree" | "branch";
1213
+ git.isolation = g.isolation as "worktree" | "branch" | "none";
1203
1214
  } else {
1204
- errors.push("git.isolation must be one of: worktree, branch");
1215
+ errors.push("git.isolation must be one of: worktree, branch, none");
1205
1216
  }
1206
1217
  }
1207
1218
  if (g.commit_docs !== undefined) {
@@ -26,7 +26,7 @@ A researcher explored the codebase and a planner decomposed the work — you are
26
26
 
27
27
  Then:
28
28
  0. Narrate step transitions, key implementation decisions, and verification outcomes as you work. Keep it terse — one line between tool-call clusters, not between every call.
29
- 1. If a `GSD Skill Preferences` block is present in system context, use it to decide which skills to load and follow during execution, without relaxing required verification or artifact rules
29
+ 1. **Load relevant skills before writing code.** Check the `GSD Skill Preferences` block in system context and the `<available_skills>` catalog in your system prompt. For each skill that matches this task's technology stack (e.g., React, Next.js, accessibility, component design), `read` its SKILL.md file now. Skills contain implementation rules and patterns that should guide your code. If no skills match this task, skip this step.
30
30
  2. Execute the steps in the inlined task plan
31
31
  3. Build the real thing. If the task plan says "create login endpoint", build an endpoint that actually authenticates against a real store, not one that returns a hardcoded success response. If the task plan says "create dashboard page", build a page that renders real data from the API, not a component with hardcoded props. Stubs and mocks are for tests, not for the shipped feature.
32
32
  4. Write or update tests as part of execution — tests are verification, not an afterthought. If the slice plan defines test files in its Verification section and this is the first task, create them (they should initially fail).
@@ -0,0 +1,71 @@
1
+ You are investigating a GSD auto-mode failure. The user has described their problem and a structured forensic report has been gathered automatically.
2
+
3
+ ## User's Problem
4
+
5
+ {{problemDescription}}
6
+
7
+ ## Forensic Report
8
+
9
+ {{forensicData}}
10
+
11
+ ## GSD Source Location
12
+
13
+ GSD extension source code is at: {{gsdSourceDir}}
14
+ Key files for understanding failures:
15
+ - auto.ts — unit dispatch loop, stuck detection, timeout recovery
16
+ - session-forensics.ts — trace extraction from activity logs
17
+ - auto-recovery.ts — artifact verification, skip logic
18
+ - crash-recovery.ts — crash lock lifecycle
19
+ - doctor.ts — state integrity checks
20
+
21
+ You may read these files to identify the specific code path that caused the failure.
22
+
23
+ ## Your Task
24
+
25
+ 1. **Analyze** the forensic report. Identify the root cause of the user's problem.
26
+
27
+ 2. **Clarify** if needed. Use ask_user_questions (max 2 questions) to narrow down ambiguity. Only ask if the report is genuinely insufficient — do not ask questions you can answer from the data.
28
+
29
+ 3. **Explain** your findings clearly:
30
+ - What happened (the failure sequence)
31
+ - Why it happened (root cause in GSD's logic)
32
+ - What the user can do to recover (immediate fix)
33
+
34
+ 4. **Offer GitHub issue creation.** Ask the user:
35
+ "Would you like me to create a GitHub issue for this on gsd-build/gsd-2?"
36
+
37
+ If yes, create the issue using bash with `gh issue create`:
38
+ - Repository: gsd-build/gsd-2
39
+ - Labels: bug, auto-generated
40
+ - Title: concise description of the failure
41
+ - Body format:
42
+ ```
43
+ ## Problem
44
+ [1-2 sentence summary]
45
+
46
+ ## Environment
47
+ - GSD version: [from report]
48
+ - Model: [from report]
49
+ - Unit: [type/id that failed]
50
+
51
+ ## Reproduction Context
52
+ [What was happening when it failed — phase, milestone, slice]
53
+
54
+ ## Forensic Findings
55
+ [Key anomalies detected, error traces, relevant tool call sequences]
56
+
57
+ ## Suggested Fix Area
58
+ [File:line references in GSD source if identified]
59
+
60
+ ---
61
+ *Auto-generated by `/gsd forensics`*
62
+ ```
63
+
64
+ **CRITICAL REDACTION RULES** before creating the issue:
65
+ - Replace all absolute paths with relative paths
66
+ - Remove any API keys, tokens, or credentials
67
+ - Remove any environment variable values
68
+ - Do not include file content (code written by the user)
69
+ - Only include GSD structural information (tool names, file names, error messages)
70
+
71
+ 5. **Report saved.** Remind the user that the full forensic report was saved locally (the path will be in the notification).
@@ -33,7 +33,7 @@ Then:
33
33
  1. Read the templates:
34
34
  - `~/.gsd/agent/extensions/gsd/templates/plan.md`
35
35
  - `~/.gsd/agent/extensions/gsd/templates/task-plan.md`
36
- 2. If a `GSD Skill Preferences` block is present in system context, use it to decide which skills to load and follow during planning, without overriding required plan formatting
36
+ 2. **Load relevant skills.** Check the `GSD Skill Preferences` block in system context and the `<available_skills>` catalog in your system prompt. `read` any skill files relevant to this slice's technology stack before decomposing. When writing task plans, note which installed skills are relevant in the task description so executors know which to load.
37
37
  3. Define slice-level verification — the objective stopping condition for this slice:
38
38
  - For non-trivial slices: plan actual test files with real assertions. Name the files.
39
39
  - For simple slices: executable commands or script assertions are fine.
@@ -42,7 +42,7 @@ An honest "this is straightforward, here's the pattern to follow" is more valuab
42
42
 
43
43
  Research what this slice needs. Narrate key findings and surprises as you go — what exists, what's missing, what constrains the approach.
44
44
  0. If `REQUIREMENTS.md` was preloaded above, identify which Active requirements this slice owns or supports. Research should target these requirements — surfacing risks, unknowns, and implementation constraints that could affect whether the slice actually delivers them.
45
- 1. If a `GSD Skill Preferences` block is present in system context, use it to decide which skills to load and follow during research, without relaxing required verification or artifact rules
45
+ 1. **Load relevant skills.** Check the `GSD Skill Preferences` block in system context and the `<available_skills>` catalog in your system prompt. `read` any skill files relevant to this slice's technology stack before exploring code. Reference specific rules from loaded skills in your findings where they inform the implementation approach.
46
46
  2. **Skill Discovery ({{skillDiscoveryMode}}):**{{skillDiscoveryInstructions}}
47
47
  3. Explore relevant code for this slice's scope. For targeted exploration, use `rg`, `find`, and reads. For broad or unfamiliar subsystems, use `scout` to map the relevant area first.
48
48
  4. Use `resolve_library` / `get_library_docs` for unfamiliar libraries — skip this for libraries already used in the codebase
@@ -90,11 +90,17 @@ Titles live inside file content (headings, frontmatter), not in file or director
90
90
  T01-SUMMARY.md
91
91
  ```
92
92
 
93
- ### Worktree Model
93
+ ### Isolation Model
94
94
 
95
- All auto-mode work happens inside a worktree at `.gsd/worktrees/<MID>/`. This is a full git worktree on the `milestone/<MID>` branch — it has its own working copy of the project and its own `.gsd/` directory. Slices commit sequentially on this branch; there are no per-slice branches. When a milestone completes, the worktree is merged back to the integration branch.
95
+ Auto-mode supports three isolation modes (configured in `.gsd/preferences.md` under `taskIsolation.mode`):
96
96
 
97
- **If you are executing in auto-mode, your working directory is already set to the worktree.** Use relative paths or the path shown in the Working Directory section of your prompt. Do not navigate to any other copy of the project.
97
+ - **worktree** (default): Work happens in `.gsd/worktrees/<MID>/`, a full git worktree on the `milestone/<MID>` branch. Each worktree has its own working copy and `.gsd/` directory. Squash-merged back to the integration branch on milestone completion.
98
+ - **branch**: Work happens in the project root on a `milestone/<MID>` branch. No worktree directory — files are checked out in-place.
99
+ - **none**: Work happens directly on the current branch. No worktree, no milestone branch. Commits land in-place.
100
+
101
+ In all modes, slices commit sequentially on the active branch; there are no per-slice branches.
102
+
103
+ **If you are executing in auto-mode, your working directory is shown in the Working Directory section of your prompt.** Use relative paths. Do not navigate to any other copy of the project.
98
104
 
99
105
  ### Conventions
100
106
 
@@ -152,6 +158,8 @@ Templates showing the expected format for each artifact type are in:
152
158
 
153
159
  **One-shot commands:** Use `async_bash` for builds, tests, and installs. The result is pushed to you when the command exits — no polling needed. Use `await_job` to block on a specific job.
154
160
 
161
+ **Stale job hygiene:** After editing source files to address a failure, `cancel_job` every in-flight `async_bash` job before re-running. If the inputs changed, in-flight outputs are untrusted.
162
+
155
163
  **Secrets:** Use `secure_env_collect`. Never ask the user to edit `.env` files or paste secrets.
156
164
 
157
165
  **Browser verification:** Verify frontend work against a running app. Discovery: `browser_find`/`browser_snapshot_refs`. Action: refs/selectors → `browser_batch` for obvious sequences. Verification: `browser_assert` for explicit pass/fail. Diagnostics: `browser_diff` for ambiguous outcomes → console/network logs when assertions fail → full page inspection as last resort. Debug in order: failing assertion → diff → diagnostics → element state → broader inspection. Retry only with a new hypothesis.
@@ -165,6 +173,7 @@ Templates showing the expected format for each artifact type are in:
165
173
  - Never read files one-by-one to understand a subsystem — use `rg` or `scout` first.
166
174
  - Never guess at library APIs from training data — use `get_library_docs`.
167
175
  - Never ask the user to run a command, set a variable, or check something you can check yourself.
176
+ - Never await stale async jobs after editing source — `cancel_job` them first, then re-run.
168
177
 
169
178
  ### Ask vs infer
170
179
 
@@ -19,7 +19,7 @@ export function parseRoadmapSlices(content: string): RoadmapSliceEntry[] {
19
19
  let currentSlice: RoadmapSliceEntry | null = null;
20
20
 
21
21
  for (const line of checkboxItems) {
22
- const cbMatch = line.match(/^\s*-\s+\[([ xX])\]\s+\*\*(\w+):\s+(.+?)\*\*\s*(.*)/);
22
+ const cbMatch = line.match(/^\s*-\s+\[([ xX])\]\s+\*\*([\w.]+):\s+(.+?)\*\*\s*(.*)/);
23
23
  if (cbMatch) {
24
24
  if (currentSlice) slices.push(currentSlice);
25
25
 
@@ -313,10 +313,10 @@ function formatRecoveryPrompt(
313
313
  const sections: string[] = [];
314
314
 
315
315
  sections.push(
316
- "## Crash Recovery Briefing",
316
+ "## Recovery Briefing",
317
317
  "",
318
- `You are resuming \`${unitType}\` for \`${unitId}\` after a crash.`,
319
- `The previous session completed **${trace.toolCallCount} tool calls** before dying.`,
318
+ `You are resuming \`${unitType}\` for \`${unitId}\` after an interruption.`,
319
+ `The previous session completed **${trace.toolCallCount} tool calls** before stopping.`,
320
320
  "Use this briefing to pick up exactly where it left off. Do NOT redo completed work.",
321
321
  );
322
322
 
@@ -352,7 +352,7 @@ function formatRecoveryPrompt(
352
352
  // Errors
353
353
  if (trace.errors.length > 0) {
354
354
  sections.push(
355
- "", "### Errors Before Crash",
355
+ "", "### Errors Before Interruption",
356
356
  ...trace.errors.slice(-3).map(e => `- ${truncate(e, 200)}`),
357
357
  );
358
358
  }
@@ -368,7 +368,7 @@ function formatRecoveryPrompt(
368
368
  // Last reasoning
369
369
  if (trace.lastReasoning) {
370
370
  sections.push(
371
- "", "### Last Agent Reasoning Before Crash",
371
+ "", "### Last Agent Reasoning Before Interruption",
372
372
  `> ${trace.lastReasoning.replace(/\n/g, "\n> ")}`,
373
373
  );
374
374
  }
@@ -0,0 +1,351 @@
1
+ /**
2
+ * TUI Command Flow Tests for import-claude
3
+ *
4
+ * Tests R015: validates the TUI command flow for /gsd prefs import-claude.
5
+ * These tests currently use mock UI, and marketplace availability is still
6
+ * derived from real/local marketplace roots. Follow-up work should route these
7
+ * through portable marketplace fixtures that mirror Claude Code's
8
+ * `/plugin marketplace add ...` source model.
9
+ */
10
+
11
+
12
+ import { describe, it, before, after, mock } from 'node:test';
13
+ import assert from 'node:assert';
14
+ import { existsSync, mkdtempSync, rmSync, writeFileSync, readFileSync, mkdirSync } from 'node:fs';
15
+ import { tmpdir } from 'node:os';
16
+ import { join } from 'node:path';
17
+ import type { ExtensionCommandContext } from '@gsd/pi-coding-agent';
18
+ import { runClaudeImportFlow, getClaudeSearchRoots, discoverClaudeSkills, discoverClaudePlugins } from '../claude-import.js';
19
+ import { getMarketplaceFixtures } from './marketplace-test-fixtures.js';
20
+
21
+ // ============================================================================
22
+ // Test Configuration
23
+ // ============================================================================
24
+
25
+ const fixtureSetup = getMarketplaceFixtures(import.meta.dirname);
26
+ const fixtures = fixtureSetup.fixtures;
27
+ const CLAUDE_SKILLS_PATH = fixtures?.claudeSkillsPath;
28
+ const CLAUDE_PLUGINS_OFFICIAL_PATH = fixtures?.claudePluginsOfficialPath;
29
+
30
+ function marketplacesAvailable(): boolean {
31
+ return Boolean(fixtures);
32
+ }
33
+
34
+ // ============================================================================
35
+ // Mock UI Context
36
+ // ============================================================================
37
+
38
+ interface MockUISelectCall {
39
+ prompt: string;
40
+ options: string[];
41
+ }
42
+
43
+ function createMockContext(selections: string[]): {
44
+ ctx: ExtensionCommandContext;
45
+ selectCalls: MockUISelectCall[];
46
+ } {
47
+ const selectCalls: MockUISelectCall[] = [];
48
+
49
+ const selectMock = mock.fn(async (prompt: string, options: string[]) => {
50
+ selectCalls.push({ prompt, options });
51
+ const next = selections.shift();
52
+ if (next && options.includes(next)) {
53
+ return next;
54
+ }
55
+ // Default: cancel or first option
56
+ return options.find(o => o.toLowerCase().includes('cancel')) || options[0];
57
+ });
58
+
59
+ const notifyMock = mock.fn();
60
+
61
+ // Create a mock that satisfies ExtensionCommandContext
62
+ // Using type assertion since we only use select, notify, waitForIdle, reload in the tests
63
+ const ctx = {
64
+ ui: {
65
+ select: selectMock,
66
+ notify: notifyMock,
67
+ confirm: async () => false,
68
+ input: async () => undefined,
69
+ onTerminalInput: () => () => {},
70
+ setStatus: () => {},
71
+ setWorkingMessage: () => {},
72
+ setWidget: () => {},
73
+ setFooter: () => {},
74
+ setHeader: () => {},
75
+ setTitle: () => {},
76
+ custom: async () => { throw new Error('Not implemented'); },
77
+ pasteToEditor: () => {},
78
+ setEditorText: () => {},
79
+ getEditorText: () => '',
80
+ editor: async () => undefined,
81
+ setEditorComponent: () => {},
82
+ theme: {},
83
+ getAllThemes: () => [],
84
+ getTheme: () => undefined,
85
+ setTheme: () => ({ success: false }),
86
+ getToolsExpanded: () => true,
87
+ setToolsExpanded: () => {},
88
+ },
89
+ hasUI: true,
90
+ cwd: process.cwd(),
91
+ sessionManager: {} as unknown,
92
+ modelRegistry: {} as unknown,
93
+ model: undefined,
94
+ isIdle: () => true,
95
+ abort: () => {},
96
+ hasPendingMessages: () => false,
97
+ shutdown: () => {},
98
+ getContextUsage: () => undefined,
99
+ compact: () => {},
100
+ getSystemPrompt: () => '',
101
+ waitForIdle: mock.fn(async () => {}),
102
+ newSession: async () => ({ cancelled: false }),
103
+ fork: async () => ({ cancelled: false }),
104
+ navigateTree: async () => ({ cancelled: false }),
105
+ switchSession: async () => ({ cancelled: false }),
106
+ reload: mock.fn(async () => {}),
107
+ } as unknown as ExtensionCommandContext;
108
+
109
+ return { ctx, selectCalls };
110
+ }
111
+
112
+ // ============================================================================
113
+ // Tests
114
+ // ============================================================================
115
+
116
+ const skipReason = !marketplacesAvailable()
117
+ ? fixtureSetup.skipReason ?? 'Marketplace repos not found for TUI testing'
118
+ : undefined;
119
+
120
+ describe(
121
+ 'TUI Command Flow Tests',
122
+ { skip: skipReason },
123
+ () => {
124
+ let tempDir: string;
125
+ let prefsPath: string;
126
+ let prefs: Record<string, unknown>;
127
+
128
+ before(() => {
129
+ tempDir = mkdtempSync(join(tmpdir(), 'gsd-tui-test-'));
130
+ prefsPath = join(tempDir, 'preferences.md');
131
+ prefs = { version: 1 };
132
+ });
133
+
134
+ after(() => {
135
+ fixtures?.cleanup();
136
+ if (existsSync(tempDir)) {
137
+ rmSync(tempDir, { recursive: true, force: true });
138
+ }
139
+ });
140
+
141
+ describe('getClaudeSearchRoots()', () => {
142
+ it('should return existing skill and plugin roots', () => {
143
+ const cwd = process.cwd();
144
+ const { skillRoots, pluginRoots } = getClaudeSearchRoots(cwd);
145
+
146
+ // At least one root should exist in our test environment
147
+ assert.ok(
148
+ skillRoots.length > 0 || pluginRoots.length > 0,
149
+ 'Should find at least one search root'
150
+ );
151
+
152
+ // All returned roots should exist
153
+ for (const root of [...skillRoots, ...pluginRoots]) {
154
+ assert.ok(existsSync(root), `Root should exist: ${root}`);
155
+ }
156
+ });
157
+ });
158
+
159
+ describe('discoverClaudeSkills()', () => {
160
+ it('should discover skills without crashing', () => {
161
+ const cwd = process.cwd();
162
+ const skills = discoverClaudeSkills(cwd);
163
+
164
+ assert.ok(Array.isArray(skills), 'Should return an array');
165
+
166
+ // Log for observability
167
+ console.log(`\nDiscovered ${skills.length} skills`);
168
+
169
+ if (skills.length > 0) {
170
+ console.log('Sample skills:');
171
+ skills.slice(0, 3).forEach(s => {
172
+ console.log(` - ${s.name} (${s.sourceLabel})`);
173
+ });
174
+
175
+ // Verify structure
176
+ const sample = skills[0]!;
177
+ assert.ok(sample.name, 'Skill should have name');
178
+ assert.ok(sample.path, 'Skill should have path');
179
+ assert.ok(sample.root, 'Skill should have root');
180
+ assert.strictEqual(sample.type, 'skill');
181
+ }
182
+ });
183
+ });
184
+
185
+ describe('discoverClaudePlugins()', () => {
186
+ it('should discover plugins without crashing', () => {
187
+ const cwd = process.cwd();
188
+ const plugins = discoverClaudePlugins(cwd);
189
+
190
+ assert.ok(Array.isArray(plugins), 'Should return an array');
191
+
192
+ // Log for observability
193
+ console.log(`\nDiscovered ${plugins.length} plugins`);
194
+
195
+ if (plugins.length > 0) {
196
+ console.log('Sample plugins:');
197
+ plugins.slice(0, 3).forEach(p => {
198
+ console.log(` - ${p.name} (${p.sourceLabel})`);
199
+ });
200
+
201
+ // Verify structure
202
+ const sample = plugins[0]!;
203
+ assert.ok(sample.name, 'Plugin should have name');
204
+ assert.ok(sample.path, 'Plugin should have path');
205
+ assert.strictEqual(sample.type, 'plugin');
206
+ }
207
+ });
208
+ });
209
+
210
+ describe('runClaudeImportFlow()', () => {
211
+ it('should not crash when user cancels at first prompt', async () => {
212
+ const { ctx, selectCalls } = createMockContext(['Cancel']);
213
+
214
+ const readPrefs = () => ({ ...prefs });
215
+ const writePrefs = async (p: Record<string, unknown>) => {
216
+ Object.assign(prefs, p);
217
+ };
218
+
219
+ // Should complete without throwing
220
+ await runClaudeImportFlow(ctx, 'global', readPrefs, writePrefs);
221
+
222
+ // Should have asked about asset type
223
+ assert.ok(selectCalls.length >= 1, 'Should have at least one select call');
224
+ assert.ok(
225
+ selectCalls[0]!.prompt.includes('Import Claude assets'),
226
+ 'First prompt should be about asset selection'
227
+ );
228
+ });
229
+
230
+ it('should not crash when selecting skills only with cancel at next step', async () => {
231
+ const { ctx, selectCalls } = createMockContext([
232
+ 'Skills only', // Select skills only
233
+ 'Cancel', // Cancel at skill selection
234
+ ]);
235
+
236
+ const readPrefs = () => ({ ...prefs });
237
+ const writePrefs = async (p: Record<string, unknown>) => {
238
+ Object.assign(prefs, p);
239
+ };
240
+
241
+ // Should complete without throwing
242
+ await runClaudeImportFlow(ctx, 'global', readPrefs, writePrefs);
243
+
244
+ // Log interaction flow
245
+ console.log('\nSelect calls made:');
246
+ selectCalls.forEach((call, i) => {
247
+ console.log(` ${i + 1}. "${call.prompt}"`);
248
+ });
249
+ });
250
+
251
+ it('should handle marketplace flow when user selects plugins', async () => {
252
+ const { ctx, selectCalls } = createMockContext([
253
+ 'Plugins only', // Select plugins only
254
+ 'Yes - discover plugins and select components', // Marketplace prompt
255
+ 'Cancel', // Cancel at component selection
256
+ ]);
257
+
258
+ const readPrefs = () => ({ ...prefs });
259
+ const writePrefs = async (p: Record<string, unknown>) => {
260
+ Object.assign(prefs, p);
261
+ };
262
+
263
+ // Should complete without throwing
264
+ await runClaudeImportFlow(ctx, 'global', readPrefs, writePrefs);
265
+
266
+ // Log interaction flow
267
+ console.log('\nMarketplace flow select calls:');
268
+ selectCalls.forEach((call, i) => {
269
+ console.log(` ${i + 1}. "${call.prompt}"`);
270
+ });
271
+ });
272
+
273
+ it('should complete import-all flow with mock UI', async () => {
274
+ // This tests the happy path where user selects "Import all"
275
+ const { ctx, selectCalls } = createMockContext([
276
+ 'Skills + plugins', // Select both
277
+ 'Cancel', // Cancel at skill selection (no skills to import)
278
+ 'Yes - discover plugins and select components', // Marketplace prompt
279
+ 'Import all components', // Import all
280
+ 'Yes, continue', // Continue with warnings (if any)
281
+ ]);
282
+
283
+ const readPrefs = () => ({ ...prefs });
284
+ const writePrefs = async (p: Record<string, unknown>) => {
285
+ Object.assign(prefs, p);
286
+ };
287
+
288
+ // Should complete without throwing
289
+ await runClaudeImportFlow(ctx, 'global', readPrefs, writePrefs);
290
+
291
+ // Log interaction flow
292
+ console.log('\nImport-all flow select calls:');
293
+ selectCalls.forEach((call, i) => {
294
+ console.log(` ${i + 1}. "${call.prompt}"`);
295
+ });
296
+
297
+ // Verify notification was called
298
+ const notifyCalls = (ctx.ui.notify as unknown as ReturnType<typeof mock.fn>).mock.calls;
299
+ assert.ok(notifyCalls.length > 0, 'Should have shown notification');
300
+
301
+ console.log('\nNotifications shown:');
302
+ notifyCalls.forEach((call, i) => {
303
+ const msg = call.arguments[0];
304
+ const level = call.arguments[1];
305
+ console.log(` ${i + 1}. [${level}]: ${String(msg).split('\n')[0]}`);
306
+ });
307
+ });
308
+
309
+ it('should not persist marketplace agent directories into package sources', async () => {
310
+ const isolatedAgentDir = join(tempDir, '.gsd', 'agent');
311
+ const settingsPath = join(isolatedAgentDir, 'settings.json');
312
+ rmSync(isolatedAgentDir, { recursive: true, force: true });
313
+ process.env.GSD_CODING_AGENT_DIR = isolatedAgentDir;
314
+
315
+ try {
316
+ mkdirSync(isolatedAgentDir, { recursive: true });
317
+ const tempSettings: Record<string, unknown> = { packages: [] };
318
+ writeFileSync(settingsPath, JSON.stringify(tempSettings, null, 2));
319
+
320
+ const { ctx } = createMockContext([
321
+ 'Plugins only',
322
+ 'Yes - discover plugins and select components',
323
+ 'Import all components',
324
+ 'Yes, continue',
325
+ ]);
326
+
327
+ const readPrefs = () => ({ ...prefs });
328
+ const writePrefs = async (p: Record<string, unknown>) => {
329
+ Object.assign(prefs, p);
330
+ };
331
+
332
+ await runClaudeImportFlow(ctx, 'global', readPrefs, writePrefs);
333
+
334
+ const settings = JSON.parse(readFileSync(settingsPath, 'utf8')) as { packages?: unknown[] };
335
+ const packageEntries = Array.isArray(settings.packages) ? settings.packages : [];
336
+ const hasAgentsDirPackage = packageEntries.some((entry) => {
337
+ const source = typeof entry === 'string'
338
+ ? entry
339
+ : (entry && typeof entry === 'object' ? (entry as { source?: unknown }).source : undefined);
340
+ return typeof source === 'string' && source.endsWith('/agents');
341
+ });
342
+
343
+ assert.strictEqual(hasAgentsDirPackage, false, 'Marketplace agent directories should not be persisted as package sources');
344
+ } finally {
345
+ delete process.env.GSD_CODING_AGENT_DIR;
346
+ rmSync(isolatedAgentDir, { recursive: true, force: true });
347
+ }
348
+ });
349
+ });
350
+ }
351
+ );