@codeworksh/aikit 0.8.0 → 0.9.0-dev.20260922184333

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 (47) hide show
  1. package/README.md +10 -1
  2. package/cli.mjs +75 -83
  3. package/cli.mjs.map +1 -1
  4. package/{codex-MtP1574D.mjs → codex-CLDBTrFm.mjs} +132 -134
  5. package/codex-CLDBTrFm.mjs.map +1 -0
  6. package/copilot-CcD3g6H8.mjs +425 -0
  7. package/copilot-CcD3g6H8.mjs.map +1 -0
  8. package/copilot-headers-DceqXlpj.mjs +104 -0
  9. package/copilot-headers-DceqXlpj.mjs.map +1 -0
  10. package/github-copilot-BJIrxOzT.mjs +3 -0
  11. package/github-copilot-SIUCJz1G.mjs +126 -0
  12. package/github-copilot-SIUCJz1G.mjs.map +1 -0
  13. package/index.d.mts +980 -932
  14. package/index.mjs +63 -11
  15. package/index.mjs.map +1 -1
  16. package/interactive-eoNnscGB.mjs +57 -0
  17. package/interactive-eoNnscGB.mjs.map +1 -0
  18. package/{model-CpX11Oob.d.mts → model-CrVLp622.d.mts} +159 -130
  19. package/{model-CBnredXj.mjs → model-gCDbmGqT.mjs} +31 -2
  20. package/model-gCDbmGqT.mjs.map +1 -0
  21. package/{modelgen-BjSsusLQ.mjs → modelgen-DvorXOjJ.mjs} +148 -29
  22. package/modelgen-DvorXOjJ.mjs.map +1 -0
  23. package/modelgen.d.mts +2 -3
  24. package/modelgen.mjs +1 -1
  25. package/oauth/github/copilot.d.mts +169 -0
  26. package/oauth/github/copilot.mjs +2 -0
  27. package/oauth/interactive.d.mts +21 -0
  28. package/oauth/interactive.mjs +2 -0
  29. package/oauth/openai/codex.d.mts +46 -28
  30. package/oauth/openai/codex.mjs +2 -2
  31. package/oauth/summary.d.mts +67 -0
  32. package/oauth/summary.mjs +2 -0
  33. package/{openai-codex-t4B7g-gv.mjs → openai-codex-Bqzti6Mc.mjs} +3 -3
  34. package/{openai-codex-t4B7g-gv.mjs.map → openai-codex-Bqzti6Mc.mjs.map} +1 -1
  35. package/openai-codex-DA1Q7mLN.mjs +2 -0
  36. package/package.json +34 -22
  37. package/{registry-DYdYTwFt.mjs → registry-ZxwIW0gX.mjs} +5 -3
  38. package/registry-ZxwIW0gX.mjs.map +1 -0
  39. package/storage-v6qjTQ0v.mjs +178 -0
  40. package/storage-v6qjTQ0v.mjs.map +1 -0
  41. package/summary-C_QyCVWa.mjs +68 -0
  42. package/summary-C_QyCVWa.mjs.map +1 -0
  43. package/codex-MtP1574D.mjs.map +0 -1
  44. package/model-CBnredXj.mjs.map +0 -1
  45. package/modelgen-BjSsusLQ.mjs.map +0 -1
  46. package/openai-codex-BRH4Qa7l.mjs +0 -2
  47. package/registry-DYdYTwFt.mjs.map +0 -1
package/package.json CHANGED
@@ -1,18 +1,19 @@
1
1
  {
2
2
  "name": "@codeworksh/aikit",
3
- "version": "0.8.0",
3
+ "version": "0.9.0-dev.20260922184333",
4
4
  "description": "TypeScript SDK that provides a unified API for working with multiple LLM providers, automatic model discovery, and more.",
5
5
  "keywords": [
6
6
  "agent",
7
7
  "ai",
8
+ "ai-sdk",
8
9
  "anthropic",
9
- "coding-agent",
10
- "nodejs",
11
- "streaming",
12
- "toolkit",
13
- "typescript"
10
+ "grok",
11
+ "harness",
12
+ "llm",
13
+ "node",
14
+ "openai"
14
15
  ],
15
- "homepage": "https://codeworksh.github.io/aikit/",
16
+ "homepage": "https://www.codework.sh",
16
17
  "bugs": {
17
18
  "url": "https://github.com/codeworksh/codework/issues"
18
19
  },
@@ -29,25 +30,36 @@
29
30
  },
30
31
  "exports": {
31
32
  ".": {
32
- "development": "./src/index.ts",
33
33
  "types": "./index.d.mts",
34
34
  "import": "./index.mjs",
35
35
  "default": "./index.mjs"
36
36
  },
37
37
  "./oauth/openai/codex": {
38
- "development": "./src/oauth/openai/codex.ts",
39
38
  "types": "./oauth/openai/codex.d.mts",
40
39
  "import": "./oauth/openai/codex.mjs",
41
40
  "default": "./oauth/openai/codex.mjs"
42
41
  },
42
+ "./oauth/github/copilot": {
43
+ "types": "./oauth/github/copilot.d.mts",
44
+ "import": "./oauth/github/copilot.mjs",
45
+ "default": "./oauth/github/copilot.mjs"
46
+ },
47
+ "./oauth/summary": {
48
+ "types": "./oauth/summary.d.mts",
49
+ "import": "./oauth/summary.mjs",
50
+ "default": "./oauth/summary.mjs"
51
+ },
52
+ "./oauth/interactive": {
53
+ "types": "./oauth/interactive.d.mts",
54
+ "import": "./oauth/interactive.mjs",
55
+ "default": "./oauth/interactive.mjs"
56
+ },
43
57
  "./modelgen": {
44
- "development": "./src/modelgen.ts",
45
58
  "types": "./modelgen.d.mts",
46
59
  "import": "./modelgen.mjs",
47
60
  "default": "./modelgen.mjs"
48
61
  },
49
62
  "./failure": {
50
- "development": "./src/llm/failure.ts",
51
63
  "types": "./llm/failure.d.mts",
52
64
  "import": "./llm/failure.mjs",
53
65
  "default": "./llm/failure.mjs"
@@ -66,20 +78,20 @@
66
78
  "node": ">=22.0.0"
67
79
  },
68
80
  "dependencies": {
69
- "@ai-sdk/anthropic": "^4.0.36",
70
- "@ai-sdk/google": "^4.0.39",
71
- "@ai-sdk/google-vertex": "^5.0.48",
72
- "@ai-sdk/openai": "^4.0.36",
73
- "@ai-sdk/openai-compatible": "^3.0.28",
74
- "@ai-sdk/provider": "^4.0.7",
75
- "@ai-sdk/xai": "^4.0.33",
81
+ "@ai-sdk/anthropic": "^4.0.53",
82
+ "@ai-sdk/google": "^4.0.69",
83
+ "@ai-sdk/google-vertex": "^5.0.81",
84
+ "@ai-sdk/openai": "^4.0.66",
85
+ "@ai-sdk/openai-compatible": "^3.0.48",
86
+ "@ai-sdk/provider": "^4.0.14",
87
+ "@ai-sdk/xai": "^4.0.58",
76
88
  "@openrouter/ai-sdk-provider": "^3.0.0",
77
- "ai": "^7.0.58",
89
+ "ai": "^7.0.99",
78
90
  "dedent": "^1.7.2",
79
- "eventsource-parser": "^3.1.0",
91
+ "eventsource-parser": "^4.1.0",
80
92
  "partial-json": "^0.1.7",
81
- "remeda": "^2.39.0",
82
- "typebox": "^1.3.12",
93
+ "remeda": "^2.48.0",
94
+ "typebox": "^1.3.30",
83
95
  "uuidv7": "^1.2.1",
84
96
  "yargs": "^18.1.0"
85
97
  }
@@ -1,4 +1,4 @@
1
- import { i as KnownProviderEnum, t as APIMethodEnum } from "./model-CBnredXj.mjs";
1
+ import { i as KnownProviderEnum, t as APIMethodEnum } from "./model-gCDbmGqT.mjs";
2
2
  //#region src/llm/registry.ts
3
3
  const DEFAULT_AI_SDK_FALLBACK = "@ai-sdk/openai-compatible";
4
4
  const AI_SDK_PACKAGE_TO_PROTOCOL = {
@@ -9,6 +9,7 @@ const AI_SDK_PACKAGE_TO_PROTOCOL = {
9
9
  "@ai-sdk/openai": KnownProviderEnum.openai,
10
10
  "@ai-sdk/openai-compatible": KnownProviderEnum.openaiCompatible,
11
11
  "@codeworksh/ai-sdk-openai-codex": KnownProviderEnum.openaiCodex,
12
+ "@codeworksh/ai-sdk-github-copilot": KnownProviderEnum.githubCopilot,
12
13
  "@openrouter/ai-sdk-provider": KnownProviderEnum.openrouter,
13
14
  "@ai-sdk/xai": KnownProviderEnum.xai
14
15
  };
@@ -21,7 +22,8 @@ const PROVIDER_LOADERS = {
21
22
  "@ai-sdk/openai-compatible": () => import("@ai-sdk/openai-compatible").then((m) => m.createOpenAICompatible),
22
23
  "@openrouter/ai-sdk-provider": () => import("@openrouter/ai-sdk-provider").then((m) => m.createOpenRouter),
23
24
  "@ai-sdk/xai": () => import("@ai-sdk/xai").then((m) => m.createXai),
24
- "@codeworksh/ai-sdk-openai-codex": () => import("./openai-codex-BRH4Qa7l.mjs").then((m) => m.createOpenAICodex)
25
+ "@codeworksh/ai-sdk-openai-codex": () => import("./openai-codex-DA1Q7mLN.mjs").then((m) => m.createOpenAICodex),
26
+ "@codeworksh/ai-sdk-github-copilot": () => import("./github-copilot-BJIrxOzT.mjs").then((m) => m.createGitHubCopilot)
25
27
  };
26
28
  function isAISDKPackage(value) {
27
29
  return value in AI_SDK_PACKAGE_TO_PROTOCOL;
@@ -62,4 +64,4 @@ function resolveLanguageModel(provider, model, methodOverride) {
62
64
  //#endregion
63
65
  export { protocolForPackage as a, packageForModel as i, isAISDKPackage as n, resolveLanguageModel as o, loadProviderFactory as r, DEFAULT_AI_SDK_FALLBACK as t };
64
66
 
65
- //# sourceMappingURL=registry-DYdYTwFt.mjs.map
67
+ //# sourceMappingURL=registry-ZxwIW0gX.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-ZxwIW0gX.mjs","names":[],"sources":["../../src/llm/registry.ts"],"sourcesContent":["import type { LanguageModel } from \"ai\";\nimport * as Model from \"../model/model.ts\";\n\nexport const DEFAULT_AI_SDK_FALLBACK = \"@ai-sdk/openai-compatible\";\n\nexport const AI_SDK_PACKAGE_TO_PROTOCOL = {\n\t\"@ai-sdk/anthropic\": Model.KnownProviderEnum.anthropic,\n\t\"@ai-sdk/google\": Model.KnownProviderEnum.google,\n\t\"@ai-sdk/google-vertex\": Model.KnownProviderEnum.googleVertex,\n\t\"@ai-sdk/google-vertex/anthropic\": Model.KnownProviderEnum.googleVertexAnthropic,\n\t\"@ai-sdk/openai\": Model.KnownProviderEnum.openai,\n\t\"@ai-sdk/openai-compatible\": Model.KnownProviderEnum.openaiCompatible,\n\t\"@codeworksh/ai-sdk-openai-codex\": Model.KnownProviderEnum.openaiCodex, // custom provider npm ID\n\t\"@codeworksh/ai-sdk-github-copilot\": Model.KnownProviderEnum.githubCopilot, // custom provider npm ID\n\t\"@openrouter/ai-sdk-provider\": Model.KnownProviderEnum.openrouter,\n\t\"@ai-sdk/xai\": Model.KnownProviderEnum.xai,\n} as const;\n\nexport type AISDKPackage = keyof typeof AI_SDK_PACKAGE_TO_PROTOCOL;\nexport type AISDKProtocol = (typeof AI_SDK_PACKAGE_TO_PROTOCOL)[AISDKPackage];\n\ntype ProviderFactory = (options?: Record<string, unknown>) => unknown;\n\nconst PROVIDER_LOADERS: Record<AISDKPackage, () => Promise<ProviderFactory>> = {\n\t\"@ai-sdk/anthropic\": () => import(\"@ai-sdk/anthropic\").then((m) => m.createAnthropic as ProviderFactory),\n\t\"@ai-sdk/google\": () => import(\"@ai-sdk/google\").then((m) => m.createGoogleGenerativeAI as ProviderFactory),\n\t\"@ai-sdk/google-vertex\": () => import(\"@ai-sdk/google-vertex\").then((m) => m.createVertex as ProviderFactory),\n\t\"@ai-sdk/google-vertex/anthropic\": () =>\n\t\timport(\"@ai-sdk/google-vertex/anthropic\").then((m) => m.createVertexAnthropic as ProviderFactory),\n\t\"@ai-sdk/openai\": () => import(\"@ai-sdk/openai\").then((m) => m.createOpenAI as ProviderFactory),\n\t\"@ai-sdk/openai-compatible\": () =>\n\t\timport(\"@ai-sdk/openai-compatible\").then((m) => m.createOpenAICompatible as unknown as ProviderFactory),\n\t\"@openrouter/ai-sdk-provider\": () =>\n\t\timport(\"@openrouter/ai-sdk-provider\").then((m) => m.createOpenRouter as ProviderFactory),\n\t\"@ai-sdk/xai\": () => import(\"@ai-sdk/xai\").then((m) => m.createXai as ProviderFactory),\n\t// Local provider for OpenAI Codex subscriptions (ChatGPT OAuth); the package\n\t// name is virtual and resolves to src/providers/openai-codex.\n\t\"@codeworksh/ai-sdk-openai-codex\": () =>\n\t\timport(\"../providers/openai-codex/index.ts\").then((m) => m.createOpenAICodex as ProviderFactory),\n\t// Local provider for GitHub Copilot; the package name is virtual and resolves\n\t// to src/providers/github-copilot.\n\t\"@codeworksh/ai-sdk-github-copilot\": () =>\n\t\timport(\"../providers/github-copilot/index.ts\").then((m) => m.createGitHubCopilot as ProviderFactory),\n};\n\nexport function isAISDKPackage(value: string): value is AISDKPackage {\n\treturn value in AI_SDK_PACKAGE_TO_PROTOCOL;\n}\n\nexport function packageForModel(model: Model.Info): AISDKPackage {\n\tconst npm = model.npm ?? DEFAULT_AI_SDK_FALLBACK;\n\treturn isAISDKPackage(npm) ? npm : DEFAULT_AI_SDK_FALLBACK;\n}\n\nexport function protocolForPackage(npm: string | undefined): AISDKProtocol {\n\tconst resolved = npm && isAISDKPackage(npm) ? npm : DEFAULT_AI_SDK_FALLBACK;\n\treturn AI_SDK_PACKAGE_TO_PROTOCOL[resolved];\n}\n\nexport async function loadProviderFactory(npm: AISDKPackage): Promise<ProviderFactory> {\n\treturn PROVIDER_LOADERS[npm]();\n}\n\ntype ProviderWithMethods = {\n\t(modelId: string): LanguageModel;\n\tlanguageModel?: (modelId: string) => LanguageModel;\n\tchat?: (modelId: string) => LanguageModel;\n\tchatModel?: (modelId: string) => LanguageModel;\n\tcompletion?: (modelId: string) => LanguageModel;\n\tcompletionModel?: (modelId: string) => LanguageModel;\n\tmessages?: (modelId: string) => LanguageModel;\n\tresponses?: (modelId: string) => LanguageModel;\n};\n\nfunction defaultMethodForModel(model: Model.Info): Model.APIMethodEnum {\n\tif (\n\t\tmodel.protocol === Model.KnownProviderEnum.openai ||\n\t\tmodel.protocol === Model.KnownProviderEnum.openaiCodex ||\n\t\tmodel.protocol === Model.KnownProviderEnum.xai\n\t) {\n\t\treturn Model.APIMethodEnum.responses;\n\t}\n\treturn Model.APIMethodEnum.languageModel;\n}\n\nexport function resolveLanguageModel(\n\tprovider: unknown,\n\tmodel: Model.Info,\n\tmethodOverride?: Model.APIMethodEnum,\n): LanguageModel {\n\tconst modelId = model.api?.id ?? model.id;\n\tconst method = methodOverride ?? model.api?.method ?? defaultMethodForModel(model);\n\tconst callable = provider as ProviderWithMethods;\n\n\tif (method === Model.APIMethodEnum.responses && callable.responses) return callable.responses(modelId);\n\tif (method === Model.APIMethodEnum.messages && callable.messages) return callable.messages(modelId);\n\tif (method === Model.APIMethodEnum.chat) {\n\t\tif (callable.chat) return callable.chat(modelId);\n\t\tif (callable.chatModel) return callable.chatModel(modelId);\n\t}\n\tif (method === Model.APIMethodEnum.completion) {\n\t\tif (callable.completion) return callable.completion(modelId);\n\t\tif (callable.completionModel) return callable.completionModel(modelId);\n\t}\n\tif (method === Model.APIMethodEnum.completionModel && callable.completionModel) {\n\t\treturn callable.completionModel(modelId);\n\t}\n\tif (callable.languageModel) return callable.languageModel(modelId);\n\treturn callable(modelId);\n}\n"],"mappings":";;AAGA,MAAa,0BAA0B;AAEvC,MAAa,6BAA6B;CACzC,qBAAA,kBAA6C;CAC7C,kBAAA,kBAA0C;CAC1C,yBAAA,kBAAiD;CACjD,mCAAA,kBAA2D;CAC3D,kBAAA,kBAA0C;CAC1C,6BAAA,kBAAqD;CACrD,mCAAA,kBAA2D;CAC3D,qCAAA,kBAA6D;CAC7D,+BAAA,kBAAuD;CACvD,eAAA,kBAAuC;AACxC;AAOA,MAAM,mBAAyE;CAC9E,2BAA2B,OAAO,oBAAoB,CAAC,MAAM,MAAM,EAAE,eAAkC;CACvG,wBAAwB,OAAO,iBAAiB,CAAC,MAAM,MAAM,EAAE,wBAA2C;CAC1G,+BAA+B,OAAO,wBAAwB,CAAC,MAAM,MAAM,EAAE,YAA+B;CAC5G,yCACC,OAAO,kCAAkC,CAAC,MAAM,MAAM,EAAE,qBAAwC;CACjG,wBAAwB,OAAO,iBAAiB,CAAC,MAAM,MAAM,EAAE,YAA+B;CAC9F,mCACC,OAAO,4BAA4B,CAAC,MAAM,MAAM,EAAE,sBAAoD;CACvG,qCACC,OAAO,8BAA8B,CAAC,MAAM,MAAM,EAAE,gBAAmC;CACxF,qBAAqB,OAAO,cAAc,CAAC,MAAM,MAAM,EAAE,SAA4B;CAGrF,yCACC,OAAO,8BAAqC,CAAC,MAAM,MAAM,EAAE,iBAAoC;CAGhG,2CACC,OAAO,gCAAuC,CAAC,MAAM,MAAM,EAAE,mBAAsC;AACrG;AAEA,SAAgB,eAAe,OAAsC;CACpE,OAAO,SAAS;AACjB;AAEA,SAAgB,gBAAgB,OAAiC;CAChE,MAAM,MAAM,MAAM,OAAA;CAClB,OAAO,eAAe,GAAG,IAAI,MAAM;AACpC;AAEA,SAAgB,mBAAmB,KAAwC;CAC1E,MAAM,WAAW,OAAO,eAAe,GAAG,IAAI,MAAM;CACpD,OAAO,2BAA2B;AACnC;AAEA,eAAsB,oBAAoB,KAA6C;CACtF,OAAO,iBAAiB,IAAI,CAAC;AAC9B;AAaA,SAAS,sBAAsB,OAAwC;CACtE,IACC,MAAM,aAAA,kBAAqC,UAC3C,MAAM,aAAA,kBAAqC,eAC3C,MAAM,aAAA,kBAAqC,KAE3C,OAAA,cAA2B;CAE5B,OAAA,cAA2B;AAC5B;AAEA,SAAgB,qBACf,UACA,OACA,gBACgB;CAChB,MAAM,UAAU,MAAM,KAAK,MAAM,MAAM;CACvC,MAAM,SAAS,kBAAkB,MAAM,KAAK,UAAU,sBAAsB,KAAK;CACjF,MAAM,WAAW;CAEjB,IAAI,WAAA,cAA+B,aAAa,SAAS,WAAW,OAAO,SAAS,UAAU,OAAO;CACrG,IAAI,WAAA,cAA+B,YAAY,SAAS,UAAU,OAAO,SAAS,SAAS,OAAO;CAClG,IAAI,WAAA,cAA+B,MAAM;EACxC,IAAI,SAAS,MAAM,OAAO,SAAS,KAAK,OAAO;EAC/C,IAAI,SAAS,WAAW,OAAO,SAAS,UAAU,OAAO;CAC1D;CACA,IAAI,WAAA,cAA+B,YAAY;EAC9C,IAAI,SAAS,YAAY,OAAO,SAAS,WAAW,OAAO;EAC3D,IAAI,SAAS,iBAAiB,OAAO,SAAS,gBAAgB,OAAO;CACtE;CACA,IAAI,WAAA,cAA+B,mBAAmB,SAAS,iBAC9D,OAAO,SAAS,gBAAgB,OAAO;CAExC,IAAI,SAAS,eAAe,OAAO,SAAS,cAAc,OAAO;CACjE,OAAO,SAAS,OAAO;AACxB"}
@@ -0,0 +1,178 @@
1
+ //#region src/oauth/devcode.ts
2
+ /**
3
+ * RFC 8628 device-code polling, shared by the Copilot and Codex logins.
4
+ *
5
+ * Both flows differ only in how a poll response is classified, so they pass a
6
+ * `poll` that maps their own payloads onto one result type and this owns the
7
+ * timing: the initial wait, the interval, `slow_down` backoff, the deadline,
8
+ * and cancellation.
9
+ */
10
+ const CANCEL_MESSAGE = "Login cancelled";
11
+ const TIMEOUT_MESSAGE = "Device authorization timed out";
12
+ const SLOW_DOWN_TIMEOUT_MESSAGE = "Device authorization timed out after one or more slow_down responses. This is often caused by clock drift in a VM or WSL; sync the clock and try again.";
13
+ const MINIMUM_INTERVAL_MS = 1e3;
14
+ /** RFC 8628 §3.2: a server that omits `interval` means 5 seconds. */
15
+ const DEFAULT_POLL_INTERVAL_SECONDS = 5;
16
+ /** RFC 8628 §3.5: `slow_down` means add 5 seconds. */
17
+ const SLOW_DOWN_INCREMENT_MS = 5e3;
18
+ function abortableSleep(ms, signal) {
19
+ return new Promise((resolve, reject) => {
20
+ if (signal?.aborted) {
21
+ reject(/* @__PURE__ */ new Error(CANCEL_MESSAGE));
22
+ return;
23
+ }
24
+ const onAbort = () => {
25
+ clearTimeout(timeout);
26
+ reject(/* @__PURE__ */ new Error(CANCEL_MESSAGE));
27
+ };
28
+ const timeout = setTimeout(() => {
29
+ signal?.removeEventListener("abort", onAbort);
30
+ resolve();
31
+ }, ms);
32
+ signal?.addEventListener("abort", onAbort, { once: true });
33
+ });
34
+ }
35
+ async function pollDeviceCode(options) {
36
+ const deadline = typeof options.expiresInSeconds === "number" ? Date.now() + options.expiresInSeconds * 1e3 : Number.POSITIVE_INFINITY;
37
+ let intervalMs = Math.max(MINIMUM_INTERVAL_MS, Math.floor((options.intervalSeconds ?? DEFAULT_POLL_INTERVAL_SECONDS) * 1e3));
38
+ let slowDowns = 0;
39
+ if (options.waitBeforeFirstPoll) {
40
+ const remaining = deadline - Date.now();
41
+ if (remaining > 0) await abortableSleep(Math.min(intervalMs, remaining), options.signal);
42
+ }
43
+ while (Date.now() < deadline) {
44
+ if (options.signal?.aborted) throw new Error(CANCEL_MESSAGE);
45
+ const result = await options.poll();
46
+ if (result.status === "complete") return result.value;
47
+ if (result.status === "failed") throw new Error(result.message);
48
+ if (result.status === "slow_down") {
49
+ slowDowns += 1;
50
+ intervalMs = typeof result.intervalSeconds === "number" && Number.isFinite(result.intervalSeconds) && result.intervalSeconds > 0 ? Math.max(MINIMUM_INTERVAL_MS, Math.floor(result.intervalSeconds * 1e3)) : Math.max(MINIMUM_INTERVAL_MS, intervalMs + SLOW_DOWN_INCREMENT_MS);
51
+ }
52
+ const remaining = deadline - Date.now();
53
+ if (remaining <= 0) break;
54
+ await abortableSleep(Math.min(intervalMs, remaining), options.signal);
55
+ }
56
+ throw new Error(slowDowns > 0 ? SLOW_DOWN_TIMEOUT_MESSAGE : TIMEOUT_MESSAGE);
57
+ }
58
+ //#endregion
59
+ //#region src/oauth/storage.ts
60
+ /**
61
+ * Shared helpers for OAuth credential modules: environment access, the
62
+ * codework auth.json path, and a JSON file store that understands both flat
63
+ * credential files and per-provider maps.
64
+ */
65
+ function readEnv(name) {
66
+ if (typeof process === "undefined") return void 0;
67
+ return process.env[name];
68
+ }
69
+ function joinPath(...parts) {
70
+ return parts.filter(Boolean).join("/").replaceAll(/\/+/g, "/");
71
+ }
72
+ function expandHome(path) {
73
+ if (path === "~") return homeDirectory();
74
+ if (path.startsWith("~/")) return joinPath(homeDirectory(), path.slice(2));
75
+ return path;
76
+ }
77
+ function homeDirectory() {
78
+ const home = readEnv("HOME") ?? readEnv("USERPROFILE");
79
+ if (!home) throw new Error("unable to resolve home directory for OAuth credential storage");
80
+ return home;
81
+ }
82
+ function codeworkHomeDirectory() {
83
+ const override = readEnv("CODEWORK_HOME_DIR");
84
+ if (override) return expandHome(override);
85
+ return joinPath(homeDirectory(), ".codework");
86
+ }
87
+ function defaultAuthFilePath() {
88
+ const authFile = readEnv("CODEWORK_CREDENTIALS");
89
+ if (authFile) return expandHome(authFile);
90
+ return joinPath(codeworkHomeDirectory(), "aikit", "auth.json");
91
+ }
92
+ function isObject(value) {
93
+ return typeof value === "object" && value !== null && !Array.isArray(value);
94
+ }
95
+ /**
96
+ * Provider-scoped credentials inside a shared JSON file.
97
+ *
98
+ * Reads tolerate three layouts: the whole file being the credentials, a
99
+ * top-level `providerId` key, or `providers[providerId]`. Writes always take
100
+ * the top-level key and leave unrelated entries untouched.
101
+ */
102
+ var JsonAuthStorage = class {
103
+ path;
104
+ providerId;
105
+ isCredentials;
106
+ constructor(options) {
107
+ this.path = options.path ? expandHome(options.path) : defaultAuthFilePath();
108
+ this.providerId = options.providerId;
109
+ this.isCredentials = options.isCredentials;
110
+ }
111
+ async get() {
112
+ const file = await this.readFile().catch(() => void 0);
113
+ if (!file) return void 0;
114
+ if (this.isCredentials(file)) return file;
115
+ const direct = file[this.providerId];
116
+ if (this.isCredentials(direct)) return direct;
117
+ const providers = file.providers;
118
+ const nested = isObject(providers) ? providers[this.providerId] : void 0;
119
+ if (this.isCredentials(nested)) return nested;
120
+ }
121
+ async set(credentials) {
122
+ const current = await this.readFile();
123
+ const next = isObject(current) && !this.isCredentials(current) ? current : {};
124
+ next[this.providerId] = credentials;
125
+ await this.writeFile(next);
126
+ }
127
+ async clear() {
128
+ const current = await this.readFile();
129
+ if (!current) return;
130
+ if (this.isCredentials(current)) {
131
+ await this.writeFile({});
132
+ return;
133
+ }
134
+ delete current[this.providerId];
135
+ const providers = current.providers;
136
+ if (isObject(providers)) delete providers[this.providerId];
137
+ await this.writeFile(current);
138
+ }
139
+ /**
140
+ * Undefined means the file is genuinely absent or holds no credential map.
141
+ * Anything else -- unparseable JSON, a permission error -- throws, because
142
+ * `set` and `clear` rewrite the whole file: treating an unreadable file as
143
+ * empty would drop every other provider's credentials on the next login.
144
+ */
145
+ async readFile() {
146
+ const fs = await import("node:fs/promises");
147
+ let text;
148
+ try {
149
+ text = await fs.readFile(this.path, "utf8");
150
+ } catch (error) {
151
+ if (isObject(error) && error.code === "ENOENT") return void 0;
152
+ throw error;
153
+ }
154
+ let parsed;
155
+ try {
156
+ parsed = JSON.parse(text);
157
+ } catch (error) {
158
+ throw new Error(`credentials file ${this.path} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
159
+ }
160
+ return isObject(parsed) ? parsed : void 0;
161
+ }
162
+ async writeFile(value) {
163
+ const fs = await import("node:fs/promises");
164
+ const path = await import("node:path");
165
+ await fs.mkdir(path.dirname(this.path), { recursive: true });
166
+ const tempPath = `${this.path}.${process.pid}.${Date.now()}.tmp`;
167
+ await fs.writeFile(tempPath, `${JSON.stringify(value, null, " ")}\n`, {
168
+ encoding: "utf8",
169
+ mode: 384
170
+ });
171
+ await fs.chmod(tempPath, 384);
172
+ await fs.rename(tempPath, this.path);
173
+ }
174
+ };
175
+ //#endregion
176
+ export { pollDeviceCode as i, isObject as n, readEnv as r, JsonAuthStorage as t };
177
+
178
+ //# sourceMappingURL=storage-v6qjTQ0v.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-v6qjTQ0v.mjs","names":[],"sources":["../../src/oauth/devcode.ts","../../src/oauth/storage.ts"],"sourcesContent":["/**\n * RFC 8628 device-code polling, shared by the Copilot and Codex logins.\n *\n * Both flows differ only in how a poll response is classified, so they pass a\n * `poll` that maps their own payloads onto one result type and this owns the\n * timing: the initial wait, the interval, `slow_down` backoff, the deadline,\n * and cancellation.\n */\n\nconst CANCEL_MESSAGE = \"Login cancelled\";\nconst TIMEOUT_MESSAGE = \"Device authorization timed out\";\nconst SLOW_DOWN_TIMEOUT_MESSAGE =\n\t\"Device authorization timed out after one or more slow_down responses. This is often caused by clock drift in a VM or WSL; sync the clock and try again.\";\nconst MINIMUM_INTERVAL_MS = 1000;\n/** RFC 8628 §3.2: a server that omits `interval` means 5 seconds. */\nconst DEFAULT_POLL_INTERVAL_SECONDS = 5;\n/** RFC 8628 §3.5: `slow_down` means add 5 seconds. */\nconst SLOW_DOWN_INCREMENT_MS = 5000;\n\nexport type DeviceCodePollResult<T> =\n\t| { status: \"pending\" }\n\t| { status: \"slow_down\"; intervalSeconds?: number | undefined }\n\t| { status: \"failed\"; message: string }\n\t| { status: \"complete\"; value: T };\n\nexport type DeviceCodePollOptions<T> = {\n\tintervalSeconds?: number | undefined;\n\texpiresInSeconds?: number | undefined;\n\t/** RFC 8628 §3.3: wait one interval before the first poll. */\n\twaitBeforeFirstPoll?: boolean | undefined;\n\tpoll: () => Promise<DeviceCodePollResult<T>>;\n\tsignal?: AbortSignal | undefined;\n};\n\nexport function abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new Error(CANCEL_MESSAGE));\n\t\t\treturn;\n\t\t}\n\t\tconst onAbort = () => {\n\t\t\tclearTimeout(timeout);\n\t\t\treject(new Error(CANCEL_MESSAGE));\n\t\t};\n\t\tconst timeout = setTimeout(() => {\n\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\tresolve();\n\t\t}, ms);\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n}\n\nexport async function pollDeviceCode<T>(options: DeviceCodePollOptions<T>): Promise<T> {\n\tconst deadline =\n\t\ttypeof options.expiresInSeconds === \"number\"\n\t\t\t? Date.now() + options.expiresInSeconds * 1000\n\t\t\t: Number.POSITIVE_INFINITY;\n\tlet intervalMs = Math.max(\n\t\tMINIMUM_INTERVAL_MS,\n\t\tMath.floor((options.intervalSeconds ?? DEFAULT_POLL_INTERVAL_SECONDS) * 1000),\n\t);\n\tlet slowDowns = 0;\n\n\tif (options.waitBeforeFirstPoll) {\n\t\tconst remaining = deadline - Date.now();\n\t\tif (remaining > 0) await abortableSleep(Math.min(intervalMs, remaining), options.signal);\n\t}\n\n\twhile (Date.now() < deadline) {\n\t\tif (options.signal?.aborted) throw new Error(CANCEL_MESSAGE);\n\n\t\tconst result = await options.poll();\n\t\tif (result.status === \"complete\") return result.value;\n\t\tif (result.status === \"failed\") throw new Error(result.message);\n\t\tif (result.status === \"slow_down\") {\n\t\t\tslowDowns += 1;\n\t\t\t// Prefer the server's new minimum when it reports one: a purely\n\t\t\t// client-tracked interval can poll early forever under clock drift.\n\t\t\tintervalMs =\n\t\t\t\ttypeof result.intervalSeconds === \"number\" &&\n\t\t\t\tNumber.isFinite(result.intervalSeconds) &&\n\t\t\t\tresult.intervalSeconds > 0\n\t\t\t\t\t? Math.max(MINIMUM_INTERVAL_MS, Math.floor(result.intervalSeconds * 1000))\n\t\t\t\t\t: Math.max(MINIMUM_INTERVAL_MS, intervalMs + SLOW_DOWN_INCREMENT_MS);\n\t\t}\n\n\t\tconst remaining = deadline - Date.now();\n\t\tif (remaining <= 0) break;\n\t\tawait abortableSleep(Math.min(intervalMs, remaining), options.signal);\n\t}\n\n\tthrow new Error(slowDowns > 0 ? SLOW_DOWN_TIMEOUT_MESSAGE : TIMEOUT_MESSAGE);\n}\n","/**\n * Shared helpers for OAuth credential modules: environment access, the\n * codework auth.json path, and a JSON file store that understands both flat\n * credential files and per-provider maps.\n */\n\nexport function readEnv(name: string): string | undefined {\n\tif (typeof process === \"undefined\") return undefined;\n\treturn process.env[name];\n}\n\nexport function joinPath(...parts: string[]): string {\n\treturn parts.filter(Boolean).join(\"/\").replaceAll(/\\/+/g, \"/\");\n}\n\nexport function expandHome(path: string): string {\n\tif (path === \"~\") return homeDirectory();\n\tif (path.startsWith(\"~/\")) return joinPath(homeDirectory(), path.slice(2));\n\treturn path;\n}\n\nexport function homeDirectory(): string {\n\tconst home = readEnv(\"HOME\") ?? readEnv(\"USERPROFILE\");\n\tif (!home) {\n\t\tthrow new Error(\"unable to resolve home directory for OAuth credential storage\");\n\t}\n\treturn home;\n}\n\nexport function codeworkHomeDirectory(): string {\n\tconst override = readEnv(\"CODEWORK_HOME_DIR\");\n\tif (override) return expandHome(override);\n\treturn joinPath(homeDirectory(), \".codework\");\n}\n\nexport function defaultAuthFilePath(): string {\n\tconst authFile = readEnv(\"CODEWORK_CREDENTIALS\");\n\tif (authFile) return expandHome(authFile);\n\treturn joinPath(codeworkHomeDirectory(), \"aikit\", \"auth.json\");\n}\n\nexport function isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport type JsonAuthStorageOptions<T> = {\n\tpath?: string;\n\tproviderId: string;\n\tisCredentials: (value: unknown) => value is T;\n};\n\n/**\n * Provider-scoped credentials inside a shared JSON file.\n *\n * Reads tolerate three layouts: the whole file being the credentials, a\n * top-level `providerId` key, or `providers[providerId]`. Writes always take\n * the top-level key and leave unrelated entries untouched.\n */\nexport class JsonAuthStorage<T> {\n\treadonly path: string;\n\treadonly providerId: string;\n\tprivate readonly isCredentials: (value: unknown) => value is T;\n\n\tconstructor(options: JsonAuthStorageOptions<T>) {\n\t\tthis.path = options.path ? expandHome(options.path) : defaultAuthFilePath();\n\t\tthis.providerId = options.providerId;\n\t\tthis.isCredentials = options.isCredentials;\n\t}\n\n\tasync get(): Promise<T | undefined> {\n\t\t// A read falls through to the next credential source, so an unreadable\n\t\t// file is simply \"no credentials here\". A write must not: see readFile.\n\t\tconst file = await this.readFile().catch(() => undefined);\n\t\tif (!file) return undefined;\n\n\t\tif (this.isCredentials(file)) return file;\n\n\t\tconst direct = file[this.providerId];\n\t\tif (this.isCredentials(direct)) return direct;\n\n\t\tconst providers = file.providers;\n\t\tconst nested = isObject(providers) ? providers[this.providerId] : undefined;\n\t\tif (this.isCredentials(nested)) {\n\t\t\treturn nested;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tasync set(credentials: T): Promise<void> {\n\t\tconst current = await this.readFile();\n\t\tconst next = isObject(current) && !this.isCredentials(current) ? current : {};\n\t\tnext[this.providerId] = credentials;\n\t\tawait this.writeFile(next);\n\t}\n\n\tasync clear(): Promise<void> {\n\t\tconst current = await this.readFile();\n\t\tif (!current) return;\n\n\t\tif (this.isCredentials(current)) {\n\t\t\tawait this.writeFile({});\n\t\t\treturn;\n\t\t}\n\n\t\tdelete current[this.providerId];\n\t\tconst providers = current.providers;\n\t\tif (isObject(providers)) delete providers[this.providerId];\n\t\tawait this.writeFile(current);\n\t}\n\n\t/**\n\t * Undefined means the file is genuinely absent or holds no credential map.\n\t * Anything else -- unparseable JSON, a permission error -- throws, because\n\t * `set` and `clear` rewrite the whole file: treating an unreadable file as\n\t * empty would drop every other provider's credentials on the next login.\n\t */\n\tprivate async readFile(): Promise<AuthFile | undefined> {\n\t\tconst fs = await import(\"node:fs/promises\");\n\t\tlet text: string;\n\t\ttry {\n\t\t\ttext = await fs.readFile(this.path, \"utf8\");\n\t\t} catch (error) {\n\t\t\tif (isObject(error) && error.code === \"ENOENT\") return undefined;\n\t\t\tthrow error;\n\t\t}\n\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = JSON.parse(text);\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`credentials file ${this.path} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t\treturn isObject(parsed) ? parsed : undefined;\n\t}\n\n\tprivate async writeFile(value: AuthFile): Promise<void> {\n\t\tconst fs = await import(\"node:fs/promises\");\n\t\tconst path = await import(\"node:path\");\n\t\tawait fs.mkdir(path.dirname(this.path), { recursive: true });\n\t\tconst tempPath = `${this.path}.${process.pid}.${Date.now()}.tmp`;\n\t\tawait fs.writeFile(tempPath, `${JSON.stringify(value, null, \"\\t\")}\\n`, { encoding: \"utf8\", mode: 0o600 });\n\t\tawait fs.chmod(tempPath, 0o600);\n\t\tawait fs.rename(tempPath, this.path);\n\t}\n}\n\ntype AuthFile = Record<string, unknown>;\n"],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ //#region src/oauth/summary.ts
2
+ const OAUTH_PROVIDER_LABELS = {
3
+ "openai-codex": "OpenAI Codex",
4
+ "github-copilot": "GitHub Copilot"
5
+ };
6
+ const oauthProviderLabel = (provider) => OAUTH_PROVIDER_LABELS[provider];
7
+ const summarizeOpenAICodex = (credentials) => ({
8
+ provider: "openai-codex",
9
+ expires: credentials.expires,
10
+ accountId: credentials.accountId
11
+ });
12
+ const summarizeGitHubCopilot = (credentials) => ({
13
+ provider: "github-copilot",
14
+ expires: credentials.expires,
15
+ ...credentials.apiEndpoint === void 0 ? {} : { apiEndpoint: credentials.apiEndpoint },
16
+ ...credentials.enterpriseUrl === void 0 ? {} : { enterpriseUrl: credentials.enterpriseUrl },
17
+ ...credentials.availableModelIds === void 0 ? {} : { availableModels: credentials.availableModelIds.length }
18
+ });
19
+ /** Render a summary. Tokens never appear in it. */
20
+ function formatOAuthSummary(summary, options = {}) {
21
+ if (options.json) return `${JSON.stringify({
22
+ ...summary,
23
+ ...summary.expires === 0 ? {} : { expiresAt: new Date(summary.expires).toISOString() }
24
+ }, null, 2)}\n`;
25
+ return `${[
26
+ `Provider: ${oauthProviderLabel(summary.provider)}`,
27
+ ...summary.accountId === void 0 ? [] : [`Account: ${summary.accountId}`],
28
+ ...summary.enterpriseUrl === void 0 ? [] : [`Enterprise: ${summary.enterpriseUrl}`],
29
+ ...summary.apiEndpoint === void 0 ? [] : [`API endpoint: ${summary.apiEndpoint}`],
30
+ ...summary.availableModels === void 0 ? [] : [`Available models: ${summary.availableModels}`],
31
+ `Expires: ${summary.expires === 0 ? "never (re-login on persistent 401s)" : new Date(summary.expires).toLocaleString()}`
32
+ ].join("\n")}\n`;
33
+ }
34
+ /** `location` is a bare place — a file path, or "the server". */
35
+ function oauthNotice(kind, provider, location) {
36
+ const label = oauthProviderLabel(provider);
37
+ switch (kind) {
38
+ case "saved": return `Saved ${label} credentials to ${location}`;
39
+ case "cleared": return `Cleared ${label} credentials from ${location}`;
40
+ case "refreshed": return `Refreshed ${label} credentials at ${location}`;
41
+ case "missing": return `no ${label} credentials found at ${location}`;
42
+ }
43
+ }
44
+ /** Resolve the provider from the two mutually exclusive flags. */
45
+ function checkOAuthProvider(flags) {
46
+ const codex = flags.openaiCodex === true;
47
+ if (codex === (flags.githubCopilot === true)) return {
48
+ ok: false,
49
+ message: "choose exactly one provider: --openai-codex or --github-copilot"
50
+ };
51
+ return {
52
+ ok: true,
53
+ provider: codex ? "openai-codex" : "github-copilot"
54
+ };
55
+ }
56
+ /** A login option the chosen provider has no use for, when one was given. */
57
+ function oauthLoginIssue(provider, flags) {
58
+ if (provider === "openai-codex" && (flags.enterprise !== void 0 || flags.enableModels === true)) return "--enterprise and --enable-models only apply to --github-copilot";
59
+ if (provider === "github-copilot" && flags.device === true) return "GitHub Copilot always uses the device-code flow; --device is redundant";
60
+ }
61
+ /** Why a provider cannot be refreshed, when it cannot. */
62
+ function oauthRefreshIssue(provider) {
63
+ return provider === "github-copilot" ? "GitHub Copilot tokens do not expire; sign in again on persistent 401s" : void 0;
64
+ }
65
+ //#endregion
66
+ export { oauthNotice as a, summarizeGitHubCopilot as c, oauthLoginIssue as i, summarizeOpenAICodex as l, checkOAuthProvider as n, oauthProviderLabel as o, formatOAuthSummary as r, oauthRefreshIssue as s, OAUTH_PROVIDER_LABELS as t };
67
+
68
+ //# sourceMappingURL=summary-C_QyCVWa.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary-C_QyCVWa.mjs","names":[],"sources":["../../src/oauth/summary.ts"],"sourcesContent":["/**\n * One presentation and one rule set for every OAuth login, so a command behaves\n * the same whichever CLI runs it.\n *\n * Credentials differ per provider; what a user is shown does not. Each provider\n * narrows to an {@link OAuthSummary} — metadata only, never a token — and\n * everything downstream works from that.\n *\n * Output convention: the summary is the command's result and belongs on stdout,\n * alone, so `--json` stays parseable. Every notice here is progress, not result,\n * and belongs on stderr.\n */\n\nexport type OAuthProviderId = \"openai-codex\" | \"github-copilot\";\n\nexport const OAUTH_PROVIDER_LABELS: Record<OAuthProviderId, string> = {\n\t\"openai-codex\": \"OpenAI Codex\",\n\t\"github-copilot\": \"GitHub Copilot\",\n};\n\nexport const oauthProviderLabel = (provider: OAuthProviderId): string => OAUTH_PROVIDER_LABELS[provider];\n\n/** A stored login as the outside world sees it. */\nexport type OAuthSummary = {\n\treadonly provider: OAuthProviderId;\n\t/** Epoch millis, or 0 for a credential that does not expire. */\n\treadonly expires: number;\n\treadonly accountId?: string | undefined;\n\treadonly apiEndpoint?: string | undefined;\n\treadonly enterpriseUrl?: string | undefined;\n\treadonly availableModels?: number | undefined;\n};\n\nexport const summarizeOpenAICodex = (credentials: {\n\treadonly accountId: string;\n\treadonly expires: number;\n}): OAuthSummary => ({\n\tprovider: \"openai-codex\",\n\texpires: credentials.expires,\n\taccountId: credentials.accountId,\n});\n\nexport const summarizeGitHubCopilot = (credentials: {\n\treadonly expires: number;\n\treadonly apiEndpoint?: string | undefined;\n\treadonly enterpriseUrl?: string | undefined;\n\treadonly availableModelIds?: ReadonlyArray<string> | undefined;\n}): OAuthSummary => ({\n\tprovider: \"github-copilot\",\n\texpires: credentials.expires,\n\t...(credentials.apiEndpoint === undefined ? {} : { apiEndpoint: credentials.apiEndpoint }),\n\t...(credentials.enterpriseUrl === undefined ? {} : { enterpriseUrl: credentials.enterpriseUrl }),\n\t...(credentials.availableModelIds === undefined ? {} : { availableModels: credentials.availableModelIds.length }),\n});\n\n/** Render a summary. Tokens never appear in it. */\nexport function formatOAuthSummary(\n\tsummary: OAuthSummary,\n\toptions: { readonly json?: boolean | undefined } = {},\n): string {\n\tif (options.json) {\n\t\treturn `${JSON.stringify(\n\t\t\t{\n\t\t\t\t...summary,\n\t\t\t\t...(summary.expires === 0 ? {} : { expiresAt: new Date(summary.expires).toISOString() }),\n\t\t\t},\n\t\t\tnull,\n\t\t\t2,\n\t\t)}\\n`;\n\t}\n\n\treturn `${[\n\t\t`Provider: ${oauthProviderLabel(summary.provider)}`,\n\t\t...(summary.accountId === undefined ? [] : [`Account: ${summary.accountId}`]),\n\t\t...(summary.enterpriseUrl === undefined ? [] : [`Enterprise: ${summary.enterpriseUrl}`]),\n\t\t...(summary.apiEndpoint === undefined ? [] : [`API endpoint: ${summary.apiEndpoint}`]),\n\t\t...(summary.availableModels === undefined ? [] : [`Available models: ${summary.availableModels}`]),\n\t\t`Expires: ${\n\t\t\tsummary.expires === 0 ? \"never (re-login on persistent 401s)\" : new Date(summary.expires).toLocaleString()\n\t\t}`,\n\t].join(\"\\n\")}\\n`;\n}\n\nexport type OAuthNoticeKind = \"saved\" | \"cleared\" | \"refreshed\" | \"missing\";\n\n/** `location` is a bare place — a file path, or \"the server\". */\nexport function oauthNotice(kind: OAuthNoticeKind, provider: OAuthProviderId, location: string): string {\n\tconst label = oauthProviderLabel(provider);\n\tswitch (kind) {\n\t\tcase \"saved\":\n\t\t\treturn `Saved ${label} credentials to ${location}`;\n\t\tcase \"cleared\":\n\t\t\treturn `Cleared ${label} credentials from ${location}`;\n\t\tcase \"refreshed\":\n\t\t\treturn `Refreshed ${label} credentials at ${location}`;\n\t\tcase \"missing\":\n\t\t\treturn `no ${label} credentials found at ${location}`;\n\t}\n}\n\nexport type OAuthProviderFlags = {\n\treadonly openaiCodex?: boolean | undefined;\n\treadonly githubCopilot?: boolean | undefined;\n};\n\nexport type OAuthFlagCheck = { ok: true; provider: OAuthProviderId } | { ok: false; message: string };\n\n/** Resolve the provider from the two mutually exclusive flags. */\nexport function checkOAuthProvider(flags: OAuthProviderFlags): OAuthFlagCheck {\n\tconst codex = flags.openaiCodex === true;\n\tconst copilot = flags.githubCopilot === true;\n\tif (codex === copilot) {\n\t\treturn { ok: false, message: \"choose exactly one provider: --openai-codex or --github-copilot\" };\n\t}\n\treturn { ok: true, provider: codex ? \"openai-codex\" : \"github-copilot\" };\n}\n\nexport type OAuthLoginFlags = {\n\treadonly device?: boolean | undefined;\n\treadonly enterprise?: string | undefined;\n\treadonly enableModels?: boolean | undefined;\n};\n\n/** A login option the chosen provider has no use for, when one was given. */\nexport function oauthLoginIssue(provider: OAuthProviderId, flags: OAuthLoginFlags): string | undefined {\n\tif (provider === \"openai-codex\" && (flags.enterprise !== undefined || flags.enableModels === true)) {\n\t\treturn \"--enterprise and --enable-models only apply to --github-copilot\";\n\t}\n\tif (provider === \"github-copilot\" && flags.device === true) {\n\t\treturn \"GitHub Copilot always uses the device-code flow; --device is redundant\";\n\t}\n\treturn undefined;\n}\n\n/** Why a provider cannot be refreshed, when it cannot. */\nexport function oauthRefreshIssue(provider: OAuthProviderId): string | undefined {\n\treturn provider === \"github-copilot\"\n\t\t? \"GitHub Copilot tokens do not expire; sign in again on persistent 401s\"\n\t\t: undefined;\n}\n"],"mappings":";AAeA,MAAa,wBAAyD;CACrE,gBAAgB;CAChB,kBAAkB;AACnB;AAEA,MAAa,sBAAsB,aAAsC,sBAAsB;AAa/F,MAAa,wBAAwB,iBAGhB;CACpB,UAAU;CACV,SAAS,YAAY;CACrB,WAAW,YAAY;AACxB;AAEA,MAAa,0BAA0B,iBAKlB;CACpB,UAAU;CACV,SAAS,YAAY;CACrB,GAAI,YAAY,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,YAAY,YAAY;CACxF,GAAI,YAAY,kBAAkB,KAAA,IAAY,CAAC,IAAI,EAAE,eAAe,YAAY,cAAc;CAC9F,GAAI,YAAY,sBAAsB,KAAA,IAAY,CAAC,IAAI,EAAE,iBAAiB,YAAY,kBAAkB,OAAO;AAChH;;AAGA,SAAgB,mBACf,SACA,UAAmD,CAAC,GAC3C;CACT,IAAI,QAAQ,MACX,OAAO,GAAG,KAAK,UACd;EACC,GAAG;EACH,GAAI,QAAQ,YAAY,IAAI,CAAC,IAAI,EAAE,WAAW,IAAI,KAAK,QAAQ,OAAO,CAAC,CAAC,YAAY,EAAE;CACvF,GACA,MACA,CACD,EAAE;CAGH,OAAO,GAAG;EACT,aAAa,mBAAmB,QAAQ,QAAQ;EAChD,GAAI,QAAQ,cAAc,KAAA,IAAY,CAAC,IAAI,CAAC,YAAY,QAAQ,WAAW;EAC3E,GAAI,QAAQ,kBAAkB,KAAA,IAAY,CAAC,IAAI,CAAC,eAAe,QAAQ,eAAe;EACtF,GAAI,QAAQ,gBAAgB,KAAA,IAAY,CAAC,IAAI,CAAC,iBAAiB,QAAQ,aAAa;EACpF,GAAI,QAAQ,oBAAoB,KAAA,IAAY,CAAC,IAAI,CAAC,qBAAqB,QAAQ,iBAAiB;EAChG,YACC,QAAQ,YAAY,IAAI,wCAAwC,IAAI,KAAK,QAAQ,OAAO,CAAC,CAAC,eAAe;CAE3G,CAAC,CAAC,KAAK,IAAI,EAAE;AACd;;AAKA,SAAgB,YAAY,MAAuB,UAA2B,UAA0B;CACvG,MAAM,QAAQ,mBAAmB,QAAQ;CACzC,QAAQ,MAAR;EACC,KAAK,SACJ,OAAO,SAAS,MAAM,kBAAkB;EACzC,KAAK,WACJ,OAAO,WAAW,MAAM,oBAAoB;EAC7C,KAAK,aACJ,OAAO,aAAa,MAAM,kBAAkB;EAC7C,KAAK,WACJ,OAAO,MAAM,MAAM,wBAAwB;CAC7C;AACD;;AAUA,SAAgB,mBAAmB,OAA2C;CAC7E,MAAM,QAAQ,MAAM,gBAAgB;CAEpC,IAAI,WADY,MAAM,kBAAkB,OAEvC,OAAO;EAAE,IAAI;EAAO,SAAS;CAAkE;CAEhG,OAAO;EAAE,IAAI;EAAM,UAAU,QAAQ,iBAAiB;CAAiB;AACxE;;AASA,SAAgB,gBAAgB,UAA2B,OAA4C;CACtG,IAAI,aAAa,mBAAmB,MAAM,eAAe,KAAA,KAAa,MAAM,iBAAiB,OAC5F,OAAO;CAER,IAAI,aAAa,oBAAoB,MAAM,WAAW,MACrD,OAAO;AAGT;;AAGA,SAAgB,kBAAkB,UAA+C;CAChF,OAAO,aAAa,mBACjB,0EACA,KAAA;AACJ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"codex-MtP1574D.mjs","names":[],"sources":["../../src/oauth/openai/codex.ts"],"sourcesContent":["/**\n * OpenAI Codex OAuth.\n *\n * Public interface, by use case:\n *\n * 1. Server OAuth integration (storage-free, bring your own routes):\n * `createOpenAICodexAuthorizationFlow`, `exchangeOpenAICodexAuthorizationCode`,\n * `parseOpenAICodexAuthorizationInput`, `refreshOpenAICodexToken`, `getOpenAICodexAccountId`.\n * 2. CLI / interactive login (localhost callback server, persisted credentials):\n * `OpenAICodexOAuthClient`, `JsonOpenAICodexAuthStorage`, `OpenAICodexAuthStorage`.\n * 3. Application credential access (get key, auto-refresh, request headers):\n * `getOpenAICodexApiKey`, `OpenAICodexOAuthClient.getCredentials/getApiKey/getHeaders`,\n * `openAICodexHeaders`, `OPENAI_CODEX_API_KEY_ENV`.\n *\n * Everything else in this module is an implementation detail and intentionally\n * not exported.\n */\n\nimport dedent from \"dedent\";\n\nconst CODEWORK_OAUTH_CALLBACK_HOST = \"CODEWORK_OAUTH_CALLBACK_HOST\";\nconst CODEWORK_CREDENTIALS = \"CODEWORK_CREDENTIALS\";\nconst CODEWORK_HOME_DIR = \"CODEWORK_HOME_DIR\";\n\nconst CLIENT_ID = \"app_EMoamEEZ73f0CkXaXp7hrann\";\nconst AUTHORIZE_URL = \"https://auth.openai.com/oauth/authorize\";\nconst TOKEN_URL = \"https://auth.openai.com/oauth/token\";\nconst DEFAULT_REDIRECT_URI = \"http://localhost:1455/auth/callback\";\nconst DEFAULT_SCOPE = \"openid profile email offline_access\";\nconst DEFAULT_ORIGINATOR = \"codework\";\nconst DEFAULT_PROVIDER_ID = \"openai-codex\";\nconst JWT_CLAIM_PATH = \"https://api.openai.com/auth\";\nconst REFRESH_SKEW_MS = 60 * 1000;\n\nexport type OpenAICodexOAuthCredentials = {\n\taccess: string;\n\trefresh: string;\n\texpires: number;\n\taccountId: string;\n};\n\nexport type OpenAICodexTokenSuccess = {\n\ttype: \"success\";\n\taccess: string;\n\trefresh: string;\n\texpires: number;\n};\n\nexport type OpenAICodexTokenFailure = {\n\ttype: \"failed\";\n\tmessage: string;\n\tstatus?: number;\n};\n\nexport type OpenAICodexTokenResult = OpenAICodexTokenSuccess | OpenAICodexTokenFailure;\n\nexport type OpenAICodexAuthorizationFlow = {\n\turl: string;\n\tverifier: string;\n\tstate: string;\n\tredirectUri: string;\n};\n\nexport type OpenAICodexAuthorizationOptions = {\n\toriginator?: string;\n\tredirectUri?: string;\n\tscope?: string;\n};\n\nexport type OpenAICodexLoginPrompt = {\n\tmessage: string;\n\tplaceholder?: string;\n\tallowEmpty?: boolean;\n};\n\nexport type OpenAICodexLoginOptions = OpenAICodexAuthorizationOptions & {\n\tonAuth: (info: { url: string; instructions?: string }) => void;\n\tonPrompt: (prompt: OpenAICodexLoginPrompt) => Promise<string>;\n\tonProgress?: (message: string) => void;\n\tonManualCodeInput?: () => Promise<string>;\n};\n\nexport interface OpenAICodexAuthStorage {\n\tget(): Promise<OpenAICodexOAuthCredentials | undefined>;\n\tset(credentials: OpenAICodexOAuthCredentials): Promise<void>;\n\tclear(): Promise<void>;\n}\n\nexport type JsonOpenAICodexAuthStorageOptions = {\n\tpath?: string;\n\tproviderId?: string;\n};\n\ntype JwtPayload = {\n\t[JWT_CLAIM_PATH]?: {\n\t\tchatgpt_account_id?: string;\n\t};\n\t[key: string]: unknown;\n};\n\ntype OAuthServerInfo = {\n\tclose: () => Promise<void>;\n\tcancelWait: () => void;\n\twaitForCode: () => Promise<{ code: string } | null>;\n};\n\ntype AuthFile = Record<string, unknown>;\n\ntype TokenEndpointPayload = {\n\taccess_token?: string;\n\trefresh_token?: string;\n\texpires_in?: number;\n};\n\nfunction readEnv(name: string): string | undefined {\n\tif (typeof process === \"undefined\") return undefined;\n\treturn process.env[name];\n}\n\nfunction joinPath(...parts: string[]): string {\n\treturn parts.filter(Boolean).join(\"/\").replaceAll(/\\/+/g, \"/\");\n}\n\nfunction expandHome(path: string): string {\n\tif (path === \"~\") return homeDirectory();\n\tif (path.startsWith(\"~/\")) return joinPath(homeDirectory(), path.slice(2));\n\treturn path;\n}\n\nfunction homeDirectory(): string {\n\tconst home = readEnv(\"HOME\") ?? readEnv(\"USERPROFILE\");\n\tif (!home) {\n\t\tthrow new Error(\"unable to resolve home directory for OpenAI Codex auth storage\");\n\t}\n\treturn home;\n}\n\nfunction codeworkHomeDirectory(): string {\n\tconst override = readEnv(CODEWORK_HOME_DIR);\n\tif (override) return expandHome(override);\n\treturn joinPath(homeDirectory(), \".codework\");\n}\n\n// Internal: the resolved location is exposed as `JsonOpenAICodexAuthStorage#path`.\nfunction defaultOpenAICodexAuthFilePath(): string {\n\tconst authFile = readEnv(CODEWORK_CREDENTIALS);\n\tif (authFile) return expandHome(authFile);\n\n\treturn joinPath(codeworkHomeDirectory(), \"aikit\", \"auth.json\");\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isOpenAICodexCredentials(value: unknown): value is OpenAICodexOAuthCredentials {\n\tif (!isObject(value)) return false;\n\treturn (\n\t\ttypeof value.access === \"string\" &&\n\t\ttypeof value.refresh === \"string\" &&\n\t\ttypeof value.expires === \"number\" &&\n\t\ttypeof value.accountId === \"string\"\n\t);\n}\n\nfunction redactOAuthSecrets(value: string, secrets: readonly string[] = []): string {\n\tlet redacted = value;\n\tfor (const secret of secrets.filter(Boolean).sort((left, right) => right.length - left.length)) {\n\t\tredacted = redacted.replaceAll(secret, \"[REDACTED]\");\n\t}\n\treturn redacted\n\t\t.replace(\n\t\t\t/((?:\"?(?:access_token|refresh_token|id_token|code|code_verifier)\"?)\\s*[:=]\\s*)(?:\"[^\"]*\"|'[^']*'|[^&\\s,}]+)/gi,\n\t\t\t'$1\"[REDACTED]\"',\n\t\t)\n\t\t.replace(/Bearer\\s+\\S+/gi, \"Bearer [REDACTED]\");\n}\n\nfunction tokenEndpointResult(payload: TokenEndpointPayload, operation: \"exchange\" | \"refresh\"): OpenAICodexTokenResult {\n\tconst missing = [\n\t\t!payload.access_token && \"access_token\",\n\t\t!payload.refresh_token && \"refresh_token\",\n\t\ttypeof payload.expires_in !== \"number\" && \"expires_in\",\n\t].filter((field): field is string => Boolean(field));\n\tif (missing.length > 0) {\n\t\treturn {\n\t\t\ttype: \"failed\",\n\t\t\tmessage: `OpenAI Codex token ${operation} response missing fields: ${missing.join(\", \")}`,\n\t\t};\n\t}\n\n\treturn {\n\t\ttype: \"success\",\n\t\taccess: payload.access_token!,\n\t\trefresh: payload.refresh_token!,\n\t\texpires: Date.now() + payload.expires_in! * 1000,\n\t};\n}\n\nfunction base64UrlEncode(bytes: Uint8Array): string {\n\tlet binary = \"\";\n\tfor (const byte of bytes) {\n\t\tbinary += String.fromCharCode(byte);\n\t}\n\treturn btoa(binary).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replaceAll(\"=\", \"\");\n}\n\nfunction base64UrlDecode(value: string): string {\n\tconst base64 = value.replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\");\n\tconst padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, \"=\");\n\treturn atob(padded);\n}\n\ntype WebCrypto = typeof globalThis.crypto;\n\nfunction getCrypto(): WebCrypto {\n\tif (!globalThis.crypto?.getRandomValues || !globalThis.crypto.subtle) {\n\t\tthrow new Error(\"openAI codex OAuth requires web crypto support\");\n\t}\n\treturn globalThis.crypto;\n}\n\nfunction createState(): string {\n\tconst bytes = new Uint8Array(16);\n\tgetCrypto().getRandomValues(bytes);\n\treturn Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nasync function generatePKCE(): Promise<{\n\tverifier: string;\n\tchallenge: string;\n}> {\n\tconst bytes = new Uint8Array(32);\n\tgetCrypto().getRandomValues(bytes);\n\tconst verifier = base64UrlEncode(bytes);\n\n\tconst data = new TextEncoder().encode(verifier);\n\tconst hash = await getCrypto().subtle.digest(\"SHA-256\", data);\n\tconst challenge = base64UrlEncode(new Uint8Array(hash));\n\n\treturn { verifier, challenge };\n}\n\nfunction authorizationInput(code: string | null | undefined, state: string | null | undefined) {\n\treturn {\n\t\t...(code != null && { code }),\n\t\t...(state != null && { state }),\n\t};\n}\n\nexport function parseOpenAICodexAuthorizationInput(input: string): {\n\tcode?: string;\n\tstate?: string;\n} {\n\tconst value = input.trim();\n\tif (!value) return {};\n\n\ttry {\n\t\tconst url = new URL(value);\n\t\treturn authorizationInput(url.searchParams.get(\"code\"), url.searchParams.get(\"state\"));\n\t} catch {\n\t\t// Not a URL.\n\t}\n\n\tif (value.includes(\"#\")) {\n\t\tconst [code, state] = value.split(\"#\", 2);\n\t\treturn authorizationInput(code, state);\n\t}\n\n\tif (value.includes(\"code=\")) {\n\t\tconst params = new URLSearchParams(value);\n\t\treturn authorizationInput(params.get(\"code\"), params.get(\"state\"));\n\t}\n\n\treturn { code: value };\n}\n\nfunction decodeJwt(token: string): JwtPayload | null {\n\ttry {\n\t\tconst parts = token.split(\".\");\n\t\tif (parts.length !== 3) return null;\n\t\treturn JSON.parse(base64UrlDecode(parts[1] ?? \"\")) as JwtPayload;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport function getOpenAICodexAccountId(accessToken: string): string | null {\n\tconst payload = decodeJwt(accessToken);\n\tconst auth = payload?.[JWT_CLAIM_PATH];\n\tconst accountId = auth?.chatgpt_account_id;\n\treturn typeof accountId === \"string\" && accountId.length > 0 ? accountId : null;\n}\n\nexport async function createOpenAICodexAuthorizationFlow(\n\toptions: OpenAICodexAuthorizationOptions = {},\n): Promise<OpenAICodexAuthorizationFlow> {\n\tconst redirectUri = options.redirectUri ?? DEFAULT_REDIRECT_URI;\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst state = createState();\n\n\tconst url = new URL(AUTHORIZE_URL);\n\turl.searchParams.set(\"response_type\", \"code\");\n\turl.searchParams.set(\"client_id\", CLIENT_ID);\n\turl.searchParams.set(\"redirect_uri\", redirectUri);\n\turl.searchParams.set(\"scope\", options.scope ?? DEFAULT_SCOPE);\n\turl.searchParams.set(\"code_challenge\", challenge);\n\turl.searchParams.set(\"code_challenge_method\", \"S256\");\n\turl.searchParams.set(\"state\", state);\n\turl.searchParams.set(\"id_token_add_organizations\", \"true\");\n\turl.searchParams.set(\"codex_cli_simplified_flow\", \"true\");\n\turl.searchParams.set(\"originator\", options.originator ?? DEFAULT_ORIGINATOR);\n\n\treturn { verifier, state, redirectUri, url: url.toString() };\n}\n\nexport async function exchangeOpenAICodexAuthorizationCode(\n\tcode: string,\n\tverifier: string,\n\tredirectUri: string = DEFAULT_REDIRECT_URI,\n): Promise<OpenAICodexTokenResult> {\n\ttry {\n\t\tconst response = await fetch(TOKEN_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: \"authorization_code\",\n\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\tcode,\n\t\t\t\tcode_verifier: verifier,\n\t\t\t\tredirect_uri: redirectUri,\n\t\t\t}),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst text = await response.text().catch(() => \"\");\n\t\t\treturn {\n\t\t\t\ttype: \"failed\",\n\t\t\t\tstatus: response.status,\n\t\t\t\tmessage: `OpenAI Codex token exchange failed (${response.status}): ${redactOAuthSecrets(\n\t\t\t\t\ttext || response.statusText,\n\t\t\t\t\t[code, verifier],\n\t\t\t\t)}`,\n\t\t\t};\n\t\t}\n\n\t\treturn tokenEndpointResult((await response.json()) as TokenEndpointPayload, \"exchange\");\n\t} catch (error) {\n\t\treturn {\n\t\t\ttype: \"failed\",\n\t\t\tmessage: `OpenAI Codex token exchange error: ${redactOAuthSecrets(\n\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t[code, verifier],\n\t\t\t)}`,\n\t\t};\n\t}\n}\n\nasync function refreshAccessToken(refreshToken: string): Promise<OpenAICodexTokenResult> {\n\ttry {\n\t\tconst response = await fetch(TOKEN_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: \"refresh_token\",\n\t\t\t\trefresh_token: refreshToken,\n\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t}),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst text = await response.text().catch(() => \"\");\n\t\t\treturn {\n\t\t\t\ttype: \"failed\",\n\t\t\t\tstatus: response.status,\n\t\t\t\tmessage: `OpenAI Codex token refresh failed (${response.status}): ${redactOAuthSecrets(\n\t\t\t\t\ttext || response.statusText,\n\t\t\t\t\t[refreshToken],\n\t\t\t\t)}`,\n\t\t\t};\n\t\t}\n\n\t\treturn tokenEndpointResult((await response.json()) as TokenEndpointPayload, \"refresh\");\n\t} catch (error) {\n\t\treturn {\n\t\t\ttype: \"failed\",\n\t\t\tmessage: `OpenAI Codex token refresh error: ${redactOAuthSecrets(\n\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t[refreshToken],\n\t\t\t)}`,\n\t\t};\n\t}\n}\n\nfunction oauthPage(options: { title: string; heading: string; message: string; details?: string }): string {\n\tconst escapeHtml = (value: string) =>\n\t\tvalue\n\t\t\t.replaceAll(\"&\", \"&amp;\")\n\t\t\t.replaceAll(\"<\", \"&lt;\")\n\t\t\t.replaceAll(\">\", \"&gt;\")\n\t\t\t.replaceAll('\"', \"&quot;\")\n\t\t\t.replaceAll(\"'\", \"&#39;\");\n\tconst details = options.details ? escapeHtml(options.details) : undefined;\n\n\treturn dedent`\n\t<!doctype html>\n\t<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\t\t<title>${escapeHtml(options.title)}</title>\n\t\t<style>\n\t\t\thtml { color-scheme: dark; }\n\t\t\tbody {\n\t\t\tmargin: 0;\n\t\t\tmin-height: 100vh;\n\t\t\tdisplay: grid;\n\t\t\tplace-items: center;\n\t\t\tpadding: 24px;\n\t\t\tbackground: #09090b;\n\t\t\tcolor: #fafafa;\n\t\t\tfont-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n\t\t\ttext-align: center;\n\t\t\t}\n\t\t\tmain { width: 100%; max-width: 560px; }\n\t\t\th1 { margin: 0 0 10px; font-size: 28px; line-height: 1.15; font-weight: 650; }\n\t\t\tp { margin: 0; line-height: 1.7; color: #a1a1aa; font-size: 15px; }\n\t\t\t.details { margin-top: 16px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; color: #a1a1aa; white-space: pre-wrap; word-break: break-word; }\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<main>\n\t\t\t<h1>${escapeHtml(options.heading)}</h1>\n\t\t\t<p>${escapeHtml(options.message)}</p>\n\t\t\t${details ? `<div class=\"details\">${details}</div>` : \"\"}\n\t\t</main>\n\t</body>\n\t</html>\n\t`;\n}\n\nfunction oauthSuccessHtml(message: string): string {\n\treturn oauthPage({\n\t\ttitle: \"Authentication successful\",\n\t\theading: \"Authentication successful\",\n\t\tmessage,\n\t});\n}\n\nfunction oauthErrorHtml(message: string, details?: string): string {\n\treturn oauthPage({\n\t\ttitle: \"Authentication failed\",\n\t\theading: \"Authentication failed\",\n\t\tmessage,\n\t\t...(details !== undefined && { details }),\n\t});\n}\n\nasync function startLocalOAuthServer(state: string): Promise<OAuthServerInfo> {\n\tconst http = await import(\"node:http\").catch(() => undefined);\n\tif (!http) {\n\t\tthrow new Error(\"openAI codex OAuth callback server is only available in Node.js environments\");\n\t}\n\n\tlet settleWait: ((value: { code: string } | null) => void) | undefined;\n\tconst waitForCodePromise = new Promise<{ code: string } | null>((resolve) => {\n\t\tlet settled = false;\n\t\tsettleWait = (value) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tresolve(value);\n\t\t};\n\t});\n\n\tconst server = http.createServer((req, res) => {\n\t\ttry {\n\t\t\tconst url = new URL(req.url || \"\", \"http://localhost\");\n\t\t\tif (url.pathname !== \"/auth/callback\") {\n\t\t\t\tres.statusCode = 404;\n\t\t\t\tres.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n\t\t\t\tres.end(oauthErrorHtml(\"Callback route not found.\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (url.searchParams.get(\"state\") !== state) {\n\t\t\t\tres.statusCode = 400;\n\t\t\t\tres.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n\t\t\t\tres.end(oauthErrorHtml(\"State mismatch.\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst code = url.searchParams.get(\"code\");\n\t\t\tif (!code) {\n\t\t\t\tres.statusCode = 400;\n\t\t\t\tres.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n\t\t\t\tres.end(oauthErrorHtml(\"Missing authorization code.\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tres.statusCode = 200;\n\t\t\tres.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n\t\t\tres.end(oauthSuccessHtml(\"OpenAI authentication completed. You can close this window.\"));\n\t\t\tsettleWait?.({ code });\n\t\t} catch (error) {\n\t\t\tres.statusCode = 500;\n\t\t\tres.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n\t\t\tres.end(\n\t\t\t\toauthErrorHtml(\n\t\t\t\t\t\"Internal error while processing OAuth callback.\",\n\t\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t});\n\tconst close = async (): Promise<void> => {\n\t\tif (!server.listening) return;\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tserver.close(() => resolve());\n\t\t\tserver.closeAllConnections();\n\t\t});\n\t};\n\n\treturn new Promise((resolve) => {\n\t\tserver\n\t\t\t.listen(1455, readEnv(CODEWORK_OAUTH_CALLBACK_HOST) || \"127.0.0.1\", () => {\n\t\t\t\tresolve({\n\t\t\t\t\tclose,\n\t\t\t\t\tcancelWait: () => {\n\t\t\t\t\t\tsettleWait?.(null);\n\t\t\t\t\t},\n\t\t\t\t\twaitForCode: () => waitForCodePromise,\n\t\t\t\t});\n\t\t\t})\n\t\t\t.on(\"error\", () => {\n\t\t\t\tsettleWait?.(null);\n\t\t\t\tresolve({\n\t\t\t\t\tclose,\n\t\t\t\t\tcancelWait: () => {},\n\t\t\t\t\twaitForCode: async () => null,\n\t\t\t\t});\n\t\t\t});\n\t});\n}\n\n// Internal: the public login entry point is `OpenAICodexOAuthClient#login`,\n// which persists the credentials. Server integrations should use the\n// storage-free authorization helpers instead of this localhost-callback flow.\nasync function loginOpenAICodex(options: OpenAICodexLoginOptions): Promise<OpenAICodexOAuthCredentials> {\n\tconst flow = await createOpenAICodexAuthorizationFlow(options);\n\tconst server = await startLocalOAuthServer(flow.state);\n\n\toptions.onAuth({\n\t\turl: flow.url,\n\t\tinstructions: \"Complete the browser login to finish OpenAI Codex authentication.\",\n\t});\n\n\tlet code: string | undefined;\n\ttry {\n\t\tif (options.onManualCodeInput) {\n\t\t\tlet manualCode: string | undefined;\n\t\t\tlet manualError: Error | undefined;\n\t\t\tconst manualPromise = options\n\t\t\t\t.onManualCodeInput()\n\t\t\t\t.then((input) => {\n\t\t\t\t\tmanualCode = input;\n\t\t\t\t\tif (input.trim()) server.cancelWait();\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tmanualError = error instanceof Error ? error : new Error(String(error));\n\t\t\t\t\tserver.cancelWait();\n\t\t\t\t});\n\n\t\t\tconst result = await server.waitForCode();\n\t\t\tif (manualError) throw manualError;\n\n\t\t\tif (result?.code) {\n\t\t\t\tcode = result.code;\n\t\t\t} else if (manualCode) {\n\t\t\t\tconst parsed = parseOpenAICodexAuthorizationInput(manualCode);\n\t\t\t\tif (parsed.state && parsed.state !== flow.state) throw new Error(\"state mismatch\");\n\t\t\t\tcode = parsed.code;\n\t\t\t}\n\n\t\t\tif (!code) {\n\t\t\t\tawait manualPromise;\n\t\t\t\tif (manualError) throw manualError;\n\t\t\t\tif (manualCode) {\n\t\t\t\t\tconst parsed = parseOpenAICodexAuthorizationInput(manualCode);\n\t\t\t\t\tif (parsed.state && parsed.state !== flow.state) throw new Error(\"state mismatch\");\n\t\t\t\t\tcode = parsed.code;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst result = await server.waitForCode();\n\t\t\tif (result?.code) code = result.code;\n\t\t}\n\n\t\tif (!code) {\n\t\t\tconst input = await options.onPrompt({\n\t\t\t\tmessage: \"Paste the authorization code or full redirect URL:\",\n\t\t\t});\n\t\t\tconst parsed = parseOpenAICodexAuthorizationInput(input);\n\t\t\tif (parsed.state && parsed.state !== flow.state) throw new Error(\"state mismatch\");\n\t\t\tcode = parsed.code;\n\t\t}\n\n\t\tif (!code) throw new Error(\"missing authorization code\");\n\n\t\tconst tokenResult = await exchangeOpenAICodexAuthorizationCode(code, flow.verifier, flow.redirectUri);\n\t\tif (tokenResult.type !== \"success\") throw new Error(tokenResult.message);\n\n\t\tconst accountId = getOpenAICodexAccountId(tokenResult.access);\n\t\tif (!accountId) throw new Error(\"failed to extract accountId from token\");\n\n\t\treturn {\n\t\t\taccess: tokenResult.access,\n\t\t\trefresh: tokenResult.refresh,\n\t\t\texpires: tokenResult.expires,\n\t\t\taccountId,\n\t\t};\n\t} finally {\n\t\tawait server.close();\n\t}\n}\n\nexport async function refreshOpenAICodexToken(refreshToken: string): Promise<OpenAICodexOAuthCredentials> {\n\tconst result = await refreshAccessToken(refreshToken);\n\tif (result.type !== \"success\") {\n\t\tthrow new Error(result.message);\n\t}\n\n\tconst accountId = getOpenAICodexAccountId(result.access);\n\tif (!accountId) {\n\t\tthrow new Error(\"failed to extract accountId from token\");\n\t}\n\n\treturn {\n\t\taccess: result.access,\n\t\trefresh: result.refresh,\n\t\texpires: result.expires,\n\t\taccountId,\n\t};\n}\n\nexport function openAICodexHeaders(credentials: OpenAICodexOAuthCredentials): Record<string, string> {\n\treturn {\n\t\tAuthorization: `Bearer ${credentials.access}`,\n\t\t\"chatgpt-account-id\": credentials.accountId,\n\t\t\"OpenAI-Beta\": \"responses=experimental\",\n\t};\n}\n\nexport class JsonOpenAICodexAuthStorage implements OpenAICodexAuthStorage {\n\treadonly path: string;\n\treadonly providerId: string;\n\n\tconstructor(options: JsonOpenAICodexAuthStorageOptions = {}) {\n\t\tthis.path = options.path ? expandHome(options.path) : defaultOpenAICodexAuthFilePath();\n\t\tthis.providerId = options.providerId ?? DEFAULT_PROVIDER_ID;\n\t}\n\n\tasync get(): Promise<OpenAICodexOAuthCredentials | undefined> {\n\t\tconst file = await this.readFile();\n\t\tif (!file) return undefined;\n\n\t\tif (isOpenAICodexCredentials(file)) return file;\n\n\t\tconst direct = file[this.providerId];\n\t\tif (isOpenAICodexCredentials(direct)) return direct;\n\n\t\tconst providers = file.providers;\n\t\tif (isObject(providers) && isOpenAICodexCredentials(providers[this.providerId])) {\n\t\t\treturn providers[this.providerId] as OpenAICodexOAuthCredentials;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tasync set(credentials: OpenAICodexOAuthCredentials): Promise<void> {\n\t\tconst current = await this.readFile();\n\t\tconst next = isObject(current) && !isOpenAICodexCredentials(current) ? current : {};\n\t\tnext[this.providerId] = credentials;\n\t\tawait this.writeFile(next);\n\t}\n\n\tasync clear(): Promise<void> {\n\t\tconst current = await this.readFile();\n\t\tif (!current) return;\n\n\t\tif (isOpenAICodexCredentials(current)) {\n\t\t\tawait this.writeFile({});\n\t\t\treturn;\n\t\t}\n\n\t\tdelete current[this.providerId];\n\t\tconst providers = current.providers;\n\t\tif (isObject(providers)) delete providers[this.providerId];\n\t\tawait this.writeFile(current);\n\t}\n\n\tprivate async readFile(): Promise<AuthFile | undefined> {\n\t\tconst fs = await import(\"node:fs/promises\");\n\t\ttry {\n\t\t\tconst text = await fs.readFile(this.path, \"utf8\");\n\t\t\tconst parsed = JSON.parse(text) as unknown;\n\t\t\treturn isObject(parsed) ? parsed : undefined;\n\t\t} catch (error) {\n\t\t\tif (isObject(error) && error.code === \"ENOENT\") return undefined;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate async writeFile(value: AuthFile): Promise<void> {\n\t\tconst fs = await import(\"node:fs/promises\");\n\t\tconst path = await import(\"node:path\");\n\t\tawait fs.mkdir(path.dirname(this.path), { recursive: true });\n\t\tconst tempPath = `${this.path}.${process.pid}.${Date.now()}.tmp`;\n\t\tawait fs.writeFile(tempPath, `${JSON.stringify(value, null, \"\\t\")}\\n`, { encoding: \"utf8\", mode: 0o600 });\n\t\tawait fs.chmod(tempPath, 0o600);\n\t\tawait fs.rename(tempPath, this.path);\n\t}\n}\n\nexport type OpenAICodexOAuthClientOptions = {\n\tstorage?: OpenAICodexAuthStorage;\n\trefreshSkewMs?: number;\n};\n\nexport class OpenAICodexOAuthClient {\n\treadonly storage: OpenAICodexAuthStorage;\n\treadonly refreshSkewMs: number;\n\n\tconstructor(options: OpenAICodexOAuthClientOptions = {}) {\n\t\tthis.storage = options.storage ?? new JsonOpenAICodexAuthStorage();\n\t\tthis.refreshSkewMs = options.refreshSkewMs ?? REFRESH_SKEW_MS;\n\t}\n\n\tasync login(options: OpenAICodexLoginOptions): Promise<OpenAICodexOAuthCredentials> {\n\t\tconst credentials = await loginOpenAICodex(options);\n\t\tawait this.storage.set(credentials);\n\t\treturn credentials;\n\t}\n\n\tasync getCredentials(): Promise<OpenAICodexOAuthCredentials | undefined> {\n\t\tconst credentials = await this.storage.get();\n\t\tif (!credentials) return undefined;\n\n\t\tif (credentials.expires > Date.now() + this.refreshSkewMs) {\n\t\t\treturn credentials;\n\t\t}\n\n\t\tconst refreshed = await refreshOpenAICodexToken(credentials.refresh);\n\t\tawait this.storage.set(refreshed);\n\t\treturn refreshed;\n\t}\n\n\tasync getApiKey(): Promise<string | undefined> {\n\t\treturn (await this.getCredentials())?.access;\n\t}\n\n\tasync getHeaders(): Promise<Record<string, string> | undefined> {\n\t\tconst credentials = await this.getCredentials();\n\t\treturn credentials ? openAICodexHeaders(credentials) : undefined;\n\t}\n\n\tasync logout(): Promise<void> {\n\t\tawait this.storage.clear();\n\t}\n}\n\nexport const OPENAI_CODEX_API_KEY_ENV = \"OPENAI_CODEX_API_KEY\";\n\n/**\n * Resolve the OpenAI Codex API key the same way other provider API keys are\n * resolved: prefer the OPENAI_CODEX_API_KEY environment variable, then fall\n * back to stored OAuth credentials (refreshing them when close to expiry).\n *\n * The result can be passed directly as `apiKey` to the runtime options or to\n * `createOpenAICodex`. Returns undefined when no key is available.\n */\nexport async function getOpenAICodexApiKey(options: OpenAICodexOAuthClientOptions = {}): Promise<string | undefined> {\n\tconst envKey = readEnv(OPENAI_CODEX_API_KEY_ENV);\n\tif (envKey) return envKey;\n\n\treturn new OpenAICodexOAuthClient(options).getApiKey();\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"model-CBnredXj.mjs","names":["KnownProviderEnum","KnownProviderEnumSchema","Type","ModelCatalogLoadError","Filesystem.readText","ModelCatalog.KnownProviderEnum","ModelCatalog.KnownProviderEnumSchema","ModelCatalog.ModelCatalogLoadError","Type","ModelCatalog.get"],"sources":["../../src/utils/lazy.ts","../../src/utils/error.ts","../../src/utils/filesystem.ts","../../src/model/catalog.ts","../../src/model/model.ts"],"sourcesContent":["export function lazy<T>(fn: () => T) {\n\tlet value: T | undefined;\n\tlet loaded = false;\n\n\tconst result = (): T => {\n\t\tif (loaded) return value as T;\n\t\tvalue = fn();\n\t\tloaded = true;\n\t\treturn value as T;\n\t};\n\n\tresult.reset = () => {\n\t\tloaded = false;\n\t\tvalue = undefined;\n\t};\n\n\treturn result;\n}\n","import type { Static, TSchema } from \"typebox\";\n\ntype SchemaLike = TSchema;\ntype StaticData<Data extends SchemaLike> = Static<Data>;\n\nexport abstract class NamedError extends Error {\n\tabstract schema(): SchemaLike;\n\tabstract toObject(): { name: string; data: unknown };\n\n\tstatic create<Name extends string, Data extends SchemaLike>(name: Name, data: Data) {\n\t\tconst schema = {\n\t\t\t$id: name,\n\t\t\ttype: \"object\",\n\t\t\trequired: [\"name\", \"data\"],\n\t\t\tproperties: {\n\t\t\t\tname: {\n\t\t\t\t\tconst: name,\n\t\t\t\t},\n\t\t\t\tdata,\n\t\t\t},\n\t\t} as const;\n\n\t\tconst result = class extends NamedError {\n\t\t\tpublic static readonly Schema = schema;\n\n\t\t\tpublic override readonly name = name as Name;\n\n\t\t\tpublic readonly data: StaticData<Data>;\n\n\t\t\tconstructor(data: StaticData<Data>, options?: ErrorOptions) {\n\t\t\t\tsuper(name, options);\n\t\t\t\tthis.data = data;\n\t\t\t\tthis.name = name;\n\t\t\t}\n\n\t\t\tstatic isInstance(input: unknown): input is InstanceType<typeof result> {\n\t\t\t\treturn typeof input === \"object\" && input !== null && \"name\" in input && input.name === name;\n\t\t\t}\n\n\t\t\tschema() {\n\t\t\t\treturn schema;\n\t\t\t}\n\n\t\t\ttoObject() {\n\t\t\t\treturn {\n\t\t\t\t\tname,\n\t\t\t\t\tdata: this.data,\n\t\t\t\t};\n\t\t\t}\n\t\t};\n\n\t\tObject.defineProperty(result, \"name\", { value: name });\n\t\treturn result;\n\t}\n\n\tpublic static readonly Unknown = NamedError.create(\"UnknownError\", {\n\t\ttype: \"object\",\n\t\trequired: [\"message\"],\n\t\tproperties: {\n\t\t\tmessage: {\n\t\t\t\ttype: \"string\",\n\t\t\t},\n\t\t},\n\t});\n}\n","import { dirname } from \"path\";\nimport { mkdir, readFile, writeFile } from \"fs/promises\";\n\nexport async function readText(path: string): Promise<string> {\n\treturn readFile(path, \"utf-8\");\n}\n\nexport async function readJson<T = unknown>(path: string): Promise<T> {\n\treturn JSON.parse(await readFile(path, \"utf-8\"));\n}\n\nfunction isEnoent(error: unknown): error is { code: \"ENOENT\" } {\n\treturn (\n\t\ttypeof error === \"object\" && error !== null && \"code\" in error && (error as { code: string }).code === \"ENOENT\"\n\t);\n}\n\nexport async function write(path: string, content: string | Buffer | Uint8Array, mode?: number): Promise<void> {\n\ttry {\n\t\tif (mode) {\n\t\t\tawait writeFile(path, content, { mode });\n\t\t} else {\n\t\t\tawait writeFile(path, content);\n\t\t}\n\t} catch (error) {\n\t\tif (isEnoent(error)) {\n\t\t\tawait mkdir(dirname(path), { recursive: true });\n\t\t\tif (mode) {\n\t\t\t\tawait writeFile(path, content, { mode });\n\t\t\t} else {\n\t\t\t\tawait writeFile(path, content);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nexport async function writeJson(path: string, data: unknown, mode?: number): Promise<void> {\n\treturn write(path, JSON.stringify(data, null, 2), mode);\n}\n","import { join, resolve } from \"node:path\";\nimport Type, { type Static } from \"typebox\";\nimport { NamedError } from \"../utils/error.ts\";\nimport * as Filesystem from \"../utils/filesystem.ts\";\nimport { lazy } from \"../utils/lazy.ts\";\n\n// known AI SDK LLM providers\n// used as the public protocol discriminator for the AI SDK transport layer\nexport const KnownProviderEnum = {\n\tanthropic: \"anthropic\",\n\tgoogle: \"google\",\n\tgoogleVertex: \"google-vertex\",\n\tgoogleVertexAnthropic: \"google-vertex-anthropic\",\n\topenai: \"openai\",\n\topenaiCompatible: \"openai-compatible\",\n\topenaiCodex: \"openai-codex\",\n\topenrouter: \"openrouter\",\n\txai: \"xai\",\n} as const;\nexport const KnownProviderEnumSchema = Type.Union([\n\tType.Literal(KnownProviderEnum.anthropic),\n\tType.Literal(KnownProviderEnum.google),\n\tType.Literal(KnownProviderEnum.googleVertex),\n\tType.Literal(KnownProviderEnum.googleVertexAnthropic),\n\tType.Literal(KnownProviderEnum.openai),\n\tType.Literal(KnownProviderEnum.openaiCompatible),\n\tType.Literal(KnownProviderEnum.openaiCodex),\n\tType.Literal(KnownProviderEnum.openrouter),\n\tType.Literal(KnownProviderEnum.xai),\n]);\nexport type KnownProviderEnum = Static<typeof KnownProviderEnumSchema>;\n\nexport type GeneratedCatalog = Partial<Record<string, Record<string, unknown>>>;\ntype LazyGeneratedCatalog = ReturnType<typeof lazy<Promise<GeneratedCatalog>>>;\n\nexport const ModelCatalogLoadError = NamedError.create(\n\t\"ModelCatalogLoadError\",\n\tType.Object({\n\t\tpath: Type.String(),\n\t\treason: Type.Union([\n\t\t\tType.Literal(\"missing\"),\n\t\t\tType.Literal(\"unreadable\"),\n\t\t\tType.Literal(\"empty\"),\n\t\t\tType.Literal(\"invalid\"),\n\t\t]),\n\t\tmessage: Type.String(),\n\t}),\n);\nexport type ModelCatalogLoadError = InstanceType<typeof ModelCatalogLoadError>;\n\nexport function projectRoot(): string {\n\treturn process.cwd();\n}\n\nexport const filename = \"models.gen.json\";\nexport function path(): string {\n\treturn resolve(process.env.CODEWORK_MODELS_FILE ?? join(projectRoot(), filename));\n}\n\nexport async function load(catalogPath = path()): Promise<GeneratedCatalog> {\n\tlet content: string;\n\ttry {\n\t\tcontent = await Filesystem.readText(catalogPath);\n\t} catch (cause) {\n\t\tconst value =\n\t\t\ttypeof cause === \"object\" && cause !== null && \"code\" in cause && typeof cause.code === \"string\"\n\t\t\t\t? cause.code\n\t\t\t\t: undefined;\n\t\tconst reason = value === \"ENOENT\" ? \"missing\" : \"unreadable\";\n\t\tthrow new ModelCatalogLoadError(\n\t\t\t{\n\t\t\t\tpath: catalogPath,\n\t\t\t\treason,\n\t\t\t\tmessage:\n\t\t\t\t\treason === \"missing\"\n\t\t\t\t\t\t? `model catalog not found at ${catalogPath}`\n\t\t\t\t\t\t: `model catalog could not be read at ${catalogPath}`,\n\t\t\t},\n\t\t\t{ cause },\n\t\t);\n\t}\n\tif (!content.trim()) {\n\t\tthrow new ModelCatalogLoadError({\n\t\t\tpath: catalogPath,\n\t\t\treason: \"empty\",\n\t\t\tmessage: `model catalog is empty at ${catalogPath}`,\n\t\t});\n\t}\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(content);\n\t\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) throw new Error(\"expected an object\");\n\t\treturn parsed as GeneratedCatalog;\n\t} catch (cause) {\n\t\tthrow new ModelCatalogLoadError(\n\t\t\t{\n\t\t\t\tpath: catalogPath,\n\t\t\t\treason: \"invalid\",\n\t\t\t\tmessage: `model catalog contains invalid json at ${catalogPath}`,\n\t\t\t},\n\t\t\t{ cause },\n\t\t);\n\t}\n}\n\nexport const data: LazyGeneratedCatalog = lazy(() => load());\n\nexport async function get(): Promise<GeneratedCatalog> {\n\treturn data();\n}\n","import Type, { type Static } from \"typebox\";\nimport { lazy } from \"../utils/lazy.ts\";\nimport * as ModelCatalog from \"./catalog.ts\";\n\n// re-export\nexport const KnownProviderEnum = ModelCatalog.KnownProviderEnum;\nexport const KnownProviderEnumSchema = ModelCatalog.KnownProviderEnumSchema;\nexport type KnownProviderEnum = ModelCatalog.KnownProviderEnum;\n\nexport const ModelCatalogLoadError = ModelCatalog.ModelCatalogLoadError;\nexport type ModelCatalogLoadError = ModelCatalog.ModelCatalogLoadError;\n\n// Common reasoning-effort levels used by adapters that expose model reasoning,\n// thinking, or deliberation controls. Protocol-specific layers can map these\n// values to native fields like OpenAI `reasoning_effort`, Anthropic `thinking`,\n// or Gemini `thinkingConfig`.\nexport const ThinkingLevelEnum = {\n\t// Disable explicit reasoning controls when the provider supports turning them off.\n\toff: \"off\",\n\t// Smallest reasoning budget/effort above off; useful for fastest low-cost responses.\n\tminimal: \"minimal\",\n\t// Light reasoning for simple tasks that still benefit from some deliberation.\n\tlow: \"low\",\n\t// Balanced default for general tasks.\n\tmedium: \"medium\",\n\t// Higher reasoning effort for complex coding, analysis, or planning.\n\thigh: \"high\",\n\t// Extra-high reasoning effort for difficult tasks when supported by the model.\n\txhigh: \"xhigh\",\n\t// Maximum provider-defined effort above xhigh when explicitly supported by the model.\n\tmax: \"max\",\n} as const;\n\nexport const ThinkingLevel = Type.Union([\n\tType.Literal(ThinkingLevelEnum.off),\n\tType.Literal(ThinkingLevelEnum.minimal),\n\tType.Literal(ThinkingLevelEnum.low),\n\tType.Literal(ThinkingLevelEnum.medium),\n\tType.Literal(ThinkingLevelEnum.high),\n\tType.Literal(ThinkingLevelEnum.xhigh),\n\tType.Literal(ThinkingLevelEnum.max),\n]);\nexport type ThinkingLevel = Static<typeof ThinkingLevel>;\n\nexport const ActiveThinkingLevel = Type.Union([\n\tType.Literal(ThinkingLevelEnum.minimal),\n\tType.Literal(ThinkingLevelEnum.low),\n\tType.Literal(ThinkingLevelEnum.medium),\n\tType.Literal(ThinkingLevelEnum.high),\n\tType.Literal(ThinkingLevelEnum.xhigh),\n\tType.Literal(ThinkingLevelEnum.max),\n]);\nexport type ActiveThinkingLevel = Static<typeof ActiveThinkingLevel>;\n\nexport const ThinkingBudgets = Type.Partial(Type.Record(ActiveThinkingLevel, Type.Number()));\nexport type ThinkingBudgets = Static<typeof ThinkingBudgets>;\n\n// Note: order of entries matters!\nconst ACTIVE_THINKING_LEVELS = [\n\tThinkingLevelEnum.minimal,\n\tThinkingLevelEnum.low,\n\tThinkingLevelEnum.medium,\n\tThinkingLevelEnum.high,\n\tThinkingLevelEnum.xhigh,\n\tThinkingLevelEnum.max,\n] as const satisfies readonly ActiveThinkingLevel[];\nconst MODEL_THINKING_LEVELS = [\n\tThinkingLevelEnum.off,\n\t...ACTIVE_THINKING_LEVELS,\n] as const satisfies readonly ThinkingLevel[];\n\nexport const ProviderInfo = Type.Object({\n\tid: Type.String(),\n\tname: Type.String(),\n\tsource: Type.Enum([\"env\", \"config\", \"custom\", \"api\", \"unknown\"]),\n\tenv: Type.Array(Type.String()),\n\tkey: Type.Optional(Type.String()), // runtime api/oauth key\n\toptions: Type.Optional(Type.Record(Type.String(), Type.Any())),\n});\nexport type ProviderInfo = Static<typeof ProviderInfo>;\n\nconst InputSchema = Type.Array(Type.Union([Type.Literal(\"text\"), Type.Literal(\"image\")]));\nconst CostRatesSchema = Type.Object({\n\tinput: Type.Number(),\n\toutput: Type.Number(),\n\tcacheRead: Type.Number(),\n\tcacheWrite: Type.Number(),\n});\nconst CostTierSchema = Type.Object({\n\t...CostRatesSchema.properties,\n\tinputTokensAbove: Type.Number(),\n});\nconst CostSchema = Type.Object({\n\t...CostRatesSchema.properties,\n\ttiers: Type.Optional(Type.Array(CostTierSchema)),\n\tserviceTierMultipliers: Type.Optional(Type.Record(Type.String(), Type.Number())),\n});\nconst SupportedProtocolsSchema = Type.Partial(\n\tType.Object({\n\t\tanthropic: KnownProviderEnumSchema,\n\t\tgoogle: KnownProviderEnumSchema,\n\t\tgoogleVertex: KnownProviderEnumSchema,\n\t\tgoogleVertexAnthropic: KnownProviderEnumSchema,\n\t\topenai: KnownProviderEnumSchema,\n\t\topenaiCompatible: KnownProviderEnumSchema,\n\t\topenaiCodex: KnownProviderEnumSchema,\n\t\topenrouter: KnownProviderEnumSchema,\n\t\txai: KnownProviderEnumSchema,\n\t}),\n);\n\nexport const APIMethodEnum = {\n\tlanguageModel: \"languageModel\",\n\tchat: \"chat\",\n\tcompletion: \"completion\",\n\tcompletionModel: \"completionModel\",\n\tmessages: \"messages\",\n\tresponses: \"responses\",\n} as const;\nexport const APIMethodEnumSchema = Type.Union([\n\tType.Literal(APIMethodEnum.languageModel),\n\tType.Literal(APIMethodEnum.chat),\n\tType.Literal(APIMethodEnum.completion),\n\tType.Literal(APIMethodEnum.completionModel),\n\tType.Literal(APIMethodEnum.messages),\n\tType.Literal(APIMethodEnum.responses),\n]);\nexport type APIMethodEnum = Static<typeof APIMethodEnumSchema>;\n\nexport const APIMetadataSchema = Type.Object({\n\tid: Type.Optional(Type.String()),\n\turl: Type.Optional(Type.String()),\n\tmethod: Type.Optional(APIMethodEnumSchema),\n});\nexport type APIMetadata = Static<typeof APIMetadataSchema>;\n\nexport const ThinkingLevelMapSchema = Type.Partial(\n\tType.Record(\n\t\tThinkingLevel, // Safe key validation\n\t\tType.Union([Type.String(), Type.Null()]), // Allowed values\n\t),\n);\nexport type ThinkingLevelMap = Static<typeof ThinkingLevelMapSchema>;\n\nexport const CompatibilitySchema = Type.Object({\n\t/** The Google protocol accepts thinking levels rather than a token budget. */\n\tsupportsThinkingLevel: Type.Optional(Type.Boolean()),\n\tsupportsToolSearch: Type.Optional(Type.Boolean()),\n\tsupportsAdditionalTools: Type.Optional(Type.Boolean()),\n\tsupportsStrictMode: Type.Optional(Type.Boolean()),\n\tsupportsOpenAIGrammarTools: Type.Optional(Type.Boolean()),\n\t/** The model takes a thinking-token budget as a top-level request field. */\n\tsupportsThinkingTokenBudget: Type.Optional(Type.Boolean()),\n\t/** Claude model that sizes its own thinking, driven by `effort` instead of a token budget. */\n\tforceAdaptiveThinking: Type.Optional(Type.Boolean()),\n\t/** Name of that field, when it is not the conventional `thinking_token_budget`. */\n\tthinkingTokenBudgetField: Type.Optional(Type.String()),\n});\nexport type Compatibility = Static<typeof CompatibilitySchema>;\n\nexport const Schema = Type.Object({\n\tid: Type.String(),\n\tname: Type.String(),\n\tprovider: ProviderInfo,\n\tbaseUrl: Type.String(),\n\treasoning: Type.Boolean(),\n\tthinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),\n\t/** Default budgets; request-level thinkingBudgets take precedence. */\n\tthinkingBudgets: Type.Optional(ThinkingBudgets),\n\tinput: InputSchema,\n\tcost: CostSchema,\n\tcontextWindow: Type.Number(),\n\tmaxTokens: Type.Number(),\n\theaders: Type.Optional(Type.Record(Type.String(), Type.String())),\n\tnpm: Type.Optional(Type.String()),\n\tapi: Type.Optional(APIMetadataSchema),\n\tproviderOptionsKey: Type.Optional(Type.String()),\n\toptions: Type.Optional(Type.Record(Type.String(), Type.Unknown())),\n\tproviderOptions: Type.Optional(Type.Record(Type.String(), Type.Unknown())),\n\tcompat: Type.Optional(CompatibilitySchema),\n\tprotocol: KnownProviderEnumSchema, // provider as the underlying protocol\n\tsupportedProtocols: Type.Optional(SupportedProtocolsSchema), // provider as the underlying supported protocols\n});\n\nexport const ExtrasSchema = Type.Object({});\n\nexport const Info = Type.Evaluate(Type.Intersect([Schema, ExtrasSchema]));\nexport type Info = Static<typeof Info>;\nexport type TModel<TProtocol extends KnownProviderEnum> = Omit<Info, \"protocol\"> & { protocol: TProtocol };\n\nexport function calculateCost(\n\tmodel: Info,\n\tusage: {\n\t\tinput: number;\n\t\toutput: number;\n\t\tcacheRead: number;\n\t\tcacheWrite: number;\n\t\tcacheWrite1h?: number;\n\t\tcost: {\n\t\t\tinput: number;\n\t\t\toutput: number;\n\t\t\tcacheRead: number;\n\t\t\tcacheWrite: number;\n\t\t\ttotal: number;\n\t\t};\n\t},\n): void {\n\tconst inputTokens = usage.input + usage.cacheRead + usage.cacheWrite;\n\tlet rates = model.cost;\n\tlet matchedThreshold = -1;\n\tfor (const tier of model.cost.tiers ?? []) {\n\t\tif (inputTokens > tier.inputTokensAbove && tier.inputTokensAbove > matchedThreshold) {\n\t\t\trates = tier;\n\t\t\tmatchedThreshold = tier.inputTokensAbove;\n\t\t}\n\t}\n\n\t// Anthropic charges 2x base input for 1h cache writes; `cost.cacheWrite` is the 5m rate.\n\tconst longWrite = usage.cacheWrite1h ?? 0;\n\tconst shortWrite = usage.cacheWrite - longWrite;\n\n\tusage.cost.input = (usage.input / 1_000_000) * rates.input;\n\tusage.cost.output = (usage.output / 1_000_000) * rates.output;\n\tusage.cost.cacheRead = (usage.cacheRead / 1_000_000) * rates.cacheRead;\n\tusage.cost.cacheWrite = (rates.cacheWrite * shortWrite + rates.input * 2 * longWrite) / 1_000_000;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n}\n\nexport type BuiltInModels = Partial<Record<string, Record<string, Info>>>;\n\nexport function normalizeInput(input?: string[]): Array<\"text\" | \"image\"> {\n\tconst normalized = new Set<\"text\" | \"image\">();\n\tfor (const modality of input ?? [\"text\"]) {\n\t\tif (modality === \"text\" || modality === \"image\") {\n\t\t\tnormalized.add(modality);\n\t\t}\n\t}\n\tif (normalized.size === 0) normalized.add(\"text\");\n\treturn [...normalized];\n}\n\nexport async function getBuiltInModels(): Promise<BuiltInModels> {\n\treturn (await ModelCatalog.get()) as BuiltInModels;\n}\n\nexport const registry = lazy(async () => {\n\tconst registry: Map<string, Map<string, Info>> = new Map();\n\tconst models = await getBuiltInModels();\n\tfor (const [provider, value] of Object.entries(models) as Array<[string, Record<string, Info>]>) {\n\t\tconst providerModels = new Map<string, Info>();\n\t\tfor (const [id, model] of Object.entries(value)) {\n\t\t\tproviderModels.set(id, model);\n\t\t}\n\t\tregistry.set(provider, providerModels);\n\t}\n\treturn registry;\n});\n\n/**\n * The key a provider's own option bag is filed under.\n *\n * Providers that speak another provider's protocol still carry their own option\n * namespace, so this is not always the protocol.\n */\n/**\n * The request-body field a model takes its thinking-token budget in, if any.\n *\n * OpenAI-compatible endpoints have no standard place for this, so each one names\n * its own field; a bare `supportsThinkingTokenBudget` means the conventional name.\n */\nexport function thinkingTokenBudgetField(model: Info): string | undefined {\n\tif (model.compat?.thinkingTokenBudgetField) return model.compat.thinkingTokenBudgetField;\n\treturn model.compat?.supportsThinkingTokenBudget ? \"thinking_token_budget\" : undefined;\n}\n\nexport function optionsKey(model: Info): string {\n\treturn model.providerOptionsKey ?? model.protocol;\n}\n\nexport function supportsProtocol(model: Info, protocol: KnownProviderEnum): boolean {\n\tif (model.protocol === protocol) return true;\n\treturn Object.values(model.supportedProtocols ?? {}).includes(protocol);\n}\n\nexport type ProviderToProtocol<TProvider extends string> = TProvider extends KnownProviderEnum\n\t? TProvider\n\t: KnownProviderEnum;\n\nexport async function getModel<\n\tTProvider extends string,\n\tTProtocol extends KnownProviderEnum = ProviderToProtocol<TProvider>,\n>(\n\tprovider: TProvider,\n\tmodel: string,\n\toverrides?: Partial<Info> & { protocol?: TProtocol },\n): Promise<TModel<TProtocol> | undefined> {\n\tconst data = await registry();\n\tconst providerModels = data.get(provider);\n\tconst result = providerModels?.get(model);\n\tif (result && overrides) {\n\t\tif (overrides.protocol && !supportsProtocol(result, overrides.protocol)) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn {\n\t\t\t...result,\n\t\t\t...overrides,\n\t\t} as TModel<TProtocol>;\n\t}\n\treturn result as TModel<TProtocol> | undefined;\n}\n\nexport async function getProviders(): Promise<string[]> {\n\tconst data = await registry();\n\treturn Array.from(data.keys());\n}\n\nexport async function getModels<TProvider extends string>(provider: TProvider): Promise<Info[]> {\n\tconst data = await registry();\n\tconst models = data.get(provider);\n\treturn models ? Array.from(models.values()) : [];\n}\n\n/**\n * Check if two models are equal by comparing both their id and provider id.\n * Returns false if either model is null or undefined.\n */\nexport function modelsAreEqual(a: Info | null | undefined, b: Info | null | undefined): boolean {\n\tif (!a || !b) return false;\n\treturn a.id === b.id && a.provider.id === b.provider.id;\n}\n\nexport function getSupportedThinkingLevels<TProtocol extends KnownProviderEnum>(\n\tmodel: TModel<TProtocol>,\n): ThinkingLevel[] {\n\tif (!model.reasoning) return [\"off\"];\n\n\treturn MODEL_THINKING_LEVELS.filter((level) => {\n\t\tconst mapped = model.thinkingLevelMap?.[level];\n\t\tif (mapped === null) return false;\n\t\tif (level === \"xhigh\" || level === \"max\") return mapped !== undefined;\n\t\treturn true;\n\t});\n}\n\nexport function clampThinkingLevel<TProtocol extends KnownProviderEnum>(\n\tmodel: TModel<TProtocol>,\n\tlevel: ThinkingLevel,\n): ThinkingLevel {\n\tconst availableLevels = getSupportedThinkingLevels(model);\n\tif (availableLevels.includes(level)) return level;\n\n\tconst requestedIndex = MODEL_THINKING_LEVELS.indexOf(level);\n\tif (requestedIndex === -1) return availableLevels[0] ?? \"off\";\n\n\t// walk up the ladder from the point and pick first supported\n\t// biased to avail more thinking, then less not round to nearest.\n\tfor (let i = requestedIndex; i < MODEL_THINKING_LEVELS.length; i++) {\n\t\tconst candidate = MODEL_THINKING_LEVELS[i]!;\n\t\tif (availableLevels.includes(candidate)) return candidate;\n\t}\n\t// otherwise walk down from the point\n\tfor (let i = requestedIndex - 1; i >= 0; i--) {\n\t\tconst candidate = MODEL_THINKING_LEVELS[i]!;\n\t\tif (availableLevels.includes(candidate)) return candidate;\n\t}\n\treturn availableLevels[0] ?? \"off\";\n}\n"],"mappings":"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"}