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
@@ -0,0 +1,105 @@
1
+ /**
2
+ * none-mode-gates.test.ts — Tests for isolation-mode gate functions.
3
+ *
4
+ * Verifies that shouldUseWorktreeIsolation(), getIsolationMode(), and
5
+ * getActiveAutoWorktreeContext() behave correctly across all three
6
+ * isolation modes (none, branch, worktree) and at baseline (no prefs).
7
+ *
8
+ * Uses the writeRunnerPreferences pattern from doctor-git.test.ts:
9
+ * PROJECT_PREFERENCES_PATH is a module-level constant frozen at import
10
+ * time, so process.chdir() won't redirect preference loading. We write
11
+ * prefs to the runner's cwd .gsd/preferences.md and clean up in finally.
12
+ */
13
+
14
+ import { mkdirSync, writeFileSync, rmSync } from "node:fs";
15
+ import { join } from "node:path";
16
+
17
+ import { shouldUseWorktreeIsolation } from "../auto.ts";
18
+ import { getIsolationMode } from "../preferences.ts";
19
+ import { getActiveAutoWorktreeContext } from "../auto-worktree.ts";
20
+ import { invalidateAllCaches } from "../cache.ts";
21
+ import { createTestContext } from "./test-helpers.ts";
22
+
23
+ const { assertEq, assertTrue, report } = createTestContext();
24
+
25
+ // --- Preferences helpers (same pattern as doctor-git.test.ts K001) ---
26
+
27
+ const RUNNER_PREFS_PATH = join(process.cwd(), ".gsd", "preferences.md");
28
+
29
+ function writeRunnerPreferences(isolation: "none" | "worktree" | "branch"): void {
30
+ mkdirSync(join(process.cwd(), ".gsd"), { recursive: true });
31
+ writeFileSync(RUNNER_PREFS_PATH, `---\ngit:\n isolation: "${isolation}"\n---\n`);
32
+ }
33
+
34
+ function removeRunnerPreferences(): void {
35
+ try { rmSync(RUNNER_PREFS_PATH); } catch { /* ignore if already gone */ }
36
+ }
37
+
38
+ // --- Tests ---
39
+
40
+ // Test 1: shouldUseWorktreeIsolation returns false for none
41
+ console.log("Test 1: shouldUseWorktreeIsolation returns false for none");
42
+ try {
43
+ writeRunnerPreferences("none");
44
+ invalidateAllCaches();
45
+ assertEq(shouldUseWorktreeIsolation(), false, "shouldUseWorktreeIsolation() with none prefs");
46
+ } finally {
47
+ removeRunnerPreferences();
48
+ invalidateAllCaches();
49
+ }
50
+
51
+ // Test 2: shouldUseWorktreeIsolation returns false for branch
52
+ console.log("Test 2: shouldUseWorktreeIsolation returns false for branch");
53
+ try {
54
+ writeRunnerPreferences("branch");
55
+ invalidateAllCaches();
56
+ assertEq(shouldUseWorktreeIsolation(), false, "shouldUseWorktreeIsolation() with branch prefs");
57
+ } finally {
58
+ removeRunnerPreferences();
59
+ invalidateAllCaches();
60
+ }
61
+
62
+ // Test 3: shouldUseWorktreeIsolation returns true for worktree
63
+ console.log("Test 3: shouldUseWorktreeIsolation returns true for worktree");
64
+ try {
65
+ writeRunnerPreferences("worktree");
66
+ invalidateAllCaches();
67
+ assertEq(shouldUseWorktreeIsolation(), true, "shouldUseWorktreeIsolation() with worktree prefs");
68
+ } finally {
69
+ removeRunnerPreferences();
70
+ invalidateAllCaches();
71
+ }
72
+
73
+ // Test 4: shouldUseWorktreeIsolation returns true for no prefs (default)
74
+ console.log("Test 4: shouldUseWorktreeIsolation returns true for no prefs (default)");
75
+ try {
76
+ removeRunnerPreferences(); // ensure no prefs file
77
+ invalidateAllCaches();
78
+ assertEq(shouldUseWorktreeIsolation(), true, "shouldUseWorktreeIsolation() with no prefs (default worktree)");
79
+ } finally {
80
+ invalidateAllCaches();
81
+ }
82
+
83
+ // Test 5: getIsolationMode returns "none" with none prefs
84
+ console.log("Test 5: getIsolationMode returns 'none' with none prefs");
85
+ try {
86
+ writeRunnerPreferences("none");
87
+ invalidateAllCaches();
88
+ assertEq(getIsolationMode(), "none", "getIsolationMode() with none prefs");
89
+ } finally {
90
+ removeRunnerPreferences();
91
+ invalidateAllCaches();
92
+ }
93
+
94
+ // Test 6: getActiveAutoWorktreeContext returns null at baseline
95
+ console.log("Test 6: getActiveAutoWorktreeContext returns null at baseline");
96
+ assertEq(getActiveAutoWorktreeContext(), null, "getActiveAutoWorktreeContext() returns null without enterAutoWorktree()");
97
+
98
+ // Test 7: System prompt worktree block absent without active worktree
99
+ console.log("Test 7: System prompt worktree block absent without active worktree");
100
+ {
101
+ const ctx = getActiveAutoWorktreeContext();
102
+ assertTrue(ctx === null, "getActiveAutoWorktreeContext() null confirms system prompt worktree block will not be injected");
103
+ }
104
+
105
+ report();
@@ -0,0 +1,481 @@
1
+ /**
2
+ * Live E2E Tests Against Real Marketplace Repos
3
+ *
4
+ * Tests R014: validates PluginImporter against real marketplace data.
5
+ *
6
+ * Source model alignment:
7
+ * - Prefer Claude Code managed marketplace locations when available
8
+ * - Fall back to cloned fixture repos for portability
9
+ * - Never require a contributor's personal sibling repo layout
10
+ */
11
+
12
+ import { describe, it, before, after } from 'node:test';
13
+ import assert from 'node:assert';
14
+ import { PluginImporter, type DiscoveryResult, type ImportManifest } from '../plugin-importer.js';
15
+ import { getMarketplaceFixtures } from './marketplace-test-fixtures.js';
16
+
17
+ // ============================================================================
18
+ // Live Test Configuration
19
+ // ============================================================================
20
+
21
+ /**
22
+ * Canonical name format regex: namespace:name or bare name
23
+ * Allows alphanumeric, underscore, hyphen, and dot in names.
24
+ * Real marketplace data has names like "ecosystem-researcher-v1.1-rt-ica".
25
+ */
26
+ const CANONICAL_NAME_REGEX = /^[a-zA-Z0-9_.-]+(?::[a-zA-Z0-9_.-]+)?$/;
27
+
28
+ // ============================================================================
29
+ // Live E2E Tests
30
+ // ============================================================================
31
+
32
+ const fixtureSetup = getMarketplaceFixtures(import.meta.dirname);
33
+ const fixtures = fixtureSetup.fixtures;
34
+ const CLAUDE_SKILLS_PATH = fixtures?.claudeSkillsPath;
35
+ const CLAUDE_PLUGINS_OFFICIAL_PATH = fixtures?.claudePluginsOfficialPath;
36
+
37
+ // Log marketplace status for observability
38
+ console.log('Live E2E Test Configuration:');
39
+ console.log(` source: ${fixtures?.source ?? 'unavailable'}`);
40
+ if (CLAUDE_SKILLS_PATH) {
41
+ console.log(` claude_skills: FOUND at ${CLAUDE_SKILLS_PATH}`);
42
+ }
43
+ if (CLAUDE_PLUGINS_OFFICIAL_PATH) {
44
+ console.log(` claude-plugins-official: FOUND at ${CLAUDE_PLUGINS_OFFICIAL_PATH}`);
45
+ }
46
+ if (!fixtureSetup.available) {
47
+ console.log(` unavailable: ${fixtureSetup.skipReason}`);
48
+ }
49
+
50
+ const skipReason = !fixtureSetup.available ? fixtureSetup.skipReason : undefined;
51
+
52
+ describe(
53
+ 'Live E2E Tests',
54
+ { skip: skipReason },
55
+ () => {
56
+ let importer: PluginImporter;
57
+ let discoveryResult: DiscoveryResult;
58
+
59
+ before(() => {
60
+ importer = new PluginImporter();
61
+ });
62
+
63
+ after(() => {
64
+ fixtures?.cleanup();
65
+ });
66
+
67
+ describe('Step 2: discover() against real marketplaces', () => {
68
+ it('should discover plugins from both marketplaces with no fatal errors', () => {
69
+ // Stage 1: Discover
70
+ discoveryResult = importer.discover([
71
+ CLAUDE_SKILLS_PATH!,
72
+ CLAUDE_PLUGINS_OFFICIAL_PATH!,
73
+ ]);
74
+
75
+ // Log discovery summary for observability
76
+ console.log('\nDiscovery Summary:');
77
+ console.log(` Marketplaces processed: ${discoveryResult.summary.marketplacesProcessed}`);
78
+ console.log(` Total plugins: ${discoveryResult.summary.totalPlugins}`);
79
+ console.log(` Total components: ${discoveryResult.summary.totalComponents}`);
80
+ console.log(` Marketplaces with errors: ${discoveryResult.summary.marketplacesWithErrors}`);
81
+
82
+ // Assert positive counts
83
+ assert.ok(
84
+ discoveryResult.summary.totalPlugins > 0,
85
+ 'Should find at least one plugin across both marketplaces'
86
+ );
87
+
88
+ assert.ok(
89
+ discoveryResult.summary.totalComponents > 0,
90
+ 'Should discover at least one component across both marketplaces'
91
+ );
92
+
93
+ // No fatal errors should crash the pipeline
94
+ assert.strictEqual(
95
+ discoveryResult.summary.marketplacesProcessed,
96
+ 2,
97
+ 'Should process both marketplace paths'
98
+ );
99
+ });
100
+
101
+ it('should have processed both marketplace.json files', () => {
102
+ assert.ok(discoveryResult, 'Discovery must run first');
103
+
104
+ // Both marketplaces should have been attempted
105
+ assert.strictEqual(
106
+ discoveryResult.marketplaceResults.length,
107
+ 2,
108
+ 'Should have results for both marketplaces'
109
+ );
110
+
111
+ // At least one should have succeeded (they're real repos)
112
+ const successfulMarketplaces = discoveryResult.marketplaceResults.filter(
113
+ (m) => m.status === 'ok'
114
+ );
115
+
116
+ assert.ok(
117
+ successfulMarketplaces.length >= 1,
118
+ 'At least one marketplace should have loaded successfully'
119
+ );
120
+ });
121
+ });
122
+
123
+ describe('Step 3: canonical name format validation', () => {
124
+ it('should have valid canonical names matching namespace:component format', () => {
125
+ assert.ok(discoveryResult, 'Discovery must run first');
126
+
127
+ const registry = importer.getRegistry();
128
+ assert.ok(registry, 'Registry should be populated');
129
+
130
+ const allComponents = registry.getAll();
131
+
132
+ // Should have components from real plugins
133
+ assert.ok(
134
+ allComponents.length > 0,
135
+ 'Should have discovered components to validate'
136
+ );
137
+
138
+ // Log sample canonical names for observability
139
+ const sampleNames = allComponents.slice(0, 5).map((c) => c.canonicalName);
140
+ console.log('\nSample canonical names from discovered components:');
141
+ sampleNames.forEach((name) => console.log(` - ${name}`));
142
+
143
+ // Validate each canonical name
144
+ for (const component of allComponents) {
145
+ assert.ok(
146
+ CANONICAL_NAME_REGEX.test(component.canonicalName),
147
+ `Canonical name "${component.canonicalName}" should match format "namespace:name" or bare "name"`
148
+ );
149
+
150
+ // Namespaced components should have colon in canonical name
151
+ if (component.namespace) {
152
+ assert.ok(
153
+ component.canonicalName.includes(':'),
154
+ `Namespaced component "${component.canonicalName}" should contain colon`
155
+ );
156
+
157
+ // Canonical should be namespace:name
158
+ const expected = `${component.namespace}:${component.name}`;
159
+ assert.strictEqual(
160
+ component.canonicalName,
161
+ expected,
162
+ `Canonical name should equal namespace:name`
163
+ );
164
+ } else {
165
+ // Flat components should NOT have colon
166
+ assert.ok(
167
+ !component.canonicalName.includes(':'),
168
+ `Flat component "${component.canonicalName}" should not contain colon`
169
+ );
170
+
171
+ assert.strictEqual(
172
+ component.canonicalName,
173
+ component.name,
174
+ `Flat component canonical should equal bare name`
175
+ );
176
+ }
177
+ }
178
+ });
179
+ });
180
+
181
+ describe('Step 4: selectComponents() filtering', () => {
182
+ it('should filter components by type and return non-empty results', () => {
183
+ assert.ok(discoveryResult, 'Discovery must run first');
184
+
185
+ // Filter by skills
186
+ const skills = importer.selectComponents((c) => c.type === 'skill');
187
+
188
+ // Filter by agents
189
+ const agents = importer.selectComponents((c) => c.type === 'agent');
190
+
191
+ console.log('\nComponent type counts:');
192
+ console.log(` Skills: ${skills.length}`);
193
+ console.log(` Agents: ${agents.length}`);
194
+
195
+ // At least one type should have components (real marketplaces have plugins)
196
+ assert.ok(
197
+ skills.length > 0 || agents.length > 0,
198
+ 'At least one component type should have results from real marketplaces'
199
+ );
200
+ });
201
+
202
+ it('should filter by namespace correctly', () => {
203
+ assert.ok(discoveryResult, 'Discovery must run first');
204
+
205
+ const registry = importer.getRegistry();
206
+ const allComponents = registry!.getAll();
207
+
208
+ // Get unique namespaces
209
+ const namespaces = new Set(
210
+ allComponents.map((c) => c.namespace).filter((n): n is string => n !== undefined)
211
+ );
212
+
213
+ console.log('\nDiscovered namespaces:');
214
+ namespaces.forEach((ns) => console.log(` - ${ns}`));
215
+
216
+ if (namespaces.size > 0) {
217
+ // Pick a namespace and filter
218
+ const testNamespace = Array.from(namespaces)[0]!;
219
+ const filtered = importer.selectComponents(
220
+ (c) => c.namespace === testNamespace
221
+ );
222
+
223
+ assert.ok(
224
+ filtered.length > 0,
225
+ `Should find components for namespace "${testNamespace}"`
226
+ );
227
+
228
+ // All results should match the filter
229
+ for (const comp of filtered) {
230
+ assert.strictEqual(
231
+ comp.namespace,
232
+ testNamespace,
233
+ 'Filtered components should have correct namespace'
234
+ );
235
+ }
236
+ }
237
+ });
238
+ });
239
+
240
+ describe('Step 5: validateImport() on real data', () => {
241
+ it('should run validation on all discovered components without crash', () => {
242
+ assert.ok(discoveryResult, 'Discovery must run first');
243
+
244
+ const registry = importer.getRegistry();
245
+ const allComponents = registry!.getAll();
246
+
247
+ // Run validation on all discovered components
248
+ const validation = importer.validateImport(allComponents);
249
+
250
+ console.log('\nValidation result:');
251
+ console.log(` Can proceed: ${validation.canProceed}`);
252
+ console.log(` Total diagnostics: ${validation.summary.total}`);
253
+ console.log(` Errors: ${validation.summary.errors}`);
254
+ console.log(` Warnings: ${validation.summary.warnings}`);
255
+
256
+ if (validation.diagnostics.length > 0) {
257
+ console.log('\nDiagnostics:');
258
+ validation.diagnostics.forEach((d) => {
259
+ console.log(` [${d.severity}] ${d.class}: ${d.remediation}`);
260
+ });
261
+ }
262
+
263
+ // Validation should complete without throwing
264
+ assert.ok(validation, 'Validation should return a result');
265
+ assert.ok(
266
+ typeof validation.canProceed === 'boolean',
267
+ 'canProceed should be boolean'
268
+ );
269
+ assert.ok(
270
+ Array.isArray(validation.diagnostics),
271
+ 'diagnostics should be an array'
272
+ );
273
+ });
274
+
275
+ it('should have valid diagnostic structure if warnings exist', () => {
276
+ const validation = importer.getLastValidation();
277
+ assert.ok(validation, 'Validation should have run');
278
+
279
+ for (const diag of validation.diagnostics) {
280
+ // Verify diagnostic structure
281
+ assert.ok(diag.class, 'Diagnostic should have class');
282
+ assert.ok(
283
+ ['error', 'warning'].includes(diag.severity),
284
+ 'Diagnostic severity should be error or warning'
285
+ );
286
+ assert.ok(diag.remediation, 'Diagnostic should have remediation');
287
+ assert.ok(
288
+ Array.isArray(diag.involvedCanonicalNames),
289
+ 'Diagnostic should have involvedCanonicalNames array'
290
+ );
291
+ assert.ok(
292
+ Array.isArray(diag.filePaths),
293
+ 'Diagnostic should have filePaths array'
294
+ );
295
+ }
296
+ });
297
+
298
+ it('should not have error-severity diagnostics blocking on real data (data quality check)', () => {
299
+ const validation = importer.getLastValidation();
300
+ assert.ok(validation, 'Validation should have run');
301
+
302
+ // Real marketplace data should not have fatal canonical collisions
303
+ // (this is a data quality assertion)
304
+ if (validation.summary.errors > 0) {
305
+ console.log('\nWARNING: Real marketplace data has error-severity diagnostics!');
306
+ console.log('This may indicate duplicate canonical names in the marketplace.');
307
+
308
+ // Log the errors for investigation
309
+ validation.diagnostics
310
+ .filter((d) => d.severity === 'error')
311
+ .forEach((d) => {
312
+ console.log(` ERROR: ${d.class}`);
313
+ console.log(` Involved: ${d.involvedCanonicalNames.join(', ')}`);
314
+ console.log(` Files: ${d.filePaths.join(', ')}`);
315
+ });
316
+ }
317
+
318
+ // Note: We allow errors in assertion but log them for visibility
319
+ // Real data might have collisions, but the pipeline should handle them
320
+ assert.strictEqual(typeof validation.canProceed, 'boolean');
321
+ });
322
+ });
323
+
324
+ describe('Step 6: getImportManifest() with canonical names', () => {
325
+ it('should generate manifest preserving canonical names from real plugins', () => {
326
+ assert.ok(discoveryResult, 'Discovery must run first');
327
+
328
+ const registry = importer.getRegistry();
329
+ const allComponents = registry!.getAll();
330
+
331
+ // Generate manifest for all components
332
+ const manifest = importer.getImportManifest(allComponents);
333
+
334
+ console.log('\nManifest summary:');
335
+ console.log(` Schema version: ${manifest.schemaVersion}`);
336
+ console.log(` Total entries: ${manifest.summary.total}`);
337
+ console.log(` Skills: ${manifest.summary.skills}`);
338
+ console.log(` Agents: ${manifest.summary.agents}`);
339
+ console.log(` Namespaces: ${manifest.summary.namespaces.length}`);
340
+
341
+ // Verify manifest structure
342
+ assert.strictEqual(manifest.schemaVersion, '1.0');
343
+ assert.strictEqual(
344
+ manifest.entries.length,
345
+ allComponents.length,
346
+ 'Manifest should have entry for each component'
347
+ );
348
+
349
+ // Verify canonical names preserved
350
+ for (const entry of manifest.entries) {
351
+ // Find matching component
352
+ const component = allComponents.find(
353
+ (c) => c.canonicalName === entry.canonicalName
354
+ );
355
+
356
+ assert.ok(
357
+ component,
358
+ `Manifest entry should match component: ${entry.canonicalName}`
359
+ );
360
+
361
+ // Canonical name should match exactly
362
+ assert.strictEqual(
363
+ entry.canonicalName,
364
+ component.canonicalName,
365
+ 'Canonical name should be preserved in manifest'
366
+ );
367
+
368
+ // Type should match
369
+ assert.strictEqual(entry.type, component.type);
370
+
371
+ // Namespace should match
372
+ assert.strictEqual(entry.namespace, component.namespace);
373
+
374
+ // Name should match
375
+ assert.strictEqual(entry.name, component.name);
376
+
377
+ // File path should be preserved
378
+ assert.strictEqual(entry.filePath, component.filePath);
379
+ }
380
+ });
381
+
382
+ it('should produce JSON-serializable manifest', () => {
383
+ const registry = importer.getRegistry();
384
+ const allComponents = registry!.getAll();
385
+
386
+ const manifest = importer.getImportManifest(allComponents);
387
+
388
+ // Should be JSON serializable
389
+ const json = JSON.stringify(manifest, null, 2);
390
+
391
+ // Should parse back correctly
392
+ const parsed: ImportManifest = JSON.parse(json);
393
+
394
+ assert.strictEqual(parsed.schemaVersion, manifest.schemaVersion);
395
+ assert.strictEqual(parsed.entries.length, manifest.entries.length);
396
+
397
+ // Sample entries should match after round-trip
398
+ const sampleEntry = parsed.entries[0];
399
+ if (sampleEntry) {
400
+ const original = manifest.entries[0]!;
401
+ assert.strictEqual(sampleEntry.canonicalName, original.canonicalName);
402
+ assert.strictEqual(sampleEntry.type, original.type);
403
+ }
404
+ });
405
+
406
+ it('should have correct summary counts', () => {
407
+ const registry = importer.getRegistry();
408
+ const allComponents = registry!.getAll();
409
+
410
+ const manifest = importer.getImportManifest(allComponents);
411
+
412
+ // Count skills and agents
413
+ const skillCount = manifest.entries.filter((e) => e.type === 'skill').length;
414
+ const agentCount = manifest.entries.filter((e) => e.type === 'agent').length;
415
+
416
+ assert.strictEqual(
417
+ manifest.summary.skills,
418
+ skillCount,
419
+ 'Skill count should match entries'
420
+ );
421
+
422
+ assert.strictEqual(
423
+ manifest.summary.agents,
424
+ agentCount,
425
+ 'Agent count should match entries'
426
+ );
427
+
428
+ assert.strictEqual(
429
+ manifest.summary.total,
430
+ manifest.entries.length,
431
+ 'Total should match entry count'
432
+ );
433
+
434
+ // Namespaces should be unique and sorted
435
+ const uniqueNamespaces = new Set(
436
+ manifest.entries
437
+ .map((e) => e.namespace)
438
+ .filter((n): n is string => n !== undefined)
439
+ );
440
+
441
+ assert.deepStrictEqual(
442
+ manifest.summary.namespaces,
443
+ Array.from(uniqueNamespaces).sort(),
444
+ 'Namespaces should be unique and sorted'
445
+ );
446
+ });
447
+ });
448
+
449
+ describe('Full pipeline verification', () => {
450
+ it('should execute discover → select → validate → manifest without error', () => {
451
+ // This test verifies the full pipeline works end-to-end
452
+
453
+ // Already have discovery from before()
454
+ assert.ok(discoveryResult, 'Discovery should have completed');
455
+
456
+ // Select subset
457
+ const skills = importer.selectComponents((c) => c.type === 'skill');
458
+
459
+ // Validate
460
+ const validation = importer.validateImport(skills);
461
+ assert.ok(validation, 'Validation should complete');
462
+
463
+ // Generate manifest
464
+ const manifest = importer.getImportManifest(skills);
465
+ assert.ok(manifest, 'Manifest generation should complete');
466
+
467
+ // All skills should be in manifest
468
+ assert.strictEqual(
469
+ manifest.summary.skills,
470
+ skills.length,
471
+ 'All selected skills should be in manifest'
472
+ );
473
+
474
+ console.log('\nFull pipeline verification:');
475
+ console.log(` Selected: ${skills.length} skills`);
476
+ console.log(` Validated: canProceed=${validation.canProceed}`);
477
+ console.log(` Manifest: ${manifest.summary.total} entries`);
478
+ });
479
+ });
480
+ }
481
+ );