@openape/apes 0.6.1 → 0.7.1
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 +68 -6
- package/dist/auth-lock-SRUFWJC3.js +41 -0
- package/dist/auth-lock-SRUFWJC3.js.map +1 -0
- package/dist/{chunk-G3Q2TMAI.js → chunk-B32ZQP5K.js} +139 -190
- package/dist/chunk-B32ZQP5K.js.map +1 -0
- package/dist/{chunk-KVBHBOED.js → chunk-ION3CWD5.js} +14 -2
- package/dist/chunk-ION3CWD5.js.map +1 -0
- package/dist/chunk-TBYYREL6.js +133 -0
- package/dist/chunk-TBYYREL6.js.map +1 -0
- package/dist/cli.js +349 -213
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +11 -9
- package/dist/orchestrator-JAMWD6DD.js +637 -0
- package/dist/orchestrator-JAMWD6DD.js.map +1 -0
- package/dist/{server-FR6GFS3S.js → server-UTCZSPCU.js} +8 -6
- package/dist/{server-FR6GFS3S.js.map → server-UTCZSPCU.js.map} +1 -1
- package/dist/ssh-key-YBNNG5K5.js +10 -0
- package/package.json +4 -2
- package/dist/chunk-G3Q2TMAI.js.map +0 -1
- package/dist/chunk-KVBHBOED.js.map +0 -1
- package/dist/ssh-key-Q7KG4K25.js +0 -8
- /package/dist/{ssh-key-Q7KG4K25.js.map → ssh-key-YBNNG5K5.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -5,13 +5,13 @@ import {
|
|
|
5
5
|
parseDuration
|
|
6
6
|
} from "./chunk-ZSJU7IXE.js";
|
|
7
7
|
import {
|
|
8
|
-
loadEd25519PrivateKey
|
|
9
|
-
|
|
8
|
+
loadEd25519PrivateKey,
|
|
9
|
+
readPublicKeyComment
|
|
10
|
+
} from "./chunk-ION3CWD5.js";
|
|
10
11
|
import {
|
|
11
12
|
ApiError,
|
|
12
13
|
apiFetch,
|
|
13
14
|
buildStructuredCliGrantRequest,
|
|
14
|
-
clearAuth,
|
|
15
15
|
createShapesGrant,
|
|
16
16
|
extractOption,
|
|
17
17
|
extractShellCommandString,
|
|
@@ -23,45 +23,58 @@ import {
|
|
|
23
23
|
findExistingGrant,
|
|
24
24
|
getAgentAuthenticateEndpoint,
|
|
25
25
|
getAgentChallengeEndpoint,
|
|
26
|
-
getAuthToken,
|
|
27
26
|
getDelegationsEndpoint,
|
|
28
27
|
getGrantsEndpoint,
|
|
29
|
-
getIdpUrl,
|
|
30
28
|
getInstalledDigest,
|
|
31
29
|
installAdapter,
|
|
32
30
|
isInstalled,
|
|
33
31
|
loadAdapter,
|
|
34
|
-
loadAuth,
|
|
35
|
-
loadConfig,
|
|
36
32
|
loadOrInstallAdapter,
|
|
37
33
|
parseShellCommand,
|
|
38
34
|
removeAdapter,
|
|
39
35
|
resolveCapabilityRequest,
|
|
40
36
|
resolveCommand,
|
|
41
|
-
saveAuth,
|
|
42
|
-
saveConfig,
|
|
43
37
|
searchAdapters,
|
|
44
38
|
verifyAndExecute,
|
|
45
39
|
waitForGrantStatus
|
|
46
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-B32ZQP5K.js";
|
|
41
|
+
import {
|
|
42
|
+
clearAuth,
|
|
43
|
+
getAuthToken,
|
|
44
|
+
getIdpUrl,
|
|
45
|
+
loadAuth,
|
|
46
|
+
loadConfig,
|
|
47
|
+
saveAuth,
|
|
48
|
+
saveConfig
|
|
49
|
+
} from "./chunk-TBYYREL6.js";
|
|
47
50
|
|
|
48
51
|
// src/cli.ts
|
|
49
|
-
import
|
|
52
|
+
import consola26 from "consola";
|
|
50
53
|
|
|
51
54
|
// src/ape-shell.ts
|
|
52
55
|
import path from "path";
|
|
53
|
-
function rewriteApeShellArgs(argv) {
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
+
function rewriteApeShellArgs(argv, argv0) {
|
|
57
|
+
const rawInvokedAs = argv[1] ?? "";
|
|
58
|
+
const dashFromArgv1 = rawInvokedAs.startsWith("-");
|
|
59
|
+
const dashFromArgv0 = typeof argv0 === "string" && argv0.startsWith("-");
|
|
60
|
+
const looksLikeLoginShell = dashFromArgv1 || dashFromArgv0;
|
|
61
|
+
const normalizedInvokedAs = dashFromArgv1 ? rawInvokedAs.slice(1) : rawInvokedAs;
|
|
62
|
+
const invokedAs = path.basename(normalizedInvokedAs);
|
|
63
|
+
const wrapperEnv = typeof process !== "undefined" && process.env?.APES_SHELL_WRAPPER === "1";
|
|
64
|
+
const argvMatch = invokedAs === "ape-shell" || invokedAs === "ape-shell.js";
|
|
65
|
+
if (!wrapperEnv && !argvMatch)
|
|
56
66
|
return null;
|
|
57
67
|
const shellArgs = argv.slice(2);
|
|
58
68
|
if (shellArgs[0] === "-c" && shellArgs.length > 1) {
|
|
59
69
|
return { action: "rewrite", argv: [argv[0], argv[1], "run", "--shell", "--", "bash", "-c", ...shellArgs.slice(1)] };
|
|
60
70
|
}
|
|
61
|
-
if (shellArgs[0] === "--version")
|
|
71
|
+
if (shellArgs[0] === "--version" || shellArgs[0] === "-v")
|
|
62
72
|
return { action: "version" };
|
|
63
73
|
if (shellArgs[0] === "--help" || shellArgs[0] === "-h")
|
|
64
74
|
return { action: "help" };
|
|
75
|
+
if (shellArgs.length === 0 || shellArgs[0] === "-i" || shellArgs[0] === "-l" || shellArgs[0] === "--login" || looksLikeLoginShell) {
|
|
76
|
+
return { action: "interactive" };
|
|
77
|
+
}
|
|
65
78
|
return { action: "error" };
|
|
66
79
|
}
|
|
67
80
|
|
|
@@ -72,9 +85,74 @@ import { defineCommand as defineCommand31, runMain } from "citty";
|
|
|
72
85
|
import { Buffer } from "buffer";
|
|
73
86
|
import { execFile } from "child_process";
|
|
74
87
|
import { createServer } from "http";
|
|
88
|
+
import { homedir as homedir2 } from "os";
|
|
89
|
+
import { resolve as resolvePath } from "path";
|
|
75
90
|
import { defineCommand } from "citty";
|
|
76
91
|
import { generateCodeChallenge, generateCodeVerifier } from "@openape/core";
|
|
92
|
+
import consola2 from "consola";
|
|
93
|
+
|
|
94
|
+
// src/commands/auth/resolve-login.ts
|
|
95
|
+
import { existsSync } from "fs";
|
|
96
|
+
import { homedir } from "os";
|
|
97
|
+
import { join } from "path";
|
|
98
|
+
import { resolveDDISA } from "@openape/core";
|
|
77
99
|
import consola from "consola";
|
|
100
|
+
var DEFAULT_KEY = join(homedir(), ".ssh", "id_ed25519");
|
|
101
|
+
async function resolveLoginInputs(flags) {
|
|
102
|
+
const config = loadConfig();
|
|
103
|
+
let keyPath;
|
|
104
|
+
if (!flags.browser) {
|
|
105
|
+
if (flags.key) {
|
|
106
|
+
keyPath = flags.key;
|
|
107
|
+
} else if (process.env.APES_KEY) {
|
|
108
|
+
keyPath = process.env.APES_KEY;
|
|
109
|
+
consola.info(`Using key from APES_KEY: ${keyPath}`);
|
|
110
|
+
} else if (config.agent?.key) {
|
|
111
|
+
keyPath = config.agent.key;
|
|
112
|
+
consola.info(`Using key from config: ${keyPath}`);
|
|
113
|
+
} else if (existsSync(DEFAULT_KEY)) {
|
|
114
|
+
keyPath = DEFAULT_KEY;
|
|
115
|
+
consola.info(`Using default key: ${keyPath}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
let email;
|
|
119
|
+
if (flags.email) {
|
|
120
|
+
email = flags.email;
|
|
121
|
+
} else if (process.env.APES_EMAIL) {
|
|
122
|
+
email = process.env.APES_EMAIL;
|
|
123
|
+
} else if (config.agent?.email) {
|
|
124
|
+
email = config.agent.email;
|
|
125
|
+
} else if (keyPath) {
|
|
126
|
+
const comment = readPublicKeyComment(`${keyPath}.pub`);
|
|
127
|
+
if (comment && comment.includes("@")) {
|
|
128
|
+
email = comment;
|
|
129
|
+
consola.info(`Using email from ${keyPath}.pub comment: ${email}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
let idp;
|
|
133
|
+
if (flags.idp) {
|
|
134
|
+
idp = flags.idp;
|
|
135
|
+
} else if (process.env.APES_IDP) {
|
|
136
|
+
idp = process.env.APES_IDP;
|
|
137
|
+
} else if (process.env.GRAPES_IDP) {
|
|
138
|
+
idp = process.env.GRAPES_IDP;
|
|
139
|
+
} else if (config.defaults?.idp) {
|
|
140
|
+
idp = config.defaults.idp;
|
|
141
|
+
} else if (email && email.includes("@")) {
|
|
142
|
+
const domain = email.split("@")[1];
|
|
143
|
+
try {
|
|
144
|
+
const record = await resolveDDISA(domain);
|
|
145
|
+
if (record?.idp) {
|
|
146
|
+
idp = record.idp;
|
|
147
|
+
consola.info(`Discovered IdP via DDISA (_ddisa.${domain}): ${idp}`);
|
|
148
|
+
}
|
|
149
|
+
} catch {
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return { keyPath, email, idp };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// src/commands/auth/login.ts
|
|
78
156
|
var CALLBACK_PORT = 9876;
|
|
79
157
|
var CLIENT_ID = "grapes-cli";
|
|
80
158
|
var loginCommand = defineCommand({
|
|
@@ -85,27 +163,56 @@ var loginCommand = defineCommand({
|
|
|
85
163
|
args: {
|
|
86
164
|
idp: {
|
|
87
165
|
type: "string",
|
|
88
|
-
description: "IdP URL (e.g. https://id.openape.at)"
|
|
166
|
+
description: "IdP URL (e.g. https://id.openape.at). Auto-discovered via DDISA DNS if omitted."
|
|
89
167
|
},
|
|
90
168
|
key: {
|
|
91
169
|
type: "string",
|
|
92
|
-
description: "Path to agent private key
|
|
170
|
+
description: "Path to agent private key. Defaults to ~/.ssh/id_ed25519 if present."
|
|
93
171
|
},
|
|
94
172
|
email: {
|
|
95
173
|
type: "string",
|
|
96
|
-
description: "Agent email
|
|
174
|
+
description: "Agent email. Extracted from <key>.pub comment if omitted."
|
|
175
|
+
},
|
|
176
|
+
browser: {
|
|
177
|
+
type: "boolean",
|
|
178
|
+
description: "Force browser (PKCE) login even if an SSH key exists"
|
|
97
179
|
}
|
|
98
180
|
},
|
|
99
181
|
async run({ args }) {
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
182
|
+
const resolved = await resolveLoginInputs({
|
|
183
|
+
key: args.key,
|
|
184
|
+
idp: args.idp,
|
|
185
|
+
email: args.email,
|
|
186
|
+
browser: args.browser
|
|
187
|
+
});
|
|
188
|
+
if (resolved.keyPath) {
|
|
189
|
+
if (!resolved.email) {
|
|
190
|
+
throw new CliError(
|
|
191
|
+
`Agent email required for key-based login. Add an email comment to ${resolved.keyPath}.pub (ssh-keygen -C <email>) or pass --email <agent-email>.`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
if (!resolved.idp) {
|
|
195
|
+
const domain = resolved.email.split("@")[1];
|
|
196
|
+
throw new CliError(
|
|
197
|
+
`No IdP found for ${resolved.email}.
|
|
198
|
+
|
|
199
|
+
There is no DDISA TXT record for ${domain} and no --idp was provided.
|
|
200
|
+
|
|
201
|
+
Options:
|
|
202
|
+
\u2022 Run your own IdP (recommended for production)
|
|
203
|
+
See: https://docs.openape.at
|
|
204
|
+
\u2022 Publish a DDISA TXT record for your domain:
|
|
205
|
+
_ddisa.${domain} TXT "v=ddisa1 idp=https://your-idp.example"
|
|
206
|
+
\u2022 Use OpenApe's free hosted IdP for testing:
|
|
207
|
+
apes login --idp https://id.openape.at`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
await loginWithKey(resolved.idp, resolved.keyPath, resolved.email);
|
|
107
211
|
} else {
|
|
108
|
-
|
|
212
|
+
if (!resolved.idp) {
|
|
213
|
+
throw new CliError("IdP URL required for browser login. Use --idp <url> or set APES_IDP.");
|
|
214
|
+
}
|
|
215
|
+
await loginWithPKCE(resolved.idp);
|
|
109
216
|
}
|
|
110
217
|
}
|
|
111
218
|
});
|
|
@@ -157,7 +264,12 @@ async function loginWithPKCE(idp) {
|
|
|
157
264
|
}
|
|
158
265
|
});
|
|
159
266
|
server.listen(CALLBACK_PORT, () => {
|
|
160
|
-
|
|
267
|
+
console.log("");
|
|
268
|
+
console.log("Visit the following URL in a browser to authenticate:");
|
|
269
|
+
console.log("");
|
|
270
|
+
console.log(` ${authUrl.toString()}`);
|
|
271
|
+
console.log("");
|
|
272
|
+
consola2.info(`Waiting for authentication callback on ${redirectUri} ...`);
|
|
161
273
|
openBrowser(authUrl.toString());
|
|
162
274
|
});
|
|
163
275
|
const timeout = setTimeout(() => {
|
|
@@ -194,16 +306,12 @@ async function loginWithPKCE(idp) {
|
|
|
194
306
|
email: payload.email || payload.sub,
|
|
195
307
|
expires_at: Math.floor(Date.now() / 1e3) + (tokens.expires_in || 3600)
|
|
196
308
|
});
|
|
197
|
-
|
|
309
|
+
consola2.success(`Logged in as ${payload.email || payload.sub}`);
|
|
198
310
|
}
|
|
199
|
-
async function loginWithKey(idp, keyPath,
|
|
311
|
+
async function loginWithKey(idp, keyPath, agentEmail) {
|
|
200
312
|
const { readFileSync: readFileSync4 } = await import("fs");
|
|
201
313
|
const { sign: sign2 } = await import("crypto");
|
|
202
|
-
const { loadEd25519PrivateKey: loadEd25519PrivateKey2 } = await import("./ssh-key-
|
|
203
|
-
const agentEmail = email;
|
|
204
|
-
if (!agentEmail) {
|
|
205
|
-
throw new CliError("Agent email required for key-based login. Use --email <agent-email>");
|
|
206
|
-
}
|
|
314
|
+
const { loadEd25519PrivateKey: loadEd25519PrivateKey2 } = await import("./ssh-key-YBNNG5K5.js");
|
|
207
315
|
const challengeUrl = await getAgentChallengeEndpoint(idp);
|
|
208
316
|
const challengeResp = await fetch(challengeUrl, {
|
|
209
317
|
method: "POST",
|
|
@@ -237,12 +345,23 @@ async function loginWithKey(idp, keyPath, email) {
|
|
|
237
345
|
email: agentEmail,
|
|
238
346
|
expires_at: Math.floor(Date.now() / 1e3) + (expires_in || 3600)
|
|
239
347
|
});
|
|
240
|
-
|
|
348
|
+
const absoluteKeyPath = resolvePath(keyPath.replace(/^~/, homedir2()));
|
|
349
|
+
const existingConfig = loadConfig();
|
|
350
|
+
saveConfig({
|
|
351
|
+
...existingConfig,
|
|
352
|
+
agent: {
|
|
353
|
+
...existingConfig.agent,
|
|
354
|
+
key: absoluteKeyPath,
|
|
355
|
+
email: agentEmail
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
consola2.success(`Logged in as ${agentEmail}`);
|
|
359
|
+
consola2.info(`Auto-refresh enabled (key path saved to ~/.config/apes/config.toml)`);
|
|
241
360
|
}
|
|
242
361
|
|
|
243
362
|
// src/commands/auth/logout.ts
|
|
244
363
|
import { defineCommand as defineCommand2 } from "citty";
|
|
245
|
-
import
|
|
364
|
+
import consola3 from "consola";
|
|
246
365
|
var logoutCommand = defineCommand2({
|
|
247
366
|
meta: {
|
|
248
367
|
name: "logout",
|
|
@@ -250,13 +369,13 @@ var logoutCommand = defineCommand2({
|
|
|
250
369
|
},
|
|
251
370
|
run() {
|
|
252
371
|
clearAuth();
|
|
253
|
-
|
|
372
|
+
consola3.success("Logged out.");
|
|
254
373
|
}
|
|
255
374
|
});
|
|
256
375
|
|
|
257
376
|
// src/commands/auth/whoami.ts
|
|
258
377
|
import { defineCommand as defineCommand3 } from "citty";
|
|
259
|
-
import
|
|
378
|
+
import consola4 from "consola";
|
|
260
379
|
var whoamiCommand = defineCommand3({
|
|
261
380
|
meta: {
|
|
262
381
|
name: "whoami",
|
|
@@ -275,14 +394,14 @@ var whoamiCommand = defineCommand3({
|
|
|
275
394
|
console.log(`IdP: ${auth.idp}`);
|
|
276
395
|
console.log(`Token: ${isExpired ? "\u26A0 EXPIRED" : "valid"} (until ${expiresAt})`);
|
|
277
396
|
if (isExpired) {
|
|
278
|
-
|
|
397
|
+
consola4.warn("Token is expired. Run `apes login` to re-authenticate.");
|
|
279
398
|
}
|
|
280
399
|
}
|
|
281
400
|
});
|
|
282
401
|
|
|
283
402
|
// src/commands/grants/list.ts
|
|
284
403
|
import { defineCommand as defineCommand4 } from "citty";
|
|
285
|
-
import
|
|
404
|
+
import consola5 from "consola";
|
|
286
405
|
var listCommand = defineCommand4({
|
|
287
406
|
meta: {
|
|
288
407
|
name: "list",
|
|
@@ -331,7 +450,7 @@ var listCommand = defineCommand4({
|
|
|
331
450
|
return;
|
|
332
451
|
}
|
|
333
452
|
if (grants.length === 0) {
|
|
334
|
-
|
|
453
|
+
consola5.info(args.all ? "No grants found." : "No grants found. Use --all to see all visible grants.");
|
|
335
454
|
return;
|
|
336
455
|
}
|
|
337
456
|
for (const grant of grants) {
|
|
@@ -343,14 +462,14 @@ var listCommand = defineCommand4({
|
|
|
343
462
|
}
|
|
344
463
|
}
|
|
345
464
|
if (response.pagination.has_more) {
|
|
346
|
-
|
|
465
|
+
consola5.info("More results available. Use --limit or pagination cursor.");
|
|
347
466
|
}
|
|
348
467
|
}
|
|
349
468
|
});
|
|
350
469
|
|
|
351
470
|
// src/commands/grants/inbox.ts
|
|
352
471
|
import { defineCommand as defineCommand5 } from "citty";
|
|
353
|
-
import
|
|
472
|
+
import consola6 from "consola";
|
|
354
473
|
var inboxCommand = defineCommand5({
|
|
355
474
|
meta: {
|
|
356
475
|
name: "inbox",
|
|
@@ -389,10 +508,10 @@ var inboxCommand = defineCommand5({
|
|
|
389
508
|
return;
|
|
390
509
|
}
|
|
391
510
|
if (grants.length === 0) {
|
|
392
|
-
|
|
511
|
+
consola6.info("No pending grants to approve.");
|
|
393
512
|
return;
|
|
394
513
|
}
|
|
395
|
-
|
|
514
|
+
consola6.info(`${grants.length} grant(s) awaiting approval:
|
|
396
515
|
`);
|
|
397
516
|
for (const grant of grants) {
|
|
398
517
|
const cmd = grant.request?.command?.join(" ") || "(no command)";
|
|
@@ -407,7 +526,7 @@ var inboxCommand = defineCommand5({
|
|
|
407
526
|
}
|
|
408
527
|
console.log();
|
|
409
528
|
}
|
|
410
|
-
|
|
529
|
+
consola6.info("Use `apes grants approve <id>` or `apes grants deny <id>` to respond.");
|
|
411
530
|
}
|
|
412
531
|
});
|
|
413
532
|
|
|
@@ -463,7 +582,7 @@ var statusCommand = defineCommand6({
|
|
|
463
582
|
// src/commands/grants/request.ts
|
|
464
583
|
import { hostname } from "os";
|
|
465
584
|
import { defineCommand as defineCommand7 } from "citty";
|
|
466
|
-
import
|
|
585
|
+
import consola7 from "consola";
|
|
467
586
|
var requestCommand = defineCommand7({
|
|
468
587
|
meta: {
|
|
469
588
|
name: "request",
|
|
@@ -530,9 +649,9 @@ var requestCommand = defineCommand7({
|
|
|
530
649
|
...args["run-as"] ? { run_as: args["run-as"] } : {}
|
|
531
650
|
}
|
|
532
651
|
});
|
|
533
|
-
|
|
652
|
+
consola7.success(`Grant requested: ${grant.id} (status: ${grant.status})`);
|
|
534
653
|
if (args.wait) {
|
|
535
|
-
|
|
654
|
+
consola7.info("Waiting for approval...");
|
|
536
655
|
await waitForApproval(grantsUrl, grant.id);
|
|
537
656
|
}
|
|
538
657
|
}
|
|
@@ -544,7 +663,7 @@ async function waitForApproval(grantsUrl, grantId) {
|
|
|
544
663
|
while (Date.now() - start < maxWait) {
|
|
545
664
|
const grant = await apiFetch(`${grantsUrl}/${grantId}`);
|
|
546
665
|
if (grant.status === "approved") {
|
|
547
|
-
|
|
666
|
+
consola7.success("Grant approved!");
|
|
548
667
|
return;
|
|
549
668
|
}
|
|
550
669
|
if (grant.status === "denied") {
|
|
@@ -561,7 +680,7 @@ async function waitForApproval(grantsUrl, grantId) {
|
|
|
561
680
|
// src/commands/grants/request-capability.ts
|
|
562
681
|
import { hostname as hostname2 } from "os";
|
|
563
682
|
import { defineCommand as defineCommand8 } from "citty";
|
|
564
|
-
import
|
|
683
|
+
import consola8 from "consola";
|
|
565
684
|
function parseCapabilityArgs(rawArgs) {
|
|
566
685
|
const tokens = [...rawArgs];
|
|
567
686
|
if (tokens[0] === "request-capability") {
|
|
@@ -668,7 +787,7 @@ async function waitForApproval2(grantsUrl, grantId) {
|
|
|
668
787
|
while (Date.now() - start < maxWait) {
|
|
669
788
|
const grant = await apiFetch(`${grantsUrl}/${grantId}`);
|
|
670
789
|
if (grant.status === "approved") {
|
|
671
|
-
|
|
790
|
+
consola8.success("Grant approved!");
|
|
672
791
|
return;
|
|
673
792
|
}
|
|
674
793
|
if (grant.status === "denied") {
|
|
@@ -769,9 +888,9 @@ var requestCapabilityCommand = defineCommand8({
|
|
|
769
888
|
idp,
|
|
770
889
|
body: request
|
|
771
890
|
});
|
|
772
|
-
|
|
891
|
+
consola8.success(`Grant requested: ${grant.id} (status: ${grant.status})`);
|
|
773
892
|
if (parsed.wait) {
|
|
774
|
-
|
|
893
|
+
consola8.info("Waiting for approval...");
|
|
775
894
|
await waitForApproval2(grantsUrl, grant.id);
|
|
776
895
|
}
|
|
777
896
|
}
|
|
@@ -779,7 +898,7 @@ var requestCapabilityCommand = defineCommand8({
|
|
|
779
898
|
|
|
780
899
|
// src/commands/grants/approve.ts
|
|
781
900
|
import { defineCommand as defineCommand9 } from "citty";
|
|
782
|
-
import
|
|
901
|
+
import consola9 from "consola";
|
|
783
902
|
var approveCommand = defineCommand9({
|
|
784
903
|
meta: {
|
|
785
904
|
name: "approve",
|
|
@@ -798,13 +917,13 @@ var approveCommand = defineCommand9({
|
|
|
798
917
|
await apiFetch(`${grantsUrl}/${args.id}/approve`, {
|
|
799
918
|
method: "POST"
|
|
800
919
|
});
|
|
801
|
-
|
|
920
|
+
consola9.success(`Grant ${args.id} approved.`);
|
|
802
921
|
}
|
|
803
922
|
});
|
|
804
923
|
|
|
805
924
|
// src/commands/grants/deny.ts
|
|
806
925
|
import { defineCommand as defineCommand10 } from "citty";
|
|
807
|
-
import
|
|
926
|
+
import consola10 from "consola";
|
|
808
927
|
var denyCommand = defineCommand10({
|
|
809
928
|
meta: {
|
|
810
929
|
name: "deny",
|
|
@@ -823,13 +942,13 @@ var denyCommand = defineCommand10({
|
|
|
823
942
|
await apiFetch(`${grantsUrl}/${args.id}/deny`, {
|
|
824
943
|
method: "POST"
|
|
825
944
|
});
|
|
826
|
-
|
|
945
|
+
consola10.success(`Grant ${args.id} denied.`);
|
|
827
946
|
}
|
|
828
947
|
});
|
|
829
948
|
|
|
830
949
|
// src/commands/grants/revoke.ts
|
|
831
950
|
import { defineCommand as defineCommand11 } from "citty";
|
|
832
|
-
import
|
|
951
|
+
import consola11 from "consola";
|
|
833
952
|
var revokeCommand = defineCommand11({
|
|
834
953
|
meta: {
|
|
835
954
|
name: "revoke",
|
|
@@ -858,11 +977,11 @@ var revokeCommand = defineCommand11({
|
|
|
858
977
|
const idp = getIdpUrl();
|
|
859
978
|
const grantsUrl = await getGrantsEndpoint(idp);
|
|
860
979
|
if (args.debug) {
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
980
|
+
consola11.debug(`idp: ${idp}`);
|
|
981
|
+
consola11.debug(`grantsUrl: ${grantsUrl}`);
|
|
982
|
+
consola11.debug(`auth.email: ${auth?.email}`);
|
|
983
|
+
consola11.debug(`auth.expires_at: ${auth?.expires_at} (now: ${Math.floor(Date.now() / 1e3)})`);
|
|
984
|
+
consola11.debug(`getAuthToken(): ${token ? `${token.substring(0, 20)}...` : "NULL"}`);
|
|
866
985
|
}
|
|
867
986
|
if (!auth || !token) {
|
|
868
987
|
throw new CliError("Authentication required. Run `apes login` and try again.");
|
|
@@ -880,11 +999,11 @@ var revokeCommand = defineCommand11({
|
|
|
880
999
|
);
|
|
881
1000
|
const ownPending = auth2?.email ? response.data.filter((g) => g.request?.requester === auth2.email) : response.data;
|
|
882
1001
|
if (ownPending.length === 0) {
|
|
883
|
-
|
|
1002
|
+
consola11.info("No pending grants to revoke.");
|
|
884
1003
|
return;
|
|
885
1004
|
}
|
|
886
1005
|
ids = ownPending.map((g) => g.id);
|
|
887
|
-
|
|
1006
|
+
consola11.info(`Found ${ids.length} pending grant(s) to revoke.`);
|
|
888
1007
|
} else if (explicitIds.length > 0) {
|
|
889
1008
|
ids = explicitIds;
|
|
890
1009
|
} else {
|
|
@@ -892,7 +1011,7 @@ var revokeCommand = defineCommand11({
|
|
|
892
1011
|
}
|
|
893
1012
|
if (ids.length === 1) {
|
|
894
1013
|
await apiFetch(`${grantsUrl}/${ids[0]}/revoke`, { method: "POST", token });
|
|
895
|
-
|
|
1014
|
+
consola11.success(`Grant ${ids[0]} revoked.`);
|
|
896
1015
|
return;
|
|
897
1016
|
}
|
|
898
1017
|
const operations = ids.map((id) => ({ id, action: "revoke" }));
|
|
@@ -903,16 +1022,16 @@ var revokeCommand = defineCommand11({
|
|
|
903
1022
|
let succeeded = 0;
|
|
904
1023
|
for (const r of results) {
|
|
905
1024
|
if (r.success) {
|
|
906
|
-
|
|
1025
|
+
consola11.success(`Grant ${r.id} revoked.`);
|
|
907
1026
|
succeeded++;
|
|
908
1027
|
} else {
|
|
909
|
-
|
|
1028
|
+
consola11.error(`Grant ${r.id}: ${r.error?.title || "Failed"}`);
|
|
910
1029
|
}
|
|
911
1030
|
}
|
|
912
1031
|
if (succeeded < results.length) {
|
|
913
1032
|
throw new CliError(`Revoked ${succeeded} of ${results.length} grants.`);
|
|
914
1033
|
} else {
|
|
915
|
-
|
|
1034
|
+
consola11.success(`All ${succeeded} grants revoked.`);
|
|
916
1035
|
}
|
|
917
1036
|
}
|
|
918
1037
|
});
|
|
@@ -946,7 +1065,7 @@ var tokenCommand = defineCommand12({
|
|
|
946
1065
|
|
|
947
1066
|
// src/commands/grants/delegate.ts
|
|
948
1067
|
import { defineCommand as defineCommand13 } from "citty";
|
|
949
|
-
import
|
|
1068
|
+
import consola12 from "consola";
|
|
950
1069
|
var delegateCommand = defineCommand13({
|
|
951
1070
|
meta: {
|
|
952
1071
|
name: "delegate",
|
|
@@ -999,7 +1118,7 @@ var delegateCommand = defineCommand13({
|
|
|
999
1118
|
method: "POST",
|
|
1000
1119
|
body
|
|
1001
1120
|
});
|
|
1002
|
-
|
|
1121
|
+
consola12.success(`Delegation created: ${result.id}`);
|
|
1003
1122
|
console.log(` Delegate: ${args.to}`);
|
|
1004
1123
|
console.log(` Audience: ${args.at}`);
|
|
1005
1124
|
if (args.scopes)
|
|
@@ -1012,7 +1131,7 @@ var delegateCommand = defineCommand13({
|
|
|
1012
1131
|
|
|
1013
1132
|
// src/commands/grants/delegations.ts
|
|
1014
1133
|
import { defineCommand as defineCommand14 } from "citty";
|
|
1015
|
-
import
|
|
1134
|
+
import consola13 from "consola";
|
|
1016
1135
|
var delegationsCommand = defineCommand14({
|
|
1017
1136
|
meta: {
|
|
1018
1137
|
name: "delegations",
|
|
@@ -1035,7 +1154,7 @@ var delegationsCommand = defineCommand14({
|
|
|
1035
1154
|
return;
|
|
1036
1155
|
}
|
|
1037
1156
|
if (delegations.length === 0) {
|
|
1038
|
-
|
|
1157
|
+
consola13.info("No delegations found.");
|
|
1039
1158
|
return;
|
|
1040
1159
|
}
|
|
1041
1160
|
for (const d of delegations) {
|
|
@@ -1048,7 +1167,7 @@ var delegationsCommand = defineCommand14({
|
|
|
1048
1167
|
|
|
1049
1168
|
// src/commands/grants/delegation-revoke.ts
|
|
1050
1169
|
import { defineCommand as defineCommand15 } from "citty";
|
|
1051
|
-
import
|
|
1170
|
+
import consola14 from "consola";
|
|
1052
1171
|
var delegationRevokeCommand = defineCommand15({
|
|
1053
1172
|
meta: {
|
|
1054
1173
|
name: "delegation-revoke",
|
|
@@ -1072,7 +1191,7 @@ var delegationRevokeCommand = defineCommand15({
|
|
|
1072
1191
|
`${delegationsUrl}/${id}`,
|
|
1073
1192
|
{ method: "DELETE" }
|
|
1074
1193
|
);
|
|
1075
|
-
|
|
1194
|
+
consola14.success(`Delegation ${result.id} revoked.`);
|
|
1076
1195
|
}
|
|
1077
1196
|
});
|
|
1078
1197
|
|
|
@@ -1081,7 +1200,7 @@ import { defineCommand as defineCommand18 } from "citty";
|
|
|
1081
1200
|
|
|
1082
1201
|
// src/commands/admin/users.ts
|
|
1083
1202
|
import { defineCommand as defineCommand16 } from "citty";
|
|
1084
|
-
import
|
|
1203
|
+
import consola15 from "consola";
|
|
1085
1204
|
function getManagementToken() {
|
|
1086
1205
|
const token = process.env.APES_MANAGEMENT_TOKEN;
|
|
1087
1206
|
if (!token) {
|
|
@@ -1131,7 +1250,7 @@ var usersListCommand = defineCommand16({
|
|
|
1131
1250
|
return;
|
|
1132
1251
|
}
|
|
1133
1252
|
if (result.data.length === 0) {
|
|
1134
|
-
|
|
1253
|
+
consola15.info("No users found.");
|
|
1135
1254
|
return;
|
|
1136
1255
|
}
|
|
1137
1256
|
for (const u of result.data) {
|
|
@@ -1140,7 +1259,7 @@ var usersListCommand = defineCommand16({
|
|
|
1140
1259
|
console.log(`${u.email} ${u.name}${owner}${active}`);
|
|
1141
1260
|
}
|
|
1142
1261
|
if (result.pagination.has_more) {
|
|
1143
|
-
|
|
1262
|
+
consola15.info(`More results available. Use --cursor="${result.pagination.cursor}" to see next page.`);
|
|
1144
1263
|
}
|
|
1145
1264
|
}
|
|
1146
1265
|
});
|
|
@@ -1175,7 +1294,7 @@ var usersCreateCommand = defineCommand16({
|
|
|
1175
1294
|
token
|
|
1176
1295
|
}
|
|
1177
1296
|
);
|
|
1178
|
-
|
|
1297
|
+
consola15.success(`User created: ${result.email} (${result.name})`);
|
|
1179
1298
|
}
|
|
1180
1299
|
});
|
|
1181
1300
|
var usersDeleteCommand = defineCommand16({
|
|
@@ -1201,16 +1320,16 @@ var usersDeleteCommand = defineCommand16({
|
|
|
1201
1320
|
method: "DELETE",
|
|
1202
1321
|
token
|
|
1203
1322
|
});
|
|
1204
|
-
|
|
1323
|
+
consola15.success(`User deleted: ${email}`);
|
|
1205
1324
|
}
|
|
1206
1325
|
});
|
|
1207
1326
|
|
|
1208
1327
|
// src/commands/admin/ssh-keys.ts
|
|
1209
|
-
import { existsSync, readFileSync } from "fs";
|
|
1328
|
+
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
1210
1329
|
import { resolve } from "path";
|
|
1211
|
-
import { homedir } from "os";
|
|
1330
|
+
import { homedir as homedir3 } from "os";
|
|
1212
1331
|
import { defineCommand as defineCommand17 } from "citty";
|
|
1213
|
-
import
|
|
1332
|
+
import consola16 from "consola";
|
|
1214
1333
|
function getManagementToken2() {
|
|
1215
1334
|
const token = process.env.APES_MANAGEMENT_TOKEN;
|
|
1216
1335
|
if (!token) {
|
|
@@ -1251,7 +1370,7 @@ var sshKeysListCommand = defineCommand17({
|
|
|
1251
1370
|
return;
|
|
1252
1371
|
}
|
|
1253
1372
|
if (keys.length === 0) {
|
|
1254
|
-
|
|
1373
|
+
consola16.info(`No SSH keys found for ${email}.`);
|
|
1255
1374
|
return;
|
|
1256
1375
|
}
|
|
1257
1376
|
for (const k of keys) {
|
|
@@ -1287,8 +1406,8 @@ var sshKeysAddCommand = defineCommand17({
|
|
|
1287
1406
|
}
|
|
1288
1407
|
const token = getManagementToken2();
|
|
1289
1408
|
let publicKey = args.key;
|
|
1290
|
-
const resolved = resolve(args.key.replace(/^~/,
|
|
1291
|
-
if (
|
|
1409
|
+
const resolved = resolve(args.key.replace(/^~/, homedir3()));
|
|
1410
|
+
if (existsSync2(resolved)) {
|
|
1292
1411
|
publicKey = readFileSync(resolved, "utf-8").trim();
|
|
1293
1412
|
}
|
|
1294
1413
|
const body = { publicKey };
|
|
@@ -1303,7 +1422,7 @@ var sshKeysAddCommand = defineCommand17({
|
|
|
1303
1422
|
token
|
|
1304
1423
|
}
|
|
1305
1424
|
);
|
|
1306
|
-
|
|
1425
|
+
consola16.success(`SSH key added: ${result.keyId} (${result.name})`);
|
|
1307
1426
|
}
|
|
1308
1427
|
});
|
|
1309
1428
|
var sshKeysDeleteCommand = defineCommand17({
|
|
@@ -1337,7 +1456,7 @@ var sshKeysDeleteCommand = defineCommand17({
|
|
|
1337
1456
|
token
|
|
1338
1457
|
}
|
|
1339
1458
|
);
|
|
1340
|
-
|
|
1459
|
+
consola16.success(`SSH key deleted: ${keyId}`);
|
|
1341
1460
|
}
|
|
1342
1461
|
});
|
|
1343
1462
|
|
|
@@ -1377,7 +1496,7 @@ var adminCommand = defineCommand18({
|
|
|
1377
1496
|
|
|
1378
1497
|
// src/commands/adapter/index.ts
|
|
1379
1498
|
import { defineCommand as defineCommand19 } from "citty";
|
|
1380
|
-
import
|
|
1499
|
+
import consola17 from "consola";
|
|
1381
1500
|
var adapterCommand = defineCommand19({
|
|
1382
1501
|
meta: {
|
|
1383
1502
|
name: "adapter",
|
|
@@ -1415,7 +1534,7 @@ var adapterCommand = defineCommand19({
|
|
|
1415
1534
|
`);
|
|
1416
1535
|
return;
|
|
1417
1536
|
}
|
|
1418
|
-
|
|
1537
|
+
consola17.info(`Registry: ${index2.adapters.length} adapters (${index2.generated_at})`);
|
|
1419
1538
|
for (const a of index2.adapters) {
|
|
1420
1539
|
const installed = isInstalled(a.id, false) ? " [installed]" : "";
|
|
1421
1540
|
console.log(` ${a.id.padEnd(12)} ${a.name.padEnd(24)} ${a.category}${installed}`);
|
|
@@ -1437,7 +1556,7 @@ var adapterCommand = defineCommand19({
|
|
|
1437
1556
|
return;
|
|
1438
1557
|
}
|
|
1439
1558
|
if (local.length === 0) {
|
|
1440
|
-
|
|
1559
|
+
consola17.info("No adapters installed. Use `apes adapter list --remote` to see available adapters.");
|
|
1441
1560
|
return;
|
|
1442
1561
|
}
|
|
1443
1562
|
for (const a of local) {
|
|
@@ -1474,20 +1593,20 @@ var adapterCommand = defineCommand19({
|
|
|
1474
1593
|
for (const id of ids) {
|
|
1475
1594
|
const entry = findAdapter(index, id);
|
|
1476
1595
|
if (!entry) {
|
|
1477
|
-
|
|
1596
|
+
consola17.error(`Adapter "${id}" not found in registry. Use \`apes adapter search ${id}\` to search.`);
|
|
1478
1597
|
continue;
|
|
1479
1598
|
}
|
|
1480
1599
|
const conflicts = findConflictingAdapters(entry.executable, id);
|
|
1481
1600
|
if (conflicts.length > 0) {
|
|
1482
1601
|
for (const c of conflicts) {
|
|
1483
|
-
|
|
1484
|
-
|
|
1602
|
+
consola17.warn(`Conflicting adapter found: ${c.path} (id: ${c.adapterId}, executable: ${c.executable})`);
|
|
1603
|
+
consola17.warn(` Remove it with: apes adapter remove ${c.adapterId}`);
|
|
1485
1604
|
}
|
|
1486
1605
|
}
|
|
1487
1606
|
const result = await installAdapter(entry, { local });
|
|
1488
1607
|
const verb = result.updated ? "Updated" : "Installed";
|
|
1489
|
-
|
|
1490
|
-
|
|
1608
|
+
consola17.success(`${verb} ${result.id} \u2192 ${result.path}`);
|
|
1609
|
+
consola17.info(`Digest: ${result.digest}`);
|
|
1491
1610
|
}
|
|
1492
1611
|
}
|
|
1493
1612
|
}),
|
|
@@ -1514,9 +1633,9 @@ var adapterCommand = defineCommand19({
|
|
|
1514
1633
|
let failed = false;
|
|
1515
1634
|
for (const id of ids) {
|
|
1516
1635
|
if (removeAdapter(id, local)) {
|
|
1517
|
-
|
|
1636
|
+
consola17.success(`Removed adapter: ${id}`);
|
|
1518
1637
|
} else {
|
|
1519
|
-
|
|
1638
|
+
consola17.error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
|
|
1520
1639
|
failed = true;
|
|
1521
1640
|
}
|
|
1522
1641
|
}
|
|
@@ -1598,7 +1717,7 @@ var adapterCommand = defineCommand19({
|
|
|
1598
1717
|
return;
|
|
1599
1718
|
}
|
|
1600
1719
|
if (results.length === 0) {
|
|
1601
|
-
|
|
1720
|
+
consola17.info(`No adapters matching "${query}"`);
|
|
1602
1721
|
return;
|
|
1603
1722
|
}
|
|
1604
1723
|
for (const a of results) {
|
|
@@ -1633,29 +1752,29 @@ var adapterCommand = defineCommand19({
|
|
|
1633
1752
|
const targetId = args.id ? String(args.id) : void 0;
|
|
1634
1753
|
const targets = targetId ? [targetId] : index.adapters.map((a) => a.id).filter((id) => isInstalled(id, false));
|
|
1635
1754
|
if (targets.length === 0) {
|
|
1636
|
-
|
|
1755
|
+
consola17.info("No adapters installed to update.");
|
|
1637
1756
|
return;
|
|
1638
1757
|
}
|
|
1639
1758
|
for (const id of targets) {
|
|
1640
1759
|
const entry = findAdapter(index, id);
|
|
1641
1760
|
if (!entry) {
|
|
1642
|
-
|
|
1761
|
+
consola17.warn(`${id}: not found in registry, skipping`);
|
|
1643
1762
|
continue;
|
|
1644
1763
|
}
|
|
1645
1764
|
const localDigest = getInstalledDigest(id, false);
|
|
1646
1765
|
if (localDigest === entry.digest) {
|
|
1647
|
-
|
|
1766
|
+
consola17.info(`${id}: already up to date`);
|
|
1648
1767
|
continue;
|
|
1649
1768
|
}
|
|
1650
1769
|
if (localDigest && !args.yes) {
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1770
|
+
consola17.warn(`${id}: digest will change \u2014 existing grants for this adapter will be invalidated`);
|
|
1771
|
+
consola17.info(` Old: ${localDigest}`);
|
|
1772
|
+
consola17.info(` New: ${entry.digest}`);
|
|
1773
|
+
consola17.info(" Use --yes to confirm");
|
|
1655
1774
|
continue;
|
|
1656
1775
|
}
|
|
1657
1776
|
const result = await installAdapter(entry);
|
|
1658
|
-
|
|
1777
|
+
consola17.success(`Updated ${result.id} \u2192 ${result.path}`);
|
|
1659
1778
|
}
|
|
1660
1779
|
}
|
|
1661
1780
|
}),
|
|
@@ -1692,7 +1811,7 @@ var adapterCommand = defineCommand19({
|
|
|
1692
1811
|
if (!localDigest)
|
|
1693
1812
|
throw new Error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
|
|
1694
1813
|
if (localDigest === entry.digest) {
|
|
1695
|
-
|
|
1814
|
+
consola17.success(`${id}: digest matches registry`);
|
|
1696
1815
|
} else {
|
|
1697
1816
|
console.log(` Local: ${localDigest}`);
|
|
1698
1817
|
console.log(` Registry: ${entry.digest}`);
|
|
@@ -1706,8 +1825,9 @@ var adapterCommand = defineCommand19({
|
|
|
1706
1825
|
// src/commands/run.ts
|
|
1707
1826
|
import { execFileSync } from "child_process";
|
|
1708
1827
|
import { hostname as hostname3 } from "os";
|
|
1828
|
+
import { basename } from "path";
|
|
1709
1829
|
import { defineCommand as defineCommand20 } from "citty";
|
|
1710
|
-
import
|
|
1830
|
+
import consola18 from "consola";
|
|
1711
1831
|
var runCommand = defineCommand20({
|
|
1712
1832
|
meta: {
|
|
1713
1833
|
name: "run",
|
|
@@ -1795,7 +1915,7 @@ async function runShellMode(command, args) {
|
|
|
1795
1915
|
}
|
|
1796
1916
|
} catch {
|
|
1797
1917
|
}
|
|
1798
|
-
|
|
1918
|
+
consola18.info(`Requesting ape-shell session grant on ${targetHost}`);
|
|
1799
1919
|
const grant = await apiFetch(grantsUrl, {
|
|
1800
1920
|
method: "POST",
|
|
1801
1921
|
body: {
|
|
@@ -1807,8 +1927,8 @@ async function runShellMode(command, args) {
|
|
|
1807
1927
|
reason: `Shell session: ${command.join(" ").slice(0, 100)}`
|
|
1808
1928
|
}
|
|
1809
1929
|
});
|
|
1810
|
-
|
|
1811
|
-
|
|
1930
|
+
consola18.info(`Grant requested: ${grant.id}`);
|
|
1931
|
+
consola18.info("Waiting for approval...");
|
|
1812
1932
|
const maxWait = 3e5;
|
|
1813
1933
|
const interval = 3e3;
|
|
1814
1934
|
const start = Date.now();
|
|
@@ -1830,17 +1950,18 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
1830
1950
|
if (parsed.isCompound) return false;
|
|
1831
1951
|
const loaded = await loadOrInstallAdapter(parsed.executable);
|
|
1832
1952
|
if (!loaded) return false;
|
|
1953
|
+
const normalizedExecutable = basename(parsed.executable);
|
|
1833
1954
|
let resolved;
|
|
1834
1955
|
try {
|
|
1835
|
-
resolved = await resolveCommand(loaded, [
|
|
1956
|
+
resolved = await resolveCommand(loaded, [normalizedExecutable, ...parsed.argv]);
|
|
1836
1957
|
} catch (err) {
|
|
1837
|
-
|
|
1958
|
+
consola18.debug(`ape-shell: adapter resolve failed for "${parsed.raw}":`, err);
|
|
1838
1959
|
return false;
|
|
1839
1960
|
}
|
|
1840
1961
|
try {
|
|
1841
1962
|
const existingGrantId = await findExistingGrant(resolved, idp);
|
|
1842
1963
|
if (existingGrantId) {
|
|
1843
|
-
|
|
1964
|
+
consola18.info(`Reusing grant ${existingGrantId} for: ${resolved.detail.display}`);
|
|
1844
1965
|
const token2 = await fetchGrantToken(idp, existingGrantId);
|
|
1845
1966
|
await verifyAndExecute(token2, resolved);
|
|
1846
1967
|
return true;
|
|
@@ -1848,18 +1969,18 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
1848
1969
|
} catch {
|
|
1849
1970
|
}
|
|
1850
1971
|
const approval = args.approval ?? "once";
|
|
1851
|
-
|
|
1972
|
+
consola18.info(`Requesting grant for: ${resolved.detail.display}`);
|
|
1852
1973
|
const grant = await createShapesGrant(resolved, {
|
|
1853
1974
|
idp,
|
|
1854
1975
|
approval,
|
|
1855
1976
|
reason: args.reason || `ape-shell: ${resolved.detail.display}`
|
|
1856
1977
|
});
|
|
1857
|
-
|
|
1858
|
-
|
|
1978
|
+
consola18.info(`Grant requested: ${grant.id}`);
|
|
1979
|
+
consola18.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
|
|
1859
1980
|
if (grant.similar_grants?.similar_grants?.length) {
|
|
1860
1981
|
const n = grant.similar_grants.similar_grants.length;
|
|
1861
|
-
|
|
1862
|
-
|
|
1982
|
+
consola18.info("");
|
|
1983
|
+
consola18.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
|
|
1863
1984
|
}
|
|
1864
1985
|
const status = await waitForGrantStatus(idp, grant.id);
|
|
1865
1986
|
if (status !== "approved")
|
|
@@ -1909,7 +2030,7 @@ async function runAdapterMode(command, rawArgs, args) {
|
|
|
1909
2030
|
try {
|
|
1910
2031
|
const existingGrantId = await findExistingGrant(resolved, idp);
|
|
1911
2032
|
if (existingGrantId) {
|
|
1912
|
-
|
|
2033
|
+
consola18.info(`Reusing existing grant: ${existingGrantId}`);
|
|
1913
2034
|
const token2 = await fetchGrantToken(idp, existingGrantId);
|
|
1914
2035
|
await verifyAndExecute(token2, resolved);
|
|
1915
2036
|
return;
|
|
@@ -1921,17 +2042,17 @@ async function runAdapterMode(command, rawArgs, args) {
|
|
|
1921
2042
|
approval,
|
|
1922
2043
|
...args.reason ? { reason: args.reason } : {}
|
|
1923
2044
|
});
|
|
1924
|
-
|
|
1925
|
-
|
|
2045
|
+
consola18.info(`Grant requested: ${grant.id}`);
|
|
2046
|
+
consola18.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
|
|
1926
2047
|
if (grant.similar_grants?.similar_grants?.length) {
|
|
1927
2048
|
const n = grant.similar_grants.similar_grants.length;
|
|
1928
|
-
|
|
1929
|
-
|
|
2049
|
+
consola18.info("");
|
|
2050
|
+
consola18.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
|
|
1930
2051
|
if (grant.similar_grants.widened_details?.length) {
|
|
1931
2052
|
const wider = grant.similar_grants.widened_details.map((d) => d.permission).join(", ");
|
|
1932
|
-
|
|
2053
|
+
consola18.info(` Broader scope: ${wider}`);
|
|
1933
2054
|
}
|
|
1934
|
-
|
|
2055
|
+
consola18.info("");
|
|
1935
2056
|
}
|
|
1936
2057
|
const status = await waitForGrantStatus(idp, grant.id);
|
|
1937
2058
|
if (status !== "approved")
|
|
@@ -1948,7 +2069,7 @@ async function runAudienceMode(audience, action, args) {
|
|
|
1948
2069
|
const grantsUrl = await getGrantsEndpoint(idp);
|
|
1949
2070
|
const command = action.split(" ");
|
|
1950
2071
|
const targetHost = args.host || hostname3();
|
|
1951
|
-
|
|
2072
|
+
consola18.info(`Requesting ${audience} grant on ${targetHost}: ${command.join(" ")}`);
|
|
1952
2073
|
const grant = await apiFetch(grantsUrl, {
|
|
1953
2074
|
method: "POST",
|
|
1954
2075
|
body: {
|
|
@@ -1961,15 +2082,15 @@ async function runAudienceMode(audience, action, args) {
|
|
|
1961
2082
|
...args.as ? { run_as: args.as } : {}
|
|
1962
2083
|
}
|
|
1963
2084
|
});
|
|
1964
|
-
|
|
1965
|
-
|
|
2085
|
+
consola18.success(`Grant requested: ${grant.id}`);
|
|
2086
|
+
consola18.info("Waiting for approval...");
|
|
1966
2087
|
const maxWait = 3e5;
|
|
1967
2088
|
const interval = 3e3;
|
|
1968
2089
|
const start = Date.now();
|
|
1969
2090
|
while (Date.now() - start < maxWait) {
|
|
1970
2091
|
const status = await apiFetch(`${grantsUrl}/${grant.id}`);
|
|
1971
2092
|
if (status.status === "approved") {
|
|
1972
|
-
|
|
2093
|
+
consola18.success("Grant approved!");
|
|
1973
2094
|
break;
|
|
1974
2095
|
}
|
|
1975
2096
|
if (status.status === "denied" || status.status === "revoked") {
|
|
@@ -1977,12 +2098,12 @@ async function runAudienceMode(audience, action, args) {
|
|
|
1977
2098
|
}
|
|
1978
2099
|
await new Promise((r) => setTimeout(r, interval));
|
|
1979
2100
|
}
|
|
1980
|
-
|
|
2101
|
+
consola18.info("Fetching grant token...");
|
|
1981
2102
|
const { authz_jwt } = await apiFetch(`${grantsUrl}/${grant.id}/token`, {
|
|
1982
2103
|
method: "POST"
|
|
1983
2104
|
});
|
|
1984
2105
|
if (audience === "escapes") {
|
|
1985
|
-
|
|
2106
|
+
consola18.info(`Executing: ${command.join(" ")}`);
|
|
1986
2107
|
try {
|
|
1987
2108
|
execFileSync(args["escapes-path"] || "escapes", ["--grant", authz_jwt, "--", ...command], {
|
|
1988
2109
|
stdio: "inherit"
|
|
@@ -2037,7 +2158,7 @@ var explainCommand = defineCommand21({
|
|
|
2037
2158
|
|
|
2038
2159
|
// src/commands/config/get.ts
|
|
2039
2160
|
import { defineCommand as defineCommand22 } from "citty";
|
|
2040
|
-
import
|
|
2161
|
+
import consola19 from "consola";
|
|
2041
2162
|
var configGetCommand = defineCommand22({
|
|
2042
2163
|
meta: {
|
|
2043
2164
|
name: "get",
|
|
@@ -2058,7 +2179,7 @@ var configGetCommand = defineCommand22({
|
|
|
2058
2179
|
if (idp)
|
|
2059
2180
|
console.log(idp);
|
|
2060
2181
|
else
|
|
2061
|
-
|
|
2182
|
+
consola19.info("No IdP configured.");
|
|
2062
2183
|
break;
|
|
2063
2184
|
}
|
|
2064
2185
|
case "email": {
|
|
@@ -2066,7 +2187,7 @@ var configGetCommand = defineCommand22({
|
|
|
2066
2187
|
if (auth?.email)
|
|
2067
2188
|
console.log(auth.email);
|
|
2068
2189
|
else
|
|
2069
|
-
|
|
2190
|
+
consola19.info("Not logged in.");
|
|
2070
2191
|
break;
|
|
2071
2192
|
}
|
|
2072
2193
|
default: {
|
|
@@ -2079,7 +2200,7 @@ var configGetCommand = defineCommand22({
|
|
|
2079
2200
|
if (sectionObj && field in sectionObj) {
|
|
2080
2201
|
console.log(sectionObj[field]);
|
|
2081
2202
|
} else {
|
|
2082
|
-
|
|
2203
|
+
consola19.info(`Key "${key}" not set.`);
|
|
2083
2204
|
}
|
|
2084
2205
|
} else {
|
|
2085
2206
|
throw new CliError(`Unknown key: "${key}". Use: idp, email, defaults.idp, defaults.approval, agent.key, agent.email`);
|
|
@@ -2091,7 +2212,7 @@ var configGetCommand = defineCommand22({
|
|
|
2091
2212
|
|
|
2092
2213
|
// src/commands/config/set.ts
|
|
2093
2214
|
import { defineCommand as defineCommand23 } from "citty";
|
|
2094
|
-
import
|
|
2215
|
+
import consola20 from "consola";
|
|
2095
2216
|
var configSetCommand = defineCommand23({
|
|
2096
2217
|
meta: {
|
|
2097
2218
|
name: "set",
|
|
@@ -2128,7 +2249,7 @@ var configSetCommand = defineCommand23({
|
|
|
2128
2249
|
throw new CliError(`Unknown section: "${section}". Use: defaults, agent`);
|
|
2129
2250
|
}
|
|
2130
2251
|
saveConfig(config);
|
|
2131
|
-
|
|
2252
|
+
consola20.success(`Set ${key} = ${value}`);
|
|
2132
2253
|
}
|
|
2133
2254
|
});
|
|
2134
2255
|
|
|
@@ -2264,25 +2385,25 @@ var mcpCommand = defineCommand25({
|
|
|
2264
2385
|
if (transport !== "stdio" && transport !== "sse") {
|
|
2265
2386
|
throw new Error('Transport must be "stdio" or "sse"');
|
|
2266
2387
|
}
|
|
2267
|
-
const { startMcpServer } = await import("./server-
|
|
2388
|
+
const { startMcpServer } = await import("./server-UTCZSPCU.js");
|
|
2268
2389
|
await startMcpServer(transport, port);
|
|
2269
2390
|
}
|
|
2270
2391
|
});
|
|
2271
2392
|
|
|
2272
2393
|
// src/commands/init/index.ts
|
|
2273
|
-
import { existsSync as
|
|
2394
|
+
import { existsSync as existsSync3, copyFileSync, writeFileSync } from "fs";
|
|
2274
2395
|
import { randomBytes } from "crypto";
|
|
2275
2396
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
2276
|
-
import { join } from "path";
|
|
2397
|
+
import { join as join2 } from "path";
|
|
2277
2398
|
import { defineCommand as defineCommand26 } from "citty";
|
|
2278
|
-
import
|
|
2399
|
+
import consola21 from "consola";
|
|
2279
2400
|
var DEFAULT_IDP_URL = "https://id.openape.at";
|
|
2280
2401
|
async function downloadTemplate(repo, targetDir) {
|
|
2281
2402
|
const { downloadTemplate: gigetDownload } = await import("giget");
|
|
2282
2403
|
await gigetDownload(`gh:${repo}`, { dir: targetDir, force: false });
|
|
2283
2404
|
}
|
|
2284
2405
|
function installDeps(dir) {
|
|
2285
|
-
const hasLockFile = (name) =>
|
|
2406
|
+
const hasLockFile = (name) => existsSync3(join2(dir, name));
|
|
2286
2407
|
if (hasLockFile("pnpm-lock.yaml")) {
|
|
2287
2408
|
execFileSync2("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
|
|
2288
2409
|
} else if (hasLockFile("bun.lockb")) {
|
|
@@ -2292,14 +2413,14 @@ function installDeps(dir) {
|
|
|
2292
2413
|
}
|
|
2293
2414
|
}
|
|
2294
2415
|
async function promptChoice(message, choices) {
|
|
2295
|
-
const result = await
|
|
2416
|
+
const result = await consola21.prompt(message, { type: "select", options: choices });
|
|
2296
2417
|
if (typeof result === "symbol") {
|
|
2297
2418
|
throw new CliExit(0);
|
|
2298
2419
|
}
|
|
2299
2420
|
return result;
|
|
2300
2421
|
}
|
|
2301
2422
|
async function promptText(message, defaultValue) {
|
|
2302
|
-
const result = await
|
|
2423
|
+
const result = await consola21.prompt(message, { type: "text", default: defaultValue, placeholder: defaultValue });
|
|
2303
2424
|
if (typeof result === "symbol") {
|
|
2304
2425
|
throw new CliExit(0);
|
|
2305
2426
|
}
|
|
@@ -2347,23 +2468,23 @@ var initCommand = defineCommand26({
|
|
|
2347
2468
|
});
|
|
2348
2469
|
async function initSP(targetDir) {
|
|
2349
2470
|
const dir = targetDir || "my-app";
|
|
2350
|
-
if (
|
|
2471
|
+
if (existsSync3(join2(dir, "package.json"))) {
|
|
2351
2472
|
throw new CliError(`Directory "${dir}" already contains a project.`);
|
|
2352
2473
|
}
|
|
2353
|
-
|
|
2474
|
+
consola21.start("Scaffolding SP starter...");
|
|
2354
2475
|
await downloadTemplate("openape-ai/openape-sp-starter", dir);
|
|
2355
|
-
|
|
2356
|
-
|
|
2476
|
+
consola21.success("Scaffolded from openape-sp-starter");
|
|
2477
|
+
consola21.start("Installing dependencies...");
|
|
2357
2478
|
installDeps(dir);
|
|
2358
|
-
|
|
2359
|
-
const envExample =
|
|
2360
|
-
const envFile =
|
|
2361
|
-
if (
|
|
2479
|
+
consola21.success("Dependencies installed");
|
|
2480
|
+
const envExample = join2(dir, ".env.example");
|
|
2481
|
+
const envFile = join2(dir, ".env");
|
|
2482
|
+
if (existsSync3(envExample) && !existsSync3(envFile)) {
|
|
2362
2483
|
copyFileSync(envExample, envFile);
|
|
2363
|
-
|
|
2484
|
+
consola21.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
|
|
2364
2485
|
}
|
|
2365
2486
|
console.log("");
|
|
2366
|
-
|
|
2487
|
+
consola21.box([
|
|
2367
2488
|
`cd ${dir}`,
|
|
2368
2489
|
"npm run dev",
|
|
2369
2490
|
"",
|
|
@@ -2372,7 +2493,7 @@ async function initSP(targetDir) {
|
|
|
2372
2493
|
}
|
|
2373
2494
|
async function initIdP(targetDir) {
|
|
2374
2495
|
const dir = targetDir || "my-idp";
|
|
2375
|
-
if (
|
|
2496
|
+
if (existsSync3(join2(dir, "package.json"))) {
|
|
2376
2497
|
throw new CliError(`Directory "${dir}" already contains a project.`);
|
|
2377
2498
|
}
|
|
2378
2499
|
const domain = await promptText("Domain for the IdP", "localhost");
|
|
@@ -2382,15 +2503,15 @@ async function initIdP(targetDir) {
|
|
|
2382
2503
|
"s3 (S3-compatible)"
|
|
2383
2504
|
]);
|
|
2384
2505
|
const adminEmail = await promptText("Admin email");
|
|
2385
|
-
|
|
2506
|
+
consola21.start("Scaffolding IdP starter...");
|
|
2386
2507
|
await downloadTemplate("openape-ai/openape-idp-starter", dir);
|
|
2387
|
-
|
|
2388
|
-
|
|
2508
|
+
consola21.success("Scaffolded from openape-idp-starter");
|
|
2509
|
+
consola21.start("Installing dependencies...");
|
|
2389
2510
|
installDeps(dir);
|
|
2390
|
-
|
|
2511
|
+
consola21.success("Dependencies installed");
|
|
2391
2512
|
const sessionSecret = randomBytes(32).toString("hex");
|
|
2392
2513
|
const managementToken = randomBytes(32).toString("hex");
|
|
2393
|
-
|
|
2514
|
+
consola21.success("Secrets generated");
|
|
2394
2515
|
const isLocalhost = domain === "localhost";
|
|
2395
2516
|
const origin = isLocalhost ? "http://localhost:3000" : `https://${domain}`;
|
|
2396
2517
|
const envContent = [
|
|
@@ -2404,11 +2525,11 @@ async function initIdP(targetDir) {
|
|
|
2404
2525
|
`NUXT_OPENAPE_RP_ID=${domain}`,
|
|
2405
2526
|
`NUXT_OPENAPE_RP_ORIGIN=${origin}`
|
|
2406
2527
|
].join("\n");
|
|
2407
|
-
writeFileSync(
|
|
2528
|
+
writeFileSync(join2(dir, ".env"), `${envContent}
|
|
2408
2529
|
`, { mode: 384 });
|
|
2409
|
-
|
|
2530
|
+
consola21.success(".env created");
|
|
2410
2531
|
console.log("");
|
|
2411
|
-
|
|
2532
|
+
consola21.box([
|
|
2412
2533
|
`cd ${dir}`,
|
|
2413
2534
|
"npm run dev",
|
|
2414
2535
|
"",
|
|
@@ -2425,19 +2546,19 @@ async function initIdP(targetDir) {
|
|
|
2425
2546
|
|
|
2426
2547
|
// src/commands/enroll.ts
|
|
2427
2548
|
import { Buffer as Buffer2 } from "buffer";
|
|
2428
|
-
import { existsSync as
|
|
2549
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync } from "fs";
|
|
2429
2550
|
import { execFile as execFile2 } from "child_process";
|
|
2430
2551
|
import { generateKeyPairSync, sign } from "crypto";
|
|
2431
2552
|
import { dirname, resolve as resolve2 } from "path";
|
|
2432
|
-
import { homedir as
|
|
2553
|
+
import { homedir as homedir4 } from "os";
|
|
2433
2554
|
import { defineCommand as defineCommand27 } from "citty";
|
|
2434
|
-
import
|
|
2555
|
+
import consola22 from "consola";
|
|
2435
2556
|
var DEFAULT_IDP_URL2 = "https://id.openape.at";
|
|
2436
2557
|
var DEFAULT_KEY_PATH = "~/.ssh/id_ed25519";
|
|
2437
2558
|
var POLL_INTERVAL = 3e3;
|
|
2438
2559
|
var POLL_TIMEOUT = 3e5;
|
|
2439
|
-
function
|
|
2440
|
-
return resolve2(p.replace(/^~/,
|
|
2560
|
+
function resolvePath2(p) {
|
|
2561
|
+
return resolve2(p.replace(/^~/, homedir4()));
|
|
2441
2562
|
}
|
|
2442
2563
|
function openBrowser2(url) {
|
|
2443
2564
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
@@ -2446,7 +2567,7 @@ function openBrowser2(url) {
|
|
|
2446
2567
|
}
|
|
2447
2568
|
function readPublicKey(keyPath) {
|
|
2448
2569
|
const pubPath = `${keyPath}.pub`;
|
|
2449
|
-
if (
|
|
2570
|
+
if (existsSync4(pubPath)) {
|
|
2450
2571
|
return readFileSync2(pubPath, "utf-8").trim();
|
|
2451
2572
|
}
|
|
2452
2573
|
const keyContent = readFileSync2(keyPath, "utf-8");
|
|
@@ -2462,9 +2583,9 @@ function readPublicKey(keyPath) {
|
|
|
2462
2583
|
return `ssh-ed25519 ${blob.toString("base64")}`;
|
|
2463
2584
|
}
|
|
2464
2585
|
function generateAndSaveKey(keyPath) {
|
|
2465
|
-
const resolved =
|
|
2586
|
+
const resolved = resolvePath2(keyPath);
|
|
2466
2587
|
const dir = dirname(resolved);
|
|
2467
|
-
if (!
|
|
2588
|
+
if (!existsSync4(dir)) {
|
|
2468
2589
|
mkdirSync(dir, { recursive: true });
|
|
2469
2590
|
}
|
|
2470
2591
|
const { publicKey, privateKey } = generateKeyPairSync("ed25519");
|
|
@@ -2484,7 +2605,7 @@ function generateAndSaveKey(keyPath) {
|
|
|
2484
2605
|
return pubKeyStr;
|
|
2485
2606
|
}
|
|
2486
2607
|
async function pollForEnrollment(idp, agentEmail, keyPath) {
|
|
2487
|
-
const resolvedKey =
|
|
2608
|
+
const resolvedKey = resolvePath2(keyPath);
|
|
2488
2609
|
const keyContent = readFileSync2(resolvedKey, "utf-8");
|
|
2489
2610
|
const privateKey = loadEd25519PrivateKey(keyContent);
|
|
2490
2611
|
const challengeUrl = await getAgentChallengeEndpoint(idp);
|
|
@@ -2536,38 +2657,38 @@ var enrollCommand = defineCommand27({
|
|
|
2536
2657
|
}
|
|
2537
2658
|
},
|
|
2538
2659
|
async run({ args }) {
|
|
2539
|
-
const idp = args.idp || await
|
|
2660
|
+
const idp = args.idp || await consola22.prompt("IdP URL", { type: "text", default: DEFAULT_IDP_URL2, placeholder: DEFAULT_IDP_URL2 }).then((r) => {
|
|
2540
2661
|
if (typeof r === "symbol") throw new CliExit(0);
|
|
2541
2662
|
return r;
|
|
2542
2663
|
}) || DEFAULT_IDP_URL2;
|
|
2543
|
-
const agentName = args.name || await
|
|
2664
|
+
const agentName = args.name || await consola22.prompt("Agent name", { type: "text", placeholder: "deploy-bot" }).then((r) => {
|
|
2544
2665
|
if (typeof r === "symbol") throw new CliExit(0);
|
|
2545
2666
|
return r;
|
|
2546
2667
|
});
|
|
2547
2668
|
if (!agentName) {
|
|
2548
2669
|
throw new CliError("Agent name is required.");
|
|
2549
2670
|
}
|
|
2550
|
-
const keyPath = args.key || await
|
|
2671
|
+
const keyPath = args.key || await consola22.prompt("Ed25519 key", { type: "text", default: DEFAULT_KEY_PATH, placeholder: DEFAULT_KEY_PATH }).then((r) => {
|
|
2551
2672
|
if (typeof r === "symbol") throw new CliExit(0);
|
|
2552
2673
|
return r;
|
|
2553
2674
|
}) || DEFAULT_KEY_PATH;
|
|
2554
|
-
const resolvedKey =
|
|
2675
|
+
const resolvedKey = resolvePath2(keyPath);
|
|
2555
2676
|
let publicKey;
|
|
2556
|
-
if (
|
|
2677
|
+
if (existsSync4(resolvedKey)) {
|
|
2557
2678
|
publicKey = readPublicKey(resolvedKey);
|
|
2558
|
-
|
|
2679
|
+
consola22.success(`Using existing key ${keyPath}`);
|
|
2559
2680
|
} else {
|
|
2560
|
-
|
|
2681
|
+
consola22.start(`Generating Ed25519 key pair at ${keyPath}...`);
|
|
2561
2682
|
publicKey = generateAndSaveKey(keyPath);
|
|
2562
|
-
|
|
2683
|
+
consola22.success(`Key pair generated at ${keyPath}`);
|
|
2563
2684
|
}
|
|
2564
2685
|
const encodedKey = encodeURIComponent(publicKey);
|
|
2565
2686
|
const enrollUrl = `${idp}/enroll?name=${encodeURIComponent(agentName)}&key=${encodedKey}`;
|
|
2566
|
-
|
|
2567
|
-
|
|
2687
|
+
consola22.info("Opening browser for enrollment...");
|
|
2688
|
+
consola22.info(`\u2192 ${idp}/enroll`);
|
|
2568
2689
|
openBrowser2(enrollUrl);
|
|
2569
2690
|
console.log("");
|
|
2570
|
-
const agentEmail = await
|
|
2691
|
+
const agentEmail = await consola22.prompt(
|
|
2571
2692
|
"Agent email (shown in browser after enrollment)",
|
|
2572
2693
|
{ type: "text", placeholder: `agent+${agentName}@...` }
|
|
2573
2694
|
).then((r) => {
|
|
@@ -2577,7 +2698,7 @@ var enrollCommand = defineCommand27({
|
|
|
2577
2698
|
if (!agentEmail) {
|
|
2578
2699
|
throw new CliError("Agent email is required to verify enrollment.");
|
|
2579
2700
|
}
|
|
2580
|
-
|
|
2701
|
+
consola22.start("Verifying enrollment...");
|
|
2581
2702
|
const { token, expiresIn } = await pollForEnrollment(idp, agentEmail, keyPath);
|
|
2582
2703
|
saveAuth({
|
|
2583
2704
|
idp,
|
|
@@ -2589,17 +2710,17 @@ var enrollCommand = defineCommand27({
|
|
|
2589
2710
|
config.defaults = { ...config.defaults, idp };
|
|
2590
2711
|
config.agent = { key: keyPath, email: agentEmail };
|
|
2591
2712
|
saveConfig(config);
|
|
2592
|
-
|
|
2593
|
-
|
|
2713
|
+
consola22.success(`Agent enrolled as ${agentEmail}`);
|
|
2714
|
+
consola22.success("Config saved to ~/.config/apes/");
|
|
2594
2715
|
console.log("");
|
|
2595
|
-
|
|
2716
|
+
consola22.info("Verify with: apes whoami");
|
|
2596
2717
|
}
|
|
2597
2718
|
});
|
|
2598
2719
|
|
|
2599
2720
|
// src/commands/register-user.ts
|
|
2600
|
-
import { existsSync as
|
|
2721
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
2601
2722
|
import { defineCommand as defineCommand28 } from "citty";
|
|
2602
|
-
import
|
|
2723
|
+
import consola23 from "consola";
|
|
2603
2724
|
var registerUserCommand = defineCommand28({
|
|
2604
2725
|
meta: {
|
|
2605
2726
|
name: "register-user",
|
|
@@ -2636,7 +2757,7 @@ var registerUserCommand = defineCommand28({
|
|
|
2636
2757
|
throw new CliError("No IdP URL configured. Run `apes login` first.");
|
|
2637
2758
|
}
|
|
2638
2759
|
let publicKey = args.key;
|
|
2639
|
-
if (
|
|
2760
|
+
if (existsSync5(args.key)) {
|
|
2640
2761
|
publicKey = readFileSync3(args.key, "utf-8").trim();
|
|
2641
2762
|
}
|
|
2642
2763
|
if (!publicKey.startsWith("ssh-ed25519 ")) {
|
|
@@ -2655,14 +2776,14 @@ var registerUserCommand = defineCommand28({
|
|
|
2655
2776
|
...userType ? { type: userType } : {}
|
|
2656
2777
|
}
|
|
2657
2778
|
});
|
|
2658
|
-
|
|
2779
|
+
consola23.success(`User registered: ${result.email} (type: ${result.type}, owner: ${result.owner})`);
|
|
2659
2780
|
}
|
|
2660
2781
|
});
|
|
2661
2782
|
|
|
2662
2783
|
// src/commands/dns-check.ts
|
|
2663
2784
|
import { defineCommand as defineCommand29 } from "citty";
|
|
2664
|
-
import
|
|
2665
|
-
import { resolveDDISA } from "@openape/core";
|
|
2785
|
+
import consola24 from "consola";
|
|
2786
|
+
import { resolveDDISA as resolveDDISA2 } from "@openape/core";
|
|
2666
2787
|
var dnsCheckCommand = defineCommand29({
|
|
2667
2788
|
meta: {
|
|
2668
2789
|
name: "dns-check",
|
|
@@ -2677,16 +2798,16 @@ var dnsCheckCommand = defineCommand29({
|
|
|
2677
2798
|
},
|
|
2678
2799
|
async run({ args }) {
|
|
2679
2800
|
const domain = args.domain;
|
|
2680
|
-
|
|
2801
|
+
consola24.start(`Checking _ddisa.${domain}...`);
|
|
2681
2802
|
try {
|
|
2682
|
-
const result = await
|
|
2803
|
+
const result = await resolveDDISA2(domain);
|
|
2683
2804
|
if (!result) {
|
|
2684
2805
|
console.log("");
|
|
2685
2806
|
console.log("To set up DDISA, add a DNS TXT record:");
|
|
2686
2807
|
console.log(` _ddisa.${domain} TXT "v=ddisa1 idp=https://id.${domain}"`);
|
|
2687
2808
|
throw new CliError(`No DDISA record found for ${domain}`);
|
|
2688
2809
|
}
|
|
2689
|
-
|
|
2810
|
+
consola24.success(`_ddisa.${domain} \u2192 ${result.idp}`);
|
|
2690
2811
|
console.log("");
|
|
2691
2812
|
console.log(` Version: ${result.version || "ddisa1"}`);
|
|
2692
2813
|
console.log(` IdP URL: ${result.idp}`);
|
|
@@ -2695,14 +2816,14 @@ var dnsCheckCommand = defineCommand29({
|
|
|
2695
2816
|
if (result.priority !== void 0)
|
|
2696
2817
|
console.log(` Priority: ${result.priority}`);
|
|
2697
2818
|
console.log("");
|
|
2698
|
-
|
|
2819
|
+
consola24.start(`Verifying IdP at ${result.idp}...`);
|
|
2699
2820
|
const discoResp = await fetch(`${result.idp}/.well-known/openid-configuration`);
|
|
2700
2821
|
if (!discoResp.ok) {
|
|
2701
|
-
|
|
2822
|
+
consola24.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
|
|
2702
2823
|
return;
|
|
2703
2824
|
}
|
|
2704
2825
|
const disco = await discoResp.json();
|
|
2705
|
-
|
|
2826
|
+
consola24.success(`IdP is reachable`);
|
|
2706
2827
|
console.log(` Issuer: ${disco.issuer}`);
|
|
2707
2828
|
console.log(` DDISA: v${disco.ddisa_version || "?"}`);
|
|
2708
2829
|
if (disco.ddisa_auth_methods_supported) {
|
|
@@ -2719,7 +2840,7 @@ var dnsCheckCommand = defineCommand29({
|
|
|
2719
2840
|
|
|
2720
2841
|
// src/commands/workflows.ts
|
|
2721
2842
|
import { defineCommand as defineCommand30 } from "citty";
|
|
2722
|
-
import
|
|
2843
|
+
import consola25 from "consola";
|
|
2723
2844
|
|
|
2724
2845
|
// src/guides/index.ts
|
|
2725
2846
|
var guides = [
|
|
@@ -2790,7 +2911,7 @@ var workflowsCommand = defineCommand30({
|
|
|
2790
2911
|
if (args.id) {
|
|
2791
2912
|
const guide = guides.find((g) => g.id === String(args.id));
|
|
2792
2913
|
if (!guide) {
|
|
2793
|
-
|
|
2914
|
+
consola25.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
|
|
2794
2915
|
throw new CliError(`Guide not found: ${args.id}`);
|
|
2795
2916
|
}
|
|
2796
2917
|
if (args.json) {
|
|
@@ -2834,19 +2955,34 @@ process.stdout.on("error", (err) => {
|
|
|
2834
2955
|
if (err.code === "EPIPE") process.exit(0);
|
|
2835
2956
|
throw err;
|
|
2836
2957
|
});
|
|
2837
|
-
var shellRewrite = rewriteApeShellArgs(process.argv);
|
|
2958
|
+
var shellRewrite = rewriteApeShellArgs(process.argv, process.argv0);
|
|
2838
2959
|
if (shellRewrite) {
|
|
2839
2960
|
if (shellRewrite.action === "rewrite") {
|
|
2840
2961
|
process.argv = shellRewrite.argv;
|
|
2841
2962
|
} else if (shellRewrite.action === "version") {
|
|
2842
|
-
console.log(`ape-shell (OpenApe DDISA shell wrapper)`);
|
|
2963
|
+
console.log(`ape-shell ${"0.7.1"} (OpenApe DDISA shell wrapper)`);
|
|
2843
2964
|
process.exit(0);
|
|
2844
2965
|
} else if (shellRewrite.action === "help") {
|
|
2845
|
-
console.log(
|
|
2846
|
-
console.log("
|
|
2966
|
+
console.log(`ape-shell ${"0.7.1"} \u2014 OpenApe DDISA shell wrapper`);
|
|
2967
|
+
console.log("");
|
|
2968
|
+
console.log("Usage:");
|
|
2969
|
+
console.log(" ape-shell Start interactive grant-mediated REPL");
|
|
2970
|
+
console.log(" ape-shell -c <command> Run a single command through the grant flow");
|
|
2971
|
+
console.log(" ape-shell -i | -l Force interactive mode");
|
|
2972
|
+
console.log("");
|
|
2973
|
+
console.log("Options:");
|
|
2974
|
+
console.log(" -c <command> Execute <command> via the apes grant flow and exit");
|
|
2975
|
+
console.log(" -i Interactive REPL (default when no args are given)");
|
|
2976
|
+
console.log(" -l, --login Login shell semantics \u2014 currently same as -i");
|
|
2977
|
+
console.log(" --version, -v Show ape-shell version");
|
|
2978
|
+
console.log(" --help, -h Show this help message");
|
|
2979
|
+
process.exit(0);
|
|
2980
|
+
} else if (shellRewrite.action === "interactive") {
|
|
2981
|
+
const { runInteractiveShell } = await import("./orchestrator-JAMWD6DD.js");
|
|
2982
|
+
await runInteractiveShell();
|
|
2847
2983
|
process.exit(0);
|
|
2848
2984
|
} else {
|
|
2849
|
-
console.error("ape-shell:
|
|
2985
|
+
console.error("ape-shell: unsupported invocation. Try `ape-shell --help`.");
|
|
2850
2986
|
process.exit(1);
|
|
2851
2987
|
}
|
|
2852
2988
|
}
|
|
@@ -2884,7 +3020,7 @@ var configCommand = defineCommand31({
|
|
|
2884
3020
|
var main = defineCommand31({
|
|
2885
3021
|
meta: {
|
|
2886
3022
|
name: "apes",
|
|
2887
|
-
version: "0.
|
|
3023
|
+
version: "0.7.1",
|
|
2888
3024
|
description: "Unified CLI for OpenApe"
|
|
2889
3025
|
},
|
|
2890
3026
|
subCommands: {
|
|
@@ -2911,13 +3047,13 @@ runMain(main).catch((err) => {
|
|
|
2911
3047
|
process.exit(err.exitCode);
|
|
2912
3048
|
}
|
|
2913
3049
|
if (err instanceof CliError) {
|
|
2914
|
-
|
|
3050
|
+
consola26.error(err.message);
|
|
2915
3051
|
process.exit(err.exitCode);
|
|
2916
3052
|
}
|
|
2917
3053
|
if (debug) {
|
|
2918
|
-
|
|
3054
|
+
consola26.error(err);
|
|
2919
3055
|
} else {
|
|
2920
|
-
|
|
3056
|
+
consola26.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
|
|
2921
3057
|
}
|
|
2922
3058
|
process.exit(1);
|
|
2923
3059
|
});
|