@kodycodes/cli 1.26.2 → 1.26.3
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/dist/auth-4FW6GCLG.js +26 -0
- package/dist/auth-4FW6GCLG.js.map +6 -0
- package/dist/bin.js +27 -3
- package/dist/bin.js.map +6 -1
- package/dist/chunk-46IJPEID.js +30 -0
- package/dist/chunk-46IJPEID.js.map +6 -0
- package/dist/chunk-4D6ORNXY.js +24404 -0
- package/dist/chunk-4D6ORNXY.js.map +6 -0
- package/dist/chunk-64IM6G4Z.js +341 -0
- package/dist/chunk-64IM6G4Z.js.map +6 -0
- package/dist/{package-local-runtime-source.js → chunk-64XN367G.js} +373 -52
- package/dist/chunk-64XN367G.js.map +6 -0
- package/dist/chunk-6XQP5SWX.js +26 -0
- package/dist/chunk-6XQP5SWX.js.map +6 -0
- package/dist/chunk-75RZUXQL.js +62 -0
- package/dist/chunk-75RZUXQL.js.map +6 -0
- package/dist/chunk-BISUL7CE.js +106 -0
- package/dist/chunk-BISUL7CE.js.map +6 -0
- package/dist/chunk-BPGY4IE7.js +57 -0
- package/dist/chunk-BPGY4IE7.js.map +6 -0
- package/dist/chunk-CASGRYOF.js +21 -0
- package/dist/chunk-CASGRYOF.js.map +6 -0
- package/dist/chunk-CWWHR4FH.js +19 -0
- package/dist/chunk-CWWHR4FH.js.map +6 -0
- package/dist/chunk-D55XPY3T.js +1382 -0
- package/dist/chunk-D55XPY3T.js.map +6 -0
- package/dist/chunk-EOCV74B2.js +948 -0
- package/dist/chunk-EOCV74B2.js.map +6 -0
- package/dist/chunk-FBVNFWR6.js +437 -0
- package/dist/chunk-FBVNFWR6.js.map +6 -0
- package/dist/chunk-G4YN6XP5.js +14 -0
- package/dist/chunk-G4YN6XP5.js.map +6 -0
- package/dist/chunk-G6LJWROP.js +18 -0
- package/dist/chunk-G6LJWROP.js.map +6 -0
- package/dist/chunk-IHP6PV6X.js +49 -0
- package/dist/chunk-IHP6PV6X.js.map +6 -0
- package/dist/chunk-JWEFKKAD.js +24 -0
- package/dist/chunk-JWEFKKAD.js.map +6 -0
- package/dist/chunk-LWNB26KO.js +147 -0
- package/dist/chunk-LWNB26KO.js.map +6 -0
- package/dist/chunk-OVGXPRSY.js +20 -0
- package/dist/chunk-OVGXPRSY.js.map +6 -0
- package/dist/chunk-PDWCKWQF.js +453 -0
- package/dist/chunk-PDWCKWQF.js.map +6 -0
- package/dist/chunk-QHBCP4OB.js +44 -0
- package/dist/chunk-QHBCP4OB.js.map +6 -0
- package/dist/chunk-R4IUV5P5.js +664 -0
- package/dist/chunk-R4IUV5P5.js.map +6 -0
- package/dist/chunk-RM34N3KI.js +525 -0
- package/dist/chunk-RM34N3KI.js.map +6 -0
- package/dist/chunk-RTWUNV76.js +309 -0
- package/dist/chunk-RTWUNV76.js.map +6 -0
- package/dist/chunk-SMURF26I.js +23 -0
- package/dist/chunk-SMURF26I.js.map +6 -0
- package/dist/chunk-SXHULGL4.js +426 -0
- package/dist/chunk-SXHULGL4.js.map +6 -0
- package/dist/chunk-TIL35OWA.js +1959 -0
- package/dist/chunk-TIL35OWA.js.map +6 -0
- package/dist/chunk-VQS5YSCI.js +54 -0
- package/dist/chunk-VQS5YSCI.js.map +6 -0
- package/dist/chunk-XDCOWU5R.js +696 -0
- package/dist/chunk-XDCOWU5R.js.map +6 -0
- package/dist/chunk-XOPPGRUP.js +605 -0
- package/dist/chunk-XOPPGRUP.js.map +6 -0
- package/dist/cli.js +74 -1500
- package/dist/cli.js.map +6 -1
- package/dist/dev-command-3LX234N6.js +4900 -0
- package/dist/dev-command-3LX234N6.js.map +6 -0
- package/dist/git-credential-FUE3JE3T.js +163 -0
- package/dist/git-credential-FUE3JE3T.js.map +6 -0
- package/dist/install-ZML2TCDG.js +10694 -0
- package/dist/install-ZML2TCDG.js.map +6 -0
- package/dist/local-execute-SZV6XN4T.js +368 -0
- package/dist/local-execute-SZV6XN4T.js.map +6 -0
- package/dist/local-package-run-2TMCAZZ2.js +23 -0
- package/dist/local-package-run-2TMCAZZ2.js.map +6 -0
- package/dist/mcp-G2AWTIXR.js +21 -0
- package/dist/mcp-G2AWTIXR.js.map +6 -0
- package/dist/mock-dep-resolve-TVABDNR7.js +52 -0
- package/dist/mock-dep-resolve-TVABDNR7.js.map +6 -0
- package/dist/mock-fetch-gateway-B5TFGGQS.js +34 -0
- package/dist/mock-fetch-gateway-B5TFGGQS.js.map +6 -0
- package/dist/mock-local-deps-5SZT3PWT.js +197 -0
- package/dist/mock-local-deps-5SZT3PWT.js.map +6 -0
- package/dist/mock-server-SV2IKC4I.js +21 -0
- package/dist/mock-server-SV2IKC4I.js.map +6 -0
- package/dist/open-api-client-DVVMLY7P.js +42 -0
- package/dist/open-api-client-DVVMLY7P.js.map +6 -0
- package/dist/org-X7B5BI4R.js +132 -0
- package/dist/org-X7B5BI4R.js.map +6 -0
- package/dist/package-manifest-QH2RU64C.js +14 -0
- package/dist/package-manifest-QH2RU64C.js.map +6 -0
- package/dist/remote-execute-QMQDVHOY.js +110 -0
- package/dist/remote-execute-QMQDVHOY.js.map +6 -0
- package/dist/setup-git-5KCUBYPB.js +88 -0
- package/dist/setup-git-5KCUBYPB.js.map +6 -0
- package/dist/skill-ENPATRIW.js +43 -0
- package/dist/skill-ENPATRIW.js.map +6 -0
- package/dist/store-WTMRH527.js +48 -0
- package/dist/store-WTMRH527.js.map +6 -0
- package/dist/structured-error-C65GQ53Z.js +13 -0
- package/dist/structured-error-C65GQ53Z.js.map +6 -0
- package/dist/target-3QHY7JT4.js +45 -0
- package/dist/target-3QHY7JT4.js.map +6 -0
- package/dist/webapi-NTVP4BO3.js +2482 -0
- package/dist/webapi-NTVP4BO3.js.map +6 -0
- package/package.json +8 -8
- 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.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
package/dist/cli.js
CHANGED
|
@@ -1,1500 +1,74 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
'no-live-reload': { type: 'boolean' },
|
|
76
|
-
'ready-file': { type: 'string' },
|
|
77
|
-
'no-attach': { type: 'boolean' },
|
|
78
|
-
method: { type: 'string' },
|
|
79
|
-
body: { type: 'string' },
|
|
80
|
-
clients: { type: 'string' },
|
|
81
|
-
yes: { type: 'boolean', short: 'y' },
|
|
82
|
-
team: { type: 'string' },
|
|
83
|
-
user: { type: 'string' },
|
|
84
|
-
preset: { type: 'string' },
|
|
85
|
-
grant: { type: 'string' },
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
export function resolveCommand(argv) {
|
|
90
|
-
const { positionals, values } = parseKnown(argv);
|
|
91
|
-
if (values.help && positionals.length === 0) {
|
|
92
|
-
return { command: 'help', positionals, values };
|
|
93
|
-
}
|
|
94
|
-
if (values.version && positionals.length === 0) {
|
|
95
|
-
return { command: 'version', positionals, values };
|
|
96
|
-
}
|
|
97
|
-
const raw = positionals[0];
|
|
98
|
-
if (!raw)
|
|
99
|
-
return { command: 'help', positionals, values };
|
|
100
|
-
switch (raw) {
|
|
101
|
-
case 'login':
|
|
102
|
-
case 'logout':
|
|
103
|
-
case 'org':
|
|
104
|
-
case 'status':
|
|
105
|
-
case 'auth':
|
|
106
|
-
case 'git-credential':
|
|
107
|
-
case 'whoami':
|
|
108
|
-
case 'search':
|
|
109
|
-
case 'api':
|
|
110
|
-
case 'package':
|
|
111
|
-
case 'execute':
|
|
112
|
-
case 'dev':
|
|
113
|
-
case 'install':
|
|
114
|
-
case 'skill':
|
|
115
|
-
case 'help':
|
|
116
|
-
case 'version':
|
|
117
|
-
return { command: raw, positionals: positionals.slice(1), values };
|
|
118
|
-
default:
|
|
119
|
-
// Never embed full usage here: git credential helpers treat any
|
|
120
|
-
// unexpected stdout as protocol data, and older CLIs that dumped
|
|
121
|
-
// help on unknown commands broke `git push`. Keep the hint short;
|
|
122
|
-
// `runCli` always writes errors to stderr only.
|
|
123
|
-
throw new Error(`Unknown command "${raw}". Run \`kody --help\` for usage.`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
export async function runCli(argv = process.argv.slice(2), io = {}) {
|
|
127
|
-
const write = io.stdout ?? ((text) => process.stdout.write(text));
|
|
128
|
-
const writeErr = io.stderr ?? ((text) => process.stderr.write(text));
|
|
129
|
-
// Best-effort: upgrade stale git helper pins (major-only / ephemeral /
|
|
130
|
-
// outdated exact) before most commands. Must not write to stdout — git
|
|
131
|
-
// reads the helper protocol from stdout only.
|
|
132
|
-
// Skip under node:test so unit tests never rewrite the developer's
|
|
133
|
-
// global git config; skip git-credential (helper must stay fast / offline
|
|
134
|
-
// while the stored token is valid); skip version/help (no git touch).
|
|
135
|
-
const head = argv[0];
|
|
136
|
-
const skipHelperRefresh = process.env.NODE_TEST === '1' ||
|
|
137
|
-
process.env.KODY_SKIP_GIT_HELPER_REFRESH === '1' ||
|
|
138
|
-
head === 'git-credential' ||
|
|
139
|
-
head === 'version' ||
|
|
140
|
-
head === '--version' ||
|
|
141
|
-
head === '-v' ||
|
|
142
|
-
head === 'help' ||
|
|
143
|
-
head === '--help' ||
|
|
144
|
-
head === '-h' ||
|
|
145
|
-
head === undefined;
|
|
146
|
-
if (!skipHelperRefresh) {
|
|
147
|
-
try {
|
|
148
|
-
refreshGitCredentialHelperPinIfNeeded({
|
|
149
|
-
mcpUrl: process.env.KODY_MCP_URL || undefined,
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
catch {
|
|
153
|
-
// Ignore refresh failures; the user's command still runs.
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
try {
|
|
157
|
-
const parsed = resolveCommand(argv);
|
|
158
|
-
const helpMcpUrl = mcpUrlFrom({
|
|
159
|
-
mcpUrl: typeof parsed.values['mcp-url'] === 'string'
|
|
160
|
-
? parsed.values['mcp-url']
|
|
161
|
-
: undefined,
|
|
162
|
-
});
|
|
163
|
-
if (parsed.values.help && parsed.command !== 'help') {
|
|
164
|
-
write(buildUsage({ mcpUrl: helpMcpUrl }));
|
|
165
|
-
return 0;
|
|
166
|
-
}
|
|
167
|
-
return await dispatch(parsed, write, writeErr);
|
|
168
|
-
}
|
|
169
|
-
catch (error) {
|
|
170
|
-
writeErr(`${redactError(error).message}\n`);
|
|
171
|
-
return 1;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
async function dispatch(parsed, write, writeErr) {
|
|
175
|
-
const mcpUrl = mcpUrlFrom({
|
|
176
|
-
mcpUrl: typeof parsed.values['mcp-url'] === 'string' ? parsed.values['mcp-url'] : undefined,
|
|
177
|
-
});
|
|
178
|
-
const json = parsed.values.json === true;
|
|
179
|
-
if (parsed.values['allow-private-network'] === true) {
|
|
180
|
-
const executeAllowsPrivateNetwork = parsed.command === 'execute' &&
|
|
181
|
-
(parsed.values.local === true ||
|
|
182
|
-
(await import('./target.js')).resolveTarget({
|
|
183
|
-
command: 'execute',
|
|
184
|
-
flag: typeof parsed.values.target === 'string'
|
|
185
|
-
? parsed.values.target
|
|
186
|
-
: undefined,
|
|
187
|
-
}) === 'mock');
|
|
188
|
-
if (parsed.command !== 'dev' && !executeAllowsPrivateNetwork) {
|
|
189
|
-
throw new Error('--allow-private-network can only be used with execute --local, execute --target mock, or kody dev.');
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
if (parsed.values['reset-storage'] === true &&
|
|
193
|
-
parsed.command !== 'dev' &&
|
|
194
|
-
parsed.command !== 'execute' &&
|
|
195
|
-
parsed.command !== 'search') {
|
|
196
|
-
throw new Error('`--reset-storage` is only used with --target mock on execute, search, or dev.');
|
|
197
|
-
}
|
|
198
|
-
if (parsed.values['dry-run'] === true && parsed.command !== 'dev') {
|
|
199
|
-
throw new Error('`--dry-run` is only used with `kody dev job|webhook|emit` (shows the plan without invoking).');
|
|
200
|
-
}
|
|
201
|
-
if (typeof parsed.values.passthrough === 'string' &&
|
|
202
|
-
parsed.command !== 'dev' &&
|
|
203
|
-
parsed.command !== 'execute') {
|
|
204
|
-
throw new Error('`--passthrough` is only used with `execute --target mock` or `kody dev` when `.kody/mocks.ts` is active.');
|
|
205
|
-
}
|
|
206
|
-
const orgFlag = typeof parsed.values.org === 'string' ? parsed.values.org : undefined;
|
|
207
|
-
if (orgFlag !== undefined && !orgScopedCommands.has(parsed.command)) {
|
|
208
|
-
throw new Error(`\`--org\` is not used with \`kody ${parsed.command}\`. Use it with login, logout, whoami, search, api, package, execute, or auth.`);
|
|
209
|
-
}
|
|
210
|
-
// Login/logout honor `--org` only — not KODY_ORG (that env is for one-shot
|
|
211
|
-
// org-scoped commands and must not bind browser login or change logout).
|
|
212
|
-
const orgFlagOnly = orgFlag !== undefined ? orgSlugFromFlag(orgFlag) : undefined;
|
|
213
|
-
const org = resolveOrgSlug({ flag: orgFlag });
|
|
214
|
-
switch (parsed.command) {
|
|
215
|
-
case 'help':
|
|
216
|
-
write(buildUsage({ mcpUrl }));
|
|
217
|
-
return 0;
|
|
218
|
-
case 'version':
|
|
219
|
-
write(`${readPackageVersion()}\n`);
|
|
220
|
-
return 0;
|
|
221
|
-
case 'login': {
|
|
222
|
-
const { login } = await import('./auth.js');
|
|
223
|
-
write('Opening the Kody login page in your browser…\n');
|
|
224
|
-
const result = await login({
|
|
225
|
-
mcpUrl,
|
|
226
|
-
...(orgFlagOnly ? { org: orgFlagOnly } : {}),
|
|
227
|
-
openBrowser: parsed.values['no-browser'] !== true,
|
|
228
|
-
onAuthorizationUrl: (url) => {
|
|
229
|
-
write(`If the browser does not open, visit:\n${url.href}\n`);
|
|
230
|
-
},
|
|
231
|
-
});
|
|
232
|
-
const orgLabel = result.org
|
|
233
|
-
? ` as org ${result.org}`
|
|
234
|
-
: result.credentials.org
|
|
235
|
-
? ` as org ${result.credentials.org}`
|
|
236
|
-
: '';
|
|
237
|
-
const accountLabel = result.account?.email
|
|
238
|
-
? ` (${result.account.email})`
|
|
239
|
-
: result.account?.displayName
|
|
240
|
-
? ` (${result.account.displayName})`
|
|
241
|
-
: '';
|
|
242
|
-
write(`Logged in to ${result.credentials.mcpUrl}${orgLabel}${accountLabel}.\n`);
|
|
243
|
-
if (result.backendKind === 'file' && result.backendPath) {
|
|
244
|
-
write(`OS keychain was unavailable; credentials saved at ${result.backendPath} (mode 0600).\n`);
|
|
245
|
-
}
|
|
246
|
-
else {
|
|
247
|
-
write('Credentials stored in the OS keychain.\n');
|
|
248
|
-
}
|
|
249
|
-
return 0;
|
|
250
|
-
}
|
|
251
|
-
case 'logout': {
|
|
252
|
-
const apiUrl = apiUrlFrom({
|
|
253
|
-
apiUrl: typeof parsed.values['api-url'] === 'string'
|
|
254
|
-
? parsed.values['api-url']
|
|
255
|
-
: undefined,
|
|
256
|
-
});
|
|
257
|
-
const oauth = deleteCredentials(mcpUrl, undefined, undefined, orgFlagOnly ? { org: orgFlagOnly } : undefined);
|
|
258
|
-
// Clear the bootstrap/API token only when removing the last org login
|
|
259
|
-
// or when not targeting a specific remaining multi-org set.
|
|
260
|
-
const clearApiToken = !orgFlagOnly || oauth.remaining === 0;
|
|
261
|
-
const apiToken = clearApiToken
|
|
262
|
-
? deleteStoredApiToken(apiUrl)
|
|
263
|
-
: { deleted: false };
|
|
264
|
-
if (!oauth.deleted && !apiToken.deleted) {
|
|
265
|
-
write(orgFlagOnly
|
|
266
|
-
? `No stored login for org "${orgFlagOnly}".\n`
|
|
267
|
-
: 'No stored credentials.\n');
|
|
268
|
-
return 0;
|
|
269
|
-
}
|
|
270
|
-
const parts = [];
|
|
271
|
-
if (oauth.deleted) {
|
|
272
|
-
parts.push(orgFlagOnly
|
|
273
|
-
? `Logged out of org ${orgFlagOnly}.`
|
|
274
|
-
: 'Logged out of the active org (kody login).');
|
|
275
|
-
}
|
|
276
|
-
if (apiToken.deleted)
|
|
277
|
-
parts.push('Cleared stored bootstrap/API token.');
|
|
278
|
-
write(`${parts.join(' ')}\n`);
|
|
279
|
-
return 0;
|
|
280
|
-
}
|
|
281
|
-
case 'org': {
|
|
282
|
-
const { chooseOrgInteractively, formatOrgListHuman, formatOrgListJson, useOrg, } = await import('./org.js');
|
|
283
|
-
const { listStoredOrgs } = await import('./store.js');
|
|
284
|
-
const action = parsed.positionals[0];
|
|
285
|
-
if (action === 'list') {
|
|
286
|
-
const orgs = listStoredOrgs(mcpUrl);
|
|
287
|
-
write(json ? formatOrgListJson(orgs) : formatOrgListHuman(orgs));
|
|
288
|
-
return orgs.length === 0 ? 1 : 0;
|
|
289
|
-
}
|
|
290
|
-
if (action === 'use') {
|
|
291
|
-
const slugArg = parsed.positionals[1];
|
|
292
|
-
if (slugArg) {
|
|
293
|
-
const next = useOrg(slugArg, mcpUrl);
|
|
294
|
-
write(`Active org is now ${next.activeOrg}.\n`);
|
|
295
|
-
return 0;
|
|
296
|
-
}
|
|
297
|
-
const orgs = listStoredOrgs(mcpUrl);
|
|
298
|
-
const chosen = await chooseOrgInteractively({ orgs });
|
|
299
|
-
const next = useOrg(chosen, mcpUrl);
|
|
300
|
-
write(`Active org is now ${next.activeOrg}.\n`);
|
|
301
|
-
return 0;
|
|
302
|
-
}
|
|
303
|
-
throw new Error('Usage: kody org list [--json] | kody org use [<slug>]');
|
|
304
|
-
}
|
|
305
|
-
case 'status': {
|
|
306
|
-
const apiUrl = apiUrlFrom({
|
|
307
|
-
apiUrl: typeof parsed.values['api-url'] === 'string'
|
|
308
|
-
? parsed.values['api-url']
|
|
309
|
-
: undefined,
|
|
310
|
-
});
|
|
311
|
-
// Status always reports the active (or pending) login — not KODY_ORG.
|
|
312
|
-
const credentials = loadCredentials(mcpUrl);
|
|
313
|
-
const orgs = listStoredOrgs(mcpUrl);
|
|
314
|
-
const storedApi = loadStoredApiToken(apiUrl);
|
|
315
|
-
if (!credentials && orgs.length === 0 && !storedApi) {
|
|
316
|
-
write('Not logged in.\n');
|
|
317
|
-
return 1;
|
|
318
|
-
}
|
|
319
|
-
const lines = [];
|
|
320
|
-
if (credentials || orgs.length > 0) {
|
|
321
|
-
const expires = credentials?.expiresAt
|
|
322
|
-
? new Date(credentials.expiresAt).toISOString()
|
|
323
|
-
: 'unknown';
|
|
324
|
-
lines.push(`mcp: ${credentials?.mcpUrl ?? mcpUrl}`, `logged in: yes`, `active org: ${credentials?.org ?? orgs.find((row) => row.active)?.slug ?? '(pending)'}`, `orgs: ${orgs.map((row) => (row.active ? `${row.slug}*` : row.slug)).join(', ') || '(pending)'}`, `access token expires: ${expires}`, `refresh token: ${credentials?.refreshToken ? 'yes' : 'no'}`, `scope: ${credentials?.scope ?? 'unknown'}`);
|
|
325
|
-
}
|
|
326
|
-
else {
|
|
327
|
-
lines.push(`mcp: ${mcpUrl}`, `logged in: no`);
|
|
328
|
-
}
|
|
329
|
-
if (storedApi) {
|
|
330
|
-
const scopes = storedApi.scopes?.join(', ') || '(unknown)';
|
|
331
|
-
lines.push(`api: ${storedApi.apiUrl}`, `stored API token: yes (${storedApi.tokenId})`, `API token scopes: ${scopes}`, `API token expires: ${storedApi.expiresAt ?? 'unknown'}`, `API token via: ${storedApi.createdVia ?? 'unknown'}`);
|
|
332
|
-
}
|
|
333
|
-
else {
|
|
334
|
-
lines.push(`api: ${apiUrl}`, `stored API token: no`);
|
|
335
|
-
}
|
|
336
|
-
lines.push('');
|
|
337
|
-
write(lines.join('\n'));
|
|
338
|
-
return 0;
|
|
339
|
-
}
|
|
340
|
-
case 'auth': {
|
|
341
|
-
const action = parsed.positionals[0];
|
|
342
|
-
if (action === 'setup-git') {
|
|
343
|
-
return runAuthSetupGit({
|
|
344
|
-
values: parsed.values,
|
|
345
|
-
mcpUrl,
|
|
346
|
-
write,
|
|
347
|
-
...(org ? { org } : {}),
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
if (action === 'remove-git') {
|
|
351
|
-
return runAuthRemoveGit({
|
|
352
|
-
values: parsed.values,
|
|
353
|
-
mcpUrl,
|
|
354
|
-
write,
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
if (action !== 'bootstrap') {
|
|
358
|
-
throw new Error('Usage: kody auth bootstrap (…) | kody auth setup-git […] | kody auth remove-git [--api-url <url>] [--mcp-url <url>]');
|
|
359
|
-
}
|
|
360
|
-
const code = typeof parsed.values.code === 'string' ? parsed.values.code.trim() : '';
|
|
361
|
-
const scopes = parseCliScopesFlag(typeof parsed.values.scopes === 'string' ? parsed.values.scopes : undefined);
|
|
362
|
-
if (!code && !scopes) {
|
|
363
|
-
throw new Error('Provide --code <kody_bc_…> from cliCredentialBootstrap (MCP api / kody.cliCredentialBootstrap), or --scopes <list> to mint one with the current kody login session or API token.');
|
|
364
|
-
}
|
|
365
|
-
const lifetime = resolveCliTokenLifetime({
|
|
366
|
-
lifetime: typeof parsed.values.lifetime === 'string'
|
|
367
|
-
? parsed.values.lifetime
|
|
368
|
-
: undefined,
|
|
369
|
-
idleTtlSeconds: parseCliLifetimeSecondsFlag(typeof parsed.values['idle-ttl-seconds'] === 'string'
|
|
370
|
-
? parsed.values['idle-ttl-seconds']
|
|
371
|
-
: undefined, '--idle-ttl-seconds'),
|
|
372
|
-
maxLifetimeSeconds: parseCliLifetimeSecondsFlag(typeof parsed.values['max-lifetime-seconds'] === 'string'
|
|
373
|
-
? parsed.values['max-lifetime-seconds']
|
|
374
|
-
: undefined, '--max-lifetime-seconds'),
|
|
375
|
-
});
|
|
376
|
-
const apiUrl = apiUrlFrom({
|
|
377
|
-
apiUrl: typeof parsed.values['api-url'] === 'string'
|
|
378
|
-
? parsed.values['api-url']
|
|
379
|
-
: undefined,
|
|
380
|
-
});
|
|
381
|
-
if (code && scopes) {
|
|
382
|
-
throw new Error(`--scopes cannot change a bootstrap code: its scopes are fixed when it is minted. From Kody MCP, call \`${cliBootstrapMintCall(scopes, bootstrapMintLifetimeFields(lifetime))}\` and redeem the new code, or drop --code to mint with the current kody login session or API token.`);
|
|
383
|
-
}
|
|
384
|
-
const result = scopes
|
|
385
|
-
? await authBootstrapWithScopes({
|
|
386
|
-
scopes,
|
|
387
|
-
lifetime,
|
|
388
|
-
apiUrl,
|
|
389
|
-
mint: bootstrapMinter({
|
|
390
|
-
scopes,
|
|
391
|
-
lifetime,
|
|
392
|
-
mcpUrl,
|
|
393
|
-
apiUrl,
|
|
394
|
-
tokenValues: tokenFlagValues(parsed.values),
|
|
395
|
-
...(org ? { org } : {}),
|
|
396
|
-
}),
|
|
397
|
-
})
|
|
398
|
-
: await authBootstrap({
|
|
399
|
-
code,
|
|
400
|
-
apiUrl,
|
|
401
|
-
...(lifetime.kind === 'alias'
|
|
402
|
-
? { lifetime: lifetime.lifetime }
|
|
403
|
-
: {
|
|
404
|
-
idleTtlSeconds: lifetime.idleTtlSeconds,
|
|
405
|
-
maxLifetimeSeconds: lifetime.maxLifetimeSeconds,
|
|
406
|
-
}),
|
|
407
|
-
});
|
|
408
|
-
const storedScopes = result.stored.scopes?.join(', ') || '(none)';
|
|
409
|
-
write([
|
|
410
|
-
`Bootstrap API token stored for execute --local, search, whoami, api, and token-auth cloud execute.`,
|
|
411
|
-
`api: ${result.stored.apiUrl}`,
|
|
412
|
-
`token id: ${result.stored.tokenId}`,
|
|
413
|
-
`scopes: ${storedScopes}`,
|
|
414
|
-
`expires: ${result.stored.expiresAt ?? 'unknown'}`,
|
|
415
|
-
result.backendKind === 'file' && result.backendPath
|
|
416
|
-
? `OS keychain was unavailable; token saved at ${result.backendPath} (mode 0600).`
|
|
417
|
-
: 'Token stored in the OS keychain.',
|
|
418
|
-
'',
|
|
419
|
-
].join('\n'));
|
|
420
|
-
return 0;
|
|
421
|
-
}
|
|
422
|
-
case 'git-credential': {
|
|
423
|
-
const { handleGitCredential, parseGitCredentialAction, parseGitCredentialInput, readGitCredentialStdin, } = await import('./git-credential.js');
|
|
424
|
-
const action = parseGitCredentialAction(parsed.positionals);
|
|
425
|
-
const raw = await readGitCredentialStdin(process.stdin);
|
|
426
|
-
const output = await handleGitCredential({
|
|
427
|
-
action,
|
|
428
|
-
request: parseGitCredentialInput(raw),
|
|
429
|
-
apiUrl: apiUrlFrom({
|
|
430
|
-
apiUrl: typeof parsed.values['api-url'] === 'string'
|
|
431
|
-
? parsed.values['api-url']
|
|
432
|
-
: undefined,
|
|
433
|
-
}),
|
|
434
|
-
mcpUrl,
|
|
435
|
-
});
|
|
436
|
-
if (output)
|
|
437
|
-
process.stdout.write(output);
|
|
438
|
-
return 0;
|
|
439
|
-
}
|
|
440
|
-
case 'whoami': {
|
|
441
|
-
const { resolveTarget } = await import('./target.js');
|
|
442
|
-
const target = resolveTarget({
|
|
443
|
-
command: 'whoami',
|
|
444
|
-
flag: typeof parsed.values.target === 'string' ? parsed.values.target : undefined,
|
|
445
|
-
});
|
|
446
|
-
const tokenValues = tokenFlagValues(parsed.values);
|
|
447
|
-
let apiUrl = apiUrlFrom({
|
|
448
|
-
apiUrl: typeof parsed.values['api-url'] === 'string'
|
|
449
|
-
? parsed.values['api-url']
|
|
450
|
-
: undefined,
|
|
451
|
-
});
|
|
452
|
-
if (target === 'mock') {
|
|
453
|
-
const { ensureMockTarget } = await import('./mock/mock-server.js');
|
|
454
|
-
const mock = await ensureMockTarget({
|
|
455
|
-
resetStorage: parsed.values['reset-storage'] === true,
|
|
456
|
-
...(org ? { orgSlug: org } : {}),
|
|
457
|
-
});
|
|
458
|
-
try {
|
|
459
|
-
const me = await fetch(`${mock.apiUrl}/v1/me${org ? `?org=${encodeURIComponent(org)}` : ''}`, {
|
|
460
|
-
headers: { authorization: `Bearer ${mock.token}` },
|
|
461
|
-
});
|
|
462
|
-
const body = (await me.json());
|
|
463
|
-
if (json) {
|
|
464
|
-
write(`${JSON.stringify({ target: 'mock', ...body }, null, 2)}\n`);
|
|
465
|
-
}
|
|
466
|
-
else {
|
|
467
|
-
const userId = typeof body.user_id === 'string' ? body.user_id : 'user_mock';
|
|
468
|
-
const username = typeof body.username === 'string' ? body.username : 'mock-user';
|
|
469
|
-
const orgBody = body.org && typeof body.org === 'object'
|
|
470
|
-
? body.org
|
|
471
|
-
: {};
|
|
472
|
-
write([
|
|
473
|
-
`target: mock`,
|
|
474
|
-
`api: ${mock.apiUrl}`,
|
|
475
|
-
`user: ${username} (${userId})`,
|
|
476
|
-
`org: ${orgBody.slug ?? org ?? 'mock-org'}`,
|
|
477
|
-
'',
|
|
478
|
-
].join('\n'));
|
|
479
|
-
}
|
|
480
|
-
return me.ok ? 0 : 1;
|
|
481
|
-
}
|
|
482
|
-
finally {
|
|
483
|
-
if (mock.started)
|
|
484
|
-
await mock.server.close();
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
if (shouldUseApiToken({
|
|
488
|
-
tokenValues,
|
|
489
|
-
mcpUrl,
|
|
490
|
-
apiUrl,
|
|
491
|
-
allowEnvWithoutLogin: true,
|
|
492
|
-
...(org ? { org } : {}),
|
|
493
|
-
})) {
|
|
494
|
-
const { whoamiWithApiToken } = await import('./open-api-client.js');
|
|
495
|
-
const identity = await whoamiWithApiToken({
|
|
496
|
-
token: requireApiToken(tokenValues, process.env, 'whoami', { apiUrl }),
|
|
497
|
-
apiUrl,
|
|
498
|
-
...(org ? { org } : {}),
|
|
499
|
-
});
|
|
500
|
-
if (json) {
|
|
501
|
-
write(`${JSON.stringify(identity, null, 2)}\n`);
|
|
502
|
-
return 0;
|
|
503
|
-
}
|
|
504
|
-
const scopeLine = identity.token.scopes.join(', ') || '(none)';
|
|
505
|
-
const userLine = identity.user
|
|
506
|
-
? `${identity.user.displayName} <${identity.user.email}>`
|
|
507
|
-
: '(account:read not on this token)';
|
|
508
|
-
write([
|
|
509
|
-
`api: ${identity.apiUrl}`,
|
|
510
|
-
`auth: API token (${identity.token.id})`,
|
|
511
|
-
`user: ${userLine}`,
|
|
512
|
-
`scopes: ${scopeLine}`,
|
|
513
|
-
`expires: ${identity.token.expiresAt ?? 'unknown'}`,
|
|
514
|
-
'',
|
|
515
|
-
].join('\n'));
|
|
516
|
-
return 0;
|
|
517
|
-
}
|
|
518
|
-
const [{ ensureFreshCredentials }, { listKodyTools }] = await Promise.all([
|
|
519
|
-
import('./auth.js'),
|
|
520
|
-
import('./mcp.js'),
|
|
521
|
-
]);
|
|
522
|
-
const credentials = await ensureFreshCredentials({ mcpUrl, org });
|
|
523
|
-
const tools = await listKodyTools({ mcpUrl, org });
|
|
524
|
-
if (json) {
|
|
525
|
-
write(`${JSON.stringify({
|
|
526
|
-
mcpUrl: credentials.mcpUrl,
|
|
527
|
-
org: credentials.org ?? null,
|
|
528
|
-
protocol: modernMcpProtocolVersion,
|
|
529
|
-
scope: credentials.scope ?? null,
|
|
530
|
-
tools: tools.map((tool) => tool.name),
|
|
531
|
-
}, null, 2)}\n`);
|
|
532
|
-
return 0;
|
|
533
|
-
}
|
|
534
|
-
const orgLine = credentials.org ? `\norg: ${credentials.org}` : '';
|
|
535
|
-
write(`Connected to ${credentials.mcpUrl} (${modernMcpProtocolVersion})${orgLine}\nTools: ${tools.map((tool) => tool.name).join(', ') || '(none)'}\n`);
|
|
536
|
-
return 0;
|
|
537
|
-
}
|
|
538
|
-
case 'search': {
|
|
539
|
-
const { resolveTarget } = await import('./target.js');
|
|
540
|
-
const target = resolveTarget({
|
|
541
|
-
command: 'search',
|
|
542
|
-
flag: typeof parsed.values.target === 'string' ? parsed.values.target : undefined,
|
|
543
|
-
});
|
|
544
|
-
const query = parsed.positionals.join(' ').trim();
|
|
545
|
-
const tokenValues = tokenFlagValues(parsed.values);
|
|
546
|
-
let apiUrl = apiUrlFrom({
|
|
547
|
-
apiUrl: typeof parsed.values['api-url'] === 'string'
|
|
548
|
-
? parsed.values['api-url']
|
|
549
|
-
: undefined,
|
|
550
|
-
});
|
|
551
|
-
let closeMock;
|
|
552
|
-
try {
|
|
553
|
-
if (target === 'mock') {
|
|
554
|
-
const { ensureMockTarget } = await import('./mock/mock-server.js');
|
|
555
|
-
const mock = await ensureMockTarget({
|
|
556
|
-
resetStorage: parsed.values['reset-storage'] === true,
|
|
557
|
-
});
|
|
558
|
-
apiUrl = mock.apiUrl;
|
|
559
|
-
closeMock = mock.started ? () => mock.server.close() : undefined;
|
|
560
|
-
const { searchWithApiToken } = await import('./open-api-client.js');
|
|
561
|
-
const result = await searchWithApiToken({
|
|
562
|
-
token: mock.token,
|
|
563
|
-
apiUrl,
|
|
564
|
-
query: query || undefined,
|
|
565
|
-
entity: typeof parsed.values.entity === 'string'
|
|
566
|
-
? parsed.values.entity
|
|
567
|
-
: undefined,
|
|
568
|
-
domain: typeof parsed.values.domain === 'string'
|
|
569
|
-
? parsed.values.domain
|
|
570
|
-
: undefined,
|
|
571
|
-
limit: typeof parsed.values.limit === 'string'
|
|
572
|
-
? Number(parsed.values.limit)
|
|
573
|
-
: undefined,
|
|
574
|
-
});
|
|
575
|
-
write(formatToolResult(result, json));
|
|
576
|
-
return result.isError ? 1 : 0;
|
|
577
|
-
}
|
|
578
|
-
if (shouldUseApiToken({
|
|
579
|
-
tokenValues,
|
|
580
|
-
mcpUrl,
|
|
581
|
-
apiUrl,
|
|
582
|
-
allowEnvWithoutLogin: true,
|
|
583
|
-
...(org ? { org } : {}),
|
|
584
|
-
})) {
|
|
585
|
-
const { searchWithApiToken } = await import('./open-api-client.js');
|
|
586
|
-
const result = await searchWithApiToken({
|
|
587
|
-
token: requireApiToken(tokenValues, process.env, 'search', { apiUrl }),
|
|
588
|
-
apiUrl,
|
|
589
|
-
...(org ? { org } : {}),
|
|
590
|
-
query: query || undefined,
|
|
591
|
-
entity: typeof parsed.values.entity === 'string'
|
|
592
|
-
? parsed.values.entity
|
|
593
|
-
: undefined,
|
|
594
|
-
domain: typeof parsed.values.domain === 'string'
|
|
595
|
-
? parsed.values.domain
|
|
596
|
-
: undefined,
|
|
597
|
-
limit: typeof parsed.values.limit === 'string'
|
|
598
|
-
? Number(parsed.values.limit)
|
|
599
|
-
: undefined,
|
|
600
|
-
});
|
|
601
|
-
write(formatToolResult(result, json));
|
|
602
|
-
return result.isError ? 1 : 0;
|
|
603
|
-
}
|
|
604
|
-
const args = {};
|
|
605
|
-
if (query)
|
|
606
|
-
args.query = query;
|
|
607
|
-
if (typeof parsed.values.entity === 'string')
|
|
608
|
-
args.entity = parsed.values.entity;
|
|
609
|
-
if (typeof parsed.values.domain === 'string')
|
|
610
|
-
args.domain = parsed.values.domain;
|
|
611
|
-
if (typeof parsed.values.limit === 'string')
|
|
612
|
-
args.limit = Number(parsed.values.limit);
|
|
613
|
-
const { callKodyTool } = await import('./mcp.js');
|
|
614
|
-
const result = await callKodyTool({
|
|
615
|
-
name: 'search',
|
|
616
|
-
args,
|
|
617
|
-
mcpUrl,
|
|
618
|
-
...(org ? { org } : {}),
|
|
619
|
-
});
|
|
620
|
-
write(formatToolResult(result, json));
|
|
621
|
-
return result.isError ? 1 : 0;
|
|
622
|
-
}
|
|
623
|
-
finally {
|
|
624
|
-
await closeMock?.();
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
case 'execute': {
|
|
628
|
-
const { resolveTarget } = await import('./target.js');
|
|
629
|
-
const target = resolveTarget({
|
|
630
|
-
command: 'execute',
|
|
631
|
-
flag: typeof parsed.values.target === 'string' ? parsed.values.target : undefined,
|
|
632
|
-
});
|
|
633
|
-
const invoke = typeof parsed.values.invoke === 'string' ? parsed.values.invoke : undefined;
|
|
634
|
-
const hasCodeFlag = typeof parsed.values.code === 'string';
|
|
635
|
-
const hasFileFlag = typeof parsed.values.file === 'string';
|
|
636
|
-
const positionalModule = parsed.positionals.join('\n').trim();
|
|
637
|
-
// --target mock always runs locally against the CLI mock (no cloud sandbox).
|
|
638
|
-
const local = parsed.values.local === true || target === 'mock';
|
|
639
|
-
const tokenValues = tokenFlagValues(parsed.values);
|
|
640
|
-
const localPackageInvoke = invoke !== undefined ? await tryResolveLocalPackageInvoke(invoke) : null;
|
|
641
|
-
/**
|
|
642
|
-
* Published-package invoke (`kody:@scope/pkg/export`) minted as the
|
|
643
|
-
* same thin passthrough `--code` would use, so `--local` / `--target
|
|
644
|
-
* mock` do not need an import wrapper.
|
|
645
|
-
*/
|
|
646
|
-
let publishedInvokeCode;
|
|
647
|
-
if (local && invoke !== undefined && !localPackageInvoke) {
|
|
648
|
-
try {
|
|
649
|
-
publishedInvokeCode = resolveExecuteInvokeCode(invoke);
|
|
650
|
-
}
|
|
651
|
-
catch {
|
|
652
|
-
throw new Error(`--invoke ${JSON.stringify(invoke)} is neither a local package export nor a published package specifier. ` +
|
|
653
|
-
`From a package directory, pass an export key from package.json#exports (e.g. \`--invoke ./greet\`). ` +
|
|
654
|
-
`To call a published export locally, use \`--invoke kody:@scope/pkg/export\` (or \`@scope/pkg#export\`) — no \`--code "import …"\` wrapper needed. ` +
|
|
655
|
-
`Or pass --code / --file / a module string.`);
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
if (executeSourcesConflict({ invoke, hasCodeFlag, hasFileFlag, positionalModule })) {
|
|
659
|
-
throw new Error('--invoke cannot be combined with --code, --file, or a module string.');
|
|
660
|
-
}
|
|
661
|
-
if (local)
|
|
662
|
-
assertLocalExecuteNodeEngine();
|
|
663
|
-
const fileArg = hasFileFlag ? parsed.values.file : undefined;
|
|
664
|
-
// `--code` wins over `--file`. Only attribute the path when the file is the source.
|
|
665
|
-
const modulePath = localPackageInvoke?.modulePath ??
|
|
666
|
-
(!hasCodeFlag && fileArg !== undefined && fileArg !== '-' ? fileArg : undefined);
|
|
667
|
-
const code = publishedInvokeCode !== undefined
|
|
668
|
-
? publishedInvokeCode
|
|
669
|
-
: invoke !== undefined && !localPackageInvoke
|
|
670
|
-
? undefined
|
|
671
|
-
: hasCodeFlag
|
|
672
|
-
? parsed.values.code
|
|
673
|
-
: modulePath !== undefined && !localPackageInvoke
|
|
674
|
-
? await readFile(modulePath, 'utf8')
|
|
675
|
-
: localPackageInvoke
|
|
676
|
-
? await readFile(localPackageInvoke.modulePath, 'utf8')
|
|
677
|
-
: fileArg === '-'
|
|
678
|
-
? await readStdin()
|
|
679
|
-
: positionalModule || undefined;
|
|
680
|
-
const credentials = parseCredentialFlags(Array.isArray(parsed.values.credential)
|
|
681
|
-
? parsed.values.credential.filter((value) => typeof value === 'string')
|
|
682
|
-
: typeof parsed.values.credential === 'string'
|
|
683
|
-
? [parsed.values.credential]
|
|
684
|
-
: undefined);
|
|
685
|
-
const args = buildExecuteToolArgs({
|
|
686
|
-
// Local published invoke is already minted into `code`.
|
|
687
|
-
invoke: localPackageInvoke || publishedInvokeCode !== undefined ? undefined : invoke,
|
|
688
|
-
code: typeof code === 'string' ? code : undefined,
|
|
689
|
-
paramsJson: typeof parsed.values.params === 'string' ? parsed.values.params : undefined,
|
|
690
|
-
conversationId: typeof parsed.values['conversation-id'] === 'string'
|
|
691
|
-
? parsed.values['conversation-id']
|
|
692
|
-
: undefined,
|
|
693
|
-
credentials,
|
|
694
|
-
});
|
|
695
|
-
const prodApiUrl = apiUrlFrom({
|
|
696
|
-
apiUrl: typeof parsed.values['api-url'] === 'string'
|
|
697
|
-
? parsed.values['api-url']
|
|
698
|
-
: undefined,
|
|
699
|
-
});
|
|
700
|
-
let apiUrl = prodApiUrl;
|
|
701
|
-
const { parsePassthroughHosts } = await import('./mock/mock-fetch-gateway.js');
|
|
702
|
-
const passthroughHosts = parsePassthroughHosts(typeof parsed.values.passthrough === 'string'
|
|
703
|
-
? parsed.values.passthrough
|
|
704
|
-
: undefined);
|
|
705
|
-
if (passthroughHosts.length > 0 && target !== 'mock') {
|
|
706
|
-
// Help documents --passthrough as ignored on prod (mock-only).
|
|
707
|
-
writeErr('note: `--passthrough` is ignored on `--target prod` (outbound fetch mocking is mock-only).\n');
|
|
708
|
-
}
|
|
709
|
-
let closeMock;
|
|
710
|
-
let mockToken;
|
|
711
|
-
let mockDepResolve;
|
|
712
|
-
/** Package context for --invoke or --file inside a package directory. */
|
|
713
|
-
let localPackageRun = localPackageInvoke;
|
|
714
|
-
if (!localPackageRun && local && modulePath !== undefined) {
|
|
715
|
-
try {
|
|
716
|
-
const { loadPackageManifest } = await import('./package-manifest.js');
|
|
717
|
-
const manifest = await loadPackageManifest(process.cwd());
|
|
718
|
-
localPackageRun = {
|
|
719
|
-
modulePath,
|
|
720
|
-
kodyId: manifest.kodyId,
|
|
721
|
-
packageRoot: manifest.root,
|
|
722
|
-
};
|
|
723
|
-
}
|
|
724
|
-
catch {
|
|
725
|
-
localPackageRun = null;
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
try {
|
|
729
|
-
if (target === 'mock') {
|
|
730
|
-
const { ensureMockTarget } = await import('./mock/mock-server.js');
|
|
731
|
-
const mock = await ensureMockTarget({
|
|
732
|
-
resetStorage: parsed.values['reset-storage'] === true,
|
|
733
|
-
packageId: localPackageRun
|
|
734
|
-
? `local:${localPackageRun.kodyId}`
|
|
735
|
-
: undefined,
|
|
736
|
-
...(org ? { orgSlug: org } : {}),
|
|
737
|
-
});
|
|
738
|
-
apiUrl = mock.apiUrl;
|
|
739
|
-
mockToken = mock.token;
|
|
740
|
-
closeMock = mock.started ? () => mock.server.close() : undefined;
|
|
741
|
-
const { tryResolveMockDepResolve } = await import('./mock-dep-resolve.js');
|
|
742
|
-
mockDepResolve = await tryResolveMockDepResolve({
|
|
743
|
-
tokenValues,
|
|
744
|
-
apiUrl: prodApiUrl,
|
|
745
|
-
mcpUrl,
|
|
746
|
-
...(org ? { org } : {}),
|
|
747
|
-
});
|
|
748
|
-
}
|
|
749
|
-
if (localPackageRun) {
|
|
750
|
-
const { buildLocalPackageContext, runLocalPackageModule } = await import('./local-package-run.js');
|
|
751
|
-
const result = await runLocalPackageModule({
|
|
752
|
-
modulePath: localPackageRun.modulePath,
|
|
753
|
-
params: args.params,
|
|
754
|
-
token: mockToken ??
|
|
755
|
-
(await resolveLocalExecuteBearer({
|
|
756
|
-
tokenValues,
|
|
757
|
-
mcpUrl,
|
|
758
|
-
apiUrl,
|
|
759
|
-
purpose: 'execute local package export',
|
|
760
|
-
...(org ? { org } : {}),
|
|
761
|
-
})),
|
|
762
|
-
apiUrl,
|
|
763
|
-
target,
|
|
764
|
-
packageContext: buildLocalPackageContext({
|
|
765
|
-
kodyId: localPackageRun.kodyId,
|
|
766
|
-
hostedUrl: 'http://127.0.0.1:0',
|
|
767
|
-
}),
|
|
768
|
-
packageRoot: localPackageRun.packageRoot,
|
|
769
|
-
...(org ? { org } : {}),
|
|
770
|
-
...(mockDepResolve ? { depResolve: mockDepResolve } : {}),
|
|
771
|
-
...(passthroughHosts.length > 0 && target === 'mock'
|
|
772
|
-
? { passthroughHosts }
|
|
773
|
-
: {}),
|
|
774
|
-
allowPrivateNetwork: parsed.values['allow-private-network'] === true,
|
|
775
|
-
onStatus: (message) => writeErr(`${message}\n`),
|
|
776
|
-
});
|
|
777
|
-
write(formatToolResult(result, json));
|
|
778
|
-
return result.isError ? 1 : 0;
|
|
779
|
-
}
|
|
780
|
-
const useToken = local ||
|
|
781
|
-
shouldUseApiToken({
|
|
782
|
-
tokenValues,
|
|
783
|
-
mcpUrl,
|
|
784
|
-
apiUrl,
|
|
785
|
-
allowEnvWithoutLogin: true,
|
|
786
|
-
...(org ? { org } : {}),
|
|
787
|
-
});
|
|
788
|
-
let packageRootForMocks;
|
|
789
|
-
if (target === 'mock') {
|
|
790
|
-
try {
|
|
791
|
-
const { loadPackageManifest } = await import('./package-manifest.js');
|
|
792
|
-
packageRootForMocks = (await loadPackageManifest(process.cwd())).root;
|
|
793
|
-
}
|
|
794
|
-
catch {
|
|
795
|
-
packageRootForMocks = undefined;
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
const result = local
|
|
799
|
-
? await (await import('./local-execute.js')).runLocalExecute({
|
|
800
|
-
code: args.code,
|
|
801
|
-
...(modulePath !== undefined ? { modulePath } : {}),
|
|
802
|
-
params: args.params,
|
|
803
|
-
conversationId: args.conversationId,
|
|
804
|
-
...(credentials !== undefined ? { credentials } : {}),
|
|
805
|
-
token: mockToken ??
|
|
806
|
-
(await resolveLocalExecuteBearer({
|
|
807
|
-
tokenValues,
|
|
808
|
-
mcpUrl,
|
|
809
|
-
apiUrl,
|
|
810
|
-
purpose: 'execute --local',
|
|
811
|
-
...(org ? { org } : {}),
|
|
812
|
-
})),
|
|
813
|
-
apiUrl,
|
|
814
|
-
target,
|
|
815
|
-
...(org ? { org } : {}),
|
|
816
|
-
...(mockDepResolve ? { depResolve: mockDepResolve } : {}),
|
|
817
|
-
...(packageRootForMocks
|
|
818
|
-
? { packageRoot: packageRootForMocks }
|
|
819
|
-
: {}),
|
|
820
|
-
...(passthroughHosts.length > 0
|
|
821
|
-
? { passthroughHosts }
|
|
822
|
-
: {}),
|
|
823
|
-
allowPrivateNetwork: parsed.values['allow-private-network'] === true,
|
|
824
|
-
onStatus: (message) => writeErr(`${message}\n`),
|
|
825
|
-
})
|
|
826
|
-
: useToken
|
|
827
|
-
? await (await import('./remote-execute.js')).runRemoteExecuteWithToken({
|
|
828
|
-
code: typeof args.code === 'string' ? args.code : undefined,
|
|
829
|
-
invoke,
|
|
830
|
-
params: args.params,
|
|
831
|
-
conversationId: args.conversationId,
|
|
832
|
-
...(credentials !== undefined ? { credentials } : {}),
|
|
833
|
-
token: requireApiToken(tokenValues, process.env, 'execute with an API token', { apiUrl }),
|
|
834
|
-
apiUrl,
|
|
835
|
-
...(org ? { org } : {}),
|
|
836
|
-
})
|
|
837
|
-
: await (await import('./mcp.js')).callKodyTool({
|
|
838
|
-
name: 'execute',
|
|
839
|
-
args,
|
|
840
|
-
mcpUrl,
|
|
841
|
-
...(org ? { org } : {}),
|
|
842
|
-
});
|
|
843
|
-
write(formatToolResult(result, json));
|
|
844
|
-
return result.isError ? 1 : 0;
|
|
845
|
-
}
|
|
846
|
-
finally {
|
|
847
|
-
await closeMock?.();
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
case 'dev': {
|
|
851
|
-
const { resolveTarget } = await import('./target.js');
|
|
852
|
-
const { parseDevPort, parseDevSubcommand, resolveDevAuth, runDevCheck, runDevEmit, runDevFetch, runDevJob, runDevServe, runDevWebhook, tryAttachedDevFetch, } = await import('./dev-command.js');
|
|
853
|
-
const target = resolveTarget({
|
|
854
|
-
command: 'dev',
|
|
855
|
-
flag: typeof parsed.values.target === 'string' ? parsed.values.target : undefined,
|
|
856
|
-
});
|
|
857
|
-
const { subcommand, rest } = parseDevSubcommand(parsed.positionals);
|
|
858
|
-
const tokenValues = tokenFlagValues(parsed.values);
|
|
859
|
-
const prodApiUrl = apiUrlFrom({
|
|
860
|
-
apiUrl: typeof parsed.values['api-url'] === 'string'
|
|
861
|
-
? parsed.values['api-url']
|
|
862
|
-
: undefined,
|
|
863
|
-
});
|
|
864
|
-
const io = { stdout: write, stderr: writeErr };
|
|
865
|
-
const bodyPath = typeof parsed.values.body === 'string' ? parsed.values.body : undefined;
|
|
866
|
-
// `check` only bundles + validates the package tree; it never talks to
|
|
867
|
-
// mock/prod, so skip auth (and the mock server) to avoid leaking a listen
|
|
868
|
-
// handle that would keep the process alive after printing results.
|
|
869
|
-
if (subcommand === 'check') {
|
|
870
|
-
return await runDevCheck({ target, json, io });
|
|
871
|
-
}
|
|
872
|
-
const dryRun = parsed.values['dry-run'] === true;
|
|
873
|
-
if (dryRun &&
|
|
874
|
-
subcommand !== 'job' &&
|
|
875
|
-
subcommand !== 'webhook' &&
|
|
876
|
-
subcommand !== 'emit') {
|
|
877
|
-
throw new Error('`--dry-run` applies to `kody dev job|webhook|emit` only (shows the plan without invoking).');
|
|
878
|
-
}
|
|
879
|
-
// Plan-only dry-run: no login, no mock listen, no --reset-storage.
|
|
880
|
-
if (dryRun) {
|
|
881
|
-
const dryAuth = { token: 'dry-run', apiUrl: prodApiUrl };
|
|
882
|
-
switch (subcommand) {
|
|
883
|
-
case 'job': {
|
|
884
|
-
const jobName = rest[0];
|
|
885
|
-
if (!jobName)
|
|
886
|
-
throw new Error('Usage: kody dev job <name>');
|
|
887
|
-
return await runDevJob({
|
|
888
|
-
target,
|
|
889
|
-
auth: dryAuth,
|
|
890
|
-
jobName,
|
|
891
|
-
json,
|
|
892
|
-
dryRun: true,
|
|
893
|
-
io,
|
|
894
|
-
});
|
|
895
|
-
}
|
|
896
|
-
case 'webhook': {
|
|
897
|
-
const webhookName = rest[0];
|
|
898
|
-
if (!webhookName || !bodyPath) {
|
|
899
|
-
throw new Error('Usage: kody dev webhook <name> --body file.json');
|
|
900
|
-
}
|
|
901
|
-
return await runDevWebhook({
|
|
902
|
-
target,
|
|
903
|
-
auth: dryAuth,
|
|
904
|
-
webhookName,
|
|
905
|
-
bodyPath,
|
|
906
|
-
json,
|
|
907
|
-
dryRun: true,
|
|
908
|
-
io,
|
|
909
|
-
});
|
|
910
|
-
}
|
|
911
|
-
case 'emit': {
|
|
912
|
-
const event = rest[0];
|
|
913
|
-
if (!event || !bodyPath) {
|
|
914
|
-
throw new Error('Usage: kody dev emit <event> --body event.json');
|
|
915
|
-
}
|
|
916
|
-
return await runDevEmit({
|
|
917
|
-
target,
|
|
918
|
-
auth: dryAuth,
|
|
919
|
-
event,
|
|
920
|
-
bodyPath,
|
|
921
|
-
json,
|
|
922
|
-
dryRun: true,
|
|
923
|
-
io,
|
|
924
|
-
});
|
|
925
|
-
}
|
|
926
|
-
default: {
|
|
927
|
-
throw new Error('`--dry-run` applies to `kody dev job|webhook|emit` only (shows the plan without invoking).');
|
|
928
|
-
}
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
if (subcommand === 'fetch' && parsed.values['no-attach'] !== true && rest[0]) {
|
|
932
|
-
const attached = await tryAttachedDevFetch({
|
|
933
|
-
target,
|
|
934
|
-
path: rest[0],
|
|
935
|
-
method: typeof parsed.values.method === 'string' ? parsed.values.method : undefined,
|
|
936
|
-
body: bodyPath ? await readFile(bodyPath, 'utf8') : undefined,
|
|
937
|
-
json,
|
|
938
|
-
io,
|
|
939
|
-
});
|
|
940
|
-
if (attached !== null)
|
|
941
|
-
return attached;
|
|
942
|
-
}
|
|
943
|
-
const token = target === 'prod'
|
|
944
|
-
? await resolveLocalExecuteBearer({
|
|
945
|
-
tokenValues,
|
|
946
|
-
mcpUrl,
|
|
947
|
-
apiUrl: prodApiUrl,
|
|
948
|
-
purpose: 'kody dev',
|
|
949
|
-
...(org ? { org } : {}),
|
|
950
|
-
})
|
|
951
|
-
: 'mock';
|
|
952
|
-
const mockDepResolve = target === 'mock'
|
|
953
|
-
? await (await import('./mock-dep-resolve.js')).tryResolveMockDepResolve({
|
|
954
|
-
tokenValues,
|
|
955
|
-
apiUrl: prodApiUrl,
|
|
956
|
-
mcpUrl,
|
|
957
|
-
...(org ? { org } : {}),
|
|
958
|
-
})
|
|
959
|
-
: undefined;
|
|
960
|
-
const { parsePassthroughHosts } = await import('./mock/mock-fetch-gateway.js');
|
|
961
|
-
const passthroughHosts = parsePassthroughHosts(typeof parsed.values.passthrough === 'string'
|
|
962
|
-
? parsed.values.passthrough
|
|
963
|
-
: undefined);
|
|
964
|
-
if (passthroughHosts.length > 0 && target !== 'mock') {
|
|
965
|
-
writeErr('note: `--passthrough` is ignored on `--target prod` (outbound fetch mocking is mock-only).\n');
|
|
966
|
-
}
|
|
967
|
-
const allowPrivateNetwork = parsed.values['allow-private-network'] === true;
|
|
968
|
-
let packageId;
|
|
969
|
-
try {
|
|
970
|
-
const { loadPackageManifest } = await import('./package-manifest.js');
|
|
971
|
-
const manifest = await loadPackageManifest(process.cwd());
|
|
972
|
-
packageId = `local:${manifest.kodyId}`;
|
|
973
|
-
}
|
|
974
|
-
catch {
|
|
975
|
-
packageId = undefined;
|
|
976
|
-
}
|
|
977
|
-
const auth = await resolveDevAuth({
|
|
978
|
-
target,
|
|
979
|
-
token,
|
|
980
|
-
apiUrl: prodApiUrl,
|
|
981
|
-
...(org ? { org } : {}),
|
|
982
|
-
...(mockDepResolve ? { depResolve: mockDepResolve } : {}),
|
|
983
|
-
...(passthroughHosts.length > 0 && target === 'mock'
|
|
984
|
-
? { passthroughHosts }
|
|
985
|
-
: {}),
|
|
986
|
-
resetStorage: parsed.values['reset-storage'] === true,
|
|
987
|
-
...(packageId ? { packageId } : {}),
|
|
988
|
-
...(org && target === 'mock' ? { orgSlug: org } : {}),
|
|
989
|
-
});
|
|
990
|
-
const port = typeof parsed.values.port === 'string' ? parseDevPort(parsed.values.port) : undefined;
|
|
991
|
-
const appBasePath = typeof parsed.values['app-base-path'] === 'string'
|
|
992
|
-
? parsed.values['app-base-path']
|
|
993
|
-
: undefined;
|
|
994
|
-
try {
|
|
995
|
-
switch (subcommand) {
|
|
996
|
-
case 'serve':
|
|
997
|
-
return await runDevServe({
|
|
998
|
-
target,
|
|
999
|
-
auth,
|
|
1000
|
-
port,
|
|
1001
|
-
appBasePath,
|
|
1002
|
-
allowPrivateNetwork,
|
|
1003
|
-
liveReload: parsed.values['no-live-reload'] !== true,
|
|
1004
|
-
json,
|
|
1005
|
-
...(typeof parsed.values['ready-file'] === 'string'
|
|
1006
|
-
? { readyFile: parsed.values['ready-file'] }
|
|
1007
|
-
: {}),
|
|
1008
|
-
io,
|
|
1009
|
-
});
|
|
1010
|
-
case 'fetch': {
|
|
1011
|
-
const path = rest[0];
|
|
1012
|
-
if (!path) {
|
|
1013
|
-
throw new Error('Usage: kody dev fetch <path> [--method GET] [--body file.json]');
|
|
1014
|
-
}
|
|
1015
|
-
let body;
|
|
1016
|
-
if (bodyPath)
|
|
1017
|
-
body = await readFile(bodyPath, 'utf8');
|
|
1018
|
-
return await runDevFetch({
|
|
1019
|
-
target,
|
|
1020
|
-
auth,
|
|
1021
|
-
path,
|
|
1022
|
-
method: typeof parsed.values.method === 'string'
|
|
1023
|
-
? parsed.values.method
|
|
1024
|
-
: undefined,
|
|
1025
|
-
body,
|
|
1026
|
-
port,
|
|
1027
|
-
appBasePath,
|
|
1028
|
-
allowPrivateNetwork,
|
|
1029
|
-
json,
|
|
1030
|
-
io,
|
|
1031
|
-
});
|
|
1032
|
-
}
|
|
1033
|
-
case 'job': {
|
|
1034
|
-
const jobName = rest[0];
|
|
1035
|
-
if (!jobName)
|
|
1036
|
-
throw new Error('Usage: kody dev job <name>');
|
|
1037
|
-
return await runDevJob({
|
|
1038
|
-
target,
|
|
1039
|
-
auth,
|
|
1040
|
-
jobName,
|
|
1041
|
-
json,
|
|
1042
|
-
allowPrivateNetwork,
|
|
1043
|
-
io,
|
|
1044
|
-
});
|
|
1045
|
-
}
|
|
1046
|
-
case 'webhook': {
|
|
1047
|
-
const webhookName = rest[0];
|
|
1048
|
-
if (!webhookName || !bodyPath) {
|
|
1049
|
-
throw new Error('Usage: kody dev webhook <name> --body file.json');
|
|
1050
|
-
}
|
|
1051
|
-
return await runDevWebhook({
|
|
1052
|
-
target,
|
|
1053
|
-
auth,
|
|
1054
|
-
webhookName,
|
|
1055
|
-
bodyPath,
|
|
1056
|
-
json,
|
|
1057
|
-
allowPrivateNetwork,
|
|
1058
|
-
io,
|
|
1059
|
-
});
|
|
1060
|
-
}
|
|
1061
|
-
case 'emit': {
|
|
1062
|
-
const event = rest[0];
|
|
1063
|
-
if (!event || !bodyPath) {
|
|
1064
|
-
throw new Error('Usage: kody dev emit <event> --body event.json');
|
|
1065
|
-
}
|
|
1066
|
-
return await runDevEmit({
|
|
1067
|
-
target,
|
|
1068
|
-
auth,
|
|
1069
|
-
event,
|
|
1070
|
-
bodyPath,
|
|
1071
|
-
json,
|
|
1072
|
-
allowPrivateNetwork,
|
|
1073
|
-
io,
|
|
1074
|
-
});
|
|
1075
|
-
}
|
|
1076
|
-
default: {
|
|
1077
|
-
const exhaustive = subcommand;
|
|
1078
|
-
throw new Error(`Unhandled kody dev subcommand: ${String(exhaustive)}`);
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
catch (error) {
|
|
1083
|
-
// Usage / surface errors after the mock started must still close it,
|
|
1084
|
-
// or the listen handle keeps the process alive (same hang as check).
|
|
1085
|
-
await auth.closeMock?.();
|
|
1086
|
-
throw error;
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
case 'api': {
|
|
1090
|
-
const operationId = parsed.positionals[0]?.trim() ?? '';
|
|
1091
|
-
if (!operationId || parsed.positionals.length > 1) {
|
|
1092
|
-
throw new Error('Usage: kody api <operationId> [--params <json>] [--token <token>] [--api-url <url>] [--json]');
|
|
1093
|
-
}
|
|
1094
|
-
const apiUrl = apiUrlFrom({
|
|
1095
|
-
apiUrl: typeof parsed.values['api-url'] === 'string'
|
|
1096
|
-
? parsed.values['api-url']
|
|
1097
|
-
: undefined,
|
|
1098
|
-
});
|
|
1099
|
-
const tokenValues = tokenFlagValues(parsed.values);
|
|
1100
|
-
const params = parseApiParamsJson(typeof parsed.values.params === 'string' ? parsed.values.params : undefined);
|
|
1101
|
-
const { callOpenApiOperation } = await import('./open-api-client.js');
|
|
1102
|
-
const result = await callOpenApiOperation({
|
|
1103
|
-
operationId,
|
|
1104
|
-
params,
|
|
1105
|
-
token: requireApiToken(tokenValues, process.env, 'api', { apiUrl }),
|
|
1106
|
-
apiUrl,
|
|
1107
|
-
...(org ? { org } : {}),
|
|
1108
|
-
});
|
|
1109
|
-
// Always JSON: mirrors MCP `api` structured results for agents/scripts.
|
|
1110
|
-
write(`${JSON.stringify(result, null, 2)}\n`);
|
|
1111
|
-
return 0;
|
|
1112
|
-
}
|
|
1113
|
-
case 'package': {
|
|
1114
|
-
const action = parsed.positionals[0];
|
|
1115
|
-
const apiUrl = apiUrlFrom({
|
|
1116
|
-
apiUrl: typeof parsed.values['api-url'] === 'string'
|
|
1117
|
-
? parsed.values['api-url']
|
|
1118
|
-
: undefined,
|
|
1119
|
-
});
|
|
1120
|
-
const tokenValues = tokenFlagValues(parsed.values);
|
|
1121
|
-
if (isPackageCollaboratorAction(action)) {
|
|
1122
|
-
const plan = parsePackageCollaboratorCommand({
|
|
1123
|
-
action,
|
|
1124
|
-
positionals: parsed.positionals.slice(1),
|
|
1125
|
-
values: parsed.values,
|
|
1126
|
-
});
|
|
1127
|
-
const token = requireApiToken(tokenValues, process.env, `package ${action}`, {
|
|
1128
|
-
apiUrl,
|
|
1129
|
-
});
|
|
1130
|
-
const { callOpenApiOperation } = await import('./open-api-client.js');
|
|
1131
|
-
write(await runPackageCollaboratorPlan({
|
|
1132
|
-
plan,
|
|
1133
|
-
json,
|
|
1134
|
-
call: (operationId, params) => callOpenApiOperation({
|
|
1135
|
-
operationId,
|
|
1136
|
-
params,
|
|
1137
|
-
token,
|
|
1138
|
-
apiUrl,
|
|
1139
|
-
...(org ? { org } : {}),
|
|
1140
|
-
}),
|
|
1141
|
-
}));
|
|
1142
|
-
return 0;
|
|
1143
|
-
}
|
|
1144
|
-
if (action !== 'publish') {
|
|
1145
|
-
throw new Error(`Usage: kody package publish [<@owner/leaf|package_id>] [--params <json>] [--token <token>] [--api-url <url>] [--org <slug>]\n${packageCollaboratorUsage}`);
|
|
1146
|
-
}
|
|
1147
|
-
const params = packagePublishParams({
|
|
1148
|
-
positional: parsed.positionals[1],
|
|
1149
|
-
paramsJson: typeof parsed.values.params === 'string' ? parsed.values.params : undefined,
|
|
1150
|
-
});
|
|
1151
|
-
const { callOpenApiOperation } = await import('./open-api-client.js');
|
|
1152
|
-
const publishToken = requireApiToken(tokenValues, process.env, 'package publish', {
|
|
1153
|
-
apiUrl,
|
|
1154
|
-
});
|
|
1155
|
-
const call = (operationId, operationParams) => callOpenApiOperation({
|
|
1156
|
-
operationId,
|
|
1157
|
-
params: operationParams,
|
|
1158
|
-
token: publishToken,
|
|
1159
|
-
apiUrl,
|
|
1160
|
-
...(org ? { org } : {}),
|
|
1161
|
-
});
|
|
1162
|
-
const result = await call('packagePublishExternalPush', await resolvePackagePublishTarget(params, call));
|
|
1163
|
-
write(`${JSON.stringify(result, null, 2)}\n`);
|
|
1164
|
-
return 0;
|
|
1165
|
-
}
|
|
1166
|
-
case 'install': {
|
|
1167
|
-
const { runInstall } = await import('./install.js');
|
|
1168
|
-
const result = await runInstall({
|
|
1169
|
-
mcpUrl,
|
|
1170
|
-
clients: typeof parsed.values.clients === 'string' ? parsed.values.clients : undefined,
|
|
1171
|
-
yes: parsed.values.yes === true,
|
|
1172
|
-
project: parsed.values.project === true,
|
|
1173
|
-
json,
|
|
1174
|
-
}, { stdout: write });
|
|
1175
|
-
return result.code;
|
|
1176
|
-
}
|
|
1177
|
-
case 'skill': {
|
|
1178
|
-
const action = parsed.positionals[0] ?? 'install';
|
|
1179
|
-
if (action !== 'install') {
|
|
1180
|
-
throw new Error('Usage: kody skill install [--project]');
|
|
1181
|
-
}
|
|
1182
|
-
const { installSkill } = await import('./skill.js');
|
|
1183
|
-
const targets = await installSkill({ project: parsed.values.project === true });
|
|
1184
|
-
write(`Installed the Kody skill to:\n${targets.map((target) => `- ${target.host}: ${target.path}`).join('\n')}\n`);
|
|
1185
|
-
return 0;
|
|
1186
|
-
}
|
|
1187
|
-
default: {
|
|
1188
|
-
const exhaustive = parsed.command;
|
|
1189
|
-
throw new Error(`Unhandled command: ${String(exhaustive)}`);
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
async function readStdin() {
|
|
1194
|
-
const chunks = [];
|
|
1195
|
-
for await (const chunk of process.stdin) {
|
|
1196
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
1197
|
-
}
|
|
1198
|
-
return Buffer.concat(chunks).toString('utf8');
|
|
1199
|
-
}
|
|
1200
|
-
async function tryResolveLocalPackageInvoke(invoke) {
|
|
1201
|
-
const trimmed = invoke.trim();
|
|
1202
|
-
if (!trimmed)
|
|
1203
|
-
return null;
|
|
1204
|
-
// Published forms (`kody:@…`, `@scope/pkg#export`) must mint passthrough —
|
|
1205
|
-
// never treat them as package.json#exports keys (Bugbot: hash invoke in
|
|
1206
|
-
// package dirs threw before resolveExecuteInvokeCode).
|
|
1207
|
-
if (isPublishedPackageInvokeSpecifier(trimmed))
|
|
1208
|
-
return null;
|
|
1209
|
-
const { loadPackageManifest, resolveExportModulePath } = await import('./package-manifest.js');
|
|
1210
|
-
const { StructuredCliError } = await import('./structured-error.js');
|
|
1211
|
-
let manifest;
|
|
1212
|
-
try {
|
|
1213
|
-
manifest = await loadPackageManifest(process.cwd());
|
|
1214
|
-
}
|
|
1215
|
-
catch {
|
|
1216
|
-
return null;
|
|
1217
|
-
}
|
|
1218
|
-
try {
|
|
1219
|
-
const modulePath = resolveExportModulePath(manifest, trimmed, {
|
|
1220
|
-
exportsOnly: true,
|
|
1221
|
-
});
|
|
1222
|
-
const { access } = await import('node:fs/promises');
|
|
1223
|
-
try {
|
|
1224
|
-
await access(modulePath);
|
|
1225
|
-
}
|
|
1226
|
-
catch {
|
|
1227
|
-
throw new StructuredCliError({
|
|
1228
|
-
code: 'dev_surface_missing',
|
|
1229
|
-
message: `No package export ${JSON.stringify(trimmed)} (path missing: ${modulePath}).`,
|
|
1230
|
-
where: manifest.packageJsonPath,
|
|
1231
|
-
fix: `Known exports: ${Object.keys(manifest.exports).join(', ') || '(none)'}.`,
|
|
1232
|
-
});
|
|
1233
|
-
}
|
|
1234
|
-
return { modulePath, kodyId: manifest.kodyId, packageRoot: manifest.root };
|
|
1235
|
-
}
|
|
1236
|
-
catch (error) {
|
|
1237
|
-
if (error instanceof StructuredCliError)
|
|
1238
|
-
throw error;
|
|
1239
|
-
return null;
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
/** True when --invoke is set alongside any code source (--code, --file, or positional). */
|
|
1243
|
-
export function executeSourcesConflict(input) {
|
|
1244
|
-
return (input.invoke !== undefined &&
|
|
1245
|
-
(input.hasCodeFlag || input.hasFileFlag || input.positionalModule.length > 0));
|
|
1246
|
-
}
|
|
1247
|
-
/**
|
|
1248
|
-
* Build MCP `execute` tool args from CLI inputs.
|
|
1249
|
-
* Pass either `invoke` or resolved `code` (from --code, --file, or a module string).
|
|
1250
|
-
*/
|
|
1251
|
-
export function buildExecuteToolArgs(input) {
|
|
1252
|
-
const invoke = input.invoke;
|
|
1253
|
-
const code = input.code;
|
|
1254
|
-
if (invoke !== undefined && code !== undefined && code.length > 0) {
|
|
1255
|
-
throw new Error('--invoke cannot be combined with --code, --file, or a module string.');
|
|
1256
|
-
}
|
|
1257
|
-
if (invoke !== undefined) {
|
|
1258
|
-
if (!invoke) {
|
|
1259
|
-
throw new Error('Provide a non-empty --invoke value.');
|
|
1260
|
-
}
|
|
1261
|
-
return attachExecuteCommonArgs({ invoke }, input);
|
|
1262
|
-
}
|
|
1263
|
-
if (code) {
|
|
1264
|
-
return attachExecuteCommonArgs({ code }, input);
|
|
1265
|
-
}
|
|
1266
|
-
throw new Error('Provide --invoke, --code, --file, or a module string.');
|
|
1267
|
-
}
|
|
1268
|
-
function attachExecuteCommonArgs(args, input) {
|
|
1269
|
-
if (input.paramsJson !== undefined) {
|
|
1270
|
-
args.params = JSON.parse(input.paramsJson);
|
|
1271
|
-
}
|
|
1272
|
-
if (input.conversationId !== undefined) {
|
|
1273
|
-
args.conversationId = input.conversationId;
|
|
1274
|
-
}
|
|
1275
|
-
if (input.credentials !== undefined) {
|
|
1276
|
-
args.credentials = input.credentials;
|
|
1277
|
-
}
|
|
1278
|
-
return args;
|
|
1279
|
-
}
|
|
1280
|
-
async function runAuthSetupGit(input) {
|
|
1281
|
-
const { authSetupGit, setupGitDefaultScopes } = await import('./setup-git.js');
|
|
1282
|
-
const apiUrl = apiUrlFrom({
|
|
1283
|
-
apiUrl: typeof input.values['api-url'] === 'string'
|
|
1284
|
-
? input.values['api-url']
|
|
1285
|
-
: undefined,
|
|
1286
|
-
});
|
|
1287
|
-
const scopes = parseCliScopesFlag(typeof input.values.scopes === 'string' ? input.values.scopes : undefined);
|
|
1288
|
-
const lifetime = resolveCliTokenLifetime({
|
|
1289
|
-
lifetime: typeof input.values.lifetime === 'string'
|
|
1290
|
-
? input.values.lifetime
|
|
1291
|
-
: 'long',
|
|
1292
|
-
idleTtlSeconds: parseCliLifetimeSecondsFlag(typeof input.values['idle-ttl-seconds'] === 'string'
|
|
1293
|
-
? input.values['idle-ttl-seconds']
|
|
1294
|
-
: undefined, '--idle-ttl-seconds'),
|
|
1295
|
-
maxLifetimeSeconds: parseCliLifetimeSecondsFlag(typeof input.values['max-lifetime-seconds'] === 'string'
|
|
1296
|
-
? input.values['max-lifetime-seconds']
|
|
1297
|
-
: undefined, '--max-lifetime-seconds'),
|
|
1298
|
-
});
|
|
1299
|
-
const tokenValues = tokenFlagValues(input.values);
|
|
1300
|
-
const mintScopes = scopes ?? setupGitDefaultScopes;
|
|
1301
|
-
const hasLoginSession = loadCredentials(input.mcpUrl, undefined, undefined, {
|
|
1302
|
-
org: input.org,
|
|
1303
|
-
}) != null;
|
|
1304
|
-
const result = await authSetupGit({
|
|
1305
|
-
apiUrl,
|
|
1306
|
-
mcpUrl: input.mcpUrl,
|
|
1307
|
-
token: tokenValues.token,
|
|
1308
|
-
hasLoginSession,
|
|
1309
|
-
...(scopes ? { scopesOverride: scopes } : {}),
|
|
1310
|
-
lifetime,
|
|
1311
|
-
mint: bootstrapMinter({
|
|
1312
|
-
scopes: mintScopes,
|
|
1313
|
-
lifetime,
|
|
1314
|
-
mcpUrl: input.mcpUrl,
|
|
1315
|
-
apiUrl,
|
|
1316
|
-
tokenValues,
|
|
1317
|
-
...(input.org ? { org: input.org } : {}),
|
|
1318
|
-
}),
|
|
1319
|
-
});
|
|
1320
|
-
input.write([
|
|
1321
|
-
`Git HTTPS credential helper installed for https://${result.host}/`,
|
|
1322
|
-
`helper: ${result.helperCommand}`,
|
|
1323
|
-
`token: ${result.minted ? 'minted' : 'reused'} ${result.tokenId} (org_binding=user)`,
|
|
1324
|
-
`scopes: ${result.scopes.join(', ') || '(none)'}`,
|
|
1325
|
-
`expires: ${result.expiresAt ?? 'unknown'}`,
|
|
1326
|
-
result.backendKind === 'file' && result.backendPath
|
|
1327
|
-
? `OS keychain was unavailable; token saved at ${result.backendPath} (mode 0600).`
|
|
1328
|
-
: result.minted
|
|
1329
|
-
? 'Token stored in the OS keychain (or existing store).'
|
|
1330
|
-
: 'Using the existing stored API token.',
|
|
1331
|
-
'',
|
|
1332
|
-
'This user-owned token authorizes every @owner/name.git you can access (all orgs).',
|
|
1333
|
-
'Try: git clone https://kody.codes/@owner/name.git',
|
|
1334
|
-
'Undo later: kody auth remove-git',
|
|
1335
|
-
'',
|
|
1336
|
-
].join('\n'));
|
|
1337
|
-
return 0;
|
|
1338
|
-
}
|
|
1339
|
-
async function runAuthRemoveGit(input) {
|
|
1340
|
-
const { authRemoveGit, formatAuthRemoveGitReport } = await import('./setup-git.js');
|
|
1341
|
-
const apiUrl = apiUrlFrom({
|
|
1342
|
-
apiUrl: typeof input.values['api-url'] === 'string'
|
|
1343
|
-
? input.values['api-url']
|
|
1344
|
-
: undefined,
|
|
1345
|
-
});
|
|
1346
|
-
const result = await authRemoveGit({
|
|
1347
|
-
apiUrl,
|
|
1348
|
-
mcpUrl: input.mcpUrl,
|
|
1349
|
-
});
|
|
1350
|
-
input.write(formatAuthRemoveGitReport(result));
|
|
1351
|
-
return 0;
|
|
1352
|
-
}
|
|
1353
|
-
/**
|
|
1354
|
-
* Pick the credential that mints a scoped bootstrap code: `--token`, else the
|
|
1355
|
-
* `kody login` session (MCP `api`), else KODY_API_TOKEN / a stored token (Open
|
|
1356
|
-
* API). A token can only mint scopes it already holds; a login session can mint
|
|
1357
|
-
* any scope the account's org role grants.
|
|
1358
|
-
*/
|
|
1359
|
-
function bootstrapMinter(input) {
|
|
1360
|
-
// Resolve credentials lazily so `auth setup-git` can validate login/token
|
|
1361
|
-
// presence (and print its own guidance) before mint runs.
|
|
1362
|
-
return async (params) => {
|
|
1363
|
-
if (shouldUseApiToken({
|
|
1364
|
-
tokenValues: input.tokenValues,
|
|
1365
|
-
mcpUrl: input.mcpUrl,
|
|
1366
|
-
apiUrl: input.apiUrl,
|
|
1367
|
-
allowEnvWithoutLogin: true,
|
|
1368
|
-
...(input.org ? { org: input.org } : {}),
|
|
1369
|
-
})) {
|
|
1370
|
-
const token = requireApiToken(input.tokenValues, process.env, 'auth bootstrap --scopes', {
|
|
1371
|
-
apiUrl: input.apiUrl,
|
|
1372
|
-
});
|
|
1373
|
-
const { callOpenApiOperation } = await import('./open-api-client.js');
|
|
1374
|
-
try {
|
|
1375
|
-
return await callOpenApiOperation({
|
|
1376
|
-
token,
|
|
1377
|
-
apiUrl: input.apiUrl,
|
|
1378
|
-
operationId: cliCredentialBootstrapOperationId,
|
|
1379
|
-
params,
|
|
1380
|
-
...(input.org ? { org: input.org } : {}),
|
|
1381
|
-
});
|
|
1382
|
-
}
|
|
1383
|
-
catch (error) {
|
|
1384
|
-
if (error instanceof Error && /cannot grant scopes it does not hold/i.test(error.message)) {
|
|
1385
|
-
throw new Error(`${error.message} A token can only mint scopes it already holds. Run \`kody login\` and retry without --token (a login session can mint any scope your org role grants), or from Kody MCP call \`${cliBootstrapMintCall(input.scopes, bootstrapMintLifetimeFields(input.lifetime))}\` and run the returned cli_command.`);
|
|
1386
|
-
}
|
|
1387
|
-
throw error;
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
1390
|
-
if (loadCredentials(input.mcpUrl, undefined, undefined, {
|
|
1391
|
-
org: input.org,
|
|
1392
|
-
})) {
|
|
1393
|
-
return (await import('./mcp.js')).callKodyApiOperation({
|
|
1394
|
-
operationId: cliCredentialBootstrapOperationId,
|
|
1395
|
-
params,
|
|
1396
|
-
mcpUrl: input.mcpUrl,
|
|
1397
|
-
...(input.org ? { org: input.org } : {}),
|
|
1398
|
-
});
|
|
1399
|
-
}
|
|
1400
|
-
throw new Error(`auth bootstrap --scopes mints with your current Kody credential, and none was found. Run \`kody login\` and retry, or from Kody MCP call \`${cliBootstrapMintCall(input.scopes, bootstrapMintLifetimeFields(input.lifetime))}\` and run the returned cli_command.`);
|
|
1401
|
-
};
|
|
1402
|
-
}
|
|
1403
|
-
function tokenFlagValues(values) {
|
|
1404
|
-
return {
|
|
1405
|
-
token: typeof values.token === 'string' ? values.token : undefined,
|
|
1406
|
-
};
|
|
1407
|
-
}
|
|
1408
|
-
/** Parse `--params` JSON for `kody api` (flat object, same as MCP `api`). */
|
|
1409
|
-
export function parseApiParamsJson(paramsJson) {
|
|
1410
|
-
if (paramsJson === undefined)
|
|
1411
|
-
return {};
|
|
1412
|
-
let parsed;
|
|
1413
|
-
try {
|
|
1414
|
-
parsed = JSON.parse(paramsJson);
|
|
1415
|
-
}
|
|
1416
|
-
catch {
|
|
1417
|
-
throw new Error('--params must be valid JSON (a flat object).');
|
|
1418
|
-
}
|
|
1419
|
-
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
1420
|
-
throw new Error('--params must be a JSON object (e.g. \'{"query":"email"}\').');
|
|
1421
|
-
}
|
|
1422
|
-
return parsed;
|
|
1423
|
-
}
|
|
1424
|
-
const packageIdUuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1425
|
-
/**
|
|
1426
|
-
* Build `packagePublishExternalPush` params for `kody package publish`.
|
|
1427
|
-
* Optional positional is `package_id` when UUID-shaped, otherwise `kody_id`.
|
|
1428
|
-
* Explicit `--params` keys win over the positional.
|
|
1429
|
-
*/
|
|
1430
|
-
export function packagePublishParams(input) {
|
|
1431
|
-
const params = parseApiParamsJson(input.paramsJson);
|
|
1432
|
-
const ref = input.positional?.trim();
|
|
1433
|
-
if (!ref)
|
|
1434
|
-
return params;
|
|
1435
|
-
if (packageIdUuidPattern.test(ref)) {
|
|
1436
|
-
if (params.package_id === undefined)
|
|
1437
|
-
params.package_id = ref;
|
|
1438
|
-
}
|
|
1439
|
-
else if (params.kody_id === undefined) {
|
|
1440
|
-
params.kody_id = ref;
|
|
1441
|
-
}
|
|
1442
|
-
return params;
|
|
1443
|
-
}
|
|
1444
|
-
/**
|
|
1445
|
-
* The publish route is `POST /v1/packages/{package_id}/external-push`, so a
|
|
1446
|
-
* package name (`@owner/leaf` or bare leaf) is resolved to its `package_id`
|
|
1447
|
-
* through `packageList` first.
|
|
1448
|
-
*/
|
|
1449
|
-
export async function resolvePackagePublishTarget(params, call) {
|
|
1450
|
-
if (params.package_id !== undefined || typeof params.kody_id !== 'string')
|
|
1451
|
-
return params;
|
|
1452
|
-
const ref = params.kody_id.trim();
|
|
1453
|
-
const listed = (await call('packageList', {}));
|
|
1454
|
-
const packages = listed.packages ?? [];
|
|
1455
|
-
const leaf = ref.includes('/') ? ref.slice(ref.lastIndexOf('/') + 1) : ref;
|
|
1456
|
-
const byName = packages.filter((pkg) => pkg.name === ref);
|
|
1457
|
-
const matches = byName.length > 0
|
|
1458
|
-
? byName
|
|
1459
|
-
: ref.startsWith('@')
|
|
1460
|
-
? []
|
|
1461
|
-
: packages.filter((pkg) => pkg.kody_id === leaf);
|
|
1462
|
-
if (matches.length !== 1) {
|
|
1463
|
-
const known = packages
|
|
1464
|
-
.map((pkg) => pkg.name)
|
|
1465
|
-
.slice(0, 20)
|
|
1466
|
-
.join(', ');
|
|
1467
|
-
throw new Error(matches.length === 0
|
|
1468
|
-
? `No saved package named "${ref}" in this org.${known ? ` Saved packages: ${known}.` : ''} Pass the scoped name (@owner/leaf), the package_id, or --org <slug> for another org.`
|
|
1469
|
-
: `"${ref}" matches several saved packages (${matches.map((pkg) => `${pkg.name} = ${pkg.package_id}`).join(', ')}). Pass the scoped name or the package_id.`);
|
|
1470
|
-
}
|
|
1471
|
-
const { kody_id: _name, ...rest } = params;
|
|
1472
|
-
return { ...rest, package_id: matches[0].package_id };
|
|
1473
|
-
}
|
|
1474
|
-
/**
|
|
1475
|
-
* Prefer a scoped API token when the user passed `--token`, or when
|
|
1476
|
-
* `KODY_API_TOKEN` / a stored bootstrap token is available and there is no
|
|
1477
|
-
* stored `kody login` session. Logged-in MCP OAuth still wins over an
|
|
1478
|
-
* env-only or stored token so a leftover token does not hijack cloud MCP
|
|
1479
|
-
* commands.
|
|
1480
|
-
*/
|
|
1481
|
-
export function shouldUseApiToken(input) {
|
|
1482
|
-
if (hasExplicitTokenFlag(input.tokenValues))
|
|
1483
|
-
return true;
|
|
1484
|
-
if (!input.allowEnvWithoutLogin)
|
|
1485
|
-
return false;
|
|
1486
|
-
if (!resolveScopedApiToken({
|
|
1487
|
-
tokenValues: input.tokenValues,
|
|
1488
|
-
env: input.env,
|
|
1489
|
-
apiUrl: input.apiUrl,
|
|
1490
|
-
loadApiToken: input.loadApiToken,
|
|
1491
|
-
})) {
|
|
1492
|
-
return false;
|
|
1493
|
-
}
|
|
1494
|
-
const loggedIn = input.hasSession ??
|
|
1495
|
-
loadCredentials(input.mcpUrl, undefined, undefined, {
|
|
1496
|
-
org: input.org,
|
|
1497
|
-
}) != null;
|
|
1498
|
-
return !loggedIn;
|
|
1499
|
-
}
|
|
1500
|
-
//# sourceMappingURL=cli.js.map
|
|
1
|
+
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
apiUrlFrom,
|
|
4
|
+
buildExecuteToolArgs,
|
|
5
|
+
executeSourcesConflict,
|
|
6
|
+
packagePublishParams,
|
|
7
|
+
parseApiParamsJson,
|
|
8
|
+
resolveCommand,
|
|
9
|
+
resolvePackagePublishTarget,
|
|
10
|
+
runCli,
|
|
11
|
+
shouldUseApiToken
|
|
12
|
+
} from "./chunk-TIL35OWA.js";
|
|
13
|
+
import "./chunk-SMURF26I.js";
|
|
14
|
+
import "./chunk-75RZUXQL.js";
|
|
15
|
+
import "./chunk-46IJPEID.js";
|
|
16
|
+
import "./chunk-PDWCKWQF.js";
|
|
17
|
+
import "./chunk-OVGXPRSY.js";
|
|
18
|
+
import {
|
|
19
|
+
resolveLocalExecuteBearer
|
|
20
|
+
} from "./chunk-VQS5YSCI.js";
|
|
21
|
+
import {
|
|
22
|
+
authBootstrap,
|
|
23
|
+
authBootstrapWithScopes,
|
|
24
|
+
bootstrapRedeemRequestBody,
|
|
25
|
+
cliTokenLifetimeAliases,
|
|
26
|
+
cliTokenLifetimeMissingError,
|
|
27
|
+
cliTokenLifetimePolicy,
|
|
28
|
+
parseCliLifetimeSecondsFlag,
|
|
29
|
+
parseCliScopesFlag,
|
|
30
|
+
redeemBootstrapCode,
|
|
31
|
+
resolveCliTokenLifetime
|
|
32
|
+
} from "./chunk-EOCV74B2.js";
|
|
33
|
+
import "./chunk-6XQP5SWX.js";
|
|
34
|
+
import "./chunk-FBVNFWR6.js";
|
|
35
|
+
import "./chunk-R4IUV5P5.js";
|
|
36
|
+
import "./chunk-BISUL7CE.js";
|
|
37
|
+
import "./chunk-G4YN6XP5.js";
|
|
38
|
+
import "./chunk-CASGRYOF.js";
|
|
39
|
+
import "./chunk-CWWHR4FH.js";
|
|
40
|
+
import "./chunk-G6LJWROP.js";
|
|
41
|
+
import {
|
|
42
|
+
readApiToken,
|
|
43
|
+
requireApiToken,
|
|
44
|
+
resolveScopedApiToken
|
|
45
|
+
} from "./chunk-RTWUNV76.js";
|
|
46
|
+
import "./chunk-RM34N3KI.js";
|
|
47
|
+
import "./chunk-IHP6PV6X.js";
|
|
48
|
+
import "./chunk-QHBCP4OB.js";
|
|
49
|
+
export {
|
|
50
|
+
apiUrlFrom,
|
|
51
|
+
authBootstrap,
|
|
52
|
+
authBootstrapWithScopes,
|
|
53
|
+
bootstrapRedeemRequestBody,
|
|
54
|
+
buildExecuteToolArgs,
|
|
55
|
+
cliTokenLifetimeAliases,
|
|
56
|
+
cliTokenLifetimeMissingError,
|
|
57
|
+
cliTokenLifetimePolicy,
|
|
58
|
+
executeSourcesConflict,
|
|
59
|
+
packagePublishParams,
|
|
60
|
+
parseApiParamsJson,
|
|
61
|
+
parseCliLifetimeSecondsFlag,
|
|
62
|
+
parseCliScopesFlag,
|
|
63
|
+
readApiToken,
|
|
64
|
+
redeemBootstrapCode,
|
|
65
|
+
requireApiToken as resolveApiToken,
|
|
66
|
+
resolveCliTokenLifetime,
|
|
67
|
+
resolveCommand,
|
|
68
|
+
resolveLocalExecuteBearer,
|
|
69
|
+
resolvePackagePublishTarget,
|
|
70
|
+
resolveScopedApiToken,
|
|
71
|
+
runCli,
|
|
72
|
+
shouldUseApiToken
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=cli.js.map
|