gsd-pi 2.77.0 → 2.78.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 (798) hide show
  1. package/README.md +18 -36
  2. package/dist/claude-cli-check.js +5 -1
  3. package/dist/cli-web-branch.d.ts +1 -0
  4. package/dist/cli-web-branch.js +3 -0
  5. package/dist/cli.js +38 -2
  6. package/dist/extension-discovery.d.ts +6 -0
  7. package/dist/extension-discovery.js +37 -0
  8. package/dist/extension-registry.d.ts +3 -0
  9. package/dist/extension-sort.d.ts +18 -0
  10. package/dist/extension-sort.js +114 -0
  11. package/dist/extension-validator.d.ts +47 -0
  12. package/dist/extension-validator.js +127 -0
  13. package/dist/headless.js +49 -4
  14. package/dist/loader.js +35 -7
  15. package/dist/provider-migrations.d.ts +18 -0
  16. package/dist/provider-migrations.js +14 -0
  17. package/dist/resource-loader.d.ts +40 -0
  18. package/dist/resource-loader.js +32 -13
  19. package/dist/resources/extensions/browser-tools/capture.js +9 -0
  20. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  21. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  22. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  23. package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
  24. package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
  25. package/dist/resources/extensions/claude-code-cli/readiness.js +5 -1
  26. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +552 -67
  27. package/dist/resources/extensions/cmux/index.js +20 -0
  28. package/dist/resources/extensions/github-sync/templates.js +103 -0
  29. package/dist/resources/extensions/google-search/extension-manifest.json +5 -4
  30. package/dist/resources/extensions/google-search/index.js +3 -375
  31. package/dist/resources/extensions/gsd/abandon-detect.js +44 -0
  32. package/dist/resources/extensions/gsd/auto/loop.js +124 -2
  33. package/dist/resources/extensions/gsd/auto/phases.js +57 -39
  34. package/dist/resources/extensions/gsd/auto/resolve.js +24 -0
  35. package/dist/resources/extensions/gsd/auto/run-unit.js +10 -2
  36. package/dist/resources/extensions/gsd/auto/session.js +6 -2
  37. package/dist/resources/extensions/gsd/auto/turn-epoch.js +95 -0
  38. package/dist/resources/extensions/gsd/auto-dispatch.js +201 -38
  39. package/dist/resources/extensions/gsd/auto-loop.js +1 -1
  40. package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
  41. package/dist/resources/extensions/gsd/auto-post-unit.js +215 -64
  42. package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
  43. package/dist/resources/extensions/gsd/auto-recovery.js +210 -24
  44. package/dist/resources/extensions/gsd/auto-start.js +122 -30
  45. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +11 -5
  46. package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
  47. package/dist/resources/extensions/gsd/auto-unit-closeout.js +11 -2
  48. package/dist/resources/extensions/gsd/auto-worktree.js +180 -34
  49. package/dist/resources/extensions/gsd/auto.js +107 -35
  50. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +19 -1
  51. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
  52. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +5 -6
  53. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +11 -0
  54. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
  55. package/dist/resources/extensions/gsd/bootstrap/system-context.js +11 -6
  56. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
  57. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +31 -4
  58. package/dist/resources/extensions/gsd/commands-cmux.js +9 -6
  59. package/dist/resources/extensions/gsd/commands-extensions.js +634 -43
  60. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  61. package/dist/resources/extensions/gsd/component-types.js +69 -0
  62. package/dist/resources/extensions/gsd/context-store.js +23 -7
  63. package/dist/resources/extensions/gsd/detection.js +49 -1
  64. package/dist/resources/extensions/gsd/dispatch-guard.js +29 -3
  65. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  66. package/dist/resources/extensions/gsd/file-lock.js +49 -9
  67. package/dist/resources/extensions/gsd/forensics.js +106 -0
  68. package/dist/resources/extensions/gsd/gate-registry.js +2 -2
  69. package/dist/resources/extensions/gsd/git-constants.js +28 -1
  70. package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
  71. package/dist/resources/extensions/gsd/git-service.js +127 -2
  72. package/dist/resources/extensions/gsd/gitignore.js +1 -0
  73. package/dist/resources/extensions/gsd/gsd-db.js +6 -3
  74. package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -1
  75. package/dist/resources/extensions/gsd/guided-flow.js +39 -13
  76. package/dist/resources/extensions/gsd/journal.js +17 -2
  77. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  78. package/dist/resources/extensions/gsd/milestone-actions.js +15 -0
  79. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  80. package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
  81. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  82. package/dist/resources/extensions/gsd/model-router.js +6 -0
  83. package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
  84. package/dist/resources/extensions/gsd/notifications.js +30 -16
  85. package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
  86. package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
  87. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  88. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  89. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  90. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  91. package/dist/resources/extensions/gsd/prompts/system.md +1 -0
  92. package/dist/resources/extensions/gsd/reports.js +5 -4
  93. package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
  94. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  95. package/dist/resources/extensions/gsd/session-lock.js +19 -10
  96. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  97. package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
  98. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
  99. package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
  100. package/dist/resources/extensions/gsd/state.js +69 -58
  101. package/dist/resources/extensions/gsd/sync-lock.js +98 -42
  102. package/dist/resources/extensions/gsd/tools/complete-slice.js +21 -0
  103. package/dist/resources/extensions/gsd/tools/complete-task.js +31 -0
  104. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
  105. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  106. package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
  107. package/dist/resources/extensions/gsd/uok/audit.js +18 -2
  108. package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
  109. package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
  110. package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
  111. package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
  112. package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
  113. package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
  114. package/dist/resources/extensions/gsd/uok/plan-v2.js +10 -4
  115. package/dist/resources/extensions/gsd/uok/writer.js +82 -0
  116. package/dist/resources/extensions/gsd/workflow-logger.js +10 -2
  117. package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
  118. package/dist/resources/extensions/gsd/worktree-manager.js +86 -8
  119. package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
  120. package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
  121. package/dist/resources/extensions/mcp-client/auth.js +10 -1
  122. package/dist/resources/extensions/mcp-client/index.js +121 -10
  123. package/dist/resources/extensions/ollama/index.js +5 -1
  124. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  125. package/dist/resources/extensions/shared/cmux-events.js +12 -0
  126. package/dist/resources/extensions/shared/rtk-session-stats.js +1 -2
  127. package/dist/resources/skills/create-skill/SKILL.md +2 -2
  128. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
  129. package/dist/resources/skills/create-skill/workflows/audit-skill.md +4 -4
  130. package/dist/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
  131. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  132. package/dist/web/standalone/.next/BUILD_ID +1 -1
  133. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  134. package/dist/web/standalone/.next/build-manifest.json +3 -3
  135. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  136. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  137. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  143. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  144. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  145. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  146. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  147. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  148. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  149. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  150. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  151. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  152. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  154. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  156. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  158. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  160. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  162. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  164. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  166. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  168. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  170. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  172. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  174. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  176. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  178. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  180. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  182. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  184. package/dist/web/standalone/.next/server/app/api/notifications/route.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  186. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  188. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  190. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  192. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  194. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  195. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  196. package/dist/web/standalone/.next/server/app/api/session/events/route.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  198. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  199. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  200. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  201. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  202. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  203. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  204. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  205. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  206. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  207. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  208. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  209. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  210. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
  211. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  212. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  213. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  214. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  215. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  216. package/dist/web/standalone/.next/server/app/index.html +1 -1
  217. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  218. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  219. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  220. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  221. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  222. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  223. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  224. package/dist/web/standalone/.next/server/chunks/1926.js +1 -0
  225. package/dist/web/standalone/.next/server/chunks/6897.js +2 -2
  226. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  227. package/dist/web/standalone/.next/server/middleware-manifest.json +1 -1
  228. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  229. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  230. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  231. package/dist/web/standalone/.next/static/chunks/2826.e9f5195e91f9cad2.js +11 -0
  232. package/dist/web/standalone/.next/static/chunks/{webpack-5fc74f13a25fa1bb.js → webpack-2e68521d7c82f7c2.js} +1 -1
  233. package/package.json +17 -16
  234. package/packages/daemon/package.json +2 -2
  235. package/packages/daemon/src/logger.ts +4 -3
  236. package/packages/mcp-server/README.md +3 -3
  237. package/packages/mcp-server/dist/env-writer.d.ts +1 -0
  238. package/packages/mcp-server/dist/env-writer.d.ts.map +1 -1
  239. package/packages/mcp-server/dist/env-writer.js +74 -6
  240. package/packages/mcp-server/dist/env-writer.js.map +1 -1
  241. package/packages/mcp-server/dist/server.d.ts +24 -0
  242. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  243. package/packages/mcp-server/dist/server.js +111 -87
  244. package/packages/mcp-server/dist/server.js.map +1 -1
  245. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  246. package/packages/mcp-server/dist/workflow-tools.js +15 -6
  247. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  248. package/packages/mcp-server/package.json +7 -2
  249. package/packages/mcp-server/src/env-writer.test.ts +79 -1
  250. package/packages/mcp-server/src/env-writer.ts +76 -6
  251. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  252. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  253. package/packages/mcp-server/src/readers/readers.test.ts +5 -1
  254. package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
  255. package/packages/mcp-server/src/server.ts +158 -105
  256. package/packages/mcp-server/src/workflow-tools.test.ts +85 -0
  257. package/packages/mcp-server/src/workflow-tools.ts +19 -6
  258. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  259. package/packages/native/package.json +7 -2
  260. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  261. package/packages/native/src/__tests__/clipboard.test.mjs +69 -23
  262. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  263. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  264. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  265. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  266. package/packages/native/tsconfig.tsbuildinfo +1 -1
  267. package/packages/pi-agent-core/package.json +6 -1
  268. package/packages/pi-agent-core/src/agent-loop.test.ts +226 -31
  269. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  270. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  271. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
  272. package/packages/pi-ai/dist/models/capability-patches.js +9 -2
  273. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
  274. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  275. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  276. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  277. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  278. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  279. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  280. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  281. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  282. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  283. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  284. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  285. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  286. package/packages/pi-ai/dist/models.test.js +36 -11
  287. package/packages/pi-ai/dist/models.test.js.map +1 -1
  288. package/packages/pi-ai/package.json +6 -1
  289. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  290. package/packages/pi-ai/src/models/capability-patches.ts +10 -2
  291. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  292. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  293. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  294. package/packages/pi-ai/src/models.test.ts +48 -11
  295. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  296. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  297. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  298. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  299. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  300. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  301. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  302. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +25 -0
  303. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  304. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +105 -6
  305. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  306. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js +230 -28
  307. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js.map +1 -1
  308. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts +30 -2
  309. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts.map +1 -1
  310. package/packages/pi-coding-agent/dist/core/compaction/utils.js +113 -12
  311. package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts +1 -0
  313. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  314. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +29 -18
  315. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  316. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts +2 -0
  317. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts.map +1 -0
  318. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js +130 -0
  319. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js.map +1 -0
  320. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +56 -1
  321. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -1
  322. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +8 -15
  323. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -1
  324. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.d.ts +25 -0
  325. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.d.ts.map +1 -0
  326. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.js +109 -0
  327. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.js.map +1 -0
  328. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.d.ts +67 -0
  329. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.d.ts.map +1 -0
  330. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.js +167 -0
  331. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.js.map +1 -0
  332. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +8 -2
  333. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  334. package/packages/pi-coding-agent/dist/core/extensions/loader.js +85 -8
  335. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  336. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
  337. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  338. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  339. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +41 -4
  340. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  341. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +19 -2
  342. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  343. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  344. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  345. package/packages/pi-coding-agent/dist/core/resource-loader.js +1 -1
  346. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  347. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  348. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  349. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  350. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  351. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  352. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  353. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  354. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  355. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  356. package/packages/pi-coding-agent/dist/core/sdk.d.ts +1 -0
  357. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  358. package/packages/pi-coding-agent/dist/core/sdk.js +4 -1
  359. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  360. package/packages/pi-coding-agent/dist/core/sdk.test.js +19 -1
  361. package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -1
  362. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  363. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  364. package/packages/pi-coding-agent/dist/core/system-prompt.js +19 -5
  365. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  366. package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js +2 -1
  367. package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js.map +1 -1
  368. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  369. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  370. package/packages/pi-coding-agent/dist/index.js +1 -0
  371. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  372. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js +15 -6
  373. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js.map +1 -1
  374. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
  375. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  376. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  377. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  378. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  379. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -5
  380. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  381. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +7 -1
  382. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  383. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +31 -9
  384. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
  385. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  386. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
  387. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  388. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  389. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
  390. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  391. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +139 -0
  392. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  393. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
  394. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  395. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  396. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  397. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  398. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
  399. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  400. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  401. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  402. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  403. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  404. package/packages/pi-coding-agent/package.json +6 -1
  405. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  406. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  407. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  408. package/packages/pi-coding-agent/src/core/compaction/compaction.test.ts +368 -28
  409. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +122 -6
  410. package/packages/pi-coding-agent/src/core/compaction/utils.ts +111 -13
  411. package/packages/pi-coding-agent/src/core/compaction-orchestrator.test.ts +154 -0
  412. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +32 -18
  413. package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +68 -1
  414. package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +9 -18
  415. package/packages/pi-coding-agent/src/core/extensions/extension-discovery.ts +119 -0
  416. package/packages/pi-coding-agent/src/core/extensions/extension-registry.ts +222 -0
  417. package/packages/pi-coding-agent/src/core/extensions/loader.ts +82 -11
  418. package/packages/pi-coding-agent/src/core/extensions/types.ts +8 -0
  419. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +48 -4
  420. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +22 -2
  421. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  422. package/packages/pi-coding-agent/src/core/resource-loader.ts +1 -1
  423. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  424. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  425. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  426. package/packages/pi-coding-agent/src/core/sdk.test.ts +25 -1
  427. package/packages/pi-coding-agent/src/core/sdk.ts +10 -3
  428. package/packages/pi-coding-agent/src/core/system-prompt.ts +38 -4
  429. package/packages/pi-coding-agent/src/core/tools/path-utils.test.ts +2 -1
  430. package/packages/pi-coding-agent/src/index.ts +1 -0
  431. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +17 -7
  432. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
  433. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  434. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +14 -5
  435. package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +45 -11
  436. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
  437. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +160 -1
  438. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
  439. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
  440. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
  441. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  442. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  443. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +31 -14
  444. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  445. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  446. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  447. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +51 -6
  448. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  449. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  450. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  451. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  452. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  453. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  454. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  455. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  456. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  457. package/packages/pi-tui/dist/components/editor.d.ts +14 -0
  458. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  459. package/packages/pi-tui/dist/components/editor.js +19 -0
  460. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  461. package/packages/pi-tui/dist/components/image.test.js +6 -5
  462. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  463. package/packages/pi-tui/dist/editor-component.d.ts +2 -0
  464. package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
  465. package/packages/pi-tui/dist/editor-component.js.map +1 -1
  466. package/packages/pi-tui/dist/stdin-buffer.d.ts +7 -0
  467. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  468. package/packages/pi-tui/dist/stdin-buffer.js +20 -0
  469. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  470. package/packages/pi-tui/package.json +6 -1
  471. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +46 -15
  472. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  473. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +62 -6
  474. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  475. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  476. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  477. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  478. package/packages/pi-tui/src/components/editor.ts +22 -0
  479. package/packages/pi-tui/src/components/image.test.ts +10 -5
  480. package/packages/pi-tui/src/editor-component.ts +3 -0
  481. package/packages/pi-tui/src/stdin-buffer.ts +26 -0
  482. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  483. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  484. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  485. package/packages/rpc-client/package.json +6 -1
  486. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  487. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  488. package/pkg/package.json +1 -1
  489. package/scripts/install.js +526 -0
  490. package/scripts/lib/workspace-manifest.cjs +86 -0
  491. package/scripts/link-workspace-packages.cjs +5 -17
  492. package/scripts/postinstall.js +9 -178
  493. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  494. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  495. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  496. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  497. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  498. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  499. package/src/resources/extensions/claude-code-cli/readiness.ts +5 -1
  500. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +602 -73
  501. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +1028 -91
  502. package/src/resources/extensions/cmux/index.ts +35 -10
  503. package/src/resources/extensions/github-sync/templates.ts +151 -0
  504. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  505. package/src/resources/extensions/github-sync/tests/templates.test.ts +92 -1
  506. package/src/resources/extensions/google-search/extension-manifest.json +5 -4
  507. package/src/resources/extensions/google-search/index.ts +9 -470
  508. package/src/resources/extensions/gsd/abandon-detect.ts +62 -0
  509. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -1
  510. package/src/resources/extensions/gsd/auto/loop.ts +142 -2
  511. package/src/resources/extensions/gsd/auto/phases.ts +62 -38
  512. package/src/resources/extensions/gsd/auto/resolve.ts +29 -0
  513. package/src/resources/extensions/gsd/auto/run-unit.ts +16 -2
  514. package/src/resources/extensions/gsd/auto/session.ts +7 -2
  515. package/src/resources/extensions/gsd/auto/turn-epoch.ts +108 -0
  516. package/src/resources/extensions/gsd/auto/types.ts +1 -1
  517. package/src/resources/extensions/gsd/auto-dispatch.ts +214 -37
  518. package/src/resources/extensions/gsd/auto-loop.ts +1 -1
  519. package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
  520. package/src/resources/extensions/gsd/auto-post-unit.ts +226 -73
  521. package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
  522. package/src/resources/extensions/gsd/auto-recovery.ts +240 -25
  523. package/src/resources/extensions/gsd/auto-start.ts +146 -14
  524. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -5
  525. package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
  526. package/src/resources/extensions/gsd/auto-unit-closeout.ts +14 -3
  527. package/src/resources/extensions/gsd/auto-worktree.ts +190 -31
  528. package/src/resources/extensions/gsd/auto.ts +127 -41
  529. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +20 -1
  530. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
  531. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +6 -6
  532. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +11 -0
  533. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
  534. package/src/resources/extensions/gsd/bootstrap/system-context.ts +13 -9
  535. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
  536. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +27 -8
  537. package/src/resources/extensions/gsd/commands-cmux.ts +10 -6
  538. package/src/resources/extensions/gsd/commands-extensions.ts +747 -41
  539. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  540. package/src/resources/extensions/gsd/component-types.ts +362 -0
  541. package/src/resources/extensions/gsd/context-store.ts +25 -8
  542. package/src/resources/extensions/gsd/detection.ts +58 -1
  543. package/src/resources/extensions/gsd/dispatch-guard.ts +26 -2
  544. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  545. package/src/resources/extensions/gsd/file-lock.ts +84 -11
  546. package/src/resources/extensions/gsd/forensics.ts +118 -1
  547. package/src/resources/extensions/gsd/gate-registry.ts +2 -2
  548. package/src/resources/extensions/gsd/git-constants.ts +30 -1
  549. package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
  550. package/src/resources/extensions/gsd/git-service.ts +150 -2
  551. package/src/resources/extensions/gsd/gitignore.ts +1 -0
  552. package/src/resources/extensions/gsd/gsd-db.ts +6 -3
  553. package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -1
  554. package/src/resources/extensions/gsd/guided-flow.ts +57 -14
  555. package/src/resources/extensions/gsd/journal.ts +38 -3
  556. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  557. package/src/resources/extensions/gsd/milestone-actions.ts +18 -0
  558. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  559. package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
  560. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  561. package/src/resources/extensions/gsd/model-router.ts +6 -0
  562. package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
  563. package/src/resources/extensions/gsd/notifications.ts +27 -15
  564. package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
  565. package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
  566. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  567. package/src/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  568. package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  569. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  570. package/src/resources/extensions/gsd/prompts/system.md +1 -0
  571. package/src/resources/extensions/gsd/reports.ts +5 -4
  572. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
  573. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  574. package/src/resources/extensions/gsd/session-lock.ts +20 -10
  575. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  576. package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
  577. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
  578. package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
  579. package/src/resources/extensions/gsd/state.ts +76 -66
  580. package/src/resources/extensions/gsd/sync-lock.ts +97 -39
  581. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
  582. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
  583. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
  584. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
  585. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +135 -285
  586. package/src/resources/extensions/gsd/tests/auto-mode-guards.test.ts +79 -0
  587. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
  588. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
  589. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
  590. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +166 -0
  591. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
  592. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
  593. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +64 -0
  594. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
  595. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  596. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
  597. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
  598. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
  599. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
  600. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  601. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
  602. package/src/resources/extensions/gsd/tests/cmux.test.ts +5 -9
  603. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  604. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
  605. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  606. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
  607. package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
  608. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  609. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  610. package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
  611. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
  612. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
  613. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +159 -0
  614. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
  615. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
  616. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
  617. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
  618. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -4
  619. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
  620. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
  621. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +14 -9
  622. package/src/resources/extensions/gsd/tests/dispatch-guard-summary-db-mismatch.test.ts +77 -0
  623. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
  624. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
  625. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
  626. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
  627. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
  628. package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
  629. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  630. package/src/resources/extensions/gsd/tests/file-lock.test.ts +86 -12
  631. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
  632. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
  633. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
  634. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +131 -0
  635. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
  636. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  637. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
  638. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
  639. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +30 -0
  640. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  641. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
  642. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  643. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
  644. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
  645. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
  646. package/src/resources/extensions/gsd/tests/integration/worktree-e2e.test.ts +11 -0
  647. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
  648. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  649. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +64 -0
  650. package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
  651. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +47 -0
  652. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  653. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
  654. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  655. package/src/resources/extensions/gsd/tests/milestone-status-authoritative.test.ts +3 -3
  656. package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
  657. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +4 -2
  658. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  659. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  660. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
  661. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  662. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
  663. package/src/resources/extensions/gsd/tests/parallel-commit-scope.test.ts +5 -0
  664. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
  665. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +150 -0
  666. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  667. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
  668. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
  669. package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
  670. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
  671. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +54 -41
  672. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +213 -0
  673. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
  674. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
  675. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +13 -7
  676. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
  677. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  678. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  679. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  680. package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +170 -0
  681. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  682. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
  683. package/src/resources/extensions/gsd/tests/rewrite-docs-abandon-detect.test.ts +195 -0
  684. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  685. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  686. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
  687. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
  688. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  689. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
  690. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  691. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  692. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
  693. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
  694. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
  695. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
  696. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
  697. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +29 -5
  698. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
  699. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
  700. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  701. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +2 -2
  702. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
  703. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  704. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
  705. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
  706. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
  707. package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
  708. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
  709. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
  710. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
  711. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +50 -2
  712. package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +162 -0
  713. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  714. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
  715. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
  716. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
  717. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
  718. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  719. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
  720. package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
  721. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +19 -2
  722. package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
  723. package/src/resources/extensions/gsd/tests/validate-extension-package.test.ts +168 -0
  724. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +139 -5
  725. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
  726. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  727. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  728. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  729. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +25 -2
  730. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  731. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  732. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  733. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  734. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  735. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
  736. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
  737. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
  738. package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
  739. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  740. package/src/resources/extensions/gsd/tools/complete-slice.ts +38 -0
  741. package/src/resources/extensions/gsd/tools/complete-task.ts +49 -0
  742. package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
  743. package/src/resources/extensions/gsd/types.ts +3 -3
  744. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  745. package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
  746. package/src/resources/extensions/gsd/uok/audit.ts +20 -2
  747. package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
  748. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
  749. package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
  750. package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
  751. package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
  752. package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
  753. package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
  754. package/src/resources/extensions/gsd/uok/plan-v2.ts +13 -5
  755. package/src/resources/extensions/gsd/uok/writer.ts +113 -0
  756. package/src/resources/extensions/gsd/workflow-logger.ts +22 -3
  757. package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
  758. package/src/resources/extensions/gsd/worktree-manager.ts +109 -7
  759. package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
  760. package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
  761. package/src/resources/extensions/mcp-client/auth.ts +12 -1
  762. package/src/resources/extensions/mcp-client/index.ts +132 -11
  763. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  764. package/src/resources/extensions/ollama/index.ts +5 -1
  765. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  766. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  767. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  768. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  769. package/src/resources/extensions/shared/cmux-events.ts +59 -0
  770. package/src/resources/extensions/shared/rtk-session-stats.ts +1 -2
  771. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  772. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  773. package/src/resources/skills/create-skill/SKILL.md +2 -2
  774. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
  775. package/src/resources/skills/create-skill/workflows/audit-skill.md +4 -4
  776. package/src/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
  777. package/dist/web/standalone/.next/server/chunks/7461.js +0 -1
  778. package/dist/web/standalone/.next/static/chunks/2826.e59e8578e2e28639.js +0 -9
  779. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  780. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  781. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  782. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  783. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  784. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
  785. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -142
  786. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  787. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  788. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  789. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  790. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  791. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
  792. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  793. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  794. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  795. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
  796. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
  797. /package/dist/web/standalone/.next/static/{pV-mPo7rYGb5JBC09C8GG → C1zT2kEfoLhDdbWPWKrXd}/_buildManifest.js +0 -0
  798. /package/dist/web/standalone/.next/static/{pV-mPo7rYGb5JBC09C8GG → C1zT2kEfoLhDdbWPWKrXd}/_ssgManifest.js +0 -0
@@ -243,6 +243,35 @@ describe('session-lock-regression', async () => {
243
243
  }
244
244
  }
245
245
 
246
+ // ─── 7d. Releasing after ownership loss preserves newer owner ─────────
247
+ test('releaseSessionLock preserves newer owner after PID mismatch', (t) => {
248
+ const base = mkdtempSync(join(tmpdir(), 'gsd-session-lock-'));
249
+ mkdirSync(join(base, '.gsd'), { recursive: true });
250
+ t.after(() => {
251
+ rmSync(base, { recursive: true, force: true });
252
+ });
253
+
254
+ const acquired = acquireSessionLock(base);
255
+ assert.ok(acquired.acquired, 'initial lock acquired');
256
+
257
+ const lockFile = join(gsdRoot(base), 'auto.lock');
258
+ const newerOwner = {
259
+ pid: process.pid + 1000,
260
+ startedAt: new Date().toISOString(),
261
+ unitType: 'execute-task',
262
+ unitId: 'M001/S01/T02',
263
+ unitStartedAt: new Date().toISOString(),
264
+ };
265
+ writeFileSync(lockFile, JSON.stringify(newerOwner, null, 2));
266
+
267
+ releaseSessionLock(base);
268
+
269
+ assert.ok(existsSync(lockFile), 'foreign lock file must not be deleted by stale owner release');
270
+ const after = JSON.parse(readFileSync(lockFile, 'utf-8'));
271
+ assert.deepStrictEqual(after.pid, newerOwner.pid, 'newer owner PID is preserved');
272
+ assert.deepStrictEqual(after.unitId, newerOwner.unitId, 'newer owner metadata is preserved');
273
+ });
274
+
246
275
  // ─── 8. Acquire after release is possible ─────────────────────────────
247
276
  console.log('\n=== 8. acquire after release → re-acquirable ===');
248
277
  {
@@ -11,6 +11,7 @@ import assert from "node:assert/strict";
11
11
  import { readFileSync } from "node:fs";
12
12
  import { join, dirname } from "node:path";
13
13
  import { fileURLToPath } from "node:url";
14
+ import { extractSourceRegion } from "./test-helpers.ts";
14
15
 
15
16
  const __dirname = dirname(fileURLToPath(import.meta.url));
16
17
  const SESSION_TS_PATH = join(__dirname, "..", "auto", "session.ts");
@@ -52,7 +53,7 @@ test("SidecarItem type is exported from session.ts", () => {
52
53
  test("SidecarItem has required kind field with hook/triage/quick-task union", () => {
53
54
  const source = getSessionTsSource();
54
55
  const ifaceIdx = source.indexOf("export interface SidecarItem");
55
- const ifaceBlock = source.slice(ifaceIdx, ifaceIdx + 500);
56
+ const ifaceBlock = extractSourceRegion(source, "export interface SidecarItem");
56
57
  assert.ok(
57
58
  ifaceBlock.includes('"hook"') && ifaceBlock.includes('"triage"') && ifaceBlock.includes('"quick-task"'),
58
59
  "SidecarItem.kind must be a union of 'hook' | 'triage' | 'quick-task'",
@@ -77,7 +78,7 @@ test("AutoSession resets sidecarQueue in reset()", () => {
77
78
  const source = getSessionTsSource();
78
79
  const resetIdx = source.indexOf("reset(): void");
79
80
  assert.ok(resetIdx > -1, "AutoSession must have a reset() method");
80
- const resetBlock = source.slice(resetIdx, resetIdx + 3000);
81
+ const resetBlock = extractSourceRegion(source, "reset(): void");
81
82
  assert.ok(
82
83
  resetBlock.includes("sidecarQueue"),
83
84
  "reset() must clear sidecarQueue",
@@ -6,6 +6,13 @@
6
6
  * Two tests:
7
7
  * 1. Auto-mode files must have zero empty catch blocks (fully migrated).
8
8
  * 2. All GSD files must not use raw stderr/console in catch blocks.
9
+ *
10
+ * Implementation note (#4836): the previous implementation walked every
11
+ * `{` / `}` character in the source to infer catch-block boundaries. That
12
+ * ignored string literals, template interpolations, regexes, and comments,
13
+ * producing both false positives and false negatives. The current
14
+ * implementation uses the TypeScript compiler API to walk real
15
+ * `CatchClause` nodes, so lexical accidents cannot flip the verdict.
9
16
  */
10
17
 
11
18
  import { describe, test } from "node:test";
@@ -13,6 +20,7 @@ import assert from "node:assert/strict";
13
20
  import { readFileSync, readdirSync, statSync } from "node:fs";
14
21
  import { join, dirname, relative } from "node:path";
15
22
  import { fileURLToPath } from "node:url";
23
+ import ts from "typescript";
16
24
 
17
25
  const __dirname = dirname(fileURLToPath(import.meta.url));
18
26
  const gsdDir = join(__dirname, "..");
@@ -73,12 +81,6 @@ const MIGRATED_FILES = new Set([
73
81
  "auto-verification.ts",
74
82
  ]);
75
83
 
76
- /** Patterns that indicate a catch block already uses workflow-logger */
77
- const LOGGER_PATTERNS = [
78
- /logWarning\s*\(/,
79
- /logError\s*\(/,
80
- ];
81
-
82
84
  function getAutoModeFiles(): string[] {
83
85
  const files: string[] = [];
84
86
 
@@ -124,103 +126,61 @@ function getGsdSourceFiles(): string[] {
124
126
  return files;
125
127
  }
126
128
 
127
- /**
128
- * Scan a file for empty catch blocks — catches whose body contains
129
- * only whitespace and/or comments but no executable statements.
130
- */
131
- function findEmptyCatches(filePath: string): Array<{ line: number; text: string }> {
129
+ function parseSourceFile(filePath: string): ts.SourceFile {
132
130
  const content = readFileSync(filePath, "utf-8");
133
- const lines = content.split("\n");
134
- const results: Array<{ line: number; text: string }> = [];
135
-
136
- for (let i = 0; i < lines.length; i++) {
137
- const line = lines[i];
138
-
139
- // Match catch block opening
140
- if (!/\}\s*catch\s*(\([^)]*\))?\s*\{/.test(line)) continue;
141
-
142
- // Inline single-line catch: } catch { ... }
143
- const inlineMatch = line.match(/\}\s*catch\s*(\([^)]*\))?\s*\{(.*)\}\s*;?\s*$/);
144
- if (inlineMatch) {
145
- const body = inlineMatch[2].trim();
146
- const stripped = body.replace(/\/\*.*?\*\//g, "").replace(/\/\/.*/g, "").trim();
147
- if (!stripped) {
148
- results.push({ line: i + 1, text: line.trim() });
149
- }
150
- continue;
151
- }
152
-
153
- // Multi-line catch — scan until matching }
154
- let j = i + 1;
155
- let depth = 1;
156
- const bodyLines: string[] = [];
157
- while (j < lines.length && depth > 0) {
158
- for (const ch of lines[j]) {
159
- if (ch === "{") depth++;
160
- else if (ch === "}") depth--;
161
- }
162
- bodyLines.push(lines[j].trim());
163
- j++;
164
- }
131
+ return ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, /*setParentNodes*/ true, ts.ScriptKind.TS);
132
+ }
165
133
 
166
- const meaningful = bodyLines.slice(0, -1).filter(
167
- (l) => l && !l.startsWith("//") && !l.startsWith("/*") && !l.startsWith("*") && l !== "}",
168
- );
134
+ function forEachCatchClause(sf: ts.SourceFile, visit: (cc: ts.CatchClause) => void): void {
135
+ const walk = (node: ts.Node): void => {
136
+ if (ts.isCatchClause(node)) visit(node);
137
+ ts.forEachChild(node, walk);
138
+ };
139
+ walk(sf);
140
+ }
169
141
 
170
- if (meaningful.length === 0) {
171
- results.push({ line: i + 1, text: line.trim() });
142
+ /**
143
+ * A catch block is "empty" if its Block has zero statements. Comments
144
+ * inside the block are trivia and are not Statement nodes, so a
145
+ * comment-only body still counts as empty — matching the intent of the
146
+ * old regex check but without its lexical blind spots.
147
+ */
148
+ function findEmptyCatches(filePath: string): Array<{ line: number }> {
149
+ const sf = parseSourceFile(filePath);
150
+ const results: Array<{ line: number }> = [];
151
+ forEachCatchClause(sf, (cc) => {
152
+ if (cc.block.statements.length === 0) {
153
+ const { line } = sf.getLineAndCharacterOfPosition(cc.getStart(sf));
154
+ results.push({ line: line + 1 });
172
155
  }
173
- }
174
-
156
+ });
175
157
  return results;
176
158
  }
177
159
 
178
160
  /**
179
- * Scan a file for catch blocks that use raw process.stderr.write or
180
- * console.error/warn instead of workflow-logger.
161
+ * A catch block uses "raw stderr/console" if its body text calls
162
+ * process.stderr.write or console.error/warn *and* does NOT also call
163
+ * logWarning / logError.
164
+ *
165
+ * We test against the block's statement subtree text — derived from the
166
+ * AST node range, not a naive substring of the whole file — so string
167
+ * literals outside the block can never leak into the decision.
181
168
  */
182
- function findRawStderrCatches(filePath: string): Array<{ line: number; text: string }> {
183
- const content = readFileSync(filePath, "utf-8");
184
- const lines = content.split("\n");
185
- const results: Array<{ line: number; text: string }> = [];
186
-
187
- for (let i = 0; i < lines.length; i++) {
188
- const line = lines[i];
189
- if (!/\}\s*catch\s*(\([^)]*\))?\s*\{/.test(line)) continue;
190
-
191
- // Inline single-line catch
192
- const inlineMatch = line.match(/\}\s*catch\s*(\([^)]*\))?\s*\{(.*)\}\s*;?\s*$/);
193
- if (inlineMatch) {
194
- const body = inlineMatch[2];
195
- if (!LOGGER_PATTERNS.some((p) => p.test(body))) {
196
- if (/process\.stderr\.write/.test(body) || /console\.(error|warn)/.test(body)) {
197
- results.push({ line: i + 1, text: line.trim() });
198
- }
199
- }
200
- continue;
169
+ function findRawStderrCatches(filePath: string): Array<{ line: number }> {
170
+ const sf = parseSourceFile(filePath);
171
+ const results: Array<{ line: number }> = [];
172
+ forEachCatchClause(sf, (cc) => {
173
+ const bodyText = cc.block.getText(sf);
174
+ const usesLogger = /\blogWarning\s*\(|\blogError\s*\(/.test(bodyText);
175
+ if (usesLogger) return;
176
+ if (
177
+ /\bprocess\.stderr\.write\b/.test(bodyText) ||
178
+ /\bconsole\.(?:error|warn)\b/.test(bodyText)
179
+ ) {
180
+ const { line } = sf.getLineAndCharacterOfPosition(cc.getStart(sf));
181
+ results.push({ line: line + 1 });
201
182
  }
202
-
203
- // Multi-line catch
204
- let j = i + 1;
205
- let depth = 1;
206
- const bodyLines: string[] = [];
207
- while (j < lines.length && depth > 0) {
208
- for (const ch of lines[j]) {
209
- if (ch === "{") depth++;
210
- else if (ch === "}") depth--;
211
- }
212
- bodyLines.push(lines[j]);
213
- j++;
214
- }
215
-
216
- const bodyText = bodyLines.slice(0, -1).join("\n");
217
- if (!LOGGER_PATTERNS.some((p) => p.test(bodyText))) {
218
- if (/process\.stderr\.write/.test(bodyText) || /console\.(error|warn)/.test(bodyText)) {
219
- results.push({ line: i + 1, text: line.trim() });
220
- }
221
- }
222
- }
223
-
183
+ });
224
184
  return results;
225
185
  }
226
186
 
@@ -248,7 +208,7 @@ describe("workflow-logger coverage (#3348)", () => {
248
208
 
249
209
  const empties = findEmptyCatches(file);
250
210
  for (const empty of empties) {
251
- violations.push(`${rel}:${empty.line} — ${empty.text}`);
211
+ violations.push(`${rel}:${empty.line}`);
252
212
  }
253
213
  }
254
214
 
@@ -271,7 +231,7 @@ describe("workflow-logger coverage (#3348)", () => {
271
231
 
272
232
  const issues = findRawStderrCatches(file);
273
233
  for (const issue of issues) {
274
- violations.push(`${rel}:${issue.line} — ${issue.text}`);
234
+ violations.push(`${rel}:${issue.line}`);
275
235
  }
276
236
  }
277
237
 
@@ -0,0 +1,158 @@
1
+ /**
2
+ * single-writer-v3-tool-surface — Verifies the MCP tool surface that closes
3
+ * the remaining gaps from .plans/single-writer-engine-v3-control-plane.md:
4
+ *
5
+ * 1. The 8 mutating workflow tools (plan/complete/replan/reassess) expose
6
+ * actorName + triggerReason as optional schema params, so an agent can
7
+ * self-identify (Stream 2: actor identity passthrough).
8
+ *
9
+ * 2. The 3 reversibility handlers (reopen-task/slice/milestone) are
10
+ * registered as MCP tools with both canonical and alias names
11
+ * (Stream 3: reversibility tools).
12
+ *
13
+ * 3. The reopen tools accept the documented core params plus optional
14
+ * reason/actorName/triggerReason without rejecting valid payloads.
15
+ */
16
+
17
+ import { test } from "node:test";
18
+ import assert from "node:assert/strict";
19
+ import { registerDbTools } from "../bootstrap/db-tools.ts";
20
+ import { Value } from "@sinclair/typebox/value";
21
+
22
+ function makeMockPi() {
23
+ const tools: any[] = [];
24
+ return {
25
+ registerTool: (tool: any) => tools.push(tool),
26
+ tools,
27
+ } as any;
28
+ }
29
+
30
+ const pi = makeMockPi();
31
+ registerDbTools(pi);
32
+
33
+ function getTool(name: string) {
34
+ return pi.tools.find((t: any) => t.name === name);
35
+ }
36
+
37
+ function getRequiredProps(tool: any): string[] {
38
+ return tool.parameters.required ?? [];
39
+ }
40
+
41
+ function getProps(tool: any): string[] {
42
+ return Object.keys(tool.parameters.properties ?? {});
43
+ }
44
+
45
+ // ─── Stream 2: actor identity exposure on 8 mutating workflow tools ─────────
46
+
47
+ const ACTOR_TOOLS = [
48
+ "gsd_plan_milestone",
49
+ "gsd_plan_slice",
50
+ "gsd_plan_task",
51
+ "gsd_task_complete",
52
+ "gsd_slice_complete",
53
+ "gsd_complete_milestone",
54
+ "gsd_replan_slice",
55
+ "gsd_reassess_roadmap",
56
+ ];
57
+
58
+ for (const name of ACTOR_TOOLS) {
59
+ test(`${name} — exposes actorName and triggerReason as optional`, () => {
60
+ const tool = getTool(name);
61
+ assert.ok(tool, `${name} must be registered`);
62
+
63
+ const props = new Set(getProps(tool));
64
+ const required = new Set(getRequiredProps(tool));
65
+
66
+ assert.ok(props.has("actorName"), `${name} must expose actorName param`);
67
+ assert.ok(props.has("triggerReason"), `${name} must expose triggerReason param`);
68
+ assert.ok(!required.has("actorName"), `${name}.actorName must be optional`);
69
+ assert.ok(!required.has("triggerReason"), `${name}.triggerReason must be optional`);
70
+ });
71
+ }
72
+
73
+ // ─── Stream 3: reopen tools registered with canonical + alias names ─────────
74
+
75
+ const REOPEN_TOOLS = [
76
+ { canonical: "gsd_task_reopen", alias: "gsd_reopen_task" },
77
+ { canonical: "gsd_slice_reopen", alias: "gsd_reopen_slice" },
78
+ { canonical: "gsd_milestone_reopen", alias: "gsd_reopen_milestone" },
79
+ ];
80
+
81
+ for (const { canonical, alias } of REOPEN_TOOLS) {
82
+ test(`${canonical} — registered with alias ${alias}`, () => {
83
+ const canonicalTool = getTool(canonical);
84
+ const aliasTool = getTool(alias);
85
+ assert.ok(canonicalTool, `${canonical} must be registered`);
86
+ assert.ok(aliasTool, `${alias} must be registered as alias`);
87
+ assert.ok(typeof canonicalTool.execute === "function", `${canonical} must have an execute function`);
88
+ assert.ok(typeof aliasTool.execute === "function", `${alias} must have an execute function`);
89
+ });
90
+ }
91
+
92
+ // ─── Reopen tool schemas accept minimal core params ──────────────────────────
93
+
94
+ test("gsd_task_reopen — validates with only milestoneId/sliceId/taskId", () => {
95
+ const tool = getTool("gsd_task_reopen");
96
+ assert.ok(tool);
97
+ const minimal = { milestoneId: "M001", sliceId: "S01", taskId: "T01" };
98
+ const errors = [...Value.Errors(tool.parameters, minimal)];
99
+ assert.strictEqual(errors.length, 0, `core params should validate; got: ${errors.map(e => `${e.path}: ${e.message}`).join(", ")}`);
100
+ });
101
+
102
+ test("gsd_task_reopen — accepts reason + actor fields", () => {
103
+ const tool = getTool("gsd_task_reopen");
104
+ assert.ok(tool);
105
+ const full = {
106
+ milestoneId: "M001",
107
+ sliceId: "S01",
108
+ taskId: "T01",
109
+ reason: "regression discovered",
110
+ actorName: "executor-01",
111
+ triggerReason: "post-completion verification failure",
112
+ };
113
+ const errors = [...Value.Errors(tool.parameters, full)];
114
+ assert.strictEqual(errors.length, 0, `full payload should validate; got: ${errors.map(e => `${e.path}: ${e.message}`).join(", ")}`);
115
+ });
116
+
117
+ test("gsd_slice_reopen — validates with only milestoneId/sliceId", () => {
118
+ const tool = getTool("gsd_slice_reopen");
119
+ assert.ok(tool);
120
+ const minimal = { milestoneId: "M001", sliceId: "S01" };
121
+ const errors = [...Value.Errors(tool.parameters, minimal)];
122
+ assert.strictEqual(errors.length, 0, `core params should validate; got: ${errors.map(e => `${e.path}: ${e.message}`).join(", ")}`);
123
+ });
124
+
125
+ test("gsd_milestone_reopen — validates with only milestoneId", () => {
126
+ const tool = getTool("gsd_milestone_reopen");
127
+ assert.ok(tool);
128
+ const minimal = { milestoneId: "M001" };
129
+ const errors = [...Value.Errors(tool.parameters, minimal)];
130
+ assert.strictEqual(errors.length, 0, `core params should validate; got: ${errors.map(e => `${e.path}: ${e.message}`).join(", ")}`);
131
+ });
132
+
133
+ // ─── MCP_WORKFLOW_TOOL_SURFACE includes the reopen tools ─────────────────────
134
+
135
+ test("workflow MCP surface includes the reopen tools", async () => {
136
+ const { getWorkflowTransportSupportError } = await import("../workflow-mcp.ts");
137
+ // The error builder reports tools that are required-but-missing from the surface.
138
+ // If the reopen tools are missing from the surface, the error message will list them.
139
+ // We probe by asking for a "claude-code" provider (which uses externalCli + local://)
140
+ // with our reopen tools as required, and assert the surface has them.
141
+ const err = getWorkflowTransportSupportError(
142
+ "claude-code",
143
+ ["gsd_task_reopen", "gsd_slice_reopen", "gsd_milestone_reopen"],
144
+ { authMode: "externalCli", baseUrl: "local://test" },
145
+ );
146
+
147
+ // err is null when surface satisfies required tools, OR a non-null error mentioning
148
+ // unrelated infra setup (like "workflow MCP server not configured"). Either way,
149
+ // the error must NOT name our three reopen tools as missing from the surface.
150
+ if (err !== null) {
151
+ assert.ok(
152
+ !err.includes("gsd_task_reopen") &&
153
+ !err.includes("gsd_slice_reopen") &&
154
+ !err.includes("gsd_milestone_reopen"),
155
+ `surface should include all three reopen tools, but error reports them missing: ${err}`,
156
+ );
157
+ }
158
+ });
@@ -4,7 +4,13 @@ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
  import { loadSkills } from "@gsd/pi-coding-agent";
7
- import { buildSkillActivationBlock } from "../auto-prompts.js";
7
+ import {
8
+ buildPlanMilestonePrompt,
9
+ buildResearchMilestonePrompt,
10
+ buildSkillActivationBlock,
11
+ } from "../auto-prompts.js";
12
+ import { warnIfManifestHasMissingSkills } from "../skill-manifest.js";
13
+ import { _resetLogs, drainLogs, setStderrLoggingEnabled } from "../workflow-logger.js";
8
14
  import type { GSDPreferences } from "../preferences.js";
9
15
 
10
16
  function makeTempBase(): string {
@@ -25,6 +31,11 @@ function loadOnlyTestSkills(base: string): void {
25
31
  loadSkills({ cwd: base, includeDefaults: false, skillPaths: [join(base, "skills")] });
26
32
  }
27
33
 
34
+ function writeProjectPreferences(base: string, preferences: string): void {
35
+ mkdirSync(join(base, ".gsd"), { recursive: true });
36
+ writeFileSync(join(base, ".gsd", "PREFERENCES.md"), `---\n${preferences}---\n`);
37
+ }
38
+
28
39
  function buildBlock(
29
40
  base: string,
30
41
  params: Partial<Parameters<typeof buildSkillActivationBlock>[0]> = {},
@@ -231,3 +242,111 @@ test("buildSkillActivationBlock allows valid skill names and rejects invalid one
231
242
  cleanup(base);
232
243
  }
233
244
  });
245
+
246
+ // ─── Per-unit-type skill manifest (RFC #4779) ─────────────────────────────────
247
+
248
+ test("buildSkillActivationBlock: explicit always_use_skills bypass the unit-type manifest", () => {
249
+ const base = makeTempBase();
250
+ try {
251
+ // write-docs is in the research-milestone manifest; swiftui is not.
252
+ // Both are in always_use_skills — a user-explicit source — so BOTH
253
+ // should activate regardless of the manifest. User intent wins over
254
+ // unit-type defaults. See RFC #4779 and skill-manifest.ts rationale.
255
+ writeSkill(base, "write-docs", "Use when writing docs or RFCs.");
256
+ writeSkill(base, "swiftui", "Use for SwiftUI views.");
257
+ loadOnlyTestSkills(base);
258
+
259
+ const result = buildBlock(base, { unitType: "research-milestone" }, {
260
+ always_use_skills: ["write-docs", "swiftui"],
261
+ });
262
+
263
+ assert.match(result, /Call Skill\(\{ skill: 'write-docs' \}\)/);
264
+ assert.match(result, /Call Skill\(\{ skill: 'swiftui' \}\)/);
265
+ } finally {
266
+ cleanup(base);
267
+ }
268
+ });
269
+
270
+ test("buildSkillActivationBlock falls through to all skills for unknown unit type", () => {
271
+ const base = makeTempBase();
272
+ try {
273
+ writeSkill(base, "swiftui", "Use for SwiftUI views.");
274
+ loadOnlyTestSkills(base);
275
+
276
+ const result = buildBlock(base, { unitType: "unknown-unit-type" }, {
277
+ always_use_skills: ["swiftui"],
278
+ });
279
+
280
+ // Unknown unit type = wildcard fallback (pre-manifest behavior).
281
+ assert.match(result, /Call Skill\(\{ skill: 'swiftui' \}\)/);
282
+ } finally {
283
+ cleanup(base);
284
+ }
285
+ });
286
+
287
+ test("buildSkillActivationBlock without unitType preserves pre-manifest behavior", () => {
288
+ const base = makeTempBase();
289
+ try {
290
+ writeSkill(base, "swiftui", "Use for SwiftUI views.");
291
+ loadOnlyTestSkills(base);
292
+
293
+ // No unitType param — filter should no-op.
294
+ const result = buildBlock(base, {}, {
295
+ always_use_skills: ["swiftui"],
296
+ });
297
+
298
+ assert.match(result, /Call Skill\(\{ skill: 'swiftui' \}\)/);
299
+ } finally {
300
+ cleanup(base);
301
+ }
302
+ });
303
+
304
+ test("milestone prompt builders propagate always_use_skills through buildSkillActivationBlock", async () => {
305
+ const base = makeTempBase();
306
+ try {
307
+ // Both skills are in always_use_skills — explicit user intent bypasses
308
+ // the unit-type manifest, so both activate in both milestone flows.
309
+ writeSkill(base, "write-docs", "Use when writing docs or RFCs.");
310
+ writeSkill(base, "swiftui", "Use for SwiftUI views.");
311
+ writeProjectPreferences(base, "always_use_skills:\n - write-docs\n - swiftui\n");
312
+ loadOnlyTestSkills(base);
313
+
314
+ const researchPrompt = await buildResearchMilestonePrompt("M001", "Test", base);
315
+ assert.match(researchPrompt, /Call Skill\(\{ skill: 'write-docs' \}\)/);
316
+ assert.match(researchPrompt, /Call Skill\(\{ skill: 'swiftui' \}\)/);
317
+
318
+ const planPrompt = await buildPlanMilestonePrompt("M001", "Test", base);
319
+ assert.match(planPrompt, /Call Skill\(\{ skill: 'write-docs' \}\)/);
320
+ assert.match(planPrompt, /Call Skill\(\{ skill: 'swiftui' \}\)/);
321
+ } finally {
322
+ cleanup(base);
323
+ }
324
+ });
325
+
326
+ test("skill manifest strict warnings require GSD_SKILL_MANIFEST_STRICT=1", (t) => {
327
+ const previousStrict = process.env.GSD_SKILL_MANIFEST_STRICT;
328
+ const previousStderr = setStderrLoggingEnabled(false);
329
+ t.after(() => {
330
+ if (previousStrict === undefined) {
331
+ delete process.env.GSD_SKILL_MANIFEST_STRICT;
332
+ } else {
333
+ process.env.GSD_SKILL_MANIFEST_STRICT = previousStrict;
334
+ }
335
+ setStderrLoggingEnabled(previousStderr);
336
+ _resetLogs();
337
+ });
338
+
339
+ process.env.GSD_SKILL_MANIFEST_STRICT = "0";
340
+ _resetLogs();
341
+ warnIfManifestHasMissingSkills("research-milestone", new Set());
342
+ assert.equal(drainLogs().length, 0, "strict=0 must preserve silent behavior");
343
+
344
+ process.env.GSD_SKILL_MANIFEST_STRICT = "1";
345
+ _resetLogs();
346
+ warnIfManifestHasMissingSkills("research-milestone", new Set());
347
+ const logs = drainLogs();
348
+ assert.ok(
349
+ logs.some(log => log.message.includes("skill-manifest: references uninstalled skill")),
350
+ "strict=1 should warn about missing manifest entries",
351
+ );
352
+ });
@@ -0,0 +1,112 @@
1
+ // GSD2 + skill-manifest.test — unit coverage for the skill manifest resolver
2
+ //
3
+ // Focused tests for `resolveSkillManifest` and `filterSkillsByManifest`.
4
+ // Covers the wildcard semantics, the newly seeded unit-type entries
5
+ // (complete-milestone, validate-milestone, reassess-roadmap, research-slice,
6
+ // plan-slice, refine-slice, replan-slice, run-uat), and the deliberate
7
+ // wildcard fallback for the execute-task hot path (RFC #4779).
8
+
9
+ import test from "node:test";
10
+ import assert from "node:assert/strict";
11
+
12
+ import {
13
+ resolveSkillManifest,
14
+ filterSkillsByManifest,
15
+ } from "../skill-manifest.js";
16
+
17
+ const NEWLY_WIRED_UNIT_TYPES = [
18
+ "complete-milestone",
19
+ "validate-milestone",
20
+ "reassess-roadmap",
21
+ "research-slice",
22
+ "plan-slice",
23
+ "refine-slice",
24
+ "replan-slice",
25
+ "run-uat",
26
+ ] as const;
27
+
28
+ test("resolveSkillManifest returns null for undefined unit type (wildcard)", () => {
29
+ assert.equal(resolveSkillManifest(undefined), null);
30
+ });
31
+
32
+ test("resolveSkillManifest returns null for unknown unit types (wildcard fallback)", () => {
33
+ assert.equal(resolveSkillManifest("nonexistent-unit-type"), null);
34
+ });
35
+
36
+ test("resolveSkillManifest returns null for execute-task (intentional wildcard)", () => {
37
+ // execute-task is the implementation hot path; allowlisting it requires
38
+ // per-task skill hints from task-plan frontmatter. Documented in
39
+ // skill-manifest.ts — regression guard.
40
+ assert.equal(resolveSkillManifest("execute-task"), null);
41
+ });
42
+
43
+ for (const unitType of NEWLY_WIRED_UNIT_TYPES) {
44
+ test(`resolveSkillManifest returns a non-empty allowlist for '${unitType}'`, () => {
45
+ const allowlist = resolveSkillManifest(unitType);
46
+ assert.ok(allowlist !== null, `${unitType} should resolve to an allowlist, not wildcard`);
47
+ assert.ok(allowlist.length > 0, `${unitType} allowlist should not be empty`);
48
+ // Every entry must be lowercase (normalized).
49
+ for (const name of allowlist) {
50
+ assert.equal(name, name.toLowerCase(), `${unitType} entry '${name}' should be lowercase`);
51
+ }
52
+ });
53
+ }
54
+
55
+ test("resolveSkillManifest: slice-level manifests include decompose-into-slices", () => {
56
+ // Planning-shaped slice flows all benefit from the decomposition skill.
57
+ // Sanity-check a representative entry from each.
58
+ for (const unitType of ["research-slice", "plan-slice", "refine-slice", "replan-slice"] as const) {
59
+ const allowlist = resolveSkillManifest(unitType);
60
+ assert.ok(
61
+ allowlist?.includes("decompose-into-slices"),
62
+ `${unitType} should list decompose-into-slices`,
63
+ );
64
+ }
65
+ });
66
+
67
+ test("resolveSkillManifest: validation / completion flows include verify-before-complete", () => {
68
+ for (const unitType of ["complete-milestone", "validate-milestone", "run-uat"] as const) {
69
+ const allowlist = resolveSkillManifest(unitType);
70
+ assert.ok(
71
+ allowlist?.includes("verify-before-complete"),
72
+ `${unitType} should list verify-before-complete`,
73
+ );
74
+ }
75
+ });
76
+
77
+ test("filterSkillsByManifest: pass-through when unit type is unknown", () => {
78
+ const skills = [{ name: "swiftui" }, { name: "solidity-security" }];
79
+ const result = filterSkillsByManifest(skills, "nonexistent-unit-type");
80
+ assert.deepEqual(result, skills);
81
+ });
82
+
83
+ test("filterSkillsByManifest: pass-through when unitType is undefined", () => {
84
+ const skills = [{ name: "swiftui" }];
85
+ const result = filterSkillsByManifest(skills, undefined);
86
+ assert.deepEqual(result, skills);
87
+ });
88
+
89
+ test("filterSkillsByManifest: restricts to allowlisted names for known unit type", () => {
90
+ // research-slice allowlists include decompose-into-slices but not swiftui.
91
+ const skills = [
92
+ { name: "decompose-into-slices" },
93
+ { name: "swiftui" },
94
+ { name: "write-docs" },
95
+ ];
96
+ const result = filterSkillsByManifest(skills, "research-slice");
97
+ const names = result.map(s => s.name);
98
+ assert.ok(names.includes("decompose-into-slices"));
99
+ assert.ok(names.includes("write-docs"));
100
+ assert.ok(!names.includes("swiftui"));
101
+ });
102
+
103
+ test("filterSkillsByManifest: matching is case-insensitive via normalize", () => {
104
+ const skills = [
105
+ { name: "Write-Docs" }, // different case from manifest entry
106
+ { name: "SWIFTUI" },
107
+ ];
108
+ const result = filterSkillsByManifest(skills, "research-milestone");
109
+ const names = result.map(s => s.name);
110
+ assert.ok(names.includes("Write-Docs"));
111
+ assert.ok(!names.includes("SWIFTUI"));
112
+ });