@openape/apes 1.9.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/chunk-TDSCDH5P.js +518 -0
- package/dist/chunk-TDSCDH5P.js.map +1 -0
- package/dist/cli.js +165 -625
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +89 -1
- package/dist/index.js +10 -2
- package/dist/{server-6WQYPDVO.js → server-F3ALNNYS.js} +2 -2
- package/dist/{server-6WQYPDVO.js.map → server-F3ALNNYS.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-ZSJU7IXE.js +0 -45
- package/dist/chunk-ZSJU7IXE.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -7,8 +7,11 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
CliError,
|
|
9
9
|
CliExit,
|
|
10
|
-
|
|
11
|
-
|
|
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((
|
|
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
|
-
|
|
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:
|
|
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 =
|
|
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((
|
|
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((
|
|
2268
|
+
await new Promise((resolve4) => setTimeout(resolve4, retryDelay));
|
|
2266
2269
|
}
|
|
2267
2270
|
return $fetchRaw(context.request, {
|
|
2268
2271
|
...context.options,
|
|
@@ -2702,23 +2705,9 @@ chown root:wheel ${shQuote(bridge.plistPath)}
|
|
|
2702
2705
|
chmod 644 ${shQuote(bridge.plistPath)}
|
|
2703
2706
|
`;
|
|
2704
2707
|
}
|
|
2705
|
-
function buildBridgeBootstrapBlock(bridge,
|
|
2708
|
+
function buildBridgeBootstrapBlock(bridge, _name) {
|
|
2706
2709
|
if (!bridge) return "";
|
|
2707
2710
|
return `
|
|
2708
|
-
echo "==> Installing bridge stack as ${name} via bun (one-time)\u2026"
|
|
2709
|
-
su - ${shQuote(name)} -c '
|
|
2710
|
-
set -euo pipefail
|
|
2711
|
-
if ! command -v bun >/dev/null 2>&1 && [ ! -x "$HOME/.bun/bin/bun" ]; then
|
|
2712
|
-
echo "==> bun not found \u2014 installing via official installer"
|
|
2713
|
-
curl -fsSL https://bun.sh/install | bash
|
|
2714
|
-
fi
|
|
2715
|
-
export PATH="$HOME/.bun/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:$HOME/.bun/install/global/bin"
|
|
2716
|
-
bun add -g @openape/chat-bridge @openape/apes
|
|
2717
|
-
'
|
|
2718
|
-
|
|
2719
|
-
# Bootstrap into the system domain. Spawn already runs as root via
|
|
2720
|
-
# \`apes run --as root\`, so we have permission. Stale label is bootouted
|
|
2721
|
-
# first to make re-spawn idempotent.
|
|
2722
2711
|
launchctl bootout "system/${bridge.plistLabel}" 2>/dev/null || true
|
|
2723
2712
|
launchctl bootstrap system ${shQuote(bridge.plistPath)} || \\
|
|
2724
2713
|
echo "warn: bridge bootstrap into system domain failed; check ${bridge.plistPath}"
|
|
@@ -3006,7 +2995,7 @@ function readPasswordSilent(prompt) {
|
|
|
3006
2995
|
"No TTY available for the silent password prompt. Set APES_ADMIN_PASSWORD in the environment instead."
|
|
3007
2996
|
));
|
|
3008
2997
|
}
|
|
3009
|
-
return new Promise((
|
|
2998
|
+
return new Promise((resolve4, reject) => {
|
|
3010
2999
|
process.stdout.write(prompt);
|
|
3011
3000
|
const wasRaw = process.stdin.isRaw ?? false;
|
|
3012
3001
|
process.stdin.setRawMode(true);
|
|
@@ -3021,7 +3010,7 @@ function readPasswordSilent(prompt) {
|
|
|
3021
3010
|
if (ch === "\r" || ch === "\n") {
|
|
3022
3011
|
cleanup();
|
|
3023
3012
|
process.stdout.write("\n");
|
|
3024
|
-
|
|
3013
|
+
resolve4(buf);
|
|
3025
3014
|
return;
|
|
3026
3015
|
}
|
|
3027
3016
|
if (code === 3) {
|
|
@@ -3317,481 +3306,12 @@ var registerAgentCommand = defineCommand23({
|
|
|
3317
3306
|
});
|
|
3318
3307
|
|
|
3319
3308
|
// src/commands/agents/run.ts
|
|
3320
|
-
import { existsSync as existsSync5, readFileSync as
|
|
3321
|
-
import { homedir as
|
|
3309
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
3310
|
+
import { homedir as homedir4 } from "os";
|
|
3322
3311
|
import { join as join3 } from "path";
|
|
3323
3312
|
import { defineCommand as defineCommand24 } from "citty";
|
|
3324
3313
|
import consola22 from "consola";
|
|
3325
3314
|
|
|
3326
|
-
// src/lib/agent-tools/file.ts
|
|
3327
|
-
import { mkdirSync, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
3328
|
-
import { homedir as homedir4 } from "os";
|
|
3329
|
-
import { dirname, normalize, resolve as resolve2 } from "path";
|
|
3330
|
-
var MAX_BYTES = 1024 * 1024;
|
|
3331
|
-
function jailPath(input) {
|
|
3332
|
-
if (typeof input !== "string" || input === "") {
|
|
3333
|
-
throw new Error("path must be a non-empty string");
|
|
3334
|
-
}
|
|
3335
|
-
const home = homedir4();
|
|
3336
|
-
const candidate = input.startsWith("~/") ? resolve2(home, input.slice(2)) : input.startsWith("/") ? normalize(input) : resolve2(home, input);
|
|
3337
|
-
if (candidate !== home && !candidate.startsWith(`${home}/`)) {
|
|
3338
|
-
throw new Error(`path "${input}" resolves outside the agent's home`);
|
|
3339
|
-
}
|
|
3340
|
-
return candidate;
|
|
3341
|
-
}
|
|
3342
|
-
var fileTools = [
|
|
3343
|
-
{
|
|
3344
|
-
name: "file.read",
|
|
3345
|
-
description: "Read a UTF-8 file from the agent's home directory ($HOME). Capped at 1MB. Path traversal blocked.",
|
|
3346
|
-
parameters: {
|
|
3347
|
-
type: "object",
|
|
3348
|
-
properties: {
|
|
3349
|
-
path: { type: "string", description: "Path relative to $HOME (or absolute under $HOME). `..` segments are rejected." }
|
|
3350
|
-
},
|
|
3351
|
-
required: ["path"]
|
|
3352
|
-
},
|
|
3353
|
-
execute: async (args) => {
|
|
3354
|
-
const a = args;
|
|
3355
|
-
const p2 = jailPath(a.path);
|
|
3356
|
-
const content = readFileSync4(p2, "utf8");
|
|
3357
|
-
if (Buffer.byteLength(content, "utf8") > MAX_BYTES) {
|
|
3358
|
-
return { path: p2, truncated: true, content: content.slice(0, MAX_BYTES) };
|
|
3359
|
-
}
|
|
3360
|
-
return { path: p2, truncated: false, content };
|
|
3361
|
-
}
|
|
3362
|
-
},
|
|
3363
|
-
{
|
|
3364
|
-
name: "file.write",
|
|
3365
|
-
description: "Write a UTF-8 file under the agent's home directory. Creates parent dirs as needed. 1MB max.",
|
|
3366
|
-
parameters: {
|
|
3367
|
-
type: "object",
|
|
3368
|
-
properties: {
|
|
3369
|
-
path: { type: "string", description: "Path relative to $HOME (or absolute under $HOME)." },
|
|
3370
|
-
content: { type: "string", description: "File body. Existing files are overwritten." }
|
|
3371
|
-
},
|
|
3372
|
-
required: ["path", "content"]
|
|
3373
|
-
},
|
|
3374
|
-
execute: async (args) => {
|
|
3375
|
-
const a = args;
|
|
3376
|
-
if (typeof a.content !== "string") throw new Error("content must be a string");
|
|
3377
|
-
if (Buffer.byteLength(a.content, "utf8") > MAX_BYTES) {
|
|
3378
|
-
throw new Error(`content exceeds ${MAX_BYTES} byte cap`);
|
|
3379
|
-
}
|
|
3380
|
-
const p2 = jailPath(a.path);
|
|
3381
|
-
mkdirSync(dirname(p2), { recursive: true });
|
|
3382
|
-
writeFileSync2(p2, a.content, { encoding: "utf8" });
|
|
3383
|
-
return { path: p2, bytes: Buffer.byteLength(a.content, "utf8") };
|
|
3384
|
-
}
|
|
3385
|
-
}
|
|
3386
|
-
];
|
|
3387
|
-
|
|
3388
|
-
// src/lib/agent-tools/http.ts
|
|
3389
|
-
var MAX_BYTES2 = 1024 * 1024;
|
|
3390
|
-
var FORBIDDEN_HEADERS = /* @__PURE__ */ new Set([
|
|
3391
|
-
"host",
|
|
3392
|
-
"authorization",
|
|
3393
|
-
"cookie",
|
|
3394
|
-
"connection",
|
|
3395
|
-
"transfer-encoding",
|
|
3396
|
-
"upgrade",
|
|
3397
|
-
"proxy-authorization"
|
|
3398
|
-
]);
|
|
3399
|
-
function sanitizeHeaders(input) {
|
|
3400
|
-
if (!input || typeof input !== "object") return {};
|
|
3401
|
-
const out = {};
|
|
3402
|
-
for (const [k, v] of Object.entries(input)) {
|
|
3403
|
-
if (typeof v !== "string") continue;
|
|
3404
|
-
if (FORBIDDEN_HEADERS.has(k.toLowerCase())) continue;
|
|
3405
|
-
out[k] = v;
|
|
3406
|
-
}
|
|
3407
|
-
return out;
|
|
3408
|
-
}
|
|
3409
|
-
async function readCappedBody(res) {
|
|
3410
|
-
const buf = new Uint8Array(MAX_BYTES2 + 1);
|
|
3411
|
-
let written = 0;
|
|
3412
|
-
const reader = res.body?.getReader();
|
|
3413
|
-
if (!reader) return await res.text();
|
|
3414
|
-
while (true) {
|
|
3415
|
-
const { value, done } = await reader.read();
|
|
3416
|
-
if (done) break;
|
|
3417
|
-
if (written + value.byteLength > MAX_BYTES2) {
|
|
3418
|
-
buf.set(value.subarray(0, MAX_BYTES2 - written), written);
|
|
3419
|
-
written = MAX_BYTES2;
|
|
3420
|
-
try {
|
|
3421
|
-
await reader.cancel();
|
|
3422
|
-
} catch {
|
|
3423
|
-
}
|
|
3424
|
-
break;
|
|
3425
|
-
}
|
|
3426
|
-
buf.set(value, written);
|
|
3427
|
-
written += value.byteLength;
|
|
3428
|
-
}
|
|
3429
|
-
return new TextDecoder().decode(buf.subarray(0, written));
|
|
3430
|
-
}
|
|
3431
|
-
var httpTools = [
|
|
3432
|
-
{
|
|
3433
|
-
name: "http.get",
|
|
3434
|
-
description: "GET an HTTPS URL and return the response body (capped at 1MB). Useful for reading public APIs, RSS feeds, web pages.",
|
|
3435
|
-
parameters: {
|
|
3436
|
-
type: "object",
|
|
3437
|
-
properties: {
|
|
3438
|
-
url: { type: "string", description: "Absolute HTTPS URL." },
|
|
3439
|
-
headers: { type: "object", description: "Optional headers (Host, Authorization, Cookie are stripped)." }
|
|
3440
|
-
},
|
|
3441
|
-
required: ["url"]
|
|
3442
|
-
},
|
|
3443
|
-
execute: async (args) => {
|
|
3444
|
-
const a = args;
|
|
3445
|
-
if (typeof a.url !== "string" || !a.url.startsWith("http")) {
|
|
3446
|
-
throw new Error("url must be an http(s) URL");
|
|
3447
|
-
}
|
|
3448
|
-
const res = await fetch(a.url, { method: "GET", headers: sanitizeHeaders(a.headers) });
|
|
3449
|
-
const body = await readCappedBody(res);
|
|
3450
|
-
return { status: res.status, headers: Object.fromEntries(res.headers), body };
|
|
3451
|
-
}
|
|
3452
|
-
},
|
|
3453
|
-
{
|
|
3454
|
-
name: "http.post",
|
|
3455
|
-
description: "POST JSON to an HTTPS URL and return the response body (capped at 1MB).",
|
|
3456
|
-
parameters: {
|
|
3457
|
-
type: "object",
|
|
3458
|
-
properties: {
|
|
3459
|
-
url: { type: "string", description: "Absolute HTTPS URL." },
|
|
3460
|
-
body: { description: "JSON-serialisable payload." },
|
|
3461
|
-
headers: { type: "object", description: "Optional headers (Host, Authorization, Cookie are stripped)." }
|
|
3462
|
-
},
|
|
3463
|
-
required: ["url", "body"]
|
|
3464
|
-
},
|
|
3465
|
-
execute: async (args) => {
|
|
3466
|
-
const a = args;
|
|
3467
|
-
if (typeof a.url !== "string" || !a.url.startsWith("http")) {
|
|
3468
|
-
throw new Error("url must be an http(s) URL");
|
|
3469
|
-
}
|
|
3470
|
-
const res = await fetch(a.url, {
|
|
3471
|
-
method: "POST",
|
|
3472
|
-
headers: { "content-type": "application/json", ...sanitizeHeaders(a.headers) },
|
|
3473
|
-
body: JSON.stringify(a.body)
|
|
3474
|
-
});
|
|
3475
|
-
const body = await readCappedBody(res);
|
|
3476
|
-
return { status: res.status, headers: Object.fromEntries(res.headers), body };
|
|
3477
|
-
}
|
|
3478
|
-
}
|
|
3479
|
-
];
|
|
3480
|
-
|
|
3481
|
-
// src/lib/agent-tools/mail.ts
|
|
3482
|
-
import { execFileSync as execFileSync5 } from "child_process";
|
|
3483
|
-
function o365(args) {
|
|
3484
|
-
try {
|
|
3485
|
-
return execFileSync5("o365-cli", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
3486
|
-
} catch (err) {
|
|
3487
|
-
const e = err;
|
|
3488
|
-
if (e.code === "ENOENT") {
|
|
3489
|
-
throw new Error("o365-cli is not installed on this agent host");
|
|
3490
|
-
}
|
|
3491
|
-
const stderr = typeof e.stderr === "string" ? e.stderr : e.stderr?.toString("utf8");
|
|
3492
|
-
throw new Error(`o365-cli failed: ${stderr ?? e.message ?? err}`);
|
|
3493
|
-
}
|
|
3494
|
-
}
|
|
3495
|
-
var mailTools = [
|
|
3496
|
-
{
|
|
3497
|
-
name: "mail.list",
|
|
3498
|
-
description: "List recent inbox messages via o365-cli. Optional `unread_only` and `limit`.",
|
|
3499
|
-
parameters: {
|
|
3500
|
-
type: "object",
|
|
3501
|
-
properties: {
|
|
3502
|
-
limit: { type: "integer", minimum: 1, maximum: 100, default: 20 },
|
|
3503
|
-
unread_only: { type: "boolean", default: false }
|
|
3504
|
-
},
|
|
3505
|
-
required: []
|
|
3506
|
-
},
|
|
3507
|
-
execute: async (args) => {
|
|
3508
|
-
const a = args ?? {};
|
|
3509
|
-
const argv = ["mail", "list", "--json", "--limit", String(a.limit ?? 20)];
|
|
3510
|
-
if (a.unread_only) argv.push("--unread");
|
|
3511
|
-
const out = o365(argv);
|
|
3512
|
-
try {
|
|
3513
|
-
return JSON.parse(out);
|
|
3514
|
-
} catch {
|
|
3515
|
-
return { raw: out };
|
|
3516
|
-
}
|
|
3517
|
-
}
|
|
3518
|
-
},
|
|
3519
|
-
{
|
|
3520
|
-
name: "mail.search",
|
|
3521
|
-
description: "Search the inbox via o365-cli using a free-form query string.",
|
|
3522
|
-
parameters: {
|
|
3523
|
-
type: "object",
|
|
3524
|
-
properties: {
|
|
3525
|
-
q: { type: "string" },
|
|
3526
|
-
limit: { type: "integer", minimum: 1, maximum: 100, default: 20 }
|
|
3527
|
-
},
|
|
3528
|
-
required: ["q"]
|
|
3529
|
-
},
|
|
3530
|
-
execute: async (args) => {
|
|
3531
|
-
const a = args;
|
|
3532
|
-
if (typeof a.q !== "string" || a.q.length === 0) throw new Error("q is required");
|
|
3533
|
-
const argv = ["mail", "search", a.q, "--json", "--limit", String(a.limit ?? 20)];
|
|
3534
|
-
const out = o365(argv);
|
|
3535
|
-
try {
|
|
3536
|
-
return JSON.parse(out);
|
|
3537
|
-
} catch {
|
|
3538
|
-
return { raw: out };
|
|
3539
|
-
}
|
|
3540
|
-
}
|
|
3541
|
-
}
|
|
3542
|
-
];
|
|
3543
|
-
|
|
3544
|
-
// src/lib/agent-tools/tasks.ts
|
|
3545
|
-
import { execFileSync as execFileSync6 } from "child_process";
|
|
3546
|
-
function ape(args) {
|
|
3547
|
-
try {
|
|
3548
|
-
return execFileSync6("ape-tasks", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
3549
|
-
} catch (err) {
|
|
3550
|
-
const e = err;
|
|
3551
|
-
const stderr = typeof e.stderr === "string" ? e.stderr : e.stderr?.toString("utf8");
|
|
3552
|
-
throw new Error(`ape-tasks failed: ${stderr ?? e.message ?? err}`);
|
|
3553
|
-
}
|
|
3554
|
-
}
|
|
3555
|
-
var tasksTools = [
|
|
3556
|
-
{
|
|
3557
|
-
name: "tasks.list",
|
|
3558
|
-
description: "List the owner's open ape-tasks (the user's personal task list at tasks.openape.ai).",
|
|
3559
|
-
parameters: {
|
|
3560
|
-
type: "object",
|
|
3561
|
-
properties: {
|
|
3562
|
-
status: { type: "string", enum: ["open", "doing", "done", "archived"] },
|
|
3563
|
-
team_id: { type: "string" }
|
|
3564
|
-
},
|
|
3565
|
-
required: []
|
|
3566
|
-
},
|
|
3567
|
-
execute: async (args) => {
|
|
3568
|
-
const a = args ?? {};
|
|
3569
|
-
const argv = ["list", "--json"];
|
|
3570
|
-
if (a.status) argv.push("--status", a.status);
|
|
3571
|
-
if (a.team_id) argv.push("--team", a.team_id);
|
|
3572
|
-
const out = ape(argv);
|
|
3573
|
-
try {
|
|
3574
|
-
return JSON.parse(out);
|
|
3575
|
-
} catch {
|
|
3576
|
-
return { raw: out };
|
|
3577
|
-
}
|
|
3578
|
-
}
|
|
3579
|
-
},
|
|
3580
|
-
{
|
|
3581
|
-
name: "tasks.create",
|
|
3582
|
-
description: "Create a new ape-task on the owner's task list at tasks.openape.ai.",
|
|
3583
|
-
parameters: {
|
|
3584
|
-
type: "object",
|
|
3585
|
-
properties: {
|
|
3586
|
-
title: { type: "string" },
|
|
3587
|
-
notes: { type: "string" },
|
|
3588
|
-
priority: { type: "string", enum: ["low", "med", "high"] },
|
|
3589
|
-
due_at: { type: "string", description: "ISO date or +Nh/+Nd shorthand." }
|
|
3590
|
-
},
|
|
3591
|
-
required: ["title"]
|
|
3592
|
-
},
|
|
3593
|
-
execute: async (args) => {
|
|
3594
|
-
const a = args;
|
|
3595
|
-
const argv = ["new", "--title", a.title, "--json"];
|
|
3596
|
-
if (a.notes) argv.push("--notes", a.notes);
|
|
3597
|
-
if (a.priority) argv.push("--priority", a.priority);
|
|
3598
|
-
if (a.due_at) argv.push("--due", a.due_at);
|
|
3599
|
-
const out = ape(argv);
|
|
3600
|
-
try {
|
|
3601
|
-
return JSON.parse(out);
|
|
3602
|
-
} catch {
|
|
3603
|
-
return { raw: out };
|
|
3604
|
-
}
|
|
3605
|
-
}
|
|
3606
|
-
}
|
|
3607
|
-
];
|
|
3608
|
-
|
|
3609
|
-
// src/lib/agent-tools/time.ts
|
|
3610
|
-
var timeTools = [
|
|
3611
|
-
{
|
|
3612
|
-
name: "time.now",
|
|
3613
|
-
description: "Returns the current UTC date and time as ISO 8601 plus epoch seconds. No inputs.",
|
|
3614
|
-
parameters: { type: "object", properties: {}, required: [] },
|
|
3615
|
-
execute: async () => {
|
|
3616
|
-
const now = /* @__PURE__ */ new Date();
|
|
3617
|
-
return {
|
|
3618
|
-
iso: now.toISOString(),
|
|
3619
|
-
epoch_seconds: Math.floor(now.getTime() / 1e3),
|
|
3620
|
-
timezone_offset_minutes: -now.getTimezoneOffset()
|
|
3621
|
-
};
|
|
3622
|
-
}
|
|
3623
|
-
}
|
|
3624
|
-
];
|
|
3625
|
-
|
|
3626
|
-
// src/lib/agent-tools/index.ts
|
|
3627
|
-
var ALL_TOOLS = [
|
|
3628
|
-
...timeTools,
|
|
3629
|
-
...httpTools,
|
|
3630
|
-
...fileTools,
|
|
3631
|
-
...tasksTools,
|
|
3632
|
-
...mailTools
|
|
3633
|
-
];
|
|
3634
|
-
var TOOLS = Object.fromEntries(
|
|
3635
|
-
ALL_TOOLS.map((t) => [t.name, t])
|
|
3636
|
-
);
|
|
3637
|
-
function taskTools(names) {
|
|
3638
|
-
const out = [];
|
|
3639
|
-
const missing = [];
|
|
3640
|
-
for (const name of names) {
|
|
3641
|
-
const tool = TOOLS[name];
|
|
3642
|
-
if (!tool) missing.push(name);
|
|
3643
|
-
else out.push(tool);
|
|
3644
|
-
}
|
|
3645
|
-
if (missing.length > 0) {
|
|
3646
|
-
throw new Error(`unknown tool(s): ${missing.join(", ")}`);
|
|
3647
|
-
}
|
|
3648
|
-
return out;
|
|
3649
|
-
}
|
|
3650
|
-
function asOpenAiTools(tools) {
|
|
3651
|
-
return tools.map((t) => ({
|
|
3652
|
-
type: "function",
|
|
3653
|
-
function: { name: wireToolName(t.name), description: t.description, parameters: t.parameters }
|
|
3654
|
-
}));
|
|
3655
|
-
}
|
|
3656
|
-
function wireToolName(local) {
|
|
3657
|
-
return local.replace(/\./g, "_");
|
|
3658
|
-
}
|
|
3659
|
-
function localToolName(wire) {
|
|
3660
|
-
for (const t of Object.values(TOOLS)) {
|
|
3661
|
-
if (wireToolName(t.name) === wire) return t.name;
|
|
3662
|
-
}
|
|
3663
|
-
return wire;
|
|
3664
|
-
}
|
|
3665
|
-
|
|
3666
|
-
// src/lib/agent-runtime.ts
|
|
3667
|
-
function previewJson(value, max = 500) {
|
|
3668
|
-
let s;
|
|
3669
|
-
try {
|
|
3670
|
-
s = JSON.stringify(value);
|
|
3671
|
-
} catch {
|
|
3672
|
-
s = String(value);
|
|
3673
|
-
}
|
|
3674
|
-
return s.length > max ? `${s.slice(0, max)}\u2026` : s;
|
|
3675
|
-
}
|
|
3676
|
-
async function runLoop(opts) {
|
|
3677
|
-
const fetchFn = opts.fetchImpl ?? fetch;
|
|
3678
|
-
const trace = [];
|
|
3679
|
-
const messages = [
|
|
3680
|
-
{ role: "system", content: opts.systemPrompt },
|
|
3681
|
-
...opts.history ?? [],
|
|
3682
|
-
{ role: "user", content: opts.userMessage }
|
|
3683
|
-
];
|
|
3684
|
-
const tools = asOpenAiTools(opts.tools);
|
|
3685
|
-
for (let step = 1; step <= opts.maxSteps; step++) {
|
|
3686
|
-
const res = await fetchFn(`${opts.config.apiBase}/chat/completions`, {
|
|
3687
|
-
method: "POST",
|
|
3688
|
-
headers: {
|
|
3689
|
-
"authorization": `Bearer ${opts.config.apiKey}`,
|
|
3690
|
-
"content-type": "application/json"
|
|
3691
|
-
},
|
|
3692
|
-
body: JSON.stringify({
|
|
3693
|
-
model: opts.config.model,
|
|
3694
|
-
messages,
|
|
3695
|
-
...tools.length > 0 ? { tools, tool_choice: "auto" } : {}
|
|
3696
|
-
})
|
|
3697
|
-
});
|
|
3698
|
-
if (!res.ok) {
|
|
3699
|
-
const text = await res.text().catch(() => "");
|
|
3700
|
-
throw new Error(`LiteLLM ${res.status}: ${text.slice(0, 500)}`);
|
|
3701
|
-
}
|
|
3702
|
-
const data = await res.json();
|
|
3703
|
-
const choice = data.choices?.[0];
|
|
3704
|
-
if (!choice) throw new Error("LiteLLM response had no choices");
|
|
3705
|
-
const assistant = choice.message;
|
|
3706
|
-
messages.push(assistant);
|
|
3707
|
-
if (assistant.content) opts.handlers?.onTextDelta?.(assistant.content);
|
|
3708
|
-
trace.push({
|
|
3709
|
-
step,
|
|
3710
|
-
type: "assistant",
|
|
3711
|
-
preview: previewJson({ content: assistant.content, tool_calls: assistant.tool_calls?.length ?? 0 })
|
|
3712
|
-
});
|
|
3713
|
-
if (!assistant.tool_calls || assistant.tool_calls.length === 0) {
|
|
3714
|
-
const result2 = {
|
|
3715
|
-
status: "ok",
|
|
3716
|
-
finalMessage: assistant.content,
|
|
3717
|
-
stepCount: step,
|
|
3718
|
-
trace
|
|
3719
|
-
};
|
|
3720
|
-
opts.handlers?.onDone?.(result2);
|
|
3721
|
-
return result2;
|
|
3722
|
-
}
|
|
3723
|
-
for (const call of assistant.tool_calls) {
|
|
3724
|
-
const wireName = call.function.name;
|
|
3725
|
-
const localName = localToolName(wireName);
|
|
3726
|
-
const tool = opts.tools.find((t) => t.name === localName);
|
|
3727
|
-
let parsedArgs;
|
|
3728
|
-
try {
|
|
3729
|
-
parsedArgs = JSON.parse(call.function.arguments);
|
|
3730
|
-
} catch {
|
|
3731
|
-
parsedArgs = {};
|
|
3732
|
-
}
|
|
3733
|
-
opts.handlers?.onToolCall?.({ name: localName, args: parsedArgs });
|
|
3734
|
-
trace.push({ step, type: "tool_call", tool: localName, preview: previewJson(parsedArgs) });
|
|
3735
|
-
let result2;
|
|
3736
|
-
let isError = false;
|
|
3737
|
-
if (!tool) {
|
|
3738
|
-
result2 = `unknown tool: ${localName}`;
|
|
3739
|
-
isError = true;
|
|
3740
|
-
} else {
|
|
3741
|
-
try {
|
|
3742
|
-
result2 = await tool.execute(parsedArgs);
|
|
3743
|
-
} catch (err) {
|
|
3744
|
-
result2 = err?.message ?? String(err);
|
|
3745
|
-
isError = true;
|
|
3746
|
-
}
|
|
3747
|
-
}
|
|
3748
|
-
if (isError) {
|
|
3749
|
-
opts.handlers?.onToolError?.({ name: localName, error: String(result2) });
|
|
3750
|
-
trace.push({ step, type: "tool_error", tool: localName, preview: previewJson(result2) });
|
|
3751
|
-
} else {
|
|
3752
|
-
opts.handlers?.onToolResult?.({ name: localName, result: result2 });
|
|
3753
|
-
trace.push({ step, type: "tool_result", tool: localName, preview: previewJson(result2) });
|
|
3754
|
-
}
|
|
3755
|
-
messages.push({
|
|
3756
|
-
role: "tool",
|
|
3757
|
-
tool_call_id: call.id,
|
|
3758
|
-
name: wireToolName(localName),
|
|
3759
|
-
content: typeof result2 === "string" ? result2 : JSON.stringify(result2)
|
|
3760
|
-
});
|
|
3761
|
-
}
|
|
3762
|
-
}
|
|
3763
|
-
const result = {
|
|
3764
|
-
status: "error",
|
|
3765
|
-
finalMessage: `max_steps (${opts.maxSteps}) reached without completion`,
|
|
3766
|
-
stepCount: opts.maxSteps,
|
|
3767
|
-
trace
|
|
3768
|
-
};
|
|
3769
|
-
opts.handlers?.onDone?.(result);
|
|
3770
|
-
return result;
|
|
3771
|
-
}
|
|
3772
|
-
var RPC_SESSION_TTL_MS = 60 * 60 * 1e3;
|
|
3773
|
-
var RpcSessionMap = class {
|
|
3774
|
-
sessions = /* @__PURE__ */ new Map();
|
|
3775
|
-
get(id) {
|
|
3776
|
-
const s = this.sessions.get(id);
|
|
3777
|
-
if (s) s.lastTouched = Date.now();
|
|
3778
|
-
return s;
|
|
3779
|
-
}
|
|
3780
|
-
put(id, s) {
|
|
3781
|
-
s.lastTouched = Date.now();
|
|
3782
|
-
this.sessions.set(id, s);
|
|
3783
|
-
}
|
|
3784
|
-
evictStale() {
|
|
3785
|
-
const cutoff = Date.now() - RPC_SESSION_TTL_MS;
|
|
3786
|
-
for (const [k, v] of this.sessions) {
|
|
3787
|
-
if (v.lastTouched < cutoff) this.sessions.delete(k);
|
|
3788
|
-
}
|
|
3789
|
-
}
|
|
3790
|
-
size() {
|
|
3791
|
-
return this.sessions.size;
|
|
3792
|
-
}
|
|
3793
|
-
};
|
|
3794
|
-
|
|
3795
3315
|
// src/lib/troop-client.ts
|
|
3796
3316
|
var DEFAULT_TROOP_URL = "https://troop.openape.ai";
|
|
3797
3317
|
var TroopClient = class {
|
|
@@ -3850,13 +3370,13 @@ function resolveTroopUrl(override) {
|
|
|
3850
3370
|
}
|
|
3851
3371
|
|
|
3852
3372
|
// src/commands/agents/run.ts
|
|
3853
|
-
var AUTH_PATH = join3(
|
|
3854
|
-
var TASK_CACHE_DIR = join3(
|
|
3373
|
+
var AUTH_PATH = join3(homedir4(), ".config", "apes", "auth.json");
|
|
3374
|
+
var TASK_CACHE_DIR = join3(homedir4(), ".openape", "agent", "tasks");
|
|
3855
3375
|
function readAuth() {
|
|
3856
3376
|
if (!existsSync5(AUTH_PATH)) {
|
|
3857
3377
|
throw new CliError(`No agent auth found at ${AUTH_PATH}. Run \`apes agents spawn <name>\` first.`);
|
|
3858
3378
|
}
|
|
3859
|
-
const parsed = JSON.parse(
|
|
3379
|
+
const parsed = JSON.parse(readFileSync4(AUTH_PATH, "utf8"));
|
|
3860
3380
|
if (!parsed.access_token) throw new CliError("auth.json missing access_token");
|
|
3861
3381
|
return parsed;
|
|
3862
3382
|
}
|
|
@@ -3896,22 +3416,22 @@ function readTaskSpec(taskId) {
|
|
|
3896
3416
|
if (!existsSync5(path2)) {
|
|
3897
3417
|
throw new CliError(`No cached task spec at ${path2}. Run \`apes agents sync\` first to pull the task list from troop.`);
|
|
3898
3418
|
}
|
|
3899
|
-
return JSON.parse(
|
|
3419
|
+
return JSON.parse(readFileSync4(path2, "utf8"));
|
|
3900
3420
|
}
|
|
3901
|
-
var AGENT_CONFIG_PATH = join3(
|
|
3421
|
+
var AGENT_CONFIG_PATH = join3(homedir4(), ".openape", "agent", "agent.json");
|
|
3902
3422
|
function readAgentConfig() {
|
|
3903
3423
|
if (!existsSync5(AGENT_CONFIG_PATH)) return { systemPrompt: "" };
|
|
3904
3424
|
try {
|
|
3905
|
-
return JSON.parse(
|
|
3425
|
+
return JSON.parse(readFileSync4(AGENT_CONFIG_PATH, "utf8"));
|
|
3906
3426
|
} catch {
|
|
3907
3427
|
return { systemPrompt: "" };
|
|
3908
3428
|
}
|
|
3909
3429
|
}
|
|
3910
3430
|
function readLitellmConfig(model) {
|
|
3911
|
-
const envPath = join3(
|
|
3431
|
+
const envPath = join3(homedir4(), "litellm", ".env");
|
|
3912
3432
|
const env = {};
|
|
3913
3433
|
if (existsSync5(envPath)) {
|
|
3914
|
-
for (const line of
|
|
3434
|
+
for (const line of readFileSync4(envPath, "utf8").split(/\r?\n/)) {
|
|
3915
3435
|
const m = line.match(/^([A-Z_]+)=(.*)$/);
|
|
3916
3436
|
if (m) env[m[1]] = m[2].replace(/^["']|["']$/g, "");
|
|
3917
3437
|
}
|
|
@@ -4016,17 +3536,17 @@ var runAgentCommand = defineCommand24({
|
|
|
4016
3536
|
});
|
|
4017
3537
|
|
|
4018
3538
|
// src/commands/agents/serve.ts
|
|
4019
|
-
import { existsSync as existsSync6, readFileSync as
|
|
4020
|
-
import { homedir as
|
|
3539
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
|
|
3540
|
+
import { homedir as homedir5 } from "os";
|
|
4021
3541
|
import { join as join4 } from "path";
|
|
4022
3542
|
import { createInterface } from "readline";
|
|
4023
3543
|
import { defineCommand as defineCommand25 } from "citty";
|
|
4024
|
-
var AUTH_PATH2 = join4(
|
|
3544
|
+
var AUTH_PATH2 = join4(homedir5(), ".config", "apes", "auth.json");
|
|
4025
3545
|
function readLitellmConfig2(model) {
|
|
4026
|
-
const envPath = join4(
|
|
3546
|
+
const envPath = join4(homedir5(), "litellm", ".env");
|
|
4027
3547
|
const env = {};
|
|
4028
3548
|
if (existsSync6(envPath)) {
|
|
4029
|
-
for (const line of
|
|
3549
|
+
for (const line of readFileSync5(envPath, "utf8").split(/\r?\n/)) {
|
|
4030
3550
|
const m = line.match(/^([A-Z_]+)=(.*)$/);
|
|
4031
3551
|
if (m) env[m[1]] = m[2].replace(/^["']|["']$/g, "");
|
|
4032
3552
|
}
|
|
@@ -4060,7 +3580,7 @@ var serveAgentCommand = defineCommand25({
|
|
|
4060
3580
|
}
|
|
4061
3581
|
if (existsSync6(AUTH_PATH2)) {
|
|
4062
3582
|
try {
|
|
4063
|
-
JSON.parse(
|
|
3583
|
+
JSON.parse(readFileSync5(AUTH_PATH2, "utf8"));
|
|
4064
3584
|
} catch {
|
|
4065
3585
|
}
|
|
4066
3586
|
}
|
|
@@ -4135,8 +3655,8 @@ async function handleInbound(msg, sessions) {
|
|
|
4135
3655
|
}
|
|
4136
3656
|
|
|
4137
3657
|
// src/commands/agents/spawn.ts
|
|
4138
|
-
import { execFileSync as
|
|
4139
|
-
import { mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as
|
|
3658
|
+
import { execFileSync as execFileSync6 } from "child_process";
|
|
3659
|
+
import { mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
4140
3660
|
import { tmpdir as tmpdir2 } from "os";
|
|
4141
3661
|
import { join as join6 } from "path";
|
|
4142
3662
|
import { defineCommand as defineCommand26 } from "citty";
|
|
@@ -4152,7 +3672,8 @@ function escape(s) {
|
|
|
4152
3672
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
4153
3673
|
}
|
|
4154
3674
|
function buildSyncPlist(input) {
|
|
4155
|
-
const
|
|
3675
|
+
const pathDirs = (input.hostBinDirs && input.hostBinDirs.length > 0 ? input.hostBinDirs : ["/opt/homebrew/bin", "/usr/local/bin"]).join(":");
|
|
3676
|
+
const pathLine = ` <key>PATH</key><string>${escape(pathDirs)}:/usr/bin:/bin</string>
|
|
4156
3677
|
`;
|
|
4157
3678
|
const agentUserLine = ` <key>AGENT_USER</key><string>${escape(input.userName)}</string>
|
|
4158
3679
|
`;
|
|
@@ -4195,12 +3716,12 @@ ${envBlock} <key>StartInterval</key>
|
|
|
4195
3716
|
|
|
4196
3717
|
// src/lib/keygen.ts
|
|
4197
3718
|
import { Buffer as Buffer4 } from "buffer";
|
|
4198
|
-
import { existsSync as existsSync7, mkdirSync
|
|
3719
|
+
import { existsSync as existsSync7, mkdirSync, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "fs";
|
|
4199
3720
|
import { generateKeyPairSync } from "crypto";
|
|
4200
|
-
import { homedir as
|
|
4201
|
-
import { dirname
|
|
3721
|
+
import { homedir as homedir6 } from "os";
|
|
3722
|
+
import { dirname, resolve as resolve2 } from "path";
|
|
4202
3723
|
function resolveKeyPath(p2) {
|
|
4203
|
-
return
|
|
3724
|
+
return resolve2(p2.replace(/^~/, homedir6()));
|
|
4204
3725
|
}
|
|
4205
3726
|
function buildSshEd25519Line(rawPub) {
|
|
4206
3727
|
const keyTypeStr = "ssh-ed25519";
|
|
@@ -4214,9 +3735,9 @@ function buildSshEd25519Line(rawPub) {
|
|
|
4214
3735
|
function readPublicKey(keyPath) {
|
|
4215
3736
|
const pubPath = `${keyPath}.pub`;
|
|
4216
3737
|
if (existsSync7(pubPath)) {
|
|
4217
|
-
return
|
|
3738
|
+
return readFileSync6(pubPath, "utf-8").trim();
|
|
4218
3739
|
}
|
|
4219
|
-
const keyContent =
|
|
3740
|
+
const keyContent = readFileSync6(keyPath, "utf-8");
|
|
4220
3741
|
const privateKey = loadEd25519PrivateKey(keyContent);
|
|
4221
3742
|
const jwk = privateKey.export({ format: "jwk" });
|
|
4222
3743
|
const pubBytes = Buffer4.from(jwk.x, "base64url");
|
|
@@ -4224,17 +3745,17 @@ function readPublicKey(keyPath) {
|
|
|
4224
3745
|
}
|
|
4225
3746
|
function generateAndSaveKey(keyPath) {
|
|
4226
3747
|
const resolved = resolveKeyPath(keyPath);
|
|
4227
|
-
const dir =
|
|
3748
|
+
const dir = dirname(resolved);
|
|
4228
3749
|
if (!existsSync7(dir)) {
|
|
4229
|
-
|
|
3750
|
+
mkdirSync(dir, { recursive: true });
|
|
4230
3751
|
}
|
|
4231
3752
|
const { publicKey, privateKey } = generateKeyPairSync("ed25519");
|
|
4232
3753
|
const privatePem = privateKey.export({ type: "pkcs8", format: "pem" });
|
|
4233
|
-
|
|
3754
|
+
writeFileSync2(resolved, privatePem, { mode: 384 });
|
|
4234
3755
|
const jwk = publicKey.export({ format: "jwk" });
|
|
4235
3756
|
const pubBytes = Buffer4.from(jwk.x, "base64url");
|
|
4236
3757
|
const pubKeyStr = buildSshEd25519Line(pubBytes);
|
|
4237
|
-
|
|
3758
|
+
writeFileSync2(`${resolved}.pub`, `${pubKeyStr}
|
|
4238
3759
|
`, { mode: 420 });
|
|
4239
3760
|
return pubKeyStr;
|
|
4240
3761
|
}
|
|
@@ -4250,14 +3771,15 @@ function generateKeyPairInMemory() {
|
|
|
4250
3771
|
}
|
|
4251
3772
|
|
|
4252
3773
|
// src/lib/llm-bridge.ts
|
|
4253
|
-
import {
|
|
4254
|
-
import {
|
|
4255
|
-
import {
|
|
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";
|
|
4256
3778
|
var PLIST_LABEL_PREFIX = "eco.hofmann.apes.bridge";
|
|
4257
|
-
function readLitellmEnv(envPath = join5(
|
|
3779
|
+
function readLitellmEnv(envPath = join5(homedir7(), "litellm", ".env")) {
|
|
4258
3780
|
if (!existsSync8(envPath)) return null;
|
|
4259
3781
|
try {
|
|
4260
|
-
const text =
|
|
3782
|
+
const text = readFileSync7(envPath, "utf8");
|
|
4261
3783
|
const out = {};
|
|
4262
3784
|
for (const line of text.split("\n")) {
|
|
4263
3785
|
const trimmed = line.trim();
|
|
@@ -4287,6 +3809,25 @@ function resolveBridgeConfig(opts) {
|
|
|
4287
3809
|
}
|
|
4288
3810
|
return { baseUrl, apiKey, model };
|
|
4289
3811
|
}
|
|
3812
|
+
function captureHostBinDirs() {
|
|
3813
|
+
const dirs = [];
|
|
3814
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3815
|
+
for (const bin of ["node", "openape-chat-bridge", "apes"]) {
|
|
3816
|
+
let resolved;
|
|
3817
|
+
try {
|
|
3818
|
+
resolved = execFileSync5("/usr/bin/which", [bin], { encoding: "utf8" }).trim();
|
|
3819
|
+
} catch {
|
|
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)";
|
|
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.`);
|
|
3822
|
+
}
|
|
3823
|
+
const dir = dirname2(resolved);
|
|
3824
|
+
if (!seen.has(dir)) {
|
|
3825
|
+
seen.add(dir);
|
|
3826
|
+
dirs.push(dir);
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3829
|
+
return dirs;
|
|
3830
|
+
}
|
|
4290
3831
|
function bridgePlistLabel(agentName) {
|
|
4291
3832
|
return `${PLIST_LABEL_PREFIX}.${agentName}`;
|
|
4292
3833
|
}
|
|
@@ -4302,34 +3843,31 @@ LITELLM_BASE_URL=${cfg.baseUrl}
|
|
|
4302
3843
|
LITELLM_API_KEY=${cfg.apiKey}
|
|
4303
3844
|
${modelLine}`;
|
|
4304
3845
|
}
|
|
4305
|
-
function buildBridgeStartScript() {
|
|
3846
|
+
function buildBridgeStartScript(hostBinDirs) {
|
|
3847
|
+
const pathLine = `export PATH="${hostBinDirs.join(":")}:/usr/bin:/bin"`;
|
|
4306
3848
|
return `#!/usr/bin/env bash
|
|
4307
3849
|
# Auto-generated by 'apes agents spawn --bridge'.
|
|
4308
|
-
# Slim launcher \u2014
|
|
3850
|
+
# Slim launcher \u2014 bridge stack lives on the host, no per-agent install.
|
|
4309
3851
|
set -euo pipefail
|
|
4310
3852
|
|
|
4311
|
-
|
|
3853
|
+
${pathLine}
|
|
4312
3854
|
|
|
4313
3855
|
# Token refresh is in-process via @openape/cli-auth's challenge-response
|
|
4314
3856
|
# path (auth.json.key_path -> ~/.ssh/id_ed25519). No "apes login" needed
|
|
4315
3857
|
# at boot \u2014 keeping start.sh slim avoids the rate-limit dance the old
|
|
4316
3858
|
# refresh hit when KeepAlive crash-restarted the daemon every 1h.
|
|
4317
3859
|
|
|
4318
|
-
# M6 dropped the third-party LLM-runtime install + extension write
|
|
4319
|
-
# that used to live here. The bridge now spawns
|
|
4320
|
-
# \`apes agents serve --rpc\` directly (M8) which calls LiteLLM
|
|
4321
|
-
# itself, so no third-party extension config is needed.
|
|
4322
|
-
|
|
4323
3860
|
set -a
|
|
4324
3861
|
. "$HOME/Library/Application Support/openape/bridge/.env"
|
|
4325
3862
|
set +a
|
|
4326
3863
|
exec openape-chat-bridge
|
|
4327
3864
|
`;
|
|
4328
3865
|
}
|
|
4329
|
-
function buildBridgePlist(agentName, homeDir, ownerEmail) {
|
|
3866
|
+
function buildBridgePlist(agentName, homeDir, ownerEmail, hostBinDirs) {
|
|
4330
3867
|
const startScript = `${homeDir}/Library/Application Support/openape/bridge/start.sh`;
|
|
4331
3868
|
const stdoutLog = `${homeDir}/Library/Logs/openape-chat-bridge.log`;
|
|
4332
3869
|
const stderrLog = `${homeDir}/Library/Logs/openape-chat-bridge.err.log`;
|
|
3870
|
+
const pathValue = `${hostBinDirs.join(":")}:/usr/bin:/bin`;
|
|
4333
3871
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
4334
3872
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
4335
3873
|
<plist version="1.0">
|
|
@@ -4360,7 +3898,7 @@ function buildBridgePlist(agentName, homeDir, ownerEmail) {
|
|
|
4360
3898
|
<key>HOME</key>
|
|
4361
3899
|
<string>${homeDir}</string>
|
|
4362
3900
|
<key>PATH</key>
|
|
4363
|
-
<string>${
|
|
3901
|
+
<string>${pathValue}</string>
|
|
4364
3902
|
<key>OPENAPE_OWNER_EMAIL</key>
|
|
4365
3903
|
<string>${ownerEmail}</string>
|
|
4366
3904
|
</dict>
|
|
@@ -4498,20 +4036,22 @@ and try again.`
|
|
|
4498
4036
|
cliBaseUrl: typeof args["bridge-base-url"] === "string" ? args["bridge-base-url"] : void 0,
|
|
4499
4037
|
cliModel: typeof args["bridge-model"] === "string" ? args["bridge-model"] : void 0
|
|
4500
4038
|
});
|
|
4039
|
+
const hostBinDirs = captureHostBinDirs();
|
|
4501
4040
|
return {
|
|
4502
4041
|
plistLabel: bridgePlistLabel(name),
|
|
4503
4042
|
plistPath: bridgePlistPath(name),
|
|
4504
|
-
plistContent: buildBridgePlist(name, homeDir, auth.email),
|
|
4505
|
-
startScript: buildBridgeStartScript(),
|
|
4043
|
+
plistContent: buildBridgePlist(name, homeDir, auth.email, hostBinDirs),
|
|
4044
|
+
startScript: buildBridgeStartScript(hostBinDirs),
|
|
4506
4045
|
envFile: buildBridgeEnvFile(cfg)
|
|
4507
4046
|
};
|
|
4508
4047
|
})() : null;
|
|
4509
4048
|
const troopPlistLabel = `openape.troop.sync.${name}`;
|
|
4510
4049
|
const troopPlistPath = `/Library/LaunchDaemons/${troopPlistLabel}.plist`;
|
|
4050
|
+
const troopBinDirs = bridge ? captureHostBinDirs() : captureHostBinDirs();
|
|
4511
4051
|
const troop = {
|
|
4512
4052
|
plistLabel: troopPlistLabel,
|
|
4513
4053
|
plistPath: troopPlistPath,
|
|
4514
|
-
plistContent: buildSyncPlist({ agentName: name, apesBin: apes, homeDir, userName: name })
|
|
4054
|
+
plistContent: buildSyncPlist({ agentName: name, apesBin: apes, homeDir, userName: name, hostBinDirs: troopBinDirs })
|
|
4515
4055
|
};
|
|
4516
4056
|
const script = buildSpawnSetupScript({
|
|
4517
4057
|
name,
|
|
@@ -4526,10 +4066,10 @@ and try again.`
|
|
|
4526
4066
|
bridge,
|
|
4527
4067
|
troop
|
|
4528
4068
|
});
|
|
4529
|
-
|
|
4069
|
+
writeFileSync3(scriptPath, script, { mode: 448 });
|
|
4530
4070
|
consola23.start("Running privileged setup as root via `apes run --as root --wait`\u2026");
|
|
4531
4071
|
consola23.info("You will be asked to approve the as=root grant in your DDISA inbox; this command blocks until you do.");
|
|
4532
|
-
|
|
4072
|
+
execFileSync6(apes, ["run", "--as", "root", "--wait", "--", "bash", scriptPath], { stdio: "inherit" });
|
|
4533
4073
|
consola23.success(`Agent ${name} spawned.`);
|
|
4534
4074
|
consola23.info(`\u{1F517} Troop: https://troop.openape.ai/agents/${name}`);
|
|
4535
4075
|
if (args.bridge) {
|
|
@@ -4568,18 +4108,18 @@ async function resolveClaudeToken(opts) {
|
|
|
4568
4108
|
}
|
|
4569
4109
|
|
|
4570
4110
|
// src/commands/agents/sync.ts
|
|
4571
|
-
import { chownSync, existsSync as existsSync9, mkdirSync as
|
|
4572
|
-
import { homedir as
|
|
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";
|
|
4573
4113
|
import { join as join7 } from "path";
|
|
4574
4114
|
import { defineCommand as defineCommand27 } from "citty";
|
|
4575
4115
|
import consola24 from "consola";
|
|
4576
4116
|
|
|
4577
4117
|
// src/lib/macos-host.ts
|
|
4578
|
-
import { execFileSync as
|
|
4118
|
+
import { execFileSync as execFileSync7 } from "child_process";
|
|
4579
4119
|
import { hostname as hostname3 } from "os";
|
|
4580
4120
|
function getHostId() {
|
|
4581
4121
|
try {
|
|
4582
|
-
const output =
|
|
4122
|
+
const output = execFileSync7(
|
|
4583
4123
|
"/usr/sbin/ioreg",
|
|
4584
4124
|
["-d2", "-c", "IOPlatformExpertDevice"],
|
|
4585
4125
|
{ encoding: "utf8", timeout: 2e3 }
|
|
@@ -4599,15 +4139,15 @@ function getHostname() {
|
|
|
4599
4139
|
}
|
|
4600
4140
|
|
|
4601
4141
|
// src/commands/agents/sync.ts
|
|
4602
|
-
var AUTH_PATH3 = join7(
|
|
4603
|
-
var TASK_CACHE_DIR2 = join7(
|
|
4142
|
+
var AUTH_PATH3 = join7(homedir8(), ".config", "apes", "auth.json");
|
|
4143
|
+
var TASK_CACHE_DIR2 = join7(homedir8(), ".openape", "agent", "tasks");
|
|
4604
4144
|
function readAuthJson() {
|
|
4605
4145
|
if (!existsSync9(AUTH_PATH3)) {
|
|
4606
4146
|
throw new CliError(
|
|
4607
4147
|
`No agent auth found at ${AUTH_PATH3}. Run \`apes agents spawn <name>\` to provision an agent first.`
|
|
4608
4148
|
);
|
|
4609
4149
|
}
|
|
4610
|
-
const raw =
|
|
4150
|
+
const raw = readFileSync8(AUTH_PATH3, "utf8");
|
|
4611
4151
|
let parsed;
|
|
4612
4152
|
try {
|
|
4613
4153
|
parsed = JSON.parse(raw);
|
|
@@ -4668,7 +4208,7 @@ var syncAgentCommand = defineCommand27({
|
|
|
4668
4208
|
let agentGid = null;
|
|
4669
4209
|
if (process.geteuid?.() === 0) {
|
|
4670
4210
|
try {
|
|
4671
|
-
const homeStat = statSync(
|
|
4211
|
+
const homeStat = statSync(homedir8());
|
|
4672
4212
|
agentUid = homeStat.uid;
|
|
4673
4213
|
agentGid = homeStat.gid;
|
|
4674
4214
|
} catch {
|
|
@@ -4682,23 +4222,23 @@ var syncAgentCommand = defineCommand27({
|
|
|
4682
4222
|
}
|
|
4683
4223
|
}
|
|
4684
4224
|
}
|
|
4685
|
-
const agentDir = join7(
|
|
4686
|
-
|
|
4687
|
-
chownToAgent(join7(
|
|
4225
|
+
const agentDir = join7(homedir8(), ".openape", "agent");
|
|
4226
|
+
mkdirSync2(agentDir, { recursive: true });
|
|
4227
|
+
chownToAgent(join7(homedir8(), ".openape"));
|
|
4688
4228
|
chownToAgent(agentDir);
|
|
4689
4229
|
const agentJsonPath = join7(agentDir, "agent.json");
|
|
4690
|
-
|
|
4230
|
+
writeFileSync4(
|
|
4691
4231
|
agentJsonPath,
|
|
4692
4232
|
`${JSON.stringify({ systemPrompt }, null, 2)}
|
|
4693
4233
|
`,
|
|
4694
4234
|
{ mode: 384 }
|
|
4695
4235
|
);
|
|
4696
4236
|
chownToAgent(agentJsonPath);
|
|
4697
|
-
|
|
4237
|
+
mkdirSync2(TASK_CACHE_DIR2, { recursive: true });
|
|
4698
4238
|
chownToAgent(TASK_CACHE_DIR2);
|
|
4699
4239
|
for (const task of tasks) {
|
|
4700
4240
|
const path2 = join7(TASK_CACHE_DIR2, `${task.taskId}.json`);
|
|
4701
|
-
|
|
4241
|
+
writeFileSync4(path2, `${JSON.stringify(task, null, 2)}
|
|
4702
4242
|
`, { mode: 384 });
|
|
4703
4243
|
chownToAgent(path2);
|
|
4704
4244
|
}
|
|
@@ -4728,19 +4268,19 @@ var agentsCommand = defineCommand28({
|
|
|
4728
4268
|
import { defineCommand as defineCommand37 } from "citty";
|
|
4729
4269
|
|
|
4730
4270
|
// src/commands/nest/authorize.ts
|
|
4731
|
-
import { execFileSync as
|
|
4732
|
-
import { existsSync as existsSync11, readFileSync as
|
|
4271
|
+
import { execFileSync as execFileSync8 } from "child_process";
|
|
4272
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
|
|
4733
4273
|
import { join as join9 } from "path";
|
|
4734
4274
|
import { defineCommand as defineCommand30 } from "citty";
|
|
4735
4275
|
import consola26 from "consola";
|
|
4736
4276
|
|
|
4737
4277
|
// src/commands/nest/enroll.ts
|
|
4738
|
-
import { hostname as hostname4, homedir as
|
|
4739
|
-
import { existsSync as existsSync10, mkdirSync as
|
|
4278
|
+
import { hostname as hostname4, homedir as homedir9 } from "os";
|
|
4279
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync3, writeFileSync as writeFileSync5, chmodSync } from "fs";
|
|
4740
4280
|
import { join as join8 } from "path";
|
|
4741
4281
|
import { defineCommand as defineCommand29 } from "citty";
|
|
4742
4282
|
import consola25 from "consola";
|
|
4743
|
-
var NEST_DATA_DIR = join8(
|
|
4283
|
+
var NEST_DATA_DIR = join8(homedir9(), ".openape", "nest");
|
|
4744
4284
|
function nestAgentName() {
|
|
4745
4285
|
const raw = hostname4().toLowerCase();
|
|
4746
4286
|
const head = raw.split(".")[0] ?? raw;
|
|
@@ -4779,13 +4319,13 @@ var enrollNestCommand = defineCommand29({
|
|
|
4779
4319
|
}
|
|
4780
4320
|
const sshDir = join8(NEST_DATA_DIR, ".ssh");
|
|
4781
4321
|
const configDir = join8(NEST_DATA_DIR, ".config", "apes");
|
|
4782
|
-
|
|
4783
|
-
|
|
4322
|
+
mkdirSync3(sshDir, { recursive: true });
|
|
4323
|
+
mkdirSync3(configDir, { recursive: true });
|
|
4784
4324
|
consola25.start(`Generating keypair for ${name}\u2026`);
|
|
4785
4325
|
const { privatePem, publicSshLine } = generateKeyPairInMemory();
|
|
4786
|
-
|
|
4326
|
+
writeFileSync5(join8(sshDir, "id_ed25519"), `${privatePem.trimEnd()}
|
|
4787
4327
|
`, { mode: 384 });
|
|
4788
|
-
|
|
4328
|
+
writeFileSync5(join8(sshDir, "id_ed25519.pub"), `${publicSshLine}
|
|
4789
4329
|
`, { mode: 420 });
|
|
4790
4330
|
chmodSync(sshDir, 448);
|
|
4791
4331
|
consola25.start(`Registering nest at ${idp}\u2026`);
|
|
@@ -4805,7 +4345,7 @@ var enrollNestCommand = defineCommand29({
|
|
|
4805
4345
|
keyPath: join8(sshDir, "id_ed25519"),
|
|
4806
4346
|
ownerEmail: ownerAuth.email
|
|
4807
4347
|
});
|
|
4808
|
-
|
|
4348
|
+
writeFileSync5(authPath, authJson, { mode: 384 });
|
|
4809
4349
|
chmodSync(configDir, 448);
|
|
4810
4350
|
consola25.success(`Nest enrolled \u2014 auth.json at ${authPath}`);
|
|
4811
4351
|
consola25.info("");
|
|
@@ -4867,7 +4407,7 @@ var authorizeNestCommand = defineCommand30({
|
|
|
4867
4407
|
if (!existsSync11(nestAuthPath)) {
|
|
4868
4408
|
throw new CliError("Nest not enrolled. Run `apes nest enroll` first.");
|
|
4869
4409
|
}
|
|
4870
|
-
const nestAuth = JSON.parse(
|
|
4410
|
+
const nestAuth = JSON.parse(readFileSync9(nestAuthPath, "utf8"));
|
|
4871
4411
|
if (!nestAuth.email) throw new CliError(`${nestAuthPath} has no email`);
|
|
4872
4412
|
const allow = args.allow ?? DEFAULT_ALLOW_PATTERNS.join(",");
|
|
4873
4413
|
consola26.info(`Configuring YOLO-policy on ${nestAuth.email} via \`apes yolo set\`\u2026`);
|
|
@@ -4884,7 +4424,7 @@ var authorizeNestCommand = defineCommand30({
|
|
|
4884
4424
|
cmdArgs.push("--expires-in", args["expires-in"]);
|
|
4885
4425
|
}
|
|
4886
4426
|
try {
|
|
4887
|
-
|
|
4427
|
+
execFileSync8("apes", cmdArgs, { stdio: "inherit" });
|
|
4888
4428
|
} catch (err) {
|
|
4889
4429
|
throw new CliError(err instanceof Error ? err.message : String(err));
|
|
4890
4430
|
}
|
|
@@ -5029,9 +4569,9 @@ var destroyNestCommand = defineCommand31({
|
|
|
5029
4569
|
});
|
|
5030
4570
|
|
|
5031
4571
|
// src/commands/nest/install.ts
|
|
5032
|
-
import { execFileSync as
|
|
5033
|
-
import { existsSync as existsSync12, mkdirSync as
|
|
5034
|
-
import { homedir as
|
|
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";
|
|
5035
4575
|
import { dirname as dirname3, join as join10 } from "path";
|
|
5036
4576
|
import { defineCommand as defineCommand32 } from "citty";
|
|
5037
4577
|
import consola29 from "consola";
|
|
@@ -5101,7 +4641,7 @@ resource_chain = ["agents:name={name}", "allowlist:email={peer_email}"]
|
|
|
5101
4641
|
// src/commands/nest/install.ts
|
|
5102
4642
|
var PLIST_LABEL = "ai.openape.nest";
|
|
5103
4643
|
function plistPath() {
|
|
5104
|
-
return join10(
|
|
4644
|
+
return join10(homedir10(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
5105
4645
|
}
|
|
5106
4646
|
function escape2(s) {
|
|
5107
4647
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
@@ -5129,7 +4669,7 @@ function buildPlist(args) {
|
|
|
5129
4669
|
<key>EnvironmentVariables</key>
|
|
5130
4670
|
<dict>
|
|
5131
4671
|
<key>HOME</key><string>${escape2(args.nestHome)}</string>
|
|
5132
|
-
<key>PATH</key><string
|
|
4672
|
+
<key>PATH</key><string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
5133
4673
|
<key>OPENAPE_NEST_PORT</key><string>${args.port}</string>
|
|
5134
4674
|
<key>OPENAPE_APES_BIN</key><string>${escape2(args.apesBin)}</string>
|
|
5135
4675
|
</dict>
|
|
@@ -5142,34 +4682,34 @@ function buildPlist(args) {
|
|
|
5142
4682
|
`;
|
|
5143
4683
|
}
|
|
5144
4684
|
function installAdapter2() {
|
|
5145
|
-
const target = join10(
|
|
5146
|
-
|
|
4685
|
+
const target = join10(homedir10(), ".openape", "shapes", "adapters", "apes-agents.toml");
|
|
4686
|
+
mkdirSync4(dirname3(target), { recursive: true });
|
|
5147
4687
|
let existing = "";
|
|
5148
4688
|
try {
|
|
5149
|
-
existing =
|
|
4689
|
+
existing = readFileSync10(target, "utf8");
|
|
5150
4690
|
} catch {
|
|
5151
4691
|
}
|
|
5152
4692
|
if (existing === APES_AGENTS_ADAPTER_TOML) return false;
|
|
5153
|
-
|
|
4693
|
+
writeFileSync6(target, APES_AGENTS_ADAPTER_TOML, { mode: 420 });
|
|
5154
4694
|
consola29.success(`Wrote shapes adapter ${target}`);
|
|
5155
4695
|
return true;
|
|
5156
4696
|
}
|
|
5157
4697
|
function writeBridgeModelDefault(model) {
|
|
5158
|
-
const envDir = join10(
|
|
4698
|
+
const envDir = join10(homedir10(), "litellm");
|
|
5159
4699
|
const envFile = join10(envDir, ".env");
|
|
5160
|
-
|
|
4700
|
+
mkdirSync4(envDir, { recursive: true });
|
|
5161
4701
|
let lines = [];
|
|
5162
4702
|
if (existsSync12(envFile)) {
|
|
5163
|
-
lines =
|
|
4703
|
+
lines = readFileSync10(envFile, "utf8").split("\n").filter((l) => !l.startsWith("APE_CHAT_BRIDGE_MODEL="));
|
|
5164
4704
|
}
|
|
5165
4705
|
lines.push(`APE_CHAT_BRIDGE_MODEL=${model}`);
|
|
5166
4706
|
while (lines.length > 0 && lines.at(-1).trim() === "") lines.pop();
|
|
5167
|
-
|
|
4707
|
+
writeFileSync6(envFile, `${lines.join("\n")}
|
|
5168
4708
|
`, { mode: 384 });
|
|
5169
4709
|
}
|
|
5170
4710
|
function findBinary(name) {
|
|
5171
4711
|
for (const dir of [
|
|
5172
|
-
join10(
|
|
4712
|
+
join10(homedir10(), ".bun", "bin"),
|
|
5173
4713
|
"/opt/homebrew/bin",
|
|
5174
4714
|
"/usr/local/bin",
|
|
5175
4715
|
"/usr/bin"
|
|
@@ -5195,7 +4735,7 @@ var installNestCommand = defineCommand32({
|
|
|
5195
4735
|
}
|
|
5196
4736
|
},
|
|
5197
4737
|
async run({ args }) {
|
|
5198
|
-
const homeDir =
|
|
4738
|
+
const homeDir = homedir10();
|
|
5199
4739
|
const port = Number(args.port ?? 9091);
|
|
5200
4740
|
if (!Number.isInteger(port) || port < 1024 || port > 65535) {
|
|
5201
4741
|
throw new Error(`invalid port ${port}`);
|
|
@@ -5211,26 +4751,26 @@ var installNestCommand = defineCommand32({
|
|
|
5211
4751
|
consola29.success(`Default bridge model set to ${args["bridge-model"]} (in ~/litellm/.env)`);
|
|
5212
4752
|
}
|
|
5213
4753
|
installAdapter2();
|
|
5214
|
-
|
|
5215
|
-
|
|
4754
|
+
mkdirSync4(join10(homeDir, "Library", "LaunchAgents"), { recursive: true });
|
|
4755
|
+
mkdirSync4(NEST_DATA_DIR, { recursive: true });
|
|
5216
4756
|
const desired = buildPlist({ nestBin, apesBin, userHome: homeDir, nestHome: NEST_DATA_DIR, port });
|
|
5217
4757
|
let existing = "";
|
|
5218
4758
|
try {
|
|
5219
|
-
existing =
|
|
4759
|
+
existing = readFileSync10(plistPath(), "utf8");
|
|
5220
4760
|
} catch {
|
|
5221
4761
|
}
|
|
5222
4762
|
if (existing !== desired) {
|
|
5223
|
-
|
|
4763
|
+
writeFileSync6(plistPath(), desired, { mode: 420 });
|
|
5224
4764
|
consola29.success("Wrote launchd plist");
|
|
5225
4765
|
} else {
|
|
5226
4766
|
consola29.info("plist already up to date");
|
|
5227
4767
|
}
|
|
5228
4768
|
const uid = userInfo2().uid;
|
|
5229
4769
|
try {
|
|
5230
|
-
|
|
4770
|
+
execFileSync9("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL}`], { stdio: "ignore" });
|
|
5231
4771
|
} catch {
|
|
5232
4772
|
}
|
|
5233
|
-
|
|
4773
|
+
execFileSync9("/bin/launchctl", ["bootstrap", `gui/${uid}`, plistPath()], { stdio: "inherit" });
|
|
5234
4774
|
consola29.success(`Nest daemon bootstrapped \u2014 http://127.0.0.1:${port}`);
|
|
5235
4775
|
consola29.info("");
|
|
5236
4776
|
consola29.info("Next steps for zero-prompt spawn \u2014 both one-time:");
|
|
@@ -5393,9 +4933,9 @@ var statusNestCommand = defineCommand35({
|
|
|
5393
4933
|
});
|
|
5394
4934
|
|
|
5395
4935
|
// src/commands/nest/uninstall.ts
|
|
5396
|
-
import { execFileSync as
|
|
4936
|
+
import { execFileSync as execFileSync10 } from "child_process";
|
|
5397
4937
|
import { existsSync as existsSync13, unlinkSync } from "fs";
|
|
5398
|
-
import { homedir as
|
|
4938
|
+
import { homedir as homedir11, userInfo as userInfo3 } from "os";
|
|
5399
4939
|
import { join as join11 } from "path";
|
|
5400
4940
|
import { defineCommand as defineCommand36 } from "citty";
|
|
5401
4941
|
import consola33 from "consola";
|
|
@@ -5407,9 +4947,9 @@ var uninstallNestCommand = defineCommand36({
|
|
|
5407
4947
|
},
|
|
5408
4948
|
async run() {
|
|
5409
4949
|
const uid = userInfo3().uid;
|
|
5410
|
-
const path2 = join11(
|
|
4950
|
+
const path2 = join11(homedir11(), "Library", "LaunchAgents", `${PLIST_LABEL2}.plist`);
|
|
5411
4951
|
try {
|
|
5412
|
-
|
|
4952
|
+
execFileSync10("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL2}`], { stdio: "ignore" });
|
|
5413
4953
|
consola33.success("Nest daemon stopped");
|
|
5414
4954
|
} catch {
|
|
5415
4955
|
consola33.info("Nest daemon was not loaded");
|
|
@@ -5964,7 +5504,7 @@ var adapterCommand = defineCommand42({
|
|
|
5964
5504
|
});
|
|
5965
5505
|
|
|
5966
5506
|
// src/commands/run.ts
|
|
5967
|
-
import { execFileSync as
|
|
5507
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
5968
5508
|
import { hostname as hostname6 } from "os";
|
|
5969
5509
|
import { basename } from "path";
|
|
5970
5510
|
import { defineCommand as defineCommand43 } from "citty";
|
|
@@ -6242,7 +5782,7 @@ function execShellCommand(command) {
|
|
|
6242
5782
|
throw new CliError("No command to execute");
|
|
6243
5783
|
try {
|
|
6244
5784
|
const { APES_SHELL_WRAPPER: _wrapperMarker, ...inheritedEnv } = process.env;
|
|
6245
|
-
|
|
5785
|
+
execFileSync11(command[0], command.slice(1), {
|
|
6246
5786
|
stdio: "inherit",
|
|
6247
5787
|
env: inheritedEnv
|
|
6248
5788
|
});
|
|
@@ -6394,7 +5934,7 @@ async function runAudienceMode(audience, action, args) {
|
|
|
6394
5934
|
consola38.info(`Executing: ${command.join(" ")}`);
|
|
6395
5935
|
try {
|
|
6396
5936
|
const { APES_SHELL_WRAPPER: _wrapperMarker, ...inheritedEnv } = process.env;
|
|
6397
|
-
|
|
5937
|
+
execFileSync11(args["escapes-path"] || "escapes", ["--grant", authz_jwt, "--", ...command], {
|
|
6398
5938
|
stdio: "inherit",
|
|
6399
5939
|
env: inheritedEnv
|
|
6400
5940
|
});
|
|
@@ -6444,10 +5984,10 @@ note = "VPC-internal hostname suffix"
|
|
|
6444
5984
|
|
|
6445
5985
|
// src/proxy/local-proxy.ts
|
|
6446
5986
|
import { spawn } from "child_process";
|
|
6447
|
-
import { mkdtempSync as mkdtempSync3, rmSync as rmSync3, writeFileSync as
|
|
5987
|
+
import { mkdtempSync as mkdtempSync3, rmSync as rmSync3, writeFileSync as writeFileSync7 } from "fs";
|
|
6448
5988
|
import { createRequire } from "module";
|
|
6449
5989
|
import { tmpdir as tmpdir3 } from "os";
|
|
6450
|
-
import { dirname as dirname4, join as join12, resolve as
|
|
5990
|
+
import { dirname as dirname4, join as join12, resolve as resolve3 } from "path";
|
|
6451
5991
|
var require2 = createRequire(import.meta.url);
|
|
6452
5992
|
function findProxyBin() {
|
|
6453
5993
|
const pkgPath = require2.resolve("@openape/proxy/package.json");
|
|
@@ -6456,12 +5996,12 @@ function findProxyBin() {
|
|
|
6456
5996
|
if (!binRel) {
|
|
6457
5997
|
throw new Error("@openape/proxy is missing the openape-proxy bin entry");
|
|
6458
5998
|
}
|
|
6459
|
-
return
|
|
5999
|
+
return resolve3(dirname4(pkgPath), binRel);
|
|
6460
6000
|
}
|
|
6461
6001
|
async function startEphemeralProxy(configToml) {
|
|
6462
6002
|
const tmpDir = mkdtempSync3(join12(tmpdir3(), "openape-proxy-"));
|
|
6463
6003
|
const configPath = join12(tmpDir, "config.toml");
|
|
6464
|
-
|
|
6004
|
+
writeFileSync7(configPath, configToml, { mode: 384 });
|
|
6465
6005
|
const binPath = findProxyBin();
|
|
6466
6006
|
const child = spawn(process.execPath, [binPath, "-c", configPath], {
|
|
6467
6007
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -6896,15 +6436,15 @@ var mcpCommand = defineCommand49({
|
|
|
6896
6436
|
if (transport !== "stdio" && transport !== "sse") {
|
|
6897
6437
|
throw new Error('Transport must be "stdio" or "sse"');
|
|
6898
6438
|
}
|
|
6899
|
-
const { startMcpServer } = await import("./server-
|
|
6439
|
+
const { startMcpServer } = await import("./server-F3ALNNYS.js");
|
|
6900
6440
|
await startMcpServer(transport, port);
|
|
6901
6441
|
}
|
|
6902
6442
|
});
|
|
6903
6443
|
|
|
6904
6444
|
// src/commands/init/index.ts
|
|
6905
|
-
import { existsSync as existsSync14, copyFileSync, writeFileSync as
|
|
6445
|
+
import { existsSync as existsSync14, copyFileSync, writeFileSync as writeFileSync8 } from "fs";
|
|
6906
6446
|
import { randomBytes } from "crypto";
|
|
6907
|
-
import { execFileSync as
|
|
6447
|
+
import { execFileSync as execFileSync12 } from "child_process";
|
|
6908
6448
|
import { join as join13 } from "path";
|
|
6909
6449
|
import { defineCommand as defineCommand50 } from "citty";
|
|
6910
6450
|
import consola42 from "consola";
|
|
@@ -6916,11 +6456,11 @@ async function downloadTemplate(repo, targetDir) {
|
|
|
6916
6456
|
function installDeps(dir) {
|
|
6917
6457
|
const hasLockFile = (name) => existsSync14(join13(dir, name));
|
|
6918
6458
|
if (hasLockFile("pnpm-lock.yaml")) {
|
|
6919
|
-
|
|
6459
|
+
execFileSync12("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
|
|
6920
6460
|
} else if (hasLockFile("bun.lockb")) {
|
|
6921
|
-
|
|
6461
|
+
execFileSync12("bun", ["install"], { cwd: dir, stdio: "inherit" });
|
|
6922
6462
|
} else {
|
|
6923
|
-
|
|
6463
|
+
execFileSync12("npm", ["install"], { cwd: dir, stdio: "inherit" });
|
|
6924
6464
|
}
|
|
6925
6465
|
}
|
|
6926
6466
|
async function promptChoice(message, choices) {
|
|
@@ -7036,7 +6576,7 @@ async function initIdP(targetDir) {
|
|
|
7036
6576
|
`NUXT_OPENAPE_RP_ID=${domain}`,
|
|
7037
6577
|
`NUXT_OPENAPE_RP_ORIGIN=${origin}`
|
|
7038
6578
|
].join("\n");
|
|
7039
|
-
|
|
6579
|
+
writeFileSync8(join13(dir, ".env"), `${envContent}
|
|
7040
6580
|
`, { mode: 384 });
|
|
7041
6581
|
consola42.success(".env created");
|
|
7042
6582
|
console.log("");
|
|
@@ -7057,7 +6597,7 @@ async function initIdP(targetDir) {
|
|
|
7057
6597
|
|
|
7058
6598
|
// src/commands/enroll.ts
|
|
7059
6599
|
import { Buffer as Buffer5 } from "buffer";
|
|
7060
|
-
import { existsSync as existsSync15, readFileSync as
|
|
6600
|
+
import { existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
|
|
7061
6601
|
import { execFile as execFile2 } from "child_process";
|
|
7062
6602
|
import { sign as sign2 } from "crypto";
|
|
7063
6603
|
import { defineCommand as defineCommand51 } from "citty";
|
|
@@ -7073,7 +6613,7 @@ function openBrowser2(url) {
|
|
|
7073
6613
|
}
|
|
7074
6614
|
async function pollForEnrollment(idp, agentEmail, keyPath) {
|
|
7075
6615
|
const resolvedKey = resolveKeyPath(keyPath);
|
|
7076
|
-
const keyContent =
|
|
6616
|
+
const keyContent = readFileSync11(resolvedKey, "utf-8");
|
|
7077
6617
|
const privateKey = loadEd25519PrivateKey(keyContent);
|
|
7078
6618
|
const challengeUrl = await getAgentChallengeEndpoint(idp);
|
|
7079
6619
|
const authenticateUrl = await getAgentAuthenticateEndpoint(idp);
|
|
@@ -7100,7 +6640,7 @@ async function pollForEnrollment(idp, agentEmail, keyPath) {
|
|
|
7100
6640
|
}
|
|
7101
6641
|
} catch {
|
|
7102
6642
|
}
|
|
7103
|
-
await new Promise((
|
|
6643
|
+
await new Promise((resolve4) => setTimeout(resolve4, POLL_INTERVAL));
|
|
7104
6644
|
}
|
|
7105
6645
|
throw new Error("Enrollment timed out. Please check the browser and try again.");
|
|
7106
6646
|
}
|
|
@@ -7185,7 +6725,7 @@ var enrollCommand = defineCommand51({
|
|
|
7185
6725
|
});
|
|
7186
6726
|
|
|
7187
6727
|
// src/commands/register-user.ts
|
|
7188
|
-
import { existsSync as existsSync16, readFileSync as
|
|
6728
|
+
import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
|
|
7189
6729
|
import { defineCommand as defineCommand52 } from "citty";
|
|
7190
6730
|
import consola44 from "consola";
|
|
7191
6731
|
var registerUserCommand = defineCommand52({
|
|
@@ -7225,7 +6765,7 @@ var registerUserCommand = defineCommand52({
|
|
|
7225
6765
|
}
|
|
7226
6766
|
let publicKey = args.key;
|
|
7227
6767
|
if (existsSync16(args.key)) {
|
|
7228
|
-
publicKey =
|
|
6768
|
+
publicKey = readFileSync12(args.key, "utf-8").trim();
|
|
7229
6769
|
}
|
|
7230
6770
|
if (!publicKey.startsWith("ssh-ed25519 ")) {
|
|
7231
6771
|
throw new CliError("Public key must be in ssh-ed25519 format.");
|
|
@@ -7534,7 +7074,7 @@ async function bestEffortGrantCount(idp) {
|
|
|
7534
7074
|
}
|
|
7535
7075
|
}
|
|
7536
7076
|
async function runHealth(args) {
|
|
7537
|
-
const version = true ? "1.
|
|
7077
|
+
const version = true ? "1.11.0" : "0.0.0";
|
|
7538
7078
|
const auth = loadAuth();
|
|
7539
7079
|
if (!auth) {
|
|
7540
7080
|
throw new CliError("Not logged in. Run `apes login` first.", 1);
|
|
@@ -7727,26 +7267,26 @@ var workflowsCommand = defineCommand60({
|
|
|
7727
7267
|
});
|
|
7728
7268
|
|
|
7729
7269
|
// src/version-check.ts
|
|
7730
|
-
import { existsSync as existsSync17, mkdirSync as
|
|
7731
|
-
import { homedir as
|
|
7270
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync5, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "fs";
|
|
7271
|
+
import { homedir as homedir12 } from "os";
|
|
7732
7272
|
import { join as join14 } from "path";
|
|
7733
7273
|
import consola50 from "consola";
|
|
7734
7274
|
var PACKAGE_NAME = "@openape/apes";
|
|
7735
7275
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
7736
|
-
var CACHE_FILE = join14(
|
|
7276
|
+
var CACHE_FILE = join14(homedir12(), ".config", "apes", ".version-check.json");
|
|
7737
7277
|
function readCache() {
|
|
7738
7278
|
if (!existsSync17(CACHE_FILE)) return null;
|
|
7739
7279
|
try {
|
|
7740
|
-
return JSON.parse(
|
|
7280
|
+
return JSON.parse(readFileSync13(CACHE_FILE, "utf-8"));
|
|
7741
7281
|
} catch {
|
|
7742
7282
|
return null;
|
|
7743
7283
|
}
|
|
7744
7284
|
}
|
|
7745
7285
|
function writeCache(entry) {
|
|
7746
7286
|
try {
|
|
7747
|
-
const dir = join14(
|
|
7748
|
-
if (!existsSync17(dir))
|
|
7749
|
-
|
|
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 });
|
|
7750
7290
|
} catch {
|
|
7751
7291
|
}
|
|
7752
7292
|
}
|
|
@@ -7807,10 +7347,10 @@ if (shellRewrite) {
|
|
|
7807
7347
|
if (shellRewrite.action === "rewrite") {
|
|
7808
7348
|
process.argv = shellRewrite.argv;
|
|
7809
7349
|
} else if (shellRewrite.action === "version") {
|
|
7810
|
-
console.log(`ape-shell ${"1.
|
|
7350
|
+
console.log(`ape-shell ${"1.11.0"} (OpenApe DDISA shell wrapper)`);
|
|
7811
7351
|
process.exit(0);
|
|
7812
7352
|
} else if (shellRewrite.action === "help") {
|
|
7813
|
-
console.log(`ape-shell ${"1.
|
|
7353
|
+
console.log(`ape-shell ${"1.11.0"} \u2014 OpenApe DDISA shell wrapper`);
|
|
7814
7354
|
console.log("");
|
|
7815
7355
|
console.log("Usage:");
|
|
7816
7356
|
console.log(" ape-shell Start interactive grant-mediated REPL");
|
|
@@ -7868,7 +7408,7 @@ var configCommand = defineCommand61({
|
|
|
7868
7408
|
var main = defineCommand61({
|
|
7869
7409
|
meta: {
|
|
7870
7410
|
name: "apes",
|
|
7871
|
-
version: "1.
|
|
7411
|
+
version: "1.11.0",
|
|
7872
7412
|
description: "Unified CLI for OpenApe"
|
|
7873
7413
|
},
|
|
7874
7414
|
subCommands: {
|
|
@@ -7925,7 +7465,7 @@ async function maybeRefreshAuth() {
|
|
|
7925
7465
|
}
|
|
7926
7466
|
}
|
|
7927
7467
|
await maybeRefreshAuth();
|
|
7928
|
-
await maybeWarnStaleVersion("1.
|
|
7468
|
+
await maybeWarnStaleVersion("1.11.0").catch(() => {
|
|
7929
7469
|
});
|
|
7930
7470
|
runMain(main).catch((err) => {
|
|
7931
7471
|
if (err instanceof CliExit) {
|