piclaw 0.0.19 → 0.0.21

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 (270) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/defult-D5RLDUrI.js +1 -0
  3. package/.output/public/assets/{dist-CMBqBOCp.js → dist-BH_oa-kv.js} +1 -1
  4. package/.output/public/assets/index-7JvURuHy.js +204 -0
  5. package/.output/public/assets/index-K43slwjJ.css +1 -0
  6. package/.output/public/index.html +11 -2
  7. package/.output/server/_...path_.get.mjs +16 -0
  8. package/.output/server/_chunks/app.mjs +261 -181
  9. package/.output/server/_chunks/browser.mjs +4 -1
  10. package/.output/server/_chunks/config.mjs +4 -0
  11. package/.output/server/_chunks/db.mjs +32 -28
  12. package/.output/server/_chunks/device-bus.mjs +123 -0
  13. package/.output/server/_chunks/dummy.mjs +1 -1
  14. package/.output/server/_chunks/logger.mjs +23 -0
  15. package/.output/server/_chunks/login.mjs +1 -1
  16. package/.output/server/_chunks/notes.mjs +1 -3
  17. package/.output/server/_chunks/renderer-template.mjs +1 -1
  18. package/.output/server/_chunks/sandbox.mjs +217 -0
  19. package/.output/server/_chunks/server.mjs +2302 -122
  20. package/.output/server/_chunks/terminal.mjs +63 -8
  21. package/.output/server/_chunks/uploads.mjs +60 -0
  22. package/.output/server/_chunks/virtual.mjs +192 -54
  23. package/.output/server/_id_.delete.mjs +5 -2
  24. package/.output/server/_id_.patch.mjs +2 -0
  25. package/.output/server/_id_2.delete.mjs +8 -0
  26. package/.output/server/_jid_.delete.mjs +5 -2
  27. package/.output/server/_jid_.patch.mjs +37 -4
  28. package/.output/server/_jid_2.delete.mjs +5 -2
  29. package/.output/server/_libs/@acemir/cssom+[...].mjs +2269 -1137
  30. package/.output/server/_libs/@google/genai.mjs +337 -273
  31. package/.output/server/_libs/@mariozechner/pi-agent-core+[...].mjs +381 -2073
  32. package/.output/server/_libs/@mariozechner/pi-coding-agent+[...].mjs +231 -131
  33. package/.output/server/_libs/_.mjs +3 -2
  34. package/.output/server/_libs/_10.mjs +2 -4
  35. package/.output/server/_libs/_11.mjs +2 -4
  36. package/.output/server/_libs/_12.mjs +2 -3
  37. package/.output/server/_libs/_13.mjs +2 -3
  38. package/.output/server/_libs/_14.mjs +2 -4
  39. package/.output/server/_libs/_15.mjs +2 -4
  40. package/.output/server/_libs/_16.mjs +2 -3
  41. package/.output/server/_libs/_17.mjs +2 -4
  42. package/.output/server/_libs/_18.mjs +2 -2
  43. package/.output/server/_libs/_19.mjs +2 -2
  44. package/.output/server/_libs/_2.mjs +3 -3
  45. package/.output/server/_libs/_20.mjs +2 -2
  46. package/.output/server/_libs/_21.mjs +2 -2
  47. package/.output/server/_libs/_22.mjs +2 -2
  48. package/.output/server/_libs/_23.mjs +2 -2
  49. package/.output/server/_libs/_24.mjs +2 -2
  50. package/.output/server/_libs/_25.mjs +2 -2
  51. package/.output/server/_libs/_26.mjs +2 -2
  52. package/.output/server/_libs/_27.mjs +2 -2
  53. package/.output/server/_libs/_28.mjs +2 -2
  54. package/.output/server/_libs/_29.mjs +2 -2
  55. package/.output/server/_libs/_3.mjs +3 -3
  56. package/.output/server/_libs/_30.mjs +2 -2
  57. package/.output/server/_libs/_31.mjs +2 -2
  58. package/.output/server/_libs/_32.mjs +2 -2
  59. package/.output/server/_libs/_33.mjs +2 -2
  60. package/.output/server/_libs/_34.mjs +2 -2
  61. package/.output/server/_libs/_35.mjs +2 -2
  62. package/.output/server/_libs/_36.mjs +2 -2
  63. package/.output/server/_libs/_37.mjs +2 -2
  64. package/.output/server/_libs/_38.mjs +2 -2
  65. package/.output/server/_libs/_39.mjs +2 -2
  66. package/.output/server/_libs/_4.mjs +4 -3
  67. package/.output/server/_libs/_40.mjs +2 -2
  68. package/.output/server/_libs/_41.mjs +2 -2
  69. package/.output/server/_libs/_42.mjs +2 -2
  70. package/.output/server/_libs/_43.mjs +2 -2
  71. package/.output/server/_libs/_44.mjs +2 -2
  72. package/.output/server/_libs/_45.mjs +2 -2
  73. package/.output/server/_libs/_46.mjs +2 -2
  74. package/.output/server/_libs/_47.mjs +2 -2
  75. package/.output/server/_libs/_48.mjs +2 -2
  76. package/.output/server/_libs/_49.mjs +2 -2
  77. package/.output/server/_libs/_5.mjs +2 -3
  78. package/.output/server/_libs/_50.mjs +2 -2
  79. package/.output/server/_libs/_51.mjs +2 -2
  80. package/.output/server/_libs/_52.mjs +2 -2
  81. package/.output/server/_libs/_53.mjs +2 -2
  82. package/.output/server/_libs/_54.mjs +2 -2
  83. package/.output/server/_libs/_55.mjs +2 -2
  84. package/.output/server/_libs/_56.mjs +2 -2
  85. package/.output/server/_libs/_57.mjs +2 -2
  86. package/.output/server/_libs/_58.mjs +2 -2
  87. package/.output/server/_libs/_59.mjs +2 -2
  88. package/.output/server/_libs/_6.mjs +2 -3
  89. package/.output/server/_libs/_60.mjs +2 -2
  90. package/.output/server/_libs/_61.mjs +2 -2
  91. package/.output/server/_libs/_62.mjs +2 -2
  92. package/.output/server/_libs/_63.mjs +2 -2
  93. package/.output/server/_libs/_64.mjs +2 -2
  94. package/.output/server/_libs/_65.mjs +2 -2
  95. package/.output/server/_libs/_66.mjs +2 -2
  96. package/.output/server/_libs/_67.mjs +2 -2
  97. package/.output/server/_libs/_68.mjs +2 -2
  98. package/.output/server/_libs/_69.mjs +2 -2
  99. package/.output/server/_libs/_7.mjs +2 -5
  100. package/.output/server/_libs/_70.mjs +2 -2
  101. package/.output/server/_libs/_71.mjs +2 -2
  102. package/.output/server/_libs/_72.mjs +2 -2
  103. package/.output/server/_libs/_73.mjs +2 -2
  104. package/.output/server/_libs/_74.mjs +2 -2
  105. package/.output/server/_libs/_75.mjs +2 -2
  106. package/.output/server/_libs/_76.mjs +2 -2
  107. package/.output/server/_libs/_77.mjs +2 -2
  108. package/.output/server/_libs/_78.mjs +2 -2
  109. package/.output/server/_libs/_79.mjs +2 -2
  110. package/.output/server/_libs/_8.mjs +2 -3
  111. package/.output/server/_libs/_80.mjs +2 -2
  112. package/.output/server/_libs/_81.mjs +2 -2
  113. package/.output/server/_libs/_82.mjs +2 -2
  114. package/.output/server/_libs/_83.mjs +2 -2
  115. package/.output/server/_libs/_84.mjs +2 -2
  116. package/.output/server/_libs/_85.mjs +2 -2
  117. package/.output/server/_libs/_86.mjs +2 -2
  118. package/.output/server/_libs/_87.mjs +2 -2
  119. package/.output/server/_libs/_88.mjs +2 -2
  120. package/.output/server/_libs/_89.mjs +2 -2
  121. package/.output/server/_libs/_9.mjs +2 -4
  122. package/.output/server/_libs/_90.mjs +5 -2
  123. package/.output/server/_libs/_91.mjs +3 -2
  124. package/.output/server/_libs/_92.mjs +2 -2
  125. package/.output/server/_libs/_93.mjs +2 -2
  126. package/.output/server/_libs/_94.mjs +2 -2
  127. package/.output/server/_libs/agent-base.mjs +1 -1
  128. package/.output/server/_libs/cheerio+[...].mjs +1 -1
  129. package/.output/server/_libs/data-uri-to-buffer.mjs +2 -67
  130. package/.output/server/_libs/data-urls+[...].mjs +1 -1
  131. package/.output/server/_libs/diff.mjs +1 -1
  132. package/.output/server/_libs/exodus__bytes.mjs +99 -81
  133. package/.output/server/_libs/fetch-blob+node-domexception.mjs +1 -1
  134. package/.output/server/_libs/h3+rou3+srvx.mjs +34 -4
  135. package/.output/server/_libs/html-encoding-sniffer.mjs +1 -1
  136. package/.output/server/_libs/https-proxy-agent.mjs +2 -2
  137. package/.output/server/_libs/jsdom.mjs +1 -1
  138. package/.output/server/_libs/just-bash+[...].mjs +4676 -3916
  139. package/.output/server/_libs/mariozechner__jiti.mjs +1 -1
  140. package/.output/server/_libs/mariozechner__pi-ai.mjs +1472 -0
  141. package/.output/server/_libs/md4x.mjs +1 -1
  142. package/.output/server/_libs/mime.mjs +838 -1
  143. package/.output/server/_libs/node-fetch.mjs +4 -4
  144. package/.output/server/_libs/node-liblzma.mjs +1 -1
  145. package/.output/server/_libs/silvia-odwyer__photon-node.mjs +1 -1
  146. package/.output/server/_routes/api/auth/approve.mjs +2 -0
  147. package/.output/server/_routes/api/auth/revoke.mjs +2 -0
  148. package/.output/server/_routes/api/auth/status.mjs +25 -6
  149. package/.output/server/_routes/api/browser2.mjs +1 -1
  150. package/.output/server/_routes/api/config2.mjs +2 -0
  151. package/.output/server/_routes/api/device_events.mjs +36 -0
  152. package/.output/server/_routes/api/files/groups.mjs +1 -2
  153. package/.output/server/_routes/api/files/raw.mjs +1 -1
  154. package/.output/server/_routes/api/groups.mjs +5 -3
  155. package/.output/server/_routes/api/groups2.mjs +18 -6
  156. package/.output/server/_routes/api/health.mjs +1 -2
  157. package/.output/server/_routes/api/messages.mjs +7 -1
  158. package/.output/server/_routes/api/notes/delete.mjs +4 -1
  159. package/.output/server/_routes/api/notes/write.mjs +2 -0
  160. package/.output/server/_routes/api/ntfy/setup.mjs +8 -0
  161. package/.output/server/_routes/api/pi/apikey.mjs +3 -2
  162. package/.output/server/_routes/api/pi/apikey_providers.mjs +1 -2
  163. package/.output/server/_routes/api/pi/commands.mjs +13 -3
  164. package/.output/server/_routes/api/pi/login/events.mjs +0 -1
  165. package/.output/server/_routes/api/pi/login/respond.mjs +2 -1
  166. package/.output/server/_routes/api/pi/login.mjs +1 -2
  167. package/.output/server/_routes/api/pi/logout.mjs +2 -1
  168. package/.output/server/_routes/api/pi/models.mjs +1 -2
  169. package/.output/server/_routes/api/pi/models_config2.mjs +2 -0
  170. package/.output/server/_routes/api/pi/settings2.mjs +2 -0
  171. package/.output/server/_routes/api/pi/status.mjs +1 -2
  172. package/.output/server/_routes/api/proxy.mjs +19 -1
  173. package/.output/server/_routes/api/sandbox.mjs +26 -0
  174. package/.output/server/_routes/api/sandbox2.mjs +17 -0
  175. package/.output/server/_routes/api/send.mjs +26 -18
  176. package/.output/server/_routes/api/status.mjs +1 -3
  177. package/.output/server/_routes/api/stop.mjs +11 -0
  178. package/.output/server/_routes/api/store/plugins.mjs +75 -0
  179. package/.output/server/_routes/api/store/skills.mjs +11 -0
  180. package/.output/server/_routes/api/tasks2.mjs +3 -2
  181. package/.output/server/_routes/api/telegram/setup.mjs +5 -2
  182. package/.output/server/_routes/api/telegram/status.mjs +1 -2
  183. package/.output/server/_routes/api/terminal2.mjs +2 -1
  184. package/.output/server/_routes/api/tunnel/setup.mjs +4 -2
  185. package/.output/server/_runtime.mjs +1 -2
  186. package/.output/server/_utils.mjs +10 -2
  187. package/.output/server/index.mjs +1 -1
  188. package/.output/server/node_modules/amdefine/amdefine.js +301 -0
  189. package/.output/server/node_modules/amdefine/package.json +16 -0
  190. package/.output/server/node_modules/compressjs/lib/BWT.js +420 -0
  191. package/.output/server/node_modules/compressjs/lib/BWTC.js +234 -0
  192. package/.output/server/node_modules/compressjs/lib/BitStream.js +108 -0
  193. package/.output/server/node_modules/compressjs/lib/Bzip2.js +936 -0
  194. package/.output/server/node_modules/compressjs/lib/CRC32.js +105 -0
  195. package/.output/server/node_modules/compressjs/lib/Context1Model.js +56 -0
  196. package/.output/server/node_modules/compressjs/lib/DefSumModel.js +152 -0
  197. package/.output/server/node_modules/compressjs/lib/DeflateDistanceModel.js +55 -0
  198. package/.output/server/node_modules/compressjs/lib/Dmc.js +197 -0
  199. package/.output/server/node_modules/compressjs/lib/DummyRangeCoder.js +81 -0
  200. package/.output/server/node_modules/compressjs/lib/FenwickModel.js +194 -0
  201. package/.output/server/node_modules/compressjs/lib/Huffman.js +514 -0
  202. package/.output/server/node_modules/compressjs/lib/HuffmanAllocator.js +227 -0
  203. package/.output/server/node_modules/compressjs/lib/LogDistanceModel.js +46 -0
  204. package/.output/server/node_modules/compressjs/lib/Lzjb.js +300 -0
  205. package/.output/server/node_modules/compressjs/lib/LzjbR.js +241 -0
  206. package/.output/server/node_modules/compressjs/lib/Lzp3.js +273 -0
  207. package/.output/server/node_modules/compressjs/lib/MTFModel.js +208 -0
  208. package/.output/server/node_modules/compressjs/lib/NoModel.js +46 -0
  209. package/.output/server/node_modules/compressjs/lib/PPM.js +343 -0
  210. package/.output/server/node_modules/compressjs/lib/RangeCoder.js +238 -0
  211. package/.output/server/node_modules/compressjs/lib/Simple.js +111 -0
  212. package/.output/server/node_modules/compressjs/lib/Stream.js +53 -0
  213. package/.output/server/node_modules/compressjs/lib/Util.js +324 -0
  214. package/.output/server/node_modules/compressjs/lib/freeze.js +14 -0
  215. package/.output/server/node_modules/compressjs/main.js +29 -0
  216. package/.output/server/node_modules/compressjs/package.json +35 -0
  217. package/.output/server/package.json +2 -1
  218. package/README.md +10 -1
  219. package/lib/index.d.mts +1 -0
  220. package/lib/index.mjs +1 -0
  221. package/lib/piclaw.mjs +100 -0
  222. package/lib/utils.mjs +96 -0
  223. package/package.json +16 -11
  224. package/.output/public/assets/defult-CMO6TZ5a.js +0 -1
  225. package/.output/public/assets/index-jdnbJw-M.js +0 -204
  226. package/.output/public/assets/index-ooXrRwgl.css +0 -1
  227. package/.output/server/_chunks/commands.mjs +0 -282
  228. package/.output/server/_chunks/pi.mjs +0 -202
  229. package/.output/server/_chunks/session.mjs +0 -1114
  230. package/.output/server/_libs/@aws-crypto/crc32+[...].mjs +0 -299
  231. package/.output/server/_libs/@aws-sdk/client-bedrock-runtime+[...].mjs +0 -17828
  232. package/.output/server/_libs/@aws-sdk/credential-provider-http+[...].mjs +0 -122
  233. package/.output/server/_libs/@aws-sdk/credential-provider-ini+[...].mjs +0 -417
  234. package/.output/server/_libs/@aws-sdk/credential-provider-process+[...].mjs +0 -54
  235. package/.output/server/_libs/@aws-sdk/credential-provider-sso+[...].mjs +0 -1151
  236. package/.output/server/_libs/@aws-sdk/credential-provider-web-identity+[...].mjs +0 -50
  237. package/.output/server/_libs/@smithy/credential-provider-imds+[...].mjs +0 -369
  238. package/.output/server/_libs/@tootallnate/quickjs-emscripten+[...].mjs +0 -3011
  239. package/.output/server/_libs/_100.mjs +0 -2
  240. package/.output/server/_libs/_101.mjs +0 -2
  241. package/.output/server/_libs/_102.mjs +0 -5
  242. package/.output/server/_libs/_103.mjs +0 -3
  243. package/.output/server/_libs/_104.mjs +0 -2
  244. package/.output/server/_libs/_105.mjs +0 -3
  245. package/.output/server/_libs/_106.mjs +0 -2
  246. package/.output/server/_libs/_107.mjs +0 -2
  247. package/.output/server/_libs/_95.mjs +0 -2
  248. package/.output/server/_libs/_96.mjs +0 -2
  249. package/.output/server/_libs/_97.mjs +0 -2
  250. package/.output/server/_libs/_98.mjs +0 -2
  251. package/.output/server/_libs/_99.mjs +0 -2
  252. package/.output/server/_libs/amdefine.mjs +0 -188
  253. package/.output/server/_libs/ast-types.mjs +0 -2270
  254. package/.output/server/_libs/aws-sdk__nested-clients.mjs +0 -3141
  255. package/.output/server/_libs/basic-ftp.mjs +0 -1906
  256. package/.output/server/_libs/compressjs.mjs +0 -50
  257. package/.output/server/_libs/degenerator+[...].mjs +0 -9964
  258. package/.output/server/_libs/get-uri.mjs +0 -413
  259. package/.output/server/_libs/http-proxy-agent.mjs +0 -123
  260. package/.output/server/_libs/ip-address.mjs +0 -1423
  261. package/.output/server/_libs/lru-cache.mjs +0 -732
  262. package/.output/server/_libs/netmask.mjs +0 -139
  263. package/.output/server/_libs/pac-proxy-agent+[...].mjs +0 -3104
  264. package/.output/server/_libs/proxy-agent+proxy-from-env.mjs +0 -204
  265. package/.output/server/_libs/smithy__core.mjs +0 -192
  266. package/.output/server/node_modules/tslib/modules/index.js +0 -70
  267. package/.output/server/node_modules/tslib/modules/package.json +0 -3
  268. package/.output/server/node_modules/tslib/package.json +0 -47
  269. package/.output/server/node_modules/tslib/tslib.js +0 -484
  270. package/bin/piclaw.mjs +0 -195
@@ -0,0 +1,1472 @@
1
+ import { r as __exportAll } from "../_runtime.mjs";
2
+ import { c as getModels } from "./@mariozechner/pi-agent-core+[...].mjs";
3
+ /**
4
+ * PKCE utilities using Web Crypto API.
5
+ * Works in both Node.js 20+ and browsers.
6
+ */
7
+ /**
8
+ * Encode bytes as base64url string.
9
+ */
10
+ function base64urlEncode(bytes) {
11
+ let binary = "";
12
+ for (const byte of bytes) binary += String.fromCharCode(byte);
13
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
14
+ }
15
+ /**
16
+ * Generate PKCE code verifier and challenge.
17
+ * Uses Web Crypto API for cross-platform compatibility.
18
+ */
19
+ async function generatePKCE() {
20
+ const verifierBytes = new Uint8Array(32);
21
+ crypto.getRandomValues(verifierBytes);
22
+ const verifier = base64urlEncode(verifierBytes);
23
+ const data = new TextEncoder().encode(verifier);
24
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
25
+ return {
26
+ verifier,
27
+ challenge: base64urlEncode(new Uint8Array(hashBuffer))
28
+ };
29
+ }
30
+ /**
31
+ * Anthropic OAuth flow (Claude Pro/Max)
32
+ */
33
+ var decode$3 = (s) => atob(s);
34
+ var CLIENT_ID$4 = decode$3("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
35
+ var AUTHORIZE_URL$1 = "https://claude.ai/oauth/authorize";
36
+ var TOKEN_URL$3 = "https://console.anthropic.com/v1/oauth/token";
37
+ var REDIRECT_URI$3 = "https://console.anthropic.com/oauth/code/callback";
38
+ var SCOPES$2 = "org:create_api_key user:profile user:inference";
39
+ /**
40
+ * Login with Anthropic OAuth (device code flow)
41
+ *
42
+ * @param onAuthUrl - Callback to handle the authorization URL (e.g., open browser)
43
+ * @param onPromptCode - Callback to prompt user for the authorization code
44
+ */
45
+ async function loginAnthropic(onAuthUrl, onPromptCode) {
46
+ const { verifier, challenge } = await generatePKCE();
47
+ onAuthUrl(`${AUTHORIZE_URL$1}?${new URLSearchParams({
48
+ code: "true",
49
+ client_id: CLIENT_ID$4,
50
+ response_type: "code",
51
+ redirect_uri: REDIRECT_URI$3,
52
+ scope: SCOPES$2,
53
+ code_challenge: challenge,
54
+ code_challenge_method: "S256",
55
+ state: verifier
56
+ }).toString()}`);
57
+ const splits = (await onPromptCode()).split("#");
58
+ const code = splits[0];
59
+ const state = splits[1];
60
+ const tokenResponse = await fetch(TOKEN_URL$3, {
61
+ method: "POST",
62
+ headers: { "Content-Type": "application/json" },
63
+ body: JSON.stringify({
64
+ grant_type: "authorization_code",
65
+ client_id: CLIENT_ID$4,
66
+ code,
67
+ state,
68
+ redirect_uri: REDIRECT_URI$3,
69
+ code_verifier: verifier
70
+ })
71
+ });
72
+ if (!tokenResponse.ok) {
73
+ const error = await tokenResponse.text();
74
+ throw new Error(`Token exchange failed: ${error}`);
75
+ }
76
+ const tokenData = await tokenResponse.json();
77
+ const expiresAt = Date.now() + tokenData.expires_in * 1e3 - 300 * 1e3;
78
+ return {
79
+ refresh: tokenData.refresh_token,
80
+ access: tokenData.access_token,
81
+ expires: expiresAt
82
+ };
83
+ }
84
+ /**
85
+ * Refresh Anthropic OAuth token
86
+ */
87
+ async function refreshAnthropicToken(refreshToken) {
88
+ const response = await fetch(TOKEN_URL$3, {
89
+ method: "POST",
90
+ headers: { "Content-Type": "application/json" },
91
+ body: JSON.stringify({
92
+ grant_type: "refresh_token",
93
+ client_id: CLIENT_ID$4,
94
+ refresh_token: refreshToken
95
+ })
96
+ });
97
+ if (!response.ok) {
98
+ const error = await response.text();
99
+ throw new Error(`Anthropic token refresh failed: ${error}`);
100
+ }
101
+ const data = await response.json();
102
+ return {
103
+ refresh: data.refresh_token,
104
+ access: data.access_token,
105
+ expires: Date.now() + data.expires_in * 1e3 - 300 * 1e3
106
+ };
107
+ }
108
+ const anthropicOAuthProvider = {
109
+ id: "anthropic",
110
+ name: "Anthropic (Claude Pro/Max)",
111
+ async login(callbacks) {
112
+ return loginAnthropic((url) => callbacks.onAuth({ url }), () => callbacks.onPrompt({ message: "Paste the authorization code:" }));
113
+ },
114
+ async refreshToken(credentials) {
115
+ return refreshAnthropicToken(credentials.refresh);
116
+ },
117
+ getApiKey(credentials) {
118
+ return credentials.access;
119
+ }
120
+ };
121
+ /**
122
+ * GitHub Copilot OAuth flow
123
+ */
124
+ var decode$2 = (s) => atob(s);
125
+ var CLIENT_ID$3 = decode$2("SXYxLmI1MDdhMDhjODdlY2ZlOTg=");
126
+ var COPILOT_HEADERS = {
127
+ "User-Agent": "GitHubCopilotChat/0.35.0",
128
+ "Editor-Version": "vscode/1.107.0",
129
+ "Editor-Plugin-Version": "copilot-chat/0.35.0",
130
+ "Copilot-Integration-Id": "vscode-chat"
131
+ };
132
+ function normalizeDomain(input) {
133
+ const trimmed = input.trim();
134
+ if (!trimmed) return null;
135
+ try {
136
+ return (trimmed.includes("://") ? new URL(trimmed) : new URL(`https://${trimmed}`)).hostname;
137
+ } catch {
138
+ return null;
139
+ }
140
+ }
141
+ function getUrls(domain) {
142
+ return {
143
+ deviceCodeUrl: `https://${domain}/login/device/code`,
144
+ accessTokenUrl: `https://${domain}/login/oauth/access_token`,
145
+ copilotTokenUrl: `https://api.${domain}/copilot_internal/v2/token`
146
+ };
147
+ }
148
+ /**
149
+ * Parse the proxy-ep from a Copilot token and convert to API base URL.
150
+ * Token format: tid=...;exp=...;proxy-ep=proxy.individual.githubcopilot.com;...
151
+ * Returns API URL like https://api.individual.githubcopilot.com
152
+ */
153
+ function getBaseUrlFromToken(token) {
154
+ const match = token.match(/proxy-ep=([^;]+)/);
155
+ if (!match) return null;
156
+ return `https://${match[1].replace(/^proxy\./, "api.")}`;
157
+ }
158
+ function getGitHubCopilotBaseUrl(token, enterpriseDomain) {
159
+ if (token) {
160
+ const urlFromToken = getBaseUrlFromToken(token);
161
+ if (urlFromToken) return urlFromToken;
162
+ }
163
+ if (enterpriseDomain) return `https://copilot-api.${enterpriseDomain}`;
164
+ return "https://api.individual.githubcopilot.com";
165
+ }
166
+ async function fetchJson(url, init) {
167
+ const response = await fetch(url, init);
168
+ if (!response.ok) {
169
+ const text = await response.text();
170
+ throw new Error(`${response.status} ${response.statusText}: ${text}`);
171
+ }
172
+ return response.json();
173
+ }
174
+ async function startDeviceFlow(domain) {
175
+ const data = await fetchJson(getUrls(domain).deviceCodeUrl, {
176
+ method: "POST",
177
+ headers: {
178
+ Accept: "application/json",
179
+ "Content-Type": "application/json",
180
+ "User-Agent": "GitHubCopilotChat/0.35.0"
181
+ },
182
+ body: JSON.stringify({
183
+ client_id: CLIENT_ID$3,
184
+ scope: "read:user"
185
+ })
186
+ });
187
+ if (!data || typeof data !== "object") throw new Error("Invalid device code response");
188
+ const deviceCode = data.device_code;
189
+ const userCode = data.user_code;
190
+ const verificationUri = data.verification_uri;
191
+ const interval = data.interval;
192
+ const expiresIn = data.expires_in;
193
+ if (typeof deviceCode !== "string" || typeof userCode !== "string" || typeof verificationUri !== "string" || typeof interval !== "number" || typeof expiresIn !== "number") throw new Error("Invalid device code response fields");
194
+ return {
195
+ device_code: deviceCode,
196
+ user_code: userCode,
197
+ verification_uri: verificationUri,
198
+ interval,
199
+ expires_in: expiresIn
200
+ };
201
+ }
202
+ /**
203
+ * Sleep that can be interrupted by an AbortSignal
204
+ */
205
+ function abortableSleep(ms, signal) {
206
+ return new Promise((resolve, reject) => {
207
+ if (signal?.aborted) {
208
+ reject(/* @__PURE__ */ new Error("Login cancelled"));
209
+ return;
210
+ }
211
+ const timeout = setTimeout(resolve, ms);
212
+ signal?.addEventListener("abort", () => {
213
+ clearTimeout(timeout);
214
+ reject(/* @__PURE__ */ new Error("Login cancelled"));
215
+ }, { once: true });
216
+ });
217
+ }
218
+ async function pollForGitHubAccessToken(domain, deviceCode, intervalSeconds, expiresIn, signal) {
219
+ const urls = getUrls(domain);
220
+ const deadline = Date.now() + expiresIn * 1e3;
221
+ let intervalMs = Math.max(1e3, Math.floor(intervalSeconds * 1e3));
222
+ while (Date.now() < deadline) {
223
+ if (signal?.aborted) throw new Error("Login cancelled");
224
+ const raw = await fetchJson(urls.accessTokenUrl, {
225
+ method: "POST",
226
+ headers: {
227
+ Accept: "application/json",
228
+ "Content-Type": "application/json",
229
+ "User-Agent": "GitHubCopilotChat/0.35.0"
230
+ },
231
+ body: JSON.stringify({
232
+ client_id: CLIENT_ID$3,
233
+ device_code: deviceCode,
234
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code"
235
+ })
236
+ });
237
+ if (raw && typeof raw === "object" && typeof raw.access_token === "string") return raw.access_token;
238
+ if (raw && typeof raw === "object" && typeof raw.error === "string") {
239
+ const err = raw.error;
240
+ if (err === "authorization_pending") {
241
+ await abortableSleep(intervalMs, signal);
242
+ continue;
243
+ }
244
+ if (err === "slow_down") {
245
+ intervalMs += 5e3;
246
+ await abortableSleep(intervalMs, signal);
247
+ continue;
248
+ }
249
+ throw new Error(`Device flow failed: ${err}`);
250
+ }
251
+ await abortableSleep(intervalMs, signal);
252
+ }
253
+ throw new Error("Device flow timed out");
254
+ }
255
+ /**
256
+ * Refresh GitHub Copilot token
257
+ */
258
+ async function refreshGitHubCopilotToken(refreshToken, enterpriseDomain) {
259
+ const raw = await fetchJson(getUrls(enterpriseDomain || "github.com").copilotTokenUrl, { headers: {
260
+ Accept: "application/json",
261
+ Authorization: `Bearer ${refreshToken}`,
262
+ ...COPILOT_HEADERS
263
+ } });
264
+ if (!raw || typeof raw !== "object") throw new Error("Invalid Copilot token response");
265
+ const token = raw.token;
266
+ const expiresAt = raw.expires_at;
267
+ if (typeof token !== "string" || typeof expiresAt !== "number") throw new Error("Invalid Copilot token response fields");
268
+ return {
269
+ refresh: refreshToken,
270
+ access: token,
271
+ expires: expiresAt * 1e3 - 300 * 1e3,
272
+ enterpriseUrl: enterpriseDomain
273
+ };
274
+ }
275
+ /**
276
+ * Enable a model for the user's GitHub Copilot account.
277
+ * This is required for some models (like Claude, Grok) before they can be used.
278
+ */
279
+ async function enableGitHubCopilotModel(token, modelId, enterpriseDomain) {
280
+ const url = `${getGitHubCopilotBaseUrl(token, enterpriseDomain)}/models/${modelId}/policy`;
281
+ try {
282
+ return (await fetch(url, {
283
+ method: "POST",
284
+ headers: {
285
+ "Content-Type": "application/json",
286
+ Authorization: `Bearer ${token}`,
287
+ ...COPILOT_HEADERS,
288
+ "openai-intent": "chat-policy",
289
+ "x-interaction-type": "chat-policy"
290
+ },
291
+ body: JSON.stringify({ state: "enabled" })
292
+ })).ok;
293
+ } catch {
294
+ return false;
295
+ }
296
+ }
297
+ /**
298
+ * Enable all known GitHub Copilot models that may require policy acceptance.
299
+ * Called after successful login to ensure all models are available.
300
+ */
301
+ async function enableAllGitHubCopilotModels(token, enterpriseDomain, onProgress) {
302
+ const models = getModels("github-copilot");
303
+ await Promise.all(models.map(async (model) => {
304
+ const success = await enableGitHubCopilotModel(token, model.id, enterpriseDomain);
305
+ onProgress?.(model.id, success);
306
+ }));
307
+ }
308
+ /**
309
+ * Login with GitHub Copilot OAuth (device code flow)
310
+ *
311
+ * @param options.onAuth - Callback with URL and optional instructions (user code)
312
+ * @param options.onPrompt - Callback to prompt user for input
313
+ * @param options.onProgress - Optional progress callback
314
+ * @param options.signal - Optional AbortSignal for cancellation
315
+ */
316
+ async function loginGitHubCopilot(options) {
317
+ const input = await options.onPrompt({
318
+ message: "GitHub Enterprise URL/domain (blank for github.com)",
319
+ placeholder: "company.ghe.com",
320
+ allowEmpty: true
321
+ });
322
+ if (options.signal?.aborted) throw new Error("Login cancelled");
323
+ const trimmed = input.trim();
324
+ const enterpriseDomain = normalizeDomain(input);
325
+ if (trimmed && !enterpriseDomain) throw new Error("Invalid GitHub Enterprise URL/domain");
326
+ const domain = enterpriseDomain || "github.com";
327
+ const device = await startDeviceFlow(domain);
328
+ options.onAuth(device.verification_uri, `Enter code: ${device.user_code}`);
329
+ const credentials = await refreshGitHubCopilotToken(await pollForGitHubAccessToken(domain, device.device_code, device.interval, device.expires_in, options.signal), enterpriseDomain ?? void 0);
330
+ options.onProgress?.("Enabling models...");
331
+ await enableAllGitHubCopilotModels(credentials.access, enterpriseDomain ?? void 0);
332
+ return credentials;
333
+ }
334
+ const githubCopilotOAuthProvider = {
335
+ id: "github-copilot",
336
+ name: "GitHub Copilot",
337
+ async login(callbacks) {
338
+ return loginGitHubCopilot({
339
+ onAuth: (url, instructions) => callbacks.onAuth({
340
+ url,
341
+ instructions
342
+ }),
343
+ onPrompt: callbacks.onPrompt,
344
+ onProgress: callbacks.onProgress,
345
+ signal: callbacks.signal
346
+ });
347
+ },
348
+ async refreshToken(credentials) {
349
+ const creds = credentials;
350
+ return refreshGitHubCopilotToken(creds.refresh, creds.enterpriseUrl);
351
+ },
352
+ getApiKey(credentials) {
353
+ return credentials.access;
354
+ },
355
+ modifyModels(models, credentials) {
356
+ const creds = credentials;
357
+ const domain = creds.enterpriseUrl ? normalizeDomain(creds.enterpriseUrl) ?? void 0 : void 0;
358
+ const baseUrl = getGitHubCopilotBaseUrl(creds.access, domain);
359
+ return models.map((m) => m.provider === "github-copilot" ? {
360
+ ...m,
361
+ baseUrl
362
+ } : m);
363
+ }
364
+ };
365
+ /**
366
+ * Antigravity OAuth flow (Gemini 3, Claude, GPT-OSS via Google Cloud)
367
+ * Uses different OAuth credentials than google-gemini-cli for access to additional models.
368
+ *
369
+ * NOTE: This module uses Node.js http.createServer for the OAuth callback.
370
+ * It is only intended for CLI use, not browser environments.
371
+ */
372
+ var _createServer$1 = null;
373
+ var _httpImportPromise$1 = null;
374
+ if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) _httpImportPromise$1 = import("node:http").then((m) => {
375
+ _createServer$1 = m.createServer;
376
+ });
377
+ var decode$1 = (s) => atob(s);
378
+ var CLIENT_ID$2 = decode$1("MTA3MTAwNjA2MDU5MS10bWhzc2luMmgyMWxjcmUyMzV2dG9sb2poNGc0MDNlcC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbQ==");
379
+ var CLIENT_SECRET$1 = decode$1("R09DU1BYLUs1OEZXUjQ4NkxkTEoxbUxCOHNYQzR6NnFEQWY=");
380
+ var REDIRECT_URI$2 = "http://localhost:51121/oauth-callback";
381
+ var SCOPES$1 = [
382
+ "https://www.googleapis.com/auth/cloud-platform",
383
+ "https://www.googleapis.com/auth/userinfo.email",
384
+ "https://www.googleapis.com/auth/userinfo.profile",
385
+ "https://www.googleapis.com/auth/cclog",
386
+ "https://www.googleapis.com/auth/experimentsandconfigs"
387
+ ];
388
+ var AUTH_URL$1 = "https://accounts.google.com/o/oauth2/v2/auth";
389
+ var TOKEN_URL$2 = "https://oauth2.googleapis.com/token";
390
+ var DEFAULT_PROJECT_ID = "rising-fact-p41fc";
391
+ /**
392
+ * Start a local HTTP server to receive the OAuth callback
393
+ */
394
+ async function getNodeCreateServer$1() {
395
+ if (_createServer$1) return _createServer$1;
396
+ if (_httpImportPromise$1) await _httpImportPromise$1;
397
+ if (_createServer$1) return _createServer$1;
398
+ throw new Error("Antigravity OAuth is only available in Node.js environments");
399
+ }
400
+ async function startCallbackServer$1() {
401
+ const createServer = await getNodeCreateServer$1();
402
+ return new Promise((resolve, reject) => {
403
+ let result = null;
404
+ let cancelled = false;
405
+ const server = createServer((req, res) => {
406
+ const url = new URL(req.url || "", `http://localhost:51121`);
407
+ if (url.pathname === "/oauth-callback") {
408
+ const code = url.searchParams.get("code");
409
+ const state = url.searchParams.get("state");
410
+ const error = url.searchParams.get("error");
411
+ if (error) {
412
+ res.writeHead(400, { "Content-Type": "text/html" });
413
+ res.end(`<html><body><h1>Authentication Failed</h1><p>Error: ${error}</p><p>You can close this window.</p></body></html>`);
414
+ return;
415
+ }
416
+ if (code && state) {
417
+ res.writeHead(200, { "Content-Type": "text/html" });
418
+ res.end(`<html><body><h1>Authentication Successful</h1><p>You can close this window and return to the terminal.</p></body></html>`);
419
+ result = {
420
+ code,
421
+ state
422
+ };
423
+ } else {
424
+ res.writeHead(400, { "Content-Type": "text/html" });
425
+ res.end(`<html><body><h1>Authentication Failed</h1><p>Missing code or state parameter.</p></body></html>`);
426
+ }
427
+ } else {
428
+ res.writeHead(404);
429
+ res.end();
430
+ }
431
+ });
432
+ server.on("error", (err) => {
433
+ reject(err);
434
+ });
435
+ server.listen(51121, "127.0.0.1", () => {
436
+ resolve({
437
+ server,
438
+ cancelWait: () => {
439
+ cancelled = true;
440
+ },
441
+ waitForCode: async () => {
442
+ const sleep = () => new Promise((r) => setTimeout(r, 100));
443
+ while (!result && !cancelled) await sleep();
444
+ return result;
445
+ }
446
+ });
447
+ });
448
+ });
449
+ }
450
+ /**
451
+ * Parse redirect URL to extract code and state
452
+ */
453
+ function parseRedirectUrl$1(input) {
454
+ const value = input.trim();
455
+ if (!value) return {};
456
+ try {
457
+ const url = new URL(value);
458
+ return {
459
+ code: url.searchParams.get("code") ?? void 0,
460
+ state: url.searchParams.get("state") ?? void 0
461
+ };
462
+ } catch {
463
+ return {};
464
+ }
465
+ }
466
+ /**
467
+ * Discover or provision a project for the user
468
+ */
469
+ async function discoverProject$1(accessToken, onProgress) {
470
+ const headers = {
471
+ Authorization: `Bearer ${accessToken}`,
472
+ "Content-Type": "application/json",
473
+ "User-Agent": "google-api-nodejs-client/9.15.1",
474
+ "X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
475
+ "Client-Metadata": JSON.stringify({
476
+ ideType: "IDE_UNSPECIFIED",
477
+ platform: "PLATFORM_UNSPECIFIED",
478
+ pluginType: "GEMINI"
479
+ })
480
+ };
481
+ const endpoints = ["https://cloudcode-pa.googleapis.com", "https://daily-cloudcode-pa.sandbox.googleapis.com"];
482
+ onProgress?.("Checking for existing project...");
483
+ for (const endpoint of endpoints) try {
484
+ const loadResponse = await fetch(`${endpoint}/v1internal:loadCodeAssist`, {
485
+ method: "POST",
486
+ headers,
487
+ body: JSON.stringify({ metadata: {
488
+ ideType: "IDE_UNSPECIFIED",
489
+ platform: "PLATFORM_UNSPECIFIED",
490
+ pluginType: "GEMINI"
491
+ } })
492
+ });
493
+ if (loadResponse.ok) {
494
+ const data = await loadResponse.json();
495
+ if (typeof data.cloudaicompanionProject === "string" && data.cloudaicompanionProject) return data.cloudaicompanionProject;
496
+ if (data.cloudaicompanionProject && typeof data.cloudaicompanionProject === "object" && data.cloudaicompanionProject.id) return data.cloudaicompanionProject.id;
497
+ }
498
+ } catch {}
499
+ onProgress?.("Using default project...");
500
+ return DEFAULT_PROJECT_ID;
501
+ }
502
+ /**
503
+ * Get user email from the access token
504
+ */
505
+ async function getUserEmail$1(accessToken) {
506
+ try {
507
+ const response = await fetch("https://www.googleapis.com/oauth2/v1/userinfo?alt=json", { headers: { Authorization: `Bearer ${accessToken}` } });
508
+ if (response.ok) return (await response.json()).email;
509
+ } catch {}
510
+ }
511
+ /**
512
+ * Refresh Antigravity token
513
+ */
514
+ async function refreshAntigravityToken(refreshToken, projectId) {
515
+ const response = await fetch(TOKEN_URL$2, {
516
+ method: "POST",
517
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
518
+ body: new URLSearchParams({
519
+ client_id: CLIENT_ID$2,
520
+ client_secret: CLIENT_SECRET$1,
521
+ refresh_token: refreshToken,
522
+ grant_type: "refresh_token"
523
+ })
524
+ });
525
+ if (!response.ok) {
526
+ const error = await response.text();
527
+ throw new Error(`Antigravity token refresh failed: ${error}`);
528
+ }
529
+ const data = await response.json();
530
+ return {
531
+ refresh: data.refresh_token || refreshToken,
532
+ access: data.access_token,
533
+ expires: Date.now() + data.expires_in * 1e3 - 300 * 1e3,
534
+ projectId
535
+ };
536
+ }
537
+ /**
538
+ * Login with Antigravity OAuth
539
+ *
540
+ * @param onAuth - Callback with URL and optional instructions
541
+ * @param onProgress - Optional progress callback
542
+ * @param onManualCodeInput - Optional promise that resolves with user-pasted redirect URL.
543
+ * Races with browser callback - whichever completes first wins.
544
+ */
545
+ async function loginAntigravity(onAuth, onProgress, onManualCodeInput) {
546
+ const { verifier, challenge } = await generatePKCE();
547
+ onProgress?.("Starting local server for OAuth callback...");
548
+ const server = await startCallbackServer$1();
549
+ let code;
550
+ try {
551
+ onAuth({
552
+ url: `${AUTH_URL$1}?${new URLSearchParams({
553
+ client_id: CLIENT_ID$2,
554
+ response_type: "code",
555
+ redirect_uri: REDIRECT_URI$2,
556
+ scope: SCOPES$1.join(" "),
557
+ code_challenge: challenge,
558
+ code_challenge_method: "S256",
559
+ state: verifier,
560
+ access_type: "offline",
561
+ prompt: "consent"
562
+ }).toString()}`,
563
+ instructions: "Complete the sign-in in your browser."
564
+ });
565
+ onProgress?.("Waiting for OAuth callback...");
566
+ if (onManualCodeInput) {
567
+ let manualInput;
568
+ let manualError;
569
+ const manualPromise = onManualCodeInput().then((input) => {
570
+ manualInput = input;
571
+ server.cancelWait();
572
+ }).catch((err) => {
573
+ manualError = err instanceof Error ? err : new Error(String(err));
574
+ server.cancelWait();
575
+ });
576
+ const result = await server.waitForCode();
577
+ if (manualError) throw manualError;
578
+ if (result?.code) {
579
+ if (result.state !== verifier) throw new Error("OAuth state mismatch - possible CSRF attack");
580
+ code = result.code;
581
+ } else if (manualInput) {
582
+ const parsed = parseRedirectUrl$1(manualInput);
583
+ if (parsed.state && parsed.state !== verifier) throw new Error("OAuth state mismatch - possible CSRF attack");
584
+ code = parsed.code;
585
+ }
586
+ if (!code) {
587
+ await manualPromise;
588
+ if (manualError) throw manualError;
589
+ if (manualInput) {
590
+ const parsed = parseRedirectUrl$1(manualInput);
591
+ if (parsed.state && parsed.state !== verifier) throw new Error("OAuth state mismatch - possible CSRF attack");
592
+ code = parsed.code;
593
+ }
594
+ }
595
+ } else {
596
+ const result = await server.waitForCode();
597
+ if (result?.code) {
598
+ if (result.state !== verifier) throw new Error("OAuth state mismatch - possible CSRF attack");
599
+ code = result.code;
600
+ }
601
+ }
602
+ if (!code) throw new Error("No authorization code received");
603
+ onProgress?.("Exchanging authorization code for tokens...");
604
+ const tokenResponse = await fetch(TOKEN_URL$2, {
605
+ method: "POST",
606
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
607
+ body: new URLSearchParams({
608
+ client_id: CLIENT_ID$2,
609
+ client_secret: CLIENT_SECRET$1,
610
+ code,
611
+ grant_type: "authorization_code",
612
+ redirect_uri: REDIRECT_URI$2,
613
+ code_verifier: verifier
614
+ })
615
+ });
616
+ if (!tokenResponse.ok) {
617
+ const error = await tokenResponse.text();
618
+ throw new Error(`Token exchange failed: ${error}`);
619
+ }
620
+ const tokenData = await tokenResponse.json();
621
+ if (!tokenData.refresh_token) throw new Error("No refresh token received. Please try again.");
622
+ onProgress?.("Getting user info...");
623
+ const email = await getUserEmail$1(tokenData.access_token);
624
+ const projectId = await discoverProject$1(tokenData.access_token, onProgress);
625
+ const expiresAt = Date.now() + tokenData.expires_in * 1e3 - 300 * 1e3;
626
+ return {
627
+ refresh: tokenData.refresh_token,
628
+ access: tokenData.access_token,
629
+ expires: expiresAt,
630
+ projectId,
631
+ email
632
+ };
633
+ } finally {
634
+ server.server.close();
635
+ }
636
+ }
637
+ const antigravityOAuthProvider = {
638
+ id: "google-antigravity",
639
+ name: "Antigravity (Gemini 3, Claude, GPT-OSS)",
640
+ usesCallbackServer: true,
641
+ async login(callbacks) {
642
+ return loginAntigravity(callbacks.onAuth, callbacks.onProgress, callbacks.onManualCodeInput);
643
+ },
644
+ async refreshToken(credentials) {
645
+ const creds = credentials;
646
+ if (!creds.projectId) throw new Error("Antigravity credentials missing projectId");
647
+ return refreshAntigravityToken(creds.refresh, creds.projectId);
648
+ },
649
+ getApiKey(credentials) {
650
+ const creds = credentials;
651
+ return JSON.stringify({
652
+ token: creds.access,
653
+ projectId: creds.projectId
654
+ });
655
+ }
656
+ };
657
+ /**
658
+ * Gemini CLI OAuth flow (Google Cloud Code Assist)
659
+ * Standard Gemini models only (gemini-2.0-flash, gemini-2.5-*)
660
+ *
661
+ * NOTE: This module uses Node.js http.createServer for the OAuth callback.
662
+ * It is only intended for CLI use, not browser environments.
663
+ */
664
+ var _createServer = null;
665
+ var _httpImportPromise = null;
666
+ if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) _httpImportPromise = import("node:http").then((m) => {
667
+ _createServer = m.createServer;
668
+ });
669
+ var decode = (s) => atob(s);
670
+ var CLIENT_ID$1 = decode("NjgxMjU1ODA5Mzk1LW9vOGZ0Mm9wcmRybnA5ZTNhcWY2YXYzaG1kaWIxMzVqLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29t");
671
+ var CLIENT_SECRET = decode("R09DU1BYLTR1SGdNUG0tMW83U2stZ2VWNkN1NWNsWEZzeGw=");
672
+ var REDIRECT_URI$1 = "http://localhost:8085/oauth2callback";
673
+ var SCOPES = [
674
+ "https://www.googleapis.com/auth/cloud-platform",
675
+ "https://www.googleapis.com/auth/userinfo.email",
676
+ "https://www.googleapis.com/auth/userinfo.profile"
677
+ ];
678
+ var AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
679
+ var TOKEN_URL$1 = "https://oauth2.googleapis.com/token";
680
+ var CODE_ASSIST_ENDPOINT = "https://cloudcode-pa.googleapis.com";
681
+ /**
682
+ * Start a local HTTP server to receive the OAuth callback
683
+ */
684
+ async function getNodeCreateServer() {
685
+ if (_createServer) return _createServer;
686
+ if (_httpImportPromise) await _httpImportPromise;
687
+ if (_createServer) return _createServer;
688
+ throw new Error("Gemini CLI OAuth is only available in Node.js environments");
689
+ }
690
+ async function startCallbackServer() {
691
+ const createServer = await getNodeCreateServer();
692
+ return new Promise((resolve, reject) => {
693
+ let result = null;
694
+ let cancelled = false;
695
+ const server = createServer((req, res) => {
696
+ const url = new URL(req.url || "", `http://localhost:8085`);
697
+ if (url.pathname === "/oauth2callback") {
698
+ const code = url.searchParams.get("code");
699
+ const state = url.searchParams.get("state");
700
+ const error = url.searchParams.get("error");
701
+ if (error) {
702
+ res.writeHead(400, { "Content-Type": "text/html" });
703
+ res.end(`<html><body><h1>Authentication Failed</h1><p>Error: ${error}</p><p>You can close this window.</p></body></html>`);
704
+ return;
705
+ }
706
+ if (code && state) {
707
+ res.writeHead(200, { "Content-Type": "text/html" });
708
+ res.end(`<html><body><h1>Authentication Successful</h1><p>You can close this window and return to the terminal.</p></body></html>`);
709
+ result = {
710
+ code,
711
+ state
712
+ };
713
+ } else {
714
+ res.writeHead(400, { "Content-Type": "text/html" });
715
+ res.end(`<html><body><h1>Authentication Failed</h1><p>Missing code or state parameter.</p></body></html>`);
716
+ }
717
+ } else {
718
+ res.writeHead(404);
719
+ res.end();
720
+ }
721
+ });
722
+ server.on("error", (err) => {
723
+ reject(err);
724
+ });
725
+ server.listen(8085, "127.0.0.1", () => {
726
+ resolve({
727
+ server,
728
+ cancelWait: () => {
729
+ cancelled = true;
730
+ },
731
+ waitForCode: async () => {
732
+ const sleep = () => new Promise((r) => setTimeout(r, 100));
733
+ while (!result && !cancelled) await sleep();
734
+ return result;
735
+ }
736
+ });
737
+ });
738
+ });
739
+ }
740
+ /**
741
+ * Parse redirect URL to extract code and state
742
+ */
743
+ function parseRedirectUrl(input) {
744
+ const value = input.trim();
745
+ if (!value) return {};
746
+ try {
747
+ const url = new URL(value);
748
+ return {
749
+ code: url.searchParams.get("code") ?? void 0,
750
+ state: url.searchParams.get("state") ?? void 0
751
+ };
752
+ } catch {
753
+ return {};
754
+ }
755
+ }
756
+ var TIER_FREE = "free-tier";
757
+ var TIER_LEGACY = "legacy-tier";
758
+ var TIER_STANDARD = "standard-tier";
759
+ /**
760
+ * Wait helper for onboarding retries
761
+ */
762
+ function wait(ms) {
763
+ return new Promise((resolve) => setTimeout(resolve, ms));
764
+ }
765
+ /**
766
+ * Get default tier from allowed tiers
767
+ */
768
+ function getDefaultTier(allowedTiers) {
769
+ if (!allowedTiers || allowedTiers.length === 0) return { id: TIER_LEGACY };
770
+ return allowedTiers.find((t) => t.isDefault) ?? { id: TIER_LEGACY };
771
+ }
772
+ function isVpcScAffectedUser(payload) {
773
+ if (!payload || typeof payload !== "object") return false;
774
+ if (!("error" in payload)) return false;
775
+ const error = payload.error;
776
+ if (!error?.details || !Array.isArray(error.details)) return false;
777
+ return error.details.some((detail) => detail.reason === "SECURITY_POLICY_VIOLATED");
778
+ }
779
+ /**
780
+ * Poll a long-running operation until completion
781
+ */
782
+ async function pollOperation(operationName, headers, onProgress) {
783
+ let attempt = 0;
784
+ while (true) {
785
+ if (attempt > 0) {
786
+ onProgress?.(`Waiting for project provisioning (attempt ${attempt + 1})...`);
787
+ await wait(5e3);
788
+ }
789
+ const response = await fetch(`${CODE_ASSIST_ENDPOINT}/v1internal/${operationName}`, {
790
+ method: "GET",
791
+ headers
792
+ });
793
+ if (!response.ok) throw new Error(`Failed to poll operation: ${response.status} ${response.statusText}`);
794
+ const data = await response.json();
795
+ if (data.done) return data;
796
+ attempt += 1;
797
+ }
798
+ }
799
+ /**
800
+ * Discover or provision a Google Cloud project for the user
801
+ */
802
+ async function discoverProject(accessToken, onProgress) {
803
+ const envProjectId = process.env.GOOGLE_CLOUD_PROJECT || process.env.GOOGLE_CLOUD_PROJECT_ID;
804
+ const headers = {
805
+ Authorization: `Bearer ${accessToken}`,
806
+ "Content-Type": "application/json",
807
+ "User-Agent": "google-api-nodejs-client/9.15.1",
808
+ "X-Goog-Api-Client": "gl-node/22.17.0"
809
+ };
810
+ onProgress?.("Checking for existing Cloud Code Assist project...");
811
+ const loadResponse = await fetch(`${CODE_ASSIST_ENDPOINT}/v1internal:loadCodeAssist`, {
812
+ method: "POST",
813
+ headers,
814
+ body: JSON.stringify({
815
+ cloudaicompanionProject: envProjectId,
816
+ metadata: {
817
+ ideType: "IDE_UNSPECIFIED",
818
+ platform: "PLATFORM_UNSPECIFIED",
819
+ pluginType: "GEMINI",
820
+ duetProject: envProjectId
821
+ }
822
+ })
823
+ });
824
+ let data;
825
+ if (!loadResponse.ok) {
826
+ let errorPayload;
827
+ try {
828
+ errorPayload = await loadResponse.clone().json();
829
+ } catch {
830
+ errorPayload = void 0;
831
+ }
832
+ if (isVpcScAffectedUser(errorPayload)) data = { currentTier: { id: TIER_STANDARD } };
833
+ else {
834
+ const errorText = await loadResponse.text();
835
+ throw new Error(`loadCodeAssist failed: ${loadResponse.status} ${loadResponse.statusText}: ${errorText}`);
836
+ }
837
+ } else data = await loadResponse.json();
838
+ if (data.currentTier) {
839
+ if (data.cloudaicompanionProject) return data.cloudaicompanionProject;
840
+ if (envProjectId) return envProjectId;
841
+ throw new Error("This account requires setting the GOOGLE_CLOUD_PROJECT or GOOGLE_CLOUD_PROJECT_ID environment variable. See https://goo.gle/gemini-cli-auth-docs#workspace-gca");
842
+ }
843
+ const tierId = getDefaultTier(data.allowedTiers)?.id ?? TIER_FREE;
844
+ if (tierId !== TIER_FREE && !envProjectId) throw new Error("This account requires setting the GOOGLE_CLOUD_PROJECT or GOOGLE_CLOUD_PROJECT_ID environment variable. See https://goo.gle/gemini-cli-auth-docs#workspace-gca");
845
+ onProgress?.("Provisioning Cloud Code Assist project (this may take a moment)...");
846
+ const onboardBody = {
847
+ tierId,
848
+ metadata: {
849
+ ideType: "IDE_UNSPECIFIED",
850
+ platform: "PLATFORM_UNSPECIFIED",
851
+ pluginType: "GEMINI"
852
+ }
853
+ };
854
+ if (tierId !== TIER_FREE && envProjectId) {
855
+ onboardBody.cloudaicompanionProject = envProjectId;
856
+ onboardBody.metadata.duetProject = envProjectId;
857
+ }
858
+ const onboardResponse = await fetch(`${CODE_ASSIST_ENDPOINT}/v1internal:onboardUser`, {
859
+ method: "POST",
860
+ headers,
861
+ body: JSON.stringify(onboardBody)
862
+ });
863
+ if (!onboardResponse.ok) {
864
+ const errorText = await onboardResponse.text();
865
+ throw new Error(`onboardUser failed: ${onboardResponse.status} ${onboardResponse.statusText}: ${errorText}`);
866
+ }
867
+ let lroData = await onboardResponse.json();
868
+ if (!lroData.done && lroData.name) lroData = await pollOperation(lroData.name, headers, onProgress);
869
+ const projectId = lroData.response?.cloudaicompanionProject?.id;
870
+ if (projectId) return projectId;
871
+ if (envProjectId) return envProjectId;
872
+ throw new Error("Could not discover or provision a Google Cloud project. Try setting the GOOGLE_CLOUD_PROJECT or GOOGLE_CLOUD_PROJECT_ID environment variable. See https://goo.gle/gemini-cli-auth-docs#workspace-gca");
873
+ }
874
+ /**
875
+ * Get user email from the access token
876
+ */
877
+ async function getUserEmail(accessToken) {
878
+ try {
879
+ const response = await fetch("https://www.googleapis.com/oauth2/v1/userinfo?alt=json", { headers: { Authorization: `Bearer ${accessToken}` } });
880
+ if (response.ok) return (await response.json()).email;
881
+ } catch {}
882
+ }
883
+ /**
884
+ * Refresh Google Cloud Code Assist token
885
+ */
886
+ async function refreshGoogleCloudToken(refreshToken, projectId) {
887
+ const response = await fetch(TOKEN_URL$1, {
888
+ method: "POST",
889
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
890
+ body: new URLSearchParams({
891
+ client_id: CLIENT_ID$1,
892
+ client_secret: CLIENT_SECRET,
893
+ refresh_token: refreshToken,
894
+ grant_type: "refresh_token"
895
+ })
896
+ });
897
+ if (!response.ok) {
898
+ const error = await response.text();
899
+ throw new Error(`Google Cloud token refresh failed: ${error}`);
900
+ }
901
+ const data = await response.json();
902
+ return {
903
+ refresh: data.refresh_token || refreshToken,
904
+ access: data.access_token,
905
+ expires: Date.now() + data.expires_in * 1e3 - 300 * 1e3,
906
+ projectId
907
+ };
908
+ }
909
+ /**
910
+ * Login with Gemini CLI (Google Cloud Code Assist) OAuth
911
+ *
912
+ * @param onAuth - Callback with URL and optional instructions
913
+ * @param onProgress - Optional progress callback
914
+ * @param onManualCodeInput - Optional promise that resolves with user-pasted redirect URL.
915
+ * Races with browser callback - whichever completes first wins.
916
+ */
917
+ async function loginGeminiCli(onAuth, onProgress, onManualCodeInput) {
918
+ const { verifier, challenge } = await generatePKCE();
919
+ onProgress?.("Starting local server for OAuth callback...");
920
+ const server = await startCallbackServer();
921
+ let code;
922
+ try {
923
+ onAuth({
924
+ url: `${AUTH_URL}?${new URLSearchParams({
925
+ client_id: CLIENT_ID$1,
926
+ response_type: "code",
927
+ redirect_uri: REDIRECT_URI$1,
928
+ scope: SCOPES.join(" "),
929
+ code_challenge: challenge,
930
+ code_challenge_method: "S256",
931
+ state: verifier,
932
+ access_type: "offline",
933
+ prompt: "consent"
934
+ }).toString()}`,
935
+ instructions: "Complete the sign-in in your browser."
936
+ });
937
+ onProgress?.("Waiting for OAuth callback...");
938
+ if (onManualCodeInput) {
939
+ let manualInput;
940
+ let manualError;
941
+ const manualPromise = onManualCodeInput().then((input) => {
942
+ manualInput = input;
943
+ server.cancelWait();
944
+ }).catch((err) => {
945
+ manualError = err instanceof Error ? err : new Error(String(err));
946
+ server.cancelWait();
947
+ });
948
+ const result = await server.waitForCode();
949
+ if (manualError) throw manualError;
950
+ if (result?.code) {
951
+ if (result.state !== verifier) throw new Error("OAuth state mismatch - possible CSRF attack");
952
+ code = result.code;
953
+ } else if (manualInput) {
954
+ const parsed = parseRedirectUrl(manualInput);
955
+ if (parsed.state && parsed.state !== verifier) throw new Error("OAuth state mismatch - possible CSRF attack");
956
+ code = parsed.code;
957
+ }
958
+ if (!code) {
959
+ await manualPromise;
960
+ if (manualError) throw manualError;
961
+ if (manualInput) {
962
+ const parsed = parseRedirectUrl(manualInput);
963
+ if (parsed.state && parsed.state !== verifier) throw new Error("OAuth state mismatch - possible CSRF attack");
964
+ code = parsed.code;
965
+ }
966
+ }
967
+ } else {
968
+ const result = await server.waitForCode();
969
+ if (result?.code) {
970
+ if (result.state !== verifier) throw new Error("OAuth state mismatch - possible CSRF attack");
971
+ code = result.code;
972
+ }
973
+ }
974
+ if (!code) throw new Error("No authorization code received");
975
+ onProgress?.("Exchanging authorization code for tokens...");
976
+ const tokenResponse = await fetch(TOKEN_URL$1, {
977
+ method: "POST",
978
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
979
+ body: new URLSearchParams({
980
+ client_id: CLIENT_ID$1,
981
+ client_secret: CLIENT_SECRET,
982
+ code,
983
+ grant_type: "authorization_code",
984
+ redirect_uri: REDIRECT_URI$1,
985
+ code_verifier: verifier
986
+ })
987
+ });
988
+ if (!tokenResponse.ok) {
989
+ const error = await tokenResponse.text();
990
+ throw new Error(`Token exchange failed: ${error}`);
991
+ }
992
+ const tokenData = await tokenResponse.json();
993
+ if (!tokenData.refresh_token) throw new Error("No refresh token received. Please try again.");
994
+ onProgress?.("Getting user info...");
995
+ const email = await getUserEmail(tokenData.access_token);
996
+ const projectId = await discoverProject(tokenData.access_token, onProgress);
997
+ const expiresAt = Date.now() + tokenData.expires_in * 1e3 - 300 * 1e3;
998
+ return {
999
+ refresh: tokenData.refresh_token,
1000
+ access: tokenData.access_token,
1001
+ expires: expiresAt,
1002
+ projectId,
1003
+ email
1004
+ };
1005
+ } finally {
1006
+ server.server.close();
1007
+ }
1008
+ }
1009
+ const geminiCliOAuthProvider = {
1010
+ id: "google-gemini-cli",
1011
+ name: "Google Cloud Code Assist (Gemini CLI)",
1012
+ usesCallbackServer: true,
1013
+ async login(callbacks) {
1014
+ return loginGeminiCli(callbacks.onAuth, callbacks.onProgress, callbacks.onManualCodeInput);
1015
+ },
1016
+ async refreshToken(credentials) {
1017
+ const creds = credentials;
1018
+ if (!creds.projectId) throw new Error("Google Cloud credentials missing projectId");
1019
+ return refreshGoogleCloudToken(creds.refresh, creds.projectId);
1020
+ },
1021
+ getApiKey(credentials) {
1022
+ const creds = credentials;
1023
+ return JSON.stringify({
1024
+ token: creds.access,
1025
+ projectId: creds.projectId
1026
+ });
1027
+ }
1028
+ };
1029
+ /**
1030
+ * OpenAI Codex (ChatGPT OAuth) flow
1031
+ *
1032
+ * NOTE: This module uses Node.js crypto and http for the OAuth callback.
1033
+ * It is only intended for CLI use, not browser environments.
1034
+ */
1035
+ var _randomBytes = null;
1036
+ var _http = null;
1037
+ if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
1038
+ import("node:crypto").then((m) => {
1039
+ _randomBytes = m.randomBytes;
1040
+ });
1041
+ import("node:http").then((m) => {
1042
+ _http = m;
1043
+ });
1044
+ }
1045
+ var CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
1046
+ var AUTHORIZE_URL = "https://auth.openai.com/oauth/authorize";
1047
+ var TOKEN_URL = "https://auth.openai.com/oauth/token";
1048
+ var REDIRECT_URI = "http://localhost:1455/auth/callback";
1049
+ var SCOPE = "openid profile email offline_access";
1050
+ var JWT_CLAIM_PATH = "https://api.openai.com/auth";
1051
+ var SUCCESS_HTML = `<!doctype html>
1052
+ <html lang="en">
1053
+ <head>
1054
+ <meta charset="utf-8" />
1055
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
1056
+ <title>Authentication successful</title>
1057
+ </head>
1058
+ <body>
1059
+ <p>Authentication successful. Return to your terminal to continue.</p>
1060
+ </body>
1061
+ </html>`;
1062
+ function createState() {
1063
+ if (!_randomBytes) throw new Error("OpenAI Codex OAuth is only available in Node.js environments");
1064
+ return _randomBytes(16).toString("hex");
1065
+ }
1066
+ function parseAuthorizationInput(input) {
1067
+ const value = input.trim();
1068
+ if (!value) return {};
1069
+ try {
1070
+ const url = new URL(value);
1071
+ return {
1072
+ code: url.searchParams.get("code") ?? void 0,
1073
+ state: url.searchParams.get("state") ?? void 0
1074
+ };
1075
+ } catch {}
1076
+ if (value.includes("#")) {
1077
+ const [code, state] = value.split("#", 2);
1078
+ return {
1079
+ code,
1080
+ state
1081
+ };
1082
+ }
1083
+ if (value.includes("code=")) {
1084
+ const params = new URLSearchParams(value);
1085
+ return {
1086
+ code: params.get("code") ?? void 0,
1087
+ state: params.get("state") ?? void 0
1088
+ };
1089
+ }
1090
+ return { code: value };
1091
+ }
1092
+ function decodeJwt(token) {
1093
+ try {
1094
+ const parts = token.split(".");
1095
+ if (parts.length !== 3) return null;
1096
+ const payload = parts[1] ?? "";
1097
+ const decoded = atob(payload);
1098
+ return JSON.parse(decoded);
1099
+ } catch {
1100
+ return null;
1101
+ }
1102
+ }
1103
+ async function exchangeAuthorizationCode(code, verifier, redirectUri = REDIRECT_URI) {
1104
+ const response = await fetch(TOKEN_URL, {
1105
+ method: "POST",
1106
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
1107
+ body: new URLSearchParams({
1108
+ grant_type: "authorization_code",
1109
+ client_id: CLIENT_ID,
1110
+ code,
1111
+ code_verifier: verifier,
1112
+ redirect_uri: redirectUri
1113
+ })
1114
+ });
1115
+ if (!response.ok) {
1116
+ const text = await response.text().catch(() => "");
1117
+ console.error("[openai-codex] code->token failed:", response.status, text);
1118
+ return { type: "failed" };
1119
+ }
1120
+ const json = await response.json();
1121
+ if (!json.access_token || !json.refresh_token || typeof json.expires_in !== "number") {
1122
+ console.error("[openai-codex] token response missing fields:", json);
1123
+ return { type: "failed" };
1124
+ }
1125
+ return {
1126
+ type: "success",
1127
+ access: json.access_token,
1128
+ refresh: json.refresh_token,
1129
+ expires: Date.now() + json.expires_in * 1e3
1130
+ };
1131
+ }
1132
+ async function refreshAccessToken(refreshToken) {
1133
+ try {
1134
+ const response = await fetch(TOKEN_URL, {
1135
+ method: "POST",
1136
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
1137
+ body: new URLSearchParams({
1138
+ grant_type: "refresh_token",
1139
+ refresh_token: refreshToken,
1140
+ client_id: CLIENT_ID
1141
+ })
1142
+ });
1143
+ if (!response.ok) {
1144
+ const text = await response.text().catch(() => "");
1145
+ console.error("[openai-codex] Token refresh failed:", response.status, text);
1146
+ return { type: "failed" };
1147
+ }
1148
+ const json = await response.json();
1149
+ if (!json.access_token || !json.refresh_token || typeof json.expires_in !== "number") {
1150
+ console.error("[openai-codex] Token refresh response missing fields:", json);
1151
+ return { type: "failed" };
1152
+ }
1153
+ return {
1154
+ type: "success",
1155
+ access: json.access_token,
1156
+ refresh: json.refresh_token,
1157
+ expires: Date.now() + json.expires_in * 1e3
1158
+ };
1159
+ } catch (error) {
1160
+ console.error("[openai-codex] Token refresh error:", error);
1161
+ return { type: "failed" };
1162
+ }
1163
+ }
1164
+ async function createAuthorizationFlow(originator = "pi") {
1165
+ const { verifier, challenge } = await generatePKCE();
1166
+ const state = createState();
1167
+ const url = new URL(AUTHORIZE_URL);
1168
+ url.searchParams.set("response_type", "code");
1169
+ url.searchParams.set("client_id", CLIENT_ID);
1170
+ url.searchParams.set("redirect_uri", REDIRECT_URI);
1171
+ url.searchParams.set("scope", SCOPE);
1172
+ url.searchParams.set("code_challenge", challenge);
1173
+ url.searchParams.set("code_challenge_method", "S256");
1174
+ url.searchParams.set("state", state);
1175
+ url.searchParams.set("id_token_add_organizations", "true");
1176
+ url.searchParams.set("codex_cli_simplified_flow", "true");
1177
+ url.searchParams.set("originator", originator);
1178
+ return {
1179
+ verifier,
1180
+ state,
1181
+ url: url.toString()
1182
+ };
1183
+ }
1184
+ function startLocalOAuthServer(state) {
1185
+ if (!_http) throw new Error("OpenAI Codex OAuth is only available in Node.js environments");
1186
+ let lastCode = null;
1187
+ let cancelled = false;
1188
+ const server = _http.createServer((req, res) => {
1189
+ try {
1190
+ const url = new URL(req.url || "", "http://localhost");
1191
+ if (url.pathname !== "/auth/callback") {
1192
+ res.statusCode = 404;
1193
+ res.end("Not found");
1194
+ return;
1195
+ }
1196
+ if (url.searchParams.get("state") !== state) {
1197
+ res.statusCode = 400;
1198
+ res.end("State mismatch");
1199
+ return;
1200
+ }
1201
+ const code = url.searchParams.get("code");
1202
+ if (!code) {
1203
+ res.statusCode = 400;
1204
+ res.end("Missing authorization code");
1205
+ return;
1206
+ }
1207
+ res.statusCode = 200;
1208
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
1209
+ res.end(SUCCESS_HTML);
1210
+ lastCode = code;
1211
+ } catch {
1212
+ res.statusCode = 500;
1213
+ res.end("Internal error");
1214
+ }
1215
+ });
1216
+ return new Promise((resolve) => {
1217
+ server.listen(1455, "127.0.0.1", () => {
1218
+ resolve({
1219
+ close: () => server.close(),
1220
+ cancelWait: () => {
1221
+ cancelled = true;
1222
+ },
1223
+ waitForCode: async () => {
1224
+ const sleep = () => new Promise((r) => setTimeout(r, 100));
1225
+ for (let i = 0; i < 600; i += 1) {
1226
+ if (lastCode) return { code: lastCode };
1227
+ if (cancelled) return null;
1228
+ await sleep();
1229
+ }
1230
+ return null;
1231
+ }
1232
+ });
1233
+ }).on("error", (err) => {
1234
+ console.error("[openai-codex] Failed to bind http://127.0.0.1:1455 (", err.code, ") Falling back to manual paste.");
1235
+ resolve({
1236
+ close: () => {
1237
+ try {
1238
+ server.close();
1239
+ } catch {}
1240
+ },
1241
+ cancelWait: () => {},
1242
+ waitForCode: async () => null
1243
+ });
1244
+ });
1245
+ });
1246
+ }
1247
+ function getAccountId(accessToken) {
1248
+ const accountId = (decodeJwt(accessToken)?.[JWT_CLAIM_PATH])?.chatgpt_account_id;
1249
+ return typeof accountId === "string" && accountId.length > 0 ? accountId : null;
1250
+ }
1251
+ /**
1252
+ * Login with OpenAI Codex OAuth
1253
+ *
1254
+ * @param options.onAuth - Called with URL and instructions when auth starts
1255
+ * @param options.onPrompt - Called to prompt user for manual code paste (fallback if no onManualCodeInput)
1256
+ * @param options.onProgress - Optional progress messages
1257
+ * @param options.onManualCodeInput - Optional promise that resolves with user-pasted code.
1258
+ * Races with browser callback - whichever completes first wins.
1259
+ * Useful for showing paste input immediately alongside browser flow.
1260
+ * @param options.originator - OAuth originator parameter (defaults to "pi")
1261
+ */
1262
+ async function loginOpenAICodex(options) {
1263
+ const { verifier, state, url } = await createAuthorizationFlow(options.originator);
1264
+ const server = await startLocalOAuthServer(state);
1265
+ options.onAuth({
1266
+ url,
1267
+ instructions: "A browser window should open. Complete login to finish."
1268
+ });
1269
+ let code;
1270
+ try {
1271
+ if (options.onManualCodeInput) {
1272
+ let manualCode;
1273
+ let manualError;
1274
+ const manualPromise = options.onManualCodeInput().then((input) => {
1275
+ manualCode = input;
1276
+ server.cancelWait();
1277
+ }).catch((err) => {
1278
+ manualError = err instanceof Error ? err : new Error(String(err));
1279
+ server.cancelWait();
1280
+ });
1281
+ const result = await server.waitForCode();
1282
+ if (manualError) throw manualError;
1283
+ if (result?.code) code = result.code;
1284
+ else if (manualCode) {
1285
+ const parsed = parseAuthorizationInput(manualCode);
1286
+ if (parsed.state && parsed.state !== state) throw new Error("State mismatch");
1287
+ code = parsed.code;
1288
+ }
1289
+ if (!code) {
1290
+ await manualPromise;
1291
+ if (manualError) throw manualError;
1292
+ if (manualCode) {
1293
+ const parsed = parseAuthorizationInput(manualCode);
1294
+ if (parsed.state && parsed.state !== state) throw new Error("State mismatch");
1295
+ code = parsed.code;
1296
+ }
1297
+ }
1298
+ } else {
1299
+ const result = await server.waitForCode();
1300
+ if (result?.code) code = result.code;
1301
+ }
1302
+ if (!code) {
1303
+ const parsed = parseAuthorizationInput(await options.onPrompt({ message: "Paste the authorization code (or full redirect URL):" }));
1304
+ if (parsed.state && parsed.state !== state) throw new Error("State mismatch");
1305
+ code = parsed.code;
1306
+ }
1307
+ if (!code) throw new Error("Missing authorization code");
1308
+ const tokenResult = await exchangeAuthorizationCode(code, verifier);
1309
+ if (tokenResult.type !== "success") throw new Error("Token exchange failed");
1310
+ const accountId = getAccountId(tokenResult.access);
1311
+ if (!accountId) throw new Error("Failed to extract accountId from token");
1312
+ return {
1313
+ access: tokenResult.access,
1314
+ refresh: tokenResult.refresh,
1315
+ expires: tokenResult.expires,
1316
+ accountId
1317
+ };
1318
+ } finally {
1319
+ server.close();
1320
+ }
1321
+ }
1322
+ /**
1323
+ * Refresh OpenAI Codex OAuth token
1324
+ */
1325
+ async function refreshOpenAICodexToken(refreshToken) {
1326
+ const result = await refreshAccessToken(refreshToken);
1327
+ if (result.type !== "success") throw new Error("Failed to refresh OpenAI Codex token");
1328
+ const accountId = getAccountId(result.access);
1329
+ if (!accountId) throw new Error("Failed to extract accountId from token");
1330
+ return {
1331
+ access: result.access,
1332
+ refresh: result.refresh,
1333
+ expires: result.expires,
1334
+ accountId
1335
+ };
1336
+ }
1337
+ const openaiCodexOAuthProvider = {
1338
+ id: "openai-codex",
1339
+ name: "ChatGPT Plus/Pro (Codex Subscription)",
1340
+ usesCallbackServer: true,
1341
+ async login(callbacks) {
1342
+ return loginOpenAICodex({
1343
+ onAuth: callbacks.onAuth,
1344
+ onPrompt: callbacks.onPrompt,
1345
+ onProgress: callbacks.onProgress,
1346
+ onManualCodeInput: callbacks.onManualCodeInput
1347
+ });
1348
+ },
1349
+ async refreshToken(credentials) {
1350
+ return refreshOpenAICodexToken(credentials.refresh);
1351
+ },
1352
+ getApiKey(credentials) {
1353
+ return credentials.access;
1354
+ }
1355
+ };
1356
+ var BUILT_IN_OAUTH_PROVIDERS = [
1357
+ anthropicOAuthProvider,
1358
+ githubCopilotOAuthProvider,
1359
+ geminiCliOAuthProvider,
1360
+ antigravityOAuthProvider,
1361
+ openaiCodexOAuthProvider
1362
+ ];
1363
+ var oauthProviderRegistry = new Map(BUILT_IN_OAUTH_PROVIDERS.map((provider) => [provider.id, provider]));
1364
+ /**
1365
+ * Get an OAuth provider by ID
1366
+ */
1367
+ function getOAuthProvider(id) {
1368
+ return oauthProviderRegistry.get(id);
1369
+ }
1370
+ /**
1371
+ * Register a custom OAuth provider
1372
+ */
1373
+ function registerOAuthProvider(provider) {
1374
+ oauthProviderRegistry.set(provider.id, provider);
1375
+ }
1376
+ /**
1377
+ * Unregister an OAuth provider.
1378
+ *
1379
+ * If the provider is built-in, restores the built-in implementation.
1380
+ * Custom providers are removed completely.
1381
+ */
1382
+ function unregisterOAuthProvider(id) {
1383
+ const builtInProvider = BUILT_IN_OAUTH_PROVIDERS.find((provider) => provider.id === id);
1384
+ if (builtInProvider) {
1385
+ oauthProviderRegistry.set(id, builtInProvider);
1386
+ return;
1387
+ }
1388
+ oauthProviderRegistry.delete(id);
1389
+ }
1390
+ /**
1391
+ * Reset OAuth providers to built-ins.
1392
+ */
1393
+ function resetOAuthProviders() {
1394
+ oauthProviderRegistry.clear();
1395
+ for (const provider of BUILT_IN_OAUTH_PROVIDERS) oauthProviderRegistry.set(provider.id, provider);
1396
+ }
1397
+ /**
1398
+ * Get all registered OAuth providers
1399
+ */
1400
+ function getOAuthProviders() {
1401
+ return Array.from(oauthProviderRegistry.values());
1402
+ }
1403
+ /**
1404
+ * @deprecated Use getOAuthProviders() which returns OAuthProviderInterface[]
1405
+ */
1406
+ function getOAuthProviderInfoList() {
1407
+ return getOAuthProviders().map((p) => ({
1408
+ id: p.id,
1409
+ name: p.name,
1410
+ available: true
1411
+ }));
1412
+ }
1413
+ /**
1414
+ * Refresh token for any OAuth provider.
1415
+ * @deprecated Use getOAuthProvider(id).refreshToken() instead
1416
+ */
1417
+ async function refreshOAuthToken(providerId, credentials) {
1418
+ const provider = getOAuthProvider(providerId);
1419
+ if (!provider) throw new Error(`Unknown OAuth provider: ${providerId}`);
1420
+ return provider.refreshToken(credentials);
1421
+ }
1422
+ /**
1423
+ * Get API key for a provider from OAuth credentials.
1424
+ * Automatically refreshes expired tokens.
1425
+ *
1426
+ * @returns API key string and updated credentials, or null if no credentials
1427
+ * @throws Error if refresh fails
1428
+ */
1429
+ async function getOAuthApiKey(providerId, credentials) {
1430
+ const provider = getOAuthProvider(providerId);
1431
+ if (!provider) throw new Error(`Unknown OAuth provider: ${providerId}`);
1432
+ let creds = credentials[providerId];
1433
+ if (!creds) return null;
1434
+ if (Date.now() >= creds.expires) try {
1435
+ creds = await provider.refreshToken(creds);
1436
+ } catch (_error) {
1437
+ throw new Error(`Failed to refresh OAuth token for ${providerId}`);
1438
+ }
1439
+ const apiKey = provider.getApiKey(creds);
1440
+ return {
1441
+ newCredentials: creds,
1442
+ apiKey
1443
+ };
1444
+ }
1445
+ var oauth_exports = /* @__PURE__ */ __exportAll({
1446
+ anthropicOAuthProvider: () => anthropicOAuthProvider,
1447
+ antigravityOAuthProvider: () => antigravityOAuthProvider,
1448
+ geminiCliOAuthProvider: () => geminiCliOAuthProvider,
1449
+ getGitHubCopilotBaseUrl: () => getGitHubCopilotBaseUrl,
1450
+ getOAuthApiKey: () => getOAuthApiKey,
1451
+ getOAuthProvider: () => getOAuthProvider,
1452
+ getOAuthProviderInfoList: () => getOAuthProviderInfoList,
1453
+ getOAuthProviders: () => getOAuthProviders,
1454
+ githubCopilotOAuthProvider: () => githubCopilotOAuthProvider,
1455
+ loginAnthropic: () => loginAnthropic,
1456
+ loginAntigravity: () => loginAntigravity,
1457
+ loginGeminiCli: () => loginGeminiCli,
1458
+ loginGitHubCopilot: () => loginGitHubCopilot,
1459
+ loginOpenAICodex: () => loginOpenAICodex,
1460
+ normalizeDomain: () => normalizeDomain,
1461
+ openaiCodexOAuthProvider: () => openaiCodexOAuthProvider,
1462
+ refreshAnthropicToken: () => refreshAnthropicToken,
1463
+ refreshAntigravityToken: () => refreshAntigravityToken,
1464
+ refreshGitHubCopilotToken: () => refreshGitHubCopilotToken,
1465
+ refreshGoogleCloudToken: () => refreshGoogleCloudToken,
1466
+ refreshOAuthToken: () => refreshOAuthToken,
1467
+ refreshOpenAICodexToken: () => refreshOpenAICodexToken,
1468
+ registerOAuthProvider: () => registerOAuthProvider,
1469
+ resetOAuthProviders: () => resetOAuthProviders,
1470
+ unregisterOAuthProvider: () => unregisterOAuthProvider
1471
+ });
1472
+ export { registerOAuthProvider as a, getOAuthProviders as i, getOAuthApiKey as n, resetOAuthProviders as o, getOAuthProvider as r, oauth_exports as t };