@openape/apes 0.27.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
} from "./chunk-IDPV5SNB.js";
|
|
64
64
|
|
|
65
65
|
// src/cli.ts
|
|
66
|
-
import
|
|
66
|
+
import consola37 from "consola";
|
|
67
67
|
|
|
68
68
|
// src/ape-shell.ts
|
|
69
69
|
import path from "path";
|
|
@@ -93,7 +93,7 @@ function rewriteApeShellArgs(argv, argv0) {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
// src/cli.ts
|
|
96
|
-
import { defineCommand as
|
|
96
|
+
import { defineCommand as defineCommand45, runMain } from "citty";
|
|
97
97
|
|
|
98
98
|
// src/commands/auth/login.ts
|
|
99
99
|
import { Buffer as Buffer2 } from "buffer";
|
|
@@ -1743,13 +1743,10 @@ var adminCommand = defineCommand19({
|
|
|
1743
1743
|
});
|
|
1744
1744
|
|
|
1745
1745
|
// src/commands/agents/index.ts
|
|
1746
|
-
import { defineCommand as
|
|
1746
|
+
import { defineCommand as defineCommand25 } from "citty";
|
|
1747
1747
|
|
|
1748
|
-
// src/commands/agents/
|
|
1748
|
+
// src/commands/agents/allow.ts
|
|
1749
1749
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
1750
|
-
import { mkdtempSync, rmSync, writeFileSync } from "fs";
|
|
1751
|
-
import { tmpdir, userInfo } from "os";
|
|
1752
|
-
import { join as join2 } from "path";
|
|
1753
1750
|
import { defineCommand as defineCommand20 } from "citty";
|
|
1754
1751
|
import consola18 from "consola";
|
|
1755
1752
|
|
|
@@ -2010,7 +2007,8 @@ function buildAgentAuthJson(input) {
|
|
|
2010
2007
|
idp: input.idp,
|
|
2011
2008
|
access_token: input.accessToken,
|
|
2012
2009
|
email: input.email,
|
|
2013
|
-
expires_at: input.expiresAt
|
|
2010
|
+
expires_at: input.expiresAt,
|
|
2011
|
+
owner_email: input.ownerEmail
|
|
2014
2012
|
}, null, 2)}
|
|
2015
2013
|
`;
|
|
2016
2014
|
}
|
|
@@ -2097,6 +2095,84 @@ function isShellRegistered(shellPath) {
|
|
|
2097
2095
|
return content.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#")).includes(shellPath);
|
|
2098
2096
|
}
|
|
2099
2097
|
|
|
2098
|
+
// src/commands/agents/allow.ts
|
|
2099
|
+
var allowAgentCommand = defineCommand20({
|
|
2100
|
+
meta: {
|
|
2101
|
+
name: "allow",
|
|
2102
|
+
description: "Add a peer to the agent's contact-allowlist so the bridge auto-accepts that peer's contact request."
|
|
2103
|
+
},
|
|
2104
|
+
args: {
|
|
2105
|
+
agent: {
|
|
2106
|
+
type: "positional",
|
|
2107
|
+
required: true,
|
|
2108
|
+
description: "Agent name (the macOS short username spawn created)"
|
|
2109
|
+
},
|
|
2110
|
+
email: {
|
|
2111
|
+
type: "positional",
|
|
2112
|
+
required: true,
|
|
2113
|
+
description: "Peer email to allow (the address that will send the contact request)"
|
|
2114
|
+
}
|
|
2115
|
+
},
|
|
2116
|
+
async run({ args }) {
|
|
2117
|
+
const agent = args.agent;
|
|
2118
|
+
const email = args.email.trim().toLowerCase();
|
|
2119
|
+
if (!AGENT_NAME_REGEX.test(agent)) {
|
|
2120
|
+
throw new CliError(`Invalid agent name "${agent}".`);
|
|
2121
|
+
}
|
|
2122
|
+
if (!email.includes("@")) {
|
|
2123
|
+
throw new CliError(`Invalid email "${email}".`);
|
|
2124
|
+
}
|
|
2125
|
+
if (!isDarwin()) {
|
|
2126
|
+
throw new CliError("`apes agents allow` is currently macOS-only.");
|
|
2127
|
+
}
|
|
2128
|
+
if (!readMacOSUser(agent)) {
|
|
2129
|
+
throw new CliError(`No macOS user "${agent}" \u2014 has the agent been spawned?`);
|
|
2130
|
+
}
|
|
2131
|
+
const apes = whichBinary("apes");
|
|
2132
|
+
if (!apes) throw new CliError("`apes` not found on PATH.");
|
|
2133
|
+
const script = `set -eu
|
|
2134
|
+
mkdir -p "$HOME/.config/openape"
|
|
2135
|
+
F="$HOME/.config/openape/bridge-allowlist.json"
|
|
2136
|
+
EMAIL=${shQuote2(email)}
|
|
2137
|
+
python3 - "$F" "$EMAIL" <<'PY'
|
|
2138
|
+
import json, os, sys
|
|
2139
|
+
path, email = sys.argv[1], sys.argv[2].lower()
|
|
2140
|
+
data = {"emails": []}
|
|
2141
|
+
if os.path.exists(path):
|
|
2142
|
+
try:
|
|
2143
|
+
with open(path) as f:
|
|
2144
|
+
data = json.load(f)
|
|
2145
|
+
if not isinstance(data, dict) or not isinstance(data.get("emails"), list):
|
|
2146
|
+
data = {"emails": []}
|
|
2147
|
+
except Exception:
|
|
2148
|
+
data = {"emails": []}
|
|
2149
|
+
emails = {e.lower() for e in data["emails"] if isinstance(e, str)}
|
|
2150
|
+
emails.add(email)
|
|
2151
|
+
data["emails"] = sorted(emails)
|
|
2152
|
+
with open(path, "w") as f:
|
|
2153
|
+
json.dump(data, f, indent=2)
|
|
2154
|
+
f.write("\\n")
|
|
2155
|
+
print("ok")
|
|
2156
|
+
PY
|
|
2157
|
+
chmod 600 "$F"
|
|
2158
|
+
`;
|
|
2159
|
+
consola18.start(`Adding ${email} to ${agent}'s allowlist\u2026`);
|
|
2160
|
+
execFileSync3(apes, ["run", "--as", agent, "--wait", "--", "bash", "-c", script], { stdio: "inherit" });
|
|
2161
|
+
consola18.success(`${agent} will auto-accept future contact requests from ${email} (within ~30s of next bridge connect).`);
|
|
2162
|
+
}
|
|
2163
|
+
});
|
|
2164
|
+
function shQuote2(s) {
|
|
2165
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
// src/commands/agents/destroy.ts
|
|
2169
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
2170
|
+
import { mkdtempSync, rmSync, writeFileSync } from "fs";
|
|
2171
|
+
import { tmpdir, userInfo } from "os";
|
|
2172
|
+
import { join as join2 } from "path";
|
|
2173
|
+
import { defineCommand as defineCommand21 } from "citty";
|
|
2174
|
+
import consola19 from "consola";
|
|
2175
|
+
|
|
2100
2176
|
// src/lib/silent-password.ts
|
|
2101
2177
|
function readPasswordSilent(prompt) {
|
|
2102
2178
|
if (!process.stdin.isTTY) {
|
|
@@ -2152,7 +2228,7 @@ function readPasswordSilent(prompt) {
|
|
|
2152
2228
|
}
|
|
2153
2229
|
|
|
2154
2230
|
// src/commands/agents/destroy.ts
|
|
2155
|
-
var destroyAgentCommand =
|
|
2231
|
+
var destroyAgentCommand = defineCommand21({
|
|
2156
2232
|
meta: {
|
|
2157
2233
|
name: "destroy",
|
|
2158
2234
|
description: "Tear down an agent: remove macOS user, hard-delete IdP agent, drop all SSH keys"
|
|
@@ -2196,7 +2272,7 @@ var destroyAgentCommand = defineCommand20({
|
|
|
2196
2272
|
const idpExists = idpAgent !== void 0;
|
|
2197
2273
|
const osUserExists = !args["keep-os-user"] && isDarwin() && readMacOSUser(name) !== null;
|
|
2198
2274
|
if (!idpExists && !osUserExists) {
|
|
2199
|
-
|
|
2275
|
+
consola19.info(`Nothing to destroy: no IdP agent and no OS user named "${name}".`);
|
|
2200
2276
|
return;
|
|
2201
2277
|
}
|
|
2202
2278
|
if (!args.force) {
|
|
@@ -2205,14 +2281,14 @@ var destroyAgentCommand = defineCommand20({
|
|
|
2205
2281
|
if (idpExists) {
|
|
2206
2282
|
consequences.push(args.soft ? `\u2022 Deactivate IdP agent ${idpAgent.email} (PATCH isActive=false)` : `\u2022 Hard-delete IdP agent ${idpAgent.email} and all its SSH keys`);
|
|
2207
2283
|
}
|
|
2208
|
-
|
|
2284
|
+
consola19.warn(`About to destroy "${name}":
|
|
2209
2285
|
${consequences.join("\n")}`);
|
|
2210
2286
|
if (!process.stdin.isTTY) {
|
|
2211
2287
|
throw new CliError(
|
|
2212
2288
|
"No TTY available for the interactive confirmation. Re-run with --force to skip the prompt (this is the same flag CI uses)."
|
|
2213
2289
|
);
|
|
2214
2290
|
}
|
|
2215
|
-
const confirmed = await
|
|
2291
|
+
const confirmed = await consola19.prompt("Proceed?", { type: "confirm", initial: false });
|
|
2216
2292
|
if (typeof confirmed === "symbol" || !confirmed) {
|
|
2217
2293
|
throw new CliExit(0);
|
|
2218
2294
|
}
|
|
@@ -2221,13 +2297,13 @@ ${consequences.join("\n")}`);
|
|
|
2221
2297
|
const id = encodeURIComponent(idpAgent.email);
|
|
2222
2298
|
if (args.soft) {
|
|
2223
2299
|
await apiFetch(`/api/my-agents/${id}`, { method: "PATCH", body: { isActive: false }, idp });
|
|
2224
|
-
|
|
2300
|
+
consola19.success(`Deactivated IdP agent ${idpAgent.email}`);
|
|
2225
2301
|
} else {
|
|
2226
2302
|
await apiFetch(`/api/my-agents/${id}`, { method: "DELETE", idp });
|
|
2227
|
-
|
|
2303
|
+
consola19.success(`Deleted IdP agent ${idpAgent.email}`);
|
|
2228
2304
|
}
|
|
2229
2305
|
} else {
|
|
2230
|
-
|
|
2306
|
+
consola19.info("No IdP agent to remove (skipped).");
|
|
2231
2307
|
}
|
|
2232
2308
|
if (osUserExists) {
|
|
2233
2309
|
const sudo = whichBinary("sudo");
|
|
@@ -2241,8 +2317,8 @@ ${consequences.join("\n")}`);
|
|
|
2241
2317
|
try {
|
|
2242
2318
|
const script = buildDestroyTeardownScript({ name, homeDir: `/Users/${name}`, adminUser });
|
|
2243
2319
|
writeFileSync(scriptPath, script, { mode: 448 });
|
|
2244
|
-
|
|
2245
|
-
|
|
2320
|
+
consola19.start("Running teardown via sudo\u2026");
|
|
2321
|
+
execFileSync4(sudo, ["-S", "--prompt=", "--", "bash", scriptPath], {
|
|
2246
2322
|
input: `${adminPassword}
|
|
2247
2323
|
${adminPassword}
|
|
2248
2324
|
`,
|
|
@@ -2252,9 +2328,9 @@ ${adminPassword}
|
|
|
2252
2328
|
rmSync(scratch, { recursive: true, force: true });
|
|
2253
2329
|
}
|
|
2254
2330
|
} else if (!args["keep-os-user"] && isDarwin()) {
|
|
2255
|
-
|
|
2331
|
+
consola19.info("No macOS user to remove (skipped).");
|
|
2256
2332
|
}
|
|
2257
|
-
|
|
2333
|
+
consola19.success(`Destroyed ${name}.`);
|
|
2258
2334
|
}
|
|
2259
2335
|
});
|
|
2260
2336
|
async function collectAdminPassword(opts) {
|
|
@@ -2268,9 +2344,9 @@ async function collectAdminPassword(opts) {
|
|
|
2268
2344
|
}
|
|
2269
2345
|
|
|
2270
2346
|
// src/commands/agents/list.ts
|
|
2271
|
-
import { defineCommand as
|
|
2272
|
-
import
|
|
2273
|
-
var listAgentsCommand =
|
|
2347
|
+
import { defineCommand as defineCommand22 } from "citty";
|
|
2348
|
+
import consola20 from "consola";
|
|
2349
|
+
var listAgentsCommand = defineCommand22({
|
|
2274
2350
|
meta: {
|
|
2275
2351
|
name: "list",
|
|
2276
2352
|
description: "List agents owned by the current user, with local OS-user status"
|
|
@@ -2311,7 +2387,7 @@ var listAgentsCommand = defineCommand21({
|
|
|
2311
2387
|
return;
|
|
2312
2388
|
}
|
|
2313
2389
|
if (rows.length === 0) {
|
|
2314
|
-
|
|
2390
|
+
consola20.info(args["include-inactive"] ? "No agents found." : "No active agents found. Use --include-inactive to show deactivated.");
|
|
2315
2391
|
return;
|
|
2316
2392
|
}
|
|
2317
2393
|
const nameW = Math.max(4, ...rows.map((r) => r.name.length));
|
|
@@ -2330,9 +2406,9 @@ var listAgentsCommand = defineCommand21({
|
|
|
2330
2406
|
|
|
2331
2407
|
// src/commands/agents/register.ts
|
|
2332
2408
|
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
2333
|
-
import { defineCommand as
|
|
2334
|
-
import
|
|
2335
|
-
var registerAgentCommand =
|
|
2409
|
+
import { defineCommand as defineCommand23 } from "citty";
|
|
2410
|
+
import consola21 from "consola";
|
|
2411
|
+
var registerAgentCommand = defineCommand23({
|
|
2336
2412
|
meta: {
|
|
2337
2413
|
name: "register",
|
|
2338
2414
|
description: "Register an agent at the IdP using a supplied public key"
|
|
@@ -2402,7 +2478,7 @@ var registerAgentCommand = defineCommand22({
|
|
|
2402
2478
|
`);
|
|
2403
2479
|
return;
|
|
2404
2480
|
}
|
|
2405
|
-
|
|
2481
|
+
consola21.success("Agent registered.");
|
|
2406
2482
|
console.log(` Name: ${result.name}`);
|
|
2407
2483
|
console.log(` Email: ${result.email}`);
|
|
2408
2484
|
console.log(` IdP: ${idp}`);
|
|
@@ -2415,62 +2491,12 @@ var registerAgentCommand = defineCommand22({
|
|
|
2415
2491
|
});
|
|
2416
2492
|
|
|
2417
2493
|
// src/commands/agents/spawn.ts
|
|
2418
|
-
import { execFileSync as
|
|
2494
|
+
import { execFileSync as execFileSync5 } from "child_process";
|
|
2419
2495
|
import { mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
2420
2496
|
import { tmpdir as tmpdir2 } from "os";
|
|
2421
2497
|
import { join as join4 } from "path";
|
|
2422
|
-
import { defineCommand as
|
|
2423
|
-
import
|
|
2424
|
-
|
|
2425
|
-
// src/lib/chat-room.ts
|
|
2426
|
-
var DEFAULT_CHAT_ENDPOINT = "https://chat.openape.ai";
|
|
2427
|
-
function chatEndpoint() {
|
|
2428
|
-
return (process.env.APE_CHAT_ENDPOINT ?? DEFAULT_CHAT_ENDPOINT).replace(/\/$/, "");
|
|
2429
|
-
}
|
|
2430
|
-
async function chatFetch(bearer, path2, init) {
|
|
2431
|
-
const url = `${chatEndpoint()}${path2}`;
|
|
2432
|
-
const res = await fetch(url, {
|
|
2433
|
-
method: init?.method ?? "GET",
|
|
2434
|
-
headers: {
|
|
2435
|
-
Authorization: `Bearer ${bearer}`,
|
|
2436
|
-
"Content-Type": "application/json"
|
|
2437
|
-
},
|
|
2438
|
-
body: init?.body !== void 0 ? JSON.stringify(init.body) : void 0
|
|
2439
|
-
});
|
|
2440
|
-
if (!res.ok) {
|
|
2441
|
-
const detail = await res.text().catch(() => "");
|
|
2442
|
-
throw new Error(`chat.openape.ai ${init?.method ?? "GET"} ${path2} \u2192 ${res.status}: ${detail.slice(0, 200)}`);
|
|
2443
|
-
}
|
|
2444
|
-
return await res.json();
|
|
2445
|
-
}
|
|
2446
|
-
async function listRooms(bearer) {
|
|
2447
|
-
return chatFetch(bearer, "/api/rooms");
|
|
2448
|
-
}
|
|
2449
|
-
async function listMembers(bearer, roomId) {
|
|
2450
|
-
return chatFetch(bearer, `/api/rooms/${encodeURIComponent(roomId)}/members`);
|
|
2451
|
-
}
|
|
2452
|
-
async function findExistingDm(bearer, callerEmail, peerEmail) {
|
|
2453
|
-
const rooms = await listRooms(bearer);
|
|
2454
|
-
for (const room of rooms) {
|
|
2455
|
-
if (room.kind !== "dm") continue;
|
|
2456
|
-
const members = await listMembers(bearer, room.id);
|
|
2457
|
-
if (members.length !== 2) continue;
|
|
2458
|
-
const emails = new Set(members.map((m) => m.userEmail.toLowerCase()));
|
|
2459
|
-
if (emails.has(callerEmail.toLowerCase()) && emails.has(peerEmail.toLowerCase())) {
|
|
2460
|
-
return room;
|
|
2461
|
-
}
|
|
2462
|
-
}
|
|
2463
|
-
return null;
|
|
2464
|
-
}
|
|
2465
|
-
async function ensureDmWith(opts) {
|
|
2466
|
-
const existing = await findExistingDm(opts.callerBearer, opts.callerEmail, opts.peerEmail);
|
|
2467
|
-
if (existing) return { roomId: existing.id, created: false };
|
|
2468
|
-
const room = await chatFetch(opts.callerBearer, "/api/rooms", {
|
|
2469
|
-
method: "POST",
|
|
2470
|
-
body: { name: opts.peerEmail, kind: "dm", members: [opts.peerEmail] }
|
|
2471
|
-
});
|
|
2472
|
-
return { roomId: room.id, created: true };
|
|
2473
|
-
}
|
|
2498
|
+
import { defineCommand as defineCommand24 } from "citty";
|
|
2499
|
+
import consola22 from "consola";
|
|
2474
2500
|
|
|
2475
2501
|
// src/lib/keygen.ts
|
|
2476
2502
|
import { Buffer as Buffer4 } from "buffer";
|
|
@@ -2688,7 +2714,7 @@ function buildBridgePlist(agentName, homeDir) {
|
|
|
2688
2714
|
}
|
|
2689
2715
|
|
|
2690
2716
|
// src/commands/agents/spawn.ts
|
|
2691
|
-
var spawnAgentCommand =
|
|
2717
|
+
var spawnAgentCommand = defineCommand24({
|
|
2692
2718
|
meta: {
|
|
2693
2719
|
name: "spawn",
|
|
2694
2720
|
description: "Provision a local macOS agent end-to-end (OS user, keypair, IdP agent, Claude hook)"
|
|
@@ -2774,12 +2800,12 @@ and try again.`
|
|
|
2774
2800
|
const scratch = mkdtempSync2(join4(tmpdir2(), `apes-spawn-${name}-`));
|
|
2775
2801
|
const scriptPath = join4(scratch, "setup.sh");
|
|
2776
2802
|
try {
|
|
2777
|
-
|
|
2803
|
+
consola22.start(`Generating keypair for ${name}\u2026`);
|
|
2778
2804
|
const { privatePem, publicSshLine } = generateKeyPairInMemory();
|
|
2779
|
-
|
|
2805
|
+
consola22.start(`Registering agent at ${idp}\u2026`);
|
|
2780
2806
|
const registration = await registerAgentAtIdp({ name, publicKey: publicSshLine, idp });
|
|
2781
|
-
|
|
2782
|
-
|
|
2807
|
+
consola22.success(`Registered as ${registration.email}`);
|
|
2808
|
+
consola22.start("Issuing agent access token\u2026");
|
|
2783
2809
|
const { token, expiresIn } = await issueAgentToken({
|
|
2784
2810
|
idp,
|
|
2785
2811
|
agentEmail: registration.email,
|
|
@@ -2789,7 +2815,8 @@ and try again.`
|
|
|
2789
2815
|
idp,
|
|
2790
2816
|
accessToken: token,
|
|
2791
2817
|
email: registration.email,
|
|
2792
|
-
expiresAt: Math.floor(Date.now() / 1e3) + expiresIn
|
|
2818
|
+
expiresAt: Math.floor(Date.now() / 1e3) + expiresIn,
|
|
2819
|
+
ownerEmail: auth.email
|
|
2793
2820
|
});
|
|
2794
2821
|
const includeClaudeHook = !args["no-claude-hook"];
|
|
2795
2822
|
const claudeOauthToken = await resolveClaudeToken({
|
|
@@ -2822,25 +2849,13 @@ and try again.`
|
|
|
2822
2849
|
bridge
|
|
2823
2850
|
});
|
|
2824
2851
|
writeFileSync3(scriptPath, script, { mode: 448 });
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2852
|
+
consola22.start("Running privileged setup as root via `apes run --as root --wait`\u2026");
|
|
2853
|
+
consola22.info("You will be asked to approve the as=root grant in your DDISA inbox; this command blocks until you do.");
|
|
2854
|
+
execFileSync5(apes, ["run", "--as", "root", "--wait", "--", "bash", scriptPath], { stdio: "inherit" });
|
|
2855
|
+
consola22.success(`Agent ${name} spawned.`);
|
|
2829
2856
|
if (args.bridge) {
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
const result = await ensureDmWith({
|
|
2833
|
-
callerBearer: auth.access_token,
|
|
2834
|
-
callerEmail: auth.email,
|
|
2835
|
-
peerEmail: registration.email
|
|
2836
|
-
});
|
|
2837
|
-
consola21.success(
|
|
2838
|
-
result.created ? `Created direct chat with ${registration.email}` : `Direct chat with ${registration.email} already existed`
|
|
2839
|
-
);
|
|
2840
|
-
} catch (err) {
|
|
2841
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2842
|
-
consola21.warn(`Could not auto-create direct chat: ${msg}`);
|
|
2843
|
-
}
|
|
2857
|
+
consola22.info(`On first boot, the bridge will send you a contact request from ${registration.email}.`);
|
|
2858
|
+
consola22.info("Open chat.openape.ai and accept it to start chatting with the agent.");
|
|
2844
2859
|
}
|
|
2845
2860
|
console.log("");
|
|
2846
2861
|
console.log("Run as the agent with:");
|
|
@@ -2874,29 +2889,30 @@ async function resolveClaudeToken(opts) {
|
|
|
2874
2889
|
}
|
|
2875
2890
|
|
|
2876
2891
|
// src/commands/agents/index.ts
|
|
2877
|
-
var agentsCommand =
|
|
2892
|
+
var agentsCommand = defineCommand25({
|
|
2878
2893
|
meta: {
|
|
2879
2894
|
name: "agents",
|
|
2880
|
-
description: "Manage owned agents (register, spawn, list, destroy)"
|
|
2895
|
+
description: "Manage owned agents (register, spawn, list, destroy, allow)"
|
|
2881
2896
|
},
|
|
2882
2897
|
subCommands: {
|
|
2883
2898
|
register: registerAgentCommand,
|
|
2884
2899
|
spawn: spawnAgentCommand,
|
|
2885
2900
|
list: listAgentsCommand,
|
|
2886
|
-
destroy: destroyAgentCommand
|
|
2901
|
+
destroy: destroyAgentCommand,
|
|
2902
|
+
allow: allowAgentCommand
|
|
2887
2903
|
}
|
|
2888
2904
|
});
|
|
2889
2905
|
|
|
2890
2906
|
// src/commands/adapter/index.ts
|
|
2891
|
-
import { defineCommand as
|
|
2892
|
-
import
|
|
2893
|
-
var adapterCommand =
|
|
2907
|
+
import { defineCommand as defineCommand26 } from "citty";
|
|
2908
|
+
import consola23 from "consola";
|
|
2909
|
+
var adapterCommand = defineCommand26({
|
|
2894
2910
|
meta: {
|
|
2895
2911
|
name: "adapter",
|
|
2896
2912
|
description: "Manage CLI adapters"
|
|
2897
2913
|
},
|
|
2898
2914
|
subCommands: {
|
|
2899
|
-
list:
|
|
2915
|
+
list: defineCommand26({
|
|
2900
2916
|
meta: {
|
|
2901
2917
|
name: "list",
|
|
2902
2918
|
description: "List available adapters"
|
|
@@ -2927,7 +2943,7 @@ var adapterCommand = defineCommand25({
|
|
|
2927
2943
|
`);
|
|
2928
2944
|
return;
|
|
2929
2945
|
}
|
|
2930
|
-
|
|
2946
|
+
consola23.info(`Registry: ${index2.adapters.length} adapters (${index2.generated_at})`);
|
|
2931
2947
|
for (const a of index2.adapters) {
|
|
2932
2948
|
const installed = isInstalled(a.id, false) ? " [installed]" : "";
|
|
2933
2949
|
console.log(` ${a.id.padEnd(12)} ${a.name.padEnd(24)} ${a.category}${installed}`);
|
|
@@ -2949,7 +2965,7 @@ var adapterCommand = defineCommand25({
|
|
|
2949
2965
|
return;
|
|
2950
2966
|
}
|
|
2951
2967
|
if (local.length === 0) {
|
|
2952
|
-
|
|
2968
|
+
consola23.info("No adapters installed. Use `apes adapter list --remote` to see available adapters.");
|
|
2953
2969
|
return;
|
|
2954
2970
|
}
|
|
2955
2971
|
for (const a of local) {
|
|
@@ -2957,7 +2973,7 @@ var adapterCommand = defineCommand25({
|
|
|
2957
2973
|
}
|
|
2958
2974
|
}
|
|
2959
2975
|
}),
|
|
2960
|
-
install:
|
|
2976
|
+
install: defineCommand26({
|
|
2961
2977
|
meta: {
|
|
2962
2978
|
name: "install",
|
|
2963
2979
|
description: "Install an adapter from the registry"
|
|
@@ -2986,24 +3002,24 @@ var adapterCommand = defineCommand25({
|
|
|
2986
3002
|
for (const id of ids) {
|
|
2987
3003
|
const entry = findAdapter(index, id);
|
|
2988
3004
|
if (!entry) {
|
|
2989
|
-
|
|
3005
|
+
consola23.error(`Adapter "${id}" not found in registry. Use \`apes adapter search ${id}\` to search.`);
|
|
2990
3006
|
continue;
|
|
2991
3007
|
}
|
|
2992
3008
|
const conflicts = findConflictingAdapters(entry.executable, id);
|
|
2993
3009
|
if (conflicts.length > 0) {
|
|
2994
3010
|
for (const c of conflicts) {
|
|
2995
|
-
|
|
2996
|
-
|
|
3011
|
+
consola23.warn(`Conflicting adapter found: ${c.path} (id: ${c.adapterId}, executable: ${c.executable})`);
|
|
3012
|
+
consola23.warn(` Remove it with: apes adapter remove ${c.adapterId}`);
|
|
2997
3013
|
}
|
|
2998
3014
|
}
|
|
2999
3015
|
const result = await installAdapter(entry, { local });
|
|
3000
3016
|
const verb = result.updated ? "Updated" : "Installed";
|
|
3001
|
-
|
|
3002
|
-
|
|
3017
|
+
consola23.success(`${verb} ${result.id} \u2192 ${result.path}`);
|
|
3018
|
+
consola23.info(`Digest: ${result.digest}`);
|
|
3003
3019
|
}
|
|
3004
3020
|
}
|
|
3005
3021
|
}),
|
|
3006
|
-
remove:
|
|
3022
|
+
remove: defineCommand26({
|
|
3007
3023
|
meta: {
|
|
3008
3024
|
name: "remove",
|
|
3009
3025
|
description: "Remove an installed adapter"
|
|
@@ -3026,9 +3042,9 @@ var adapterCommand = defineCommand25({
|
|
|
3026
3042
|
let failed = false;
|
|
3027
3043
|
for (const id of ids) {
|
|
3028
3044
|
if (removeAdapter(id, local)) {
|
|
3029
|
-
|
|
3045
|
+
consola23.success(`Removed adapter: ${id}`);
|
|
3030
3046
|
} else {
|
|
3031
|
-
|
|
3047
|
+
consola23.error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
|
|
3032
3048
|
failed = true;
|
|
3033
3049
|
}
|
|
3034
3050
|
}
|
|
@@ -3036,7 +3052,7 @@ var adapterCommand = defineCommand25({
|
|
|
3036
3052
|
throw new CliError("Some adapters could not be removed");
|
|
3037
3053
|
}
|
|
3038
3054
|
}),
|
|
3039
|
-
info:
|
|
3055
|
+
info: defineCommand26({
|
|
3040
3056
|
meta: {
|
|
3041
3057
|
name: "info",
|
|
3042
3058
|
description: "Show detailed adapter information"
|
|
@@ -3078,7 +3094,7 @@ var adapterCommand = defineCommand25({
|
|
|
3078
3094
|
}
|
|
3079
3095
|
}
|
|
3080
3096
|
}),
|
|
3081
|
-
search:
|
|
3097
|
+
search: defineCommand26({
|
|
3082
3098
|
meta: {
|
|
3083
3099
|
name: "search",
|
|
3084
3100
|
description: "Search adapters in the registry"
|
|
@@ -3110,7 +3126,7 @@ var adapterCommand = defineCommand25({
|
|
|
3110
3126
|
return;
|
|
3111
3127
|
}
|
|
3112
3128
|
if (results.length === 0) {
|
|
3113
|
-
|
|
3129
|
+
consola23.info(`No adapters matching "${query}"`);
|
|
3114
3130
|
return;
|
|
3115
3131
|
}
|
|
3116
3132
|
for (const a of results) {
|
|
@@ -3119,7 +3135,7 @@ var adapterCommand = defineCommand25({
|
|
|
3119
3135
|
}
|
|
3120
3136
|
}
|
|
3121
3137
|
}),
|
|
3122
|
-
update:
|
|
3138
|
+
update: defineCommand26({
|
|
3123
3139
|
meta: {
|
|
3124
3140
|
name: "update",
|
|
3125
3141
|
description: "Update installed adapters"
|
|
@@ -3145,33 +3161,33 @@ var adapterCommand = defineCommand25({
|
|
|
3145
3161
|
const targetId = args.id ? String(args.id) : void 0;
|
|
3146
3162
|
const targets = targetId ? [targetId] : index.adapters.map((a) => a.id).filter((id) => isInstalled(id, false));
|
|
3147
3163
|
if (targets.length === 0) {
|
|
3148
|
-
|
|
3164
|
+
consola23.info("No adapters installed to update.");
|
|
3149
3165
|
return;
|
|
3150
3166
|
}
|
|
3151
3167
|
for (const id of targets) {
|
|
3152
3168
|
const entry = findAdapter(index, id);
|
|
3153
3169
|
if (!entry) {
|
|
3154
|
-
|
|
3170
|
+
consola23.warn(`${id}: not found in registry, skipping`);
|
|
3155
3171
|
continue;
|
|
3156
3172
|
}
|
|
3157
3173
|
const localDigest = getInstalledDigest(id, false);
|
|
3158
3174
|
if (localDigest === entry.digest) {
|
|
3159
|
-
|
|
3175
|
+
consola23.info(`${id}: already up to date`);
|
|
3160
3176
|
continue;
|
|
3161
3177
|
}
|
|
3162
3178
|
if (localDigest && !args.yes) {
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3179
|
+
consola23.warn(`${id}: digest will change \u2014 existing grants for this adapter will be invalidated`);
|
|
3180
|
+
consola23.info(` Old: ${localDigest}`);
|
|
3181
|
+
consola23.info(` New: ${entry.digest}`);
|
|
3182
|
+
consola23.info(" Use --yes to confirm");
|
|
3167
3183
|
continue;
|
|
3168
3184
|
}
|
|
3169
3185
|
const result = await installAdapter(entry);
|
|
3170
|
-
|
|
3186
|
+
consola23.success(`Updated ${result.id} \u2192 ${result.path}`);
|
|
3171
3187
|
}
|
|
3172
3188
|
}
|
|
3173
3189
|
}),
|
|
3174
|
-
verify:
|
|
3190
|
+
verify: defineCommand26({
|
|
3175
3191
|
meta: {
|
|
3176
3192
|
name: "verify",
|
|
3177
3193
|
description: "Verify installed adapter against registry digest"
|
|
@@ -3204,7 +3220,7 @@ var adapterCommand = defineCommand25({
|
|
|
3204
3220
|
if (!localDigest)
|
|
3205
3221
|
throw new Error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
|
|
3206
3222
|
if (localDigest === entry.digest) {
|
|
3207
|
-
|
|
3223
|
+
consola23.success(`${id}: digest matches registry`);
|
|
3208
3224
|
} else {
|
|
3209
3225
|
console.log(` Local: ${localDigest}`);
|
|
3210
3226
|
console.log(` Registry: ${entry.digest}`);
|
|
@@ -3216,11 +3232,11 @@ var adapterCommand = defineCommand25({
|
|
|
3216
3232
|
});
|
|
3217
3233
|
|
|
3218
3234
|
// src/commands/run.ts
|
|
3219
|
-
import { execFileSync as
|
|
3235
|
+
import { execFileSync as execFileSync6 } from "child_process";
|
|
3220
3236
|
import { hostname as hostname3 } from "os";
|
|
3221
3237
|
import { basename } from "path";
|
|
3222
|
-
import { defineCommand as
|
|
3223
|
-
import
|
|
3238
|
+
import { defineCommand as defineCommand27 } from "citty";
|
|
3239
|
+
import consola24 from "consola";
|
|
3224
3240
|
function shouldWaitForGrant(args) {
|
|
3225
3241
|
return args.wait === true || process.env.APE_WAIT === "1";
|
|
3226
3242
|
}
|
|
@@ -3257,7 +3273,7 @@ function printPendingGrantInfo(grant, idp) {
|
|
|
3257
3273
|
const statusCmd = `apes grants status ${grant.id}`;
|
|
3258
3274
|
const executeCmd = `apes grants run ${grant.id}`;
|
|
3259
3275
|
if (mode === "human") {
|
|
3260
|
-
|
|
3276
|
+
consola24.success(`Grant ${grant.id} created \u2014 awaiting your approval`);
|
|
3261
3277
|
console.log(` Approve in browser: ${approveUrl}`);
|
|
3262
3278
|
console.log(` Check status: ${statusCmd}`);
|
|
3263
3279
|
console.log(` Run after approval: ${executeCmd}`);
|
|
@@ -3267,7 +3283,7 @@ function printPendingGrantInfo(grant, idp) {
|
|
|
3267
3283
|
return;
|
|
3268
3284
|
}
|
|
3269
3285
|
const maxMin = getPollMaxMinutes();
|
|
3270
|
-
|
|
3286
|
+
consola24.success(`Grant ${grant.id} created (pending approval)`);
|
|
3271
3287
|
console.log(` Approve: ${approveUrl}`);
|
|
3272
3288
|
console.log(` Status: ${statusCmd} [--json]`);
|
|
3273
3289
|
console.log(` Execute: ${executeCmd} --wait`);
|
|
@@ -3289,7 +3305,7 @@ function printPendingGrantInfo(grant, idp) {
|
|
|
3289
3305
|
console.log(' Tip: Approve as "timed" or "always" in the browser to let this');
|
|
3290
3306
|
console.log(" grant be reused on subsequent invocations without re-approval.");
|
|
3291
3307
|
}
|
|
3292
|
-
var runCommand =
|
|
3308
|
+
var runCommand = defineCommand27({
|
|
3293
3309
|
meta: {
|
|
3294
3310
|
name: "run",
|
|
3295
3311
|
description: "Execute a grant-secured command"
|
|
@@ -3392,7 +3408,7 @@ async function runShellMode(command, args) {
|
|
|
3392
3408
|
}
|
|
3393
3409
|
} catch {
|
|
3394
3410
|
}
|
|
3395
|
-
|
|
3411
|
+
consola24.info(`Requesting ape-shell session grant on ${targetHost}`);
|
|
3396
3412
|
const grant = await apiFetch(grantsUrl, {
|
|
3397
3413
|
method: "POST",
|
|
3398
3414
|
body: {
|
|
@@ -3412,8 +3428,8 @@ async function runShellMode(command, args) {
|
|
|
3412
3428
|
host: targetHost
|
|
3413
3429
|
});
|
|
3414
3430
|
if (shouldWaitForGrant(args)) {
|
|
3415
|
-
|
|
3416
|
-
|
|
3431
|
+
consola24.info(`Grant requested: ${grant.id}`);
|
|
3432
|
+
consola24.info("Waiting for approval...");
|
|
3417
3433
|
const maxWait = 3e5;
|
|
3418
3434
|
const interval = 3e3;
|
|
3419
3435
|
const start = Date.now();
|
|
@@ -3444,13 +3460,13 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
3444
3460
|
try {
|
|
3445
3461
|
resolved = await resolveCommand(loaded, [normalizedExecutable, ...parsed.argv]);
|
|
3446
3462
|
} catch (err) {
|
|
3447
|
-
|
|
3463
|
+
consola24.debug(`ape-shell: adapter resolve failed for "${parsed.raw}":`, err);
|
|
3448
3464
|
return false;
|
|
3449
3465
|
}
|
|
3450
3466
|
try {
|
|
3451
3467
|
const existingGrantId = await findExistingGrant(resolved, idp);
|
|
3452
3468
|
if (existingGrantId) {
|
|
3453
|
-
|
|
3469
|
+
consola24.info(`Reusing grant ${existingGrantId} for: ${resolved.detail.display}`);
|
|
3454
3470
|
const token = await fetchGrantToken(idp, existingGrantId);
|
|
3455
3471
|
await verifyAndExecute(token, resolved, existingGrantId);
|
|
3456
3472
|
return true;
|
|
@@ -3458,7 +3474,7 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
3458
3474
|
} catch {
|
|
3459
3475
|
}
|
|
3460
3476
|
const approval = args.approval ?? "once";
|
|
3461
|
-
|
|
3477
|
+
consola24.info(`Requesting grant for: ${resolved.detail.display}`);
|
|
3462
3478
|
const grant = await createShapesGrant(resolved, {
|
|
3463
3479
|
idp,
|
|
3464
3480
|
approval,
|
|
@@ -3466,8 +3482,8 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
3466
3482
|
});
|
|
3467
3483
|
if (grant.similar_grants?.similar_grants?.length) {
|
|
3468
3484
|
const n = grant.similar_grants.similar_grants.length;
|
|
3469
|
-
|
|
3470
|
-
|
|
3485
|
+
consola24.info("");
|
|
3486
|
+
consola24.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
|
|
3471
3487
|
}
|
|
3472
3488
|
notifyGrantPending({
|
|
3473
3489
|
grantId: grant.id,
|
|
@@ -3477,8 +3493,8 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
3477
3493
|
host: args.host || hostname3()
|
|
3478
3494
|
});
|
|
3479
3495
|
if (shouldWaitForGrant(args)) {
|
|
3480
|
-
|
|
3481
|
-
|
|
3496
|
+
consola24.info(`Grant requested: ${grant.id}`);
|
|
3497
|
+
consola24.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
|
|
3482
3498
|
const status = await waitForGrantStatus(idp, grant.id);
|
|
3483
3499
|
if (status !== "approved")
|
|
3484
3500
|
throw new CliError(`Grant ${status}`);
|
|
@@ -3494,7 +3510,7 @@ function execShellCommand(command) {
|
|
|
3494
3510
|
throw new CliError("No command to execute");
|
|
3495
3511
|
try {
|
|
3496
3512
|
const { APES_SHELL_WRAPPER: _wrapperMarker, ...inheritedEnv } = process.env;
|
|
3497
|
-
|
|
3513
|
+
execFileSync6(command[0], command.slice(1), {
|
|
3498
3514
|
stdio: "inherit",
|
|
3499
3515
|
env: inheritedEnv
|
|
3500
3516
|
});
|
|
@@ -3552,7 +3568,7 @@ async function runAdapterMode(command, rawArgs, args) {
|
|
|
3552
3568
|
try {
|
|
3553
3569
|
const existingGrantId = await findExistingGrant(resolved, idp);
|
|
3554
3570
|
if (existingGrantId) {
|
|
3555
|
-
|
|
3571
|
+
consola24.info(`Reusing existing grant: ${existingGrantId}`);
|
|
3556
3572
|
const token = await fetchGrantToken(idp, existingGrantId);
|
|
3557
3573
|
await verifyAndExecute(token, resolved, existingGrantId);
|
|
3558
3574
|
return;
|
|
@@ -3566,17 +3582,17 @@ async function runAdapterMode(command, rawArgs, args) {
|
|
|
3566
3582
|
});
|
|
3567
3583
|
if (grant.similar_grants?.similar_grants?.length) {
|
|
3568
3584
|
const n = grant.similar_grants.similar_grants.length;
|
|
3569
|
-
|
|
3570
|
-
|
|
3585
|
+
consola24.info("");
|
|
3586
|
+
consola24.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
|
|
3571
3587
|
if (grant.similar_grants.widened_details?.length) {
|
|
3572
3588
|
const wider = grant.similar_grants.widened_details.map((d) => d.permission).join(", ");
|
|
3573
|
-
|
|
3589
|
+
consola24.info(` Broader scope: ${wider}`);
|
|
3574
3590
|
}
|
|
3575
|
-
|
|
3591
|
+
consola24.info("");
|
|
3576
3592
|
}
|
|
3577
3593
|
if (shouldWaitForGrant(args)) {
|
|
3578
|
-
|
|
3579
|
-
|
|
3594
|
+
consola24.info(`Grant requested: ${grant.id}`);
|
|
3595
|
+
consola24.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
|
|
3580
3596
|
const status = await waitForGrantStatus(idp, grant.id);
|
|
3581
3597
|
if (status !== "approved")
|
|
3582
3598
|
throw new Error(`Grant ${status}`);
|
|
@@ -3596,7 +3612,7 @@ async function runAudienceMode(audience, action, args) {
|
|
|
3596
3612
|
const grantsUrl = await getGrantsEndpoint(idp);
|
|
3597
3613
|
const command = action.split(" ");
|
|
3598
3614
|
const targetHost = args.host || hostname3();
|
|
3599
|
-
|
|
3615
|
+
consola24.info(`Requesting ${audience} grant on ${targetHost}: ${command.join(" ")}`);
|
|
3600
3616
|
const grant = await apiFetch(grantsUrl, {
|
|
3601
3617
|
method: "POST",
|
|
3602
3618
|
body: {
|
|
@@ -3613,9 +3629,9 @@ async function runAudienceMode(audience, action, args) {
|
|
|
3613
3629
|
printPendingGrantInfo(grant, idp);
|
|
3614
3630
|
throw new CliExit(getAsyncExitCode());
|
|
3615
3631
|
}
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3632
|
+
consola24.success(`Grant requested: ${grant.id}`);
|
|
3633
|
+
consola24.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
|
|
3634
|
+
consola24.info("Waiting for approval...");
|
|
3619
3635
|
const maxWait = 15 * 60 * 1e3;
|
|
3620
3636
|
const interval = 3e3;
|
|
3621
3637
|
const start = Date.now();
|
|
@@ -3623,7 +3639,7 @@ async function runAudienceMode(audience, action, args) {
|
|
|
3623
3639
|
while (Date.now() - start < maxWait) {
|
|
3624
3640
|
const status = await apiFetch(`${grantsUrl}/${grant.id}`);
|
|
3625
3641
|
if (status.status === "approved") {
|
|
3626
|
-
|
|
3642
|
+
consola24.success("Grant approved!");
|
|
3627
3643
|
approved = true;
|
|
3628
3644
|
break;
|
|
3629
3645
|
}
|
|
@@ -3638,15 +3654,15 @@ async function runAudienceMode(audience, action, args) {
|
|
|
3638
3654
|
`Grant approval timed out after ${minutes} min (still pending). Check your DDISA inbox at ${idp}/grant-approval?grant_id=${grant.id} \u2014 if approved later, re-run the same \`apes run\` command and it will reuse the grant.`
|
|
3639
3655
|
);
|
|
3640
3656
|
}
|
|
3641
|
-
|
|
3657
|
+
consola24.info("Fetching grant token...");
|
|
3642
3658
|
const { authz_jwt } = await apiFetch(`${grantsUrl}/${grant.id}/token`, {
|
|
3643
3659
|
method: "POST"
|
|
3644
3660
|
});
|
|
3645
3661
|
if (audience === "escapes") {
|
|
3646
|
-
|
|
3662
|
+
consola24.info(`Executing: ${command.join(" ")}`);
|
|
3647
3663
|
try {
|
|
3648
3664
|
const { APES_SHELL_WRAPPER: _wrapperMarker, ...inheritedEnv } = process.env;
|
|
3649
|
-
|
|
3665
|
+
execFileSync6(args["escapes-path"] || "escapes", ["--grant", authz_jwt, "--", ...command], {
|
|
3650
3666
|
stdio: "inherit",
|
|
3651
3667
|
env: inheritedEnv
|
|
3652
3668
|
});
|
|
@@ -3661,8 +3677,8 @@ async function runAudienceMode(audience, action, args) {
|
|
|
3661
3677
|
|
|
3662
3678
|
// src/commands/proxy.ts
|
|
3663
3679
|
import { spawn as spawn2 } from "child_process";
|
|
3664
|
-
import { defineCommand as
|
|
3665
|
-
import
|
|
3680
|
+
import { defineCommand as defineCommand28 } from "citty";
|
|
3681
|
+
import consola25 from "consola";
|
|
3666
3682
|
|
|
3667
3683
|
// src/proxy/config.ts
|
|
3668
3684
|
function buildDefaultProxyConfigToml(opts) {
|
|
@@ -3805,10 +3821,10 @@ function resolveProxyConfigOptions() {
|
|
|
3805
3821
|
77
|
|
3806
3822
|
);
|
|
3807
3823
|
}
|
|
3808
|
-
|
|
3824
|
+
consola25.info(`[apes proxy] IdP-mediated mode \u2014 agent=${auth.email}, idp=${auth.idp}`);
|
|
3809
3825
|
return { agentEmail: auth.email, idpUrl: auth.idp, mediated: true };
|
|
3810
3826
|
}
|
|
3811
|
-
var proxyCommand =
|
|
3827
|
+
var proxyCommand = defineCommand28({
|
|
3812
3828
|
meta: {
|
|
3813
3829
|
name: "proxy",
|
|
3814
3830
|
description: "Run a command with HTTPS_PROXY routed through the OpenApe egress proxy."
|
|
@@ -3830,12 +3846,12 @@ var proxyCommand = defineCommand27({
|
|
|
3830
3846
|
let close = null;
|
|
3831
3847
|
if (reuseUrl) {
|
|
3832
3848
|
proxyUrl = reuseUrl;
|
|
3833
|
-
|
|
3849
|
+
consola25.info(`[apes proxy] reusing existing proxy at ${proxyUrl}`);
|
|
3834
3850
|
} else {
|
|
3835
3851
|
const ephemeral = await startEphemeralProxy(buildDefaultProxyConfigToml(resolveProxyConfigOptions()));
|
|
3836
3852
|
proxyUrl = ephemeral.url;
|
|
3837
3853
|
close = ephemeral.close;
|
|
3838
|
-
|
|
3854
|
+
consola25.info(`[apes proxy] started ephemeral proxy at ${proxyUrl}`);
|
|
3839
3855
|
}
|
|
3840
3856
|
const noProxy = process.env.NO_PROXY ?? process.env.no_proxy ?? "127.0.0.1,localhost";
|
|
3841
3857
|
const childEnv = {
|
|
@@ -3867,7 +3883,7 @@ var proxyCommand = defineCommand27({
|
|
|
3867
3883
|
else resolveExit(code ?? 0);
|
|
3868
3884
|
});
|
|
3869
3885
|
child.once("error", (err) => {
|
|
3870
|
-
|
|
3886
|
+
consola25.error(`[apes proxy] failed to spawn '${wrapped[0]}':`, err.message);
|
|
3871
3887
|
resolveExit(127);
|
|
3872
3888
|
});
|
|
3873
3889
|
});
|
|
@@ -3881,8 +3897,8 @@ function signalNumber(signal) {
|
|
|
3881
3897
|
}
|
|
3882
3898
|
|
|
3883
3899
|
// src/commands/explain.ts
|
|
3884
|
-
import { defineCommand as
|
|
3885
|
-
var explainCommand =
|
|
3900
|
+
import { defineCommand as defineCommand29 } from "citty";
|
|
3901
|
+
var explainCommand = defineCommand29({
|
|
3886
3902
|
meta: {
|
|
3887
3903
|
name: "explain",
|
|
3888
3904
|
description: "Show what permission a command would need"
|
|
@@ -3920,9 +3936,9 @@ var explainCommand = defineCommand28({
|
|
|
3920
3936
|
});
|
|
3921
3937
|
|
|
3922
3938
|
// src/commands/config/get.ts
|
|
3923
|
-
import { defineCommand as
|
|
3924
|
-
import
|
|
3925
|
-
var configGetCommand =
|
|
3939
|
+
import { defineCommand as defineCommand30 } from "citty";
|
|
3940
|
+
import consola26 from "consola";
|
|
3941
|
+
var configGetCommand = defineCommand30({
|
|
3926
3942
|
meta: {
|
|
3927
3943
|
name: "get",
|
|
3928
3944
|
description: "Get a configuration value"
|
|
@@ -3942,7 +3958,7 @@ var configGetCommand = defineCommand29({
|
|
|
3942
3958
|
if (idp)
|
|
3943
3959
|
console.log(idp);
|
|
3944
3960
|
else
|
|
3945
|
-
|
|
3961
|
+
consola26.info("No IdP configured.");
|
|
3946
3962
|
break;
|
|
3947
3963
|
}
|
|
3948
3964
|
case "email": {
|
|
@@ -3950,7 +3966,7 @@ var configGetCommand = defineCommand29({
|
|
|
3950
3966
|
if (auth?.email)
|
|
3951
3967
|
console.log(auth.email);
|
|
3952
3968
|
else
|
|
3953
|
-
|
|
3969
|
+
consola26.info("Not logged in.");
|
|
3954
3970
|
break;
|
|
3955
3971
|
}
|
|
3956
3972
|
default: {
|
|
@@ -3963,7 +3979,7 @@ var configGetCommand = defineCommand29({
|
|
|
3963
3979
|
if (sectionObj && field in sectionObj) {
|
|
3964
3980
|
console.log(sectionObj[field]);
|
|
3965
3981
|
} else {
|
|
3966
|
-
|
|
3982
|
+
consola26.info(`Key "${key}" not set.`);
|
|
3967
3983
|
}
|
|
3968
3984
|
} else {
|
|
3969
3985
|
throw new CliError(`Unknown key: "${key}". Use: idp, email, defaults.idp, defaults.approval, agent.key, agent.email`);
|
|
@@ -3974,9 +3990,9 @@ var configGetCommand = defineCommand29({
|
|
|
3974
3990
|
});
|
|
3975
3991
|
|
|
3976
3992
|
// src/commands/config/set.ts
|
|
3977
|
-
import { defineCommand as
|
|
3978
|
-
import
|
|
3979
|
-
var configSetCommand =
|
|
3993
|
+
import { defineCommand as defineCommand31 } from "citty";
|
|
3994
|
+
import consola27 from "consola";
|
|
3995
|
+
var configSetCommand = defineCommand31({
|
|
3980
3996
|
meta: {
|
|
3981
3997
|
name: "set",
|
|
3982
3998
|
description: "Set a configuration value"
|
|
@@ -4012,12 +4028,12 @@ var configSetCommand = defineCommand30({
|
|
|
4012
4028
|
throw new CliError(`Unknown section: "${section}". Use: defaults, agent`);
|
|
4013
4029
|
}
|
|
4014
4030
|
saveConfig(config);
|
|
4015
|
-
|
|
4031
|
+
consola27.success(`Set ${key} = ${value}`);
|
|
4016
4032
|
}
|
|
4017
4033
|
});
|
|
4018
4034
|
|
|
4019
4035
|
// src/commands/fetch/index.ts
|
|
4020
|
-
import { defineCommand as
|
|
4036
|
+
import { defineCommand as defineCommand32 } from "citty";
|
|
4021
4037
|
async function doRequest(method, url, body, contentType, raw, showHeaders) {
|
|
4022
4038
|
const token = getAuthToken();
|
|
4023
4039
|
if (!token) {
|
|
@@ -4053,13 +4069,13 @@ async function doRequest(method, url, body, contentType, raw, showHeaders) {
|
|
|
4053
4069
|
throw new CliError(`HTTP ${response.status} ${response.statusText}`);
|
|
4054
4070
|
}
|
|
4055
4071
|
}
|
|
4056
|
-
var fetchCommand =
|
|
4072
|
+
var fetchCommand = defineCommand32({
|
|
4057
4073
|
meta: {
|
|
4058
4074
|
name: "fetch",
|
|
4059
4075
|
description: "Make authenticated HTTP requests"
|
|
4060
4076
|
},
|
|
4061
4077
|
subCommands: {
|
|
4062
|
-
get:
|
|
4078
|
+
get: defineCommand32({
|
|
4063
4079
|
meta: {
|
|
4064
4080
|
name: "get",
|
|
4065
4081
|
description: "GET request with auth token"
|
|
@@ -4085,7 +4101,7 @@ var fetchCommand = defineCommand31({
|
|
|
4085
4101
|
await doRequest("GET", String(args.url), void 0, "application/json", Boolean(args.raw), Boolean(args.headers));
|
|
4086
4102
|
}
|
|
4087
4103
|
}),
|
|
4088
|
-
post:
|
|
4104
|
+
post: defineCommand32({
|
|
4089
4105
|
meta: {
|
|
4090
4106
|
name: "post",
|
|
4091
4107
|
description: "POST request with auth token"
|
|
@@ -4124,8 +4140,8 @@ var fetchCommand = defineCommand31({
|
|
|
4124
4140
|
});
|
|
4125
4141
|
|
|
4126
4142
|
// src/commands/mcp/index.ts
|
|
4127
|
-
import { defineCommand as
|
|
4128
|
-
var mcpCommand =
|
|
4143
|
+
import { defineCommand as defineCommand33 } from "citty";
|
|
4144
|
+
var mcpCommand = defineCommand33({
|
|
4129
4145
|
meta: {
|
|
4130
4146
|
name: "mcp",
|
|
4131
4147
|
description: "Start MCP server for AI agents"
|
|
@@ -4148,7 +4164,7 @@ var mcpCommand = defineCommand32({
|
|
|
4148
4164
|
if (transport !== "stdio" && transport !== "sse") {
|
|
4149
4165
|
throw new Error('Transport must be "stdio" or "sse"');
|
|
4150
4166
|
}
|
|
4151
|
-
const { startMcpServer } = await import("./server-
|
|
4167
|
+
const { startMcpServer } = await import("./server-QGV3ED6I.js");
|
|
4152
4168
|
await startMcpServer(transport, port);
|
|
4153
4169
|
}
|
|
4154
4170
|
});
|
|
@@ -4156,10 +4172,10 @@ var mcpCommand = defineCommand32({
|
|
|
4156
4172
|
// src/commands/init/index.ts
|
|
4157
4173
|
import { existsSync as existsSync7, copyFileSync, writeFileSync as writeFileSync5 } from "fs";
|
|
4158
4174
|
import { randomBytes } from "crypto";
|
|
4159
|
-
import { execFileSync as
|
|
4175
|
+
import { execFileSync as execFileSync7 } from "child_process";
|
|
4160
4176
|
import { join as join6 } from "path";
|
|
4161
|
-
import { defineCommand as
|
|
4162
|
-
import
|
|
4177
|
+
import { defineCommand as defineCommand34 } from "citty";
|
|
4178
|
+
import consola28 from "consola";
|
|
4163
4179
|
var DEFAULT_IDP_URL = "https://id.openape.at";
|
|
4164
4180
|
async function downloadTemplate(repo, targetDir) {
|
|
4165
4181
|
const { downloadTemplate: gigetDownload } = await import("giget");
|
|
@@ -4168,28 +4184,28 @@ async function downloadTemplate(repo, targetDir) {
|
|
|
4168
4184
|
function installDeps(dir) {
|
|
4169
4185
|
const hasLockFile = (name) => existsSync7(join6(dir, name));
|
|
4170
4186
|
if (hasLockFile("pnpm-lock.yaml")) {
|
|
4171
|
-
|
|
4187
|
+
execFileSync7("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
|
|
4172
4188
|
} else if (hasLockFile("bun.lockb")) {
|
|
4173
|
-
|
|
4189
|
+
execFileSync7("bun", ["install"], { cwd: dir, stdio: "inherit" });
|
|
4174
4190
|
} else {
|
|
4175
|
-
|
|
4191
|
+
execFileSync7("npm", ["install"], { cwd: dir, stdio: "inherit" });
|
|
4176
4192
|
}
|
|
4177
4193
|
}
|
|
4178
4194
|
async function promptChoice(message, choices) {
|
|
4179
|
-
const result = await
|
|
4195
|
+
const result = await consola28.prompt(message, { type: "select", options: choices });
|
|
4180
4196
|
if (typeof result === "symbol") {
|
|
4181
4197
|
throw new CliExit(0);
|
|
4182
4198
|
}
|
|
4183
4199
|
return result;
|
|
4184
4200
|
}
|
|
4185
4201
|
async function promptText(message, defaultValue) {
|
|
4186
|
-
const result = await
|
|
4202
|
+
const result = await consola28.prompt(message, { type: "text", default: defaultValue, placeholder: defaultValue });
|
|
4187
4203
|
if (typeof result === "symbol") {
|
|
4188
4204
|
throw new CliExit(0);
|
|
4189
4205
|
}
|
|
4190
4206
|
return result || defaultValue || "";
|
|
4191
4207
|
}
|
|
4192
|
-
var initCommand =
|
|
4208
|
+
var initCommand = defineCommand34({
|
|
4193
4209
|
meta: {
|
|
4194
4210
|
name: "init",
|
|
4195
4211
|
description: "Scaffold a new OpenApe project"
|
|
@@ -4234,20 +4250,20 @@ async function initSP(targetDir) {
|
|
|
4234
4250
|
if (existsSync7(join6(dir, "package.json"))) {
|
|
4235
4251
|
throw new CliError(`Directory "${dir}" already contains a project.`);
|
|
4236
4252
|
}
|
|
4237
|
-
|
|
4253
|
+
consola28.start("Scaffolding SP starter...");
|
|
4238
4254
|
await downloadTemplate("openape-ai/openape-sp-starter", dir);
|
|
4239
|
-
|
|
4240
|
-
|
|
4255
|
+
consola28.success("Scaffolded from openape-sp-starter");
|
|
4256
|
+
consola28.start("Installing dependencies...");
|
|
4241
4257
|
installDeps(dir);
|
|
4242
|
-
|
|
4258
|
+
consola28.success("Dependencies installed");
|
|
4243
4259
|
const envExample = join6(dir, ".env.example");
|
|
4244
4260
|
const envFile = join6(dir, ".env");
|
|
4245
4261
|
if (existsSync7(envExample) && !existsSync7(envFile)) {
|
|
4246
4262
|
copyFileSync(envExample, envFile);
|
|
4247
|
-
|
|
4263
|
+
consola28.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
|
|
4248
4264
|
}
|
|
4249
4265
|
console.log("");
|
|
4250
|
-
|
|
4266
|
+
consola28.box([
|
|
4251
4267
|
`cd ${dir}`,
|
|
4252
4268
|
"npm run dev",
|
|
4253
4269
|
"",
|
|
@@ -4266,15 +4282,15 @@ async function initIdP(targetDir) {
|
|
|
4266
4282
|
"s3 (S3-compatible)"
|
|
4267
4283
|
]);
|
|
4268
4284
|
const adminEmail = await promptText("Admin email");
|
|
4269
|
-
|
|
4285
|
+
consola28.start("Scaffolding IdP starter...");
|
|
4270
4286
|
await downloadTemplate("openape-ai/openape-idp-starter", dir);
|
|
4271
|
-
|
|
4272
|
-
|
|
4287
|
+
consola28.success("Scaffolded from openape-idp-starter");
|
|
4288
|
+
consola28.start("Installing dependencies...");
|
|
4273
4289
|
installDeps(dir);
|
|
4274
|
-
|
|
4290
|
+
consola28.success("Dependencies installed");
|
|
4275
4291
|
const sessionSecret = randomBytes(32).toString("hex");
|
|
4276
4292
|
const managementToken = randomBytes(32).toString("hex");
|
|
4277
|
-
|
|
4293
|
+
consola28.success("Secrets generated");
|
|
4278
4294
|
const isLocalhost = domain === "localhost";
|
|
4279
4295
|
const origin = isLocalhost ? "http://localhost:3000" : `https://${domain}`;
|
|
4280
4296
|
const envContent = [
|
|
@@ -4290,9 +4306,9 @@ async function initIdP(targetDir) {
|
|
|
4290
4306
|
].join("\n");
|
|
4291
4307
|
writeFileSync5(join6(dir, ".env"), `${envContent}
|
|
4292
4308
|
`, { mode: 384 });
|
|
4293
|
-
|
|
4309
|
+
consola28.success(".env created");
|
|
4294
4310
|
console.log("");
|
|
4295
|
-
|
|
4311
|
+
consola28.box([
|
|
4296
4312
|
`cd ${dir}`,
|
|
4297
4313
|
"npm run dev",
|
|
4298
4314
|
"",
|
|
@@ -4312,8 +4328,8 @@ import { Buffer as Buffer5 } from "buffer";
|
|
|
4312
4328
|
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
|
|
4313
4329
|
import { execFile as execFile2 } from "child_process";
|
|
4314
4330
|
import { sign as sign2 } from "crypto";
|
|
4315
|
-
import { defineCommand as
|
|
4316
|
-
import
|
|
4331
|
+
import { defineCommand as defineCommand35 } from "citty";
|
|
4332
|
+
import consola29 from "consola";
|
|
4317
4333
|
var DEFAULT_IDP_URL2 = "https://id.openape.at";
|
|
4318
4334
|
var DEFAULT_KEY_PATH = "~/.ssh/id_ed25519";
|
|
4319
4335
|
var POLL_INTERVAL = 3e3;
|
|
@@ -4356,7 +4372,7 @@ async function pollForEnrollment(idp, agentEmail, keyPath) {
|
|
|
4356
4372
|
}
|
|
4357
4373
|
throw new Error("Enrollment timed out. Please check the browser and try again.");
|
|
4358
4374
|
}
|
|
4359
|
-
var enrollCommand =
|
|
4375
|
+
var enrollCommand = defineCommand35({
|
|
4360
4376
|
meta: {
|
|
4361
4377
|
name: "enroll",
|
|
4362
4378
|
description: "Enroll an agent with an Identity Provider"
|
|
@@ -4376,18 +4392,18 @@ var enrollCommand = defineCommand34({
|
|
|
4376
4392
|
}
|
|
4377
4393
|
},
|
|
4378
4394
|
async run({ args }) {
|
|
4379
|
-
const idp = args.idp || await
|
|
4395
|
+
const idp = args.idp || await consola29.prompt("IdP URL", { type: "text", default: DEFAULT_IDP_URL2, placeholder: DEFAULT_IDP_URL2 }).then((r) => {
|
|
4380
4396
|
if (typeof r === "symbol") throw new CliExit(0);
|
|
4381
4397
|
return r;
|
|
4382
4398
|
}) || DEFAULT_IDP_URL2;
|
|
4383
|
-
const agentName = args.name || await
|
|
4399
|
+
const agentName = args.name || await consola29.prompt("Agent name", { type: "text", placeholder: "deploy-bot" }).then((r) => {
|
|
4384
4400
|
if (typeof r === "symbol") throw new CliExit(0);
|
|
4385
4401
|
return r;
|
|
4386
4402
|
});
|
|
4387
4403
|
if (!agentName) {
|
|
4388
4404
|
throw new CliError("Agent name is required.");
|
|
4389
4405
|
}
|
|
4390
|
-
const keyPath = args.key || await
|
|
4406
|
+
const keyPath = args.key || await consola29.prompt("Ed25519 key", { type: "text", default: DEFAULT_KEY_PATH, placeholder: DEFAULT_KEY_PATH }).then((r) => {
|
|
4391
4407
|
if (typeof r === "symbol") throw new CliExit(0);
|
|
4392
4408
|
return r;
|
|
4393
4409
|
}) || DEFAULT_KEY_PATH;
|
|
@@ -4395,19 +4411,19 @@ var enrollCommand = defineCommand34({
|
|
|
4395
4411
|
let publicKey;
|
|
4396
4412
|
if (existsSync8(resolvedKey)) {
|
|
4397
4413
|
publicKey = readPublicKey(resolvedKey);
|
|
4398
|
-
|
|
4414
|
+
consola29.success(`Using existing key ${keyPath}`);
|
|
4399
4415
|
} else {
|
|
4400
|
-
|
|
4416
|
+
consola29.start(`Generating Ed25519 key pair at ${keyPath}...`);
|
|
4401
4417
|
publicKey = generateAndSaveKey(keyPath);
|
|
4402
|
-
|
|
4418
|
+
consola29.success(`Key pair generated at ${keyPath}`);
|
|
4403
4419
|
}
|
|
4404
4420
|
const encodedKey = encodeURIComponent(publicKey);
|
|
4405
4421
|
const enrollUrl = `${idp}/enroll?name=${encodeURIComponent(agentName)}&key=${encodedKey}`;
|
|
4406
|
-
|
|
4407
|
-
|
|
4422
|
+
consola29.info("Opening browser for enrollment...");
|
|
4423
|
+
consola29.info(`\u2192 ${idp}/enroll`);
|
|
4408
4424
|
openBrowser2(enrollUrl);
|
|
4409
4425
|
console.log("");
|
|
4410
|
-
const agentEmail = await
|
|
4426
|
+
const agentEmail = await consola29.prompt(
|
|
4411
4427
|
"Agent email (shown in browser after enrollment)",
|
|
4412
4428
|
{ type: "text", placeholder: `agent+${agentName}@...` }
|
|
4413
4429
|
).then((r) => {
|
|
@@ -4417,7 +4433,7 @@ var enrollCommand = defineCommand34({
|
|
|
4417
4433
|
if (!agentEmail) {
|
|
4418
4434
|
throw new CliError("Agent email is required to verify enrollment.");
|
|
4419
4435
|
}
|
|
4420
|
-
|
|
4436
|
+
consola29.start("Verifying enrollment...");
|
|
4421
4437
|
const { token, expiresIn } = await pollForEnrollment(idp, agentEmail, keyPath);
|
|
4422
4438
|
saveAuth({
|
|
4423
4439
|
idp,
|
|
@@ -4429,18 +4445,18 @@ var enrollCommand = defineCommand34({
|
|
|
4429
4445
|
config.defaults = { ...config.defaults, idp };
|
|
4430
4446
|
config.agent = { key: keyPath, email: agentEmail };
|
|
4431
4447
|
saveConfig(config);
|
|
4432
|
-
|
|
4433
|
-
|
|
4448
|
+
consola29.success(`Agent enrolled as ${agentEmail}`);
|
|
4449
|
+
consola29.success("Config saved to ~/.config/apes/");
|
|
4434
4450
|
console.log("");
|
|
4435
|
-
|
|
4451
|
+
consola29.info("Verify with: apes whoami");
|
|
4436
4452
|
}
|
|
4437
4453
|
});
|
|
4438
4454
|
|
|
4439
4455
|
// src/commands/register-user.ts
|
|
4440
4456
|
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
|
|
4441
|
-
import { defineCommand as
|
|
4442
|
-
import
|
|
4443
|
-
var registerUserCommand =
|
|
4457
|
+
import { defineCommand as defineCommand36 } from "citty";
|
|
4458
|
+
import consola30 from "consola";
|
|
4459
|
+
var registerUserCommand = defineCommand36({
|
|
4444
4460
|
meta: {
|
|
4445
4461
|
name: "register-user",
|
|
4446
4462
|
description: "Register a sub-user with SSH key"
|
|
@@ -4495,18 +4511,18 @@ var registerUserCommand = defineCommand35({
|
|
|
4495
4511
|
...userType ? { type: userType } : {}
|
|
4496
4512
|
}
|
|
4497
4513
|
});
|
|
4498
|
-
|
|
4514
|
+
consola30.success(`User registered: ${result.email} (type: ${result.type}, owner: ${result.owner})`);
|
|
4499
4515
|
}
|
|
4500
4516
|
});
|
|
4501
4517
|
|
|
4502
4518
|
// src/commands/utils/index.ts
|
|
4503
|
-
import { defineCommand as
|
|
4519
|
+
import { defineCommand as defineCommand38 } from "citty";
|
|
4504
4520
|
|
|
4505
4521
|
// src/commands/utils/dig.ts
|
|
4506
|
-
import { defineCommand as
|
|
4507
|
-
import
|
|
4522
|
+
import { defineCommand as defineCommand37 } from "citty";
|
|
4523
|
+
import consola31 from "consola";
|
|
4508
4524
|
import { resolveDDISA as resolveDDISA2 } from "@openape/core";
|
|
4509
|
-
var digCommand =
|
|
4525
|
+
var digCommand = defineCommand37({
|
|
4510
4526
|
meta: {
|
|
4511
4527
|
name: "dig",
|
|
4512
4528
|
description: "Resolve DDISA IdP for a domain or email (admin/diag tool)"
|
|
@@ -4579,12 +4595,12 @@ var digCommand = defineCommand36({
|
|
|
4579
4595
|
console.log(` domain: ${domain}`);
|
|
4580
4596
|
console.log("");
|
|
4581
4597
|
if (!result.ddisa.found) {
|
|
4582
|
-
|
|
4598
|
+
consola31.warn(`No DDISA record at _ddisa.${domain}`);
|
|
4583
4599
|
if (result.hint) console.log(`
|
|
4584
4600
|
${result.hint}`);
|
|
4585
4601
|
throw new CliError(`No DDISA record found for ${domain}`);
|
|
4586
4602
|
}
|
|
4587
|
-
|
|
4603
|
+
consola31.success(`_ddisa.${domain} \u2192 ${result.ddisa.idp}`);
|
|
4588
4604
|
console.log(` Version: ${result.ddisa.version || "ddisa1"}`);
|
|
4589
4605
|
console.log(` IdP URL: ${result.ddisa.idp}`);
|
|
4590
4606
|
if (result.ddisa.mode) console.log(` Mode: ${result.ddisa.mode}`);
|
|
@@ -4594,13 +4610,13 @@ ${result.hint}`);
|
|
|
4594
4610
|
return;
|
|
4595
4611
|
}
|
|
4596
4612
|
if (result.idpDiscovery.ok) {
|
|
4597
|
-
|
|
4613
|
+
consola31.success(`IdP reachable (${result.idpDiscovery.status ?? 200})`);
|
|
4598
4614
|
if (result.idpDiscovery.issuer) console.log(` Issuer: ${result.idpDiscovery.issuer}`);
|
|
4599
4615
|
if (result.idpDiscovery.ddisaVersion) console.log(` DDISA: v${result.idpDiscovery.ddisaVersion}`);
|
|
4600
4616
|
if (result.idpDiscovery.authMethods?.length) console.log(` Auth: ${result.idpDiscovery.authMethods.join(", ")}`);
|
|
4601
4617
|
if (result.idpDiscovery.grantTypes?.length) console.log(` Grants: ${result.idpDiscovery.grantTypes.join(", ")}`);
|
|
4602
4618
|
} else {
|
|
4603
|
-
|
|
4619
|
+
consola31.warn(`IdP discovery failed${result.idpDiscovery.status ? ` (HTTP ${result.idpDiscovery.status})` : ""}`);
|
|
4604
4620
|
if (result.hint) console.log(`
|
|
4605
4621
|
${result.hint}`);
|
|
4606
4622
|
throw new CliError(`IdP at ${result.ddisa.idp} not reachable`);
|
|
@@ -4609,7 +4625,7 @@ ${result.hint}`);
|
|
|
4609
4625
|
});
|
|
4610
4626
|
|
|
4611
4627
|
// src/commands/utils/index.ts
|
|
4612
|
-
var utilsCommand =
|
|
4628
|
+
var utilsCommand = defineCommand38({
|
|
4613
4629
|
meta: {
|
|
4614
4630
|
name: "utils",
|
|
4615
4631
|
description: "Admin/diagnostic utilities (dig, \u2026)"
|
|
@@ -4620,12 +4636,12 @@ var utilsCommand = defineCommand37({
|
|
|
4620
4636
|
});
|
|
4621
4637
|
|
|
4622
4638
|
// src/commands/sessions/index.ts
|
|
4623
|
-
import { defineCommand as
|
|
4639
|
+
import { defineCommand as defineCommand41 } from "citty";
|
|
4624
4640
|
|
|
4625
4641
|
// src/commands/sessions/list.ts
|
|
4626
|
-
import { defineCommand as
|
|
4627
|
-
import
|
|
4628
|
-
var sessionsListCommand =
|
|
4642
|
+
import { defineCommand as defineCommand39 } from "citty";
|
|
4643
|
+
import consola32 from "consola";
|
|
4644
|
+
var sessionsListCommand = defineCommand39({
|
|
4629
4645
|
meta: {
|
|
4630
4646
|
name: "list",
|
|
4631
4647
|
description: "List your active refresh-token families (one per logged-in device)."
|
|
@@ -4643,7 +4659,7 @@ var sessionsListCommand = defineCommand38({
|
|
|
4643
4659
|
return;
|
|
4644
4660
|
}
|
|
4645
4661
|
if (result.data.length === 0) {
|
|
4646
|
-
|
|
4662
|
+
consola32.info("No active sessions.");
|
|
4647
4663
|
return;
|
|
4648
4664
|
}
|
|
4649
4665
|
for (const f of result.data) {
|
|
@@ -4655,9 +4671,9 @@ var sessionsListCommand = defineCommand38({
|
|
|
4655
4671
|
});
|
|
4656
4672
|
|
|
4657
4673
|
// src/commands/sessions/remove.ts
|
|
4658
|
-
import { defineCommand as
|
|
4659
|
-
import
|
|
4660
|
-
var sessionsRemoveCommand =
|
|
4674
|
+
import { defineCommand as defineCommand40 } from "citty";
|
|
4675
|
+
import consola33 from "consola";
|
|
4676
|
+
var sessionsRemoveCommand = defineCommand40({
|
|
4661
4677
|
meta: {
|
|
4662
4678
|
name: "remove",
|
|
4663
4679
|
description: "Revoke one of your active refresh-token families by id."
|
|
@@ -4673,12 +4689,12 @@ var sessionsRemoveCommand = defineCommand39({
|
|
|
4673
4689
|
const id = String(args.familyId).trim();
|
|
4674
4690
|
if (!id) throw new CliError("familyId required");
|
|
4675
4691
|
await apiFetch(`/api/me/sessions/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
4676
|
-
|
|
4692
|
+
consola33.success(`Session ${id} revoked. The device using it will need to \`apes login\` again on its next refresh.`);
|
|
4677
4693
|
}
|
|
4678
4694
|
});
|
|
4679
4695
|
|
|
4680
4696
|
// src/commands/sessions/index.ts
|
|
4681
|
-
var sessionsCommand =
|
|
4697
|
+
var sessionsCommand = defineCommand41({
|
|
4682
4698
|
meta: {
|
|
4683
4699
|
name: "sessions",
|
|
4684
4700
|
description: "Manage your active refresh-token sessions across devices"
|
|
@@ -4690,10 +4706,10 @@ var sessionsCommand = defineCommand40({
|
|
|
4690
4706
|
});
|
|
4691
4707
|
|
|
4692
4708
|
// src/commands/dns-check.ts
|
|
4693
|
-
import { defineCommand as
|
|
4694
|
-
import
|
|
4709
|
+
import { defineCommand as defineCommand42 } from "citty";
|
|
4710
|
+
import consola34 from "consola";
|
|
4695
4711
|
import { resolveDDISA as resolveDDISA3 } from "@openape/core";
|
|
4696
|
-
var dnsCheckCommand =
|
|
4712
|
+
var dnsCheckCommand = defineCommand42({
|
|
4697
4713
|
meta: {
|
|
4698
4714
|
name: "dns-check",
|
|
4699
4715
|
description: "Validate DDISA DNS TXT records for a domain"
|
|
@@ -4707,7 +4723,7 @@ var dnsCheckCommand = defineCommand41({
|
|
|
4707
4723
|
},
|
|
4708
4724
|
async run({ args }) {
|
|
4709
4725
|
const domain = args.domain;
|
|
4710
|
-
|
|
4726
|
+
consola34.start(`Checking _ddisa.${domain}...`);
|
|
4711
4727
|
try {
|
|
4712
4728
|
const result = await resolveDDISA3(domain);
|
|
4713
4729
|
if (!result) {
|
|
@@ -4716,7 +4732,7 @@ var dnsCheckCommand = defineCommand41({
|
|
|
4716
4732
|
console.log(` _ddisa.${domain} TXT "v=ddisa1 idp=https://id.${domain}"`);
|
|
4717
4733
|
throw new CliError(`No DDISA record found for ${domain}`);
|
|
4718
4734
|
}
|
|
4719
|
-
|
|
4735
|
+
consola34.success(`_ddisa.${domain} \u2192 ${result.idp}`);
|
|
4720
4736
|
console.log("");
|
|
4721
4737
|
console.log(` Version: ${result.version || "ddisa1"}`);
|
|
4722
4738
|
console.log(` IdP URL: ${result.idp}`);
|
|
@@ -4725,14 +4741,14 @@ var dnsCheckCommand = defineCommand41({
|
|
|
4725
4741
|
if (result.priority !== void 0)
|
|
4726
4742
|
console.log(` Priority: ${result.priority}`);
|
|
4727
4743
|
console.log("");
|
|
4728
|
-
|
|
4744
|
+
consola34.start(`Verifying IdP at ${result.idp}...`);
|
|
4729
4745
|
const discoResp = await fetch(`${result.idp}/.well-known/openid-configuration`);
|
|
4730
4746
|
if (!discoResp.ok) {
|
|
4731
|
-
|
|
4747
|
+
consola34.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
|
|
4732
4748
|
return;
|
|
4733
4749
|
}
|
|
4734
4750
|
const disco = await discoResp.json();
|
|
4735
|
-
|
|
4751
|
+
consola34.success(`IdP is reachable`);
|
|
4736
4752
|
console.log(` Issuer: ${disco.issuer}`);
|
|
4737
4753
|
console.log(` DDISA: v${disco.ddisa_version || "?"}`);
|
|
4738
4754
|
if (disco.ddisa_auth_methods_supported) {
|
|
@@ -4750,7 +4766,7 @@ var dnsCheckCommand = defineCommand41({
|
|
|
4750
4766
|
// src/commands/health.ts
|
|
4751
4767
|
import { exec } from "child_process";
|
|
4752
4768
|
import { promisify } from "util";
|
|
4753
|
-
import { defineCommand as
|
|
4769
|
+
import { defineCommand as defineCommand43 } from "citty";
|
|
4754
4770
|
var execAsync = promisify(exec);
|
|
4755
4771
|
async function resolveApeShellPath() {
|
|
4756
4772
|
try {
|
|
@@ -4786,7 +4802,7 @@ async function bestEffortGrantCount(idp) {
|
|
|
4786
4802
|
}
|
|
4787
4803
|
}
|
|
4788
4804
|
async function runHealth(args) {
|
|
4789
|
-
const version = true ? "0.
|
|
4805
|
+
const version = true ? "0.29.0" : "0.0.0";
|
|
4790
4806
|
const auth = loadAuth();
|
|
4791
4807
|
if (!auth) {
|
|
4792
4808
|
throw new CliError("Not logged in. Run `apes login` first.", 1);
|
|
@@ -4849,7 +4865,7 @@ async function runHealth(args) {
|
|
|
4849
4865
|
throw new CliError(`IdP ${auth.idp} unreachable: ${idpProbe.error}`, 1);
|
|
4850
4866
|
}
|
|
4851
4867
|
}
|
|
4852
|
-
var healthCommand =
|
|
4868
|
+
var healthCommand = defineCommand43({
|
|
4853
4869
|
meta: {
|
|
4854
4870
|
name: "health",
|
|
4855
4871
|
description: "Report CLI diagnostic state (auth, IdP, grants, binaries)"
|
|
@@ -4867,8 +4883,8 @@ var healthCommand = defineCommand42({
|
|
|
4867
4883
|
});
|
|
4868
4884
|
|
|
4869
4885
|
// src/commands/workflows.ts
|
|
4870
|
-
import { defineCommand as
|
|
4871
|
-
import
|
|
4886
|
+
import { defineCommand as defineCommand44 } from "citty";
|
|
4887
|
+
import consola35 from "consola";
|
|
4872
4888
|
|
|
4873
4889
|
// src/guides/index.ts
|
|
4874
4890
|
var guides = [
|
|
@@ -4918,7 +4934,7 @@ var guides = [
|
|
|
4918
4934
|
];
|
|
4919
4935
|
|
|
4920
4936
|
// src/commands/workflows.ts
|
|
4921
|
-
var workflowsCommand =
|
|
4937
|
+
var workflowsCommand = defineCommand44({
|
|
4922
4938
|
meta: {
|
|
4923
4939
|
name: "workflows",
|
|
4924
4940
|
description: "Discover workflow guides"
|
|
@@ -4939,7 +4955,7 @@ var workflowsCommand = defineCommand43({
|
|
|
4939
4955
|
if (args.id) {
|
|
4940
4956
|
const guide = guides.find((g) => g.id === String(args.id));
|
|
4941
4957
|
if (!guide) {
|
|
4942
|
-
|
|
4958
|
+
consola35.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
|
|
4943
4959
|
throw new CliError(`Guide not found: ${args.id}`);
|
|
4944
4960
|
}
|
|
4945
4961
|
if (args.json) {
|
|
@@ -4982,7 +4998,7 @@ var workflowsCommand = defineCommand43({
|
|
|
4982
4998
|
import { existsSync as existsSync10, mkdirSync as mkdirSync2, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
|
|
4983
4999
|
import { homedir as homedir6 } from "os";
|
|
4984
5000
|
import { join as join7 } from "path";
|
|
4985
|
-
import
|
|
5001
|
+
import consola36 from "consola";
|
|
4986
5002
|
var PACKAGE_NAME = "@openape/apes";
|
|
4987
5003
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
4988
5004
|
var CACHE_FILE = join7(homedir6(), ".config", "apes", ".version-check.json");
|
|
@@ -5027,7 +5043,7 @@ async function fetchLatestVersion() {
|
|
|
5027
5043
|
}
|
|
5028
5044
|
function warnIfBehind(currentVersion, latest) {
|
|
5029
5045
|
if (compareSemver(currentVersion, latest) < 0) {
|
|
5030
|
-
|
|
5046
|
+
consola36.warn(
|
|
5031
5047
|
`apes ${currentVersion} is behind latest @openape/apes@${latest}. Run \`npm i -g @openape/apes@latest\` to update. (Suppress with APES_NO_UPDATE_CHECK=1.)`
|
|
5032
5048
|
);
|
|
5033
5049
|
}
|
|
@@ -5059,10 +5075,10 @@ if (shellRewrite) {
|
|
|
5059
5075
|
if (shellRewrite.action === "rewrite") {
|
|
5060
5076
|
process.argv = shellRewrite.argv;
|
|
5061
5077
|
} else if (shellRewrite.action === "version") {
|
|
5062
|
-
console.log(`ape-shell ${"0.
|
|
5078
|
+
console.log(`ape-shell ${"0.29.0"} (OpenApe DDISA shell wrapper)`);
|
|
5063
5079
|
process.exit(0);
|
|
5064
5080
|
} else if (shellRewrite.action === "help") {
|
|
5065
|
-
console.log(`ape-shell ${"0.
|
|
5081
|
+
console.log(`ape-shell ${"0.29.0"} \u2014 OpenApe DDISA shell wrapper`);
|
|
5066
5082
|
console.log("");
|
|
5067
5083
|
console.log("Usage:");
|
|
5068
5084
|
console.log(" ape-shell Start interactive grant-mediated REPL");
|
|
@@ -5086,7 +5102,7 @@ if (shellRewrite) {
|
|
|
5086
5102
|
}
|
|
5087
5103
|
}
|
|
5088
5104
|
var debug = process.argv.includes("--debug");
|
|
5089
|
-
var grantsCommand =
|
|
5105
|
+
var grantsCommand = defineCommand45({
|
|
5090
5106
|
meta: {
|
|
5091
5107
|
name: "grants",
|
|
5092
5108
|
description: "Grant management"
|
|
@@ -5107,7 +5123,7 @@ var grantsCommand = defineCommand44({
|
|
|
5107
5123
|
"delegation-revoke": delegationRevokeCommand
|
|
5108
5124
|
}
|
|
5109
5125
|
});
|
|
5110
|
-
var configCommand =
|
|
5126
|
+
var configCommand = defineCommand45({
|
|
5111
5127
|
meta: {
|
|
5112
5128
|
name: "config",
|
|
5113
5129
|
description: "Configuration management"
|
|
@@ -5117,10 +5133,10 @@ var configCommand = defineCommand44({
|
|
|
5117
5133
|
set: configSetCommand
|
|
5118
5134
|
}
|
|
5119
5135
|
});
|
|
5120
|
-
var main =
|
|
5136
|
+
var main = defineCommand45({
|
|
5121
5137
|
meta: {
|
|
5122
5138
|
name: "apes",
|
|
5123
|
-
version: "0.
|
|
5139
|
+
version: "0.29.0",
|
|
5124
5140
|
description: "Unified CLI for OpenApe"
|
|
5125
5141
|
},
|
|
5126
5142
|
subCommands: {
|
|
@@ -5175,20 +5191,20 @@ async function maybeRefreshAuth() {
|
|
|
5175
5191
|
}
|
|
5176
5192
|
}
|
|
5177
5193
|
await maybeRefreshAuth();
|
|
5178
|
-
await maybeWarnStaleVersion("0.
|
|
5194
|
+
await maybeWarnStaleVersion("0.29.0").catch(() => {
|
|
5179
5195
|
});
|
|
5180
5196
|
runMain(main).catch((err) => {
|
|
5181
5197
|
if (err instanceof CliExit) {
|
|
5182
5198
|
process.exit(err.exitCode);
|
|
5183
5199
|
}
|
|
5184
5200
|
if (err instanceof CliError) {
|
|
5185
|
-
|
|
5201
|
+
consola37.error(err.message);
|
|
5186
5202
|
process.exit(err.exitCode);
|
|
5187
5203
|
}
|
|
5188
5204
|
if (debug) {
|
|
5189
|
-
|
|
5205
|
+
consola37.error(err);
|
|
5190
5206
|
} else {
|
|
5191
|
-
|
|
5207
|
+
consola37.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
|
|
5192
5208
|
}
|
|
5193
5209
|
process.exit(1);
|
|
5194
5210
|
});
|