@openape/apes 0.11.0 → 0.11.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.
@@ -58,9 +58,19 @@ function isApesSelfDispatch(parsed) {
58
58
  return false;
59
59
  return !APES_GATED_SUBCOMMANDS.has(subCommand);
60
60
  }
61
+ function checkSudoRejection(parsed) {
62
+ if (!parsed || parsed.isCompound) return null;
63
+ if (basename(parsed.executable) !== "sudo") return null;
64
+ const rest = parsed.argv.join(" ").trim();
65
+ const hint = rest.length > 0 ? `apes run --as root -- ${rest}` : "apes run --as root -- <cmd>";
66
+ return {
67
+ reason: `sudo is not available in ape-shell. Use \`${hint}\` for privileged commands.`
68
+ };
69
+ }
61
70
 
62
71
  export {
63
72
  notifyGrantPending,
64
- isApesSelfDispatch
73
+ isApesSelfDispatch,
74
+ checkSudoRejection
65
75
  };
66
- //# sourceMappingURL=chunk-EAXBC4KC.js.map
76
+ //# sourceMappingURL=chunk-M2NBHR2E.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/notifications.ts","../src/shell/apes-self-dispatch.ts"],"sourcesContent":["import { spawn } from 'node:child_process'\nimport consola from 'consola'\nimport { quote } from 'shell-quote'\nimport { loadConfig } from './config'\n\nexport interface PendingGrantInfo {\n grantId: string\n approveUrl: string\n command: string\n audience: string\n host: string\n}\n\n/**\n * Resolve the notification command for pending grants. Checks (in order):\n * 1. `APES_NOTIFY_PENDING_COMMAND` env var (highest priority — lets\n * parent programs like openclaw override per invocation)\n * 2. `[notifications] pending_command` in ~/.config/apes/config.toml\n *\n * Returns undefined if no notification command is configured.\n */\nfunction resolvePendingCommand(): string | undefined {\n if (process.env.APES_NOTIFY_PENDING_COMMAND)\n return process.env.APES_NOTIFY_PENDING_COMMAND\n\n const config = loadConfig()\n return config.notifications?.pending_command\n}\n\n/**\n * Escape a value for safe embedding inside a single-quoted shell string.\n * We use `shell-quote` to produce a safe literal, then strip the outer\n * quoting because the template substitution embeds the value inside the\n * user's command template which is itself passed to `sh -c`.\n */\nfunction shellEscape(value: string): string {\n // quote() wraps in single quotes and escapes internal single quotes\n // e.g. \"it's\" → \"'it'\\\\''s'\"\n // We return the raw escaped form so it's safe inside sh -c.\n return quote([value])\n}\n\n/**\n * Substitute template variables in the notification command.\n * All values are shell-escaped to prevent injection.\n */\nfunction renderTemplate(template: string, info: PendingGrantInfo): string {\n return template\n .replace(/\\{grant_id\\}/g, shellEscape(info.grantId))\n .replace(/\\{approve_url\\}/g, shellEscape(info.approveUrl))\n .replace(/\\{command\\}/g, shellEscape(info.command))\n .replace(/\\{audience\\}/g, shellEscape(info.audience))\n .replace(/\\{host\\}/g, shellEscape(info.host))\n}\n\n/**\n * Send a notification that a grant is awaiting human approval.\n *\n * This is **fire-and-forget**: the notification subprocess runs detached\n * and unref'd so it cannot block the grant flow. A 10-second timeout\n * kills it if it hangs (e.g. network issue reaching Telegram API).\n *\n * Only fires when a notification command is configured. Silently returns\n * if not — the grant flow must never depend on notifications.\n *\n * Only call this when the grant **actually requires waiting** (new grant\n * with pending status). Do NOT call when:\n * - An existing timed/always grant was reused (no human action needed)\n * - The grant was instantly approved (no waiting phase)\n */\nexport function notifyGrantPending(info: PendingGrantInfo): void {\n const template = resolvePendingCommand()\n if (!template)\n return\n\n const rendered = renderTemplate(template, info)\n\n try {\n const child = spawn('sh', ['-c', rendered], {\n detached: true,\n stdio: 'ignore',\n env: { ...process.env },\n })\n\n // Don't let the notification process keep the parent alive\n child.unref()\n\n // Kill after 10 seconds if it hasn't exited\n const timeout = setTimeout(() => {\n try {\n child.kill('SIGKILL')\n }\n catch {}\n }, 10_000)\n timeout.unref()\n\n child.on('exit', () => clearTimeout(timeout))\n }\n catch (err) {\n // Never let notification failure break the grant flow\n consola.debug('Notification command failed:', err)\n }\n}\n","import { basename } from 'node:path'\nimport type { ParsedShellCommand } from '../shapes/shell-parser.js'\n\n/**\n * Subset of `apes` subcommands that remain grant-gated even when invoked\n * as self-dispatches from inside an ape-shell context. These are the\n * three categories where the shell-grant layer adds real security value\n * that isn't duplicated by server-side auth gates or local-file-only\n * semantics:\n *\n * - `run` — spawns arbitrary executables, the core of the grant system\n * - `fetch` — forwards the bearer token to a user-specified URL\n * - `mcp` — binds a network port and serves a persistent API\n *\n * Every other `apes <subcmd>` either reads state, mutates the user's own\n * local config, or talks to the IdP through endpoints that are already\n * scoped by the auth token — gating them in the shell is redundant\n * friction, and under 0.9.0's async-default grant flow it actively\n * breaks `apes grants run <id>` via recursion (the polling call itself\n * creates a new grant, cascading indefinitely).\n *\n * This is the single source of truth shared by both dispatch paths:\n * - Interactive REPL: `shell/grant-dispatch.ts` → `requestGrantForShellLine`\n * - One-shot `ape-shell -c`: `commands/run.ts` → `runShellMode` (which\n * receives the bash-c-wrapped command after `rewriteApeShellArgs`\n * rewrites `ape-shell -c \"<cmd>\"` into `apes run --shell -- bash -c <cmd>`)\n *\n * Keep this list in sync with the blocklist snapshot test in\n * `shell-grant-dispatch.test.ts` — the tripwire that forces a review\n * decision whenever a new top-level apes subcommand is added.\n */\nexport const APES_GATED_SUBCOMMANDS = new Set(['run', 'fetch', 'mcp'])\n\n/**\n * Returns true if the parsed shell command is an `apes <subcmd>`\n * invocation that should bypass the grant flow entirely. Non-apes\n * binaries, compound lines (pipes, &&, etc.), and subcommands in\n * `APES_GATED_SUBCOMMANDS` all return false so they stay on the normal\n * grant path.\n *\n * The caller (either `requestGrantForShellLine` for the REPL path or\n * `runShellMode` for the one-shot path) is responsible for parsing the\n * input string and passing the resulting ParsedShellCommand here.\n */\nexport function isApesSelfDispatch(parsed: ParsedShellCommand | null | undefined): boolean {\n if (!parsed || parsed.isCompound)\n return false\n const invokedName = basename(parsed.executable)\n if (invokedName !== 'apes' && invokedName !== 'apes.js')\n return false\n const subCommand = parsed.argv[0]\n if (!subCommand)\n return false\n return !APES_GATED_SUBCOMMANDS.has(subCommand)\n}\n"],"mappings":";;;;;;AAAA,SAAS,aAAa;AACtB,OAAO,aAAa;AACpB,SAAS,aAAa;AAmBtB,SAAS,wBAA4C;AACnD,MAAI,QAAQ,IAAI;AACd,WAAO,QAAQ,IAAI;AAErB,QAAM,SAAS,WAAW;AAC1B,SAAO,OAAO,eAAe;AAC/B;AAQA,SAAS,YAAY,OAAuB;AAI1C,SAAO,MAAM,CAAC,KAAK,CAAC;AACtB;AAMA,SAAS,eAAe,UAAkB,MAAgC;AACxE,SAAO,SACJ,QAAQ,iBAAiB,YAAY,KAAK,OAAO,CAAC,EAClD,QAAQ,oBAAoB,YAAY,KAAK,UAAU,CAAC,EACxD,QAAQ,gBAAgB,YAAY,KAAK,OAAO,CAAC,EACjD,QAAQ,iBAAiB,YAAY,KAAK,QAAQ,CAAC,EACnD,QAAQ,aAAa,YAAY,KAAK,IAAI,CAAC;AAChD;AAiBO,SAAS,mBAAmB,MAA8B;AAC/D,QAAM,WAAW,sBAAsB;AACvC,MAAI,CAAC;AACH;AAEF,QAAM,WAAW,eAAe,UAAU,IAAI;AAE9C,MAAI;AACF,UAAM,QAAQ,MAAM,MAAM,CAAC,MAAM,QAAQ,GAAG;AAAA,MAC1C,UAAU;AAAA,MACV,OAAO;AAAA,MACP,KAAK,EAAE,GAAG,QAAQ,IAAI;AAAA,IACxB,CAAC;AAGD,UAAM,MAAM;AAGZ,UAAM,UAAU,WAAW,MAAM;AAC/B,UAAI;AACF,cAAM,KAAK,SAAS;AAAA,MACtB,QACM;AAAA,MAAC;AAAA,IACT,GAAG,GAAM;AACT,YAAQ,MAAM;AAEd,UAAM,GAAG,QAAQ,MAAM,aAAa,OAAO,CAAC;AAAA,EAC9C,SACO,KAAK;AAEV,YAAQ,MAAM,gCAAgC,GAAG;AAAA,EACnD;AACF;;;ACtGA,SAAS,gBAAgB;AA+BlB,IAAM,yBAAyB,oBAAI,IAAI,CAAC,OAAO,SAAS,KAAK,CAAC;AAa9D,SAAS,mBAAmB,QAAwD;AACzF,MAAI,CAAC,UAAU,OAAO;AACpB,WAAO;AACT,QAAM,cAAc,SAAS,OAAO,UAAU;AAC9C,MAAI,gBAAgB,UAAU,gBAAgB;AAC5C,WAAO;AACT,QAAM,aAAa,OAAO,KAAK,CAAC;AAChC,MAAI,CAAC;AACH,WAAO;AACT,SAAO,CAAC,uBAAuB,IAAI,UAAU;AAC/C;","names":[]}
1
+ {"version":3,"sources":["../src/notifications.ts","../src/shell/apes-self-dispatch.ts"],"sourcesContent":["import { spawn } from 'node:child_process'\nimport consola from 'consola'\nimport { quote } from 'shell-quote'\nimport { loadConfig } from './config'\n\nexport interface PendingGrantInfo {\n grantId: string\n approveUrl: string\n command: string\n audience: string\n host: string\n}\n\n/**\n * Resolve the notification command for pending grants. Checks (in order):\n * 1. `APES_NOTIFY_PENDING_COMMAND` env var (highest priority — lets\n * parent programs like openclaw override per invocation)\n * 2. `[notifications] pending_command` in ~/.config/apes/config.toml\n *\n * Returns undefined if no notification command is configured.\n */\nfunction resolvePendingCommand(): string | undefined {\n if (process.env.APES_NOTIFY_PENDING_COMMAND)\n return process.env.APES_NOTIFY_PENDING_COMMAND\n\n const config = loadConfig()\n return config.notifications?.pending_command\n}\n\n/**\n * Escape a value for safe embedding inside a single-quoted shell string.\n * We use `shell-quote` to produce a safe literal, then strip the outer\n * quoting because the template substitution embeds the value inside the\n * user's command template which is itself passed to `sh -c`.\n */\nfunction shellEscape(value: string): string {\n // quote() wraps in single quotes and escapes internal single quotes\n // e.g. \"it's\" → \"'it'\\\\''s'\"\n // We return the raw escaped form so it's safe inside sh -c.\n return quote([value])\n}\n\n/**\n * Substitute template variables in the notification command.\n * All values are shell-escaped to prevent injection.\n */\nfunction renderTemplate(template: string, info: PendingGrantInfo): string {\n return template\n .replace(/\\{grant_id\\}/g, shellEscape(info.grantId))\n .replace(/\\{approve_url\\}/g, shellEscape(info.approveUrl))\n .replace(/\\{command\\}/g, shellEscape(info.command))\n .replace(/\\{audience\\}/g, shellEscape(info.audience))\n .replace(/\\{host\\}/g, shellEscape(info.host))\n}\n\n/**\n * Send a notification that a grant is awaiting human approval.\n *\n * This is **fire-and-forget**: the notification subprocess runs detached\n * and unref'd so it cannot block the grant flow. A 10-second timeout\n * kills it if it hangs (e.g. network issue reaching Telegram API).\n *\n * Only fires when a notification command is configured. Silently returns\n * if not — the grant flow must never depend on notifications.\n *\n * Only call this when the grant **actually requires waiting** (new grant\n * with pending status). Do NOT call when:\n * - An existing timed/always grant was reused (no human action needed)\n * - The grant was instantly approved (no waiting phase)\n */\nexport function notifyGrantPending(info: PendingGrantInfo): void {\n const template = resolvePendingCommand()\n if (!template)\n return\n\n const rendered = renderTemplate(template, info)\n\n try {\n const child = spawn('sh', ['-c', rendered], {\n detached: true,\n stdio: 'ignore',\n env: { ...process.env },\n })\n\n // Don't let the notification process keep the parent alive\n child.unref()\n\n // Kill after 10 seconds if it hasn't exited\n const timeout = setTimeout(() => {\n try {\n child.kill('SIGKILL')\n }\n catch {}\n }, 10_000)\n timeout.unref()\n\n child.on('exit', () => clearTimeout(timeout))\n }\n catch (err) {\n // Never let notification failure break the grant flow\n consola.debug('Notification command failed:', err)\n }\n}\n","import { basename } from 'node:path'\nimport type { ParsedShellCommand } from '../shapes/shell-parser.js'\n\n/**\n * Subset of `apes` subcommands that remain grant-gated even when invoked\n * as self-dispatches from inside an ape-shell context. These are the\n * three categories where the shell-grant layer adds real security value\n * that isn't duplicated by server-side auth gates or local-file-only\n * semantics:\n *\n * - `run` — spawns arbitrary executables, the core of the grant system\n * - `fetch` — forwards the bearer token to a user-specified URL\n * - `mcp` — binds a network port and serves a persistent API\n *\n * Every other `apes <subcmd>` either reads state, mutates the user's own\n * local config, or talks to the IdP through endpoints that are already\n * scoped by the auth token — gating them in the shell is redundant\n * friction, and under 0.9.0's async-default grant flow it actively\n * breaks `apes grants run <id>` via recursion (the polling call itself\n * creates a new grant, cascading indefinitely).\n *\n * This is the single source of truth shared by both dispatch paths:\n * - Interactive REPL: `shell/grant-dispatch.ts` → `requestGrantForShellLine`\n * - One-shot `ape-shell -c`: `commands/run.ts` → `runShellMode` (which\n * receives the bash-c-wrapped command after `rewriteApeShellArgs`\n * rewrites `ape-shell -c \"<cmd>\"` into `apes run --shell -- bash -c <cmd>`)\n *\n * Keep this list in sync with the blocklist snapshot test in\n * `shell-grant-dispatch.test.ts` — the tripwire that forces a review\n * decision whenever a new top-level apes subcommand is added.\n */\nexport const APES_GATED_SUBCOMMANDS = new Set(['run', 'fetch', 'mcp'])\n\n/**\n * Returns true if the parsed shell command is an `apes <subcmd>`\n * invocation that should bypass the grant flow entirely. Non-apes\n * binaries, compound lines (pipes, &&, etc.), and subcommands in\n * `APES_GATED_SUBCOMMANDS` all return false so they stay on the normal\n * grant path.\n *\n * The caller (either `requestGrantForShellLine` for the REPL path or\n * `runShellMode` for the one-shot path) is responsible for parsing the\n * input string and passing the resulting ParsedShellCommand here.\n */\nexport function isApesSelfDispatch(parsed: ParsedShellCommand | null | undefined): boolean {\n if (!parsed || parsed.isCompound)\n return false\n const invokedName = basename(parsed.executable)\n if (invokedName !== 'apes' && invokedName !== 'apes.js')\n return false\n const subCommand = parsed.argv[0]\n if (!subCommand)\n return false\n return !APES_GATED_SUBCOMMANDS.has(subCommand)\n}\n\n/**\n * Result of checking a parsed shell command for a leading `sudo` token.\n * The `reason` doubles as a ready-to-print error message so the REPL\n * and one-shot paths emit byte-identical text.\n */\nexport interface SudoRejection {\n reason: string\n}\n\n/**\n * Returns a rejection hint if the parsed line is a simple, non-compound\n * command whose leading executable is `sudo`. `sudo` is not available\n * inside ape-shell (the wrapper user is not in /etc/sudoers by design),\n * so agents and humans should use the explicit\n * `apes run --as root -- <cmd>` flow which routes through the escapes\n * setuid binary.\n *\n * Compound lines (pipes, &&, etc.) return null so the downstream\n * session-grant path can still negotiate a grant and bash surfaces the\n * real sudo error. We only short-circuit the leading-sudo case which is\n * the agent footgun.\n *\n * Shared by both dispatch paths:\n * - Interactive REPL: `shell/grant-dispatch.ts` → `requestGrantForShellLine`\n * - One-shot `ape-shell -c`: `commands/run.ts` → `runShellMode`\n */\nexport function checkSudoRejection(parsed: ParsedShellCommand | null | undefined): SudoRejection | null {\n if (!parsed || parsed.isCompound) return null\n if (basename(parsed.executable) !== 'sudo') return null\n const rest = parsed.argv.join(' ').trim()\n const hint = rest.length > 0\n ? `apes run --as root -- ${rest}`\n : 'apes run --as root -- <cmd>'\n return {\n reason: `sudo is not available in ape-shell. Use \\`${hint}\\` for privileged commands.`,\n }\n}\n"],"mappings":";;;;;;AAAA,SAAS,aAAa;AACtB,OAAO,aAAa;AACpB,SAAS,aAAa;AAmBtB,SAAS,wBAA4C;AACnD,MAAI,QAAQ,IAAI;AACd,WAAO,QAAQ,IAAI;AAErB,QAAM,SAAS,WAAW;AAC1B,SAAO,OAAO,eAAe;AAC/B;AAQA,SAAS,YAAY,OAAuB;AAI1C,SAAO,MAAM,CAAC,KAAK,CAAC;AACtB;AAMA,SAAS,eAAe,UAAkB,MAAgC;AACxE,SAAO,SACJ,QAAQ,iBAAiB,YAAY,KAAK,OAAO,CAAC,EAClD,QAAQ,oBAAoB,YAAY,KAAK,UAAU,CAAC,EACxD,QAAQ,gBAAgB,YAAY,KAAK,OAAO,CAAC,EACjD,QAAQ,iBAAiB,YAAY,KAAK,QAAQ,CAAC,EACnD,QAAQ,aAAa,YAAY,KAAK,IAAI,CAAC;AAChD;AAiBO,SAAS,mBAAmB,MAA8B;AAC/D,QAAM,WAAW,sBAAsB;AACvC,MAAI,CAAC;AACH;AAEF,QAAM,WAAW,eAAe,UAAU,IAAI;AAE9C,MAAI;AACF,UAAM,QAAQ,MAAM,MAAM,CAAC,MAAM,QAAQ,GAAG;AAAA,MAC1C,UAAU;AAAA,MACV,OAAO;AAAA,MACP,KAAK,EAAE,GAAG,QAAQ,IAAI;AAAA,IACxB,CAAC;AAGD,UAAM,MAAM;AAGZ,UAAM,UAAU,WAAW,MAAM;AAC/B,UAAI;AACF,cAAM,KAAK,SAAS;AAAA,MACtB,QACM;AAAA,MAAC;AAAA,IACT,GAAG,GAAM;AACT,YAAQ,MAAM;AAEd,UAAM,GAAG,QAAQ,MAAM,aAAa,OAAO,CAAC;AAAA,EAC9C,SACO,KAAK;AAEV,YAAQ,MAAM,gCAAgC,GAAG;AAAA,EACnD;AACF;;;ACtGA,SAAS,gBAAgB;AA+BlB,IAAM,yBAAyB,oBAAI,IAAI,CAAC,OAAO,SAAS,KAAK,CAAC;AAa9D,SAAS,mBAAmB,QAAwD;AACzF,MAAI,CAAC,UAAU,OAAO;AACpB,WAAO;AACT,QAAM,cAAc,SAAS,OAAO,UAAU;AAC9C,MAAI,gBAAgB,UAAU,gBAAgB;AAC5C,WAAO;AACT,QAAM,aAAa,OAAO,KAAK,CAAC;AAChC,MAAI,CAAC;AACH,WAAO;AACT,SAAO,CAAC,uBAAuB,IAAI,UAAU;AAC/C;AA4BO,SAAS,mBAAmB,QAAqE;AACtG,MAAI,CAAC,UAAU,OAAO,WAAY,QAAO;AACzC,MAAI,SAAS,OAAO,UAAU,MAAM,OAAQ,QAAO;AACnD,QAAM,OAAO,OAAO,KAAK,KAAK,GAAG,EAAE,KAAK;AACxC,QAAM,OAAO,KAAK,SAAS,IACvB,yBAAyB,IAAI,KAC7B;AACJ,SAAO;AAAA,IACL,QAAQ,6CAA6C,IAAI;AAAA,EAC3D;AACF;","names":[]}
package/dist/cli.js CHANGED
@@ -9,9 +9,10 @@ import {
9
9
  readPublicKeyComment
10
10
  } from "./chunk-ION3CWD5.js";
11
11
  import {
12
+ checkSudoRejection,
12
13
  isApesSelfDispatch,
13
14
  notifyGrantPending
14
- } from "./chunk-EAXBC4KC.js";
15
+ } from "./chunk-M2NBHR2E.js";
15
16
  import {
16
17
  ApiError,
17
18
  apiFetch,
@@ -2162,6 +2163,9 @@ async function runShellMode(command, args) {
2162
2163
  execShellCommand(command);
2163
2164
  return;
2164
2165
  }
2166
+ const sudoRejection = checkSudoRejection(parsedInner);
2167
+ if (sudoRejection)
2168
+ throw new CliError(sudoRejection.reason);
2165
2169
  }
2166
2170
  const adapterHandled = await tryAdapterModeFromShell(command, idp, args);
2167
2171
  if (adapterHandled) return;
@@ -2688,7 +2692,7 @@ var mcpCommand = defineCommand26({
2688
2692
  if (transport !== "stdio" && transport !== "sse") {
2689
2693
  throw new Error('Transport must be "stdio" or "sse"');
2690
2694
  }
2691
- const { startMcpServer } = await import("./server-YNJ5SURM.js");
2695
+ const { startMcpServer } = await import("./server-TGIP55VI.js");
2692
2696
  await startMcpServer(transport, port);
2693
2697
  }
2694
2698
  });
@@ -3180,7 +3184,7 @@ async function bestEffortGrantCount(idp) {
3180
3184
  }
3181
3185
  }
3182
3186
  async function runHealth(args) {
3183
- const version = true ? "0.11.0" : "0.0.0";
3187
+ const version = true ? "0.11.1" : "0.0.0";
3184
3188
  const auth = loadAuth();
3185
3189
  if (!auth) {
3186
3190
  throw new CliError("Not logged in. Run `apes login` first.", 1);
@@ -3382,10 +3386,10 @@ if (shellRewrite) {
3382
3386
  if (shellRewrite.action === "rewrite") {
3383
3387
  process.argv = shellRewrite.argv;
3384
3388
  } else if (shellRewrite.action === "version") {
3385
- console.log(`ape-shell ${"0.11.0"} (OpenApe DDISA shell wrapper)`);
3389
+ console.log(`ape-shell ${"0.11.1"} (OpenApe DDISA shell wrapper)`);
3386
3390
  process.exit(0);
3387
3391
  } else if (shellRewrite.action === "help") {
3388
- console.log(`ape-shell ${"0.11.0"} \u2014 OpenApe DDISA shell wrapper`);
3392
+ console.log(`ape-shell ${"0.11.1"} \u2014 OpenApe DDISA shell wrapper`);
3389
3393
  console.log("");
3390
3394
  console.log("Usage:");
3391
3395
  console.log(" ape-shell Start interactive grant-mediated REPL");
@@ -3400,7 +3404,7 @@ if (shellRewrite) {
3400
3404
  console.log(" --help, -h Show this help message");
3401
3405
  process.exit(0);
3402
3406
  } else if (shellRewrite.action === "interactive") {
3403
- const { runInteractiveShell } = await import("./orchestrator-U5TZ2KXF.js");
3407
+ const { runInteractiveShell } = await import("./orchestrator-OF2YGFMR.js");
3404
3408
  await runInteractiveShell();
3405
3409
  process.exit(0);
3406
3410
  } else {
@@ -3443,7 +3447,7 @@ var configCommand = defineCommand33({
3443
3447
  var main = defineCommand33({
3444
3448
  meta: {
3445
3449
  name: "apes",
3446
- version: "0.11.0",
3450
+ version: "0.11.1",
3447
3451
  description: "Unified CLI for OpenApe"
3448
3452
  },
3449
3453
  subCommands: {