@openape/apes 0.5.5 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-AGHP6MNV.js → chunk-ZSJU7IXE.js} +19 -1
- package/dist/chunk-ZSJU7IXE.js.map +1 -0
- package/dist/cli.js +292 -179
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/{server-R2EVEMKX.js → server-IYR5LM63.js} +2 -2
- package/package.json +10 -6
- package/dist/chunk-AGHP6MNV.js.map +0 -1
- /package/dist/{server-R2EVEMKX.js.map → server-IYR5LM63.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
CliError,
|
|
4
|
+
CliExit,
|
|
3
5
|
parseDuration
|
|
4
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-ZSJU7IXE.js";
|
|
5
7
|
import {
|
|
6
8
|
loadEd25519PrivateKey
|
|
7
9
|
} from "./chunk-KVBHBOED.js";
|
|
@@ -22,8 +24,8 @@ import {
|
|
|
22
24
|
} from "./chunk-KXESKY4X.js";
|
|
23
25
|
|
|
24
26
|
// src/cli.ts
|
|
25
|
-
import
|
|
26
|
-
import { defineCommand as
|
|
27
|
+
import consola21 from "consola";
|
|
28
|
+
import { defineCommand as defineCommand26, runMain } from "citty";
|
|
27
29
|
|
|
28
30
|
// src/commands/auth/login.ts
|
|
29
31
|
import { Buffer } from "buffer";
|
|
@@ -57,8 +59,7 @@ var loginCommand = defineCommand({
|
|
|
57
59
|
const config = loadConfig();
|
|
58
60
|
const idp = args.idp || process.env.APES_IDP || process.env.GRAPES_IDP || config.defaults?.idp;
|
|
59
61
|
if (!idp) {
|
|
60
|
-
|
|
61
|
-
return process.exit(1);
|
|
62
|
+
throw new CliError("IdP URL required. Use --idp <url> or set APES_IDP.");
|
|
62
63
|
}
|
|
63
64
|
if (args.key) {
|
|
64
65
|
await loginWithKey(idp, args.key, args.email);
|
|
@@ -137,14 +138,12 @@ async function loginWithPKCE(idp) {
|
|
|
137
138
|
});
|
|
138
139
|
if (!tokenResponse.ok) {
|
|
139
140
|
const text = await tokenResponse.text();
|
|
140
|
-
|
|
141
|
-
return process.exit(1);
|
|
141
|
+
throw new CliError(`Token exchange failed: ${text}`);
|
|
142
142
|
}
|
|
143
143
|
const tokens = await tokenResponse.json();
|
|
144
144
|
const accessToken = tokens.access_token || tokens.id_token || tokens.assertion;
|
|
145
145
|
if (!accessToken) {
|
|
146
|
-
|
|
147
|
-
return process.exit(1);
|
|
146
|
+
throw new CliError("No access token received");
|
|
148
147
|
}
|
|
149
148
|
const payload = JSON.parse(atob(accessToken.split(".")[1]));
|
|
150
149
|
saveAuth({
|
|
@@ -162,8 +161,7 @@ async function loginWithKey(idp, keyPath, email) {
|
|
|
162
161
|
const { loadEd25519PrivateKey: loadEd25519PrivateKey2 } = await import("./ssh-key-Q7KG4K25.js");
|
|
163
162
|
const agentEmail = email;
|
|
164
163
|
if (!agentEmail) {
|
|
165
|
-
|
|
166
|
-
return process.exit(1);
|
|
164
|
+
throw new CliError("Agent email required for key-based login. Use --email <agent-email>");
|
|
167
165
|
}
|
|
168
166
|
const challengeUrl = await getAgentChallengeEndpoint(idp);
|
|
169
167
|
const challengeResp = await fetch(challengeUrl, {
|
|
@@ -172,8 +170,7 @@ async function loginWithKey(idp, keyPath, email) {
|
|
|
172
170
|
body: JSON.stringify({ agent_id: agentEmail })
|
|
173
171
|
});
|
|
174
172
|
if (!challengeResp.ok) {
|
|
175
|
-
|
|
176
|
-
return process.exit(1);
|
|
173
|
+
throw new CliError(`Challenge failed: ${await challengeResp.text()}`);
|
|
177
174
|
}
|
|
178
175
|
const { challenge } = await challengeResp.json();
|
|
179
176
|
const keyContent = readFileSync2(keyPath, "utf-8");
|
|
@@ -190,8 +187,7 @@ async function loginWithKey(idp, keyPath, email) {
|
|
|
190
187
|
})
|
|
191
188
|
});
|
|
192
189
|
if (!authResp.ok) {
|
|
193
|
-
|
|
194
|
-
return process.exit(1);
|
|
190
|
+
throw new CliError(`Authentication failed: ${await authResp.text()}`);
|
|
195
191
|
}
|
|
196
192
|
const { token, expires_in } = await authResp.json();
|
|
197
193
|
saveAuth({
|
|
@@ -228,8 +224,7 @@ var whoamiCommand = defineCommand3({
|
|
|
228
224
|
run() {
|
|
229
225
|
const auth = loadAuth();
|
|
230
226
|
if (!auth) {
|
|
231
|
-
|
|
232
|
-
return process.exit(1);
|
|
227
|
+
throw new CliError("Not logged in. Run `apes login` first.");
|
|
233
228
|
}
|
|
234
229
|
const isAgent = auth.email.includes("agent+");
|
|
235
230
|
const expiresAt = new Date(auth.expires_at * 1e3).toISOString();
|
|
@@ -275,8 +270,7 @@ var listCommand = defineCommand4({
|
|
|
275
270
|
async run({ args }) {
|
|
276
271
|
const idp = getIdpUrl();
|
|
277
272
|
if (!idp) {
|
|
278
|
-
|
|
279
|
-
return process.exit(1);
|
|
273
|
+
throw new CliError("No IdP URL configured. Run `apes login` first or pass --idp.");
|
|
280
274
|
}
|
|
281
275
|
const auth = loadAuth();
|
|
282
276
|
const grantsUrl = await getGrantsEndpoint(idp);
|
|
@@ -335,13 +329,11 @@ var inboxCommand = defineCommand5({
|
|
|
335
329
|
async run({ args }) {
|
|
336
330
|
const idp = getIdpUrl();
|
|
337
331
|
if (!idp) {
|
|
338
|
-
|
|
339
|
-
return process.exit(1);
|
|
332
|
+
throw new CliError("No IdP URL configured. Run `apes login` first.");
|
|
340
333
|
}
|
|
341
334
|
const auth = loadAuth();
|
|
342
335
|
if (!auth) {
|
|
343
|
-
|
|
344
|
-
return process.exit(1);
|
|
336
|
+
throw new CliError("Not logged in. Run `apes login` first.");
|
|
345
337
|
}
|
|
346
338
|
const grantsUrl = await getGrantsEndpoint(idp);
|
|
347
339
|
const params = new URLSearchParams();
|
|
@@ -477,8 +469,7 @@ var requestCommand = defineCommand7({
|
|
|
477
469
|
async run({ args }) {
|
|
478
470
|
const auth = loadAuth();
|
|
479
471
|
if (!auth) {
|
|
480
|
-
|
|
481
|
-
return process.exit(1);
|
|
472
|
+
throw new CliError("Not logged in. Run `apes login` first.");
|
|
482
473
|
}
|
|
483
474
|
const idp = getIdpUrl();
|
|
484
475
|
const grantsUrl = await getGrantsEndpoint(idp);
|
|
@@ -516,17 +507,14 @@ async function waitForApproval(grantsUrl, grantId) {
|
|
|
516
507
|
return;
|
|
517
508
|
}
|
|
518
509
|
if (grant.status === "denied") {
|
|
519
|
-
|
|
520
|
-
return process.exit(1);
|
|
510
|
+
throw new CliError("Grant denied.");
|
|
521
511
|
}
|
|
522
512
|
if (grant.status === "revoked") {
|
|
523
|
-
|
|
524
|
-
return process.exit(1);
|
|
513
|
+
throw new CliError("Grant revoked.");
|
|
525
514
|
}
|
|
526
515
|
await new Promise((r) => setTimeout(r, interval));
|
|
527
516
|
}
|
|
528
|
-
|
|
529
|
-
return process.exit(1);
|
|
517
|
+
throw new CliError("Timed out waiting for approval.");
|
|
530
518
|
}
|
|
531
519
|
|
|
532
520
|
// src/commands/grants/request-capability.ts
|
|
@@ -644,17 +632,14 @@ async function waitForApproval2(grantsUrl, grantId) {
|
|
|
644
632
|
return;
|
|
645
633
|
}
|
|
646
634
|
if (grant.status === "denied") {
|
|
647
|
-
|
|
648
|
-
process.exit(1);
|
|
635
|
+
throw new CliError("Grant denied.");
|
|
649
636
|
}
|
|
650
637
|
if (grant.status === "revoked") {
|
|
651
|
-
|
|
652
|
-
process.exit(1);
|
|
638
|
+
throw new CliError("Grant revoked.");
|
|
653
639
|
}
|
|
654
640
|
await new Promise((resolve2) => setTimeout(resolve2, interval));
|
|
655
641
|
}
|
|
656
|
-
|
|
657
|
-
process.exit(1);
|
|
642
|
+
throw new CliError("Timed out waiting for approval.");
|
|
658
643
|
}
|
|
659
644
|
var requestCapabilityCommand = defineCommand8({
|
|
660
645
|
meta: {
|
|
@@ -713,14 +698,12 @@ var requestCapabilityCommand = defineCommand8({
|
|
|
713
698
|
async run({ rawArgs }) {
|
|
714
699
|
const auth = loadAuth();
|
|
715
700
|
if (!auth) {
|
|
716
|
-
|
|
717
|
-
return process.exit(1);
|
|
701
|
+
throw new CliError("Not logged in. Run `apes login` first.");
|
|
718
702
|
}
|
|
719
703
|
const parsed = parseCapabilityArgs(rawArgs);
|
|
720
704
|
const idp = getIdpUrl(parsed.idp);
|
|
721
705
|
if (!idp) {
|
|
722
|
-
|
|
723
|
-
return process.exit(1);
|
|
706
|
+
throw new CliError("No IdP URL configured. Use --idp or log in first.");
|
|
724
707
|
}
|
|
725
708
|
const loaded = loadAdapter(parsed.cliId, parsed.adapter);
|
|
726
709
|
const resolved = resolveCapabilityRequest(loaded, {
|
|
@@ -822,6 +805,11 @@ var revokeCommand = defineCommand11({
|
|
|
822
805
|
type: "boolean",
|
|
823
806
|
description: "Revoke all own pending grants",
|
|
824
807
|
default: false
|
|
808
|
+
},
|
|
809
|
+
debug: {
|
|
810
|
+
type: "boolean",
|
|
811
|
+
description: "Print debug information (does not include full tokens)",
|
|
812
|
+
default: false
|
|
825
813
|
}
|
|
826
814
|
},
|
|
827
815
|
async run({ args }) {
|
|
@@ -829,25 +817,28 @@ var revokeCommand = defineCommand11({
|
|
|
829
817
|
const token = getAuthToken();
|
|
830
818
|
const idp = getIdpUrl();
|
|
831
819
|
const grantsUrl = await getGrantsEndpoint(idp);
|
|
832
|
-
if (
|
|
820
|
+
if (args.debug) {
|
|
833
821
|
consola10.debug(`idp: ${idp}`);
|
|
834
822
|
consola10.debug(`grantsUrl: ${grantsUrl}`);
|
|
835
823
|
consola10.debug(`auth.email: ${auth?.email}`);
|
|
836
824
|
consola10.debug(`auth.expires_at: ${auth?.expires_at} (now: ${Math.floor(Date.now() / 1e3)})`);
|
|
837
825
|
consola10.debug(`getAuthToken(): ${token ? `${token.substring(0, 20)}...` : "NULL"}`);
|
|
838
826
|
}
|
|
827
|
+
if (!auth || !token) {
|
|
828
|
+
throw new CliError("Authentication required. Run `apes login` and try again.");
|
|
829
|
+
}
|
|
839
830
|
const explicitIds = args.id ? [String(args.id), ...args._].filter(Boolean) : [];
|
|
840
831
|
if (args.allPending && explicitIds.length > 0) {
|
|
841
|
-
|
|
842
|
-
return process.exit(1);
|
|
832
|
+
throw new CliError("Use either --all-pending or grant IDs, not both.");
|
|
843
833
|
}
|
|
844
834
|
let ids;
|
|
845
835
|
if (args.allPending) {
|
|
846
836
|
const auth2 = loadAuth();
|
|
847
837
|
const response = await apiFetch(
|
|
848
|
-
`${grantsUrl}?status=pending&limit=100
|
|
838
|
+
`${grantsUrl}?status=pending&limit=100`,
|
|
839
|
+
{ token }
|
|
849
840
|
);
|
|
850
|
-
const ownPending = auth2?.email ? response.data.filter((g) => g.requester === auth2.email) : response.data;
|
|
841
|
+
const ownPending = auth2?.email ? response.data.filter((g) => g.request?.requester === auth2.email) : response.data;
|
|
851
842
|
if (ownPending.length === 0) {
|
|
852
843
|
consola10.info("No pending grants to revoke.");
|
|
853
844
|
return;
|
|
@@ -857,18 +848,17 @@ var revokeCommand = defineCommand11({
|
|
|
857
848
|
} else if (explicitIds.length > 0) {
|
|
858
849
|
ids = explicitIds;
|
|
859
850
|
} else {
|
|
860
|
-
|
|
861
|
-
return process.exit(1);
|
|
851
|
+
throw new CliError("Provide grant ID(s) or use --all-pending.");
|
|
862
852
|
}
|
|
863
853
|
if (ids.length === 1) {
|
|
864
|
-
await apiFetch(`${grantsUrl}/${ids[0]}/revoke`, { method: "POST", token
|
|
854
|
+
await apiFetch(`${grantsUrl}/${ids[0]}/revoke`, { method: "POST", token });
|
|
865
855
|
consola10.success(`Grant ${ids[0]} revoked.`);
|
|
866
856
|
return;
|
|
867
857
|
}
|
|
868
858
|
const operations = ids.map((id) => ({ id, action: "revoke" }));
|
|
869
859
|
const { results } = await apiFetch(
|
|
870
860
|
`${grantsUrl}/batch`,
|
|
871
|
-
{ method: "POST", body: { operations }, token
|
|
861
|
+
{ method: "POST", body: { operations }, token }
|
|
872
862
|
);
|
|
873
863
|
let succeeded = 0;
|
|
874
864
|
for (const r of results) {
|
|
@@ -880,8 +870,7 @@ var revokeCommand = defineCommand11({
|
|
|
880
870
|
}
|
|
881
871
|
}
|
|
882
872
|
if (succeeded < results.length) {
|
|
883
|
-
|
|
884
|
-
process.exit(1);
|
|
873
|
+
throw new CliError(`Revoked ${succeeded} of ${results.length} grants.`);
|
|
885
874
|
} else {
|
|
886
875
|
consola10.success(`All ${succeeded} grants revoked.`);
|
|
887
876
|
}
|
|
@@ -890,7 +879,6 @@ var revokeCommand = defineCommand11({
|
|
|
890
879
|
|
|
891
880
|
// src/commands/grants/token.ts
|
|
892
881
|
import { defineCommand as defineCommand12 } from "citty";
|
|
893
|
-
import consola11 from "consola";
|
|
894
882
|
var tokenCommand = defineCommand12({
|
|
895
883
|
meta: {
|
|
896
884
|
name: "token",
|
|
@@ -910,8 +898,7 @@ var tokenCommand = defineCommand12({
|
|
|
910
898
|
method: "POST"
|
|
911
899
|
});
|
|
912
900
|
if (!result.authz_jwt) {
|
|
913
|
-
|
|
914
|
-
return process.exit(1);
|
|
901
|
+
throw new CliError("No token received. Grant may not be approved.");
|
|
915
902
|
}
|
|
916
903
|
process.stdout.write(result.authz_jwt);
|
|
917
904
|
}
|
|
@@ -919,7 +906,7 @@ var tokenCommand = defineCommand12({
|
|
|
919
906
|
|
|
920
907
|
// src/commands/grants/delegate.ts
|
|
921
908
|
import { defineCommand as defineCommand13 } from "citty";
|
|
922
|
-
import
|
|
909
|
+
import consola11 from "consola";
|
|
923
910
|
var delegateCommand = defineCommand13({
|
|
924
911
|
meta: {
|
|
925
912
|
name: "delegate",
|
|
@@ -953,8 +940,7 @@ var delegateCommand = defineCommand13({
|
|
|
953
940
|
async run({ args }) {
|
|
954
941
|
const auth = loadAuth();
|
|
955
942
|
if (!auth) {
|
|
956
|
-
|
|
957
|
-
return process.exit(1);
|
|
943
|
+
throw new CliError("Not logged in. Run `apes login` first.");
|
|
958
944
|
}
|
|
959
945
|
const idp = getIdpUrl();
|
|
960
946
|
const delegationsUrl = await getDelegationsEndpoint(idp);
|
|
@@ -973,7 +959,7 @@ var delegateCommand = defineCommand13({
|
|
|
973
959
|
method: "POST",
|
|
974
960
|
body
|
|
975
961
|
});
|
|
976
|
-
|
|
962
|
+
consola11.success(`Delegation created: ${result.id}`);
|
|
977
963
|
console.log(` Delegate: ${args.to}`);
|
|
978
964
|
console.log(` Audience: ${args.at}`);
|
|
979
965
|
if (args.scopes)
|
|
@@ -986,7 +972,7 @@ var delegateCommand = defineCommand13({
|
|
|
986
972
|
|
|
987
973
|
// src/commands/grants/delegations.ts
|
|
988
974
|
import { defineCommand as defineCommand14 } from "citty";
|
|
989
|
-
import
|
|
975
|
+
import consola12 from "consola";
|
|
990
976
|
var delegationsCommand = defineCommand14({
|
|
991
977
|
meta: {
|
|
992
978
|
name: "delegations",
|
|
@@ -1008,7 +994,7 @@ var delegationsCommand = defineCommand14({
|
|
|
1008
994
|
return;
|
|
1009
995
|
}
|
|
1010
996
|
if (delegations.length === 0) {
|
|
1011
|
-
|
|
997
|
+
consola12.info("No delegations found.");
|
|
1012
998
|
return;
|
|
1013
999
|
}
|
|
1014
1000
|
for (const d of delegations) {
|
|
@@ -1021,7 +1007,7 @@ var delegationsCommand = defineCommand14({
|
|
|
1021
1007
|
|
|
1022
1008
|
// src/commands/adapter/index.ts
|
|
1023
1009
|
import { defineCommand as defineCommand15 } from "citty";
|
|
1024
|
-
import
|
|
1010
|
+
import consola13 from "consola";
|
|
1025
1011
|
import {
|
|
1026
1012
|
fetchRegistry,
|
|
1027
1013
|
findAdapter,
|
|
@@ -1070,7 +1056,7 @@ var adapterCommand = defineCommand15({
|
|
|
1070
1056
|
`);
|
|
1071
1057
|
return;
|
|
1072
1058
|
}
|
|
1073
|
-
|
|
1059
|
+
consola13.info(`Registry: ${index2.adapters.length} adapters (${index2.generated_at})`);
|
|
1074
1060
|
for (const a of index2.adapters) {
|
|
1075
1061
|
const installed = isInstalled(a.id, false) ? " [installed]" : "";
|
|
1076
1062
|
console.log(` ${a.id.padEnd(12)} ${a.name.padEnd(24)} ${a.category}${installed}`);
|
|
@@ -1092,7 +1078,7 @@ var adapterCommand = defineCommand15({
|
|
|
1092
1078
|
return;
|
|
1093
1079
|
}
|
|
1094
1080
|
if (local.length === 0) {
|
|
1095
|
-
|
|
1081
|
+
consola13.info("No adapters installed. Use `apes adapter list --remote` to see available adapters.");
|
|
1096
1082
|
return;
|
|
1097
1083
|
}
|
|
1098
1084
|
for (const a of local) {
|
|
@@ -1129,20 +1115,20 @@ var adapterCommand = defineCommand15({
|
|
|
1129
1115
|
for (const id of ids) {
|
|
1130
1116
|
const entry = findAdapter(index, id);
|
|
1131
1117
|
if (!entry) {
|
|
1132
|
-
|
|
1118
|
+
consola13.error(`Adapter "${id}" not found in registry. Use \`apes adapter search ${id}\` to search.`);
|
|
1133
1119
|
continue;
|
|
1134
1120
|
}
|
|
1135
1121
|
const conflicts = findConflictingAdapters(entry.executable, id);
|
|
1136
1122
|
if (conflicts.length > 0) {
|
|
1137
1123
|
for (const c of conflicts) {
|
|
1138
|
-
|
|
1139
|
-
|
|
1124
|
+
consola13.warn(`Conflicting adapter found: ${c.path} (id: ${c.adapterId}, executable: ${c.executable})`);
|
|
1125
|
+
consola13.warn(` Remove it with: apes adapter remove ${c.adapterId}`);
|
|
1140
1126
|
}
|
|
1141
1127
|
}
|
|
1142
1128
|
const result = await installAdapter(entry, { local });
|
|
1143
1129
|
const verb = result.updated ? "Updated" : "Installed";
|
|
1144
|
-
|
|
1145
|
-
|
|
1130
|
+
consola13.success(`${verb} ${result.id} \u2192 ${result.path}`);
|
|
1131
|
+
consola13.info(`Digest: ${result.digest}`);
|
|
1146
1132
|
}
|
|
1147
1133
|
}
|
|
1148
1134
|
}),
|
|
@@ -1169,14 +1155,14 @@ var adapterCommand = defineCommand15({
|
|
|
1169
1155
|
let failed = false;
|
|
1170
1156
|
for (const id of ids) {
|
|
1171
1157
|
if (removeAdapter(id, local)) {
|
|
1172
|
-
|
|
1158
|
+
consola13.success(`Removed adapter: ${id}`);
|
|
1173
1159
|
} else {
|
|
1174
|
-
|
|
1160
|
+
consola13.error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
|
|
1175
1161
|
failed = true;
|
|
1176
1162
|
}
|
|
1177
1163
|
}
|
|
1178
1164
|
if (failed)
|
|
1179
|
-
|
|
1165
|
+
throw new CliError("Some adapters could not be removed");
|
|
1180
1166
|
}
|
|
1181
1167
|
}),
|
|
1182
1168
|
info: defineCommand15({
|
|
@@ -1253,7 +1239,7 @@ var adapterCommand = defineCommand15({
|
|
|
1253
1239
|
return;
|
|
1254
1240
|
}
|
|
1255
1241
|
if (results.length === 0) {
|
|
1256
|
-
|
|
1242
|
+
consola13.info(`No adapters matching "${query}"`);
|
|
1257
1243
|
return;
|
|
1258
1244
|
}
|
|
1259
1245
|
for (const a of results) {
|
|
@@ -1288,29 +1274,29 @@ var adapterCommand = defineCommand15({
|
|
|
1288
1274
|
const targetId = args.id ? String(args.id) : void 0;
|
|
1289
1275
|
const targets = targetId ? [targetId] : index.adapters.map((a) => a.id).filter((id) => isInstalled(id, false));
|
|
1290
1276
|
if (targets.length === 0) {
|
|
1291
|
-
|
|
1277
|
+
consola13.info("No adapters installed to update.");
|
|
1292
1278
|
return;
|
|
1293
1279
|
}
|
|
1294
1280
|
for (const id of targets) {
|
|
1295
1281
|
const entry = findAdapter(index, id);
|
|
1296
1282
|
if (!entry) {
|
|
1297
|
-
|
|
1283
|
+
consola13.warn(`${id}: not found in registry, skipping`);
|
|
1298
1284
|
continue;
|
|
1299
1285
|
}
|
|
1300
1286
|
const localDigest = getInstalledDigest(id, false);
|
|
1301
1287
|
if (localDigest === entry.digest) {
|
|
1302
|
-
|
|
1288
|
+
consola13.info(`${id}: already up to date`);
|
|
1303
1289
|
continue;
|
|
1304
1290
|
}
|
|
1305
1291
|
if (localDigest && !args.yes) {
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1292
|
+
consola13.warn(`${id}: digest will change \u2014 existing grants for this adapter will be invalidated`);
|
|
1293
|
+
consola13.info(` Old: ${localDigest}`);
|
|
1294
|
+
consola13.info(` New: ${entry.digest}`);
|
|
1295
|
+
consola13.info(" Use --yes to confirm");
|
|
1310
1296
|
continue;
|
|
1311
1297
|
}
|
|
1312
1298
|
const result = await installAdapter(entry);
|
|
1313
|
-
|
|
1299
|
+
consola13.success(`Updated ${result.id} \u2192 ${result.path}`);
|
|
1314
1300
|
}
|
|
1315
1301
|
}
|
|
1316
1302
|
}),
|
|
@@ -1347,12 +1333,11 @@ var adapterCommand = defineCommand15({
|
|
|
1347
1333
|
if (!localDigest)
|
|
1348
1334
|
throw new Error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
|
|
1349
1335
|
if (localDigest === entry.digest) {
|
|
1350
|
-
|
|
1336
|
+
consola13.success(`${id}: digest matches registry`);
|
|
1351
1337
|
} else {
|
|
1352
|
-
consola14.error(`${id}: digest mismatch`);
|
|
1353
1338
|
console.log(` Local: ${localDigest}`);
|
|
1354
1339
|
console.log(` Registry: ${entry.digest}`);
|
|
1355
|
-
|
|
1340
|
+
throw new CliError(`${id}: digest mismatch`);
|
|
1356
1341
|
}
|
|
1357
1342
|
}
|
|
1358
1343
|
})
|
|
@@ -1374,7 +1359,7 @@ import {
|
|
|
1374
1359
|
verifyAndExecute,
|
|
1375
1360
|
waitForGrantStatus
|
|
1376
1361
|
} from "@openape/shapes";
|
|
1377
|
-
import
|
|
1362
|
+
import consola14 from "consola";
|
|
1378
1363
|
var runCommand = defineCommand16({
|
|
1379
1364
|
meta: {
|
|
1380
1365
|
name: "run",
|
|
@@ -1449,6 +1434,10 @@ async function runAdapterMode(command, rawArgs, args) {
|
|
|
1449
1434
|
const idp = getIdpUrl(args.idp);
|
|
1450
1435
|
if (!idp)
|
|
1451
1436
|
throw new Error("No IdP URL configured. Run `apes login` first or pass --idp.");
|
|
1437
|
+
if (args.as) {
|
|
1438
|
+
await runAudienceMode("escapes", command.join(" "), args);
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1452
1441
|
const adapterOpt = extractOption(rawArgs, "adapter");
|
|
1453
1442
|
const loaded = loadAdapter3(command[0], adapterOpt);
|
|
1454
1443
|
const resolved = await resolveCommand(loaded, command);
|
|
@@ -1456,7 +1445,7 @@ async function runAdapterMode(command, rawArgs, args) {
|
|
|
1456
1445
|
try {
|
|
1457
1446
|
const existingGrantId = await findExistingGrant(resolved, idp);
|
|
1458
1447
|
if (existingGrantId) {
|
|
1459
|
-
|
|
1448
|
+
consola14.info(`Reusing existing grant: ${existingGrantId}`);
|
|
1460
1449
|
const token2 = await fetchGrantToken(idp, existingGrantId);
|
|
1461
1450
|
await verifyAndExecute(token2, resolved);
|
|
1462
1451
|
return;
|
|
@@ -1468,17 +1457,17 @@ async function runAdapterMode(command, rawArgs, args) {
|
|
|
1468
1457
|
approval,
|
|
1469
1458
|
...args.reason ? { reason: args.reason } : {}
|
|
1470
1459
|
});
|
|
1471
|
-
|
|
1472
|
-
|
|
1460
|
+
consola14.info(`Grant requested: ${grant.id}`);
|
|
1461
|
+
consola14.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
|
|
1473
1462
|
if (grant.similar_grants?.similar_grants?.length) {
|
|
1474
1463
|
const n = grant.similar_grants.similar_grants.length;
|
|
1475
|
-
|
|
1476
|
-
|
|
1464
|
+
consola14.info("");
|
|
1465
|
+
consola14.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
|
|
1477
1466
|
if (grant.similar_grants.widened_details?.length) {
|
|
1478
1467
|
const wider = grant.similar_grants.widened_details.map((d) => d.permission).join(", ");
|
|
1479
|
-
|
|
1468
|
+
consola14.info(` Broader scope: ${wider}`);
|
|
1480
1469
|
}
|
|
1481
|
-
|
|
1470
|
+
consola14.info("");
|
|
1482
1471
|
}
|
|
1483
1472
|
const status = await waitForGrantStatus(idp, grant.id);
|
|
1484
1473
|
if (status !== "approved")
|
|
@@ -1489,14 +1478,13 @@ async function runAdapterMode(command, rawArgs, args) {
|
|
|
1489
1478
|
async function runAudienceMode(audience, action, args) {
|
|
1490
1479
|
const auth = loadAuth();
|
|
1491
1480
|
if (!auth) {
|
|
1492
|
-
|
|
1493
|
-
return process.exit(1);
|
|
1481
|
+
throw new CliError("Not logged in. Run `apes login` first.");
|
|
1494
1482
|
}
|
|
1495
1483
|
const idp = getIdpUrl(args.idp);
|
|
1496
1484
|
const grantsUrl = await getGrantsEndpoint(idp);
|
|
1497
1485
|
const command = action.split(" ");
|
|
1498
1486
|
const targetHost = args.host || hostname3();
|
|
1499
|
-
|
|
1487
|
+
consola14.info(`Requesting ${audience} grant on ${targetHost}: ${command.join(" ")}`);
|
|
1500
1488
|
const grant = await apiFetch(grantsUrl, {
|
|
1501
1489
|
method: "POST",
|
|
1502
1490
|
body: {
|
|
@@ -1509,36 +1497,35 @@ async function runAudienceMode(audience, action, args) {
|
|
|
1509
1497
|
...args.as ? { run_as: args.as } : {}
|
|
1510
1498
|
}
|
|
1511
1499
|
});
|
|
1512
|
-
|
|
1513
|
-
|
|
1500
|
+
consola14.success(`Grant requested: ${grant.id}`);
|
|
1501
|
+
consola14.info("Waiting for approval...");
|
|
1514
1502
|
const maxWait = 3e5;
|
|
1515
1503
|
const interval = 3e3;
|
|
1516
1504
|
const start = Date.now();
|
|
1517
1505
|
while (Date.now() - start < maxWait) {
|
|
1518
1506
|
const status = await apiFetch(`${grantsUrl}/${grant.id}`);
|
|
1519
1507
|
if (status.status === "approved") {
|
|
1520
|
-
|
|
1508
|
+
consola14.success("Grant approved!");
|
|
1521
1509
|
break;
|
|
1522
1510
|
}
|
|
1523
1511
|
if (status.status === "denied" || status.status === "revoked") {
|
|
1524
|
-
|
|
1525
|
-
return process.exit(1);
|
|
1512
|
+
throw new CliError(`Grant ${status.status}.`);
|
|
1526
1513
|
}
|
|
1527
1514
|
await new Promise((r) => setTimeout(r, interval));
|
|
1528
1515
|
}
|
|
1529
|
-
|
|
1516
|
+
consola14.info("Fetching grant token...");
|
|
1530
1517
|
const { authz_jwt } = await apiFetch(`${grantsUrl}/${grant.id}/token`, {
|
|
1531
1518
|
method: "POST"
|
|
1532
1519
|
});
|
|
1533
1520
|
if (audience === "escapes") {
|
|
1534
|
-
|
|
1521
|
+
consola14.info(`Executing: ${command.join(" ")}`);
|
|
1535
1522
|
try {
|
|
1536
1523
|
execFileSync(args["escapes-path"] || "escapes", ["--grant", authz_jwt, "--", ...command], {
|
|
1537
1524
|
stdio: "inherit"
|
|
1538
1525
|
});
|
|
1539
1526
|
} catch (err) {
|
|
1540
1527
|
const exitCode = err.status || 1;
|
|
1541
|
-
|
|
1528
|
+
throw new CliExit(exitCode);
|
|
1542
1529
|
}
|
|
1543
1530
|
} else {
|
|
1544
1531
|
process.stdout.write(authz_jwt);
|
|
@@ -1587,7 +1574,7 @@ var explainCommand = defineCommand17({
|
|
|
1587
1574
|
|
|
1588
1575
|
// src/commands/config/get.ts
|
|
1589
1576
|
import { defineCommand as defineCommand18 } from "citty";
|
|
1590
|
-
import
|
|
1577
|
+
import consola15 from "consola";
|
|
1591
1578
|
var configGetCommand = defineCommand18({
|
|
1592
1579
|
meta: {
|
|
1593
1580
|
name: "get",
|
|
@@ -1608,7 +1595,7 @@ var configGetCommand = defineCommand18({
|
|
|
1608
1595
|
if (idp)
|
|
1609
1596
|
console.log(idp);
|
|
1610
1597
|
else
|
|
1611
|
-
|
|
1598
|
+
consola15.info("No IdP configured.");
|
|
1612
1599
|
break;
|
|
1613
1600
|
}
|
|
1614
1601
|
case "email": {
|
|
@@ -1616,7 +1603,7 @@ var configGetCommand = defineCommand18({
|
|
|
1616
1603
|
if (auth?.email)
|
|
1617
1604
|
console.log(auth.email);
|
|
1618
1605
|
else
|
|
1619
|
-
|
|
1606
|
+
consola15.info("Not logged in.");
|
|
1620
1607
|
break;
|
|
1621
1608
|
}
|
|
1622
1609
|
default: {
|
|
@@ -1629,11 +1616,10 @@ var configGetCommand = defineCommand18({
|
|
|
1629
1616
|
if (sectionObj && field in sectionObj) {
|
|
1630
1617
|
console.log(sectionObj[field]);
|
|
1631
1618
|
} else {
|
|
1632
|
-
|
|
1619
|
+
consola15.info(`Key "${key}" not set.`);
|
|
1633
1620
|
}
|
|
1634
1621
|
} else {
|
|
1635
|
-
|
|
1636
|
-
process.exit(1);
|
|
1622
|
+
throw new CliError(`Unknown key: "${key}". Use: idp, email, defaults.idp, defaults.approval, agent.key, agent.email`);
|
|
1637
1623
|
}
|
|
1638
1624
|
}
|
|
1639
1625
|
}
|
|
@@ -1642,7 +1628,7 @@ var configGetCommand = defineCommand18({
|
|
|
1642
1628
|
|
|
1643
1629
|
// src/commands/config/set.ts
|
|
1644
1630
|
import { defineCommand as defineCommand19 } from "citty";
|
|
1645
|
-
import
|
|
1631
|
+
import consola16 from "consola";
|
|
1646
1632
|
var configSetCommand = defineCommand19({
|
|
1647
1633
|
meta: {
|
|
1648
1634
|
name: "set",
|
|
@@ -1666,8 +1652,7 @@ var configSetCommand = defineCommand19({
|
|
|
1666
1652
|
const config = loadConfig();
|
|
1667
1653
|
const parts = key.split(".");
|
|
1668
1654
|
if (parts.length !== 2) {
|
|
1669
|
-
|
|
1670
|
-
return process.exit(1);
|
|
1655
|
+
throw new CliError(`Invalid key: "${key}". Use: defaults.idp, defaults.approval, agent.key, agent.email`);
|
|
1671
1656
|
}
|
|
1672
1657
|
const [section, field] = parts;
|
|
1673
1658
|
if (section === "defaults") {
|
|
@@ -1677,22 +1662,19 @@ var configSetCommand = defineCommand19({
|
|
|
1677
1662
|
config.agent = config.agent || {};
|
|
1678
1663
|
config.agent[field] = value;
|
|
1679
1664
|
} else {
|
|
1680
|
-
|
|
1681
|
-
return process.exit(1);
|
|
1665
|
+
throw new CliError(`Unknown section: "${section}". Use: defaults, agent`);
|
|
1682
1666
|
}
|
|
1683
1667
|
saveConfig(config);
|
|
1684
|
-
|
|
1668
|
+
consola16.success(`Set ${key} = ${value}`);
|
|
1685
1669
|
}
|
|
1686
1670
|
});
|
|
1687
1671
|
|
|
1688
1672
|
// src/commands/fetch/index.ts
|
|
1689
1673
|
import { defineCommand as defineCommand20 } from "citty";
|
|
1690
|
-
import consola18 from "consola";
|
|
1691
1674
|
async function doRequest(method, url, body, contentType, raw, showHeaders) {
|
|
1692
1675
|
const token = getAuthToken();
|
|
1693
1676
|
if (!token) {
|
|
1694
|
-
|
|
1695
|
-
return process.exit(1);
|
|
1677
|
+
throw new CliError("Not authenticated. Run `apes login` first.");
|
|
1696
1678
|
}
|
|
1697
1679
|
const response = await fetch(url, {
|
|
1698
1680
|
method,
|
|
@@ -1721,7 +1703,7 @@ async function doRequest(method, url, body, contentType, raw, showHeaders) {
|
|
|
1721
1703
|
}
|
|
1722
1704
|
}
|
|
1723
1705
|
if (!response.ok) {
|
|
1724
|
-
|
|
1706
|
+
throw new CliError(`HTTP ${response.status} ${response.statusText}`);
|
|
1725
1707
|
}
|
|
1726
1708
|
}
|
|
1727
1709
|
var fetchCommand = defineCommand20({
|
|
@@ -1819,7 +1801,7 @@ var mcpCommand = defineCommand21({
|
|
|
1819
1801
|
if (transport !== "stdio" && transport !== "sse") {
|
|
1820
1802
|
throw new Error('Transport must be "stdio" or "sse"');
|
|
1821
1803
|
}
|
|
1822
|
-
const { startMcpServer } = await import("./server-
|
|
1804
|
+
const { startMcpServer } = await import("./server-IYR5LM63.js");
|
|
1823
1805
|
await startMcpServer(transport, port);
|
|
1824
1806
|
}
|
|
1825
1807
|
});
|
|
@@ -1830,7 +1812,7 @@ import { randomBytes } from "crypto";
|
|
|
1830
1812
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
1831
1813
|
import { join } from "path";
|
|
1832
1814
|
import { defineCommand as defineCommand22 } from "citty";
|
|
1833
|
-
import
|
|
1815
|
+
import consola17 from "consola";
|
|
1834
1816
|
var DEFAULT_IDP_URL = "https://id.openape.at";
|
|
1835
1817
|
async function downloadTemplate(repo, targetDir) {
|
|
1836
1818
|
const { downloadTemplate: gigetDownload } = await import("giget");
|
|
@@ -1847,16 +1829,16 @@ function installDeps(dir) {
|
|
|
1847
1829
|
}
|
|
1848
1830
|
}
|
|
1849
1831
|
async function promptChoice(message, choices) {
|
|
1850
|
-
const result = await
|
|
1832
|
+
const result = await consola17.prompt(message, { type: "select", options: choices });
|
|
1851
1833
|
if (typeof result === "symbol") {
|
|
1852
|
-
|
|
1834
|
+
throw new CliExit(0);
|
|
1853
1835
|
}
|
|
1854
1836
|
return result;
|
|
1855
1837
|
}
|
|
1856
1838
|
async function promptText(message, defaultValue) {
|
|
1857
|
-
const result = await
|
|
1839
|
+
const result = await consola17.prompt(message, { type: "text", default: defaultValue, placeholder: defaultValue });
|
|
1858
1840
|
if (typeof result === "symbol") {
|
|
1859
|
-
|
|
1841
|
+
throw new CliExit(0);
|
|
1860
1842
|
}
|
|
1861
1843
|
return result || defaultValue || "";
|
|
1862
1844
|
}
|
|
@@ -1903,23 +1885,22 @@ var initCommand = defineCommand22({
|
|
|
1903
1885
|
async function initSP(targetDir) {
|
|
1904
1886
|
const dir = targetDir || "my-app";
|
|
1905
1887
|
if (existsSync(join(dir, "package.json"))) {
|
|
1906
|
-
|
|
1907
|
-
return process.exit(1);
|
|
1888
|
+
throw new CliError(`Directory "${dir}" already contains a project.`);
|
|
1908
1889
|
}
|
|
1909
|
-
|
|
1890
|
+
consola17.start("Scaffolding SP starter...");
|
|
1910
1891
|
await downloadTemplate("openape-ai/openape-sp-starter", dir);
|
|
1911
|
-
|
|
1912
|
-
|
|
1892
|
+
consola17.success("Scaffolded from openape-sp-starter");
|
|
1893
|
+
consola17.start("Installing dependencies...");
|
|
1913
1894
|
installDeps(dir);
|
|
1914
|
-
|
|
1895
|
+
consola17.success("Dependencies installed");
|
|
1915
1896
|
const envExample = join(dir, ".env.example");
|
|
1916
1897
|
const envFile = join(dir, ".env");
|
|
1917
1898
|
if (existsSync(envExample) && !existsSync(envFile)) {
|
|
1918
1899
|
copyFileSync(envExample, envFile);
|
|
1919
|
-
|
|
1900
|
+
consola17.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
|
|
1920
1901
|
}
|
|
1921
1902
|
console.log("");
|
|
1922
|
-
|
|
1903
|
+
consola17.box([
|
|
1923
1904
|
`cd ${dir}`,
|
|
1924
1905
|
"npm run dev",
|
|
1925
1906
|
"",
|
|
@@ -1929,8 +1910,7 @@ async function initSP(targetDir) {
|
|
|
1929
1910
|
async function initIdP(targetDir) {
|
|
1930
1911
|
const dir = targetDir || "my-idp";
|
|
1931
1912
|
if (existsSync(join(dir, "package.json"))) {
|
|
1932
|
-
|
|
1933
|
-
return process.exit(1);
|
|
1913
|
+
throw new CliError(`Directory "${dir}" already contains a project.`);
|
|
1934
1914
|
}
|
|
1935
1915
|
const domain = await promptText("Domain for the IdP", "localhost");
|
|
1936
1916
|
const storage = await promptChoice("Storage backend", [
|
|
@@ -1939,15 +1919,15 @@ async function initIdP(targetDir) {
|
|
|
1939
1919
|
"s3 (S3-compatible)"
|
|
1940
1920
|
]);
|
|
1941
1921
|
const adminEmail = await promptText("Admin email");
|
|
1942
|
-
|
|
1922
|
+
consola17.start("Scaffolding IdP starter...");
|
|
1943
1923
|
await downloadTemplate("openape-ai/openape-idp-starter", dir);
|
|
1944
|
-
|
|
1945
|
-
|
|
1924
|
+
consola17.success("Scaffolded from openape-idp-starter");
|
|
1925
|
+
consola17.start("Installing dependencies...");
|
|
1946
1926
|
installDeps(dir);
|
|
1947
|
-
|
|
1927
|
+
consola17.success("Dependencies installed");
|
|
1948
1928
|
const sessionSecret = randomBytes(32).toString("hex");
|
|
1949
1929
|
const managementToken = randomBytes(32).toString("hex");
|
|
1950
|
-
|
|
1930
|
+
consola17.success("Secrets generated");
|
|
1951
1931
|
const isLocalhost = domain === "localhost";
|
|
1952
1932
|
const origin = isLocalhost ? "http://localhost:3000" : `https://${domain}`;
|
|
1953
1933
|
const envContent = [
|
|
@@ -1961,10 +1941,11 @@ async function initIdP(targetDir) {
|
|
|
1961
1941
|
`NUXT_OPENAPE_RP_ID=${domain}`,
|
|
1962
1942
|
`NUXT_OPENAPE_RP_ORIGIN=${origin}`
|
|
1963
1943
|
].join("\n");
|
|
1964
|
-
writeFileSync(join(dir, ".env"), envContent
|
|
1965
|
-
|
|
1944
|
+
writeFileSync(join(dir, ".env"), `${envContent}
|
|
1945
|
+
`, { mode: 384 });
|
|
1946
|
+
consola17.success(".env created");
|
|
1966
1947
|
console.log("");
|
|
1967
|
-
|
|
1948
|
+
consola17.box([
|
|
1968
1949
|
`cd ${dir}`,
|
|
1969
1950
|
"npm run dev",
|
|
1970
1951
|
"",
|
|
@@ -1987,7 +1968,7 @@ import { generateKeyPairSync, sign } from "crypto";
|
|
|
1987
1968
|
import { dirname, resolve } from "path";
|
|
1988
1969
|
import { homedir } from "os";
|
|
1989
1970
|
import { defineCommand as defineCommand23 } from "citty";
|
|
1990
|
-
import
|
|
1971
|
+
import consola18 from "consola";
|
|
1991
1972
|
var DEFAULT_IDP_URL2 = "https://id.openape.at";
|
|
1992
1973
|
var DEFAULT_KEY_PATH = "~/.ssh/id_ed25519";
|
|
1993
1974
|
var POLL_INTERVAL = 3e3;
|
|
@@ -2092,38 +2073,48 @@ var enrollCommand = defineCommand23({
|
|
|
2092
2073
|
}
|
|
2093
2074
|
},
|
|
2094
2075
|
async run({ args }) {
|
|
2095
|
-
const idp = args.idp || await
|
|
2096
|
-
|
|
2076
|
+
const idp = args.idp || await consola18.prompt("IdP URL", { type: "text", default: DEFAULT_IDP_URL2, placeholder: DEFAULT_IDP_URL2 }).then((r) => {
|
|
2077
|
+
if (typeof r === "symbol") throw new CliExit(0);
|
|
2078
|
+
return r;
|
|
2079
|
+
}) || DEFAULT_IDP_URL2;
|
|
2080
|
+
const agentName = args.name || await consola18.prompt("Agent name", { type: "text", placeholder: "deploy-bot" }).then((r) => {
|
|
2081
|
+
if (typeof r === "symbol") throw new CliExit(0);
|
|
2082
|
+
return r;
|
|
2083
|
+
});
|
|
2097
2084
|
if (!agentName) {
|
|
2098
|
-
|
|
2099
|
-
return process.exit(1);
|
|
2085
|
+
throw new CliError("Agent name is required.");
|
|
2100
2086
|
}
|
|
2101
|
-
const keyPath = args.key || await
|
|
2087
|
+
const keyPath = args.key || await consola18.prompt("Ed25519 key", { type: "text", default: DEFAULT_KEY_PATH, placeholder: DEFAULT_KEY_PATH }).then((r) => {
|
|
2088
|
+
if (typeof r === "symbol") throw new CliExit(0);
|
|
2089
|
+
return r;
|
|
2090
|
+
}) || DEFAULT_KEY_PATH;
|
|
2102
2091
|
const resolvedKey = resolvePath(keyPath);
|
|
2103
2092
|
let publicKey;
|
|
2104
2093
|
if (existsSync2(resolvedKey)) {
|
|
2105
2094
|
publicKey = readPublicKey(resolvedKey);
|
|
2106
|
-
|
|
2095
|
+
consola18.success(`Using existing key ${keyPath}`);
|
|
2107
2096
|
} else {
|
|
2108
|
-
|
|
2097
|
+
consola18.start(`Generating Ed25519 key pair at ${keyPath}...`);
|
|
2109
2098
|
publicKey = generateAndSaveKey(keyPath);
|
|
2110
|
-
|
|
2099
|
+
consola18.success(`Key pair generated at ${keyPath}`);
|
|
2111
2100
|
}
|
|
2112
2101
|
const encodedKey = encodeURIComponent(publicKey);
|
|
2113
2102
|
const enrollUrl = `${idp}/enroll?name=${encodeURIComponent(agentName)}&key=${encodedKey}`;
|
|
2114
|
-
|
|
2115
|
-
|
|
2103
|
+
consola18.info("Opening browser for enrollment...");
|
|
2104
|
+
consola18.info(`\u2192 ${idp}/enroll`);
|
|
2116
2105
|
openBrowser2(enrollUrl);
|
|
2117
2106
|
console.log("");
|
|
2118
|
-
const agentEmail = await
|
|
2107
|
+
const agentEmail = await consola18.prompt(
|
|
2119
2108
|
"Agent email (shown in browser after enrollment)",
|
|
2120
2109
|
{ type: "text", placeholder: `agent+${agentName}@...` }
|
|
2121
|
-
).then((r) =>
|
|
2110
|
+
).then((r) => {
|
|
2111
|
+
if (typeof r === "symbol") throw new CliExit(0);
|
|
2112
|
+
return r;
|
|
2113
|
+
});
|
|
2122
2114
|
if (!agentEmail) {
|
|
2123
|
-
|
|
2124
|
-
return process.exit(1);
|
|
2115
|
+
throw new CliError("Agent email is required to verify enrollment.");
|
|
2125
2116
|
}
|
|
2126
|
-
|
|
2117
|
+
consola18.start("Verifying enrollment...");
|
|
2127
2118
|
const { token, expiresIn } = await pollForEnrollment(idp, agentEmail, keyPath);
|
|
2128
2119
|
saveAuth({
|
|
2129
2120
|
idp,
|
|
@@ -2135,16 +2126,16 @@ var enrollCommand = defineCommand23({
|
|
|
2135
2126
|
config.defaults = { ...config.defaults, idp };
|
|
2136
2127
|
config.agent = { key: keyPath, email: agentEmail };
|
|
2137
2128
|
saveConfig(config);
|
|
2138
|
-
|
|
2139
|
-
|
|
2129
|
+
consola18.success(`Agent enrolled as ${agentEmail}`);
|
|
2130
|
+
consola18.success("Config saved to ~/.config/apes/");
|
|
2140
2131
|
console.log("");
|
|
2141
|
-
|
|
2132
|
+
consola18.info("Verify with: apes whoami");
|
|
2142
2133
|
}
|
|
2143
2134
|
});
|
|
2144
2135
|
|
|
2145
2136
|
// src/commands/dns-check.ts
|
|
2146
2137
|
import { defineCommand as defineCommand24 } from "citty";
|
|
2147
|
-
import
|
|
2138
|
+
import consola19 from "consola";
|
|
2148
2139
|
import { resolveDDISA } from "@openape/core";
|
|
2149
2140
|
var dnsCheckCommand = defineCommand24({
|
|
2150
2141
|
meta: {
|
|
@@ -2160,17 +2151,16 @@ var dnsCheckCommand = defineCommand24({
|
|
|
2160
2151
|
},
|
|
2161
2152
|
async run({ args }) {
|
|
2162
2153
|
const domain = args.domain;
|
|
2163
|
-
|
|
2154
|
+
consola19.start(`Checking _ddisa.${domain}...`);
|
|
2164
2155
|
try {
|
|
2165
2156
|
const result = await resolveDDISA(domain);
|
|
2166
2157
|
if (!result) {
|
|
2167
|
-
consola21.error(`No DDISA record found for ${domain}`);
|
|
2168
2158
|
console.log("");
|
|
2169
2159
|
console.log("To set up DDISA, add a DNS TXT record:");
|
|
2170
2160
|
console.log(` _ddisa.${domain} TXT "v=ddisa1 idp=https://id.${domain}"`);
|
|
2171
|
-
|
|
2161
|
+
throw new CliError(`No DDISA record found for ${domain}`);
|
|
2172
2162
|
}
|
|
2173
|
-
|
|
2163
|
+
consola19.success(`_ddisa.${domain} \u2192 ${result.idp}`);
|
|
2174
2164
|
console.log("");
|
|
2175
2165
|
console.log(` Version: ${result.version || "ddisa1"}`);
|
|
2176
2166
|
console.log(` IdP URL: ${result.idp}`);
|
|
@@ -2179,14 +2169,14 @@ var dnsCheckCommand = defineCommand24({
|
|
|
2179
2169
|
if (result.priority !== void 0)
|
|
2180
2170
|
console.log(` Priority: ${result.priority}`);
|
|
2181
2171
|
console.log("");
|
|
2182
|
-
|
|
2172
|
+
consola19.start(`Verifying IdP at ${result.idp}...`);
|
|
2183
2173
|
const discoResp = await fetch(`${result.idp}/.well-known/openid-configuration`);
|
|
2184
2174
|
if (!discoResp.ok) {
|
|
2185
|
-
|
|
2175
|
+
consola19.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
|
|
2186
2176
|
return;
|
|
2187
2177
|
}
|
|
2188
2178
|
const disco = await discoResp.json();
|
|
2189
|
-
|
|
2179
|
+
consola19.success(`IdP is reachable`);
|
|
2190
2180
|
console.log(` Issuer: ${disco.issuer}`);
|
|
2191
2181
|
console.log(` DDISA: v${disco.ddisa_version || "?"}`);
|
|
2192
2182
|
if (disco.ddisa_auth_methods_supported) {
|
|
@@ -2196,15 +2186,130 @@ var dnsCheckCommand = defineCommand24({
|
|
|
2196
2186
|
console.log(` Grants: ${disco.openape_grant_types_supported.join(", ")}`);
|
|
2197
2187
|
}
|
|
2198
2188
|
} catch (err) {
|
|
2199
|
-
|
|
2200
|
-
|
|
2189
|
+
throw new CliError(`DNS check failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
});
|
|
2193
|
+
|
|
2194
|
+
// src/commands/workflows.ts
|
|
2195
|
+
import { defineCommand as defineCommand25 } from "citty";
|
|
2196
|
+
import consola20 from "consola";
|
|
2197
|
+
|
|
2198
|
+
// src/guides/index.ts
|
|
2199
|
+
var guides = [
|
|
2200
|
+
{
|
|
2201
|
+
id: "timed-session",
|
|
2202
|
+
title: "Timed maintenance session",
|
|
2203
|
+
description: "Request a timed grant for multiple commands without per-command approval.",
|
|
2204
|
+
steps: [
|
|
2205
|
+
{ description: "Request a timed grant (e.g. 1 hour)", command: "apes run --approval timed -- <your-command>" },
|
|
2206
|
+
{ description: "Approve the grant in the browser (link is printed)" },
|
|
2207
|
+
{ description: "Subsequent commands reuse the timed grant until it expires" },
|
|
2208
|
+
{ note: "Use --approval always for standing permissions (revoke manually when done)" }
|
|
2209
|
+
]
|
|
2210
|
+
},
|
|
2211
|
+
{
|
|
2212
|
+
id: "agent-onboarding",
|
|
2213
|
+
title: "Onboard a new agent",
|
|
2214
|
+
description: "Register an AI agent with a DDISA identity in under 3 minutes.",
|
|
2215
|
+
steps: [
|
|
2216
|
+
{ description: "Initialize a new project (optional)", command: "apes init --sp my-app" },
|
|
2217
|
+
{ description: "Enroll the agent at an IdP", command: "apes enroll" },
|
|
2218
|
+
{ description: "Verify enrollment", command: "apes whoami" },
|
|
2219
|
+
{ description: "Check DNS discovery", command: "apes dns-check" }
|
|
2220
|
+
]
|
|
2221
|
+
},
|
|
2222
|
+
{
|
|
2223
|
+
id: "delegation",
|
|
2224
|
+
title: "Delegate permissions",
|
|
2225
|
+
description: "Let an agent act on your behalf at a specific service.",
|
|
2226
|
+
steps: [
|
|
2227
|
+
{ description: "Create a delegation", command: "apes grants delegate --to agent@example.com --at api.example.com" },
|
|
2228
|
+
{ description: "List active delegations", command: "apes grants delegations" },
|
|
2229
|
+
{ description: "Revoke when no longer needed", command: "apes grants revoke <delegation-id>" }
|
|
2230
|
+
]
|
|
2231
|
+
},
|
|
2232
|
+
{
|
|
2233
|
+
id: "privilege-escalation",
|
|
2234
|
+
title: "Run commands as root (escapes)",
|
|
2235
|
+
description: "Execute privileged commands with grant-verified escalation.",
|
|
2236
|
+
steps: [
|
|
2237
|
+
{ description: "Request a grant to run a command as root", command: "apes run --as root -- apt-get upgrade" },
|
|
2238
|
+
{ description: "Approve the grant in the browser" },
|
|
2239
|
+
{ description: "The command executes via escapes with verified authorization" },
|
|
2240
|
+
{ note: "escapes must be installed on the target machine (cargo build && sudo make install)" }
|
|
2241
|
+
]
|
|
2242
|
+
}
|
|
2243
|
+
];
|
|
2244
|
+
|
|
2245
|
+
// src/commands/workflows.ts
|
|
2246
|
+
var workflowsCommand = defineCommand25({
|
|
2247
|
+
meta: {
|
|
2248
|
+
name: "workflows",
|
|
2249
|
+
description: "Discover workflow guides"
|
|
2250
|
+
},
|
|
2251
|
+
args: {
|
|
2252
|
+
id: {
|
|
2253
|
+
type: "positional",
|
|
2254
|
+
description: "Guide ID to show (omit for list)",
|
|
2255
|
+
required: false
|
|
2256
|
+
},
|
|
2257
|
+
json: {
|
|
2258
|
+
type: "boolean",
|
|
2259
|
+
description: "Output as JSON",
|
|
2260
|
+
default: false
|
|
2261
|
+
}
|
|
2262
|
+
},
|
|
2263
|
+
run({ args }) {
|
|
2264
|
+
if (args.id) {
|
|
2265
|
+
const guide = guides.find((g) => g.id === String(args.id));
|
|
2266
|
+
if (!guide) {
|
|
2267
|
+
consola20.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
|
|
2268
|
+
throw new CliError(`Guide not found: ${args.id}`);
|
|
2269
|
+
}
|
|
2270
|
+
if (args.json) {
|
|
2271
|
+
console.log(JSON.stringify(guide, null, 2));
|
|
2272
|
+
return;
|
|
2273
|
+
}
|
|
2274
|
+
console.log(`
|
|
2275
|
+
${guide.title}`);
|
|
2276
|
+
console.log(` ${guide.description}
|
|
2277
|
+
`);
|
|
2278
|
+
for (let i = 0; i < guide.steps.length; i++) {
|
|
2279
|
+
const step = guide.steps[i];
|
|
2280
|
+
if (step.note) {
|
|
2281
|
+
console.log(` Note: ${step.note}`);
|
|
2282
|
+
} else {
|
|
2283
|
+
console.log(` ${i + 1}. ${step.description}`);
|
|
2284
|
+
if (step.command) {
|
|
2285
|
+
console.log(` $ ${step.command}`);
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
console.log();
|
|
2290
|
+
return;
|
|
2291
|
+
}
|
|
2292
|
+
if (args.json) {
|
|
2293
|
+
console.log(JSON.stringify(guides.map((g) => ({ id: g.id, title: g.title, description: g.description })), null, 2));
|
|
2294
|
+
return;
|
|
2295
|
+
}
|
|
2296
|
+
console.log("\n Workflow Guides\n");
|
|
2297
|
+
for (const guide of guides) {
|
|
2298
|
+
console.log(` ${guide.id.padEnd(24)} ${guide.title}`);
|
|
2201
2299
|
}
|
|
2300
|
+
console.log(`
|
|
2301
|
+
Show a guide: apes workflows <id>
|
|
2302
|
+
`);
|
|
2202
2303
|
}
|
|
2203
2304
|
});
|
|
2204
2305
|
|
|
2205
2306
|
// src/cli.ts
|
|
2307
|
+
process.stdout.on("error", (err) => {
|
|
2308
|
+
if (err.code === "EPIPE") process.exit(0);
|
|
2309
|
+
throw err;
|
|
2310
|
+
});
|
|
2206
2311
|
var debug = process.argv.includes("--debug");
|
|
2207
|
-
var grantsCommand =
|
|
2312
|
+
var grantsCommand = defineCommand26({
|
|
2208
2313
|
meta: {
|
|
2209
2314
|
name: "grants",
|
|
2210
2315
|
description: "Grant management"
|
|
@@ -2223,7 +2328,7 @@ var grantsCommand = defineCommand25({
|
|
|
2223
2328
|
delegations: delegationsCommand
|
|
2224
2329
|
}
|
|
2225
2330
|
});
|
|
2226
|
-
var configCommand =
|
|
2331
|
+
var configCommand = defineCommand26({
|
|
2227
2332
|
meta: {
|
|
2228
2333
|
name: "config",
|
|
2229
2334
|
description: "Configuration management"
|
|
@@ -2233,10 +2338,10 @@ var configCommand = defineCommand25({
|
|
|
2233
2338
|
set: configSetCommand
|
|
2234
2339
|
}
|
|
2235
2340
|
});
|
|
2236
|
-
var main =
|
|
2341
|
+
var main = defineCommand26({
|
|
2237
2342
|
meta: {
|
|
2238
2343
|
name: "apes",
|
|
2239
|
-
version: "0.
|
|
2344
|
+
version: "0.6.0",
|
|
2240
2345
|
description: "Unified CLI for OpenApe"
|
|
2241
2346
|
},
|
|
2242
2347
|
subCommands: {
|
|
@@ -2252,14 +2357,22 @@ var main = defineCommand25({
|
|
|
2252
2357
|
adapter: adapterCommand,
|
|
2253
2358
|
config: configCommand,
|
|
2254
2359
|
fetch: fetchCommand,
|
|
2255
|
-
mcp: mcpCommand
|
|
2360
|
+
mcp: mcpCommand,
|
|
2361
|
+
workflows: workflowsCommand
|
|
2256
2362
|
}
|
|
2257
2363
|
});
|
|
2258
2364
|
runMain(main).catch((err) => {
|
|
2365
|
+
if (err instanceof CliExit) {
|
|
2366
|
+
process.exit(err.exitCode);
|
|
2367
|
+
}
|
|
2368
|
+
if (err instanceof CliError) {
|
|
2369
|
+
consola21.error(err.message);
|
|
2370
|
+
process.exit(err.exitCode);
|
|
2371
|
+
}
|
|
2259
2372
|
if (debug) {
|
|
2260
|
-
|
|
2373
|
+
consola21.error(err);
|
|
2261
2374
|
} else {
|
|
2262
|
-
|
|
2375
|
+
consola21.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
|
|
2263
2376
|
}
|
|
2264
2377
|
process.exit(1);
|
|
2265
2378
|
});
|