@openape/apes 1.28.11 → 1.28.12
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-4KPKANZT.js → chunk-NYJSBFLG.js} +7 -5
- package/dist/chunk-NYJSBFLG.js.map +1 -0
- package/dist/{chunk-OOKB2IL2.js → chunk-ZEUSCNCH.js} +59 -9
- package/dist/chunk-ZEUSCNCH.js.map +1 -0
- package/dist/cli.js +624 -375
- package/dist/cli.js.map +1 -1
- package/dist/{http-6OKWT52Z.js → http-UPOTOYQV.js} +2 -2
- package/dist/index.d.ts +12 -0
- package/dist/index.js +2 -2
- package/dist/{orchestrator-CIDV7OGM.js → orchestrator-BDX3WK7Q.js} +2 -2
- package/dist/{server-WB77GNKJ.js → server-OAINN75J.js} +3 -3
- package/package.json +4 -4
- package/dist/chunk-4KPKANZT.js.map +0 -1
- package/dist/chunk-OOKB2IL2.js.map +0 -1
- /package/dist/{http-6OKWT52Z.js.map → http-UPOTOYQV.js.map} +0 -0
- /package/dist/{orchestrator-CIDV7OGM.js.map → orchestrator-BDX3WK7Q.js.map} +0 -0
- /package/dist/{server-WB77GNKJ.js.map → server-OAINN75J.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
runLoop,
|
|
14
14
|
taskTools,
|
|
15
15
|
worktreePathFor
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-ZEUSCNCH.js";
|
|
17
17
|
import {
|
|
18
18
|
loadEd25519PrivateKey,
|
|
19
19
|
readPublicKeyComment
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
getAgentChallengeEndpoint,
|
|
59
59
|
getDelegationsEndpoint,
|
|
60
60
|
getGrantsEndpoint
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-NYJSBFLG.js";
|
|
62
62
|
import {
|
|
63
63
|
AUTH_FILE,
|
|
64
64
|
CONFIG_DIR,
|
|
@@ -389,28 +389,30 @@ async function loginWithPKCE(idp) {
|
|
|
389
389
|
consola2.success(`Logged in as ${payload.email || payload.sub}`);
|
|
390
390
|
}
|
|
391
391
|
async function loginWithKey(idp, keyPath, agentEmail) {
|
|
392
|
-
const { readFileSync:
|
|
392
|
+
const { readFileSync: readFileSync21 } = await import("fs");
|
|
393
393
|
const { sign: sign3 } = await import("crypto");
|
|
394
394
|
const { loadEd25519PrivateKey: loadEd25519PrivateKey2 } = await import("./ssh-key-YBNNG5K5.js");
|
|
395
395
|
const challengeUrl = await getAgentChallengeEndpoint(idp);
|
|
396
396
|
const challengeResp = await fetch(challengeUrl, {
|
|
397
397
|
method: "POST",
|
|
398
398
|
headers: { "Content-Type": "application/json" },
|
|
399
|
-
|
|
399
|
+
// Use canonical `id` field (the server's /api/auth/challenge handler expects `id`).
|
|
400
|
+
body: JSON.stringify({ id: agentEmail })
|
|
400
401
|
});
|
|
401
402
|
if (!challengeResp.ok) {
|
|
402
403
|
throw new CliError(`Challenge failed: ${await challengeResp.text()}`);
|
|
403
404
|
}
|
|
404
405
|
const { challenge } = await challengeResp.json();
|
|
405
|
-
const keyContent =
|
|
406
|
+
const keyContent = readFileSync21(keyPath, "utf-8");
|
|
406
407
|
const privateKey = loadEd25519PrivateKey2(keyContent);
|
|
407
408
|
const signature = sign3(null, Buffer2.from(challenge), privateKey).toString("base64");
|
|
408
409
|
const authenticateUrl = await getAgentAuthenticateEndpoint(idp);
|
|
409
410
|
const authResp = await fetch(authenticateUrl, {
|
|
410
411
|
method: "POST",
|
|
411
412
|
headers: { "Content-Type": "application/json" },
|
|
413
|
+
// Use canonical `id` field (the server's /api/auth/authenticate handler expects `id`).
|
|
412
414
|
body: JSON.stringify({
|
|
413
|
-
|
|
415
|
+
id: agentEmail,
|
|
414
416
|
challenge,
|
|
415
417
|
signature
|
|
416
418
|
})
|
|
@@ -1982,7 +1984,7 @@ var agentCommand = defineCommand21({
|
|
|
1982
1984
|
import { defineCommand as defineCommand32 } from "citty";
|
|
1983
1985
|
|
|
1984
1986
|
// src/commands/agents/allow.ts
|
|
1985
|
-
import { execFileSync as
|
|
1987
|
+
import { execFileSync as execFileSync10 } from "child_process";
|
|
1986
1988
|
import { defineCommand as defineCommand22 } from "citty";
|
|
1987
1989
|
import consola19 from "consola";
|
|
1988
1990
|
|
|
@@ -2496,6 +2498,348 @@ function isShellRegistered(shellPath) {
|
|
|
2496
2498
|
return content.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#")).includes(shellPath);
|
|
2497
2499
|
}
|
|
2498
2500
|
|
|
2501
|
+
// src/lib/host-platform/index.ts
|
|
2502
|
+
import process2 from "process";
|
|
2503
|
+
|
|
2504
|
+
// src/lib/macos-host.ts
|
|
2505
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
2506
|
+
import { hostname as hostname3 } from "os";
|
|
2507
|
+
function getHostId() {
|
|
2508
|
+
try {
|
|
2509
|
+
const output = execFileSync4(
|
|
2510
|
+
"/usr/sbin/ioreg",
|
|
2511
|
+
["-d2", "-c", "IOPlatformExpertDevice"],
|
|
2512
|
+
{ encoding: "utf8", timeout: 2e3 }
|
|
2513
|
+
);
|
|
2514
|
+
const match = output.match(/"IOPlatformUUID"\s*=\s*"([^"]+)"/);
|
|
2515
|
+
return match ? match[1].trim().toLowerCase() : "";
|
|
2516
|
+
} catch {
|
|
2517
|
+
return "";
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
function getHostname() {
|
|
2521
|
+
try {
|
|
2522
|
+
return hostname3();
|
|
2523
|
+
} catch {
|
|
2524
|
+
return "";
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
// src/lib/host-platform/darwin-nest.ts
|
|
2529
|
+
import { execFileSync as execFileSync5 } from "child_process";
|
|
2530
|
+
import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync3, unlinkSync, writeFileSync } from "fs";
|
|
2531
|
+
import { userInfo } from "os";
|
|
2532
|
+
import { join as join2 } from "path";
|
|
2533
|
+
var PLIST_LABEL = "ai.openape.nest";
|
|
2534
|
+
function plistPath(userHome) {
|
|
2535
|
+
return join2(userHome, "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
2536
|
+
}
|
|
2537
|
+
function xmlEscape(s) {
|
|
2538
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
2539
|
+
}
|
|
2540
|
+
function buildNestPlist(spec) {
|
|
2541
|
+
const logsDir = join2(spec.userHome, "Library", "Logs");
|
|
2542
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
2543
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
2544
|
+
<plist version="1.0">
|
|
2545
|
+
<dict>
|
|
2546
|
+
<key>Label</key>
|
|
2547
|
+
<string>${xmlEscape(PLIST_LABEL)}</string>
|
|
2548
|
+
<key>ProgramArguments</key>
|
|
2549
|
+
<array>
|
|
2550
|
+
<string>${xmlEscape(spec.nestBin)}</string>
|
|
2551
|
+
</array>
|
|
2552
|
+
<key>WorkingDirectory</key>
|
|
2553
|
+
<string>${xmlEscape(spec.nestHome)}</string>
|
|
2554
|
+
<key>RunAtLoad</key>
|
|
2555
|
+
<true/>
|
|
2556
|
+
<key>KeepAlive</key>
|
|
2557
|
+
<true/>
|
|
2558
|
+
<key>ThrottleInterval</key>
|
|
2559
|
+
<integer>10</integer>
|
|
2560
|
+
<key>EnvironmentVariables</key>
|
|
2561
|
+
<dict>
|
|
2562
|
+
<key>HOME</key><string>${xmlEscape(spec.nestHome)}</string>
|
|
2563
|
+
<key>PATH</key><string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
2564
|
+
<key>OPENAPE_NEST_PORT</key><string>${spec.port}</string>
|
|
2565
|
+
<key>OPENAPE_APES_BIN</key><string>${xmlEscape(spec.apesBin)}</string>
|
|
2566
|
+
</dict>
|
|
2567
|
+
<key>StandardOutPath</key>
|
|
2568
|
+
<string>${xmlEscape(logsDir)}/openape-nest.log</string>
|
|
2569
|
+
<key>StandardErrorPath</key>
|
|
2570
|
+
<string>${xmlEscape(logsDir)}/openape-nest.log</string>
|
|
2571
|
+
</dict>
|
|
2572
|
+
</plist>
|
|
2573
|
+
`;
|
|
2574
|
+
}
|
|
2575
|
+
async function installNestSupervisorOnDarwin(spec) {
|
|
2576
|
+
const path2 = plistPath(spec.userHome);
|
|
2577
|
+
mkdirSync(join2(spec.userHome, "Library", "LaunchAgents"), { recursive: true });
|
|
2578
|
+
const desired = buildNestPlist(spec);
|
|
2579
|
+
let existing = "";
|
|
2580
|
+
try {
|
|
2581
|
+
existing = readFileSync3(path2, "utf8");
|
|
2582
|
+
} catch {
|
|
2583
|
+
}
|
|
2584
|
+
if (existing !== desired) {
|
|
2585
|
+
writeFileSync(path2, desired, { mode: 420 });
|
|
2586
|
+
}
|
|
2587
|
+
const uid = userInfo().uid;
|
|
2588
|
+
try {
|
|
2589
|
+
execFileSync5("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL}`], { stdio: "ignore" });
|
|
2590
|
+
} catch {
|
|
2591
|
+
}
|
|
2592
|
+
execFileSync5("/bin/launchctl", ["bootstrap", `gui/${uid}`, path2], { stdio: "inherit" });
|
|
2593
|
+
}
|
|
2594
|
+
async function uninstallNestSupervisorOnDarwin() {
|
|
2595
|
+
const home = userInfo().homedir;
|
|
2596
|
+
const uid = userInfo().uid;
|
|
2597
|
+
const path2 = plistPath(home);
|
|
2598
|
+
try {
|
|
2599
|
+
execFileSync5("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL}`], { stdio: "ignore" });
|
|
2600
|
+
} catch {
|
|
2601
|
+
}
|
|
2602
|
+
if (existsSync4(path2)) unlinkSync(path2);
|
|
2603
|
+
}
|
|
2604
|
+
|
|
2605
|
+
// src/lib/host-platform/darwin-exec.ts
|
|
2606
|
+
import { execFileSync as execFileSync6, spawnSync } from "child_process";
|
|
2607
|
+
import { mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
2608
|
+
import { tmpdir } from "os";
|
|
2609
|
+
import { join as join3 } from "path";
|
|
2610
|
+
function resolveApesBinary() {
|
|
2611
|
+
return process.env.OPENAPE_APES_BIN || "apes";
|
|
2612
|
+
}
|
|
2613
|
+
async function runPrivilegedBashOnDarwin(script) {
|
|
2614
|
+
const dir = mkdtempSync(join3(tmpdir(), "apes-privileged-"));
|
|
2615
|
+
const scriptPath = join3(dir, "run.sh");
|
|
2616
|
+
writeFileSync2(scriptPath, script, { mode: 448 });
|
|
2617
|
+
try {
|
|
2618
|
+
if (process.getuid?.() === 0) {
|
|
2619
|
+
execFileSync6("bash", [scriptPath], { stdio: "inherit" });
|
|
2620
|
+
} else {
|
|
2621
|
+
execFileSync6(resolveApesBinary(), ["run", "--as", "root", "--wait", "--", "bash", scriptPath], { stdio: "inherit" });
|
|
2622
|
+
}
|
|
2623
|
+
} finally {
|
|
2624
|
+
try {
|
|
2625
|
+
rmSync2(dir, { recursive: true, force: true });
|
|
2626
|
+
} catch {
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
async function runAsAgentUserOnDarwin(agentName, argv) {
|
|
2631
|
+
const r = spawnSync(
|
|
2632
|
+
resolveApesBinary(),
|
|
2633
|
+
["run", "--as", agentName, "--wait", "--", ...argv],
|
|
2634
|
+
{ encoding: "utf8" }
|
|
2635
|
+
);
|
|
2636
|
+
return {
|
|
2637
|
+
stdout: r.stdout ?? "",
|
|
2638
|
+
stderr: r.stderr ?? "",
|
|
2639
|
+
exitCode: r.status ?? 1
|
|
2640
|
+
};
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
// src/lib/host-platform/darwin.ts
|
|
2644
|
+
var darwinHostPlatform = {
|
|
2645
|
+
getHostId,
|
|
2646
|
+
getHostname,
|
|
2647
|
+
agentUsername: macOSUsernameForAgent,
|
|
2648
|
+
lookupAgentUser: (agentName) => lookupMacOSUserForAgent(agentName),
|
|
2649
|
+
readAgentUser: (osName) => readMacOSUser(osName),
|
|
2650
|
+
listAgentUserNames: listMacOSUserNames,
|
|
2651
|
+
listOrphanAgentUsers: () => listOrphanedAgentRecords().map((r) => ({ name: r.name, uid: r.uid, homeDir: r.homeDir })),
|
|
2652
|
+
installNestSupervisor: installNestSupervisorOnDarwin,
|
|
2653
|
+
uninstallNestSupervisor: uninstallNestSupervisorOnDarwin,
|
|
2654
|
+
runPrivilegedBash: runPrivilegedBashOnDarwin,
|
|
2655
|
+
runAsAgentUser: runAsAgentUserOnDarwin
|
|
2656
|
+
};
|
|
2657
|
+
|
|
2658
|
+
// src/lib/host-platform/linux-host.ts
|
|
2659
|
+
import { hostname as hostname4 } from "os";
|
|
2660
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
2661
|
+
var FALLBACK_PATHS = ["/etc/machine-id", "/var/lib/dbus/machine-id"];
|
|
2662
|
+
function getLinuxHostId() {
|
|
2663
|
+
for (const path2 of FALLBACK_PATHS) {
|
|
2664
|
+
if (!existsSync5(path2)) continue;
|
|
2665
|
+
try {
|
|
2666
|
+
const v = readFileSync4(path2, "utf-8").trim();
|
|
2667
|
+
if (v) return v;
|
|
2668
|
+
} catch {
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
return hostname4();
|
|
2672
|
+
}
|
|
2673
|
+
function getLinuxHostname() {
|
|
2674
|
+
return hostname4();
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2677
|
+
// src/lib/host-platform/linux-user.ts
|
|
2678
|
+
import { execFileSync as execFileSync7 } from "child_process";
|
|
2679
|
+
function getentPasswd(name) {
|
|
2680
|
+
try {
|
|
2681
|
+
return execFileSync7("getent", ["passwd", name], {
|
|
2682
|
+
encoding: "utf-8",
|
|
2683
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
2684
|
+
}).trim() || null;
|
|
2685
|
+
} catch {
|
|
2686
|
+
return null;
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
2689
|
+
function parsePasswdLine(line) {
|
|
2690
|
+
const parts = line.split(":");
|
|
2691
|
+
if (parts.length < 7) return null;
|
|
2692
|
+
const [name, , uidStr, , , homeDir, shell] = parts;
|
|
2693
|
+
if (!name || !uidStr) return null;
|
|
2694
|
+
const uid = Number.parseInt(uidStr, 10);
|
|
2695
|
+
return {
|
|
2696
|
+
name,
|
|
2697
|
+
uid: Number.isFinite(uid) ? uid : null,
|
|
2698
|
+
shell: shell?.trim() || null,
|
|
2699
|
+
homeDir: homeDir?.trim() || null
|
|
2700
|
+
};
|
|
2701
|
+
}
|
|
2702
|
+
function readLinuxUser(name) {
|
|
2703
|
+
const line = getentPasswd(name);
|
|
2704
|
+
if (!line) return null;
|
|
2705
|
+
return parsePasswdLine(line);
|
|
2706
|
+
}
|
|
2707
|
+
function listLinuxUserNames() {
|
|
2708
|
+
try {
|
|
2709
|
+
const out = execFileSync7("getent", ["passwd"], {
|
|
2710
|
+
encoding: "utf-8",
|
|
2711
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
2712
|
+
});
|
|
2713
|
+
const names = /* @__PURE__ */ new Set();
|
|
2714
|
+
for (const line of out.split("\n")) {
|
|
2715
|
+
const name = line.split(":", 1)[0]?.trim();
|
|
2716
|
+
if (name) names.add(name);
|
|
2717
|
+
}
|
|
2718
|
+
return names;
|
|
2719
|
+
} catch {
|
|
2720
|
+
return /* @__PURE__ */ new Set();
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
// src/lib/host-platform/linux-exec.ts
|
|
2725
|
+
import { execFileSync as execFileSync8, spawnSync as spawnSync2 } from "child_process";
|
|
2726
|
+
import { mkdtempSync as mkdtempSync2, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
2727
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
2728
|
+
import { join as join4 } from "path";
|
|
2729
|
+
async function runPrivilegedBashOnLinux(script) {
|
|
2730
|
+
const dir = mkdtempSync2(join4(tmpdir2(), "apes-privileged-"));
|
|
2731
|
+
const scriptPath = join4(dir, "run.sh");
|
|
2732
|
+
writeFileSync3(scriptPath, script, { mode: 448 });
|
|
2733
|
+
try {
|
|
2734
|
+
if (process.getuid?.() === 0) {
|
|
2735
|
+
execFileSync8("bash", [scriptPath], { stdio: "inherit" });
|
|
2736
|
+
} else {
|
|
2737
|
+
execFileSync8("sudo", ["-n", "--", "bash", scriptPath], { stdio: "inherit" });
|
|
2738
|
+
}
|
|
2739
|
+
} finally {
|
|
2740
|
+
try {
|
|
2741
|
+
rmSync3(dir, { recursive: true, force: true });
|
|
2742
|
+
} catch {
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
async function runAsAgentUserOnLinux(agentName, argv) {
|
|
2747
|
+
const r = spawnSync2("sudo", ["-n", "-H", "-u", agentName, "--", ...argv], { encoding: "utf8" });
|
|
2748
|
+
return {
|
|
2749
|
+
stdout: r.stdout ?? "",
|
|
2750
|
+
stderr: r.stderr ?? "",
|
|
2751
|
+
exitCode: r.status ?? 1
|
|
2752
|
+
};
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
// src/lib/host-platform/linux-nest.ts
|
|
2756
|
+
import { execFileSync as execFileSync9 } from "child_process";
|
|
2757
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
2758
|
+
var UNIT_NAME = "openape-nest.service";
|
|
2759
|
+
var UNIT_PATH = `/etc/systemd/system/${UNIT_NAME}`;
|
|
2760
|
+
function buildNestUnit(spec) {
|
|
2761
|
+
return `[Unit]
|
|
2762
|
+
Description=OpenApe Nest supervisor
|
|
2763
|
+
After=network-online.target
|
|
2764
|
+
Wants=network-online.target
|
|
2765
|
+
|
|
2766
|
+
[Service]
|
|
2767
|
+
Type=simple
|
|
2768
|
+
ExecStart=${spec.nestBin}
|
|
2769
|
+
WorkingDirectory=${spec.nestHome}
|
|
2770
|
+
Restart=always
|
|
2771
|
+
RestartSec=10
|
|
2772
|
+
Environment=HOME=${spec.nestHome}
|
|
2773
|
+
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
|
2774
|
+
Environment=OPENAPE_NEST_PORT=${spec.port}
|
|
2775
|
+
Environment=OPENAPE_APES_BIN=${spec.apesBin}
|
|
2776
|
+
StandardOutput=journal
|
|
2777
|
+
StandardError=journal
|
|
2778
|
+
|
|
2779
|
+
[Install]
|
|
2780
|
+
WantedBy=multi-user.target
|
|
2781
|
+
`;
|
|
2782
|
+
}
|
|
2783
|
+
async function installNestSupervisorOnLinux(spec) {
|
|
2784
|
+
const desired = buildNestUnit(spec);
|
|
2785
|
+
let existing = "";
|
|
2786
|
+
try {
|
|
2787
|
+
existing = readFileSync5(UNIT_PATH, "utf8");
|
|
2788
|
+
} catch {
|
|
2789
|
+
}
|
|
2790
|
+
if (existing !== desired) {
|
|
2791
|
+
writeFileSync4(UNIT_PATH, desired, { mode: 420 });
|
|
2792
|
+
}
|
|
2793
|
+
execFileSync9("systemctl", ["daemon-reload"], { stdio: "inherit" });
|
|
2794
|
+
execFileSync9("systemctl", ["enable", "--now", UNIT_NAME], { stdio: "inherit" });
|
|
2795
|
+
}
|
|
2796
|
+
async function uninstallNestSupervisorOnLinux() {
|
|
2797
|
+
try {
|
|
2798
|
+
execFileSync9("systemctl", ["disable", "--now", UNIT_NAME], { stdio: "inherit" });
|
|
2799
|
+
} catch {
|
|
2800
|
+
}
|
|
2801
|
+
if (existsSync6(UNIT_PATH)) unlinkSync2(UNIT_PATH);
|
|
2802
|
+
try {
|
|
2803
|
+
execFileSync9("systemctl", ["daemon-reload"], { stdio: "inherit" });
|
|
2804
|
+
} catch {
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
|
|
2808
|
+
// src/lib/host-platform/linux.ts
|
|
2809
|
+
var linuxHostPlatform = {
|
|
2810
|
+
getHostId: getLinuxHostId,
|
|
2811
|
+
getHostname: getLinuxHostname,
|
|
2812
|
+
// No prefix on Linux — the agent name IS the OS username. In the
|
|
2813
|
+
// container, the OpenApe namespace IS the namespace; no need to
|
|
2814
|
+
// disambiguate with `openape-agent-`. (Linux limits usernames to
|
|
2815
|
+
// 32 chars, so a prefix would also reject longer agent names.)
|
|
2816
|
+
agentUsername: (agentName) => agentName,
|
|
2817
|
+
lookupAgentUser: (agentName) => readLinuxUser(agentName),
|
|
2818
|
+
readAgentUser: (osName) => readLinuxUser(osName),
|
|
2819
|
+
listAgentUserNames: listLinuxUserNames,
|
|
2820
|
+
// No tombstone concept on Linux — userdel + groupdel are clean.
|
|
2821
|
+
listOrphanAgentUsers: () => [],
|
|
2822
|
+
installNestSupervisor: installNestSupervisorOnLinux,
|
|
2823
|
+
uninstallNestSupervisor: uninstallNestSupervisorOnLinux,
|
|
2824
|
+
runPrivilegedBash: runPrivilegedBashOnLinux,
|
|
2825
|
+
runAsAgentUser: runAsAgentUserOnLinux
|
|
2826
|
+
};
|
|
2827
|
+
|
|
2828
|
+
// src/lib/host-platform/index.ts
|
|
2829
|
+
function isDarwin2() {
|
|
2830
|
+
return process2.platform === "darwin";
|
|
2831
|
+
}
|
|
2832
|
+
function isLinux() {
|
|
2833
|
+
return process2.platform === "linux";
|
|
2834
|
+
}
|
|
2835
|
+
var testOverride = null;
|
|
2836
|
+
function getHostPlatform() {
|
|
2837
|
+
if (testOverride) return testOverride;
|
|
2838
|
+
if (isDarwin2()) return darwinHostPlatform;
|
|
2839
|
+
if (isLinux()) return linuxHostPlatform;
|
|
2840
|
+
throw new Error(`unsupported host platform: ${process2.platform}`);
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2499
2843
|
// src/commands/agents/allow.ts
|
|
2500
2844
|
var allowAgentCommand = defineCommand22({
|
|
2501
2845
|
meta: {
|
|
@@ -2523,10 +2867,10 @@ var allowAgentCommand = defineCommand22({
|
|
|
2523
2867
|
if (!email.includes("@")) {
|
|
2524
2868
|
throw new CliError(`Invalid email "${email}".`);
|
|
2525
2869
|
}
|
|
2526
|
-
if (!
|
|
2870
|
+
if (!isDarwin2()) {
|
|
2527
2871
|
throw new CliError("`apes agents allow` is currently macOS-only.");
|
|
2528
2872
|
}
|
|
2529
|
-
if (!
|
|
2873
|
+
if (!getHostPlatform().lookupAgentUser(agent)) {
|
|
2530
2874
|
throw new CliError(`No macOS user for agent "${agent}" \u2014 has it been spawned?`);
|
|
2531
2875
|
}
|
|
2532
2876
|
const apes = whichBinary("apes");
|
|
@@ -2558,7 +2902,7 @@ PY
|
|
|
2558
2902
|
chmod 600 "$F"
|
|
2559
2903
|
`;
|
|
2560
2904
|
consola19.start(`Adding ${email} to ${agent}'s allowlist\u2026`);
|
|
2561
|
-
|
|
2905
|
+
execFileSync10(apes, ["run", "--as", agent, "--wait", "--", "bash", "-c", script], { stdio: "inherit" });
|
|
2562
2906
|
consola19.success(`${agent} will auto-accept future contact requests from ${email} (within ~30s of next bridge connect).`);
|
|
2563
2907
|
}
|
|
2564
2908
|
});
|
|
@@ -2567,7 +2911,7 @@ function shQuote2(s) {
|
|
|
2567
2911
|
}
|
|
2568
2912
|
|
|
2569
2913
|
// src/commands/agents/cleanup-orphans.ts
|
|
2570
|
-
import { execFileSync as
|
|
2914
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
2571
2915
|
import { defineCommand as defineCommand23 } from "citty";
|
|
2572
2916
|
import consola20 from "consola";
|
|
2573
2917
|
var cleanupOrphansCommand = defineCommand23({
|
|
@@ -2586,10 +2930,10 @@ var cleanupOrphansCommand = defineCommand23({
|
|
|
2586
2930
|
}
|
|
2587
2931
|
},
|
|
2588
2932
|
async run({ args }) {
|
|
2589
|
-
if (!
|
|
2933
|
+
if (!isDarwin2()) {
|
|
2590
2934
|
throw new CliError(`\`apes agents cleanup-orphans\` is macOS-only. Detected platform: ${process.platform}.`);
|
|
2591
2935
|
}
|
|
2592
|
-
const orphans =
|
|
2936
|
+
const orphans = getHostPlatform().listOrphanAgentUsers();
|
|
2593
2937
|
if (orphans.length === 0) {
|
|
2594
2938
|
consola20.success("No agent tombstones found \u2014 dscl is clean.");
|
|
2595
2939
|
return;
|
|
@@ -2626,7 +2970,7 @@ var cleanupOrphansCommand = defineCommand23({
|
|
|
2626
2970
|
let failed = 0;
|
|
2627
2971
|
for (const o of orphans) {
|
|
2628
2972
|
try {
|
|
2629
|
-
|
|
2973
|
+
execFileSync11("/usr/sbin/sysadminctl", ["-deleteUser", o.name], {
|
|
2630
2974
|
stdio: ["ignore", "inherit", "inherit"]
|
|
2631
2975
|
});
|
|
2632
2976
|
consola20.success(`Deleted ${o.name}`);
|
|
@@ -2644,21 +2988,21 @@ var cleanupOrphansCommand = defineCommand23({
|
|
|
2644
2988
|
});
|
|
2645
2989
|
|
|
2646
2990
|
// src/commands/agents/code.ts
|
|
2647
|
-
import { existsSync as
|
|
2991
|
+
import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
|
|
2648
2992
|
import { homedir as homedir5 } from "os";
|
|
2649
|
-
import { join as
|
|
2650
|
-
import
|
|
2993
|
+
import { join as join6 } from "path";
|
|
2994
|
+
import process3 from "process";
|
|
2651
2995
|
import { defineCommand as defineCommand24 } from "citty";
|
|
2652
2996
|
import { consola as consola21 } from "consola";
|
|
2653
2997
|
|
|
2654
2998
|
// src/lib/agent-secrets-runtime.ts
|
|
2655
|
-
import { existsSync as
|
|
2999
|
+
import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync6, watch } from "fs";
|
|
2656
3000
|
import { homedir as homedir4 } from "os";
|
|
2657
|
-
import { join as
|
|
3001
|
+
import { join as join5 } from "path";
|
|
2658
3002
|
import { openString } from "@openape/core";
|
|
2659
|
-
var CONFIG_DIR2 =
|
|
2660
|
-
var SECRETS_DIR =
|
|
2661
|
-
var X25519_KEY_PATH =
|
|
3003
|
+
var CONFIG_DIR2 = join5(homedir4(), ".config", "openape");
|
|
3004
|
+
var SECRETS_DIR = join5(CONFIG_DIR2, "secrets.d");
|
|
3005
|
+
var X25519_KEY_PATH = join5(CONFIG_DIR2, "agent-x25519.key");
|
|
2662
3006
|
var X25519_PUBKEY_PATH = `${X25519_KEY_PATH}.pub`;
|
|
2663
3007
|
function envNameFromFile(file) {
|
|
2664
3008
|
if (!file.endsWith(".blob")) return null;
|
|
@@ -2666,13 +3010,13 @@ function envNameFromFile(file) {
|
|
|
2666
3010
|
return /^[A-Z][A-Z0-9_]*$/.test(env) ? env : null;
|
|
2667
3011
|
}
|
|
2668
3012
|
function readAgentEncryptionKey(keyPath = X25519_KEY_PATH) {
|
|
2669
|
-
if (!
|
|
2670
|
-
const k =
|
|
3013
|
+
if (!existsSync7(keyPath)) return null;
|
|
3014
|
+
const k = readFileSync6(keyPath, "utf8").trim();
|
|
2671
3015
|
return k.length > 0 ? k : null;
|
|
2672
3016
|
}
|
|
2673
3017
|
function readAgentEncryptionPublicKey(pubPath = X25519_PUBKEY_PATH) {
|
|
2674
|
-
if (!
|
|
2675
|
-
const k =
|
|
3018
|
+
if (!existsSync7(pubPath)) return null;
|
|
3019
|
+
const k = readFileSync6(pubPath, "utf8").trim();
|
|
2676
3020
|
return k.length > 0 ? k : null;
|
|
2677
3021
|
}
|
|
2678
3022
|
function materializeSecrets(opts = {}) {
|
|
@@ -2683,12 +3027,12 @@ function materializeSecrets(opts = {}) {
|
|
|
2683
3027
|
const applied = [];
|
|
2684
3028
|
const failed = [];
|
|
2685
3029
|
const key = readAgentEncryptionKey(opts.keyPath);
|
|
2686
|
-
const files = key &&
|
|
3030
|
+
const files = key && existsSync7(dir) ? readdirSync(dir) : [];
|
|
2687
3031
|
for (const file of files) {
|
|
2688
3032
|
const name = envNameFromFile(file);
|
|
2689
3033
|
if (!name) continue;
|
|
2690
3034
|
try {
|
|
2691
|
-
const box = JSON.parse(
|
|
3035
|
+
const box = JSON.parse(readFileSync6(join5(dir, file), "utf8"));
|
|
2692
3036
|
env[name] = openString(box, key);
|
|
2693
3037
|
applied.push(name);
|
|
2694
3038
|
} catch (e) {
|
|
@@ -2715,7 +3059,7 @@ function startSecretsWatcher(opts = {}) {
|
|
|
2715
3059
|
appliedNames = new Set(r.applied);
|
|
2716
3060
|
};
|
|
2717
3061
|
run();
|
|
2718
|
-
if (!
|
|
3062
|
+
if (!existsSync7(dir)) return () => {
|
|
2719
3063
|
};
|
|
2720
3064
|
let timer = null;
|
|
2721
3065
|
const watcher = watch(dir, () => {
|
|
@@ -2815,9 +3159,9 @@ function decideMerge(paths, policy = SECURE_DEFAULT_POLICY, agentRisk) {
|
|
|
2815
3159
|
}
|
|
2816
3160
|
async function loadMergePolicy(worktreeDir) {
|
|
2817
3161
|
const { readFile } = await import("fs/promises");
|
|
2818
|
-
const { join:
|
|
3162
|
+
const { join: join21 } = await import("path");
|
|
2819
3163
|
try {
|
|
2820
|
-
const raw = await readFile(
|
|
3164
|
+
const raw = await readFile(join21(worktreeDir, ".openape", "coding.json"), "utf8");
|
|
2821
3165
|
const parsed = JSON.parse(raw);
|
|
2822
3166
|
const mp = parsed.mergePolicy;
|
|
2823
3167
|
if (!mp) return SECURE_DEFAULT_POLICY;
|
|
@@ -2877,8 +3221,14 @@ async function runCodingTask(input, deps) {
|
|
|
2877
3221
|
|
|
2878
3222
|
Worktree: ${worktree}`,
|
|
2879
3223
|
tools: deps.tools,
|
|
2880
|
-
maxSteps: deps.maxSteps
|
|
3224
|
+
maxSteps: deps.maxSteps,
|
|
3225
|
+
streamAggregate: deps.streamAggregate
|
|
2881
3226
|
});
|
|
3227
|
+
if (process.env.OPENAPE_VERBOSE_TRACE === "1") {
|
|
3228
|
+
for (const t of run.trace) {
|
|
3229
|
+
log(`[trace] step=${t.step} type=${t.type}${t.tool ? ` tool=${t.tool}` : ""} ${t.preview}`);
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
2882
3232
|
if (run.status !== "ok") {
|
|
2883
3233
|
return { branch, worktree, runStatus: "error", changedFiles: [], outcome: "run-failed", reason: `coding loop errored after ${run.stepCount} steps` };
|
|
2884
3234
|
}
|
|
@@ -3054,15 +3404,15 @@ function parseCodeowners(text) {
|
|
|
3054
3404
|
}
|
|
3055
3405
|
async function deriveRiskGlobs(worktreeDir) {
|
|
3056
3406
|
const { readFile, readdir } = await import("fs/promises");
|
|
3057
|
-
const { join:
|
|
3407
|
+
const { join: join21 } = await import("path");
|
|
3058
3408
|
const globs = /* @__PURE__ */ new Set();
|
|
3059
3409
|
try {
|
|
3060
|
-
const wfDir =
|
|
3410
|
+
const wfDir = join21(worktreeDir, ".github", "workflows");
|
|
3061
3411
|
const files = await readdir(wfDir);
|
|
3062
3412
|
for (const f of files) {
|
|
3063
3413
|
if (!/deploy.*\.ya?ml$/i.test(f)) continue;
|
|
3064
3414
|
try {
|
|
3065
|
-
const text = await readFile(
|
|
3415
|
+
const text = await readFile(join21(wfDir, f), "utf8");
|
|
3066
3416
|
for (const g of extractWorkflowPaths(text)) globs.add(g);
|
|
3067
3417
|
} catch {
|
|
3068
3418
|
}
|
|
@@ -3071,7 +3421,7 @@ async function deriveRiskGlobs(worktreeDir) {
|
|
|
3071
3421
|
}
|
|
3072
3422
|
for (const loc of [".github/CODEOWNERS", "CODEOWNERS", "docs/CODEOWNERS"]) {
|
|
3073
3423
|
try {
|
|
3074
|
-
const text = await readFile(
|
|
3424
|
+
const text = await readFile(join21(worktreeDir, loc), "utf8");
|
|
3075
3425
|
for (const g of parseCodeowners(text)) globs.add(g);
|
|
3076
3426
|
break;
|
|
3077
3427
|
} catch {
|
|
@@ -3102,29 +3452,29 @@ var DEFAULT_PERSONA = [
|
|
|
3102
3452
|
].join(" ");
|
|
3103
3453
|
function readLitellmConfig(model) {
|
|
3104
3454
|
const env = {};
|
|
3105
|
-
const envPath =
|
|
3106
|
-
if (
|
|
3107
|
-
for (const raw of
|
|
3455
|
+
const envPath = join6(homedir5(), "litellm", ".env");
|
|
3456
|
+
if (existsSync8(envPath)) {
|
|
3457
|
+
for (const raw of readFileSync7(envPath, "utf8").split("\n")) {
|
|
3108
3458
|
const line = raw.trim();
|
|
3109
3459
|
const m = /^([A-Z_][A-Z0-9_]*)=(.*)$/.exec(line);
|
|
3110
3460
|
if (m) env[m[1]] = m[2].trim().replace(/^["']|["']$/g, "");
|
|
3111
3461
|
}
|
|
3112
3462
|
}
|
|
3113
3463
|
for (const k of ["LITELLM_API_KEY", "LITELLM_MASTER_KEY", "LITELLM_BASE_URL"]) {
|
|
3114
|
-
if (
|
|
3464
|
+
if (process3.env[k]) env[k] = process3.env[k];
|
|
3115
3465
|
}
|
|
3116
3466
|
const apiBase = (env.LITELLM_BASE_URL || "http://127.0.0.1:4000/v1").replace(/\/$/, "");
|
|
3117
3467
|
const isLoopback = /^https?:\/\/(?:127\.0\.0\.1|localhost|\[::1\])(?::\d+)?(?:\/|$)/.test(apiBase);
|
|
3118
3468
|
const apiKey = env.LITELLM_API_KEY || env.LITELLM_MASTER_KEY || (isLoopback ? "sk-loopback-noauth" : "");
|
|
3119
3469
|
if (!apiKey) throw new CliError2("No LITELLM_API_KEY / LITELLM_MASTER_KEY for non-loopback LITELLM_BASE_URL.");
|
|
3120
|
-
return { apiBase, apiKey, model: model ||
|
|
3470
|
+
return { apiBase, apiKey, model: model || process3.env.APE_CHAT_BRIDGE_MODEL || "claude-haiku-4-5" };
|
|
3121
3471
|
}
|
|
3122
3472
|
function readPersona(file) {
|
|
3123
|
-
if (file &&
|
|
3124
|
-
const agentJson =
|
|
3125
|
-
if (
|
|
3473
|
+
if (file && existsSync8(file)) return readFileSync7(file, "utf8");
|
|
3474
|
+
const agentJson = join6(homedir5(), ".openape", "agent", "agent.json");
|
|
3475
|
+
if (existsSync8(agentJson)) {
|
|
3126
3476
|
try {
|
|
3127
|
-
const p = JSON.parse(
|
|
3477
|
+
const p = JSON.parse(readFileSync7(agentJson, "utf8"));
|
|
3128
3478
|
if (p.systemPrompt?.trim()) return p.systemPrompt;
|
|
3129
3479
|
} catch {
|
|
3130
3480
|
}
|
|
@@ -3165,6 +3515,7 @@ var codeAgentCommand = defineCommand24({
|
|
|
3165
3515
|
const persona = readPersona(args["persona-file"]);
|
|
3166
3516
|
const maxSteps = Number(args["max-steps"]) > 0 ? Number(args["max-steps"]) : 40;
|
|
3167
3517
|
const tools = taskTools(CODING_TOOLS);
|
|
3518
|
+
const streamAggregate = process3.env.OPENAPE_STREAM_AGGREGATE === "1";
|
|
3168
3519
|
const deps = {
|
|
3169
3520
|
runtimeConfig: config,
|
|
3170
3521
|
tools,
|
|
@@ -3173,7 +3524,8 @@ var codeAgentCommand = defineCommand24({
|
|
|
3173
3524
|
resolvePolicy: (worktree) => resolveMergePolicy(worktree),
|
|
3174
3525
|
reviewer: createLlmReviewer(config),
|
|
3175
3526
|
riskAssessor: createLlmRiskAssessor(config),
|
|
3176
|
-
log: (l) => consola21.info(l)
|
|
3527
|
+
log: (l) => consola21.info(l),
|
|
3528
|
+
streamAggregate
|
|
3177
3529
|
};
|
|
3178
3530
|
const refs = [];
|
|
3179
3531
|
if (args["poll-label"]) {
|
|
@@ -3207,30 +3559,30 @@ ${result.reason}`);
|
|
|
3207
3559
|
});
|
|
3208
3560
|
|
|
3209
3561
|
// src/commands/agents/destroy.ts
|
|
3210
|
-
import { execFileSync as
|
|
3211
|
-
import { mkdtempSync, rmSync as
|
|
3212
|
-
import { tmpdir, userInfo } from "os";
|
|
3213
|
-
import { join as
|
|
3562
|
+
import { execFileSync as execFileSync12 } from "child_process";
|
|
3563
|
+
import { mkdtempSync as mkdtempSync3, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
3564
|
+
import { tmpdir as tmpdir3, userInfo as userInfo2 } from "os";
|
|
3565
|
+
import { join as join8 } from "path";
|
|
3214
3566
|
import { defineCommand as defineCommand25 } from "citty";
|
|
3215
3567
|
import consola22 from "consola";
|
|
3216
3568
|
|
|
3217
3569
|
// src/lib/nest-registry.ts
|
|
3218
|
-
import { existsSync as
|
|
3570
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync2, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
|
|
3219
3571
|
import { homedir as homedir6 } from "os";
|
|
3220
|
-
import { join as
|
|
3572
|
+
import { join as join7 } from "path";
|
|
3221
3573
|
function resolveRegistryPath() {
|
|
3222
|
-
if (
|
|
3223
|
-
if (
|
|
3224
|
-
return
|
|
3574
|
+
if (existsSync9("/var/openape/nest/agents.json")) return "/var/openape/nest/agents.json";
|
|
3575
|
+
if (existsSync9("/var/openape/nest")) return "/var/openape/nest/agents.json";
|
|
3576
|
+
return join7(homedir6(), ".openape", "nest", "agents.json");
|
|
3225
3577
|
}
|
|
3226
3578
|
function emptyRegistry() {
|
|
3227
3579
|
return { version: 1, agents: [] };
|
|
3228
3580
|
}
|
|
3229
3581
|
function readNestRegistry() {
|
|
3230
3582
|
const path2 = resolveRegistryPath();
|
|
3231
|
-
if (!
|
|
3583
|
+
if (!existsSync9(path2)) return emptyRegistry();
|
|
3232
3584
|
try {
|
|
3233
|
-
const parsed = JSON.parse(
|
|
3585
|
+
const parsed = JSON.parse(readFileSync8(path2, "utf8"));
|
|
3234
3586
|
if (parsed?.version !== 1 || !Array.isArray(parsed.agents)) return emptyRegistry();
|
|
3235
3587
|
return parsed;
|
|
3236
3588
|
} catch {
|
|
@@ -3241,10 +3593,10 @@ function writeNestRegistry(reg) {
|
|
|
3241
3593
|
const path2 = resolveRegistryPath();
|
|
3242
3594
|
const dir = path2.replace(/\/agents\.json$/, "");
|
|
3243
3595
|
try {
|
|
3244
|
-
|
|
3596
|
+
mkdirSync2(dir, { recursive: true });
|
|
3245
3597
|
} catch {
|
|
3246
3598
|
}
|
|
3247
|
-
|
|
3599
|
+
writeFileSync5(path2, `${JSON.stringify(reg, null, 2)}
|
|
3248
3600
|
`, { mode: 432 });
|
|
3249
3601
|
}
|
|
3250
3602
|
function upsertNestAgent(entry) {
|
|
@@ -3357,8 +3709,9 @@ var destroyAgentCommand = defineCommand25({
|
|
|
3357
3709
|
if (process.geteuid?.() !== 0) {
|
|
3358
3710
|
throw new CliError("--root-stage was passed but this process is not running as root. Refusing to continue.");
|
|
3359
3711
|
}
|
|
3360
|
-
const
|
|
3361
|
-
const
|
|
3712
|
+
const platform = getHostPlatform();
|
|
3713
|
+
const resolved = platform.lookupAgentUser(name);
|
|
3714
|
+
const macOSUsername = resolved?.name ?? platform.agentUsername(name);
|
|
3362
3715
|
const homeDir = resolved?.homeDir ?? `/var/openape/homes/${macOSUsername}`;
|
|
3363
3716
|
consola22.start(`Running teardown for ${name} (Phase-G, root-stage)\u2026`);
|
|
3364
3717
|
runPhaseGTeardownInProcess({ name, homeDir, macOSUsername });
|
|
@@ -3375,7 +3728,7 @@ var destroyAgentCommand = defineCommand25({
|
|
|
3375
3728
|
const owned = await apiFetch("/api/my-agents", { idp });
|
|
3376
3729
|
const idpAgent = owned.find((u) => u.name === name);
|
|
3377
3730
|
const idpExists = idpAgent !== void 0;
|
|
3378
|
-
const osUser =
|
|
3731
|
+
const osUser = isDarwin2() ? getHostPlatform().lookupAgentUser(name) : null;
|
|
3379
3732
|
const osUserExists = !args["keep-os-user"] && osUser !== null;
|
|
3380
3733
|
if (!idpExists && !osUserExists) {
|
|
3381
3734
|
consola22.info(`Nothing to destroy: no IdP agent and no OS user for "${name}".`);
|
|
@@ -3415,7 +3768,7 @@ ${consequences.join("\n")}`);
|
|
|
3415
3768
|
consola22.info("No IdP agent to remove (skipped).");
|
|
3416
3769
|
}
|
|
3417
3770
|
if (osUserExists) {
|
|
3418
|
-
const macOSUsername = osUser?.name ??
|
|
3771
|
+
const macOSUsername = osUser?.name ?? getHostPlatform().agentUsername(name);
|
|
3419
3772
|
const fallbackHome = macOSUsername.startsWith("openape-agent-") ? `/var/openape/homes/${macOSUsername}` : `/Users/${macOSUsername}`;
|
|
3420
3773
|
const homeDir = osUser?.homeDir ?? fallbackHome;
|
|
3421
3774
|
const isPhaseG = homeDir.startsWith("/var/openape/homes/");
|
|
@@ -3425,7 +3778,7 @@ ${consequences.join("\n")}`);
|
|
|
3425
3778
|
runPhaseGTeardownInProcess({ name, homeDir, macOSUsername });
|
|
3426
3779
|
} else {
|
|
3427
3780
|
consola22.start("Running teardown (Phase G \u2014 no admin password needed)\u2026");
|
|
3428
|
-
|
|
3781
|
+
execFileSync12("apes", [
|
|
3429
3782
|
"run",
|
|
3430
3783
|
"--as",
|
|
3431
3784
|
"root",
|
|
@@ -3445,7 +3798,7 @@ ${consequences.join("\n")}`);
|
|
|
3445
3798
|
if (!sudo) {
|
|
3446
3799
|
throw new CliError("`sudo` not found on PATH; required for OS teardown.");
|
|
3447
3800
|
}
|
|
3448
|
-
const adminUser =
|
|
3801
|
+
const adminUser = userInfo2().username;
|
|
3449
3802
|
let adminPassword;
|
|
3450
3803
|
try {
|
|
3451
3804
|
adminPassword = await collectAdminPassword({ adminUser });
|
|
@@ -3459,24 +3812,24 @@ ${consequences.join("\n")}`);
|
|
|
3459
3812
|
}
|
|
3460
3813
|
}
|
|
3461
3814
|
if (adminPassword) {
|
|
3462
|
-
const scratch =
|
|
3463
|
-
const scriptPath =
|
|
3815
|
+
const scratch = mkdtempSync3(join8(tmpdir3(), `apes-destroy-${name}-`));
|
|
3816
|
+
const scriptPath = join8(scratch, "teardown.sh");
|
|
3464
3817
|
try {
|
|
3465
3818
|
const script = buildDestroyTeardownScript({ name, homeDir, adminUser });
|
|
3466
|
-
|
|
3819
|
+
writeFileSync6(scriptPath, script, { mode: 448 });
|
|
3467
3820
|
consola22.start("Running teardown via sudo\u2026");
|
|
3468
|
-
|
|
3821
|
+
execFileSync12(sudo, ["-S", "--prompt=", "--", "bash", scriptPath], {
|
|
3469
3822
|
input: `${adminPassword}
|
|
3470
3823
|
${adminPassword}
|
|
3471
3824
|
`,
|
|
3472
3825
|
stdio: ["pipe", "inherit", "inherit"]
|
|
3473
3826
|
});
|
|
3474
3827
|
} finally {
|
|
3475
|
-
|
|
3828
|
+
rmSync4(scratch, { recursive: true, force: true });
|
|
3476
3829
|
}
|
|
3477
3830
|
}
|
|
3478
3831
|
}
|
|
3479
|
-
} else if (!args["keep-os-user"] &&
|
|
3832
|
+
} else if (!args["keep-os-user"] && isDarwin2()) {
|
|
3480
3833
|
consola22.info("No macOS user to remove (skipped).");
|
|
3481
3834
|
}
|
|
3482
3835
|
try {
|
|
@@ -3526,11 +3879,12 @@ var listAgentsCommand = defineCommand26({
|
|
|
3526
3879
|
}
|
|
3527
3880
|
const all = await apiFetch("/api/my-agents", { idp });
|
|
3528
3881
|
const filtered = args["include-inactive"] ? all : all.filter((u) => u.isActive !== false);
|
|
3529
|
-
const
|
|
3882
|
+
const platform = getHostPlatform();
|
|
3883
|
+
const osUsers = isDarwin2() ? platform.listAgentUserNames() : /* @__PURE__ */ new Set();
|
|
3530
3884
|
const osStateOf = (agentName) => {
|
|
3531
|
-
const u =
|
|
3885
|
+
const u = platform.lookupAgentUser(agentName);
|
|
3532
3886
|
if (u) return { osUser: true, home: u.homeDir };
|
|
3533
|
-
if (osUsers.has(
|
|
3887
|
+
if (osUsers.has(platform.agentUsername(agentName)) || osUsers.has(agentName)) {
|
|
3534
3888
|
return { osUser: true, home: null };
|
|
3535
3889
|
}
|
|
3536
3890
|
return { osUser: false, home: null };
|
|
@@ -3562,14 +3916,14 @@ var listAgentsCommand = defineCommand26({
|
|
|
3562
3916
|
for (const r of rows) {
|
|
3563
3917
|
const active = r.isActive ? "\u2713" : "\u2717";
|
|
3564
3918
|
const os = r.osUser ? "\u2713" : "\u2717";
|
|
3565
|
-
const homeCol = r.home ?? (
|
|
3919
|
+
const homeCol = r.home ?? (isDarwin2() ? "(missing)" : "(non-darwin)");
|
|
3566
3920
|
console.log(`${r.name.padEnd(nameW)} ${r.email.padEnd(emailW)} ${active.padEnd(6)} ${os.padEnd(7)} ${homeCol}`);
|
|
3567
3921
|
}
|
|
3568
3922
|
}
|
|
3569
3923
|
});
|
|
3570
3924
|
|
|
3571
3925
|
// src/commands/agents/register.ts
|
|
3572
|
-
import { existsSync as
|
|
3926
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
|
|
3573
3927
|
import { defineCommand as defineCommand27 } from "citty";
|
|
3574
3928
|
import consola24 from "consola";
|
|
3575
3929
|
var registerAgentCommand = defineCommand27({
|
|
@@ -3617,10 +3971,10 @@ var registerAgentCommand = defineCommand27({
|
|
|
3617
3971
|
throw new CliError("Pass either --public-key or --public-key-file, not both.");
|
|
3618
3972
|
}
|
|
3619
3973
|
if (!publicKey && keyFile) {
|
|
3620
|
-
if (!
|
|
3974
|
+
if (!existsSync10(keyFile)) {
|
|
3621
3975
|
throw new CliError(`Public-key file not found: ${keyFile}`);
|
|
3622
3976
|
}
|
|
3623
|
-
publicKey =
|
|
3977
|
+
publicKey = readFileSync9(keyFile, "utf-8").trim();
|
|
3624
3978
|
}
|
|
3625
3979
|
if (!publicKey) {
|
|
3626
3980
|
throw new CliError('Provide --public-key "<ssh-ed25519 line>" or --public-key-file <path>.');
|
|
@@ -3655,18 +4009,18 @@ var registerAgentCommand = defineCommand27({
|
|
|
3655
4009
|
});
|
|
3656
4010
|
|
|
3657
4011
|
// src/commands/agents/run.ts
|
|
3658
|
-
import { existsSync as
|
|
4012
|
+
import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
|
|
3659
4013
|
import { homedir as homedir7 } from "os";
|
|
3660
|
-
import { join as
|
|
4014
|
+
import { join as join9 } from "path";
|
|
3661
4015
|
import { defineCommand as defineCommand28 } from "citty";
|
|
3662
4016
|
import consola25 from "consola";
|
|
3663
|
-
var AUTH_PATH =
|
|
3664
|
-
var TASK_CACHE_DIR =
|
|
4017
|
+
var AUTH_PATH = join9(homedir7(), ".config", "apes", "auth.json");
|
|
4018
|
+
var TASK_CACHE_DIR = join9(homedir7(), ".openape", "agent", "tasks");
|
|
3665
4019
|
function readAuth() {
|
|
3666
|
-
if (!
|
|
4020
|
+
if (!existsSync11(AUTH_PATH)) {
|
|
3667
4021
|
throw new CliError(`No agent auth found at ${AUTH_PATH}. Run \`apes agents spawn <name>\` first.`);
|
|
3668
4022
|
}
|
|
3669
|
-
const parsed = JSON.parse(
|
|
4023
|
+
const parsed = JSON.parse(readFileSync10(AUTH_PATH, "utf8"));
|
|
3670
4024
|
if (!parsed.access_token) throw new CliError("auth.json missing access_token");
|
|
3671
4025
|
return parsed;
|
|
3672
4026
|
}
|
|
@@ -3702,26 +4056,26 @@ ${msg}`.slice(0, 9e3);
|
|
|
3702
4056
|
}
|
|
3703
4057
|
}
|
|
3704
4058
|
function readTaskSpec(taskId) {
|
|
3705
|
-
const path2 =
|
|
3706
|
-
if (!
|
|
4059
|
+
const path2 = join9(TASK_CACHE_DIR, `${taskId}.json`);
|
|
4060
|
+
if (!existsSync11(path2)) {
|
|
3707
4061
|
throw new CliError(`No cached task spec at ${path2}. Run \`apes agents sync\` first to pull the task list from troop.`);
|
|
3708
4062
|
}
|
|
3709
|
-
return JSON.parse(
|
|
4063
|
+
return JSON.parse(readFileSync10(path2, "utf8"));
|
|
3710
4064
|
}
|
|
3711
|
-
var AGENT_CONFIG_PATH =
|
|
4065
|
+
var AGENT_CONFIG_PATH = join9(homedir7(), ".openape", "agent", "agent.json");
|
|
3712
4066
|
function readAgentConfig() {
|
|
3713
|
-
if (!
|
|
4067
|
+
if (!existsSync11(AGENT_CONFIG_PATH)) return { systemPrompt: "" };
|
|
3714
4068
|
try {
|
|
3715
|
-
return JSON.parse(
|
|
4069
|
+
return JSON.parse(readFileSync10(AGENT_CONFIG_PATH, "utf8"));
|
|
3716
4070
|
} catch {
|
|
3717
4071
|
return { systemPrompt: "" };
|
|
3718
4072
|
}
|
|
3719
4073
|
}
|
|
3720
4074
|
function readLitellmConfig2(model) {
|
|
3721
|
-
const envPath =
|
|
4075
|
+
const envPath = join9(homedir7(), "litellm", ".env");
|
|
3722
4076
|
const env = {};
|
|
3723
|
-
if (
|
|
3724
|
-
for (const line of
|
|
4077
|
+
if (existsSync11(envPath)) {
|
|
4078
|
+
for (const line of readFileSync10(envPath, "utf8").split(/\r?\n/)) {
|
|
3725
4079
|
const m = line.match(/^([A-Z_]+)=(.*)$/);
|
|
3726
4080
|
if (m) env[m[1]] = m[2].replace(/^["']|["']$/g, "");
|
|
3727
4081
|
}
|
|
@@ -3827,17 +4181,17 @@ var runAgentCommand = defineCommand28({
|
|
|
3827
4181
|
});
|
|
3828
4182
|
|
|
3829
4183
|
// src/commands/agents/serve.ts
|
|
3830
|
-
import { existsSync as
|
|
4184
|
+
import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
|
|
3831
4185
|
import { homedir as homedir8 } from "os";
|
|
3832
|
-
import { join as
|
|
4186
|
+
import { join as join10 } from "path";
|
|
3833
4187
|
import { createInterface } from "readline";
|
|
3834
4188
|
import { defineCommand as defineCommand29 } from "citty";
|
|
3835
|
-
var AUTH_PATH2 =
|
|
4189
|
+
var AUTH_PATH2 = join10(homedir8(), ".config", "apes", "auth.json");
|
|
3836
4190
|
function readLitellmConfig3(model) {
|
|
3837
|
-
const envPath =
|
|
4191
|
+
const envPath = join10(homedir8(), "litellm", ".env");
|
|
3838
4192
|
const env = {};
|
|
3839
|
-
if (
|
|
3840
|
-
for (const line of
|
|
4193
|
+
if (existsSync12(envPath)) {
|
|
4194
|
+
for (const line of readFileSync11(envPath, "utf8").split(/\r?\n/)) {
|
|
3841
4195
|
const m = line.match(/^([A-Z_]+)=(.*)$/);
|
|
3842
4196
|
if (m) env[m[1]] = m[2].replace(/^["']|["']$/g, "");
|
|
3843
4197
|
}
|
|
@@ -3869,9 +4223,9 @@ var serveAgentCommand = defineCommand29({
|
|
|
3869
4223
|
if (!args.rpc) {
|
|
3870
4224
|
throw new CliError("apes agents serve currently only supports --rpc mode");
|
|
3871
4225
|
}
|
|
3872
|
-
if (
|
|
4226
|
+
if (existsSync12(AUTH_PATH2)) {
|
|
3873
4227
|
try {
|
|
3874
|
-
JSON.parse(
|
|
4228
|
+
JSON.parse(readFileSync11(AUTH_PATH2, "utf8"));
|
|
3875
4229
|
} catch {
|
|
3876
4230
|
}
|
|
3877
4231
|
}
|
|
@@ -3951,10 +4305,6 @@ async function handleInbound(msg, sessions) {
|
|
|
3951
4305
|
}
|
|
3952
4306
|
|
|
3953
4307
|
// src/commands/agents/spawn.ts
|
|
3954
|
-
import { execFileSync as execFileSync8 } from "child_process";
|
|
3955
|
-
import { mkdtempSync as mkdtempSync2, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
3956
|
-
import { tmpdir as tmpdir2 } from "os";
|
|
3957
|
-
import { join as join9 } from "path";
|
|
3958
4308
|
import { defineCommand as defineCommand30 } from "citty";
|
|
3959
4309
|
import consola26 from "consola";
|
|
3960
4310
|
|
|
@@ -4012,7 +4362,7 @@ ${envBlock} <key>StartInterval</key>
|
|
|
4012
4362
|
|
|
4013
4363
|
// src/lib/keygen.ts
|
|
4014
4364
|
import { Buffer as Buffer4 } from "buffer";
|
|
4015
|
-
import { existsSync as
|
|
4365
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync3, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "fs";
|
|
4016
4366
|
import { generateKeyPairSync } from "crypto";
|
|
4017
4367
|
import { homedir as homedir9 } from "os";
|
|
4018
4368
|
import { dirname, resolve as resolve2 } from "path";
|
|
@@ -4031,10 +4381,10 @@ function buildSshEd25519Line(rawPub) {
|
|
|
4031
4381
|
}
|
|
4032
4382
|
function readPublicKey(keyPath) {
|
|
4033
4383
|
const pubPath = `${keyPath}.pub`;
|
|
4034
|
-
if (
|
|
4035
|
-
return
|
|
4384
|
+
if (existsSync13(pubPath)) {
|
|
4385
|
+
return readFileSync12(pubPath, "utf-8").trim();
|
|
4036
4386
|
}
|
|
4037
|
-
const keyContent =
|
|
4387
|
+
const keyContent = readFileSync12(keyPath, "utf-8");
|
|
4038
4388
|
const privateKey = loadEd25519PrivateKey(keyContent);
|
|
4039
4389
|
const jwk = privateKey.export({ format: "jwk" });
|
|
4040
4390
|
const pubBytes = Buffer4.from(jwk.x, "base64url");
|
|
@@ -4043,16 +4393,16 @@ function readPublicKey(keyPath) {
|
|
|
4043
4393
|
function generateAndSaveKey(keyPath) {
|
|
4044
4394
|
const resolved = resolveKeyPath(keyPath);
|
|
4045
4395
|
const dir = dirname(resolved);
|
|
4046
|
-
if (!
|
|
4047
|
-
|
|
4396
|
+
if (!existsSync13(dir)) {
|
|
4397
|
+
mkdirSync3(dir, { recursive: true });
|
|
4048
4398
|
}
|
|
4049
4399
|
const { publicKey, privateKey } = generateKeyPairSync("ed25519");
|
|
4050
4400
|
const privatePem = privateKey.export({ type: "pkcs8", format: "pem" });
|
|
4051
|
-
|
|
4401
|
+
writeFileSync7(resolved, privatePem, { mode: 384 });
|
|
4052
4402
|
const jwk = publicKey.export({ format: "jwk" });
|
|
4053
4403
|
const pubBytes = Buffer4.from(jwk.x, "base64url");
|
|
4054
4404
|
const pubKeyStr = buildSshEd25519Line(pubBytes);
|
|
4055
|
-
|
|
4405
|
+
writeFileSync7(`${resolved}.pub`, `${pubKeyStr}
|
|
4056
4406
|
`, { mode: 420 });
|
|
4057
4407
|
return pubKeyStr;
|
|
4058
4408
|
}
|
|
@@ -4071,15 +4421,15 @@ function generateKeyPairInMemory() {
|
|
|
4071
4421
|
}
|
|
4072
4422
|
|
|
4073
4423
|
// src/lib/llm-bridge.ts
|
|
4074
|
-
import { execFileSync as
|
|
4075
|
-
import { existsSync as
|
|
4424
|
+
import { execFileSync as execFileSync13 } from "child_process";
|
|
4425
|
+
import { existsSync as existsSync14, readFileSync as readFileSync13 } from "fs";
|
|
4076
4426
|
import { homedir as homedir10 } from "os";
|
|
4077
|
-
import { dirname as dirname2, join as
|
|
4427
|
+
import { dirname as dirname2, join as join11 } from "path";
|
|
4078
4428
|
var PLIST_LABEL_PREFIX = "eco.hofmann.apes.bridge";
|
|
4079
|
-
function readLitellmEnv(envPath =
|
|
4080
|
-
if (!
|
|
4429
|
+
function readLitellmEnv(envPath = join11(homedir10(), "litellm", ".env")) {
|
|
4430
|
+
if (!existsSync14(envPath)) return null;
|
|
4081
4431
|
try {
|
|
4082
|
-
const text =
|
|
4432
|
+
const text = readFileSync13(envPath, "utf8");
|
|
4083
4433
|
const out = {};
|
|
4084
4434
|
for (const line of text.split("\n")) {
|
|
4085
4435
|
const trimmed = line.trim();
|
|
@@ -4115,7 +4465,7 @@ function captureHostBinDirs() {
|
|
|
4115
4465
|
for (const bin of ["node", "ape-agent", "apes"]) {
|
|
4116
4466
|
let resolved;
|
|
4117
4467
|
try {
|
|
4118
|
-
resolved =
|
|
4468
|
+
resolved = execFileSync13("/usr/bin/which", [bin], { encoding: "utf8" }).trim();
|
|
4119
4469
|
} catch {
|
|
4120
4470
|
const installCmd = bin === "ape-agent" ? "npm i -g @openape/ape-agent" : bin === "apes" ? "npm i -g @openape/apes" : "install Node.js (e.g. brew install node)";
|
|
4121
4471
|
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.`);
|
|
@@ -4210,7 +4560,7 @@ function buildBridgePlist(agentName, homeDir, ownerEmail, hostBinDirs) {
|
|
|
4210
4560
|
// src/commands/agents/spawn.ts
|
|
4211
4561
|
function readMacOSUidOrNull(name) {
|
|
4212
4562
|
try {
|
|
4213
|
-
const u =
|
|
4563
|
+
const u = getHostPlatform().readAgentUser(name);
|
|
4214
4564
|
return u?.uid ?? null;
|
|
4215
4565
|
} catch {
|
|
4216
4566
|
return null;
|
|
@@ -4267,7 +4617,7 @@ var spawnAgentCommand = defineCommand30({
|
|
|
4267
4617
|
`Invalid agent name "${name}". Must match /^[a-z][a-z0-9-]{0,23}$/ \u2014 lowercase letters, digits and hyphens, 1\u201324 chars, must start with a letter.`
|
|
4268
4618
|
);
|
|
4269
4619
|
}
|
|
4270
|
-
if (!
|
|
4620
|
+
if (!isDarwin2()) {
|
|
4271
4621
|
throw new CliError(
|
|
4272
4622
|
`\`apes agents spawn\` is currently macOS-only. Detected platform: ${process.platform}. Linux support is a follow-up; for now, use \`apes agents register\` plus a manually provisioned user.`
|
|
4273
4623
|
);
|
|
@@ -4298,14 +4648,13 @@ var spawnAgentCommand = defineCommand30({
|
|
|
4298
4648
|
and try again.`
|
|
4299
4649
|
);
|
|
4300
4650
|
}
|
|
4301
|
-
const
|
|
4302
|
-
const
|
|
4651
|
+
const platform = getHostPlatform();
|
|
4652
|
+
const macOSUsername = platform.agentUsername(name);
|
|
4653
|
+
const existing = platform.readAgentUser(macOSUsername) ?? platform.readAgentUser(name);
|
|
4303
4654
|
if (existing) {
|
|
4304
4655
|
throw new CliError(`macOS user "${existing.name}" already exists (uid=${existing.uid ?? "?"}). Refusing to overwrite.`);
|
|
4305
4656
|
}
|
|
4306
4657
|
const homeDir = `/var/openape/homes/${macOSUsername}`;
|
|
4307
|
-
const scratch = mkdtempSync2(join9(tmpdir2(), `apes-spawn-${name}-`));
|
|
4308
|
-
const scriptPath = join9(scratch, "setup.sh");
|
|
4309
4658
|
try {
|
|
4310
4659
|
consola26.start(`Generating keypair for ${name}\u2026`);
|
|
4311
4660
|
const { privatePem, publicSshLine, x25519PrivateKey, x25519PublicKey } = generateKeyPairInMemory();
|
|
@@ -4379,16 +4728,11 @@ and try again.`
|
|
|
4379
4728
|
bridge,
|
|
4380
4729
|
troop
|
|
4381
4730
|
});
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
if (alreadyRoot) {
|
|
4385
|
-
consola26.start("Running privileged setup directly (already root)\u2026");
|
|
4386
|
-
execFileSync8("bash", [scriptPath], { stdio: "inherit" });
|
|
4387
|
-
} else {
|
|
4388
|
-
consola26.start("Running privileged setup as root via `apes run --as root --wait`\u2026");
|
|
4731
|
+
consola26.start("Running privileged setup\u2026");
|
|
4732
|
+
if (process.getuid?.() !== 0) {
|
|
4389
4733
|
consola26.info("You will be asked to approve the as=root grant in your DDISA inbox; this command blocks until you do.");
|
|
4390
|
-
execFileSync8(apes, ["run", "--as", "root", "--wait", "--", "bash", scriptPath], { stdio: "inherit" });
|
|
4391
4734
|
}
|
|
4735
|
+
await platform.runPrivilegedBash(script);
|
|
4392
4736
|
try {
|
|
4393
4737
|
const uid = readMacOSUidOrNull(macOSUsername) ?? readMacOSUidOrNull(name);
|
|
4394
4738
|
upsertNestAgent({
|
|
@@ -4416,7 +4760,6 @@ and try again.`
|
|
|
4416
4760
|
console.log("Run as the agent with:");
|
|
4417
4761
|
console.log(` apes run --as ${name} -- claude --session-name ${name} --dangerously-skip-permissions`);
|
|
4418
4762
|
} finally {
|
|
4419
|
-
rmSync3(scratch, { recursive: true, force: true });
|
|
4420
4763
|
}
|
|
4421
4764
|
}
|
|
4422
4765
|
});
|
|
@@ -4444,46 +4787,20 @@ async function resolveClaudeToken(opts) {
|
|
|
4444
4787
|
}
|
|
4445
4788
|
|
|
4446
4789
|
// src/commands/agents/sync.ts
|
|
4447
|
-
import { chownSync, existsSync as
|
|
4790
|
+
import { chownSync, existsSync as existsSync15, mkdirSync as mkdirSync4, readdirSync as readdirSync2, readFileSync as readFileSync14, rmSync as rmSync5, statSync, writeFileSync as writeFileSync8 } from "fs";
|
|
4448
4791
|
import { homedir as homedir11 } from "os";
|
|
4449
|
-
import { join as
|
|
4792
|
+
import { join as join12 } from "path";
|
|
4450
4793
|
import { defineCommand as defineCommand31 } from "citty";
|
|
4451
4794
|
import consola27 from "consola";
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
import { execFileSync as execFileSync9 } from "child_process";
|
|
4455
|
-
import { hostname as hostname3 } from "os";
|
|
4456
|
-
function getHostId() {
|
|
4457
|
-
try {
|
|
4458
|
-
const output = execFileSync9(
|
|
4459
|
-
"/usr/sbin/ioreg",
|
|
4460
|
-
["-d2", "-c", "IOPlatformExpertDevice"],
|
|
4461
|
-
{ encoding: "utf8", timeout: 2e3 }
|
|
4462
|
-
);
|
|
4463
|
-
const match = output.match(/"IOPlatformUUID"\s*=\s*"([^"]+)"/);
|
|
4464
|
-
return match ? match[1].trim().toLowerCase() : "";
|
|
4465
|
-
} catch {
|
|
4466
|
-
return "";
|
|
4467
|
-
}
|
|
4468
|
-
}
|
|
4469
|
-
function getHostname() {
|
|
4470
|
-
try {
|
|
4471
|
-
return hostname3();
|
|
4472
|
-
} catch {
|
|
4473
|
-
return "";
|
|
4474
|
-
}
|
|
4475
|
-
}
|
|
4476
|
-
|
|
4477
|
-
// src/commands/agents/sync.ts
|
|
4478
|
-
var AUTH_PATH3 = join10(homedir11(), ".config", "apes", "auth.json");
|
|
4479
|
-
var TASK_CACHE_DIR2 = join10(homedir11(), ".openape", "agent", "tasks");
|
|
4795
|
+
var AUTH_PATH3 = join12(homedir11(), ".config", "apes", "auth.json");
|
|
4796
|
+
var TASK_CACHE_DIR2 = join12(homedir11(), ".openape", "agent", "tasks");
|
|
4480
4797
|
function readAuthJson() {
|
|
4481
|
-
if (!
|
|
4798
|
+
if (!existsSync15(AUTH_PATH3)) {
|
|
4482
4799
|
throw new CliError(
|
|
4483
4800
|
`No agent auth found at ${AUTH_PATH3}. Run \`apes agents spawn <name>\` to provision an agent first.`
|
|
4484
4801
|
);
|
|
4485
4802
|
}
|
|
4486
|
-
const raw =
|
|
4803
|
+
const raw = readFileSync14(AUTH_PATH3, "utf8");
|
|
4487
4804
|
let parsed;
|
|
4488
4805
|
try {
|
|
4489
4806
|
parsed = JSON.parse(raw);
|
|
@@ -4523,8 +4840,9 @@ var syncAgentCommand = defineCommand31({
|
|
|
4523
4840
|
const agentName = agentNameFromEmail(auth.email);
|
|
4524
4841
|
const troopUrl = resolveTroopUrl(args["troop-url"]);
|
|
4525
4842
|
const client = new TroopClient(troopUrl, auth.access_token);
|
|
4526
|
-
const
|
|
4527
|
-
const
|
|
4843
|
+
const platform = getHostPlatform();
|
|
4844
|
+
const hostId = platform.getHostId();
|
|
4845
|
+
const host = platform.getHostname();
|
|
4528
4846
|
if (!hostId) {
|
|
4529
4847
|
throw new CliError("Could not read IOPlatformUUID \u2014 is this macOS? Troop sync only works on macOS for v1.");
|
|
4530
4848
|
}
|
|
@@ -4563,46 +4881,46 @@ var syncAgentCommand = defineCommand31({
|
|
|
4563
4881
|
}
|
|
4564
4882
|
}
|
|
4565
4883
|
}
|
|
4566
|
-
const agentDir =
|
|
4567
|
-
|
|
4568
|
-
chownToAgent(
|
|
4884
|
+
const agentDir = join12(homedir11(), ".openape", "agent");
|
|
4885
|
+
mkdirSync4(agentDir, { recursive: true });
|
|
4886
|
+
chownToAgent(join12(homedir11(), ".openape"));
|
|
4569
4887
|
chownToAgent(agentDir);
|
|
4570
|
-
const agentJsonPath =
|
|
4571
|
-
|
|
4888
|
+
const agentJsonPath = join12(agentDir, "agent.json");
|
|
4889
|
+
writeFileSync8(
|
|
4572
4890
|
agentJsonPath,
|
|
4573
4891
|
`${JSON.stringify({ systemPrompt, tools }, null, 2)}
|
|
4574
4892
|
`,
|
|
4575
4893
|
{ mode: 384 }
|
|
4576
4894
|
);
|
|
4577
4895
|
chownToAgent(agentJsonPath);
|
|
4578
|
-
|
|
4896
|
+
mkdirSync4(TASK_CACHE_DIR2, { recursive: true });
|
|
4579
4897
|
chownToAgent(TASK_CACHE_DIR2);
|
|
4580
4898
|
for (const task of tasks) {
|
|
4581
|
-
const path2 =
|
|
4582
|
-
|
|
4899
|
+
const path2 = join12(TASK_CACHE_DIR2, `${task.taskId}.json`);
|
|
4900
|
+
writeFileSync8(path2, `${JSON.stringify(task, null, 2)}
|
|
4583
4901
|
`, { mode: 384 });
|
|
4584
4902
|
chownToAgent(path2);
|
|
4585
4903
|
}
|
|
4586
|
-
const skillsDir =
|
|
4587
|
-
|
|
4904
|
+
const skillsDir = join12(agentDir, "skills");
|
|
4905
|
+
mkdirSync4(skillsDir, { recursive: true });
|
|
4588
4906
|
chownToAgent(skillsDir);
|
|
4589
4907
|
const incomingNames = new Set(skills.map((s) => s.name));
|
|
4590
4908
|
try {
|
|
4591
4909
|
for (const entry of readdirSync2(skillsDir)) {
|
|
4592
4910
|
if (incomingNames.has(entry)) continue;
|
|
4593
4911
|
try {
|
|
4594
|
-
|
|
4912
|
+
rmSync5(join12(skillsDir, entry), { recursive: true, force: true });
|
|
4595
4913
|
} catch {
|
|
4596
4914
|
}
|
|
4597
4915
|
}
|
|
4598
4916
|
} catch {
|
|
4599
4917
|
}
|
|
4600
4918
|
for (const skill of skills) {
|
|
4601
|
-
const skillDir =
|
|
4602
|
-
|
|
4919
|
+
const skillDir = join12(skillsDir, skill.name);
|
|
4920
|
+
mkdirSync4(skillDir, { recursive: true });
|
|
4603
4921
|
chownToAgent(skillDir);
|
|
4604
|
-
const skillPath =
|
|
4605
|
-
|
|
4922
|
+
const skillPath = join12(skillDir, "SKILL.md");
|
|
4923
|
+
writeFileSync8(skillPath, skill.body.endsWith("\n") ? skill.body : `${skill.body}
|
|
4606
4924
|
`, { mode: 384 });
|
|
4607
4925
|
chownToAgent(skillPath);
|
|
4608
4926
|
}
|
|
@@ -4634,21 +4952,21 @@ var agentsCommand = defineCommand32({
|
|
|
4634
4952
|
import { defineCommand as defineCommand40 } from "citty";
|
|
4635
4953
|
|
|
4636
4954
|
// src/commands/nest/authorize.ts
|
|
4637
|
-
import { execFileSync as
|
|
4638
|
-
import { existsSync as
|
|
4639
|
-
import { join as
|
|
4955
|
+
import { execFileSync as execFileSync14 } from "child_process";
|
|
4956
|
+
import { existsSync as existsSync17, readFileSync as readFileSync15 } from "fs";
|
|
4957
|
+
import { join as join14 } from "path";
|
|
4640
4958
|
import { defineCommand as defineCommand34 } from "citty";
|
|
4641
4959
|
import consola29 from "consola";
|
|
4642
4960
|
|
|
4643
4961
|
// src/commands/nest/enroll.ts
|
|
4644
|
-
import { hostname as
|
|
4645
|
-
import { existsSync as
|
|
4646
|
-
import { join as
|
|
4962
|
+
import { hostname as hostname5, homedir as homedir12 } from "os";
|
|
4963
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync5, writeFileSync as writeFileSync9, chmodSync } from "fs";
|
|
4964
|
+
import { join as join13 } from "path";
|
|
4647
4965
|
import { defineCommand as defineCommand33 } from "citty";
|
|
4648
4966
|
import consola28 from "consola";
|
|
4649
|
-
var NEST_DATA_DIR =
|
|
4967
|
+
var NEST_DATA_DIR = join13(homedir12(), ".openape", "nest");
|
|
4650
4968
|
function nestAgentName() {
|
|
4651
|
-
const raw =
|
|
4969
|
+
const raw = hostname5().toLowerCase();
|
|
4652
4970
|
const head = raw.split(".")[0] ?? raw;
|
|
4653
4971
|
const safe = head.replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
4654
4972
|
const trimmed = safe.slice(0, 16);
|
|
@@ -4679,19 +4997,19 @@ var enrollNestCommand = defineCommand33({
|
|
|
4679
4997
|
throw new CliError("Run `apes login <email>` first \u2014 nest enroll attaches the new identity to your owner account.");
|
|
4680
4998
|
}
|
|
4681
4999
|
const name = args.name || nestAgentName();
|
|
4682
|
-
const authPath =
|
|
4683
|
-
if (
|
|
5000
|
+
const authPath = join13(NEST_DATA_DIR, ".config", "apes", "auth.json");
|
|
5001
|
+
if (existsSync16(authPath) && !args.force) {
|
|
4684
5002
|
throw new CliError(`Nest already enrolled at ${authPath}. Pass --force to re-enroll.`);
|
|
4685
5003
|
}
|
|
4686
|
-
const sshDir =
|
|
4687
|
-
const configDir =
|
|
4688
|
-
|
|
4689
|
-
|
|
5004
|
+
const sshDir = join13(NEST_DATA_DIR, ".ssh");
|
|
5005
|
+
const configDir = join13(NEST_DATA_DIR, ".config", "apes");
|
|
5006
|
+
mkdirSync5(sshDir, { recursive: true });
|
|
5007
|
+
mkdirSync5(configDir, { recursive: true });
|
|
4690
5008
|
consola28.start(`Generating keypair for ${name}\u2026`);
|
|
4691
5009
|
const { privatePem, publicSshLine } = generateKeyPairInMemory();
|
|
4692
|
-
|
|
5010
|
+
writeFileSync9(join13(sshDir, "id_ed25519"), `${privatePem.trimEnd()}
|
|
4693
5011
|
`, { mode: 384 });
|
|
4694
|
-
|
|
5012
|
+
writeFileSync9(join13(sshDir, "id_ed25519.pub"), `${publicSshLine}
|
|
4695
5013
|
`, { mode: 420 });
|
|
4696
5014
|
chmodSync(sshDir, 448);
|
|
4697
5015
|
consola28.start(`Registering nest at ${idp}\u2026`);
|
|
@@ -4708,10 +5026,10 @@ var enrollNestCommand = defineCommand33({
|
|
|
4708
5026
|
accessToken: token,
|
|
4709
5027
|
email: registration.email,
|
|
4710
5028
|
expiresAt: Math.floor(Date.now() / 1e3) + expiresIn,
|
|
4711
|
-
keyPath:
|
|
5029
|
+
keyPath: join13(sshDir, "id_ed25519"),
|
|
4712
5030
|
ownerEmail: ownerAuth.email
|
|
4713
5031
|
});
|
|
4714
|
-
|
|
5032
|
+
writeFileSync9(authPath, authJson, { mode: 384 });
|
|
4715
5033
|
chmodSync(configDir, 448);
|
|
4716
5034
|
consola28.success(`Nest enrolled \u2014 auth.json at ${authPath}`);
|
|
4717
5035
|
consola28.info("");
|
|
@@ -4780,11 +5098,11 @@ var authorizeNestCommand = defineCommand34({
|
|
|
4780
5098
|
}
|
|
4781
5099
|
},
|
|
4782
5100
|
async run({ args }) {
|
|
4783
|
-
const nestAuthPath =
|
|
4784
|
-
if (!
|
|
5101
|
+
const nestAuthPath = join14(NEST_DATA_DIR, ".config", "apes", "auth.json");
|
|
5102
|
+
if (!existsSync17(nestAuthPath)) {
|
|
4785
5103
|
throw new CliError("Nest not enrolled. Run `apes nest enroll` first.");
|
|
4786
5104
|
}
|
|
4787
|
-
const nestAuth = JSON.parse(
|
|
5105
|
+
const nestAuth = JSON.parse(readFileSync15(nestAuthPath, "utf8"));
|
|
4788
5106
|
if (!nestAuth.email) throw new CliError(`${nestAuthPath} has no email`);
|
|
4789
5107
|
const allow = args.allow ?? DEFAULT_ALLOW_PATTERNS.join(",");
|
|
4790
5108
|
consola29.info(`Configuring YOLO-policy on ${nestAuth.email} via \`apes yolo set\`\u2026`);
|
|
@@ -4801,7 +5119,7 @@ var authorizeNestCommand = defineCommand34({
|
|
|
4801
5119
|
cmdArgs.push("--expires-in", args["expires-in"]);
|
|
4802
5120
|
}
|
|
4803
5121
|
try {
|
|
4804
|
-
|
|
5122
|
+
execFileSync14("apes", cmdArgs, { stdio: "inherit" });
|
|
4805
5123
|
} catch (err) {
|
|
4806
5124
|
throw new CliError(err instanceof Error ? err.message : String(err));
|
|
4807
5125
|
}
|
|
@@ -4811,7 +5129,7 @@ var authorizeNestCommand = defineCommand34({
|
|
|
4811
5129
|
});
|
|
4812
5130
|
|
|
4813
5131
|
// src/commands/nest/destroy.ts
|
|
4814
|
-
import { execFileSync as
|
|
5132
|
+
import { execFileSync as execFileSync15 } from "child_process";
|
|
4815
5133
|
import { defineCommand as defineCommand35 } from "citty";
|
|
4816
5134
|
import consola30 from "consola";
|
|
4817
5135
|
var destroyNestCommand = defineCommand35({
|
|
@@ -4825,7 +5143,7 @@ var destroyNestCommand = defineCommand35({
|
|
|
4825
5143
|
async run({ args }) {
|
|
4826
5144
|
const name = String(args.name);
|
|
4827
5145
|
try {
|
|
4828
|
-
|
|
5146
|
+
execFileSync15("apes", ["run", "--as", "root", "--wait", "--", "apes", "agents", "destroy", name, "--force"], { stdio: "inherit" });
|
|
4829
5147
|
consola30.success(`Nest will tear down ${name}'s pm2 process on its next reconcile (\u22642s).`);
|
|
4830
5148
|
} catch (err) {
|
|
4831
5149
|
const status = err.status ?? 1;
|
|
@@ -4835,10 +5153,9 @@ var destroyNestCommand = defineCommand35({
|
|
|
4835
5153
|
});
|
|
4836
5154
|
|
|
4837
5155
|
// src/commands/nest/install.ts
|
|
4838
|
-
import {
|
|
4839
|
-
import {
|
|
4840
|
-
import {
|
|
4841
|
-
import { dirname as dirname3, join as join13 } from "path";
|
|
5156
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync6, readFileSync as readFileSync16, writeFileSync as writeFileSync10 } from "fs";
|
|
5157
|
+
import { homedir as homedir13 } from "os";
|
|
5158
|
+
import { dirname as dirname3, join as join15 } from "path";
|
|
4842
5159
|
import { defineCommand as defineCommand36 } from "citty";
|
|
4843
5160
|
import consola31 from "consola";
|
|
4844
5161
|
|
|
@@ -4905,84 +5222,42 @@ resource_chain = ["agents:name={name}", "allowlist:email={peer_email}"]
|
|
|
4905
5222
|
`;
|
|
4906
5223
|
|
|
4907
5224
|
// src/commands/nest/install.ts
|
|
4908
|
-
var PLIST_LABEL = "ai.openape.nest";
|
|
4909
|
-
function plistPath() {
|
|
4910
|
-
return join13(homedir13(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
4911
|
-
}
|
|
4912
|
-
function escape2(s) {
|
|
4913
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
4914
|
-
}
|
|
4915
|
-
function buildPlist(args) {
|
|
4916
|
-
const logsDir = join13(args.userHome, "Library", "Logs");
|
|
4917
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
4918
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
4919
|
-
<plist version="1.0">
|
|
4920
|
-
<dict>
|
|
4921
|
-
<key>Label</key>
|
|
4922
|
-
<string>${escape2(PLIST_LABEL)}</string>
|
|
4923
|
-
<key>ProgramArguments</key>
|
|
4924
|
-
<array>
|
|
4925
|
-
<string>${escape2(args.nestBin)}</string>
|
|
4926
|
-
</array>
|
|
4927
|
-
<key>WorkingDirectory</key>
|
|
4928
|
-
<string>${escape2(args.nestHome)}</string>
|
|
4929
|
-
<key>RunAtLoad</key>
|
|
4930
|
-
<true/>
|
|
4931
|
-
<key>KeepAlive</key>
|
|
4932
|
-
<true/>
|
|
4933
|
-
<key>ThrottleInterval</key>
|
|
4934
|
-
<integer>10</integer>
|
|
4935
|
-
<key>EnvironmentVariables</key>
|
|
4936
|
-
<dict>
|
|
4937
|
-
<key>HOME</key><string>${escape2(args.nestHome)}</string>
|
|
4938
|
-
<key>PATH</key><string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
4939
|
-
<key>OPENAPE_NEST_PORT</key><string>${args.port}</string>
|
|
4940
|
-
<key>OPENAPE_APES_BIN</key><string>${escape2(args.apesBin)}</string>
|
|
4941
|
-
</dict>
|
|
4942
|
-
<key>StandardOutPath</key>
|
|
4943
|
-
<string>${escape2(logsDir)}/openape-nest.log</string>
|
|
4944
|
-
<key>StandardErrorPath</key>
|
|
4945
|
-
<string>${escape2(logsDir)}/openape-nest.log</string>
|
|
4946
|
-
</dict>
|
|
4947
|
-
</plist>
|
|
4948
|
-
`;
|
|
4949
|
-
}
|
|
4950
5225
|
function installAdapter2() {
|
|
4951
|
-
const target =
|
|
4952
|
-
|
|
5226
|
+
const target = join15(homedir13(), ".openape", "shapes", "adapters", "apes-agents.toml");
|
|
5227
|
+
mkdirSync6(dirname3(target), { recursive: true });
|
|
4953
5228
|
let existing = "";
|
|
4954
5229
|
try {
|
|
4955
|
-
existing =
|
|
5230
|
+
existing = readFileSync16(target, "utf8");
|
|
4956
5231
|
} catch {
|
|
4957
5232
|
}
|
|
4958
5233
|
if (existing === APES_AGENTS_ADAPTER_TOML) return false;
|
|
4959
|
-
|
|
5234
|
+
writeFileSync10(target, APES_AGENTS_ADAPTER_TOML, { mode: 420 });
|
|
4960
5235
|
consola31.success(`Wrote shapes adapter ${target}`);
|
|
4961
5236
|
return true;
|
|
4962
5237
|
}
|
|
4963
5238
|
function writeBridgeModelDefault(model) {
|
|
4964
|
-
for (const envDir of [
|
|
4965
|
-
const envFile =
|
|
4966
|
-
|
|
5239
|
+
for (const envDir of [join15(homedir13(), "litellm"), join15(NEST_DATA_DIR, "litellm")]) {
|
|
5240
|
+
const envFile = join15(envDir, ".env");
|
|
5241
|
+
mkdirSync6(envDir, { recursive: true });
|
|
4967
5242
|
let lines = [];
|
|
4968
|
-
if (
|
|
4969
|
-
lines =
|
|
5243
|
+
if (existsSync18(envFile)) {
|
|
5244
|
+
lines = readFileSync16(envFile, "utf8").split("\n").filter((l) => !l.startsWith("APE_CHAT_BRIDGE_MODEL="));
|
|
4970
5245
|
}
|
|
4971
5246
|
lines.push(`APE_CHAT_BRIDGE_MODEL=${model}`);
|
|
4972
5247
|
while (lines.length > 0 && lines.at(-1).trim() === "") lines.pop();
|
|
4973
|
-
|
|
5248
|
+
writeFileSync10(envFile, `${lines.join("\n")}
|
|
4974
5249
|
`, { mode: 384 });
|
|
4975
5250
|
}
|
|
4976
5251
|
}
|
|
4977
5252
|
function findBinary(name) {
|
|
4978
5253
|
for (const dir of [
|
|
4979
|
-
|
|
5254
|
+
join15(homedir13(), ".bun", "bin"),
|
|
4980
5255
|
"/opt/homebrew/bin",
|
|
4981
5256
|
"/usr/local/bin",
|
|
4982
5257
|
"/usr/bin"
|
|
4983
5258
|
]) {
|
|
4984
|
-
const p =
|
|
4985
|
-
if (
|
|
5259
|
+
const p = join15(dir, name);
|
|
5260
|
+
if (existsSync18(p)) return p;
|
|
4986
5261
|
}
|
|
4987
5262
|
throw new Error(`could not locate ${name} on PATH; install it first`);
|
|
4988
5263
|
}
|
|
@@ -5009,7 +5284,7 @@ var installNestCommand = defineCommand36({
|
|
|
5009
5284
|
}
|
|
5010
5285
|
const nestBin = findBinary("openape-nest");
|
|
5011
5286
|
const apesBin = findBinary("apes");
|
|
5012
|
-
consola31.info(`Installing nest
|
|
5287
|
+
consola31.info(`Installing nest supervisor`);
|
|
5013
5288
|
consola31.info(` nest binary: ${nestBin}`);
|
|
5014
5289
|
consola31.info(` apes binary: ${apesBin}`);
|
|
5015
5290
|
consola31.info(` HTTP port: ${port}`);
|
|
@@ -5018,26 +5293,14 @@ var installNestCommand = defineCommand36({
|
|
|
5018
5293
|
consola31.success(`Default bridge model set to ${args["bridge-model"]} (in ~/litellm/.env)`);
|
|
5019
5294
|
}
|
|
5020
5295
|
installAdapter2();
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
}
|
|
5029
|
-
if (existing !== desired) {
|
|
5030
|
-
writeFileSync7(plistPath(), desired, { mode: 420 });
|
|
5031
|
-
consola31.success("Wrote launchd plist");
|
|
5032
|
-
} else {
|
|
5033
|
-
consola31.info("plist already up to date");
|
|
5034
|
-
}
|
|
5035
|
-
const uid = userInfo2().uid;
|
|
5036
|
-
try {
|
|
5037
|
-
execFileSync12("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL}`], { stdio: "ignore" });
|
|
5038
|
-
} catch {
|
|
5039
|
-
}
|
|
5040
|
-
execFileSync12("/bin/launchctl", ["bootstrap", `gui/${uid}`, plistPath()], { stdio: "inherit" });
|
|
5296
|
+
mkdirSync6(NEST_DATA_DIR, { recursive: true });
|
|
5297
|
+
await getHostPlatform().installNestSupervisor({
|
|
5298
|
+
nestBin,
|
|
5299
|
+
apesBin,
|
|
5300
|
+
userHome: homeDir,
|
|
5301
|
+
nestHome: NEST_DATA_DIR,
|
|
5302
|
+
port
|
|
5303
|
+
});
|
|
5041
5304
|
consola31.success(`Nest daemon bootstrapped \u2014 http://127.0.0.1:${port}`);
|
|
5042
5305
|
consola31.info("");
|
|
5043
5306
|
consola31.info("Next steps for zero-prompt spawn \u2014 both one-time:");
|
|
@@ -5079,7 +5342,7 @@ var listNestCommand = defineCommand37({
|
|
|
5079
5342
|
});
|
|
5080
5343
|
|
|
5081
5344
|
// src/commands/nest/spawn.ts
|
|
5082
|
-
import { execFileSync as
|
|
5345
|
+
import { execFileSync as execFileSync16 } from "child_process";
|
|
5083
5346
|
import { defineCommand as defineCommand38 } from "citty";
|
|
5084
5347
|
import consola33 from "consola";
|
|
5085
5348
|
var spawnNestCommand = defineCommand38({
|
|
@@ -5112,7 +5375,7 @@ var spawnNestCommand = defineCommand38({
|
|
|
5112
5375
|
if (typeof args["bridge-base-url"] === "string") apesArgs.push("--bridge-base-url", args["bridge-base-url"]);
|
|
5113
5376
|
if (typeof args["bridge-model"] === "string") apesArgs.push("--bridge-model", args["bridge-model"]);
|
|
5114
5377
|
try {
|
|
5115
|
-
|
|
5378
|
+
execFileSync16("apes", apesArgs, { stdio: "inherit" });
|
|
5116
5379
|
consola33.success(`Nest will pick up ${name} on its next reconcile (\u22642s).`);
|
|
5117
5380
|
} catch (err) {
|
|
5118
5381
|
const status = err.status ?? 1;
|
|
@@ -5122,31 +5385,16 @@ var spawnNestCommand = defineCommand38({
|
|
|
5122
5385
|
});
|
|
5123
5386
|
|
|
5124
5387
|
// src/commands/nest/uninstall.ts
|
|
5125
|
-
import { execFileSync as execFileSync14 } from "child_process";
|
|
5126
|
-
import { existsSync as existsSync16, unlinkSync } from "fs";
|
|
5127
|
-
import { homedir as homedir14, userInfo as userInfo3 } from "os";
|
|
5128
|
-
import { join as join14 } from "path";
|
|
5129
5388
|
import { defineCommand as defineCommand39 } from "citty";
|
|
5130
5389
|
import consola34 from "consola";
|
|
5131
|
-
var PLIST_LABEL2 = "ai.openape.nest";
|
|
5132
5390
|
var uninstallNestCommand = defineCommand39({
|
|
5133
5391
|
meta: {
|
|
5134
5392
|
name: "uninstall",
|
|
5135
5393
|
description: "Stop + remove the local nest-daemon (registry + agents preserved)"
|
|
5136
5394
|
},
|
|
5137
5395
|
async run() {
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
try {
|
|
5141
|
-
execFileSync14("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL2}`], { stdio: "ignore" });
|
|
5142
|
-
consola34.success("Nest daemon stopped");
|
|
5143
|
-
} catch {
|
|
5144
|
-
consola34.info("Nest daemon was not loaded");
|
|
5145
|
-
}
|
|
5146
|
-
if (existsSync16(path2)) {
|
|
5147
|
-
unlinkSync(path2);
|
|
5148
|
-
consola34.success(`Removed ${path2}`);
|
|
5149
|
-
}
|
|
5396
|
+
await getHostPlatform().uninstallNestSupervisor();
|
|
5397
|
+
consola34.success("Nest daemon stopped + supervisor unit removed");
|
|
5150
5398
|
consola34.info("Registry at ~/.openape/nest/agents.json kept \u2014 re-run `apes nest install` to resume supervision.");
|
|
5151
5399
|
}
|
|
5152
5400
|
});
|
|
@@ -5692,18 +5940,19 @@ var adapterCommand = defineCommand45({
|
|
|
5692
5940
|
});
|
|
5693
5941
|
|
|
5694
5942
|
// src/commands/run.ts
|
|
5695
|
-
import { execFileSync as
|
|
5696
|
-
import { hostname as
|
|
5943
|
+
import { execFileSync as execFileSync17 } from "child_process";
|
|
5944
|
+
import { hostname as hostname6 } from "os";
|
|
5697
5945
|
import { basename } from "path";
|
|
5698
5946
|
import { defineCommand as defineCommand46 } from "citty";
|
|
5699
5947
|
import consola39 from "consola";
|
|
5700
5948
|
function resolveRunAsTarget(runAs) {
|
|
5701
5949
|
if (!runAs) return runAs;
|
|
5702
|
-
if (!
|
|
5950
|
+
if (!isDarwin2()) return runAs;
|
|
5703
5951
|
if (!AGENT_NAME_REGEX.test(runAs)) return runAs;
|
|
5704
5952
|
if (runAs.startsWith("openape-agent-")) return runAs;
|
|
5705
|
-
const
|
|
5706
|
-
|
|
5953
|
+
const platform = getHostPlatform();
|
|
5954
|
+
const prefixed = platform.agentUsername(runAs);
|
|
5955
|
+
if (platform.readAgentUser(prefixed)) return prefixed;
|
|
5707
5956
|
return runAs;
|
|
5708
5957
|
}
|
|
5709
5958
|
function shouldWaitForGrant(args) {
|
|
@@ -5876,7 +6125,7 @@ async function runShellMode(command, args) {
|
|
|
5876
6125
|
const adapterHandled = await tryAdapterModeFromShell(command, idp, args);
|
|
5877
6126
|
if (adapterHandled) return;
|
|
5878
6127
|
const grantsUrl = await getGrantsEndpoint(idp);
|
|
5879
|
-
const targetHost = args.host ||
|
|
6128
|
+
const targetHost = args.host || hostname6();
|
|
5880
6129
|
try {
|
|
5881
6130
|
const grants = await apiFetch(
|
|
5882
6131
|
`${grantsUrl}?requester=${encodeURIComponent(auth.email)}&status=approved&limit=20`
|
|
@@ -5972,7 +6221,7 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
5972
6221
|
approveUrl: `${idp}/grant-approval?grant_id=${grant.id}`,
|
|
5973
6222
|
command: resolved.detail?.display || parsed?.raw || "unknown",
|
|
5974
6223
|
audience: resolved.adapter?.cli?.audience ?? "shapes",
|
|
5975
|
-
host: args.host ||
|
|
6224
|
+
host: args.host || hostname6()
|
|
5976
6225
|
});
|
|
5977
6226
|
if (shouldWaitForGrant(args)) {
|
|
5978
6227
|
consola39.info(`Grant requested: ${grant.id}`);
|
|
@@ -5992,7 +6241,7 @@ function execShellCommand(command) {
|
|
|
5992
6241
|
throw new CliError("No command to execute");
|
|
5993
6242
|
try {
|
|
5994
6243
|
const { APES_SHELL_WRAPPER: _wrapperMarker, ...inheritedEnv } = process.env;
|
|
5995
|
-
|
|
6244
|
+
execFileSync17(command[0], command.slice(1), {
|
|
5996
6245
|
stdio: "inherit",
|
|
5997
6246
|
env: inheritedEnv
|
|
5998
6247
|
});
|
|
@@ -6093,7 +6342,7 @@ async function runAudienceMode(audience, action, args, commandArgv) {
|
|
|
6093
6342
|
const idp = getIdpUrl(args.idp);
|
|
6094
6343
|
const grantsUrl = await getGrantsEndpoint(idp);
|
|
6095
6344
|
const command = commandArgv ?? action.split(" ");
|
|
6096
|
-
const targetHost = args.host ||
|
|
6345
|
+
const targetHost = args.host || hostname6();
|
|
6097
6346
|
const runAs = resolveRunAsTarget(args.as ?? void 0);
|
|
6098
6347
|
const reusableId = await findReusableAudienceGrant({
|
|
6099
6348
|
grantsUrl,
|
|
@@ -6161,7 +6410,7 @@ function executeWithGrantToken(opts) {
|
|
|
6161
6410
|
consola39.info(`Executing: ${command.join(" ")}`);
|
|
6162
6411
|
try {
|
|
6163
6412
|
const { APES_SHELL_WRAPPER: _wrapperMarker, ...inheritedEnv } = process.env;
|
|
6164
|
-
|
|
6413
|
+
execFileSync17(args["escapes-path"] || "escapes", ["--grant", token, "--", ...command], {
|
|
6165
6414
|
stdio: "inherit",
|
|
6166
6415
|
env: inheritedEnv
|
|
6167
6416
|
});
|
|
@@ -6197,9 +6446,9 @@ async function findReusableAudienceGrant(opts) {
|
|
|
6197
6446
|
|
|
6198
6447
|
// src/commands/proxy.ts
|
|
6199
6448
|
import { spawn as spawn2 } from "child_process";
|
|
6200
|
-
import { existsSync as
|
|
6201
|
-
import { homedir as
|
|
6202
|
-
import { join as
|
|
6449
|
+
import { existsSync as existsSync20 } from "fs";
|
|
6450
|
+
import { homedir as homedir14 } from "os";
|
|
6451
|
+
import { join as join18 } from "path";
|
|
6203
6452
|
import { defineCommand as defineCommand47 } from "citty";
|
|
6204
6453
|
import consola40 from "consola";
|
|
6205
6454
|
|
|
@@ -6235,10 +6484,10 @@ note = "VPC-internal hostname suffix"
|
|
|
6235
6484
|
|
|
6236
6485
|
// src/proxy/local-proxy.ts
|
|
6237
6486
|
import { spawn } from "child_process";
|
|
6238
|
-
import { mkdtempSync as
|
|
6487
|
+
import { mkdtempSync as mkdtempSync4, rmSync as rmSync6, writeFileSync as writeFileSync11 } from "fs";
|
|
6239
6488
|
import { createRequire } from "module";
|
|
6240
|
-
import { tmpdir as
|
|
6241
|
-
import { dirname as dirname4, join as
|
|
6489
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
6490
|
+
import { dirname as dirname4, join as join16, resolve as resolve3 } from "path";
|
|
6242
6491
|
var require2 = createRequire(import.meta.url);
|
|
6243
6492
|
function findProxyBin() {
|
|
6244
6493
|
const pkgPath = require2.resolve("@openape/proxy/package.json");
|
|
@@ -6250,9 +6499,9 @@ function findProxyBin() {
|
|
|
6250
6499
|
return resolve3(dirname4(pkgPath), binRel);
|
|
6251
6500
|
}
|
|
6252
6501
|
async function startEphemeralProxy(configToml) {
|
|
6253
|
-
const tmpDir =
|
|
6254
|
-
const configPath =
|
|
6255
|
-
|
|
6502
|
+
const tmpDir = mkdtempSync4(join16(tmpdir4(), "openape-proxy-"));
|
|
6503
|
+
const configPath = join16(tmpDir, "config.toml");
|
|
6504
|
+
writeFileSync11(configPath, configToml, { mode: 384 });
|
|
6256
6505
|
const binPath = findProxyBin();
|
|
6257
6506
|
const child = spawn(process.execPath, [binPath, "-c", configPath], {
|
|
6258
6507
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -6260,7 +6509,7 @@ async function startEphemeralProxy(configToml) {
|
|
|
6260
6509
|
});
|
|
6261
6510
|
const cleanupTmp = () => {
|
|
6262
6511
|
try {
|
|
6263
|
-
|
|
6512
|
+
rmSync6(tmpDir, { recursive: true, force: true });
|
|
6264
6513
|
} catch {
|
|
6265
6514
|
}
|
|
6266
6515
|
};
|
|
@@ -6334,9 +6583,9 @@ function waitForListenLine(child) {
|
|
|
6334
6583
|
}
|
|
6335
6584
|
|
|
6336
6585
|
// src/proxy/trust-bundle.ts
|
|
6337
|
-
import { existsSync as
|
|
6338
|
-
import { tmpdir as
|
|
6339
|
-
import { join as
|
|
6586
|
+
import { existsSync as existsSync19, mkdtempSync as mkdtempSync5, readFileSync as readFileSync17, rmdirSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync12 } from "fs";
|
|
6587
|
+
import { tmpdir as tmpdir5 } from "os";
|
|
6588
|
+
import { join as join17 } from "path";
|
|
6340
6589
|
var CANDIDATES = [
|
|
6341
6590
|
"/etc/ssl/cert.pem",
|
|
6342
6591
|
// macOS
|
|
@@ -6349,25 +6598,25 @@ var CANDIDATES = [
|
|
|
6349
6598
|
];
|
|
6350
6599
|
function detectSystemCaPath() {
|
|
6351
6600
|
for (const p of CANDIDATES) {
|
|
6352
|
-
if (
|
|
6601
|
+
if (existsSync19(p)) return p;
|
|
6353
6602
|
}
|
|
6354
6603
|
throw new Error(
|
|
6355
6604
|
`Could not locate a system CA bundle. Tried: ${CANDIDATES.join(", ")}. Set NODE_EXTRA_CA_CERTS yourself or pass --allow-no-system-ca.`
|
|
6356
6605
|
);
|
|
6357
6606
|
}
|
|
6358
6607
|
function buildTrustBundle(opts) {
|
|
6359
|
-
const dir =
|
|
6360
|
-
const path2 =
|
|
6361
|
-
const sys =
|
|
6362
|
-
const local =
|
|
6363
|
-
|
|
6608
|
+
const dir = mkdtempSync5(join17(tmpdir5(), "openape-trust-"));
|
|
6609
|
+
const path2 = join17(dir, "bundle.pem");
|
|
6610
|
+
const sys = readFileSync17(opts.systemCaPath, "utf-8");
|
|
6611
|
+
const local = readFileSync17(opts.localCaPath, "utf-8");
|
|
6612
|
+
writeFileSync12(path2, `${sys.trimEnd()}
|
|
6364
6613
|
${local.trimEnd()}
|
|
6365
6614
|
`, { mode: 384 });
|
|
6366
6615
|
return {
|
|
6367
6616
|
path: path2,
|
|
6368
6617
|
cleanup: () => {
|
|
6369
6618
|
try {
|
|
6370
|
-
|
|
6619
|
+
unlinkSync3(path2);
|
|
6371
6620
|
} catch {
|
|
6372
6621
|
}
|
|
6373
6622
|
try {
|
|
@@ -6417,8 +6666,8 @@ var proxyCommand = defineCommand47({
|
|
|
6417
6666
|
if (reuseHostPort) {
|
|
6418
6667
|
proxyUrl = `http://${reuseHostPort}`;
|
|
6419
6668
|
consola40.info(`[apes proxy] using long-running daemon at ${proxyUrl}`);
|
|
6420
|
-
const localCaPath =
|
|
6421
|
-
if (!
|
|
6669
|
+
const localCaPath = join18(homedir14(), ".openape", "proxy", "ca.crt");
|
|
6670
|
+
if (!existsSync20(localCaPath)) {
|
|
6422
6671
|
throw new CliError(
|
|
6423
6672
|
`OPENAPE_PROXY is set but no local CA found at ${localCaPath}. Start the daemon (sudo -u <agent> apes proxy --global < secrets.toml) first.`
|
|
6424
6673
|
);
|
|
@@ -6760,16 +7009,16 @@ var mcpCommand = defineCommand52({
|
|
|
6760
7009
|
if (transport !== "stdio" && transport !== "sse") {
|
|
6761
7010
|
throw new Error('Transport must be "stdio" or "sse"');
|
|
6762
7011
|
}
|
|
6763
|
-
const { startMcpServer } = await import("./server-
|
|
7012
|
+
const { startMcpServer } = await import("./server-OAINN75J.js");
|
|
6764
7013
|
await startMcpServer(transport, port);
|
|
6765
7014
|
}
|
|
6766
7015
|
});
|
|
6767
7016
|
|
|
6768
7017
|
// src/commands/init/index.ts
|
|
6769
|
-
import { existsSync as
|
|
7018
|
+
import { existsSync as existsSync21, copyFileSync, writeFileSync as writeFileSync13 } from "fs";
|
|
6770
7019
|
import { randomBytes } from "crypto";
|
|
6771
|
-
import { execFileSync as
|
|
6772
|
-
import { join as
|
|
7020
|
+
import { execFileSync as execFileSync18 } from "child_process";
|
|
7021
|
+
import { join as join19 } from "path";
|
|
6773
7022
|
import { defineCommand as defineCommand53 } from "citty";
|
|
6774
7023
|
import consola43 from "consola";
|
|
6775
7024
|
var DEFAULT_IDP_URL = "https://id.openape.at";
|
|
@@ -6778,13 +7027,13 @@ async function downloadTemplate(repo, targetDir) {
|
|
|
6778
7027
|
await gigetDownload(`gh:${repo}`, { dir: targetDir, force: false });
|
|
6779
7028
|
}
|
|
6780
7029
|
function installDeps(dir) {
|
|
6781
|
-
const hasLockFile = (name) =>
|
|
7030
|
+
const hasLockFile = (name) => existsSync21(join19(dir, name));
|
|
6782
7031
|
if (hasLockFile("pnpm-lock.yaml")) {
|
|
6783
|
-
|
|
7032
|
+
execFileSync18("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
|
|
6784
7033
|
} else if (hasLockFile("bun.lockb")) {
|
|
6785
|
-
|
|
7034
|
+
execFileSync18("bun", ["install"], { cwd: dir, stdio: "inherit" });
|
|
6786
7035
|
} else {
|
|
6787
|
-
|
|
7036
|
+
execFileSync18("npm", ["install"], { cwd: dir, stdio: "inherit" });
|
|
6788
7037
|
}
|
|
6789
7038
|
}
|
|
6790
7039
|
async function promptChoice(message, choices) {
|
|
@@ -6843,7 +7092,7 @@ var initCommand = defineCommand53({
|
|
|
6843
7092
|
});
|
|
6844
7093
|
async function initSP(targetDir) {
|
|
6845
7094
|
const dir = targetDir || "my-app";
|
|
6846
|
-
if (
|
|
7095
|
+
if (existsSync21(join19(dir, "package.json"))) {
|
|
6847
7096
|
throw new CliError(`Directory "${dir}" already contains a project.`);
|
|
6848
7097
|
}
|
|
6849
7098
|
consola43.start("Scaffolding SP starter...");
|
|
@@ -6852,9 +7101,9 @@ async function initSP(targetDir) {
|
|
|
6852
7101
|
consola43.start("Installing dependencies...");
|
|
6853
7102
|
installDeps(dir);
|
|
6854
7103
|
consola43.success("Dependencies installed");
|
|
6855
|
-
const envExample =
|
|
6856
|
-
const envFile =
|
|
6857
|
-
if (
|
|
7104
|
+
const envExample = join19(dir, ".env.example");
|
|
7105
|
+
const envFile = join19(dir, ".env");
|
|
7106
|
+
if (existsSync21(envExample) && !existsSync21(envFile)) {
|
|
6858
7107
|
copyFileSync(envExample, envFile);
|
|
6859
7108
|
consola43.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
|
|
6860
7109
|
}
|
|
@@ -6868,7 +7117,7 @@ async function initSP(targetDir) {
|
|
|
6868
7117
|
}
|
|
6869
7118
|
async function initIdP(targetDir) {
|
|
6870
7119
|
const dir = targetDir || "my-idp";
|
|
6871
|
-
if (
|
|
7120
|
+
if (existsSync21(join19(dir, "package.json"))) {
|
|
6872
7121
|
throw new CliError(`Directory "${dir}" already contains a project.`);
|
|
6873
7122
|
}
|
|
6874
7123
|
const domain = await promptText("Domain for the IdP", "localhost");
|
|
@@ -6900,7 +7149,7 @@ async function initIdP(targetDir) {
|
|
|
6900
7149
|
`NUXT_OPENAPE_RP_ID=${domain}`,
|
|
6901
7150
|
`NUXT_OPENAPE_RP_ORIGIN=${origin}`
|
|
6902
7151
|
].join("\n");
|
|
6903
|
-
|
|
7152
|
+
writeFileSync13(join19(dir, ".env"), `${envContent}
|
|
6904
7153
|
`, { mode: 384 });
|
|
6905
7154
|
consola43.success(".env created");
|
|
6906
7155
|
console.log("");
|
|
@@ -6921,7 +7170,7 @@ async function initIdP(targetDir) {
|
|
|
6921
7170
|
|
|
6922
7171
|
// src/commands/enroll.ts
|
|
6923
7172
|
import { Buffer as Buffer5 } from "buffer";
|
|
6924
|
-
import { existsSync as
|
|
7173
|
+
import { existsSync as existsSync22, readFileSync as readFileSync18 } from "fs";
|
|
6925
7174
|
import { execFile as execFile2 } from "child_process";
|
|
6926
7175
|
import { sign as sign2 } from "crypto";
|
|
6927
7176
|
import { defineCommand as defineCommand54 } from "citty";
|
|
@@ -6937,7 +7186,7 @@ function openBrowser2(url) {
|
|
|
6937
7186
|
}
|
|
6938
7187
|
async function pollForEnrollment(idp, agentEmail, keyPath) {
|
|
6939
7188
|
const resolvedKey = resolveKeyPath(keyPath);
|
|
6940
|
-
const keyContent =
|
|
7189
|
+
const keyContent = readFileSync18(resolvedKey, "utf-8");
|
|
6941
7190
|
const privateKey = loadEd25519PrivateKey(keyContent);
|
|
6942
7191
|
const challengeUrl = await getAgentChallengeEndpoint(idp);
|
|
6943
7192
|
const authenticateUrl = await getAgentAuthenticateEndpoint(idp);
|
|
@@ -7005,7 +7254,7 @@ var enrollCommand = defineCommand54({
|
|
|
7005
7254
|
}) || DEFAULT_KEY_PATH;
|
|
7006
7255
|
const resolvedKey = resolveKeyPath(keyPath);
|
|
7007
7256
|
let publicKey;
|
|
7008
|
-
if (
|
|
7257
|
+
if (existsSync22(resolvedKey)) {
|
|
7009
7258
|
publicKey = readPublicKey(resolvedKey);
|
|
7010
7259
|
consola44.success(`Using existing key ${keyPath}`);
|
|
7011
7260
|
} else {
|
|
@@ -7049,7 +7298,7 @@ var enrollCommand = defineCommand54({
|
|
|
7049
7298
|
});
|
|
7050
7299
|
|
|
7051
7300
|
// src/commands/register-user.ts
|
|
7052
|
-
import { existsSync as
|
|
7301
|
+
import { existsSync as existsSync23, readFileSync as readFileSync19 } from "fs";
|
|
7053
7302
|
import { defineCommand as defineCommand55 } from "citty";
|
|
7054
7303
|
import consola45 from "consola";
|
|
7055
7304
|
var registerUserCommand = defineCommand55({
|
|
@@ -7088,8 +7337,8 @@ var registerUserCommand = defineCommand55({
|
|
|
7088
7337
|
throw new CliError("No IdP URL configured. Run `apes login` first.");
|
|
7089
7338
|
}
|
|
7090
7339
|
let publicKey = args.key;
|
|
7091
|
-
if (
|
|
7092
|
-
publicKey =
|
|
7340
|
+
if (existsSync23(args.key)) {
|
|
7341
|
+
publicKey = readFileSync19(args.key, "utf-8").trim();
|
|
7093
7342
|
}
|
|
7094
7343
|
if (!publicKey.startsWith("ssh-ed25519 ")) {
|
|
7095
7344
|
throw new CliError("Public key must be in ssh-ed25519 format.");
|
|
@@ -7398,7 +7647,7 @@ async function bestEffortGrantCount(idp) {
|
|
|
7398
7647
|
}
|
|
7399
7648
|
}
|
|
7400
7649
|
async function runHealth(args) {
|
|
7401
|
-
const version = true ? "1.28.
|
|
7650
|
+
const version = true ? "1.28.12" : "0.0.0";
|
|
7402
7651
|
const auth = loadAuth();
|
|
7403
7652
|
if (!auth) {
|
|
7404
7653
|
throw new CliError("Not logged in. Run `apes login` first.", 1);
|
|
@@ -7591,26 +7840,26 @@ var workflowsCommand = defineCommand63({
|
|
|
7591
7840
|
});
|
|
7592
7841
|
|
|
7593
7842
|
// src/version-check.ts
|
|
7594
|
-
import { existsSync as
|
|
7595
|
-
import { homedir as
|
|
7596
|
-
import { join as
|
|
7843
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync7, readFileSync as readFileSync20, writeFileSync as writeFileSync14 } from "fs";
|
|
7844
|
+
import { homedir as homedir15 } from "os";
|
|
7845
|
+
import { join as join20 } from "path";
|
|
7597
7846
|
import consola51 from "consola";
|
|
7598
7847
|
var PACKAGE_NAME = "@openape/apes";
|
|
7599
7848
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
7600
|
-
var CACHE_FILE =
|
|
7849
|
+
var CACHE_FILE = join20(homedir15(), ".config", "apes", ".version-check.json");
|
|
7601
7850
|
function readCache() {
|
|
7602
|
-
if (!
|
|
7851
|
+
if (!existsSync24(CACHE_FILE)) return null;
|
|
7603
7852
|
try {
|
|
7604
|
-
return JSON.parse(
|
|
7853
|
+
return JSON.parse(readFileSync20(CACHE_FILE, "utf-8"));
|
|
7605
7854
|
} catch {
|
|
7606
7855
|
return null;
|
|
7607
7856
|
}
|
|
7608
7857
|
}
|
|
7609
7858
|
function writeCache(entry) {
|
|
7610
7859
|
try {
|
|
7611
|
-
const dir =
|
|
7612
|
-
if (!
|
|
7613
|
-
|
|
7860
|
+
const dir = join20(homedir15(), ".config", "apes");
|
|
7861
|
+
if (!existsSync24(dir)) mkdirSync7(dir, { recursive: true, mode: 448 });
|
|
7862
|
+
writeFileSync14(CACHE_FILE, JSON.stringify(entry), { mode: 384 });
|
|
7614
7863
|
} catch {
|
|
7615
7864
|
}
|
|
7616
7865
|
}
|
|
@@ -7671,10 +7920,10 @@ if (shellRewrite) {
|
|
|
7671
7920
|
if (shellRewrite.action === "rewrite") {
|
|
7672
7921
|
process.argv = shellRewrite.argv;
|
|
7673
7922
|
} else if (shellRewrite.action === "version") {
|
|
7674
|
-
console.log(`ape-shell ${"1.28.
|
|
7923
|
+
console.log(`ape-shell ${"1.28.12"} (OpenApe DDISA shell wrapper)`);
|
|
7675
7924
|
process.exit(0);
|
|
7676
7925
|
} else if (shellRewrite.action === "help") {
|
|
7677
|
-
console.log(`ape-shell ${"1.28.
|
|
7926
|
+
console.log(`ape-shell ${"1.28.12"} \u2014 OpenApe DDISA shell wrapper`);
|
|
7678
7927
|
console.log("");
|
|
7679
7928
|
console.log("Usage:");
|
|
7680
7929
|
console.log(" ape-shell Start interactive grant-mediated REPL");
|
|
@@ -7689,7 +7938,7 @@ if (shellRewrite) {
|
|
|
7689
7938
|
console.log(" --help, -h Show this help message");
|
|
7690
7939
|
process.exit(0);
|
|
7691
7940
|
} else if (shellRewrite.action === "interactive") {
|
|
7692
|
-
const { runInteractiveShell } = await import("./orchestrator-
|
|
7941
|
+
const { runInteractiveShell } = await import("./orchestrator-BDX3WK7Q.js");
|
|
7693
7942
|
await runInteractiveShell();
|
|
7694
7943
|
process.exit(0);
|
|
7695
7944
|
} else {
|
|
@@ -7732,7 +7981,7 @@ var configCommand = defineCommand64({
|
|
|
7732
7981
|
var main = defineCommand64({
|
|
7733
7982
|
meta: {
|
|
7734
7983
|
name: "apes",
|
|
7735
|
-
version: "1.28.
|
|
7984
|
+
version: "1.28.12",
|
|
7736
7985
|
description: "Unified CLI for OpenApe"
|
|
7737
7986
|
},
|
|
7738
7987
|
subCommands: {
|
|
@@ -7784,13 +8033,13 @@ async function maybeRefreshAuth() {
|
|
|
7784
8033
|
const { loadAuth: loadAuth2 } = await import("./config-MOB5DJ6H.js");
|
|
7785
8034
|
if (!loadAuth2()) return;
|
|
7786
8035
|
try {
|
|
7787
|
-
const { ensureFreshToken } = await import("./http-
|
|
8036
|
+
const { ensureFreshToken } = await import("./http-UPOTOYQV.js");
|
|
7788
8037
|
await ensureFreshToken();
|
|
7789
8038
|
} catch {
|
|
7790
8039
|
}
|
|
7791
8040
|
}
|
|
7792
8041
|
await maybeRefreshAuth();
|
|
7793
|
-
await maybeWarnStaleVersion("1.28.
|
|
8042
|
+
await maybeWarnStaleVersion("1.28.12").catch(() => {
|
|
7794
8043
|
});
|
|
7795
8044
|
runMain(main).catch((err) => {
|
|
7796
8045
|
if (err instanceof CliExit) {
|