@openape/apes 1.10.0 → 1.11.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
@@ -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);
@@ -390,7 +393,7 @@ async function loginWithPKCE(idp) {
390
393
  consola2.success(`Logged in as ${payload.email || payload.sub}`);
391
394
  }
392
395
  async function loginWithKey(idp, keyPath, agentEmail) {
393
- const { readFileSync: readFileSync15 } = await import("fs");
396
+ const { readFileSync: readFileSync14 } = await import("fs");
394
397
  const { sign: sign3 } = await import("crypto");
395
398
  const { loadEd25519PrivateKey: loadEd25519PrivateKey2 } = await import("./ssh-key-6X3YZXSD.js");
396
399
  const challengeUrl = await getAgentChallengeEndpoint(idp);
@@ -403,7 +406,7 @@ async function loginWithKey(idp, keyPath, agentEmail) {
403
406
  throw new CliError(`Challenge failed: ${await challengeResp.text()}`);
404
407
  }
405
408
  const { challenge } = await challengeResp.json();
406
- const keyContent = readFileSync15(keyPath, "utf-8");
409
+ const keyContent = readFileSync14(keyPath, "utf-8");
407
410
  const privateKey = loadEd25519PrivateKey2(keyContent);
408
411
  const signature = sign3(null, Buffer2.from(challenge), privateKey).toString("base64");
409
412
  const authenticateUrl = await getAgentAuthenticateEndpoint(idp);
@@ -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,
@@ -2992,7 +2995,7 @@ function readPasswordSilent(prompt) {
2992
2995
  "No TTY available for the silent password prompt. Set APES_ADMIN_PASSWORD in the environment instead."
2993
2996
  ));
2994
2997
  }
2995
- return new Promise((resolve5, reject) => {
2998
+ return new Promise((resolve4, reject) => {
2996
2999
  process.stdout.write(prompt);
2997
3000
  const wasRaw = process.stdin.isRaw ?? false;
2998
3001
  process.stdin.setRawMode(true);
@@ -3007,7 +3010,7 @@ function readPasswordSilent(prompt) {
3007
3010
  if (ch === "\r" || ch === "\n") {
3008
3011
  cleanup();
3009
3012
  process.stdout.write("\n");
3010
- resolve5(buf);
3013
+ resolve4(buf);
3011
3014
  return;
3012
3015
  }
3013
3016
  if (code === 3) {
@@ -3303,481 +3306,12 @@ var registerAgentCommand = defineCommand23({
3303
3306
  });
3304
3307
 
3305
3308
  // src/commands/agents/run.ts
3306
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
3307
- import { homedir as homedir5 } from "os";
3309
+ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
3310
+ import { homedir as homedir4 } from "os";
3308
3311
  import { join as join3 } from "path";
3309
3312
  import { defineCommand as defineCommand24 } from "citty";
3310
3313
  import consola22 from "consola";
3311
3314
 
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
3315
  // src/lib/troop-client.ts
3782
3316
  var DEFAULT_TROOP_URL = "https://troop.openape.ai";
3783
3317
  var TroopClient = class {
@@ -3836,13 +3370,13 @@ function resolveTroopUrl(override) {
3836
3370
  }
3837
3371
 
3838
3372
  // 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");
3373
+ var AUTH_PATH = join3(homedir4(), ".config", "apes", "auth.json");
3374
+ var TASK_CACHE_DIR = join3(homedir4(), ".openape", "agent", "tasks");
3841
3375
  function readAuth() {
3842
3376
  if (!existsSync5(AUTH_PATH)) {
3843
3377
  throw new CliError(`No agent auth found at ${AUTH_PATH}. Run \`apes agents spawn <name>\` first.`);
3844
3378
  }
3845
- const parsed = JSON.parse(readFileSync5(AUTH_PATH, "utf8"));
3379
+ const parsed = JSON.parse(readFileSync4(AUTH_PATH, "utf8"));
3846
3380
  if (!parsed.access_token) throw new CliError("auth.json missing access_token");
3847
3381
  return parsed;
3848
3382
  }
@@ -3882,22 +3416,22 @@ function readTaskSpec(taskId) {
3882
3416
  if (!existsSync5(path2)) {
3883
3417
  throw new CliError(`No cached task spec at ${path2}. Run \`apes agents sync\` first to pull the task list from troop.`);
3884
3418
  }
3885
- return JSON.parse(readFileSync5(path2, "utf8"));
3419
+ return JSON.parse(readFileSync4(path2, "utf8"));
3886
3420
  }
3887
- var AGENT_CONFIG_PATH = join3(homedir5(), ".openape", "agent", "agent.json");
3421
+ var AGENT_CONFIG_PATH = join3(homedir4(), ".openape", "agent", "agent.json");
3888
3422
  function readAgentConfig() {
3889
3423
  if (!existsSync5(AGENT_CONFIG_PATH)) return { systemPrompt: "" };
3890
3424
  try {
3891
- return JSON.parse(readFileSync5(AGENT_CONFIG_PATH, "utf8"));
3425
+ return JSON.parse(readFileSync4(AGENT_CONFIG_PATH, "utf8"));
3892
3426
  } catch {
3893
3427
  return { systemPrompt: "" };
3894
3428
  }
3895
3429
  }
3896
3430
  function readLitellmConfig(model) {
3897
- const envPath = join3(homedir5(), "litellm", ".env");
3431
+ const envPath = join3(homedir4(), "litellm", ".env");
3898
3432
  const env = {};
3899
3433
  if (existsSync5(envPath)) {
3900
- for (const line of readFileSync5(envPath, "utf8").split(/\r?\n/)) {
3434
+ for (const line of readFileSync4(envPath, "utf8").split(/\r?\n/)) {
3901
3435
  const m = line.match(/^([A-Z_]+)=(.*)$/);
3902
3436
  if (m) env[m[1]] = m[2].replace(/^["']|["']$/g, "");
3903
3437
  }
@@ -4002,17 +3536,17 @@ var runAgentCommand = defineCommand24({
4002
3536
  });
4003
3537
 
4004
3538
  // src/commands/agents/serve.ts
4005
- import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
4006
- import { homedir as homedir6 } from "os";
3539
+ import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
3540
+ import { homedir as homedir5 } from "os";
4007
3541
  import { join as join4 } from "path";
4008
3542
  import { createInterface } from "readline";
4009
3543
  import { defineCommand as defineCommand25 } from "citty";
4010
- var AUTH_PATH2 = join4(homedir6(), ".config", "apes", "auth.json");
3544
+ var AUTH_PATH2 = join4(homedir5(), ".config", "apes", "auth.json");
4011
3545
  function readLitellmConfig2(model) {
4012
- const envPath = join4(homedir6(), "litellm", ".env");
3546
+ const envPath = join4(homedir5(), "litellm", ".env");
4013
3547
  const env = {};
4014
3548
  if (existsSync6(envPath)) {
4015
- for (const line of readFileSync6(envPath, "utf8").split(/\r?\n/)) {
3549
+ for (const line of readFileSync5(envPath, "utf8").split(/\r?\n/)) {
4016
3550
  const m = line.match(/^([A-Z_]+)=(.*)$/);
4017
3551
  if (m) env[m[1]] = m[2].replace(/^["']|["']$/g, "");
4018
3552
  }
@@ -4046,7 +3580,7 @@ var serveAgentCommand = defineCommand25({
4046
3580
  }
4047
3581
  if (existsSync6(AUTH_PATH2)) {
4048
3582
  try {
4049
- JSON.parse(readFileSync6(AUTH_PATH2, "utf8"));
3583
+ JSON.parse(readFileSync5(AUTH_PATH2, "utf8"));
4050
3584
  } catch {
4051
3585
  }
4052
3586
  }
@@ -4121,8 +3655,8 @@ async function handleInbound(msg, sessions) {
4121
3655
  }
4122
3656
 
4123
3657
  // 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";
3658
+ import { execFileSync as execFileSync6 } from "child_process";
3659
+ import { mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
4126
3660
  import { tmpdir as tmpdir2 } from "os";
4127
3661
  import { join as join6 } from "path";
4128
3662
  import { defineCommand as defineCommand26 } from "citty";
@@ -4182,12 +3716,12 @@ ${envBlock} <key>StartInterval</key>
4182
3716
 
4183
3717
  // src/lib/keygen.ts
4184
3718
  import { Buffer as Buffer4 } from "buffer";
4185
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
3719
+ import { existsSync as existsSync7, mkdirSync, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "fs";
4186
3720
  import { generateKeyPairSync } from "crypto";
4187
- import { homedir as homedir7 } from "os";
4188
- import { dirname as dirname2, resolve as resolve3 } from "path";
3721
+ import { homedir as homedir6 } from "os";
3722
+ import { dirname, resolve as resolve2 } from "path";
4189
3723
  function resolveKeyPath(p2) {
4190
- return resolve3(p2.replace(/^~/, homedir7()));
3724
+ return resolve2(p2.replace(/^~/, homedir6()));
4191
3725
  }
4192
3726
  function buildSshEd25519Line(rawPub) {
4193
3727
  const keyTypeStr = "ssh-ed25519";
@@ -4201,9 +3735,9 @@ function buildSshEd25519Line(rawPub) {
4201
3735
  function readPublicKey(keyPath) {
4202
3736
  const pubPath = `${keyPath}.pub`;
4203
3737
  if (existsSync7(pubPath)) {
4204
- return readFileSync7(pubPath, "utf-8").trim();
3738
+ return readFileSync6(pubPath, "utf-8").trim();
4205
3739
  }
4206
- const keyContent = readFileSync7(keyPath, "utf-8");
3740
+ const keyContent = readFileSync6(keyPath, "utf-8");
4207
3741
  const privateKey = loadEd25519PrivateKey(keyContent);
4208
3742
  const jwk = privateKey.export({ format: "jwk" });
4209
3743
  const pubBytes = Buffer4.from(jwk.x, "base64url");
@@ -4211,17 +3745,17 @@ function readPublicKey(keyPath) {
4211
3745
  }
4212
3746
  function generateAndSaveKey(keyPath) {
4213
3747
  const resolved = resolveKeyPath(keyPath);
4214
- const dir = dirname2(resolved);
3748
+ const dir = dirname(resolved);
4215
3749
  if (!existsSync7(dir)) {
4216
- mkdirSync2(dir, { recursive: true });
3750
+ mkdirSync(dir, { recursive: true });
4217
3751
  }
4218
3752
  const { publicKey, privateKey } = generateKeyPairSync("ed25519");
4219
3753
  const privatePem = privateKey.export({ type: "pkcs8", format: "pem" });
4220
- writeFileSync3(resolved, privatePem, { mode: 384 });
3754
+ writeFileSync2(resolved, privatePem, { mode: 384 });
4221
3755
  const jwk = publicKey.export({ format: "jwk" });
4222
3756
  const pubBytes = Buffer4.from(jwk.x, "base64url");
4223
3757
  const pubKeyStr = buildSshEd25519Line(pubBytes);
4224
- writeFileSync3(`${resolved}.pub`, `${pubKeyStr}
3758
+ writeFileSync2(`${resolved}.pub`, `${pubKeyStr}
4225
3759
  `, { mode: 420 });
4226
3760
  return pubKeyStr;
4227
3761
  }
@@ -4237,15 +3771,15 @@ function generateKeyPairInMemory() {
4237
3771
  }
4238
3772
 
4239
3773
  // 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";
3774
+ import { execFileSync as execFileSync5 } from "child_process";
3775
+ import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
3776
+ import { homedir as homedir7 } from "os";
3777
+ import { dirname as dirname2, join as join5 } from "path";
4244
3778
  var PLIST_LABEL_PREFIX = "eco.hofmann.apes.bridge";
4245
- function readLitellmEnv(envPath = join5(homedir8(), "litellm", ".env")) {
3779
+ function readLitellmEnv(envPath = join5(homedir7(), "litellm", ".env")) {
4246
3780
  if (!existsSync8(envPath)) return null;
4247
3781
  try {
4248
- const text = readFileSync8(envPath, "utf8");
3782
+ const text = readFileSync7(envPath, "utf8");
4249
3783
  const out = {};
4250
3784
  for (const line of text.split("\n")) {
4251
3785
  const trimmed = line.trim();
@@ -4281,12 +3815,12 @@ function captureHostBinDirs() {
4281
3815
  for (const bin of ["node", "openape-chat-bridge", "apes"]) {
4282
3816
  let resolved;
4283
3817
  try {
4284
- resolved = execFileSync7("/usr/bin/which", [bin], { encoding: "utf8" }).trim();
3818
+ resolved = execFileSync5("/usr/bin/which", [bin], { encoding: "utf8" }).trim();
4285
3819
  } catch {
4286
3820
  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
3821
  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
3822
  }
4289
- const dir = dirname3(resolved);
3823
+ const dir = dirname2(resolved);
4290
3824
  if (!seen.has(dir)) {
4291
3825
  seen.add(dir);
4292
3826
  dirs.push(dir);
@@ -4532,10 +4066,10 @@ and try again.`
4532
4066
  bridge,
4533
4067
  troop
4534
4068
  });
4535
- writeFileSync4(scriptPath, script, { mode: 448 });
4069
+ writeFileSync3(scriptPath, script, { mode: 448 });
4536
4070
  consola23.start("Running privileged setup as root via `apes run --as root --wait`\u2026");
4537
4071
  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" });
4072
+ execFileSync6(apes, ["run", "--as", "root", "--wait", "--", "bash", scriptPath], { stdio: "inherit" });
4539
4073
  consola23.success(`Agent ${name} spawned.`);
4540
4074
  consola23.info(`\u{1F517} Troop: https://troop.openape.ai/agents/${name}`);
4541
4075
  if (args.bridge) {
@@ -4574,18 +4108,18 @@ async function resolveClaudeToken(opts) {
4574
4108
  }
4575
4109
 
4576
4110
  // 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";
4111
+ import { chownSync, existsSync as existsSync9, mkdirSync as mkdirSync2, readFileSync as readFileSync8, statSync, writeFileSync as writeFileSync4 } from "fs";
4112
+ import { homedir as homedir8 } from "os";
4579
4113
  import { join as join7 } from "path";
4580
4114
  import { defineCommand as defineCommand27 } from "citty";
4581
4115
  import consola24 from "consola";
4582
4116
 
4583
4117
  // src/lib/macos-host.ts
4584
- import { execFileSync as execFileSync9 } from "child_process";
4118
+ import { execFileSync as execFileSync7 } from "child_process";
4585
4119
  import { hostname as hostname3 } from "os";
4586
4120
  function getHostId() {
4587
4121
  try {
4588
- const output = execFileSync9(
4122
+ const output = execFileSync7(
4589
4123
  "/usr/sbin/ioreg",
4590
4124
  ["-d2", "-c", "IOPlatformExpertDevice"],
4591
4125
  { encoding: "utf8", timeout: 2e3 }
@@ -4605,15 +4139,15 @@ function getHostname() {
4605
4139
  }
4606
4140
 
4607
4141
  // 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");
4142
+ var AUTH_PATH3 = join7(homedir8(), ".config", "apes", "auth.json");
4143
+ var TASK_CACHE_DIR2 = join7(homedir8(), ".openape", "agent", "tasks");
4610
4144
  function readAuthJson() {
4611
4145
  if (!existsSync9(AUTH_PATH3)) {
4612
4146
  throw new CliError(
4613
4147
  `No agent auth found at ${AUTH_PATH3}. Run \`apes agents spawn <name>\` to provision an agent first.`
4614
4148
  );
4615
4149
  }
4616
- const raw = readFileSync9(AUTH_PATH3, "utf8");
4150
+ const raw = readFileSync8(AUTH_PATH3, "utf8");
4617
4151
  let parsed;
4618
4152
  try {
4619
4153
  parsed = JSON.parse(raw);
@@ -4674,7 +4208,7 @@ var syncAgentCommand = defineCommand27({
4674
4208
  let agentGid = null;
4675
4209
  if (process.geteuid?.() === 0) {
4676
4210
  try {
4677
- const homeStat = statSync(homedir9());
4211
+ const homeStat = statSync(homedir8());
4678
4212
  agentUid = homeStat.uid;
4679
4213
  agentGid = homeStat.gid;
4680
4214
  } catch {
@@ -4688,23 +4222,23 @@ var syncAgentCommand = defineCommand27({
4688
4222
  }
4689
4223
  }
4690
4224
  }
4691
- const agentDir = join7(homedir9(), ".openape", "agent");
4692
- mkdirSync3(agentDir, { recursive: true });
4693
- chownToAgent(join7(homedir9(), ".openape"));
4225
+ const agentDir = join7(homedir8(), ".openape", "agent");
4226
+ mkdirSync2(agentDir, { recursive: true });
4227
+ chownToAgent(join7(homedir8(), ".openape"));
4694
4228
  chownToAgent(agentDir);
4695
4229
  const agentJsonPath = join7(agentDir, "agent.json");
4696
- writeFileSync5(
4230
+ writeFileSync4(
4697
4231
  agentJsonPath,
4698
4232
  `${JSON.stringify({ systemPrompt }, null, 2)}
4699
4233
  `,
4700
4234
  { mode: 384 }
4701
4235
  );
4702
4236
  chownToAgent(agentJsonPath);
4703
- mkdirSync3(TASK_CACHE_DIR2, { recursive: true });
4237
+ mkdirSync2(TASK_CACHE_DIR2, { recursive: true });
4704
4238
  chownToAgent(TASK_CACHE_DIR2);
4705
4239
  for (const task of tasks) {
4706
4240
  const path2 = join7(TASK_CACHE_DIR2, `${task.taskId}.json`);
4707
- writeFileSync5(path2, `${JSON.stringify(task, null, 2)}
4241
+ writeFileSync4(path2, `${JSON.stringify(task, null, 2)}
4708
4242
  `, { mode: 384 });
4709
4243
  chownToAgent(path2);
4710
4244
  }
@@ -4734,19 +4268,19 @@ var agentsCommand = defineCommand28({
4734
4268
  import { defineCommand as defineCommand37 } from "citty";
4735
4269
 
4736
4270
  // src/commands/nest/authorize.ts
4737
- import { execFileSync as execFileSync10 } from "child_process";
4738
- import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
4271
+ import { execFileSync as execFileSync8 } from "child_process";
4272
+ import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
4739
4273
  import { join as join9 } from "path";
4740
4274
  import { defineCommand as defineCommand30 } from "citty";
4741
4275
  import consola26 from "consola";
4742
4276
 
4743
4277
  // 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";
4278
+ import { hostname as hostname4, homedir as homedir9 } from "os";
4279
+ import { existsSync as existsSync10, mkdirSync as mkdirSync3, writeFileSync as writeFileSync5, chmodSync } from "fs";
4746
4280
  import { join as join8 } from "path";
4747
4281
  import { defineCommand as defineCommand29 } from "citty";
4748
4282
  import consola25 from "consola";
4749
- var NEST_DATA_DIR = join8(homedir10(), ".openape", "nest");
4283
+ var NEST_DATA_DIR = join8(homedir9(), ".openape", "nest");
4750
4284
  function nestAgentName() {
4751
4285
  const raw = hostname4().toLowerCase();
4752
4286
  const head = raw.split(".")[0] ?? raw;
@@ -4785,13 +4319,13 @@ var enrollNestCommand = defineCommand29({
4785
4319
  }
4786
4320
  const sshDir = join8(NEST_DATA_DIR, ".ssh");
4787
4321
  const configDir = join8(NEST_DATA_DIR, ".config", "apes");
4788
- mkdirSync4(sshDir, { recursive: true });
4789
- mkdirSync4(configDir, { recursive: true });
4322
+ mkdirSync3(sshDir, { recursive: true });
4323
+ mkdirSync3(configDir, { recursive: true });
4790
4324
  consola25.start(`Generating keypair for ${name}\u2026`);
4791
4325
  const { privatePem, publicSshLine } = generateKeyPairInMemory();
4792
- writeFileSync6(join8(sshDir, "id_ed25519"), `${privatePem.trimEnd()}
4326
+ writeFileSync5(join8(sshDir, "id_ed25519"), `${privatePem.trimEnd()}
4793
4327
  `, { mode: 384 });
4794
- writeFileSync6(join8(sshDir, "id_ed25519.pub"), `${publicSshLine}
4328
+ writeFileSync5(join8(sshDir, "id_ed25519.pub"), `${publicSshLine}
4795
4329
  `, { mode: 420 });
4796
4330
  chmodSync(sshDir, 448);
4797
4331
  consola25.start(`Registering nest at ${idp}\u2026`);
@@ -4811,7 +4345,7 @@ var enrollNestCommand = defineCommand29({
4811
4345
  keyPath: join8(sshDir, "id_ed25519"),
4812
4346
  ownerEmail: ownerAuth.email
4813
4347
  });
4814
- writeFileSync6(authPath, authJson, { mode: 384 });
4348
+ writeFileSync5(authPath, authJson, { mode: 384 });
4815
4349
  chmodSync(configDir, 448);
4816
4350
  consola25.success(`Nest enrolled \u2014 auth.json at ${authPath}`);
4817
4351
  consola25.info("");
@@ -4873,7 +4407,7 @@ var authorizeNestCommand = defineCommand30({
4873
4407
  if (!existsSync11(nestAuthPath)) {
4874
4408
  throw new CliError("Nest not enrolled. Run `apes nest enroll` first.");
4875
4409
  }
4876
- const nestAuth = JSON.parse(readFileSync10(nestAuthPath, "utf8"));
4410
+ const nestAuth = JSON.parse(readFileSync9(nestAuthPath, "utf8"));
4877
4411
  if (!nestAuth.email) throw new CliError(`${nestAuthPath} has no email`);
4878
4412
  const allow = args.allow ?? DEFAULT_ALLOW_PATTERNS.join(",");
4879
4413
  consola26.info(`Configuring YOLO-policy on ${nestAuth.email} via \`apes yolo set\`\u2026`);
@@ -4890,7 +4424,7 @@ var authorizeNestCommand = defineCommand30({
4890
4424
  cmdArgs.push("--expires-in", args["expires-in"]);
4891
4425
  }
4892
4426
  try {
4893
- execFileSync10("apes", cmdArgs, { stdio: "inherit" });
4427
+ execFileSync8("apes", cmdArgs, { stdio: "inherit" });
4894
4428
  } catch (err) {
4895
4429
  throw new CliError(err instanceof Error ? err.message : String(err));
4896
4430
  }
@@ -5035,10 +4569,10 @@ var destroyNestCommand = defineCommand31({
5035
4569
  });
5036
4570
 
5037
4571
  // 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";
5040
- import { homedir as homedir11, userInfo as userInfo2 } from "os";
5041
- import { dirname as dirname4, join as join10 } from "path";
4572
+ import { execFileSync as execFileSync9 } from "child_process";
4573
+ import { existsSync as existsSync12, mkdirSync as mkdirSync4, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
4574
+ import { homedir as homedir10, userInfo as userInfo2 } from "os";
4575
+ import { dirname as dirname3, join as join10 } from "path";
5042
4576
  import { defineCommand as defineCommand32 } from "citty";
5043
4577
  import consola29 from "consola";
5044
4578
 
@@ -5107,7 +4641,7 @@ resource_chain = ["agents:name={name}", "allowlist:email={peer_email}"]
5107
4641
  // src/commands/nest/install.ts
5108
4642
  var PLIST_LABEL = "ai.openape.nest";
5109
4643
  function plistPath() {
5110
- return join10(homedir11(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
4644
+ return join10(homedir10(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
5111
4645
  }
5112
4646
  function escape2(s) {
5113
4647
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -5148,34 +4682,34 @@ function buildPlist(args) {
5148
4682
  `;
5149
4683
  }
5150
4684
  function installAdapter2() {
5151
- const target = join10(homedir11(), ".openape", "shapes", "adapters", "apes-agents.toml");
5152
- mkdirSync5(dirname4(target), { recursive: true });
4685
+ const target = join10(homedir10(), ".openape", "shapes", "adapters", "apes-agents.toml");
4686
+ mkdirSync4(dirname3(target), { recursive: true });
5153
4687
  let existing = "";
5154
4688
  try {
5155
- existing = readFileSync11(target, "utf8");
4689
+ existing = readFileSync10(target, "utf8");
5156
4690
  } catch {
5157
4691
  }
5158
4692
  if (existing === APES_AGENTS_ADAPTER_TOML) return false;
5159
- writeFileSync7(target, APES_AGENTS_ADAPTER_TOML, { mode: 420 });
4693
+ writeFileSync6(target, APES_AGENTS_ADAPTER_TOML, { mode: 420 });
5160
4694
  consola29.success(`Wrote shapes adapter ${target}`);
5161
4695
  return true;
5162
4696
  }
5163
4697
  function writeBridgeModelDefault(model) {
5164
- const envDir = join10(homedir11(), "litellm");
4698
+ const envDir = join10(homedir10(), "litellm");
5165
4699
  const envFile = join10(envDir, ".env");
5166
- mkdirSync5(envDir, { recursive: true });
4700
+ mkdirSync4(envDir, { recursive: true });
5167
4701
  let lines = [];
5168
4702
  if (existsSync12(envFile)) {
5169
- lines = readFileSync11(envFile, "utf8").split("\n").filter((l) => !l.startsWith("APE_CHAT_BRIDGE_MODEL="));
4703
+ lines = readFileSync10(envFile, "utf8").split("\n").filter((l) => !l.startsWith("APE_CHAT_BRIDGE_MODEL="));
5170
4704
  }
5171
4705
  lines.push(`APE_CHAT_BRIDGE_MODEL=${model}`);
5172
4706
  while (lines.length > 0 && lines.at(-1).trim() === "") lines.pop();
5173
- writeFileSync7(envFile, `${lines.join("\n")}
4707
+ writeFileSync6(envFile, `${lines.join("\n")}
5174
4708
  `, { mode: 384 });
5175
4709
  }
5176
4710
  function findBinary(name) {
5177
4711
  for (const dir of [
5178
- join10(homedir11(), ".bun", "bin"),
4712
+ join10(homedir10(), ".bun", "bin"),
5179
4713
  "/opt/homebrew/bin",
5180
4714
  "/usr/local/bin",
5181
4715
  "/usr/bin"
@@ -5201,7 +4735,7 @@ var installNestCommand = defineCommand32({
5201
4735
  }
5202
4736
  },
5203
4737
  async run({ args }) {
5204
- const homeDir = homedir11();
4738
+ const homeDir = homedir10();
5205
4739
  const port = Number(args.port ?? 9091);
5206
4740
  if (!Number.isInteger(port) || port < 1024 || port > 65535) {
5207
4741
  throw new Error(`invalid port ${port}`);
@@ -5217,26 +4751,26 @@ var installNestCommand = defineCommand32({
5217
4751
  consola29.success(`Default bridge model set to ${args["bridge-model"]} (in ~/litellm/.env)`);
5218
4752
  }
5219
4753
  installAdapter2();
5220
- mkdirSync5(join10(homeDir, "Library", "LaunchAgents"), { recursive: true });
5221
- mkdirSync5(NEST_DATA_DIR, { recursive: true });
4754
+ mkdirSync4(join10(homeDir, "Library", "LaunchAgents"), { recursive: true });
4755
+ mkdirSync4(NEST_DATA_DIR, { recursive: true });
5222
4756
  const desired = buildPlist({ nestBin, apesBin, userHome: homeDir, nestHome: NEST_DATA_DIR, port });
5223
4757
  let existing = "";
5224
4758
  try {
5225
- existing = readFileSync11(plistPath(), "utf8");
4759
+ existing = readFileSync10(plistPath(), "utf8");
5226
4760
  } catch {
5227
4761
  }
5228
4762
  if (existing !== desired) {
5229
- writeFileSync7(plistPath(), desired, { mode: 420 });
4763
+ writeFileSync6(plistPath(), desired, { mode: 420 });
5230
4764
  consola29.success("Wrote launchd plist");
5231
4765
  } else {
5232
4766
  consola29.info("plist already up to date");
5233
4767
  }
5234
4768
  const uid = userInfo2().uid;
5235
4769
  try {
5236
- execFileSync11("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL}`], { stdio: "ignore" });
4770
+ execFileSync9("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL}`], { stdio: "ignore" });
5237
4771
  } catch {
5238
4772
  }
5239
- execFileSync11("/bin/launchctl", ["bootstrap", `gui/${uid}`, plistPath()], { stdio: "inherit" });
4773
+ execFileSync9("/bin/launchctl", ["bootstrap", `gui/${uid}`, plistPath()], { stdio: "inherit" });
5240
4774
  consola29.success(`Nest daemon bootstrapped \u2014 http://127.0.0.1:${port}`);
5241
4775
  consola29.info("");
5242
4776
  consola29.info("Next steps for zero-prompt spawn \u2014 both one-time:");
@@ -5399,9 +4933,9 @@ var statusNestCommand = defineCommand35({
5399
4933
  });
5400
4934
 
5401
4935
  // src/commands/nest/uninstall.ts
5402
- import { execFileSync as execFileSync12 } from "child_process";
4936
+ import { execFileSync as execFileSync10 } from "child_process";
5403
4937
  import { existsSync as existsSync13, unlinkSync } from "fs";
5404
- import { homedir as homedir12, userInfo as userInfo3 } from "os";
4938
+ import { homedir as homedir11, userInfo as userInfo3 } from "os";
5405
4939
  import { join as join11 } from "path";
5406
4940
  import { defineCommand as defineCommand36 } from "citty";
5407
4941
  import consola33 from "consola";
@@ -5413,9 +4947,9 @@ var uninstallNestCommand = defineCommand36({
5413
4947
  },
5414
4948
  async run() {
5415
4949
  const uid = userInfo3().uid;
5416
- const path2 = join11(homedir12(), "Library", "LaunchAgents", `${PLIST_LABEL2}.plist`);
4950
+ const path2 = join11(homedir11(), "Library", "LaunchAgents", `${PLIST_LABEL2}.plist`);
5417
4951
  try {
5418
- execFileSync12("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL2}`], { stdio: "ignore" });
4952
+ execFileSync10("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL2}`], { stdio: "ignore" });
5419
4953
  consola33.success("Nest daemon stopped");
5420
4954
  } catch {
5421
4955
  consola33.info("Nest daemon was not loaded");
@@ -5970,7 +5504,7 @@ var adapterCommand = defineCommand42({
5970
5504
  });
5971
5505
 
5972
5506
  // src/commands/run.ts
5973
- import { execFileSync as execFileSync13 } from "child_process";
5507
+ import { execFileSync as execFileSync11 } from "child_process";
5974
5508
  import { hostname as hostname6 } from "os";
5975
5509
  import { basename } from "path";
5976
5510
  import { defineCommand as defineCommand43 } from "citty";
@@ -6248,7 +5782,7 @@ function execShellCommand(command) {
6248
5782
  throw new CliError("No command to execute");
6249
5783
  try {
6250
5784
  const { APES_SHELL_WRAPPER: _wrapperMarker, ...inheritedEnv } = process.env;
6251
- execFileSync13(command[0], command.slice(1), {
5785
+ execFileSync11(command[0], command.slice(1), {
6252
5786
  stdio: "inherit",
6253
5787
  env: inheritedEnv
6254
5788
  });
@@ -6400,7 +5934,7 @@ async function runAudienceMode(audience, action, args) {
6400
5934
  consola38.info(`Executing: ${command.join(" ")}`);
6401
5935
  try {
6402
5936
  const { APES_SHELL_WRAPPER: _wrapperMarker, ...inheritedEnv } = process.env;
6403
- execFileSync13(args["escapes-path"] || "escapes", ["--grant", authz_jwt, "--", ...command], {
5937
+ execFileSync11(args["escapes-path"] || "escapes", ["--grant", authz_jwt, "--", ...command], {
6404
5938
  stdio: "inherit",
6405
5939
  env: inheritedEnv
6406
5940
  });
@@ -6450,10 +5984,10 @@ note = "VPC-internal hostname suffix"
6450
5984
 
6451
5985
  // src/proxy/local-proxy.ts
6452
5986
  import { spawn } from "child_process";
6453
- import { mkdtempSync as mkdtempSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "fs";
5987
+ import { mkdtempSync as mkdtempSync3, rmSync as rmSync3, writeFileSync as writeFileSync7 } from "fs";
6454
5988
  import { createRequire } from "module";
6455
5989
  import { tmpdir as tmpdir3 } from "os";
6456
- import { dirname as dirname5, join as join12, resolve as resolve4 } from "path";
5990
+ import { dirname as dirname4, join as join12, resolve as resolve3 } from "path";
6457
5991
  var require2 = createRequire(import.meta.url);
6458
5992
  function findProxyBin() {
6459
5993
  const pkgPath = require2.resolve("@openape/proxy/package.json");
@@ -6462,12 +5996,12 @@ function findProxyBin() {
6462
5996
  if (!binRel) {
6463
5997
  throw new Error("@openape/proxy is missing the openape-proxy bin entry");
6464
5998
  }
6465
- return resolve4(dirname5(pkgPath), binRel);
5999
+ return resolve3(dirname4(pkgPath), binRel);
6466
6000
  }
6467
6001
  async function startEphemeralProxy(configToml) {
6468
6002
  const tmpDir = mkdtempSync3(join12(tmpdir3(), "openape-proxy-"));
6469
6003
  const configPath = join12(tmpDir, "config.toml");
6470
- writeFileSync8(configPath, configToml, { mode: 384 });
6004
+ writeFileSync7(configPath, configToml, { mode: 384 });
6471
6005
  const binPath = findProxyBin();
6472
6006
  const child = spawn(process.execPath, [binPath, "-c", configPath], {
6473
6007
  stdio: ["ignore", "pipe", "pipe"],
@@ -6902,15 +6436,15 @@ var mcpCommand = defineCommand49({
6902
6436
  if (transport !== "stdio" && transport !== "sse") {
6903
6437
  throw new Error('Transport must be "stdio" or "sse"');
6904
6438
  }
6905
- const { startMcpServer } = await import("./server-AZOEKT55.js");
6439
+ const { startMcpServer } = await import("./server-F3ALNNYS.js");
6906
6440
  await startMcpServer(transport, port);
6907
6441
  }
6908
6442
  });
6909
6443
 
6910
6444
  // src/commands/init/index.ts
6911
- import { existsSync as existsSync14, copyFileSync, writeFileSync as writeFileSync9 } from "fs";
6445
+ import { existsSync as existsSync14, copyFileSync, writeFileSync as writeFileSync8 } from "fs";
6912
6446
  import { randomBytes } from "crypto";
6913
- import { execFileSync as execFileSync14 } from "child_process";
6447
+ import { execFileSync as execFileSync12 } from "child_process";
6914
6448
  import { join as join13 } from "path";
6915
6449
  import { defineCommand as defineCommand50 } from "citty";
6916
6450
  import consola42 from "consola";
@@ -6922,11 +6456,11 @@ async function downloadTemplate(repo, targetDir) {
6922
6456
  function installDeps(dir) {
6923
6457
  const hasLockFile = (name) => existsSync14(join13(dir, name));
6924
6458
  if (hasLockFile("pnpm-lock.yaml")) {
6925
- execFileSync14("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
6459
+ execFileSync12("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
6926
6460
  } else if (hasLockFile("bun.lockb")) {
6927
- execFileSync14("bun", ["install"], { cwd: dir, stdio: "inherit" });
6461
+ execFileSync12("bun", ["install"], { cwd: dir, stdio: "inherit" });
6928
6462
  } else {
6929
- execFileSync14("npm", ["install"], { cwd: dir, stdio: "inherit" });
6463
+ execFileSync12("npm", ["install"], { cwd: dir, stdio: "inherit" });
6930
6464
  }
6931
6465
  }
6932
6466
  async function promptChoice(message, choices) {
@@ -7042,7 +6576,7 @@ async function initIdP(targetDir) {
7042
6576
  `NUXT_OPENAPE_RP_ID=${domain}`,
7043
6577
  `NUXT_OPENAPE_RP_ORIGIN=${origin}`
7044
6578
  ].join("\n");
7045
- writeFileSync9(join13(dir, ".env"), `${envContent}
6579
+ writeFileSync8(join13(dir, ".env"), `${envContent}
7046
6580
  `, { mode: 384 });
7047
6581
  consola42.success(".env created");
7048
6582
  console.log("");
@@ -7063,7 +6597,7 @@ async function initIdP(targetDir) {
7063
6597
 
7064
6598
  // src/commands/enroll.ts
7065
6599
  import { Buffer as Buffer5 } from "buffer";
7066
- import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
6600
+ import { existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
7067
6601
  import { execFile as execFile2 } from "child_process";
7068
6602
  import { sign as sign2 } from "crypto";
7069
6603
  import { defineCommand as defineCommand51 } from "citty";
@@ -7079,7 +6613,7 @@ function openBrowser2(url) {
7079
6613
  }
7080
6614
  async function pollForEnrollment(idp, agentEmail, keyPath) {
7081
6615
  const resolvedKey = resolveKeyPath(keyPath);
7082
- const keyContent = readFileSync12(resolvedKey, "utf-8");
6616
+ const keyContent = readFileSync11(resolvedKey, "utf-8");
7083
6617
  const privateKey = loadEd25519PrivateKey(keyContent);
7084
6618
  const challengeUrl = await getAgentChallengeEndpoint(idp);
7085
6619
  const authenticateUrl = await getAgentAuthenticateEndpoint(idp);
@@ -7106,7 +6640,7 @@ async function pollForEnrollment(idp, agentEmail, keyPath) {
7106
6640
  }
7107
6641
  } catch {
7108
6642
  }
7109
- await new Promise((resolve5) => setTimeout(resolve5, POLL_INTERVAL));
6643
+ await new Promise((resolve4) => setTimeout(resolve4, POLL_INTERVAL));
7110
6644
  }
7111
6645
  throw new Error("Enrollment timed out. Please check the browser and try again.");
7112
6646
  }
@@ -7191,7 +6725,7 @@ var enrollCommand = defineCommand51({
7191
6725
  });
7192
6726
 
7193
6727
  // src/commands/register-user.ts
7194
- import { existsSync as existsSync16, readFileSync as readFileSync13 } from "fs";
6728
+ import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
7195
6729
  import { defineCommand as defineCommand52 } from "citty";
7196
6730
  import consola44 from "consola";
7197
6731
  var registerUserCommand = defineCommand52({
@@ -7231,7 +6765,7 @@ var registerUserCommand = defineCommand52({
7231
6765
  }
7232
6766
  let publicKey = args.key;
7233
6767
  if (existsSync16(args.key)) {
7234
- publicKey = readFileSync13(args.key, "utf-8").trim();
6768
+ publicKey = readFileSync12(args.key, "utf-8").trim();
7235
6769
  }
7236
6770
  if (!publicKey.startsWith("ssh-ed25519 ")) {
7237
6771
  throw new CliError("Public key must be in ssh-ed25519 format.");
@@ -7540,7 +7074,7 @@ async function bestEffortGrantCount(idp) {
7540
7074
  }
7541
7075
  }
7542
7076
  async function runHealth(args) {
7543
- const version = true ? "1.10.0" : "0.0.0";
7077
+ const version = true ? "1.11.0" : "0.0.0";
7544
7078
  const auth = loadAuth();
7545
7079
  if (!auth) {
7546
7080
  throw new CliError("Not logged in. Run `apes login` first.", 1);
@@ -7733,26 +7267,26 @@ var workflowsCommand = defineCommand60({
7733
7267
  });
7734
7268
 
7735
7269
  // src/version-check.ts
7736
- import { existsSync as existsSync17, mkdirSync as mkdirSync6, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "fs";
7737
- import { homedir as homedir13 } from "os";
7270
+ import { existsSync as existsSync17, mkdirSync as mkdirSync5, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "fs";
7271
+ import { homedir as homedir12 } from "os";
7738
7272
  import { join as join14 } from "path";
7739
7273
  import consola50 from "consola";
7740
7274
  var PACKAGE_NAME = "@openape/apes";
7741
7275
  var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
7742
- var CACHE_FILE = join14(homedir13(), ".config", "apes", ".version-check.json");
7276
+ var CACHE_FILE = join14(homedir12(), ".config", "apes", ".version-check.json");
7743
7277
  function readCache() {
7744
7278
  if (!existsSync17(CACHE_FILE)) return null;
7745
7279
  try {
7746
- return JSON.parse(readFileSync14(CACHE_FILE, "utf-8"));
7280
+ return JSON.parse(readFileSync13(CACHE_FILE, "utf-8"));
7747
7281
  } catch {
7748
7282
  return null;
7749
7283
  }
7750
7284
  }
7751
7285
  function writeCache(entry) {
7752
7286
  try {
7753
- const dir = join14(homedir13(), ".config", "apes");
7754
- if (!existsSync17(dir)) mkdirSync6(dir, { recursive: true, mode: 448 });
7755
- writeFileSync10(CACHE_FILE, JSON.stringify(entry), { mode: 384 });
7287
+ const dir = join14(homedir12(), ".config", "apes");
7288
+ if (!existsSync17(dir)) mkdirSync5(dir, { recursive: true, mode: 448 });
7289
+ writeFileSync9(CACHE_FILE, JSON.stringify(entry), { mode: 384 });
7756
7290
  } catch {
7757
7291
  }
7758
7292
  }
@@ -7813,10 +7347,10 @@ if (shellRewrite) {
7813
7347
  if (shellRewrite.action === "rewrite") {
7814
7348
  process.argv = shellRewrite.argv;
7815
7349
  } else if (shellRewrite.action === "version") {
7816
- console.log(`ape-shell ${"1.10.0"} (OpenApe DDISA shell wrapper)`);
7350
+ console.log(`ape-shell ${"1.11.0"} (OpenApe DDISA shell wrapper)`);
7817
7351
  process.exit(0);
7818
7352
  } else if (shellRewrite.action === "help") {
7819
- console.log(`ape-shell ${"1.10.0"} \u2014 OpenApe DDISA shell wrapper`);
7353
+ console.log(`ape-shell ${"1.11.0"} \u2014 OpenApe DDISA shell wrapper`);
7820
7354
  console.log("");
7821
7355
  console.log("Usage:");
7822
7356
  console.log(" ape-shell Start interactive grant-mediated REPL");
@@ -7874,7 +7408,7 @@ var configCommand = defineCommand61({
7874
7408
  var main = defineCommand61({
7875
7409
  meta: {
7876
7410
  name: "apes",
7877
- version: "1.10.0",
7411
+ version: "1.11.0",
7878
7412
  description: "Unified CLI for OpenApe"
7879
7413
  },
7880
7414
  subCommands: {
@@ -7931,7 +7465,7 @@ async function maybeRefreshAuth() {
7931
7465
  }
7932
7466
  }
7933
7467
  await maybeRefreshAuth();
7934
- await maybeWarnStaleVersion("1.10.0").catch(() => {
7468
+ await maybeWarnStaleVersion("1.11.0").catch(() => {
7935
7469
  });
7936
7470
  runMain(main).catch((err) => {
7937
7471
  if (err instanceof CliExit) {