gsd-pi 2.80.0-dev.fbe7c8c6f → 2.81.0-dev.3cddbbba2

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 (814) hide show
  1. package/README.md +47 -59
  2. package/dist/claude-cli-check.d.ts +30 -0
  3. package/dist/claude-cli-check.js +18 -7
  4. package/dist/cli.js +0 -19
  5. package/dist/headless-query.d.ts +10 -0
  6. package/dist/headless-query.js +6 -4
  7. package/dist/loader-entrypoint.d.ts +8 -0
  8. package/dist/loader-entrypoint.js +27 -0
  9. package/dist/loader.js +2 -11
  10. package/dist/mcp-server.d.ts +1 -0
  11. package/dist/mcp-server.js +6 -3
  12. package/dist/resources/.managed-resources-content-hash +1 -1
  13. package/dist/resources/extensions/claude-code-cli/readiness.js +18 -7
  14. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +40 -3
  15. package/dist/resources/extensions/github-sync/sync.js +4 -1
  16. package/dist/resources/extensions/gsd/auto/contracts.js +2 -0
  17. package/dist/resources/extensions/gsd/auto/loop.js +214 -17
  18. package/dist/resources/extensions/gsd/auto/orchestrator.js +48 -4
  19. package/dist/resources/extensions/gsd/auto/phases.js +372 -134
  20. package/dist/resources/extensions/gsd/auto/resolve.js +29 -0
  21. package/dist/resources/extensions/gsd/auto/run-unit.js +88 -33
  22. package/dist/resources/extensions/gsd/auto/session.js +18 -1
  23. package/dist/resources/extensions/gsd/auto/unit-runner-events.js +7 -0
  24. package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
  25. package/dist/resources/extensions/gsd/auto/workflow-dispatch-claim.js +33 -1
  26. package/dist/resources/extensions/gsd/auto/workflow-worker-heartbeat.js +9 -1
  27. package/dist/resources/extensions/gsd/auto-dashboard.js +199 -177
  28. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +5 -32
  29. package/dist/resources/extensions/gsd/auto-dispatch.js +30 -11
  30. package/dist/resources/extensions/gsd/auto-post-unit.js +119 -79
  31. package/dist/resources/extensions/gsd/auto-prompts.js +103 -16
  32. package/dist/resources/extensions/gsd/auto-recovery.js +43 -1
  33. package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
  34. package/dist/resources/extensions/gsd/auto-start.js +251 -16
  35. package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
  36. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
  37. package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
  38. package/dist/resources/extensions/gsd/auto-verification.js +12 -6
  39. package/dist/resources/extensions/gsd/auto-worktree.js +237 -336
  40. package/dist/resources/extensions/gsd/auto.js +493 -129
  41. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +133 -12
  42. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +44 -37
  43. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +37 -10
  44. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +30 -20
  45. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +4 -1
  46. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +6 -4
  47. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +5 -3
  48. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +1 -1
  49. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +337 -55
  50. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
  51. package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +4 -0
  52. package/dist/resources/extensions/gsd/bootstrap/system-context.js +82 -23
  53. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +19 -2
  54. package/dist/resources/extensions/gsd/clean-root-preflight.js +24 -6
  55. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
  56. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
  57. package/dist/resources/extensions/gsd/commands-config.js +1 -1
  58. package/dist/resources/extensions/gsd/commands-eval-review.js +2 -2
  59. package/dist/resources/extensions/gsd/commands-handlers.js +23 -9
  60. package/dist/resources/extensions/gsd/context-budget.js +37 -2
  61. package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
  62. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
  63. package/dist/resources/extensions/gsd/db/unit-dispatches.js +92 -0
  64. package/dist/resources/extensions/gsd/db-base-schema.js +4 -2
  65. package/dist/resources/extensions/gsd/db-migration-steps.js +6 -0
  66. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +2 -0
  67. package/dist/resources/extensions/gsd/git-service.js +75 -6
  68. package/dist/resources/extensions/gsd/gsd-db.js +46 -13
  69. package/dist/resources/extensions/gsd/guided-flow.js +119 -42
  70. package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
  71. package/dist/resources/extensions/gsd/health-widget.js +6 -9
  72. package/dist/resources/extensions/gsd/init-wizard.js +4 -1
  73. package/dist/resources/extensions/gsd/memory-store.js +69 -12
  74. package/dist/resources/extensions/gsd/migrate/command.js +40 -1
  75. package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
  76. package/dist/resources/extensions/gsd/native-git-bridge.js +46 -22
  77. package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
  78. package/dist/resources/extensions/gsd/orphan-stash-audit.js +101 -0
  79. package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
  80. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
  81. package/dist/resources/extensions/gsd/parallel-orchestrator.js +13 -3
  82. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  83. package/dist/resources/extensions/gsd/pre-execution-checks.js +22 -0
  84. package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
  85. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +22 -17
  86. package/dist/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  87. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  88. package/dist/resources/extensions/gsd/prompts/discuss.md +20 -2
  89. package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -2
  90. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  91. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  92. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
  93. package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  94. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  95. package/dist/resources/extensions/gsd/quick.js +34 -2
  96. package/dist/resources/extensions/gsd/recovery-classification.js +94 -0
  97. package/dist/resources/extensions/gsd/slice-cadence.js +45 -2
  98. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +15 -9
  99. package/dist/resources/extensions/gsd/state-reconciliation.js +27 -0
  100. package/dist/resources/extensions/gsd/tool-contract.js +50 -0
  101. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -7
  102. package/dist/resources/extensions/gsd/tools/complete-task.js +1 -1
  103. package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
  104. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
  105. package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
  106. package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
  107. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  108. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  109. package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
  110. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
  111. package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
  112. package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
  113. package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
  114. package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
  115. package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
  116. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
  117. package/dist/resources/extensions/gsd/workflow-protocol.js +131 -0
  118. package/dist/resources/extensions/gsd/worktree-lifecycle.js +1364 -0
  119. package/dist/resources/extensions/gsd/worktree-safety.js +119 -0
  120. package/dist/resources/extensions/gsd/worktree-state-projection.js +317 -0
  121. package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
  122. package/dist/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  123. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  124. package/dist/web/standalone/.next/BUILD_ID +1 -1
  125. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  126. package/dist/web/standalone/.next/build-manifest.json +3 -3
  127. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  128. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  129. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  131. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  140. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  143. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  144. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  145. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  146. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  147. package/dist/web/standalone/.next/server/app/index.html +1 -1
  148. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  149. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  150. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  151. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  152. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  153. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  154. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  156. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/middleware.js +3 -3
  159. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  160. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  161. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  162. package/dist/web/standalone/.next/static/chunks/8359.e059d86b255fce1c.js +10 -0
  163. package/dist/web/standalone/.next/static/chunks/app/{page-fab3ebb85b006001.js → page-752f1e2ebdaa3e45.js} +1 -1
  164. package/dist/web/standalone/.next/static/chunks/{webpack-0481f1221120a7c6.js → webpack-de742b64187e13fe.js} +1 -1
  165. package/dist/welcome-screen.d.ts +2 -7
  166. package/dist/welcome-screen.js +68 -75
  167. package/package.json +3 -3
  168. package/packages/daemon/package.json +2 -2
  169. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  170. package/packages/mcp-server/dist/workflow-tools.js +22 -17
  171. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  172. package/packages/mcp-server/package.json +2 -2
  173. package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
  174. package/packages/mcp-server/src/workflow-tools.ts +30 -16
  175. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  176. package/packages/native/package.json +1 -1
  177. package/packages/native/tsconfig.tsbuildinfo +1 -1
  178. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  179. package/packages/pi-agent-core/dist/agent-loop.js +4 -1
  180. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  181. package/packages/pi-agent-core/dist/agent.d.ts +9 -2
  182. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  183. package/packages/pi-agent-core/dist/agent.js +43 -11
  184. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  185. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  186. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  187. package/packages/pi-agent-core/dist/index.js +2 -0
  188. package/packages/pi-agent-core/dist/index.js.map +1 -1
  189. package/packages/pi-agent-core/dist/token-audit.d.ts +47 -0
  190. package/packages/pi-agent-core/dist/token-audit.d.ts.map +1 -0
  191. package/packages/pi-agent-core/dist/token-audit.js +221 -0
  192. package/packages/pi-agent-core/dist/token-audit.js.map +1 -0
  193. package/packages/pi-agent-core/dist/types.d.ts +31 -0
  194. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  195. package/packages/pi-agent-core/dist/types.js.map +1 -1
  196. package/packages/pi-agent-core/package.json +1 -1
  197. package/packages/pi-agent-core/src/agent-loop.test.ts +128 -0
  198. package/packages/pi-agent-core/src/agent-loop.ts +4 -1
  199. package/packages/pi-agent-core/src/agent.ts +52 -11
  200. package/packages/pi-agent-core/src/index.ts +2 -0
  201. package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
  202. package/packages/pi-agent-core/src/token-audit.ts +287 -0
  203. package/packages/pi-agent-core/src/types.ts +26 -10
  204. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  205. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +35 -13
  206. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  207. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +21 -11
  208. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -1
  209. package/packages/pi-ai/dist/providers/anthropic.d.ts +7 -0
  210. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  211. package/packages/pi-ai/dist/providers/anthropic.js +9 -7
  212. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  213. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +23 -14
  214. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -1
  215. package/packages/pi-ai/dist/types.d.ts +2 -0
  216. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  217. package/packages/pi-ai/dist/types.js.map +1 -1
  218. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +48 -21
  219. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  220. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +22 -21
  221. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -1
  222. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +22 -21
  223. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -1
  224. package/packages/pi-ai/package.json +1 -1
  225. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +39 -25
  226. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -22
  227. package/packages/pi-ai/src/providers/anthropic.ts +22 -9
  228. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +34 -21
  229. package/packages/pi-ai/src/types.ts +3 -0
  230. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +56 -22
  231. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +24 -28
  232. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +24 -28
  233. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  234. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +36 -1
  235. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  236. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +30 -1
  237. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  238. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +21 -2
  239. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  240. package/packages/pi-coding-agent/dist/core/agent-session.js +94 -16
  241. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  242. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +6 -2
  243. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  244. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
  245. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  246. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
  247. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  248. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
  249. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
  250. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
  251. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
  252. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  253. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  254. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  255. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  256. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  257. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  258. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  259. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  260. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  261. package/packages/pi-coding-agent/dist/core/extensions/loader.js +8 -0
  262. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  263. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +3 -0
  264. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  265. package/packages/pi-coding-agent/dist/core/extensions/runner.js +6 -6
  266. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  267. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +5 -3
  268. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  269. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +60 -4
  270. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  271. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  272. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +2 -0
  273. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -1
  274. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts +2 -0
  275. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts.map +1 -0
  276. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js +46 -0
  277. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js.map +1 -0
  278. package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -2
  279. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  280. package/packages/pi-coding-agent/dist/core/sdk.js +81 -4
  281. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  282. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
  283. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  284. package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
  285. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  286. package/packages/pi-coding-agent/dist/core/skill-tool.test.js +22 -0
  287. package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
  288. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -7
  289. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  290. package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -3
  291. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  292. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +22 -56
  293. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -1
  294. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +1 -0
  295. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  296. package/packages/pi-coding-agent/dist/core/tools/bash.js +3 -1
  297. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  298. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts +2 -0
  299. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  300. package/packages/pi-coding-agent/dist/core/tools/edit.js +12 -1
  301. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  302. package/packages/pi-coding-agent/dist/core/tools/find.d.ts +2 -0
  303. package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  304. package/packages/pi-coding-agent/dist/core/tools/find.js +14 -6
  305. package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  306. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts +2 -0
  307. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
  308. package/packages/pi-coding-agent/dist/core/tools/grep.js +12 -3
  309. package/packages/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  310. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts +2 -0
  311. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +3 -1
  313. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
  314. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -1
  315. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  316. package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
  317. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  318. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts +2 -0
  319. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
  320. package/packages/pi-coding-agent/dist/core/tools/ls.js +10 -3
  321. package/packages/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
  322. package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -0
  323. package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  324. package/packages/pi-coding-agent/dist/core/tools/read.js +3 -1
  325. package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  326. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +7 -62
  327. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -1
  328. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts +2 -0
  329. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts.map +1 -0
  330. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js +115 -0
  331. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js.map +1 -0
  332. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts +19 -0
  333. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts.map +1 -0
  334. package/packages/pi-coding-agent/dist/core/tools/tool-target.js +20 -0
  335. package/packages/pi-coding-agent/dist/core/tools/tool-target.js.map +1 -0
  336. package/packages/pi-coding-agent/dist/core/tools/write.d.ts +4 -0
  337. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  338. package/packages/pi-coding-agent/dist/core/tools/write.js +9 -1
  339. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  340. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
  341. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
  342. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
  343. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
  344. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +161 -7
  345. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  346. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
  347. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
  348. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
  349. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
  350. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
  351. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
  352. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
  353. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
  354. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
  355. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
  356. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  357. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
  358. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  359. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
  360. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  361. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
  362. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  363. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
  364. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
  365. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
  366. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
  367. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  368. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
  369. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  370. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +25 -1
  371. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  372. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +6 -1
  373. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  374. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +225 -73
  375. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  376. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
  377. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
  378. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
  379. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
  380. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
  381. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
  382. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
  383. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
  384. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
  385. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  386. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
  387. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  388. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  389. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +31 -6
  390. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  391. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +71 -0
  392. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  393. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
  394. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  395. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +25 -3
  396. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  397. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  398. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  399. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  400. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  401. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  402. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
  403. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  404. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  405. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
  406. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  407. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
  408. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
  409. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
  410. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  411. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  412. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  413. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +28 -0
  414. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  415. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  416. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  417. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  418. package/packages/pi-coding-agent/package.json +1 -1
  419. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +40 -1
  420. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +40 -1
  421. package/packages/pi-coding-agent/src/core/agent-session.ts +102 -16
  422. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +6 -2
  423. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
  424. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  425. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  426. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  427. package/packages/pi-coding-agent/src/core/extensions/loader.ts +10 -0
  428. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +5 -3
  429. package/packages/pi-coding-agent/src/core/extensions/runner.ts +8 -5
  430. package/packages/pi-coding-agent/src/core/extensions/types.ts +63 -2
  431. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +2 -0
  432. package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
  433. package/packages/pi-coding-agent/src/core/sdk.ts +92 -4
  434. package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
  435. package/packages/pi-coding-agent/src/core/skill-tool.test.ts +28 -0
  436. package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -10
  437. package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +22 -66
  438. package/packages/pi-coding-agent/src/core/tools/bash.ts +4 -1
  439. package/packages/pi-coding-agent/src/core/tools/edit.ts +13 -1
  440. package/packages/pi-coding-agent/src/core/tools/find.ts +15 -6
  441. package/packages/pi-coding-agent/src/core/tools/grep.ts +13 -3
  442. package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +4 -1
  443. package/packages/pi-coding-agent/src/core/tools/index.ts +8 -0
  444. package/packages/pi-coding-agent/src/core/tools/ls.ts +11 -3
  445. package/packages/pi-coding-agent/src/core/tools/read.ts +4 -1
  446. package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +11 -72
  447. package/packages/pi-coding-agent/src/core/tools/tool-target-metadata.test.ts +127 -0
  448. package/packages/pi-coding-agent/src/core/tools/tool-target.ts +48 -0
  449. package/packages/pi-coding-agent/src/core/tools/write.ts +14 -2
  450. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
  451. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +228 -7
  452. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
  453. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
  454. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
  455. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
  456. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
  457. package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
  458. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
  459. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +31 -1
  460. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +247 -94
  461. package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
  462. package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
  463. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
  464. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +75 -0
  465. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +39 -8
  466. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +27 -3
  467. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
  468. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
  469. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
  470. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
  471. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +1 -1
  472. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +31 -0
  473. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  474. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  475. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
  476. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  477. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
  478. package/packages/pi-tui/dist/overlay-layout.js +9 -6
  479. package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
  480. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  481. package/packages/pi-tui/dist/tui.js +18 -8
  482. package/packages/pi-tui/dist/tui.js.map +1 -1
  483. package/packages/pi-tui/package.json +1 -1
  484. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
  485. package/packages/pi-tui/src/overlay-layout.ts +10 -7
  486. package/packages/pi-tui/src/tui.ts +20 -8
  487. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  488. package/packages/rpc-client/README.md +7 -0
  489. package/packages/rpc-client/package.json +1 -1
  490. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  491. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  492. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  493. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  494. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  495. package/pkg/dist/modes/interactive/theme/theme.js +105 -1
  496. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  497. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  498. package/pkg/dist/modes/interactive/theme/themes.js +27 -26
  499. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  500. package/pkg/package.json +1 -1
  501. package/src/resources/extensions/claude-code-cli/readiness.ts +25 -7
  502. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +42 -3
  503. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +67 -0
  504. package/src/resources/extensions/github-sync/sync.ts +8 -1
  505. package/src/resources/extensions/github-sync/tests/sync-source.test.ts +6 -18
  506. package/src/resources/extensions/gsd/auto/contracts.ts +19 -2
  507. package/src/resources/extensions/gsd/auto/loop-deps.ts +19 -16
  508. package/src/resources/extensions/gsd/auto/loop.ts +247 -25
  509. package/src/resources/extensions/gsd/auto/orchestrator.ts +52 -4
  510. package/src/resources/extensions/gsd/auto/phases.ts +512 -202
  511. package/src/resources/extensions/gsd/auto/resolve.ts +42 -1
  512. package/src/resources/extensions/gsd/auto/run-unit.ts +97 -34
  513. package/src/resources/extensions/gsd/auto/session.ts +19 -1
  514. package/src/resources/extensions/gsd/auto/types.ts +3 -0
  515. package/src/resources/extensions/gsd/auto/unit-runner-events.ts +15 -0
  516. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
  517. package/src/resources/extensions/gsd/auto/workflow-dispatch-claim.ts +63 -1
  518. package/src/resources/extensions/gsd/auto/workflow-worker-heartbeat.ts +14 -1
  519. package/src/resources/extensions/gsd/auto-dashboard.ts +249 -182
  520. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -34
  521. package/src/resources/extensions/gsd/auto-dispatch.ts +31 -1
  522. package/src/resources/extensions/gsd/auto-post-unit.ts +131 -81
  523. package/src/resources/extensions/gsd/auto-prompts.ts +112 -15
  524. package/src/resources/extensions/gsd/auto-recovery.ts +54 -0
  525. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  526. package/src/resources/extensions/gsd/auto-start.ts +321 -21
  527. package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
  528. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
  529. package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
  530. package/src/resources/extensions/gsd/auto-verification.ts +12 -6
  531. package/src/resources/extensions/gsd/auto-worktree.ts +267 -360
  532. package/src/resources/extensions/gsd/auto.ts +578 -126
  533. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +166 -12
  534. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +45 -37
  535. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +36 -10
  536. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +32 -19
  537. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +5 -1
  538. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +7 -4
  539. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +6 -3
  540. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +1 -1
  541. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +384 -55
  542. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
  543. package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +4 -0
  544. package/src/resources/extensions/gsd/bootstrap/system-context.ts +90 -22
  545. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -2
  546. package/src/resources/extensions/gsd/clean-root-preflight.ts +32 -7
  547. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
  548. package/src/resources/extensions/gsd/commands/handlers/ops.ts +4 -2
  549. package/src/resources/extensions/gsd/commands-config.ts +1 -1
  550. package/src/resources/extensions/gsd/commands-eval-review.ts +2 -2
  551. package/src/resources/extensions/gsd/commands-handlers.ts +34 -15
  552. package/src/resources/extensions/gsd/context-budget.ts +44 -2
  553. package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
  554. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
  555. package/src/resources/extensions/gsd/db/unit-dispatches.ts +107 -0
  556. package/src/resources/extensions/gsd/db-base-schema.ts +4 -2
  557. package/src/resources/extensions/gsd/db-migration-steps.ts +8 -0
  558. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +3 -0
  559. package/src/resources/extensions/gsd/git-service.ts +89 -10
  560. package/src/resources/extensions/gsd/gsd-db.ts +50 -13
  561. package/src/resources/extensions/gsd/guided-flow.ts +148 -49
  562. package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
  563. package/src/resources/extensions/gsd/health-widget.ts +8 -9
  564. package/src/resources/extensions/gsd/init-wizard.ts +5 -1
  565. package/src/resources/extensions/gsd/journal.ts +2 -0
  566. package/src/resources/extensions/gsd/memory-store.ts +77 -12
  567. package/src/resources/extensions/gsd/migrate/command.ts +47 -1
  568. package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
  569. package/src/resources/extensions/gsd/native-git-bridge.ts +53 -19
  570. package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
  571. package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
  572. package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
  573. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
  574. package/src/resources/extensions/gsd/parallel-orchestrator.ts +13 -3
  575. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  576. package/src/resources/extensions/gsd/pre-execution-checks.ts +23 -0
  577. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  578. package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
  579. package/src/resources/extensions/gsd/prompts/complete-milestone.md +22 -17
  580. package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  581. package/src/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  582. package/src/resources/extensions/gsd/prompts/discuss.md +20 -2
  583. package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
  584. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  585. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  586. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
  587. package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  588. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  589. package/src/resources/extensions/gsd/quick.ts +37 -2
  590. package/src/resources/extensions/gsd/recovery-classification.ts +122 -0
  591. package/src/resources/extensions/gsd/slice-cadence.ts +49 -2
  592. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +23 -9
  593. package/src/resources/extensions/gsd/state-reconciliation.ts +57 -0
  594. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +59 -89
  595. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +47 -172
  596. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +0 -35
  597. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +134 -9
  598. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +1125 -215
  599. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +80 -59
  600. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +119 -2
  601. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +3 -47
  602. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +363 -18
  603. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +175 -11
  604. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +54 -95
  605. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +67 -26
  606. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +14 -1
  607. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +32 -30
  608. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +16 -1
  609. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +32 -128
  610. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +20 -54
  611. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +20 -30
  612. package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +17 -29
  613. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +160 -0
  614. package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +21 -39
  615. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +15 -24
  616. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +44 -29
  617. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
  618. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +39 -51
  619. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +159 -213
  620. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +15 -32
  621. package/src/resources/extensions/gsd/tests/browser-teardown.test.ts +0 -41
  622. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +15 -6
  623. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +34 -27
  624. package/src/resources/extensions/gsd/tests/cmux.test.ts +51 -53
  625. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +39 -61
  626. package/src/resources/extensions/gsd/tests/commands-config.test.ts +26 -19
  627. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
  628. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
  629. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +140 -0
  630. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
  631. package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +29 -33
  632. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +45 -108
  633. package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
  634. package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -1
  635. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +90 -31
  636. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
  637. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +46 -11
  638. package/src/resources/extensions/gsd/tests/cwd-fallback-hardening.test.ts +138 -0
  639. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +4 -68
  640. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +24 -11
  641. package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +14 -65
  642. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +44 -37
  643. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +100 -38
  644. package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +25 -15
  645. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
  646. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +35 -17
  647. package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +16 -21
  648. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +15 -82
  649. package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
  650. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
  651. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +5 -2
  652. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
  653. package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +151 -0
  654. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +2 -20
  655. package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +18 -26
  656. package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
  657. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
  658. package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
  659. package/src/resources/extensions/gsd/tests/init-skip-git.test.ts +9 -12
  660. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +40 -0
  661. package/src/resources/extensions/gsd/tests/integration/commands-eval-review.integration.test.ts +4 -2
  662. package/src/resources/extensions/gsd/tests/integration/git-locale.test.ts +31 -20
  663. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +92 -0
  664. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +0 -47
  665. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
  666. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +60 -202
  667. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +13 -56
  668. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +248 -11
  669. package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +32 -0
  670. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -0
  671. package/src/resources/extensions/gsd/tests/lazy-pi-tui-import.test.ts +44 -6
  672. package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
  673. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +21 -35
  674. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +77 -12
  675. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
  676. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
  677. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +267 -0
  678. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +88 -98
  679. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +70 -278
  680. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
  681. package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +37 -30
  682. package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +32 -28
  683. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
  684. package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
  685. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -182
  686. package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +144 -0
  687. package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
  688. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
  689. package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -0
  690. package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +24 -37
  691. package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +9 -24
  692. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +95 -75
  693. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  694. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  695. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
  696. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +36 -22
  697. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +36 -30
  698. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +45 -5
  699. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +74 -4
  700. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +20 -22
  701. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +130 -32
  702. package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +18 -36
  703. package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +35 -73
  704. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +76 -138
  705. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +24 -1
  706. package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
  707. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  708. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +70 -106
  709. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +59 -161
  710. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +33 -29
  711. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +22 -196
  712. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +23 -93
  713. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  714. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +50 -79
  715. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +27 -13
  716. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +151 -251
  717. package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +41 -29
  718. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +58 -69
  719. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +36 -164
  720. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +57 -41
  721. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +91 -0
  722. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
  723. package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
  724. package/src/resources/extensions/gsd/tests/session-model-override.test.ts +14 -9
  725. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +77 -0
  726. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +222 -0
  727. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +44 -42
  728. package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
  729. package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +56 -24
  730. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +51 -11
  731. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +23 -0
  732. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +66 -50
  733. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +68 -107
  734. package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +115 -42
  735. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +21 -77
  736. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +25 -116
  737. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +21 -57
  738. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +29 -76
  739. package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +33 -24
  740. package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +39 -30
  741. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
  742. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +55 -0
  743. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -56
  744. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +35 -40
  745. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +48 -46
  746. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +14 -102
  747. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +78 -232
  748. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +32 -35
  749. package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
  750. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +7 -9
  751. package/src/resources/extensions/gsd/tests/token-profile.test.ts +84 -309
  752. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +295 -0
  753. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +134 -341
  754. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +330 -0
  755. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
  756. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
  757. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +8 -25
  758. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +80 -1
  759. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
  760. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -99
  761. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +43 -36
  762. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
  763. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -444
  764. package/src/resources/extensions/gsd/tests/workflow-dispatch-claim.test.ts +142 -0
  765. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +44 -189
  766. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +8 -57
  767. package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
  768. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
  769. package/src/resources/extensions/gsd/tests/workflow-worker-heartbeat.test.ts +32 -1
  770. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +21 -44
  771. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +27 -26
  772. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +14 -13
  773. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +197 -78
  774. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +888 -0
  775. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -18
  776. package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +22 -19
  777. package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
  778. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +327 -0
  779. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +120 -0
  780. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
  781. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
  782. package/src/resources/extensions/gsd/tests/write-gate.test.ts +40 -1
  783. package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -13
  784. package/src/resources/extensions/gsd/tool-contract.ts +82 -0
  785. package/src/resources/extensions/gsd/tools/complete-milestone.ts +14 -15
  786. package/src/resources/extensions/gsd/tools/complete-task.ts +1 -1
  787. package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
  788. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
  789. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
  790. package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
  791. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  792. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  793. package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
  794. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
  795. package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
  796. package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
  797. package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
  798. package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
  799. package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
  800. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
  801. package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
  802. package/src/resources/extensions/gsd/worktree-lifecycle.ts +1882 -0
  803. package/src/resources/extensions/gsd/worktree-safety.ts +282 -0
  804. package/src/resources/extensions/gsd/worktree-state-projection.ts +404 -0
  805. package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
  806. package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +86 -40
  807. package/src/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  808. package/dist/resources/extensions/gsd/worktree-resolver.js +0 -733
  809. package/dist/web/standalone/.next/static/chunks/8336.631939fb583761fa.js +0 -10
  810. package/src/resources/extensions/gsd/tests/sync-layer-scope.test.ts +0 -434
  811. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1247
  812. package/src/resources/extensions/gsd/worktree-resolver.ts +0 -909
  813. /package/dist/web/standalone/.next/static/{yTuahMMuJzVnsov5PreWl → F5x9E6H9k_52fjqyql93y}/_buildManifest.js +0 -0
  814. /package/dist/web/standalone/.next/static/{yTuahMMuJzVnsov5PreWl → F5x9E6H9k_52fjqyql93y}/_ssgManifest.js +0 -0
@@ -1,17 +1,6 @@
1
1
  import { describe, test } from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { existsSync, readFileSync } from "node:fs";
4
- import { join } from "node:path";
5
- import { fileURLToPath } from "node:url";
6
- import { getGitHubCopilotBaseUrl, githubCopilotOAuthProvider, normalizeDomain, } from "./github-copilot.js";
7
- const __dirname = fileURLToPath(new URL(".", import.meta.url));
8
- const packageRoot = join(__dirname, "..", "..", "..");
9
- const sourceDir = existsSync(join(__dirname, "github-copilot.ts"))
10
- ? __dirname
11
- : join(packageRoot, "src", "utils", "oauth");
12
- function readSourceFile(name) {
13
- return readFileSync(join(sourceDir, name), "utf-8");
14
- }
3
+ import { getGitHubCopilotBaseUrl, githubCopilotOAuthProvider, loginGitHubCopilot, normalizeDomain, } from "./github-copilot.js";
15
4
  function createModel(overrides = {}) {
16
5
  return {
17
6
  id: "test-model",
@@ -163,15 +152,53 @@ describe("GitHub Copilot OAuth — credential regression", () => {
163
152
  test("module imports successfully", () => {
164
153
  assert.ok(githubCopilotOAuthProvider);
165
154
  });
166
- test("CLIENT_ID is plaintext (not base64)", () => {
167
- const content = readSourceFile("github-copilot.ts");
168
- assert.ok(content.includes('CLIENT_ID = "Iv1.b507a08c87ecfe98"'));
169
- assert.ok(!content.includes("atob("));
170
- });
171
- test("security explanation comments are present", () => {
172
- const content = readSourceFile("github-copilot.ts");
173
- assert.ok(content.includes("NOTE: This credential is public"));
174
- assert.ok(content.includes("obfuscated") || content.includes("security scanners"));
155
+ test("device login sends the public OAuth client id without a client secret", async (t) => {
156
+ const calls = [];
157
+ const originalFetch = globalThis.fetch;
158
+ t.after(() => {
159
+ globalThis.fetch = originalFetch;
160
+ });
161
+ globalThis.fetch = async (input, init) => {
162
+ const url = String(input);
163
+ calls.push({ url, init: init ?? {} });
164
+ if (url.endsWith("/login/device/code")) {
165
+ return Response.json({
166
+ device_code: "device-code",
167
+ user_code: "ABCD-EFGH",
168
+ verification_uri: "https://github.com/login/device",
169
+ interval: 1,
170
+ expires_in: 600,
171
+ });
172
+ }
173
+ if (url.endsWith("/login/oauth/access_token")) {
174
+ return Response.json({ access_token: "github-access-token" });
175
+ }
176
+ if (url.endsWith("/copilot_internal/v2/token")) {
177
+ return Response.json({
178
+ token: "tid=123;exp=1234567890;proxy-ep=proxy.individual.githubcopilot.com;",
179
+ expires_at: Math.floor(Date.now() / 1000) + 3600,
180
+ });
181
+ }
182
+ if (url.endsWith("/models")) {
183
+ return Response.json({ data: [] });
184
+ }
185
+ if (url.includes("/models/") && url.endsWith("/policy")) {
186
+ return Response.json({ ok: true });
187
+ }
188
+ throw new Error(`Unexpected fetch: ${url}`);
189
+ };
190
+ const credentials = await loginGitHubCopilot({
191
+ onPrompt: async () => "",
192
+ onAuth: () => { },
193
+ });
194
+ assert.equal(credentials.access, "tid=123;exp=1234567890;proxy-ep=proxy.individual.githubcopilot.com;");
195
+ const deviceCodeCall = calls.find((call) => call.url.endsWith("/login/device/code"));
196
+ assert.ok(deviceCodeCall, "device-code request should be sent");
197
+ const requestBody = deviceCodeCall.init.body;
198
+ assert.equal(typeof requestBody, "string");
199
+ const body = JSON.parse(requestBody);
200
+ assert.equal(body.client_id, "Iv1.b507a08c87ecfe98");
201
+ assert.equal("client_secret" in body, false, "GitHub device flow must not send a client secret");
175
202
  });
176
203
  });
177
204
  test("githubCopilotOAuthProvider.modifyModels filters unavailable copilot models (#3849)", () => {
@@ -1 +1 @@
1
- {"version":3,"file":"github-copilot.test.js","sourceRoot":"","sources":["../../../src/utils/oauth/github-copilot.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, test } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Api, Model } from \"../../types.js\";\nimport type { OAuthCredentials } from \"./types.js\";\nimport {\n\tgetGitHubCopilotBaseUrl,\n\tgithubCopilotOAuthProvider,\n\tnormalizeDomain,\n} from \"./github-copilot.js\";\n\nconst __dirname = fileURLToPath(new URL(\".\", import.meta.url));\nconst packageRoot = join(__dirname, \"..\", \"..\", \"..\");\nconst sourceDir = existsSync(join(__dirname, \"github-copilot.ts\"))\n\t? __dirname\n\t: join(packageRoot, \"src\", \"utils\", \"oauth\");\n\nfunction readSourceFile(name: string): string {\n\treturn readFileSync(join(sourceDir, name), \"utf-8\");\n}\n\nfunction createModel(overrides: Partial<Model<Api>> = {}): Model<Api> {\n\treturn {\n\t\tid: \"test-model\",\n\t\tname: \"Test Model\",\n\t\tapi: \"openai-completions\",\n\t\tprovider: \"test-provider\",\n\t\tbaseUrl: \"https://example.com\",\n\t\treasoning: false,\n\t\tinput: [\"text\"],\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 8192,\n\t\t...overrides,\n\t} as Model<Api>;\n}\n\nfunction makeCredentials(\n\toverrides: Partial<OAuthCredentials & { modelLimits?: Record<string, { contextWindow: number; maxTokens: number }> }> = {},\n) {\n\treturn {\n\t\taccess: \"copilot-token\",\n\t\trefresh: \"refresh-token\",\n\t\texpires: Date.now() + 60_000,\n\t\t...overrides,\n\t};\n}\n\ndescribe(\"GitHub Copilot OAuth — normalizeDomain\", () => {\n\ttest(\"returns null for empty input\", () => {\n\t\tassert.equal(normalizeDomain(\"\"), null);\n\t\tassert.equal(normalizeDomain(\" \"), null);\n\t});\n\n\ttest(\"returns null for invalid domain\", () => {\n\t\tassert.equal(normalizeDomain(\"not a domain!@#\"), null);\n\t});\n\n\ttest(\"extracts hostname from full URL\", () => {\n\t\tassert.equal(normalizeDomain(\"https://github.com\"), \"github.com\");\n\t\tassert.equal(normalizeDomain(\"https://company.ghe.com\"), \"company.ghe.com\");\n\t\tassert.equal(normalizeDomain(\"http://example.com/path\"), \"example.com\");\n\t});\n\n\ttest(\"returns domain as-is when no protocol\", () => {\n\t\tassert.equal(normalizeDomain(\"github.com\"), \"github.com\");\n\t\tassert.equal(normalizeDomain(\"company.ghe.com\"), \"company.ghe.com\");\n\t});\n\n\ttest(\"trims whitespace\", () => {\n\t\tassert.equal(normalizeDomain(\" github.com \"), \"github.com\");\n\t});\n});\n\ndescribe(\"GitHub Copilot OAuth — getBaseUrlFromToken\", () => {\n\ttest(\"extracts API URL from token with proxy-ep\", () => {\n\t\tconst token = \"tid=123;exp=1234567890;proxy-ep=proxy.individual.githubcopilot.com;other=value\";\n\t\tconst baseUrl = getGitHubCopilotBaseUrl(token);\n\t\tassert.equal(baseUrl, \"https://api.individual.githubcopilot.com\");\n\t});\n\n\ttest(\"extracts API URL from enterprise proxy-ep\", () => {\n\t\tconst token = \"tid=123;exp=1234567890;proxy-ep=proxy.company.ghe.com;other=value\";\n\t\tconst baseUrl = getGitHubCopilotBaseUrl(token);\n\t\tassert.equal(baseUrl, \"https://api.company.ghe.com\");\n\t});\n\n\ttest(\"falls back to default when no token provided\", () => {\n\t\tconst baseUrl = getGitHubCopilotBaseUrl();\n\t\tassert.equal(baseUrl, \"https://api.individual.githubcopilot.com\");\n\t});\n\n\ttest(\"falls back to default when token has no proxy-ep\", () => {\n\t\tconst token = \"tid=123;exp=1234567890;other=value\";\n\t\tconst baseUrl = getGitHubCopilotBaseUrl(token);\n\t\tassert.equal(baseUrl, \"https://api.individual.githubcopilot.com\");\n\t});\n\n\ttest(\"uses enterprise domain when provided\", () => {\n\t\tconst baseUrl = getGitHubCopilotBaseUrl(undefined, \"company.ghe.com\");\n\t\tassert.equal(baseUrl, \"https://copilot-api.company.ghe.com\");\n\t});\n\n\ttest(\"prioritizes token proxy-ep over enterprise domain\", () => {\n\t\tconst token = \"tid=123;exp=1234567890;proxy-ep=proxy.individual.githubcopilot.com;other=value\";\n\t\tconst baseUrl = getGitHubCopilotBaseUrl(token, \"company.ghe.com\");\n\t\tassert.equal(baseUrl, \"https://api.individual.githubcopilot.com\");\n\t});\n});\n\ndescribe(\"GitHub Copilot OAuth — provider structure\", () => {\n\ttest(\"has correct id and name\", () => {\n\t\tassert.equal(githubCopilotOAuthProvider.id, \"github-copilot\");\n\t\tassert.equal(githubCopilotOAuthProvider.name, \"GitHub Copilot\");\n\t});\n\n\ttest(\"has required methods\", () => {\n\t\tassert.equal(typeof githubCopilotOAuthProvider.login, \"function\");\n\t\tassert.equal(typeof githubCopilotOAuthProvider.refreshToken, \"function\");\n\t\tassert.equal(typeof githubCopilotOAuthProvider.getApiKey, \"function\");\n\t\tassert.equal(typeof githubCopilotOAuthProvider.modifyModels, \"function\");\n\t});\n\n\ttest(\"getApiKey returns access token\", () => {\n\t\tconst credentials: OAuthCredentials = {\n\t\t\taccess: \"test-access-token\",\n\t\t\trefresh: \"test-refresh-token\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t};\n\t\tconst apiKey = githubCopilotOAuthProvider.getApiKey(credentials);\n\t\tassert.equal(apiKey, \"test-access-token\");\n\t});\n\n\ttest(\"modifyModels preserves non-Copilot models\", () => {\n\t\tif (!githubCopilotOAuthProvider.modifyModels) return;\n\t\tconst models = [createModel({ id: \"gpt-4\", provider: \"openai\" })];\n\t\tconst credentials: OAuthCredentials = {\n\t\t\taccess: \"test-token\",\n\t\t\trefresh: \"test-refresh\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t};\n\t\tconst result = githubCopilotOAuthProvider.modifyModels(models, credentials);\n\t\tassert.deepEqual(result, models);\n\t});\n\n\ttest(\"modifyModels updates Copilot model baseUrl when token has proxy-ep\", () => {\n\t\tif (!githubCopilotOAuthProvider.modifyModels) return;\n\t\tconst models = [\n\t\t\tcreateModel({\n\t\t\t\tid: \"claude-3.5-sonnet\",\n\t\t\t\tprovider: \"github-copilot\",\n\t\t\t\tbaseUrl: \"https://api.default.com\",\n\t\t\t}),\n\t\t];\n\t\tconst credentials: OAuthCredentials = {\n\t\t\taccess: \"tid=123;exp=1234567890;proxy-ep=proxy.individual.githubcopilot.com;\",\n\t\t\trefresh: \"test-refresh\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t};\n\t\tconst result = githubCopilotOAuthProvider.modifyModels(models, credentials);\n\t\tassert.equal(result[0].baseUrl, \"https://api.individual.githubcopilot.com\");\n\t});\n\n\ttest(\"modifyModels applies model limits when available\", () => {\n\t\tif (!githubCopilotOAuthProvider.modifyModels) return;\n\t\tconst models = [\n\t\t\tcreateModel({\n\t\t\t\tid: \"claude-3.5-sonnet\",\n\t\t\t\tprovider: \"github-copilot\",\n\t\t\t\tbaseUrl: \"https://api.default.com\",\n\t\t\t}),\n\t\t];\n\t\tconst credentials = {\n\t\t\taccess: \"test-token\",\n\t\t\trefresh: \"test-refresh\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t\tmodelLimits: {\n\t\t\t\t\"claude-3.5-sonnet\": { contextWindow: 123456, maxTokens: 4096 },\n\t\t\t},\n\t\t};\n\t\tconst result = githubCopilotOAuthProvider.modifyModels(models, credentials);\n\t\tassert.equal(result[0].contextWindow, 123456);\n\t\tassert.equal(result[0].maxTokens, 4096);\n\t});\n});\n\ndescribe(\"GitHub Copilot OAuth — credential regression\", () => {\n\ttest(\"module imports successfully\", () => {\n\t\tassert.ok(githubCopilotOAuthProvider);\n\t});\n\n\ttest(\"CLIENT_ID is plaintext (not base64)\", () => {\n\t\tconst content = readSourceFile(\"github-copilot.ts\");\n\t\tassert.ok(content.includes('CLIENT_ID = \"Iv1.b507a08c87ecfe98\"'));\n\t\tassert.ok(!content.includes(\"atob(\"));\n\t});\n\n\ttest(\"security explanation comments are present\", () => {\n\t\tconst content = readSourceFile(\"github-copilot.ts\");\n\t\tassert.ok(content.includes(\"NOTE: This credential is public\"));\n\t\tassert.ok(content.includes(\"obfuscated\") || content.includes(\"security scanners\"));\n\t});\n});\n\ntest(\"githubCopilotOAuthProvider.modifyModels filters unavailable copilot models (#3849)\", () => {\n\tconst models = [\n\t\tcreateModel({ provider: \"github-copilot\", id: \"gpt-5\", name: \"gpt-5\", baseUrl: \"github-copilot:\" }),\n\t\tcreateModel({ provider: \"github-copilot\", id: \"claude-sonnet-4\", name: \"claude-sonnet-4\", baseUrl: \"github-copilot:\" }),\n\t\tcreateModel({ provider: \"openai\", id: \"gpt-4.1\", name: \"gpt-4.1\", baseUrl: \"openai:\" }),\n\t];\n\n\tassert.ok(githubCopilotOAuthProvider.modifyModels, \"github copilot provider should expose modifyModels\");\n\tconst modified = githubCopilotOAuthProvider.modifyModels(\n\t\tmodels,\n\t\tmakeCredentials({\n\t\t\tmodelLimits: {\n\t\t\t\t\"gpt-5\": { contextWindow: 256000, maxTokens: 32000 },\n\t\t\t},\n\t\t}),\n\t);\n\n\tassert.deepEqual(\n\t\tmodified.map((model) => `${model.provider}/${model.id}`),\n\t\t[\"github-copilot/gpt-5\", \"openai/gpt-4.1\"],\n\t);\n\n\tconst copilotModel = modified.find((model) => model.provider === \"github-copilot\" && model.id === \"gpt-5\");\n\tassert.ok(copilotModel, \"available copilot model should remain\");\n\tassert.equal(copilotModel.contextWindow, 256000);\n\tassert.equal(copilotModel.maxTokens, 32000);\n\tassert.match(copilotModel.baseUrl, /githubcopilot\\.com/);\n});\n\ntest(\"githubCopilotOAuthProvider.modifyModels keeps all copilot models when limits are unavailable\", () => {\n\tconst models = [\n\t\tcreateModel({ provider: \"github-copilot\", id: \"gpt-5\", name: \"gpt-5\", baseUrl: \"github-copilot:\" }),\n\t\tcreateModel({ provider: \"github-copilot\", id: \"claude-sonnet-4\", name: \"claude-sonnet-4\", baseUrl: \"github-copilot:\" }),\n\t];\n\n\tassert.ok(githubCopilotOAuthProvider.modifyModels, \"github copilot provider should expose modifyModels\");\n\tconst modified = githubCopilotOAuthProvider.modifyModels(models, makeCredentials());\n\n\tassert.equal(modified.length, 2, \"lack of limits should not hide every copilot model\");\n\tassert.ok(modified.every((model) => model.provider === \"github-copilot\"));\n\tassert.ok(modified.every((model) => model.baseUrl.includes(\"githubcopilot.com\")));\n});\n"]}
1
+ {"version":3,"file":"github-copilot.test.js","sourceRoot":"","sources":["../../../src/utils/oauth/github-copilot.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, test } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport type { Api, Model } from \"../../types.js\";\nimport type { OAuthCredentials } from \"./types.js\";\nimport {\n\tgetGitHubCopilotBaseUrl,\n\tgithubCopilotOAuthProvider,\n\tloginGitHubCopilot,\n\tnormalizeDomain,\n} from \"./github-copilot.js\";\n\nfunction createModel(overrides: Partial<Model<Api>> = {}): Model<Api> {\n\treturn {\n\t\tid: \"test-model\",\n\t\tname: \"Test Model\",\n\t\tapi: \"openai-completions\",\n\t\tprovider: \"test-provider\",\n\t\tbaseUrl: \"https://example.com\",\n\t\treasoning: false,\n\t\tinput: [\"text\"],\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 8192,\n\t\t...overrides,\n\t} as Model<Api>;\n}\n\nfunction makeCredentials(\n\toverrides: Partial<OAuthCredentials & { modelLimits?: Record<string, { contextWindow: number; maxTokens: number }> }> = {},\n) {\n\treturn {\n\t\taccess: \"copilot-token\",\n\t\trefresh: \"refresh-token\",\n\t\texpires: Date.now() + 60_000,\n\t\t...overrides,\n\t};\n}\n\ndescribe(\"GitHub Copilot OAuth — normalizeDomain\", () => {\n\ttest(\"returns null for empty input\", () => {\n\t\tassert.equal(normalizeDomain(\"\"), null);\n\t\tassert.equal(normalizeDomain(\" \"), null);\n\t});\n\n\ttest(\"returns null for invalid domain\", () => {\n\t\tassert.equal(normalizeDomain(\"not a domain!@#\"), null);\n\t});\n\n\ttest(\"extracts hostname from full URL\", () => {\n\t\tassert.equal(normalizeDomain(\"https://github.com\"), \"github.com\");\n\t\tassert.equal(normalizeDomain(\"https://company.ghe.com\"), \"company.ghe.com\");\n\t\tassert.equal(normalizeDomain(\"http://example.com/path\"), \"example.com\");\n\t});\n\n\ttest(\"returns domain as-is when no protocol\", () => {\n\t\tassert.equal(normalizeDomain(\"github.com\"), \"github.com\");\n\t\tassert.equal(normalizeDomain(\"company.ghe.com\"), \"company.ghe.com\");\n\t});\n\n\ttest(\"trims whitespace\", () => {\n\t\tassert.equal(normalizeDomain(\" github.com \"), \"github.com\");\n\t});\n});\n\ndescribe(\"GitHub Copilot OAuth — getBaseUrlFromToken\", () => {\n\ttest(\"extracts API URL from token with proxy-ep\", () => {\n\t\tconst token = \"tid=123;exp=1234567890;proxy-ep=proxy.individual.githubcopilot.com;other=value\";\n\t\tconst baseUrl = getGitHubCopilotBaseUrl(token);\n\t\tassert.equal(baseUrl, \"https://api.individual.githubcopilot.com\");\n\t});\n\n\ttest(\"extracts API URL from enterprise proxy-ep\", () => {\n\t\tconst token = \"tid=123;exp=1234567890;proxy-ep=proxy.company.ghe.com;other=value\";\n\t\tconst baseUrl = getGitHubCopilotBaseUrl(token);\n\t\tassert.equal(baseUrl, \"https://api.company.ghe.com\");\n\t});\n\n\ttest(\"falls back to default when no token provided\", () => {\n\t\tconst baseUrl = getGitHubCopilotBaseUrl();\n\t\tassert.equal(baseUrl, \"https://api.individual.githubcopilot.com\");\n\t});\n\n\ttest(\"falls back to default when token has no proxy-ep\", () => {\n\t\tconst token = \"tid=123;exp=1234567890;other=value\";\n\t\tconst baseUrl = getGitHubCopilotBaseUrl(token);\n\t\tassert.equal(baseUrl, \"https://api.individual.githubcopilot.com\");\n\t});\n\n\ttest(\"uses enterprise domain when provided\", () => {\n\t\tconst baseUrl = getGitHubCopilotBaseUrl(undefined, \"company.ghe.com\");\n\t\tassert.equal(baseUrl, \"https://copilot-api.company.ghe.com\");\n\t});\n\n\ttest(\"prioritizes token proxy-ep over enterprise domain\", () => {\n\t\tconst token = \"tid=123;exp=1234567890;proxy-ep=proxy.individual.githubcopilot.com;other=value\";\n\t\tconst baseUrl = getGitHubCopilotBaseUrl(token, \"company.ghe.com\");\n\t\tassert.equal(baseUrl, \"https://api.individual.githubcopilot.com\");\n\t});\n});\n\ndescribe(\"GitHub Copilot OAuth — provider structure\", () => {\n\ttest(\"has correct id and name\", () => {\n\t\tassert.equal(githubCopilotOAuthProvider.id, \"github-copilot\");\n\t\tassert.equal(githubCopilotOAuthProvider.name, \"GitHub Copilot\");\n\t});\n\n\ttest(\"has required methods\", () => {\n\t\tassert.equal(typeof githubCopilotOAuthProvider.login, \"function\");\n\t\tassert.equal(typeof githubCopilotOAuthProvider.refreshToken, \"function\");\n\t\tassert.equal(typeof githubCopilotOAuthProvider.getApiKey, \"function\");\n\t\tassert.equal(typeof githubCopilotOAuthProvider.modifyModels, \"function\");\n\t});\n\n\ttest(\"getApiKey returns access token\", () => {\n\t\tconst credentials: OAuthCredentials = {\n\t\t\taccess: \"test-access-token\",\n\t\t\trefresh: \"test-refresh-token\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t};\n\t\tconst apiKey = githubCopilotOAuthProvider.getApiKey(credentials);\n\t\tassert.equal(apiKey, \"test-access-token\");\n\t});\n\n\ttest(\"modifyModels preserves non-Copilot models\", () => {\n\t\tif (!githubCopilotOAuthProvider.modifyModels) return;\n\t\tconst models = [createModel({ id: \"gpt-4\", provider: \"openai\" })];\n\t\tconst credentials: OAuthCredentials = {\n\t\t\taccess: \"test-token\",\n\t\t\trefresh: \"test-refresh\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t};\n\t\tconst result = githubCopilotOAuthProvider.modifyModels(models, credentials);\n\t\tassert.deepEqual(result, models);\n\t});\n\n\ttest(\"modifyModels updates Copilot model baseUrl when token has proxy-ep\", () => {\n\t\tif (!githubCopilotOAuthProvider.modifyModels) return;\n\t\tconst models = [\n\t\t\tcreateModel({\n\t\t\t\tid: \"claude-3.5-sonnet\",\n\t\t\t\tprovider: \"github-copilot\",\n\t\t\t\tbaseUrl: \"https://api.default.com\",\n\t\t\t}),\n\t\t];\n\t\tconst credentials: OAuthCredentials = {\n\t\t\taccess: \"tid=123;exp=1234567890;proxy-ep=proxy.individual.githubcopilot.com;\",\n\t\t\trefresh: \"test-refresh\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t};\n\t\tconst result = githubCopilotOAuthProvider.modifyModels(models, credentials);\n\t\tassert.equal(result[0].baseUrl, \"https://api.individual.githubcopilot.com\");\n\t});\n\n\ttest(\"modifyModels applies model limits when available\", () => {\n\t\tif (!githubCopilotOAuthProvider.modifyModels) return;\n\t\tconst models = [\n\t\t\tcreateModel({\n\t\t\t\tid: \"claude-3.5-sonnet\",\n\t\t\t\tprovider: \"github-copilot\",\n\t\t\t\tbaseUrl: \"https://api.default.com\",\n\t\t\t}),\n\t\t];\n\t\tconst credentials = {\n\t\t\taccess: \"test-token\",\n\t\t\trefresh: \"test-refresh\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t\tmodelLimits: {\n\t\t\t\t\"claude-3.5-sonnet\": { contextWindow: 123456, maxTokens: 4096 },\n\t\t\t},\n\t\t};\n\t\tconst result = githubCopilotOAuthProvider.modifyModels(models, credentials);\n\t\tassert.equal(result[0].contextWindow, 123456);\n\t\tassert.equal(result[0].maxTokens, 4096);\n\t});\n});\n\ndescribe(\"GitHub Copilot OAuth — credential regression\", () => {\n\ttest(\"module imports successfully\", () => {\n\t\tassert.ok(githubCopilotOAuthProvider);\n\t});\n\n\ttest(\"device login sends the public OAuth client id without a client secret\", async (t) => {\n\t\tconst calls: Array<{ url: string; init: RequestInit }> = [];\n\t\tconst originalFetch = globalThis.fetch;\n\t\tt.after(() => {\n\t\t\tglobalThis.fetch = originalFetch;\n\t\t});\n\n\t\tglobalThis.fetch = async (input: string | URL | Request, init?: RequestInit) => {\n\t\t\tconst url = String(input);\n\t\t\tcalls.push({ url, init: init ?? {} });\n\n\t\t\tif (url.endsWith(\"/login/device/code\")) {\n\t\t\t\treturn Response.json({\n\t\t\t\t\tdevice_code: \"device-code\",\n\t\t\t\t\tuser_code: \"ABCD-EFGH\",\n\t\t\t\t\tverification_uri: \"https://github.com/login/device\",\n\t\t\t\t\tinterval: 1,\n\t\t\t\t\texpires_in: 600,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (url.endsWith(\"/login/oauth/access_token\")) {\n\t\t\t\treturn Response.json({ access_token: \"github-access-token\" });\n\t\t\t}\n\n\t\t\tif (url.endsWith(\"/copilot_internal/v2/token\")) {\n\t\t\t\treturn Response.json({\n\t\t\t\t\ttoken: \"tid=123;exp=1234567890;proxy-ep=proxy.individual.githubcopilot.com;\",\n\t\t\t\t\texpires_at: Math.floor(Date.now() / 1000) + 3600,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (url.endsWith(\"/models\")) {\n\t\t\t\treturn Response.json({ data: [] });\n\t\t\t}\n\n\t\t\tif (url.includes(\"/models/\") && url.endsWith(\"/policy\")) {\n\t\t\t\treturn Response.json({ ok: true });\n\t\t\t}\n\n\t\t\tthrow new Error(`Unexpected fetch: ${url}`);\n\t\t};\n\n\t\tconst credentials = await loginGitHubCopilot({\n\t\t\tonPrompt: async () => \"\",\n\t\t\tonAuth: () => {},\n\t\t});\n\n\t\tassert.equal(credentials.access, \"tid=123;exp=1234567890;proxy-ep=proxy.individual.githubcopilot.com;\");\n\t\tconst deviceCodeCall = calls.find((call) => call.url.endsWith(\"/login/device/code\"));\n\t\tassert.ok(deviceCodeCall, \"device-code request should be sent\");\n\t\tconst requestBody = deviceCodeCall.init.body;\n\t\tassert.equal(typeof requestBody, \"string\");\n\t\tconst body = JSON.parse(requestBody as string) as Record<string, unknown>;\n\t\tassert.equal(body.client_id, \"Iv1.b507a08c87ecfe98\");\n\t\tassert.equal(\"client_secret\" in body, false, \"GitHub device flow must not send a client secret\");\n\t});\n});\n\ntest(\"githubCopilotOAuthProvider.modifyModels filters unavailable copilot models (#3849)\", () => {\n\tconst models = [\n\t\tcreateModel({ provider: \"github-copilot\", id: \"gpt-5\", name: \"gpt-5\", baseUrl: \"github-copilot:\" }),\n\t\tcreateModel({ provider: \"github-copilot\", id: \"claude-sonnet-4\", name: \"claude-sonnet-4\", baseUrl: \"github-copilot:\" }),\n\t\tcreateModel({ provider: \"openai\", id: \"gpt-4.1\", name: \"gpt-4.1\", baseUrl: \"openai:\" }),\n\t];\n\n\tassert.ok(githubCopilotOAuthProvider.modifyModels, \"github copilot provider should expose modifyModels\");\n\tconst modified = githubCopilotOAuthProvider.modifyModels(\n\t\tmodels,\n\t\tmakeCredentials({\n\t\t\tmodelLimits: {\n\t\t\t\t\"gpt-5\": { contextWindow: 256000, maxTokens: 32000 },\n\t\t\t},\n\t\t}),\n\t);\n\n\tassert.deepEqual(\n\t\tmodified.map((model) => `${model.provider}/${model.id}`),\n\t\t[\"github-copilot/gpt-5\", \"openai/gpt-4.1\"],\n\t);\n\n\tconst copilotModel = modified.find((model) => model.provider === \"github-copilot\" && model.id === \"gpt-5\");\n\tassert.ok(copilotModel, \"available copilot model should remain\");\n\tassert.equal(copilotModel.contextWindow, 256000);\n\tassert.equal(copilotModel.maxTokens, 32000);\n\tassert.match(copilotModel.baseUrl, /githubcopilot\\.com/);\n});\n\ntest(\"githubCopilotOAuthProvider.modifyModels keeps all copilot models when limits are unavailable\", () => {\n\tconst models = [\n\t\tcreateModel({ provider: \"github-copilot\", id: \"gpt-5\", name: \"gpt-5\", baseUrl: \"github-copilot:\" }),\n\t\tcreateModel({ provider: \"github-copilot\", id: \"claude-sonnet-4\", name: \"claude-sonnet-4\", baseUrl: \"github-copilot:\" }),\n\t];\n\n\tassert.ok(githubCopilotOAuthProvider.modifyModels, \"github copilot provider should expose modifyModels\");\n\tconst modified = githubCopilotOAuthProvider.modifyModels(models, makeCredentials());\n\n\tassert.equal(modified.length, 2, \"lack of limits should not hide every copilot model\");\n\tassert.ok(modified.every((model) => model.provider === \"github-copilot\"));\n\tassert.ok(modified.every((model) => model.baseUrl.includes(\"githubcopilot.com\")));\n});\n"]}
@@ -1,17 +1,6 @@
1
1
  import { describe, test } from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { existsSync, readFileSync } from "node:fs";
4
- import { join } from "node:path";
5
- import { fileURLToPath } from "node:url";
6
3
  import { antigravityOAuthProvider } from "./google-antigravity.js";
7
- const __dirname = fileURLToPath(new URL(".", import.meta.url));
8
- const packageRoot = join(__dirname, "..", "..", "..");
9
- const sourceDir = existsSync(join(__dirname, "google-antigravity.ts"))
10
- ? __dirname
11
- : join(packageRoot, "src", "utils", "oauth");
12
- function readSourceFile(name) {
13
- return readFileSync(join(sourceDir, name), "utf-8");
14
- }
15
4
  describe("Antigravity OAuth — provider structure", () => {
16
5
  test("has correct id and name", () => {
17
6
  assert.equal(antigravityOAuthProvider.id, "google-antigravity");
@@ -52,16 +41,28 @@ describe("Antigravity OAuth — credential regression", () => {
52
41
  test("module imports successfully", () => {
53
42
  assert.ok(antigravityOAuthProvider);
54
43
  });
55
- test("CLIENT_ID and CLIENT_SECRET are plaintext", () => {
56
- const content = readSourceFile("google-antigravity.ts");
57
- assert.ok(content.includes('CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com"'));
58
- assert.ok(content.includes('CLIENT_SECRET = "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"'));
59
- assert.ok(!content.includes("atob("));
60
- });
61
- test("security explanation comments are present", () => {
62
- const content = readSourceFile("google-antigravity.ts");
63
- assert.ok(content.includes("NOTE: These credentials are public"));
64
- assert.ok(content.includes("obfuscated") || content.includes("security scanners"));
44
+ test("refreshToken sends the desktop OAuth client credentials to Google", async (t) => {
45
+ const calls = [];
46
+ const originalFetch = globalThis.fetch;
47
+ t.after(() => {
48
+ globalThis.fetch = originalFetch;
49
+ });
50
+ globalThis.fetch = async (_input, init) => {
51
+ calls.push(init ?? {});
52
+ return Response.json({ access_token: "new-access-token", expires_in: 3600 });
53
+ };
54
+ const credentials = await antigravityOAuthProvider.refreshToken({
55
+ access: "old-access-token",
56
+ refresh: "refresh-token",
57
+ expires: Date.now() + 3600000,
58
+ projectId: "test-project-123",
59
+ });
60
+ assert.equal(credentials.access, "new-access-token");
61
+ assert.equal(credentials.projectId, "test-project-123");
62
+ assert.ok(calls[0]?.body instanceof URLSearchParams);
63
+ const body = calls[0].body;
64
+ assert.equal(body.get("client_id"), "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com");
65
+ assert.equal(body.get("client_secret"), "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");
65
66
  });
66
67
  });
67
68
  //# sourceMappingURL=google-antigravity.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"google-antigravity.test.js","sourceRoot":"","sources":["../../../src/utils/oauth/google-antigravity.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, test } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { OAuthCredentials } from \"./types.js\";\nimport { antigravityOAuthProvider } from \"./google-antigravity.js\";\n\nconst __dirname = fileURLToPath(new URL(\".\", import.meta.url));\nconst packageRoot = join(__dirname, \"..\", \"..\", \"..\");\nconst sourceDir = existsSync(join(__dirname, \"google-antigravity.ts\"))\n\t? __dirname\n\t: join(packageRoot, \"src\", \"utils\", \"oauth\");\n\nfunction readSourceFile(name: string): string {\n\treturn readFileSync(join(sourceDir, name), \"utf-8\");\n}\n\ndescribe(\"Antigravity OAuth — provider structure\", () => {\n\ttest(\"has correct id and name\", () => {\n\t\tassert.equal(antigravityOAuthProvider.id, \"google-antigravity\");\n\t\tassert.equal(antigravityOAuthProvider.name, \"Antigravity (Gemini 3, Claude, GPT-OSS)\");\n\t});\n\n\ttest(\"uses callback server\", () => {\n\t\tassert.equal(antigravityOAuthProvider.usesCallbackServer, true);\n\t});\n\n\ttest(\"has required methods\", () => {\n\t\tassert.equal(typeof antigravityOAuthProvider.login, \"function\");\n\t\tassert.equal(typeof antigravityOAuthProvider.refreshToken, \"function\");\n\t\tassert.equal(typeof antigravityOAuthProvider.getApiKey, \"function\");\n\t});\n\n\ttest(\"getApiKey returns JSON with token and projectId\", () => {\n\t\tconst credentials: OAuthCredentials = {\n\t\t\taccess: \"test-access-token\",\n\t\t\trefresh: \"test-refresh-token\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t\tprojectId: \"test-project-123\",\n\t\t\temail: \"test@example.com\",\n\t\t};\n\t\tconst apiKey = antigravityOAuthProvider.getApiKey(credentials);\n\t\tassert.equal(typeof apiKey, \"string\");\n\t\tconst parsed = JSON.parse(apiKey);\n\t\tassert.equal(parsed.token, \"test-access-token\");\n\t\tassert.equal(parsed.projectId, \"test-project-123\");\n\t});\n\n\ttest(\"refreshToken throws when projectId is missing\", async () => {\n\t\tconst credentials: OAuthCredentials = {\n\t\t\taccess: \"test-access-token\",\n\t\t\trefresh: \"test-refresh-token\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t};\n\t\tawait assert.rejects(\n\t\t\tantigravityOAuthProvider.refreshToken(credentials),\n\t\t\t/Antigravity credentials missing projectId/,\n\t\t);\n\t});\n});\n\ndescribe(\"Antigravity OAuth — credential regression\", () => {\n\ttest(\"module imports successfully\", () => {\n\t\tassert.ok(antigravityOAuthProvider);\n\t});\n\n\ttest(\"CLIENT_ID and CLIENT_SECRET are plaintext\", () => {\n\t\tconst content = readSourceFile(\"google-antigravity.ts\");\n\t\tassert.ok(\n\t\t\tcontent.includes(\n\t\t\t\t'CLIENT_ID = \"1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com\"',\n\t\t\t),\n\t\t);\n\t\tassert.ok(content.includes('CLIENT_SECRET = \"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\"'));\n\t\tassert.ok(!content.includes(\"atob(\"));\n\t});\n\n\ttest(\"security explanation comments are present\", () => {\n\t\tconst content = readSourceFile(\"google-antigravity.ts\");\n\t\tassert.ok(content.includes(\"NOTE: These credentials are public\"));\n\t\tassert.ok(content.includes(\"obfuscated\") || content.includes(\"security scanners\"));\n\t});\n});"]}
1
+ {"version":3,"file":"google-antigravity.test.js","sourceRoot":"","sources":["../../../src/utils/oauth/google-antigravity.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, test } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport type { OAuthCredentials } from \"./types.js\";\nimport { antigravityOAuthProvider } from \"./google-antigravity.js\";\n\ndescribe(\"Antigravity OAuth — provider structure\", () => {\n\ttest(\"has correct id and name\", () => {\n\t\tassert.equal(antigravityOAuthProvider.id, \"google-antigravity\");\n\t\tassert.equal(antigravityOAuthProvider.name, \"Antigravity (Gemini 3, Claude, GPT-OSS)\");\n\t});\n\n\ttest(\"uses callback server\", () => {\n\t\tassert.equal(antigravityOAuthProvider.usesCallbackServer, true);\n\t});\n\n\ttest(\"has required methods\", () => {\n\t\tassert.equal(typeof antigravityOAuthProvider.login, \"function\");\n\t\tassert.equal(typeof antigravityOAuthProvider.refreshToken, \"function\");\n\t\tassert.equal(typeof antigravityOAuthProvider.getApiKey, \"function\");\n\t});\n\n\ttest(\"getApiKey returns JSON with token and projectId\", () => {\n\t\tconst credentials: OAuthCredentials = {\n\t\t\taccess: \"test-access-token\",\n\t\t\trefresh: \"test-refresh-token\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t\tprojectId: \"test-project-123\",\n\t\t\temail: \"test@example.com\",\n\t\t};\n\t\tconst apiKey = antigravityOAuthProvider.getApiKey(credentials);\n\t\tassert.equal(typeof apiKey, \"string\");\n\t\tconst parsed = JSON.parse(apiKey);\n\t\tassert.equal(parsed.token, \"test-access-token\");\n\t\tassert.equal(parsed.projectId, \"test-project-123\");\n\t});\n\n\ttest(\"refreshToken throws when projectId is missing\", async () => {\n\t\tconst credentials: OAuthCredentials = {\n\t\t\taccess: \"test-access-token\",\n\t\t\trefresh: \"test-refresh-token\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t};\n\t\tawait assert.rejects(\n\t\t\tantigravityOAuthProvider.refreshToken(credentials),\n\t\t\t/Antigravity credentials missing projectId/,\n\t\t);\n\t});\n});\n\ndescribe(\"Antigravity OAuth — credential regression\", () => {\n\ttest(\"module imports successfully\", () => {\n\t\tassert.ok(antigravityOAuthProvider);\n\t});\n\n\ttest(\"refreshToken sends the desktop OAuth client credentials to Google\", async (t) => {\n\t\tconst calls: RequestInit[] = [];\n\t\tconst originalFetch = globalThis.fetch;\n\t\tt.after(() => {\n\t\t\tglobalThis.fetch = originalFetch;\n\t\t});\n\t\tglobalThis.fetch = async (_input: string | URL | Request, init?: RequestInit) => {\n\t\t\tcalls.push(init ?? {});\n\t\t\treturn Response.json({ access_token: \"new-access-token\", expires_in: 3600 });\n\t\t};\n\n\t\tconst credentials = await antigravityOAuthProvider.refreshToken({\n\t\t\taccess: \"old-access-token\",\n\t\t\trefresh: \"refresh-token\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t\tprojectId: \"test-project-123\",\n\t\t});\n\n\t\tassert.equal(credentials.access, \"new-access-token\");\n\t\tassert.equal(credentials.projectId, \"test-project-123\");\n\t\tassert.ok(calls[0]?.body instanceof URLSearchParams);\n\t\tconst body = calls[0].body;\n\t\tassert.equal(body.get(\"client_id\"), \"1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com\");\n\t\tassert.equal(body.get(\"client_secret\"), \"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\");\n\t});\n});\n"]}
@@ -1,17 +1,6 @@
1
1
  import { describe, test } from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { existsSync, readFileSync } from "node:fs";
4
- import { join } from "node:path";
5
- import { fileURLToPath } from "node:url";
6
3
  import { geminiCliOAuthProvider } from "./google-gemini-cli.js";
7
- const __dirname = fileURLToPath(new URL(".", import.meta.url));
8
- const packageRoot = join(__dirname, "..", "..", "..");
9
- const sourceDir = existsSync(join(__dirname, "google-gemini-cli.ts"))
10
- ? __dirname
11
- : join(packageRoot, "src", "utils", "oauth");
12
- function readSourceFile(name) {
13
- return readFileSync(join(sourceDir, name), "utf-8");
14
- }
15
4
  describe("Gemini CLI OAuth — provider structure", () => {
16
5
  test("has correct id and name", () => {
17
6
  assert.equal(geminiCliOAuthProvider.id, "google-gemini-cli");
@@ -52,16 +41,28 @@ describe("Gemini CLI OAuth — credential regression", () => {
52
41
  test("module imports successfully", () => {
53
42
  assert.ok(geminiCliOAuthProvider);
54
43
  });
55
- test("CLIENT_ID and CLIENT_SECRET are plaintext", () => {
56
- const content = readSourceFile("google-gemini-cli.ts");
57
- assert.ok(content.includes('CLIENT_ID = "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com"'));
58
- assert.ok(content.includes('CLIENT_SECRET = "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"'));
59
- assert.ok(!content.includes("atob("));
60
- });
61
- test("security explanation comments are present", () => {
62
- const content = readSourceFile("google-gemini-cli.ts");
63
- assert.ok(content.includes("NOTE: These credentials are public"));
64
- assert.ok(content.includes("obfuscated") || content.includes("security scanners"));
44
+ test("refreshToken sends the desktop OAuth client credentials to Google", async (t) => {
45
+ const calls = [];
46
+ const originalFetch = globalThis.fetch;
47
+ t.after(() => {
48
+ globalThis.fetch = originalFetch;
49
+ });
50
+ globalThis.fetch = async (_input, init) => {
51
+ calls.push(init ?? {});
52
+ return Response.json({ access_token: "new-access-token", expires_in: 3600 });
53
+ };
54
+ const credentials = await geminiCliOAuthProvider.refreshToken({
55
+ access: "old-access-token",
56
+ refresh: "refresh-token",
57
+ expires: Date.now() + 3600000,
58
+ projectId: "test-project-456",
59
+ });
60
+ assert.equal(credentials.access, "new-access-token");
61
+ assert.equal(credentials.projectId, "test-project-456");
62
+ assert.ok(calls[0]?.body instanceof URLSearchParams);
63
+ const body = calls[0].body;
64
+ assert.equal(body.get("client_id"), "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com");
65
+ assert.equal(body.get("client_secret"), "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");
65
66
  });
66
67
  });
67
68
  //# sourceMappingURL=google-gemini-cli.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"google-gemini-cli.test.js","sourceRoot":"","sources":["../../../src/utils/oauth/google-gemini-cli.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, test } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { OAuthCredentials } from \"./types.js\";\nimport { geminiCliOAuthProvider } from \"./google-gemini-cli.js\";\n\nconst __dirname = fileURLToPath(new URL(\".\", import.meta.url));\nconst packageRoot = join(__dirname, \"..\", \"..\", \"..\");\nconst sourceDir = existsSync(join(__dirname, \"google-gemini-cli.ts\"))\n\t? __dirname\n\t: join(packageRoot, \"src\", \"utils\", \"oauth\");\n\nfunction readSourceFile(name: string): string {\n\treturn readFileSync(join(sourceDir, name), \"utf-8\");\n}\n\ndescribe(\"Gemini CLI OAuth — provider structure\", () => {\n\ttest(\"has correct id and name\", () => {\n\t\tassert.equal(geminiCliOAuthProvider.id, \"google-gemini-cli\");\n\t\tassert.equal(geminiCliOAuthProvider.name, \"Google Cloud Code Assist (Gemini CLI)\");\n\t});\n\n\ttest(\"uses callback server\", () => {\n\t\tassert.equal(geminiCliOAuthProvider.usesCallbackServer, true);\n\t});\n\n\ttest(\"has required methods\", () => {\n\t\tassert.equal(typeof geminiCliOAuthProvider.login, \"function\");\n\t\tassert.equal(typeof geminiCliOAuthProvider.refreshToken, \"function\");\n\t\tassert.equal(typeof geminiCliOAuthProvider.getApiKey, \"function\");\n\t});\n\n\ttest(\"getApiKey returns JSON with token and projectId\", () => {\n\t\tconst credentials: OAuthCredentials = {\n\t\t\taccess: \"test-access-token\",\n\t\t\trefresh: \"test-refresh-token\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t\tprojectId: \"test-project-456\",\n\t\t\temail: \"test@example.com\",\n\t\t};\n\t\tconst apiKey = geminiCliOAuthProvider.getApiKey(credentials);\n\t\tassert.equal(typeof apiKey, \"string\");\n\t\tconst parsed = JSON.parse(apiKey);\n\t\tassert.equal(parsed.token, \"test-access-token\");\n\t\tassert.equal(parsed.projectId, \"test-project-456\");\n\t});\n\n\ttest(\"refreshToken throws when projectId is missing\", async () => {\n\t\tconst credentials: OAuthCredentials = {\n\t\t\taccess: \"test-access-token\",\n\t\t\trefresh: \"test-refresh-token\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t};\n\t\tawait assert.rejects(\n\t\t\tgeminiCliOAuthProvider.refreshToken(credentials),\n\t\t\t/Google Cloud credentials missing projectId/,\n\t\t);\n\t});\n});\n\ndescribe(\"Gemini CLI OAuth — credential regression\", () => {\n\ttest(\"module imports successfully\", () => {\n\t\tassert.ok(geminiCliOAuthProvider);\n\t});\n\n\ttest(\"CLIENT_ID and CLIENT_SECRET are plaintext\", () => {\n\t\tconst content = readSourceFile(\"google-gemini-cli.ts\");\n\t\tassert.ok(\n\t\t\tcontent.includes(\n\t\t\t\t'CLIENT_ID = \"681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com\"',\n\t\t\t),\n\t\t);\n\t\tassert.ok(content.includes('CLIENT_SECRET = \"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\"'));\n\t\tassert.ok(!content.includes(\"atob(\"));\n\t});\n\n\ttest(\"security explanation comments are present\", () => {\n\t\tconst content = readSourceFile(\"google-gemini-cli.ts\");\n\t\tassert.ok(content.includes(\"NOTE: These credentials are public\"));\n\t\tassert.ok(content.includes(\"obfuscated\") || content.includes(\"security scanners\"));\n\t});\n});"]}
1
+ {"version":3,"file":"google-gemini-cli.test.js","sourceRoot":"","sources":["../../../src/utils/oauth/google-gemini-cli.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, test } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport type { OAuthCredentials } from \"./types.js\";\nimport { geminiCliOAuthProvider } from \"./google-gemini-cli.js\";\n\ndescribe(\"Gemini CLI OAuth — provider structure\", () => {\n\ttest(\"has correct id and name\", () => {\n\t\tassert.equal(geminiCliOAuthProvider.id, \"google-gemini-cli\");\n\t\tassert.equal(geminiCliOAuthProvider.name, \"Google Cloud Code Assist (Gemini CLI)\");\n\t});\n\n\ttest(\"uses callback server\", () => {\n\t\tassert.equal(geminiCliOAuthProvider.usesCallbackServer, true);\n\t});\n\n\ttest(\"has required methods\", () => {\n\t\tassert.equal(typeof geminiCliOAuthProvider.login, \"function\");\n\t\tassert.equal(typeof geminiCliOAuthProvider.refreshToken, \"function\");\n\t\tassert.equal(typeof geminiCliOAuthProvider.getApiKey, \"function\");\n\t});\n\n\ttest(\"getApiKey returns JSON with token and projectId\", () => {\n\t\tconst credentials: OAuthCredentials = {\n\t\t\taccess: \"test-access-token\",\n\t\t\trefresh: \"test-refresh-token\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t\tprojectId: \"test-project-456\",\n\t\t\temail: \"test@example.com\",\n\t\t};\n\t\tconst apiKey = geminiCliOAuthProvider.getApiKey(credentials);\n\t\tassert.equal(typeof apiKey, \"string\");\n\t\tconst parsed = JSON.parse(apiKey);\n\t\tassert.equal(parsed.token, \"test-access-token\");\n\t\tassert.equal(parsed.projectId, \"test-project-456\");\n\t});\n\n\ttest(\"refreshToken throws when projectId is missing\", async () => {\n\t\tconst credentials: OAuthCredentials = {\n\t\t\taccess: \"test-access-token\",\n\t\t\trefresh: \"test-refresh-token\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t};\n\t\tawait assert.rejects(\n\t\t\tgeminiCliOAuthProvider.refreshToken(credentials),\n\t\t\t/Google Cloud credentials missing projectId/,\n\t\t);\n\t});\n});\n\ndescribe(\"Gemini CLI OAuth — credential regression\", () => {\n\ttest(\"module imports successfully\", () => {\n\t\tassert.ok(geminiCliOAuthProvider);\n\t});\n\n\ttest(\"refreshToken sends the desktop OAuth client credentials to Google\", async (t) => {\n\t\tconst calls: RequestInit[] = [];\n\t\tconst originalFetch = globalThis.fetch;\n\t\tt.after(() => {\n\t\t\tglobalThis.fetch = originalFetch;\n\t\t});\n\t\tglobalThis.fetch = async (_input: string | URL | Request, init?: RequestInit) => {\n\t\t\tcalls.push(init ?? {});\n\t\t\treturn Response.json({ access_token: \"new-access-token\", expires_in: 3600 });\n\t\t};\n\n\t\tconst credentials = await geminiCliOAuthProvider.refreshToken({\n\t\t\taccess: \"old-access-token\",\n\t\t\trefresh: \"refresh-token\",\n\t\t\texpires: Date.now() + 3600000,\n\t\t\tprojectId: \"test-project-456\",\n\t\t});\n\n\t\tassert.equal(credentials.access, \"new-access-token\");\n\t\tassert.equal(credentials.projectId, \"test-project-456\");\n\t\tassert.ok(calls[0]?.body instanceof URLSearchParams);\n\t\tconst body = calls[0].body;\n\t\tassert.equal(body.get(\"client_id\"), \"681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com\");\n\t\tassert.equal(body.get(\"client_secret\"), \"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\");\n\t});\n});\n"]}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gsd/pi-ai",
3
- "version": "2.80.0",
3
+ "version": "2.81.0",
4
4
  "description": "Unified LLM API (vendored from pi-mono)",
5
5
  "type": "module",
6
6
  "gsd": {
@@ -1,12 +1,24 @@
1
1
  import test from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { readFileSync } from "node:fs";
4
- import { dirname, join } from "node:path";
5
- import { fileURLToPath } from "node:url";
3
+ import type { Model } from "../types.js";
6
4
 
7
- import { usesAnthropicBearerAuth, resolveAnthropicBaseUrl } from "./anthropic.js";
5
+ import { buildAnthropicClientOptions, usesAnthropicBearerAuth, resolveAnthropicBaseUrl } from "./anthropic.js";
8
6
 
9
- const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ function anthropicModel(overrides: Partial<Model<"anthropic-messages">> = {}): Model<"anthropic-messages"> {
8
+ return {
9
+ id: "claude-sonnet-4",
10
+ name: "Claude Sonnet 4",
11
+ api: "anthropic-messages",
12
+ provider: "anthropic",
13
+ baseUrl: "https://api.anthropic.com",
14
+ reasoning: true,
15
+ input: ["text"],
16
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
17
+ contextWindow: 200000,
18
+ maxTokens: 8192,
19
+ ...overrides,
20
+ };
21
+ }
10
22
 
11
23
  test("usesAnthropicBearerAuth covers Bearer-only Anthropic-compatible providers (#3783)", () => {
12
24
  assert.equal(usesAnthropicBearerAuth("alibaba-coding-plan"), true);
@@ -16,19 +28,10 @@ test("usesAnthropicBearerAuth covers Bearer-only Anthropic-compatible providers
16
28
  });
17
29
 
18
30
  test("createClient routes Bearer-auth providers through authToken (#3783)", () => {
19
- const source = readFileSync(join(__dirname, "..", "..", "src", "providers", "anthropic.ts"), "utf-8");
20
- assert.ok(
21
- source.includes("const usesBearerAuth = usesAnthropicBearerAuth(model.provider)"),
22
- "createClient should derive auth mode from usesAnthropicBearerAuth",
23
- );
24
- assert.ok(
25
- source.includes("apiKey: usesBearerAuth ? null : apiKey"),
26
- "Bearer-auth providers should skip x-api-key auth",
27
- );
28
- assert.ok(
29
- source.includes("authToken: usesBearerAuth ? apiKey : undefined"),
30
- "Bearer-auth providers should send authToken instead",
31
- );
31
+ const options = buildAnthropicClientOptions(anthropicModel({ provider: "minimax" }), "bearer-token", false);
32
+
33
+ assert.equal(options.apiKey, null, "Bearer-auth providers should skip x-api-key auth");
34
+ assert.equal(options.authToken, "bearer-token", "Bearer-auth providers should send authToken instead");
32
35
  });
33
36
 
34
37
  // Minimal model stub — only the field resolveAnthropicBaseUrl cares about.
@@ -68,11 +71,22 @@ test("resolveAnthropicBaseUrl ignores whitespace-only ANTHROPIC_BASE_URL (#4140)
68
71
  });
69
72
 
70
73
  test("createClient uses resolveAnthropicBaseUrl for all auth paths (#4140)", () => {
71
- const source = readFileSync(join(__dirname, "..", "..", "src", "providers", "anthropic.ts"), "utf-8");
72
- const directUsages = (source.match(/baseURL:\s*model\.baseUrl/g) ?? []).length;
73
- assert.equal(directUsages, 0, "createClient must not use model.baseUrl directly — use resolveAnthropicBaseUrl(model)");
74
- assert.ok(
75
- source.includes("baseURL: resolveAnthropicBaseUrl(model)"),
76
- "all createClient branches should pass baseURL through resolveAnthropicBaseUrl",
77
- );
74
+ const saved = process.env.ANTHROPIC_BASE_URL;
75
+ try {
76
+ process.env.ANTHROPIC_BASE_URL = "https://proxy.example.com";
77
+ const apiKeyOptions = buildAnthropicClientOptions(anthropicModel(), "api-key", false);
78
+ const bearerOptions = buildAnthropicClientOptions(anthropicModel({ provider: "minimax" }), "bearer-token", false);
79
+ const copilotOptions = buildAnthropicClientOptions(
80
+ anthropicModel({ provider: "github-copilot", baseUrl: "https://api.githubcopilot.com" }),
81
+ "copilot-token",
82
+ false,
83
+ );
84
+
85
+ assert.equal(apiKeyOptions.baseURL, "https://proxy.example.com");
86
+ assert.equal(bearerOptions.baseURL, "https://proxy.example.com");
87
+ assert.equal(copilotOptions.baseURL, "https://proxy.example.com");
88
+ } finally {
89
+ if (saved === undefined) delete process.env.ANTHROPIC_BASE_URL;
90
+ else process.env.ANTHROPIC_BASE_URL = saved;
91
+ }
78
92
  });
@@ -1,32 +1,36 @@
1
1
  import assert from "node:assert/strict";
2
2
  import { describe, it } from "node:test";
3
- import { existsSync, readFileSync } from "node:fs";
4
- import { join } from "node:path";
3
+ import type { Model } from "../types.js";
4
+ import { buildAnthropicClientOptions } from "./anthropic.js";
5
5
 
6
- function resolveSourcePath(fileName: string): string {
7
- const localPath = join(import.meta.dirname, fileName);
8
- if (existsSync(localPath)) return localPath;
9
- return join(import.meta.dirname, "..", "..", "src", "providers", fileName);
6
+ function anthropicModel(overrides: Partial<Model<"anthropic-messages">> = {}): Model<"anthropic-messages"> {
7
+ return {
8
+ id: "claude-sonnet-4",
9
+ name: "Claude Sonnet 4",
10
+ api: "anthropic-messages",
11
+ provider: "anthropic",
12
+ baseUrl: "https://api.anthropic.com",
13
+ reasoning: true,
14
+ input: ["text"],
15
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
16
+ contextWindow: 200000,
17
+ maxTokens: 8192,
18
+ ...overrides,
19
+ };
10
20
  }
11
21
 
12
- const source = readFileSync(resolveSourcePath("anthropic.ts"), "utf-8");
13
-
14
22
  describe("anthropic bearer auth for custom providers (#3874)", () => {
15
23
  it("treats Bearer Authorization headers as authToken-capable providers", () => {
16
- assert.match(
17
- source,
18
- /usesAnthropicBearerAuth\(model\.provider\) \|\| hasBearerAuthorizationHeader\(model\)/,
19
- "custom providers with Authorization headers should opt into bearer auth",
20
- );
21
- assert.match(
22
- source,
23
- /apiKey: usesBearerAuth \? null : apiKey/,
24
- "bearer-auth providers should not send x-api-key",
25
- );
26
- assert.match(
27
- source,
28
- /authToken: usesBearerAuth \? apiKey : undefined/,
29
- "bearer-auth providers should send authToken instead",
24
+ const options = buildAnthropicClientOptions(
25
+ anthropicModel({
26
+ provider: "custom-anthropic-compatible",
27
+ headers: { Authorization: "Bearer upstream-token" },
28
+ }),
29
+ "request-token",
30
+ false,
30
31
  );
32
+
33
+ assert.equal(options.apiKey, null, "custom providers with Authorization headers should not send x-api-key");
34
+ assert.equal(options.authToken, "request-token", "custom providers with Authorization headers should use authToken");
31
35
  });
32
36
  });
@@ -71,14 +71,13 @@ function hasBearerAuthorizationHeader(model: Model<"anthropic-messages">): boole
71
71
  return typeof authHeader === "string" && authHeader.trim().toLowerCase().startsWith("bearer ");
72
72
  }
73
73
 
74
- async function createClient(
74
+ export function buildAnthropicClientOptions(
75
75
  model: Model<"anthropic-messages">,
76
76
  apiKey: string,
77
77
  interleavedThinking: boolean,
78
78
  optionsHeaders?: Record<string, string>,
79
79
  dynamicHeaders?: Record<string, string>,
80
- ): Promise<{ client: Anthropic; isOAuthToken: boolean }> {
81
- const AnthropicClass = await getAnthropicClass();
80
+ ) {
82
81
  // Adaptive thinking models (Opus 4.6, Sonnet 4.6) have interleaved thinking built-in.
83
82
  // The beta header is deprecated on Opus 4.6 and redundant on Sonnet 4.6, so skip it.
84
83
  const needsInterleavedBeta = interleavedThinking && !supportsAdaptiveThinking(model.id);
@@ -90,7 +89,7 @@ async function createClient(
90
89
  betaFeatures.push("interleaved-thinking-2025-05-14");
91
90
  }
92
91
 
93
- const client = new AnthropicClass({
92
+ return {
94
93
  apiKey: null,
95
94
  authToken: apiKey,
96
95
  baseURL: resolveAnthropicBaseUrl(model),
@@ -105,9 +104,7 @@ async function createClient(
105
104
  dynamicHeaders,
106
105
  optionsHeaders,
107
106
  ),
108
- });
109
-
110
- return { client, isOAuthToken: false };
107
+ };
111
108
  }
112
109
 
113
110
  // Skip beta headers for providers that don't support fine-grained-tool-streaming.
@@ -126,7 +123,7 @@ async function createClient(
126
123
  // API key auth (Anthropic OAuth removed per TOS compliance — use API keys or Claude CLI)
127
124
  // Some Anthropic-compatible providers require Bearer auth instead of x-api-key.
128
125
  const usesBearerAuth = usesAnthropicBearerAuth(model.provider) || hasBearerAuthorizationHeader(model);
129
- const client = new AnthropicClass({
126
+ return {
130
127
  apiKey: usesBearerAuth ? null : apiKey,
131
128
  authToken: usesBearerAuth ? apiKey : undefined,
132
129
  baseURL: resolveAnthropicBaseUrl(model),
@@ -140,8 +137,24 @@ async function createClient(
140
137
  model.headers,
141
138
  optionsHeaders,
142
139
  ),
143
- });
140
+ };
141
+ }
144
142
 
143
+ async function createClient(
144
+ model: Model<"anthropic-messages">,
145
+ apiKey: string,
146
+ interleavedThinking: boolean,
147
+ optionsHeaders?: Record<string, string>,
148
+ dynamicHeaders?: Record<string, string>,
149
+ ): Promise<{ client: Anthropic; isOAuthToken: boolean }> {
150
+ const AnthropicClass = await getAnthropicClass();
151
+ const client = new AnthropicClass(buildAnthropicClientOptions(
152
+ model,
153
+ apiKey,
154
+ interleavedThinking,
155
+ optionsHeaders,
156
+ dynamicHeaders,
157
+ ));
145
158
  return { client, isOAuthToken: false };
146
159
  }
147
160