gsd-pi 2.76.0 → 2.77.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (536) hide show
  1. package/README.md +45 -25
  2. package/dist/claude-cli-check.js +32 -3
  3. package/dist/mcp-server.d.ts +7 -0
  4. package/dist/mcp-server.js +35 -1
  5. package/dist/onboarding.js +45 -0
  6. package/dist/resource-loader.d.ts +1 -1
  7. package/dist/resource-loader.js +2 -8
  8. package/dist/resources/agents/researcher.md +1 -1
  9. package/dist/resources/extensions/claude-code-cli/readiness.js +31 -8
  10. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +77 -17
  11. package/dist/resources/extensions/gsd/auto/loop.js +9 -0
  12. package/dist/resources/extensions/gsd/auto/phases.js +104 -11
  13. package/dist/resources/extensions/gsd/auto/run-unit.js +38 -2
  14. package/dist/resources/extensions/gsd/auto/session.js +22 -1
  15. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -3
  16. package/dist/resources/extensions/gsd/auto-model-selection.js +53 -16
  17. package/dist/resources/extensions/gsd/auto-post-unit.js +25 -2
  18. package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
  19. package/dist/resources/extensions/gsd/auto-recovery.js +32 -1
  20. package/dist/resources/extensions/gsd/auto-start.js +58 -57
  21. package/dist/resources/extensions/gsd/auto-verification.js +33 -0
  22. package/dist/resources/extensions/gsd/auto-worktree.js +51 -53
  23. package/dist/resources/extensions/gsd/auto.js +70 -28
  24. package/dist/resources/extensions/gsd/blocked-models.js +68 -0
  25. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +93 -1
  26. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +39 -9
  27. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
  28. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +3 -0
  29. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +12 -0
  30. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +52 -6
  31. package/dist/resources/extensions/gsd/bootstrap/system-context.js +84 -23
  32. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
  33. package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
  34. package/dist/resources/extensions/gsd/commands-extract-learnings.js +54 -89
  35. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
  36. package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
  37. package/dist/resources/extensions/gsd/complexity-classifier.js +5 -3
  38. package/dist/resources/extensions/gsd/db-writer.js +88 -16
  39. package/dist/resources/extensions/gsd/doctor-git-checks.js +23 -29
  40. package/dist/resources/extensions/gsd/doctor-providers.js +51 -5
  41. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +1 -0
  42. package/dist/resources/extensions/gsd/error-classifier.js +31 -3
  43. package/dist/resources/extensions/gsd/exec-history.js +120 -0
  44. package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
  45. package/dist/resources/extensions/gsd/gitignore.js +1 -0
  46. package/dist/resources/extensions/gsd/gsd-db.js +168 -23
  47. package/dist/resources/extensions/gsd/guided-flow.js +190 -1
  48. package/dist/resources/extensions/gsd/health-widget.js +4 -1
  49. package/dist/resources/extensions/gsd/hook-emitter.js +108 -0
  50. package/dist/resources/extensions/gsd/init-wizard.js +15 -1
  51. package/dist/resources/extensions/gsd/key-manager.js +28 -0
  52. package/dist/resources/extensions/gsd/memory-backfill.js +126 -0
  53. package/dist/resources/extensions/gsd/memory-store.js +19 -0
  54. package/dist/resources/extensions/gsd/model-router.js +36 -3
  55. package/dist/resources/extensions/gsd/pre-execution-checks.js +44 -9
  56. package/dist/resources/extensions/gsd/preferences-types.js +9 -0
  57. package/dist/resources/extensions/gsd/preferences-validation.js +83 -0
  58. package/dist/resources/extensions/gsd/preferences.js +17 -17
  59. package/dist/resources/extensions/gsd/prompt-loader.js +22 -7
  60. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  61. package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  62. package/dist/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
  63. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  64. package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
  65. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -2
  66. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  67. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  68. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -0
  69. package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
  70. package/dist/resources/extensions/gsd/safety/file-change-validator.js +13 -5
  71. package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
  72. package/dist/resources/extensions/gsd/state.js +43 -4
  73. package/dist/resources/extensions/gsd/token-counter.js +22 -5
  74. package/dist/resources/extensions/gsd/tools/complete-milestone.js +16 -10
  75. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
  76. package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
  77. package/dist/resources/extensions/gsd/tools/memory-tools.js +26 -1
  78. package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
  79. package/dist/resources/extensions/gsd/uok/plan-v2.js +20 -3
  80. package/dist/resources/extensions/gsd/workflow-mcp.js +3 -0
  81. package/dist/resources/extensions/gsd/workflow-templates/spike.md +6 -0
  82. package/dist/resources/extensions/gsd/worktree-resolver.js +50 -10
  83. package/dist/resources/extensions/search-the-web/command-search-provider.js +5 -4
  84. package/dist/resources/extensions/search-the-web/native-search.js +45 -13
  85. package/dist/resources/skills/api-design/SKILL.md +190 -0
  86. package/dist/resources/skills/create-mcp-server/SKILL.md +121 -0
  87. package/dist/resources/skills/decompose-into-slices/SKILL.md +139 -0
  88. package/dist/resources/skills/dependency-upgrade/SKILL.md +158 -0
  89. package/dist/resources/skills/design-an-interface/SKILL.md +102 -0
  90. package/dist/resources/skills/forensics/SKILL.md +153 -0
  91. package/dist/resources/skills/grill-me/SKILL.md +93 -0
  92. package/dist/resources/skills/handoff/SKILL.md +121 -0
  93. package/dist/resources/skills/observability/SKILL.md +174 -0
  94. package/dist/resources/skills/security-review/SKILL.md +181 -0
  95. package/dist/resources/skills/spike-wrap-up/SKILL.md +138 -0
  96. package/dist/resources/skills/tdd/SKILL.md +112 -0
  97. package/dist/resources/skills/verify-before-complete/SKILL.md +98 -0
  98. package/dist/resources/skills/write-docs/SKILL.md +82 -0
  99. package/dist/resources/skills/write-milestone-brief/SKILL.md +135 -0
  100. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  101. package/dist/web/standalone/.next/BUILD_ID +1 -1
  102. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  103. package/dist/web/standalone/.next/build-manifest.json +2 -2
  104. package/dist/web/standalone/.next/required-server-files.json +1 -1
  105. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/index.html +1 -1
  122. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  129. package/dist/web/standalone/.next/server/chunks/6897.js +2 -2
  130. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/middleware-manifest.json +1 -1
  132. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  133. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  134. package/dist/web/standalone/server.js +1 -1
  135. package/dist/welcome-screen.js +6 -1
  136. package/dist/wizard.js +2 -0
  137. package/package.json +1 -1
  138. package/packages/daemon/package.json +2 -2
  139. package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
  140. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
  141. package/packages/mcp-server/dist/remote-questions.js +732 -0
  142. package/packages/mcp-server/dist/remote-questions.js.map +1 -0
  143. package/packages/mcp-server/dist/server.d.ts +7 -0
  144. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  145. package/packages/mcp-server/dist/server.js +70 -8
  146. package/packages/mcp-server/dist/server.js.map +1 -1
  147. package/packages/mcp-server/dist/session-manager.d.ts +14 -0
  148. package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
  149. package/packages/mcp-server/dist/session-manager.js +49 -1
  150. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  151. package/packages/mcp-server/dist/workflow-tools.d.ts +1 -1
  152. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  153. package/packages/mcp-server/dist/workflow-tools.js +163 -25
  154. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  155. package/packages/mcp-server/package.json +4 -3
  156. package/packages/mcp-server/src/mcp-server.test.ts +67 -0
  157. package/packages/mcp-server/src/remote-questions.test.ts +294 -0
  158. package/packages/mcp-server/src/remote-questions.ts +916 -0
  159. package/packages/mcp-server/src/server.ts +89 -14
  160. package/packages/mcp-server/src/session-manager.ts +43 -1
  161. package/packages/mcp-server/src/workflow-tools.test.ts +146 -1
  162. package/packages/mcp-server/src/workflow-tools.ts +215 -43
  163. package/packages/mcp-server/tsconfig.test.json +19 -0
  164. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  165. package/packages/native/package.json +1 -1
  166. package/packages/pi-agent-core/dist/agent-loop.js +12 -0
  167. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  168. package/packages/pi-agent-core/dist/types.d.ts +30 -0
  169. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  170. package/packages/pi-agent-core/dist/types.js.map +1 -1
  171. package/packages/pi-agent-core/package.json +1 -1
  172. package/packages/pi-agent-core/src/agent-loop.ts +14 -0
  173. package/packages/pi-agent-core/src/types.ts +34 -0
  174. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  175. package/packages/pi-ai/dist/models/custom.d.ts +38 -0
  176. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -1
  177. package/packages/pi-ai/dist/models/custom.js +41 -0
  178. package/packages/pi-ai/dist/models/custom.js.map +1 -1
  179. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
  180. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  181. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts +2 -0
  182. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts.map +1 -0
  183. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +13 -0
  184. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -0
  185. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  186. package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
  187. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  188. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  189. package/packages/pi-ai/dist/providers/anthropic.js +13 -4
  190. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  191. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
  192. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
  193. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
  194. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
  195. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  196. package/packages/pi-ai/dist/providers/openai-completions.js +60 -15
  197. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  198. package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
  199. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  200. package/packages/pi-ai/dist/providers/simple-options.js +16 -1
  201. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  202. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts +17 -0
  203. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts.map +1 -0
  204. package/packages/pi-ai/dist/providers/think-tag-parser.js +75 -0
  205. package/packages/pi-ai/dist/providers/think-tag-parser.js.map +1 -0
  206. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts +2 -0
  207. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts.map +1 -0
  208. package/packages/pi-ai/dist/providers/think-tag-parser.test.js +41 -0
  209. package/packages/pi-ai/dist/providers/think-tag-parser.test.js.map +1 -0
  210. package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  211. package/packages/pi-ai/dist/utils/oauth/github-copilot.js +12 -2
  212. package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  213. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +164 -14
  214. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  215. package/packages/pi-ai/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
  216. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js +15 -3
  217. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js.map +1 -1
  218. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts +2 -0
  219. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts.map +1 -0
  220. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +67 -0
  221. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -0
  222. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
  223. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js +16 -3
  224. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js.map +1 -1
  225. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts +2 -0
  226. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts.map +1 -0
  227. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +67 -0
  228. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -0
  229. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +2 -0
  230. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +1 -0
  231. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +289 -0
  232. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +1 -0
  233. package/packages/pi-ai/package.json +1 -1
  234. package/packages/pi-ai/src/models/custom.ts +42 -0
  235. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
  236. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -0
  237. package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
  238. package/packages/pi-ai/src/providers/anthropic.ts +15 -4
  239. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
  240. package/packages/pi-ai/src/providers/openai-completions.ts +57 -16
  241. package/packages/pi-ai/src/providers/simple-options.ts +17 -1
  242. package/packages/pi-ai/src/providers/think-tag-parser.test.ts +44 -0
  243. package/packages/pi-ai/src/providers/think-tag-parser.ts +94 -0
  244. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +200 -23
  245. package/packages/pi-ai/src/utils/oauth/github-copilot.ts +12 -2
  246. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +84 -0
  247. package/packages/pi-ai/src/utils/oauth/google-antigravity.ts +15 -5
  248. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +84 -0
  249. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.ts +16 -5
  250. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +363 -0
  251. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  252. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +3 -2
  253. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  254. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +2 -0
  255. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  256. package/packages/pi-coding-agent/dist/core/agent-session.js +32 -2
  257. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  258. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  259. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  260. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  261. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  262. package/packages/pi-coding-agent/dist/core/extensions/loader.js +4 -0
  263. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  264. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +35 -2
  265. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/core/extensions/runner.js +233 -0
  267. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  268. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +205 -2
  269. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  270. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  271. package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts +53 -0
  272. package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts.map +1 -0
  273. package/packages/pi-coding-agent/dist/core/hooks-runner.js +337 -0
  274. package/packages/pi-coding-agent/dist/core/hooks-runner.js.map +1 -0
  275. package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts +2 -0
  276. package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts.map +1 -0
  277. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +234 -0
  278. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -0
  279. package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
  280. package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
  281. package/packages/pi-coding-agent/dist/core/index.js +1 -0
  282. package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts +3 -1
  284. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/model-discovery.js +92 -12
  286. package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/model-discovery.test.js +16 -1
  288. package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts +2 -0
  290. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts.map +1 -0
  291. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js +40 -0
  292. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js.map +1 -0
  293. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
  294. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
  295. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
  296. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
  297. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +61 -1
  298. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -1
  299. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +5 -0
  300. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  301. package/packages/pi-coding-agent/dist/core/model-registry.js +90 -10
  302. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  303. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
  304. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
  305. package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
  306. package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
  307. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
  308. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
  309. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
  310. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
  311. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/session-manager.js +10 -6
  313. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  314. package/packages/pi-coding-agent/dist/core/session-manager.test.js +45 -1
  315. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  316. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +55 -0
  317. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  318. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  319. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  320. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  321. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  322. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
  323. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  324. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
  325. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  326. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  327. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +13 -7
  328. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  329. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
  330. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  331. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
  332. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  333. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  334. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -1
  335. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  336. package/packages/pi-coding-agent/package.json +1 -1
  337. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +3 -2
  338. package/packages/pi-coding-agent/src/core/agent-session.ts +38 -2
  339. package/packages/pi-coding-agent/src/core/extensions/index.ts +16 -0
  340. package/packages/pi-coding-agent/src/core/extensions/loader.ts +5 -0
  341. package/packages/pi-coding-agent/src/core/extensions/runner.ts +351 -0
  342. package/packages/pi-coding-agent/src/core/extensions/types.ts +258 -0
  343. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +269 -0
  344. package/packages/pi-coding-agent/src/core/hooks-runner.ts +460 -0
  345. package/packages/pi-coding-agent/src/core/index.ts +10 -0
  346. package/packages/pi-coding-agent/src/core/model-discovery.test.ts +19 -0
  347. package/packages/pi-coding-agent/src/core/model-discovery.ts +99 -12
  348. package/packages/pi-coding-agent/src/core/model-registry-auth-header.test.ts +44 -0
  349. package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
  350. package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +75 -0
  351. package/packages/pi-coding-agent/src/core/model-registry.ts +102 -10
  352. package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
  353. package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
  354. package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -1
  355. package/packages/pi-coding-agent/src/core/session-manager.ts +10 -6
  356. package/packages/pi-coding-agent/src/core/settings-manager.ts +57 -0
  357. package/packages/pi-coding-agent/src/index.ts +16 -0
  358. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
  359. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -7
  360. package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
  361. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
  362. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  363. package/packages/pi-tui/package.json +1 -1
  364. package/packages/rpc-client/package.json +1 -1
  365. package/pkg/package.json +1 -1
  366. package/scripts/link-workspace-packages.cjs +1 -0
  367. package/src/resources/agents/researcher.md +1 -1
  368. package/src/resources/extensions/claude-code-cli/readiness.ts +32 -8
  369. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +78 -17
  370. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +149 -5
  371. package/src/resources/extensions/gsd/auto/loop-deps.ts +14 -0
  372. package/src/resources/extensions/gsd/auto/loop.ts +9 -0
  373. package/src/resources/extensions/gsd/auto/phases.ts +131 -10
  374. package/src/resources/extensions/gsd/auto/run-unit.ts +40 -2
  375. package/src/resources/extensions/gsd/auto/session.ts +35 -2
  376. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -3
  377. package/src/resources/extensions/gsd/auto-model-selection.ts +71 -15
  378. package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
  379. package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
  380. package/src/resources/extensions/gsd/auto-recovery.ts +26 -1
  381. package/src/resources/extensions/gsd/auto-start.ts +60 -68
  382. package/src/resources/extensions/gsd/auto-verification.ts +33 -0
  383. package/src/resources/extensions/gsd/auto-worktree.ts +62 -63
  384. package/src/resources/extensions/gsd/auto.ts +73 -28
  385. package/src/resources/extensions/gsd/blocked-models.ts +98 -0
  386. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +120 -1
  387. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +40 -9
  388. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
  389. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +5 -0
  390. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -0
  391. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +54 -6
  392. package/src/resources/extensions/gsd/bootstrap/system-context.ts +89 -26
  393. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
  394. package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
  395. package/src/resources/extensions/gsd/commands-extract-learnings.ts +55 -90
  396. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
  397. package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
  398. package/src/resources/extensions/gsd/complexity-classifier.ts +5 -3
  399. package/src/resources/extensions/gsd/db-writer.ts +88 -17
  400. package/src/resources/extensions/gsd/doctor-git-checks.ts +23 -27
  401. package/src/resources/extensions/gsd/doctor-providers.ts +59 -6
  402. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +2 -0
  403. package/src/resources/extensions/gsd/error-classifier.ts +36 -3
  404. package/src/resources/extensions/gsd/exec-history.ts +153 -0
  405. package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
  406. package/src/resources/extensions/gsd/gitignore.ts +1 -1
  407. package/src/resources/extensions/gsd/gsd-db.ts +186 -23
  408. package/src/resources/extensions/gsd/guided-flow.ts +222 -1
  409. package/src/resources/extensions/gsd/health-widget.ts +3 -1
  410. package/src/resources/extensions/gsd/hook-emitter.ts +188 -0
  411. package/src/resources/extensions/gsd/init-wizard.ts +15 -1
  412. package/src/resources/extensions/gsd/journal.ts +2 -1
  413. package/src/resources/extensions/gsd/key-manager.ts +28 -0
  414. package/src/resources/extensions/gsd/memory-backfill.ts +140 -0
  415. package/src/resources/extensions/gsd/memory-store.ts +26 -0
  416. package/src/resources/extensions/gsd/model-router.ts +42 -1
  417. package/src/resources/extensions/gsd/pre-execution-checks.ts +46 -10
  418. package/src/resources/extensions/gsd/preferences-types.ts +46 -0
  419. package/src/resources/extensions/gsd/preferences-validation.ts +79 -0
  420. package/src/resources/extensions/gsd/preferences.ts +17 -17
  421. package/src/resources/extensions/gsd/prompt-loader.ts +30 -7
  422. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  423. package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  424. package/src/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
  425. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  426. package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
  427. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -2
  428. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  429. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  430. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -0
  431. package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
  432. package/src/resources/extensions/gsd/safety/file-change-validator.ts +17 -4
  433. package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
  434. package/src/resources/extensions/gsd/state.ts +45 -4
  435. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +188 -2
  436. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +95 -1
  437. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
  438. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +49 -0
  439. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +141 -0
  440. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +33 -3
  441. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +38 -0
  442. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +23 -0
  443. package/src/resources/extensions/gsd/tests/blocked-models.test.ts +98 -0
  444. package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +54 -0
  445. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
  446. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +68 -66
  447. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
  448. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +61 -1
  449. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  450. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  451. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +3 -3
  452. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  453. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +42 -0
  454. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +8 -4
  455. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +148 -3
  456. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
  457. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +306 -1
  458. package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
  459. package/src/resources/extensions/gsd/tests/exec-history.test.ts +237 -0
  460. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
  461. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +58 -0
  462. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +40 -9
  463. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +62 -0
  464. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +447 -1
  465. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
  466. package/src/resources/extensions/gsd/tests/integration/doctor-git-symlink-cwd.test.ts +11 -0
  467. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +78 -0
  468. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +1 -0
  469. package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +1 -0
  470. package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +30 -0
  471. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +1 -1
  472. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
  473. package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
  474. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +37 -0
  475. package/src/resources/extensions/gsd/tests/key-manager.test.ts +9 -0
  476. package/src/resources/extensions/gsd/tests/load-memory-block.test.ts +36 -0
  477. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  478. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +12 -0
  479. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  480. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
  481. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +37 -0
  482. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
  483. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
  484. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +356 -0
  485. package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
  486. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
  487. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +49 -0
  488. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +103 -4
  489. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
  490. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
  491. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +230 -0
  492. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
  493. package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
  494. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +413 -0
  495. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
  496. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
  497. package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
  498. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
  499. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +23 -0
  500. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +9 -3
  501. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
  502. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +35 -0
  503. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +6 -1
  504. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -5
  505. package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
  506. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
  507. package/src/resources/extensions/gsd/token-counter.ts +22 -5
  508. package/src/resources/extensions/gsd/tools/complete-milestone.ts +15 -9
  509. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
  510. package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
  511. package/src/resources/extensions/gsd/tools/memory-tools.ts +31 -1
  512. package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
  513. package/src/resources/extensions/gsd/uok/plan-v2.ts +26 -3
  514. package/src/resources/extensions/gsd/workflow-logger.ts +4 -1
  515. package/src/resources/extensions/gsd/workflow-mcp.ts +3 -0
  516. package/src/resources/extensions/gsd/workflow-templates/spike.md +6 -0
  517. package/src/resources/extensions/gsd/worktree-resolver.ts +54 -9
  518. package/src/resources/extensions/search-the-web/command-search-provider.ts +5 -4
  519. package/src/resources/extensions/search-the-web/native-search.ts +48 -12
  520. package/src/resources/skills/api-design/SKILL.md +190 -0
  521. package/src/resources/skills/create-mcp-server/SKILL.md +121 -0
  522. package/src/resources/skills/decompose-into-slices/SKILL.md +139 -0
  523. package/src/resources/skills/dependency-upgrade/SKILL.md +158 -0
  524. package/src/resources/skills/design-an-interface/SKILL.md +102 -0
  525. package/src/resources/skills/forensics/SKILL.md +153 -0
  526. package/src/resources/skills/grill-me/SKILL.md +93 -0
  527. package/src/resources/skills/handoff/SKILL.md +121 -0
  528. package/src/resources/skills/observability/SKILL.md +174 -0
  529. package/src/resources/skills/security-review/SKILL.md +181 -0
  530. package/src/resources/skills/spike-wrap-up/SKILL.md +138 -0
  531. package/src/resources/skills/tdd/SKILL.md +112 -0
  532. package/src/resources/skills/verify-before-complete/SKILL.md +98 -0
  533. package/src/resources/skills/write-docs/SKILL.md +82 -0
  534. package/src/resources/skills/write-milestone-brief/SKILL.md +135 -0
  535. /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_buildManifest.js +0 -0
  536. /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"github-copilot.js","sourceRoot":"","sources":["../../../src/utils/oauth/github-copilot.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * GitHub Copilot OAuth flow\n */\n\nimport { getModels } from \"../../models.js\";\nimport type { Api, Model } from \"../../types.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.js\";\n\ntype CopilotCredentials = OAuthCredentials & {\n\tenterpriseUrl?: string;\n\t/** Model limits from the /models API, keyed by model ID */\n\tmodelLimits?: Record<string, { contextWindow: number; maxTokens: number }>;\n};\n\nconst decode = (s: string) => atob(s);\nconst CLIENT_ID = decode(\"SXYxLmI1MDdhMDhjODdlY2ZlOTg=\");\n\nconst COPILOT_HEADERS = {\n\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\"Editor-Version\": \"vscode/1.107.0\",\n\t\"Editor-Plugin-Version\": \"copilot-chat/0.35.0\",\n\t\"Copilot-Integration-Id\": \"vscode-chat\",\n} as const;\n\ntype DeviceCodeResponse = {\n\tdevice_code: string;\n\tuser_code: string;\n\tverification_uri: string;\n\tinterval: number;\n\texpires_in: number;\n};\n\ntype DeviceTokenSuccessResponse = {\n\taccess_token: string;\n\ttoken_type?: string;\n\tscope?: string;\n};\n\ntype DeviceTokenErrorResponse = {\n\terror: string;\n\terror_description?: string;\n\tinterval?: number;\n};\n\nexport function normalizeDomain(input: string): string | null {\n\tconst trimmed = input.trim();\n\tif (!trimmed) return null;\n\ttry {\n\t\tconst url = trimmed.includes(\"://\") ? new URL(trimmed) : new URL(`https://${trimmed}`);\n\t\treturn url.hostname;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction getUrls(domain: string): {\n\tdeviceCodeUrl: string;\n\taccessTokenUrl: string;\n\tcopilotTokenUrl: string;\n} {\n\treturn {\n\t\tdeviceCodeUrl: `https://${domain}/login/device/code`,\n\t\taccessTokenUrl: `https://${domain}/login/oauth/access_token`,\n\t\tcopilotTokenUrl: `https://api.${domain}/copilot_internal/v2/token`,\n\t};\n}\n\n/**\n * Parse the proxy-ep from a Copilot token and convert to API base URL.\n * Token format: tid=...;exp=...;proxy-ep=proxy.individual.githubcopilot.com;...\n * Returns API URL like https://api.individual.githubcopilot.com\n */\nfunction getBaseUrlFromToken(token: string): string | null {\n\tconst match = token.match(/proxy-ep=([^;]+)/);\n\tif (!match) return null;\n\tconst proxyHost = match[1];\n\t// Convert proxy.xxx to api.xxx\n\tconst apiHost = proxyHost.replace(/^proxy\\./, \"api.\");\n\treturn `https://${apiHost}`;\n}\n\nexport function getGitHubCopilotBaseUrl(token?: string, enterpriseDomain?: string): string {\n\t// If we have a token, extract the base URL from proxy-ep\n\tif (token) {\n\t\tconst urlFromToken = getBaseUrlFromToken(token);\n\t\tif (urlFromToken) return urlFromToken;\n\t}\n\t// Fallback for enterprise or if token parsing fails\n\tif (enterpriseDomain) return `https://copilot-api.${enterpriseDomain}`;\n\treturn \"https://api.individual.githubcopilot.com\";\n}\n\nasync function fetchJson(url: string, init: RequestInit): Promise<unknown> {\n\tconst response = await fetch(url, {\n\t\t...init,\n\t\tsignal: init.signal ?? AbortSignal.timeout(30_000),\n\t});\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${text}`);\n\t}\n\treturn response.json();\n}\n\nasync function startDeviceFlow(domain: string): Promise<DeviceCodeResponse> {\n\tconst urls = getUrls(domain);\n\tconst data = await fetchJson(urls.deviceCodeUrl, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tscope: \"read:user\",\n\t\t}),\n\t});\n\n\tif (!data || typeof data !== \"object\") {\n\t\tthrow new Error(\"Invalid device code response\");\n\t}\n\n\tconst deviceCode = (data as Record<string, unknown>).device_code;\n\tconst userCode = (data as Record<string, unknown>).user_code;\n\tconst verificationUri = (data as Record<string, unknown>).verification_uri;\n\tconst interval = (data as Record<string, unknown>).interval;\n\tconst expiresIn = (data as Record<string, unknown>).expires_in;\n\n\tif (\n\t\ttypeof deviceCode !== \"string\" ||\n\t\ttypeof userCode !== \"string\" ||\n\t\ttypeof verificationUri !== \"string\" ||\n\t\ttypeof interval !== \"number\" ||\n\t\ttypeof expiresIn !== \"number\"\n\t) {\n\t\tthrow new Error(\"Invalid device code response fields\");\n\t}\n\n\treturn {\n\t\tdevice_code: deviceCode,\n\t\tuser_code: userCode,\n\t\tverification_uri: verificationUri,\n\t\tinterval,\n\t\texpires_in: expiresIn,\n\t};\n}\n\n/**\n * Sleep that can be interrupted by an AbortSignal\n */\nfunction abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new Error(\"Login cancelled\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst timeout = setTimeout(resolve, ms);\n\n\t\tsignal?.addEventListener(\n\t\t\t\"abort\",\n\t\t\t() => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\treject(new Error(\"Login cancelled\"));\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t});\n}\n\nasync function pollForGitHubAccessToken(\n\tdomain: string,\n\tdeviceCode: string,\n\tintervalSeconds: number,\n\texpiresIn: number,\n\tsignal?: AbortSignal,\n) {\n\tconst urls = getUrls(domain);\n\tconst deadline = Date.now() + expiresIn * 1000;\n\tlet intervalMs = Math.max(1000, Math.floor(intervalSeconds * 1000));\n\n\twhile (Date.now() < deadline) {\n\t\tif (signal?.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\n\t\tconst raw = await fetchJson(urls.accessTokenUrl, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\tdevice_code: deviceCode,\n\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t}),\n\t\t});\n\n\t\tif (raw && typeof raw === \"object\" && typeof (raw as DeviceTokenSuccessResponse).access_token === \"string\") {\n\t\t\treturn (raw as DeviceTokenSuccessResponse).access_token;\n\t\t}\n\n\t\tif (raw && typeof raw === \"object\" && typeof (raw as DeviceTokenErrorResponse).error === \"string\") {\n\t\t\tconst err = (raw as DeviceTokenErrorResponse).error;\n\t\t\tif (err === \"authorization_pending\") {\n\t\t\t\tawait abortableSleep(intervalMs, signal);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (err === \"slow_down\") {\n\t\t\t\tintervalMs += 5000;\n\t\t\t\tawait abortableSleep(intervalMs, signal);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthrow new Error(`Device flow failed: ${err}`);\n\t\t}\n\n\t\tawait abortableSleep(intervalMs, signal);\n\t}\n\n\tthrow new Error(\"Device flow timed out\");\n}\n\n/**\n * Refresh GitHub Copilot token\n */\nexport async function refreshGitHubCopilotToken(\n\trefreshToken: string,\n\tenterpriseDomain?: string,\n): Promise<OAuthCredentials> {\n\tconst domain = enterpriseDomain || \"github.com\";\n\tconst urls = getUrls(domain);\n\n\tconst raw = await fetchJson(urls.copilotTokenUrl, {\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\tAuthorization: `Bearer ${refreshToken}`,\n\t\t\t...COPILOT_HEADERS,\n\t\t},\n\t});\n\n\tif (!raw || typeof raw !== \"object\") {\n\t\tthrow new Error(\"Invalid Copilot token response\");\n\t}\n\n\tconst token = (raw as Record<string, unknown>).token;\n\tconst expiresAt = (raw as Record<string, unknown>).expires_at;\n\n\tif (typeof token !== \"string\" || typeof expiresAt !== \"number\") {\n\t\tthrow new Error(\"Invalid Copilot token response fields\");\n\t}\n\n\treturn {\n\t\trefresh: refreshToken,\n\t\taccess: token,\n\t\texpires: expiresAt * 1000 - 5 * 60 * 1000,\n\t\tenterpriseUrl: enterpriseDomain,\n\t};\n}\n\n/**\n * Enable a model for the user's GitHub Copilot account.\n * This is required for some models (like Claude, Grok) before they can be used.\n */\nasync function enableGitHubCopilotModel(token: string, modelId: string, enterpriseDomain?: string): Promise<boolean> {\n\tconst baseUrl = getGitHubCopilotBaseUrl(token, enterpriseDomain);\n\tconst url = `${baseUrl}/models/${modelId}/policy`;\n\n\ttry {\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\t\t...COPILOT_HEADERS,\n\t\t\t\t\"openai-intent\": \"chat-policy\",\n\t\t\t\t\"x-interaction-type\": \"chat-policy\",\n\t\t\t},\n\t\t\tbody: JSON.stringify({ state: \"enabled\" }),\n\t\t\tsignal: AbortSignal.timeout(30_000),\n\t\t});\n\t\treturn response.ok;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Enable all known GitHub Copilot models that may require policy acceptance.\n * Called after successful login to ensure all models are available.\n */\nasync function enableAllGitHubCopilotModels(\n\ttoken: string,\n\tenterpriseDomain?: string,\n\tonProgress?: (model: string, success: boolean) => void,\n): Promise<void> {\n\tconst models = getModels(\"github-copilot\");\n\tawait Promise.all(\n\t\tmodels.map(async (model) => {\n\t\t\tconst success = await enableGitHubCopilotModel(token, model.id, enterpriseDomain);\n\t\t\tonProgress?.(model.id, success);\n\t\t}),\n\t);\n}\n\nasync function fetchCopilotModelLimits(\n\ttoken: string,\n\tenterpriseDomain?: string,\n): Promise<Record<string, { contextWindow: number; maxTokens: number }>> {\n\tconst baseUrl = getGitHubCopilotBaseUrl(token, enterpriseDomain);\n\ttry {\n\t\tconst response = await fetch(`${baseUrl}/models`, {\n\t\t\theaders: {\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\t\t\"X-GitHub-Api-Version\": \"2025-05-01\",\n\t\t\t\t...COPILOT_HEADERS,\n\t\t\t},\n\t\t\tsignal: AbortSignal.timeout(30_000),\n\t\t});\n\t\tif (!response.ok) return {};\n\t\tconst data = (await response.json()) as {\n\t\t\tdata?: Array<{\n\t\t\t\tid: string;\n\t\t\t\tcapabilities?: {\n\t\t\t\t\tlimits?: {\n\t\t\t\t\t\tmax_context_window_tokens?: number;\n\t\t\t\t\t\tmax_output_tokens?: number;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t}>;\n\t\t};\n\t\tconst limits: Record<string, { contextWindow: number; maxTokens: number }> = {};\n\t\tfor (const m of data.data || []) {\n\t\t\tconst ctx = m.capabilities?.limits?.max_context_window_tokens;\n\t\t\tconst out = m.capabilities?.limits?.max_output_tokens;\n\t\t\tif (typeof ctx === \"number\" && typeof out === \"number\" && ctx > 0 && out > 0 && Number.isFinite(ctx) && Number.isFinite(out)) {\n\t\t\t\tlimits[m.id] = { contextWindow: ctx, maxTokens: out };\n\t\t\t}\n\t\t}\n\t\treturn limits;\n\t} catch {\n\t\treturn {};\n\t}\n}\n\n/**\n * Login with GitHub Copilot OAuth (device code flow)\n *\n * @param options.onAuth - Callback with URL and optional instructions (user code)\n * @param options.onPrompt - Callback to prompt user for input\n * @param options.onProgress - Optional progress callback\n * @param options.signal - Optional AbortSignal for cancellation\n */\nexport async function loginGitHubCopilot(options: {\n\tonAuth: (url: string, instructions?: string) => void;\n\tonPrompt: (prompt: { message: string; placeholder?: string; allowEmpty?: boolean }) => Promise<string>;\n\tonProgress?: (message: string) => void;\n\tsignal?: AbortSignal;\n}): Promise<OAuthCredentials> {\n\tconst input = await options.onPrompt({\n\t\tmessage: \"GitHub Enterprise URL/domain (blank for github.com)\",\n\t\tplaceholder: \"company.ghe.com\",\n\t\tallowEmpty: true,\n\t});\n\n\tif (options.signal?.aborted) {\n\t\tthrow new Error(\"Login cancelled\");\n\t}\n\n\tconst trimmed = input.trim();\n\tconst enterpriseDomain = normalizeDomain(input);\n\tif (trimmed && !enterpriseDomain) {\n\t\tthrow new Error(\"Invalid GitHub Enterprise URL/domain\");\n\t}\n\tconst domain = enterpriseDomain || \"github.com\";\n\n\tconst device = await startDeviceFlow(domain);\n\toptions.onAuth(device.verification_uri, `Enter code: ${device.user_code}`);\n\n\tconst githubAccessToken = await pollForGitHubAccessToken(\n\t\tdomain,\n\t\tdevice.device_code,\n\t\tdevice.interval,\n\t\tdevice.expires_in,\n\t\toptions.signal,\n\t);\n\tconst credentials = await refreshGitHubCopilotToken(githubAccessToken, enterpriseDomain ?? undefined);\n\n\t// Enable all models after successful login\n\toptions.onProgress?.(\"Enabling models...\");\n\tawait enableAllGitHubCopilotModels(credentials.access, enterpriseDomain ?? undefined);\n\n\t// Fetch real model limits from the Copilot API\n\toptions.onProgress?.(\"Fetching model limits...\");\n\tconst modelLimits = await fetchCopilotModelLimits(credentials.access, enterpriseDomain ?? undefined);\n\tif (Object.keys(modelLimits).length > 0) {\n\t\t(credentials as CopilotCredentials).modelLimits = modelLimits;\n\t}\n\n\treturn credentials;\n}\n\nexport const githubCopilotOAuthProvider: OAuthProviderInterface = {\n\tid: \"github-copilot\",\n\tname: \"GitHub Copilot\",\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginGitHubCopilot({\n\t\t\tonAuth: (url, instructions) => callbacks.onAuth({ url, instructions }),\n\t\t\tonPrompt: callbacks.onPrompt,\n\t\t\tonProgress: callbacks.onProgress,\n\t\t\tsignal: callbacks.signal,\n\t\t});\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\tconst creds = credentials as CopilotCredentials;\n\t\tconst refreshed = await refreshGitHubCopilotToken(creds.refresh, creds.enterpriseUrl);\n\t\ttry {\n\t\t\tconst modelLimits = await fetchCopilotModelLimits(refreshed.access, creds.enterpriseUrl);\n\t\t\tif (Object.keys(modelLimits).length > 0) {\n\t\t\t\t(refreshed as CopilotCredentials).modelLimits = modelLimits;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Model limits fetch is best-effort; don't block token refresh\n\t\t}\n\t\treturn refreshed;\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n\n\tmodifyModels(models: Model<Api>[], credentials: OAuthCredentials): Model<Api>[] {\n\t\tconst creds = credentials as CopilotCredentials;\n\t\tconst domain = creds.enterpriseUrl ? (normalizeDomain(creds.enterpriseUrl) ?? undefined) : undefined;\n\t\tconst baseUrl = getGitHubCopilotBaseUrl(creds.access, domain);\n\t\tconst limits = creds.modelLimits;\n\t\tconst availableModelIds = limits ? new Set(Object.keys(limits)) : null;\n\t\tconst shouldFilterByAvailability = !!availableModelIds && availableModelIds.size > 0;\n\t\treturn models.flatMap((m) => {\n\t\t\tif (m.provider !== \"github-copilot\") return m;\n\t\t\tif (shouldFilterByAvailability && !availableModelIds.has(m.id)) return [];\n\t\t\tconst modelLimits = limits?.[m.id];\n\t\t\treturn {\n\t\t\t\t...m,\n\t\t\t\tbaseUrl,\n\t\t\t\t...(modelLimits && {\n\t\t\t\t\tcontextWindow: modelLimits.contextWindow,\n\t\t\t\t\tmaxTokens: modelLimits.maxTokens,\n\t\t\t\t}),\n\t\t\t};\n\t\t});\n\t},\n};\n"]}
1
+ {"version":3,"file":"github-copilot.js","sourceRoot":"","sources":["../../../src/utils/oauth/github-copilot.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * GitHub Copilot OAuth flow\n */\n\nimport { getModels } from \"../../models.js\";\nimport type { Api, Model } from \"../../types.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.js\";\n\ntype CopilotCredentials = OAuthCredentials & {\n\tenterpriseUrl?: string;\n\t/** Model limits from the /models API, keyed by model ID */\n\tmodelLimits?: Record<string, { contextWindow: number; maxTokens: number }>;\n};\n\n// GitHub Copilot OAuth Client ID\n//\n// NOTE: This credential is public in the source code. It should NOT be\n// obfuscated because security scanners flag obfuscated data as potentially\n// malicious (see: https://socket.dev/npm/package/gsd-pi/alerts/2.70.1?alert_name=obfuscatedFile)\n//\n// GitHub's device flow for public clients (CLI/desktop apps) does not use\n// a client secret - only the client ID is required. This is standard OAuth\n// for public clients and is intentionally public.\n//\n// See: https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps\nconst CLIENT_ID = \"Iv1.b507a08c87ecfe98\";\n\nconst COPILOT_HEADERS = {\n\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\"Editor-Version\": \"vscode/1.107.0\",\n\t\"Editor-Plugin-Version\": \"copilot-chat/0.35.0\",\n\t\"Copilot-Integration-Id\": \"vscode-chat\",\n} as const;\n\ntype DeviceCodeResponse = {\n\tdevice_code: string;\n\tuser_code: string;\n\tverification_uri: string;\n\tinterval: number;\n\texpires_in: number;\n};\n\ntype DeviceTokenSuccessResponse = {\n\taccess_token: string;\n\ttoken_type?: string;\n\tscope?: string;\n};\n\ntype DeviceTokenErrorResponse = {\n\terror: string;\n\terror_description?: string;\n\tinterval?: number;\n};\n\nexport function normalizeDomain(input: string): string | null {\n\tconst trimmed = input.trim();\n\tif (!trimmed) return null;\n\ttry {\n\t\tconst url = trimmed.includes(\"://\") ? new URL(trimmed) : new URL(`https://${trimmed}`);\n\t\treturn url.hostname;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction getUrls(domain: string): {\n\tdeviceCodeUrl: string;\n\taccessTokenUrl: string;\n\tcopilotTokenUrl: string;\n} {\n\treturn {\n\t\tdeviceCodeUrl: `https://${domain}/login/device/code`,\n\t\taccessTokenUrl: `https://${domain}/login/oauth/access_token`,\n\t\tcopilotTokenUrl: `https://api.${domain}/copilot_internal/v2/token`,\n\t};\n}\n\n/**\n * Parse the proxy-ep from a Copilot token and convert to API base URL.\n * Token format: tid=...;exp=...;proxy-ep=proxy.individual.githubcopilot.com;...\n * Returns API URL like https://api.individual.githubcopilot.com\n */\nfunction getBaseUrlFromToken(token: string): string | null {\n\tconst match = token.match(/proxy-ep=([^;]+)/);\n\tif (!match) return null;\n\tconst proxyHost = match[1];\n\t// Convert proxy.xxx to api.xxx\n\tconst apiHost = proxyHost.replace(/^proxy\\./, \"api.\");\n\treturn `https://${apiHost}`;\n}\n\nexport function getGitHubCopilotBaseUrl(token?: string, enterpriseDomain?: string): string {\n\t// If we have a token, extract the base URL from proxy-ep\n\tif (token) {\n\t\tconst urlFromToken = getBaseUrlFromToken(token);\n\t\tif (urlFromToken) return urlFromToken;\n\t}\n\t// Fallback for enterprise or if token parsing fails\n\tif (enterpriseDomain) return `https://copilot-api.${enterpriseDomain}`;\n\treturn \"https://api.individual.githubcopilot.com\";\n}\n\nasync function fetchJson(url: string, init: RequestInit): Promise<unknown> {\n\tconst response = await fetch(url, {\n\t\t...init,\n\t\tsignal: init.signal ?? AbortSignal.timeout(30_000),\n\t});\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${text}`);\n\t}\n\treturn response.json();\n}\n\nasync function startDeviceFlow(domain: string): Promise<DeviceCodeResponse> {\n\tconst urls = getUrls(domain);\n\tconst data = await fetchJson(urls.deviceCodeUrl, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tscope: \"read:user\",\n\t\t}),\n\t});\n\n\tif (!data || typeof data !== \"object\") {\n\t\tthrow new Error(\"Invalid device code response\");\n\t}\n\n\tconst deviceCode = (data as Record<string, unknown>).device_code;\n\tconst userCode = (data as Record<string, unknown>).user_code;\n\tconst verificationUri = (data as Record<string, unknown>).verification_uri;\n\tconst interval = (data as Record<string, unknown>).interval;\n\tconst expiresIn = (data as Record<string, unknown>).expires_in;\n\n\tif (\n\t\ttypeof deviceCode !== \"string\" ||\n\t\ttypeof userCode !== \"string\" ||\n\t\ttypeof verificationUri !== \"string\" ||\n\t\ttypeof interval !== \"number\" ||\n\t\ttypeof expiresIn !== \"number\"\n\t) {\n\t\tthrow new Error(\"Invalid device code response fields\");\n\t}\n\n\treturn {\n\t\tdevice_code: deviceCode,\n\t\tuser_code: userCode,\n\t\tverification_uri: verificationUri,\n\t\tinterval,\n\t\texpires_in: expiresIn,\n\t};\n}\n\n/**\n * Sleep that can be interrupted by an AbortSignal\n */\nfunction abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new Error(\"Login cancelled\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst timeout = setTimeout(resolve, ms);\n\n\t\tsignal?.addEventListener(\n\t\t\t\"abort\",\n\t\t\t() => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\treject(new Error(\"Login cancelled\"));\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t});\n}\n\nasync function pollForGitHubAccessToken(\n\tdomain: string,\n\tdeviceCode: string,\n\tintervalSeconds: number,\n\texpiresIn: number,\n\tsignal?: AbortSignal,\n) {\n\tconst urls = getUrls(domain);\n\tconst deadline = Date.now() + expiresIn * 1000;\n\tlet intervalMs = Math.max(1000, Math.floor(intervalSeconds * 1000));\n\n\twhile (Date.now() < deadline) {\n\t\tif (signal?.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\n\t\tconst raw = await fetchJson(urls.accessTokenUrl, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\tdevice_code: deviceCode,\n\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t}),\n\t\t});\n\n\t\tif (raw && typeof raw === \"object\" && typeof (raw as DeviceTokenSuccessResponse).access_token === \"string\") {\n\t\t\treturn (raw as DeviceTokenSuccessResponse).access_token;\n\t\t}\n\n\t\tif (raw && typeof raw === \"object\" && typeof (raw as DeviceTokenErrorResponse).error === \"string\") {\n\t\t\tconst err = (raw as DeviceTokenErrorResponse).error;\n\t\t\tif (err === \"authorization_pending\") {\n\t\t\t\tawait abortableSleep(intervalMs, signal);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (err === \"slow_down\") {\n\t\t\t\tintervalMs += 5000;\n\t\t\t\tawait abortableSleep(intervalMs, signal);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthrow new Error(`Device flow failed: ${err}`);\n\t\t}\n\n\t\tawait abortableSleep(intervalMs, signal);\n\t}\n\n\tthrow new Error(\"Device flow timed out\");\n}\n\n/**\n * Refresh GitHub Copilot token\n */\nexport async function refreshGitHubCopilotToken(\n\trefreshToken: string,\n\tenterpriseDomain?: string,\n): Promise<OAuthCredentials> {\n\tconst domain = enterpriseDomain || \"github.com\";\n\tconst urls = getUrls(domain);\n\n\tconst raw = await fetchJson(urls.copilotTokenUrl, {\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\tAuthorization: `Bearer ${refreshToken}`,\n\t\t\t...COPILOT_HEADERS,\n\t\t},\n\t});\n\n\tif (!raw || typeof raw !== \"object\") {\n\t\tthrow new Error(\"Invalid Copilot token response\");\n\t}\n\n\tconst token = (raw as Record<string, unknown>).token;\n\tconst expiresAt = (raw as Record<string, unknown>).expires_at;\n\n\tif (typeof token !== \"string\" || typeof expiresAt !== \"number\") {\n\t\tthrow new Error(\"Invalid Copilot token response fields\");\n\t}\n\n\treturn {\n\t\trefresh: refreshToken,\n\t\taccess: token,\n\t\texpires: expiresAt * 1000 - 5 * 60 * 1000,\n\t\tenterpriseUrl: enterpriseDomain,\n\t};\n}\n\n/**\n * Enable a model for the user's GitHub Copilot account.\n * This is required for some models (like Claude, Grok) before they can be used.\n */\nasync function enableGitHubCopilotModel(token: string, modelId: string, enterpriseDomain?: string): Promise<boolean> {\n\tconst baseUrl = getGitHubCopilotBaseUrl(token, enterpriseDomain);\n\tconst url = `${baseUrl}/models/${modelId}/policy`;\n\n\ttry {\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\t\t...COPILOT_HEADERS,\n\t\t\t\t\"openai-intent\": \"chat-policy\",\n\t\t\t\t\"x-interaction-type\": \"chat-policy\",\n\t\t\t},\n\t\t\tbody: JSON.stringify({ state: \"enabled\" }),\n\t\t\tsignal: AbortSignal.timeout(30_000),\n\t\t});\n\t\treturn response.ok;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Enable all known GitHub Copilot models that may require policy acceptance.\n * Called after successful login to ensure all models are available.\n */\nasync function enableAllGitHubCopilotModels(\n\ttoken: string,\n\tenterpriseDomain?: string,\n\tonProgress?: (model: string, success: boolean) => void,\n): Promise<void> {\n\tconst models = getModels(\"github-copilot\");\n\tawait Promise.all(\n\t\tmodels.map(async (model) => {\n\t\t\tconst success = await enableGitHubCopilotModel(token, model.id, enterpriseDomain);\n\t\t\tonProgress?.(model.id, success);\n\t\t}),\n\t);\n}\n\nasync function fetchCopilotModelLimits(\n\ttoken: string,\n\tenterpriseDomain?: string,\n): Promise<Record<string, { contextWindow: number; maxTokens: number }>> {\n\tconst baseUrl = getGitHubCopilotBaseUrl(token, enterpriseDomain);\n\ttry {\n\t\tconst response = await fetch(`${baseUrl}/models`, {\n\t\t\theaders: {\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\t\t\"X-GitHub-Api-Version\": \"2025-05-01\",\n\t\t\t\t...COPILOT_HEADERS,\n\t\t\t},\n\t\t\tsignal: AbortSignal.timeout(30_000),\n\t\t});\n\t\tif (!response.ok) return {};\n\t\tconst data = (await response.json()) as {\n\t\t\tdata?: Array<{\n\t\t\t\tid: string;\n\t\t\t\tcapabilities?: {\n\t\t\t\t\tlimits?: {\n\t\t\t\t\t\tmax_context_window_tokens?: number;\n\t\t\t\t\t\tmax_output_tokens?: number;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t}>;\n\t\t};\n\t\tconst limits: Record<string, { contextWindow: number; maxTokens: number }> = {};\n\t\tfor (const m of data.data || []) {\n\t\t\tconst ctx = m.capabilities?.limits?.max_context_window_tokens;\n\t\t\tconst out = m.capabilities?.limits?.max_output_tokens;\n\t\t\tif (typeof ctx === \"number\" && typeof out === \"number\" && ctx > 0 && out > 0 && Number.isFinite(ctx) && Number.isFinite(out)) {\n\t\t\t\tlimits[m.id] = { contextWindow: ctx, maxTokens: out };\n\t\t\t}\n\t\t}\n\t\treturn limits;\n\t} catch {\n\t\treturn {};\n\t}\n}\n\n/**\n * Login with GitHub Copilot OAuth (device code flow)\n *\n * @param options.onAuth - Callback with URL and optional instructions (user code)\n * @param options.onPrompt - Callback to prompt user for input\n * @param options.onProgress - Optional progress callback\n * @param options.signal - Optional AbortSignal for cancellation\n */\nexport async function loginGitHubCopilot(options: {\n\tonAuth: (url: string, instructions?: string) => void;\n\tonPrompt: (prompt: { message: string; placeholder?: string; allowEmpty?: boolean }) => Promise<string>;\n\tonProgress?: (message: string) => void;\n\tsignal?: AbortSignal;\n}): Promise<OAuthCredentials> {\n\tconst input = await options.onPrompt({\n\t\tmessage: \"GitHub Enterprise URL/domain (blank for github.com)\",\n\t\tplaceholder: \"company.ghe.com\",\n\t\tallowEmpty: true,\n\t});\n\n\tif (options.signal?.aborted) {\n\t\tthrow new Error(\"Login cancelled\");\n\t}\n\n\tconst trimmed = input.trim();\n\tconst enterpriseDomain = normalizeDomain(input);\n\tif (trimmed && !enterpriseDomain) {\n\t\tthrow new Error(\"Invalid GitHub Enterprise URL/domain\");\n\t}\n\tconst domain = enterpriseDomain || \"github.com\";\n\n\tconst device = await startDeviceFlow(domain);\n\toptions.onAuth(device.verification_uri, `Enter code: ${device.user_code}`);\n\n\tconst githubAccessToken = await pollForGitHubAccessToken(\n\t\tdomain,\n\t\tdevice.device_code,\n\t\tdevice.interval,\n\t\tdevice.expires_in,\n\t\toptions.signal,\n\t);\n\tconst credentials = await refreshGitHubCopilotToken(githubAccessToken, enterpriseDomain ?? undefined);\n\n\t// Enable all models after successful login\n\toptions.onProgress?.(\"Enabling models...\");\n\tawait enableAllGitHubCopilotModels(credentials.access, enterpriseDomain ?? undefined);\n\n\t// Fetch real model limits from the Copilot API\n\toptions.onProgress?.(\"Fetching model limits...\");\n\tconst modelLimits = await fetchCopilotModelLimits(credentials.access, enterpriseDomain ?? undefined);\n\tif (Object.keys(modelLimits).length > 0) {\n\t\t(credentials as CopilotCredentials).modelLimits = modelLimits;\n\t}\n\n\treturn credentials;\n}\n\nexport const githubCopilotOAuthProvider: OAuthProviderInterface = {\n\tid: \"github-copilot\",\n\tname: \"GitHub Copilot\",\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginGitHubCopilot({\n\t\t\tonAuth: (url, instructions) => callbacks.onAuth({ url, instructions }),\n\t\t\tonPrompt: callbacks.onPrompt,\n\t\t\tonProgress: callbacks.onProgress,\n\t\t\tsignal: callbacks.signal,\n\t\t});\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\tconst creds = credentials as CopilotCredentials;\n\t\tconst refreshed = await refreshGitHubCopilotToken(creds.refresh, creds.enterpriseUrl);\n\t\ttry {\n\t\t\tconst modelLimits = await fetchCopilotModelLimits(refreshed.access, creds.enterpriseUrl);\n\t\t\tif (Object.keys(modelLimits).length > 0) {\n\t\t\t\t(refreshed as CopilotCredentials).modelLimits = modelLimits;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Model limits fetch is best-effort; don't block token refresh\n\t\t}\n\t\treturn refreshed;\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n\n\tmodifyModels(models: Model<Api>[], credentials: OAuthCredentials): Model<Api>[] {\n\t\tconst creds = credentials as CopilotCredentials;\n\t\tconst domain = creds.enterpriseUrl ? (normalizeDomain(creds.enterpriseUrl) ?? undefined) : undefined;\n\t\tconst baseUrl = getGitHubCopilotBaseUrl(creds.access, domain);\n\t\tconst limits = creds.modelLimits;\n\t\tconst availableModelIds = limits ? new Set(Object.keys(limits)) : null;\n\t\tconst shouldFilterByAvailability = !!availableModelIds && availableModelIds.size > 0;\n\t\treturn models.flatMap((m) => {\n\t\t\tif (m.provider !== \"github-copilot\") return m;\n\t\t\tif (shouldFilterByAvailability && !availableModelIds.has(m.id)) return [];\n\t\t\tconst modelLimits = limits?.[m.id];\n\t\t\treturn {\n\t\t\t\t...m,\n\t\t\t\tbaseUrl,\n\t\t\t\t...(modelLimits && {\n\t\t\t\t\tcontextWindow: modelLimits.contextWindow,\n\t\t\t\t\tmaxTokens: modelLimits.maxTokens,\n\t\t\t\t}),\n\t\t\t};\n\t\t});\n\t},\n};\n"]}
@@ -1,34 +1,184 @@
1
+ import { describe, test } from "node:test";
1
2
  import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import { githubCopilotOAuthProvider } from "./github-copilot.js";
4
- function makeModel(provider, id) {
3
+ import { existsSync, readFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { getGitHubCopilotBaseUrl, githubCopilotOAuthProvider, normalizeDomain, } from "./github-copilot.js";
7
+ const __dirname = fileURLToPath(new URL(".", import.meta.url));
8
+ const packageRoot = join(__dirname, "..", "..", "..");
9
+ const sourceDir = existsSync(join(__dirname, "github-copilot.ts"))
10
+ ? __dirname
11
+ : join(packageRoot, "src", "utils", "oauth");
12
+ function readSourceFile(name) {
13
+ return readFileSync(join(sourceDir, name), "utf-8");
14
+ }
15
+ function createModel(overrides = {}) {
5
16
  return {
6
- id,
7
- name: id,
17
+ id: "test-model",
18
+ name: "Test Model",
8
19
  api: "openai-completions",
9
- provider,
10
- baseUrl: `${provider}:`,
20
+ provider: "test-provider",
21
+ baseUrl: "https://example.com",
11
22
  reasoning: false,
12
23
  input: ["text"],
13
24
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
14
25
  contextWindow: 128000,
15
- maxTokens: 16384,
26
+ maxTokens: 8192,
27
+ ...overrides,
16
28
  };
17
29
  }
18
30
  function makeCredentials(overrides = {}) {
19
31
  return {
20
- type: "oauth",
21
32
  access: "copilot-token",
22
33
  refresh: "refresh-token",
23
34
  expires: Date.now() + 60_000,
24
35
  ...overrides,
25
36
  };
26
37
  }
38
+ describe("GitHub Copilot OAuth — normalizeDomain", () => {
39
+ test("returns null for empty input", () => {
40
+ assert.equal(normalizeDomain(""), null);
41
+ assert.equal(normalizeDomain(" "), null);
42
+ });
43
+ test("returns null for invalid domain", () => {
44
+ assert.equal(normalizeDomain("not a domain!@#"), null);
45
+ });
46
+ test("extracts hostname from full URL", () => {
47
+ assert.equal(normalizeDomain("https://github.com"), "github.com");
48
+ assert.equal(normalizeDomain("https://company.ghe.com"), "company.ghe.com");
49
+ assert.equal(normalizeDomain("http://example.com/path"), "example.com");
50
+ });
51
+ test("returns domain as-is when no protocol", () => {
52
+ assert.equal(normalizeDomain("github.com"), "github.com");
53
+ assert.equal(normalizeDomain("company.ghe.com"), "company.ghe.com");
54
+ });
55
+ test("trims whitespace", () => {
56
+ assert.equal(normalizeDomain(" github.com "), "github.com");
57
+ });
58
+ });
59
+ describe("GitHub Copilot OAuth — getBaseUrlFromToken", () => {
60
+ test("extracts API URL from token with proxy-ep", () => {
61
+ const token = "tid=123;exp=1234567890;proxy-ep=proxy.individual.githubcopilot.com;other=value";
62
+ const baseUrl = getGitHubCopilotBaseUrl(token);
63
+ assert.equal(baseUrl, "https://api.individual.githubcopilot.com");
64
+ });
65
+ test("extracts API URL from enterprise proxy-ep", () => {
66
+ const token = "tid=123;exp=1234567890;proxy-ep=proxy.company.ghe.com;other=value";
67
+ const baseUrl = getGitHubCopilotBaseUrl(token);
68
+ assert.equal(baseUrl, "https://api.company.ghe.com");
69
+ });
70
+ test("falls back to default when no token provided", () => {
71
+ const baseUrl = getGitHubCopilotBaseUrl();
72
+ assert.equal(baseUrl, "https://api.individual.githubcopilot.com");
73
+ });
74
+ test("falls back to default when token has no proxy-ep", () => {
75
+ const token = "tid=123;exp=1234567890;other=value";
76
+ const baseUrl = getGitHubCopilotBaseUrl(token);
77
+ assert.equal(baseUrl, "https://api.individual.githubcopilot.com");
78
+ });
79
+ test("uses enterprise domain when provided", () => {
80
+ const baseUrl = getGitHubCopilotBaseUrl(undefined, "company.ghe.com");
81
+ assert.equal(baseUrl, "https://copilot-api.company.ghe.com");
82
+ });
83
+ test("prioritizes token proxy-ep over enterprise domain", () => {
84
+ const token = "tid=123;exp=1234567890;proxy-ep=proxy.individual.githubcopilot.com;other=value";
85
+ const baseUrl = getGitHubCopilotBaseUrl(token, "company.ghe.com");
86
+ assert.equal(baseUrl, "https://api.individual.githubcopilot.com");
87
+ });
88
+ });
89
+ describe("GitHub Copilot OAuth — provider structure", () => {
90
+ test("has correct id and name", () => {
91
+ assert.equal(githubCopilotOAuthProvider.id, "github-copilot");
92
+ assert.equal(githubCopilotOAuthProvider.name, "GitHub Copilot");
93
+ });
94
+ test("has required methods", () => {
95
+ assert.equal(typeof githubCopilotOAuthProvider.login, "function");
96
+ assert.equal(typeof githubCopilotOAuthProvider.refreshToken, "function");
97
+ assert.equal(typeof githubCopilotOAuthProvider.getApiKey, "function");
98
+ assert.equal(typeof githubCopilotOAuthProvider.modifyModels, "function");
99
+ });
100
+ test("getApiKey returns access token", () => {
101
+ const credentials = {
102
+ access: "test-access-token",
103
+ refresh: "test-refresh-token",
104
+ expires: Date.now() + 3600000,
105
+ };
106
+ const apiKey = githubCopilotOAuthProvider.getApiKey(credentials);
107
+ assert.equal(apiKey, "test-access-token");
108
+ });
109
+ test("modifyModels preserves non-Copilot models", () => {
110
+ if (!githubCopilotOAuthProvider.modifyModels)
111
+ return;
112
+ const models = [createModel({ id: "gpt-4", provider: "openai" })];
113
+ const credentials = {
114
+ access: "test-token",
115
+ refresh: "test-refresh",
116
+ expires: Date.now() + 3600000,
117
+ };
118
+ const result = githubCopilotOAuthProvider.modifyModels(models, credentials);
119
+ assert.deepEqual(result, models);
120
+ });
121
+ test("modifyModels updates Copilot model baseUrl when token has proxy-ep", () => {
122
+ if (!githubCopilotOAuthProvider.modifyModels)
123
+ return;
124
+ const models = [
125
+ createModel({
126
+ id: "claude-3.5-sonnet",
127
+ provider: "github-copilot",
128
+ baseUrl: "https://api.default.com",
129
+ }),
130
+ ];
131
+ const credentials = {
132
+ access: "tid=123;exp=1234567890;proxy-ep=proxy.individual.githubcopilot.com;",
133
+ refresh: "test-refresh",
134
+ expires: Date.now() + 3600000,
135
+ };
136
+ const result = githubCopilotOAuthProvider.modifyModels(models, credentials);
137
+ assert.equal(result[0].baseUrl, "https://api.individual.githubcopilot.com");
138
+ });
139
+ test("modifyModels applies model limits when available", () => {
140
+ if (!githubCopilotOAuthProvider.modifyModels)
141
+ return;
142
+ const models = [
143
+ createModel({
144
+ id: "claude-3.5-sonnet",
145
+ provider: "github-copilot",
146
+ baseUrl: "https://api.default.com",
147
+ }),
148
+ ];
149
+ const credentials = {
150
+ access: "test-token",
151
+ refresh: "test-refresh",
152
+ expires: Date.now() + 3600000,
153
+ modelLimits: {
154
+ "claude-3.5-sonnet": { contextWindow: 123456, maxTokens: 4096 },
155
+ },
156
+ };
157
+ const result = githubCopilotOAuthProvider.modifyModels(models, credentials);
158
+ assert.equal(result[0].contextWindow, 123456);
159
+ assert.equal(result[0].maxTokens, 4096);
160
+ });
161
+ });
162
+ describe("GitHub Copilot OAuth — credential regression", () => {
163
+ test("module imports successfully", () => {
164
+ assert.ok(githubCopilotOAuthProvider);
165
+ });
166
+ test("CLIENT_ID is plaintext (not base64)", () => {
167
+ const content = readSourceFile("github-copilot.ts");
168
+ assert.ok(content.includes('CLIENT_ID = "Iv1.b507a08c87ecfe98"'));
169
+ assert.ok(!content.includes("atob("));
170
+ });
171
+ test("security explanation comments are present", () => {
172
+ const content = readSourceFile("github-copilot.ts");
173
+ assert.ok(content.includes("NOTE: This credential is public"));
174
+ assert.ok(content.includes("obfuscated") || content.includes("security scanners"));
175
+ });
176
+ });
27
177
  test("githubCopilotOAuthProvider.modifyModels filters unavailable copilot models (#3849)", () => {
28
178
  const models = [
29
- makeModel("github-copilot", "gpt-5"),
30
- makeModel("github-copilot", "claude-sonnet-4"),
31
- makeModel("openai", "gpt-4.1"),
179
+ createModel({ provider: "github-copilot", id: "gpt-5", name: "gpt-5", baseUrl: "github-copilot:" }),
180
+ createModel({ provider: "github-copilot", id: "claude-sonnet-4", name: "claude-sonnet-4", baseUrl: "github-copilot:" }),
181
+ createModel({ provider: "openai", id: "gpt-4.1", name: "gpt-4.1", baseUrl: "openai:" }),
32
182
  ];
33
183
  assert.ok(githubCopilotOAuthProvider.modifyModels, "github copilot provider should expose modifyModels");
34
184
  const modified = githubCopilotOAuthProvider.modifyModels(models, makeCredentials({
@@ -45,8 +195,8 @@ test("githubCopilotOAuthProvider.modifyModels filters unavailable copilot models
45
195
  });
46
196
  test("githubCopilotOAuthProvider.modifyModels keeps all copilot models when limits are unavailable", () => {
47
197
  const models = [
48
- makeModel("github-copilot", "gpt-5"),
49
- makeModel("github-copilot", "claude-sonnet-4"),
198
+ createModel({ provider: "github-copilot", id: "gpt-5", name: "gpt-5", baseUrl: "github-copilot:" }),
199
+ createModel({ provider: "github-copilot", id: "claude-sonnet-4", name: "claude-sonnet-4", baseUrl: "github-copilot:" }),
50
200
  ];
51
201
  assert.ok(githubCopilotOAuthProvider.modifyModels, "github copilot provider should expose modifyModels");
52
202
  const modified = githubCopilotOAuthProvider.modifyModels(models, makeCredentials());
@@ -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 assert from \"node:assert/strict\";\nimport test from \"node:test\";\n\nimport type { Api, Model } from \"../../types.js\";\nimport type { OAuthCredentials } from \"./index.js\";\nimport { githubCopilotOAuthProvider } from \"./github-copilot.js\";\n\nfunction makeModel(provider: string, id: string): Model<Api> {\n\treturn {\n\t\tid,\n\t\tname: id,\n\t\tapi: \"openai-completions\",\n\t\tprovider,\n\t\tbaseUrl: `${provider}:`,\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: 16384,\n\t};\n}\n\nfunction makeCredentials(overrides: Partial<OAuthCredentials & { modelLimits?: Record<string, { contextWindow: number; maxTokens: number }> }> = {}) {\n\treturn {\n\t\ttype: \"oauth\" as const,\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\ntest(\"githubCopilotOAuthProvider.modifyModels filters unavailable copilot models (#3849)\", () => {\n\tconst models = [\n\t\tmakeModel(\"github-copilot\", \"gpt-5\"),\n\t\tmakeModel(\"github-copilot\", \"claude-sonnet-4\"),\n\t\tmakeModel(\"openai\", \"gpt-4.1\"),\n\t];\n\n\tassert.ok(githubCopilotOAuthProvider.modifyModels, \"github copilot provider should expose modifyModels\");\n\tconst modified = githubCopilotOAuthProvider.modifyModels(models, makeCredentials({\n\t\tmodelLimits: {\n\t\t\t\"gpt-5\": { contextWindow: 256000, maxTokens: 32000 },\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\tmakeModel(\"github-copilot\", \"gpt-5\"),\n\t\tmakeModel(\"github-copilot\", \"claude-sonnet-4\"),\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 { 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 +1 @@
1
- {"version":3,"file":"google-antigravity.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/google-antigravity.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,OAAO,KAAK,EAAE,gBAAgB,EAAuB,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAoGhG;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEhH;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACrC,MAAM,EAAE,CAAC,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,EAC9D,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EACtC,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GACvC,OAAO,CAAC,gBAAgB,CAAC,CA0J3B;AAED,eAAO,MAAM,wBAAwB,EAAE,sBAqBtC,CAAC"}
1
+ {"version":3,"file":"google-antigravity.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/google-antigravity.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,OAAO,KAAK,EAAE,gBAAgB,EAAuB,sBAAsB,EAAE,MAAM,YAAY,CAAC;AA8GhG;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEhH;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACrC,MAAM,EAAE,CAAC,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,EAC9D,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EACtC,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GACvC,OAAO,CAAC,gBAAgB,CAAC,CA0J3B;AAED,eAAO,MAAM,wBAAwB,EAAE,sBAqBtC,CAAC"}
@@ -8,9 +8,21 @@
8
8
  import { getGoogleUserEmail, parseRedirectUrl, refreshGoogleOAuthToken, startCallbackServer, } from "./google-oauth-utils.js";
9
9
  import { generatePKCE } from "./pkce.js";
10
10
  // Antigravity OAuth credentials (different from Gemini CLI)
11
- const decode = (s) => atob(s);
12
- const CLIENT_ID = decode("MTA3MTAwNjA2MDU5MS10bWhzc2luMmgyMWxjcmUyMzV2dG9sb2poNGc0MDNlcC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbQ==");
13
- const CLIENT_SECRET = decode("R09DU1BYLUs1OEZXUjQ4NkxkTEoxbUxCOHNYQzR6NnFEQWY=");
11
+ //
12
+ // NOTE: These credentials are public in the source code. They should NOT be
13
+ // obfuscated because security scanners flag obfuscated data as potentially
14
+ // malicious (see: https://socket.dev/npm/package/gsd-pi/alerts/2.70.1?alert_name=obfuscatedFile)
15
+ //
16
+ // Google's OAuth implementation requires client_secret for Desktop App OAuth
17
+ // clients even though it cannot be kept secret in distributed applications.
18
+ // The actual security relies on:
19
+ // - PKCE (Proof Key for Code Exchange) via code_verifier
20
+ // - Redirect URI validation (localhost only)
21
+ // - User consent and token scope limits
22
+ //
23
+ // See: https://developers.google.com/identity/protocols/oauth2/native-app
24
+ const CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com";
25
+ const CLIENT_SECRET = "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";
14
26
  const REDIRECT_URI = "http://localhost:51121/oauth-callback";
15
27
  // Antigravity requires additional scopes
16
28
  const SCOPES = [
@@ -1 +1 @@
1
- {"version":3,"file":"google-antigravity.js","sourceRoot":"","sources":["../../../src/utils/oauth/google-antigravity.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Antigravity OAuth flow (Gemini 3, Claude, GPT-OSS via Google Cloud)\n * Uses different OAuth credentials than google-gemini-cli for access to additional models.\n *\n * NOTE: This module uses Node.js http.createServer for the OAuth callback.\n * It is only intended for CLI use, not browser environments.\n */\n\nimport {\n\ttype CallbackServerInfo,\n\tgetGoogleUserEmail,\n\tparseRedirectUrl,\n\trefreshGoogleOAuthToken,\n\tstartCallbackServer,\n} from \"./google-oauth-utils.js\";\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.js\";\n\ntype AntigravityCredentials = OAuthCredentials & {\n\tprojectId: string;\n};\n\n// Antigravity OAuth credentials (different from Gemini CLI)\nconst decode = (s: string) => atob(s);\nconst CLIENT_ID = decode(\n\t\"MTA3MTAwNjA2MDU5MS10bWhzc2luMmgyMWxjcmUyMzV2dG9sb2poNGc0MDNlcC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbQ==\",\n);\nconst CLIENT_SECRET = decode(\"R09DU1BYLUs1OEZXUjQ4NkxkTEoxbUxCOHNYQzR6NnFEQWY=\");\nconst REDIRECT_URI = \"http://localhost:51121/oauth-callback\";\n\n// Antigravity requires additional scopes\nconst SCOPES = [\n\t\"https://www.googleapis.com/auth/cloud-platform\",\n\t\"https://www.googleapis.com/auth/userinfo.email\",\n\t\"https://www.googleapis.com/auth/userinfo.profile\",\n\t\"https://www.googleapis.com/auth/cclog\",\n\t\"https://www.googleapis.com/auth/experimentsandconfigs\",\n];\n\nconst AUTH_URL = \"https://accounts.google.com/o/oauth2/v2/auth\";\nconst TOKEN_URL = \"https://oauth2.googleapis.com/token\";\n\n// Callback server configuration\nconst CALLBACK_PORT = 51121;\nconst CALLBACK_PATH = \"/oauth-callback\";\n\n// Fallback project ID when discovery fails\nconst DEFAULT_PROJECT_ID = \"rising-fact-p41fc\";\n\ninterface LoadCodeAssistPayload {\n\tcloudaicompanionProject?: string | { id?: string };\n\tcurrentTier?: { id?: string };\n\tallowedTiers?: Array<{ id?: string; isDefault?: boolean }>;\n}\n\n/**\n * Discover or provision a project for the user\n */\nasync function discoverProject(accessToken: string, onProgress?: (message: string) => void): Promise<string> {\n\tconst headers = {\n\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\"Content-Type\": \"application/json\",\n\t\t\"User-Agent\": \"google-api-nodejs-client/9.15.1\",\n\t\t\"X-Goog-Api-Client\": \"google-cloud-sdk vscode_cloudshelleditor/0.1\",\n\t\t\"Client-Metadata\": JSON.stringify({\n\t\t\tideType: \"IDE_UNSPECIFIED\",\n\t\t\tplatform: \"PLATFORM_UNSPECIFIED\",\n\t\t\tpluginType: \"GEMINI\",\n\t\t}),\n\t};\n\n\t// Try endpoints in order: prod first, then sandbox\n\tconst endpoints = [\"https://cloudcode-pa.googleapis.com\", \"https://daily-cloudcode-pa.sandbox.googleapis.com\"];\n\n\tonProgress?.(\"Checking for existing project...\");\n\n\tfor (const endpoint of endpoints) {\n\t\ttry {\n\t\t\tconst loadResponse = await fetch(`${endpoint}/v1internal:loadCodeAssist`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders,\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\tideType: \"IDE_UNSPECIFIED\",\n\t\t\t\t\t\tplatform: \"PLATFORM_UNSPECIFIED\",\n\t\t\t\t\t\tpluginType: \"GEMINI\",\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tsignal: AbortSignal.timeout(30_000),\n\t\t\t});\n\n\t\t\tif (loadResponse.ok) {\n\t\t\t\tconst data = (await loadResponse.json()) as LoadCodeAssistPayload;\n\n\t\t\t\t// Handle both string and object formats\n\t\t\t\tif (typeof data.cloudaicompanionProject === \"string\" && data.cloudaicompanionProject) {\n\t\t\t\t\treturn data.cloudaicompanionProject;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\tdata.cloudaicompanionProject &&\n\t\t\t\t\ttypeof data.cloudaicompanionProject === \"object\" &&\n\t\t\t\t\tdata.cloudaicompanionProject.id\n\t\t\t\t) {\n\t\t\t\t\treturn data.cloudaicompanionProject.id;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Try next endpoint\n\t\t}\n\t}\n\n\t// Use fallback project ID\n\tonProgress?.(\"Using default project...\");\n\treturn DEFAULT_PROJECT_ID;\n}\n\n/**\n * Refresh Antigravity token\n */\nexport async function refreshAntigravityToken(refreshToken: string, projectId: string): Promise<OAuthCredentials> {\n\treturn refreshGoogleOAuthToken(refreshToken, CLIENT_ID, CLIENT_SECRET, \"Antigravity\", { projectId });\n}\n\n/**\n * Login with Antigravity OAuth\n *\n * @param onAuth - Callback with URL and optional instructions\n * @param onProgress - Optional progress callback\n * @param onManualCodeInput - Optional promise that resolves with user-pasted redirect URL.\n * Races with browser callback - whichever completes first wins.\n */\nexport async function loginAntigravity(\n\tonAuth: (info: { url: string; instructions?: string }) => void,\n\tonProgress?: (message: string) => void,\n\tonManualCodeInput?: () => Promise<string>,\n): Promise<OAuthCredentials> {\n\tconst { verifier, challenge } = await generatePKCE();\n\n\t// Start local server for callback\n\tonProgress?.(\"Starting local server for OAuth callback...\");\n\tconst server: CallbackServerInfo = await startCallbackServer(CALLBACK_PORT, CALLBACK_PATH, \"Antigravity\");\n\n\tlet code: string | undefined;\n\n\ttry {\n\t\t// Build authorization URL\n\t\tconst authParams = new URLSearchParams({\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tresponse_type: \"code\",\n\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\tscope: SCOPES.join(\" \"),\n\t\t\tcode_challenge: challenge,\n\t\t\tcode_challenge_method: \"S256\",\n\t\t\tstate: verifier,\n\t\t\taccess_type: \"offline\",\n\t\t\tprompt: \"consent\",\n\t\t});\n\n\t\tconst authUrl = `${AUTH_URL}?${authParams.toString()}`;\n\n\t\t// Notify caller with URL to open\n\t\tonAuth({\n\t\t\turl: authUrl,\n\t\t\tinstructions: \"Complete the sign-in in your browser.\",\n\t\t});\n\n\t\t// Wait for the callback, racing with manual input if provided\n\t\tonProgress?.(\"Waiting for OAuth callback...\");\n\n\t\tif (onManualCodeInput) {\n\t\t\t// Race between browser callback and manual input\n\t\t\tlet manualInput: string | undefined;\n\t\t\tlet manualError: Error | undefined;\n\t\t\tconst manualPromise = onManualCodeInput()\n\t\t\t\t.then((input) => {\n\t\t\t\t\tmanualInput = input;\n\t\t\t\t\tserver.cancelWait();\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tmanualError = err instanceof Error ? err : new Error(String(err));\n\t\t\t\t\tserver.cancelWait();\n\t\t\t\t});\n\n\t\t\tconst result = await server.waitForCode();\n\n\t\t\t// If manual input was cancelled, throw that error\n\t\t\tif (manualError) {\n\t\t\t\tthrow manualError;\n\t\t\t}\n\n\t\t\tif (result?.code) {\n\t\t\t\t// Browser callback won - verify state\n\t\t\t\tif (result.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t}\n\t\t\t\tcode = result.code;\n\t\t\t} else if (manualInput) {\n\t\t\t\t// Manual input won\n\t\t\t\tconst parsed = parseRedirectUrl(manualInput);\n\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t}\n\t\t\t\tcode = parsed.code;\n\t\t\t}\n\n\t\t\t// If still no code, wait for manual promise and try that\n\t\t\tif (!code) {\n\t\t\t\tawait manualPromise;\n\t\t\t\tif (manualError) {\n\t\t\t\t\tthrow manualError;\n\t\t\t\t}\n\t\t\t\tif (manualInput) {\n\t\t\t\t\tconst parsed = parseRedirectUrl(manualInput);\n\t\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t\t}\n\t\t\t\t\tcode = parsed.code;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Original flow: just wait for callback\n\t\t\tconst result = await server.waitForCode();\n\t\t\tif (result?.code) {\n\t\t\t\tif (result.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t}\n\t\t\t\tcode = result.code;\n\t\t\t}\n\t\t}\n\n\t\tif (!code) {\n\t\t\tthrow new Error(\"No authorization code received\");\n\t\t}\n\n\t\t// Exchange code for tokens\n\t\tonProgress?.(\"Exchanging authorization code for tokens...\");\n\t\tconst tokenResponse = await fetch(TOKEN_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\tclient_secret: CLIENT_SECRET,\n\t\t\t\tcode,\n\t\t\t\tgrant_type: \"authorization_code\",\n\t\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\t\tcode_verifier: verifier,\n\t\t\t}),\n\t\t\tsignal: AbortSignal.timeout(30_000),\n\t\t});\n\n\t\tif (!tokenResponse.ok) {\n\t\t\tconst error = await tokenResponse.text();\n\t\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t\t}\n\n\t\tconst tokenData = (await tokenResponse.json()) as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\tif (!tokenData.refresh_token) {\n\t\t\tthrow new Error(\"No refresh token received. Please try again.\");\n\t\t}\n\n\t\t// Get user email\n\t\tonProgress?.(\"Getting user info...\");\n\t\tconst email = await getGoogleUserEmail(tokenData.access_token);\n\n\t\t// Discover project\n\t\tconst projectId = await discoverProject(tokenData.access_token, onProgress);\n\n\t\t// Calculate expiry time (current time + expires_in seconds - 5 min buffer)\n\t\tconst expiresAt = Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000;\n\n\t\tconst credentials: OAuthCredentials = {\n\t\t\trefresh: tokenData.refresh_token,\n\t\t\taccess: tokenData.access_token,\n\t\t\texpires: expiresAt,\n\t\t\tprojectId,\n\t\t\temail,\n\t\t};\n\n\t\treturn credentials;\n\t} finally {\n\t\tserver.server.close();\n\t}\n}\n\nexport const antigravityOAuthProvider: OAuthProviderInterface = {\n\tid: \"google-antigravity\",\n\tname: \"Antigravity (Gemini 3, Claude, GPT-OSS)\",\n\tusesCallbackServer: true,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginAntigravity(callbacks.onAuth, callbacks.onProgress, callbacks.onManualCodeInput);\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\tconst creds = credentials as AntigravityCredentials;\n\t\tif (!creds.projectId) {\n\t\t\tthrow new Error(\"Antigravity credentials missing projectId\");\n\t\t}\n\t\treturn refreshAntigravityToken(creds.refresh, creds.projectId);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\tconst creds = credentials as AntigravityCredentials;\n\t\treturn JSON.stringify({ token: creds.access, projectId: creds.projectId });\n\t},\n};\n"]}
1
+ {"version":3,"file":"google-antigravity.js","sourceRoot":"","sources":["../../../src/utils/oauth/google-antigravity.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAEN,kBAAkB,EAClB,gBAAgB,EAChB,uBAAuB,EACvB,mBAAmB,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAOzC,4DAA4D;AAC5D,EAAE;AACF,4EAA4E;AAC5E,2EAA2E;AAC3E,iGAAiG;AACjG,EAAE;AACF,6EAA6E;AAC7E,4EAA4E;AAC5E,iCAAiC;AACjC,yDAAyD;AACzD,6CAA6C;AAC7C,wCAAwC;AACxC,EAAE;AACF,0EAA0E;AAC1E,MAAM,SAAS,GAAG,2EAA2E,CAAC;AAC9F,MAAM,aAAa,GAAG,qCAAqC,CAAC;AAC5D,MAAM,YAAY,GAAG,uCAAuC,CAAC;AAE7D,yCAAyC;AACzC,MAAM,MAAM,GAAG;IACd,gDAAgD;IAChD,gDAAgD;IAChD,kDAAkD;IAClD,uCAAuC;IACvC,uDAAuD;CACvD,CAAC;AAEF,MAAM,QAAQ,GAAG,8CAA8C,CAAC;AAChE,MAAM,SAAS,GAAG,qCAAqC,CAAC;AAExD,gCAAgC;AAChC,MAAM,aAAa,GAAG,KAAK,CAAC;AAC5B,MAAM,aAAa,GAAG,iBAAiB,CAAC;AAExC,2CAA2C;AAC3C,MAAM,kBAAkB,GAAG,mBAAmB,CAAC;AAQ/C;;GAEG;AACH,KAAK,UAAU,eAAe,CAAC,WAAmB,EAAE,UAAsC;IACzF,MAAM,OAAO,GAAG;QACf,aAAa,EAAE,UAAU,WAAW,EAAE;QACtC,cAAc,EAAE,kBAAkB;QAClC,YAAY,EAAE,iCAAiC;QAC/C,mBAAmB,EAAE,8CAA8C;QACnE,iBAAiB,EAAE,IAAI,CAAC,SAAS,CAAC;YACjC,OAAO,EAAE,iBAAiB;YAC1B,QAAQ,EAAE,sBAAsB;YAChC,UAAU,EAAE,QAAQ;SACpB,CAAC;KACF,CAAC;IAEF,mDAAmD;IACnD,MAAM,SAAS,GAAG,CAAC,qCAAqC,EAAE,mDAAmD,CAAC,CAAC;IAE/G,UAAU,EAAE,CAAC,kCAAkC,CAAC,CAAC;IAEjD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QAClC,IAAI,CAAC;YACJ,MAAM,YAAY,GAAG,MAAM,KAAK,CAAC,GAAG,QAAQ,4BAA4B,EAAE;gBACzE,MAAM,EAAE,MAAM;gBACd,OAAO;gBACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACpB,QAAQ,EAAE;wBACT,OAAO,EAAE,iBAAiB;wBAC1B,QAAQ,EAAE,sBAAsB;wBAChC,UAAU,EAAE,QAAQ;qBACpB;iBACD,CAAC;gBACF,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;aACnC,CAAC,CAAC;YAEH,IAAI,YAAY,CAAC,EAAE,EAAE,CAAC;gBACrB,MAAM,IAAI,GAAG,CAAC,MAAM,YAAY,CAAC,IAAI,EAAE,CAA0B,CAAC;gBAElE,wCAAwC;gBACxC,IAAI,OAAO,IAAI,CAAC,uBAAuB,KAAK,QAAQ,IAAI,IAAI,CAAC,uBAAuB,EAAE,CAAC;oBACtF,OAAO,IAAI,CAAC,uBAAuB,CAAC;gBACrC,CAAC;gBACD,IACC,IAAI,CAAC,uBAAuB;oBAC5B,OAAO,IAAI,CAAC,uBAAuB,KAAK,QAAQ;oBAChD,IAAI,CAAC,uBAAuB,CAAC,EAAE,EAC9B,CAAC;oBACF,OAAO,IAAI,CAAC,uBAAuB,CAAC,EAAE,CAAC;gBACxC,CAAC;YACF,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,oBAAoB;QACrB,CAAC;IACF,CAAC;IAED,0BAA0B;IAC1B,UAAU,EAAE,CAAC,0BAA0B,CAAC,CAAC;IACzC,OAAO,kBAAkB,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,YAAoB,EAAE,SAAiB;IACpF,OAAO,uBAAuB,CAAC,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;AACtG,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACrC,MAA8D,EAC9D,UAAsC,EACtC,iBAAyC;IAEzC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;IAErD,kCAAkC;IAClC,UAAU,EAAE,CAAC,6CAA6C,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAuB,MAAM,mBAAmB,CAAC,aAAa,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;IAE1G,IAAI,IAAwB,CAAC;IAE7B,IAAI,CAAC;QACJ,0BAA0B;QAC1B,MAAM,UAAU,GAAG,IAAI,eAAe,CAAC;YACtC,SAAS,EAAE,SAAS;YACpB,aAAa,EAAE,MAAM;YACrB,YAAY,EAAE,YAAY;YAC1B,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;YACvB,cAAc,EAAE,SAAS;YACzB,qBAAqB,EAAE,MAAM;YAC7B,KAAK,EAAE,QAAQ;YACf,WAAW,EAAE,SAAS;YACtB,MAAM,EAAE,SAAS;SACjB,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,GAAG,QAAQ,IAAI,UAAU,CAAC,QAAQ,EAAE,EAAE,CAAC;QAEvD,iCAAiC;QACjC,MAAM,CAAC;YACN,GAAG,EAAE,OAAO;YACZ,YAAY,EAAE,uCAAuC;SACrD,CAAC,CAAC;QAEH,8DAA8D;QAC9D,UAAU,EAAE,CAAC,+BAA+B,CAAC,CAAC;QAE9C,IAAI,iBAAiB,EAAE,CAAC;YACvB,iDAAiD;YACjD,IAAI,WAA+B,CAAC;YACpC,IAAI,WAA8B,CAAC;YACnC,MAAM,aAAa,GAAG,iBAAiB,EAAE;iBACvC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;gBACf,WAAW,GAAG,KAAK,CAAC;gBACpB,MAAM,CAAC,UAAU,EAAE,CAAC;YACrB,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBACd,WAAW,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBAClE,MAAM,CAAC,UAAU,EAAE,CAAC;YACrB,CAAC,CAAC,CAAC;YAEJ,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YAE1C,kDAAkD;YAClD,IAAI,WAAW,EAAE,CAAC;gBACjB,MAAM,WAAW,CAAC;YACnB,CAAC;YAED,IAAI,MAAM,EAAE,IAAI,EAAE,CAAC;gBAClB,sCAAsC;gBACtC,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC/B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;gBAChE,CAAC;gBACD,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACpB,CAAC;iBAAM,IAAI,WAAW,EAAE,CAAC;gBACxB,mBAAmB;gBACnB,MAAM,MAAM,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;gBAC7C,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC/C,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;gBAChE,CAAC;gBACD,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACpB,CAAC;YAED,yDAAyD;YACzD,IAAI,CAAC,IAAI,EAAE,CAAC;gBACX,MAAM,aAAa,CAAC;gBACpB,IAAI,WAAW,EAAE,CAAC;oBACjB,MAAM,WAAW,CAAC;gBACnB,CAAC;gBACD,IAAI,WAAW,EAAE,CAAC;oBACjB,MAAM,MAAM,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;oBAC7C,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;wBAC/C,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;oBAChE,CAAC;oBACD,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;gBACpB,CAAC;YACF,CAAC;QACF,CAAC;aAAM,CAAC;YACP,wCAAwC;YACxC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YAC1C,IAAI,MAAM,EAAE,IAAI,EAAE,CAAC;gBAClB,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC/B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;gBAChE,CAAC;gBACD,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACpB,CAAC;QACF,CAAC;QAED,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACnD,CAAC;QAED,2BAA2B;QAC3B,UAAU,EAAE,CAAC,6CAA6C,CAAC,CAAC;QAC5D,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE;YAC5C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACR,cAAc,EAAE,mCAAmC;aACnD;YACD,IAAI,EAAE,IAAI,eAAe,CAAC;gBACzB,SAAS,EAAE,SAAS;gBACpB,aAAa,EAAE,aAAa;gBAC5B,IAAI;gBACJ,UAAU,EAAE,oBAAoB;gBAChC,YAAY,EAAE,YAAY;gBAC1B,aAAa,EAAE,QAAQ;aACvB,CAAC;YACF,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;SACnC,CAAC,CAAC;QAEH,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,0BAA0B,KAAK,EAAE,CAAC,CAAC;QACpD,CAAC;QAED,MAAM,SAAS,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,CAI5C,CAAC;QAEF,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QACjE,CAAC;QAED,iBAAiB;QACjB,UAAU,EAAE,CAAC,sBAAsB,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAE/D,mBAAmB;QACnB,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,SAAS,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QAE5E,2EAA2E;QAC3E,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,UAAU,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;QAE3E,MAAM,WAAW,GAAqB;YACrC,OAAO,EAAE,SAAS,CAAC,aAAa;YAChC,MAAM,EAAE,SAAS,CAAC,YAAY;YAC9B,OAAO,EAAE,SAAS;YAClB,SAAS;YACT,KAAK;SACL,CAAC;QAEF,OAAO,WAAW,CAAC;IACpB,CAAC;YAAS,CAAC;QACV,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,wBAAwB,GAA2B;IAC/D,EAAE,EAAE,oBAAoB;IACxB,IAAI,EAAE,yCAAyC;IAC/C,kBAAkB,EAAE,IAAI;IAExB,KAAK,CAAC,KAAK,CAAC,SAA8B;QACzC,OAAO,gBAAgB,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,UAAU,EAAE,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAC9F,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,WAA6B;QAC/C,MAAM,KAAK,GAAG,WAAqC,CAAC;QACpD,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,uBAAuB,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,CAAC;IAED,SAAS,CAAC,WAA6B;QACtC,MAAM,KAAK,GAAG,WAAqC,CAAC;QACpD,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;IAC5E,CAAC;CACD,CAAC","sourcesContent":["/**\n * Antigravity OAuth flow (Gemini 3, Claude, GPT-OSS via Google Cloud)\n * Uses different OAuth credentials than google-gemini-cli for access to additional models.\n *\n * NOTE: This module uses Node.js http.createServer for the OAuth callback.\n * It is only intended for CLI use, not browser environments.\n */\n\nimport {\n\ttype CallbackServerInfo,\n\tgetGoogleUserEmail,\n\tparseRedirectUrl,\n\trefreshGoogleOAuthToken,\n\tstartCallbackServer,\n} from \"./google-oauth-utils.js\";\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.js\";\n\ntype AntigravityCredentials = OAuthCredentials & {\n\tprojectId: string;\n};\n\n// Antigravity OAuth credentials (different from Gemini CLI)\n//\n// NOTE: These credentials are public in the source code. They should NOT be\n// obfuscated because security scanners flag obfuscated data as potentially\n// malicious (see: https://socket.dev/npm/package/gsd-pi/alerts/2.70.1?alert_name=obfuscatedFile)\n//\n// Google's OAuth implementation requires client_secret for Desktop App OAuth\n// clients even though it cannot be kept secret in distributed applications.\n// The actual security relies on:\n// - PKCE (Proof Key for Code Exchange) via code_verifier\n// - Redirect URI validation (localhost only)\n// - User consent and token scope limits\n//\n// See: https://developers.google.com/identity/protocols/oauth2/native-app\nconst CLIENT_ID = \"1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com\";\nconst CLIENT_SECRET = \"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\";\nconst REDIRECT_URI = \"http://localhost:51121/oauth-callback\";\n\n// Antigravity requires additional scopes\nconst SCOPES = [\n\t\"https://www.googleapis.com/auth/cloud-platform\",\n\t\"https://www.googleapis.com/auth/userinfo.email\",\n\t\"https://www.googleapis.com/auth/userinfo.profile\",\n\t\"https://www.googleapis.com/auth/cclog\",\n\t\"https://www.googleapis.com/auth/experimentsandconfigs\",\n];\n\nconst AUTH_URL = \"https://accounts.google.com/o/oauth2/v2/auth\";\nconst TOKEN_URL = \"https://oauth2.googleapis.com/token\";\n\n// Callback server configuration\nconst CALLBACK_PORT = 51121;\nconst CALLBACK_PATH = \"/oauth-callback\";\n\n// Fallback project ID when discovery fails\nconst DEFAULT_PROJECT_ID = \"rising-fact-p41fc\";\n\ninterface LoadCodeAssistPayload {\n\tcloudaicompanionProject?: string | { id?: string };\n\tcurrentTier?: { id?: string };\n\tallowedTiers?: Array<{ id?: string; isDefault?: boolean }>;\n}\n\n/**\n * Discover or provision a project for the user\n */\nasync function discoverProject(accessToken: string, onProgress?: (message: string) => void): Promise<string> {\n\tconst headers = {\n\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\"Content-Type\": \"application/json\",\n\t\t\"User-Agent\": \"google-api-nodejs-client/9.15.1\",\n\t\t\"X-Goog-Api-Client\": \"google-cloud-sdk vscode_cloudshelleditor/0.1\",\n\t\t\"Client-Metadata\": JSON.stringify({\n\t\t\tideType: \"IDE_UNSPECIFIED\",\n\t\t\tplatform: \"PLATFORM_UNSPECIFIED\",\n\t\t\tpluginType: \"GEMINI\",\n\t\t}),\n\t};\n\n\t// Try endpoints in order: prod first, then sandbox\n\tconst endpoints = [\"https://cloudcode-pa.googleapis.com\", \"https://daily-cloudcode-pa.sandbox.googleapis.com\"];\n\n\tonProgress?.(\"Checking for existing project...\");\n\n\tfor (const endpoint of endpoints) {\n\t\ttry {\n\t\t\tconst loadResponse = await fetch(`${endpoint}/v1internal:loadCodeAssist`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders,\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\tideType: \"IDE_UNSPECIFIED\",\n\t\t\t\t\t\tplatform: \"PLATFORM_UNSPECIFIED\",\n\t\t\t\t\t\tpluginType: \"GEMINI\",\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tsignal: AbortSignal.timeout(30_000),\n\t\t\t});\n\n\t\t\tif (loadResponse.ok) {\n\t\t\t\tconst data = (await loadResponse.json()) as LoadCodeAssistPayload;\n\n\t\t\t\t// Handle both string and object formats\n\t\t\t\tif (typeof data.cloudaicompanionProject === \"string\" && data.cloudaicompanionProject) {\n\t\t\t\t\treturn data.cloudaicompanionProject;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\tdata.cloudaicompanionProject &&\n\t\t\t\t\ttypeof data.cloudaicompanionProject === \"object\" &&\n\t\t\t\t\tdata.cloudaicompanionProject.id\n\t\t\t\t) {\n\t\t\t\t\treturn data.cloudaicompanionProject.id;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Try next endpoint\n\t\t}\n\t}\n\n\t// Use fallback project ID\n\tonProgress?.(\"Using default project...\");\n\treturn DEFAULT_PROJECT_ID;\n}\n\n/**\n * Refresh Antigravity token\n */\nexport async function refreshAntigravityToken(refreshToken: string, projectId: string): Promise<OAuthCredentials> {\n\treturn refreshGoogleOAuthToken(refreshToken, CLIENT_ID, CLIENT_SECRET, \"Antigravity\", { projectId });\n}\n\n/**\n * Login with Antigravity OAuth\n *\n * @param onAuth - Callback with URL and optional instructions\n * @param onProgress - Optional progress callback\n * @param onManualCodeInput - Optional promise that resolves with user-pasted redirect URL.\n * Races with browser callback - whichever completes first wins.\n */\nexport async function loginAntigravity(\n\tonAuth: (info: { url: string; instructions?: string }) => void,\n\tonProgress?: (message: string) => void,\n\tonManualCodeInput?: () => Promise<string>,\n): Promise<OAuthCredentials> {\n\tconst { verifier, challenge } = await generatePKCE();\n\n\t// Start local server for callback\n\tonProgress?.(\"Starting local server for OAuth callback...\");\n\tconst server: CallbackServerInfo = await startCallbackServer(CALLBACK_PORT, CALLBACK_PATH, \"Antigravity\");\n\n\tlet code: string | undefined;\n\n\ttry {\n\t\t// Build authorization URL\n\t\tconst authParams = new URLSearchParams({\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tresponse_type: \"code\",\n\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\tscope: SCOPES.join(\" \"),\n\t\t\tcode_challenge: challenge,\n\t\t\tcode_challenge_method: \"S256\",\n\t\t\tstate: verifier,\n\t\t\taccess_type: \"offline\",\n\t\t\tprompt: \"consent\",\n\t\t});\n\n\t\tconst authUrl = `${AUTH_URL}?${authParams.toString()}`;\n\n\t\t// Notify caller with URL to open\n\t\tonAuth({\n\t\t\turl: authUrl,\n\t\t\tinstructions: \"Complete the sign-in in your browser.\",\n\t\t});\n\n\t\t// Wait for the callback, racing with manual input if provided\n\t\tonProgress?.(\"Waiting for OAuth callback...\");\n\n\t\tif (onManualCodeInput) {\n\t\t\t// Race between browser callback and manual input\n\t\t\tlet manualInput: string | undefined;\n\t\t\tlet manualError: Error | undefined;\n\t\t\tconst manualPromise = onManualCodeInput()\n\t\t\t\t.then((input) => {\n\t\t\t\t\tmanualInput = input;\n\t\t\t\t\tserver.cancelWait();\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tmanualError = err instanceof Error ? err : new Error(String(err));\n\t\t\t\t\tserver.cancelWait();\n\t\t\t\t});\n\n\t\t\tconst result = await server.waitForCode();\n\n\t\t\t// If manual input was cancelled, throw that error\n\t\t\tif (manualError) {\n\t\t\t\tthrow manualError;\n\t\t\t}\n\n\t\t\tif (result?.code) {\n\t\t\t\t// Browser callback won - verify state\n\t\t\t\tif (result.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t}\n\t\t\t\tcode = result.code;\n\t\t\t} else if (manualInput) {\n\t\t\t\t// Manual input won\n\t\t\t\tconst parsed = parseRedirectUrl(manualInput);\n\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t}\n\t\t\t\tcode = parsed.code;\n\t\t\t}\n\n\t\t\t// If still no code, wait for manual promise and try that\n\t\t\tif (!code) {\n\t\t\t\tawait manualPromise;\n\t\t\t\tif (manualError) {\n\t\t\t\t\tthrow manualError;\n\t\t\t\t}\n\t\t\t\tif (manualInput) {\n\t\t\t\t\tconst parsed = parseRedirectUrl(manualInput);\n\t\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t\t}\n\t\t\t\t\tcode = parsed.code;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Original flow: just wait for callback\n\t\t\tconst result = await server.waitForCode();\n\t\t\tif (result?.code) {\n\t\t\t\tif (result.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t}\n\t\t\t\tcode = result.code;\n\t\t\t}\n\t\t}\n\n\t\tif (!code) {\n\t\t\tthrow new Error(\"No authorization code received\");\n\t\t}\n\n\t\t// Exchange code for tokens\n\t\tonProgress?.(\"Exchanging authorization code for tokens...\");\n\t\tconst tokenResponse = await fetch(TOKEN_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\tclient_secret: CLIENT_SECRET,\n\t\t\t\tcode,\n\t\t\t\tgrant_type: \"authorization_code\",\n\t\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\t\tcode_verifier: verifier,\n\t\t\t}),\n\t\t\tsignal: AbortSignal.timeout(30_000),\n\t\t});\n\n\t\tif (!tokenResponse.ok) {\n\t\t\tconst error = await tokenResponse.text();\n\t\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t\t}\n\n\t\tconst tokenData = (await tokenResponse.json()) as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\tif (!tokenData.refresh_token) {\n\t\t\tthrow new Error(\"No refresh token received. Please try again.\");\n\t\t}\n\n\t\t// Get user email\n\t\tonProgress?.(\"Getting user info...\");\n\t\tconst email = await getGoogleUserEmail(tokenData.access_token);\n\n\t\t// Discover project\n\t\tconst projectId = await discoverProject(tokenData.access_token, onProgress);\n\n\t\t// Calculate expiry time (current time + expires_in seconds - 5 min buffer)\n\t\tconst expiresAt = Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000;\n\n\t\tconst credentials: OAuthCredentials = {\n\t\t\trefresh: tokenData.refresh_token,\n\t\t\taccess: tokenData.access_token,\n\t\t\texpires: expiresAt,\n\t\t\tprojectId,\n\t\t\temail,\n\t\t};\n\n\t\treturn credentials;\n\t} finally {\n\t\tserver.server.close();\n\t}\n}\n\nexport const antigravityOAuthProvider: OAuthProviderInterface = {\n\tid: \"google-antigravity\",\n\tname: \"Antigravity (Gemini 3, Claude, GPT-OSS)\",\n\tusesCallbackServer: true,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginAntigravity(callbacks.onAuth, callbacks.onProgress, callbacks.onManualCodeInput);\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\tconst creds = credentials as AntigravityCredentials;\n\t\tif (!creds.projectId) {\n\t\t\tthrow new Error(\"Antigravity credentials missing projectId\");\n\t\t}\n\t\treturn refreshAntigravityToken(creds.refresh, creds.projectId);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\tconst creds = credentials as AntigravityCredentials;\n\t\treturn JSON.stringify({ token: creds.access, projectId: creds.projectId });\n\t},\n};\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=google-antigravity.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-antigravity.test.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/google-antigravity.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,67 @@
1
+ import { describe, test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { existsSync, readFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { 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
+ describe("Antigravity OAuth — provider structure", () => {
16
+ test("has correct id and name", () => {
17
+ assert.equal(antigravityOAuthProvider.id, "google-antigravity");
18
+ assert.equal(antigravityOAuthProvider.name, "Antigravity (Gemini 3, Claude, GPT-OSS)");
19
+ });
20
+ test("uses callback server", () => {
21
+ assert.equal(antigravityOAuthProvider.usesCallbackServer, true);
22
+ });
23
+ test("has required methods", () => {
24
+ assert.equal(typeof antigravityOAuthProvider.login, "function");
25
+ assert.equal(typeof antigravityOAuthProvider.refreshToken, "function");
26
+ assert.equal(typeof antigravityOAuthProvider.getApiKey, "function");
27
+ });
28
+ test("getApiKey returns JSON with token and projectId", () => {
29
+ const credentials = {
30
+ access: "test-access-token",
31
+ refresh: "test-refresh-token",
32
+ expires: Date.now() + 3600000,
33
+ projectId: "test-project-123",
34
+ email: "test@example.com",
35
+ };
36
+ const apiKey = antigravityOAuthProvider.getApiKey(credentials);
37
+ assert.equal(typeof apiKey, "string");
38
+ const parsed = JSON.parse(apiKey);
39
+ assert.equal(parsed.token, "test-access-token");
40
+ assert.equal(parsed.projectId, "test-project-123");
41
+ });
42
+ test("refreshToken throws when projectId is missing", async () => {
43
+ const credentials = {
44
+ access: "test-access-token",
45
+ refresh: "test-refresh-token",
46
+ expires: Date.now() + 3600000,
47
+ };
48
+ await assert.rejects(antigravityOAuthProvider.refreshToken(credentials), /Antigravity credentials missing projectId/);
49
+ });
50
+ });
51
+ describe("Antigravity OAuth — credential regression", () => {
52
+ test("module imports successfully", () => {
53
+ assert.ok(antigravityOAuthProvider);
54
+ });
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"));
65
+ });
66
+ });
67
+ //# sourceMappingURL=google-antigravity.test.js.map
@@ -0,0 +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});"]}