@opengsd/gsd-pi 1.0.2-dev.867e002 → 1.0.2-dev.cce3612

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 (318) hide show
  1. package/dist/onboarding.js +22 -3
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/context7/index.js +12 -2
  4. package/dist/resources/extensions/get-secrets-from-user.js +16 -16
  5. package/dist/resources/extensions/google-cli/index.js +30 -0
  6. package/dist/resources/extensions/google-cli/models.js +55 -0
  7. package/dist/resources/extensions/google-cli/package.json +11 -0
  8. package/dist/resources/extensions/google-cli/readiness.js +12 -0
  9. package/dist/resources/extensions/google-cli/stream-adapter.js +191 -0
  10. package/dist/resources/extensions/gsd/auto/loop.js +62 -1
  11. package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -2
  12. package/dist/resources/extensions/gsd/auto/phases.js +37 -0
  13. package/dist/resources/extensions/gsd/auto/run-unit.js +8 -0
  14. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  15. package/dist/resources/extensions/gsd/auto-dispatch.js +17 -7
  16. package/dist/resources/extensions/gsd/auto-post-unit.js +18 -2
  17. package/dist/resources/extensions/gsd/auto-prompts.js +5 -236
  18. package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
  19. package/dist/resources/extensions/gsd/auto-start.js +232 -49
  20. package/dist/resources/extensions/gsd/auto.js +6 -1
  21. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +4 -3
  22. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +39 -5
  23. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -7
  24. package/dist/resources/extensions/gsd/bootstrap/system-context.js +3 -27
  25. package/dist/resources/extensions/gsd/closeout-recovery.js +7 -1
  26. package/dist/resources/extensions/gsd/commands/handlers/auto.js +9 -1
  27. package/dist/resources/extensions/gsd/commands-usage.js +105 -1
  28. package/dist/resources/extensions/gsd/config-overlay.js +20 -14
  29. package/dist/resources/extensions/gsd/context-overlay.js +22 -16
  30. package/dist/resources/extensions/gsd/dashboard-overlay.js +10 -23
  31. package/dist/resources/extensions/gsd/doctor-engine-checks.js +87 -0
  32. package/dist/resources/extensions/gsd/doctor-providers.js +54 -24
  33. package/dist/resources/extensions/gsd/doctor.js +6 -1
  34. package/dist/resources/extensions/gsd/git-conflict-state.js +26 -1
  35. package/dist/resources/extensions/gsd/guided-flow.js +5 -6
  36. package/dist/resources/extensions/gsd/key-manager.js +45 -13
  37. package/dist/resources/extensions/gsd/milestone-reopen-events.js +28 -0
  38. package/dist/resources/extensions/gsd/notification-overlay.js +8 -9
  39. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +15 -13
  40. package/dist/resources/extensions/gsd/preferences-skills.js +11 -4
  41. package/dist/resources/extensions/gsd/preferences.js +14 -2
  42. package/dist/resources/extensions/gsd/prompt-loader.js +2 -0
  43. package/dist/resources/extensions/gsd/prompts/discuss.md +4 -2
  44. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  45. package/dist/resources/extensions/gsd/prompts/system.md +1 -3
  46. package/dist/resources/extensions/gsd/queue-reorder-ui.js +28 -18
  47. package/dist/resources/extensions/gsd/repository-registry.js +3 -1
  48. package/dist/resources/extensions/gsd/skill-activation.js +233 -0
  49. package/dist/resources/extensions/gsd/skill-catalog.data.js +820 -0
  50. package/dist/resources/extensions/gsd/skill-catalog.install.js +179 -0
  51. package/dist/resources/extensions/gsd/skill-catalog.js +5 -1028
  52. package/dist/resources/extensions/gsd/skill-discovery.js +121 -79
  53. package/dist/resources/extensions/gsd/skill-scope.js +52 -0
  54. package/dist/resources/extensions/gsd/skill-telemetry.js +6 -39
  55. package/dist/resources/extensions/gsd/skills.js +60 -0
  56. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +351 -0
  57. package/dist/resources/extensions/gsd/state-reconciliation/index.js +41 -0
  58. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +4 -0
  59. package/dist/resources/extensions/gsd/tools/complete-task.js +9 -0
  60. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +63 -2
  61. package/dist/resources/extensions/gsd/tui/render-kit.js +51 -0
  62. package/dist/resources/extensions/gsd/unit-context-manifest.js +35 -26
  63. package/dist/resources/extensions/gsd/user-input-boundary.js +1 -1
  64. package/dist/resources/extensions/gsd/vision-ask.js +22 -0
  65. package/dist/resources/extensions/gsd/visualizer-overlay.js +8 -36
  66. package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -3
  67. package/dist/resources/extensions/search-the-web/native-search.js +57 -8
  68. package/dist/resources/extensions/shared/confirm-ui.js +9 -6
  69. package/dist/resources/extensions/shared/dialog-frame.js +42 -0
  70. package/dist/resources/extensions/shared/interview-ui.js +42 -30
  71. package/dist/resources/extensions/shared/next-action-ui.js +6 -6
  72. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
  73. package/dist/web/standalone/.next/BUILD_ID +1 -1
  74. package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
  75. package/dist/web/standalone/.next/build-manifest.json +2 -2
  76. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  77. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  86. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/index.html +1 -1
  94. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
  101. package/dist/web/standalone/.next/server/chunks/1834.js +2 -2
  102. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  104. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  105. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  106. package/package.json +1 -1
  107. package/packages/cloud-mcp-gateway/package.json +2 -2
  108. package/packages/contracts/package.json +1 -1
  109. package/packages/daemon/package.json +4 -4
  110. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +1 -0
  111. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
  112. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +22 -8
  113. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
  114. package/packages/gsd-agent-core/package.json +5 -5
  115. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts +12 -0
  116. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts.map +1 -0
  117. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js +45 -0
  118. package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js.map +1 -0
  119. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts +3 -2
  120. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  121. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js +11 -11
  122. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js.map +1 -1
  123. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts +3 -3
  124. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  125. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js +13 -11
  126. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js.map +1 -1
  127. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts +3 -3
  128. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  129. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js +12 -10
  130. package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js.map +1 -1
  131. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts +1 -0
  132. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts.map +1 -1
  133. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js +1 -0
  134. package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js.map +1 -1
  135. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts +1 -1
  136. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  137. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js +2 -2
  138. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js.map +1 -1
  139. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts +6 -1
  140. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  141. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js +9 -6
  142. package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  143. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
  144. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +0 -1
  145. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  146. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts +3 -0
  147. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  148. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +144 -2
  149. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  150. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.d.ts.map +1 -1
  151. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js +2 -14
  152. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js.map +1 -1
  153. package/packages/gsd-agent-modes/package.json +7 -7
  154. package/packages/mcp-server/dist/workflow-tools.js +1 -1
  155. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  156. package/packages/mcp-server/package.json +3 -3
  157. package/packages/native/package.json +1 -1
  158. package/packages/pi-agent-core/dist/harness/skills.d.ts.map +1 -1
  159. package/packages/pi-agent-core/dist/harness/skills.js +6 -0
  160. package/packages/pi-agent-core/dist/harness/skills.js.map +1 -1
  161. package/packages/pi-agent-core/dist/harness/system-prompt.d.ts +7 -0
  162. package/packages/pi-agent-core/dist/harness/system-prompt.d.ts.map +1 -1
  163. package/packages/pi-agent-core/dist/harness/system-prompt.js +7 -0
  164. package/packages/pi-agent-core/dist/harness/system-prompt.js.map +1 -1
  165. package/packages/pi-agent-core/package.json +1 -1
  166. package/packages/pi-ai/dist/models.generated.d.ts +8 -59
  167. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  168. package/packages/pi-ai/dist/models.generated.js +21 -72
  169. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  170. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  171. package/packages/pi-ai/dist/providers/anthropic.js +50 -0
  172. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  173. package/packages/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
  174. package/packages/pi-ai/dist/providers/openai-responses-shared.js +28 -4
  175. package/packages/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
  176. package/packages/pi-ai/dist/types.d.ts +2 -0
  177. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  178. package/packages/pi-ai/dist/types.js.map +1 -1
  179. package/packages/pi-ai/package.json +1 -1
  180. package/packages/pi-coding-agent/README.md +1 -1
  181. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +2 -2
  182. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/extensions/loader.js +1 -1
  185. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  186. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/extensions/runner.js +8 -2
  188. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/skills.d.ts +3 -0
  190. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/skills.js +3 -0
  192. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  193. package/packages/pi-coding-agent/package.json +7 -7
  194. package/packages/pi-tui/package.json +1 -1
  195. package/packages/rpc-client/package.json +2 -2
  196. package/pkg/package.json +1 -1
  197. package/src/resources/extensions/context7/index.ts +15 -2
  198. package/src/resources/extensions/get-secrets-from-user.ts +17 -16
  199. package/src/resources/extensions/google-cli/index.ts +34 -0
  200. package/src/resources/extensions/google-cli/models.ts +57 -0
  201. package/src/resources/extensions/google-cli/package.json +11 -0
  202. package/src/resources/extensions/google-cli/readiness.ts +15 -0
  203. package/src/resources/extensions/google-cli/stream-adapter.ts +245 -0
  204. package/src/resources/extensions/gsd/auto/loop.ts +74 -1
  205. package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -2
  206. package/src/resources/extensions/gsd/auto/phases.ts +46 -0
  207. package/src/resources/extensions/gsd/auto/run-unit.ts +10 -0
  208. package/src/resources/extensions/gsd/auto/session.ts +3 -0
  209. package/src/resources/extensions/gsd/auto-dispatch.ts +31 -11
  210. package/src/resources/extensions/gsd/auto-post-unit.ts +37 -2
  211. package/src/resources/extensions/gsd/auto-prompts.ts +4 -284
  212. package/src/resources/extensions/gsd/auto-recovery.ts +10 -7
  213. package/src/resources/extensions/gsd/auto-start.ts +307 -56
  214. package/src/resources/extensions/gsd/auto.ts +6 -1
  215. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +4 -3
  216. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +42 -5
  217. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +18 -6
  218. package/src/resources/extensions/gsd/bootstrap/system-context.ts +3 -28
  219. package/src/resources/extensions/gsd/closeout-recovery.ts +6 -1
  220. package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -1
  221. package/src/resources/extensions/gsd/commands-usage.ts +110 -5
  222. package/src/resources/extensions/gsd/config-overlay.ts +19 -16
  223. package/src/resources/extensions/gsd/context-overlay.ts +24 -19
  224. package/src/resources/extensions/gsd/dashboard-overlay.ts +14 -27
  225. package/src/resources/extensions/gsd/doctor-engine-checks.ts +99 -0
  226. package/src/resources/extensions/gsd/doctor-providers.ts +55 -27
  227. package/src/resources/extensions/gsd/doctor-types.ts +2 -0
  228. package/src/resources/extensions/gsd/doctor.ts +6 -1
  229. package/src/resources/extensions/gsd/git-conflict-state.ts +25 -1
  230. package/src/resources/extensions/gsd/guided-flow.ts +5 -6
  231. package/src/resources/extensions/gsd/key-manager.ts +57 -14
  232. package/src/resources/extensions/gsd/milestone-reopen-events.ts +28 -0
  233. package/src/resources/extensions/gsd/notification-overlay.ts +12 -11
  234. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +16 -12
  235. package/src/resources/extensions/gsd/preferences-skills.ts +11 -4
  236. package/src/resources/extensions/gsd/preferences.ts +17 -2
  237. package/src/resources/extensions/gsd/prompt-loader.ts +2 -0
  238. package/src/resources/extensions/gsd/prompts/discuss.md +4 -2
  239. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  240. package/src/resources/extensions/gsd/prompts/system.md +1 -3
  241. package/src/resources/extensions/gsd/queue-reorder-ui.ts +29 -20
  242. package/src/resources/extensions/gsd/repository-registry.ts +3 -1
  243. package/src/resources/extensions/gsd/skill-activation.ts +292 -0
  244. package/src/resources/extensions/gsd/skill-catalog.data.ts +858 -0
  245. package/src/resources/extensions/gsd/skill-catalog.install.ts +205 -0
  246. package/src/resources/extensions/gsd/skill-catalog.ts +16 -1087
  247. package/src/resources/extensions/gsd/skill-discovery.ts +134 -78
  248. package/src/resources/extensions/gsd/skill-scope.ts +63 -0
  249. package/src/resources/extensions/gsd/skill-telemetry.ts +6 -40
  250. package/src/resources/extensions/gsd/skills.ts +75 -0
  251. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +499 -0
  252. package/src/resources/extensions/gsd/state-reconciliation/index.ts +40 -0
  253. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +8 -0
  254. package/src/resources/extensions/gsd/state-reconciliation/types.ts +30 -0
  255. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +328 -2
  256. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +21 -0
  257. package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +28 -2
  258. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +41 -0
  259. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +436 -0
  260. package/src/resources/extensions/gsd/tests/closeout-recovery.test.ts +15 -0
  261. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +31 -0
  262. package/src/resources/extensions/gsd/tests/commands-context.test.ts +5 -3
  263. package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +15 -2
  264. package/src/resources/extensions/gsd/tests/commands-usage.test.ts +97 -0
  265. package/src/resources/extensions/gsd/tests/context-chart.test.ts +9 -0
  266. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +25 -0
  267. package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +1 -0
  268. package/src/resources/extensions/gsd/tests/discuss-prompt.test.ts +4 -2
  269. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +1 -1
  270. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +105 -0
  271. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +101 -1
  272. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +6 -0
  273. package/src/resources/extensions/gsd/tests/key-manager.test.ts +23 -4
  274. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +6 -1
  275. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +70 -10
  276. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +7 -1
  277. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +93 -0
  278. package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +46 -0
  279. package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +116 -11
  280. package/src/resources/extensions/gsd/tests/repository-registry.test.ts +30 -1
  281. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +4 -0
  282. package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +111 -0
  283. package/src/resources/extensions/gsd/tests/skill-scope-auto.test.ts +67 -0
  284. package/src/resources/extensions/gsd/tests/skills.test.ts +55 -0
  285. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +13 -2
  286. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +303 -0
  287. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +19 -0
  288. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +24 -1
  289. package/src/resources/extensions/gsd/tests/tui-border-assertions.ts +28 -0
  290. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +14 -0
  291. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +18 -0
  292. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +26 -0
  293. package/src/resources/extensions/gsd/tests/vision-ask.test.ts +23 -0
  294. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -1
  295. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +74 -1
  296. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +82 -0
  297. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +16 -1
  298. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +28 -0
  299. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +45 -1
  300. package/src/resources/extensions/gsd/tools/complete-task.ts +9 -0
  301. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +82 -5
  302. package/src/resources/extensions/gsd/tui/render-kit.ts +82 -0
  303. package/src/resources/extensions/gsd/unit-context-manifest.ts +37 -26
  304. package/src/resources/extensions/gsd/user-input-boundary.ts +1 -1
  305. package/src/resources/extensions/gsd/vision-ask.ts +28 -0
  306. package/src/resources/extensions/gsd/visualizer-overlay.ts +12 -40
  307. package/src/resources/extensions/gsd/worktree-lifecycle.ts +37 -2
  308. package/src/resources/extensions/search-the-web/native-search.ts +60 -8
  309. package/src/resources/extensions/shared/confirm-ui.ts +8 -12
  310. package/src/resources/extensions/shared/dialog-frame.ts +71 -0
  311. package/src/resources/extensions/shared/interview-ui.ts +43 -42
  312. package/src/resources/extensions/shared/next-action-ui.ts +6 -6
  313. package/src/resources/extensions/shared/tests/confirm-ui.test.ts +57 -0
  314. package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +163 -0
  315. package/src/resources/extensions/shared/tests/next-action-ui-hasui.test.ts +55 -0
  316. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
  317. /package/dist/web/standalone/.next/static/{praHP_OATcjBkvAVejjGK → orfEoZqDIo6Be_Z9ZFipD}/_buildManifest.js +0 -0
  318. /package/dist/web/standalone/.next/static/{praHP_OATcjBkvAVejjGK → orfEoZqDIo6Be_Z9ZFipD}/_ssgManifest.js +0 -0
@@ -108,6 +108,34 @@ test("executeSummarySave persists artifact and returns computed path", async ()
108
108
  }
109
109
  });
110
110
 
111
+ test("executeSummarySave mirrors milestone artifacts into the active worktree projection", async () => {
112
+ const base = makeTmpBase();
113
+ const worktree = join(base, ".gsd", "worktrees", "M001");
114
+ try {
115
+ mkdirSync(join(worktree, ".gsd"), { recursive: true });
116
+ writeFileSync(join(worktree, ".git"), "gitdir: ../../../.git/worktrees/M001\n");
117
+ openTestDb(base);
118
+
119
+ const result = await inProjectDir(worktree, () => executeSummarySave({
120
+ milestone_id: "M001",
121
+ slice_id: "S02",
122
+ artifact_type: "RESEARCH",
123
+ content: "# S02 Research\n\ncanonical and worktree",
124
+ }, worktree));
125
+
126
+ assert.equal(result.details.operation, "save_summary");
127
+ const relPath = "milestones/M001/slices/S02/S02-RESEARCH.md";
128
+ const projectPath = join(base, ".gsd", relPath);
129
+ const worktreePath = join(worktree, ".gsd", relPath);
130
+ assert.equal(existsSync(projectPath), true, "canonical artifact should be written");
131
+ assert.equal(existsSync(worktreePath), true, "active worktree projection should be mirrored");
132
+ assert.match(readFileSync(worktreePath, "utf-8"), /S02 Research/);
133
+ } finally {
134
+ closeDatabase();
135
+ cleanup(base);
136
+ }
137
+ });
138
+
111
139
  test("executeTaskComplete coerces string verificationEvidence entries", async () => {
112
140
  const base = makeTmpBase();
113
141
  try {
@@ -148,6 +176,60 @@ test("executeTaskComplete coerces string verificationEvidence entries", async ()
148
176
  }
149
177
  });
150
178
 
179
+ test("executeTaskComplete derives missing verification from evidence", async () => {
180
+ const base = makeTmpBase();
181
+ try {
182
+ openTestDb(base);
183
+ const planDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
184
+ mkdirSync(planDir, { recursive: true });
185
+ writeFileSync(join(planDir, "S01-PLAN.md"), "# S01\n\n- [ ] **T01: Demo** `est:5m`\n");
186
+
187
+ const result = await inProjectDir(base, () => executeTaskComplete({
188
+ milestoneId: "M001",
189
+ sliceId: "S01",
190
+ taskId: "T01",
191
+ oneLiner: "Completed task",
192
+ narrative: "Did the work",
193
+ verificationEvidence: [
194
+ { command: "npm test", exitCode: 0, verdict: "pass", durationMs: 1234 },
195
+ ],
196
+ }, base));
197
+
198
+ assert.equal(result.details.operation, "complete_task");
199
+ const db = _getAdapter();
200
+ assert.ok(db, "DB should be open");
201
+ const row = db!.prepare(
202
+ "SELECT verification_result FROM tasks WHERE milestone_id = ? AND slice_id = ? AND id = ?",
203
+ ).get("M001", "S01", "T01") as Record<string, unknown> | undefined;
204
+
205
+ assert.match(String(row?.verification_result), /Verification evidence recorded/);
206
+ assert.match(String(row?.verification_result), /`npm test` exited 0 \(pass\)/);
207
+ } finally {
208
+ closeDatabase();
209
+ cleanup(base);
210
+ }
211
+ });
212
+
213
+ test("executeTaskComplete returns a tool error when verification cannot be derived", async () => {
214
+ const base = makeTmpBase();
215
+ try {
216
+ openTestDb(base);
217
+ const result = await inProjectDir(base, () => executeTaskComplete({
218
+ milestoneId: "M001",
219
+ sliceId: "S01",
220
+ taskId: "T01",
221
+ oneLiner: "Completed task",
222
+ narrative: "Did the work",
223
+ }, base));
224
+
225
+ assert.equal(result.isError, true);
226
+ assert.match(String(result.content[0]?.text), /verification is required/);
227
+ } finally {
228
+ closeDatabase();
229
+ cleanup(base);
230
+ }
231
+ });
232
+
151
233
  test("executeSliceComplete preserves omitted optional requirement arrays", async () => {
152
234
  const base = makeTmpBase();
153
235
  try {
@@ -9,7 +9,7 @@ import { join } from "node:path";
9
9
  import { probeGitConflictState } from "../git-conflict-state.js";
10
10
  import { ensureWorkspaceGitReadyForPath } from "../workspace-git-preflight.js";
11
11
  import { isWorkspaceGitAllowedCommand } from "../workspace-git-guard.js";
12
- import { cleanup, git, makeTempRepo } from "./test-utils.ts";
12
+ import { cleanup, git, makeTempDir, makeTempRepo } from "./test-utils.ts";
13
13
 
14
14
  function seedGsdConflict(base: string): void {
15
15
  mkdirSync(join(base, ".gsd"), { recursive: true });
@@ -60,6 +60,21 @@ test("probeGitConflictState reports clean repo", () => {
60
60
  }
61
61
  });
62
62
 
63
+ test("ensureWorkspaceGitReadyForPath allows fresh non-git project setup folders", async () => {
64
+ const base = makeTempDir("gsd-ws-git-non-repo-");
65
+ try {
66
+ mkdirSync(join(base, ".gsd"), { recursive: true });
67
+
68
+ const probe = probeGitConflictState(base);
69
+ assert.equal(probe.status, "clean");
70
+
71
+ const ready = await ensureWorkspaceGitReadyForPath(base);
72
+ assert.equal(ready.ok, true);
73
+ } finally {
74
+ cleanup(base);
75
+ }
76
+ });
77
+
63
78
  test("ensureWorkspaceGitReadyForPath auto-resolves .gsd/ conflicts", async () => {
64
79
  const base = makeTempRepo("gsd-ws-git-heal-");
65
80
  try {
@@ -212,6 +212,34 @@ test("enterMilestone returns ok:true mode:none when isolation disabled", () => {
212
212
  assert.equal(s.basePath, "/project");
213
213
  });
214
214
 
215
+ test("adoptStrandedMilestone forces branch recovery even when normal preferences differ", (t) => {
216
+ const previousCwd = process.cwd();
217
+ const base = makeGitRepoBase({ isolation: "worktree" });
218
+ t.after(() => cleanupRepoBase(base, previousCwd));
219
+
220
+ const s = makeSession({ basePath: base, originalBasePath: base });
221
+ const deps = makeDeps();
222
+ const ctx = makeCtx();
223
+ const lifecycle = new WorktreeLifecycle(s, deps);
224
+
225
+ const result = lifecycle.adoptStrandedMilestone("M001", base, ctx, {
226
+ mode: "branch",
227
+ });
228
+
229
+ assert.equal(result.ok, true, `expected ok:true, got: ${JSON.stringify(result)}`);
230
+ if (result.ok) {
231
+ assert.equal(result.mode, "branch");
232
+ assert.equal(result.path, base);
233
+ }
234
+ assert.equal(s.basePath, base);
235
+ assert.equal(s.strandedRecoveryIsolationMode, "branch");
236
+ const currentBranch = execFileSync("git", ["branch", "--show-current"], {
237
+ cwd: base,
238
+ encoding: "utf-8",
239
+ }).trim();
240
+ assert.equal(currentBranch, "milestone/M001");
241
+ });
242
+
215
243
  test("enterMilestone returns ok:false reason:isolation-degraded when session degraded", () => {
216
244
  const s = makeSession({ isolationDegraded: true });
217
245
  const deps = makeDeps({ getIsolationMode: () => "branch" });
@@ -14,7 +14,7 @@
14
14
 
15
15
  import { test } from "node:test";
16
16
  import assert from "node:assert/strict";
17
- import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
17
+ import { existsSync, mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
18
18
  import { join } from "node:path";
19
19
  import { tmpdir } from "node:os";
20
20
 
@@ -79,3 +79,47 @@ test("#2942: injected existsFn — milestones/ alone is enough", () => {
79
79
  p === "/proj/.gsd" || p === "/proj/.gsd/milestones";
80
80
  assert.equal(hasGsdBootstrapArtifacts("/proj/.gsd", existsFn), true);
81
81
  });
82
+
83
+ test("bare /gsd routes zombie .gsd folders to project init before closeout/db checks", async (t) => {
84
+ const base = mkdtempSync(join(tmpdir(), "gsd-zombie-bare-command-"));
85
+ t.after(() => rmSync(base, { recursive: true, force: true }));
86
+ mkdirSync(join(base, ".gsd", "runtime"), { recursive: true });
87
+
88
+ const previousCwd = process.cwd();
89
+ const previousGsdHome = process.env.GSD_HOME;
90
+ const previousProjectRoot = process.env.GSD_PROJECT_ROOT;
91
+ try {
92
+ process.chdir(base);
93
+ process.env.GSD_HOME = join(base, ".test-gsd-home");
94
+ delete process.env.GSD_PROJECT_ROOT;
95
+
96
+ const notifications: string[] = [];
97
+ const ctx = {
98
+ hasUI: false,
99
+ ui: {
100
+ notify: (content: unknown) => notifications.push(String(content)),
101
+ setStatus: () => {},
102
+ setWidget: () => {},
103
+ },
104
+ };
105
+ const { handleAutoCommand } = await import("../commands/handlers/auto.ts");
106
+
107
+ await handleAutoCommand("", ctx as any, {} as any);
108
+
109
+ assert.ok(
110
+ notifications.some((message) => message.includes("/gsd init did not start")),
111
+ "bare /gsd should route unbootstrapped zombie folders to the init wizard",
112
+ );
113
+ assert.equal(
114
+ existsSync(join(base, ".gsd", "gsd.db")),
115
+ false,
116
+ "bare /gsd should not create the project DB before init has bootstrapped .gsd/",
117
+ );
118
+ } finally {
119
+ process.chdir(previousCwd);
120
+ if (previousGsdHome === undefined) delete process.env.GSD_HOME;
121
+ else process.env.GSD_HOME = previousGsdHome;
122
+ if (previousProjectRoot === undefined) delete process.env.GSD_PROJECT_ROOT;
123
+ else process.env.GSD_PROJECT_ROOT = previousProjectRoot;
124
+ }
125
+ });
@@ -173,6 +173,15 @@ export async function handleCompleteTask(
173
173
  if (!params.milestoneId || typeof params.milestoneId !== "string" || params.milestoneId.trim() === "") {
174
174
  return { error: "milestoneId is required and must be a non-empty string" };
175
175
  }
176
+ if (!params.oneLiner || typeof params.oneLiner !== "string" || params.oneLiner.trim() === "") {
177
+ return { error: "oneLiner is required and must be a non-empty string" };
178
+ }
179
+ if (!params.narrative || typeof params.narrative !== "string" || params.narrative.trim() === "") {
180
+ return { error: "narrative is required and must be a non-empty string" };
181
+ }
182
+ if (!params.verification || typeof params.verification !== "string" || params.verification.trim() === "") {
183
+ return { error: "verification is required and must be a non-empty string" };
184
+ }
176
185
 
177
186
  const artifactBasePath = resolveCanonicalMilestoneRoot(basePath, params.milestoneId);
178
187
 
@@ -15,8 +15,10 @@ import {
15
15
  } from "../gsd-db.js";
16
16
  import { GATE_REGISTRY } from "../gate-registry.js";
17
17
  import { generateRequirementsMd, saveArtifactToDb } from "../db-writer.js";
18
- import { resolveMilestoneFile, resolveSliceFile } from "../paths.js";
18
+ import { clearPathCache, resolveGsdPathContract, resolveMilestoneFile, resolveSliceFile } from "../paths.js";
19
+ import { saveFile, clearParseCache } from "../files.js";
19
20
  import { unlinkSync } from "node:fs";
21
+ import { join } from "node:path";
20
22
  import type { CompleteMilestoneParams } from "./complete-milestone.js";
21
23
  import { handleCompleteMilestone } from "./complete-milestone.js";
22
24
  import { handleCompleteTask } from "./complete-task.js";
@@ -96,6 +98,28 @@ function registerProjectMilestoneSequence(content: string): string[] {
96
98
  return registered;
97
99
  }
98
100
 
101
+ async function mirrorArtifactToActiveWorktreeProjection(
102
+ basePath: string,
103
+ relativePath: string,
104
+ content: string,
105
+ ): Promise<void> {
106
+ const contract = resolveGsdPathContract(basePath);
107
+ if (!contract.worktreeGsd) return;
108
+ if (contract.worktreeGsd === contract.projectGsd) return;
109
+
110
+ const fullPath = join(contract.worktreeGsd, relativePath);
111
+ try {
112
+ await saveFile(fullPath, content);
113
+ clearPathCache();
114
+ clearParseCache();
115
+ invalidateStateCache();
116
+ } catch (err) {
117
+ logWarning("tool", `gsd_summary_save worktree projection mirror failed: ${(err as Error).message}`, {
118
+ path: relativePath,
119
+ });
120
+ }
121
+ }
122
+
99
123
  export async function executeSummarySave(
100
124
  params: SummarySaveParams,
101
125
  basePath: string = process.cwd(),
@@ -197,6 +221,7 @@ export async function executeSummarySave(
197
221
  },
198
222
  basePath,
199
223
  );
224
+ await mirrorArtifactToActiveWorktreeProjection(basePath, relativePath, contentToSave);
200
225
 
201
226
  let registeredMilestones: string[] = [];
202
227
  if (params.artifact_type === "PROJECT") {
@@ -306,7 +331,7 @@ export interface TaskCompleteParams {
306
331
  milestoneId: string;
307
332
  oneLiner: string;
308
333
  narrative: string;
309
- verification: string;
334
+ verification?: string;
310
335
  deviations?: string;
311
336
  knownIssues?: string;
312
337
  keyFiles?: string[];
@@ -315,6 +340,40 @@ export interface TaskCompleteParams {
315
340
  verificationEvidence?: VerificationEvidenceInput[];
316
341
  }
317
342
 
343
+ type NormalizedVerificationEvidence = {
344
+ command: string;
345
+ exitCode: number;
346
+ verdict: string;
347
+ durationMs: number;
348
+ };
349
+
350
+ function normalizeVerificationEvidence(
351
+ evidence: VerificationEvidenceInput[] | undefined,
352
+ ): NormalizedVerificationEvidence[] {
353
+ return (evidence ?? []).map((entry) =>
354
+ typeof entry === "string"
355
+ ? { command: entry, exitCode: -1, verdict: "unknown (coerced from string)", durationMs: 0 }
356
+ : entry,
357
+ );
358
+ }
359
+
360
+ function deriveVerificationSummary(
361
+ evidence: NormalizedVerificationEvidence[],
362
+ ): string | null {
363
+ if (evidence.length === 0) return null;
364
+
365
+ const rendered = evidence.slice(0, 3).map((entry) => {
366
+ const command = entry.command.trim() || "(unspecified command)";
367
+ const verdict = entry.verdict.trim() || "recorded";
368
+ return `\`${command}\` exited ${entry.exitCode} (${verdict})`;
369
+ });
370
+ const suffix = evidence.length > rendered.length
371
+ ? `; ${evidence.length - rendered.length} more check(s) recorded`
372
+ : "";
373
+
374
+ return `Verification evidence recorded: ${rendered.join("; ")}${suffix}.`;
375
+ }
376
+
318
377
  export type CompleteMilestoneExecutorParams = Partial<CompleteMilestoneParams> & Record<string, unknown>;
319
378
  export type SliceCompleteExecutorParams = CompleteSliceParams;
320
379
  export type PlanMilestoneExecutorParams = PlanMilestoneParams;
@@ -350,9 +409,27 @@ export async function executeTaskComplete(
350
409
  }
351
410
  try {
352
411
  const coerced = { ...params };
353
- coerced.verificationEvidence = (params.verificationEvidence ?? []).map((v) =>
354
- typeof v === "string" ? { command: v, exitCode: -1, verdict: "unknown (coerced from string)", durationMs: 0 } : v,
355
- );
412
+ const verificationEvidence = normalizeVerificationEvidence(params.verificationEvidence);
413
+ coerced.verificationEvidence = verificationEvidence;
414
+
415
+ const verification = typeof params.verification === "string" ? params.verification.trim() : "";
416
+ if (verification.length === 0) {
417
+ const derived = deriveVerificationSummary(verificationEvidence);
418
+ if (derived) {
419
+ coerced.verification = derived;
420
+ } else if (params.blockerDiscovered === true) {
421
+ coerced.verification = "Not run: blocker discovered before verification.";
422
+ } else {
423
+ return {
424
+ content: [{
425
+ type: "text",
426
+ text: "Error completing task: verification is required unless verificationEvidence is provided or blockerDiscovered is true.",
427
+ }],
428
+ details: { operation: "complete_task", error: "verification_required" },
429
+ isError: true,
430
+ };
431
+ }
432
+ }
356
433
 
357
434
  const result = await handleCompleteTask(coerced as any, basePath);
358
435
  if ("error" in result) {
@@ -151,3 +151,85 @@ export function renderFrame(
151
151
  lines.push(border("╰" + "─".repeat(width - 2) + "╯"));
152
152
  return lines.map((line) => safeLine(line, width, ""));
153
153
  }
154
+
155
+ export interface DialogFrameOptions {
156
+ borderColor?: string;
157
+ paddingX?: number;
158
+ footer?: string | string[];
159
+ scroll?: {
160
+ offset: number;
161
+ visibleRows: number;
162
+ totalRows: number;
163
+ trackOffset?: number;
164
+ trackRows?: number;
165
+ };
166
+ }
167
+
168
+ function renderTitledTopBorder(
169
+ theme: ThemeLike,
170
+ title: string,
171
+ width: number,
172
+ border: (text: string) => string,
173
+ ): string {
174
+ const trimmedTitle = title.trim();
175
+ if (!trimmedTitle || width < 10) {
176
+ return border("╭" + "─".repeat(width - 2) + "╮");
177
+ }
178
+
179
+ const maxTitleWidth = Math.max(0, width - 7);
180
+ const safeTitle = safeLine(trimmedTitle, maxTitleWidth);
181
+ const fill = Math.max(0, width - visibleWidth(safeTitle) - 5);
182
+ return border("╭─ ") + theme.bold(theme.fg("accent", safeTitle)) + border(" " + "─".repeat(fill) + "╮");
183
+ }
184
+
185
+ export function renderDialogFrame(
186
+ theme: ThemeLike,
187
+ title: string,
188
+ inner: string[],
189
+ width: number,
190
+ options: DialogFrameOptions = {},
191
+ ): string[] {
192
+ if (width < 4) return inner.map((line) => safeLine(line, width));
193
+
194
+ const borderColor = options.borderColor ?? "borderAccent";
195
+ const paddingX = Math.max(0, options.paddingX ?? 1);
196
+ const contentWidth = Math.max(0, width - 2 - paddingX * 2);
197
+ const border = (text: string) => theme.fg(borderColor, text);
198
+ const pad = " ".repeat(paddingX);
199
+ const lines = [renderTitledTopBorder(theme, title, width, border)];
200
+
201
+ const scroll = options.scroll;
202
+ const bodyRows = inner.length;
203
+ const trackOffset = Math.max(0, Math.min(scroll?.trackOffset ?? 0, bodyRows));
204
+ const trackRows = Math.max(0, Math.min(scroll?.trackRows ?? bodyRows, bodyRows - trackOffset));
205
+ const scrollable = !!scroll && scroll.totalRows > scroll.visibleRows && trackRows > 0;
206
+ const thumbLen = scrollable
207
+ ? Math.max(1, Math.round((scroll.visibleRows / scroll.totalRows) * trackRows))
208
+ : 0;
209
+ const maxThumbStart = Math.max(0, trackRows - thumbLen);
210
+ const maxScrollOffset = scrollable ? Math.max(1, scroll.totalRows - scroll.visibleRows) : 1;
211
+ const thumbStart = scrollable
212
+ ? trackOffset + Math.min(maxThumbStart, Math.round((scroll.offset / maxScrollOffset) * maxThumbStart))
213
+ : -1;
214
+
215
+ for (let i = 0; i < inner.length; i++) {
216
+ const line = inner[i] ?? "";
217
+ const rightBorder = scrollable && i >= thumbStart && i < thumbStart + thumbLen ? "┃" : "│";
218
+ lines.push(border("│") + pad + padRightVisible(line, contentWidth) + pad + border(rightBorder));
219
+ }
220
+
221
+ const footer = Array.isArray(options.footer)
222
+ ? options.footer
223
+ : options.footer
224
+ ? [options.footer]
225
+ : [];
226
+ if (footer.length > 0) {
227
+ lines.push(border("├" + "─".repeat(width - 2) + "┤"));
228
+ for (const line of footer) {
229
+ lines.push(border("│") + pad + padRightVisible(line, contentWidth) + pad + border("│"));
230
+ }
231
+ }
232
+
233
+ lines.push(border("╰" + "─".repeat(width - 2) + "╯"));
234
+ return lines.map((line) => safeLine(line, width, ""));
235
+ }
@@ -13,6 +13,8 @@
13
13
  //
14
14
  // Phased rollout tracking:
15
15
  // - Phase 1 (this PR): schema + manifests + coverage test.
16
+ // - Phase 1b (skill token savings): skills policy wired via skill-scope.ts
17
+ // and setVisibleSkills(); allowlists derived from skill-manifest.ts.
16
18
  // - Phase 2: add composeSystemPromptForUnit(); migrate one low-risk
17
19
  // unit type (e.g. reassess-roadmap) as the pilot.
18
20
  // - Phase 3: migrate remaining unit types, tighten manifests per
@@ -277,11 +279,20 @@ export interface UnitContextManifest {
277
279
 
278
280
  // ─── Manifests ────────────────────────────────────────────────────────────
279
281
 
280
- // Phase 1 policy: every manifest encodes today's behavior. Skills = "all"
281
- // unless the unit type was already narrowed via the existing skill-manifest
282
- // resolver (#4779). Memory/knowledge policies reflect the defaults in
283
- // `bootstrap/system-context.ts`. Artifact classifications follow what
284
- // `auto-prompts.ts` inlines today for each unit type.
282
+ // Phase 1 policy: skills policy is derived from skill-manifest.ts allowlists
283
+ // via `skillPolicyForUnit()`; units without an allowlist keep mode "all".
284
+ // Explicit mode "none" remains for lightweight config units.
285
+
286
+ import { resolveSkillManifest } from "./skill-manifest.js";
287
+
288
+ /** Derive skills policy from skill-manifest allowlists; default to full catalog. */
289
+ function skillPolicyForUnit(unitType: string): SkillsPolicy {
290
+ const allowlist = resolveSkillManifest(unitType);
291
+ if (allowlist) {
292
+ return { mode: "allowlist", skills: allowlist };
293
+ }
294
+ return { mode: "all" };
295
+ }
285
296
 
286
297
  const COMMON_BUDGET_LARGE = 1_500_000; // ~400K tokens
287
298
  const COMMON_BUDGET_MEDIUM = 750_000; // ~200K tokens
@@ -360,7 +371,7 @@ export type UnitType = typeof KNOWN_UNIT_TYPES[number];
360
371
  export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
361
372
  // ─── Milestone-scoped ────────────────────────────────────────────────
362
373
  "research-milestone": {
363
- skills: { mode: "all" },
374
+ skills: skillPolicyForUnit("research-milestone"),
364
375
  knowledge: "full",
365
376
  memory: "prompt-relevant",
366
377
  codebaseMap: true,
@@ -377,7 +388,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
377
388
  maxSystemPromptChars: COMMON_BUDGET_MEDIUM,
378
389
  },
379
390
  "plan-milestone": {
380
- skills: { mode: "all" },
391
+ skills: skillPolicyForUnit("plan-milestone"),
381
392
  knowledge: "full",
382
393
  memory: "prompt-relevant",
383
394
  codebaseMap: true,
@@ -392,7 +403,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
392
403
  maxSystemPromptChars: COMMON_BUDGET_LARGE,
393
404
  },
394
405
  "discuss-milestone": {
395
- skills: { mode: "all" },
406
+ skills: skillPolicyForUnit("discuss-milestone"),
396
407
  knowledge: "full",
397
408
  memory: "prompt-relevant",
398
409
  codebaseMap: true,
@@ -407,7 +418,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
407
418
  maxSystemPromptChars: COMMON_BUDGET_MEDIUM,
408
419
  },
409
420
  "validate-milestone": {
410
- skills: { mode: "all" },
421
+ skills: skillPolicyForUnit("validate-milestone"),
411
422
  knowledge: "scoped",
412
423
  memory: "prompt-relevant",
413
424
  codebaseMap: false,
@@ -424,7 +435,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
424
435
  maxSystemPromptChars: COMMON_BUDGET_LARGE,
425
436
  },
426
437
  "complete-milestone": {
427
- skills: { mode: "all" },
438
+ skills: skillPolicyForUnit("complete-milestone"),
428
439
  knowledge: "scoped",
429
440
  memory: "prompt-relevant",
430
441
  codebaseMap: false,
@@ -446,7 +457,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
446
457
 
447
458
  // ─── Slice-scoped ────────────────────────────────────────────────────
448
459
  "research-slice": {
449
- skills: { mode: "all" },
460
+ skills: skillPolicyForUnit("research-slice"),
450
461
  knowledge: "full",
451
462
  memory: "prompt-relevant",
452
463
  codebaseMap: true,
@@ -463,7 +474,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
463
474
  maxSystemPromptChars: COMMON_BUDGET_MEDIUM,
464
475
  },
465
476
  "plan-slice": {
466
- skills: { mode: "all" },
477
+ skills: skillPolicyForUnit("plan-slice"),
467
478
  knowledge: "full",
468
479
  memory: "prompt-relevant",
469
480
  codebaseMap: true,
@@ -481,7 +492,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
481
492
  maxSystemPromptChars: COMMON_BUDGET_LARGE,
482
493
  },
483
494
  "refine-slice": {
484
- skills: { mode: "all" },
495
+ skills: skillPolicyForUnit("refine-slice"),
485
496
  knowledge: "scoped",
486
497
  memory: "prompt-relevant",
487
498
  codebaseMap: true,
@@ -499,7 +510,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
499
510
  maxSystemPromptChars: COMMON_BUDGET_MEDIUM,
500
511
  },
501
512
  "replan-slice": {
502
- skills: { mode: "all" },
513
+ skills: skillPolicyForUnit("replan-slice"),
503
514
  knowledge: "scoped",
504
515
  memory: "prompt-relevant",
505
516
  codebaseMap: true,
@@ -514,7 +525,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
514
525
  maxSystemPromptChars: COMMON_BUDGET_MEDIUM,
515
526
  },
516
527
  "complete-slice": {
517
- skills: { mode: "all" },
528
+ skills: skillPolicyForUnit("complete-slice"),
518
529
  knowledge: "scoped",
519
530
  memory: "prompt-relevant",
520
531
  codebaseMap: false,
@@ -535,7 +546,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
535
546
  maxSystemPromptChars: COMMON_BUDGET_LARGE,
536
547
  },
537
548
  "reassess-roadmap": {
538
- skills: { mode: "all" },
549
+ skills: skillPolicyForUnit("reassess-roadmap"),
539
550
  knowledge: "scoped",
540
551
  memory: "critical-only",
541
552
  codebaseMap: false,
@@ -552,7 +563,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
552
563
 
553
564
  // ─── Task-scoped ─────────────────────────────────────────────────────
554
565
  "execute-task": {
555
- skills: { mode: "all" },
566
+ skills: skillPolicyForUnit("execute-task"),
556
567
  knowledge: "scoped",
557
568
  memory: "prompt-relevant",
558
569
  codebaseMap: true,
@@ -567,7 +578,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
567
578
  maxSystemPromptChars: COMMON_BUDGET_LARGE,
568
579
  },
569
580
  "reactive-execute": {
570
- skills: { mode: "all" },
581
+ skills: skillPolicyForUnit("reactive-execute"),
571
582
  knowledge: "scoped",
572
583
  memory: "prompt-relevant",
573
584
  codebaseMap: true,
@@ -584,7 +595,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
584
595
 
585
596
  // ─── Ancillary units ─────────────────────────────────────────────────
586
597
  "run-uat": {
587
- skills: { mode: "all" },
598
+ skills: skillPolicyForUnit("run-uat"),
588
599
  knowledge: "critical-only",
589
600
  memory: "critical-only",
590
601
  codebaseMap: false,
@@ -599,7 +610,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
599
610
  maxSystemPromptChars: COMMON_BUDGET_SMALL,
600
611
  },
601
612
  "gate-evaluate": {
602
- skills: { mode: "all" },
613
+ skills: skillPolicyForUnit("gate-evaluate"),
603
614
  knowledge: "critical-only",
604
615
  memory: "critical-only",
605
616
  codebaseMap: false,
@@ -616,7 +627,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
616
627
  maxSystemPromptChars: COMMON_BUDGET_SMALL,
617
628
  },
618
629
  "rewrite-docs": {
619
- skills: { mode: "all" },
630
+ skills: skillPolicyForUnit("rewrite-docs"),
620
631
  knowledge: "scoped",
621
632
  memory: "prompt-relevant",
622
633
  codebaseMap: true,
@@ -631,7 +642,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
631
642
  maxSystemPromptChars: COMMON_BUDGET_MEDIUM,
632
643
  },
633
644
  "triage-captures": {
634
- skills: { mode: "all" },
645
+ skills: skillPolicyForUnit("triage-captures"),
635
646
  knowledge: "scoped",
636
647
  memory: "prompt-relevant",
637
648
  codebaseMap: false,
@@ -646,7 +657,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
646
657
  maxSystemPromptChars: COMMON_BUDGET_MEDIUM,
647
658
  },
648
659
  "quick-task": {
649
- skills: { mode: "all" },
660
+ skills: skillPolicyForUnit("quick-task"),
650
661
  knowledge: "full",
651
662
  memory: "prompt-relevant",
652
663
  codebaseMap: true,
@@ -684,7 +695,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
684
695
  // discussion runs before any milestone exists, so milestone artifacts are
685
696
  // not loaded. Keeps templates available for PROJECT.md scaffolding.
686
697
  "discuss-project": {
687
- skills: { mode: "all" },
698
+ skills: skillPolicyForUnit("discuss-project"),
688
699
  knowledge: "scoped",
689
700
  memory: "prompt-relevant",
690
701
  codebaseMap: true,
@@ -701,7 +712,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
701
712
  // discuss-requirements: REQUIREMENTS.md interview. PROJECT.md is the
702
713
  // primary context input; templates carry the requirements format.
703
714
  "discuss-requirements": {
704
- skills: { mode: "all" },
715
+ skills: skillPolicyForUnit("discuss-requirements"),
705
716
  knowledge: "scoped",
706
717
  memory: "prompt-relevant",
707
718
  codebaseMap: true,
@@ -737,7 +748,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
737
748
  // planning-dispatch policy to dispatch them. PROJECT.md + REQUIREMENTS.md
738
749
  // give the orchestrator the framing context.
739
750
  "research-project": {
740
- skills: { mode: "all" },
751
+ skills: skillPolicyForUnit("research-project"),
741
752
  knowledge: "scoped",
742
753
  memory: "prompt-relevant",
743
754
  codebaseMap: true,