@openape/apes 1.10.0 → 1.12.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
@@ -7,8 +7,11 @@ import {
7
7
  import {
8
8
  CliError,
9
9
  CliExit,
10
- parseDuration
11
- } from "./chunk-ZSJU7IXE.js";
10
+ RpcSessionMap,
11
+ parseDuration,
12
+ runLoop,
13
+ taskTools
14
+ } from "./chunk-TDSCDH5P.js";
12
15
  import {
13
16
  loadEd25519PrivateKey,
14
17
  readPublicKeyComment
@@ -74,7 +77,7 @@ import {
74
77
  import "./chunk-7OCVIDC7.js";
75
78
 
76
79
  // src/cli.ts
77
- import consola51 from "consola";
80
+ import consola49 from "consola";
78
81
 
79
82
  // src/ape-shell.ts
80
83
  import path from "path";
@@ -104,7 +107,7 @@ function rewriteApeShellArgs(argv, argv0) {
104
107
  }
105
108
 
106
109
  // src/cli.ts
107
- import { defineCommand as defineCommand61, runMain } from "citty";
110
+ import { defineCommand as defineCommand60, runMain } from "citty";
108
111
 
109
112
  // src/commands/auth/login.ts
110
113
  import { Buffer as Buffer2 } from "buffer";
@@ -317,7 +320,7 @@ async function loginWithPKCE(idp) {
317
320
  authUrl.searchParams.set("state", state);
318
321
  authUrl.searchParams.set("nonce", nonce);
319
322
  authUrl.searchParams.set("scope", "openid email profile offline_access");
320
- const code = await new Promise((resolve5, reject) => {
323
+ const code = await new Promise((resolve4, reject) => {
321
324
  const server = createServer((req, res) => {
322
325
  const url = new URL(req.url, `http://localhost:${CALLBACK_PORT}`);
323
326
  if (url.pathname === "/callback") {
@@ -334,7 +337,7 @@ async function loginWithPKCE(idp) {
334
337
  res.writeHead(200, { "Content-Type": "text/html" });
335
338
  res.end("<h1>Login successful!</h1><p>You can close this window.</p>");
336
339
  server.close();
337
- resolve5(authCode);
340
+ resolve4(authCode);
338
341
  return;
339
342
  }
340
343
  res.writeHead(400);
@@ -895,7 +898,7 @@ async function waitForApproval2(grantsUrl, grantId) {
895
898
  if (grant.status === "revoked") {
896
899
  throw new CliError("Grant revoked.");
897
900
  }
898
- await new Promise((resolve5) => setTimeout(resolve5, interval));
901
+ await new Promise((resolve4) => setTimeout(resolve4, interval));
899
902
  }
900
903
  throw new CliError("Timed out waiting for approval.");
901
904
  }
@@ -2262,7 +2265,7 @@ function createFetch(globalOptions = {}) {
2262
2265
  if (retries > 0 && (Array.isArray(context.options.retryStatusCodes) ? context.options.retryStatusCodes.includes(responseCode) : retryStatusCodes.has(responseCode))) {
2263
2266
  const retryDelay = typeof context.options.retryDelay === "function" ? context.options.retryDelay(context) : context.options.retryDelay || 0;
2264
2267
  if (retryDelay > 0) {
2265
- await new Promise((resolve5) => setTimeout(resolve5, retryDelay));
2268
+ await new Promise((resolve4) => setTimeout(resolve4, retryDelay));
2266
2269
  }
2267
2270
  return $fetchRaw(context.request, {
2268
2271
  ...context.options,
@@ -2690,46 +2693,19 @@ function buildBridgeBlock(bridge) {
2690
2693
  return `
2691
2694
  mkdir -p "$HOME_DIR/Library/Application Support/openape/bridge" "$HOME_DIR/Library/Logs"
2692
2695
  cat > "$HOME_DIR/Library/Application Support/openape/bridge/.env" ${shHeredoc(bridge.envFile)}
2693
- cat > "$HOME_DIR/Library/Application Support/openape/bridge/start.sh" ${shHeredoc(bridge.startScript)}
2694
- chmod 755 "$HOME_DIR/Library/Application Support/openape/bridge/start.sh"
2695
2696
  chmod 600 "$HOME_DIR/Library/Application Support/openape/bridge/.env"
2696
-
2697
- # System-wide LaunchDaemon \u2014 root-owned, mode 644 (launchd refuses
2698
- # group/world-writable plists). UserName in the plist makes launchd run
2699
- # the binary as the agent, not root.
2700
- cat > ${shQuote(bridge.plistPath)} ${shHeredoc(bridge.plistContent)}
2701
- chown root:wheel ${shQuote(bridge.plistPath)}
2702
- chmod 644 ${shQuote(bridge.plistPath)}
2703
2697
  `;
2704
2698
  }
2705
- function buildBridgeBootstrapBlock(bridge, _name) {
2706
- if (!bridge) return "";
2707
- return `
2708
- launchctl bootout "system/${bridge.plistLabel}" 2>/dev/null || true
2709
- launchctl bootstrap system ${shQuote(bridge.plistPath)} || \\
2710
- echo "warn: bridge bootstrap into system domain failed; check ${bridge.plistPath}"
2711
- `;
2699
+ function buildBridgeBootstrapBlock(_bridge, _name) {
2700
+ return "";
2712
2701
  }
2713
- function buildTroopBlock(troop) {
2714
- if (!troop) return "";
2702
+ function buildTroopBlock(_troop) {
2715
2703
  return `
2716
- mkdir -p "$HOME_DIR/Library/LaunchAgents" "$HOME_DIR/Library/Logs" "$HOME_DIR/.openape/agent/tasks"
2717
- cat > ${shQuote(troop.plistPath)} ${shHeredoc(troop.plistContent)}
2718
- chown root:wheel ${shQuote(troop.plistPath)}
2719
- chmod 644 ${shQuote(troop.plistPath)}
2704
+ mkdir -p "$HOME_DIR/Library/Logs" "$HOME_DIR/.openape/agent/tasks"
2720
2705
  `;
2721
2706
  }
2722
- function buildTroopBootstrapBlock(troop, name) {
2723
- if (!troop) return "";
2724
- return `
2725
- # Bootstrap the troop sync launchd in the system domain. setup.sh runs
2726
- # as root via \`apes run --as root\`, so we have permission. Stale label
2727
- # is bootouted first to make re-spawn idempotent.
2728
- echo "==> Installing troop sync launchd as ${name}\u2026"
2729
- launchctl bootout "system/${troop.plistLabel}" 2>/dev/null || true
2730
- launchctl bootstrap system ${shQuote(troop.plistPath)} || \\
2731
- echo "warn: troop sync bootstrap failed; check ${troop.plistPath}"
2732
- `;
2707
+ function buildTroopBootstrapBlock(_troop, _name) {
2708
+ return "";
2733
2709
  }
2734
2710
  function buildDestroyTeardownScript(input) {
2735
2711
  const { name, homeDir, adminUser } = input;
@@ -2992,7 +2968,7 @@ function readPasswordSilent(prompt) {
2992
2968
  "No TTY available for the silent password prompt. Set APES_ADMIN_PASSWORD in the environment instead."
2993
2969
  ));
2994
2970
  }
2995
- return new Promise((resolve5, reject) => {
2971
+ return new Promise((resolve4, reject) => {
2996
2972
  process.stdout.write(prompt);
2997
2973
  const wasRaw = process.stdin.isRaw ?? false;
2998
2974
  process.stdin.setRawMode(true);
@@ -3007,7 +2983,7 @@ function readPasswordSilent(prompt) {
3007
2983
  if (ch === "\r" || ch === "\n") {
3008
2984
  cleanup();
3009
2985
  process.stdout.write("\n");
3010
- resolve5(buf);
2986
+ resolve4(buf);
3011
2987
  return;
3012
2988
  }
3013
2989
  if (code === 3) {
@@ -3303,481 +3279,12 @@ var registerAgentCommand = defineCommand23({
3303
3279
  });
3304
3280
 
3305
3281
  // src/commands/agents/run.ts
3306
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
3307
- import { homedir as homedir5 } from "os";
3282
+ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
3283
+ import { homedir as homedir4 } from "os";
3308
3284
  import { join as join3 } from "path";
3309
3285
  import { defineCommand as defineCommand24 } from "citty";
3310
3286
  import consola22 from "consola";
3311
3287
 
3312
- // src/lib/agent-tools/file.ts
3313
- import { mkdirSync, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
3314
- import { homedir as homedir4 } from "os";
3315
- import { dirname, normalize, resolve as resolve2 } from "path";
3316
- var MAX_BYTES = 1024 * 1024;
3317
- function jailPath(input) {
3318
- if (typeof input !== "string" || input === "") {
3319
- throw new Error("path must be a non-empty string");
3320
- }
3321
- const home = homedir4();
3322
- const candidate = input.startsWith("~/") ? resolve2(home, input.slice(2)) : input.startsWith("/") ? normalize(input) : resolve2(home, input);
3323
- if (candidate !== home && !candidate.startsWith(`${home}/`)) {
3324
- throw new Error(`path "${input}" resolves outside the agent's home`);
3325
- }
3326
- return candidate;
3327
- }
3328
- var fileTools = [
3329
- {
3330
- name: "file.read",
3331
- description: "Read a UTF-8 file from the agent's home directory ($HOME). Capped at 1MB. Path traversal blocked.",
3332
- parameters: {
3333
- type: "object",
3334
- properties: {
3335
- path: { type: "string", description: "Path relative to $HOME (or absolute under $HOME). `..` segments are rejected." }
3336
- },
3337
- required: ["path"]
3338
- },
3339
- execute: async (args) => {
3340
- const a = args;
3341
- const p2 = jailPath(a.path);
3342
- const content = readFileSync4(p2, "utf8");
3343
- if (Buffer.byteLength(content, "utf8") > MAX_BYTES) {
3344
- return { path: p2, truncated: true, content: content.slice(0, MAX_BYTES) };
3345
- }
3346
- return { path: p2, truncated: false, content };
3347
- }
3348
- },
3349
- {
3350
- name: "file.write",
3351
- description: "Write a UTF-8 file under the agent's home directory. Creates parent dirs as needed. 1MB max.",
3352
- parameters: {
3353
- type: "object",
3354
- properties: {
3355
- path: { type: "string", description: "Path relative to $HOME (or absolute under $HOME)." },
3356
- content: { type: "string", description: "File body. Existing files are overwritten." }
3357
- },
3358
- required: ["path", "content"]
3359
- },
3360
- execute: async (args) => {
3361
- const a = args;
3362
- if (typeof a.content !== "string") throw new Error("content must be a string");
3363
- if (Buffer.byteLength(a.content, "utf8") > MAX_BYTES) {
3364
- throw new Error(`content exceeds ${MAX_BYTES} byte cap`);
3365
- }
3366
- const p2 = jailPath(a.path);
3367
- mkdirSync(dirname(p2), { recursive: true });
3368
- writeFileSync2(p2, a.content, { encoding: "utf8" });
3369
- return { path: p2, bytes: Buffer.byteLength(a.content, "utf8") };
3370
- }
3371
- }
3372
- ];
3373
-
3374
- // src/lib/agent-tools/http.ts
3375
- var MAX_BYTES2 = 1024 * 1024;
3376
- var FORBIDDEN_HEADERS = /* @__PURE__ */ new Set([
3377
- "host",
3378
- "authorization",
3379
- "cookie",
3380
- "connection",
3381
- "transfer-encoding",
3382
- "upgrade",
3383
- "proxy-authorization"
3384
- ]);
3385
- function sanitizeHeaders(input) {
3386
- if (!input || typeof input !== "object") return {};
3387
- const out = {};
3388
- for (const [k, v] of Object.entries(input)) {
3389
- if (typeof v !== "string") continue;
3390
- if (FORBIDDEN_HEADERS.has(k.toLowerCase())) continue;
3391
- out[k] = v;
3392
- }
3393
- return out;
3394
- }
3395
- async function readCappedBody(res) {
3396
- const buf = new Uint8Array(MAX_BYTES2 + 1);
3397
- let written = 0;
3398
- const reader = res.body?.getReader();
3399
- if (!reader) return await res.text();
3400
- while (true) {
3401
- const { value, done } = await reader.read();
3402
- if (done) break;
3403
- if (written + value.byteLength > MAX_BYTES2) {
3404
- buf.set(value.subarray(0, MAX_BYTES2 - written), written);
3405
- written = MAX_BYTES2;
3406
- try {
3407
- await reader.cancel();
3408
- } catch {
3409
- }
3410
- break;
3411
- }
3412
- buf.set(value, written);
3413
- written += value.byteLength;
3414
- }
3415
- return new TextDecoder().decode(buf.subarray(0, written));
3416
- }
3417
- var httpTools = [
3418
- {
3419
- name: "http.get",
3420
- description: "GET an HTTPS URL and return the response body (capped at 1MB). Useful for reading public APIs, RSS feeds, web pages.",
3421
- parameters: {
3422
- type: "object",
3423
- properties: {
3424
- url: { type: "string", description: "Absolute HTTPS URL." },
3425
- headers: { type: "object", description: "Optional headers (Host, Authorization, Cookie are stripped)." }
3426
- },
3427
- required: ["url"]
3428
- },
3429
- execute: async (args) => {
3430
- const a = args;
3431
- if (typeof a.url !== "string" || !a.url.startsWith("http")) {
3432
- throw new Error("url must be an http(s) URL");
3433
- }
3434
- const res = await fetch(a.url, { method: "GET", headers: sanitizeHeaders(a.headers) });
3435
- const body = await readCappedBody(res);
3436
- return { status: res.status, headers: Object.fromEntries(res.headers), body };
3437
- }
3438
- },
3439
- {
3440
- name: "http.post",
3441
- description: "POST JSON to an HTTPS URL and return the response body (capped at 1MB).",
3442
- parameters: {
3443
- type: "object",
3444
- properties: {
3445
- url: { type: "string", description: "Absolute HTTPS URL." },
3446
- body: { description: "JSON-serialisable payload." },
3447
- headers: { type: "object", description: "Optional headers (Host, Authorization, Cookie are stripped)." }
3448
- },
3449
- required: ["url", "body"]
3450
- },
3451
- execute: async (args) => {
3452
- const a = args;
3453
- if (typeof a.url !== "string" || !a.url.startsWith("http")) {
3454
- throw new Error("url must be an http(s) URL");
3455
- }
3456
- const res = await fetch(a.url, {
3457
- method: "POST",
3458
- headers: { "content-type": "application/json", ...sanitizeHeaders(a.headers) },
3459
- body: JSON.stringify(a.body)
3460
- });
3461
- const body = await readCappedBody(res);
3462
- return { status: res.status, headers: Object.fromEntries(res.headers), body };
3463
- }
3464
- }
3465
- ];
3466
-
3467
- // src/lib/agent-tools/mail.ts
3468
- import { execFileSync as execFileSync5 } from "child_process";
3469
- function o365(args) {
3470
- try {
3471
- return execFileSync5("o365-cli", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
3472
- } catch (err) {
3473
- const e = err;
3474
- if (e.code === "ENOENT") {
3475
- throw new Error("o365-cli is not installed on this agent host");
3476
- }
3477
- const stderr = typeof e.stderr === "string" ? e.stderr : e.stderr?.toString("utf8");
3478
- throw new Error(`o365-cli failed: ${stderr ?? e.message ?? err}`);
3479
- }
3480
- }
3481
- var mailTools = [
3482
- {
3483
- name: "mail.list",
3484
- description: "List recent inbox messages via o365-cli. Optional `unread_only` and `limit`.",
3485
- parameters: {
3486
- type: "object",
3487
- properties: {
3488
- limit: { type: "integer", minimum: 1, maximum: 100, default: 20 },
3489
- unread_only: { type: "boolean", default: false }
3490
- },
3491
- required: []
3492
- },
3493
- execute: async (args) => {
3494
- const a = args ?? {};
3495
- const argv = ["mail", "list", "--json", "--limit", String(a.limit ?? 20)];
3496
- if (a.unread_only) argv.push("--unread");
3497
- const out = o365(argv);
3498
- try {
3499
- return JSON.parse(out);
3500
- } catch {
3501
- return { raw: out };
3502
- }
3503
- }
3504
- },
3505
- {
3506
- name: "mail.search",
3507
- description: "Search the inbox via o365-cli using a free-form query string.",
3508
- parameters: {
3509
- type: "object",
3510
- properties: {
3511
- q: { type: "string" },
3512
- limit: { type: "integer", minimum: 1, maximum: 100, default: 20 }
3513
- },
3514
- required: ["q"]
3515
- },
3516
- execute: async (args) => {
3517
- const a = args;
3518
- if (typeof a.q !== "string" || a.q.length === 0) throw new Error("q is required");
3519
- const argv = ["mail", "search", a.q, "--json", "--limit", String(a.limit ?? 20)];
3520
- const out = o365(argv);
3521
- try {
3522
- return JSON.parse(out);
3523
- } catch {
3524
- return { raw: out };
3525
- }
3526
- }
3527
- }
3528
- ];
3529
-
3530
- // src/lib/agent-tools/tasks.ts
3531
- import { execFileSync as execFileSync6 } from "child_process";
3532
- function ape(args) {
3533
- try {
3534
- return execFileSync6("ape-tasks", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
3535
- } catch (err) {
3536
- const e = err;
3537
- const stderr = typeof e.stderr === "string" ? e.stderr : e.stderr?.toString("utf8");
3538
- throw new Error(`ape-tasks failed: ${stderr ?? e.message ?? err}`);
3539
- }
3540
- }
3541
- var tasksTools = [
3542
- {
3543
- name: "tasks.list",
3544
- description: "List the owner's open ape-tasks (the user's personal task list at tasks.openape.ai).",
3545
- parameters: {
3546
- type: "object",
3547
- properties: {
3548
- status: { type: "string", enum: ["open", "doing", "done", "archived"] },
3549
- team_id: { type: "string" }
3550
- },
3551
- required: []
3552
- },
3553
- execute: async (args) => {
3554
- const a = args ?? {};
3555
- const argv = ["list", "--json"];
3556
- if (a.status) argv.push("--status", a.status);
3557
- if (a.team_id) argv.push("--team", a.team_id);
3558
- const out = ape(argv);
3559
- try {
3560
- return JSON.parse(out);
3561
- } catch {
3562
- return { raw: out };
3563
- }
3564
- }
3565
- },
3566
- {
3567
- name: "tasks.create",
3568
- description: "Create a new ape-task on the owner's task list at tasks.openape.ai.",
3569
- parameters: {
3570
- type: "object",
3571
- properties: {
3572
- title: { type: "string" },
3573
- notes: { type: "string" },
3574
- priority: { type: "string", enum: ["low", "med", "high"] },
3575
- due_at: { type: "string", description: "ISO date or +Nh/+Nd shorthand." }
3576
- },
3577
- required: ["title"]
3578
- },
3579
- execute: async (args) => {
3580
- const a = args;
3581
- const argv = ["new", "--title", a.title, "--json"];
3582
- if (a.notes) argv.push("--notes", a.notes);
3583
- if (a.priority) argv.push("--priority", a.priority);
3584
- if (a.due_at) argv.push("--due", a.due_at);
3585
- const out = ape(argv);
3586
- try {
3587
- return JSON.parse(out);
3588
- } catch {
3589
- return { raw: out };
3590
- }
3591
- }
3592
- }
3593
- ];
3594
-
3595
- // src/lib/agent-tools/time.ts
3596
- var timeTools = [
3597
- {
3598
- name: "time.now",
3599
- description: "Returns the current UTC date and time as ISO 8601 plus epoch seconds. No inputs.",
3600
- parameters: { type: "object", properties: {}, required: [] },
3601
- execute: async () => {
3602
- const now = /* @__PURE__ */ new Date();
3603
- return {
3604
- iso: now.toISOString(),
3605
- epoch_seconds: Math.floor(now.getTime() / 1e3),
3606
- timezone_offset_minutes: -now.getTimezoneOffset()
3607
- };
3608
- }
3609
- }
3610
- ];
3611
-
3612
- // src/lib/agent-tools/index.ts
3613
- var ALL_TOOLS = [
3614
- ...timeTools,
3615
- ...httpTools,
3616
- ...fileTools,
3617
- ...tasksTools,
3618
- ...mailTools
3619
- ];
3620
- var TOOLS = Object.fromEntries(
3621
- ALL_TOOLS.map((t) => [t.name, t])
3622
- );
3623
- function taskTools(names) {
3624
- const out = [];
3625
- const missing = [];
3626
- for (const name of names) {
3627
- const tool = TOOLS[name];
3628
- if (!tool) missing.push(name);
3629
- else out.push(tool);
3630
- }
3631
- if (missing.length > 0) {
3632
- throw new Error(`unknown tool(s): ${missing.join(", ")}`);
3633
- }
3634
- return out;
3635
- }
3636
- function asOpenAiTools(tools) {
3637
- return tools.map((t) => ({
3638
- type: "function",
3639
- function: { name: wireToolName(t.name), description: t.description, parameters: t.parameters }
3640
- }));
3641
- }
3642
- function wireToolName(local) {
3643
- return local.replace(/\./g, "_");
3644
- }
3645
- function localToolName(wire) {
3646
- for (const t of Object.values(TOOLS)) {
3647
- if (wireToolName(t.name) === wire) return t.name;
3648
- }
3649
- return wire;
3650
- }
3651
-
3652
- // src/lib/agent-runtime.ts
3653
- function previewJson(value, max = 500) {
3654
- let s;
3655
- try {
3656
- s = JSON.stringify(value);
3657
- } catch {
3658
- s = String(value);
3659
- }
3660
- return s.length > max ? `${s.slice(0, max)}\u2026` : s;
3661
- }
3662
- async function runLoop(opts) {
3663
- const fetchFn = opts.fetchImpl ?? fetch;
3664
- const trace = [];
3665
- const messages = [
3666
- { role: "system", content: opts.systemPrompt },
3667
- ...opts.history ?? [],
3668
- { role: "user", content: opts.userMessage }
3669
- ];
3670
- const tools = asOpenAiTools(opts.tools);
3671
- for (let step = 1; step <= opts.maxSteps; step++) {
3672
- const res = await fetchFn(`${opts.config.apiBase}/chat/completions`, {
3673
- method: "POST",
3674
- headers: {
3675
- "authorization": `Bearer ${opts.config.apiKey}`,
3676
- "content-type": "application/json"
3677
- },
3678
- body: JSON.stringify({
3679
- model: opts.config.model,
3680
- messages,
3681
- ...tools.length > 0 ? { tools, tool_choice: "auto" } : {}
3682
- })
3683
- });
3684
- if (!res.ok) {
3685
- const text = await res.text().catch(() => "");
3686
- throw new Error(`LiteLLM ${res.status}: ${text.slice(0, 500)}`);
3687
- }
3688
- const data = await res.json();
3689
- const choice = data.choices?.[0];
3690
- if (!choice) throw new Error("LiteLLM response had no choices");
3691
- const assistant = choice.message;
3692
- messages.push(assistant);
3693
- if (assistant.content) opts.handlers?.onTextDelta?.(assistant.content);
3694
- trace.push({
3695
- step,
3696
- type: "assistant",
3697
- preview: previewJson({ content: assistant.content, tool_calls: assistant.tool_calls?.length ?? 0 })
3698
- });
3699
- if (!assistant.tool_calls || assistant.tool_calls.length === 0) {
3700
- const result2 = {
3701
- status: "ok",
3702
- finalMessage: assistant.content,
3703
- stepCount: step,
3704
- trace
3705
- };
3706
- opts.handlers?.onDone?.(result2);
3707
- return result2;
3708
- }
3709
- for (const call of assistant.tool_calls) {
3710
- const wireName = call.function.name;
3711
- const localName = localToolName(wireName);
3712
- const tool = opts.tools.find((t) => t.name === localName);
3713
- let parsedArgs;
3714
- try {
3715
- parsedArgs = JSON.parse(call.function.arguments);
3716
- } catch {
3717
- parsedArgs = {};
3718
- }
3719
- opts.handlers?.onToolCall?.({ name: localName, args: parsedArgs });
3720
- trace.push({ step, type: "tool_call", tool: localName, preview: previewJson(parsedArgs) });
3721
- let result2;
3722
- let isError = false;
3723
- if (!tool) {
3724
- result2 = `unknown tool: ${localName}`;
3725
- isError = true;
3726
- } else {
3727
- try {
3728
- result2 = await tool.execute(parsedArgs);
3729
- } catch (err) {
3730
- result2 = err?.message ?? String(err);
3731
- isError = true;
3732
- }
3733
- }
3734
- if (isError) {
3735
- opts.handlers?.onToolError?.({ name: localName, error: String(result2) });
3736
- trace.push({ step, type: "tool_error", tool: localName, preview: previewJson(result2) });
3737
- } else {
3738
- opts.handlers?.onToolResult?.({ name: localName, result: result2 });
3739
- trace.push({ step, type: "tool_result", tool: localName, preview: previewJson(result2) });
3740
- }
3741
- messages.push({
3742
- role: "tool",
3743
- tool_call_id: call.id,
3744
- name: wireToolName(localName),
3745
- content: typeof result2 === "string" ? result2 : JSON.stringify(result2)
3746
- });
3747
- }
3748
- }
3749
- const result = {
3750
- status: "error",
3751
- finalMessage: `max_steps (${opts.maxSteps}) reached without completion`,
3752
- stepCount: opts.maxSteps,
3753
- trace
3754
- };
3755
- opts.handlers?.onDone?.(result);
3756
- return result;
3757
- }
3758
- var RPC_SESSION_TTL_MS = 60 * 60 * 1e3;
3759
- var RpcSessionMap = class {
3760
- sessions = /* @__PURE__ */ new Map();
3761
- get(id) {
3762
- const s = this.sessions.get(id);
3763
- if (s) s.lastTouched = Date.now();
3764
- return s;
3765
- }
3766
- put(id, s) {
3767
- s.lastTouched = Date.now();
3768
- this.sessions.set(id, s);
3769
- }
3770
- evictStale() {
3771
- const cutoff = Date.now() - RPC_SESSION_TTL_MS;
3772
- for (const [k, v] of this.sessions) {
3773
- if (v.lastTouched < cutoff) this.sessions.delete(k);
3774
- }
3775
- }
3776
- size() {
3777
- return this.sessions.size;
3778
- }
3779
- };
3780
-
3781
3288
  // src/lib/troop-client.ts
3782
3289
  var DEFAULT_TROOP_URL = "https://troop.openape.ai";
3783
3290
  var TroopClient = class {
@@ -3836,13 +3343,13 @@ function resolveTroopUrl(override) {
3836
3343
  }
3837
3344
 
3838
3345
  // src/commands/agents/run.ts
3839
- var AUTH_PATH = join3(homedir5(), ".config", "apes", "auth.json");
3840
- var TASK_CACHE_DIR = join3(homedir5(), ".openape", "agent", "tasks");
3346
+ var AUTH_PATH = join3(homedir4(), ".config", "apes", "auth.json");
3347
+ var TASK_CACHE_DIR = join3(homedir4(), ".openape", "agent", "tasks");
3841
3348
  function readAuth() {
3842
3349
  if (!existsSync5(AUTH_PATH)) {
3843
3350
  throw new CliError(`No agent auth found at ${AUTH_PATH}. Run \`apes agents spawn <name>\` first.`);
3844
3351
  }
3845
- const parsed = JSON.parse(readFileSync5(AUTH_PATH, "utf8"));
3352
+ const parsed = JSON.parse(readFileSync4(AUTH_PATH, "utf8"));
3846
3353
  if (!parsed.access_token) throw new CliError("auth.json missing access_token");
3847
3354
  return parsed;
3848
3355
  }
@@ -3882,22 +3389,22 @@ function readTaskSpec(taskId) {
3882
3389
  if (!existsSync5(path2)) {
3883
3390
  throw new CliError(`No cached task spec at ${path2}. Run \`apes agents sync\` first to pull the task list from troop.`);
3884
3391
  }
3885
- return JSON.parse(readFileSync5(path2, "utf8"));
3392
+ return JSON.parse(readFileSync4(path2, "utf8"));
3886
3393
  }
3887
- var AGENT_CONFIG_PATH = join3(homedir5(), ".openape", "agent", "agent.json");
3394
+ var AGENT_CONFIG_PATH = join3(homedir4(), ".openape", "agent", "agent.json");
3888
3395
  function readAgentConfig() {
3889
3396
  if (!existsSync5(AGENT_CONFIG_PATH)) return { systemPrompt: "" };
3890
3397
  try {
3891
- return JSON.parse(readFileSync5(AGENT_CONFIG_PATH, "utf8"));
3398
+ return JSON.parse(readFileSync4(AGENT_CONFIG_PATH, "utf8"));
3892
3399
  } catch {
3893
3400
  return { systemPrompt: "" };
3894
3401
  }
3895
3402
  }
3896
3403
  function readLitellmConfig(model) {
3897
- const envPath = join3(homedir5(), "litellm", ".env");
3404
+ const envPath = join3(homedir4(), "litellm", ".env");
3898
3405
  const env = {};
3899
3406
  if (existsSync5(envPath)) {
3900
- for (const line of readFileSync5(envPath, "utf8").split(/\r?\n/)) {
3407
+ for (const line of readFileSync4(envPath, "utf8").split(/\r?\n/)) {
3901
3408
  const m = line.match(/^([A-Z_]+)=(.*)$/);
3902
3409
  if (m) env[m[1]] = m[2].replace(/^["']|["']$/g, "");
3903
3410
  }
@@ -4002,17 +3509,17 @@ var runAgentCommand = defineCommand24({
4002
3509
  });
4003
3510
 
4004
3511
  // src/commands/agents/serve.ts
4005
- import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
4006
- import { homedir as homedir6 } from "os";
3512
+ import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
3513
+ import { homedir as homedir5 } from "os";
4007
3514
  import { join as join4 } from "path";
4008
3515
  import { createInterface } from "readline";
4009
3516
  import { defineCommand as defineCommand25 } from "citty";
4010
- var AUTH_PATH2 = join4(homedir6(), ".config", "apes", "auth.json");
3517
+ var AUTH_PATH2 = join4(homedir5(), ".config", "apes", "auth.json");
4011
3518
  function readLitellmConfig2(model) {
4012
- const envPath = join4(homedir6(), "litellm", ".env");
3519
+ const envPath = join4(homedir5(), "litellm", ".env");
4013
3520
  const env = {};
4014
3521
  if (existsSync6(envPath)) {
4015
- for (const line of readFileSync6(envPath, "utf8").split(/\r?\n/)) {
3522
+ for (const line of readFileSync5(envPath, "utf8").split(/\r?\n/)) {
4016
3523
  const m = line.match(/^([A-Z_]+)=(.*)$/);
4017
3524
  if (m) env[m[1]] = m[2].replace(/^["']|["']$/g, "");
4018
3525
  }
@@ -4046,7 +3553,7 @@ var serveAgentCommand = defineCommand25({
4046
3553
  }
4047
3554
  if (existsSync6(AUTH_PATH2)) {
4048
3555
  try {
4049
- JSON.parse(readFileSync6(AUTH_PATH2, "utf8"));
3556
+ JSON.parse(readFileSync5(AUTH_PATH2, "utf8"));
4050
3557
  } catch {
4051
3558
  }
4052
3559
  }
@@ -4121,8 +3628,8 @@ async function handleInbound(msg, sessions) {
4121
3628
  }
4122
3629
 
4123
3630
  // src/commands/agents/spawn.ts
4124
- import { execFileSync as execFileSync8 } from "child_process";
4125
- import { mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
3631
+ import { execFileSync as execFileSync6 } from "child_process";
3632
+ import { mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
4126
3633
  import { tmpdir as tmpdir2 } from "os";
4127
3634
  import { join as join6 } from "path";
4128
3635
  import { defineCommand as defineCommand26 } from "citty";
@@ -4182,12 +3689,12 @@ ${envBlock} <key>StartInterval</key>
4182
3689
 
4183
3690
  // src/lib/keygen.ts
4184
3691
  import { Buffer as Buffer4 } from "buffer";
4185
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
3692
+ import { existsSync as existsSync7, mkdirSync, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "fs";
4186
3693
  import { generateKeyPairSync } from "crypto";
4187
- import { homedir as homedir7 } from "os";
4188
- import { dirname as dirname2, resolve as resolve3 } from "path";
3694
+ import { homedir as homedir6 } from "os";
3695
+ import { dirname, resolve as resolve2 } from "path";
4189
3696
  function resolveKeyPath(p2) {
4190
- return resolve3(p2.replace(/^~/, homedir7()));
3697
+ return resolve2(p2.replace(/^~/, homedir6()));
4191
3698
  }
4192
3699
  function buildSshEd25519Line(rawPub) {
4193
3700
  const keyTypeStr = "ssh-ed25519";
@@ -4201,9 +3708,9 @@ function buildSshEd25519Line(rawPub) {
4201
3708
  function readPublicKey(keyPath) {
4202
3709
  const pubPath = `${keyPath}.pub`;
4203
3710
  if (existsSync7(pubPath)) {
4204
- return readFileSync7(pubPath, "utf-8").trim();
3711
+ return readFileSync6(pubPath, "utf-8").trim();
4205
3712
  }
4206
- const keyContent = readFileSync7(keyPath, "utf-8");
3713
+ const keyContent = readFileSync6(keyPath, "utf-8");
4207
3714
  const privateKey = loadEd25519PrivateKey(keyContent);
4208
3715
  const jwk = privateKey.export({ format: "jwk" });
4209
3716
  const pubBytes = Buffer4.from(jwk.x, "base64url");
@@ -4211,17 +3718,17 @@ function readPublicKey(keyPath) {
4211
3718
  }
4212
3719
  function generateAndSaveKey(keyPath) {
4213
3720
  const resolved = resolveKeyPath(keyPath);
4214
- const dir = dirname2(resolved);
3721
+ const dir = dirname(resolved);
4215
3722
  if (!existsSync7(dir)) {
4216
- mkdirSync2(dir, { recursive: true });
3723
+ mkdirSync(dir, { recursive: true });
4217
3724
  }
4218
3725
  const { publicKey, privateKey } = generateKeyPairSync("ed25519");
4219
3726
  const privatePem = privateKey.export({ type: "pkcs8", format: "pem" });
4220
- writeFileSync3(resolved, privatePem, { mode: 384 });
3727
+ writeFileSync2(resolved, privatePem, { mode: 384 });
4221
3728
  const jwk = publicKey.export({ format: "jwk" });
4222
3729
  const pubBytes = Buffer4.from(jwk.x, "base64url");
4223
3730
  const pubKeyStr = buildSshEd25519Line(pubBytes);
4224
- writeFileSync3(`${resolved}.pub`, `${pubKeyStr}
3731
+ writeFileSync2(`${resolved}.pub`, `${pubKeyStr}
4225
3732
  `, { mode: 420 });
4226
3733
  return pubKeyStr;
4227
3734
  }
@@ -4237,15 +3744,15 @@ function generateKeyPairInMemory() {
4237
3744
  }
4238
3745
 
4239
3746
  // src/lib/llm-bridge.ts
4240
- import { execFileSync as execFileSync7 } from "child_process";
4241
- import { existsSync as existsSync8, readFileSync as readFileSync8 } from "fs";
4242
- import { homedir as homedir8 } from "os";
4243
- import { dirname as dirname3, join as join5 } from "path";
3747
+ import { execFileSync as execFileSync5 } from "child_process";
3748
+ import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
3749
+ import { homedir as homedir7 } from "os";
3750
+ import { dirname as dirname2, join as join5 } from "path";
4244
3751
  var PLIST_LABEL_PREFIX = "eco.hofmann.apes.bridge";
4245
- function readLitellmEnv(envPath = join5(homedir8(), "litellm", ".env")) {
3752
+ function readLitellmEnv(envPath = join5(homedir7(), "litellm", ".env")) {
4246
3753
  if (!existsSync8(envPath)) return null;
4247
3754
  try {
4248
- const text = readFileSync8(envPath, "utf8");
3755
+ const text = readFileSync7(envPath, "utf8");
4249
3756
  const out = {};
4250
3757
  for (const line of text.split("\n")) {
4251
3758
  const trimmed = line.trim();
@@ -4281,12 +3788,12 @@ function captureHostBinDirs() {
4281
3788
  for (const bin of ["node", "openape-chat-bridge", "apes"]) {
4282
3789
  let resolved;
4283
3790
  try {
4284
- resolved = execFileSync7("/usr/bin/which", [bin], { encoding: "utf8" }).trim();
3791
+ resolved = execFileSync5("/usr/bin/which", [bin], { encoding: "utf8" }).trim();
4285
3792
  } catch {
4286
3793
  const installCmd = bin === "openape-chat-bridge" ? "npm i -g @openape/chat-bridge" : bin === "apes" ? "npm i -g @openape/apes" : "install Node.js (e.g. brew install node)";
4287
3794
  throw new Error(`'${bin}' not found on host PATH. ${installCmd} before spawning agents \u2014 the bridge runtime resolves these at spawn time and bakes the dir into the agent's launchd plist.`);
4288
3795
  }
4289
- const dir = dirname3(resolved);
3796
+ const dir = dirname2(resolved);
4290
3797
  if (!seen.has(dir)) {
4291
3798
  seen.add(dir);
4292
3799
  dirs.push(dir);
@@ -4532,10 +4039,10 @@ and try again.`
4532
4039
  bridge,
4533
4040
  troop
4534
4041
  });
4535
- writeFileSync4(scriptPath, script, { mode: 448 });
4042
+ writeFileSync3(scriptPath, script, { mode: 448 });
4536
4043
  consola23.start("Running privileged setup as root via `apes run --as root --wait`\u2026");
4537
4044
  consola23.info("You will be asked to approve the as=root grant in your DDISA inbox; this command blocks until you do.");
4538
- execFileSync8(apes, ["run", "--as", "root", "--wait", "--", "bash", scriptPath], { stdio: "inherit" });
4045
+ execFileSync6(apes, ["run", "--as", "root", "--wait", "--", "bash", scriptPath], { stdio: "inherit" });
4539
4046
  consola23.success(`Agent ${name} spawned.`);
4540
4047
  consola23.info(`\u{1F517} Troop: https://troop.openape.ai/agents/${name}`);
4541
4048
  if (args.bridge) {
@@ -4574,18 +4081,18 @@ async function resolveClaudeToken(opts) {
4574
4081
  }
4575
4082
 
4576
4083
  // src/commands/agents/sync.ts
4577
- import { chownSync, existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync9, statSync, writeFileSync as writeFileSync5 } from "fs";
4578
- import { homedir as homedir9 } from "os";
4084
+ import { chownSync, existsSync as existsSync9, mkdirSync as mkdirSync2, readFileSync as readFileSync8, statSync, writeFileSync as writeFileSync4 } from "fs";
4085
+ import { homedir as homedir8 } from "os";
4579
4086
  import { join as join7 } from "path";
4580
4087
  import { defineCommand as defineCommand27 } from "citty";
4581
4088
  import consola24 from "consola";
4582
4089
 
4583
4090
  // src/lib/macos-host.ts
4584
- import { execFileSync as execFileSync9 } from "child_process";
4091
+ import { execFileSync as execFileSync7 } from "child_process";
4585
4092
  import { hostname as hostname3 } from "os";
4586
4093
  function getHostId() {
4587
4094
  try {
4588
- const output = execFileSync9(
4095
+ const output = execFileSync7(
4589
4096
  "/usr/sbin/ioreg",
4590
4097
  ["-d2", "-c", "IOPlatformExpertDevice"],
4591
4098
  { encoding: "utf8", timeout: 2e3 }
@@ -4605,15 +4112,15 @@ function getHostname() {
4605
4112
  }
4606
4113
 
4607
4114
  // src/commands/agents/sync.ts
4608
- var AUTH_PATH3 = join7(homedir9(), ".config", "apes", "auth.json");
4609
- var TASK_CACHE_DIR2 = join7(homedir9(), ".openape", "agent", "tasks");
4115
+ var AUTH_PATH3 = join7(homedir8(), ".config", "apes", "auth.json");
4116
+ var TASK_CACHE_DIR2 = join7(homedir8(), ".openape", "agent", "tasks");
4610
4117
  function readAuthJson() {
4611
4118
  if (!existsSync9(AUTH_PATH3)) {
4612
4119
  throw new CliError(
4613
4120
  `No agent auth found at ${AUTH_PATH3}. Run \`apes agents spawn <name>\` to provision an agent first.`
4614
4121
  );
4615
4122
  }
4616
- const raw = readFileSync9(AUTH_PATH3, "utf8");
4123
+ const raw = readFileSync8(AUTH_PATH3, "utf8");
4617
4124
  let parsed;
4618
4125
  try {
4619
4126
  parsed = JSON.parse(raw);
@@ -4674,7 +4181,7 @@ var syncAgentCommand = defineCommand27({
4674
4181
  let agentGid = null;
4675
4182
  if (process.geteuid?.() === 0) {
4676
4183
  try {
4677
- const homeStat = statSync(homedir9());
4184
+ const homeStat = statSync(homedir8());
4678
4185
  agentUid = homeStat.uid;
4679
4186
  agentGid = homeStat.gid;
4680
4187
  } catch {
@@ -4688,23 +4195,23 @@ var syncAgentCommand = defineCommand27({
4688
4195
  }
4689
4196
  }
4690
4197
  }
4691
- const agentDir = join7(homedir9(), ".openape", "agent");
4692
- mkdirSync3(agentDir, { recursive: true });
4693
- chownToAgent(join7(homedir9(), ".openape"));
4198
+ const agentDir = join7(homedir8(), ".openape", "agent");
4199
+ mkdirSync2(agentDir, { recursive: true });
4200
+ chownToAgent(join7(homedir8(), ".openape"));
4694
4201
  chownToAgent(agentDir);
4695
4202
  const agentJsonPath = join7(agentDir, "agent.json");
4696
- writeFileSync5(
4203
+ writeFileSync4(
4697
4204
  agentJsonPath,
4698
4205
  `${JSON.stringify({ systemPrompt }, null, 2)}
4699
4206
  `,
4700
4207
  { mode: 384 }
4701
4208
  );
4702
4209
  chownToAgent(agentJsonPath);
4703
- mkdirSync3(TASK_CACHE_DIR2, { recursive: true });
4210
+ mkdirSync2(TASK_CACHE_DIR2, { recursive: true });
4704
4211
  chownToAgent(TASK_CACHE_DIR2);
4705
4212
  for (const task of tasks) {
4706
4213
  const path2 = join7(TASK_CACHE_DIR2, `${task.taskId}.json`);
4707
- writeFileSync5(path2, `${JSON.stringify(task, null, 2)}
4214
+ writeFileSync4(path2, `${JSON.stringify(task, null, 2)}
4708
4215
  `, { mode: 384 });
4709
4216
  chownToAgent(path2);
4710
4217
  }
@@ -4731,22 +4238,22 @@ var agentsCommand = defineCommand28({
4731
4238
  });
4732
4239
 
4733
4240
  // src/commands/nest/index.ts
4734
- import { defineCommand as defineCommand37 } from "citty";
4241
+ import { defineCommand as defineCommand36 } from "citty";
4735
4242
 
4736
4243
  // src/commands/nest/authorize.ts
4737
- import { execFileSync as execFileSync10 } from "child_process";
4738
- import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
4244
+ import { execFileSync as execFileSync8 } from "child_process";
4245
+ import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
4739
4246
  import { join as join9 } from "path";
4740
4247
  import { defineCommand as defineCommand30 } from "citty";
4741
4248
  import consola26 from "consola";
4742
4249
 
4743
4250
  // src/commands/nest/enroll.ts
4744
- import { hostname as hostname4, homedir as homedir10 } from "os";
4745
- import { existsSync as existsSync10, mkdirSync as mkdirSync4, writeFileSync as writeFileSync6, chmodSync } from "fs";
4251
+ import { hostname as hostname4, homedir as homedir9 } from "os";
4252
+ import { existsSync as existsSync10, mkdirSync as mkdirSync3, writeFileSync as writeFileSync5, chmodSync } from "fs";
4746
4253
  import { join as join8 } from "path";
4747
4254
  import { defineCommand as defineCommand29 } from "citty";
4748
4255
  import consola25 from "consola";
4749
- var NEST_DATA_DIR = join8(homedir10(), ".openape", "nest");
4256
+ var NEST_DATA_DIR = join8(homedir9(), ".openape", "nest");
4750
4257
  function nestAgentName() {
4751
4258
  const raw = hostname4().toLowerCase();
4752
4259
  const head = raw.split(".")[0] ?? raw;
@@ -4785,13 +4292,13 @@ var enrollNestCommand = defineCommand29({
4785
4292
  }
4786
4293
  const sshDir = join8(NEST_DATA_DIR, ".ssh");
4787
4294
  const configDir = join8(NEST_DATA_DIR, ".config", "apes");
4788
- mkdirSync4(sshDir, { recursive: true });
4789
- mkdirSync4(configDir, { recursive: true });
4295
+ mkdirSync3(sshDir, { recursive: true });
4296
+ mkdirSync3(configDir, { recursive: true });
4790
4297
  consola25.start(`Generating keypair for ${name}\u2026`);
4791
4298
  const { privatePem, publicSshLine } = generateKeyPairInMemory();
4792
- writeFileSync6(join8(sshDir, "id_ed25519"), `${privatePem.trimEnd()}
4299
+ writeFileSync5(join8(sshDir, "id_ed25519"), `${privatePem.trimEnd()}
4793
4300
  `, { mode: 384 });
4794
- writeFileSync6(join8(sshDir, "id_ed25519.pub"), `${publicSshLine}
4301
+ writeFileSync5(join8(sshDir, "id_ed25519.pub"), `${publicSshLine}
4795
4302
  `, { mode: 420 });
4796
4303
  chmodSync(sshDir, 448);
4797
4304
  consola25.start(`Registering nest at ${idp}\u2026`);
@@ -4811,7 +4318,7 @@ var enrollNestCommand = defineCommand29({
4811
4318
  keyPath: join8(sshDir, "id_ed25519"),
4812
4319
  ownerEmail: ownerAuth.email
4813
4320
  });
4814
- writeFileSync6(authPath, authJson, { mode: 384 });
4321
+ writeFileSync5(authPath, authJson, { mode: 384 });
4815
4322
  chmodSync(configDir, 448);
4816
4323
  consola25.success(`Nest enrolled \u2014 auth.json at ${authPath}`);
4817
4324
  consola25.info("");
@@ -4873,7 +4380,7 @@ var authorizeNestCommand = defineCommand30({
4873
4380
  if (!existsSync11(nestAuthPath)) {
4874
4381
  throw new CliError("Nest not enrolled. Run `apes nest enroll` first.");
4875
4382
  }
4876
- const nestAuth = JSON.parse(readFileSync10(nestAuthPath, "utf8"));
4383
+ const nestAuth = JSON.parse(readFileSync9(nestAuthPath, "utf8"));
4877
4384
  if (!nestAuth.email) throw new CliError(`${nestAuthPath} has no email`);
4878
4385
  const allow = args.allow ?? DEFAULT_ALLOW_PATTERNS.join(",");
4879
4386
  consola26.info(`Configuring YOLO-policy on ${nestAuth.email} via \`apes yolo set\`\u2026`);
@@ -4890,7 +4397,7 @@ var authorizeNestCommand = defineCommand30({
4890
4397
  cmdArgs.push("--expires-in", args["expires-in"]);
4891
4398
  }
4892
4399
  try {
4893
- execFileSync10("apes", cmdArgs, { stdio: "inherit" });
4400
+ execFileSync8("apes", cmdArgs, { stdio: "inherit" });
4894
4401
  } catch (err) {
4895
4402
  throw new CliError(err instanceof Error ? err.message : String(err));
4896
4403
  }
@@ -4900,147 +4407,107 @@ var authorizeNestCommand = defineCommand30({
4900
4407
  });
4901
4408
 
4902
4409
  // src/commands/nest/destroy.ts
4903
- import process2 from "process";
4904
4410
  import { defineCommand as defineCommand31 } from "citty";
4905
- import consola28 from "consola";
4906
-
4907
- // src/lib/nest-grant-flow.ts
4908
- import { hostname as hostname5 } from "os";
4909
4411
  import consola27 from "consola";
4910
- var NEST_AUDIENCE = "nest";
4911
- async function requestNestGrant(opts) {
4912
- const auth = loadAuth();
4913
- if (!auth) {
4914
- throw new CliError("Not logged in. Run `apes login` first.");
4915
- }
4916
- const idp = getIdpUrl(opts.idp) ?? void 0;
4917
- if (!idp) {
4918
- throw new CliError("No IdP URL resolved. Pass --idp or run `apes login` first.");
4919
- }
4920
- const grantsUrl = await getGrantsEndpoint(idp);
4921
- const targetHost = opts.targetHost ?? hostname5();
4922
- const approval = opts.approval ?? "always";
4923
- const reusableId = await findReusableNestGrant({
4924
- grantsUrl,
4925
- requester: auth.email,
4926
- command: opts.command,
4927
- targetHost
4928
- });
4929
- if (reusableId) {
4930
- const { authz_jwt: authz_jwt2 } = await apiFetch(`${grantsUrl}/${reusableId}/token`, {
4931
- method: "POST"
4932
- });
4933
- return authz_jwt2;
4934
- }
4935
- consola27.info(`Requesting nest grant: ${opts.command.join(" ")}`);
4936
- const grant = await apiFetch(grantsUrl, {
4937
- method: "POST",
4938
- body: {
4939
- requester: auth.email,
4940
- target_host: targetHost,
4941
- audience: NEST_AUDIENCE,
4942
- grant_type: approval,
4943
- command: opts.command,
4944
- reason: opts.reason ?? opts.command.join(" ")
4945
- }
4946
- });
4947
- let approved = grant.status === "approved";
4948
- const maxWait = 15 * 60 * 1e3;
4949
- const interval = 3e3;
4950
- const start = Date.now();
4951
- while (!approved && Date.now() - start < maxWait) {
4952
- const status = await apiFetch(`${grantsUrl}/${grant.id}`);
4953
- if (status.status === "approved") {
4954
- approved = true;
4955
- break;
4956
- }
4957
- if (status.status === "denied" || status.status === "revoked") {
4958
- throw new CliError(`Grant ${status.status}.`);
4959
- }
4960
- if (!approved) {
4961
- consola27.info(`Waiting for approval: ${idp}/grant-approval?grant_id=${grant.id}`);
4962
- await new Promise((r3) => setTimeout(r3, interval));
4412
+
4413
+ // src/lib/nest-intent.ts
4414
+ import { existsSync as existsSync12, mkdirSync as mkdirSync4, readFileSync as readFileSync10, statSync as statSync2, unlinkSync, writeFileSync as writeFileSync6 } from "fs";
4415
+ import { homedir as homedir10 } from "os";
4416
+ import { join as join10 } from "path";
4417
+ import { randomUUID } from "crypto";
4418
+ var POLL_INTERVAL_MS = 200;
4419
+ var DEFAULT_TIMEOUT_MS = 5 * 60 * 1e3;
4420
+ function resolveIntentDir() {
4421
+ if (process.env.OPENAPE_NEST_INTENT_DIR) return process.env.OPENAPE_NEST_INTENT_DIR;
4422
+ if (existsSync12("/var/openape/nest/intents")) return "/var/openape/nest/intents";
4423
+ return join10(homedir10(), ".openape", "nest", "intents");
4424
+ }
4425
+ async function dispatchIntent(intent, opts = {}) {
4426
+ const id = randomUUID();
4427
+ const dir = resolveIntentDir();
4428
+ if (!existsSync12(dir)) {
4429
+ throw new CliError(`Nest intent dir does not exist: ${dir}
4430
+ Is the nest daemon running? Try \`ps aux | grep openape-nest\`.`);
4431
+ }
4432
+ const intentPath = join10(dir, `${id}.json`);
4433
+ const responsePath = join10(dir, `${id}.response`);
4434
+ const tmpPath = `${intentPath}.tmp`;
4435
+ writeFileSync6(tmpPath, `${JSON.stringify({ id, ...intent })}
4436
+ `, { mode: 432 });
4437
+ try {
4438
+ const fs = await import("fs");
4439
+ fs.renameSync(tmpPath, intentPath);
4440
+ } catch (err) {
4441
+ try {
4442
+ unlinkSync(tmpPath);
4443
+ } catch {
4963
4444
  }
4445
+ throw err;
4964
4446
  }
4965
- if (!approved) {
4966
- throw new CliError(
4967
- `Grant approval timed out after 15 min (still pending). Check your DDISA inbox at ${idp}/grant-approval?grant_id=${grant.id}.`
4968
- );
4447
+ const deadline = Date.now() + (opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
4448
+ while (Date.now() < deadline) {
4449
+ if (existsSync12(responsePath)) {
4450
+ let raw;
4451
+ try {
4452
+ const st = statSync2(responsePath);
4453
+ if (Date.now() - st.mtimeMs < 50) {
4454
+ await sleep(50);
4455
+ }
4456
+ raw = readFileSync10(responsePath, "utf8");
4457
+ } catch {
4458
+ await sleep(POLL_INTERVAL_MS);
4459
+ continue;
4460
+ }
4461
+ try {
4462
+ unlinkSync(responsePath);
4463
+ } catch {
4464
+ }
4465
+ let parsed;
4466
+ try {
4467
+ parsed = JSON.parse(raw);
4468
+ } catch (err) {
4469
+ throw new CliError(`malformed nest response: ${err instanceof Error ? err.message : String(err)}`);
4470
+ }
4471
+ if (!parsed.ok) {
4472
+ throw new CliError(`nest: ${parsed.error}`);
4473
+ }
4474
+ return parsed.result;
4475
+ }
4476
+ await sleep(POLL_INTERVAL_MS);
4969
4477
  }
4970
- const { authz_jwt } = await apiFetch(`${grantsUrl}/${grant.id}/token`, {
4971
- method: "POST"
4972
- });
4973
- return authz_jwt;
4974
- }
4975
- function nestBaseUrl(port) {
4976
- const p2 = port ?? Number(process.env.OPENAPE_NEST_PORT ?? 9091);
4977
- return `http://127.0.0.1:${p2}`;
4978
- }
4979
- async function findReusableNestGrant(opts) {
4980
4478
  try {
4981
- const grants = await apiFetch(
4982
- `${opts.grantsUrl}?requester=${encodeURIComponent(opts.requester)}&status=approved&limit=50`
4983
- );
4984
- const now = Math.floor(Date.now() / 1e3);
4985
- const match = grants.data.find((g) => {
4986
- const r3 = g.request;
4987
- if (r3.audience !== NEST_AUDIENCE) return false;
4988
- if (r3.target_host !== opts.targetHost) return false;
4989
- if (r3.grant_type === "once") return false;
4990
- if (r3.grant_type === "timed" && g.expires_at && g.expires_at <= now) return false;
4991
- const cmd = r3.command ?? [];
4992
- if (cmd.length !== opts.command.length) return false;
4993
- return cmd.every((c2, i) => c2 === opts.command[i]);
4994
- });
4995
- return match?.id ?? null;
4479
+ unlinkSync(intentPath);
4996
4480
  } catch {
4997
- return null;
4998
4481
  }
4482
+ throw new CliError(`nest intent timeout (${(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS) / 1e3}s) \u2014 Nest daemon may not be running or is stuck.`);
4483
+ }
4484
+ function sleep(ms) {
4485
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
4999
4486
  }
5000
4487
 
5001
4488
  // src/commands/nest/destroy.ts
5002
4489
  var destroyNestCommand = defineCommand31({
5003
4490
  meta: {
5004
4491
  name: "destroy",
5005
- description: "Tear down an agent on the local nest (removes macOS user, hard-deletes IdP record, drops bridge plist). Requires a DDISA `nest destroy <name>` grant."
4492
+ description: "Tear down an agent on the local nest. Drops an intent file the nest daemon picks up."
5006
4493
  },
5007
4494
  args: {
5008
- name: { type: "positional", required: true, description: "Agent name to destroy" },
5009
- port: { type: "string", description: "Override nest port (default: 9091)" }
4495
+ name: { type: "positional", required: true, description: "Agent name to destroy" }
5010
4496
  },
5011
4497
  async run({ args }) {
5012
4498
  const name = String(args.name);
5013
- const token = await requestNestGrant({ command: ["nest", "destroy", name] });
5014
- const base = nestBaseUrl(args.port ? Number(args.port) : void 0);
5015
- try {
5016
- const res = await fetch(`${base}/agents/${encodeURIComponent(name)}`, {
5017
- method: "DELETE",
5018
- headers: { Authorization: `Bearer ${token}` }
5019
- });
5020
- if (!res.ok) {
5021
- const text = await res.text().catch(() => "");
5022
- throw new CliError(`nest DELETE /agents/${name} failed: ${res.status} ${text}`);
5023
- }
5024
- } catch (err) {
5025
- const msg = err instanceof Error ? err.message : String(err);
5026
- if (msg.includes("ECONNREFUSED") || msg.includes("fetch failed")) {
5027
- consola28.error(`Nest daemon is not running at ${base}`);
5028
- consola28.info(" Run: apes nest install");
5029
- process2.exit(2);
5030
- }
5031
- throw err;
5032
- }
5033
- consola28.success(`Destroyed ${name}`);
4499
+ await dispatchIntent({ action: "destroy", name });
4500
+ consola27.success(`Destroyed ${name}`);
5034
4501
  }
5035
4502
  });
5036
4503
 
5037
4504
  // src/commands/nest/install.ts
5038
- import { execFileSync as execFileSync11 } from "child_process";
5039
- import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync7 } from "fs";
4505
+ import { execFileSync as execFileSync9 } from "child_process";
4506
+ import { existsSync as existsSync13, mkdirSync as mkdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync7 } from "fs";
5040
4507
  import { homedir as homedir11, userInfo as userInfo2 } from "os";
5041
- import { dirname as dirname4, join as join10 } from "path";
4508
+ import { dirname as dirname3, join as join11 } from "path";
5042
4509
  import { defineCommand as defineCommand32 } from "citty";
5043
- import consola29 from "consola";
4510
+ import consola28 from "consola";
5044
4511
 
5045
4512
  // src/commands/nest/apes-agents-adapter.ts
5046
4513
  var APES_AGENTS_ADAPTER_TOML = `schema = "openape-shapes/v1"
@@ -5107,13 +4574,13 @@ resource_chain = ["agents:name={name}", "allowlist:email={peer_email}"]
5107
4574
  // src/commands/nest/install.ts
5108
4575
  var PLIST_LABEL = "ai.openape.nest";
5109
4576
  function plistPath() {
5110
- return join10(homedir11(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
4577
+ return join11(homedir11(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
5111
4578
  }
5112
4579
  function escape2(s) {
5113
4580
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5114
4581
  }
5115
4582
  function buildPlist(args) {
5116
- const logsDir = join10(args.userHome, "Library", "Logs");
4583
+ const logsDir = join11(args.userHome, "Library", "Logs");
5117
4584
  return `<?xml version="1.0" encoding="UTF-8"?>
5118
4585
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
5119
4586
  <plist version="1.0">
@@ -5148,8 +4615,8 @@ function buildPlist(args) {
5148
4615
  `;
5149
4616
  }
5150
4617
  function installAdapter2() {
5151
- const target = join10(homedir11(), ".openape", "shapes", "adapters", "apes-agents.toml");
5152
- mkdirSync5(dirname4(target), { recursive: true });
4618
+ const target = join11(homedir11(), ".openape", "shapes", "adapters", "apes-agents.toml");
4619
+ mkdirSync5(dirname3(target), { recursive: true });
5153
4620
  let existing = "";
5154
4621
  try {
5155
4622
  existing = readFileSync11(target, "utf8");
@@ -5157,15 +4624,15 @@ function installAdapter2() {
5157
4624
  }
5158
4625
  if (existing === APES_AGENTS_ADAPTER_TOML) return false;
5159
4626
  writeFileSync7(target, APES_AGENTS_ADAPTER_TOML, { mode: 420 });
5160
- consola29.success(`Wrote shapes adapter ${target}`);
4627
+ consola28.success(`Wrote shapes adapter ${target}`);
5161
4628
  return true;
5162
4629
  }
5163
4630
  function writeBridgeModelDefault(model) {
5164
- const envDir = join10(homedir11(), "litellm");
5165
- const envFile = join10(envDir, ".env");
4631
+ const envDir = join11(homedir11(), "litellm");
4632
+ const envFile = join11(envDir, ".env");
5166
4633
  mkdirSync5(envDir, { recursive: true });
5167
4634
  let lines = [];
5168
- if (existsSync12(envFile)) {
4635
+ if (existsSync13(envFile)) {
5169
4636
  lines = readFileSync11(envFile, "utf8").split("\n").filter((l) => !l.startsWith("APE_CHAT_BRIDGE_MODEL="));
5170
4637
  }
5171
4638
  lines.push(`APE_CHAT_BRIDGE_MODEL=${model}`);
@@ -5175,13 +4642,13 @@ function writeBridgeModelDefault(model) {
5175
4642
  }
5176
4643
  function findBinary(name) {
5177
4644
  for (const dir of [
5178
- join10(homedir11(), ".bun", "bin"),
4645
+ join11(homedir11(), ".bun", "bin"),
5179
4646
  "/opt/homebrew/bin",
5180
4647
  "/usr/local/bin",
5181
4648
  "/usr/bin"
5182
4649
  ]) {
5183
- const p2 = join10(dir, name);
5184
- if (existsSync12(p2)) return p2;
4650
+ const p2 = join11(dir, name);
4651
+ if (existsSync13(p2)) return p2;
5185
4652
  }
5186
4653
  throw new Error(`could not locate ${name} on PATH; install it first`);
5187
4654
  }
@@ -5208,16 +4675,16 @@ var installNestCommand = defineCommand32({
5208
4675
  }
5209
4676
  const nestBin = findBinary("openape-nest");
5210
4677
  const apesBin = findBinary("apes");
5211
- consola29.info(`Installing nest at ${plistPath()}`);
5212
- consola29.info(` nest binary: ${nestBin}`);
5213
- consola29.info(` apes binary: ${apesBin}`);
5214
- consola29.info(` HTTP port: ${port}`);
4678
+ consola28.info(`Installing nest at ${plistPath()}`);
4679
+ consola28.info(` nest binary: ${nestBin}`);
4680
+ consola28.info(` apes binary: ${apesBin}`);
4681
+ consola28.info(` HTTP port: ${port}`);
5215
4682
  if (typeof args["bridge-model"] === "string" && args["bridge-model"]) {
5216
4683
  writeBridgeModelDefault(args["bridge-model"]);
5217
- consola29.success(`Default bridge model set to ${args["bridge-model"]} (in ~/litellm/.env)`);
4684
+ consola28.success(`Default bridge model set to ${args["bridge-model"]} (in ~/litellm/.env)`);
5218
4685
  }
5219
4686
  installAdapter2();
5220
- mkdirSync5(join10(homeDir, "Library", "LaunchAgents"), { recursive: true });
4687
+ mkdirSync5(join11(homeDir, "Library", "LaunchAgents"), { recursive: true });
5221
4688
  mkdirSync5(NEST_DATA_DIR, { recursive: true });
5222
4689
  const desired = buildPlist({ nestBin, apesBin, userHome: homeDir, nestHome: NEST_DATA_DIR, port });
5223
4690
  let existing = "";
@@ -5227,218 +4694,126 @@ var installNestCommand = defineCommand32({
5227
4694
  }
5228
4695
  if (existing !== desired) {
5229
4696
  writeFileSync7(plistPath(), desired, { mode: 420 });
5230
- consola29.success("Wrote launchd plist");
4697
+ consola28.success("Wrote launchd plist");
5231
4698
  } else {
5232
- consola29.info("plist already up to date");
4699
+ consola28.info("plist already up to date");
5233
4700
  }
5234
4701
  const uid = userInfo2().uid;
5235
4702
  try {
5236
- execFileSync11("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL}`], { stdio: "ignore" });
4703
+ execFileSync9("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL}`], { stdio: "ignore" });
5237
4704
  } catch {
5238
4705
  }
5239
- execFileSync11("/bin/launchctl", ["bootstrap", `gui/${uid}`, plistPath()], { stdio: "inherit" });
5240
- consola29.success(`Nest daemon bootstrapped \u2014 http://127.0.0.1:${port}`);
5241
- consola29.info("");
5242
- consola29.info("Next steps for zero-prompt spawn \u2014 both one-time:");
5243
- consola29.info("");
5244
- consola29.info(" 1. apes nest enroll # register nest as DDISA agent (creates own auth.json)");
5245
- consola29.info(" 2. apes nest authorize # set YOLO-policy on the nest agent");
5246
- consola29.info("");
5247
- consola29.info("After that, every `POST http://127.0.0.1:9091/agents` runs without DDISA prompts.");
4706
+ execFileSync9("/bin/launchctl", ["bootstrap", `gui/${uid}`, plistPath()], { stdio: "inherit" });
4707
+ consola28.success(`Nest daemon bootstrapped \u2014 http://127.0.0.1:${port}`);
4708
+ consola28.info("");
4709
+ consola28.info("Next steps for zero-prompt spawn \u2014 both one-time:");
4710
+ consola28.info("");
4711
+ consola28.info(" 1. apes nest enroll # register nest as DDISA agent (creates own auth.json)");
4712
+ consola28.info(" 2. apes nest authorize # set YOLO-policy on the nest agent");
4713
+ consola28.info("");
4714
+ consola28.info("After that, every `POST http://127.0.0.1:9091/agents` runs without DDISA prompts.");
5248
4715
  }
5249
4716
  });
5250
4717
 
5251
4718
  // src/commands/nest/list.ts
5252
- import process3 from "process";
5253
4719
  import { defineCommand as defineCommand33 } from "citty";
5254
- import consola30 from "consola";
4720
+ import consola29 from "consola";
5255
4721
  var listNestCommand = defineCommand33({
5256
4722
  meta: {
5257
4723
  name: "list",
5258
- description: "List agents registered with the local nest. Goes through DDISA grants \u2014 YOLO auto-approves under the standard nest policy."
4724
+ description: "List agents registered with the local nest. File-based intent."
5259
4725
  },
5260
4726
  args: {
5261
- port: { type: "string", description: "Override nest port (default: 9091)" },
5262
4727
  json: { type: "boolean", description: "JSON output for scripts" }
5263
4728
  },
5264
4729
  async run({ args }) {
5265
- const token = await requestNestGrant({ command: ["nest", "list"] });
5266
- const base = nestBaseUrl(args.port ? Number(args.port) : void 0);
5267
- let resp;
5268
- try {
5269
- const res = await fetch(`${base}/agents`, {
5270
- headers: { Authorization: `Bearer ${token}` }
5271
- });
5272
- if (!res.ok) {
5273
- const text = await res.text().catch(() => "");
5274
- throw new CliError(`nest GET /agents failed: ${res.status} ${text}`);
5275
- }
5276
- resp = await res.json();
5277
- } catch (err) {
5278
- const msg = err instanceof Error ? err.message : String(err);
5279
- if (msg.includes("ECONNREFUSED") || msg.includes("fetch failed")) {
5280
- consola30.error(`Nest daemon is not running at ${base}`);
5281
- consola30.info(" Run: apes nest install");
5282
- process3.exit(2);
5283
- }
5284
- throw err;
5285
- }
4730
+ const result = await dispatchIntent({ action: "list" });
5286
4731
  if (args.json) {
5287
- console.log(JSON.stringify(resp, null, 2));
4732
+ console.log(JSON.stringify(result, null, 2));
5288
4733
  return;
5289
4734
  }
5290
- if (resp.agents.length === 0) {
5291
- consola30.info("(no agents registered with this nest)");
4735
+ if (result.agents.length === 0) {
4736
+ consola29.info("(no agents registered with this nest)");
5292
4737
  return;
5293
4738
  }
5294
- consola30.info(`${resp.agents.length} agent(s) registered with this nest:`);
5295
- for (const a of resp.agents) {
4739
+ consola29.info(`${result.agents.length} agent(s) registered with this nest:`);
4740
+ for (const a of result.agents) {
5296
4741
  const bridge = a.bridge ? " bridge=on" : "";
5297
- consola30.info(` ${a.name.padEnd(16)} uid=${String(a.uid).padEnd(5)} home=${a.home}${bridge}`);
4742
+ consola29.info(` ${a.name.padEnd(16)} uid=${String(a.uid).padEnd(5)} home=${a.home}${bridge}`);
5298
4743
  }
5299
4744
  }
5300
4745
  });
5301
4746
 
5302
4747
  // src/commands/nest/spawn.ts
5303
- import process4 from "process";
5304
4748
  import { defineCommand as defineCommand34 } from "citty";
5305
- import consola31 from "consola";
4749
+ import consola30 from "consola";
5306
4750
  var spawnNestCommand = defineCommand34({
5307
4751
  meta: {
5308
4752
  name: "spawn",
5309
- description: "Spawn a new agent on the local nest. Requires a DDISA `nest spawn <name>` grant \u2014 auto-approved by Patrick's policy on first use, reused on subsequent calls."
4753
+ description: "Spawn a new agent on the local nest. Drops an intent file the nest daemon picks up; UNIX permissions on the intents dir gate access."
5310
4754
  },
5311
4755
  args: {
5312
4756
  name: { type: "positional", required: true, description: "Agent name (lowercase, [a-z0-9-], max 24 chars)" },
5313
4757
  "no-bridge": { type: "boolean", description: "Skip installing the chat-bridge daemon (default: install it)" },
5314
4758
  "bridge-key": { type: "string", description: "Override LITELLM_API_KEY (default: read from ~/litellm/.env)" },
5315
4759
  "bridge-base-url": { type: "string", description: "Override LITELLM_BASE_URL (default: read from ~/litellm/.env)" },
5316
- "bridge-model": { type: "string", description: "Override APE_CHAT_BRIDGE_MODEL" },
5317
- "port": { type: "string", description: "Override nest port (default: 9091)" }
4760
+ "bridge-model": { type: "string", description: "Override APE_CHAT_BRIDGE_MODEL" }
5318
4761
  },
5319
4762
  async run({ args }) {
5320
4763
  const name = String(args.name);
5321
- const token = await requestNestGrant({ command: ["nest", "spawn"] });
5322
- const base = nestBaseUrl(args.port ? Number(args.port) : void 0);
5323
- const reqBody = {
4764
+ const intent = {
4765
+ action: "spawn",
5324
4766
  name,
5325
4767
  bridge: !args["no-bridge"]
5326
4768
  };
5327
- if (typeof args["bridge-key"] === "string") reqBody.bridgeKey = args["bridge-key"];
5328
- if (typeof args["bridge-base-url"] === "string") reqBody.bridgeBaseUrl = args["bridge-base-url"];
5329
- if (typeof args["bridge-model"] === "string") reqBody.bridgeModel = args["bridge-model"];
5330
- let resp;
5331
- try {
5332
- const res = await fetch(`${base}/agents`, {
5333
- method: "POST",
5334
- headers: {
5335
- "Authorization": `Bearer ${token}`,
5336
- "Content-Type": "application/json"
5337
- },
5338
- body: JSON.stringify(reqBody)
5339
- });
5340
- if (!res.ok) {
5341
- const text = await res.text().catch(() => "");
5342
- throw new CliError(`nest POST /agents failed: ${res.status} ${text}`);
5343
- }
5344
- resp = await res.json();
5345
- } catch (err) {
5346
- const msg = err instanceof Error ? err.message : String(err);
5347
- if (msg.includes("ECONNREFUSED") || msg.includes("fetch failed")) {
5348
- consola31.error(`Nest daemon is not running at ${base}`);
5349
- consola31.info(" Run: apes nest install");
5350
- process4.exit(2);
5351
- }
5352
- throw err;
5353
- }
5354
- consola31.success(`Spawned ${resp.name} (uid=${resp.uid}, home=${resp.home})`);
5355
- }
5356
- });
5357
-
5358
- // src/commands/nest/status.ts
5359
- import process5 from "process";
5360
- import { defineCommand as defineCommand35 } from "citty";
5361
- import consola32 from "consola";
5362
- var statusNestCommand = defineCommand35({
5363
- meta: {
5364
- name: "status",
5365
- description: "Print health of the local nest-daemon (agents registered). Goes through DDISA grants."
5366
- },
5367
- args: {
5368
- port: { type: "string", description: "Override nest port (default: 9091)" },
5369
- json: { type: "boolean", description: "JSON output for scripts" }
5370
- },
5371
- async run({ args }) {
5372
- const token = await requestNestGrant({ command: ["nest", "status"] });
5373
- const base = nestBaseUrl(args.port ? Number(args.port) : void 0);
5374
- let status;
5375
- try {
5376
- const res = await fetch(`${base}/status`, {
5377
- headers: { Authorization: `Bearer ${token}` }
5378
- });
5379
- if (!res.ok) {
5380
- const text = await res.text().catch(() => "");
5381
- throw new CliError(`nest GET /status failed: ${res.status} ${text}`);
5382
- }
5383
- status = await res.json();
5384
- } catch (err) {
5385
- const msg = err instanceof Error ? err.message : String(err);
5386
- if (msg.includes("ECONNREFUSED") || msg.includes("fetch failed")) {
5387
- consola32.error(`Nest daemon is not running at ${base}`);
5388
- consola32.info(" Run: apes nest install");
5389
- process5.exit(2);
5390
- }
5391
- throw err;
5392
- }
5393
- if (args.json) {
5394
- console.log(JSON.stringify(status, null, 2));
5395
- return;
5396
- }
5397
- consola32.info(`Nest at ${base} \u2014 ${status.agents} agent(s) registered`);
4769
+ if (typeof args["bridge-key"] === "string") intent.bridgeKey = args["bridge-key"];
4770
+ if (typeof args["bridge-base-url"] === "string") intent.bridgeBaseUrl = args["bridge-base-url"];
4771
+ if (typeof args["bridge-model"] === "string") intent.bridgeModel = args["bridge-model"];
4772
+ const result = await dispatchIntent(intent);
4773
+ consola30.success(`Spawned ${result.name} (uid=${result.uid}, home=${result.home})`);
5398
4774
  }
5399
4775
  });
5400
4776
 
5401
4777
  // src/commands/nest/uninstall.ts
5402
- import { execFileSync as execFileSync12 } from "child_process";
5403
- import { existsSync as existsSync13, unlinkSync } from "fs";
4778
+ import { execFileSync as execFileSync10 } from "child_process";
4779
+ import { existsSync as existsSync14, unlinkSync as unlinkSync2 } from "fs";
5404
4780
  import { homedir as homedir12, userInfo as userInfo3 } from "os";
5405
- import { join as join11 } from "path";
5406
- import { defineCommand as defineCommand36 } from "citty";
5407
- import consola33 from "consola";
4781
+ import { join as join12 } from "path";
4782
+ import { defineCommand as defineCommand35 } from "citty";
4783
+ import consola31 from "consola";
5408
4784
  var PLIST_LABEL2 = "ai.openape.nest";
5409
- var uninstallNestCommand = defineCommand36({
4785
+ var uninstallNestCommand = defineCommand35({
5410
4786
  meta: {
5411
4787
  name: "uninstall",
5412
4788
  description: "Stop + remove the local nest-daemon (registry + agents preserved)"
5413
4789
  },
5414
4790
  async run() {
5415
4791
  const uid = userInfo3().uid;
5416
- const path2 = join11(homedir12(), "Library", "LaunchAgents", `${PLIST_LABEL2}.plist`);
4792
+ const path2 = join12(homedir12(), "Library", "LaunchAgents", `${PLIST_LABEL2}.plist`);
5417
4793
  try {
5418
- execFileSync12("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL2}`], { stdio: "ignore" });
5419
- consola33.success("Nest daemon stopped");
4794
+ execFileSync10("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL2}`], { stdio: "ignore" });
4795
+ consola31.success("Nest daemon stopped");
5420
4796
  } catch {
5421
- consola33.info("Nest daemon was not loaded");
4797
+ consola31.info("Nest daemon was not loaded");
5422
4798
  }
5423
- if (existsSync13(path2)) {
5424
- unlinkSync(path2);
5425
- consola33.success(`Removed ${path2}`);
4799
+ if (existsSync14(path2)) {
4800
+ unlinkSync2(path2);
4801
+ consola31.success(`Removed ${path2}`);
5426
4802
  }
5427
- consola33.info("Registry at ~/.openape/nest/agents.json kept \u2014 re-run `apes nest install` to resume supervision.");
4803
+ consola31.info("Registry at ~/.openape/nest/agents.json kept \u2014 re-run `apes nest install` to resume supervision.");
5428
4804
  }
5429
4805
  });
5430
4806
 
5431
4807
  // src/commands/nest/index.ts
5432
- var nestCommand = defineCommand37({
4808
+ var nestCommand = defineCommand36({
5433
4809
  meta: {
5434
4810
  name: "nest",
5435
- description: "Manage the local Nest control-plane daemon. One-time setup: `install` (launchd) \u2192 `enroll` (own DDISA identity) \u2192 `authorize` (YOLO-policy). Day-to-day: `status` / `list` (read-only) and `spawn` / `destroy` (mutating) \u2014 every API call is gated by a DDISA grant audited at the IdP, YOLO-approved silently under the policy `apes nest authorize` sets up."
4811
+ description: "Manage the local Nest control-plane daemon. One-time setup: `install` \u2192 `enroll` \u2192 `authorize`. Day-to-day: `list` / `spawn` / `destroy`. As of Phase D the Nest is a long-running CLIENT \u2014 commands talk to it via filesystem intent files in $NEST_HOME/intents (mode 770, group _openape_nest) instead of HTTP."
5436
4812
  },
5437
4813
  subCommands: {
5438
4814
  install: installNestCommand,
5439
4815
  enroll: enrollNestCommand,
5440
4816
  authorize: authorizeNestCommand,
5441
- status: statusNestCommand,
5442
4817
  list: listNestCommand,
5443
4818
  spawn: spawnNestCommand,
5444
4819
  destroy: destroyNestCommand,
@@ -5447,12 +4822,12 @@ var nestCommand = defineCommand37({
5447
4822
  });
5448
4823
 
5449
4824
  // src/commands/yolo/index.ts
5450
- import { defineCommand as defineCommand41 } from "citty";
4825
+ import { defineCommand as defineCommand40 } from "citty";
5451
4826
 
5452
4827
  // src/commands/yolo/clear.ts
5453
- import { defineCommand as defineCommand38 } from "citty";
5454
- import consola34 from "consola";
5455
- var yoloClearCommand = defineCommand38({
4828
+ import { defineCommand as defineCommand37 } from "citty";
4829
+ import consola32 from "consola";
4830
+ var yoloClearCommand = defineCommand37({
5456
4831
  meta: {
5457
4832
  name: "clear",
5458
4833
  description: "Remove the YOLO-policy from a DDISA agent (subsequent grants need human approval)"
@@ -5481,15 +4856,15 @@ var yoloClearCommand = defineCommand38({
5481
4856
  const text = await res.text().catch(() => "");
5482
4857
  throw new CliError(`DELETE /yolo-policy failed (${res.status}): ${text}`);
5483
4858
  }
5484
- consola34.success(`YOLO-policy cleared on ${email}`);
4859
+ consola32.success(`YOLO-policy cleared on ${email}`);
5485
4860
  }
5486
4861
  });
5487
4862
 
5488
4863
  // src/commands/yolo/set.ts
5489
- import { defineCommand as defineCommand39 } from "citty";
5490
- import consola35 from "consola";
4864
+ import { defineCommand as defineCommand38 } from "citty";
4865
+ import consola33 from "consola";
5491
4866
  var VALID_MODES = ["allow-list", "deny-list"];
5492
- var yoloSetCommand = defineCommand39({
4867
+ var yoloSetCommand = defineCommand38({
5493
4868
  meta: {
5494
4869
  name: "set",
5495
4870
  description: "Write a YOLO-policy on a DDISA agent you own"
@@ -5537,12 +4912,12 @@ var yoloSetCommand = defineCommand39({
5537
4912
  const denyPatterns = parseList(args.deny);
5538
4913
  const denyRiskThreshold = args["deny-risk"] ?? null;
5539
4914
  const expiresAt = parseExpiresIn(args["expires-in"]);
5540
- consola35.info(`Setting YOLO-policy on ${email}`);
5541
- consola35.info(` mode: ${mode}`);
5542
- if (allowPatterns.length) consola35.info(` allow_patterns: ${allowPatterns.join(", ")}`);
5543
- if (denyPatterns.length) consola35.info(` deny_patterns: ${denyPatterns.join(", ")}`);
5544
- if (denyRiskThreshold) consola35.info(` deny_risk: ${denyRiskThreshold}`);
5545
- if (expiresAt) consola35.info(` expires_at: ${new Date(expiresAt * 1e3).toISOString()}`);
4915
+ consola33.info(`Setting YOLO-policy on ${email}`);
4916
+ consola33.info(` mode: ${mode}`);
4917
+ if (allowPatterns.length) consola33.info(` allow_patterns: ${allowPatterns.join(", ")}`);
4918
+ if (denyPatterns.length) consola33.info(` deny_patterns: ${denyPatterns.join(", ")}`);
4919
+ if (denyRiskThreshold) consola33.info(` deny_risk: ${denyRiskThreshold}`);
4920
+ if (expiresAt) consola33.info(` expires_at: ${new Date(expiresAt * 1e3).toISOString()}`);
5546
4921
  const url = `${idp}/api/users/${encodeURIComponent(email)}/yolo-policy`;
5547
4922
  const res = await fetch(url, {
5548
4923
  method: "PUT",
@@ -5562,7 +4937,7 @@ var yoloSetCommand = defineCommand39({
5562
4937
  const text = await res.text().catch(() => "");
5563
4938
  throw new CliError(`PUT /yolo-policy failed (${res.status}): ${text}`);
5564
4939
  }
5565
- consola35.success(`YOLO-policy applied to ${email}`);
4940
+ consola33.success(`YOLO-policy applied to ${email}`);
5566
4941
  }
5567
4942
  });
5568
4943
  function parseList(s) {
@@ -5580,9 +4955,9 @@ function parseExpiresIn(s) {
5580
4955
  }
5581
4956
 
5582
4957
  // src/commands/yolo/show.ts
5583
- import { defineCommand as defineCommand40 } from "citty";
5584
- import consola36 from "consola";
5585
- var yoloShowCommand = defineCommand40({
4958
+ import { defineCommand as defineCommand39 } from "citty";
4959
+ import consola34 from "consola";
4960
+ var yoloShowCommand = defineCommand39({
5586
4961
  meta: {
5587
4962
  name: "show",
5588
4963
  description: "Print the YOLO-policy currently set on a DDISA agent"
@@ -5619,17 +4994,17 @@ var yoloShowCommand = defineCommand40({
5619
4994
  console.log(JSON.stringify(policy, null, 2));
5620
4995
  return;
5621
4996
  }
5622
- consola36.info(`YOLO-policy for ${email}`);
5623
- consola36.info(` mode: ${policy.mode}`);
5624
- consola36.info(` allow_patterns: ${policy.allowPatterns.length ? policy.allowPatterns.join(", ") : "(none)"}`);
5625
- consola36.info(` deny_patterns: ${policy.denyPatterns.length ? policy.denyPatterns.join(", ") : "(none)"}`);
5626
- consola36.info(` deny_risk: ${policy.denyRiskThreshold ?? "(none)"}`);
5627
- consola36.info(` expires_at: ${policy.expiresAt ? new Date(policy.expiresAt * 1e3).toISOString() : "(never)"}`);
4997
+ consola34.info(`YOLO-policy for ${email}`);
4998
+ consola34.info(` mode: ${policy.mode}`);
4999
+ consola34.info(` allow_patterns: ${policy.allowPatterns.length ? policy.allowPatterns.join(", ") : "(none)"}`);
5000
+ consola34.info(` deny_patterns: ${policy.denyPatterns.length ? policy.denyPatterns.join(", ") : "(none)"}`);
5001
+ consola34.info(` deny_risk: ${policy.denyRiskThreshold ?? "(none)"}`);
5002
+ consola34.info(` expires_at: ${policy.expiresAt ? new Date(policy.expiresAt * 1e3).toISOString() : "(never)"}`);
5628
5003
  }
5629
5004
  });
5630
5005
 
5631
5006
  // src/commands/yolo/index.ts
5632
- var yoloCommand = defineCommand41({
5007
+ var yoloCommand = defineCommand40({
5633
5008
  meta: {
5634
5009
  name: "yolo",
5635
5010
  description: "Manage YOLO-policies on DDISA agents you own \u2014 auto-approve grant patterns at the IdP layer (allow-list) or block dangerous ones outright (deny-list)."
@@ -5642,15 +5017,15 @@ var yoloCommand = defineCommand41({
5642
5017
  });
5643
5018
 
5644
5019
  // src/commands/adapter/index.ts
5645
- import { defineCommand as defineCommand42 } from "citty";
5646
- import consola37 from "consola";
5647
- var adapterCommand = defineCommand42({
5020
+ import { defineCommand as defineCommand41 } from "citty";
5021
+ import consola35 from "consola";
5022
+ var adapterCommand = defineCommand41({
5648
5023
  meta: {
5649
5024
  name: "adapter",
5650
5025
  description: "Manage CLI adapters"
5651
5026
  },
5652
5027
  subCommands: {
5653
- list: defineCommand42({
5028
+ list: defineCommand41({
5654
5029
  meta: {
5655
5030
  name: "list",
5656
5031
  description: "List available adapters"
@@ -5681,7 +5056,7 @@ var adapterCommand = defineCommand42({
5681
5056
  `);
5682
5057
  return;
5683
5058
  }
5684
- consola37.info(`Registry: ${index2.adapters.length} adapters (${index2.generated_at})`);
5059
+ consola35.info(`Registry: ${index2.adapters.length} adapters (${index2.generated_at})`);
5685
5060
  for (const a of index2.adapters) {
5686
5061
  const installed = isInstalled(a.id, false) ? " [installed]" : "";
5687
5062
  console.log(` ${a.id.padEnd(12)} ${a.name.padEnd(24)} ${a.category}${installed}`);
@@ -5703,7 +5078,7 @@ var adapterCommand = defineCommand42({
5703
5078
  return;
5704
5079
  }
5705
5080
  if (local.length === 0) {
5706
- consola37.info("No adapters installed. Use `apes adapter list --remote` to see available adapters.");
5081
+ consola35.info("No adapters installed. Use `apes adapter list --remote` to see available adapters.");
5707
5082
  return;
5708
5083
  }
5709
5084
  for (const a of local) {
@@ -5711,7 +5086,7 @@ var adapterCommand = defineCommand42({
5711
5086
  }
5712
5087
  }
5713
5088
  }),
5714
- install: defineCommand42({
5089
+ install: defineCommand41({
5715
5090
  meta: {
5716
5091
  name: "install",
5717
5092
  description: "Install an adapter from the registry"
@@ -5740,24 +5115,24 @@ var adapterCommand = defineCommand42({
5740
5115
  for (const id of ids) {
5741
5116
  const entry = findAdapter(index, id);
5742
5117
  if (!entry) {
5743
- consola37.error(`Adapter "${id}" not found in registry. Use \`apes adapter search ${id}\` to search.`);
5118
+ consola35.error(`Adapter "${id}" not found in registry. Use \`apes adapter search ${id}\` to search.`);
5744
5119
  continue;
5745
5120
  }
5746
5121
  const conflicts = findConflictingAdapters(entry.executable, id);
5747
5122
  if (conflicts.length > 0) {
5748
5123
  for (const c2 of conflicts) {
5749
- consola37.warn(`Conflicting adapter found: ${c2.path} (id: ${c2.adapterId}, executable: ${c2.executable})`);
5750
- consola37.warn(` Remove it with: apes adapter remove ${c2.adapterId}`);
5124
+ consola35.warn(`Conflicting adapter found: ${c2.path} (id: ${c2.adapterId}, executable: ${c2.executable})`);
5125
+ consola35.warn(` Remove it with: apes adapter remove ${c2.adapterId}`);
5751
5126
  }
5752
5127
  }
5753
5128
  const result = await installAdapter(entry, { local });
5754
5129
  const verb = result.updated ? "Updated" : "Installed";
5755
- consola37.success(`${verb} ${result.id} \u2192 ${result.path}`);
5756
- consola37.info(`Digest: ${result.digest}`);
5130
+ consola35.success(`${verb} ${result.id} \u2192 ${result.path}`);
5131
+ consola35.info(`Digest: ${result.digest}`);
5757
5132
  }
5758
5133
  }
5759
5134
  }),
5760
- remove: defineCommand42({
5135
+ remove: defineCommand41({
5761
5136
  meta: {
5762
5137
  name: "remove",
5763
5138
  description: "Remove an installed adapter"
@@ -5780,9 +5155,9 @@ var adapterCommand = defineCommand42({
5780
5155
  let failed = false;
5781
5156
  for (const id of ids) {
5782
5157
  if (removeAdapter(id, local)) {
5783
- consola37.success(`Removed adapter: ${id}`);
5158
+ consola35.success(`Removed adapter: ${id}`);
5784
5159
  } else {
5785
- consola37.error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
5160
+ consola35.error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
5786
5161
  failed = true;
5787
5162
  }
5788
5163
  }
@@ -5790,7 +5165,7 @@ var adapterCommand = defineCommand42({
5790
5165
  throw new CliError("Some adapters could not be removed");
5791
5166
  }
5792
5167
  }),
5793
- info: defineCommand42({
5168
+ info: defineCommand41({
5794
5169
  meta: {
5795
5170
  name: "info",
5796
5171
  description: "Show detailed adapter information"
@@ -5832,7 +5207,7 @@ var adapterCommand = defineCommand42({
5832
5207
  }
5833
5208
  }
5834
5209
  }),
5835
- search: defineCommand42({
5210
+ search: defineCommand41({
5836
5211
  meta: {
5837
5212
  name: "search",
5838
5213
  description: "Search adapters in the registry"
@@ -5864,7 +5239,7 @@ var adapterCommand = defineCommand42({
5864
5239
  return;
5865
5240
  }
5866
5241
  if (results.length === 0) {
5867
- consola37.info(`No adapters matching "${query}"`);
5242
+ consola35.info(`No adapters matching "${query}"`);
5868
5243
  return;
5869
5244
  }
5870
5245
  for (const a of results) {
@@ -5873,7 +5248,7 @@ var adapterCommand = defineCommand42({
5873
5248
  }
5874
5249
  }
5875
5250
  }),
5876
- update: defineCommand42({
5251
+ update: defineCommand41({
5877
5252
  meta: {
5878
5253
  name: "update",
5879
5254
  description: "Update installed adapters"
@@ -5899,33 +5274,33 @@ var adapterCommand = defineCommand42({
5899
5274
  const targetId = args.id ? String(args.id) : void 0;
5900
5275
  const targets = targetId ? [targetId] : index.adapters.map((a) => a.id).filter((id) => isInstalled(id, false));
5901
5276
  if (targets.length === 0) {
5902
- consola37.info("No adapters installed to update.");
5277
+ consola35.info("No adapters installed to update.");
5903
5278
  return;
5904
5279
  }
5905
5280
  for (const id of targets) {
5906
5281
  const entry = findAdapter(index, id);
5907
5282
  if (!entry) {
5908
- consola37.warn(`${id}: not found in registry, skipping`);
5283
+ consola35.warn(`${id}: not found in registry, skipping`);
5909
5284
  continue;
5910
5285
  }
5911
5286
  const localDigest = getInstalledDigest(id, false);
5912
5287
  if (localDigest === entry.digest) {
5913
- consola37.info(`${id}: already up to date`);
5288
+ consola35.info(`${id}: already up to date`);
5914
5289
  continue;
5915
5290
  }
5916
5291
  if (localDigest && !args.yes) {
5917
- consola37.warn(`${id}: digest will change \u2014 existing grants for this adapter will be invalidated`);
5918
- consola37.info(` Old: ${localDigest}`);
5919
- consola37.info(` New: ${entry.digest}`);
5920
- consola37.info(" Use --yes to confirm");
5292
+ consola35.warn(`${id}: digest will change \u2014 existing grants for this adapter will be invalidated`);
5293
+ consola35.info(` Old: ${localDigest}`);
5294
+ consola35.info(` New: ${entry.digest}`);
5295
+ consola35.info(" Use --yes to confirm");
5921
5296
  continue;
5922
5297
  }
5923
5298
  const result = await installAdapter(entry);
5924
- consola37.success(`Updated ${result.id} \u2192 ${result.path}`);
5299
+ consola35.success(`Updated ${result.id} \u2192 ${result.path}`);
5925
5300
  }
5926
5301
  }
5927
5302
  }),
5928
- verify: defineCommand42({
5303
+ verify: defineCommand41({
5929
5304
  meta: {
5930
5305
  name: "verify",
5931
5306
  description: "Verify installed adapter against registry digest"
@@ -5958,7 +5333,7 @@ var adapterCommand = defineCommand42({
5958
5333
  if (!localDigest)
5959
5334
  throw new Error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
5960
5335
  if (localDigest === entry.digest) {
5961
- consola37.success(`${id}: digest matches registry`);
5336
+ consola35.success(`${id}: digest matches registry`);
5962
5337
  } else {
5963
5338
  console.log(` Local: ${localDigest}`);
5964
5339
  console.log(` Registry: ${entry.digest}`);
@@ -5970,11 +5345,11 @@ var adapterCommand = defineCommand42({
5970
5345
  });
5971
5346
 
5972
5347
  // src/commands/run.ts
5973
- import { execFileSync as execFileSync13 } from "child_process";
5974
- import { hostname as hostname6 } from "os";
5348
+ import { execFileSync as execFileSync11 } from "child_process";
5349
+ import { hostname as hostname5 } from "os";
5975
5350
  import { basename } from "path";
5976
- import { defineCommand as defineCommand43 } from "citty";
5977
- import consola38 from "consola";
5351
+ import { defineCommand as defineCommand42 } from "citty";
5352
+ import consola36 from "consola";
5978
5353
  function shouldWaitForGrant(args) {
5979
5354
  return args.wait === true || process.env.APE_WAIT === "1";
5980
5355
  }
@@ -6011,7 +5386,7 @@ function printPendingGrantInfo(grant, idp) {
6011
5386
  const statusCmd = `apes grants status ${grant.id}`;
6012
5387
  const executeCmd = `apes grants run ${grant.id}`;
6013
5388
  if (mode === "human") {
6014
- consola38.success(`Grant ${grant.id} created \u2014 awaiting your approval`);
5389
+ consola36.success(`Grant ${grant.id} created \u2014 awaiting your approval`);
6015
5390
  console.log(` Approve in browser: ${approveUrl}`);
6016
5391
  console.log(` Check status: ${statusCmd}`);
6017
5392
  console.log(` Run after approval: ${executeCmd}`);
@@ -6021,7 +5396,7 @@ function printPendingGrantInfo(grant, idp) {
6021
5396
  return;
6022
5397
  }
6023
5398
  const maxMin = getPollMaxMinutes();
6024
- consola38.success(`Grant ${grant.id} created (pending approval)`);
5399
+ consola36.success(`Grant ${grant.id} created (pending approval)`);
6025
5400
  console.log(` Approve: ${approveUrl}`);
6026
5401
  console.log(` Status: ${statusCmd} [--json]`);
6027
5402
  console.log(` Execute: ${executeCmd} --wait`);
@@ -6043,7 +5418,7 @@ function printPendingGrantInfo(grant, idp) {
6043
5418
  console.log(' Tip: Approve as "timed" or "always" in the browser to let this');
6044
5419
  console.log(" grant be reused on subsequent invocations without re-approval.");
6045
5420
  }
6046
- var runCommand = defineCommand43({
5421
+ var runCommand = defineCommand42({
6047
5422
  meta: {
6048
5423
  name: "run",
6049
5424
  description: "Execute a grant-secured command"
@@ -6132,7 +5507,7 @@ async function runShellMode(command, args) {
6132
5507
  const adapterHandled = await tryAdapterModeFromShell(command, idp, args);
6133
5508
  if (adapterHandled) return;
6134
5509
  const grantsUrl = await getGrantsEndpoint(idp);
6135
- const targetHost = args.host || hostname6();
5510
+ const targetHost = args.host || hostname5();
6136
5511
  try {
6137
5512
  const grants = await apiFetch(
6138
5513
  `${grantsUrl}?requester=${encodeURIComponent(auth.email)}&status=approved&limit=20`
@@ -6146,7 +5521,7 @@ async function runShellMode(command, args) {
6146
5521
  }
6147
5522
  } catch {
6148
5523
  }
6149
- consola38.info(`Requesting ape-shell session grant on ${targetHost}`);
5524
+ consola36.info(`Requesting ape-shell session grant on ${targetHost}`);
6150
5525
  const grant = await apiFetch(grantsUrl, {
6151
5526
  method: "POST",
6152
5527
  body: {
@@ -6166,8 +5541,8 @@ async function runShellMode(command, args) {
6166
5541
  host: targetHost
6167
5542
  });
6168
5543
  if (shouldWaitForGrant(args)) {
6169
- consola38.info(`Grant requested: ${grant.id}`);
6170
- consola38.info("Waiting for approval...");
5544
+ consola36.info(`Grant requested: ${grant.id}`);
5545
+ consola36.info("Waiting for approval...");
6171
5546
  const maxWait = 3e5;
6172
5547
  const interval = 3e3;
6173
5548
  const start = Date.now();
@@ -6198,13 +5573,13 @@ async function tryAdapterModeFromShell(command, idp, args) {
6198
5573
  try {
6199
5574
  resolved = await resolveCommand(loaded, [normalizedExecutable, ...parsed.argv]);
6200
5575
  } catch (err) {
6201
- consola38.debug(`ape-shell: adapter resolve failed for "${parsed.raw}":`, err);
5576
+ consola36.debug(`ape-shell: adapter resolve failed for "${parsed.raw}":`, err);
6202
5577
  return false;
6203
5578
  }
6204
5579
  try {
6205
5580
  const existingGrantId = await findExistingGrant(resolved, idp);
6206
5581
  if (existingGrantId) {
6207
- consola38.info(`Reusing grant ${existingGrantId} for: ${resolved.detail.display}`);
5582
+ consola36.info(`Reusing grant ${existingGrantId} for: ${resolved.detail.display}`);
6208
5583
  const token = await fetchGrantToken(idp, existingGrantId);
6209
5584
  await verifyAndExecute(token, resolved, existingGrantId);
6210
5585
  return true;
@@ -6212,7 +5587,7 @@ async function tryAdapterModeFromShell(command, idp, args) {
6212
5587
  } catch {
6213
5588
  }
6214
5589
  const approval = args.approval ?? "once";
6215
- consola38.info(`Requesting grant for: ${resolved.detail.display}`);
5590
+ consola36.info(`Requesting grant for: ${resolved.detail.display}`);
6216
5591
  const grant = await createShapesGrant(resolved, {
6217
5592
  idp,
6218
5593
  approval,
@@ -6220,19 +5595,19 @@ async function tryAdapterModeFromShell(command, idp, args) {
6220
5595
  });
6221
5596
  if (grant.similar_grants?.similar_grants?.length) {
6222
5597
  const n2 = grant.similar_grants.similar_grants.length;
6223
- consola38.info("");
6224
- consola38.info(` Similar grant(s) found (${n2}). Your approver can extend an existing grant to cover this request.`);
5598
+ consola36.info("");
5599
+ consola36.info(` Similar grant(s) found (${n2}). Your approver can extend an existing grant to cover this request.`);
6225
5600
  }
6226
5601
  notifyGrantPending({
6227
5602
  grantId: grant.id,
6228
5603
  approveUrl: `${idp}/grant-approval?grant_id=${grant.id}`,
6229
5604
  command: resolved.detail?.display || parsed?.raw || "unknown",
6230
5605
  audience: resolved.adapter?.cli?.audience ?? "shapes",
6231
- host: args.host || hostname6()
5606
+ host: args.host || hostname5()
6232
5607
  });
6233
5608
  if (shouldWaitForGrant(args)) {
6234
- consola38.info(`Grant requested: ${grant.id}`);
6235
- consola38.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
5609
+ consola36.info(`Grant requested: ${grant.id}`);
5610
+ consola36.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
6236
5611
  const status = await waitForGrantStatus(idp, grant.id);
6237
5612
  if (status !== "approved")
6238
5613
  throw new CliError(`Grant ${status}`);
@@ -6248,7 +5623,7 @@ function execShellCommand(command) {
6248
5623
  throw new CliError("No command to execute");
6249
5624
  try {
6250
5625
  const { APES_SHELL_WRAPPER: _wrapperMarker, ...inheritedEnv } = process.env;
6251
- execFileSync13(command[0], command.slice(1), {
5626
+ execFileSync11(command[0], command.slice(1), {
6252
5627
  stdio: "inherit",
6253
5628
  env: inheritedEnv
6254
5629
  });
@@ -6306,7 +5681,7 @@ async function runAdapterMode(command, rawArgs, args) {
6306
5681
  try {
6307
5682
  const existingGrantId = await findExistingGrant(resolved, idp);
6308
5683
  if (existingGrantId) {
6309
- consola38.info(`Reusing existing grant: ${existingGrantId}`);
5684
+ consola36.info(`Reusing existing grant: ${existingGrantId}`);
6310
5685
  const token = await fetchGrantToken(idp, existingGrantId);
6311
5686
  await verifyAndExecute(token, resolved, existingGrantId);
6312
5687
  return;
@@ -6320,17 +5695,17 @@ async function runAdapterMode(command, rawArgs, args) {
6320
5695
  });
6321
5696
  if (grant.similar_grants?.similar_grants?.length) {
6322
5697
  const n2 = grant.similar_grants.similar_grants.length;
6323
- consola38.info("");
6324
- consola38.info(` Similar grant(s) found (${n2}). Your approver can extend an existing grant to cover this request.`);
5698
+ consola36.info("");
5699
+ consola36.info(` Similar grant(s) found (${n2}). Your approver can extend an existing grant to cover this request.`);
6325
5700
  if (grant.similar_grants.widened_details?.length) {
6326
5701
  const wider = grant.similar_grants.widened_details.map((d) => d.permission).join(", ");
6327
- consola38.info(` Broader scope: ${wider}`);
5702
+ consola36.info(` Broader scope: ${wider}`);
6328
5703
  }
6329
- consola38.info("");
5704
+ consola36.info("");
6330
5705
  }
6331
5706
  if (shouldWaitForGrant(args)) {
6332
- consola38.info(`Grant requested: ${grant.id}`);
6333
- consola38.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
5707
+ consola36.info(`Grant requested: ${grant.id}`);
5708
+ consola36.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
6334
5709
  const status = await waitForGrantStatus(idp, grant.id);
6335
5710
  if (status !== "approved")
6336
5711
  throw new Error(`Grant ${status}`);
@@ -6349,8 +5724,8 @@ async function runAudienceMode(audience, action, args) {
6349
5724
  const idp = getIdpUrl(args.idp);
6350
5725
  const grantsUrl = await getGrantsEndpoint(idp);
6351
5726
  const command = action.split(" ");
6352
- const targetHost = args.host || hostname6();
6353
- consola38.info(`Requesting ${audience} grant on ${targetHost}: ${command.join(" ")}`);
5727
+ const targetHost = args.host || hostname5();
5728
+ consola36.info(`Requesting ${audience} grant on ${targetHost}: ${command.join(" ")}`);
6354
5729
  const grant = await apiFetch(grantsUrl, {
6355
5730
  method: "POST",
6356
5731
  body: {
@@ -6367,9 +5742,9 @@ async function runAudienceMode(audience, action, args) {
6367
5742
  printPendingGrantInfo(grant, idp);
6368
5743
  throw new CliExit(getAsyncExitCode());
6369
5744
  }
6370
- consola38.success(`Grant requested: ${grant.id}`);
6371
- consola38.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
6372
- consola38.info("Waiting for approval...");
5745
+ consola36.success(`Grant requested: ${grant.id}`);
5746
+ consola36.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
5747
+ consola36.info("Waiting for approval...");
6373
5748
  const maxWait = 15 * 60 * 1e3;
6374
5749
  const interval = 3e3;
6375
5750
  const start = Date.now();
@@ -6377,7 +5752,7 @@ async function runAudienceMode(audience, action, args) {
6377
5752
  while (Date.now() - start < maxWait) {
6378
5753
  const status = await apiFetch(`${grantsUrl}/${grant.id}`);
6379
5754
  if (status.status === "approved") {
6380
- consola38.success("Grant approved!");
5755
+ consola36.success("Grant approved!");
6381
5756
  approved = true;
6382
5757
  break;
6383
5758
  }
@@ -6392,15 +5767,15 @@ async function runAudienceMode(audience, action, args) {
6392
5767
  `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.`
6393
5768
  );
6394
5769
  }
6395
- consola38.info("Fetching grant token...");
5770
+ consola36.info("Fetching grant token...");
6396
5771
  const { authz_jwt } = await apiFetch(`${grantsUrl}/${grant.id}/token`, {
6397
5772
  method: "POST"
6398
5773
  });
6399
5774
  if (audience === "escapes") {
6400
- consola38.info(`Executing: ${command.join(" ")}`);
5775
+ consola36.info(`Executing: ${command.join(" ")}`);
6401
5776
  try {
6402
5777
  const { APES_SHELL_WRAPPER: _wrapperMarker, ...inheritedEnv } = process.env;
6403
- execFileSync13(args["escapes-path"] || "escapes", ["--grant", authz_jwt, "--", ...command], {
5778
+ execFileSync11(args["escapes-path"] || "escapes", ["--grant", authz_jwt, "--", ...command], {
6404
5779
  stdio: "inherit",
6405
5780
  env: inheritedEnv
6406
5781
  });
@@ -6415,8 +5790,8 @@ async function runAudienceMode(audience, action, args) {
6415
5790
 
6416
5791
  // src/commands/proxy.ts
6417
5792
  import { spawn as spawn2 } from "child_process";
6418
- import { defineCommand as defineCommand44 } from "citty";
6419
- import consola39 from "consola";
5793
+ import { defineCommand as defineCommand43 } from "citty";
5794
+ import consola37 from "consola";
6420
5795
 
6421
5796
  // src/proxy/config.ts
6422
5797
  function buildDefaultProxyConfigToml(opts) {
@@ -6453,7 +5828,7 @@ import { spawn } from "child_process";
6453
5828
  import { mkdtempSync as mkdtempSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "fs";
6454
5829
  import { createRequire } from "module";
6455
5830
  import { tmpdir as tmpdir3 } from "os";
6456
- import { dirname as dirname5, join as join12, resolve as resolve4 } from "path";
5831
+ import { dirname as dirname4, join as join13, resolve as resolve3 } from "path";
6457
5832
  var require2 = createRequire(import.meta.url);
6458
5833
  function findProxyBin() {
6459
5834
  const pkgPath = require2.resolve("@openape/proxy/package.json");
@@ -6462,11 +5837,11 @@ function findProxyBin() {
6462
5837
  if (!binRel) {
6463
5838
  throw new Error("@openape/proxy is missing the openape-proxy bin entry");
6464
5839
  }
6465
- return resolve4(dirname5(pkgPath), binRel);
5840
+ return resolve3(dirname4(pkgPath), binRel);
6466
5841
  }
6467
5842
  async function startEphemeralProxy(configToml) {
6468
- const tmpDir = mkdtempSync3(join12(tmpdir3(), "openape-proxy-"));
6469
- const configPath = join12(tmpDir, "config.toml");
5843
+ const tmpDir = mkdtempSync3(join13(tmpdir3(), "openape-proxy-"));
5844
+ const configPath = join13(tmpDir, "config.toml");
6470
5845
  writeFileSync8(configPath, configToml, { mode: 384 });
6471
5846
  const binPath = findProxyBin();
6472
5847
  const child = spawn(process.execPath, [binPath, "-c", configPath], {
@@ -6559,10 +5934,10 @@ function resolveProxyConfigOptions() {
6559
5934
  77
6560
5935
  );
6561
5936
  }
6562
- consola39.info(`[apes proxy] IdP-mediated mode \u2014 agent=${auth.email}, idp=${auth.idp}`);
5937
+ consola37.info(`[apes proxy] IdP-mediated mode \u2014 agent=${auth.email}, idp=${auth.idp}`);
6563
5938
  return { agentEmail: auth.email, idpUrl: auth.idp, mediated: true };
6564
5939
  }
6565
- var proxyCommand = defineCommand44({
5940
+ var proxyCommand = defineCommand43({
6566
5941
  meta: {
6567
5942
  name: "proxy",
6568
5943
  description: "Run a command with HTTPS_PROXY routed through the OpenApe egress proxy."
@@ -6584,12 +5959,12 @@ var proxyCommand = defineCommand44({
6584
5959
  let close = null;
6585
5960
  if (reuseUrl) {
6586
5961
  proxyUrl = reuseUrl;
6587
- consola39.info(`[apes proxy] reusing existing proxy at ${proxyUrl}`);
5962
+ consola37.info(`[apes proxy] reusing existing proxy at ${proxyUrl}`);
6588
5963
  } else {
6589
5964
  const ephemeral = await startEphemeralProxy(buildDefaultProxyConfigToml(resolveProxyConfigOptions()));
6590
5965
  proxyUrl = ephemeral.url;
6591
5966
  close = ephemeral.close;
6592
- consola39.info(`[apes proxy] started ephemeral proxy at ${proxyUrl}`);
5967
+ consola37.info(`[apes proxy] started ephemeral proxy at ${proxyUrl}`);
6593
5968
  }
6594
5969
  const noProxy = process.env.NO_PROXY ?? process.env.no_proxy ?? "127.0.0.1,localhost";
6595
5970
  const childEnv = {
@@ -6621,7 +5996,7 @@ var proxyCommand = defineCommand44({
6621
5996
  else resolveExit(code ?? 0);
6622
5997
  });
6623
5998
  child.once("error", (err) => {
6624
- consola39.error(`[apes proxy] failed to spawn '${wrapped[0]}':`, err.message);
5999
+ consola37.error(`[apes proxy] failed to spawn '${wrapped[0]}':`, err.message);
6625
6000
  resolveExit(127);
6626
6001
  });
6627
6002
  });
@@ -6635,8 +6010,8 @@ function signalNumber(signal) {
6635
6010
  }
6636
6011
 
6637
6012
  // src/commands/explain.ts
6638
- import { defineCommand as defineCommand45 } from "citty";
6639
- var explainCommand = defineCommand45({
6013
+ import { defineCommand as defineCommand44 } from "citty";
6014
+ var explainCommand = defineCommand44({
6640
6015
  meta: {
6641
6016
  name: "explain",
6642
6017
  description: "Show what permission a command would need"
@@ -6674,9 +6049,9 @@ var explainCommand = defineCommand45({
6674
6049
  });
6675
6050
 
6676
6051
  // src/commands/config/get.ts
6677
- import { defineCommand as defineCommand46 } from "citty";
6678
- import consola40 from "consola";
6679
- var configGetCommand = defineCommand46({
6052
+ import { defineCommand as defineCommand45 } from "citty";
6053
+ import consola38 from "consola";
6054
+ var configGetCommand = defineCommand45({
6680
6055
  meta: {
6681
6056
  name: "get",
6682
6057
  description: "Get a configuration value"
@@ -6696,7 +6071,7 @@ var configGetCommand = defineCommand46({
6696
6071
  if (idp)
6697
6072
  console.log(idp);
6698
6073
  else
6699
- consola40.info("No IdP configured.");
6074
+ consola38.info("No IdP configured.");
6700
6075
  break;
6701
6076
  }
6702
6077
  case "email": {
@@ -6704,7 +6079,7 @@ var configGetCommand = defineCommand46({
6704
6079
  if (auth?.email)
6705
6080
  console.log(auth.email);
6706
6081
  else
6707
- consola40.info("Not logged in.");
6082
+ consola38.info("Not logged in.");
6708
6083
  break;
6709
6084
  }
6710
6085
  default: {
@@ -6717,7 +6092,7 @@ var configGetCommand = defineCommand46({
6717
6092
  if (sectionObj && field in sectionObj) {
6718
6093
  console.log(sectionObj[field]);
6719
6094
  } else {
6720
- consola40.info(`Key "${key}" not set.`);
6095
+ consola38.info(`Key "${key}" not set.`);
6721
6096
  }
6722
6097
  } else {
6723
6098
  throw new CliError(`Unknown key: "${key}". Use: idp, email, defaults.idp, defaults.approval, agent.key, agent.email`);
@@ -6728,9 +6103,9 @@ var configGetCommand = defineCommand46({
6728
6103
  });
6729
6104
 
6730
6105
  // src/commands/config/set.ts
6731
- import { defineCommand as defineCommand47 } from "citty";
6732
- import consola41 from "consola";
6733
- var configSetCommand = defineCommand47({
6106
+ import { defineCommand as defineCommand46 } from "citty";
6107
+ import consola39 from "consola";
6108
+ var configSetCommand = defineCommand46({
6734
6109
  meta: {
6735
6110
  name: "set",
6736
6111
  description: "Set a configuration value"
@@ -6766,12 +6141,12 @@ var configSetCommand = defineCommand47({
6766
6141
  throw new CliError(`Unknown section: "${section}". Use: defaults, agent`);
6767
6142
  }
6768
6143
  saveConfig(config);
6769
- consola41.success(`Set ${key} = ${value}`);
6144
+ consola39.success(`Set ${key} = ${value}`);
6770
6145
  }
6771
6146
  });
6772
6147
 
6773
6148
  // src/commands/fetch/index.ts
6774
- import { defineCommand as defineCommand48 } from "citty";
6149
+ import { defineCommand as defineCommand47 } from "citty";
6775
6150
  async function doRequest(method, url, body, contentType, raw, showHeaders) {
6776
6151
  const token = getAuthToken();
6777
6152
  if (!token) {
@@ -6807,13 +6182,13 @@ async function doRequest(method, url, body, contentType, raw, showHeaders) {
6807
6182
  throw new CliError(`HTTP ${response.status} ${response.statusText}`);
6808
6183
  }
6809
6184
  }
6810
- var fetchCommand = defineCommand48({
6185
+ var fetchCommand = defineCommand47({
6811
6186
  meta: {
6812
6187
  name: "fetch",
6813
6188
  description: "Make authenticated HTTP requests"
6814
6189
  },
6815
6190
  subCommands: {
6816
- get: defineCommand48({
6191
+ get: defineCommand47({
6817
6192
  meta: {
6818
6193
  name: "get",
6819
6194
  description: "GET request with auth token"
@@ -6839,7 +6214,7 @@ var fetchCommand = defineCommand48({
6839
6214
  await doRequest("GET", String(args.url), void 0, "application/json", Boolean(args.raw), Boolean(args.headers));
6840
6215
  }
6841
6216
  }),
6842
- post: defineCommand48({
6217
+ post: defineCommand47({
6843
6218
  meta: {
6844
6219
  name: "post",
6845
6220
  description: "POST request with auth token"
@@ -6878,8 +6253,8 @@ var fetchCommand = defineCommand48({
6878
6253
  });
6879
6254
 
6880
6255
  // src/commands/mcp/index.ts
6881
- import { defineCommand as defineCommand49 } from "citty";
6882
- var mcpCommand = defineCommand49({
6256
+ import { defineCommand as defineCommand48 } from "citty";
6257
+ var mcpCommand = defineCommand48({
6883
6258
  meta: {
6884
6259
  name: "mcp",
6885
6260
  description: "Start MCP server for AI agents"
@@ -6902,48 +6277,48 @@ var mcpCommand = defineCommand49({
6902
6277
  if (transport !== "stdio" && transport !== "sse") {
6903
6278
  throw new Error('Transport must be "stdio" or "sse"');
6904
6279
  }
6905
- const { startMcpServer } = await import("./server-AZOEKT55.js");
6280
+ const { startMcpServer } = await import("./server-TGGXHP4H.js");
6906
6281
  await startMcpServer(transport, port);
6907
6282
  }
6908
6283
  });
6909
6284
 
6910
6285
  // src/commands/init/index.ts
6911
- import { existsSync as existsSync14, copyFileSync, writeFileSync as writeFileSync9 } from "fs";
6286
+ import { existsSync as existsSync15, copyFileSync, writeFileSync as writeFileSync9 } from "fs";
6912
6287
  import { randomBytes } from "crypto";
6913
- import { execFileSync as execFileSync14 } from "child_process";
6914
- import { join as join13 } from "path";
6915
- import { defineCommand as defineCommand50 } from "citty";
6916
- import consola42 from "consola";
6288
+ import { execFileSync as execFileSync12 } from "child_process";
6289
+ import { join as join14 } from "path";
6290
+ import { defineCommand as defineCommand49 } from "citty";
6291
+ import consola40 from "consola";
6917
6292
  var DEFAULT_IDP_URL = "https://id.openape.at";
6918
6293
  async function downloadTemplate(repo, targetDir) {
6919
6294
  const { downloadTemplate: gigetDownload } = await import("giget");
6920
6295
  await gigetDownload(`gh:${repo}`, { dir: targetDir, force: false });
6921
6296
  }
6922
6297
  function installDeps(dir) {
6923
- const hasLockFile = (name) => existsSync14(join13(dir, name));
6298
+ const hasLockFile = (name) => existsSync15(join14(dir, name));
6924
6299
  if (hasLockFile("pnpm-lock.yaml")) {
6925
- execFileSync14("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
6300
+ execFileSync12("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
6926
6301
  } else if (hasLockFile("bun.lockb")) {
6927
- execFileSync14("bun", ["install"], { cwd: dir, stdio: "inherit" });
6302
+ execFileSync12("bun", ["install"], { cwd: dir, stdio: "inherit" });
6928
6303
  } else {
6929
- execFileSync14("npm", ["install"], { cwd: dir, stdio: "inherit" });
6304
+ execFileSync12("npm", ["install"], { cwd: dir, stdio: "inherit" });
6930
6305
  }
6931
6306
  }
6932
6307
  async function promptChoice(message, choices) {
6933
- const result = await consola42.prompt(message, { type: "select", options: choices });
6308
+ const result = await consola40.prompt(message, { type: "select", options: choices });
6934
6309
  if (typeof result === "symbol") {
6935
6310
  throw new CliExit(0);
6936
6311
  }
6937
6312
  return result;
6938
6313
  }
6939
6314
  async function promptText(message, defaultValue) {
6940
- const result = await consola42.prompt(message, { type: "text", default: defaultValue, placeholder: defaultValue });
6315
+ const result = await consola40.prompt(message, { type: "text", default: defaultValue, placeholder: defaultValue });
6941
6316
  if (typeof result === "symbol") {
6942
6317
  throw new CliExit(0);
6943
6318
  }
6944
6319
  return result || defaultValue || "";
6945
6320
  }
6946
- var initCommand = defineCommand50({
6321
+ var initCommand = defineCommand49({
6947
6322
  meta: {
6948
6323
  name: "init",
6949
6324
  description: "Scaffold a new OpenApe project"
@@ -6985,23 +6360,23 @@ var initCommand = defineCommand50({
6985
6360
  });
6986
6361
  async function initSP(targetDir) {
6987
6362
  const dir = targetDir || "my-app";
6988
- if (existsSync14(join13(dir, "package.json"))) {
6363
+ if (existsSync15(join14(dir, "package.json"))) {
6989
6364
  throw new CliError(`Directory "${dir}" already contains a project.`);
6990
6365
  }
6991
- consola42.start("Scaffolding SP starter...");
6366
+ consola40.start("Scaffolding SP starter...");
6992
6367
  await downloadTemplate("openape-ai/openape-sp-starter", dir);
6993
- consola42.success("Scaffolded from openape-sp-starter");
6994
- consola42.start("Installing dependencies...");
6368
+ consola40.success("Scaffolded from openape-sp-starter");
6369
+ consola40.start("Installing dependencies...");
6995
6370
  installDeps(dir);
6996
- consola42.success("Dependencies installed");
6997
- const envExample = join13(dir, ".env.example");
6998
- const envFile = join13(dir, ".env");
6999
- if (existsSync14(envExample) && !existsSync14(envFile)) {
6371
+ consola40.success("Dependencies installed");
6372
+ const envExample = join14(dir, ".env.example");
6373
+ const envFile = join14(dir, ".env");
6374
+ if (existsSync15(envExample) && !existsSync15(envFile)) {
7000
6375
  copyFileSync(envExample, envFile);
7001
- consola42.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
6376
+ consola40.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
7002
6377
  }
7003
6378
  console.log("");
7004
- consola42.box([
6379
+ consola40.box([
7005
6380
  `cd ${dir}`,
7006
6381
  "npm run dev",
7007
6382
  "",
@@ -7010,7 +6385,7 @@ async function initSP(targetDir) {
7010
6385
  }
7011
6386
  async function initIdP(targetDir) {
7012
6387
  const dir = targetDir || "my-idp";
7013
- if (existsSync14(join13(dir, "package.json"))) {
6388
+ if (existsSync15(join14(dir, "package.json"))) {
7014
6389
  throw new CliError(`Directory "${dir}" already contains a project.`);
7015
6390
  }
7016
6391
  const domain = await promptText("Domain for the IdP", "localhost");
@@ -7020,15 +6395,15 @@ async function initIdP(targetDir) {
7020
6395
  "s3 (S3-compatible)"
7021
6396
  ]);
7022
6397
  const adminEmail = await promptText("Admin email");
7023
- consola42.start("Scaffolding IdP starter...");
6398
+ consola40.start("Scaffolding IdP starter...");
7024
6399
  await downloadTemplate("openape-ai/openape-idp-starter", dir);
7025
- consola42.success("Scaffolded from openape-idp-starter");
7026
- consola42.start("Installing dependencies...");
6400
+ consola40.success("Scaffolded from openape-idp-starter");
6401
+ consola40.start("Installing dependencies...");
7027
6402
  installDeps(dir);
7028
- consola42.success("Dependencies installed");
6403
+ consola40.success("Dependencies installed");
7029
6404
  const sessionSecret = randomBytes(32).toString("hex");
7030
6405
  const managementToken = randomBytes(32).toString("hex");
7031
- consola42.success("Secrets generated");
6406
+ consola40.success("Secrets generated");
7032
6407
  const isLocalhost = domain === "localhost";
7033
6408
  const origin = isLocalhost ? "http://localhost:3000" : `https://${domain}`;
7034
6409
  const envContent = [
@@ -7042,11 +6417,11 @@ async function initIdP(targetDir) {
7042
6417
  `NUXT_OPENAPE_RP_ID=${domain}`,
7043
6418
  `NUXT_OPENAPE_RP_ORIGIN=${origin}`
7044
6419
  ].join("\n");
7045
- writeFileSync9(join13(dir, ".env"), `${envContent}
6420
+ writeFileSync9(join14(dir, ".env"), `${envContent}
7046
6421
  `, { mode: 384 });
7047
- consola42.success(".env created");
6422
+ consola40.success(".env created");
7048
6423
  console.log("");
7049
- consola42.box([
6424
+ consola40.box([
7050
6425
  `cd ${dir}`,
7051
6426
  "npm run dev",
7052
6427
  "",
@@ -7063,11 +6438,11 @@ async function initIdP(targetDir) {
7063
6438
 
7064
6439
  // src/commands/enroll.ts
7065
6440
  import { Buffer as Buffer5 } from "buffer";
7066
- import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
6441
+ import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
7067
6442
  import { execFile as execFile2 } from "child_process";
7068
6443
  import { sign as sign2 } from "crypto";
7069
- import { defineCommand as defineCommand51 } from "citty";
7070
- import consola43 from "consola";
6444
+ import { defineCommand as defineCommand50 } from "citty";
6445
+ import consola41 from "consola";
7071
6446
  var DEFAULT_IDP_URL2 = "https://id.openape.at";
7072
6447
  var DEFAULT_KEY_PATH = "~/.ssh/id_ed25519";
7073
6448
  var POLL_INTERVAL = 3e3;
@@ -7106,11 +6481,11 @@ async function pollForEnrollment(idp, agentEmail, keyPath) {
7106
6481
  }
7107
6482
  } catch {
7108
6483
  }
7109
- await new Promise((resolve5) => setTimeout(resolve5, POLL_INTERVAL));
6484
+ await new Promise((resolve4) => setTimeout(resolve4, POLL_INTERVAL));
7110
6485
  }
7111
6486
  throw new Error("Enrollment timed out. Please check the browser and try again.");
7112
6487
  }
7113
- var enrollCommand = defineCommand51({
6488
+ var enrollCommand = defineCommand50({
7114
6489
  meta: {
7115
6490
  name: "enroll",
7116
6491
  description: "Enroll an agent with an Identity Provider"
@@ -7130,38 +6505,38 @@ var enrollCommand = defineCommand51({
7130
6505
  }
7131
6506
  },
7132
6507
  async run({ args }) {
7133
- const idp = args.idp || await consola43.prompt("IdP URL", { type: "text", default: DEFAULT_IDP_URL2, placeholder: DEFAULT_IDP_URL2 }).then((r3) => {
6508
+ const idp = args.idp || await consola41.prompt("IdP URL", { type: "text", default: DEFAULT_IDP_URL2, placeholder: DEFAULT_IDP_URL2 }).then((r3) => {
7134
6509
  if (typeof r3 === "symbol") throw new CliExit(0);
7135
6510
  return r3;
7136
6511
  }) || DEFAULT_IDP_URL2;
7137
- const agentName = args.name || await consola43.prompt("Agent name", { type: "text", placeholder: "deploy-bot" }).then((r3) => {
6512
+ const agentName = args.name || await consola41.prompt("Agent name", { type: "text", placeholder: "deploy-bot" }).then((r3) => {
7138
6513
  if (typeof r3 === "symbol") throw new CliExit(0);
7139
6514
  return r3;
7140
6515
  });
7141
6516
  if (!agentName) {
7142
6517
  throw new CliError("Agent name is required.");
7143
6518
  }
7144
- const keyPath = args.key || await consola43.prompt("Ed25519 key", { type: "text", default: DEFAULT_KEY_PATH, placeholder: DEFAULT_KEY_PATH }).then((r3) => {
6519
+ const keyPath = args.key || await consola41.prompt("Ed25519 key", { type: "text", default: DEFAULT_KEY_PATH, placeholder: DEFAULT_KEY_PATH }).then((r3) => {
7145
6520
  if (typeof r3 === "symbol") throw new CliExit(0);
7146
6521
  return r3;
7147
6522
  }) || DEFAULT_KEY_PATH;
7148
6523
  const resolvedKey = resolveKeyPath(keyPath);
7149
6524
  let publicKey;
7150
- if (existsSync15(resolvedKey)) {
6525
+ if (existsSync16(resolvedKey)) {
7151
6526
  publicKey = readPublicKey(resolvedKey);
7152
- consola43.success(`Using existing key ${keyPath}`);
6527
+ consola41.success(`Using existing key ${keyPath}`);
7153
6528
  } else {
7154
- consola43.start(`Generating Ed25519 key pair at ${keyPath}...`);
6529
+ consola41.start(`Generating Ed25519 key pair at ${keyPath}...`);
7155
6530
  publicKey = generateAndSaveKey(keyPath);
7156
- consola43.success(`Key pair generated at ${keyPath}`);
6531
+ consola41.success(`Key pair generated at ${keyPath}`);
7157
6532
  }
7158
6533
  const encodedKey = encodeURIComponent(publicKey);
7159
6534
  const enrollUrl = `${idp}/enroll?name=${encodeURIComponent(agentName)}&key=${encodedKey}`;
7160
- consola43.info("Opening browser for enrollment...");
7161
- consola43.info(`\u2192 ${idp}/enroll`);
6535
+ consola41.info("Opening browser for enrollment...");
6536
+ consola41.info(`\u2192 ${idp}/enroll`);
7162
6537
  openBrowser2(enrollUrl);
7163
6538
  console.log("");
7164
- const agentEmail = await consola43.prompt(
6539
+ const agentEmail = await consola41.prompt(
7165
6540
  "Agent email (shown in browser after enrollment)",
7166
6541
  { type: "text", placeholder: `agent+${agentName}@...` }
7167
6542
  ).then((r3) => {
@@ -7171,7 +6546,7 @@ var enrollCommand = defineCommand51({
7171
6546
  if (!agentEmail) {
7172
6547
  throw new CliError("Agent email is required to verify enrollment.");
7173
6548
  }
7174
- consola43.start("Verifying enrollment...");
6549
+ consola41.start("Verifying enrollment...");
7175
6550
  const { token, expiresIn } = await pollForEnrollment(idp, agentEmail, keyPath);
7176
6551
  saveAuth({
7177
6552
  idp,
@@ -7183,18 +6558,18 @@ var enrollCommand = defineCommand51({
7183
6558
  config.defaults = { ...config.defaults, idp };
7184
6559
  config.agent = { key: keyPath, email: agentEmail };
7185
6560
  saveConfig(config);
7186
- consola43.success(`Agent enrolled as ${agentEmail}`);
7187
- consola43.success("Config saved to ~/.config/apes/");
6561
+ consola41.success(`Agent enrolled as ${agentEmail}`);
6562
+ consola41.success("Config saved to ~/.config/apes/");
7188
6563
  console.log("");
7189
- consola43.info("Verify with: apes whoami");
6564
+ consola41.info("Verify with: apes whoami");
7190
6565
  }
7191
6566
  });
7192
6567
 
7193
6568
  // src/commands/register-user.ts
7194
- import { existsSync as existsSync16, readFileSync as readFileSync13 } from "fs";
7195
- import { defineCommand as defineCommand52 } from "citty";
7196
- import consola44 from "consola";
7197
- var registerUserCommand = defineCommand52({
6569
+ import { existsSync as existsSync17, readFileSync as readFileSync13 } from "fs";
6570
+ import { defineCommand as defineCommand51 } from "citty";
6571
+ import consola42 from "consola";
6572
+ var registerUserCommand = defineCommand51({
7198
6573
  meta: {
7199
6574
  name: "register-user",
7200
6575
  description: "Register a sub-user with SSH key"
@@ -7230,7 +6605,7 @@ var registerUserCommand = defineCommand52({
7230
6605
  throw new CliError("No IdP URL configured. Run `apes login` first.");
7231
6606
  }
7232
6607
  let publicKey = args.key;
7233
- if (existsSync16(args.key)) {
6608
+ if (existsSync17(args.key)) {
7234
6609
  publicKey = readFileSync13(args.key, "utf-8").trim();
7235
6610
  }
7236
6611
  if (!publicKey.startsWith("ssh-ed25519 ")) {
@@ -7249,18 +6624,18 @@ var registerUserCommand = defineCommand52({
7249
6624
  ...userType ? { type: userType } : {}
7250
6625
  }
7251
6626
  });
7252
- consola44.success(`User registered: ${result.email} (type: ${result.type}, owner: ${result.owner})`);
6627
+ consola42.success(`User registered: ${result.email} (type: ${result.type}, owner: ${result.owner})`);
7253
6628
  }
7254
6629
  });
7255
6630
 
7256
6631
  // src/commands/utils/index.ts
7257
- import { defineCommand as defineCommand54 } from "citty";
6632
+ import { defineCommand as defineCommand53 } from "citty";
7258
6633
 
7259
6634
  // src/commands/utils/dig.ts
7260
- import { defineCommand as defineCommand53 } from "citty";
7261
- import consola45 from "consola";
6635
+ import { defineCommand as defineCommand52 } from "citty";
6636
+ import consola43 from "consola";
7262
6637
  import { resolveDDISA as resolveDDISA2 } from "@openape/core";
7263
- var digCommand = defineCommand53({
6638
+ var digCommand = defineCommand52({
7264
6639
  meta: {
7265
6640
  name: "dig",
7266
6641
  description: "Resolve DDISA IdP for a domain or email (admin/diag tool)"
@@ -7333,12 +6708,12 @@ var digCommand = defineCommand53({
7333
6708
  console.log(` domain: ${domain}`);
7334
6709
  console.log("");
7335
6710
  if (!result.ddisa.found) {
7336
- consola45.warn(`No DDISA record at _ddisa.${domain}`);
6711
+ consola43.warn(`No DDISA record at _ddisa.${domain}`);
7337
6712
  if (result.hint) console.log(`
7338
6713
  ${result.hint}`);
7339
6714
  throw new CliError(`No DDISA record found for ${domain}`);
7340
6715
  }
7341
- consola45.success(`_ddisa.${domain} \u2192 ${result.ddisa.idp}`);
6716
+ consola43.success(`_ddisa.${domain} \u2192 ${result.ddisa.idp}`);
7342
6717
  console.log(` Version: ${result.ddisa.version || "ddisa1"}`);
7343
6718
  console.log(` IdP URL: ${result.ddisa.idp}`);
7344
6719
  if (result.ddisa.mode) console.log(` Mode: ${result.ddisa.mode}`);
@@ -7348,13 +6723,13 @@ ${result.hint}`);
7348
6723
  return;
7349
6724
  }
7350
6725
  if (result.idpDiscovery.ok) {
7351
- consola45.success(`IdP reachable (${result.idpDiscovery.status ?? 200})`);
6726
+ consola43.success(`IdP reachable (${result.idpDiscovery.status ?? 200})`);
7352
6727
  if (result.idpDiscovery.issuer) console.log(` Issuer: ${result.idpDiscovery.issuer}`);
7353
6728
  if (result.idpDiscovery.ddisaVersion) console.log(` DDISA: v${result.idpDiscovery.ddisaVersion}`);
7354
6729
  if (result.idpDiscovery.authMethods?.length) console.log(` Auth: ${result.idpDiscovery.authMethods.join(", ")}`);
7355
6730
  if (result.idpDiscovery.grantTypes?.length) console.log(` Grants: ${result.idpDiscovery.grantTypes.join(", ")}`);
7356
6731
  } else {
7357
- consola45.warn(`IdP discovery failed${result.idpDiscovery.status ? ` (HTTP ${result.idpDiscovery.status})` : ""}`);
6732
+ consola43.warn(`IdP discovery failed${result.idpDiscovery.status ? ` (HTTP ${result.idpDiscovery.status})` : ""}`);
7358
6733
  if (result.hint) console.log(`
7359
6734
  ${result.hint}`);
7360
6735
  throw new CliError(`IdP at ${result.ddisa.idp} not reachable`);
@@ -7363,7 +6738,7 @@ ${result.hint}`);
7363
6738
  });
7364
6739
 
7365
6740
  // src/commands/utils/index.ts
7366
- var utilsCommand = defineCommand54({
6741
+ var utilsCommand = defineCommand53({
7367
6742
  meta: {
7368
6743
  name: "utils",
7369
6744
  description: "Admin/diagnostic utilities (dig, \u2026)"
@@ -7374,12 +6749,12 @@ var utilsCommand = defineCommand54({
7374
6749
  });
7375
6750
 
7376
6751
  // src/commands/sessions/index.ts
7377
- import { defineCommand as defineCommand57 } from "citty";
6752
+ import { defineCommand as defineCommand56 } from "citty";
7378
6753
 
7379
6754
  // src/commands/sessions/list.ts
7380
- import { defineCommand as defineCommand55 } from "citty";
7381
- import consola46 from "consola";
7382
- var sessionsListCommand = defineCommand55({
6755
+ import { defineCommand as defineCommand54 } from "citty";
6756
+ import consola44 from "consola";
6757
+ var sessionsListCommand = defineCommand54({
7383
6758
  meta: {
7384
6759
  name: "list",
7385
6760
  description: "List your active refresh-token families (one per logged-in device)."
@@ -7397,7 +6772,7 @@ var sessionsListCommand = defineCommand55({
7397
6772
  return;
7398
6773
  }
7399
6774
  if (result.data.length === 0) {
7400
- consola46.info("No active sessions.");
6775
+ consola44.info("No active sessions.");
7401
6776
  return;
7402
6777
  }
7403
6778
  for (const f of result.data) {
@@ -7409,9 +6784,9 @@ var sessionsListCommand = defineCommand55({
7409
6784
  });
7410
6785
 
7411
6786
  // src/commands/sessions/remove.ts
7412
- import { defineCommand as defineCommand56 } from "citty";
7413
- import consola47 from "consola";
7414
- var sessionsRemoveCommand = defineCommand56({
6787
+ import { defineCommand as defineCommand55 } from "citty";
6788
+ import consola45 from "consola";
6789
+ var sessionsRemoveCommand = defineCommand55({
7415
6790
  meta: {
7416
6791
  name: "remove",
7417
6792
  description: "Revoke one of your active refresh-token families by id."
@@ -7427,12 +6802,12 @@ var sessionsRemoveCommand = defineCommand56({
7427
6802
  const id = String(args.familyId).trim();
7428
6803
  if (!id) throw new CliError("familyId required");
7429
6804
  await apiFetch(`/api/me/sessions/${encodeURIComponent(id)}`, { method: "DELETE" });
7430
- consola47.success(`Session ${id} revoked. The device using it will need to \`apes login\` again on its next refresh.`);
6805
+ consola45.success(`Session ${id} revoked. The device using it will need to \`apes login\` again on its next refresh.`);
7431
6806
  }
7432
6807
  });
7433
6808
 
7434
6809
  // src/commands/sessions/index.ts
7435
- var sessionsCommand = defineCommand57({
6810
+ var sessionsCommand = defineCommand56({
7436
6811
  meta: {
7437
6812
  name: "sessions",
7438
6813
  description: "Manage your active refresh-token sessions across devices"
@@ -7444,10 +6819,10 @@ var sessionsCommand = defineCommand57({
7444
6819
  });
7445
6820
 
7446
6821
  // src/commands/dns-check.ts
7447
- import { defineCommand as defineCommand58 } from "citty";
7448
- import consola48 from "consola";
6822
+ import { defineCommand as defineCommand57 } from "citty";
6823
+ import consola46 from "consola";
7449
6824
  import { resolveDDISA as resolveDDISA3 } from "@openape/core";
7450
- var dnsCheckCommand = defineCommand58({
6825
+ var dnsCheckCommand = defineCommand57({
7451
6826
  meta: {
7452
6827
  name: "dns-check",
7453
6828
  description: "Validate DDISA DNS TXT records for a domain"
@@ -7461,7 +6836,7 @@ var dnsCheckCommand = defineCommand58({
7461
6836
  },
7462
6837
  async run({ args }) {
7463
6838
  const domain = args.domain;
7464
- consola48.start(`Checking _ddisa.${domain}...`);
6839
+ consola46.start(`Checking _ddisa.${domain}...`);
7465
6840
  try {
7466
6841
  const result = await resolveDDISA3(domain);
7467
6842
  if (!result) {
@@ -7470,7 +6845,7 @@ var dnsCheckCommand = defineCommand58({
7470
6845
  console.log(` _ddisa.${domain} TXT "v=ddisa1 idp=https://id.${domain}"`);
7471
6846
  throw new CliError(`No DDISA record found for ${domain}`);
7472
6847
  }
7473
- consola48.success(`_ddisa.${domain} \u2192 ${result.idp}`);
6848
+ consola46.success(`_ddisa.${domain} \u2192 ${result.idp}`);
7474
6849
  console.log("");
7475
6850
  console.log(` Version: ${result.version || "ddisa1"}`);
7476
6851
  console.log(` IdP URL: ${result.idp}`);
@@ -7479,14 +6854,14 @@ var dnsCheckCommand = defineCommand58({
7479
6854
  if (result.priority !== void 0)
7480
6855
  console.log(` Priority: ${result.priority}`);
7481
6856
  console.log("");
7482
- consola48.start(`Verifying IdP at ${result.idp}...`);
6857
+ consola46.start(`Verifying IdP at ${result.idp}...`);
7483
6858
  const discoResp = await fetch(`${result.idp}/.well-known/openid-configuration`);
7484
6859
  if (!discoResp.ok) {
7485
- consola48.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
6860
+ consola46.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
7486
6861
  return;
7487
6862
  }
7488
6863
  const disco = await discoResp.json();
7489
- consola48.success(`IdP is reachable`);
6864
+ consola46.success(`IdP is reachable`);
7490
6865
  console.log(` Issuer: ${disco.issuer}`);
7491
6866
  console.log(` DDISA: v${disco.ddisa_version || "?"}`);
7492
6867
  if (disco.ddisa_auth_methods_supported) {
@@ -7504,7 +6879,7 @@ var dnsCheckCommand = defineCommand58({
7504
6879
  // src/commands/health.ts
7505
6880
  import { exec } from "child_process";
7506
6881
  import { promisify } from "util";
7507
- import { defineCommand as defineCommand59 } from "citty";
6882
+ import { defineCommand as defineCommand58 } from "citty";
7508
6883
  var execAsync = promisify(exec);
7509
6884
  async function resolveApeShellPath() {
7510
6885
  try {
@@ -7540,7 +6915,7 @@ async function bestEffortGrantCount(idp) {
7540
6915
  }
7541
6916
  }
7542
6917
  async function runHealth(args) {
7543
- const version = true ? "1.10.0" : "0.0.0";
6918
+ const version = true ? "1.12.0" : "0.0.0";
7544
6919
  const auth = loadAuth();
7545
6920
  if (!auth) {
7546
6921
  throw new CliError("Not logged in. Run `apes login` first.", 1);
@@ -7603,7 +6978,7 @@ async function runHealth(args) {
7603
6978
  throw new CliError(`IdP ${auth.idp} unreachable: ${idpProbe.error}`, 1);
7604
6979
  }
7605
6980
  }
7606
- var healthCommand = defineCommand59({
6981
+ var healthCommand = defineCommand58({
7607
6982
  meta: {
7608
6983
  name: "health",
7609
6984
  description: "Report CLI diagnostic state (auth, IdP, grants, binaries)"
@@ -7621,8 +6996,8 @@ var healthCommand = defineCommand59({
7621
6996
  });
7622
6997
 
7623
6998
  // src/commands/workflows.ts
7624
- import { defineCommand as defineCommand60 } from "citty";
7625
- import consola49 from "consola";
6999
+ import { defineCommand as defineCommand59 } from "citty";
7000
+ import consola47 from "consola";
7626
7001
 
7627
7002
  // src/guides/index.ts
7628
7003
  var guides = [
@@ -7672,7 +7047,7 @@ var guides = [
7672
7047
  ];
7673
7048
 
7674
7049
  // src/commands/workflows.ts
7675
- var workflowsCommand = defineCommand60({
7050
+ var workflowsCommand = defineCommand59({
7676
7051
  meta: {
7677
7052
  name: "workflows",
7678
7053
  description: "Discover workflow guides"
@@ -7693,7 +7068,7 @@ var workflowsCommand = defineCommand60({
7693
7068
  if (args.id) {
7694
7069
  const guide = guides.find((g) => g.id === String(args.id));
7695
7070
  if (!guide) {
7696
- consola49.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
7071
+ consola47.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
7697
7072
  throw new CliError(`Guide not found: ${args.id}`);
7698
7073
  }
7699
7074
  if (args.json) {
@@ -7733,15 +7108,15 @@ var workflowsCommand = defineCommand60({
7733
7108
  });
7734
7109
 
7735
7110
  // src/version-check.ts
7736
- import { existsSync as existsSync17, mkdirSync as mkdirSync6, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "fs";
7111
+ import { existsSync as existsSync18, mkdirSync as mkdirSync6, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "fs";
7737
7112
  import { homedir as homedir13 } from "os";
7738
- import { join as join14 } from "path";
7739
- import consola50 from "consola";
7113
+ import { join as join15 } from "path";
7114
+ import consola48 from "consola";
7740
7115
  var PACKAGE_NAME = "@openape/apes";
7741
7116
  var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
7742
- var CACHE_FILE = join14(homedir13(), ".config", "apes", ".version-check.json");
7117
+ var CACHE_FILE = join15(homedir13(), ".config", "apes", ".version-check.json");
7743
7118
  function readCache() {
7744
- if (!existsSync17(CACHE_FILE)) return null;
7119
+ if (!existsSync18(CACHE_FILE)) return null;
7745
7120
  try {
7746
7121
  return JSON.parse(readFileSync14(CACHE_FILE, "utf-8"));
7747
7122
  } catch {
@@ -7750,8 +7125,8 @@ function readCache() {
7750
7125
  }
7751
7126
  function writeCache(entry) {
7752
7127
  try {
7753
- const dir = join14(homedir13(), ".config", "apes");
7754
- if (!existsSync17(dir)) mkdirSync6(dir, { recursive: true, mode: 448 });
7128
+ const dir = join15(homedir13(), ".config", "apes");
7129
+ if (!existsSync18(dir)) mkdirSync6(dir, { recursive: true, mode: 448 });
7755
7130
  writeFileSync10(CACHE_FILE, JSON.stringify(entry), { mode: 384 });
7756
7131
  } catch {
7757
7132
  }
@@ -7781,7 +7156,7 @@ async function fetchLatestVersion() {
7781
7156
  }
7782
7157
  function warnIfBehind(currentVersion, latest) {
7783
7158
  if (compareSemver(currentVersion, latest) < 0) {
7784
- consola50.warn(
7159
+ consola48.warn(
7785
7160
  `apes ${currentVersion} is behind latest @openape/apes@${latest}. Run \`npm i -g @openape/apes@latest\` to update. (Suppress with APES_NO_UPDATE_CHECK=1.)`
7786
7161
  );
7787
7162
  }
@@ -7813,10 +7188,10 @@ if (shellRewrite) {
7813
7188
  if (shellRewrite.action === "rewrite") {
7814
7189
  process.argv = shellRewrite.argv;
7815
7190
  } else if (shellRewrite.action === "version") {
7816
- console.log(`ape-shell ${"1.10.0"} (OpenApe DDISA shell wrapper)`);
7191
+ console.log(`ape-shell ${"1.12.0"} (OpenApe DDISA shell wrapper)`);
7817
7192
  process.exit(0);
7818
7193
  } else if (shellRewrite.action === "help") {
7819
- console.log(`ape-shell ${"1.10.0"} \u2014 OpenApe DDISA shell wrapper`);
7194
+ console.log(`ape-shell ${"1.12.0"} \u2014 OpenApe DDISA shell wrapper`);
7820
7195
  console.log("");
7821
7196
  console.log("Usage:");
7822
7197
  console.log(" ape-shell Start interactive grant-mediated REPL");
@@ -7840,7 +7215,7 @@ if (shellRewrite) {
7840
7215
  }
7841
7216
  }
7842
7217
  var debug = process.argv.includes("--debug");
7843
- var grantsCommand = defineCommand61({
7218
+ var grantsCommand = defineCommand60({
7844
7219
  meta: {
7845
7220
  name: "grants",
7846
7221
  description: "Grant management"
@@ -7861,7 +7236,7 @@ var grantsCommand = defineCommand61({
7861
7236
  "delegation-revoke": delegationRevokeCommand
7862
7237
  }
7863
7238
  });
7864
- var configCommand = defineCommand61({
7239
+ var configCommand = defineCommand60({
7865
7240
  meta: {
7866
7241
  name: "config",
7867
7242
  description: "Configuration management"
@@ -7871,10 +7246,10 @@ var configCommand = defineCommand61({
7871
7246
  set: configSetCommand
7872
7247
  }
7873
7248
  });
7874
- var main = defineCommand61({
7249
+ var main = defineCommand60({
7875
7250
  meta: {
7876
7251
  name: "apes",
7877
- version: "1.10.0",
7252
+ version: "1.12.0",
7878
7253
  description: "Unified CLI for OpenApe"
7879
7254
  },
7880
7255
  subCommands: {
@@ -7931,20 +7306,20 @@ async function maybeRefreshAuth() {
7931
7306
  }
7932
7307
  }
7933
7308
  await maybeRefreshAuth();
7934
- await maybeWarnStaleVersion("1.10.0").catch(() => {
7309
+ await maybeWarnStaleVersion("1.12.0").catch(() => {
7935
7310
  });
7936
7311
  runMain(main).catch((err) => {
7937
7312
  if (err instanceof CliExit) {
7938
7313
  process.exit(err.exitCode);
7939
7314
  }
7940
7315
  if (err instanceof CliError) {
7941
- consola51.error(err.message);
7316
+ consola49.error(err.message);
7942
7317
  process.exit(err.exitCode);
7943
7318
  }
7944
7319
  if (debug) {
7945
- consola51.error(err);
7320
+ consola49.error(err);
7946
7321
  } else {
7947
- consola51.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
7322
+ consola49.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
7948
7323
  }
7949
7324
  process.exit(1);
7950
7325
  });