@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,964 @@
1
+ import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
2
+ import {
3
+ which
4
+ } from "./chunk-6ZYUGXVW.js";
5
+ import {
6
+ OpenApiError,
7
+ openApiGet,
8
+ openApiRequest
9
+ } from "./chunk-W2SAFAT4.js";
10
+ import {
11
+ assertTokenSafeApiUrl,
12
+ capabilityProxyUrl,
13
+ deleteStoredApiToken,
14
+ loadStoredApiToken,
15
+ readPackageVersion,
16
+ saveStoredApiToken
17
+ } from "./chunk-5JIRHJQP.js";
18
+ import {
19
+ describeNetworkError
20
+ } from "./chunk-4GIFJVGT.js";
21
+ import {
22
+ apiTokenEnvVar,
23
+ cliName,
24
+ defaultApiUrl,
25
+ defaultMcpUrl
26
+ } from "./chunk-BTL3PJ2H.js";
27
+
28
+ // src/setup-git.ts
29
+ import { spawnSync } from "node:child_process";
30
+ import { createRequire } from "node:module";
31
+
32
+ // src/http-error-body.ts
33
+ var nonJsonErrorBodyMaxChars = 200;
34
+ function summarizeNonJsonErrorBody(text) {
35
+ const trimmed = text.trim();
36
+ const looksLikeHtml = /^<(?:!doctype|html|head|body)\b/i.test(trimmed);
37
+ const title = looksLikeHtml ? trimmed.match(/<title[^>]*>([\s\S]*?)<\/title>/i)?.[1] : void 0;
38
+ const excerpt = collapseWhitespace(
39
+ looksLikeHtml ? stripHtml(title?.trim() ? title : trimmed) : trimmed
40
+ );
41
+ const kind = looksLikeHtml ? "HTML" : "non-JSON";
42
+ const bytes = Buffer.byteLength(text);
43
+ if (excerpt.length <= nonJsonErrorBodyMaxChars && !looksLikeHtml)
44
+ return excerpt;
45
+ const shortened = excerpt.length > nonJsonErrorBodyMaxChars ? `${excerpt.slice(0, nonJsonErrorBodyMaxChars).trimEnd()}\u2026` : excerpt;
46
+ return `${shortened ? `${shortened} ` : ""}(${kind} response, ${bytes} bytes; check --api-url / KODY_API_URL points at the Kody API host)`;
47
+ }
48
+ function stripHtml(html) {
49
+ return html.replace(/<(script|style)\b[\s\S]*?<\/\1>/gi, " ").replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&amp;/g, "&");
50
+ }
51
+ function collapseWhitespace(text) {
52
+ return text.replace(/\s+/g, " ").trim();
53
+ }
54
+
55
+ // src/auth-bootstrap.ts
56
+ var cliBootstrapCodePrefix = "kody_bc_";
57
+ var bootstrapCodePattern = /^kody_bc_([a-z0-9]{16})_([A-Za-z0-9_-]{32})$/;
58
+ var bootstrapRedeemPath = "v1/tokens/bootstrap/redeem";
59
+ var cliTokenLifetimePolicy = {
60
+ minIdleTtlSeconds: 60,
61
+ /** Idle timeout at most 14 days. */
62
+ maxIdleTtlSeconds: 14 * 24 * 60 * 60,
63
+ /** Absolute lifetime at most 3 months. */
64
+ maxMaxLifetimeSeconds: 90 * 24 * 60 * 60
65
+ };
66
+ var cliTokenLifetimeAliases = {
67
+ short: {
68
+ idleTtlSeconds: 60 * 60,
69
+ maxLifetimeSeconds: 24 * 60 * 60
70
+ },
71
+ long: {
72
+ idleTtlSeconds: cliTokenLifetimePolicy.maxIdleTtlSeconds,
73
+ maxLifetimeSeconds: cliTokenLifetimePolicy.maxMaxLifetimeSeconds
74
+ }
75
+ };
76
+ function parseCliBootstrapCode(value) {
77
+ const match = bootstrapCodePattern.exec(value.trim());
78
+ if (!match) return null;
79
+ const [, codeId, secret] = match;
80
+ if (!codeId || !secret) return null;
81
+ return { codeId, secret };
82
+ }
83
+ function assertCliBootstrapCode(code) {
84
+ const trimmed = code.trim();
85
+ if (!parseCliBootstrapCode(trimmed)) {
86
+ throw new Error(
87
+ `Invalid bootstrap code. Expected a one-shot ${cliBootstrapCodePrefix}\u2026 from cliCredentialBootstrap (MCP api / kody.cliCredentialBootstrap).`
88
+ );
89
+ }
90
+ return trimmed;
91
+ }
92
+ function cliTokenLifetimeMissingError() {
93
+ return `Token lifetime is required. Pass --lifetime short|long, or both --idle-ttl-seconds <n> and --max-lifetime-seconds <n> (idle ${cliTokenLifetimePolicy.minIdleTtlSeconds}-${cliTokenLifetimePolicy.maxIdleTtlSeconds}s, max age up to ${cliTokenLifetimePolicy.maxMaxLifetimeSeconds}s). Single-task agents should use --lifetime short.`;
94
+ }
95
+ function resolveCliTokenLifetime(input) {
96
+ const aliasRaw = typeof input.lifetime === "string" ? input.lifetime.trim() : "";
97
+ const hasAlias = aliasRaw.length > 0;
98
+ const hasIdle = input.idleTtlSeconds !== void 0;
99
+ const hasMax = input.maxLifetimeSeconds !== void 0;
100
+ if (!hasAlias && !hasIdle && !hasMax) {
101
+ throw new Error(cliTokenLifetimeMissingError());
102
+ }
103
+ if (hasAlias && (hasIdle || hasMax)) {
104
+ throw new Error(
105
+ "Pass --lifetime short|long, or both --idle-ttl-seconds and --max-lifetime-seconds, not both forms."
106
+ );
107
+ }
108
+ if (hasAlias) {
109
+ if (!(aliasRaw in cliTokenLifetimeAliases)) {
110
+ throw new Error(
111
+ `--lifetime must be short or long (got ${JSON.stringify(aliasRaw)}).`
112
+ );
113
+ }
114
+ const lifetime = aliasRaw;
115
+ const resolved = cliTokenLifetimeAliases[lifetime];
116
+ return {
117
+ kind: "alias",
118
+ lifetime,
119
+ idleTtlSeconds: resolved.idleTtlSeconds,
120
+ maxLifetimeSeconds: resolved.maxLifetimeSeconds
121
+ };
122
+ }
123
+ if (!hasIdle || !hasMax) {
124
+ throw new Error(
125
+ "When not using --lifetime short|long, both --idle-ttl-seconds and --max-lifetime-seconds are required."
126
+ );
127
+ }
128
+ const idleTtlSeconds = readRequiredInteger({
129
+ value: input.idleTtlSeconds,
130
+ min: cliTokenLifetimePolicy.minIdleTtlSeconds,
131
+ max: cliTokenLifetimePolicy.maxIdleTtlSeconds,
132
+ field: "--idle-ttl-seconds"
133
+ });
134
+ const maxLifetimeSeconds = readRequiredInteger({
135
+ value: input.maxLifetimeSeconds,
136
+ min: idleTtlSeconds,
137
+ max: cliTokenLifetimePolicy.maxMaxLifetimeSeconds,
138
+ field: "--max-lifetime-seconds"
139
+ });
140
+ return {
141
+ kind: "explicit",
142
+ idleTtlSeconds,
143
+ maxLifetimeSeconds
144
+ };
145
+ }
146
+ function bootstrapRedeemRequestBody(code, lifetime) {
147
+ if (lifetime.kind === "alias") {
148
+ return { code, lifetime: lifetime.lifetime };
149
+ }
150
+ return {
151
+ code,
152
+ idle_ttl_seconds: lifetime.idleTtlSeconds,
153
+ max_lifetime_seconds: lifetime.maxLifetimeSeconds
154
+ };
155
+ }
156
+ function parseCliLifetimeSecondsFlag(raw, flag) {
157
+ if (raw === void 0) return void 0;
158
+ const trimmed = raw.trim();
159
+ if (!/^-?\d+$/.test(trimmed)) {
160
+ throw new Error(`${flag} must be an integer.`);
161
+ }
162
+ return Number(trimmed);
163
+ }
164
+ function resolveMintedRedeemLifetime(minted) {
165
+ const maxLifetimeSeconds = minted.max_lifetime_seconds;
166
+ const idleTtlSeconds = Math.min(minted.idle_ttl_seconds, maxLifetimeSeconds);
167
+ return {
168
+ kind: "explicit",
169
+ idleTtlSeconds,
170
+ maxLifetimeSeconds
171
+ };
172
+ }
173
+ async function redeemBootstrapCode(input) {
174
+ const code = assertCliBootstrapCode(input.code);
175
+ const lifetime = input.trustedMintLifetime ? resolveMintedRedeemLifetime(input.trustedMintLifetime) : resolveCliTokenLifetime({
176
+ lifetime: input.lifetime,
177
+ idleTtlSeconds: input.idleTtlSeconds,
178
+ maxLifetimeSeconds: input.maxLifetimeSeconds
179
+ });
180
+ const apiUrl = input.apiUrl || defaultApiUrl;
181
+ assertTokenSafeApiUrl(apiUrl);
182
+ const url = capabilityProxyUrl(apiUrl, bootstrapRedeemPath);
183
+ const fetchFn = input.fetchFn ?? fetch;
184
+ let response;
185
+ try {
186
+ response = await fetchFn(url, {
187
+ method: "POST",
188
+ headers: {
189
+ accept: "application/json",
190
+ "content-type": "application/json",
191
+ "user-agent": `${cliName}/${readPackageVersion()}`
192
+ },
193
+ body: JSON.stringify(bootstrapRedeemRequestBody(code, lifetime))
194
+ });
195
+ } catch (error) {
196
+ const reason = describeNetworkError(error);
197
+ throw new Error(
198
+ `Could not reach the Kody API at ${url.origin} (${reason}). Check --api-url / KODY_API_URL and your network.`
199
+ );
200
+ }
201
+ const body = await readJson(response);
202
+ if (!response.ok) {
203
+ throw describeRedeemFailure(response.status, body, url);
204
+ }
205
+ return parseRedeemResponse(body);
206
+ }
207
+ function storedApiTokenFromRedeem(input) {
208
+ const token = input.redeemed.token.trim();
209
+ if (!token.startsWith("kody_at_")) {
210
+ throw new Error(
211
+ "Bootstrap redeem did not return a scoped kody_at_\u2026 API token."
212
+ );
213
+ }
214
+ return {
215
+ version: 1,
216
+ apiUrl: input.apiUrl,
217
+ token,
218
+ tokenId: input.redeemed.id,
219
+ ...input.redeemed.name ? { name: input.redeemed.name } : {},
220
+ ...Array.isArray(input.redeemed.scopes) ? { scopes: input.redeemed.scopes } : {},
221
+ expiresAt: input.redeemed.expires_at ?? null,
222
+ maxExpiresAt: input.redeemed.max_expires_at ?? null,
223
+ createdVia: input.redeemed.created_via ?? "cli-bootstrap"
224
+ };
225
+ }
226
+ async function authBootstrap(input) {
227
+ const apiUrl = input.apiUrl || defaultApiUrl;
228
+ const redeemed = await redeemBootstrapCode({
229
+ code: input.code,
230
+ lifetime: input.lifetime,
231
+ idleTtlSeconds: input.idleTtlSeconds,
232
+ maxLifetimeSeconds: input.maxLifetimeSeconds,
233
+ apiUrl,
234
+ fetchFn: input.fetchFn
235
+ });
236
+ const stored = storedApiTokenFromRedeem({ apiUrl, redeemed });
237
+ const saved = saveStoredApiToken(stored, input.backend, input.resolution);
238
+ return {
239
+ stored,
240
+ backendKind: saved.backend.kind,
241
+ ...saved.backend.path ? { backendPath: saved.backend.path } : {}
242
+ };
243
+ }
244
+ var cliCredentialBootstrapOperationId = "cliCredentialBootstrap";
245
+ function parseCliScopesFlag(raw) {
246
+ if (raw === void 0) return void 0;
247
+ const scopes = [
248
+ ...new Set(
249
+ raw.split(/[\s,]+/).map((scope) => scope.trim()).filter(Boolean)
250
+ )
251
+ ];
252
+ if (scopes.length === 0) {
253
+ throw new Error(
254
+ "--scopes needs at least one scope (e.g. --scopes org:execute,package:write)."
255
+ );
256
+ }
257
+ return scopes;
258
+ }
259
+ function bootstrapMintParams(scopes, lifetime) {
260
+ return {
261
+ scopes: [...scopes],
262
+ ...bootstrapMintLifetimeFields(lifetime)
263
+ };
264
+ }
265
+ function bootstrapMintLifetimeFields(lifetime) {
266
+ return lifetime.kind === "alias" ? { lifetime: lifetime.lifetime } : {
267
+ idle_ttl_seconds: lifetime.idleTtlSeconds,
268
+ max_lifetime_seconds: lifetime.maxLifetimeSeconds
269
+ };
270
+ }
271
+ function parseBootstrapMintResponse(body) {
272
+ if (!isRecord(body) || typeof body.bootstrap_code !== "string" || typeof body.idle_ttl_seconds !== "number" || typeof body.max_lifetime_seconds !== "number") {
273
+ throw new Error("cliCredentialBootstrap returned an unexpected response.");
274
+ }
275
+ return {
276
+ bootstrap_code: body.bootstrap_code,
277
+ scopes: Array.isArray(body.scopes) ? body.scopes.filter(
278
+ (scope) => typeof scope === "string"
279
+ ) : [],
280
+ idle_ttl_seconds: body.idle_ttl_seconds,
281
+ max_lifetime_seconds: body.max_lifetime_seconds
282
+ };
283
+ }
284
+ async function authBootstrapWithScopes(input) {
285
+ const minted = parseBootstrapMintResponse(
286
+ await input.mint(bootstrapMintParams(input.scopes, input.lifetime))
287
+ );
288
+ const apiUrl = input.apiUrl || defaultApiUrl;
289
+ const redeemed = await redeemBootstrapCode({
290
+ code: minted.bootstrap_code,
291
+ trustedMintLifetime: {
292
+ idle_ttl_seconds: minted.idle_ttl_seconds,
293
+ max_lifetime_seconds: minted.max_lifetime_seconds
294
+ },
295
+ apiUrl,
296
+ fetchFn: input.fetchFn
297
+ });
298
+ const stored = storedApiTokenFromRedeem({ apiUrl, redeemed });
299
+ const saved = saveStoredApiToken(stored, input.backend, input.resolution);
300
+ return {
301
+ stored,
302
+ backendKind: saved.backend.kind,
303
+ ...saved.backend.path ? { backendPath: saved.backend.path } : {}
304
+ };
305
+ }
306
+ function readRequiredInteger(input) {
307
+ if (!Number.isInteger(input.value) || input.value < input.min || input.value > input.max) {
308
+ throw new Error(
309
+ `${input.field} must be an integer between ${input.min} and ${input.max}.`
310
+ );
311
+ }
312
+ return input.value;
313
+ }
314
+ function parseRedeemResponse(body) {
315
+ if (!isRecord(body) || typeof body.token !== "string" || typeof body.id !== "string") {
316
+ throw new Error("Bootstrap redeem returned an unexpected response.");
317
+ }
318
+ return {
319
+ token: body.token,
320
+ token_type: typeof body.token_type === "string" ? body.token_type : void 0,
321
+ id: body.id,
322
+ name: typeof body.name === "string" ? body.name : null,
323
+ scopes: Array.isArray(body.scopes) ? body.scopes.filter(
324
+ (scope) => typeof scope === "string"
325
+ ) : void 0,
326
+ status: typeof body.status === "string" ? body.status : void 0,
327
+ idle_ttl_seconds: typeof body.idle_ttl_seconds === "number" ? body.idle_ttl_seconds : void 0,
328
+ expires_at: typeof body.expires_at === "string" ? body.expires_at : null,
329
+ max_expires_at: typeof body.max_expires_at === "string" ? body.max_expires_at : null,
330
+ created_via: typeof body.created_via === "string" ? body.created_via : void 0
331
+ };
332
+ }
333
+ function describeRedeemFailure(status, body, url) {
334
+ const failure = readErrorBody(body);
335
+ const detail = failure?.message ? ` Server said: ${failure.message}` : "";
336
+ if (status === 400 || status === 401 || status === 403 || status === 404) {
337
+ return new Error(
338
+ `Bootstrap redeem failed (HTTP ${status}). The code may be invalid, expired, or already used. Call cliCredentialBootstrap again for a fresh code.${detail}`
339
+ );
340
+ }
341
+ return new Error(
342
+ failure?.message ?? `Bootstrap redeem failed with HTTP ${status} (${url.pathname}).${detail}`
343
+ );
344
+ }
345
+ async function readJson(response) {
346
+ const text = await response.text();
347
+ if (!text) return null;
348
+ try {
349
+ return JSON.parse(text);
350
+ } catch {
351
+ return text;
352
+ }
353
+ }
354
+ function readErrorBody(body) {
355
+ if (!isRecord(body) || body.error == null) {
356
+ if (typeof body === "string" && body.trim()) {
357
+ return { code: null, message: summarizeNonJsonErrorBody(body) };
358
+ }
359
+ if (isRecord(body) && typeof body.message === "string") {
360
+ return { code: null, message: body.message };
361
+ }
362
+ return null;
363
+ }
364
+ const { error } = body;
365
+ if (typeof error === "string") return { code: null, message: error };
366
+ if (isRecord(error)) {
367
+ const code = typeof error.code === "string" ? error.code : null;
368
+ const message = typeof error.message === "string" ? error.message : code ?? JSON.stringify(error);
369
+ return { code, message };
370
+ }
371
+ return { code: null, message: String(error) };
372
+ }
373
+ function isRecord(value) {
374
+ return value !== null && typeof value === "object" && !Array.isArray(value);
375
+ }
376
+
377
+ // src/setup-git.ts
378
+ var setupGitRequiredScopes = ["package:read", "package:write"];
379
+ var setupGitDefaultScopes = [
380
+ "app:execute",
381
+ "app:read",
382
+ "email:read",
383
+ "email:send",
384
+ "integration:read",
385
+ "integration:use",
386
+ "job:execute",
387
+ "job:read",
388
+ "memory:read",
389
+ "org:execute",
390
+ "org:read",
391
+ "package:execute",
392
+ "package:read",
393
+ "package:write",
394
+ "secret:use",
395
+ "token:delete"
396
+ ];
397
+ function gitCredentialHostFromMcpUrl(mcpUrl = defaultMcpUrl) {
398
+ return new URL(mcpUrl).host;
399
+ }
400
+ function scopesIncludeRequired(scopes, required = setupGitRequiredScopes) {
401
+ if (!scopes) return false;
402
+ const held = new Set(scopes);
403
+ return required.every((scope) => held.has(scope));
404
+ }
405
+ function ensureSetupGitScopes(base = setupGitDefaultScopes) {
406
+ const out = [...base];
407
+ for (const required of setupGitRequiredScopes) {
408
+ if (!out.includes(required)) out.push(required);
409
+ }
410
+ return out;
411
+ }
412
+ async function fetchTokenCurrentMetadata(input) {
413
+ const apiUrl = input.apiUrl || defaultApiUrl;
414
+ const current = await openApiGet({
415
+ token: input.token,
416
+ apiUrl,
417
+ path: "v1/tokens/current",
418
+ fetchFn: input.fetchFn
419
+ });
420
+ const orgBindingRaw = current.org_binding;
421
+ const orgBinding = orgBindingRaw === "user" || orgBindingRaw === "org" ? orgBindingRaw : null;
422
+ return {
423
+ id: String(current.id ?? ""),
424
+ orgBinding,
425
+ scopes: Array.isArray(current.scopes) ? current.scopes.filter(
426
+ (scope) => typeof scope === "string"
427
+ ) : [],
428
+ expiresAt: typeof current.expires_at === "string" ? current.expires_at : null
429
+ };
430
+ }
431
+ function assertUserOwnedTokensLive(metadata) {
432
+ if (metadata.orgBinding === null) {
433
+ throw new Error(
434
+ "This Kody origin does not advertise user-owned API tokens (`org_binding` missing on GET /v1/tokens/current). Upgrade the server (kody auth setup-git / persistent git HTTPS) before installing the credential helper."
435
+ );
436
+ }
437
+ }
438
+ function decideSetupGitToken(input) {
439
+ const lifetime = input.lifetime ?? resolveCliTokenLifetime({ lifetime: "long" });
440
+ if (input.stored && input.metadata && input.metadata.orgBinding === "user" && scopesIncludeRequired(input.metadata.scopes) && !input.scopesOverride) {
441
+ return { action: "reuse", stored: input.stored, metadata: input.metadata };
442
+ }
443
+ const scopes = ensureSetupGitScopes(
444
+ input.scopesOverride ?? input.metadata?.scopes ?? input.stored?.scopes ?? setupGitDefaultScopes
445
+ );
446
+ const reason = !input.stored ? "No stored API token yet." : input.metadata?.orgBinding !== "user" ? "Stored token is not user-owned (`org_binding` must be `user`)." : !scopesIncludeRequired(input.metadata?.scopes) ? "Stored token is missing package:read and/or package:write." : "Minting with the requested --scopes list.";
447
+ return { action: "mint", scopes, lifetime, reason };
448
+ }
449
+ function defaultGitConfigRunner(args) {
450
+ const result = spawnSync("git", [...args], {
451
+ encoding: "utf8",
452
+ env: process.env
453
+ });
454
+ if (result.error) {
455
+ return { status: 1, stderr: result.error.message };
456
+ }
457
+ return {
458
+ status: result.status ?? 1,
459
+ stderr: (result.stderr || "").trim()
460
+ };
461
+ }
462
+ function installGitCredentialConfig(input) {
463
+ const runGit = input.runGit ?? defaultGitConfigRunner;
464
+ const scope = input.global === false ? "--local" : "--global";
465
+ const helperKey = `credential.https://${input.host}.helper`;
466
+ const pathKey = `credential.https://${input.host}.useHttpPath`;
467
+ for (const [key, value] of [
468
+ [helperKey, input.helperCommand],
469
+ [pathKey, "true"]
470
+ ]) {
471
+ const result = runGit(["config", scope, key, value]);
472
+ if (result.status !== 0) {
473
+ throw new Error(
474
+ `git config ${scope} ${key} failed${result.stderr ? `: ${result.stderr}` : ""}. Is git installed?`
475
+ );
476
+ }
477
+ }
478
+ return { host: input.host, helperCommand: input.helperCommand, scope };
479
+ }
480
+ var gitApiTokenRefreshSkewMs = 60 * 60 * 1e3;
481
+ var gitCredentialMinCliVersion = "1.16.0";
482
+ var gitCredentialHelperPinFallbackVersion = "1.18.0";
483
+ var requireFromSetupGit = createRequire(import.meta.url);
484
+ function readCliPackageVersion() {
485
+ try {
486
+ const pkg = requireFromSetupGit("../package.json");
487
+ return typeof pkg.version === "string" ? pkg.version : gitCredentialHelperPinFallbackVersion;
488
+ } catch {
489
+ return gitCredentialHelperPinFallbackVersion;
490
+ }
491
+ }
492
+ function isEphemeralNpxEntryPath(entryPath) {
493
+ const normalized = entryPath.replace(/\\/g, "/");
494
+ return normalized.includes("/.npm/_npx/") || normalized.includes("/npm/_npx/") || /\/_npx\//.test(normalized);
495
+ }
496
+ function parseCliSemver(version) {
497
+ const match = /^(\d+)\.(\d+)\.(\d+)/.exec(version.trim());
498
+ if (!match) return null;
499
+ return {
500
+ major: Number(match[1]),
501
+ minor: Number(match[2]),
502
+ patch: Number(match[3])
503
+ };
504
+ }
505
+ function compareCliSemver(a, b) {
506
+ if (a.major !== b.major) return a.major < b.major ? -1 : 1;
507
+ if (a.minor !== b.minor) return a.minor < b.minor ? -1 : 1;
508
+ if (a.patch !== b.patch) return a.patch < b.patch ? -1 : 1;
509
+ return 0;
510
+ }
511
+ function cliVersionGte(version, minimum) {
512
+ const left = parseCliSemver(version);
513
+ const right = parseCliSemver(minimum);
514
+ if (!left || !right) return false;
515
+ return compareCliSemver(left, right) >= 0;
516
+ }
517
+ function cliVersionGt(version, other) {
518
+ const left = parseCliSemver(version);
519
+ const right = parseCliSemver(other);
520
+ if (!left || !right) return false;
521
+ return compareCliSemver(left, right) > 0;
522
+ }
523
+ function cliVersionSupportsGitCredential(version) {
524
+ return cliVersionGte(version, gitCredentialMinCliVersion);
525
+ }
526
+ function cliExactVersionForNpx(packageVersion) {
527
+ const parsed = parseCliSemver(packageVersion);
528
+ if (parsed && parsed.major >= 1) {
529
+ return `${parsed.major}.${parsed.minor}.${parsed.patch}`;
530
+ }
531
+ return gitCredentialHelperPinFallbackVersion;
532
+ }
533
+ function cliMajorVersionForNpx(packageVersion) {
534
+ return cliExactVersionForNpx(packageVersion);
535
+ }
536
+ function apiTokenNeedsRefresh(stored, nowMs = Date.now(), skewMs = gitApiTokenRefreshSkewMs) {
537
+ if (!stored) return true;
538
+ if (stored.expiresAt == null || stored.expiresAt === "") return false;
539
+ const expiresMs = Date.parse(stored.expiresAt);
540
+ if (!Number.isFinite(expiresMs)) return true;
541
+ return expiresMs - nowMs <= skewMs;
542
+ }
543
+ function readVersionFromKodyBinary(binPath, args = ["--version"]) {
544
+ const result = spawnSync(binPath, [...args], {
545
+ encoding: "utf8",
546
+ env: {
547
+ ...process.env,
548
+ KODY_SKIP_GIT_HELPER_REFRESH: "1"
549
+ },
550
+ timeout: 8e3
551
+ });
552
+ if (result.error || (result.status ?? 1) !== 0) return null;
553
+ const text = `${result.stdout || ""}
554
+ ${result.stderr || ""}`;
555
+ const match = /(\d+\.\d+\.\d+)/.exec(text);
556
+ return match?.[1] ?? null;
557
+ }
558
+ function defaultReadGlobalKodyVersion(binPath) {
559
+ return readVersionFromKodyBinary(binPath);
560
+ }
561
+ function gitCredentialHelperCommand(input) {
562
+ const env = input?.env ?? process.env;
563
+ const whichFn = input?.which ?? which;
564
+ const entryPath = input?.entryPath ?? process.argv[1];
565
+ const readVersion = input?.readKodyVersion ?? defaultReadGlobalKodyVersion;
566
+ const globalKody = whichFn("kody", env);
567
+ if (globalKody && !isEphemeralNpxEntryPath(globalKody)) {
568
+ const globalVersion = readVersion(globalKody);
569
+ if (globalVersion && cliVersionSupportsGitCredential(globalVersion)) {
570
+ return `!${shellQuote(globalKody)} git-credential`;
571
+ }
572
+ }
573
+ if (entryPath && entryPath.length > 0 && !isEphemeralNpxEntryPath(entryPath)) {
574
+ const execPath = input?.execPath ?? process.execPath;
575
+ return `!${shellQuote(execPath)} ${shellQuote(entryPath)} git-credential`;
576
+ }
577
+ const exact = cliExactVersionForNpx(
578
+ input?.packageVersion ?? readCliPackageVersion()
579
+ );
580
+ return `!npx -y ${cliName}@${exact} git-credential`;
581
+ }
582
+ function shellQuote(value) {
583
+ if (/^[A-Za-z0-9_./:@+=,-]+$/.test(value)) return value;
584
+ return `'${value.replace(/'/g, `'\\''`)}'`;
585
+ }
586
+ function isMajorOnlyNpxHelper(helper) {
587
+ return /@kodycodes\/cli@\d+(?![.\d])/.test(helper);
588
+ }
589
+ function exactNpxHelperVersion(helper) {
590
+ const match = /@kodycodes\/cli@(\d+\.\d+\.\d+)/.exec(helper);
591
+ return match?.[1] ?? null;
592
+ }
593
+ function gitCredentialHelperNeedsRepair(input) {
594
+ const helper = input.helper?.trim();
595
+ if (!helper) return false;
596
+ if (isEphemeralNpxEntryPath(helper)) return true;
597
+ if (isMajorOnlyNpxHelper(helper)) return true;
598
+ const pinned = exactNpxHelperVersion(helper);
599
+ if (pinned) {
600
+ if (!cliVersionSupportsGitCredential(pinned)) return true;
601
+ const current = cliExactVersionForNpx(
602
+ input.packageVersion ?? readCliPackageVersion()
603
+ );
604
+ return cliVersionGt(current, pinned);
605
+ }
606
+ if (input.probeBinaryVersion !== true) {
607
+ return false;
608
+ }
609
+ const readVersion = input.readKodyVersion ?? defaultReadGlobalKodyVersion;
610
+ const bang = helper.startsWith("!") ? helper.slice(1).trim() : helper.trim();
611
+ const parts = bang.split(/\s+/).filter(Boolean);
612
+ if (parts.length >= 2 && parts[parts.length - 1] === "git-credential") {
613
+ const invocation = parts.slice(0, -1);
614
+ if (invocation.length === 1) {
615
+ const version = readVersion(invocation[0]);
616
+ if (version && !cliVersionSupportsGitCredential(version)) return true;
617
+ } else if (invocation.length >= 2) {
618
+ const version = readVersionFromKodyBinary(invocation[0], [
619
+ ...invocation.slice(1),
620
+ "--version"
621
+ ]);
622
+ if (version && !cliVersionSupportsGitCredential(version)) return true;
623
+ }
624
+ }
625
+ return false;
626
+ }
627
+ function defaultGitConfigGetRunner(args) {
628
+ const result = spawnSync("git", [...args], {
629
+ encoding: "utf8",
630
+ env: process.env
631
+ });
632
+ if (result.error) {
633
+ return { status: 1, stdout: "", stderr: result.error.message };
634
+ }
635
+ return {
636
+ status: result.status ?? 1,
637
+ stdout: (result.stdout || "").trim(),
638
+ stderr: (result.stderr || "").trim()
639
+ };
640
+ }
641
+ function refreshGitCredentialHelperPinIfNeeded(input) {
642
+ const mcpUrl = input?.mcpUrl || defaultMcpUrl;
643
+ const host = gitCredentialHostFromMcpUrl(mcpUrl);
644
+ const scope = input?.global === false ? "--local" : "--global";
645
+ const runGet = input?.runGitGet ?? defaultGitConfigGetRunner;
646
+ const helperKey = `credential.https://${host}.helper`;
647
+ const got = runGet(["config", scope, "--get", helperKey]);
648
+ if (got.status !== 0 || !got.stdout) return false;
649
+ const packageVersion = input?.packageVersion ?? readCliPackageVersion();
650
+ if (!gitCredentialHelperNeedsRepair({
651
+ helper: got.stdout,
652
+ packageVersion,
653
+ readKodyVersion: input?.readKodyVersion,
654
+ probeBinaryVersion: input?.probeBinaryVersion === true
655
+ })) {
656
+ return false;
657
+ }
658
+ const helperCommand = input?.helperCommand ?? gitCredentialHelperCommand({
659
+ packageVersion,
660
+ which: input?.which,
661
+ execPath: input?.execPath,
662
+ entryPath: input?.entryPath,
663
+ env: input?.env,
664
+ readKodyVersion: input?.readKodyVersion
665
+ });
666
+ if (helperCommand === got.stdout) return false;
667
+ installGitCredentialConfig({
668
+ host,
669
+ helperCommand,
670
+ global: input?.global,
671
+ runGit: input?.runGit
672
+ });
673
+ return true;
674
+ }
675
+ async function authSetupGit(input) {
676
+ const apiUrl = input.apiUrl || defaultApiUrl;
677
+ const mcpUrl = input.mcpUrl || defaultMcpUrl;
678
+ const host = gitCredentialHostFromMcpUrl(mcpUrl);
679
+ const storedExisting = loadStoredApiToken(
680
+ apiUrl,
681
+ input.backend,
682
+ input.resolution
683
+ );
684
+ const probeToken = input.token || storedExisting?.token;
685
+ const hasLoginSession = input.hasLoginSession === true;
686
+ if (!probeToken && !hasLoginSession) {
687
+ throw new Error(
688
+ `setup-git needs a Kody credential to detect server support and mint a token. Run \`kody login\`, or set ${apiTokenEnvVar}, or pass --token.`
689
+ );
690
+ }
691
+ let probeMetadata = null;
692
+ if (probeToken) {
693
+ try {
694
+ probeMetadata = await fetchTokenCurrentMetadata({
695
+ token: probeToken,
696
+ apiUrl,
697
+ fetchFn: input.fetchFn
698
+ });
699
+ } catch (error) {
700
+ if (error instanceof OpenApiError && error.status === 401) {
701
+ throw new Error(
702
+ `Could not read token metadata from ${apiUrl} (unauthorized). Run \`kody login\` or pass a valid --token / ${apiTokenEnvVar}.`
703
+ );
704
+ }
705
+ throw error;
706
+ }
707
+ assertUserOwnedTokensLive(probeMetadata);
708
+ }
709
+ let storedMetadata = null;
710
+ if (storedExisting) {
711
+ if (probeMetadata && storedExisting.token === probeToken) {
712
+ storedMetadata = probeMetadata;
713
+ } else {
714
+ try {
715
+ storedMetadata = await fetchTokenCurrentMetadata({
716
+ token: storedExisting.token,
717
+ apiUrl,
718
+ fetchFn: input.fetchFn
719
+ });
720
+ } catch {
721
+ storedMetadata = null;
722
+ }
723
+ }
724
+ }
725
+ const decision = decideSetupGitToken({
726
+ stored: storedExisting,
727
+ metadata: storedMetadata,
728
+ scopesOverride: input.scopesOverride,
729
+ lifetime: input.lifetime
730
+ });
731
+ let stored;
732
+ let minted = false;
733
+ let backendKind;
734
+ let backendPath;
735
+ let finalMetadata;
736
+ if (decision.action === "reuse") {
737
+ stored = decision.stored;
738
+ backendKind = "existing";
739
+ finalMetadata = decision.metadata;
740
+ } else {
741
+ const result = await authBootstrapWithScopes({
742
+ scopes: decision.scopes,
743
+ lifetime: decision.lifetime,
744
+ mint: input.mint,
745
+ apiUrl,
746
+ fetchFn: input.fetchFn,
747
+ backend: input.backend,
748
+ resolution: input.resolution
749
+ });
750
+ stored = result.stored;
751
+ minted = true;
752
+ backendKind = result.backendKind;
753
+ backendPath = result.backendPath;
754
+ const after = await fetchTokenCurrentMetadata({
755
+ token: stored.token,
756
+ apiUrl,
757
+ fetchFn: input.fetchFn
758
+ });
759
+ assertUserOwnedTokensLive(after);
760
+ if (after.orgBinding !== "user") {
761
+ throw new Error(
762
+ `Minted token ${stored.tokenId} has org_binding=${JSON.stringify(after.orgBinding)}; expected "user". Refusing to install the git helper.`
763
+ );
764
+ }
765
+ if (!scopesIncludeRequired(after.scopes)) {
766
+ throw new Error(
767
+ `Minted token ${stored.tokenId} is missing package:read and/or package:write. Pass --scopes that include both.`
768
+ );
769
+ }
770
+ finalMetadata = after;
771
+ }
772
+ const helperCommand = input.helperCommand ?? gitCredentialHelperCommand();
773
+ installGitCredentialConfig({
774
+ host,
775
+ helperCommand,
776
+ global: input.global,
777
+ runGit: input.runGit
778
+ });
779
+ return {
780
+ host,
781
+ helperCommand,
782
+ tokenId: stored.tokenId,
783
+ scopes: finalMetadata.scopes,
784
+ orgBinding: "user",
785
+ minted,
786
+ backendKind,
787
+ ...backendPath ? { backendPath } : {},
788
+ expiresAt: finalMetadata.expiresAt
789
+ };
790
+ }
791
+ var setupGitConfigScopes = ["--global", "--local"];
792
+ function isKodyGitCredentialHelperValue(value) {
793
+ const v = value.trim();
794
+ if (!v) return false;
795
+ if (v.includes("@kodycodes/cli")) return true;
796
+ if (isEphemeralNpxEntryPath(v)) return true;
797
+ if (/\bgit-credential\b/.test(v) && /(^|[/\s!])kody(\s|$)/.test(v))
798
+ return true;
799
+ if (/\bgit-credential\b/.test(v) && /kody/i.test(v)) return true;
800
+ return false;
801
+ }
802
+ async function authRemoveGit(input) {
803
+ const apiUrl = input.apiUrl || defaultApiUrl;
804
+ const mcpUrl = input.mcpUrl || defaultMcpUrl;
805
+ const host = gitCredentialHostFromMcpUrl(mcpUrl);
806
+ const runGet = input.runGitGet ?? defaultGitConfigGetRunner;
807
+ const runGit = input.runGit ?? defaultGitConfigRunner;
808
+ const helperKey = `credential.https://${host}.helper`;
809
+ const pathKey = `credential.https://${host}.useHttpPath`;
810
+ const removedHelpers = [];
811
+ const removedPathKeys = [];
812
+ for (const scope of setupGitConfigScopes) {
813
+ const helpers = runGet(["config", scope, "--get-all", helperKey]);
814
+ if (helpers.status === 0 && helpers.stdout.trim()) {
815
+ const values = helpers.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
816
+ const unset = runGit(["config", scope, "--unset-all", helperKey]);
817
+ if (unset.status === 0) {
818
+ for (const value of values) {
819
+ removedHelpers.push({ scope, key: helperKey, value });
820
+ }
821
+ }
822
+ }
823
+ const pathGot = runGet(["config", scope, "--get-all", pathKey]);
824
+ if (pathGot.status === 0 && pathGot.stdout.trim()) {
825
+ const unset = runGit(["config", scope, "--unset-all", pathKey]);
826
+ if (unset.status === 0) {
827
+ removedPathKeys.push({
828
+ scope,
829
+ key: pathKey,
830
+ value: pathGot.stdout.trim().split(/\r?\n/)[0]
831
+ });
832
+ }
833
+ }
834
+ }
835
+ const stored = loadStoredApiToken(apiUrl, input.backend, input.resolution);
836
+ let tokenRevoked = "skipped";
837
+ let tokenRevokeError;
838
+ let tokenId = stored?.tokenId ?? null;
839
+ if (stored?.token) {
840
+ try {
841
+ await openApiRequest({
842
+ token: stored.token,
843
+ apiUrl,
844
+ method: "DELETE",
845
+ path: "v1/tokens/current",
846
+ fetchFn: input.fetchFn
847
+ });
848
+ tokenRevoked = "yes";
849
+ } catch (error) {
850
+ if (error instanceof OpenApiError && (error.status === 401 || error.status === 404)) {
851
+ tokenRevoked = "already";
852
+ } else {
853
+ tokenRevoked = "failed";
854
+ tokenRevokeError = error instanceof Error ? error.message : String(error);
855
+ }
856
+ }
857
+ }
858
+ const deleted = deleteStoredApiToken(apiUrl, input.backend, input.resolution);
859
+ return {
860
+ host,
861
+ removedHelpers,
862
+ removedPathKeys,
863
+ tokenId,
864
+ tokenRevoked,
865
+ ...tokenRevokeError ? { tokenRevokeError } : {},
866
+ tokenDeletedLocally: deleted.deleted
867
+ };
868
+ }
869
+ function formatAuthRemoveGitReport(result) {
870
+ const lines = [];
871
+ const removedAnything = result.removedHelpers.length > 0 || result.removedPathKeys.length > 0 || result.tokenDeletedLocally || result.tokenRevoked === "yes" || result.tokenRevoked === "already";
872
+ if (!removedAnything) {
873
+ return [
874
+ `No Kody Git HTTPS credential helper or stored API token found for https://${result.host}/.`,
875
+ "Nothing to remove. (kody login sessions were not touched.)",
876
+ ""
877
+ ].join("\n");
878
+ }
879
+ lines.push(`Removed Kody Git HTTPS setup for https://${result.host}/`);
880
+ for (const entry of result.removedHelpers) {
881
+ lines.push(` ${entry.scope} ${entry.key}: ${entry.value}`);
882
+ }
883
+ for (const entry of result.removedPathKeys) {
884
+ lines.push(
885
+ ` ${entry.scope} ${entry.key}${entry.value ? `: ${entry.value}` : ""}`
886
+ );
887
+ }
888
+ if (result.tokenRevoked === "yes") {
889
+ lines.push(
890
+ `Revoked API token${result.tokenId ? ` ${result.tokenId}` : ""} on the server (token:delete).`
891
+ );
892
+ } else if (result.tokenRevoked === "already") {
893
+ lines.push(
894
+ `API token${result.tokenId ? ` ${result.tokenId}` : ""} already revoked or expired on the server.`
895
+ );
896
+ } else if (result.tokenRevoked === "failed") {
897
+ lines.push(
898
+ `Could not revoke API token on the server${result.tokenRevokeError ? `: ${result.tokenRevokeError}` : "."}`
899
+ );
900
+ } else if (result.tokenRevoked === "skipped") {
901
+ lines.push("No stored API token to revoke.");
902
+ }
903
+ if (result.tokenDeletedLocally) {
904
+ lines.push(
905
+ "Deleted stored API token from the OS keychain (and file fallback)."
906
+ );
907
+ } else if (result.tokenRevoked !== "skipped") {
908
+ lines.push("Stored API token was already absent from the local store.");
909
+ }
910
+ lines.push("Left kody login sessions alone.");
911
+ lines.push("");
912
+ return lines.join("\n");
913
+ }
914
+
915
+ export {
916
+ cliTokenLifetimePolicy,
917
+ cliTokenLifetimeAliases,
918
+ cliTokenLifetimeMissingError,
919
+ resolveCliTokenLifetime,
920
+ bootstrapRedeemRequestBody,
921
+ parseCliLifetimeSecondsFlag,
922
+ redeemBootstrapCode,
923
+ authBootstrap,
924
+ cliCredentialBootstrapOperationId,
925
+ parseCliScopesFlag,
926
+ bootstrapMintLifetimeFields,
927
+ authBootstrapWithScopes,
928
+ setupGitRequiredScopes,
929
+ setupGitDefaultScopes,
930
+ gitCredentialHostFromMcpUrl,
931
+ scopesIncludeRequired,
932
+ ensureSetupGitScopes,
933
+ fetchTokenCurrentMetadata,
934
+ assertUserOwnedTokensLive,
935
+ decideSetupGitToken,
936
+ defaultGitConfigRunner,
937
+ installGitCredentialConfig,
938
+ gitApiTokenRefreshSkewMs,
939
+ gitCredentialMinCliVersion,
940
+ gitCredentialHelperPinFallbackVersion,
941
+ readCliPackageVersion,
942
+ isEphemeralNpxEntryPath,
943
+ parseCliSemver,
944
+ compareCliSemver,
945
+ cliVersionGte,
946
+ cliVersionGt,
947
+ cliVersionSupportsGitCredential,
948
+ cliExactVersionForNpx,
949
+ cliMajorVersionForNpx,
950
+ apiTokenNeedsRefresh,
951
+ readVersionFromKodyBinary,
952
+ gitCredentialHelperCommand,
953
+ isMajorOnlyNpxHelper,
954
+ exactNpxHelperVersion,
955
+ gitCredentialHelperNeedsRepair,
956
+ defaultGitConfigGetRunner,
957
+ refreshGitCredentialHelperPinIfNeeded,
958
+ authSetupGit,
959
+ setupGitConfigScopes,
960
+ isKodyGitCredentialHelperValue,
961
+ authRemoveGit,
962
+ formatAuthRemoveGitReport
963
+ };
964
+ //# sourceMappingURL=chunk-OZDWOZLV.js.map