@kodycodes/cli 1.26.2 → 1.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. package/README.md +175 -167
  2. package/dist/add-mcp-install.d.ts +1 -1
  3. package/dist/api-token.d.ts +1 -1
  4. package/dist/auth-6ZE6QQXA.js +31 -0
  5. package/dist/auth-6ZE6QQXA.js.map +6 -0
  6. package/dist/auth-bootstrap.d.ts +1 -1
  7. package/dist/auth.d.ts +27 -3
  8. package/dist/bin.js +27 -3
  9. package/dist/bin.js.map +6 -1
  10. package/dist/capability-proxy.d.ts +1 -1
  11. package/dist/chunk-2IHISXHN.js +1413 -0
  12. package/dist/chunk-2IHISXHN.js.map +6 -0
  13. package/dist/chunk-2XPH7L2P.js +23 -0
  14. package/dist/chunk-2XPH7L2P.js.map +6 -0
  15. package/dist/chunk-3H72XY5R.js +535 -0
  16. package/dist/chunk-3H72XY5R.js.map +6 -0
  17. package/dist/chunk-46IJPEID.js +30 -0
  18. package/dist/chunk-46IJPEID.js.map +6 -0
  19. package/dist/chunk-4GIFJVGT.js +14 -0
  20. package/dist/chunk-4GIFJVGT.js.map +6 -0
  21. package/dist/chunk-5JIRHJQP.js +1016 -0
  22. package/dist/chunk-5JIRHJQP.js.map +6 -0
  23. package/dist/chunk-5ZBJAP6G.js +2005 -0
  24. package/dist/chunk-5ZBJAP6G.js.map +6 -0
  25. package/dist/chunk-6ZYUGXVW.js +26 -0
  26. package/dist/chunk-6ZYUGXVW.js.map +6 -0
  27. package/dist/chunk-7PRJ36I5.js +23 -0
  28. package/dist/chunk-7PRJ36I5.js.map +6 -0
  29. package/dist/chunk-BTL3PJ2H.js +38 -0
  30. package/dist/chunk-BTL3PJ2H.js.map +6 -0
  31. package/dist/chunk-CASGRYOF.js +21 -0
  32. package/dist/chunk-CASGRYOF.js.map +6 -0
  33. package/dist/chunk-CPS7HW4T.js +56 -0
  34. package/dist/chunk-CPS7HW4T.js.map +6 -0
  35. package/dist/chunk-CWWHR4FH.js +19 -0
  36. package/dist/chunk-CWWHR4FH.js.map +6 -0
  37. package/dist/chunk-D366STO5.js +2051 -0
  38. package/dist/chunk-D366STO5.js.map +6 -0
  39. package/dist/chunk-DW5UTJ6T.js +115 -0
  40. package/dist/chunk-DW5UTJ6T.js.map +6 -0
  41. package/dist/chunk-EJXEVGWF.js +47 -0
  42. package/dist/chunk-EJXEVGWF.js.map +6 -0
  43. package/dist/chunk-FBEZ6PZ7.js +746 -0
  44. package/dist/chunk-FBEZ6PZ7.js.map +6 -0
  45. package/dist/chunk-JOMBXQOS.js +435 -0
  46. package/dist/chunk-JOMBXQOS.js.map +6 -0
  47. package/dist/{package-local-runtime-source.js → chunk-LU7I7CQ4.js} +395 -52
  48. package/dist/chunk-LU7I7CQ4.js.map +6 -0
  49. package/dist/chunk-OZDWOZLV.js +964 -0
  50. package/dist/chunk-OZDWOZLV.js.map +6 -0
  51. package/dist/chunk-SLNAWWQK.js +64 -0
  52. package/dist/chunk-SLNAWWQK.js.map +6 -0
  53. package/dist/chunk-TUUFQYWP.js +348 -0
  54. package/dist/chunk-TUUFQYWP.js.map +6 -0
  55. package/dist/chunk-UW6AWLXX.js +43 -0
  56. package/dist/chunk-UW6AWLXX.js.map +6 -0
  57. package/dist/chunk-W2SAFAT4.js +1563 -0
  58. package/dist/chunk-W2SAFAT4.js.map +6 -0
  59. package/dist/chunk-XV6D6HSG.js +57 -0
  60. package/dist/chunk-XV6D6HSG.js.map +6 -0
  61. package/dist/chunk-Y4FOJETX.js +616 -0
  62. package/dist/chunk-Y4FOJETX.js.map +6 -0
  63. package/dist/chunk-YDWTXEKQ.js +469 -0
  64. package/dist/chunk-YDWTXEKQ.js.map +6 -0
  65. package/dist/chunk-ZILB2HWE.js +24 -0
  66. package/dist/chunk-ZILB2HWE.js.map +6 -0
  67. package/dist/cli.js +74 -1500
  68. package/dist/cli.js.map +6 -1
  69. package/dist/defaults.d.ts +1 -1
  70. package/dist/detect-running-hosts.d.ts +1 -1
  71. package/dist/dev/dev-assets.d.ts +1 -1
  72. package/dist/dev/dev-registry.d.ts +1 -1
  73. package/dist/dev/error-page.d.ts +1 -1
  74. package/dist/dev/live-reload.d.ts +2 -2
  75. package/dist/dev-command-5PDEIWOC.js +5025 -0
  76. package/dist/dev-command-5PDEIWOC.js.map +6 -0
  77. package/dist/dev-command.d.ts +1 -1
  78. package/dist/discover-login-identity.d.ts +6 -7
  79. package/dist/discover-org.d.ts +2 -3
  80. package/dist/generated/openapi-routes.d.ts +6 -0
  81. package/dist/git-credential-INB2UV4C.js +170 -0
  82. package/dist/git-credential-INB2UV4C.js.map +6 -0
  83. package/dist/install-ONEJRYZ3.js +10728 -0
  84. package/dist/install-ONEJRYZ3.js.map +6 -0
  85. package/dist/install.d.ts +1 -1
  86. package/dist/local-execute-I3BP5NEQ.js +395 -0
  87. package/dist/local-execute-I3BP5NEQ.js.map +6 -0
  88. package/dist/local-execute-auth.d.ts +2 -2
  89. package/dist/local-execute.d.ts +1 -1
  90. package/dist/local-gateway-fetch-forward.d.ts +2 -2
  91. package/dist/local-package-run-JFKNSNWM.js +23 -0
  92. package/dist/local-package-run-JFKNSNWM.js.map +6 -0
  93. package/dist/local-package-run.d.ts +2 -2
  94. package/dist/mock/mock-fetch-gateway.d.ts +2 -2
  95. package/dist/mock/mock-supported.d.ts +1 -1
  96. package/dist/mock-dep-resolve-B5ZH4U3H.js +60 -0
  97. package/dist/mock-dep-resolve-B5ZH4U3H.js.map +6 -0
  98. package/dist/mock-fetch-gateway-S2ULVFAI.js +35 -0
  99. package/dist/mock-fetch-gateway-S2ULVFAI.js.map +6 -0
  100. package/dist/mock-local-deps-2VVNJLFF.js +200 -0
  101. package/dist/mock-local-deps-2VVNJLFF.js.map +6 -0
  102. package/dist/mock-local-deps.d.ts +1 -1
  103. package/dist/mock-server-TFO7Q26H.js +22 -0
  104. package/dist/mock-server-TFO7Q26H.js.map +6 -0
  105. package/dist/oauth-browser.d.ts +42 -0
  106. package/dist/oauth-provider.d.ts +14 -19
  107. package/dist/open-api-client-SR4B7265.js +43 -0
  108. package/dist/open-api-client-SR4B7265.js.map +6 -0
  109. package/dist/open-api-client.d.ts +2 -1
  110. package/dist/org-535LB4PD.js +134 -0
  111. package/dist/org-535LB4PD.js.map +6 -0
  112. package/dist/org-resolve.d.ts +2 -0
  113. package/dist/package-app-dev.d.ts +2 -2
  114. package/dist/package-manifest-DFF6XCPV.js +15 -0
  115. package/dist/package-manifest-DFF6XCPV.js.map +6 -0
  116. package/dist/remote-execute-JN6DRFEU.js +129 -0
  117. package/dist/remote-execute-JN6DRFEU.js.map +6 -0
  118. package/dist/remote-execute.d.ts +3 -3
  119. package/dist/setup-git-MHK563LB.js +87 -0
  120. package/dist/setup-git-MHK563LB.js.map +6 -0
  121. package/dist/setup-git.d.ts +1 -1
  122. package/dist/skill-D74XVI6T.js +61 -0
  123. package/dist/skill-D74XVI6T.js.map +6 -0
  124. package/dist/store-27J4CQZ2.js +48 -0
  125. package/dist/store-27J4CQZ2.js.map +6 -0
  126. package/dist/structured-error-5MLWXYR3.js +14 -0
  127. package/dist/structured-error-5MLWXYR3.js.map +6 -0
  128. package/dist/structured-error.d.ts +1 -1
  129. package/dist/target-33ATHDUF.js +17 -0
  130. package/dist/target-33ATHDUF.js.map +6 -0
  131. package/package.json +12 -11
  132. package/skills/kody/SKILL.md +53 -50
  133. package/dist/add-mcp-install.js +0 -59
  134. package/dist/add-mcp-install.js.map +0 -1
  135. package/dist/api-token-store.js +0 -120
  136. package/dist/api-token-store.js.map +0 -1
  137. package/dist/api-token.js +0 -238
  138. package/dist/api-token.js.map +0 -1
  139. package/dist/auth-bootstrap.js +0 -373
  140. package/dist/auth-bootstrap.js.map +0 -1
  141. package/dist/auth.js +0 -386
  142. package/dist/auth.js.map +0 -1
  143. package/dist/capability-proxy.js +0 -527
  144. package/dist/capability-proxy.js.map +0 -1
  145. package/dist/credential-call-map.js +0 -155
  146. package/dist/credential-call-map.js.map +0 -1
  147. package/dist/credential-client-runtime-source.js +0 -9
  148. package/dist/credential-client-runtime-source.js.map +0 -1
  149. package/dist/credentialed-fetch-scan.js +0 -98
  150. package/dist/credentialed-fetch-scan.js.map +0 -1
  151. package/dist/defaults.js +0 -34
  152. package/dist/defaults.js.map +0 -1
  153. package/dist/detect-running-hosts.js +0 -13
  154. package/dist/detect-running-hosts.js.map +0 -1
  155. package/dist/dev/dev-assets.js +0 -202
  156. package/dist/dev/dev-assets.js.map +0 -1
  157. package/dist/dev/dev-bundler.js +0 -65
  158. package/dist/dev/dev-bundler.js.map +0 -1
  159. package/dist/dev/dev-events.js +0 -94
  160. package/dist/dev/dev-events.js.map +0 -1
  161. package/dist/dev/dev-port.js +0 -80
  162. package/dist/dev/dev-port.js.map +0 -1
  163. package/dist/dev/dev-protocol.js +0 -14
  164. package/dist/dev/dev-protocol.js.map +0 -1
  165. package/dist/dev/dev-registry.js +0 -95
  166. package/dist/dev/dev-registry.js.map +0 -1
  167. package/dist/dev/dev-watcher.js +0 -162
  168. package/dist/dev/dev-watcher.js.map +0 -1
  169. package/dist/dev/error-page.js +0 -64
  170. package/dist/dev/error-page.js.map +0 -1
  171. package/dist/dev/live-reload.js +0 -151
  172. package/dist/dev/live-reload.js.map +0 -1
  173. package/dist/dev/prebuild.js +0 -102
  174. package/dist/dev/prebuild.js.map +0 -1
  175. package/dist/dev/process-reaper.js +0 -151
  176. package/dist/dev/process-reaper.js.map +0 -1
  177. package/dist/dev/stack-trace.js +0 -56
  178. package/dist/dev/stack-trace.js.map +0 -1
  179. package/dist/dev/workerd-process.js +0 -118
  180. package/dist/dev/workerd-process.js.map +0 -1
  181. package/dist/dev-command.js +0 -676
  182. package/dist/dev-command.js.map +0 -1
  183. package/dist/discover-login-identity.js +0 -77
  184. package/dist/discover-login-identity.js.map +0 -1
  185. package/dist/discover-org.js +0 -62
  186. package/dist/discover-org.js.map +0 -1
  187. package/dist/git-credential.js +0 -147
  188. package/dist/git-credential.js.map +0 -1
  189. package/dist/help.js +0 -333
  190. package/dist/help.js.map +0 -1
  191. package/dist/host-catalog.js +0 -427
  192. package/dist/host-catalog.js.map +0 -1
  193. package/dist/host-config.js +0 -80
  194. package/dist/host-config.js.map +0 -1
  195. package/dist/http-error-body.js +0 -35
  196. package/dist/http-error-body.js.map +0 -1
  197. package/dist/install-hosts.js +0 -328
  198. package/dist/install-hosts.js.map +0 -1
  199. package/dist/install.js +0 -120
  200. package/dist/install.js.map +0 -1
  201. package/dist/invoke-passthrough.js +0 -60
  202. package/dist/invoke-passthrough.js.map +0 -1
  203. package/dist/local-bundle.js +0 -200
  204. package/dist/local-bundle.js.map +0 -1
  205. package/dist/local-execute-auth.js +0 -53
  206. package/dist/local-execute-auth.js.map +0 -1
  207. package/dist/local-execute.js +0 -338
  208. package/dist/local-execute.js.map +0 -1
  209. package/dist/local-gateway-fetch-forward.js +0 -135
  210. package/dist/local-gateway-fetch-forward.js.map +0 -1
  211. package/dist/local-host-runtime-surface.js +0 -75
  212. package/dist/local-host-runtime-surface.js.map +0 -1
  213. package/dist/local-package-graph.js +0 -405
  214. package/dist/local-package-graph.js.map +0 -1
  215. package/dist/local-package-run.js +0 -307
  216. package/dist/local-package-run.js.map +0 -1
  217. package/dist/local-runtime-bridge.js +0 -132
  218. package/dist/local-runtime-bridge.js.map +0 -1
  219. package/dist/local-runtime-source.js +0 -541
  220. package/dist/local-runtime-source.js.map +0 -1
  221. package/dist/login-callback-assets.js +0 -10
  222. package/dist/login-callback-assets.js.map +0 -1
  223. package/dist/login-callback-page.js +0 -362
  224. package/dist/login-callback-page.js.map +0 -1
  225. package/dist/mcp.d.ts +0 -34
  226. package/dist/mcp.js +0 -134
  227. package/dist/mcp.js.map +0 -1
  228. package/dist/mock/ensure-msw.js +0 -215
  229. package/dist/mock/ensure-msw.js.map +0 -1
  230. package/dist/mock/install-mock-fetch-shim.js +0 -36
  231. package/dist/mock/install-mock-fetch-shim.js.map +0 -1
  232. package/dist/mock/load-package-mocks.js +0 -136
  233. package/dist/mock/load-package-mocks.js.map +0 -1
  234. package/dist/mock/mock-fetch-gateway.js +0 -343
  235. package/dist/mock/mock-fetch-gateway.js.map +0 -1
  236. package/dist/mock/mock-gateway-fetch-shim.js +0 -104
  237. package/dist/mock/mock-gateway-fetch-shim.js.map +0 -1
  238. package/dist/mock/mock-server.js +0 -499
  239. package/dist/mock/mock-server.js.map +0 -1
  240. package/dist/mock/mock-storage.js +0 -186
  241. package/dist/mock/mock-storage.js.map +0 -1
  242. package/dist/mock/mock-supported.js +0 -63
  243. package/dist/mock/mock-supported.js.map +0 -1
  244. package/dist/mock-dep-resolve.js +0 -47
  245. package/dist/mock-dep-resolve.js.map +0 -1
  246. package/dist/mock-local-deps.js +0 -207
  247. package/dist/mock-local-deps.js.map +0 -1
  248. package/dist/network-error.js +0 -11
  249. package/dist/network-error.js.map +0 -1
  250. package/dist/node-engine.js +0 -21
  251. package/dist/node-engine.js.map +0 -1
  252. package/dist/oauth-provider.js +0 -107
  253. package/dist/oauth-provider.js.map +0 -1
  254. package/dist/onboarding-prompt.js +0 -15
  255. package/dist/onboarding-prompt.js.map +0 -1
  256. package/dist/open-api-client.js +0 -432
  257. package/dist/open-api-client.js.map +0 -1
  258. package/dist/open-url.js +0 -21
  259. package/dist/open-url.js.map +0 -1
  260. package/dist/org-resolve.js +0 -16
  261. package/dist/org-resolve.js.map +0 -1
  262. package/dist/org-slug.js +0 -11
  263. package/dist/org-slug.js.map +0 -1
  264. package/dist/org.js +0 -100
  265. package/dist/org.js.map +0 -1
  266. package/dist/package-app-dev.js +0 -922
  267. package/dist/package-app-dev.js.map +0 -1
  268. package/dist/package-collaborators.js +0 -179
  269. package/dist/package-collaborators.js.map +0 -1
  270. package/dist/package-info.js +0 -19
  271. package/dist/package-info.js.map +0 -1
  272. package/dist/package-local-runtime-source.js.map +0 -1
  273. package/dist/package-manifest.js +0 -364
  274. package/dist/package-manifest.js.map +0 -1
  275. package/dist/process-info.js +0 -14
  276. package/dist/process-info.js.map +0 -1
  277. package/dist/redact.js +0 -16
  278. package/dist/redact.js.map +0 -1
  279. package/dist/remote-execute.js +0 -108
  280. package/dist/remote-execute.js.map +0 -1
  281. package/dist/setup-git.js +0 -676
  282. package/dist/setup-git.js.map +0 -1
  283. package/dist/skill.js +0 -35
  284. package/dist/skill.js.map +0 -1
  285. package/dist/store.js +0 -597
  286. package/dist/store.js.map +0 -1
  287. package/dist/structured-error.js +0 -57
  288. package/dist/structured-error.js.map +0 -1
  289. package/dist/target.js +0 -52
  290. package/dist/target.js.map +0 -1
  291. package/dist/tool-result.js +0 -19
  292. package/dist/tool-result.js.map +0 -1
  293. package/dist/which.js +0 -22
  294. package/dist/which.js.map +0 -1
  295. package/dist/workerd-binary.js +0 -98
  296. package/dist/workerd-binary.js.map +0 -1
@@ -0,0 +1,1016 @@
1
+ import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
2
+ import {
3
+ describeNetworkError
4
+ } from "./chunk-4GIFJVGT.js";
5
+ import {
6
+ createFileBackend,
7
+ secretServiceKeyringOptions
8
+ } from "./chunk-3H72XY5R.js";
9
+ import {
10
+ apiTokenEnvVar,
11
+ cliName,
12
+ defaultApiUrl,
13
+ defaultMcpUrl,
14
+ keyringService
15
+ } from "./chunk-BTL3PJ2H.js";
16
+
17
+ // src/api-token-store.ts
18
+ import { Entry } from "@napi-rs/keyring";
19
+ import { homedir } from "node:os";
20
+ import { join } from "node:path";
21
+ function accountForApiUrl(apiUrl) {
22
+ return `cli-api-token:${new URL(apiUrl).origin}`;
23
+ }
24
+ function apiTokenFileStorePath(apiUrl, home = homedir()) {
25
+ const origin = new URL(apiUrl).host.replace(/[^a-zA-Z0-9.-]/g, "_");
26
+ const base = process.platform === "win32" ? join(process.env.APPDATA || join(home, "AppData", "Roaming"), "kody") : process.platform === "darwin" ? join(home, "Library", "Application Support", "kody") : join(process.env.XDG_CONFIG_HOME || join(home, ".config"), "kody");
27
+ return join(base, `api-token-${origin}.json`);
28
+ }
29
+ function createApiTokenKeyringBackend(apiUrl) {
30
+ const entry = new Entry(
31
+ keyringService,
32
+ accountForApiUrl(apiUrl),
33
+ secretServiceKeyringOptions
34
+ );
35
+ return {
36
+ kind: "keyring",
37
+ get() {
38
+ try {
39
+ return entry.getPassword();
40
+ } catch {
41
+ return null;
42
+ }
43
+ },
44
+ set(value) {
45
+ entry.setPassword(value);
46
+ },
47
+ delete() {
48
+ try {
49
+ return entry.deleteCredential();
50
+ } catch {
51
+ return false;
52
+ }
53
+ }
54
+ };
55
+ }
56
+ function fileBackendFor(apiUrl, resolution) {
57
+ const path = resolution?.fileStorePath?.(apiUrl) ?? apiTokenFileStorePath(apiUrl);
58
+ return createFileBackend(path);
59
+ }
60
+ function resolveApiTokenBackend(apiUrl, preferred, resolution) {
61
+ if (preferred) return preferred;
62
+ try {
63
+ return (resolution?.createKeyring ?? createApiTokenKeyringBackend)(apiUrl);
64
+ } catch {
65
+ return fileBackendFor(apiUrl, resolution);
66
+ }
67
+ }
68
+ function parseStoredApiToken(raw) {
69
+ const parsed = JSON.parse(raw);
70
+ if (parsed.version !== 1 || typeof parsed.token !== "string" || !parsed.token.startsWith("kody_at_") || typeof parsed.apiUrl !== "string" || typeof parsed.tokenId !== "string") {
71
+ throw new Error(
72
+ "Stored Kody API token is invalid. Run `kody auth bootstrap --code \u2026` again."
73
+ );
74
+ }
75
+ return parsed;
76
+ }
77
+ function readParsed(store) {
78
+ const raw = store.get();
79
+ if (!raw) return null;
80
+ return parseStoredApiToken(raw);
81
+ }
82
+ function loadStoredApiToken(apiUrl = defaultApiUrl, backend, resolution) {
83
+ const store = resolveApiTokenBackend(apiUrl, backend, resolution);
84
+ try {
85
+ const loaded = readParsed(store);
86
+ if (loaded) return loaded;
87
+ } catch (error) {
88
+ if (!(store.kind === "keyring" && !backend)) throw error;
89
+ }
90
+ if (store.kind === "keyring" && !backend) {
91
+ return readParsed(fileBackendFor(apiUrl, resolution));
92
+ }
93
+ return null;
94
+ }
95
+ function saveStoredApiToken(credentials, backend, resolution) {
96
+ const store = resolveApiTokenBackend(credentials.apiUrl, backend, resolution);
97
+ try {
98
+ store.set(JSON.stringify(credentials));
99
+ return { backend: store };
100
+ } catch (error) {
101
+ if (store.kind === "keyring" && !backend) {
102
+ const fallback = fileBackendFor(credentials.apiUrl, resolution);
103
+ fallback.set(JSON.stringify(credentials));
104
+ return { backend: fallback };
105
+ }
106
+ throw error;
107
+ }
108
+ }
109
+ function deleteStoredApiToken(apiUrl = defaultApiUrl, backend, resolution) {
110
+ const store = resolveApiTokenBackend(apiUrl, backend, resolution);
111
+ let deleted = false;
112
+ try {
113
+ deleted = store.delete();
114
+ } catch {
115
+ deleted = false;
116
+ }
117
+ if (store.kind === "keyring" && !backend) {
118
+ const file = fileBackendFor(apiUrl, resolution);
119
+ deleted = file.delete() || deleted;
120
+ }
121
+ return { deleted, backend: store };
122
+ }
123
+
124
+ // src/api-token.ts
125
+ var shortAbsoluteLifetimeMs = 24 * 60 * 60 * 1e3;
126
+ var localExecuteOauthPlatformIssueUrl = "https://github.com/kentcdodds/kody/issues/2812";
127
+ var loopbackHosts = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]", "::1"]);
128
+ function tryParseUrl(value) {
129
+ try {
130
+ return new URL(value);
131
+ } catch {
132
+ return null;
133
+ }
134
+ }
135
+ function isWorkersDevHostname(hostname) {
136
+ return hostname.endsWith(".workers.dev");
137
+ }
138
+ function isPairedApiUrl(apiUrl = defaultApiUrl, mcpUrl = defaultMcpUrl) {
139
+ const api = tryParseUrl(apiUrl);
140
+ const mcp = tryParseUrl(mcpUrl);
141
+ if (!api || !mcp) return false;
142
+ const apiIsLoopback = loopbackHosts.has(api.hostname.toLowerCase());
143
+ const mcpIsLoopback = loopbackHosts.has(mcp.hostname.toLowerCase());
144
+ if (apiIsLoopback && mcpIsLoopback) {
145
+ return ["http:", "https:"].includes(api.protocol) && ["http:", "https:"].includes(mcp.protocol);
146
+ }
147
+ if (api.protocol !== "https:" || mcp.protocol !== "https:") return false;
148
+ const apiIsWorkersDev = isWorkersDevHostname(api.hostname);
149
+ const mcpIsWorkersDev = isWorkersDevHostname(mcp.hostname);
150
+ if (apiIsWorkersDev || mcpIsWorkersDev) {
151
+ if (!apiIsWorkersDev || !mcpIsWorkersDev) return false;
152
+ const apiLabels = api.hostname.toLowerCase().split(".");
153
+ const mcpLabels = mcp.hostname.toLowerCase().split(".");
154
+ return apiLabels.length === mcpLabels.length && apiLabels.slice(1).join(".") === mcpLabels.slice(1).join(".") && apiLabels[0] === `${mcpLabels[0]}-api`;
155
+ }
156
+ return api.hostname.toLowerCase() === `api.${mcp.hostname.toLowerCase()}`;
157
+ }
158
+ function expectedPairedApiOrigin(mcpUrl) {
159
+ const mcp = tryParseUrl(mcpUrl);
160
+ if (!mcp) return "a paired API origin";
161
+ if (loopbackHosts.has(mcp.hostname.toLowerCase())) {
162
+ return "a loopback API origin";
163
+ }
164
+ const hostname = mcp.hostname.toLowerCase();
165
+ if (isWorkersDevHostname(hostname)) {
166
+ const labels = hostname.split(".");
167
+ labels[0] = `${labels[0]}-api`;
168
+ return `https://${labels.join(".")}`;
169
+ }
170
+ return `https://api.${hostname}`;
171
+ }
172
+ function readApiToken(values = {}, env = process.env) {
173
+ const token = (values.token ?? env[apiTokenEnvVar] ?? "").trim();
174
+ return token.length > 0 ? token : null;
175
+ }
176
+ function resolveScopedApiToken(input = {}) {
177
+ const token = readApiToken(input.tokenValues, input.env);
178
+ if (token) return token;
179
+ const apiUrl = input.apiUrl || defaultApiUrl;
180
+ const loadApi = input.loadApiToken ?? loadStoredApiToken;
181
+ return loadApi(apiUrl, input.apiTokenBackend, input.apiTokenResolution)?.token ?? null;
182
+ }
183
+ function isScopedApiToken(token) {
184
+ return token.startsWith("kody_at_");
185
+ }
186
+ function apiTokenMintInstructions() {
187
+ return `For CI/headless only: mint with the Kody MCP \`api\` tool \`tokenCreate\` (include \`org:execute\` plus the capability scopes this command needs, e.g. \`package:execute\` / \`integration:read\`) and pass --token or set ${apiTokenEnvVar}.`;
188
+ }
189
+ function capabilityProxyForbiddenMessage(input) {
190
+ const reason = input.serverMessage ? `: ${input.serverMessage}` : "";
191
+ return `The API token is not allowed to use CapabilityProxy (${input.code ?? "forbidden"})${reason}.
192
+ Fix: run \`npx @kodycodes/cli login\` (agents on Kody MCP: ${cliBootstrapInstructions()}; CI: tokenCreate with \`org:execute\`, passed via --token or ${apiTokenEnvVar}).`;
193
+ }
194
+ function cliBootstrapInstructions(lifetime = "short") {
195
+ return `From MCP, call \`cliCredentialBootstrap\` (MCP \`api\` / \`kody.cliCredentialBootstrap\`), then run \`npx @kodycodes/cli auth bootstrap --code <kody_bc_\u2026> --lifetime ${lifetime}\``;
196
+ }
197
+ function inferCliTokenLifetimeAlias(stored, nowMs = Date.now()) {
198
+ if (!stored) return "short";
199
+ const absoluteMs = Date.parse(stored.maxExpiresAt ?? "") || Date.parse(stored.expiresAt ?? "");
200
+ if (!Number.isFinite(absoluteMs)) return "short";
201
+ return absoluteMs - nowMs > shortAbsoluteLifetimeMs ? "long" : "short";
202
+ }
203
+ function cliBootstrapLifetimeFlags(lifetime = "short") {
204
+ return `--lifetime ${lifetime}`;
205
+ }
206
+ function cliBootstrapLifetimeMintFields(lifetime = "short") {
207
+ return { lifetime };
208
+ }
209
+ function currentStoredTokenLifetimeAlias(apiUrl = defaultApiUrl, nowMs = Date.now(), loadApiToken = loadStoredApiToken) {
210
+ return inferCliTokenLifetimeAlias(loadApiToken(apiUrl), nowMs);
211
+ }
212
+ function missingApiTokenMessage(purpose) {
213
+ return `${purpose} needs a scoped Kody API token. ${cliBootstrapInstructions()}, or ${apiTokenMintInstructions()}`;
214
+ }
215
+ function missingLocalExecuteAuthMessage(purpose = "execute --local") {
216
+ return `${purpose} needs auth. ${cliBootstrapInstructions()}; or run \`kody login\`; or for CI/headless, ${apiTokenMintInstructions()}`;
217
+ }
218
+ function missingCliAuthMessage() {
219
+ return `Not logged in, and no API token is set. ${cliBootstrapInstructions()}; or run \`kody login\` for browser OAuth (search, whoami, cloud execute, and login-backed \`execute --local\`); or for CI/headless, ${apiTokenMintInstructions()}`;
220
+ }
221
+ function rejectedOauthBearerMessage() {
222
+ return `Kody rejected the bearer from \`kody login\`: the Open API still accepts only scoped \`kody_at_\u2026\` API tokens on CapabilityProxy / package-graph (not MCP OAuth). See ${localExecuteOauthPlatformIssueUrl}. Until that lands, ${apiTokenMintInstructions()}`;
223
+ }
224
+ function readInsufficientScopeDetails(body) {
225
+ const details = isRecord(body) && isRecord(body.error) && isRecord(body.error.details) ? body.error.details : null;
226
+ if (!details) return { requiredScope: null, mintScopes: null, denial: null };
227
+ const requiredScope = readNonEmptyString(details.required_scope) ?? readNonEmptyString(details.required_permission) ?? readStringList(details.required_scopes)?.join(", ") ?? null;
228
+ return {
229
+ requiredScope,
230
+ mintScopes: readStringList(details.mint_scopes),
231
+ denial: readNonEmptyString(details.denial)
232
+ };
233
+ }
234
+ function cliBootstrapScopesCommand(scopes, lifetimeFlags = "short") {
235
+ const flags = lifetimeFlags === "short" || lifetimeFlags === "long" ? cliBootstrapLifetimeFlags(lifetimeFlags) : lifetimeFlags;
236
+ return `npx @kodycodes/cli auth bootstrap ${flags} --scopes ${scopes.join(",")}`;
237
+ }
238
+ function cliBootstrapMintCall(scopes, lifetime = "short") {
239
+ const fieldsRecord = lifetime === "short" || lifetime === "long" ? cliBootstrapLifetimeMintFields(lifetime) : lifetime;
240
+ const fields = [
241
+ ...Object.entries(fieldsRecord).map(
242
+ ([key, value]) => `${key}: ${JSON.stringify(value)}`
243
+ ),
244
+ `scopes: [${scopes.map((scope) => JSON.stringify(scope)).join(", ")}]`
245
+ ];
246
+ return `cliCredentialBootstrap({ ${fields.join(", ")} })`;
247
+ }
248
+ function insufficientScopeMessage(input) {
249
+ const required = input.requiredScope ?? null;
250
+ const lifetime = input.currentLifetime === "long" || input.currentLifetime === "short" ? input.currentLifetime : "short";
251
+ const lifetimeFlags = cliBootstrapLifetimeFlags(lifetime);
252
+ const lifetimeMint = cliBootstrapLifetimeMintFields(lifetime);
253
+ if (input.denial === "missing_permission") {
254
+ return `Kody returned insufficient_scope: your org role does not grant ${required ? `"${required}"` : "the required permission"}. A new token cannot add it; an org Owner can grant it.`;
255
+ }
256
+ if (!required) {
257
+ return `Kody returned insufficient_scope. Mint a token that includes the missing scope: run \`${cliBootstrapScopesCommand(["<scope>", "\u2026"], lifetimeFlags)}\` after \`kody login\`, or from Kody MCP call \`${cliBootstrapMintCall(["<scope>", "\u2026"], lifetimeMint)}\` and run its cli_command. Scopes replace the defaults, so list every scope you need. For CI/headless, mint with tokenCreate and pass --token or set ${apiTokenEnvVar}.`;
258
+ }
259
+ const mintScopes = input.mintScopes && input.mintScopes.length > 0 ? input.mintScopes : input.currentScopes && input.currentScopes.length > 0 ? [
260
+ .../* @__PURE__ */ new Set([...input.currentScopes, ...required.split(/,\s*/)])
261
+ ].sort() : null;
262
+ if (!mintScopes) {
263
+ return `Kody returned insufficient_scope: this token is missing "${required}". Mint a token whose scopes include "${required}" plus the ones you already use (scopes replace the defaults): run \`${cliBootstrapScopesCommand(["<current scopes>", required], lifetimeFlags)}\` after \`kody login\`, or from Kody MCP call \`${cliBootstrapMintCall(["<current scopes>", required], lifetimeMint)}\` and run its cli_command. For CI/headless, mint with tokenCreate including "${required}" and pass --token or set ${apiTokenEnvVar}.`;
264
+ }
265
+ return `Kody returned insufficient_scope: this token is missing "${required}". Mint one that includes it: run \`${cliBootstrapScopesCommand(mintScopes, lifetimeFlags)}\` after \`kody login\`, or from Kody MCP call \`${cliBootstrapMintCall(mintScopes, lifetimeMint)}\` and run its cli_command. For CI/headless, mint with tokenCreate using those scopes and pass --token or set ${apiTokenEnvVar}.`;
266
+ }
267
+ function isRecord(value) {
268
+ return value !== null && typeof value === "object" && !Array.isArray(value);
269
+ }
270
+ function readNonEmptyString(value) {
271
+ return typeof value === "string" && value.trim() ? value.trim() : null;
272
+ }
273
+ function readStringList(value) {
274
+ if (!Array.isArray(value)) return null;
275
+ const list = value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
276
+ return list.length > 0 ? list : null;
277
+ }
278
+ function featureDisabledMessage() {
279
+ return "Kody returned feature_disabled: CapabilityProxy is not enabled for this Kody account (feature flag `local-execute`). `execute --local` and token-auth cloud execute both stop here; minting another token does not bypass the flag. Browser `kody login` can still run cloud execute over MCP.";
280
+ }
281
+ function requireApiToken(values = {}, env = process.env, purpose = "this command", options = {}) {
282
+ const token = resolveScopedApiToken({
283
+ tokenValues: values,
284
+ env,
285
+ ...options
286
+ });
287
+ if (!token) throw new Error(missingApiTokenMessage(purpose));
288
+ return token;
289
+ }
290
+ function hasExplicitTokenFlag(values) {
291
+ return typeof values.token === "string" && values.token.trim().length > 0;
292
+ }
293
+
294
+ // src/credential-call-map.ts
295
+ var credentialCallMapFeature = "credential-call-map";
296
+ var credentialCallMapLimits = {
297
+ maxKeys: 32,
298
+ maxPicksPerKey: 16,
299
+ maxTextLength: 100
300
+ };
301
+ var keyPattern = new RegExp(
302
+ `^[A-Za-z0-9][A-Za-z0-9._-]{0,${credentialCallMapLimits.maxTextLength - 1}}$`
303
+ );
304
+ function parseCredentialFlag(raw) {
305
+ const eq = raw.indexOf("=");
306
+ if (eq <= 0) {
307
+ throw new Error(
308
+ `Invalid --credential ${JSON.stringify(raw)}. Use --credential key=name, --credential key=org:name, or --credential key= for none.`
309
+ );
310
+ }
311
+ const key = raw.slice(0, eq);
312
+ const value = raw.slice(eq + 1);
313
+ assertCredentialMapKey(key);
314
+ if (value === "") return { key, picks: [], empty: true };
315
+ return { key, picks: [parseCredentialPick(value)], empty: false };
316
+ }
317
+ function parseCredentialFlags(flags) {
318
+ if (!flags || flags.length === 0) return void 0;
319
+ const collected = /* @__PURE__ */ new Map();
320
+ const emptyKeys = /* @__PURE__ */ new Set();
321
+ for (const flag of flags) {
322
+ const { key, picks, empty } = parseCredentialFlag(flag);
323
+ if (empty) {
324
+ if ((collected.get(key)?.length ?? 0) > 0) {
325
+ throw new Error(
326
+ `Invalid --credential for ${key}: cannot combine an empty pick (none) with a named pick.`
327
+ );
328
+ }
329
+ emptyKeys.add(key);
330
+ collected.set(key, []);
331
+ continue;
332
+ }
333
+ if (emptyKeys.has(key)) {
334
+ throw new Error(
335
+ `Invalid --credential for ${key}: cannot combine an empty pick (none) with a named pick.`
336
+ );
337
+ }
338
+ const existing = collected.get(key) ?? [];
339
+ existing.push(...picks);
340
+ if (existing.length > credentialCallMapLimits.maxPicksPerKey) {
341
+ throw new Error(
342
+ `A credentials map takes at most ${credentialCallMapLimits.maxPicksPerKey} picks per key (${key}).`
343
+ );
344
+ }
345
+ collected.set(key, existing);
346
+ }
347
+ if (collected.size > credentialCallMapLimits.maxKeys) {
348
+ throw new Error(
349
+ `A credentials map takes at most ${credentialCallMapLimits.maxKeys} keys.`
350
+ );
351
+ }
352
+ const map = {};
353
+ for (const [key, picks] of collected) {
354
+ if (emptyKeys.has(key)) {
355
+ map[key] = [];
356
+ continue;
357
+ }
358
+ map[key] = picks.length === 1 ? picks[0] : picks;
359
+ }
360
+ return map;
361
+ }
362
+ function parseCredentialPick(value) {
363
+ const trimmed = value.trim();
364
+ const colon = trimmed.indexOf(":");
365
+ if (colon > 0) {
366
+ const prefix = trimmed.slice(0, colon);
367
+ if (prefix === "org" || prefix === "personal") {
368
+ const name = trimmed.slice(colon + 1).trim();
369
+ assertCredentialText(name, "credential name");
370
+ return { name, scope: prefix };
371
+ }
372
+ }
373
+ assertCredentialText(trimmed, "credential name");
374
+ return trimmed;
375
+ }
376
+ function assertCredentialMapKey(key) {
377
+ if (!keyPattern.test(key)) {
378
+ throw new Error(
379
+ `Invalid --credential key ${JSON.stringify(key)}. A key starts with a letter or digit and uses letters, digits, dots, underscores, or hyphens (max ${credentialCallMapLimits.maxTextLength}).`
380
+ );
381
+ }
382
+ }
383
+ function assertCredentialText(value, label) {
384
+ if (!value || value.length > credentialCallMapLimits.maxTextLength) {
385
+ throw new Error(
386
+ `Invalid --credential ${label} ${JSON.stringify(value)}. Use 1\u2013${credentialCallMapLimits.maxTextLength} characters.`
387
+ );
388
+ }
389
+ }
390
+ function sessionSupportsCredentialCallMap(features) {
391
+ return Array.isArray(features) && features.includes(credentialCallMapFeature);
392
+ }
393
+ function missingCredentialCallMapFeatureMessage() {
394
+ return "This Kody host does not support --credential yet.";
395
+ }
396
+ function formatCredentialFlagSuggestion(key, pick) {
397
+ if (typeof pick === "string") {
398
+ return `--credential ${key}=${pick}`;
399
+ }
400
+ if (Array.isArray(pick)) {
401
+ if (pick.length === 0) return `--credential ${key}=`;
402
+ return pick.map((entry) => formatCredentialFlagSuggestion(key, entry)).filter((line) => line !== null).join("\n");
403
+ }
404
+ if (pick && typeof pick === "object") {
405
+ const record = pick;
406
+ if (typeof record.name !== "string" || !record.name) return null;
407
+ if (record.scope === "org" || record.scope === "personal") {
408
+ return `--credential ${key}=${record.scope}:${record.name}`;
409
+ }
410
+ return `--credential ${key}=${record.name}`;
411
+ }
412
+ return null;
413
+ }
414
+ function formatCredentialClientError(error) {
415
+ const code = typeof error.code === "string" && error.code ? error.code : "credential_error";
416
+ const message = typeof error.message === "string" && error.message ? error.message : "The credential could not be used.";
417
+ const lines = [`${code}: ${message}`];
418
+ const retries = Array.isArray(error.retryWith) ? error.retryWith : [];
419
+ for (const entry of retries) {
420
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
421
+ const credentials = entry.credentials;
422
+ if (!credentials || typeof credentials !== "object" || Array.isArray(credentials)) {
423
+ continue;
424
+ }
425
+ for (const [key, pick] of Object.entries(
426
+ credentials
427
+ )) {
428
+ const suggestion = formatCredentialFlagSuggestion(key, pick);
429
+ if (suggestion) {
430
+ for (const line of suggestion.split("\n")) {
431
+ lines.push(` retry: ${line}`);
432
+ }
433
+ }
434
+ }
435
+ }
436
+ return lines.join("\n");
437
+ }
438
+
439
+ // src/package-info.ts
440
+ import { createRequire } from "node:module";
441
+ var require2 = createRequire(import.meta.url);
442
+ function readPackageVersion() {
443
+ try {
444
+ const pkg = require2("../package.json");
445
+ return typeof pkg.version === "string" && pkg.version.trim() ? pkg.version.trim() : "0.0.0";
446
+ } catch {
447
+ return "0.0.0";
448
+ }
449
+ }
450
+
451
+ // src/capability-proxy.ts
452
+ import { Readable } from "node:stream";
453
+ var capabilityProxySessionPath = "v1/capability-proxy/session";
454
+ var capabilityProxyCallPath = "v1/capability-proxy/call";
455
+ var capabilityProxyGatewayFetchPath = "v1/capability-proxy/gateway-fetch";
456
+ var gatewayFetchUrlHeaderName = "X-Kody-Gateway-Url";
457
+ var gatewayFetchMethodHeaderName = "X-Kody-Gateway-Method";
458
+ var gatewayFetchPackageIdHeaderName = "X-Kody-Gateway-Package-Id";
459
+ var gatewayFetchHeadersHeaderName = "X-Kody-Gateway-Headers";
460
+ var secretResolutionHeaderName = "x-kody-secret-resolution";
461
+ var capabilityProxyGatewayDeadlineMs = 5 * 6e4;
462
+ var capabilityProxyHttpTimeoutMs = 7 * 6e4;
463
+ var capabilityProxyConnectTimeoutMs = 1e4;
464
+ function nodeUsesEnvProxy(env = process.env, execArgv = process.execArgv) {
465
+ if (env.NODE_USE_ENV_PROXY === "1") return true;
466
+ const flags = [...execArgv, ...(env.NODE_OPTIONS ?? "").split(/\s+/)];
467
+ return flags.includes("--use-env-proxy");
468
+ }
469
+ var envProxyAgentMinimumNode = { 22: 21, 24: 5 };
470
+ function nodeAgentHonorsEnvProxy(version = process.versions.node) {
471
+ const [major = 0, minor = 0] = version.split(".").map(Number);
472
+ const minimumMinor = envProxyAgentMinimumNode[major];
473
+ if (minimumMinor === void 0) return major > 24;
474
+ return minor >= minimumMinor;
475
+ }
476
+ function createCapabilityProxyFetch(options = {}) {
477
+ const timeoutMs = options.timeoutMs ?? capabilityProxyHttpTimeoutMs;
478
+ const connectTimeoutMs = options.connectTimeoutMs ?? capabilityProxyConnectTimeoutMs;
479
+ const useEnvProxy = options.useEnvProxy ?? nodeUsesEnvProxy();
480
+ if (useEnvProxy && !nodeAgentHonorsEnvProxy()) {
481
+ throw new Error(
482
+ `Node ${process.version} cannot route CapabilityProxy requests through HTTP_PROXY / HTTPS_PROXY: env-proxy support needs Node 22.21 or 24.5 and later. Upgrade Node or unset NODE_USE_ENV_PROXY / --use-env-proxy.`
483
+ );
484
+ }
485
+ let transports = null;
486
+ return async (input, init = {}) => {
487
+ const url = input instanceof URL ? input : new URL(input instanceof Request ? input.url : input);
488
+ transports ??= loadTransports(useEnvProxy);
489
+ const transport = (await transports)[url.protocol];
490
+ if (!transport) {
491
+ throw new TypeError(
492
+ `Unsupported protocol for the Kody API: ${url.protocol}`
493
+ );
494
+ }
495
+ const body = init.body;
496
+ if (body !== void 0 && body !== null && typeof body !== "string") {
497
+ throw new TypeError("CapabilityProxy requests send string bodies.");
498
+ }
499
+ return new Promise((resolve, reject) => {
500
+ const request = transport.request(
501
+ url,
502
+ {
503
+ agent: transport.agent,
504
+ method: init.method ?? "GET",
505
+ headers: Object.fromEntries(new Headers(init.headers))
506
+ },
507
+ (response) => {
508
+ clearTimeout(connectTimer);
509
+ const chunks = [];
510
+ response.on("data", (chunk) => chunks.push(chunk));
511
+ response.on("error", reject);
512
+ response.on(
513
+ "end",
514
+ () => resolve(toResponse(response, Buffer.concat(chunks)))
515
+ );
516
+ }
517
+ );
518
+ const connectTimer = setTimeout(() => {
519
+ request.destroy(
520
+ new Error(
521
+ `Kody API did not connect within ${connectTimeoutMs}ms (${url.pathname}).`
522
+ )
523
+ );
524
+ }, connectTimeoutMs);
525
+ request.on("socket", (socket) => {
526
+ const clearConnectTimer = () => clearTimeout(connectTimer);
527
+ if (url.protocol === "https:") {
528
+ if (tlsHandshakePending(socket) === false) {
529
+ clearConnectTimer();
530
+ return;
531
+ }
532
+ socket.once("secureConnect", clearConnectTimer);
533
+ return;
534
+ }
535
+ if (!socket.connecting) {
536
+ clearConnectTimer();
537
+ return;
538
+ }
539
+ socket.once("connect", clearConnectTimer);
540
+ });
541
+ request.setTimeout(
542
+ timeoutMs,
543
+ () => request.destroy(
544
+ new Error(
545
+ `Kody API sent nothing for ${timeoutMs}ms (${url.pathname}).`
546
+ )
547
+ )
548
+ );
549
+ request.on("error", (error) => {
550
+ clearTimeout(connectTimer);
551
+ reject(error);
552
+ });
553
+ const { signal } = init;
554
+ if (signal) {
555
+ const abort = () => {
556
+ clearTimeout(connectTimer);
557
+ request.destroy(abortError(signal.reason));
558
+ };
559
+ if (signal.aborted) {
560
+ abort();
561
+ } else {
562
+ signal.addEventListener("abort", abort, { once: true });
563
+ request.once(
564
+ "close",
565
+ () => signal.removeEventListener("abort", abort)
566
+ );
567
+ }
568
+ }
569
+ request.end(body ?? void 0);
570
+ });
571
+ };
572
+ }
573
+ async function loadTransports(useEnvProxy) {
574
+ const [http, https] = await Promise.all([
575
+ import("node:http"),
576
+ import("node:https")
577
+ ]);
578
+ const agentOptions = {
579
+ keepAlive: true,
580
+ ...useEnvProxy ? { proxyEnv: process.env } : {}
581
+ };
582
+ return {
583
+ "http:": {
584
+ agent: unrefFreeSockets(new http.Agent(agentOptions)),
585
+ request: http.request
586
+ },
587
+ "https:": {
588
+ agent: unrefFreeSockets(new https.Agent(agentOptions)),
589
+ request: https.request
590
+ }
591
+ };
592
+ }
593
+ function unrefFreeSockets(agent) {
594
+ agent.on("free", (socket) => {
595
+ socket.unref();
596
+ });
597
+ return agent;
598
+ }
599
+ function tlsHandshakePending(socket) {
600
+ if (!("secureConnecting" in socket)) return null;
601
+ return socket.secureConnecting;
602
+ }
603
+ function abortError(reason) {
604
+ if (reason instanceof Error) return reason;
605
+ return new DOMException(
606
+ typeof reason === "string" ? reason : "This operation was aborted",
607
+ "AbortError"
608
+ );
609
+ }
610
+ function toResponse(response, body) {
611
+ const headers = new Headers();
612
+ for (const [name, value] of Object.entries(response.headers)) {
613
+ if (Array.isArray(value)) {
614
+ for (const entry of value) headers.append(name, entry);
615
+ } else if (value !== void 0) {
616
+ headers.set(name, value);
617
+ }
618
+ }
619
+ const status = response.statusCode ?? 0;
620
+ const bodyless = status === 204 || status === 205 || status === 304;
621
+ return new Response(bodyless ? null : body, {
622
+ status,
623
+ statusText: response.statusMessage ?? "",
624
+ headers
625
+ });
626
+ }
627
+ var defaultCapabilityProxyFetch = null;
628
+ function capabilityProxyFetch() {
629
+ defaultCapabilityProxyFetch ??= createCapabilityProxyFetch();
630
+ return defaultCapabilityProxyFetch;
631
+ }
632
+ var CapabilityProxyError = class extends Error {
633
+ status;
634
+ code;
635
+ constructor(message, options = {}) {
636
+ super(message);
637
+ this.name = "CapabilityProxyError";
638
+ this.status = options.status ?? null;
639
+ this.code = options.code ?? null;
640
+ }
641
+ };
642
+ var loopbackHosts2 = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
643
+ function assertTokenSafeApiUrl(apiUrl) {
644
+ let url;
645
+ try {
646
+ url = new URL(apiUrl);
647
+ } catch {
648
+ throw new Error(`Invalid Kody API URL: ${apiUrl}`);
649
+ }
650
+ if (url.protocol === "https:") return;
651
+ if (url.protocol === "http:" && loopbackHosts2.has(url.hostname)) return;
652
+ throw new Error(
653
+ `Refusing to send the API token to ${url.origin}: use https (plain http is only allowed for localhost).`
654
+ );
655
+ }
656
+ function capabilityProxyUrl(apiUrl, path) {
657
+ const base = apiUrl.endsWith("/") ? apiUrl : `${apiUrl}/`;
658
+ return new URL(path, base);
659
+ }
660
+ function withOrgQuery(url, org) {
661
+ if (org) url.searchParams.set("org", org);
662
+ return url;
663
+ }
664
+ async function openCapabilityProxySession(input) {
665
+ const url = withOrgQuery(
666
+ capabilityProxyUrl(input.apiUrl, capabilityProxySessionPath),
667
+ input.org
668
+ );
669
+ const response = await send(input, url, { method: "GET" });
670
+ const body = await readJson(response);
671
+ if (!response.ok) {
672
+ throw describeFailure(response.status, body, url, "session", input.token);
673
+ }
674
+ const record = isRecord2(body) ? body : {};
675
+ return {
676
+ scopes: Array.isArray(record.scopes) ? record.scopes.filter(
677
+ (scope) => typeof scope === "string"
678
+ ) : [],
679
+ expiresAt: typeof record.expiresAt === "string" ? record.expiresAt : null,
680
+ features: Array.isArray(record.features) ? record.features.filter(
681
+ (feature) => typeof feature === "string"
682
+ ) : []
683
+ };
684
+ }
685
+ async function callCapabilityProxy(input) {
686
+ const url = withOrgQuery(
687
+ capabilityProxyUrl(input.apiUrl, capabilityProxyCallPath),
688
+ input.org
689
+ );
690
+ const payload = { path: input.path, args: input.args };
691
+ if (input.conversationId !== void 0)
692
+ payload.conversationId = input.conversationId;
693
+ if (input.credentials !== void 0) payload.credentials = input.credentials;
694
+ const response = await send(input, url, {
695
+ method: "POST",
696
+ headers: { "content-type": "application/json" },
697
+ body: JSON.stringify(payload)
698
+ });
699
+ const body = await readJson(response);
700
+ if (!response.ok) {
701
+ throw describeFailure(response.status, body, url, "call", input.token);
702
+ }
703
+ const failure = readErrorBody(body);
704
+ if (failure) {
705
+ throw new CapabilityProxyError(failure.message, {
706
+ status: response.status,
707
+ code: failure.code
708
+ });
709
+ }
710
+ return isRecord2(body) ? body.result : void 0;
711
+ }
712
+ async function callCapabilityProxyGatewayFetchStream(input) {
713
+ assertTokenSafeApiUrl(input.apiUrl);
714
+ const url = withOrgQuery(
715
+ capabilityProxyUrl(input.apiUrl, capabilityProxyGatewayFetchPath),
716
+ input.org
717
+ );
718
+ const timeoutMs = capabilityProxyHttpTimeoutMs;
719
+ const connectTimeoutMs = capabilityProxyConnectTimeoutMs;
720
+ const useEnvProxy = nodeUsesEnvProxy();
721
+ if (useEnvProxy && !nodeAgentHonorsEnvProxy()) {
722
+ throw new Error(
723
+ `Node ${process.version} cannot route CapabilityProxy requests through HTTP_PROXY / HTTPS_PROXY: env-proxy support needs Node 22.21 or 24.5 and later. Upgrade Node or unset NODE_USE_ENV_PROXY / --use-env-proxy.`
724
+ );
725
+ }
726
+ const transports = await loadTransports(useEnvProxy);
727
+ const transport = transports[url.protocol];
728
+ if (!transport) {
729
+ throw new TypeError(
730
+ `Unsupported protocol for the Kody API: ${url.protocol}`
731
+ );
732
+ }
733
+ const headers = {
734
+ accept: "*/*",
735
+ authorization: `Bearer ${input.token}`,
736
+ "user-agent": `${cliName}/${readPackageVersion()}`,
737
+ [gatewayFetchUrlHeaderName]: input.gateway.url
738
+ };
739
+ if (input.gateway.method) {
740
+ headers[gatewayFetchMethodHeaderName] = input.gateway.method;
741
+ }
742
+ if (input.gateway.packageId) {
743
+ headers[gatewayFetchPackageIdHeaderName] = input.gateway.packageId;
744
+ }
745
+ if (input.gateway.headers && Object.keys(input.gateway.headers).length > 0) {
746
+ headers[gatewayFetchHeadersHeaderName] = JSON.stringify(
747
+ input.gateway.headers
748
+ );
749
+ }
750
+ if (input.gateway.secretResolution) {
751
+ headers[secretResolutionHeaderName] = input.gateway.secretResolution;
752
+ }
753
+ if (input.gateway.contentType) {
754
+ headers["content-type"] = input.gateway.contentType;
755
+ }
756
+ if (input.contentLength) {
757
+ headers["content-length"] = input.contentLength;
758
+ }
759
+ const signal = input.signal;
760
+ return await new Promise((resolve, reject) => {
761
+ const request = transport.request(
762
+ url,
763
+ {
764
+ agent: transport.agent,
765
+ method: "POST",
766
+ headers
767
+ },
768
+ (response) => {
769
+ clearTimeout(connectTimer);
770
+ resolve(nodeIncomingToWebResponse(response));
771
+ }
772
+ );
773
+ const connectTimer = setTimeout(() => {
774
+ request.destroy(
775
+ new Error(
776
+ `Kody API did not connect within ${connectTimeoutMs}ms (${url.pathname}).`
777
+ )
778
+ );
779
+ }, connectTimeoutMs);
780
+ request.on("socket", (socket) => {
781
+ const clearConnectTimer = () => clearTimeout(connectTimer);
782
+ if (url.protocol === "https:") {
783
+ if (tlsHandshakePending(socket) === false) {
784
+ clearConnectTimer();
785
+ return;
786
+ }
787
+ socket.once("secureConnect", clearConnectTimer);
788
+ return;
789
+ }
790
+ if (!socket.connecting) {
791
+ clearConnectTimer();
792
+ return;
793
+ }
794
+ socket.once("connect", clearConnectTimer);
795
+ });
796
+ request.setTimeout(
797
+ timeoutMs,
798
+ () => request.destroy(
799
+ new Error(
800
+ `Kody API sent nothing for ${timeoutMs}ms (${url.pathname}).`
801
+ )
802
+ )
803
+ );
804
+ request.on("error", (error) => {
805
+ clearTimeout(connectTimer);
806
+ reject(
807
+ error instanceof CapabilityProxyError ? error : new CapabilityProxyError(
808
+ `Could not reach the Kody API at ${url.origin} (${describeNetworkError(error)}). Check --api-url / KODY_API_URL and your network.`
809
+ )
810
+ );
811
+ });
812
+ if (signal) {
813
+ const abort = () => {
814
+ clearTimeout(connectTimer);
815
+ request.destroy(abortError(signal.reason));
816
+ };
817
+ if (signal.aborted) {
818
+ abort();
819
+ } else {
820
+ signal.addEventListener("abort", abort, { once: true });
821
+ request.once("close", () => signal.removeEventListener("abort", abort));
822
+ }
823
+ }
824
+ if (input.body) {
825
+ input.body.pipe(request);
826
+ input.body.on("error", (error) => {
827
+ clearTimeout(connectTimer);
828
+ request.destroy(error);
829
+ });
830
+ } else {
831
+ request.end();
832
+ }
833
+ });
834
+ }
835
+ function nodeIncomingToWebResponse(response) {
836
+ const headers = new Headers();
837
+ for (const [name, value] of Object.entries(response.headers)) {
838
+ if (Array.isArray(value)) {
839
+ for (const entry of value) headers.append(name, entry);
840
+ } else if (value !== void 0) {
841
+ headers.set(name, value);
842
+ }
843
+ }
844
+ const status = response.statusCode ?? 0;
845
+ const bodyless = status === 101 || status === 103 || status === 204 || status === 205 || status === 304;
846
+ if (bodyless) {
847
+ response.resume();
848
+ return new Response(null, {
849
+ status,
850
+ statusText: response.statusMessage ?? "",
851
+ headers
852
+ });
853
+ }
854
+ return new Response(
855
+ Readable.toWeb(response),
856
+ {
857
+ status,
858
+ statusText: response.statusMessage ?? "",
859
+ headers
860
+ }
861
+ );
862
+ }
863
+ async function checkCredentialCallMap(input) {
864
+ const args = {};
865
+ if (input.strict === true) args.strict = true;
866
+ if (input.packageId !== void 0) args.packageId = input.packageId;
867
+ const result = await callCapabilityProxy({
868
+ apiUrl: input.apiUrl,
869
+ token: input.token,
870
+ fetchFn: input.fetchFn,
871
+ signal: input.signal,
872
+ path: ["kody", "credentialClientCheck"],
873
+ args: [args],
874
+ conversationId: input.conversationId,
875
+ credentials: input.credentials
876
+ });
877
+ if (!isRecord2(result)) {
878
+ throw new CapabilityProxyError(
879
+ "credentialClientCheck returned an unexpected result."
880
+ );
881
+ }
882
+ if (result.ok === false) {
883
+ const error = isRecord2(result.error) ? result.error : {};
884
+ const code = typeof error.code === "string" ? error.code : "credential_error";
885
+ throw new CapabilityProxyError(formatCredentialClientError(error), { code });
886
+ }
887
+ const value = isRecord2(result.value) ? result.value : null;
888
+ const warnings = Array.isArray(value?.warnings) ? value.warnings.filter(
889
+ (warning) => typeof warning === "string"
890
+ ) : [];
891
+ return { warnings };
892
+ }
893
+ async function send(input, url, init) {
894
+ const fetchFn = input.fetchFn ?? capabilityProxyFetch();
895
+ try {
896
+ return await fetchFn(url, {
897
+ ...init,
898
+ signal: input.signal,
899
+ headers: {
900
+ ...init.headers,
901
+ accept: "application/json",
902
+ authorization: `Bearer ${input.token}`,
903
+ "user-agent": `${cliName}/${readPackageVersion()}`
904
+ }
905
+ });
906
+ } catch (error) {
907
+ const reason = describeNetworkError(error);
908
+ throw new CapabilityProxyError(
909
+ `Could not reach the Kody API at ${url.origin} (${reason}). Check --api-url / KODY_API_URL and your network.`
910
+ );
911
+ }
912
+ }
913
+ async function readJson(response) {
914
+ const text = await response.text();
915
+ if (!text) return null;
916
+ try {
917
+ return JSON.parse(text);
918
+ } catch {
919
+ return text;
920
+ }
921
+ }
922
+ function readErrorBody(body) {
923
+ if (!isRecord2(body) || body.error == null) return null;
924
+ const { error } = body;
925
+ if (typeof error === "string") return { code: null, message: error };
926
+ if (isRecord2(error)) {
927
+ const code = typeof error.code === "string" ? error.code : null;
928
+ const message = typeof error.message === "string" ? error.message : code ?? JSON.stringify(error);
929
+ return { code, message };
930
+ }
931
+ return { code: null, message: String(error) };
932
+ }
933
+ function describeFailure(status, body, url, stage, token) {
934
+ const failure = readErrorBody(body);
935
+ const code = failure?.code ?? null;
936
+ const detail = failure?.message ? ` Server said: ${failure.message}` : "";
937
+ if (status === 401) {
938
+ const message = isScopedApiToken(token) ? `Kody rejected the API token (expired, revoked, or malformed). Mint a fresh scoped token and pass it with --token or ${apiTokenEnvVar}.${detail}` : `${rejectedOauthBearerMessage()}${detail}`;
939
+ return new CapabilityProxyError(message, { status, code });
940
+ }
941
+ if (code === "feature_disabled") {
942
+ return new CapabilityProxyError(`${featureDisabledMessage()}${detail}`, {
943
+ status,
944
+ code
945
+ });
946
+ }
947
+ if (code === "insufficient_scope") {
948
+ return new CapabilityProxyError(
949
+ `${insufficientScopeMessage({
950
+ ...readInsufficientScopeDetails(body),
951
+ currentLifetime: currentStoredTokenLifetimeAlias(url.origin)
952
+ })}${detail}`,
953
+ { status, code }
954
+ );
955
+ }
956
+ if (status === 403 && stage === "session") {
957
+ return new CapabilityProxyError(
958
+ capabilityProxyForbiddenMessage({
959
+ code,
960
+ serverMessage: failure?.message
961
+ }),
962
+ { status, code }
963
+ );
964
+ }
965
+ if (status === 404 && stage === "session") {
966
+ return new CapabilityProxyError(
967
+ `CapabilityProxy was not found at ${url.href}. Local execute may not be deployed on this Kody API yet; check --api-url / KODY_API_URL.`,
968
+ { status, code }
969
+ );
970
+ }
971
+ return new CapabilityProxyError(
972
+ failure?.message ?? `Kody API request failed with HTTP ${status} (${url.pathname}).`,
973
+ { status, code }
974
+ );
975
+ }
976
+ function isRecord2(value) {
977
+ return value !== null && typeof value === "object" && !Array.isArray(value);
978
+ }
979
+
980
+ export {
981
+ loadStoredApiToken,
982
+ saveStoredApiToken,
983
+ deleteStoredApiToken,
984
+ isPairedApiUrl,
985
+ expectedPairedApiOrigin,
986
+ readApiToken,
987
+ resolveScopedApiToken,
988
+ isScopedApiToken,
989
+ capabilityProxyForbiddenMessage,
990
+ currentStoredTokenLifetimeAlias,
991
+ missingLocalExecuteAuthMessage,
992
+ missingCliAuthMessage,
993
+ rejectedOauthBearerMessage,
994
+ readInsufficientScopeDetails,
995
+ cliBootstrapMintCall,
996
+ insufficientScopeMessage,
997
+ featureDisabledMessage,
998
+ requireApiToken,
999
+ hasExplicitTokenFlag,
1000
+ parseCredentialFlags,
1001
+ sessionSupportsCredentialCallMap,
1002
+ missingCredentialCallMapFeatureMessage,
1003
+ readPackageVersion,
1004
+ gatewayFetchUrlHeaderName,
1005
+ gatewayFetchMethodHeaderName,
1006
+ gatewayFetchPackageIdHeaderName,
1007
+ gatewayFetchHeadersHeaderName,
1008
+ secretResolutionHeaderName,
1009
+ assertTokenSafeApiUrl,
1010
+ capabilityProxyUrl,
1011
+ openCapabilityProxySession,
1012
+ callCapabilityProxy,
1013
+ callCapabilityProxyGatewayFetchStream,
1014
+ checkCredentialCallMap
1015
+ };
1016
+ //# sourceMappingURL=chunk-5JIRHJQP.js.map