@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 consola36 from "consola";
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 defineCommand44, runMain } from "citty";
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 defineCommand24 } from "citty";
1746
+ import { defineCommand as defineCommand25 } from "citty";
1747
1747
 
1748
- // src/commands/agents/destroy.ts
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 = defineCommand20({
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
- consola18.info(`Nothing to destroy: no IdP agent and no OS user named "${name}".`);
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
- consola18.warn(`About to destroy "${name}":
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 consola18.prompt("Proceed?", { type: "confirm", initial: false });
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
- consola18.success(`Deactivated IdP agent ${idpAgent.email}`);
2300
+ consola19.success(`Deactivated IdP agent ${idpAgent.email}`);
2225
2301
  } else {
2226
2302
  await apiFetch(`/api/my-agents/${id}`, { method: "DELETE", idp });
2227
- consola18.success(`Deleted IdP agent ${idpAgent.email}`);
2303
+ consola19.success(`Deleted IdP agent ${idpAgent.email}`);
2228
2304
  }
2229
2305
  } else {
2230
- consola18.info("No IdP agent to remove (skipped).");
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
- consola18.start("Running teardown via sudo\u2026");
2245
- execFileSync3(sudo, ["-S", "--prompt=", "--", "bash", scriptPath], {
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
- consola18.info("No macOS user to remove (skipped).");
2331
+ consola19.info("No macOS user to remove (skipped).");
2256
2332
  }
2257
- consola18.success(`Destroyed ${name}.`);
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 defineCommand21 } from "citty";
2272
- import consola19 from "consola";
2273
- var listAgentsCommand = defineCommand21({
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
- consola19.info(args["include-inactive"] ? "No agents found." : "No active agents found. Use --include-inactive to show deactivated.");
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 defineCommand22 } from "citty";
2334
- import consola20 from "consola";
2335
- var registerAgentCommand = defineCommand22({
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
- consola20.success("Agent registered.");
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 execFileSync4 } from "child_process";
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 defineCommand23 } from "citty";
2423
- import consola21 from "consola";
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 = defineCommand23({
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
- consola21.start(`Generating keypair for ${name}\u2026`);
2803
+ consola22.start(`Generating keypair for ${name}\u2026`);
2778
2804
  const { privatePem, publicSshLine } = generateKeyPairInMemory();
2779
- consola21.start(`Registering agent at ${idp}\u2026`);
2805
+ consola22.start(`Registering agent at ${idp}\u2026`);
2780
2806
  const registration = await registerAgentAtIdp({ name, publicKey: publicSshLine, idp });
2781
- consola21.success(`Registered as ${registration.email}`);
2782
- consola21.start("Issuing agent access token\u2026");
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
- consola21.start("Running privileged setup as root via `apes run --as root --wait`\u2026");
2826
- consola21.info("You will be asked to approve the as=root grant in your DDISA inbox; this command blocks until you do.");
2827
- execFileSync4(apes, ["run", "--as", "root", "--wait", "--", "bash", scriptPath], { stdio: "inherit" });
2828
- consola21.success(`Agent ${name} spawned.`);
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
- try {
2831
- consola21.start("Setting up direct chat with the agent\u2026");
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 = defineCommand24({
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 defineCommand25 } from "citty";
2892
- import consola22 from "consola";
2893
- var adapterCommand = defineCommand25({
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: defineCommand25({
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
- consola22.info(`Registry: ${index2.adapters.length} adapters (${index2.generated_at})`);
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
- consola22.info("No adapters installed. Use `apes adapter list --remote` to see available adapters.");
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: defineCommand25({
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
- consola22.error(`Adapter "${id}" not found in registry. Use \`apes adapter search ${id}\` to search.`);
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
- consola22.warn(`Conflicting adapter found: ${c.path} (id: ${c.adapterId}, executable: ${c.executable})`);
2996
- consola22.warn(` Remove it with: apes adapter remove ${c.adapterId}`);
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
- consola22.success(`${verb} ${result.id} \u2192 ${result.path}`);
3002
- consola22.info(`Digest: ${result.digest}`);
3017
+ consola23.success(`${verb} ${result.id} \u2192 ${result.path}`);
3018
+ consola23.info(`Digest: ${result.digest}`);
3003
3019
  }
3004
3020
  }
3005
3021
  }),
3006
- remove: defineCommand25({
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
- consola22.success(`Removed adapter: ${id}`);
3045
+ consola23.success(`Removed adapter: ${id}`);
3030
3046
  } else {
3031
- consola22.error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
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: defineCommand25({
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: defineCommand25({
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
- consola22.info(`No adapters matching "${query}"`);
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: defineCommand25({
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
- consola22.info("No adapters installed to update.");
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
- consola22.warn(`${id}: not found in registry, skipping`);
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
- consola22.info(`${id}: already up to date`);
3175
+ consola23.info(`${id}: already up to date`);
3160
3176
  continue;
3161
3177
  }
3162
3178
  if (localDigest && !args.yes) {
3163
- consola22.warn(`${id}: digest will change \u2014 existing grants for this adapter will be invalidated`);
3164
- consola22.info(` Old: ${localDigest}`);
3165
- consola22.info(` New: ${entry.digest}`);
3166
- consola22.info(" Use --yes to confirm");
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
- consola22.success(`Updated ${result.id} \u2192 ${result.path}`);
3186
+ consola23.success(`Updated ${result.id} \u2192 ${result.path}`);
3171
3187
  }
3172
3188
  }
3173
3189
  }),
3174
- verify: defineCommand25({
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
- consola22.success(`${id}: digest matches registry`);
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 execFileSync5 } from "child_process";
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 defineCommand26 } from "citty";
3223
- import consola23 from "consola";
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
- consola23.success(`Grant ${grant.id} created \u2014 awaiting your approval`);
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
- consola23.success(`Grant ${grant.id} created (pending approval)`);
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 = defineCommand26({
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
- consola23.info(`Requesting ape-shell session grant on ${targetHost}`);
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
- consola23.info(`Grant requested: ${grant.id}`);
3416
- consola23.info("Waiting for approval...");
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
- consola23.debug(`ape-shell: adapter resolve failed for "${parsed.raw}":`, err);
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
- consola23.info(`Reusing grant ${existingGrantId} for: ${resolved.detail.display}`);
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
- consola23.info(`Requesting grant for: ${resolved.detail.display}`);
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
- consola23.info("");
3470
- consola23.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
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
- consola23.info(`Grant requested: ${grant.id}`);
3481
- consola23.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
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
- execFileSync5(command[0], command.slice(1), {
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
- consola23.info(`Reusing existing grant: ${existingGrantId}`);
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
- consola23.info("");
3570
- consola23.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
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
- consola23.info(` Broader scope: ${wider}`);
3589
+ consola24.info(` Broader scope: ${wider}`);
3574
3590
  }
3575
- consola23.info("");
3591
+ consola24.info("");
3576
3592
  }
3577
3593
  if (shouldWaitForGrant(args)) {
3578
- consola23.info(`Grant requested: ${grant.id}`);
3579
- consola23.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
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
- consola23.info(`Requesting ${audience} grant on ${targetHost}: ${command.join(" ")}`);
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
- consola23.success(`Grant requested: ${grant.id}`);
3617
- consola23.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
3618
- consola23.info("Waiting for approval...");
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
- consola23.success("Grant approved!");
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
- consola23.info("Fetching grant token...");
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
- consola23.info(`Executing: ${command.join(" ")}`);
3662
+ consola24.info(`Executing: ${command.join(" ")}`);
3647
3663
  try {
3648
3664
  const { APES_SHELL_WRAPPER: _wrapperMarker, ...inheritedEnv } = process.env;
3649
- execFileSync5(args["escapes-path"] || "escapes", ["--grant", authz_jwt, "--", ...command], {
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 defineCommand27 } from "citty";
3665
- import consola24 from "consola";
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
- consola24.info(`[apes proxy] IdP-mediated mode \u2014 agent=${auth.email}, idp=${auth.idp}`);
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 = defineCommand27({
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
- consola24.info(`[apes proxy] reusing existing proxy at ${proxyUrl}`);
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
- consola24.info(`[apes proxy] started ephemeral proxy at ${proxyUrl}`);
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
- consola24.error(`[apes proxy] failed to spawn '${wrapped[0]}':`, err.message);
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 defineCommand28 } from "citty";
3885
- var explainCommand = defineCommand28({
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 defineCommand29 } from "citty";
3924
- import consola25 from "consola";
3925
- var configGetCommand = defineCommand29({
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
- consola25.info("No IdP configured.");
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
- consola25.info("Not logged in.");
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
- consola25.info(`Key "${key}" not set.`);
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 defineCommand30 } from "citty";
3978
- import consola26 from "consola";
3979
- var configSetCommand = defineCommand30({
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
- consola26.success(`Set ${key} = ${value}`);
4031
+ consola27.success(`Set ${key} = ${value}`);
4016
4032
  }
4017
4033
  });
4018
4034
 
4019
4035
  // src/commands/fetch/index.ts
4020
- import { defineCommand as defineCommand31 } from "citty";
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 = defineCommand31({
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: defineCommand31({
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: defineCommand31({
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 defineCommand32 } from "citty";
4128
- var mcpCommand = defineCommand32({
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-TNWUMXYI.js");
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 execFileSync6 } from "child_process";
4175
+ import { execFileSync as execFileSync7 } from "child_process";
4160
4176
  import { join as join6 } from "path";
4161
- import { defineCommand as defineCommand33 } from "citty";
4162
- import consola27 from "consola";
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
- execFileSync6("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
4187
+ execFileSync7("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
4172
4188
  } else if (hasLockFile("bun.lockb")) {
4173
- execFileSync6("bun", ["install"], { cwd: dir, stdio: "inherit" });
4189
+ execFileSync7("bun", ["install"], { cwd: dir, stdio: "inherit" });
4174
4190
  } else {
4175
- execFileSync6("npm", ["install"], { cwd: dir, stdio: "inherit" });
4191
+ execFileSync7("npm", ["install"], { cwd: dir, stdio: "inherit" });
4176
4192
  }
4177
4193
  }
4178
4194
  async function promptChoice(message, choices) {
4179
- const result = await consola27.prompt(message, { type: "select", options: choices });
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 consola27.prompt(message, { type: "text", default: defaultValue, placeholder: defaultValue });
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 = defineCommand33({
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
- consola27.start("Scaffolding SP starter...");
4253
+ consola28.start("Scaffolding SP starter...");
4238
4254
  await downloadTemplate("openape-ai/openape-sp-starter", dir);
4239
- consola27.success("Scaffolded from openape-sp-starter");
4240
- consola27.start("Installing dependencies...");
4255
+ consola28.success("Scaffolded from openape-sp-starter");
4256
+ consola28.start("Installing dependencies...");
4241
4257
  installDeps(dir);
4242
- consola27.success("Dependencies installed");
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
- consola27.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
4263
+ consola28.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
4248
4264
  }
4249
4265
  console.log("");
4250
- consola27.box([
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
- consola27.start("Scaffolding IdP starter...");
4285
+ consola28.start("Scaffolding IdP starter...");
4270
4286
  await downloadTemplate("openape-ai/openape-idp-starter", dir);
4271
- consola27.success("Scaffolded from openape-idp-starter");
4272
- consola27.start("Installing dependencies...");
4287
+ consola28.success("Scaffolded from openape-idp-starter");
4288
+ consola28.start("Installing dependencies...");
4273
4289
  installDeps(dir);
4274
- consola27.success("Dependencies installed");
4290
+ consola28.success("Dependencies installed");
4275
4291
  const sessionSecret = randomBytes(32).toString("hex");
4276
4292
  const managementToken = randomBytes(32).toString("hex");
4277
- consola27.success("Secrets generated");
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
- consola27.success(".env created");
4309
+ consola28.success(".env created");
4294
4310
  console.log("");
4295
- consola27.box([
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 defineCommand34 } from "citty";
4316
- import consola28 from "consola";
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 = defineCommand34({
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 consola28.prompt("IdP URL", { type: "text", default: DEFAULT_IDP_URL2, placeholder: DEFAULT_IDP_URL2 }).then((r) => {
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 consola28.prompt("Agent name", { type: "text", placeholder: "deploy-bot" }).then((r) => {
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 consola28.prompt("Ed25519 key", { type: "text", default: DEFAULT_KEY_PATH, placeholder: DEFAULT_KEY_PATH }).then((r) => {
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
- consola28.success(`Using existing key ${keyPath}`);
4414
+ consola29.success(`Using existing key ${keyPath}`);
4399
4415
  } else {
4400
- consola28.start(`Generating Ed25519 key pair at ${keyPath}...`);
4416
+ consola29.start(`Generating Ed25519 key pair at ${keyPath}...`);
4401
4417
  publicKey = generateAndSaveKey(keyPath);
4402
- consola28.success(`Key pair generated at ${keyPath}`);
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
- consola28.info("Opening browser for enrollment...");
4407
- consola28.info(`\u2192 ${idp}/enroll`);
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 consola28.prompt(
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
- consola28.start("Verifying enrollment...");
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
- consola28.success(`Agent enrolled as ${agentEmail}`);
4433
- consola28.success("Config saved to ~/.config/apes/");
4448
+ consola29.success(`Agent enrolled as ${agentEmail}`);
4449
+ consola29.success("Config saved to ~/.config/apes/");
4434
4450
  console.log("");
4435
- consola28.info("Verify with: apes whoami");
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 defineCommand35 } from "citty";
4442
- import consola29 from "consola";
4443
- var registerUserCommand = defineCommand35({
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
- consola29.success(`User registered: ${result.email} (type: ${result.type}, owner: ${result.owner})`);
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 defineCommand37 } from "citty";
4519
+ import { defineCommand as defineCommand38 } from "citty";
4504
4520
 
4505
4521
  // src/commands/utils/dig.ts
4506
- import { defineCommand as defineCommand36 } from "citty";
4507
- import consola30 from "consola";
4522
+ import { defineCommand as defineCommand37 } from "citty";
4523
+ import consola31 from "consola";
4508
4524
  import { resolveDDISA as resolveDDISA2 } from "@openape/core";
4509
- var digCommand = defineCommand36({
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
- consola30.warn(`No DDISA record at _ddisa.${domain}`);
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
- consola30.success(`_ddisa.${domain} \u2192 ${result.ddisa.idp}`);
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
- consola30.success(`IdP reachable (${result.idpDiscovery.status ?? 200})`);
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
- consola30.warn(`IdP discovery failed${result.idpDiscovery.status ? ` (HTTP ${result.idpDiscovery.status})` : ""}`);
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 = defineCommand37({
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 defineCommand40 } from "citty";
4639
+ import { defineCommand as defineCommand41 } from "citty";
4624
4640
 
4625
4641
  // src/commands/sessions/list.ts
4626
- import { defineCommand as defineCommand38 } from "citty";
4627
- import consola31 from "consola";
4628
- var sessionsListCommand = defineCommand38({
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
- consola31.info("No active sessions.");
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 defineCommand39 } from "citty";
4659
- import consola32 from "consola";
4660
- var sessionsRemoveCommand = defineCommand39({
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
- consola32.success(`Session ${id} revoked. The device using it will need to \`apes login\` again on its next refresh.`);
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 = defineCommand40({
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 defineCommand41 } from "citty";
4694
- import consola33 from "consola";
4709
+ import { defineCommand as defineCommand42 } from "citty";
4710
+ import consola34 from "consola";
4695
4711
  import { resolveDDISA as resolveDDISA3 } from "@openape/core";
4696
- var dnsCheckCommand = defineCommand41({
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
- consola33.start(`Checking _ddisa.${domain}...`);
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
- consola33.success(`_ddisa.${domain} \u2192 ${result.idp}`);
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
- consola33.start(`Verifying IdP at ${result.idp}...`);
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
- consola33.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
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
- consola33.success(`IdP is reachable`);
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 defineCommand42 } from "citty";
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.27.0" : "0.0.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 = defineCommand42({
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 defineCommand43 } from "citty";
4871
- import consola34 from "consola";
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 = defineCommand43({
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
- consola34.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
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 consola35 from "consola";
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
- consola35.warn(
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.27.0"} (OpenApe DDISA shell wrapper)`);
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.27.0"} \u2014 OpenApe DDISA shell wrapper`);
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 = defineCommand44({
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 = defineCommand44({
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 = defineCommand44({
5136
+ var main = defineCommand45({
5121
5137
  meta: {
5122
5138
  name: "apes",
5123
- version: "0.27.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.27.0").catch(() => {
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
- consola36.error(err.message);
5201
+ consola37.error(err.message);
5186
5202
  process.exit(err.exitCode);
5187
5203
  }
5188
5204
  if (debug) {
5189
- consola36.error(err);
5205
+ consola37.error(err);
5190
5206
  } else {
5191
- consola36.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
5207
+ consola37.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
5192
5208
  }
5193
5209
  process.exit(1);
5194
5210
  });