@openape/apes 1.3.1 → 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);
|
|
@@ -3917,16 +3917,232 @@ var agentsCommand = defineCommand28({
|
|
|
3917
3917
|
}
|
|
3918
3918
|
});
|
|
3919
3919
|
|
|
3920
|
-
// 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";
|
|
3921
3928
|
import { defineCommand as defineCommand29 } from "citty";
|
|
3922
3929
|
import consola25 from "consola";
|
|
3923
|
-
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({
|
|
3924
4140
|
meta: {
|
|
3925
4141
|
name: "adapter",
|
|
3926
4142
|
description: "Manage CLI adapters"
|
|
3927
4143
|
},
|
|
3928
4144
|
subCommands: {
|
|
3929
|
-
list:
|
|
4145
|
+
list: defineCommand33({
|
|
3930
4146
|
meta: {
|
|
3931
4147
|
name: "list",
|
|
3932
4148
|
description: "List available adapters"
|
|
@@ -3957,7 +4173,7 @@ var adapterCommand = defineCommand29({
|
|
|
3957
4173
|
`);
|
|
3958
4174
|
return;
|
|
3959
4175
|
}
|
|
3960
|
-
|
|
4176
|
+
consola28.info(`Registry: ${index2.adapters.length} adapters (${index2.generated_at})`);
|
|
3961
4177
|
for (const a of index2.adapters) {
|
|
3962
4178
|
const installed = isInstalled(a.id, false) ? " [installed]" : "";
|
|
3963
4179
|
console.log(` ${a.id.padEnd(12)} ${a.name.padEnd(24)} ${a.category}${installed}`);
|
|
@@ -3979,7 +4195,7 @@ var adapterCommand = defineCommand29({
|
|
|
3979
4195
|
return;
|
|
3980
4196
|
}
|
|
3981
4197
|
if (local.length === 0) {
|
|
3982
|
-
|
|
4198
|
+
consola28.info("No adapters installed. Use `apes adapter list --remote` to see available adapters.");
|
|
3983
4199
|
return;
|
|
3984
4200
|
}
|
|
3985
4201
|
for (const a of local) {
|
|
@@ -3987,7 +4203,7 @@ var adapterCommand = defineCommand29({
|
|
|
3987
4203
|
}
|
|
3988
4204
|
}
|
|
3989
4205
|
}),
|
|
3990
|
-
install:
|
|
4206
|
+
install: defineCommand33({
|
|
3991
4207
|
meta: {
|
|
3992
4208
|
name: "install",
|
|
3993
4209
|
description: "Install an adapter from the registry"
|
|
@@ -4016,24 +4232,24 @@ var adapterCommand = defineCommand29({
|
|
|
4016
4232
|
for (const id of ids) {
|
|
4017
4233
|
const entry = findAdapter(index, id);
|
|
4018
4234
|
if (!entry) {
|
|
4019
|
-
|
|
4235
|
+
consola28.error(`Adapter "${id}" not found in registry. Use \`apes adapter search ${id}\` to search.`);
|
|
4020
4236
|
continue;
|
|
4021
4237
|
}
|
|
4022
4238
|
const conflicts = findConflictingAdapters(entry.executable, id);
|
|
4023
4239
|
if (conflicts.length > 0) {
|
|
4024
4240
|
for (const c of conflicts) {
|
|
4025
|
-
|
|
4026
|
-
|
|
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}`);
|
|
4027
4243
|
}
|
|
4028
4244
|
}
|
|
4029
4245
|
const result = await installAdapter(entry, { local });
|
|
4030
4246
|
const verb = result.updated ? "Updated" : "Installed";
|
|
4031
|
-
|
|
4032
|
-
|
|
4247
|
+
consola28.success(`${verb} ${result.id} \u2192 ${result.path}`);
|
|
4248
|
+
consola28.info(`Digest: ${result.digest}`);
|
|
4033
4249
|
}
|
|
4034
4250
|
}
|
|
4035
4251
|
}),
|
|
4036
|
-
remove:
|
|
4252
|
+
remove: defineCommand33({
|
|
4037
4253
|
meta: {
|
|
4038
4254
|
name: "remove",
|
|
4039
4255
|
description: "Remove an installed adapter"
|
|
@@ -4056,9 +4272,9 @@ var adapterCommand = defineCommand29({
|
|
|
4056
4272
|
let failed = false;
|
|
4057
4273
|
for (const id of ids) {
|
|
4058
4274
|
if (removeAdapter(id, local)) {
|
|
4059
|
-
|
|
4275
|
+
consola28.success(`Removed adapter: ${id}`);
|
|
4060
4276
|
} else {
|
|
4061
|
-
|
|
4277
|
+
consola28.error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
|
|
4062
4278
|
failed = true;
|
|
4063
4279
|
}
|
|
4064
4280
|
}
|
|
@@ -4066,7 +4282,7 @@ var adapterCommand = defineCommand29({
|
|
|
4066
4282
|
throw new CliError("Some adapters could not be removed");
|
|
4067
4283
|
}
|
|
4068
4284
|
}),
|
|
4069
|
-
info:
|
|
4285
|
+
info: defineCommand33({
|
|
4070
4286
|
meta: {
|
|
4071
4287
|
name: "info",
|
|
4072
4288
|
description: "Show detailed adapter information"
|
|
@@ -4108,7 +4324,7 @@ var adapterCommand = defineCommand29({
|
|
|
4108
4324
|
}
|
|
4109
4325
|
}
|
|
4110
4326
|
}),
|
|
4111
|
-
search:
|
|
4327
|
+
search: defineCommand33({
|
|
4112
4328
|
meta: {
|
|
4113
4329
|
name: "search",
|
|
4114
4330
|
description: "Search adapters in the registry"
|
|
@@ -4140,7 +4356,7 @@ var adapterCommand = defineCommand29({
|
|
|
4140
4356
|
return;
|
|
4141
4357
|
}
|
|
4142
4358
|
if (results.length === 0) {
|
|
4143
|
-
|
|
4359
|
+
consola28.info(`No adapters matching "${query}"`);
|
|
4144
4360
|
return;
|
|
4145
4361
|
}
|
|
4146
4362
|
for (const a of results) {
|
|
@@ -4149,7 +4365,7 @@ var adapterCommand = defineCommand29({
|
|
|
4149
4365
|
}
|
|
4150
4366
|
}
|
|
4151
4367
|
}),
|
|
4152
|
-
update:
|
|
4368
|
+
update: defineCommand33({
|
|
4153
4369
|
meta: {
|
|
4154
4370
|
name: "update",
|
|
4155
4371
|
description: "Update installed adapters"
|
|
@@ -4175,33 +4391,33 @@ var adapterCommand = defineCommand29({
|
|
|
4175
4391
|
const targetId = args.id ? String(args.id) : void 0;
|
|
4176
4392
|
const targets = targetId ? [targetId] : index.adapters.map((a) => a.id).filter((id) => isInstalled(id, false));
|
|
4177
4393
|
if (targets.length === 0) {
|
|
4178
|
-
|
|
4394
|
+
consola28.info("No adapters installed to update.");
|
|
4179
4395
|
return;
|
|
4180
4396
|
}
|
|
4181
4397
|
for (const id of targets) {
|
|
4182
4398
|
const entry = findAdapter(index, id);
|
|
4183
4399
|
if (!entry) {
|
|
4184
|
-
|
|
4400
|
+
consola28.warn(`${id}: not found in registry, skipping`);
|
|
4185
4401
|
continue;
|
|
4186
4402
|
}
|
|
4187
4403
|
const localDigest = getInstalledDigest(id, false);
|
|
4188
4404
|
if (localDigest === entry.digest) {
|
|
4189
|
-
|
|
4405
|
+
consola28.info(`${id}: already up to date`);
|
|
4190
4406
|
continue;
|
|
4191
4407
|
}
|
|
4192
4408
|
if (localDigest && !args.yes) {
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
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");
|
|
4197
4413
|
continue;
|
|
4198
4414
|
}
|
|
4199
4415
|
const result = await installAdapter(entry);
|
|
4200
|
-
|
|
4416
|
+
consola28.success(`Updated ${result.id} \u2192 ${result.path}`);
|
|
4201
4417
|
}
|
|
4202
4418
|
}
|
|
4203
4419
|
}),
|
|
4204
|
-
verify:
|
|
4420
|
+
verify: defineCommand33({
|
|
4205
4421
|
meta: {
|
|
4206
4422
|
name: "verify",
|
|
4207
4423
|
description: "Verify installed adapter against registry digest"
|
|
@@ -4234,7 +4450,7 @@ var adapterCommand = defineCommand29({
|
|
|
4234
4450
|
if (!localDigest)
|
|
4235
4451
|
throw new Error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
|
|
4236
4452
|
if (localDigest === entry.digest) {
|
|
4237
|
-
|
|
4453
|
+
consola28.success(`${id}: digest matches registry`);
|
|
4238
4454
|
} else {
|
|
4239
4455
|
console.log(` Local: ${localDigest}`);
|
|
4240
4456
|
console.log(` Registry: ${entry.digest}`);
|
|
@@ -4246,11 +4462,11 @@ var adapterCommand = defineCommand29({
|
|
|
4246
4462
|
});
|
|
4247
4463
|
|
|
4248
4464
|
// src/commands/run.ts
|
|
4249
|
-
import { execFileSync as
|
|
4465
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
4250
4466
|
import { hostname as hostname4 } from "os";
|
|
4251
4467
|
import { basename } from "path";
|
|
4252
|
-
import { defineCommand as
|
|
4253
|
-
import
|
|
4468
|
+
import { defineCommand as defineCommand34 } from "citty";
|
|
4469
|
+
import consola29 from "consola";
|
|
4254
4470
|
function shouldWaitForGrant(args) {
|
|
4255
4471
|
return args.wait === true || process.env.APE_WAIT === "1";
|
|
4256
4472
|
}
|
|
@@ -4287,7 +4503,7 @@ function printPendingGrantInfo(grant, idp) {
|
|
|
4287
4503
|
const statusCmd = `apes grants status ${grant.id}`;
|
|
4288
4504
|
const executeCmd = `apes grants run ${grant.id}`;
|
|
4289
4505
|
if (mode === "human") {
|
|
4290
|
-
|
|
4506
|
+
consola29.success(`Grant ${grant.id} created \u2014 awaiting your approval`);
|
|
4291
4507
|
console.log(` Approve in browser: ${approveUrl}`);
|
|
4292
4508
|
console.log(` Check status: ${statusCmd}`);
|
|
4293
4509
|
console.log(` Run after approval: ${executeCmd}`);
|
|
@@ -4297,7 +4513,7 @@ function printPendingGrantInfo(grant, idp) {
|
|
|
4297
4513
|
return;
|
|
4298
4514
|
}
|
|
4299
4515
|
const maxMin = getPollMaxMinutes();
|
|
4300
|
-
|
|
4516
|
+
consola29.success(`Grant ${grant.id} created (pending approval)`);
|
|
4301
4517
|
console.log(` Approve: ${approveUrl}`);
|
|
4302
4518
|
console.log(` Status: ${statusCmd} [--json]`);
|
|
4303
4519
|
console.log(` Execute: ${executeCmd} --wait`);
|
|
@@ -4319,7 +4535,7 @@ function printPendingGrantInfo(grant, idp) {
|
|
|
4319
4535
|
console.log(' Tip: Approve as "timed" or "always" in the browser to let this');
|
|
4320
4536
|
console.log(" grant be reused on subsequent invocations without re-approval.");
|
|
4321
4537
|
}
|
|
4322
|
-
var runCommand =
|
|
4538
|
+
var runCommand = defineCommand34({
|
|
4323
4539
|
meta: {
|
|
4324
4540
|
name: "run",
|
|
4325
4541
|
description: "Execute a grant-secured command"
|
|
@@ -4422,7 +4638,7 @@ async function runShellMode(command, args) {
|
|
|
4422
4638
|
}
|
|
4423
4639
|
} catch {
|
|
4424
4640
|
}
|
|
4425
|
-
|
|
4641
|
+
consola29.info(`Requesting ape-shell session grant on ${targetHost}`);
|
|
4426
4642
|
const grant = await apiFetch(grantsUrl, {
|
|
4427
4643
|
method: "POST",
|
|
4428
4644
|
body: {
|
|
@@ -4442,8 +4658,8 @@ async function runShellMode(command, args) {
|
|
|
4442
4658
|
host: targetHost
|
|
4443
4659
|
});
|
|
4444
4660
|
if (shouldWaitForGrant(args)) {
|
|
4445
|
-
|
|
4446
|
-
|
|
4661
|
+
consola29.info(`Grant requested: ${grant.id}`);
|
|
4662
|
+
consola29.info("Waiting for approval...");
|
|
4447
4663
|
const maxWait = 3e5;
|
|
4448
4664
|
const interval = 3e3;
|
|
4449
4665
|
const start = Date.now();
|
|
@@ -4474,13 +4690,13 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
4474
4690
|
try {
|
|
4475
4691
|
resolved = await resolveCommand(loaded, [normalizedExecutable, ...parsed.argv]);
|
|
4476
4692
|
} catch (err) {
|
|
4477
|
-
|
|
4693
|
+
consola29.debug(`ape-shell: adapter resolve failed for "${parsed.raw}":`, err);
|
|
4478
4694
|
return false;
|
|
4479
4695
|
}
|
|
4480
4696
|
try {
|
|
4481
4697
|
const existingGrantId = await findExistingGrant(resolved, idp);
|
|
4482
4698
|
if (existingGrantId) {
|
|
4483
|
-
|
|
4699
|
+
consola29.info(`Reusing grant ${existingGrantId} for: ${resolved.detail.display}`);
|
|
4484
4700
|
const token = await fetchGrantToken(idp, existingGrantId);
|
|
4485
4701
|
await verifyAndExecute(token, resolved, existingGrantId);
|
|
4486
4702
|
return true;
|
|
@@ -4488,7 +4704,7 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
4488
4704
|
} catch {
|
|
4489
4705
|
}
|
|
4490
4706
|
const approval = args.approval ?? "once";
|
|
4491
|
-
|
|
4707
|
+
consola29.info(`Requesting grant for: ${resolved.detail.display}`);
|
|
4492
4708
|
const grant = await createShapesGrant(resolved, {
|
|
4493
4709
|
idp,
|
|
4494
4710
|
approval,
|
|
@@ -4496,8 +4712,8 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
4496
4712
|
});
|
|
4497
4713
|
if (grant.similar_grants?.similar_grants?.length) {
|
|
4498
4714
|
const n = grant.similar_grants.similar_grants.length;
|
|
4499
|
-
|
|
4500
|
-
|
|
4715
|
+
consola29.info("");
|
|
4716
|
+
consola29.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
|
|
4501
4717
|
}
|
|
4502
4718
|
notifyGrantPending({
|
|
4503
4719
|
grantId: grant.id,
|
|
@@ -4507,8 +4723,8 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
4507
4723
|
host: args.host || hostname4()
|
|
4508
4724
|
});
|
|
4509
4725
|
if (shouldWaitForGrant(args)) {
|
|
4510
|
-
|
|
4511
|
-
|
|
4726
|
+
consola29.info(`Grant requested: ${grant.id}`);
|
|
4727
|
+
consola29.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
|
|
4512
4728
|
const status = await waitForGrantStatus(idp, grant.id);
|
|
4513
4729
|
if (status !== "approved")
|
|
4514
4730
|
throw new CliError(`Grant ${status}`);
|
|
@@ -4524,7 +4740,7 @@ function execShellCommand(command) {
|
|
|
4524
4740
|
throw new CliError("No command to execute");
|
|
4525
4741
|
try {
|
|
4526
4742
|
const { APES_SHELL_WRAPPER: _wrapperMarker, ...inheritedEnv } = process.env;
|
|
4527
|
-
|
|
4743
|
+
execFileSync11(command[0], command.slice(1), {
|
|
4528
4744
|
stdio: "inherit",
|
|
4529
4745
|
env: inheritedEnv
|
|
4530
4746
|
});
|
|
@@ -4582,7 +4798,7 @@ async function runAdapterMode(command, rawArgs, args) {
|
|
|
4582
4798
|
try {
|
|
4583
4799
|
const existingGrantId = await findExistingGrant(resolved, idp);
|
|
4584
4800
|
if (existingGrantId) {
|
|
4585
|
-
|
|
4801
|
+
consola29.info(`Reusing existing grant: ${existingGrantId}`);
|
|
4586
4802
|
const token = await fetchGrantToken(idp, existingGrantId);
|
|
4587
4803
|
await verifyAndExecute(token, resolved, existingGrantId);
|
|
4588
4804
|
return;
|
|
@@ -4596,17 +4812,17 @@ async function runAdapterMode(command, rawArgs, args) {
|
|
|
4596
4812
|
});
|
|
4597
4813
|
if (grant.similar_grants?.similar_grants?.length) {
|
|
4598
4814
|
const n = grant.similar_grants.similar_grants.length;
|
|
4599
|
-
|
|
4600
|
-
|
|
4815
|
+
consola29.info("");
|
|
4816
|
+
consola29.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
|
|
4601
4817
|
if (grant.similar_grants.widened_details?.length) {
|
|
4602
4818
|
const wider = grant.similar_grants.widened_details.map((d) => d.permission).join(", ");
|
|
4603
|
-
|
|
4819
|
+
consola29.info(` Broader scope: ${wider}`);
|
|
4604
4820
|
}
|
|
4605
|
-
|
|
4821
|
+
consola29.info("");
|
|
4606
4822
|
}
|
|
4607
4823
|
if (shouldWaitForGrant(args)) {
|
|
4608
|
-
|
|
4609
|
-
|
|
4824
|
+
consola29.info(`Grant requested: ${grant.id}`);
|
|
4825
|
+
consola29.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
|
|
4610
4826
|
const status = await waitForGrantStatus(idp, grant.id);
|
|
4611
4827
|
if (status !== "approved")
|
|
4612
4828
|
throw new Error(`Grant ${status}`);
|
|
@@ -4626,7 +4842,7 @@ async function runAudienceMode(audience, action, args) {
|
|
|
4626
4842
|
const grantsUrl = await getGrantsEndpoint(idp);
|
|
4627
4843
|
const command = action.split(" ");
|
|
4628
4844
|
const targetHost = args.host || hostname4();
|
|
4629
|
-
|
|
4845
|
+
consola29.info(`Requesting ${audience} grant on ${targetHost}: ${command.join(" ")}`);
|
|
4630
4846
|
const grant = await apiFetch(grantsUrl, {
|
|
4631
4847
|
method: "POST",
|
|
4632
4848
|
body: {
|
|
@@ -4643,9 +4859,9 @@ async function runAudienceMode(audience, action, args) {
|
|
|
4643
4859
|
printPendingGrantInfo(grant, idp);
|
|
4644
4860
|
throw new CliExit(getAsyncExitCode());
|
|
4645
4861
|
}
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
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...");
|
|
4649
4865
|
const maxWait = 15 * 60 * 1e3;
|
|
4650
4866
|
const interval = 3e3;
|
|
4651
4867
|
const start = Date.now();
|
|
@@ -4653,7 +4869,7 @@ async function runAudienceMode(audience, action, args) {
|
|
|
4653
4869
|
while (Date.now() - start < maxWait) {
|
|
4654
4870
|
const status = await apiFetch(`${grantsUrl}/${grant.id}`);
|
|
4655
4871
|
if (status.status === "approved") {
|
|
4656
|
-
|
|
4872
|
+
consola29.success("Grant approved!");
|
|
4657
4873
|
approved = true;
|
|
4658
4874
|
break;
|
|
4659
4875
|
}
|
|
@@ -4668,15 +4884,15 @@ async function runAudienceMode(audience, action, args) {
|
|
|
4668
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.`
|
|
4669
4885
|
);
|
|
4670
4886
|
}
|
|
4671
|
-
|
|
4887
|
+
consola29.info("Fetching grant token...");
|
|
4672
4888
|
const { authz_jwt } = await apiFetch(`${grantsUrl}/${grant.id}/token`, {
|
|
4673
4889
|
method: "POST"
|
|
4674
4890
|
});
|
|
4675
4891
|
if (audience === "escapes") {
|
|
4676
|
-
|
|
4892
|
+
consola29.info(`Executing: ${command.join(" ")}`);
|
|
4677
4893
|
try {
|
|
4678
4894
|
const { APES_SHELL_WRAPPER: _wrapperMarker, ...inheritedEnv } = process.env;
|
|
4679
|
-
|
|
4895
|
+
execFileSync11(args["escapes-path"] || "escapes", ["--grant", authz_jwt, "--", ...command], {
|
|
4680
4896
|
stdio: "inherit",
|
|
4681
4897
|
env: inheritedEnv
|
|
4682
4898
|
});
|
|
@@ -4691,8 +4907,8 @@ async function runAudienceMode(audience, action, args) {
|
|
|
4691
4907
|
|
|
4692
4908
|
// src/commands/proxy.ts
|
|
4693
4909
|
import { spawn as spawn2 } from "child_process";
|
|
4694
|
-
import { defineCommand as
|
|
4695
|
-
import
|
|
4910
|
+
import { defineCommand as defineCommand35 } from "citty";
|
|
4911
|
+
import consola30 from "consola";
|
|
4696
4912
|
|
|
4697
4913
|
// src/proxy/config.ts
|
|
4698
4914
|
function buildDefaultProxyConfigToml(opts) {
|
|
@@ -4726,10 +4942,10 @@ note = "VPC-internal hostname suffix"
|
|
|
4726
4942
|
|
|
4727
4943
|
// src/proxy/local-proxy.ts
|
|
4728
4944
|
import { spawn } from "child_process";
|
|
4729
|
-
import { mkdtempSync as mkdtempSync3, rmSync as rmSync3, writeFileSync as
|
|
4945
|
+
import { mkdtempSync as mkdtempSync3, rmSync as rmSync3, writeFileSync as writeFileSync7 } from "fs";
|
|
4730
4946
|
import { createRequire } from "module";
|
|
4731
4947
|
import { tmpdir as tmpdir3 } from "os";
|
|
4732
|
-
import { dirname as dirname3, join as
|
|
4948
|
+
import { dirname as dirname3, join as join10, resolve as resolve4 } from "path";
|
|
4733
4949
|
var require2 = createRequire(import.meta.url);
|
|
4734
4950
|
function findProxyBin() {
|
|
4735
4951
|
const pkgPath = require2.resolve("@openape/proxy/package.json");
|
|
@@ -4741,9 +4957,9 @@ function findProxyBin() {
|
|
|
4741
4957
|
return resolve4(dirname3(pkgPath), binRel);
|
|
4742
4958
|
}
|
|
4743
4959
|
async function startEphemeralProxy(configToml) {
|
|
4744
|
-
const tmpDir = mkdtempSync3(
|
|
4745
|
-
const configPath =
|
|
4746
|
-
|
|
4960
|
+
const tmpDir = mkdtempSync3(join10(tmpdir3(), "openape-proxy-"));
|
|
4961
|
+
const configPath = join10(tmpDir, "config.toml");
|
|
4962
|
+
writeFileSync7(configPath, configToml, { mode: 384 });
|
|
4747
4963
|
const binPath = findProxyBin();
|
|
4748
4964
|
const child = spawn(process.execPath, [binPath, "-c", configPath], {
|
|
4749
4965
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -4835,10 +5051,10 @@ function resolveProxyConfigOptions() {
|
|
|
4835
5051
|
77
|
|
4836
5052
|
);
|
|
4837
5053
|
}
|
|
4838
|
-
|
|
5054
|
+
consola30.info(`[apes proxy] IdP-mediated mode \u2014 agent=${auth.email}, idp=${auth.idp}`);
|
|
4839
5055
|
return { agentEmail: auth.email, idpUrl: auth.idp, mediated: true };
|
|
4840
5056
|
}
|
|
4841
|
-
var proxyCommand =
|
|
5057
|
+
var proxyCommand = defineCommand35({
|
|
4842
5058
|
meta: {
|
|
4843
5059
|
name: "proxy",
|
|
4844
5060
|
description: "Run a command with HTTPS_PROXY routed through the OpenApe egress proxy."
|
|
@@ -4860,12 +5076,12 @@ var proxyCommand = defineCommand31({
|
|
|
4860
5076
|
let close = null;
|
|
4861
5077
|
if (reuseUrl) {
|
|
4862
5078
|
proxyUrl = reuseUrl;
|
|
4863
|
-
|
|
5079
|
+
consola30.info(`[apes proxy] reusing existing proxy at ${proxyUrl}`);
|
|
4864
5080
|
} else {
|
|
4865
5081
|
const ephemeral = await startEphemeralProxy(buildDefaultProxyConfigToml(resolveProxyConfigOptions()));
|
|
4866
5082
|
proxyUrl = ephemeral.url;
|
|
4867
5083
|
close = ephemeral.close;
|
|
4868
|
-
|
|
5084
|
+
consola30.info(`[apes proxy] started ephemeral proxy at ${proxyUrl}`);
|
|
4869
5085
|
}
|
|
4870
5086
|
const noProxy = process.env.NO_PROXY ?? process.env.no_proxy ?? "127.0.0.1,localhost";
|
|
4871
5087
|
const childEnv = {
|
|
@@ -4897,7 +5113,7 @@ var proxyCommand = defineCommand31({
|
|
|
4897
5113
|
else resolveExit(code ?? 0);
|
|
4898
5114
|
});
|
|
4899
5115
|
child.once("error", (err) => {
|
|
4900
|
-
|
|
5116
|
+
consola30.error(`[apes proxy] failed to spawn '${wrapped[0]}':`, err.message);
|
|
4901
5117
|
resolveExit(127);
|
|
4902
5118
|
});
|
|
4903
5119
|
});
|
|
@@ -4911,8 +5127,8 @@ function signalNumber(signal) {
|
|
|
4911
5127
|
}
|
|
4912
5128
|
|
|
4913
5129
|
// src/commands/explain.ts
|
|
4914
|
-
import { defineCommand as
|
|
4915
|
-
var explainCommand =
|
|
5130
|
+
import { defineCommand as defineCommand36 } from "citty";
|
|
5131
|
+
var explainCommand = defineCommand36({
|
|
4916
5132
|
meta: {
|
|
4917
5133
|
name: "explain",
|
|
4918
5134
|
description: "Show what permission a command would need"
|
|
@@ -4950,9 +5166,9 @@ var explainCommand = defineCommand32({
|
|
|
4950
5166
|
});
|
|
4951
5167
|
|
|
4952
5168
|
// src/commands/config/get.ts
|
|
4953
|
-
import { defineCommand as
|
|
4954
|
-
import
|
|
4955
|
-
var configGetCommand =
|
|
5169
|
+
import { defineCommand as defineCommand37 } from "citty";
|
|
5170
|
+
import consola31 from "consola";
|
|
5171
|
+
var configGetCommand = defineCommand37({
|
|
4956
5172
|
meta: {
|
|
4957
5173
|
name: "get",
|
|
4958
5174
|
description: "Get a configuration value"
|
|
@@ -4972,7 +5188,7 @@ var configGetCommand = defineCommand33({
|
|
|
4972
5188
|
if (idp)
|
|
4973
5189
|
console.log(idp);
|
|
4974
5190
|
else
|
|
4975
|
-
|
|
5191
|
+
consola31.info("No IdP configured.");
|
|
4976
5192
|
break;
|
|
4977
5193
|
}
|
|
4978
5194
|
case "email": {
|
|
@@ -4980,7 +5196,7 @@ var configGetCommand = defineCommand33({
|
|
|
4980
5196
|
if (auth?.email)
|
|
4981
5197
|
console.log(auth.email);
|
|
4982
5198
|
else
|
|
4983
|
-
|
|
5199
|
+
consola31.info("Not logged in.");
|
|
4984
5200
|
break;
|
|
4985
5201
|
}
|
|
4986
5202
|
default: {
|
|
@@ -4993,7 +5209,7 @@ var configGetCommand = defineCommand33({
|
|
|
4993
5209
|
if (sectionObj && field in sectionObj) {
|
|
4994
5210
|
console.log(sectionObj[field]);
|
|
4995
5211
|
} else {
|
|
4996
|
-
|
|
5212
|
+
consola31.info(`Key "${key}" not set.`);
|
|
4997
5213
|
}
|
|
4998
5214
|
} else {
|
|
4999
5215
|
throw new CliError(`Unknown key: "${key}". Use: idp, email, defaults.idp, defaults.approval, agent.key, agent.email`);
|
|
@@ -5004,9 +5220,9 @@ var configGetCommand = defineCommand33({
|
|
|
5004
5220
|
});
|
|
5005
5221
|
|
|
5006
5222
|
// src/commands/config/set.ts
|
|
5007
|
-
import { defineCommand as
|
|
5008
|
-
import
|
|
5009
|
-
var configSetCommand =
|
|
5223
|
+
import { defineCommand as defineCommand38 } from "citty";
|
|
5224
|
+
import consola32 from "consola";
|
|
5225
|
+
var configSetCommand = defineCommand38({
|
|
5010
5226
|
meta: {
|
|
5011
5227
|
name: "set",
|
|
5012
5228
|
description: "Set a configuration value"
|
|
@@ -5042,12 +5258,12 @@ var configSetCommand = defineCommand34({
|
|
|
5042
5258
|
throw new CliError(`Unknown section: "${section}". Use: defaults, agent`);
|
|
5043
5259
|
}
|
|
5044
5260
|
saveConfig(config);
|
|
5045
|
-
|
|
5261
|
+
consola32.success(`Set ${key} = ${value}`);
|
|
5046
5262
|
}
|
|
5047
5263
|
});
|
|
5048
5264
|
|
|
5049
5265
|
// src/commands/fetch/index.ts
|
|
5050
|
-
import { defineCommand as
|
|
5266
|
+
import { defineCommand as defineCommand39 } from "citty";
|
|
5051
5267
|
async function doRequest(method, url, body, contentType, raw, showHeaders) {
|
|
5052
5268
|
const token = getAuthToken();
|
|
5053
5269
|
if (!token) {
|
|
@@ -5083,13 +5299,13 @@ async function doRequest(method, url, body, contentType, raw, showHeaders) {
|
|
|
5083
5299
|
throw new CliError(`HTTP ${response.status} ${response.statusText}`);
|
|
5084
5300
|
}
|
|
5085
5301
|
}
|
|
5086
|
-
var fetchCommand =
|
|
5302
|
+
var fetchCommand = defineCommand39({
|
|
5087
5303
|
meta: {
|
|
5088
5304
|
name: "fetch",
|
|
5089
5305
|
description: "Make authenticated HTTP requests"
|
|
5090
5306
|
},
|
|
5091
5307
|
subCommands: {
|
|
5092
|
-
get:
|
|
5308
|
+
get: defineCommand39({
|
|
5093
5309
|
meta: {
|
|
5094
5310
|
name: "get",
|
|
5095
5311
|
description: "GET request with auth token"
|
|
@@ -5115,7 +5331,7 @@ var fetchCommand = defineCommand35({
|
|
|
5115
5331
|
await doRequest("GET", String(args.url), void 0, "application/json", Boolean(args.raw), Boolean(args.headers));
|
|
5116
5332
|
}
|
|
5117
5333
|
}),
|
|
5118
|
-
post:
|
|
5334
|
+
post: defineCommand39({
|
|
5119
5335
|
meta: {
|
|
5120
5336
|
name: "post",
|
|
5121
5337
|
description: "POST request with auth token"
|
|
@@ -5154,8 +5370,8 @@ var fetchCommand = defineCommand35({
|
|
|
5154
5370
|
});
|
|
5155
5371
|
|
|
5156
5372
|
// src/commands/mcp/index.ts
|
|
5157
|
-
import { defineCommand as
|
|
5158
|
-
var mcpCommand =
|
|
5373
|
+
import { defineCommand as defineCommand40 } from "citty";
|
|
5374
|
+
var mcpCommand = defineCommand40({
|
|
5159
5375
|
meta: {
|
|
5160
5376
|
name: "mcp",
|
|
5161
5377
|
description: "Start MCP server for AI agents"
|
|
@@ -5178,48 +5394,48 @@ var mcpCommand = defineCommand36({
|
|
|
5178
5394
|
if (transport !== "stdio" && transport !== "sse") {
|
|
5179
5395
|
throw new Error('Transport must be "stdio" or "sse"');
|
|
5180
5396
|
}
|
|
5181
|
-
const { startMcpServer } = await import("./server-
|
|
5397
|
+
const { startMcpServer } = await import("./server-A56K7VDD.js");
|
|
5182
5398
|
await startMcpServer(transport, port);
|
|
5183
5399
|
}
|
|
5184
5400
|
});
|
|
5185
5401
|
|
|
5186
5402
|
// src/commands/init/index.ts
|
|
5187
|
-
import { existsSync as
|
|
5403
|
+
import { existsSync as existsSync12, copyFileSync, writeFileSync as writeFileSync8 } from "fs";
|
|
5188
5404
|
import { randomBytes } from "crypto";
|
|
5189
|
-
import { execFileSync as
|
|
5190
|
-
import { join as
|
|
5191
|
-
import { defineCommand as
|
|
5192
|
-
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";
|
|
5193
5409
|
var DEFAULT_IDP_URL = "https://id.openape.at";
|
|
5194
5410
|
async function downloadTemplate(repo, targetDir) {
|
|
5195
5411
|
const { downloadTemplate: gigetDownload } = await import("giget");
|
|
5196
5412
|
await gigetDownload(`gh:${repo}`, { dir: targetDir, force: false });
|
|
5197
5413
|
}
|
|
5198
5414
|
function installDeps(dir) {
|
|
5199
|
-
const hasLockFile = (name) =>
|
|
5415
|
+
const hasLockFile = (name) => existsSync12(join11(dir, name));
|
|
5200
5416
|
if (hasLockFile("pnpm-lock.yaml")) {
|
|
5201
|
-
|
|
5417
|
+
execFileSync12("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
|
|
5202
5418
|
} else if (hasLockFile("bun.lockb")) {
|
|
5203
|
-
|
|
5419
|
+
execFileSync12("bun", ["install"], { cwd: dir, stdio: "inherit" });
|
|
5204
5420
|
} else {
|
|
5205
|
-
|
|
5421
|
+
execFileSync12("npm", ["install"], { cwd: dir, stdio: "inherit" });
|
|
5206
5422
|
}
|
|
5207
5423
|
}
|
|
5208
5424
|
async function promptChoice(message, choices) {
|
|
5209
|
-
const result = await
|
|
5425
|
+
const result = await consola33.prompt(message, { type: "select", options: choices });
|
|
5210
5426
|
if (typeof result === "symbol") {
|
|
5211
5427
|
throw new CliExit(0);
|
|
5212
5428
|
}
|
|
5213
5429
|
return result;
|
|
5214
5430
|
}
|
|
5215
5431
|
async function promptText(message, defaultValue) {
|
|
5216
|
-
const result = await
|
|
5432
|
+
const result = await consola33.prompt(message, { type: "text", default: defaultValue, placeholder: defaultValue });
|
|
5217
5433
|
if (typeof result === "symbol") {
|
|
5218
5434
|
throw new CliExit(0);
|
|
5219
5435
|
}
|
|
5220
5436
|
return result || defaultValue || "";
|
|
5221
5437
|
}
|
|
5222
|
-
var initCommand =
|
|
5438
|
+
var initCommand = defineCommand41({
|
|
5223
5439
|
meta: {
|
|
5224
5440
|
name: "init",
|
|
5225
5441
|
description: "Scaffold a new OpenApe project"
|
|
@@ -5261,23 +5477,23 @@ var initCommand = defineCommand37({
|
|
|
5261
5477
|
});
|
|
5262
5478
|
async function initSP(targetDir) {
|
|
5263
5479
|
const dir = targetDir || "my-app";
|
|
5264
|
-
if (
|
|
5480
|
+
if (existsSync12(join11(dir, "package.json"))) {
|
|
5265
5481
|
throw new CliError(`Directory "${dir}" already contains a project.`);
|
|
5266
5482
|
}
|
|
5267
|
-
|
|
5483
|
+
consola33.start("Scaffolding SP starter...");
|
|
5268
5484
|
await downloadTemplate("openape-ai/openape-sp-starter", dir);
|
|
5269
|
-
|
|
5270
|
-
|
|
5485
|
+
consola33.success("Scaffolded from openape-sp-starter");
|
|
5486
|
+
consola33.start("Installing dependencies...");
|
|
5271
5487
|
installDeps(dir);
|
|
5272
|
-
|
|
5273
|
-
const envExample =
|
|
5274
|
-
const envFile =
|
|
5275
|
-
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)) {
|
|
5276
5492
|
copyFileSync(envExample, envFile);
|
|
5277
|
-
|
|
5493
|
+
consola33.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
|
|
5278
5494
|
}
|
|
5279
5495
|
console.log("");
|
|
5280
|
-
|
|
5496
|
+
consola33.box([
|
|
5281
5497
|
`cd ${dir}`,
|
|
5282
5498
|
"npm run dev",
|
|
5283
5499
|
"",
|
|
@@ -5286,7 +5502,7 @@ async function initSP(targetDir) {
|
|
|
5286
5502
|
}
|
|
5287
5503
|
async function initIdP(targetDir) {
|
|
5288
5504
|
const dir = targetDir || "my-idp";
|
|
5289
|
-
if (
|
|
5505
|
+
if (existsSync12(join11(dir, "package.json"))) {
|
|
5290
5506
|
throw new CliError(`Directory "${dir}" already contains a project.`);
|
|
5291
5507
|
}
|
|
5292
5508
|
const domain = await promptText("Domain for the IdP", "localhost");
|
|
@@ -5296,15 +5512,15 @@ async function initIdP(targetDir) {
|
|
|
5296
5512
|
"s3 (S3-compatible)"
|
|
5297
5513
|
]);
|
|
5298
5514
|
const adminEmail = await promptText("Admin email");
|
|
5299
|
-
|
|
5515
|
+
consola33.start("Scaffolding IdP starter...");
|
|
5300
5516
|
await downloadTemplate("openape-ai/openape-idp-starter", dir);
|
|
5301
|
-
|
|
5302
|
-
|
|
5517
|
+
consola33.success("Scaffolded from openape-idp-starter");
|
|
5518
|
+
consola33.start("Installing dependencies...");
|
|
5303
5519
|
installDeps(dir);
|
|
5304
|
-
|
|
5520
|
+
consola33.success("Dependencies installed");
|
|
5305
5521
|
const sessionSecret = randomBytes(32).toString("hex");
|
|
5306
5522
|
const managementToken = randomBytes(32).toString("hex");
|
|
5307
|
-
|
|
5523
|
+
consola33.success("Secrets generated");
|
|
5308
5524
|
const isLocalhost = domain === "localhost";
|
|
5309
5525
|
const origin = isLocalhost ? "http://localhost:3000" : `https://${domain}`;
|
|
5310
5526
|
const envContent = [
|
|
@@ -5318,11 +5534,11 @@ async function initIdP(targetDir) {
|
|
|
5318
5534
|
`NUXT_OPENAPE_RP_ID=${domain}`,
|
|
5319
5535
|
`NUXT_OPENAPE_RP_ORIGIN=${origin}`
|
|
5320
5536
|
].join("\n");
|
|
5321
|
-
|
|
5537
|
+
writeFileSync8(join11(dir, ".env"), `${envContent}
|
|
5322
5538
|
`, { mode: 384 });
|
|
5323
|
-
|
|
5539
|
+
consola33.success(".env created");
|
|
5324
5540
|
console.log("");
|
|
5325
|
-
|
|
5541
|
+
consola33.box([
|
|
5326
5542
|
`cd ${dir}`,
|
|
5327
5543
|
"npm run dev",
|
|
5328
5544
|
"",
|
|
@@ -5339,11 +5555,11 @@ async function initIdP(targetDir) {
|
|
|
5339
5555
|
|
|
5340
5556
|
// src/commands/enroll.ts
|
|
5341
5557
|
import { Buffer as Buffer5 } from "buffer";
|
|
5342
|
-
import { existsSync as
|
|
5558
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11 } from "fs";
|
|
5343
5559
|
import { execFile as execFile2 } from "child_process";
|
|
5344
5560
|
import { sign as sign2 } from "crypto";
|
|
5345
|
-
import { defineCommand as
|
|
5346
|
-
import
|
|
5561
|
+
import { defineCommand as defineCommand42 } from "citty";
|
|
5562
|
+
import consola34 from "consola";
|
|
5347
5563
|
var DEFAULT_IDP_URL2 = "https://id.openape.at";
|
|
5348
5564
|
var DEFAULT_KEY_PATH = "~/.ssh/id_ed25519";
|
|
5349
5565
|
var POLL_INTERVAL = 3e3;
|
|
@@ -5355,7 +5571,7 @@ function openBrowser2(url) {
|
|
|
5355
5571
|
}
|
|
5356
5572
|
async function pollForEnrollment(idp, agentEmail, keyPath) {
|
|
5357
5573
|
const resolvedKey = resolveKeyPath(keyPath);
|
|
5358
|
-
const keyContent =
|
|
5574
|
+
const keyContent = readFileSync11(resolvedKey, "utf-8");
|
|
5359
5575
|
const privateKey = loadEd25519PrivateKey(keyContent);
|
|
5360
5576
|
const challengeUrl = await getAgentChallengeEndpoint(idp);
|
|
5361
5577
|
const authenticateUrl = await getAgentAuthenticateEndpoint(idp);
|
|
@@ -5386,7 +5602,7 @@ async function pollForEnrollment(idp, agentEmail, keyPath) {
|
|
|
5386
5602
|
}
|
|
5387
5603
|
throw new Error("Enrollment timed out. Please check the browser and try again.");
|
|
5388
5604
|
}
|
|
5389
|
-
var enrollCommand =
|
|
5605
|
+
var enrollCommand = defineCommand42({
|
|
5390
5606
|
meta: {
|
|
5391
5607
|
name: "enroll",
|
|
5392
5608
|
description: "Enroll an agent with an Identity Provider"
|
|
@@ -5406,38 +5622,38 @@ var enrollCommand = defineCommand38({
|
|
|
5406
5622
|
}
|
|
5407
5623
|
},
|
|
5408
5624
|
async run({ args }) {
|
|
5409
|
-
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) => {
|
|
5410
5626
|
if (typeof r === "symbol") throw new CliExit(0);
|
|
5411
5627
|
return r;
|
|
5412
5628
|
}) || DEFAULT_IDP_URL2;
|
|
5413
|
-
const agentName = args.name || await
|
|
5629
|
+
const agentName = args.name || await consola34.prompt("Agent name", { type: "text", placeholder: "deploy-bot" }).then((r) => {
|
|
5414
5630
|
if (typeof r === "symbol") throw new CliExit(0);
|
|
5415
5631
|
return r;
|
|
5416
5632
|
});
|
|
5417
5633
|
if (!agentName) {
|
|
5418
5634
|
throw new CliError("Agent name is required.");
|
|
5419
5635
|
}
|
|
5420
|
-
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) => {
|
|
5421
5637
|
if (typeof r === "symbol") throw new CliExit(0);
|
|
5422
5638
|
return r;
|
|
5423
5639
|
}) || DEFAULT_KEY_PATH;
|
|
5424
5640
|
const resolvedKey = resolveKeyPath(keyPath);
|
|
5425
5641
|
let publicKey;
|
|
5426
|
-
if (
|
|
5642
|
+
if (existsSync13(resolvedKey)) {
|
|
5427
5643
|
publicKey = readPublicKey(resolvedKey);
|
|
5428
|
-
|
|
5644
|
+
consola34.success(`Using existing key ${keyPath}`);
|
|
5429
5645
|
} else {
|
|
5430
|
-
|
|
5646
|
+
consola34.start(`Generating Ed25519 key pair at ${keyPath}...`);
|
|
5431
5647
|
publicKey = generateAndSaveKey(keyPath);
|
|
5432
|
-
|
|
5648
|
+
consola34.success(`Key pair generated at ${keyPath}`);
|
|
5433
5649
|
}
|
|
5434
5650
|
const encodedKey = encodeURIComponent(publicKey);
|
|
5435
5651
|
const enrollUrl = `${idp}/enroll?name=${encodeURIComponent(agentName)}&key=${encodedKey}`;
|
|
5436
|
-
|
|
5437
|
-
|
|
5652
|
+
consola34.info("Opening browser for enrollment...");
|
|
5653
|
+
consola34.info(`\u2192 ${idp}/enroll`);
|
|
5438
5654
|
openBrowser2(enrollUrl);
|
|
5439
5655
|
console.log("");
|
|
5440
|
-
const agentEmail = await
|
|
5656
|
+
const agentEmail = await consola34.prompt(
|
|
5441
5657
|
"Agent email (shown in browser after enrollment)",
|
|
5442
5658
|
{ type: "text", placeholder: `agent+${agentName}@...` }
|
|
5443
5659
|
).then((r) => {
|
|
@@ -5447,7 +5663,7 @@ var enrollCommand = defineCommand38({
|
|
|
5447
5663
|
if (!agentEmail) {
|
|
5448
5664
|
throw new CliError("Agent email is required to verify enrollment.");
|
|
5449
5665
|
}
|
|
5450
|
-
|
|
5666
|
+
consola34.start("Verifying enrollment...");
|
|
5451
5667
|
const { token, expiresIn } = await pollForEnrollment(idp, agentEmail, keyPath);
|
|
5452
5668
|
saveAuth({
|
|
5453
5669
|
idp,
|
|
@@ -5459,18 +5675,18 @@ var enrollCommand = defineCommand38({
|
|
|
5459
5675
|
config.defaults = { ...config.defaults, idp };
|
|
5460
5676
|
config.agent = { key: keyPath, email: agentEmail };
|
|
5461
5677
|
saveConfig(config);
|
|
5462
|
-
|
|
5463
|
-
|
|
5678
|
+
consola34.success(`Agent enrolled as ${agentEmail}`);
|
|
5679
|
+
consola34.success("Config saved to ~/.config/apes/");
|
|
5464
5680
|
console.log("");
|
|
5465
|
-
|
|
5681
|
+
consola34.info("Verify with: apes whoami");
|
|
5466
5682
|
}
|
|
5467
5683
|
});
|
|
5468
5684
|
|
|
5469
5685
|
// src/commands/register-user.ts
|
|
5470
|
-
import { existsSync as
|
|
5471
|
-
import { defineCommand as
|
|
5472
|
-
import
|
|
5473
|
-
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({
|
|
5474
5690
|
meta: {
|
|
5475
5691
|
name: "register-user",
|
|
5476
5692
|
description: "Register a sub-user with SSH key"
|
|
@@ -5506,8 +5722,8 @@ var registerUserCommand = defineCommand39({
|
|
|
5506
5722
|
throw new CliError("No IdP URL configured. Run `apes login` first.");
|
|
5507
5723
|
}
|
|
5508
5724
|
let publicKey = args.key;
|
|
5509
|
-
if (
|
|
5510
|
-
publicKey =
|
|
5725
|
+
if (existsSync14(args.key)) {
|
|
5726
|
+
publicKey = readFileSync12(args.key, "utf-8").trim();
|
|
5511
5727
|
}
|
|
5512
5728
|
if (!publicKey.startsWith("ssh-ed25519 ")) {
|
|
5513
5729
|
throw new CliError("Public key must be in ssh-ed25519 format.");
|
|
@@ -5525,18 +5741,18 @@ var registerUserCommand = defineCommand39({
|
|
|
5525
5741
|
...userType ? { type: userType } : {}
|
|
5526
5742
|
}
|
|
5527
5743
|
});
|
|
5528
|
-
|
|
5744
|
+
consola35.success(`User registered: ${result.email} (type: ${result.type}, owner: ${result.owner})`);
|
|
5529
5745
|
}
|
|
5530
5746
|
});
|
|
5531
5747
|
|
|
5532
5748
|
// src/commands/utils/index.ts
|
|
5533
|
-
import { defineCommand as
|
|
5749
|
+
import { defineCommand as defineCommand45 } from "citty";
|
|
5534
5750
|
|
|
5535
5751
|
// src/commands/utils/dig.ts
|
|
5536
|
-
import { defineCommand as
|
|
5537
|
-
import
|
|
5752
|
+
import { defineCommand as defineCommand44 } from "citty";
|
|
5753
|
+
import consola36 from "consola";
|
|
5538
5754
|
import { resolveDDISA as resolveDDISA2 } from "@openape/core";
|
|
5539
|
-
var digCommand =
|
|
5755
|
+
var digCommand = defineCommand44({
|
|
5540
5756
|
meta: {
|
|
5541
5757
|
name: "dig",
|
|
5542
5758
|
description: "Resolve DDISA IdP for a domain or email (admin/diag tool)"
|
|
@@ -5609,12 +5825,12 @@ var digCommand = defineCommand40({
|
|
|
5609
5825
|
console.log(` domain: ${domain}`);
|
|
5610
5826
|
console.log("");
|
|
5611
5827
|
if (!result.ddisa.found) {
|
|
5612
|
-
|
|
5828
|
+
consola36.warn(`No DDISA record at _ddisa.${domain}`);
|
|
5613
5829
|
if (result.hint) console.log(`
|
|
5614
5830
|
${result.hint}`);
|
|
5615
5831
|
throw new CliError(`No DDISA record found for ${domain}`);
|
|
5616
5832
|
}
|
|
5617
|
-
|
|
5833
|
+
consola36.success(`_ddisa.${domain} \u2192 ${result.ddisa.idp}`);
|
|
5618
5834
|
console.log(` Version: ${result.ddisa.version || "ddisa1"}`);
|
|
5619
5835
|
console.log(` IdP URL: ${result.ddisa.idp}`);
|
|
5620
5836
|
if (result.ddisa.mode) console.log(` Mode: ${result.ddisa.mode}`);
|
|
@@ -5624,13 +5840,13 @@ ${result.hint}`);
|
|
|
5624
5840
|
return;
|
|
5625
5841
|
}
|
|
5626
5842
|
if (result.idpDiscovery.ok) {
|
|
5627
|
-
|
|
5843
|
+
consola36.success(`IdP reachable (${result.idpDiscovery.status ?? 200})`);
|
|
5628
5844
|
if (result.idpDiscovery.issuer) console.log(` Issuer: ${result.idpDiscovery.issuer}`);
|
|
5629
5845
|
if (result.idpDiscovery.ddisaVersion) console.log(` DDISA: v${result.idpDiscovery.ddisaVersion}`);
|
|
5630
5846
|
if (result.idpDiscovery.authMethods?.length) console.log(` Auth: ${result.idpDiscovery.authMethods.join(", ")}`);
|
|
5631
5847
|
if (result.idpDiscovery.grantTypes?.length) console.log(` Grants: ${result.idpDiscovery.grantTypes.join(", ")}`);
|
|
5632
5848
|
} else {
|
|
5633
|
-
|
|
5849
|
+
consola36.warn(`IdP discovery failed${result.idpDiscovery.status ? ` (HTTP ${result.idpDiscovery.status})` : ""}`);
|
|
5634
5850
|
if (result.hint) console.log(`
|
|
5635
5851
|
${result.hint}`);
|
|
5636
5852
|
throw new CliError(`IdP at ${result.ddisa.idp} not reachable`);
|
|
@@ -5639,7 +5855,7 @@ ${result.hint}`);
|
|
|
5639
5855
|
});
|
|
5640
5856
|
|
|
5641
5857
|
// src/commands/utils/index.ts
|
|
5642
|
-
var utilsCommand =
|
|
5858
|
+
var utilsCommand = defineCommand45({
|
|
5643
5859
|
meta: {
|
|
5644
5860
|
name: "utils",
|
|
5645
5861
|
description: "Admin/diagnostic utilities (dig, \u2026)"
|
|
@@ -5650,12 +5866,12 @@ var utilsCommand = defineCommand41({
|
|
|
5650
5866
|
});
|
|
5651
5867
|
|
|
5652
5868
|
// src/commands/sessions/index.ts
|
|
5653
|
-
import { defineCommand as
|
|
5869
|
+
import { defineCommand as defineCommand48 } from "citty";
|
|
5654
5870
|
|
|
5655
5871
|
// src/commands/sessions/list.ts
|
|
5656
|
-
import { defineCommand as
|
|
5657
|
-
import
|
|
5658
|
-
var sessionsListCommand =
|
|
5872
|
+
import { defineCommand as defineCommand46 } from "citty";
|
|
5873
|
+
import consola37 from "consola";
|
|
5874
|
+
var sessionsListCommand = defineCommand46({
|
|
5659
5875
|
meta: {
|
|
5660
5876
|
name: "list",
|
|
5661
5877
|
description: "List your active refresh-token families (one per logged-in device)."
|
|
@@ -5673,7 +5889,7 @@ var sessionsListCommand = defineCommand42({
|
|
|
5673
5889
|
return;
|
|
5674
5890
|
}
|
|
5675
5891
|
if (result.data.length === 0) {
|
|
5676
|
-
|
|
5892
|
+
consola37.info("No active sessions.");
|
|
5677
5893
|
return;
|
|
5678
5894
|
}
|
|
5679
5895
|
for (const f of result.data) {
|
|
@@ -5685,9 +5901,9 @@ var sessionsListCommand = defineCommand42({
|
|
|
5685
5901
|
});
|
|
5686
5902
|
|
|
5687
5903
|
// src/commands/sessions/remove.ts
|
|
5688
|
-
import { defineCommand as
|
|
5689
|
-
import
|
|
5690
|
-
var sessionsRemoveCommand =
|
|
5904
|
+
import { defineCommand as defineCommand47 } from "citty";
|
|
5905
|
+
import consola38 from "consola";
|
|
5906
|
+
var sessionsRemoveCommand = defineCommand47({
|
|
5691
5907
|
meta: {
|
|
5692
5908
|
name: "remove",
|
|
5693
5909
|
description: "Revoke one of your active refresh-token families by id."
|
|
@@ -5703,12 +5919,12 @@ var sessionsRemoveCommand = defineCommand43({
|
|
|
5703
5919
|
const id = String(args.familyId).trim();
|
|
5704
5920
|
if (!id) throw new CliError("familyId required");
|
|
5705
5921
|
await apiFetch(`/api/me/sessions/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
5706
|
-
|
|
5922
|
+
consola38.success(`Session ${id} revoked. The device using it will need to \`apes login\` again on its next refresh.`);
|
|
5707
5923
|
}
|
|
5708
5924
|
});
|
|
5709
5925
|
|
|
5710
5926
|
// src/commands/sessions/index.ts
|
|
5711
|
-
var sessionsCommand =
|
|
5927
|
+
var sessionsCommand = defineCommand48({
|
|
5712
5928
|
meta: {
|
|
5713
5929
|
name: "sessions",
|
|
5714
5930
|
description: "Manage your active refresh-token sessions across devices"
|
|
@@ -5720,10 +5936,10 @@ var sessionsCommand = defineCommand44({
|
|
|
5720
5936
|
});
|
|
5721
5937
|
|
|
5722
5938
|
// src/commands/dns-check.ts
|
|
5723
|
-
import { defineCommand as
|
|
5724
|
-
import
|
|
5939
|
+
import { defineCommand as defineCommand49 } from "citty";
|
|
5940
|
+
import consola39 from "consola";
|
|
5725
5941
|
import { resolveDDISA as resolveDDISA3 } from "@openape/core";
|
|
5726
|
-
var dnsCheckCommand =
|
|
5942
|
+
var dnsCheckCommand = defineCommand49({
|
|
5727
5943
|
meta: {
|
|
5728
5944
|
name: "dns-check",
|
|
5729
5945
|
description: "Validate DDISA DNS TXT records for a domain"
|
|
@@ -5737,7 +5953,7 @@ var dnsCheckCommand = defineCommand45({
|
|
|
5737
5953
|
},
|
|
5738
5954
|
async run({ args }) {
|
|
5739
5955
|
const domain = args.domain;
|
|
5740
|
-
|
|
5956
|
+
consola39.start(`Checking _ddisa.${domain}...`);
|
|
5741
5957
|
try {
|
|
5742
5958
|
const result = await resolveDDISA3(domain);
|
|
5743
5959
|
if (!result) {
|
|
@@ -5746,7 +5962,7 @@ var dnsCheckCommand = defineCommand45({
|
|
|
5746
5962
|
console.log(` _ddisa.${domain} TXT "v=ddisa1 idp=https://id.${domain}"`);
|
|
5747
5963
|
throw new CliError(`No DDISA record found for ${domain}`);
|
|
5748
5964
|
}
|
|
5749
|
-
|
|
5965
|
+
consola39.success(`_ddisa.${domain} \u2192 ${result.idp}`);
|
|
5750
5966
|
console.log("");
|
|
5751
5967
|
console.log(` Version: ${result.version || "ddisa1"}`);
|
|
5752
5968
|
console.log(` IdP URL: ${result.idp}`);
|
|
@@ -5755,14 +5971,14 @@ var dnsCheckCommand = defineCommand45({
|
|
|
5755
5971
|
if (result.priority !== void 0)
|
|
5756
5972
|
console.log(` Priority: ${result.priority}`);
|
|
5757
5973
|
console.log("");
|
|
5758
|
-
|
|
5974
|
+
consola39.start(`Verifying IdP at ${result.idp}...`);
|
|
5759
5975
|
const discoResp = await fetch(`${result.idp}/.well-known/openid-configuration`);
|
|
5760
5976
|
if (!discoResp.ok) {
|
|
5761
|
-
|
|
5977
|
+
consola39.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
|
|
5762
5978
|
return;
|
|
5763
5979
|
}
|
|
5764
5980
|
const disco = await discoResp.json();
|
|
5765
|
-
|
|
5981
|
+
consola39.success(`IdP is reachable`);
|
|
5766
5982
|
console.log(` Issuer: ${disco.issuer}`);
|
|
5767
5983
|
console.log(` DDISA: v${disco.ddisa_version || "?"}`);
|
|
5768
5984
|
if (disco.ddisa_auth_methods_supported) {
|
|
@@ -5780,7 +5996,7 @@ var dnsCheckCommand = defineCommand45({
|
|
|
5780
5996
|
// src/commands/health.ts
|
|
5781
5997
|
import { exec } from "child_process";
|
|
5782
5998
|
import { promisify } from "util";
|
|
5783
|
-
import { defineCommand as
|
|
5999
|
+
import { defineCommand as defineCommand50 } from "citty";
|
|
5784
6000
|
var execAsync = promisify(exec);
|
|
5785
6001
|
async function resolveApeShellPath() {
|
|
5786
6002
|
try {
|
|
@@ -5816,7 +6032,7 @@ async function bestEffortGrantCount(idp) {
|
|
|
5816
6032
|
}
|
|
5817
6033
|
}
|
|
5818
6034
|
async function runHealth(args) {
|
|
5819
|
-
const version = true ? "1.
|
|
6035
|
+
const version = true ? "1.4.0" : "0.0.0";
|
|
5820
6036
|
const auth = loadAuth();
|
|
5821
6037
|
if (!auth) {
|
|
5822
6038
|
throw new CliError("Not logged in. Run `apes login` first.", 1);
|
|
@@ -5879,7 +6095,7 @@ async function runHealth(args) {
|
|
|
5879
6095
|
throw new CliError(`IdP ${auth.idp} unreachable: ${idpProbe.error}`, 1);
|
|
5880
6096
|
}
|
|
5881
6097
|
}
|
|
5882
|
-
var healthCommand =
|
|
6098
|
+
var healthCommand = defineCommand50({
|
|
5883
6099
|
meta: {
|
|
5884
6100
|
name: "health",
|
|
5885
6101
|
description: "Report CLI diagnostic state (auth, IdP, grants, binaries)"
|
|
@@ -5897,8 +6113,8 @@ var healthCommand = defineCommand46({
|
|
|
5897
6113
|
});
|
|
5898
6114
|
|
|
5899
6115
|
// src/commands/workflows.ts
|
|
5900
|
-
import { defineCommand as
|
|
5901
|
-
import
|
|
6116
|
+
import { defineCommand as defineCommand51 } from "citty";
|
|
6117
|
+
import consola40 from "consola";
|
|
5902
6118
|
|
|
5903
6119
|
// src/guides/index.ts
|
|
5904
6120
|
var guides = [
|
|
@@ -5948,7 +6164,7 @@ var guides = [
|
|
|
5948
6164
|
];
|
|
5949
6165
|
|
|
5950
6166
|
// src/commands/workflows.ts
|
|
5951
|
-
var workflowsCommand =
|
|
6167
|
+
var workflowsCommand = defineCommand51({
|
|
5952
6168
|
meta: {
|
|
5953
6169
|
name: "workflows",
|
|
5954
6170
|
description: "Discover workflow guides"
|
|
@@ -5969,7 +6185,7 @@ var workflowsCommand = defineCommand47({
|
|
|
5969
6185
|
if (args.id) {
|
|
5970
6186
|
const guide = guides.find((g) => g.id === String(args.id));
|
|
5971
6187
|
if (!guide) {
|
|
5972
|
-
|
|
6188
|
+
consola40.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
|
|
5973
6189
|
throw new CliError(`Guide not found: ${args.id}`);
|
|
5974
6190
|
}
|
|
5975
6191
|
if (args.json) {
|
|
@@ -6009,26 +6225,26 @@ var workflowsCommand = defineCommand47({
|
|
|
6009
6225
|
});
|
|
6010
6226
|
|
|
6011
6227
|
// src/version-check.ts
|
|
6012
|
-
import { existsSync as
|
|
6013
|
-
import { homedir as
|
|
6014
|
-
import { join as
|
|
6015
|
-
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";
|
|
6016
6232
|
var PACKAGE_NAME = "@openape/apes";
|
|
6017
6233
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
6018
|
-
var CACHE_FILE =
|
|
6234
|
+
var CACHE_FILE = join12(homedir12(), ".config", "apes", ".version-check.json");
|
|
6019
6235
|
function readCache() {
|
|
6020
|
-
if (!
|
|
6236
|
+
if (!existsSync15(CACHE_FILE)) return null;
|
|
6021
6237
|
try {
|
|
6022
|
-
return JSON.parse(
|
|
6238
|
+
return JSON.parse(readFileSync13(CACHE_FILE, "utf-8"));
|
|
6023
6239
|
} catch {
|
|
6024
6240
|
return null;
|
|
6025
6241
|
}
|
|
6026
6242
|
}
|
|
6027
6243
|
function writeCache(entry) {
|
|
6028
6244
|
try {
|
|
6029
|
-
const dir =
|
|
6030
|
-
if (!
|
|
6031
|
-
|
|
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 });
|
|
6032
6248
|
} catch {
|
|
6033
6249
|
}
|
|
6034
6250
|
}
|
|
@@ -6057,7 +6273,7 @@ async function fetchLatestVersion() {
|
|
|
6057
6273
|
}
|
|
6058
6274
|
function warnIfBehind(currentVersion, latest) {
|
|
6059
6275
|
if (compareSemver(currentVersion, latest) < 0) {
|
|
6060
|
-
|
|
6276
|
+
consola41.warn(
|
|
6061
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.)`
|
|
6062
6278
|
);
|
|
6063
6279
|
}
|
|
@@ -6089,10 +6305,10 @@ if (shellRewrite) {
|
|
|
6089
6305
|
if (shellRewrite.action === "rewrite") {
|
|
6090
6306
|
process.argv = shellRewrite.argv;
|
|
6091
6307
|
} else if (shellRewrite.action === "version") {
|
|
6092
|
-
console.log(`ape-shell ${"1.
|
|
6308
|
+
console.log(`ape-shell ${"1.4.0"} (OpenApe DDISA shell wrapper)`);
|
|
6093
6309
|
process.exit(0);
|
|
6094
6310
|
} else if (shellRewrite.action === "help") {
|
|
6095
|
-
console.log(`ape-shell ${"1.
|
|
6311
|
+
console.log(`ape-shell ${"1.4.0"} \u2014 OpenApe DDISA shell wrapper`);
|
|
6096
6312
|
console.log("");
|
|
6097
6313
|
console.log("Usage:");
|
|
6098
6314
|
console.log(" ape-shell Start interactive grant-mediated REPL");
|
|
@@ -6116,7 +6332,7 @@ if (shellRewrite) {
|
|
|
6116
6332
|
}
|
|
6117
6333
|
}
|
|
6118
6334
|
var debug = process.argv.includes("--debug");
|
|
6119
|
-
var grantsCommand =
|
|
6335
|
+
var grantsCommand = defineCommand52({
|
|
6120
6336
|
meta: {
|
|
6121
6337
|
name: "grants",
|
|
6122
6338
|
description: "Grant management"
|
|
@@ -6137,7 +6353,7 @@ var grantsCommand = defineCommand48({
|
|
|
6137
6353
|
"delegation-revoke": delegationRevokeCommand
|
|
6138
6354
|
}
|
|
6139
6355
|
});
|
|
6140
|
-
var configCommand =
|
|
6356
|
+
var configCommand = defineCommand52({
|
|
6141
6357
|
meta: {
|
|
6142
6358
|
name: "config",
|
|
6143
6359
|
description: "Configuration management"
|
|
@@ -6147,10 +6363,10 @@ var configCommand = defineCommand48({
|
|
|
6147
6363
|
set: configSetCommand
|
|
6148
6364
|
}
|
|
6149
6365
|
});
|
|
6150
|
-
var main =
|
|
6366
|
+
var main = defineCommand52({
|
|
6151
6367
|
meta: {
|
|
6152
6368
|
name: "apes",
|
|
6153
|
-
version: "1.
|
|
6369
|
+
version: "1.4.0",
|
|
6154
6370
|
description: "Unified CLI for OpenApe"
|
|
6155
6371
|
},
|
|
6156
6372
|
subCommands: {
|
|
@@ -6166,6 +6382,7 @@ var main = defineCommand48({
|
|
|
6166
6382
|
health: healthCommand,
|
|
6167
6383
|
grants: grantsCommand,
|
|
6168
6384
|
agents: agentsCommand,
|
|
6385
|
+
nest: nestCommand,
|
|
6169
6386
|
admin: adminCommand,
|
|
6170
6387
|
run: runCommand,
|
|
6171
6388
|
proxy: proxyCommand,
|
|
@@ -6205,20 +6422,20 @@ async function maybeRefreshAuth() {
|
|
|
6205
6422
|
}
|
|
6206
6423
|
}
|
|
6207
6424
|
await maybeRefreshAuth();
|
|
6208
|
-
await maybeWarnStaleVersion("1.
|
|
6425
|
+
await maybeWarnStaleVersion("1.4.0").catch(() => {
|
|
6209
6426
|
});
|
|
6210
6427
|
runMain(main).catch((err) => {
|
|
6211
6428
|
if (err instanceof CliExit) {
|
|
6212
6429
|
process.exit(err.exitCode);
|
|
6213
6430
|
}
|
|
6214
6431
|
if (err instanceof CliError) {
|
|
6215
|
-
|
|
6432
|
+
consola42.error(err.message);
|
|
6216
6433
|
process.exit(err.exitCode);
|
|
6217
6434
|
}
|
|
6218
6435
|
if (debug) {
|
|
6219
|
-
|
|
6436
|
+
consola42.error(err);
|
|
6220
6437
|
} else {
|
|
6221
|
-
|
|
6438
|
+
consola42.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
|
|
6222
6439
|
}
|
|
6223
6440
|
process.exit(1);
|
|
6224
6441
|
});
|