@openape/apes 0.9.4 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{auth-lock-6GGWZVOA.js → auth-lock-O7BTENTJ.js} +2 -2
- package/dist/{chunk-ILKZ5HGV.js → chunk-6JSOSD7R.js} +1 -1
- package/dist/chunk-6JSOSD7R.js.map +1 -0
- package/dist/{chunk-ZHTLP2DD.js → chunk-EAXBC4KC.js} +2 -2
- package/dist/{chunk-D3OMN7RV.js → chunk-U4CI2RBO.js} +3 -3
- package/dist/cli.js +116 -44
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.js +2 -2
- package/dist/{orchestrator-5EZD7ZQE.js → orchestrator-QL3AT67U.js} +4 -4
- package/dist/{server-ED5MMYT3.js → server-GTATJDYX.js} +4 -4
- package/dist/{server-ED5MMYT3.js.map → server-GTATJDYX.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-ILKZ5HGV.js.map +0 -1
- /package/dist/{auth-lock-6GGWZVOA.js.map → auth-lock-O7BTENTJ.js.map} +0 -0
- /package/dist/{chunk-ZHTLP2DD.js.map → chunk-EAXBC4KC.js.map} +0 -0
- /package/dist/{chunk-D3OMN7RV.js.map → chunk-U4CI2RBO.js.map} +0 -0
- /package/dist/{orchestrator-5EZD7ZQE.js.map → orchestrator-QL3AT67U.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
CONFIG_DIR
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-6JSOSD7R.js";
|
|
5
5
|
|
|
6
6
|
// src/auth-lock.ts
|
|
7
7
|
import { open, rm, stat } from "fs/promises";
|
|
@@ -38,4 +38,4 @@ export {
|
|
|
38
38
|
acquireAuthLock,
|
|
39
39
|
releaseAuthLock
|
|
40
40
|
};
|
|
41
|
-
//# sourceMappingURL=auth-lock-
|
|
41
|
+
//# sourceMappingURL=auth-lock-O7BTENTJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport interface AuthData {\n idp: string\n access_token: string\n refresh_token?: string\n email: string\n expires_at: number\n}\n\nexport interface ApesConfig {\n defaults?: {\n idp?: string\n approval?: string\n /**\n * Audience for the `apes run` async info block. `agent` (default)\n * emits verbose agent-facing instructions with a polling protocol;\n * `human` emits a short friendly block. Env var `APES_USER` wins.\n */\n user?: 'agent' | 'human'\n /**\n * Poll interval (seconds) embedded in the agent-mode instructions.\n * Default 10. Env var `APES_GRANT_POLL_INTERVAL` wins. Stored as a\n * string in TOML because the hand-rolled parser only handles quoted\n * values — casting to number happens at read time.\n */\n grant_poll_interval_seconds?: string\n /**\n * Maximum poll duration (minutes) embedded in the agent-mode\n * instructions. Default 5. Env var `APES_GRANT_POLL_MAX_MINUTES` wins.\n */\n grant_poll_max_minutes?: string\n /**\n * Exit code emitted by `apes run` / `ape-shell -c` when the async\n * default path creates a pending grant. Default `75` (`EX_TEMPFAIL`\n * from sysexits.h — \"temporary failure, retry later\"). Set to `0`\n * to restore the pre-0.10.0 exit-0 behaviour. Env var\n * `APES_ASYNC_EXIT_CODE` wins. Valid range 0–255.\n */\n async_exit_code?: string\n }\n agent?: {\n key?: string\n email?: string\n }\n notifications?: {\n pending_command?: string\n }\n}\n\nconst CONFIG_DIR = join(homedir(), '.config', 'apes')\nconst AUTH_FILE = join(CONFIG_DIR, 'auth.json')\nconst CONFIG_FILE = join(CONFIG_DIR, 'config.toml')\n\nfunction ensureDir() {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true })\n }\n}\n\nexport function loadAuth(): AuthData | null {\n if (!existsSync(AUTH_FILE))\n return null\n try {\n return JSON.parse(readFileSync(AUTH_FILE, 'utf-8'))\n }\n catch {\n return null\n }\n}\n\nexport function saveAuth(data: AuthData): void {\n ensureDir()\n writeFileSync(AUTH_FILE, JSON.stringify(data, null, 2), { mode: 0o600 })\n}\n\nexport function clearAuth(): void {\n if (existsSync(AUTH_FILE)) {\n writeFileSync(AUTH_FILE, '', { mode: 0o600 })\n }\n // Also wipe the [agent] section from config.toml so logout disables\n // auto-refresh. Preserves [defaults] so the IdP URL stays configured.\n if (existsSync(CONFIG_FILE)) {\n const existing = loadConfig()\n if (existing.agent) {\n const { agent: _removed, ...rest } = existing\n saveConfig(rest)\n }\n }\n}\n\nexport function loadConfig(): ApesConfig {\n if (!existsSync(CONFIG_FILE))\n return {}\n try {\n return parseTOML(readFileSync(CONFIG_FILE, 'utf-8'))\n }\n catch {\n return {}\n }\n}\n\nfunction parseTOML(content: string): ApesConfig {\n const config: ApesConfig = {}\n let section = ''\n\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('#'))\n continue\n\n const sectionMatch = trimmed.match(/^\\[(.+)\\]$/)\n if (sectionMatch) {\n section = sectionMatch[1]!\n continue\n }\n\n const kvMatch = trimmed.match(/^(\\w+)\\s*=\\s*\"(.+)\"$/)\n if (kvMatch) {\n const [, key, value] = kvMatch\n if (section === 'defaults') {\n config.defaults = config.defaults || {}\n ;(config.defaults as Record<string, string>)[key!] = value!\n }\n else if (section === 'agent') {\n config.agent = config.agent || {}\n ;(config.agent as Record<string, string>)[key!] = value!\n }\n else if (section === 'notifications') {\n config.notifications = config.notifications || {}\n ;(config.notifications as Record<string, string>)[key!] = value!\n }\n }\n }\n\n return config\n}\n\nexport function saveConfig(config: ApesConfig): void {\n ensureDir()\n const lines: string[] = []\n\n if (config.defaults) {\n lines.push('[defaults]')\n for (const [key, value] of Object.entries(config.defaults)) {\n if (value)\n lines.push(`${key} = \"${value}\"`)\n }\n lines.push('')\n }\n\n if (config.agent) {\n lines.push('[agent]')\n for (const [key, value] of Object.entries(config.agent)) {\n if (value)\n lines.push(`${key} = \"${value}\"`)\n }\n lines.push('')\n }\n\n if (config.notifications) {\n lines.push('[notifications]')\n for (const [key, value] of Object.entries(config.notifications)) {\n if (value)\n lines.push(`${key} = \"${value}\"`)\n }\n lines.push('')\n }\n\n writeFileSync(CONFIG_FILE, lines.join('\\n'), { mode: 0o600 })\n}\n\nexport function getIdpUrl(explicit?: string): string | null {\n if (explicit)\n return explicit\n if (process.env.APES_IDP)\n return process.env.APES_IDP\n\n const auth = loadAuth()\n if (auth?.idp)\n return auth.idp\n\n const config = loadConfig()\n if (config.defaults?.idp)\n return config.defaults.idp\n\n return null\n}\n\nexport function getAuthToken(): string | null {\n const auth = loadAuth()\n if (!auth)\n return null\n\n // Check expiry (with 30s buffer)\n if (auth.expires_at && Date.now() / 1000 > auth.expires_at - 30) {\n return null // expired\n }\n\n return auth.access_token\n}\n\nexport function getRequesterIdentity(): string | null {\n return loadAuth()?.email ?? null\n}\n\nexport { CONFIG_DIR, AUTH_FILE }\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
loadConfig
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-6JSOSD7R.js";
|
|
5
5
|
|
|
6
6
|
// src/notifications.ts
|
|
7
7
|
import { spawn } from "child_process";
|
|
@@ -63,4 +63,4 @@ export {
|
|
|
63
63
|
notifyGrantPending,
|
|
64
64
|
isApesSelfDispatch
|
|
65
65
|
};
|
|
66
|
-
//# sourceMappingURL=chunk-
|
|
66
|
+
//# sourceMappingURL=chunk-EAXBC4KC.js.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
loadAuth,
|
|
6
6
|
loadConfig,
|
|
7
7
|
saveAuth
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-6JSOSD7R.js";
|
|
9
9
|
|
|
10
10
|
// src/http.ts
|
|
11
11
|
import consola from "consola";
|
|
@@ -104,7 +104,7 @@ async function refreshOAuthToken() {
|
|
|
104
104
|
const auth = loadAuth();
|
|
105
105
|
if (!auth?.refresh_token)
|
|
106
106
|
return null;
|
|
107
|
-
const { acquireAuthLock, releaseAuthLock } = await import("./auth-lock-
|
|
107
|
+
const { acquireAuthLock, releaseAuthLock } = await import("./auth-lock-O7BTENTJ.js");
|
|
108
108
|
const lock = await acquireAuthLock({ timeoutMs: 5e3 });
|
|
109
109
|
if (!lock) {
|
|
110
110
|
return getAuthToken();
|
|
@@ -1302,4 +1302,4 @@ export {
|
|
|
1302
1302
|
buildExactCommandGrantRequest,
|
|
1303
1303
|
buildStructuredCliGrantRequest
|
|
1304
1304
|
};
|
|
1305
|
-
//# sourceMappingURL=chunk-
|
|
1305
|
+
//# sourceMappingURL=chunk-U4CI2RBO.js.map
|
package/dist/cli.js
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
isApesSelfDispatch,
|
|
13
13
|
notifyGrantPending
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-EAXBC4KC.js";
|
|
15
15
|
import {
|
|
16
16
|
ApiError,
|
|
17
17
|
apiFetch,
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
searchAdapters,
|
|
43
43
|
verifyAndExecute,
|
|
44
44
|
waitForGrantStatus
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-U4CI2RBO.js";
|
|
46
46
|
import {
|
|
47
47
|
AUTH_FILE,
|
|
48
48
|
CONFIG_DIR,
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
loadConfig,
|
|
54
54
|
saveAuth,
|
|
55
55
|
saveConfig
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-6JSOSD7R.js";
|
|
57
57
|
|
|
58
58
|
// src/cli.ts
|
|
59
59
|
import consola27 from "consola";
|
|
@@ -1064,6 +1064,59 @@ var revokeCommand = defineCommand11({
|
|
|
1064
1064
|
import { execFileSync } from "child_process";
|
|
1065
1065
|
import { defineCommand as defineCommand12 } from "citty";
|
|
1066
1066
|
import consola12 from "consola";
|
|
1067
|
+
|
|
1068
|
+
// src/grant-poll.ts
|
|
1069
|
+
function getPollIntervalSeconds() {
|
|
1070
|
+
const envValue = process.env.APES_GRANT_POLL_INTERVAL;
|
|
1071
|
+
if (envValue) {
|
|
1072
|
+
const n = Number(envValue);
|
|
1073
|
+
if (Number.isFinite(n) && n > 0)
|
|
1074
|
+
return Math.floor(n);
|
|
1075
|
+
}
|
|
1076
|
+
const cfg = loadConfig();
|
|
1077
|
+
const cfgValue = cfg.defaults?.grant_poll_interval_seconds;
|
|
1078
|
+
if (cfgValue) {
|
|
1079
|
+
const n = Number(cfgValue);
|
|
1080
|
+
if (Number.isFinite(n) && n > 0)
|
|
1081
|
+
return Math.floor(n);
|
|
1082
|
+
}
|
|
1083
|
+
return 10;
|
|
1084
|
+
}
|
|
1085
|
+
function getPollMaxMinutes() {
|
|
1086
|
+
const envValue = process.env.APES_GRANT_POLL_MAX_MINUTES;
|
|
1087
|
+
if (envValue) {
|
|
1088
|
+
const n = Number(envValue);
|
|
1089
|
+
if (Number.isFinite(n) && n > 0)
|
|
1090
|
+
return Math.floor(n);
|
|
1091
|
+
}
|
|
1092
|
+
const cfg = loadConfig();
|
|
1093
|
+
const cfgValue = cfg.defaults?.grant_poll_max_minutes;
|
|
1094
|
+
if (cfgValue) {
|
|
1095
|
+
const n = Number(cfgValue);
|
|
1096
|
+
if (Number.isFinite(n) && n > 0)
|
|
1097
|
+
return Math.floor(n);
|
|
1098
|
+
}
|
|
1099
|
+
return 5;
|
|
1100
|
+
}
|
|
1101
|
+
async function pollGrantUntilResolved(idp, grantId) {
|
|
1102
|
+
const grantsEndpoint = await getGrantsEndpoint(idp);
|
|
1103
|
+
const intervalSec = getPollIntervalSeconds();
|
|
1104
|
+
const maxMinutes = getPollMaxMinutes();
|
|
1105
|
+
const maxMs = maxMinutes * 6e4;
|
|
1106
|
+
const intervalMs = intervalSec * 1e3;
|
|
1107
|
+
const start = Date.now();
|
|
1108
|
+
while (Date.now() - start < maxMs) {
|
|
1109
|
+
const grant = await apiFetch(`${grantsEndpoint}/${grantId}`);
|
|
1110
|
+
if (grant.status === "approved")
|
|
1111
|
+
return { kind: "approved" };
|
|
1112
|
+
if (grant.status === "denied" || grant.status === "revoked" || grant.status === "used")
|
|
1113
|
+
return { kind: "terminal", status: grant.status };
|
|
1114
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
1115
|
+
}
|
|
1116
|
+
return { kind: "timeout" };
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// src/commands/grants/run.ts
|
|
1067
1120
|
var runGrantCommand = defineCommand12({
|
|
1068
1121
|
meta: {
|
|
1069
1122
|
name: "run",
|
|
@@ -1079,6 +1132,11 @@ var runGrantCommand = defineCommand12({
|
|
|
1079
1132
|
type: "string",
|
|
1080
1133
|
description: "Path to escapes binary (audience=escapes only)",
|
|
1081
1134
|
default: "escapes"
|
|
1135
|
+
},
|
|
1136
|
+
wait: {
|
|
1137
|
+
type: "boolean",
|
|
1138
|
+
description: "If the grant is pending, block and poll until approved (or denied/revoked/used/timeout). Reuses APES_GRANT_POLL_INTERVAL / APES_GRANT_POLL_MAX_MINUTES knobs.",
|
|
1139
|
+
default: false
|
|
1082
1140
|
}
|
|
1083
1141
|
},
|
|
1084
1142
|
async run({ args }) {
|
|
@@ -1086,9 +1144,29 @@ var runGrantCommand = defineCommand12({
|
|
|
1086
1144
|
if (!idp)
|
|
1087
1145
|
throw new CliError("No IdP URL configured. Run `apes login` first or pass --idp.");
|
|
1088
1146
|
const grantsUrl = await getGrantsEndpoint(idp);
|
|
1089
|
-
|
|
1090
|
-
if (grant.status === "pending")
|
|
1091
|
-
|
|
1147
|
+
let grant = await apiFetch(`${grantsUrl}/${args.id}`);
|
|
1148
|
+
if (grant.status === "pending") {
|
|
1149
|
+
if (!args.wait) {
|
|
1150
|
+
throw new CliError(
|
|
1151
|
+
`Grant ${grant.id} is still pending. Approve at: ${idp}/grant-approval?grant_id=${grant.id}`
|
|
1152
|
+
);
|
|
1153
|
+
}
|
|
1154
|
+
const maxMinutes = getPollMaxMinutes();
|
|
1155
|
+
consola12.info(`Waiting for grant ${grant.id} approval (up to ${maxMinutes} minute${maxMinutes === 1 ? "" : "s"})...`);
|
|
1156
|
+
const outcome = await pollGrantUntilResolved(idp, grant.id);
|
|
1157
|
+
if (outcome.kind === "timeout") {
|
|
1158
|
+
throw new CliError(
|
|
1159
|
+
`Grant ${grant.id} approval timed out after ${maxMinutes} minute${maxMinutes === 1 ? "" : "s"}. Re-run after approval, or extend the timeout via APES_GRANT_POLL_MAX_MINUTES.`
|
|
1160
|
+
);
|
|
1161
|
+
}
|
|
1162
|
+
if (outcome.kind === "terminal") {
|
|
1163
|
+
throw new CliError(
|
|
1164
|
+
`Grant ${grant.id} resolved to ${outcome.status}. Request a new one.`
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
grant = await apiFetch(`${grantsUrl}/${args.id}`);
|
|
1168
|
+
consola12.info(`Grant ${grant.id} approved \u2014 continuing`);
|
|
1169
|
+
}
|
|
1092
1170
|
if (grant.status === "denied" || grant.status === "revoked")
|
|
1093
1171
|
throw new CliError(`Grant ${grant.id} is ${grant.status}. Request a new one.`);
|
|
1094
1172
|
if (grant.status === "used")
|
|
@@ -1940,37 +2018,21 @@ function getUserMode() {
|
|
|
1940
2018
|
return "human";
|
|
1941
2019
|
return "agent";
|
|
1942
2020
|
}
|
|
1943
|
-
function
|
|
1944
|
-
const envValue = process.env.
|
|
1945
|
-
if (envValue) {
|
|
2021
|
+
function getAsyncExitCode() {
|
|
2022
|
+
const envValue = process.env.APES_ASYNC_EXIT_CODE;
|
|
2023
|
+
if (envValue !== void 0 && envValue !== "") {
|
|
1946
2024
|
const n = Number(envValue);
|
|
1947
|
-
if (Number.isFinite(n) && n
|
|
2025
|
+
if (Number.isFinite(n) && n >= 0 && n <= 255)
|
|
1948
2026
|
return Math.floor(n);
|
|
1949
2027
|
}
|
|
1950
2028
|
const cfg = loadConfig();
|
|
1951
|
-
const cfgValue = cfg.defaults?.
|
|
1952
|
-
if (cfgValue) {
|
|
2029
|
+
const cfgValue = cfg.defaults?.async_exit_code;
|
|
2030
|
+
if (cfgValue !== void 0 && cfgValue !== "") {
|
|
1953
2031
|
const n = Number(cfgValue);
|
|
1954
|
-
if (Number.isFinite(n) && n
|
|
2032
|
+
if (Number.isFinite(n) && n >= 0 && n <= 255)
|
|
1955
2033
|
return Math.floor(n);
|
|
1956
2034
|
}
|
|
1957
|
-
return
|
|
1958
|
-
}
|
|
1959
|
-
function getPollMaxMinutes() {
|
|
1960
|
-
const envValue = process.env.APES_GRANT_POLL_MAX_MINUTES;
|
|
1961
|
-
if (envValue) {
|
|
1962
|
-
const n = Number(envValue);
|
|
1963
|
-
if (Number.isFinite(n) && n > 0)
|
|
1964
|
-
return Math.floor(n);
|
|
1965
|
-
}
|
|
1966
|
-
const cfg = loadConfig();
|
|
1967
|
-
const cfgValue = cfg.defaults?.grant_poll_max_minutes;
|
|
1968
|
-
if (cfgValue) {
|
|
1969
|
-
const n = Number(cfgValue);
|
|
1970
|
-
if (Number.isFinite(n) && n > 0)
|
|
1971
|
-
return Math.floor(n);
|
|
1972
|
-
}
|
|
1973
|
-
return 5;
|
|
2035
|
+
return 75;
|
|
1974
2036
|
}
|
|
1975
2037
|
function printPendingGrantInfo(grant, idp) {
|
|
1976
2038
|
const mode = getUserMode();
|
|
@@ -1987,17 +2049,25 @@ function printPendingGrantInfo(grant, idp) {
|
|
|
1987
2049
|
console.log(" this grant without re-approval on the next invocation.");
|
|
1988
2050
|
return;
|
|
1989
2051
|
}
|
|
1990
|
-
const pollSec = getPollIntervalSeconds();
|
|
1991
2052
|
const maxMin = getPollMaxMinutes();
|
|
1992
2053
|
consola19.success(`Grant ${grant.id} created (pending approval)`);
|
|
1993
2054
|
console.log(` Approve: ${approveUrl}`);
|
|
1994
2055
|
console.log(` Status: ${statusCmd} [--json]`);
|
|
1995
|
-
console.log(` Execute: ${executeCmd}`);
|
|
2056
|
+
console.log(` Execute: ${executeCmd} --wait`);
|
|
1996
2057
|
console.log("");
|
|
1997
|
-
console.log(
|
|
1998
|
-
console.log(`
|
|
1999
|
-
console.log(`
|
|
2000
|
-
console.log(`
|
|
2058
|
+
console.log(" For agents:");
|
|
2059
|
+
console.log(` 1. Tell the user about the pending grant and the approve URL above.`);
|
|
2060
|
+
console.log(` 2. Run \`${executeCmd} --wait\`. This blocks up to ${maxMin} minutes`);
|
|
2061
|
+
console.log(` until the user approves (or denies/timeout) and then executes`);
|
|
2062
|
+
console.log(` the command in a single step. The CLI handles the polling loop`);
|
|
2063
|
+
console.log(` internally \u2014 you do not need to poll the status yourself.`);
|
|
2064
|
+
console.log(` 3. Exit 0 means approved + executed; stdout is the command output.`);
|
|
2065
|
+
console.log(` Exit 75 (pending) only appears if you accidentally call this`);
|
|
2066
|
+
console.log(` without --wait. Any other non-zero exit means denied, revoked,`);
|
|
2067
|
+
console.log(` used, or timeout \u2014 report the reason to the user.`);
|
|
2068
|
+
console.log("");
|
|
2069
|
+
console.log(' Note: exit code 75 (EX_TEMPFAIL) from this command means "pending,');
|
|
2070
|
+
console.log(' retry later" \u2014 do not abort your workflow, follow the steps above.');
|
|
2001
2071
|
console.log("");
|
|
2002
2072
|
console.log(' Tip: Approve as "timed" or "always" in the browser to let this');
|
|
2003
2073
|
console.log(" grant be reused on subsequent invocations without re-approval.");
|
|
@@ -2139,6 +2209,7 @@ async function runShellMode(command, args) {
|
|
|
2139
2209
|
return;
|
|
2140
2210
|
}
|
|
2141
2211
|
printPendingGrantInfo(grant, idp);
|
|
2212
|
+
throw new CliExit(getAsyncExitCode());
|
|
2142
2213
|
}
|
|
2143
2214
|
async function tryAdapterModeFromShell(command, idp, args) {
|
|
2144
2215
|
const cmdString = extractShellCommandString(command);
|
|
@@ -2196,7 +2267,7 @@ async function tryAdapterModeFromShell(command, idp, args) {
|
|
|
2196
2267
|
return true;
|
|
2197
2268
|
}
|
|
2198
2269
|
printPendingGrantInfo(grant, idp);
|
|
2199
|
-
|
|
2270
|
+
throw new CliExit(getAsyncExitCode());
|
|
2200
2271
|
}
|
|
2201
2272
|
function execShellCommand(command) {
|
|
2202
2273
|
if (command.length === 0)
|
|
@@ -2276,6 +2347,7 @@ async function runAdapterMode(command, rawArgs, args) {
|
|
|
2276
2347
|
return;
|
|
2277
2348
|
}
|
|
2278
2349
|
printPendingGrantInfo(grant, idp);
|
|
2350
|
+
throw new CliExit(getAsyncExitCode());
|
|
2279
2351
|
}
|
|
2280
2352
|
async function runAudienceMode(audience, action, args) {
|
|
2281
2353
|
const auth = loadAuth();
|
|
@@ -2301,7 +2373,7 @@ async function runAudienceMode(audience, action, args) {
|
|
|
2301
2373
|
});
|
|
2302
2374
|
if (!shouldWaitForGrant(args)) {
|
|
2303
2375
|
printPendingGrantInfo(grant, idp);
|
|
2304
|
-
|
|
2376
|
+
throw new CliExit(getAsyncExitCode());
|
|
2305
2377
|
}
|
|
2306
2378
|
consola19.success(`Grant requested: ${grant.id}`);
|
|
2307
2379
|
consola19.info("Waiting for approval...");
|
|
@@ -2608,7 +2680,7 @@ var mcpCommand = defineCommand26({
|
|
|
2608
2680
|
if (transport !== "stdio" && transport !== "sse") {
|
|
2609
2681
|
throw new Error('Transport must be "stdio" or "sse"');
|
|
2610
2682
|
}
|
|
2611
|
-
const { startMcpServer } = await import("./server-
|
|
2683
|
+
const { startMcpServer } = await import("./server-GTATJDYX.js");
|
|
2612
2684
|
await startMcpServer(transport, port);
|
|
2613
2685
|
}
|
|
2614
2686
|
});
|
|
@@ -3100,7 +3172,7 @@ async function bestEffortGrantCount(idp) {
|
|
|
3100
3172
|
}
|
|
3101
3173
|
}
|
|
3102
3174
|
async function runHealth(args) {
|
|
3103
|
-
const version = true ? "0.
|
|
3175
|
+
const version = true ? "0.10.1" : "0.0.0";
|
|
3104
3176
|
const auth = loadAuth();
|
|
3105
3177
|
if (!auth) {
|
|
3106
3178
|
throw new CliError("Not logged in. Run `apes login` first.", 1);
|
|
@@ -3302,10 +3374,10 @@ if (shellRewrite) {
|
|
|
3302
3374
|
if (shellRewrite.action === "rewrite") {
|
|
3303
3375
|
process.argv = shellRewrite.argv;
|
|
3304
3376
|
} else if (shellRewrite.action === "version") {
|
|
3305
|
-
console.log(`ape-shell ${"0.
|
|
3377
|
+
console.log(`ape-shell ${"0.10.1"} (OpenApe DDISA shell wrapper)`);
|
|
3306
3378
|
process.exit(0);
|
|
3307
3379
|
} else if (shellRewrite.action === "help") {
|
|
3308
|
-
console.log(`ape-shell ${"0.
|
|
3380
|
+
console.log(`ape-shell ${"0.10.1"} \u2014 OpenApe DDISA shell wrapper`);
|
|
3309
3381
|
console.log("");
|
|
3310
3382
|
console.log("Usage:");
|
|
3311
3383
|
console.log(" ape-shell Start interactive grant-mediated REPL");
|
|
@@ -3320,7 +3392,7 @@ if (shellRewrite) {
|
|
|
3320
3392
|
console.log(" --help, -h Show this help message");
|
|
3321
3393
|
process.exit(0);
|
|
3322
3394
|
} else if (shellRewrite.action === "interactive") {
|
|
3323
|
-
const { runInteractiveShell } = await import("./orchestrator-
|
|
3395
|
+
const { runInteractiveShell } = await import("./orchestrator-QL3AT67U.js");
|
|
3324
3396
|
await runInteractiveShell();
|
|
3325
3397
|
process.exit(0);
|
|
3326
3398
|
} else {
|
|
@@ -3363,7 +3435,7 @@ var configCommand = defineCommand33({
|
|
|
3363
3435
|
var main = defineCommand33({
|
|
3364
3436
|
meta: {
|
|
3365
3437
|
name: "apes",
|
|
3366
|
-
version: "0.
|
|
3438
|
+
version: "0.10.1",
|
|
3367
3439
|
description: "Unified CLI for OpenApe"
|
|
3368
3440
|
},
|
|
3369
3441
|
subCommands: {
|