@openape/apes 0.20.0 → 0.21.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
@@ -96,7 +96,7 @@ function rewriteApeShellArgs(argv, argv0) {
96
96
  import { defineCommand as defineCommand44, runMain } from "citty";
97
97
 
98
98
  // src/commands/auth/login.ts
99
- import { Buffer } from "buffer";
99
+ import { Buffer as Buffer2 } from "buffer";
100
100
  import { execFile } from "child_process";
101
101
  import { createServer } from "http";
102
102
  import { homedir as homedir2 } from "os";
@@ -394,7 +394,7 @@ async function loginWithKey(idp, keyPath, agentEmail) {
394
394
  const { challenge } = await challengeResp.json();
395
395
  const keyContent = readFileSync7(keyPath, "utf-8");
396
396
  const privateKey = loadEd25519PrivateKey2(keyContent);
397
- const signature = sign3(null, Buffer.from(challenge), privateKey).toString("base64");
397
+ const signature = sign3(null, Buffer2.from(challenge), privateKey).toString("base64");
398
398
  const authenticateUrl = await getAgentAuthenticateEndpoint(idp);
399
399
  const authResp = await fetch(authenticateUrl, {
400
400
  method: "POST",
@@ -1754,7 +1754,7 @@ import { defineCommand as defineCommand20 } from "citty";
1754
1754
  import consola18 from "consola";
1755
1755
 
1756
1756
  // src/lib/agent-bootstrap.ts
1757
- import { Buffer as Buffer2 } from "buffer";
1757
+ import { Buffer as Buffer3 } from "buffer";
1758
1758
  import { createPrivateKey, sign } from "crypto";
1759
1759
  var AGENT_NAME_REGEX = /^[a-z][a-z0-9-]{0,23}$/;
1760
1760
  var SSH_ED25519_PREFIX = "ssh-ed25519 ";
@@ -1779,7 +1779,7 @@ async function issueAgentToken(input) {
1779
1779
  throw new Error(`Challenge failed (${challengeResp.status}): ${text}`);
1780
1780
  }
1781
1781
  const { challenge } = await challengeResp.json();
1782
- const signature = sign(null, Buffer2.from(challenge), privateKey).toString("base64");
1782
+ const signature = sign(null, Buffer3.from(challenge), privateKey).toString("base64");
1783
1783
  const authenticateUrl = await getAgentAuthenticateEndpoint(input.idp);
1784
1784
  const authResp = await fetch(authenticateUrl, {
1785
1785
  method: "POST",
@@ -1811,6 +1811,25 @@ mkdir -p "$HOME_DIR/.claude/hooks"
1811
1811
  cat > "$HOME_DIR/.claude/settings.json" ${shHeredoc(input.claudeSettingsJson)}
1812
1812
  cat > "$HOME_DIR/.claude/hooks/bash-via-ape-shell.sh" ${shHeredoc(input.hookScriptSource)}
1813
1813
  chmod 755 "$HOME_DIR/.claude/hooks/bash-via-ape-shell.sh"
1814
+ ` : "";
1815
+ const claudeTokenBlock = input.claudeOauthToken ? `
1816
+ mkdir -p "$HOME_DIR/.config/openape"
1817
+ cat > "$HOME_DIR/.config/openape/claude-token.env" ${shHeredoc(`# Auto-generated by 'apes agents spawn'. chmod 600 \u2014 contains a long-lived
1818
+ # Claude Code OAuth token. Rotate by editing this file in place; the
1819
+ # .zshenv / .profile source-lines below will pick it up automatically.
1820
+ export CLAUDE_CODE_OAUTH_TOKEN=${shQuote(input.claudeOauthToken)}
1821
+ `)}
1822
+ SOURCE_LINE='[ -f "$HOME/.config/openape/claude-token.env" ] && . "$HOME/.config/openape/claude-token.env"'
1823
+ for f in "$HOME_DIR/.zshenv" "$HOME_DIR/.profile"; do
1824
+ touch "$f"
1825
+ if ! grep -qF 'config/openape/claude-token.env' "$f" 2>/dev/null; then
1826
+ {
1827
+ echo ''
1828
+ echo '# OpenApe: load Claude Code OAuth token (added by apes agents spawn)'
1829
+ echo "$SOURCE_LINE"
1830
+ } >> "$f"
1831
+ fi
1832
+ done
1814
1833
  ` : "";
1815
1834
  return `#!/bin/bash
1816
1835
  set -euo pipefail
@@ -1854,13 +1873,17 @@ mkdir -p "$HOME_DIR/.ssh" "$HOME_DIR/.config/apes"
1854
1873
  cat > "$HOME_DIR/.ssh/id_ed25519" ${shHeredoc(privatePemForHeredoc.trimEnd())}
1855
1874
  cat > "$HOME_DIR/.ssh/id_ed25519.pub" ${shHeredoc(`${input.publicKeySshLine}`)}
1856
1875
  cat > "$HOME_DIR/.config/apes/auth.json" ${shHeredoc(input.authJson)}
1857
- ${claudeBlock}
1876
+ ${claudeBlock}${claudeTokenBlock}
1858
1877
  chown -R "$NAME:staff" "$HOME_DIR"
1859
1878
  chmod 700 "$HOME_DIR/.ssh"
1860
1879
  chmod 700 "$HOME_DIR/.config"
1861
1880
  chmod 600 "$HOME_DIR/.ssh/id_ed25519"
1862
1881
  chmod 644 "$HOME_DIR/.ssh/id_ed25519.pub"
1863
1882
  chmod 600 "$HOME_DIR/.config/apes/auth.json"
1883
+ if [ -f "$HOME_DIR/.config/openape/claude-token.env" ]; then
1884
+ chmod 700 "$HOME_DIR/.config/openape"
1885
+ chmod 600 "$HOME_DIR/.config/openape/claude-token.env"
1886
+ fi
1864
1887
 
1865
1888
  echo "OK $NAME uid=$NEXT_UID home=$HOME_DIR"
1866
1889
  `;
@@ -2068,6 +2091,11 @@ var destroyAgentCommand = defineCommand20({
2068
2091
  }
2069
2092
  consola18.warn(`About to destroy "${name}":
2070
2093
  ${consequences.join("\n")}`);
2094
+ if (!process.stdin.isTTY) {
2095
+ throw new CliError(
2096
+ "No TTY available for the interactive confirmation. Re-run with --force to skip the prompt (this is the same flag CI uses)."
2097
+ );
2098
+ }
2071
2099
  const confirmed = await consola18.prompt("Proceed?", { type: "confirm", initial: false });
2072
2100
  if (typeof confirmed === "symbol" || !confirmed) {
2073
2101
  throw new CliExit(0);
@@ -2268,7 +2296,7 @@ import { defineCommand as defineCommand23 } from "citty";
2268
2296
  import consola21 from "consola";
2269
2297
 
2270
2298
  // src/lib/keygen.ts
2271
- import { Buffer as Buffer3 } from "buffer";
2299
+ import { Buffer as Buffer4 } from "buffer";
2272
2300
  import { existsSync as existsSync5, mkdirSync, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
2273
2301
  import { generateKeyPairSync } from "crypto";
2274
2302
  import { homedir as homedir4 } from "os";
@@ -2278,11 +2306,11 @@ function resolveKeyPath(p) {
2278
2306
  }
2279
2307
  function buildSshEd25519Line(rawPub) {
2280
2308
  const keyTypeStr = "ssh-ed25519";
2281
- const keyTypeLen = Buffer3.alloc(4);
2309
+ const keyTypeLen = Buffer4.alloc(4);
2282
2310
  keyTypeLen.writeUInt32BE(keyTypeStr.length);
2283
- const pubKeyLen = Buffer3.alloc(4);
2311
+ const pubKeyLen = Buffer4.alloc(4);
2284
2312
  pubKeyLen.writeUInt32BE(rawPub.length);
2285
- const blob = Buffer3.concat([keyTypeLen, Buffer3.from(keyTypeStr), pubKeyLen, rawPub]);
2313
+ const blob = Buffer4.concat([keyTypeLen, Buffer4.from(keyTypeStr), pubKeyLen, rawPub]);
2286
2314
  return `ssh-ed25519 ${blob.toString("base64")}`;
2287
2315
  }
2288
2316
  function readPublicKey(keyPath) {
@@ -2293,7 +2321,7 @@ function readPublicKey(keyPath) {
2293
2321
  const keyContent = readFileSync4(keyPath, "utf-8");
2294
2322
  const privateKey = loadEd25519PrivateKey(keyContent);
2295
2323
  const jwk = privateKey.export({ format: "jwk" });
2296
- const pubBytes = Buffer3.from(jwk.x, "base64url");
2324
+ const pubBytes = Buffer4.from(jwk.x, "base64url");
2297
2325
  return buildSshEd25519Line(pubBytes);
2298
2326
  }
2299
2327
  function generateAndSaveKey(keyPath) {
@@ -2306,7 +2334,7 @@ function generateAndSaveKey(keyPath) {
2306
2334
  const privatePem = privateKey.export({ type: "pkcs8", format: "pem" });
2307
2335
  writeFileSync2(resolved, privatePem, { mode: 384 });
2308
2336
  const jwk = publicKey.export({ format: "jwk" });
2309
- const pubBytes = Buffer3.from(jwk.x, "base64url");
2337
+ const pubBytes = Buffer4.from(jwk.x, "base64url");
2310
2338
  const pubKeyStr = buildSshEd25519Line(pubBytes);
2311
2339
  writeFileSync2(`${resolved}.pub`, `${pubKeyStr}
2312
2340
  `, { mode: 420 });
@@ -2316,7 +2344,7 @@ function generateKeyPairInMemory() {
2316
2344
  const { publicKey, privateKey } = generateKeyPairSync("ed25519");
2317
2345
  const privatePem = privateKey.export({ type: "pkcs8", format: "pem" });
2318
2346
  const jwk = publicKey.export({ format: "jwk" });
2319
- const pubBytes = Buffer3.from(jwk.x, "base64url");
2347
+ const pubBytes = Buffer4.from(jwk.x, "base64url");
2320
2348
  return {
2321
2349
  privatePem,
2322
2350
  publicSshLine: buildSshEd25519Line(pubBytes)
@@ -2342,6 +2370,14 @@ var spawnAgentCommand = defineCommand23({
2342
2370
  "no-claude-hook": {
2343
2371
  type: "boolean",
2344
2372
  description: "Skip writing ~/.claude/settings.json + the Bash-rewrite hook"
2373
+ },
2374
+ "claude-token": {
2375
+ type: "string",
2376
+ description: "Claude Code OAuth token (sk-ant-oat01-\u2026) from `claude setup-token`. Visible to ps \u2014 prefer --claude-token-stdin in scripts."
2377
+ },
2378
+ "claude-token-stdin": {
2379
+ type: "boolean",
2380
+ description: "Read the Claude Code OAuth token from stdin (paranoid form of --claude-token)."
2345
2381
  }
2346
2382
  },
2347
2383
  async run({ args }) {
@@ -2408,6 +2444,10 @@ and try again.`
2408
2444
  expiresAt: Math.floor(Date.now() / 1e3) + expiresIn
2409
2445
  });
2410
2446
  const includeClaudeHook = !args["no-claude-hook"];
2447
+ const claudeOauthToken = await resolveClaudeToken({
2448
+ flag: typeof args["claude-token"] === "string" ? args["claude-token"] : void 0,
2449
+ fromStdin: !!args["claude-token-stdin"]
2450
+ });
2411
2451
  const script = buildSpawnSetupScript({
2412
2452
  name,
2413
2453
  homeDir,
@@ -2416,7 +2456,8 @@ and try again.`
2416
2456
  publicKeySshLine: publicSshLine,
2417
2457
  authJson,
2418
2458
  claudeSettingsJson: includeClaudeHook ? CLAUDE_SETTINGS_JSON : null,
2419
- hookScriptSource: includeClaudeHook ? BASH_VIA_APE_SHELL_HOOK_SOURCE : null
2459
+ hookScriptSource: includeClaudeHook ? BASH_VIA_APE_SHELL_HOOK_SOURCE : null,
2460
+ claudeOauthToken
2420
2461
  });
2421
2462
  writeFileSync3(scriptPath, script, { mode: 448 });
2422
2463
  consola21.start("Running privileged setup as root via `apes run --as root --wait`\u2026");
@@ -2431,6 +2472,28 @@ and try again.`
2431
2472
  }
2432
2473
  }
2433
2474
  });
2475
+ async function resolveClaudeToken(opts) {
2476
+ if (opts.flag && opts.fromStdin) {
2477
+ throw new CliError("Pass --claude-token OR --claude-token-stdin, not both.");
2478
+ }
2479
+ let raw = null;
2480
+ if (typeof opts.flag === "string") {
2481
+ raw = opts.flag.trim();
2482
+ } else if (opts.fromStdin) {
2483
+ const chunks = [];
2484
+ for await (const chunk of process.stdin) {
2485
+ chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
2486
+ }
2487
+ raw = Buffer.concat(chunks).toString("utf-8").trim();
2488
+ }
2489
+ if (!raw) return null;
2490
+ if (!raw.startsWith("sk-ant-oat01-")) {
2491
+ throw new CliError(
2492
+ `Claude token doesn't look right (expected sk-ant-oat01-\u2026). Run \`claude setup-token\` and paste the resulting token.`
2493
+ );
2494
+ }
2495
+ return raw;
2496
+ }
2434
2497
 
2435
2498
  // src/commands/agents/index.ts
2436
2499
  var agentsCommand = defineCommand24({
@@ -3698,7 +3761,7 @@ var mcpCommand = defineCommand32({
3698
3761
  if (transport !== "stdio" && transport !== "sse") {
3699
3762
  throw new Error('Transport must be "stdio" or "sse"');
3700
3763
  }
3701
- const { startMcpServer } = await import("./server-XZHBOWRD.js");
3764
+ const { startMcpServer } = await import("./server-3KAKSSMI.js");
3702
3765
  await startMcpServer(transport, port);
3703
3766
  }
3704
3767
  });
@@ -3858,7 +3921,7 @@ async function initIdP(targetDir) {
3858
3921
  }
3859
3922
 
3860
3923
  // src/commands/enroll.ts
3861
- import { Buffer as Buffer4 } from "buffer";
3924
+ import { Buffer as Buffer5 } from "buffer";
3862
3925
  import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
3863
3926
  import { execFile as execFile2 } from "child_process";
3864
3927
  import { sign as sign2 } from "crypto";
@@ -3889,7 +3952,7 @@ async function pollForEnrollment(idp, agentEmail, keyPath) {
3889
3952
  });
3890
3953
  if (challengeResp.ok) {
3891
3954
  const { challenge } = await challengeResp.json();
3892
- const signature = sign2(null, Buffer4.from(challenge), privateKey).toString("base64");
3955
+ const signature = sign2(null, Buffer5.from(challenge), privateKey).toString("base64");
3893
3956
  const authResp = await fetch(authenticateUrl, {
3894
3957
  method: "POST",
3895
3958
  headers: { "Content-Type": "application/json" },
@@ -4336,7 +4399,7 @@ async function bestEffortGrantCount(idp) {
4336
4399
  }
4337
4400
  }
4338
4401
  async function runHealth(args) {
4339
- const version = true ? "0.20.0" : "0.0.0";
4402
+ const version = true ? "0.21.1" : "0.0.0";
4340
4403
  const auth = loadAuth();
4341
4404
  if (!auth) {
4342
4405
  throw new CliError("Not logged in. Run `apes login` first.", 1);
@@ -4538,10 +4601,10 @@ if (shellRewrite) {
4538
4601
  if (shellRewrite.action === "rewrite") {
4539
4602
  process.argv = shellRewrite.argv;
4540
4603
  } else if (shellRewrite.action === "version") {
4541
- console.log(`ape-shell ${"0.20.0"} (OpenApe DDISA shell wrapper)`);
4604
+ console.log(`ape-shell ${"0.21.1"} (OpenApe DDISA shell wrapper)`);
4542
4605
  process.exit(0);
4543
4606
  } else if (shellRewrite.action === "help") {
4544
- console.log(`ape-shell ${"0.20.0"} \u2014 OpenApe DDISA shell wrapper`);
4607
+ console.log(`ape-shell ${"0.21.1"} \u2014 OpenApe DDISA shell wrapper`);
4545
4608
  console.log("");
4546
4609
  console.log("Usage:");
4547
4610
  console.log(" ape-shell Start interactive grant-mediated REPL");
@@ -4599,7 +4662,7 @@ var configCommand = defineCommand44({
4599
4662
  var main = defineCommand44({
4600
4663
  meta: {
4601
4664
  name: "apes",
4602
- version: "0.20.0",
4665
+ version: "0.21.1",
4603
4666
  description: "Unified CLI for OpenApe"
4604
4667
  },
4605
4668
  subCommands: {