@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.
- package/README.md +175 -167
- package/dist/add-mcp-install.d.ts +1 -1
- package/dist/api-token.d.ts +1 -1
- package/dist/auth-6ZE6QQXA.js +31 -0
- package/dist/auth-6ZE6QQXA.js.map +6 -0
- package/dist/auth-bootstrap.d.ts +1 -1
- package/dist/auth.d.ts +27 -3
- package/dist/bin.js +27 -3
- package/dist/bin.js.map +6 -1
- package/dist/capability-proxy.d.ts +1 -1
- package/dist/chunk-2IHISXHN.js +1413 -0
- package/dist/chunk-2IHISXHN.js.map +6 -0
- package/dist/chunk-2XPH7L2P.js +23 -0
- package/dist/chunk-2XPH7L2P.js.map +6 -0
- package/dist/chunk-3H72XY5R.js +535 -0
- package/dist/chunk-3H72XY5R.js.map +6 -0
- package/dist/chunk-46IJPEID.js +30 -0
- package/dist/chunk-46IJPEID.js.map +6 -0
- package/dist/chunk-4GIFJVGT.js +14 -0
- package/dist/chunk-4GIFJVGT.js.map +6 -0
- package/dist/chunk-5JIRHJQP.js +1016 -0
- package/dist/chunk-5JIRHJQP.js.map +6 -0
- package/dist/chunk-5ZBJAP6G.js +2005 -0
- package/dist/chunk-5ZBJAP6G.js.map +6 -0
- package/dist/chunk-6ZYUGXVW.js +26 -0
- package/dist/chunk-6ZYUGXVW.js.map +6 -0
- package/dist/chunk-7PRJ36I5.js +23 -0
- package/dist/chunk-7PRJ36I5.js.map +6 -0
- package/dist/chunk-BTL3PJ2H.js +38 -0
- package/dist/chunk-BTL3PJ2H.js.map +6 -0
- package/dist/chunk-CASGRYOF.js +21 -0
- package/dist/chunk-CASGRYOF.js.map +6 -0
- package/dist/chunk-CPS7HW4T.js +56 -0
- package/dist/chunk-CPS7HW4T.js.map +6 -0
- package/dist/chunk-CWWHR4FH.js +19 -0
- package/dist/chunk-CWWHR4FH.js.map +6 -0
- package/dist/chunk-D366STO5.js +2051 -0
- package/dist/chunk-D366STO5.js.map +6 -0
- package/dist/chunk-DW5UTJ6T.js +115 -0
- package/dist/chunk-DW5UTJ6T.js.map +6 -0
- package/dist/chunk-EJXEVGWF.js +47 -0
- package/dist/chunk-EJXEVGWF.js.map +6 -0
- package/dist/chunk-FBEZ6PZ7.js +746 -0
- package/dist/chunk-FBEZ6PZ7.js.map +6 -0
- package/dist/chunk-JOMBXQOS.js +435 -0
- package/dist/chunk-JOMBXQOS.js.map +6 -0
- package/dist/{package-local-runtime-source.js → chunk-LU7I7CQ4.js} +395 -52
- package/dist/chunk-LU7I7CQ4.js.map +6 -0
- package/dist/chunk-OZDWOZLV.js +964 -0
- package/dist/chunk-OZDWOZLV.js.map +6 -0
- package/dist/chunk-SLNAWWQK.js +64 -0
- package/dist/chunk-SLNAWWQK.js.map +6 -0
- package/dist/chunk-TUUFQYWP.js +348 -0
- package/dist/chunk-TUUFQYWP.js.map +6 -0
- package/dist/chunk-UW6AWLXX.js +43 -0
- package/dist/chunk-UW6AWLXX.js.map +6 -0
- package/dist/chunk-W2SAFAT4.js +1563 -0
- package/dist/chunk-W2SAFAT4.js.map +6 -0
- package/dist/chunk-XV6D6HSG.js +57 -0
- package/dist/chunk-XV6D6HSG.js.map +6 -0
- package/dist/chunk-Y4FOJETX.js +616 -0
- package/dist/chunk-Y4FOJETX.js.map +6 -0
- package/dist/chunk-YDWTXEKQ.js +469 -0
- package/dist/chunk-YDWTXEKQ.js.map +6 -0
- package/dist/chunk-ZILB2HWE.js +24 -0
- package/dist/chunk-ZILB2HWE.js.map +6 -0
- package/dist/cli.js +74 -1500
- package/dist/cli.js.map +6 -1
- package/dist/defaults.d.ts +1 -1
- package/dist/detect-running-hosts.d.ts +1 -1
- package/dist/dev/dev-assets.d.ts +1 -1
- package/dist/dev/dev-registry.d.ts +1 -1
- package/dist/dev/error-page.d.ts +1 -1
- package/dist/dev/live-reload.d.ts +2 -2
- package/dist/dev-command-5PDEIWOC.js +5025 -0
- package/dist/dev-command-5PDEIWOC.js.map +6 -0
- package/dist/dev-command.d.ts +1 -1
- package/dist/discover-login-identity.d.ts +6 -7
- package/dist/discover-org.d.ts +2 -3
- package/dist/generated/openapi-routes.d.ts +6 -0
- package/dist/git-credential-INB2UV4C.js +170 -0
- package/dist/git-credential-INB2UV4C.js.map +6 -0
- package/dist/install-ONEJRYZ3.js +10728 -0
- package/dist/install-ONEJRYZ3.js.map +6 -0
- package/dist/install.d.ts +1 -1
- package/dist/local-execute-I3BP5NEQ.js +395 -0
- package/dist/local-execute-I3BP5NEQ.js.map +6 -0
- package/dist/local-execute-auth.d.ts +2 -2
- package/dist/local-execute.d.ts +1 -1
- package/dist/local-gateway-fetch-forward.d.ts +2 -2
- package/dist/local-package-run-JFKNSNWM.js +23 -0
- package/dist/local-package-run-JFKNSNWM.js.map +6 -0
- package/dist/local-package-run.d.ts +2 -2
- package/dist/mock/mock-fetch-gateway.d.ts +2 -2
- package/dist/mock/mock-supported.d.ts +1 -1
- package/dist/mock-dep-resolve-B5ZH4U3H.js +60 -0
- package/dist/mock-dep-resolve-B5ZH4U3H.js.map +6 -0
- package/dist/mock-fetch-gateway-S2ULVFAI.js +35 -0
- package/dist/mock-fetch-gateway-S2ULVFAI.js.map +6 -0
- package/dist/mock-local-deps-2VVNJLFF.js +200 -0
- package/dist/mock-local-deps-2VVNJLFF.js.map +6 -0
- package/dist/mock-local-deps.d.ts +1 -1
- package/dist/mock-server-TFO7Q26H.js +22 -0
- package/dist/mock-server-TFO7Q26H.js.map +6 -0
- package/dist/oauth-browser.d.ts +42 -0
- package/dist/oauth-provider.d.ts +14 -19
- package/dist/open-api-client-SR4B7265.js +43 -0
- package/dist/open-api-client-SR4B7265.js.map +6 -0
- package/dist/open-api-client.d.ts +2 -1
- package/dist/org-535LB4PD.js +134 -0
- package/dist/org-535LB4PD.js.map +6 -0
- package/dist/org-resolve.d.ts +2 -0
- package/dist/package-app-dev.d.ts +2 -2
- package/dist/package-manifest-DFF6XCPV.js +15 -0
- package/dist/package-manifest-DFF6XCPV.js.map +6 -0
- package/dist/remote-execute-JN6DRFEU.js +129 -0
- package/dist/remote-execute-JN6DRFEU.js.map +6 -0
- package/dist/remote-execute.d.ts +3 -3
- package/dist/setup-git-MHK563LB.js +87 -0
- package/dist/setup-git-MHK563LB.js.map +6 -0
- package/dist/setup-git.d.ts +1 -1
- package/dist/skill-D74XVI6T.js +61 -0
- package/dist/skill-D74XVI6T.js.map +6 -0
- package/dist/store-27J4CQZ2.js +48 -0
- package/dist/store-27J4CQZ2.js.map +6 -0
- package/dist/structured-error-5MLWXYR3.js +14 -0
- package/dist/structured-error-5MLWXYR3.js.map +6 -0
- package/dist/structured-error.d.ts +1 -1
- package/dist/target-33ATHDUF.js +17 -0
- package/dist/target-33ATHDUF.js.map +6 -0
- package/package.json +12 -11
- package/skills/kody/SKILL.md +53 -50
- package/dist/add-mcp-install.js +0 -59
- package/dist/add-mcp-install.js.map +0 -1
- package/dist/api-token-store.js +0 -120
- package/dist/api-token-store.js.map +0 -1
- package/dist/api-token.js +0 -238
- package/dist/api-token.js.map +0 -1
- package/dist/auth-bootstrap.js +0 -373
- package/dist/auth-bootstrap.js.map +0 -1
- package/dist/auth.js +0 -386
- package/dist/auth.js.map +0 -1
- package/dist/capability-proxy.js +0 -527
- package/dist/capability-proxy.js.map +0 -1
- package/dist/credential-call-map.js +0 -155
- package/dist/credential-call-map.js.map +0 -1
- package/dist/credential-client-runtime-source.js +0 -9
- package/dist/credential-client-runtime-source.js.map +0 -1
- package/dist/credentialed-fetch-scan.js +0 -98
- package/dist/credentialed-fetch-scan.js.map +0 -1
- package/dist/defaults.js +0 -34
- package/dist/defaults.js.map +0 -1
- package/dist/detect-running-hosts.js +0 -13
- package/dist/detect-running-hosts.js.map +0 -1
- package/dist/dev/dev-assets.js +0 -202
- package/dist/dev/dev-assets.js.map +0 -1
- package/dist/dev/dev-bundler.js +0 -65
- package/dist/dev/dev-bundler.js.map +0 -1
- package/dist/dev/dev-events.js +0 -94
- package/dist/dev/dev-events.js.map +0 -1
- package/dist/dev/dev-port.js +0 -80
- package/dist/dev/dev-port.js.map +0 -1
- package/dist/dev/dev-protocol.js +0 -14
- package/dist/dev/dev-protocol.js.map +0 -1
- package/dist/dev/dev-registry.js +0 -95
- package/dist/dev/dev-registry.js.map +0 -1
- package/dist/dev/dev-watcher.js +0 -162
- package/dist/dev/dev-watcher.js.map +0 -1
- package/dist/dev/error-page.js +0 -64
- package/dist/dev/error-page.js.map +0 -1
- package/dist/dev/live-reload.js +0 -151
- package/dist/dev/live-reload.js.map +0 -1
- package/dist/dev/prebuild.js +0 -102
- package/dist/dev/prebuild.js.map +0 -1
- package/dist/dev/process-reaper.js +0 -151
- package/dist/dev/process-reaper.js.map +0 -1
- package/dist/dev/stack-trace.js +0 -56
- package/dist/dev/stack-trace.js.map +0 -1
- package/dist/dev/workerd-process.js +0 -118
- package/dist/dev/workerd-process.js.map +0 -1
- package/dist/dev-command.js +0 -676
- package/dist/dev-command.js.map +0 -1
- package/dist/discover-login-identity.js +0 -77
- package/dist/discover-login-identity.js.map +0 -1
- package/dist/discover-org.js +0 -62
- package/dist/discover-org.js.map +0 -1
- package/dist/git-credential.js +0 -147
- package/dist/git-credential.js.map +0 -1
- package/dist/help.js +0 -333
- package/dist/help.js.map +0 -1
- package/dist/host-catalog.js +0 -427
- package/dist/host-catalog.js.map +0 -1
- package/dist/host-config.js +0 -80
- package/dist/host-config.js.map +0 -1
- package/dist/http-error-body.js +0 -35
- package/dist/http-error-body.js.map +0 -1
- package/dist/install-hosts.js +0 -328
- package/dist/install-hosts.js.map +0 -1
- package/dist/install.js +0 -120
- package/dist/install.js.map +0 -1
- package/dist/invoke-passthrough.js +0 -60
- package/dist/invoke-passthrough.js.map +0 -1
- package/dist/local-bundle.js +0 -200
- package/dist/local-bundle.js.map +0 -1
- package/dist/local-execute-auth.js +0 -53
- package/dist/local-execute-auth.js.map +0 -1
- package/dist/local-execute.js +0 -338
- package/dist/local-execute.js.map +0 -1
- package/dist/local-gateway-fetch-forward.js +0 -135
- package/dist/local-gateway-fetch-forward.js.map +0 -1
- package/dist/local-host-runtime-surface.js +0 -75
- package/dist/local-host-runtime-surface.js.map +0 -1
- package/dist/local-package-graph.js +0 -405
- package/dist/local-package-graph.js.map +0 -1
- package/dist/local-package-run.js +0 -307
- package/dist/local-package-run.js.map +0 -1
- package/dist/local-runtime-bridge.js +0 -132
- package/dist/local-runtime-bridge.js.map +0 -1
- package/dist/local-runtime-source.js +0 -541
- package/dist/local-runtime-source.js.map +0 -1
- package/dist/login-callback-assets.js +0 -10
- package/dist/login-callback-assets.js.map +0 -1
- package/dist/login-callback-page.js +0 -362
- package/dist/login-callback-page.js.map +0 -1
- package/dist/mcp.d.ts +0 -34
- package/dist/mcp.js +0 -134
- package/dist/mcp.js.map +0 -1
- package/dist/mock/ensure-msw.js +0 -215
- package/dist/mock/ensure-msw.js.map +0 -1
- package/dist/mock/install-mock-fetch-shim.js +0 -36
- package/dist/mock/install-mock-fetch-shim.js.map +0 -1
- package/dist/mock/load-package-mocks.js +0 -136
- package/dist/mock/load-package-mocks.js.map +0 -1
- package/dist/mock/mock-fetch-gateway.js +0 -343
- package/dist/mock/mock-fetch-gateway.js.map +0 -1
- package/dist/mock/mock-gateway-fetch-shim.js +0 -104
- package/dist/mock/mock-gateway-fetch-shim.js.map +0 -1
- package/dist/mock/mock-server.js +0 -499
- package/dist/mock/mock-server.js.map +0 -1
- package/dist/mock/mock-storage.js +0 -186
- package/dist/mock/mock-storage.js.map +0 -1
- package/dist/mock/mock-supported.js +0 -63
- package/dist/mock/mock-supported.js.map +0 -1
- package/dist/mock-dep-resolve.js +0 -47
- package/dist/mock-dep-resolve.js.map +0 -1
- package/dist/mock-local-deps.js +0 -207
- package/dist/mock-local-deps.js.map +0 -1
- package/dist/network-error.js +0 -11
- package/dist/network-error.js.map +0 -1
- package/dist/node-engine.js +0 -21
- package/dist/node-engine.js.map +0 -1
- package/dist/oauth-provider.js +0 -107
- package/dist/oauth-provider.js.map +0 -1
- package/dist/onboarding-prompt.js +0 -15
- package/dist/onboarding-prompt.js.map +0 -1
- package/dist/open-api-client.js +0 -432
- package/dist/open-api-client.js.map +0 -1
- package/dist/open-url.js +0 -21
- package/dist/open-url.js.map +0 -1
- package/dist/org-resolve.js +0 -16
- package/dist/org-resolve.js.map +0 -1
- package/dist/org-slug.js +0 -11
- package/dist/org-slug.js.map +0 -1
- package/dist/org.js +0 -100
- package/dist/org.js.map +0 -1
- package/dist/package-app-dev.js +0 -922
- package/dist/package-app-dev.js.map +0 -1
- package/dist/package-collaborators.js +0 -179
- package/dist/package-collaborators.js.map +0 -1
- package/dist/package-info.js +0 -19
- package/dist/package-info.js.map +0 -1
- package/dist/package-local-runtime-source.js.map +0 -1
- package/dist/package-manifest.js +0 -364
- package/dist/package-manifest.js.map +0 -1
- package/dist/process-info.js +0 -14
- package/dist/process-info.js.map +0 -1
- package/dist/redact.js +0 -16
- package/dist/redact.js.map +0 -1
- package/dist/remote-execute.js +0 -108
- package/dist/remote-execute.js.map +0 -1
- package/dist/setup-git.js +0 -676
- package/dist/setup-git.js.map +0 -1
- package/dist/skill.js +0 -35
- package/dist/skill.js.map +0 -1
- package/dist/store.js +0 -597
- package/dist/store.js.map +0 -1
- package/dist/structured-error.js +0 -57
- package/dist/structured-error.js.map +0 -1
- package/dist/target.js +0 -52
- package/dist/target.js.map +0 -1
- package/dist/tool-result.js +0 -19
- package/dist/tool-result.js.map +0 -1
- package/dist/which.js +0 -22
- package/dist/which.js.map +0 -1
- package/dist/workerd-binary.js +0 -98
- 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(/ /g, " ").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/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
|