gsd-pi 2.80.0-dev.42bd34838 → 2.80.0-dev.488219eb6

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 (509) hide show
  1. package/dist/claude-cli-check.d.ts +30 -0
  2. package/dist/claude-cli-check.js +18 -7
  3. package/dist/cli.js +0 -19
  4. package/dist/headless-query.d.ts +10 -0
  5. package/dist/headless-query.js +6 -4
  6. package/dist/loader-entrypoint.d.ts +8 -0
  7. package/dist/loader-entrypoint.js +27 -0
  8. package/dist/loader.js +2 -11
  9. package/dist/mcp-server.d.ts +1 -0
  10. package/dist/mcp-server.js +6 -3
  11. package/dist/resources/.managed-resources-content-hash +1 -1
  12. package/dist/resources/extensions/claude-code-cli/readiness.js +18 -7
  13. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +29 -0
  14. package/dist/resources/extensions/github-sync/sync.js +4 -1
  15. package/dist/resources/extensions/gsd/auto/loop.js +71 -8
  16. package/dist/resources/extensions/gsd/auto/phases.js +179 -99
  17. package/dist/resources/extensions/gsd/auto/resolve.js +12 -0
  18. package/dist/resources/extensions/gsd/auto/run-unit.js +10 -30
  19. package/dist/resources/extensions/gsd/auto/session.js +8 -0
  20. package/dist/resources/extensions/gsd/auto/workflow-dispatch-claim.js +33 -1
  21. package/dist/resources/extensions/gsd/auto/workflow-worker-heartbeat.js +9 -1
  22. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +5 -32
  23. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -0
  24. package/dist/resources/extensions/gsd/auto-post-unit.js +94 -76
  25. package/dist/resources/extensions/gsd/auto-prompts.js +90 -15
  26. package/dist/resources/extensions/gsd/auto-start.js +238 -12
  27. package/dist/resources/extensions/gsd/auto-worktree.js +209 -81
  28. package/dist/resources/extensions/gsd/auto.js +95 -44
  29. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +96 -26
  30. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +44 -37
  31. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +37 -10
  32. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +6 -3
  33. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +4 -1
  34. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +6 -4
  35. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +5 -3
  36. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +1 -1
  37. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +298 -54
  38. package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +4 -0
  39. package/dist/resources/extensions/gsd/bootstrap/system-context.js +82 -23
  40. package/dist/resources/extensions/gsd/clean-root-preflight.js +24 -6
  41. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
  42. package/dist/resources/extensions/gsd/commands-config.js +1 -1
  43. package/dist/resources/extensions/gsd/commands-eval-review.js +2 -2
  44. package/dist/resources/extensions/gsd/commands-handlers.js +23 -9
  45. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
  46. package/dist/resources/extensions/gsd/db/unit-dispatches.js +53 -0
  47. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +2 -0
  48. package/dist/resources/extensions/gsd/git-service.js +37 -1
  49. package/dist/resources/extensions/gsd/guided-flow.js +61 -32
  50. package/dist/resources/extensions/gsd/init-wizard.js +4 -1
  51. package/dist/resources/extensions/gsd/native-git-bridge.js +32 -8
  52. package/dist/resources/extensions/gsd/orphan-stash-audit.js +101 -0
  53. package/dist/resources/extensions/gsd/parallel-orchestrator.js +13 -3
  54. package/dist/resources/extensions/gsd/pre-execution-checks.js +22 -0
  55. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +8 -4
  56. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  57. package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -2
  58. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  59. package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  60. package/dist/resources/extensions/gsd/slice-cadence.js +45 -2
  61. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +15 -9
  62. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -7
  63. package/dist/resources/extensions/gsd/tools/complete-task.js +1 -1
  64. package/dist/resources/extensions/gsd/workflow-protocol.js +131 -0
  65. package/dist/resources/extensions/gsd/worktree-resolver.js +57 -5
  66. package/dist/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  67. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  68. package/dist/web/standalone/.next/BUILD_ID +1 -1
  69. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  70. package/dist/web/standalone/.next/build-manifest.json +3 -3
  71. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  72. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  73. package/dist/web/standalone/.next/required-server-files.json +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/index.html +1 -1
  93. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  94. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  95. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  96. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  101. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/middleware.js +3 -3
  104. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  105. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  106. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  107. package/dist/web/standalone/.next/static/chunks/8359.e059d86b255fce1c.js +10 -0
  108. package/dist/web/standalone/.next/static/chunks/app/{page-fab3ebb85b006001.js → page-752f1e2ebdaa3e45.js} +1 -1
  109. package/dist/web/standalone/.next/static/chunks/{webpack-0481f1221120a7c6.js → webpack-de742b64187e13fe.js} +1 -1
  110. package/dist/web/standalone/server.js +1 -1
  111. package/dist/welcome-screen.d.ts +2 -0
  112. package/dist/welcome-screen.js +9 -7
  113. package/package.json +1 -1
  114. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  115. package/packages/pi-agent-core/dist/agent-loop.js +4 -1
  116. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  117. package/packages/pi-agent-core/dist/agent.d.ts +5 -0
  118. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  119. package/packages/pi-agent-core/dist/agent.js +2 -0
  120. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  121. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  122. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  123. package/packages/pi-agent-core/dist/index.js +2 -0
  124. package/packages/pi-agent-core/dist/index.js.map +1 -1
  125. package/packages/pi-agent-core/dist/token-audit.d.ts +47 -0
  126. package/packages/pi-agent-core/dist/token-audit.d.ts.map +1 -0
  127. package/packages/pi-agent-core/dist/token-audit.js +221 -0
  128. package/packages/pi-agent-core/dist/token-audit.js.map +1 -0
  129. package/packages/pi-agent-core/dist/types.d.ts +9 -0
  130. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  131. package/packages/pi-agent-core/dist/types.js.map +1 -1
  132. package/packages/pi-agent-core/src/agent-loop.test.ts +128 -0
  133. package/packages/pi-agent-core/src/agent-loop.ts +4 -1
  134. package/packages/pi-agent-core/src/agent.ts +8 -0
  135. package/packages/pi-agent-core/src/index.ts +2 -0
  136. package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
  137. package/packages/pi-agent-core/src/token-audit.ts +287 -0
  138. package/packages/pi-agent-core/src/types.ts +14 -0
  139. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  140. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +35 -13
  141. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  142. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +21 -11
  143. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -1
  144. package/packages/pi-ai/dist/providers/anthropic.d.ts +7 -0
  145. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  146. package/packages/pi-ai/dist/providers/anthropic.js +9 -7
  147. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  148. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +23 -14
  149. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -1
  150. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +48 -21
  151. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  152. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +22 -21
  153. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -1
  154. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +22 -21
  155. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -1
  156. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +39 -25
  157. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -22
  158. package/packages/pi-ai/src/providers/anthropic.ts +22 -9
  159. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +34 -21
  160. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +56 -22
  161. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +24 -28
  162. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +24 -28
  163. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  164. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +18 -0
  165. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  166. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +12 -0
  167. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  168. package/packages/pi-coding-agent/dist/core/agent-session.js +36 -7
  169. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +3 -1
  171. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  173. package/packages/pi-coding-agent/dist/core/extensions/loader.js +8 -0
  174. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  175. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -0
  176. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  177. package/packages/pi-coding-agent/dist/core/extensions/runner.js +3 -6
  178. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +3 -3
  180. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +34 -3
  182. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +2 -0
  185. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -1
  186. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts +2 -0
  187. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts.map +1 -0
  188. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js +46 -0
  189. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js.map +1 -0
  190. package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -2
  191. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  192. package/packages/pi-coding-agent/dist/core/sdk.js +74 -2
  193. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  194. package/packages/pi-coding-agent/dist/core/skill-tool.test.js +22 -0
  195. package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -7
  197. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  198. package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -3
  199. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  200. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +22 -56
  201. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +1 -0
  203. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  204. package/packages/pi-coding-agent/dist/core/tools/bash.js +3 -1
  205. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  206. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts +2 -0
  207. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  208. package/packages/pi-coding-agent/dist/core/tools/edit.js +12 -1
  209. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/core/tools/find.d.ts +2 -0
  211. package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  212. package/packages/pi-coding-agent/dist/core/tools/find.js +14 -6
  213. package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  214. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts +2 -0
  215. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
  216. package/packages/pi-coding-agent/dist/core/tools/grep.js +12 -3
  217. package/packages/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  218. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts +2 -0
  219. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
  220. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +3 -1
  221. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
  222. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -1
  223. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  224. package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
  225. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  226. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts +2 -0
  227. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
  228. package/packages/pi-coding-agent/dist/core/tools/ls.js +10 -3
  229. package/packages/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
  230. package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -0
  231. package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  232. package/packages/pi-coding-agent/dist/core/tools/read.js +3 -1
  233. package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  234. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +7 -62
  235. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -1
  236. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts +2 -0
  237. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts.map +1 -0
  238. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js +115 -0
  239. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js.map +1 -0
  240. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts +19 -0
  241. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts.map +1 -0
  242. package/packages/pi-coding-agent/dist/core/tools/tool-target.js +20 -0
  243. package/packages/pi-coding-agent/dist/core/tools/tool-target.js.map +1 -0
  244. package/packages/pi-coding-agent/dist/core/tools/write.d.ts +4 -0
  245. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  246. package/packages/pi-coding-agent/dist/core/tools/write.js +9 -1
  247. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  248. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +89 -2
  249. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  250. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +25 -1
  251. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  252. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +5 -0
  253. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  254. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +153 -8
  255. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  256. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  257. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +18 -1
  258. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  259. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +23 -5
  260. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  261. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
  262. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  263. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +19 -0
  264. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  265. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +23 -5
  266. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -1
  267. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +25 -0
  268. package/packages/pi-coding-agent/src/core/agent-session.ts +40 -7
  269. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
  270. package/packages/pi-coding-agent/src/core/extensions/loader.ts +10 -0
  271. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +3 -3
  272. package/packages/pi-coding-agent/src/core/extensions/runner.ts +5 -5
  273. package/packages/pi-coding-agent/src/core/extensions/types.ts +37 -2
  274. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +2 -0
  275. package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
  276. package/packages/pi-coding-agent/src/core/sdk.ts +85 -3
  277. package/packages/pi-coding-agent/src/core/skill-tool.test.ts +28 -0
  278. package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -10
  279. package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +22 -66
  280. package/packages/pi-coding-agent/src/core/tools/bash.ts +4 -1
  281. package/packages/pi-coding-agent/src/core/tools/edit.ts +13 -1
  282. package/packages/pi-coding-agent/src/core/tools/find.ts +15 -6
  283. package/packages/pi-coding-agent/src/core/tools/grep.ts +13 -3
  284. package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +4 -1
  285. package/packages/pi-coding-agent/src/core/tools/index.ts +8 -0
  286. package/packages/pi-coding-agent/src/core/tools/ls.ts +11 -3
  287. package/packages/pi-coding-agent/src/core/tools/read.ts +4 -1
  288. package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +11 -72
  289. package/packages/pi-coding-agent/src/core/tools/tool-target-metadata.test.ts +127 -0
  290. package/packages/pi-coding-agent/src/core/tools/tool-target.ts +48 -0
  291. package/packages/pi-coding-agent/src/core/tools/write.ts +14 -2
  292. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +119 -2
  293. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +31 -1
  294. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +177 -8
  295. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +24 -5
  296. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +17 -1
  297. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +21 -0
  298. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +25 -8
  299. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  300. package/src/resources/extensions/claude-code-cli/readiness.ts +25 -7
  301. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +30 -0
  302. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +26 -0
  303. package/src/resources/extensions/github-sync/sync.ts +8 -1
  304. package/src/resources/extensions/github-sync/tests/sync-source.test.ts +6 -18
  305. package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -2
  306. package/src/resources/extensions/gsd/auto/loop.ts +84 -8
  307. package/src/resources/extensions/gsd/auto/phases.ts +258 -159
  308. package/src/resources/extensions/gsd/auto/resolve.ts +19 -0
  309. package/src/resources/extensions/gsd/auto/run-unit.ts +10 -29
  310. package/src/resources/extensions/gsd/auto/session.ts +8 -0
  311. package/src/resources/extensions/gsd/auto/workflow-dispatch-claim.ts +63 -1
  312. package/src/resources/extensions/gsd/auto/workflow-worker-heartbeat.ts +14 -1
  313. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -34
  314. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -0
  315. package/src/resources/extensions/gsd/auto-post-unit.ts +107 -78
  316. package/src/resources/extensions/gsd/auto-prompts.ts +95 -14
  317. package/src/resources/extensions/gsd/auto-start.ts +286 -15
  318. package/src/resources/extensions/gsd/auto-worktree.ts +241 -72
  319. package/src/resources/extensions/gsd/auto.ts +132 -40
  320. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +116 -24
  321. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +45 -37
  322. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +36 -10
  323. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +8 -3
  324. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +5 -1
  325. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +7 -4
  326. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +6 -3
  327. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +1 -1
  328. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +347 -54
  329. package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +4 -0
  330. package/src/resources/extensions/gsd/bootstrap/system-context.ts +90 -22
  331. package/src/resources/extensions/gsd/clean-root-preflight.ts +32 -7
  332. package/src/resources/extensions/gsd/commands/handlers/ops.ts +4 -2
  333. package/src/resources/extensions/gsd/commands-config.ts +1 -1
  334. package/src/resources/extensions/gsd/commands-eval-review.ts +2 -2
  335. package/src/resources/extensions/gsd/commands-handlers.ts +34 -15
  336. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
  337. package/src/resources/extensions/gsd/db/unit-dispatches.ts +66 -0
  338. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +3 -0
  339. package/src/resources/extensions/gsd/git-service.ts +41 -2
  340. package/src/resources/extensions/gsd/guided-flow.ts +71 -39
  341. package/src/resources/extensions/gsd/init-wizard.ts +5 -1
  342. package/src/resources/extensions/gsd/native-git-bridge.ts +39 -6
  343. package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
  344. package/src/resources/extensions/gsd/parallel-orchestrator.ts +13 -3
  345. package/src/resources/extensions/gsd/pre-execution-checks.ts +23 -0
  346. package/src/resources/extensions/gsd/prompts/complete-milestone.md +8 -4
  347. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  348. package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
  349. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  350. package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  351. package/src/resources/extensions/gsd/slice-cadence.ts +49 -2
  352. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +23 -9
  353. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +59 -89
  354. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +47 -172
  355. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +0 -35
  356. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +35 -9
  357. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +361 -10
  358. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +80 -59
  359. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +3 -47
  360. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +76 -18
  361. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +106 -0
  362. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +54 -95
  363. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +67 -26
  364. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +32 -30
  365. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +32 -128
  366. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +20 -54
  367. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +20 -30
  368. package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +17 -29
  369. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +138 -0
  370. package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +21 -39
  371. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +15 -24
  372. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +44 -29
  373. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +39 -51
  374. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +159 -213
  375. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +15 -32
  376. package/src/resources/extensions/gsd/tests/browser-teardown.test.ts +0 -41
  377. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +15 -6
  378. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +34 -27
  379. package/src/resources/extensions/gsd/tests/cmux.test.ts +51 -53
  380. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +39 -61
  381. package/src/resources/extensions/gsd/tests/commands-config.test.ts +26 -19
  382. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
  383. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +140 -0
  384. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
  385. package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +29 -33
  386. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +45 -108
  387. package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -1
  388. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +35 -31
  389. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +5 -1
  390. package/src/resources/extensions/gsd/tests/cwd-fallback-hardening.test.ts +138 -0
  391. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +4 -68
  392. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +4 -9
  393. package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +14 -65
  394. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +44 -37
  395. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +58 -40
  396. package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +25 -15
  397. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +35 -17
  398. package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +16 -21
  399. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +15 -82
  400. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +5 -2
  401. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
  402. package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +132 -0
  403. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +2 -20
  404. package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +18 -26
  405. package/src/resources/extensions/gsd/tests/init-skip-git.test.ts +9 -12
  406. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +40 -0
  407. package/src/resources/extensions/gsd/tests/integration/commands-eval-review.integration.test.ts +4 -2
  408. package/src/resources/extensions/gsd/tests/integration/git-locale.test.ts +31 -20
  409. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +12 -0
  410. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +0 -47
  411. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +60 -202
  412. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +13 -56
  413. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +5 -1
  414. package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +32 -0
  415. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -0
  416. package/src/resources/extensions/gsd/tests/lazy-pi-tui-import.test.ts +44 -6
  417. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +21 -35
  418. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +1 -0
  419. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +242 -0
  420. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +79 -98
  421. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +70 -278
  422. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
  423. package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +37 -30
  424. package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +32 -28
  425. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -0
  426. package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +133 -0
  427. package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
  428. package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -0
  429. package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +24 -37
  430. package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +9 -24
  431. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +91 -75
  432. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +36 -22
  433. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +36 -30
  434. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +45 -5
  435. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +74 -4
  436. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +20 -22
  437. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +130 -32
  438. package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +18 -36
  439. package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +35 -73
  440. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +76 -138
  441. package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
  442. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +70 -125
  443. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +59 -161
  444. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +33 -29
  445. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +22 -196
  446. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +23 -93
  447. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +50 -79
  448. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +27 -13
  449. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +151 -251
  450. package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +41 -29
  451. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +58 -69
  452. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +32 -164
  453. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +57 -41
  454. package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
  455. package/src/resources/extensions/gsd/tests/session-model-override.test.ts +14 -9
  456. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +77 -0
  457. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +166 -0
  458. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +44 -42
  459. package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +56 -24
  460. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +51 -11
  461. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +23 -0
  462. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +66 -50
  463. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +68 -107
  464. package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +115 -42
  465. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +21 -97
  466. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +25 -116
  467. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +21 -57
  468. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +29 -76
  469. package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +33 -24
  470. package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +39 -30
  471. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
  472. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +33 -47
  473. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +48 -46
  474. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +14 -102
  475. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +78 -232
  476. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +32 -35
  477. package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
  478. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +7 -9
  479. package/src/resources/extensions/gsd/tests/token-profile.test.ts +84 -309
  480. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +291 -0
  481. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +134 -341
  482. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +8 -25
  483. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +50 -1
  484. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -99
  485. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +43 -36
  486. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -444
  487. package/src/resources/extensions/gsd/tests/workflow-dispatch-claim.test.ts +142 -0
  488. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +44 -189
  489. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -57
  490. package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
  491. package/src/resources/extensions/gsd/tests/workflow-worker-heartbeat.test.ts +32 -1
  492. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +21 -44
  493. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +27 -26
  494. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +14 -13
  495. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +1 -0
  496. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -18
  497. package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +22 -19
  498. package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
  499. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +140 -3
  500. package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -13
  501. package/src/resources/extensions/gsd/tools/complete-milestone.ts +14 -15
  502. package/src/resources/extensions/gsd/tools/complete-task.ts +1 -1
  503. package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
  504. package/src/resources/extensions/gsd/worktree-resolver.ts +83 -5
  505. package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +86 -40
  506. package/src/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  507. package/dist/web/standalone/.next/static/chunks/8336.631939fb583761fa.js +0 -10
  508. /package/dist/web/standalone/.next/static/{tht0ltP8EIjsohPOA_WZf → G68KoLv5claox_Dyd4pZn}/_buildManifest.js +0 -0
  509. /package/dist/web/standalone/.next/static/{tht0ltP8EIjsohPOA_WZf → G68KoLv5claox_Dyd4pZn}/_ssgManifest.js +0 -0
@@ -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,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
 
@@ -12,40 +12,53 @@
12
12
  */
13
13
  import test, { describe } from "node:test";
14
14
  import assert from "node:assert/strict";
15
- import { existsSync, readFileSync } from "node:fs";
16
- import { dirname, join } from "node:path";
17
- import { fileURLToPath } from "node:url";
15
+ import { buildAnthropicClientOptions } from "./anthropic.js";
18
16
  import { convertMessages } from "./anthropic-shared.js";
17
+ import type { Model } from "../types.js";
19
18
  import type { AssistantMessage } from "../types.js";
20
19
 
21
- const __dirname = dirname(fileURLToPath(import.meta.url));
22
-
23
- function resolveSourcePath(fileName: string): string {
24
- const localPath = join(__dirname, fileName);
25
- if (existsSync(localPath)) return localPath;
26
- return join(__dirname, "..", "..", "src", "providers", fileName);
20
+ function anthropicModel(overrides: Partial<Model<"anthropic-messages">> = {}): Model<"anthropic-messages"> {
21
+ return {
22
+ id: "claude-sonnet-4",
23
+ name: "Claude Sonnet 4",
24
+ api: "anthropic-messages",
25
+ provider: "anthropic",
26
+ baseUrl: "https://api.anthropic.com",
27
+ reasoning: true,
28
+ input: ["text"],
29
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
30
+ contextWindow: 200000,
31
+ maxTokens: 8192,
32
+ ...overrides,
33
+ };
27
34
  }
28
35
 
29
- const source = readFileSync(resolveSourcePath("anthropic.ts"), "utf-8");
30
-
31
36
  describe("MiniMax fine-grained-tool-streaming exclusion (#4538)", () => {
32
37
  test("minimax is excluded from fine-grained-tool-streaming-2025-05-14 beta", () => {
33
- // The skipBetaHeaders flag must include minimax so it never receives the
34
- // fine-grained-tool-streaming beta that causes empty tool names.
35
- assert.match(
36
- source,
37
- /skipBetaHeaders.*minimax/s,
38
- "minimax must be included in skipBetaHeaders to suppress fine-grained-tool-streaming",
38
+ const options = buildAnthropicClientOptions(anthropicModel({ provider: "minimax" }), "api-key", false);
39
+
40
+ assert.equal(
41
+ options.defaultHeaders["anthropic-beta"],
42
+ undefined,
43
+ "minimax must suppress fine-grained-tool-streaming",
39
44
  );
40
45
  });
41
46
 
42
47
  test("minimax-cn is excluded from fine-grained-tool-streaming-2025-05-14 beta", () => {
43
- assert.match(
44
- source,
45
- /skipBetaHeaders.*minimax-cn/s,
46
- "minimax-cn must be included in skipBetaHeaders to suppress fine-grained-tool-streaming",
48
+ const options = buildAnthropicClientOptions(anthropicModel({ provider: "minimax-cn" }), "api-key", false);
49
+
50
+ assert.equal(
51
+ options.defaultHeaders["anthropic-beta"],
52
+ undefined,
53
+ "minimax-cn must suppress fine-grained-tool-streaming",
47
54
  );
48
55
  });
56
+
57
+ test("standard Anthropic-compatible providers keep fine-grained-tool-streaming enabled", () => {
58
+ const options = buildAnthropicClientOptions(anthropicModel(), "api-key", false);
59
+
60
+ assert.equal(options.defaultHeaders["anthropic-beta"], "fine-grained-tool-streaming-2025-05-14");
61
+ });
49
62
  });
50
63
 
51
64
  describe("empty tool name guard in convertMessages (#4538)", () => {