@openape/apes 0.12.6 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -61,7 +61,7 @@ import {
61
61
  } from "./chunk-6GPSKAMU.js";
62
62
 
63
63
  // src/cli.ts
64
- import consola27 from "consola";
64
+ import consola28 from "consola";
65
65
 
66
66
  // src/ape-shell.ts
67
67
  import path from "path";
@@ -91,7 +91,7 @@ function rewriteApeShellArgs(argv, argv0) {
91
91
  }
92
92
 
93
93
  // src/cli.ts
94
- import { defineCommand as defineCommand33, runMain } from "citty";
94
+ import { defineCommand as defineCommand34, runMain } from "citty";
95
95
 
96
96
  // src/commands/auth/login.ts
97
97
  import { Buffer } from "buffer";
@@ -256,7 +256,7 @@ async function loginWithPKCE(idp) {
256
256
  authUrl.searchParams.set("state", state);
257
257
  authUrl.searchParams.set("nonce", nonce);
258
258
  authUrl.searchParams.set("scope", "openid email profile offline_access");
259
- const code = await new Promise((resolve3, reject) => {
259
+ const code = await new Promise((resolve4, reject) => {
260
260
  const server = createServer((req, res) => {
261
261
  const url = new URL(req.url, `http://localhost:${CALLBACK_PORT}`);
262
262
  if (url.pathname === "/callback") {
@@ -273,7 +273,7 @@ async function loginWithPKCE(idp) {
273
273
  res.writeHead(200, { "Content-Type": "text/html" });
274
274
  res.end("<h1>Login successful!</h1><p>You can close this window.</p>");
275
275
  server.close();
276
- resolve3(authCode);
276
+ resolve4(authCode);
277
277
  return;
278
278
  }
279
279
  res.writeHead(400);
@@ -833,7 +833,7 @@ async function waitForApproval2(grantsUrl, grantId) {
833
833
  if (grant.status === "revoked") {
834
834
  throw new CliError("Grant revoked.");
835
835
  }
836
- await new Promise((resolve3) => setTimeout(resolve3, interval));
836
+ await new Promise((resolve4) => setTimeout(resolve4, interval));
837
837
  }
838
838
  throw new CliError("Timed out waiting for approval.");
839
839
  }
@@ -2455,9 +2455,222 @@ async function runAudienceMode(audience, action, args) {
2455
2455
  }
2456
2456
  }
2457
2457
 
2458
- // src/commands/explain.ts
2458
+ // src/commands/proxy.ts
2459
+ import { spawn as spawn2 } from "child_process";
2459
2460
  import { defineCommand as defineCommand22 } from "citty";
2460
- var explainCommand = defineCommand22({
2461
+ import consola20 from "consola";
2462
+
2463
+ // src/proxy/config.ts
2464
+ import { homedir as homedir4 } from "os";
2465
+ import { join as join2 } from "path";
2466
+ function defaultAuditPath() {
2467
+ const xdg = process.env.XDG_STATE_HOME;
2468
+ const stateDir = xdg && xdg.length > 0 ? xdg : join2(homedir4(), ".local", "state");
2469
+ return join2(stateDir, "openape", "proxy-audit.jsonl");
2470
+ }
2471
+ function buildDefaultProxyConfigToml() {
2472
+ const auditPath = defaultAuditPath();
2473
+ return `# Auto-generated by apes proxy -- (M1a). Do not edit; this file is
2474
+ # recreated for every \`apes proxy --\` invocation and deleted on exit.
2475
+ [proxy]
2476
+ listen = "127.0.0.1:0"
2477
+ idp_url = "https://id.openape.ai"
2478
+ agent_email = "ephemeral@apes-proxy.local"
2479
+ default_action = "allow"
2480
+ audit_log = "${auditPath.replace(/"/g, '\\"')}"
2481
+
2482
+ # Cloud / link-local metadata endpoints \u2014 never let agent traffic reach these
2483
+ # even if a downstream policy mistake would otherwise allow it.
2484
+ [[deny]]
2485
+ domain = "169.254.169.254"
2486
+ note = "AWS / DigitalOcean / Azure metadata endpoint"
2487
+
2488
+ [[deny]]
2489
+ domain = "metadata.google.internal"
2490
+ note = "GCP metadata endpoint"
2491
+
2492
+ [[deny]]
2493
+ domain = "*.internal"
2494
+ note = "VPC-internal hostname suffix"
2495
+ `;
2496
+ }
2497
+
2498
+ // src/proxy/local-proxy.ts
2499
+ import { spawn } from "child_process";
2500
+ import { mkdtempSync, rmSync, writeFileSync } from "fs";
2501
+ import { createRequire } from "module";
2502
+ import { tmpdir } from "os";
2503
+ import { dirname, join as join3, resolve as resolve2 } from "path";
2504
+ var require2 = createRequire(import.meta.url);
2505
+ function findProxyBin() {
2506
+ const pkgPath = require2.resolve("@openape/proxy/package.json");
2507
+ const pkg = require2("@openape/proxy/package.json");
2508
+ const binRel = pkg.bin?.["openape-proxy"];
2509
+ if (!binRel) {
2510
+ throw new Error("@openape/proxy is missing the openape-proxy bin entry");
2511
+ }
2512
+ return resolve2(dirname(pkgPath), binRel);
2513
+ }
2514
+ async function startEphemeralProxy(configToml) {
2515
+ const tmpDir = mkdtempSync(join3(tmpdir(), "openape-proxy-"));
2516
+ const configPath = join3(tmpDir, "config.toml");
2517
+ writeFileSync(configPath, configToml, { mode: 384 });
2518
+ const binPath = findProxyBin();
2519
+ const child = spawn(process.execPath, [binPath, "-c", configPath], {
2520
+ stdio: ["ignore", "pipe", "pipe"],
2521
+ detached: false
2522
+ });
2523
+ const cleanupTmp = () => {
2524
+ try {
2525
+ rmSync(tmpDir, { recursive: true, force: true });
2526
+ } catch {
2527
+ }
2528
+ };
2529
+ let port;
2530
+ try {
2531
+ port = await waitForListenLine(child);
2532
+ } catch (err) {
2533
+ child.kill("SIGTERM");
2534
+ cleanupTmp();
2535
+ throw err;
2536
+ }
2537
+ child.stderr?.on("data", (chunk) => process.stderr.write(chunk));
2538
+ return {
2539
+ url: `http://127.0.0.1:${port}`,
2540
+ port,
2541
+ child,
2542
+ close: () => new Promise((resolveClose) => {
2543
+ const done = () => {
2544
+ cleanupTmp();
2545
+ resolveClose();
2546
+ };
2547
+ if (child.exitCode !== null || child.signalCode !== null) {
2548
+ done();
2549
+ return;
2550
+ }
2551
+ child.once("exit", done);
2552
+ child.kill("SIGTERM");
2553
+ setTimeout(() => {
2554
+ if (child.exitCode === null && child.signalCode === null) {
2555
+ child.kill("SIGKILL");
2556
+ }
2557
+ }, 2e3).unref();
2558
+ })
2559
+ };
2560
+ }
2561
+ function waitForListenLine(child) {
2562
+ return new Promise((resolveWait, rejectWait) => {
2563
+ let buf = "";
2564
+ let timer;
2565
+ function onData(chunk) {
2566
+ buf += chunk.toString("utf8");
2567
+ const m = buf.match(/Listening on http:\/\/[^:\s]+:(\d+)/);
2568
+ if (m) {
2569
+ cleanup();
2570
+ resolveWait(Number(m[1]));
2571
+ }
2572
+ }
2573
+ function onExit(code) {
2574
+ cleanup();
2575
+ rejectWait(new Error(`openape-proxy exited before listening (code=${code}, stderr accumulated above)`));
2576
+ }
2577
+ function onError(err) {
2578
+ cleanup();
2579
+ rejectWait(err);
2580
+ }
2581
+ function cleanup() {
2582
+ clearTimeout(timer);
2583
+ child.stdout?.off("data", onData);
2584
+ child.off("exit", onExit);
2585
+ child.off("error", onError);
2586
+ }
2587
+ timer = setTimeout(() => {
2588
+ cleanup();
2589
+ rejectWait(new Error("openape-proxy startup timeout (5s)"));
2590
+ }, 5e3);
2591
+ timer.unref();
2592
+ child.stdout?.on("data", onData);
2593
+ child.once("exit", onExit);
2594
+ child.once("error", onError);
2595
+ });
2596
+ }
2597
+
2598
+ // src/commands/proxy.ts
2599
+ var proxyCommand = defineCommand22({
2600
+ meta: {
2601
+ name: "proxy",
2602
+ description: "Run a command with HTTPS_PROXY routed through the OpenApe egress proxy."
2603
+ },
2604
+ args: {
2605
+ _: {
2606
+ type: "positional",
2607
+ description: "Command to execute (after --)",
2608
+ required: false
2609
+ }
2610
+ },
2611
+ async run({ rawArgs }) {
2612
+ const wrapped = extractWrappedCommand(rawArgs ?? []);
2613
+ if (wrapped.length === 0) {
2614
+ throw new CliError("Usage: apes proxy -- <cmd> [args...]");
2615
+ }
2616
+ const reuseUrl = process.env.OPENAPE_PROXY_URL;
2617
+ let proxyUrl;
2618
+ let close = null;
2619
+ if (reuseUrl) {
2620
+ proxyUrl = reuseUrl;
2621
+ consola20.info(`[apes proxy] reusing existing proxy at ${proxyUrl}`);
2622
+ } else {
2623
+ const ephemeral = await startEphemeralProxy(buildDefaultProxyConfigToml());
2624
+ proxyUrl = ephemeral.url;
2625
+ close = ephemeral.close;
2626
+ consola20.info(`[apes proxy] started ephemeral proxy at ${proxyUrl}`);
2627
+ }
2628
+ const noProxy = process.env.NO_PROXY ?? process.env.no_proxy ?? "127.0.0.1,localhost";
2629
+ const childEnv = {
2630
+ ...process.env,
2631
+ HTTPS_PROXY: proxyUrl,
2632
+ https_proxy: proxyUrl,
2633
+ HTTP_PROXY: proxyUrl,
2634
+ http_proxy: proxyUrl,
2635
+ ALL_PROXY: proxyUrl,
2636
+ all_proxy: proxyUrl,
2637
+ NO_PROXY: noProxy,
2638
+ no_proxy: noProxy,
2639
+ NODE_USE_ENV_PROXY: "1"
2640
+ };
2641
+ const exitCode = await new Promise((resolveExit) => {
2642
+ const child = spawn2(wrapped[0], wrapped.slice(1), {
2643
+ stdio: "inherit",
2644
+ env: childEnv
2645
+ });
2646
+ const forward = (sig) => () => child.kill(sig);
2647
+ const onSigint = forward("SIGINT");
2648
+ const onSigterm = forward("SIGTERM");
2649
+ process.on("SIGINT", onSigint);
2650
+ process.on("SIGTERM", onSigterm);
2651
+ child.once("exit", (code, signal) => {
2652
+ process.off("SIGINT", onSigint);
2653
+ process.off("SIGTERM", onSigterm);
2654
+ if (signal) resolveExit(128 + (signalNumber(signal) ?? 0));
2655
+ else resolveExit(code ?? 0);
2656
+ });
2657
+ child.once("error", (err) => {
2658
+ consola20.error(`[apes proxy] failed to spawn '${wrapped[0]}':`, err.message);
2659
+ resolveExit(127);
2660
+ });
2661
+ });
2662
+ if (close) await close();
2663
+ if (exitCode !== 0) throw new CliExit(exitCode);
2664
+ }
2665
+ });
2666
+ function signalNumber(signal) {
2667
+ const map = { SIGINT: 2, SIGTERM: 15, SIGHUP: 1, SIGQUIT: 3, SIGKILL: 9 };
2668
+ return map[signal];
2669
+ }
2670
+
2671
+ // src/commands/explain.ts
2672
+ import { defineCommand as defineCommand23 } from "citty";
2673
+ var explainCommand = defineCommand23({
2461
2674
  meta: {
2462
2675
  name: "explain",
2463
2676
  description: "Show what permission a command would need"
@@ -2495,9 +2708,9 @@ var explainCommand = defineCommand22({
2495
2708
  });
2496
2709
 
2497
2710
  // src/commands/config/get.ts
2498
- import { defineCommand as defineCommand23 } from "citty";
2499
- import consola20 from "consola";
2500
- var configGetCommand = defineCommand23({
2711
+ import { defineCommand as defineCommand24 } from "citty";
2712
+ import consola21 from "consola";
2713
+ var configGetCommand = defineCommand24({
2501
2714
  meta: {
2502
2715
  name: "get",
2503
2716
  description: "Get a configuration value"
@@ -2517,7 +2730,7 @@ var configGetCommand = defineCommand23({
2517
2730
  if (idp)
2518
2731
  console.log(idp);
2519
2732
  else
2520
- consola20.info("No IdP configured.");
2733
+ consola21.info("No IdP configured.");
2521
2734
  break;
2522
2735
  }
2523
2736
  case "email": {
@@ -2525,7 +2738,7 @@ var configGetCommand = defineCommand23({
2525
2738
  if (auth?.email)
2526
2739
  console.log(auth.email);
2527
2740
  else
2528
- consola20.info("Not logged in.");
2741
+ consola21.info("Not logged in.");
2529
2742
  break;
2530
2743
  }
2531
2744
  default: {
@@ -2538,7 +2751,7 @@ var configGetCommand = defineCommand23({
2538
2751
  if (sectionObj && field in sectionObj) {
2539
2752
  console.log(sectionObj[field]);
2540
2753
  } else {
2541
- consola20.info(`Key "${key}" not set.`);
2754
+ consola21.info(`Key "${key}" not set.`);
2542
2755
  }
2543
2756
  } else {
2544
2757
  throw new CliError(`Unknown key: "${key}". Use: idp, email, defaults.idp, defaults.approval, agent.key, agent.email`);
@@ -2549,9 +2762,9 @@ var configGetCommand = defineCommand23({
2549
2762
  });
2550
2763
 
2551
2764
  // src/commands/config/set.ts
2552
- import { defineCommand as defineCommand24 } from "citty";
2553
- import consola21 from "consola";
2554
- var configSetCommand = defineCommand24({
2765
+ import { defineCommand as defineCommand25 } from "citty";
2766
+ import consola22 from "consola";
2767
+ var configSetCommand = defineCommand25({
2555
2768
  meta: {
2556
2769
  name: "set",
2557
2770
  description: "Set a configuration value"
@@ -2587,12 +2800,12 @@ var configSetCommand = defineCommand24({
2587
2800
  throw new CliError(`Unknown section: "${section}". Use: defaults, agent`);
2588
2801
  }
2589
2802
  saveConfig(config);
2590
- consola21.success(`Set ${key} = ${value}`);
2803
+ consola22.success(`Set ${key} = ${value}`);
2591
2804
  }
2592
2805
  });
2593
2806
 
2594
2807
  // src/commands/fetch/index.ts
2595
- import { defineCommand as defineCommand25 } from "citty";
2808
+ import { defineCommand as defineCommand26 } from "citty";
2596
2809
  async function doRequest(method, url, body, contentType, raw, showHeaders) {
2597
2810
  const token = getAuthToken();
2598
2811
  if (!token) {
@@ -2628,13 +2841,13 @@ async function doRequest(method, url, body, contentType, raw, showHeaders) {
2628
2841
  throw new CliError(`HTTP ${response.status} ${response.statusText}`);
2629
2842
  }
2630
2843
  }
2631
- var fetchCommand = defineCommand25({
2844
+ var fetchCommand = defineCommand26({
2632
2845
  meta: {
2633
2846
  name: "fetch",
2634
2847
  description: "Make authenticated HTTP requests"
2635
2848
  },
2636
2849
  subCommands: {
2637
- get: defineCommand25({
2850
+ get: defineCommand26({
2638
2851
  meta: {
2639
2852
  name: "get",
2640
2853
  description: "GET request with auth token"
@@ -2660,7 +2873,7 @@ var fetchCommand = defineCommand25({
2660
2873
  await doRequest("GET", String(args.url), void 0, "application/json", Boolean(args.raw), Boolean(args.headers));
2661
2874
  }
2662
2875
  }),
2663
- post: defineCommand25({
2876
+ post: defineCommand26({
2664
2877
  meta: {
2665
2878
  name: "post",
2666
2879
  description: "POST request with auth token"
@@ -2699,8 +2912,8 @@ var fetchCommand = defineCommand25({
2699
2912
  });
2700
2913
 
2701
2914
  // src/commands/mcp/index.ts
2702
- import { defineCommand as defineCommand26 } from "citty";
2703
- var mcpCommand = defineCommand26({
2915
+ import { defineCommand as defineCommand27 } from "citty";
2916
+ var mcpCommand = defineCommand27({
2704
2917
  meta: {
2705
2918
  name: "mcp",
2706
2919
  description: "Start MCP server for AI agents"
@@ -2723,25 +2936,25 @@ var mcpCommand = defineCommand26({
2723
2936
  if (transport !== "stdio" && transport !== "sse") {
2724
2937
  throw new Error('Transport must be "stdio" or "sse"');
2725
2938
  }
2726
- const { startMcpServer } = await import("./server-RP56MNWI.js");
2939
+ const { startMcpServer } = await import("./server-6RPIR76X.js");
2727
2940
  await startMcpServer(transport, port);
2728
2941
  }
2729
2942
  });
2730
2943
 
2731
2944
  // src/commands/init/index.ts
2732
- import { existsSync as existsSync3, copyFileSync, writeFileSync } from "fs";
2945
+ import { existsSync as existsSync3, copyFileSync, writeFileSync as writeFileSync2 } from "fs";
2733
2946
  import { randomBytes } from "crypto";
2734
2947
  import { execFileSync as execFileSync3 } from "child_process";
2735
- import { join as join2 } from "path";
2736
- import { defineCommand as defineCommand27 } from "citty";
2737
- import consola22 from "consola";
2948
+ import { join as join4 } from "path";
2949
+ import { defineCommand as defineCommand28 } from "citty";
2950
+ import consola23 from "consola";
2738
2951
  var DEFAULT_IDP_URL = "https://id.openape.at";
2739
2952
  async function downloadTemplate(repo, targetDir) {
2740
2953
  const { downloadTemplate: gigetDownload } = await import("giget");
2741
2954
  await gigetDownload(`gh:${repo}`, { dir: targetDir, force: false });
2742
2955
  }
2743
2956
  function installDeps(dir) {
2744
- const hasLockFile = (name) => existsSync3(join2(dir, name));
2957
+ const hasLockFile = (name) => existsSync3(join4(dir, name));
2745
2958
  if (hasLockFile("pnpm-lock.yaml")) {
2746
2959
  execFileSync3("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
2747
2960
  } else if (hasLockFile("bun.lockb")) {
@@ -2751,20 +2964,20 @@ function installDeps(dir) {
2751
2964
  }
2752
2965
  }
2753
2966
  async function promptChoice(message, choices) {
2754
- const result = await consola22.prompt(message, { type: "select", options: choices });
2967
+ const result = await consola23.prompt(message, { type: "select", options: choices });
2755
2968
  if (typeof result === "symbol") {
2756
2969
  throw new CliExit(0);
2757
2970
  }
2758
2971
  return result;
2759
2972
  }
2760
2973
  async function promptText(message, defaultValue) {
2761
- const result = await consola22.prompt(message, { type: "text", default: defaultValue, placeholder: defaultValue });
2974
+ const result = await consola23.prompt(message, { type: "text", default: defaultValue, placeholder: defaultValue });
2762
2975
  if (typeof result === "symbol") {
2763
2976
  throw new CliExit(0);
2764
2977
  }
2765
2978
  return result || defaultValue || "";
2766
2979
  }
2767
- var initCommand = defineCommand27({
2980
+ var initCommand = defineCommand28({
2768
2981
  meta: {
2769
2982
  name: "init",
2770
2983
  description: "Scaffold a new OpenApe project"
@@ -2806,23 +3019,23 @@ var initCommand = defineCommand27({
2806
3019
  });
2807
3020
  async function initSP(targetDir) {
2808
3021
  const dir = targetDir || "my-app";
2809
- if (existsSync3(join2(dir, "package.json"))) {
3022
+ if (existsSync3(join4(dir, "package.json"))) {
2810
3023
  throw new CliError(`Directory "${dir}" already contains a project.`);
2811
3024
  }
2812
- consola22.start("Scaffolding SP starter...");
3025
+ consola23.start("Scaffolding SP starter...");
2813
3026
  await downloadTemplate("openape-ai/openape-sp-starter", dir);
2814
- consola22.success("Scaffolded from openape-sp-starter");
2815
- consola22.start("Installing dependencies...");
3027
+ consola23.success("Scaffolded from openape-sp-starter");
3028
+ consola23.start("Installing dependencies...");
2816
3029
  installDeps(dir);
2817
- consola22.success("Dependencies installed");
2818
- const envExample = join2(dir, ".env.example");
2819
- const envFile = join2(dir, ".env");
3030
+ consola23.success("Dependencies installed");
3031
+ const envExample = join4(dir, ".env.example");
3032
+ const envFile = join4(dir, ".env");
2820
3033
  if (existsSync3(envExample) && !existsSync3(envFile)) {
2821
3034
  copyFileSync(envExample, envFile);
2822
- consola22.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
3035
+ consola23.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
2823
3036
  }
2824
3037
  console.log("");
2825
- consola22.box([
3038
+ consola23.box([
2826
3039
  `cd ${dir}`,
2827
3040
  "npm run dev",
2828
3041
  "",
@@ -2831,7 +3044,7 @@ async function initSP(targetDir) {
2831
3044
  }
2832
3045
  async function initIdP(targetDir) {
2833
3046
  const dir = targetDir || "my-idp";
2834
- if (existsSync3(join2(dir, "package.json"))) {
3047
+ if (existsSync3(join4(dir, "package.json"))) {
2835
3048
  throw new CliError(`Directory "${dir}" already contains a project.`);
2836
3049
  }
2837
3050
  const domain = await promptText("Domain for the IdP", "localhost");
@@ -2841,15 +3054,15 @@ async function initIdP(targetDir) {
2841
3054
  "s3 (S3-compatible)"
2842
3055
  ]);
2843
3056
  const adminEmail = await promptText("Admin email");
2844
- consola22.start("Scaffolding IdP starter...");
3057
+ consola23.start("Scaffolding IdP starter...");
2845
3058
  await downloadTemplate("openape-ai/openape-idp-starter", dir);
2846
- consola22.success("Scaffolded from openape-idp-starter");
2847
- consola22.start("Installing dependencies...");
3059
+ consola23.success("Scaffolded from openape-idp-starter");
3060
+ consola23.start("Installing dependencies...");
2848
3061
  installDeps(dir);
2849
- consola22.success("Dependencies installed");
3062
+ consola23.success("Dependencies installed");
2850
3063
  const sessionSecret = randomBytes(32).toString("hex");
2851
3064
  const managementToken = randomBytes(32).toString("hex");
2852
- consola22.success("Secrets generated");
3065
+ consola23.success("Secrets generated");
2853
3066
  const isLocalhost = domain === "localhost";
2854
3067
  const origin = isLocalhost ? "http://localhost:3000" : `https://${domain}`;
2855
3068
  const envContent = [
@@ -2863,11 +3076,11 @@ async function initIdP(targetDir) {
2863
3076
  `NUXT_OPENAPE_RP_ID=${domain}`,
2864
3077
  `NUXT_OPENAPE_RP_ORIGIN=${origin}`
2865
3078
  ].join("\n");
2866
- writeFileSync(join2(dir, ".env"), `${envContent}
3079
+ writeFileSync2(join4(dir, ".env"), `${envContent}
2867
3080
  `, { mode: 384 });
2868
- consola22.success(".env created");
3081
+ consola23.success(".env created");
2869
3082
  console.log("");
2870
- consola22.box([
3083
+ consola23.box([
2871
3084
  `cd ${dir}`,
2872
3085
  "npm run dev",
2873
3086
  "",
@@ -2884,19 +3097,19 @@ async function initIdP(targetDir) {
2884
3097
 
2885
3098
  // src/commands/enroll.ts
2886
3099
  import { Buffer as Buffer2 } from "buffer";
2887
- import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync } from "fs";
3100
+ import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync3, mkdirSync } from "fs";
2888
3101
  import { execFile as execFile2 } from "child_process";
2889
3102
  import { generateKeyPairSync, sign } from "crypto";
2890
- import { dirname, resolve as resolve2 } from "path";
2891
- import { homedir as homedir4 } from "os";
2892
- import { defineCommand as defineCommand28 } from "citty";
2893
- import consola23 from "consola";
3103
+ import { dirname as dirname2, resolve as resolve3 } from "path";
3104
+ import { homedir as homedir5 } from "os";
3105
+ import { defineCommand as defineCommand29 } from "citty";
3106
+ import consola24 from "consola";
2894
3107
  var DEFAULT_IDP_URL2 = "https://id.openape.at";
2895
3108
  var DEFAULT_KEY_PATH = "~/.ssh/id_ed25519";
2896
3109
  var POLL_INTERVAL = 3e3;
2897
3110
  var POLL_TIMEOUT = 3e5;
2898
3111
  function resolvePath2(p) {
2899
- return resolve2(p.replace(/^~/, homedir4()));
3112
+ return resolve3(p.replace(/^~/, homedir5()));
2900
3113
  }
2901
3114
  function openBrowser2(url) {
2902
3115
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
@@ -2922,13 +3135,13 @@ function readPublicKey(keyPath) {
2922
3135
  }
2923
3136
  function generateAndSaveKey(keyPath) {
2924
3137
  const resolved = resolvePath2(keyPath);
2925
- const dir = dirname(resolved);
3138
+ const dir = dirname2(resolved);
2926
3139
  if (!existsSync4(dir)) {
2927
3140
  mkdirSync(dir, { recursive: true });
2928
3141
  }
2929
3142
  const { publicKey, privateKey } = generateKeyPairSync("ed25519");
2930
3143
  const privatePem = privateKey.export({ type: "pkcs8", format: "pem" });
2931
- writeFileSync2(resolved, privatePem, { mode: 384 });
3144
+ writeFileSync3(resolved, privatePem, { mode: 384 });
2932
3145
  const jwk = publicKey.export({ format: "jwk" });
2933
3146
  const pubBytes = Buffer2.from(jwk.x, "base64url");
2934
3147
  const keyTypeStr = "ssh-ed25519";
@@ -2938,7 +3151,7 @@ function generateAndSaveKey(keyPath) {
2938
3151
  pubKeyLen.writeUInt32BE(pubBytes.length);
2939
3152
  const blob = Buffer2.concat([keyTypeLen, Buffer2.from(keyTypeStr), pubKeyLen, pubBytes]);
2940
3153
  const pubKeyStr = `ssh-ed25519 ${blob.toString("base64")}`;
2941
- writeFileSync2(`${resolved}.pub`, `${pubKeyStr}
3154
+ writeFileSync3(`${resolved}.pub`, `${pubKeyStr}
2942
3155
  `, { mode: 420 });
2943
3156
  return pubKeyStr;
2944
3157
  }
@@ -2971,11 +3184,11 @@ async function pollForEnrollment(idp, agentEmail, keyPath) {
2971
3184
  }
2972
3185
  } catch {
2973
3186
  }
2974
- await new Promise((resolve3) => setTimeout(resolve3, POLL_INTERVAL));
3187
+ await new Promise((resolve4) => setTimeout(resolve4, POLL_INTERVAL));
2975
3188
  }
2976
3189
  throw new Error("Enrollment timed out. Please check the browser and try again.");
2977
3190
  }
2978
- var enrollCommand = defineCommand28({
3191
+ var enrollCommand = defineCommand29({
2979
3192
  meta: {
2980
3193
  name: "enroll",
2981
3194
  description: "Enroll an agent with an Identity Provider"
@@ -2995,18 +3208,18 @@ var enrollCommand = defineCommand28({
2995
3208
  }
2996
3209
  },
2997
3210
  async run({ args }) {
2998
- const idp = args.idp || await consola23.prompt("IdP URL", { type: "text", default: DEFAULT_IDP_URL2, placeholder: DEFAULT_IDP_URL2 }).then((r) => {
3211
+ const idp = args.idp || await consola24.prompt("IdP URL", { type: "text", default: DEFAULT_IDP_URL2, placeholder: DEFAULT_IDP_URL2 }).then((r) => {
2999
3212
  if (typeof r === "symbol") throw new CliExit(0);
3000
3213
  return r;
3001
3214
  }) || DEFAULT_IDP_URL2;
3002
- const agentName = args.name || await consola23.prompt("Agent name", { type: "text", placeholder: "deploy-bot" }).then((r) => {
3215
+ const agentName = args.name || await consola24.prompt("Agent name", { type: "text", placeholder: "deploy-bot" }).then((r) => {
3003
3216
  if (typeof r === "symbol") throw new CliExit(0);
3004
3217
  return r;
3005
3218
  });
3006
3219
  if (!agentName) {
3007
3220
  throw new CliError("Agent name is required.");
3008
3221
  }
3009
- const keyPath = args.key || await consola23.prompt("Ed25519 key", { type: "text", default: DEFAULT_KEY_PATH, placeholder: DEFAULT_KEY_PATH }).then((r) => {
3222
+ const keyPath = args.key || await consola24.prompt("Ed25519 key", { type: "text", default: DEFAULT_KEY_PATH, placeholder: DEFAULT_KEY_PATH }).then((r) => {
3010
3223
  if (typeof r === "symbol") throw new CliExit(0);
3011
3224
  return r;
3012
3225
  }) || DEFAULT_KEY_PATH;
@@ -3014,19 +3227,19 @@ var enrollCommand = defineCommand28({
3014
3227
  let publicKey;
3015
3228
  if (existsSync4(resolvedKey)) {
3016
3229
  publicKey = readPublicKey(resolvedKey);
3017
- consola23.success(`Using existing key ${keyPath}`);
3230
+ consola24.success(`Using existing key ${keyPath}`);
3018
3231
  } else {
3019
- consola23.start(`Generating Ed25519 key pair at ${keyPath}...`);
3232
+ consola24.start(`Generating Ed25519 key pair at ${keyPath}...`);
3020
3233
  publicKey = generateAndSaveKey(keyPath);
3021
- consola23.success(`Key pair generated at ${keyPath}`);
3234
+ consola24.success(`Key pair generated at ${keyPath}`);
3022
3235
  }
3023
3236
  const encodedKey = encodeURIComponent(publicKey);
3024
3237
  const enrollUrl = `${idp}/enroll?name=${encodeURIComponent(agentName)}&key=${encodedKey}`;
3025
- consola23.info("Opening browser for enrollment...");
3026
- consola23.info(`\u2192 ${idp}/enroll`);
3238
+ consola24.info("Opening browser for enrollment...");
3239
+ consola24.info(`\u2192 ${idp}/enroll`);
3027
3240
  openBrowser2(enrollUrl);
3028
3241
  console.log("");
3029
- const agentEmail = await consola23.prompt(
3242
+ const agentEmail = await consola24.prompt(
3030
3243
  "Agent email (shown in browser after enrollment)",
3031
3244
  { type: "text", placeholder: `agent+${agentName}@...` }
3032
3245
  ).then((r) => {
@@ -3036,7 +3249,7 @@ var enrollCommand = defineCommand28({
3036
3249
  if (!agentEmail) {
3037
3250
  throw new CliError("Agent email is required to verify enrollment.");
3038
3251
  }
3039
- consola23.start("Verifying enrollment...");
3252
+ consola24.start("Verifying enrollment...");
3040
3253
  const { token, expiresIn } = await pollForEnrollment(idp, agentEmail, keyPath);
3041
3254
  saveAuth({
3042
3255
  idp,
@@ -3048,18 +3261,18 @@ var enrollCommand = defineCommand28({
3048
3261
  config.defaults = { ...config.defaults, idp };
3049
3262
  config.agent = { key: keyPath, email: agentEmail };
3050
3263
  saveConfig(config);
3051
- consola23.success(`Agent enrolled as ${agentEmail}`);
3052
- consola23.success("Config saved to ~/.config/apes/");
3264
+ consola24.success(`Agent enrolled as ${agentEmail}`);
3265
+ consola24.success("Config saved to ~/.config/apes/");
3053
3266
  console.log("");
3054
- consola23.info("Verify with: apes whoami");
3267
+ consola24.info("Verify with: apes whoami");
3055
3268
  }
3056
3269
  });
3057
3270
 
3058
3271
  // src/commands/register-user.ts
3059
3272
  import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
3060
- import { defineCommand as defineCommand29 } from "citty";
3061
- import consola24 from "consola";
3062
- var registerUserCommand = defineCommand29({
3273
+ import { defineCommand as defineCommand30 } from "citty";
3274
+ import consola25 from "consola";
3275
+ var registerUserCommand = defineCommand30({
3063
3276
  meta: {
3064
3277
  name: "register-user",
3065
3278
  description: "Register a sub-user with SSH key"
@@ -3114,15 +3327,15 @@ var registerUserCommand = defineCommand29({
3114
3327
  ...userType ? { type: userType } : {}
3115
3328
  }
3116
3329
  });
3117
- consola24.success(`User registered: ${result.email} (type: ${result.type}, owner: ${result.owner})`);
3330
+ consola25.success(`User registered: ${result.email} (type: ${result.type}, owner: ${result.owner})`);
3118
3331
  }
3119
3332
  });
3120
3333
 
3121
3334
  // src/commands/dns-check.ts
3122
- import { defineCommand as defineCommand30 } from "citty";
3123
- import consola25 from "consola";
3335
+ import { defineCommand as defineCommand31 } from "citty";
3336
+ import consola26 from "consola";
3124
3337
  import { resolveDDISA as resolveDDISA2 } from "@openape/core";
3125
- var dnsCheckCommand = defineCommand30({
3338
+ var dnsCheckCommand = defineCommand31({
3126
3339
  meta: {
3127
3340
  name: "dns-check",
3128
3341
  description: "Validate DDISA DNS TXT records for a domain"
@@ -3136,7 +3349,7 @@ var dnsCheckCommand = defineCommand30({
3136
3349
  },
3137
3350
  async run({ args }) {
3138
3351
  const domain = args.domain;
3139
- consola25.start(`Checking _ddisa.${domain}...`);
3352
+ consola26.start(`Checking _ddisa.${domain}...`);
3140
3353
  try {
3141
3354
  const result = await resolveDDISA2(domain);
3142
3355
  if (!result) {
@@ -3145,7 +3358,7 @@ var dnsCheckCommand = defineCommand30({
3145
3358
  console.log(` _ddisa.${domain} TXT "v=ddisa1 idp=https://id.${domain}"`);
3146
3359
  throw new CliError(`No DDISA record found for ${domain}`);
3147
3360
  }
3148
- consola25.success(`_ddisa.${domain} \u2192 ${result.idp}`);
3361
+ consola26.success(`_ddisa.${domain} \u2192 ${result.idp}`);
3149
3362
  console.log("");
3150
3363
  console.log(` Version: ${result.version || "ddisa1"}`);
3151
3364
  console.log(` IdP URL: ${result.idp}`);
@@ -3154,14 +3367,14 @@ var dnsCheckCommand = defineCommand30({
3154
3367
  if (result.priority !== void 0)
3155
3368
  console.log(` Priority: ${result.priority}`);
3156
3369
  console.log("");
3157
- consola25.start(`Verifying IdP at ${result.idp}...`);
3370
+ consola26.start(`Verifying IdP at ${result.idp}...`);
3158
3371
  const discoResp = await fetch(`${result.idp}/.well-known/openid-configuration`);
3159
3372
  if (!discoResp.ok) {
3160
- consola25.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
3373
+ consola26.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
3161
3374
  return;
3162
3375
  }
3163
3376
  const disco = await discoResp.json();
3164
- consola25.success(`IdP is reachable`);
3377
+ consola26.success(`IdP is reachable`);
3165
3378
  console.log(` Issuer: ${disco.issuer}`);
3166
3379
  console.log(` DDISA: v${disco.ddisa_version || "?"}`);
3167
3380
  if (disco.ddisa_auth_methods_supported) {
@@ -3179,7 +3392,7 @@ var dnsCheckCommand = defineCommand30({
3179
3392
  // src/commands/health.ts
3180
3393
  import { exec } from "child_process";
3181
3394
  import { promisify } from "util";
3182
- import { defineCommand as defineCommand31 } from "citty";
3395
+ import { defineCommand as defineCommand32 } from "citty";
3183
3396
  var execAsync = promisify(exec);
3184
3397
  async function resolveApeShellPath() {
3185
3398
  try {
@@ -3215,7 +3428,7 @@ async function bestEffortGrantCount(idp) {
3215
3428
  }
3216
3429
  }
3217
3430
  async function runHealth(args) {
3218
- const version = true ? "0.12.6" : "0.0.0";
3431
+ const version = true ? "0.13.1" : "0.0.0";
3219
3432
  const auth = loadAuth();
3220
3433
  if (!auth) {
3221
3434
  throw new CliError("Not logged in. Run `apes login` first.", 1);
@@ -3278,7 +3491,7 @@ async function runHealth(args) {
3278
3491
  throw new CliError(`IdP ${auth.idp} unreachable: ${idpProbe.error}`, 1);
3279
3492
  }
3280
3493
  }
3281
- var healthCommand = defineCommand31({
3494
+ var healthCommand = defineCommand32({
3282
3495
  meta: {
3283
3496
  name: "health",
3284
3497
  description: "Report CLI diagnostic state (auth, IdP, grants, binaries)"
@@ -3296,8 +3509,8 @@ var healthCommand = defineCommand31({
3296
3509
  });
3297
3510
 
3298
3511
  // src/commands/workflows.ts
3299
- import { defineCommand as defineCommand32 } from "citty";
3300
- import consola26 from "consola";
3512
+ import { defineCommand as defineCommand33 } from "citty";
3513
+ import consola27 from "consola";
3301
3514
 
3302
3515
  // src/guides/index.ts
3303
3516
  var guides = [
@@ -3347,7 +3560,7 @@ var guides = [
3347
3560
  ];
3348
3561
 
3349
3562
  // src/commands/workflows.ts
3350
- var workflowsCommand = defineCommand32({
3563
+ var workflowsCommand = defineCommand33({
3351
3564
  meta: {
3352
3565
  name: "workflows",
3353
3566
  description: "Discover workflow guides"
@@ -3368,7 +3581,7 @@ var workflowsCommand = defineCommand32({
3368
3581
  if (args.id) {
3369
3582
  const guide = guides.find((g) => g.id === String(args.id));
3370
3583
  if (!guide) {
3371
- consola26.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
3584
+ consola27.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
3372
3585
  throw new CliError(`Guide not found: ${args.id}`);
3373
3586
  }
3374
3587
  if (args.json) {
@@ -3417,10 +3630,10 @@ if (shellRewrite) {
3417
3630
  if (shellRewrite.action === "rewrite") {
3418
3631
  process.argv = shellRewrite.argv;
3419
3632
  } else if (shellRewrite.action === "version") {
3420
- console.log(`ape-shell ${"0.12.6"} (OpenApe DDISA shell wrapper)`);
3633
+ console.log(`ape-shell ${"0.13.1"} (OpenApe DDISA shell wrapper)`);
3421
3634
  process.exit(0);
3422
3635
  } else if (shellRewrite.action === "help") {
3423
- console.log(`ape-shell ${"0.12.6"} \u2014 OpenApe DDISA shell wrapper`);
3636
+ console.log(`ape-shell ${"0.13.1"} \u2014 OpenApe DDISA shell wrapper`);
3424
3637
  console.log("");
3425
3638
  console.log("Usage:");
3426
3639
  console.log(" ape-shell Start interactive grant-mediated REPL");
@@ -3444,7 +3657,7 @@ if (shellRewrite) {
3444
3657
  }
3445
3658
  }
3446
3659
  var debug = process.argv.includes("--debug");
3447
- var grantsCommand = defineCommand33({
3660
+ var grantsCommand = defineCommand34({
3448
3661
  meta: {
3449
3662
  name: "grants",
3450
3663
  description: "Grant management"
@@ -3465,7 +3678,7 @@ var grantsCommand = defineCommand33({
3465
3678
  "delegation-revoke": delegationRevokeCommand
3466
3679
  }
3467
3680
  });
3468
- var configCommand = defineCommand33({
3681
+ var configCommand = defineCommand34({
3469
3682
  meta: {
3470
3683
  name: "config",
3471
3684
  description: "Configuration management"
@@ -3475,10 +3688,10 @@ var configCommand = defineCommand33({
3475
3688
  set: configSetCommand
3476
3689
  }
3477
3690
  });
3478
- var main = defineCommand33({
3691
+ var main = defineCommand34({
3479
3692
  meta: {
3480
3693
  name: "apes",
3481
- version: "0.12.6",
3694
+ version: "0.13.1",
3482
3695
  description: "Unified CLI for OpenApe"
3483
3696
  },
3484
3697
  subCommands: {
@@ -3493,6 +3706,7 @@ var main = defineCommand33({
3493
3706
  grants: grantsCommand,
3494
3707
  admin: adminCommand,
3495
3708
  run: runCommand,
3709
+ proxy: proxyCommand,
3496
3710
  explain: explainCommand,
3497
3711
  adapter: adapterCommand,
3498
3712
  config: configCommand,
@@ -3506,13 +3720,13 @@ runMain(main).catch((err) => {
3506
3720
  process.exit(err.exitCode);
3507
3721
  }
3508
3722
  if (err instanceof CliError) {
3509
- consola27.error(err.message);
3723
+ consola28.error(err.message);
3510
3724
  process.exit(err.exitCode);
3511
3725
  }
3512
3726
  if (debug) {
3513
- consola27.error(err);
3727
+ consola28.error(err);
3514
3728
  } else {
3515
- consola27.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
3729
+ consola28.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
3516
3730
  }
3517
3731
  process.exit(1);
3518
3732
  });