@openape/apes 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
} from "./chunk-OBF7IMQ2.js";
|
|
64
64
|
|
|
65
65
|
// src/cli.ts
|
|
66
|
-
import
|
|
66
|
+
import consola42 from "consola";
|
|
67
67
|
|
|
68
68
|
// src/ape-shell.ts
|
|
69
69
|
import path from "path";
|
|
@@ -93,7 +93,7 @@ function rewriteApeShellArgs(argv, argv0) {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
// src/cli.ts
|
|
96
|
-
import { defineCommand as
|
|
96
|
+
import { defineCommand as defineCommand52, runMain } from "citty";
|
|
97
97
|
|
|
98
98
|
// src/commands/auth/login.ts
|
|
99
99
|
import { Buffer as Buffer2 } from "buffer";
|
|
@@ -379,7 +379,7 @@ async function loginWithPKCE(idp) {
|
|
|
379
379
|
consola2.success(`Logged in as ${payload.email || payload.sub}`);
|
|
380
380
|
}
|
|
381
381
|
async function loginWithKey(idp, keyPath, agentEmail) {
|
|
382
|
-
const { readFileSync:
|
|
382
|
+
const { readFileSync: readFileSync14 } = await import("fs");
|
|
383
383
|
const { sign: sign3 } = await import("crypto");
|
|
384
384
|
const { loadEd25519PrivateKey: loadEd25519PrivateKey2 } = await import("./ssh-key-YBNNG5K5.js");
|
|
385
385
|
const challengeUrl = await getAgentChallengeEndpoint(idp);
|
|
@@ -392,7 +392,7 @@ async function loginWithKey(idp, keyPath, agentEmail) {
|
|
|
392
392
|
throw new CliError(`Challenge failed: ${await challengeResp.text()}`);
|
|
393
393
|
}
|
|
394
394
|
const { challenge } = await challengeResp.json();
|
|
395
|
-
const keyContent =
|
|
395
|
+
const keyContent = readFileSync14(keyPath, "utf-8");
|
|
396
396
|
const privateKey = loadEd25519PrivateKey2(keyContent);
|
|
397
397
|
const signature = sign3(null, Buffer2.from(challenge), privateKey).toString("base64");
|
|
398
398
|
const authenticateUrl = await getAgentAuthenticateEndpoint(idp);
|
|
@@ -2851,9 +2851,18 @@ function taskTools(names) {
|
|
|
2851
2851
|
function asOpenAiTools(tools) {
|
|
2852
2852
|
return tools.map((t) => ({
|
|
2853
2853
|
type: "function",
|
|
2854
|
-
function: { name: t.name, description: t.description, parameters: t.parameters }
|
|
2854
|
+
function: { name: wireToolName(t.name), description: t.description, parameters: t.parameters }
|
|
2855
2855
|
}));
|
|
2856
2856
|
}
|
|
2857
|
+
function wireToolName(local) {
|
|
2858
|
+
return local.replace(/\./g, "_");
|
|
2859
|
+
}
|
|
2860
|
+
function localToolName(wire) {
|
|
2861
|
+
for (const t of Object.values(TOOLS)) {
|
|
2862
|
+
if (wireToolName(t.name) === wire) return t.name;
|
|
2863
|
+
}
|
|
2864
|
+
return wire;
|
|
2865
|
+
}
|
|
2857
2866
|
|
|
2858
2867
|
// src/lib/agent-runtime.ts
|
|
2859
2868
|
function previewJson(value, max = 500) {
|
|
@@ -2913,19 +2922,21 @@ async function runLoop(opts) {
|
|
|
2913
2922
|
return result2;
|
|
2914
2923
|
}
|
|
2915
2924
|
for (const call of assistant.tool_calls) {
|
|
2916
|
-
const
|
|
2925
|
+
const wireName = call.function.name;
|
|
2926
|
+
const localName = localToolName(wireName);
|
|
2927
|
+
const tool = opts.tools.find((t) => t.name === localName);
|
|
2917
2928
|
let parsedArgs;
|
|
2918
2929
|
try {
|
|
2919
2930
|
parsedArgs = JSON.parse(call.function.arguments);
|
|
2920
2931
|
} catch {
|
|
2921
2932
|
parsedArgs = {};
|
|
2922
2933
|
}
|
|
2923
|
-
opts.handlers?.onToolCall?.({ name:
|
|
2924
|
-
trace.push({ step, type: "tool_call", tool:
|
|
2934
|
+
opts.handlers?.onToolCall?.({ name: localName, args: parsedArgs });
|
|
2935
|
+
trace.push({ step, type: "tool_call", tool: localName, preview: previewJson(parsedArgs) });
|
|
2925
2936
|
let result2;
|
|
2926
2937
|
let isError = false;
|
|
2927
2938
|
if (!tool) {
|
|
2928
|
-
result2 = `unknown tool: ${
|
|
2939
|
+
result2 = `unknown tool: ${localName}`;
|
|
2929
2940
|
isError = true;
|
|
2930
2941
|
} else {
|
|
2931
2942
|
try {
|
|
@@ -2936,16 +2947,16 @@ async function runLoop(opts) {
|
|
|
2936
2947
|
}
|
|
2937
2948
|
}
|
|
2938
2949
|
if (isError) {
|
|
2939
|
-
opts.handlers?.onToolError?.({ name:
|
|
2940
|
-
trace.push({ step, type: "tool_error", tool:
|
|
2950
|
+
opts.handlers?.onToolError?.({ name: localName, error: String(result2) });
|
|
2951
|
+
trace.push({ step, type: "tool_error", tool: localName, preview: previewJson(result2) });
|
|
2941
2952
|
} else {
|
|
2942
|
-
opts.handlers?.onToolResult?.({ name:
|
|
2943
|
-
trace.push({ step, type: "tool_result", tool:
|
|
2953
|
+
opts.handlers?.onToolResult?.({ name: localName, result: result2 });
|
|
2954
|
+
trace.push({ step, type: "tool_result", tool: localName, preview: previewJson(result2) });
|
|
2944
2955
|
}
|
|
2945
2956
|
messages.push({
|
|
2946
2957
|
role: "tool",
|
|
2947
2958
|
tool_call_id: call.id,
|
|
2948
|
-
name:
|
|
2959
|
+
name: wireToolName(localName),
|
|
2949
2960
|
content: typeof result2 === "string" ? result2 : JSON.stringify(result2)
|
|
2950
2961
|
});
|
|
2951
2962
|
}
|
|
@@ -3906,16 +3917,232 @@ var agentsCommand = defineCommand28({
|
|
|
3906
3917
|
}
|
|
3907
3918
|
});
|
|
3908
3919
|
|
|
3909
|
-
// src/commands/
|
|
3920
|
+
// src/commands/nest/index.ts
|
|
3921
|
+
import { defineCommand as defineCommand32 } from "citty";
|
|
3922
|
+
|
|
3923
|
+
// src/commands/nest/install.ts
|
|
3924
|
+
import { execFileSync as execFileSync9 } from "child_process";
|
|
3925
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
|
|
3926
|
+
import { homedir as homedir10, userInfo as userInfo2 } from "os";
|
|
3927
|
+
import { join as join8 } from "path";
|
|
3910
3928
|
import { defineCommand as defineCommand29 } from "citty";
|
|
3911
3929
|
import consola25 from "consola";
|
|
3912
|
-
var
|
|
3930
|
+
var PLIST_LABEL = "ai.openape.nest";
|
|
3931
|
+
function plistPath() {
|
|
3932
|
+
return join8(homedir10(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
3933
|
+
}
|
|
3934
|
+
function escape2(s) {
|
|
3935
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
3936
|
+
}
|
|
3937
|
+
function buildPlist(args) {
|
|
3938
|
+
const logsDir = join8(args.homeDir, "Library", "Logs");
|
|
3939
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
3940
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3941
|
+
<plist version="1.0">
|
|
3942
|
+
<dict>
|
|
3943
|
+
<key>Label</key>
|
|
3944
|
+
<string>${escape2(PLIST_LABEL)}</string>
|
|
3945
|
+
<key>ProgramArguments</key>
|
|
3946
|
+
<array>
|
|
3947
|
+
<string>${escape2(args.nestBin)}</string>
|
|
3948
|
+
</array>
|
|
3949
|
+
<key>WorkingDirectory</key>
|
|
3950
|
+
<string>${escape2(args.homeDir)}</string>
|
|
3951
|
+
<key>RunAtLoad</key>
|
|
3952
|
+
<true/>
|
|
3953
|
+
<key>KeepAlive</key>
|
|
3954
|
+
<true/>
|
|
3955
|
+
<key>ThrottleInterval</key>
|
|
3956
|
+
<integer>10</integer>
|
|
3957
|
+
<key>EnvironmentVariables</key>
|
|
3958
|
+
<dict>
|
|
3959
|
+
<key>HOME</key><string>${escape2(args.homeDir)}</string>
|
|
3960
|
+
<key>PATH</key><string>${escape2(args.homeDir)}/.bun/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
3961
|
+
<key>OPENAPE_NEST_PORT</key><string>${args.port}</string>
|
|
3962
|
+
<key>OPENAPE_APES_BIN</key><string>${escape2(args.apesBin)}</string>
|
|
3963
|
+
</dict>
|
|
3964
|
+
<key>StandardOutPath</key>
|
|
3965
|
+
<string>${escape2(logsDir)}/openape-nest.log</string>
|
|
3966
|
+
<key>StandardErrorPath</key>
|
|
3967
|
+
<string>${escape2(logsDir)}/openape-nest.log</string>
|
|
3968
|
+
</dict>
|
|
3969
|
+
</plist>
|
|
3970
|
+
`;
|
|
3971
|
+
}
|
|
3972
|
+
function findBinary(name) {
|
|
3973
|
+
for (const dir of [
|
|
3974
|
+
join8(homedir10(), ".bun", "bin"),
|
|
3975
|
+
"/opt/homebrew/bin",
|
|
3976
|
+
"/usr/local/bin",
|
|
3977
|
+
"/usr/bin"
|
|
3978
|
+
]) {
|
|
3979
|
+
const p = join8(dir, name);
|
|
3980
|
+
if (existsSync10(p)) return p;
|
|
3981
|
+
}
|
|
3982
|
+
throw new Error(`could not locate ${name} on PATH; install it first`);
|
|
3983
|
+
}
|
|
3984
|
+
var installNestCommand = defineCommand29({
|
|
3985
|
+
meta: {
|
|
3986
|
+
name: "install",
|
|
3987
|
+
description: "Install + start the local nest-daemon (idempotent \u2014 re-running just restarts)"
|
|
3988
|
+
},
|
|
3989
|
+
args: {
|
|
3990
|
+
port: {
|
|
3991
|
+
type: "string",
|
|
3992
|
+
description: "Port for the nest HTTP API (default: 9091)"
|
|
3993
|
+
}
|
|
3994
|
+
},
|
|
3995
|
+
async run({ args }) {
|
|
3996
|
+
const homeDir = homedir10();
|
|
3997
|
+
const port = Number(args.port ?? 9091);
|
|
3998
|
+
if (!Number.isInteger(port) || port < 1024 || port > 65535) {
|
|
3999
|
+
throw new Error(`invalid port ${port}`);
|
|
4000
|
+
}
|
|
4001
|
+
const nestBin = findBinary("openape-nest");
|
|
4002
|
+
const apesBin = findBinary("apes");
|
|
4003
|
+
consola25.info(`Installing nest at ${plistPath()}`);
|
|
4004
|
+
consola25.info(` nest binary: ${nestBin}`);
|
|
4005
|
+
consola25.info(` apes binary: ${apesBin}`);
|
|
4006
|
+
consola25.info(` HTTP port: ${port}`);
|
|
4007
|
+
mkdirSync4(join8(homeDir, "Library", "LaunchAgents"), { recursive: true });
|
|
4008
|
+
const desired = buildPlist({ nestBin, apesBin, homeDir, port });
|
|
4009
|
+
let existing = "";
|
|
4010
|
+
try {
|
|
4011
|
+
existing = readFileSync10(plistPath(), "utf8");
|
|
4012
|
+
} catch {
|
|
4013
|
+
}
|
|
4014
|
+
if (existing !== desired) {
|
|
4015
|
+
writeFileSync6(plistPath(), desired, { mode: 420 });
|
|
4016
|
+
consola25.success("Wrote launchd plist");
|
|
4017
|
+
} else {
|
|
4018
|
+
consola25.info("plist already up to date");
|
|
4019
|
+
}
|
|
4020
|
+
const uid = userInfo2().uid;
|
|
4021
|
+
try {
|
|
4022
|
+
execFileSync9("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL}`], { stdio: "ignore" });
|
|
4023
|
+
} catch {
|
|
4024
|
+
}
|
|
4025
|
+
execFileSync9("/bin/launchctl", ["bootstrap", `gui/${uid}`, plistPath()], { stdio: "inherit" });
|
|
4026
|
+
consola25.success(`Nest daemon bootstrapped \u2014 http://127.0.0.1:${port}`);
|
|
4027
|
+
consola25.info("");
|
|
4028
|
+
consola25.info("Next: approve the always-grant for nest-managed spawn/destroy.");
|
|
4029
|
+
consola25.info('Run this once and choose "Always" when the IdP UI prompts:');
|
|
4030
|
+
consola25.info("");
|
|
4031
|
+
consola25.info(' apes run --as root --approval=always --reason "nest-managed agent spawn" \\');
|
|
4032
|
+
consola25.info(" -- apes agents spawn _grant_pattern_seed_");
|
|
4033
|
+
consola25.info("");
|
|
4034
|
+
consola25.info('(The seed-spawn will fail because "_grant_pattern_seed_" is not a valid');
|
|
4035
|
+
consola25.info("agent name \u2014 that's expected. The grant just needs to be approved-as-always.)");
|
|
4036
|
+
}
|
|
4037
|
+
});
|
|
4038
|
+
|
|
4039
|
+
// src/commands/nest/status.ts
|
|
4040
|
+
import process2 from "process";
|
|
4041
|
+
import { defineCommand as defineCommand30 } from "citty";
|
|
4042
|
+
import consola26 from "consola";
|
|
4043
|
+
var DEFAULT_PORT = 9091;
|
|
4044
|
+
var statusNestCommand = defineCommand30({
|
|
4045
|
+
meta: {
|
|
4046
|
+
name: "status",
|
|
4047
|
+
description: "Print state of the local nest-daemon (agents registered, processes supervised)"
|
|
4048
|
+
},
|
|
4049
|
+
args: {
|
|
4050
|
+
port: { type: "string", description: "Override nest port (default: 9091)" },
|
|
4051
|
+
json: { type: "boolean", description: "JSON output for scripts" }
|
|
4052
|
+
},
|
|
4053
|
+
async run({ args }) {
|
|
4054
|
+
const port = Number(args.port ?? process2.env.OPENAPE_NEST_PORT ?? DEFAULT_PORT);
|
|
4055
|
+
const url = `http://127.0.0.1:${port}/status`;
|
|
4056
|
+
let status;
|
|
4057
|
+
try {
|
|
4058
|
+
const res = await fetch(url);
|
|
4059
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
4060
|
+
status = await res.json();
|
|
4061
|
+
} catch (err) {
|
|
4062
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4063
|
+
if (msg.includes("ECONNREFUSED") || msg.includes("fetch failed")) {
|
|
4064
|
+
consola26.error(`Nest daemon is not running at http://127.0.0.1:${port}`);
|
|
4065
|
+
consola26.info(" Run: apes nest install");
|
|
4066
|
+
process2.exit(2);
|
|
4067
|
+
}
|
|
4068
|
+
throw err;
|
|
4069
|
+
}
|
|
4070
|
+
if (args.json) {
|
|
4071
|
+
console.log(JSON.stringify(status, null, 2));
|
|
4072
|
+
return;
|
|
4073
|
+
}
|
|
4074
|
+
consola26.info(`Nest at http://127.0.0.1:${port} \u2014 ${status.agents} agent(s) registered, ${status.processes.length} supervised`);
|
|
4075
|
+
if (status.processes.length === 0) {
|
|
4076
|
+
consola26.info(" (no processes running)");
|
|
4077
|
+
return;
|
|
4078
|
+
}
|
|
4079
|
+
for (const p of status.processes) {
|
|
4080
|
+
const uptime = humanDuration(p.uptimeSec);
|
|
4081
|
+
const crashTag = p.consecutiveCrashes > 0 ? ` \u26A0 ${p.consecutiveCrashes} crash(es)` : "";
|
|
4082
|
+
consola26.info(` ${p.name.padEnd(16)} pid=${String(p.pid).padEnd(6)} up=${uptime}${crashTag}`);
|
|
4083
|
+
}
|
|
4084
|
+
}
|
|
4085
|
+
});
|
|
4086
|
+
function humanDuration(sec) {
|
|
4087
|
+
if (sec < 60) return `${sec}s`;
|
|
4088
|
+
if (sec < 3600) return `${Math.floor(sec / 60)}m`;
|
|
4089
|
+
if (sec < 86400) return `${Math.floor(sec / 3600)}h`;
|
|
4090
|
+
return `${Math.floor(sec / 86400)}d`;
|
|
4091
|
+
}
|
|
4092
|
+
|
|
4093
|
+
// src/commands/nest/uninstall.ts
|
|
4094
|
+
import { execFileSync as execFileSync10 } from "child_process";
|
|
4095
|
+
import { existsSync as existsSync11, unlinkSync } from "fs";
|
|
4096
|
+
import { homedir as homedir11, userInfo as userInfo3 } from "os";
|
|
4097
|
+
import { join as join9 } from "path";
|
|
4098
|
+
import { defineCommand as defineCommand31 } from "citty";
|
|
4099
|
+
import consola27 from "consola";
|
|
4100
|
+
var PLIST_LABEL2 = "ai.openape.nest";
|
|
4101
|
+
var uninstallNestCommand = defineCommand31({
|
|
4102
|
+
meta: {
|
|
4103
|
+
name: "uninstall",
|
|
4104
|
+
description: "Stop + remove the local nest-daemon (registry + agents preserved)"
|
|
4105
|
+
},
|
|
4106
|
+
async run() {
|
|
4107
|
+
const uid = userInfo3().uid;
|
|
4108
|
+
const path2 = join9(homedir11(), "Library", "LaunchAgents", `${PLIST_LABEL2}.plist`);
|
|
4109
|
+
try {
|
|
4110
|
+
execFileSync10("/bin/launchctl", ["bootout", `gui/${uid}/${PLIST_LABEL2}`], { stdio: "ignore" });
|
|
4111
|
+
consola27.success("Nest daemon stopped");
|
|
4112
|
+
} catch {
|
|
4113
|
+
consola27.info("Nest daemon was not loaded");
|
|
4114
|
+
}
|
|
4115
|
+
if (existsSync11(path2)) {
|
|
4116
|
+
unlinkSync(path2);
|
|
4117
|
+
consola27.success(`Removed ${path2}`);
|
|
4118
|
+
}
|
|
4119
|
+
consola27.info("Registry at ~/.openape/nest/agents.json kept \u2014 re-run `apes nest install` to resume supervision.");
|
|
4120
|
+
}
|
|
4121
|
+
});
|
|
4122
|
+
|
|
4123
|
+
// src/commands/nest/index.ts
|
|
4124
|
+
var nestCommand = defineCommand32({
|
|
4125
|
+
meta: {
|
|
4126
|
+
name: "nest",
|
|
4127
|
+
description: "Manage the local Nest control-plane daemon (install, status, uninstall). The Nest hosts agents on this computer \u2014 once installed, `apes agents spawn` is fast (no per-spawn DDISA approvals) and per-agent launchd plists are replaced by a single supervised process tree."
|
|
4128
|
+
},
|
|
4129
|
+
subCommands: {
|
|
4130
|
+
install: installNestCommand,
|
|
4131
|
+
status: statusNestCommand,
|
|
4132
|
+
uninstall: uninstallNestCommand
|
|
4133
|
+
}
|
|
4134
|
+
});
|
|
4135
|
+
|
|
4136
|
+
// src/commands/adapter/index.ts
|
|
4137
|
+
import { defineCommand as defineCommand33 } from "citty";
|
|
4138
|
+
import consola28 from "consola";
|
|
4139
|
+
var adapterCommand = defineCommand33({
|
|
3913
4140
|
meta: {
|
|
3914
4141
|
name: "adapter",
|
|
3915
4142
|
description: "Manage CLI adapters"
|
|
3916
4143
|
},
|
|
3917
4144
|
subCommands: {
|
|
3918
|
-
list:
|
|
4145
|
+
list: defineCommand33({
|
|
3919
4146
|
meta: {
|
|
3920
4147
|
name: "list",
|
|
3921
4148
|
description: "List available adapters"
|
|
@@ -3946,7 +4173,7 @@ var adapterCommand = defineCommand29({
|
|
|
3946
4173
|
`);
|
|
3947
4174
|
return;
|
|
3948
4175
|
}
|
|
3949
|
-
|
|
4176
|
+
consola28.info(`Registry: ${index2.adapters.length} adapters (${index2.generated_at})`);
|
|
3950
4177
|
for (const a of index2.adapters) {
|
|
3951
4178
|
const installed = isInstalled(a.id, false) ? " [installed]" : "";
|
|
3952
4179
|
console.log(` ${a.id.padEnd(12)} ${a.name.padEnd(24)} ${a.category}${installed}`);
|
|
@@ -3968,7 +4195,7 @@ var adapterCommand = defineCommand29({
|
|
|
3968
4195
|
return;
|
|
3969
4196
|
}
|
|
3970
4197
|
if (local.length === 0) {
|
|
3971
|
-
|
|
4198
|
+
consola28.info("No adapters installed. Use `apes adapter list --remote` to see available adapters.");
|
|
3972
4199
|
return;
|
|
3973
4200
|
}
|
|
3974
4201
|
for (const a of local) {
|
|
@@ -3976,7 +4203,7 @@ var adapterCommand = defineCommand29({
|
|
|
3976
4203
|
}
|
|
3977
4204
|
}
|
|
3978
4205
|
}),
|
|
3979
|
-
install:
|
|
4206
|
+
install: defineCommand33({
|
|
3980
4207
|
meta: {
|
|
3981
4208
|
name: "install",
|
|
3982
4209
|
description: "Install an adapter from the registry"
|
|
@@ -4005,24 +4232,24 @@ var adapterCommand = defineCommand29({
|
|
|
4005
4232
|
for (const id of ids) {
|
|
4006
4233
|
const entry = findAdapter(index, id);
|
|
4007
4234
|
if (!entry) {
|
|
4008
|
-
|
|
4235
|
+
consola28.error(`Adapter "${id}" not found in registry. Use \`apes adapter search ${id}\` to search.`);
|
|
4009
4236
|
continue;
|
|
4010
4237
|
}
|
|
4011
4238
|
const conflicts = findConflictingAdapters(entry.executable, id);
|
|
4012
4239
|
if (conflicts.length > 0) {
|
|
4013
4240
|
for (const c of conflicts) {
|
|
4014
|
-
|
|
4015
|
-
|
|
4241
|
+
consola28.warn(`Conflicting adapter found: ${c.path} (id: ${c.adapterId}, executable: ${c.executable})`);
|
|
4242
|
+
consola28.warn(` Remove it with: apes adapter remove ${c.adapterId}`);
|
|
4016
4243
|
}
|
|
4017
4244
|
}
|
|
4018
4245
|
const result = await installAdapter(entry, { local });
|
|
4019
4246
|
const verb = result.updated ? "Updated" : "Installed";
|
|
4020
|
-
|
|
4021
|
-
|
|
4247
|
+
consola28.success(`${verb} ${result.id} \u2192 ${result.path}`);
|
|
4248
|
+
consola28.info(`Digest: ${result.digest}`);
|
|
4022
4249
|
}
|
|
4023
4250
|
}
|
|
4024
4251
|
}),
|
|
4025
|
-
remove:
|
|
4252
|
+
remove: defineCommand33({
|
|
4026
4253
|
meta: {
|
|
4027
4254
|
name: "remove",
|
|
4028
4255
|
description: "Remove an installed adapter"
|
|
@@ -4045,9 +4272,9 @@ var adapterCommand = defineCommand29({
|
|
|
4045
4272
|
let failed = false;
|
|
4046
4273
|
for (const id of ids) {
|
|
4047
4274
|
if (removeAdapter(id, local)) {
|
|
4048
|
-
|
|
4275
|
+
consola28.success(`Removed adapter: ${id}`);
|
|
4049
4276
|
} else {
|
|
4050
|
-
|
|
4277
|
+
consola28.error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
|
|
4051
4278
|
failed = true;
|
|
4052
4279
|
}
|
|
4053
4280
|
}
|
|
@@ -4055,7 +4282,7 @@ var adapterCommand = defineCommand29({
|
|
|
4055
4282
|
throw new CliError("Some adapters could not be removed");
|
|
4056
4283
|
}
|
|
4057
4284
|
}),
|
|
4058
|
-
info:
|
|
4285
|
+
info: defineCommand33({
|
|
4059
4286
|
meta: {
|
|
4060
4287
|
name: "info",
|
|
4061
4288
|
description: "Show detailed adapter information"
|
|
@@ -4097,7 +4324,7 @@ var adapterCommand = defineCommand29({
|
|
|
4097
4324
|
}
|
|
4098
4325
|
}
|
|
4099
4326
|
}),
|
|
4100
|
-
search:
|
|
4327
|
+
search: defineCommand33({
|
|
4101
4328
|
meta: {
|
|
4102
4329
|
name: "search",
|
|
4103
4330
|
description: "Search adapters in the registry"
|
|
@@ -4129,7 +4356,7 @@ var adapterCommand = defineCommand29({
|
|
|
4129
4356
|
return;
|
|
4130
4357
|
}
|
|
4131
4358
|
if (results.length === 0) {
|
|
4132
|
-
|
|
4359
|
+
consola28.info(`No adapters matching "${query}"`);
|
|
4133
4360
|
return;
|
|
4134
4361
|
}
|
|
4135
4362
|
for (const a of results) {
|
|
@@ -4138,7 +4365,7 @@ var adapterCommand = defineCommand29({
|
|
|
4138
4365
|
}
|
|
4139
4366
|
}
|
|
4140
4367
|
}),
|
|
4141
|
-
update:
|
|
4368
|
+
update: defineCommand33({
|
|
4142
4369
|
meta: {
|
|
4143
4370
|
name: "update",
|
|
4144
4371
|
description: "Update installed adapters"
|
|
@@ -4164,33 +4391,33 @@ var adapterCommand = defineCommand29({
|
|
|
4164
4391
|
const targetId = args.id ? String(args.id) : void 0;
|
|
4165
4392
|
const targets = targetId ? [targetId] : index.adapters.map((a) => a.id).filter((id) => isInstalled(id, false));
|
|
4166
4393
|
if (targets.length === 0) {
|
|
4167
|
-
|
|
4394
|
+
consola28.info("No adapters installed to update.");
|
|
4168
4395
|
return;
|
|
4169
4396
|
}
|
|
4170
4397
|
for (const id of targets) {
|
|
4171
4398
|
const entry = findAdapter(index, id);
|
|
4172
4399
|
if (!entry) {
|
|
4173
|
-
|
|
4400
|
+
consola28.warn(`${id}: not found in registry, skipping`);
|
|
4174
4401
|
continue;
|
|
4175
4402
|
}
|
|
4176
4403
|
const localDigest = getInstalledDigest(id, false);
|
|
4177
4404
|
if (localDigest === entry.digest) {
|
|
4178
|
-
|
|
4405
|
+
consola28.info(`${id}: already up to date`);
|
|
4179
4406
|
continue;
|
|
4180
4407
|
}
|
|
4181
4408
|
if (localDigest && !args.yes) {
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4409
|
+
consola28.warn(`${id}: digest will change \u2014 existing grants for this adapter will be invalidated`);
|
|
4410
|
+
consola28.info(` Old: ${localDigest}`);
|
|
4411
|
+
consola28.info(` New: ${entry.digest}`);
|
|
4412
|
+
consola28.info(" Use --yes to confirm");
|
|
4186
4413
|
continue;
|
|
4187
4414
|
}
|
|
4188
4415
|
const result = await installAdapter(entry);
|
|
4189
|
-
|
|
4416
|
+
consola28.success(`Updated ${result.id} \u2192 ${result.path}`);
|
|
4190
4417
|
}
|
|
4191
4418
|
}
|
|
4192
4419
|
}),
|
|
4193
|
-
verify:
|
|
4420
|
+
verify: defineCommand33({
|
|
4194
4421
|
meta: {
|
|
4195
4422
|
name: "verify",
|
|
4196
4423
|
description: "Verify installed adapter against registry digest"
|
|
@@ -4223,7 +4450,7 @@ var adapterCommand = defineCommand29({
|
|
|
4223
4450
|
if (!localDigest)
|
|
4224
4451
|
throw new Error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
|
|
4225
4452
|
if (localDigest === entry.digest) {
|
|
4226
|
-
|
|
4453
|
+
consola28.success(`${id}: digest matches registry`);
|
|
4227
4454
|
} else {
|
|
4228
4455
|
console.log(` Local: ${localDigest}`);
|
|
4229
4456
|
console.log(` Registry: ${entry.digest}`);
|
|
@@ -4235,11 +4462,11 @@ var adapterCommand = defineCommand29({
|
|
|
4235
4462
|
});
|
|
4236
4463
|
|
|
4237
4464
|
// src/commands/run.ts
|
|
4238
|
-
import { execFileSync as
|
|
4465
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
4239
4466
|
import { hostname as hostname4 } from "os";
|
|
4240
4467
|
import { basename } from "path";
|
|
4241
|
-
import { defineCommand as
|
|
4242
|
-
import
|
|
4468
|
+
import { defineCommand as defineCommand34 } from "citty";
|
|
4469
|
+
import consola29 from "consola";
|
|
4243
4470
|
function shouldWaitForGrant(args) {
|
|
4244
4471
|
return args.wait === true || process.env.APE_WAIT === "1";
|
|
4245
4472
|
}
|
|
@@ -4276,7 +4503,7 @@ function printPendingGrantInfo(grant, idp) {
|
|
|
4276
4503
|
const statusCmd = `apes grants status ${grant.id}`;
|
|
4277
4504
|
const executeCmd = `apes grants run ${grant.id}`;
|
|
4278
4505
|
if (mode === "human") {
|
|
4279
|
-
|
|
4506
|
+
consola29.success(`Grant ${grant.id} created \u2014 awaiting your approval`);
|
|
4280
4507
|
console.log(` Approve in browser: ${approveUrl}`);
|
|
4281
4508
|
console.log(` Check status: ${statusCmd}`);
|
|
4282
4509
|
console.log(` Run after approval: ${executeCmd}`);
|
|
@@ -4286,7 +4513,7 @@ function printPendingGrantInfo(grant, idp) {
|
|
|
4286
4513
|
return;
|
|
4287
4514
|
}
|
|
4288
4515
|
const maxMin = getPollMaxMinutes();
|
|
4289
|
-
|
|
4516
|
+
consola29.success(`Grant ${grant.id} created (pending approval)`);
|
|
4290
4517
|
console.log(` Approve: ${approveUrl}`);
|
|
4291
4518
|
console.log(` Status: ${statusCmd} [--json]`);
|
|
4292
4519
|
console.log(` Execute: ${executeCmd} --wait`);
|
|
@@ -4308,7 +4535,7 @@ function printPendingGrantInfo(grant, idp) {
|
|
|
4308
4535
|
console.log(' Tip: Approve as "timed" or "always" in the browser to let this');
|
|
4309
4536
|
console.log(" grant be reused on subsequent invocations without re-approval.");
|
|
4310
4537
|
}
|
|
4311
|
-
var runCommand =
|
|
4538
|
+
var runCommand = defineCommand34({
|
|
4312
4539
|
meta: {
|
|
4313
4540
|
name: "run",
|
|
4314
4541
|
description: "Execute a grant-secured command"
|
|
@@ -4411,7 +4638,7 @@ async function runShellMode(command, args) {
|
|
|
4411
4638
|
}
|
|
4412
4639
|
} catch {
|
|
4413
4640
|
}
|
|
4414
|
-
|
|
4641
|
+
consola29.info(`Requesting ape-shell session grant on ${targetHost}`);
|
|
4415
4642
|
const grant = await apiFetch(grantsUrl, {
|
|
4416
4643
|
method: "POST",
|
|
4417
4644
|
body: {
|
|
@@ -4431,8 +4658,8 @@ async function runShellMode(command, args) {
|
|
|
4431
4658
|
host: targetHost
|
|
4432
4659
|
});
|
|
4433
4660
|
if (shouldWaitForGrant(args)) {
|
|
4434
|
-
|
|
4435
|
-
|
|
4661
|
+
consola29.info(`Grant requested: ${grant.id}`);
|
|
4662
|
+
consola29.info("Waiting for approval...");
|
|
4436
4663
|
const maxWait = 3e5;
|
|
4437
4664
|
const interval = 3e3;
|
|
4438
4665
|
const start = Date.now();
|
|
@@ -4463,13 +4690,13 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
4463
4690
|
try {
|
|
4464
4691
|
resolved = await resolveCommand(loaded, [normalizedExecutable, ...parsed.argv]);
|
|
4465
4692
|
} catch (err) {
|
|
4466
|
-
|
|
4693
|
+
consola29.debug(`ape-shell: adapter resolve failed for "${parsed.raw}":`, err);
|
|
4467
4694
|
return false;
|
|
4468
4695
|
}
|
|
4469
4696
|
try {
|
|
4470
4697
|
const existingGrantId = await findExistingGrant(resolved, idp);
|
|
4471
4698
|
if (existingGrantId) {
|
|
4472
|
-
|
|
4699
|
+
consola29.info(`Reusing grant ${existingGrantId} for: ${resolved.detail.display}`);
|
|
4473
4700
|
const token = await fetchGrantToken(idp, existingGrantId);
|
|
4474
4701
|
await verifyAndExecute(token, resolved, existingGrantId);
|
|
4475
4702
|
return true;
|
|
@@ -4477,7 +4704,7 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
4477
4704
|
} catch {
|
|
4478
4705
|
}
|
|
4479
4706
|
const approval = args.approval ?? "once";
|
|
4480
|
-
|
|
4707
|
+
consola29.info(`Requesting grant for: ${resolved.detail.display}`);
|
|
4481
4708
|
const grant = await createShapesGrant(resolved, {
|
|
4482
4709
|
idp,
|
|
4483
4710
|
approval,
|
|
@@ -4485,8 +4712,8 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
4485
4712
|
});
|
|
4486
4713
|
if (grant.similar_grants?.similar_grants?.length) {
|
|
4487
4714
|
const n = grant.similar_grants.similar_grants.length;
|
|
4488
|
-
|
|
4489
|
-
|
|
4715
|
+
consola29.info("");
|
|
4716
|
+
consola29.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
|
|
4490
4717
|
}
|
|
4491
4718
|
notifyGrantPending({
|
|
4492
4719
|
grantId: grant.id,
|
|
@@ -4496,8 +4723,8 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
4496
4723
|
host: args.host || hostname4()
|
|
4497
4724
|
});
|
|
4498
4725
|
if (shouldWaitForGrant(args)) {
|
|
4499
|
-
|
|
4500
|
-
|
|
4726
|
+
consola29.info(`Grant requested: ${grant.id}`);
|
|
4727
|
+
consola29.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
|
|
4501
4728
|
const status = await waitForGrantStatus(idp, grant.id);
|
|
4502
4729
|
if (status !== "approved")
|
|
4503
4730
|
throw new CliError(`Grant ${status}`);
|
|
@@ -4513,7 +4740,7 @@ function execShellCommand(command) {
|
|
|
4513
4740
|
throw new CliError("No command to execute");
|
|
4514
4741
|
try {
|
|
4515
4742
|
const { APES_SHELL_WRAPPER: _wrapperMarker, ...inheritedEnv } = process.env;
|
|
4516
|
-
|
|
4743
|
+
execFileSync11(command[0], command.slice(1), {
|
|
4517
4744
|
stdio: "inherit",
|
|
4518
4745
|
env: inheritedEnv
|
|
4519
4746
|
});
|
|
@@ -4571,7 +4798,7 @@ async function runAdapterMode(command, rawArgs, args) {
|
|
|
4571
4798
|
try {
|
|
4572
4799
|
const existingGrantId = await findExistingGrant(resolved, idp);
|
|
4573
4800
|
if (existingGrantId) {
|
|
4574
|
-
|
|
4801
|
+
consola29.info(`Reusing existing grant: ${existingGrantId}`);
|
|
4575
4802
|
const token = await fetchGrantToken(idp, existingGrantId);
|
|
4576
4803
|
await verifyAndExecute(token, resolved, existingGrantId);
|
|
4577
4804
|
return;
|
|
@@ -4585,17 +4812,17 @@ async function runAdapterMode(command, rawArgs, args) {
|
|
|
4585
4812
|
});
|
|
4586
4813
|
if (grant.similar_grants?.similar_grants?.length) {
|
|
4587
4814
|
const n = grant.similar_grants.similar_grants.length;
|
|
4588
|
-
|
|
4589
|
-
|
|
4815
|
+
consola29.info("");
|
|
4816
|
+
consola29.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
|
|
4590
4817
|
if (grant.similar_grants.widened_details?.length) {
|
|
4591
4818
|
const wider = grant.similar_grants.widened_details.map((d) => d.permission).join(", ");
|
|
4592
|
-
|
|
4819
|
+
consola29.info(` Broader scope: ${wider}`);
|
|
4593
4820
|
}
|
|
4594
|
-
|
|
4821
|
+
consola29.info("");
|
|
4595
4822
|
}
|
|
4596
4823
|
if (shouldWaitForGrant(args)) {
|
|
4597
|
-
|
|
4598
|
-
|
|
4824
|
+
consola29.info(`Grant requested: ${grant.id}`);
|
|
4825
|
+
consola29.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
|
|
4599
4826
|
const status = await waitForGrantStatus(idp, grant.id);
|
|
4600
4827
|
if (status !== "approved")
|
|
4601
4828
|
throw new Error(`Grant ${status}`);
|
|
@@ -4615,7 +4842,7 @@ async function runAudienceMode(audience, action, args) {
|
|
|
4615
4842
|
const grantsUrl = await getGrantsEndpoint(idp);
|
|
4616
4843
|
const command = action.split(" ");
|
|
4617
4844
|
const targetHost = args.host || hostname4();
|
|
4618
|
-
|
|
4845
|
+
consola29.info(`Requesting ${audience} grant on ${targetHost}: ${command.join(" ")}`);
|
|
4619
4846
|
const grant = await apiFetch(grantsUrl, {
|
|
4620
4847
|
method: "POST",
|
|
4621
4848
|
body: {
|
|
@@ -4632,9 +4859,9 @@ async function runAudienceMode(audience, action, args) {
|
|
|
4632
4859
|
printPendingGrantInfo(grant, idp);
|
|
4633
4860
|
throw new CliExit(getAsyncExitCode());
|
|
4634
4861
|
}
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4862
|
+
consola29.success(`Grant requested: ${grant.id}`);
|
|
4863
|
+
consola29.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
|
|
4864
|
+
consola29.info("Waiting for approval...");
|
|
4638
4865
|
const maxWait = 15 * 60 * 1e3;
|
|
4639
4866
|
const interval = 3e3;
|
|
4640
4867
|
const start = Date.now();
|
|
@@ -4642,7 +4869,7 @@ async function runAudienceMode(audience, action, args) {
|
|
|
4642
4869
|
while (Date.now() - start < maxWait) {
|
|
4643
4870
|
const status = await apiFetch(`${grantsUrl}/${grant.id}`);
|
|
4644
4871
|
if (status.status === "approved") {
|
|
4645
|
-
|
|
4872
|
+
consola29.success("Grant approved!");
|
|
4646
4873
|
approved = true;
|
|
4647
4874
|
break;
|
|
4648
4875
|
}
|
|
@@ -4657,15 +4884,15 @@ async function runAudienceMode(audience, action, args) {
|
|
|
4657
4884
|
`Grant approval timed out after ${minutes} min (still pending). Check your DDISA inbox at ${idp}/grant-approval?grant_id=${grant.id} \u2014 if approved later, re-run the same \`apes run\` command and it will reuse the grant.`
|
|
4658
4885
|
);
|
|
4659
4886
|
}
|
|
4660
|
-
|
|
4887
|
+
consola29.info("Fetching grant token...");
|
|
4661
4888
|
const { authz_jwt } = await apiFetch(`${grantsUrl}/${grant.id}/token`, {
|
|
4662
4889
|
method: "POST"
|
|
4663
4890
|
});
|
|
4664
4891
|
if (audience === "escapes") {
|
|
4665
|
-
|
|
4892
|
+
consola29.info(`Executing: ${command.join(" ")}`);
|
|
4666
4893
|
try {
|
|
4667
4894
|
const { APES_SHELL_WRAPPER: _wrapperMarker, ...inheritedEnv } = process.env;
|
|
4668
|
-
|
|
4895
|
+
execFileSync11(args["escapes-path"] || "escapes", ["--grant", authz_jwt, "--", ...command], {
|
|
4669
4896
|
stdio: "inherit",
|
|
4670
4897
|
env: inheritedEnv
|
|
4671
4898
|
});
|
|
@@ -4680,8 +4907,8 @@ async function runAudienceMode(audience, action, args) {
|
|
|
4680
4907
|
|
|
4681
4908
|
// src/commands/proxy.ts
|
|
4682
4909
|
import { spawn as spawn2 } from "child_process";
|
|
4683
|
-
import { defineCommand as
|
|
4684
|
-
import
|
|
4910
|
+
import { defineCommand as defineCommand35 } from "citty";
|
|
4911
|
+
import consola30 from "consola";
|
|
4685
4912
|
|
|
4686
4913
|
// src/proxy/config.ts
|
|
4687
4914
|
function buildDefaultProxyConfigToml(opts) {
|
|
@@ -4715,10 +4942,10 @@ note = "VPC-internal hostname suffix"
|
|
|
4715
4942
|
|
|
4716
4943
|
// src/proxy/local-proxy.ts
|
|
4717
4944
|
import { spawn } from "child_process";
|
|
4718
|
-
import { mkdtempSync as mkdtempSync3, rmSync as rmSync3, writeFileSync as
|
|
4945
|
+
import { mkdtempSync as mkdtempSync3, rmSync as rmSync3, writeFileSync as writeFileSync7 } from "fs";
|
|
4719
4946
|
import { createRequire } from "module";
|
|
4720
4947
|
import { tmpdir as tmpdir3 } from "os";
|
|
4721
|
-
import { dirname as dirname3, join as
|
|
4948
|
+
import { dirname as dirname3, join as join10, resolve as resolve4 } from "path";
|
|
4722
4949
|
var require2 = createRequire(import.meta.url);
|
|
4723
4950
|
function findProxyBin() {
|
|
4724
4951
|
const pkgPath = require2.resolve("@openape/proxy/package.json");
|
|
@@ -4730,9 +4957,9 @@ function findProxyBin() {
|
|
|
4730
4957
|
return resolve4(dirname3(pkgPath), binRel);
|
|
4731
4958
|
}
|
|
4732
4959
|
async function startEphemeralProxy(configToml) {
|
|
4733
|
-
const tmpDir = mkdtempSync3(
|
|
4734
|
-
const configPath =
|
|
4735
|
-
|
|
4960
|
+
const tmpDir = mkdtempSync3(join10(tmpdir3(), "openape-proxy-"));
|
|
4961
|
+
const configPath = join10(tmpDir, "config.toml");
|
|
4962
|
+
writeFileSync7(configPath, configToml, { mode: 384 });
|
|
4736
4963
|
const binPath = findProxyBin();
|
|
4737
4964
|
const child = spawn(process.execPath, [binPath, "-c", configPath], {
|
|
4738
4965
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -4824,10 +5051,10 @@ function resolveProxyConfigOptions() {
|
|
|
4824
5051
|
77
|
|
4825
5052
|
);
|
|
4826
5053
|
}
|
|
4827
|
-
|
|
5054
|
+
consola30.info(`[apes proxy] IdP-mediated mode \u2014 agent=${auth.email}, idp=${auth.idp}`);
|
|
4828
5055
|
return { agentEmail: auth.email, idpUrl: auth.idp, mediated: true };
|
|
4829
5056
|
}
|
|
4830
|
-
var proxyCommand =
|
|
5057
|
+
var proxyCommand = defineCommand35({
|
|
4831
5058
|
meta: {
|
|
4832
5059
|
name: "proxy",
|
|
4833
5060
|
description: "Run a command with HTTPS_PROXY routed through the OpenApe egress proxy."
|
|
@@ -4849,12 +5076,12 @@ var proxyCommand = defineCommand31({
|
|
|
4849
5076
|
let close = null;
|
|
4850
5077
|
if (reuseUrl) {
|
|
4851
5078
|
proxyUrl = reuseUrl;
|
|
4852
|
-
|
|
5079
|
+
consola30.info(`[apes proxy] reusing existing proxy at ${proxyUrl}`);
|
|
4853
5080
|
} else {
|
|
4854
5081
|
const ephemeral = await startEphemeralProxy(buildDefaultProxyConfigToml(resolveProxyConfigOptions()));
|
|
4855
5082
|
proxyUrl = ephemeral.url;
|
|
4856
5083
|
close = ephemeral.close;
|
|
4857
|
-
|
|
5084
|
+
consola30.info(`[apes proxy] started ephemeral proxy at ${proxyUrl}`);
|
|
4858
5085
|
}
|
|
4859
5086
|
const noProxy = process.env.NO_PROXY ?? process.env.no_proxy ?? "127.0.0.1,localhost";
|
|
4860
5087
|
const childEnv = {
|
|
@@ -4886,7 +5113,7 @@ var proxyCommand = defineCommand31({
|
|
|
4886
5113
|
else resolveExit(code ?? 0);
|
|
4887
5114
|
});
|
|
4888
5115
|
child.once("error", (err) => {
|
|
4889
|
-
|
|
5116
|
+
consola30.error(`[apes proxy] failed to spawn '${wrapped[0]}':`, err.message);
|
|
4890
5117
|
resolveExit(127);
|
|
4891
5118
|
});
|
|
4892
5119
|
});
|
|
@@ -4900,8 +5127,8 @@ function signalNumber(signal) {
|
|
|
4900
5127
|
}
|
|
4901
5128
|
|
|
4902
5129
|
// src/commands/explain.ts
|
|
4903
|
-
import { defineCommand as
|
|
4904
|
-
var explainCommand =
|
|
5130
|
+
import { defineCommand as defineCommand36 } from "citty";
|
|
5131
|
+
var explainCommand = defineCommand36({
|
|
4905
5132
|
meta: {
|
|
4906
5133
|
name: "explain",
|
|
4907
5134
|
description: "Show what permission a command would need"
|
|
@@ -4939,9 +5166,9 @@ var explainCommand = defineCommand32({
|
|
|
4939
5166
|
});
|
|
4940
5167
|
|
|
4941
5168
|
// src/commands/config/get.ts
|
|
4942
|
-
import { defineCommand as
|
|
4943
|
-
import
|
|
4944
|
-
var configGetCommand =
|
|
5169
|
+
import { defineCommand as defineCommand37 } from "citty";
|
|
5170
|
+
import consola31 from "consola";
|
|
5171
|
+
var configGetCommand = defineCommand37({
|
|
4945
5172
|
meta: {
|
|
4946
5173
|
name: "get",
|
|
4947
5174
|
description: "Get a configuration value"
|
|
@@ -4961,7 +5188,7 @@ var configGetCommand = defineCommand33({
|
|
|
4961
5188
|
if (idp)
|
|
4962
5189
|
console.log(idp);
|
|
4963
5190
|
else
|
|
4964
|
-
|
|
5191
|
+
consola31.info("No IdP configured.");
|
|
4965
5192
|
break;
|
|
4966
5193
|
}
|
|
4967
5194
|
case "email": {
|
|
@@ -4969,7 +5196,7 @@ var configGetCommand = defineCommand33({
|
|
|
4969
5196
|
if (auth?.email)
|
|
4970
5197
|
console.log(auth.email);
|
|
4971
5198
|
else
|
|
4972
|
-
|
|
5199
|
+
consola31.info("Not logged in.");
|
|
4973
5200
|
break;
|
|
4974
5201
|
}
|
|
4975
5202
|
default: {
|
|
@@ -4982,7 +5209,7 @@ var configGetCommand = defineCommand33({
|
|
|
4982
5209
|
if (sectionObj && field in sectionObj) {
|
|
4983
5210
|
console.log(sectionObj[field]);
|
|
4984
5211
|
} else {
|
|
4985
|
-
|
|
5212
|
+
consola31.info(`Key "${key}" not set.`);
|
|
4986
5213
|
}
|
|
4987
5214
|
} else {
|
|
4988
5215
|
throw new CliError(`Unknown key: "${key}". Use: idp, email, defaults.idp, defaults.approval, agent.key, agent.email`);
|
|
@@ -4993,9 +5220,9 @@ var configGetCommand = defineCommand33({
|
|
|
4993
5220
|
});
|
|
4994
5221
|
|
|
4995
5222
|
// src/commands/config/set.ts
|
|
4996
|
-
import { defineCommand as
|
|
4997
|
-
import
|
|
4998
|
-
var configSetCommand =
|
|
5223
|
+
import { defineCommand as defineCommand38 } from "citty";
|
|
5224
|
+
import consola32 from "consola";
|
|
5225
|
+
var configSetCommand = defineCommand38({
|
|
4999
5226
|
meta: {
|
|
5000
5227
|
name: "set",
|
|
5001
5228
|
description: "Set a configuration value"
|
|
@@ -5031,12 +5258,12 @@ var configSetCommand = defineCommand34({
|
|
|
5031
5258
|
throw new CliError(`Unknown section: "${section}". Use: defaults, agent`);
|
|
5032
5259
|
}
|
|
5033
5260
|
saveConfig(config);
|
|
5034
|
-
|
|
5261
|
+
consola32.success(`Set ${key} = ${value}`);
|
|
5035
5262
|
}
|
|
5036
5263
|
});
|
|
5037
5264
|
|
|
5038
5265
|
// src/commands/fetch/index.ts
|
|
5039
|
-
import { defineCommand as
|
|
5266
|
+
import { defineCommand as defineCommand39 } from "citty";
|
|
5040
5267
|
async function doRequest(method, url, body, contentType, raw, showHeaders) {
|
|
5041
5268
|
const token = getAuthToken();
|
|
5042
5269
|
if (!token) {
|
|
@@ -5072,13 +5299,13 @@ async function doRequest(method, url, body, contentType, raw, showHeaders) {
|
|
|
5072
5299
|
throw new CliError(`HTTP ${response.status} ${response.statusText}`);
|
|
5073
5300
|
}
|
|
5074
5301
|
}
|
|
5075
|
-
var fetchCommand =
|
|
5302
|
+
var fetchCommand = defineCommand39({
|
|
5076
5303
|
meta: {
|
|
5077
5304
|
name: "fetch",
|
|
5078
5305
|
description: "Make authenticated HTTP requests"
|
|
5079
5306
|
},
|
|
5080
5307
|
subCommands: {
|
|
5081
|
-
get:
|
|
5308
|
+
get: defineCommand39({
|
|
5082
5309
|
meta: {
|
|
5083
5310
|
name: "get",
|
|
5084
5311
|
description: "GET request with auth token"
|
|
@@ -5104,7 +5331,7 @@ var fetchCommand = defineCommand35({
|
|
|
5104
5331
|
await doRequest("GET", String(args.url), void 0, "application/json", Boolean(args.raw), Boolean(args.headers));
|
|
5105
5332
|
}
|
|
5106
5333
|
}),
|
|
5107
|
-
post:
|
|
5334
|
+
post: defineCommand39({
|
|
5108
5335
|
meta: {
|
|
5109
5336
|
name: "post",
|
|
5110
5337
|
description: "POST request with auth token"
|
|
@@ -5143,8 +5370,8 @@ var fetchCommand = defineCommand35({
|
|
|
5143
5370
|
});
|
|
5144
5371
|
|
|
5145
5372
|
// src/commands/mcp/index.ts
|
|
5146
|
-
import { defineCommand as
|
|
5147
|
-
var mcpCommand =
|
|
5373
|
+
import { defineCommand as defineCommand40 } from "citty";
|
|
5374
|
+
var mcpCommand = defineCommand40({
|
|
5148
5375
|
meta: {
|
|
5149
5376
|
name: "mcp",
|
|
5150
5377
|
description: "Start MCP server for AI agents"
|
|
@@ -5167,48 +5394,48 @@ var mcpCommand = defineCommand36({
|
|
|
5167
5394
|
if (transport !== "stdio" && transport !== "sse") {
|
|
5168
5395
|
throw new Error('Transport must be "stdio" or "sse"');
|
|
5169
5396
|
}
|
|
5170
|
-
const { startMcpServer } = await import("./server-
|
|
5397
|
+
const { startMcpServer } = await import("./server-A56K7VDD.js");
|
|
5171
5398
|
await startMcpServer(transport, port);
|
|
5172
5399
|
}
|
|
5173
5400
|
});
|
|
5174
5401
|
|
|
5175
5402
|
// src/commands/init/index.ts
|
|
5176
|
-
import { existsSync as
|
|
5403
|
+
import { existsSync as existsSync12, copyFileSync, writeFileSync as writeFileSync8 } from "fs";
|
|
5177
5404
|
import { randomBytes } from "crypto";
|
|
5178
|
-
import { execFileSync as
|
|
5179
|
-
import { join as
|
|
5180
|
-
import { defineCommand as
|
|
5181
|
-
import
|
|
5405
|
+
import { execFileSync as execFileSync12 } from "child_process";
|
|
5406
|
+
import { join as join11 } from "path";
|
|
5407
|
+
import { defineCommand as defineCommand41 } from "citty";
|
|
5408
|
+
import consola33 from "consola";
|
|
5182
5409
|
var DEFAULT_IDP_URL = "https://id.openape.at";
|
|
5183
5410
|
async function downloadTemplate(repo, targetDir) {
|
|
5184
5411
|
const { downloadTemplate: gigetDownload } = await import("giget");
|
|
5185
5412
|
await gigetDownload(`gh:${repo}`, { dir: targetDir, force: false });
|
|
5186
5413
|
}
|
|
5187
5414
|
function installDeps(dir) {
|
|
5188
|
-
const hasLockFile = (name) =>
|
|
5415
|
+
const hasLockFile = (name) => existsSync12(join11(dir, name));
|
|
5189
5416
|
if (hasLockFile("pnpm-lock.yaml")) {
|
|
5190
|
-
|
|
5417
|
+
execFileSync12("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
|
|
5191
5418
|
} else if (hasLockFile("bun.lockb")) {
|
|
5192
|
-
|
|
5419
|
+
execFileSync12("bun", ["install"], { cwd: dir, stdio: "inherit" });
|
|
5193
5420
|
} else {
|
|
5194
|
-
|
|
5421
|
+
execFileSync12("npm", ["install"], { cwd: dir, stdio: "inherit" });
|
|
5195
5422
|
}
|
|
5196
5423
|
}
|
|
5197
5424
|
async function promptChoice(message, choices) {
|
|
5198
|
-
const result = await
|
|
5425
|
+
const result = await consola33.prompt(message, { type: "select", options: choices });
|
|
5199
5426
|
if (typeof result === "symbol") {
|
|
5200
5427
|
throw new CliExit(0);
|
|
5201
5428
|
}
|
|
5202
5429
|
return result;
|
|
5203
5430
|
}
|
|
5204
5431
|
async function promptText(message, defaultValue) {
|
|
5205
|
-
const result = await
|
|
5432
|
+
const result = await consola33.prompt(message, { type: "text", default: defaultValue, placeholder: defaultValue });
|
|
5206
5433
|
if (typeof result === "symbol") {
|
|
5207
5434
|
throw new CliExit(0);
|
|
5208
5435
|
}
|
|
5209
5436
|
return result || defaultValue || "";
|
|
5210
5437
|
}
|
|
5211
|
-
var initCommand =
|
|
5438
|
+
var initCommand = defineCommand41({
|
|
5212
5439
|
meta: {
|
|
5213
5440
|
name: "init",
|
|
5214
5441
|
description: "Scaffold a new OpenApe project"
|
|
@@ -5250,23 +5477,23 @@ var initCommand = defineCommand37({
|
|
|
5250
5477
|
});
|
|
5251
5478
|
async function initSP(targetDir) {
|
|
5252
5479
|
const dir = targetDir || "my-app";
|
|
5253
|
-
if (
|
|
5480
|
+
if (existsSync12(join11(dir, "package.json"))) {
|
|
5254
5481
|
throw new CliError(`Directory "${dir}" already contains a project.`);
|
|
5255
5482
|
}
|
|
5256
|
-
|
|
5483
|
+
consola33.start("Scaffolding SP starter...");
|
|
5257
5484
|
await downloadTemplate("openape-ai/openape-sp-starter", dir);
|
|
5258
|
-
|
|
5259
|
-
|
|
5485
|
+
consola33.success("Scaffolded from openape-sp-starter");
|
|
5486
|
+
consola33.start("Installing dependencies...");
|
|
5260
5487
|
installDeps(dir);
|
|
5261
|
-
|
|
5262
|
-
const envExample =
|
|
5263
|
-
const envFile =
|
|
5264
|
-
if (
|
|
5488
|
+
consola33.success("Dependencies installed");
|
|
5489
|
+
const envExample = join11(dir, ".env.example");
|
|
5490
|
+
const envFile = join11(dir, ".env");
|
|
5491
|
+
if (existsSync12(envExample) && !existsSync12(envFile)) {
|
|
5265
5492
|
copyFileSync(envExample, envFile);
|
|
5266
|
-
|
|
5493
|
+
consola33.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
|
|
5267
5494
|
}
|
|
5268
5495
|
console.log("");
|
|
5269
|
-
|
|
5496
|
+
consola33.box([
|
|
5270
5497
|
`cd ${dir}`,
|
|
5271
5498
|
"npm run dev",
|
|
5272
5499
|
"",
|
|
@@ -5275,7 +5502,7 @@ async function initSP(targetDir) {
|
|
|
5275
5502
|
}
|
|
5276
5503
|
async function initIdP(targetDir) {
|
|
5277
5504
|
const dir = targetDir || "my-idp";
|
|
5278
|
-
if (
|
|
5505
|
+
if (existsSync12(join11(dir, "package.json"))) {
|
|
5279
5506
|
throw new CliError(`Directory "${dir}" already contains a project.`);
|
|
5280
5507
|
}
|
|
5281
5508
|
const domain = await promptText("Domain for the IdP", "localhost");
|
|
@@ -5285,15 +5512,15 @@ async function initIdP(targetDir) {
|
|
|
5285
5512
|
"s3 (S3-compatible)"
|
|
5286
5513
|
]);
|
|
5287
5514
|
const adminEmail = await promptText("Admin email");
|
|
5288
|
-
|
|
5515
|
+
consola33.start("Scaffolding IdP starter...");
|
|
5289
5516
|
await downloadTemplate("openape-ai/openape-idp-starter", dir);
|
|
5290
|
-
|
|
5291
|
-
|
|
5517
|
+
consola33.success("Scaffolded from openape-idp-starter");
|
|
5518
|
+
consola33.start("Installing dependencies...");
|
|
5292
5519
|
installDeps(dir);
|
|
5293
|
-
|
|
5520
|
+
consola33.success("Dependencies installed");
|
|
5294
5521
|
const sessionSecret = randomBytes(32).toString("hex");
|
|
5295
5522
|
const managementToken = randomBytes(32).toString("hex");
|
|
5296
|
-
|
|
5523
|
+
consola33.success("Secrets generated");
|
|
5297
5524
|
const isLocalhost = domain === "localhost";
|
|
5298
5525
|
const origin = isLocalhost ? "http://localhost:3000" : `https://${domain}`;
|
|
5299
5526
|
const envContent = [
|
|
@@ -5307,11 +5534,11 @@ async function initIdP(targetDir) {
|
|
|
5307
5534
|
`NUXT_OPENAPE_RP_ID=${domain}`,
|
|
5308
5535
|
`NUXT_OPENAPE_RP_ORIGIN=${origin}`
|
|
5309
5536
|
].join("\n");
|
|
5310
|
-
|
|
5537
|
+
writeFileSync8(join11(dir, ".env"), `${envContent}
|
|
5311
5538
|
`, { mode: 384 });
|
|
5312
|
-
|
|
5539
|
+
consola33.success(".env created");
|
|
5313
5540
|
console.log("");
|
|
5314
|
-
|
|
5541
|
+
consola33.box([
|
|
5315
5542
|
`cd ${dir}`,
|
|
5316
5543
|
"npm run dev",
|
|
5317
5544
|
"",
|
|
@@ -5328,11 +5555,11 @@ async function initIdP(targetDir) {
|
|
|
5328
5555
|
|
|
5329
5556
|
// src/commands/enroll.ts
|
|
5330
5557
|
import { Buffer as Buffer5 } from "buffer";
|
|
5331
|
-
import { existsSync as
|
|
5558
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11 } from "fs";
|
|
5332
5559
|
import { execFile as execFile2 } from "child_process";
|
|
5333
5560
|
import { sign as sign2 } from "crypto";
|
|
5334
|
-
import { defineCommand as
|
|
5335
|
-
import
|
|
5561
|
+
import { defineCommand as defineCommand42 } from "citty";
|
|
5562
|
+
import consola34 from "consola";
|
|
5336
5563
|
var DEFAULT_IDP_URL2 = "https://id.openape.at";
|
|
5337
5564
|
var DEFAULT_KEY_PATH = "~/.ssh/id_ed25519";
|
|
5338
5565
|
var POLL_INTERVAL = 3e3;
|
|
@@ -5344,7 +5571,7 @@ function openBrowser2(url) {
|
|
|
5344
5571
|
}
|
|
5345
5572
|
async function pollForEnrollment(idp, agentEmail, keyPath) {
|
|
5346
5573
|
const resolvedKey = resolveKeyPath(keyPath);
|
|
5347
|
-
const keyContent =
|
|
5574
|
+
const keyContent = readFileSync11(resolvedKey, "utf-8");
|
|
5348
5575
|
const privateKey = loadEd25519PrivateKey(keyContent);
|
|
5349
5576
|
const challengeUrl = await getAgentChallengeEndpoint(idp);
|
|
5350
5577
|
const authenticateUrl = await getAgentAuthenticateEndpoint(idp);
|
|
@@ -5375,7 +5602,7 @@ async function pollForEnrollment(idp, agentEmail, keyPath) {
|
|
|
5375
5602
|
}
|
|
5376
5603
|
throw new Error("Enrollment timed out. Please check the browser and try again.");
|
|
5377
5604
|
}
|
|
5378
|
-
var enrollCommand =
|
|
5605
|
+
var enrollCommand = defineCommand42({
|
|
5379
5606
|
meta: {
|
|
5380
5607
|
name: "enroll",
|
|
5381
5608
|
description: "Enroll an agent with an Identity Provider"
|
|
@@ -5395,38 +5622,38 @@ var enrollCommand = defineCommand38({
|
|
|
5395
5622
|
}
|
|
5396
5623
|
},
|
|
5397
5624
|
async run({ args }) {
|
|
5398
|
-
const idp = args.idp || await
|
|
5625
|
+
const idp = args.idp || await consola34.prompt("IdP URL", { type: "text", default: DEFAULT_IDP_URL2, placeholder: DEFAULT_IDP_URL2 }).then((r) => {
|
|
5399
5626
|
if (typeof r === "symbol") throw new CliExit(0);
|
|
5400
5627
|
return r;
|
|
5401
5628
|
}) || DEFAULT_IDP_URL2;
|
|
5402
|
-
const agentName = args.name || await
|
|
5629
|
+
const agentName = args.name || await consola34.prompt("Agent name", { type: "text", placeholder: "deploy-bot" }).then((r) => {
|
|
5403
5630
|
if (typeof r === "symbol") throw new CliExit(0);
|
|
5404
5631
|
return r;
|
|
5405
5632
|
});
|
|
5406
5633
|
if (!agentName) {
|
|
5407
5634
|
throw new CliError("Agent name is required.");
|
|
5408
5635
|
}
|
|
5409
|
-
const keyPath = args.key || await
|
|
5636
|
+
const keyPath = args.key || await consola34.prompt("Ed25519 key", { type: "text", default: DEFAULT_KEY_PATH, placeholder: DEFAULT_KEY_PATH }).then((r) => {
|
|
5410
5637
|
if (typeof r === "symbol") throw new CliExit(0);
|
|
5411
5638
|
return r;
|
|
5412
5639
|
}) || DEFAULT_KEY_PATH;
|
|
5413
5640
|
const resolvedKey = resolveKeyPath(keyPath);
|
|
5414
5641
|
let publicKey;
|
|
5415
|
-
if (
|
|
5642
|
+
if (existsSync13(resolvedKey)) {
|
|
5416
5643
|
publicKey = readPublicKey(resolvedKey);
|
|
5417
|
-
|
|
5644
|
+
consola34.success(`Using existing key ${keyPath}`);
|
|
5418
5645
|
} else {
|
|
5419
|
-
|
|
5646
|
+
consola34.start(`Generating Ed25519 key pair at ${keyPath}...`);
|
|
5420
5647
|
publicKey = generateAndSaveKey(keyPath);
|
|
5421
|
-
|
|
5648
|
+
consola34.success(`Key pair generated at ${keyPath}`);
|
|
5422
5649
|
}
|
|
5423
5650
|
const encodedKey = encodeURIComponent(publicKey);
|
|
5424
5651
|
const enrollUrl = `${idp}/enroll?name=${encodeURIComponent(agentName)}&key=${encodedKey}`;
|
|
5425
|
-
|
|
5426
|
-
|
|
5652
|
+
consola34.info("Opening browser for enrollment...");
|
|
5653
|
+
consola34.info(`\u2192 ${idp}/enroll`);
|
|
5427
5654
|
openBrowser2(enrollUrl);
|
|
5428
5655
|
console.log("");
|
|
5429
|
-
const agentEmail = await
|
|
5656
|
+
const agentEmail = await consola34.prompt(
|
|
5430
5657
|
"Agent email (shown in browser after enrollment)",
|
|
5431
5658
|
{ type: "text", placeholder: `agent+${agentName}@...` }
|
|
5432
5659
|
).then((r) => {
|
|
@@ -5436,7 +5663,7 @@ var enrollCommand = defineCommand38({
|
|
|
5436
5663
|
if (!agentEmail) {
|
|
5437
5664
|
throw new CliError("Agent email is required to verify enrollment.");
|
|
5438
5665
|
}
|
|
5439
|
-
|
|
5666
|
+
consola34.start("Verifying enrollment...");
|
|
5440
5667
|
const { token, expiresIn } = await pollForEnrollment(idp, agentEmail, keyPath);
|
|
5441
5668
|
saveAuth({
|
|
5442
5669
|
idp,
|
|
@@ -5448,18 +5675,18 @@ var enrollCommand = defineCommand38({
|
|
|
5448
5675
|
config.defaults = { ...config.defaults, idp };
|
|
5449
5676
|
config.agent = { key: keyPath, email: agentEmail };
|
|
5450
5677
|
saveConfig(config);
|
|
5451
|
-
|
|
5452
|
-
|
|
5678
|
+
consola34.success(`Agent enrolled as ${agentEmail}`);
|
|
5679
|
+
consola34.success("Config saved to ~/.config/apes/");
|
|
5453
5680
|
console.log("");
|
|
5454
|
-
|
|
5681
|
+
consola34.info("Verify with: apes whoami");
|
|
5455
5682
|
}
|
|
5456
5683
|
});
|
|
5457
5684
|
|
|
5458
5685
|
// src/commands/register-user.ts
|
|
5459
|
-
import { existsSync as
|
|
5460
|
-
import { defineCommand as
|
|
5461
|
-
import
|
|
5462
|
-
var registerUserCommand =
|
|
5686
|
+
import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
|
|
5687
|
+
import { defineCommand as defineCommand43 } from "citty";
|
|
5688
|
+
import consola35 from "consola";
|
|
5689
|
+
var registerUserCommand = defineCommand43({
|
|
5463
5690
|
meta: {
|
|
5464
5691
|
name: "register-user",
|
|
5465
5692
|
description: "Register a sub-user with SSH key"
|
|
@@ -5495,8 +5722,8 @@ var registerUserCommand = defineCommand39({
|
|
|
5495
5722
|
throw new CliError("No IdP URL configured. Run `apes login` first.");
|
|
5496
5723
|
}
|
|
5497
5724
|
let publicKey = args.key;
|
|
5498
|
-
if (
|
|
5499
|
-
publicKey =
|
|
5725
|
+
if (existsSync14(args.key)) {
|
|
5726
|
+
publicKey = readFileSync12(args.key, "utf-8").trim();
|
|
5500
5727
|
}
|
|
5501
5728
|
if (!publicKey.startsWith("ssh-ed25519 ")) {
|
|
5502
5729
|
throw new CliError("Public key must be in ssh-ed25519 format.");
|
|
@@ -5514,18 +5741,18 @@ var registerUserCommand = defineCommand39({
|
|
|
5514
5741
|
...userType ? { type: userType } : {}
|
|
5515
5742
|
}
|
|
5516
5743
|
});
|
|
5517
|
-
|
|
5744
|
+
consola35.success(`User registered: ${result.email} (type: ${result.type}, owner: ${result.owner})`);
|
|
5518
5745
|
}
|
|
5519
5746
|
});
|
|
5520
5747
|
|
|
5521
5748
|
// src/commands/utils/index.ts
|
|
5522
|
-
import { defineCommand as
|
|
5749
|
+
import { defineCommand as defineCommand45 } from "citty";
|
|
5523
5750
|
|
|
5524
5751
|
// src/commands/utils/dig.ts
|
|
5525
|
-
import { defineCommand as
|
|
5526
|
-
import
|
|
5752
|
+
import { defineCommand as defineCommand44 } from "citty";
|
|
5753
|
+
import consola36 from "consola";
|
|
5527
5754
|
import { resolveDDISA as resolveDDISA2 } from "@openape/core";
|
|
5528
|
-
var digCommand =
|
|
5755
|
+
var digCommand = defineCommand44({
|
|
5529
5756
|
meta: {
|
|
5530
5757
|
name: "dig",
|
|
5531
5758
|
description: "Resolve DDISA IdP for a domain or email (admin/diag tool)"
|
|
@@ -5598,12 +5825,12 @@ var digCommand = defineCommand40({
|
|
|
5598
5825
|
console.log(` domain: ${domain}`);
|
|
5599
5826
|
console.log("");
|
|
5600
5827
|
if (!result.ddisa.found) {
|
|
5601
|
-
|
|
5828
|
+
consola36.warn(`No DDISA record at _ddisa.${domain}`);
|
|
5602
5829
|
if (result.hint) console.log(`
|
|
5603
5830
|
${result.hint}`);
|
|
5604
5831
|
throw new CliError(`No DDISA record found for ${domain}`);
|
|
5605
5832
|
}
|
|
5606
|
-
|
|
5833
|
+
consola36.success(`_ddisa.${domain} \u2192 ${result.ddisa.idp}`);
|
|
5607
5834
|
console.log(` Version: ${result.ddisa.version || "ddisa1"}`);
|
|
5608
5835
|
console.log(` IdP URL: ${result.ddisa.idp}`);
|
|
5609
5836
|
if (result.ddisa.mode) console.log(` Mode: ${result.ddisa.mode}`);
|
|
@@ -5613,13 +5840,13 @@ ${result.hint}`);
|
|
|
5613
5840
|
return;
|
|
5614
5841
|
}
|
|
5615
5842
|
if (result.idpDiscovery.ok) {
|
|
5616
|
-
|
|
5843
|
+
consola36.success(`IdP reachable (${result.idpDiscovery.status ?? 200})`);
|
|
5617
5844
|
if (result.idpDiscovery.issuer) console.log(` Issuer: ${result.idpDiscovery.issuer}`);
|
|
5618
5845
|
if (result.idpDiscovery.ddisaVersion) console.log(` DDISA: v${result.idpDiscovery.ddisaVersion}`);
|
|
5619
5846
|
if (result.idpDiscovery.authMethods?.length) console.log(` Auth: ${result.idpDiscovery.authMethods.join(", ")}`);
|
|
5620
5847
|
if (result.idpDiscovery.grantTypes?.length) console.log(` Grants: ${result.idpDiscovery.grantTypes.join(", ")}`);
|
|
5621
5848
|
} else {
|
|
5622
|
-
|
|
5849
|
+
consola36.warn(`IdP discovery failed${result.idpDiscovery.status ? ` (HTTP ${result.idpDiscovery.status})` : ""}`);
|
|
5623
5850
|
if (result.hint) console.log(`
|
|
5624
5851
|
${result.hint}`);
|
|
5625
5852
|
throw new CliError(`IdP at ${result.ddisa.idp} not reachable`);
|
|
@@ -5628,7 +5855,7 @@ ${result.hint}`);
|
|
|
5628
5855
|
});
|
|
5629
5856
|
|
|
5630
5857
|
// src/commands/utils/index.ts
|
|
5631
|
-
var utilsCommand =
|
|
5858
|
+
var utilsCommand = defineCommand45({
|
|
5632
5859
|
meta: {
|
|
5633
5860
|
name: "utils",
|
|
5634
5861
|
description: "Admin/diagnostic utilities (dig, \u2026)"
|
|
@@ -5639,12 +5866,12 @@ var utilsCommand = defineCommand41({
|
|
|
5639
5866
|
});
|
|
5640
5867
|
|
|
5641
5868
|
// src/commands/sessions/index.ts
|
|
5642
|
-
import { defineCommand as
|
|
5869
|
+
import { defineCommand as defineCommand48 } from "citty";
|
|
5643
5870
|
|
|
5644
5871
|
// src/commands/sessions/list.ts
|
|
5645
|
-
import { defineCommand as
|
|
5646
|
-
import
|
|
5647
|
-
var sessionsListCommand =
|
|
5872
|
+
import { defineCommand as defineCommand46 } from "citty";
|
|
5873
|
+
import consola37 from "consola";
|
|
5874
|
+
var sessionsListCommand = defineCommand46({
|
|
5648
5875
|
meta: {
|
|
5649
5876
|
name: "list",
|
|
5650
5877
|
description: "List your active refresh-token families (one per logged-in device)."
|
|
@@ -5662,7 +5889,7 @@ var sessionsListCommand = defineCommand42({
|
|
|
5662
5889
|
return;
|
|
5663
5890
|
}
|
|
5664
5891
|
if (result.data.length === 0) {
|
|
5665
|
-
|
|
5892
|
+
consola37.info("No active sessions.");
|
|
5666
5893
|
return;
|
|
5667
5894
|
}
|
|
5668
5895
|
for (const f of result.data) {
|
|
@@ -5674,9 +5901,9 @@ var sessionsListCommand = defineCommand42({
|
|
|
5674
5901
|
});
|
|
5675
5902
|
|
|
5676
5903
|
// src/commands/sessions/remove.ts
|
|
5677
|
-
import { defineCommand as
|
|
5678
|
-
import
|
|
5679
|
-
var sessionsRemoveCommand =
|
|
5904
|
+
import { defineCommand as defineCommand47 } from "citty";
|
|
5905
|
+
import consola38 from "consola";
|
|
5906
|
+
var sessionsRemoveCommand = defineCommand47({
|
|
5680
5907
|
meta: {
|
|
5681
5908
|
name: "remove",
|
|
5682
5909
|
description: "Revoke one of your active refresh-token families by id."
|
|
@@ -5692,12 +5919,12 @@ var sessionsRemoveCommand = defineCommand43({
|
|
|
5692
5919
|
const id = String(args.familyId).trim();
|
|
5693
5920
|
if (!id) throw new CliError("familyId required");
|
|
5694
5921
|
await apiFetch(`/api/me/sessions/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
5695
|
-
|
|
5922
|
+
consola38.success(`Session ${id} revoked. The device using it will need to \`apes login\` again on its next refresh.`);
|
|
5696
5923
|
}
|
|
5697
5924
|
});
|
|
5698
5925
|
|
|
5699
5926
|
// src/commands/sessions/index.ts
|
|
5700
|
-
var sessionsCommand =
|
|
5927
|
+
var sessionsCommand = defineCommand48({
|
|
5701
5928
|
meta: {
|
|
5702
5929
|
name: "sessions",
|
|
5703
5930
|
description: "Manage your active refresh-token sessions across devices"
|
|
@@ -5709,10 +5936,10 @@ var sessionsCommand = defineCommand44({
|
|
|
5709
5936
|
});
|
|
5710
5937
|
|
|
5711
5938
|
// src/commands/dns-check.ts
|
|
5712
|
-
import { defineCommand as
|
|
5713
|
-
import
|
|
5939
|
+
import { defineCommand as defineCommand49 } from "citty";
|
|
5940
|
+
import consola39 from "consola";
|
|
5714
5941
|
import { resolveDDISA as resolveDDISA3 } from "@openape/core";
|
|
5715
|
-
var dnsCheckCommand =
|
|
5942
|
+
var dnsCheckCommand = defineCommand49({
|
|
5716
5943
|
meta: {
|
|
5717
5944
|
name: "dns-check",
|
|
5718
5945
|
description: "Validate DDISA DNS TXT records for a domain"
|
|
@@ -5726,7 +5953,7 @@ var dnsCheckCommand = defineCommand45({
|
|
|
5726
5953
|
},
|
|
5727
5954
|
async run({ args }) {
|
|
5728
5955
|
const domain = args.domain;
|
|
5729
|
-
|
|
5956
|
+
consola39.start(`Checking _ddisa.${domain}...`);
|
|
5730
5957
|
try {
|
|
5731
5958
|
const result = await resolveDDISA3(domain);
|
|
5732
5959
|
if (!result) {
|
|
@@ -5735,7 +5962,7 @@ var dnsCheckCommand = defineCommand45({
|
|
|
5735
5962
|
console.log(` _ddisa.${domain} TXT "v=ddisa1 idp=https://id.${domain}"`);
|
|
5736
5963
|
throw new CliError(`No DDISA record found for ${domain}`);
|
|
5737
5964
|
}
|
|
5738
|
-
|
|
5965
|
+
consola39.success(`_ddisa.${domain} \u2192 ${result.idp}`);
|
|
5739
5966
|
console.log("");
|
|
5740
5967
|
console.log(` Version: ${result.version || "ddisa1"}`);
|
|
5741
5968
|
console.log(` IdP URL: ${result.idp}`);
|
|
@@ -5744,14 +5971,14 @@ var dnsCheckCommand = defineCommand45({
|
|
|
5744
5971
|
if (result.priority !== void 0)
|
|
5745
5972
|
console.log(` Priority: ${result.priority}`);
|
|
5746
5973
|
console.log("");
|
|
5747
|
-
|
|
5974
|
+
consola39.start(`Verifying IdP at ${result.idp}...`);
|
|
5748
5975
|
const discoResp = await fetch(`${result.idp}/.well-known/openid-configuration`);
|
|
5749
5976
|
if (!discoResp.ok) {
|
|
5750
|
-
|
|
5977
|
+
consola39.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
|
|
5751
5978
|
return;
|
|
5752
5979
|
}
|
|
5753
5980
|
const disco = await discoResp.json();
|
|
5754
|
-
|
|
5981
|
+
consola39.success(`IdP is reachable`);
|
|
5755
5982
|
console.log(` Issuer: ${disco.issuer}`);
|
|
5756
5983
|
console.log(` DDISA: v${disco.ddisa_version || "?"}`);
|
|
5757
5984
|
if (disco.ddisa_auth_methods_supported) {
|
|
@@ -5769,7 +5996,7 @@ var dnsCheckCommand = defineCommand45({
|
|
|
5769
5996
|
// src/commands/health.ts
|
|
5770
5997
|
import { exec } from "child_process";
|
|
5771
5998
|
import { promisify } from "util";
|
|
5772
|
-
import { defineCommand as
|
|
5999
|
+
import { defineCommand as defineCommand50 } from "citty";
|
|
5773
6000
|
var execAsync = promisify(exec);
|
|
5774
6001
|
async function resolveApeShellPath() {
|
|
5775
6002
|
try {
|
|
@@ -5805,7 +6032,7 @@ async function bestEffortGrantCount(idp) {
|
|
|
5805
6032
|
}
|
|
5806
6033
|
}
|
|
5807
6034
|
async function runHealth(args) {
|
|
5808
|
-
const version = true ? "1.
|
|
6035
|
+
const version = true ? "1.4.0" : "0.0.0";
|
|
5809
6036
|
const auth = loadAuth();
|
|
5810
6037
|
if (!auth) {
|
|
5811
6038
|
throw new CliError("Not logged in. Run `apes login` first.", 1);
|
|
@@ -5868,7 +6095,7 @@ async function runHealth(args) {
|
|
|
5868
6095
|
throw new CliError(`IdP ${auth.idp} unreachable: ${idpProbe.error}`, 1);
|
|
5869
6096
|
}
|
|
5870
6097
|
}
|
|
5871
|
-
var healthCommand =
|
|
6098
|
+
var healthCommand = defineCommand50({
|
|
5872
6099
|
meta: {
|
|
5873
6100
|
name: "health",
|
|
5874
6101
|
description: "Report CLI diagnostic state (auth, IdP, grants, binaries)"
|
|
@@ -5886,8 +6113,8 @@ var healthCommand = defineCommand46({
|
|
|
5886
6113
|
});
|
|
5887
6114
|
|
|
5888
6115
|
// src/commands/workflows.ts
|
|
5889
|
-
import { defineCommand as
|
|
5890
|
-
import
|
|
6116
|
+
import { defineCommand as defineCommand51 } from "citty";
|
|
6117
|
+
import consola40 from "consola";
|
|
5891
6118
|
|
|
5892
6119
|
// src/guides/index.ts
|
|
5893
6120
|
var guides = [
|
|
@@ -5937,7 +6164,7 @@ var guides = [
|
|
|
5937
6164
|
];
|
|
5938
6165
|
|
|
5939
6166
|
// src/commands/workflows.ts
|
|
5940
|
-
var workflowsCommand =
|
|
6167
|
+
var workflowsCommand = defineCommand51({
|
|
5941
6168
|
meta: {
|
|
5942
6169
|
name: "workflows",
|
|
5943
6170
|
description: "Discover workflow guides"
|
|
@@ -5958,7 +6185,7 @@ var workflowsCommand = defineCommand47({
|
|
|
5958
6185
|
if (args.id) {
|
|
5959
6186
|
const guide = guides.find((g) => g.id === String(args.id));
|
|
5960
6187
|
if (!guide) {
|
|
5961
|
-
|
|
6188
|
+
consola40.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
|
|
5962
6189
|
throw new CliError(`Guide not found: ${args.id}`);
|
|
5963
6190
|
}
|
|
5964
6191
|
if (args.json) {
|
|
@@ -5998,26 +6225,26 @@ var workflowsCommand = defineCommand47({
|
|
|
5998
6225
|
});
|
|
5999
6226
|
|
|
6000
6227
|
// src/version-check.ts
|
|
6001
|
-
import { existsSync as
|
|
6002
|
-
import { homedir as
|
|
6003
|
-
import { join as
|
|
6004
|
-
import
|
|
6228
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "fs";
|
|
6229
|
+
import { homedir as homedir12 } from "os";
|
|
6230
|
+
import { join as join12 } from "path";
|
|
6231
|
+
import consola41 from "consola";
|
|
6005
6232
|
var PACKAGE_NAME = "@openape/apes";
|
|
6006
6233
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
6007
|
-
var CACHE_FILE =
|
|
6234
|
+
var CACHE_FILE = join12(homedir12(), ".config", "apes", ".version-check.json");
|
|
6008
6235
|
function readCache() {
|
|
6009
|
-
if (!
|
|
6236
|
+
if (!existsSync15(CACHE_FILE)) return null;
|
|
6010
6237
|
try {
|
|
6011
|
-
return JSON.parse(
|
|
6238
|
+
return JSON.parse(readFileSync13(CACHE_FILE, "utf-8"));
|
|
6012
6239
|
} catch {
|
|
6013
6240
|
return null;
|
|
6014
6241
|
}
|
|
6015
6242
|
}
|
|
6016
6243
|
function writeCache(entry) {
|
|
6017
6244
|
try {
|
|
6018
|
-
const dir =
|
|
6019
|
-
if (!
|
|
6020
|
-
|
|
6245
|
+
const dir = join12(homedir12(), ".config", "apes");
|
|
6246
|
+
if (!existsSync15(dir)) mkdirSync5(dir, { recursive: true, mode: 448 });
|
|
6247
|
+
writeFileSync9(CACHE_FILE, JSON.stringify(entry), { mode: 384 });
|
|
6021
6248
|
} catch {
|
|
6022
6249
|
}
|
|
6023
6250
|
}
|
|
@@ -6046,7 +6273,7 @@ async function fetchLatestVersion() {
|
|
|
6046
6273
|
}
|
|
6047
6274
|
function warnIfBehind(currentVersion, latest) {
|
|
6048
6275
|
if (compareSemver(currentVersion, latest) < 0) {
|
|
6049
|
-
|
|
6276
|
+
consola41.warn(
|
|
6050
6277
|
`apes ${currentVersion} is behind latest @openape/apes@${latest}. Run \`npm i -g @openape/apes@latest\` to update. (Suppress with APES_NO_UPDATE_CHECK=1.)`
|
|
6051
6278
|
);
|
|
6052
6279
|
}
|
|
@@ -6078,10 +6305,10 @@ if (shellRewrite) {
|
|
|
6078
6305
|
if (shellRewrite.action === "rewrite") {
|
|
6079
6306
|
process.argv = shellRewrite.argv;
|
|
6080
6307
|
} else if (shellRewrite.action === "version") {
|
|
6081
|
-
console.log(`ape-shell ${"1.
|
|
6308
|
+
console.log(`ape-shell ${"1.4.0"} (OpenApe DDISA shell wrapper)`);
|
|
6082
6309
|
process.exit(0);
|
|
6083
6310
|
} else if (shellRewrite.action === "help") {
|
|
6084
|
-
console.log(`ape-shell ${"1.
|
|
6311
|
+
console.log(`ape-shell ${"1.4.0"} \u2014 OpenApe DDISA shell wrapper`);
|
|
6085
6312
|
console.log("");
|
|
6086
6313
|
console.log("Usage:");
|
|
6087
6314
|
console.log(" ape-shell Start interactive grant-mediated REPL");
|
|
@@ -6105,7 +6332,7 @@ if (shellRewrite) {
|
|
|
6105
6332
|
}
|
|
6106
6333
|
}
|
|
6107
6334
|
var debug = process.argv.includes("--debug");
|
|
6108
|
-
var grantsCommand =
|
|
6335
|
+
var grantsCommand = defineCommand52({
|
|
6109
6336
|
meta: {
|
|
6110
6337
|
name: "grants",
|
|
6111
6338
|
description: "Grant management"
|
|
@@ -6126,7 +6353,7 @@ var grantsCommand = defineCommand48({
|
|
|
6126
6353
|
"delegation-revoke": delegationRevokeCommand
|
|
6127
6354
|
}
|
|
6128
6355
|
});
|
|
6129
|
-
var configCommand =
|
|
6356
|
+
var configCommand = defineCommand52({
|
|
6130
6357
|
meta: {
|
|
6131
6358
|
name: "config",
|
|
6132
6359
|
description: "Configuration management"
|
|
@@ -6136,10 +6363,10 @@ var configCommand = defineCommand48({
|
|
|
6136
6363
|
set: configSetCommand
|
|
6137
6364
|
}
|
|
6138
6365
|
});
|
|
6139
|
-
var main =
|
|
6366
|
+
var main = defineCommand52({
|
|
6140
6367
|
meta: {
|
|
6141
6368
|
name: "apes",
|
|
6142
|
-
version: "1.
|
|
6369
|
+
version: "1.4.0",
|
|
6143
6370
|
description: "Unified CLI for OpenApe"
|
|
6144
6371
|
},
|
|
6145
6372
|
subCommands: {
|
|
@@ -6155,6 +6382,7 @@ var main = defineCommand48({
|
|
|
6155
6382
|
health: healthCommand,
|
|
6156
6383
|
grants: grantsCommand,
|
|
6157
6384
|
agents: agentsCommand,
|
|
6385
|
+
nest: nestCommand,
|
|
6158
6386
|
admin: adminCommand,
|
|
6159
6387
|
run: runCommand,
|
|
6160
6388
|
proxy: proxyCommand,
|
|
@@ -6194,20 +6422,20 @@ async function maybeRefreshAuth() {
|
|
|
6194
6422
|
}
|
|
6195
6423
|
}
|
|
6196
6424
|
await maybeRefreshAuth();
|
|
6197
|
-
await maybeWarnStaleVersion("1.
|
|
6425
|
+
await maybeWarnStaleVersion("1.4.0").catch(() => {
|
|
6198
6426
|
});
|
|
6199
6427
|
runMain(main).catch((err) => {
|
|
6200
6428
|
if (err instanceof CliExit) {
|
|
6201
6429
|
process.exit(err.exitCode);
|
|
6202
6430
|
}
|
|
6203
6431
|
if (err instanceof CliError) {
|
|
6204
|
-
|
|
6432
|
+
consola42.error(err.message);
|
|
6205
6433
|
process.exit(err.exitCode);
|
|
6206
6434
|
}
|
|
6207
6435
|
if (debug) {
|
|
6208
|
-
|
|
6436
|
+
consola42.error(err);
|
|
6209
6437
|
} else {
|
|
6210
|
-
|
|
6438
|
+
consola42.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
|
|
6211
6439
|
}
|
|
6212
6440
|
process.exit(1);
|
|
6213
6441
|
});
|