@openape/apes 0.8.0 → 0.9.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
@@ -37,10 +37,11 @@ import {
37
37
  removeAdapter,
38
38
  resolveCapabilityRequest,
39
39
  resolveCommand,
40
+ resolveFromGrant,
40
41
  searchAdapters,
41
42
  verifyAndExecute,
42
43
  waitForGrantStatus
43
- } from "./chunk-HGCKOCJA.js";
44
+ } from "./chunk-UQ673USC.js";
44
45
  import {
45
46
  AUTH_FILE,
46
47
  CONFIG_DIR,
@@ -54,7 +55,7 @@ import {
54
55
  } from "./chunk-AZVY3X7Q.js";
55
56
 
56
57
  // src/cli.ts
57
- import consola26 from "consola";
58
+ import consola27 from "consola";
58
59
 
59
60
  // src/ape-shell.ts
60
61
  import path from "path";
@@ -84,7 +85,7 @@ function rewriteApeShellArgs(argv, argv0) {
84
85
  }
85
86
 
86
87
  // src/cli.ts
87
- import { defineCommand as defineCommand32, runMain } from "citty";
88
+ import { defineCommand as defineCommand33, runMain } from "citty";
88
89
 
89
90
  // src/commands/auth/login.ts
90
91
  import { Buffer } from "buffer";
@@ -1041,9 +1042,83 @@ var revokeCommand = defineCommand11({
1041
1042
  }
1042
1043
  });
1043
1044
 
1044
- // src/commands/grants/token.ts
1045
+ // src/commands/grants/run.ts
1046
+ import { execFileSync } from "child_process";
1045
1047
  import { defineCommand as defineCommand12 } from "citty";
1046
- var tokenCommand = defineCommand12({
1048
+ import consola12 from "consola";
1049
+ var runGrantCommand = defineCommand12({
1050
+ meta: {
1051
+ name: "run",
1052
+ description: "Execute a previously-approved grant by ID"
1053
+ },
1054
+ args: {
1055
+ id: {
1056
+ type: "positional",
1057
+ description: "Grant ID",
1058
+ required: true
1059
+ },
1060
+ "escapes-path": {
1061
+ type: "string",
1062
+ description: "Path to escapes binary (audience=escapes only)",
1063
+ default: "escapes"
1064
+ }
1065
+ },
1066
+ async run({ args }) {
1067
+ const idp = getIdpUrl();
1068
+ if (!idp)
1069
+ throw new CliError("No IdP URL configured. Run `apes login` first or pass --idp.");
1070
+ const grantsUrl = await getGrantsEndpoint(idp);
1071
+ const grant = await apiFetch(`${grantsUrl}/${args.id}`);
1072
+ if (grant.status === "pending")
1073
+ throw new CliError(`Grant ${grant.id} is still pending. Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
1074
+ if (grant.status === "denied" || grant.status === "revoked")
1075
+ throw new CliError(`Grant ${grant.id} is ${grant.status}. Request a new one.`);
1076
+ if (grant.status === "used")
1077
+ throw new CliError(`Grant ${grant.id} has already been used. Request a new one (single-use grants cannot be re-executed).`);
1078
+ if (grant.status !== "approved")
1079
+ throw new CliError(`Grant ${grant.id} has unexpected status: ${grant.status}`);
1080
+ const audience = grant.request?.audience;
1081
+ const authDetails = grant.request?.authorization_details ?? [];
1082
+ const hasOpenApeCliDetail = authDetails.some((d) => d?.type === "openape_cli");
1083
+ const isShapesGrant = hasOpenApeCliDetail || audience === "shapes";
1084
+ if (isShapesGrant) {
1085
+ let resolved;
1086
+ try {
1087
+ resolved = await resolveFromGrant(grant);
1088
+ } catch (err) {
1089
+ const msg = err instanceof Error ? err.message : String(err);
1090
+ throw new CliError(`Cannot re-resolve grant: ${msg}`);
1091
+ }
1092
+ const token = await fetchGrantToken(idp, grant.id);
1093
+ await verifyAndExecute(token, resolved);
1094
+ return;
1095
+ }
1096
+ if (audience === "escapes") {
1097
+ const { authz_jwt } = await apiFetch(`${grantsUrl}/${grant.id}/token`, { method: "POST" });
1098
+ const command = grant.request?.command ?? [];
1099
+ if (command.length === 0)
1100
+ throw new CliError(`Grant ${grant.id} has no command to execute.`);
1101
+ consola12.info(`Executing via escapes: ${command.join(" ")}`);
1102
+ try {
1103
+ execFileSync(args["escapes-path"], ["--grant", authz_jwt, "--", ...command], { stdio: "inherit" });
1104
+ } catch (err) {
1105
+ const exitCode = err.status || 1;
1106
+ throw new CliExit(exitCode);
1107
+ }
1108
+ return;
1109
+ }
1110
+ if (audience === "ape-shell") {
1111
+ throw new CliError(
1112
+ `Grant ${grant.id} is an ape-shell session grant and cannot be re-executed via \`apes grants run\`. Re-run the original command \u2014 if the grant was approved as timed/always, the REPL will reuse it automatically.`
1113
+ );
1114
+ }
1115
+ throw new CliError(`Grant ${grant.id} has unsupported audience "${audience}" \u2014 no execution path available.`);
1116
+ }
1117
+ });
1118
+
1119
+ // src/commands/grants/token.ts
1120
+ import { defineCommand as defineCommand13 } from "citty";
1121
+ var tokenCommand = defineCommand13({
1047
1122
  meta: {
1048
1123
  name: "token",
1049
1124
  description: "Get grant token JWT"
@@ -1069,9 +1144,9 @@ var tokenCommand = defineCommand12({
1069
1144
  });
1070
1145
 
1071
1146
  // src/commands/grants/delegate.ts
1072
- import { defineCommand as defineCommand13 } from "citty";
1073
- import consola12 from "consola";
1074
- var delegateCommand = defineCommand13({
1147
+ import { defineCommand as defineCommand14 } from "citty";
1148
+ import consola13 from "consola";
1149
+ var delegateCommand = defineCommand14({
1075
1150
  meta: {
1076
1151
  name: "delegate",
1077
1152
  description: "Create a delegation"
@@ -1123,7 +1198,7 @@ var delegateCommand = defineCommand13({
1123
1198
  method: "POST",
1124
1199
  body
1125
1200
  });
1126
- consola12.success(`Delegation created: ${result.id}`);
1201
+ consola13.success(`Delegation created: ${result.id}`);
1127
1202
  console.log(` Delegate: ${args.to}`);
1128
1203
  console.log(` Audience: ${args.at}`);
1129
1204
  if (args.scopes)
@@ -1135,9 +1210,9 @@ var delegateCommand = defineCommand13({
1135
1210
  });
1136
1211
 
1137
1212
  // src/commands/grants/delegations.ts
1138
- import { defineCommand as defineCommand14 } from "citty";
1139
- import consola13 from "consola";
1140
- var delegationsCommand = defineCommand14({
1213
+ import { defineCommand as defineCommand15 } from "citty";
1214
+ import consola14 from "consola";
1215
+ var delegationsCommand = defineCommand15({
1141
1216
  meta: {
1142
1217
  name: "delegations",
1143
1218
  description: "List delegations"
@@ -1159,7 +1234,7 @@ var delegationsCommand = defineCommand14({
1159
1234
  return;
1160
1235
  }
1161
1236
  if (delegations.length === 0) {
1162
- consola13.info("No delegations found.");
1237
+ consola14.info("No delegations found.");
1163
1238
  return;
1164
1239
  }
1165
1240
  for (const d of delegations) {
@@ -1171,9 +1246,9 @@ var delegationsCommand = defineCommand14({
1171
1246
  });
1172
1247
 
1173
1248
  // src/commands/grants/delegation-revoke.ts
1174
- import { defineCommand as defineCommand15 } from "citty";
1175
- import consola14 from "consola";
1176
- var delegationRevokeCommand = defineCommand15({
1249
+ import { defineCommand as defineCommand16 } from "citty";
1250
+ import consola15 from "consola";
1251
+ var delegationRevokeCommand = defineCommand16({
1177
1252
  meta: {
1178
1253
  name: "delegation-revoke",
1179
1254
  description: "Revoke a delegation"
@@ -1196,16 +1271,16 @@ var delegationRevokeCommand = defineCommand15({
1196
1271
  `${delegationsUrl}/${id}`,
1197
1272
  { method: "DELETE" }
1198
1273
  );
1199
- consola14.success(`Delegation ${result.id} revoked.`);
1274
+ consola15.success(`Delegation ${result.id} revoked.`);
1200
1275
  }
1201
1276
  });
1202
1277
 
1203
1278
  // src/commands/admin/index.ts
1204
- import { defineCommand as defineCommand18 } from "citty";
1279
+ import { defineCommand as defineCommand19 } from "citty";
1205
1280
 
1206
1281
  // src/commands/admin/users.ts
1207
- import { defineCommand as defineCommand16 } from "citty";
1208
- import consola15 from "consola";
1282
+ import { defineCommand as defineCommand17 } from "citty";
1283
+ import consola16 from "consola";
1209
1284
  function getManagementToken() {
1210
1285
  const token = process.env.APES_MANAGEMENT_TOKEN;
1211
1286
  if (!token) {
@@ -1213,7 +1288,7 @@ function getManagementToken() {
1213
1288
  }
1214
1289
  return token;
1215
1290
  }
1216
- var usersListCommand = defineCommand16({
1291
+ var usersListCommand = defineCommand17({
1217
1292
  meta: {
1218
1293
  name: "list",
1219
1294
  description: "List all users"
@@ -1255,7 +1330,7 @@ var usersListCommand = defineCommand16({
1255
1330
  return;
1256
1331
  }
1257
1332
  if (result.data.length === 0) {
1258
- consola15.info("No users found.");
1333
+ consola16.info("No users found.");
1259
1334
  return;
1260
1335
  }
1261
1336
  for (const u of result.data) {
@@ -1264,11 +1339,11 @@ var usersListCommand = defineCommand16({
1264
1339
  console.log(`${u.email} ${u.name}${owner}${active}`);
1265
1340
  }
1266
1341
  if (result.pagination.has_more) {
1267
- consola15.info(`More results available. Use --cursor="${result.pagination.cursor}" to see next page.`);
1342
+ consola16.info(`More results available. Use --cursor="${result.pagination.cursor}" to see next page.`);
1268
1343
  }
1269
1344
  }
1270
1345
  });
1271
- var usersCreateCommand = defineCommand16({
1346
+ var usersCreateCommand = defineCommand17({
1272
1347
  meta: {
1273
1348
  name: "create",
1274
1349
  description: "Create a user"
@@ -1299,10 +1374,10 @@ var usersCreateCommand = defineCommand16({
1299
1374
  token
1300
1375
  }
1301
1376
  );
1302
- consola15.success(`User created: ${result.email} (${result.name})`);
1377
+ consola16.success(`User created: ${result.email} (${result.name})`);
1303
1378
  }
1304
1379
  });
1305
- var usersDeleteCommand = defineCommand16({
1380
+ var usersDeleteCommand = defineCommand17({
1306
1381
  meta: {
1307
1382
  name: "delete",
1308
1383
  description: "Delete a user"
@@ -1325,7 +1400,7 @@ var usersDeleteCommand = defineCommand16({
1325
1400
  method: "DELETE",
1326
1401
  token
1327
1402
  });
1328
- consola15.success(`User deleted: ${email}`);
1403
+ consola16.success(`User deleted: ${email}`);
1329
1404
  }
1330
1405
  });
1331
1406
 
@@ -1333,8 +1408,8 @@ var usersDeleteCommand = defineCommand16({
1333
1408
  import { existsSync as existsSync2, readFileSync } from "fs";
1334
1409
  import { resolve } from "path";
1335
1410
  import { homedir as homedir3 } from "os";
1336
- import { defineCommand as defineCommand17 } from "citty";
1337
- import consola16 from "consola";
1411
+ import { defineCommand as defineCommand18 } from "citty";
1412
+ import consola17 from "consola";
1338
1413
  function getManagementToken2() {
1339
1414
  const token = process.env.APES_MANAGEMENT_TOKEN;
1340
1415
  if (!token) {
@@ -1342,7 +1417,7 @@ function getManagementToken2() {
1342
1417
  }
1343
1418
  return token;
1344
1419
  }
1345
- var sshKeysListCommand = defineCommand17({
1420
+ var sshKeysListCommand = defineCommand18({
1346
1421
  meta: {
1347
1422
  name: "list",
1348
1423
  description: "List SSH keys for a user"
@@ -1375,7 +1450,7 @@ var sshKeysListCommand = defineCommand17({
1375
1450
  return;
1376
1451
  }
1377
1452
  if (keys.length === 0) {
1378
- consola16.info(`No SSH keys found for ${email}.`);
1453
+ consola17.info(`No SSH keys found for ${email}.`);
1379
1454
  return;
1380
1455
  }
1381
1456
  for (const k of keys) {
@@ -1383,7 +1458,7 @@ var sshKeysListCommand = defineCommand17({
1383
1458
  }
1384
1459
  }
1385
1460
  });
1386
- var sshKeysAddCommand = defineCommand17({
1461
+ var sshKeysAddCommand = defineCommand18({
1387
1462
  meta: {
1388
1463
  name: "add",
1389
1464
  description: "Add an SSH key for a user"
@@ -1427,10 +1502,10 @@ var sshKeysAddCommand = defineCommand17({
1427
1502
  token
1428
1503
  }
1429
1504
  );
1430
- consola16.success(`SSH key added: ${result.keyId} (${result.name})`);
1505
+ consola17.success(`SSH key added: ${result.keyId} (${result.name})`);
1431
1506
  }
1432
1507
  });
1433
- var sshKeysDeleteCommand = defineCommand17({
1508
+ var sshKeysDeleteCommand = defineCommand18({
1434
1509
  meta: {
1435
1510
  name: "delete",
1436
1511
  description: "Delete an SSH key"
@@ -1461,12 +1536,12 @@ var sshKeysDeleteCommand = defineCommand17({
1461
1536
  token
1462
1537
  }
1463
1538
  );
1464
- consola16.success(`SSH key deleted: ${keyId}`);
1539
+ consola17.success(`SSH key deleted: ${keyId}`);
1465
1540
  }
1466
1541
  });
1467
1542
 
1468
1543
  // src/commands/admin/index.ts
1469
- var usersCommand = defineCommand18({
1544
+ var usersCommand = defineCommand19({
1470
1545
  meta: {
1471
1546
  name: "users",
1472
1547
  description: "Manage users"
@@ -1477,7 +1552,7 @@ var usersCommand = defineCommand18({
1477
1552
  delete: usersDeleteCommand
1478
1553
  }
1479
1554
  });
1480
- var sshKeysCommand = defineCommand18({
1555
+ var sshKeysCommand = defineCommand19({
1481
1556
  meta: {
1482
1557
  name: "ssh-keys",
1483
1558
  description: "Manage SSH keys"
@@ -1488,7 +1563,7 @@ var sshKeysCommand = defineCommand18({
1488
1563
  delete: sshKeysDeleteCommand
1489
1564
  }
1490
1565
  });
1491
- var adminCommand = defineCommand18({
1566
+ var adminCommand = defineCommand19({
1492
1567
  meta: {
1493
1568
  name: "admin",
1494
1569
  description: "Admin commands (requires APES_MANAGEMENT_TOKEN)"
@@ -1500,15 +1575,15 @@ var adminCommand = defineCommand18({
1500
1575
  });
1501
1576
 
1502
1577
  // src/commands/adapter/index.ts
1503
- import { defineCommand as defineCommand19 } from "citty";
1504
- import consola17 from "consola";
1505
- var adapterCommand = defineCommand19({
1578
+ import { defineCommand as defineCommand20 } from "citty";
1579
+ import consola18 from "consola";
1580
+ var adapterCommand = defineCommand20({
1506
1581
  meta: {
1507
1582
  name: "adapter",
1508
1583
  description: "Manage CLI adapters"
1509
1584
  },
1510
1585
  subCommands: {
1511
- list: defineCommand19({
1586
+ list: defineCommand20({
1512
1587
  meta: {
1513
1588
  name: "list",
1514
1589
  description: "List available adapters"
@@ -1539,7 +1614,7 @@ var adapterCommand = defineCommand19({
1539
1614
  `);
1540
1615
  return;
1541
1616
  }
1542
- consola17.info(`Registry: ${index2.adapters.length} adapters (${index2.generated_at})`);
1617
+ consola18.info(`Registry: ${index2.adapters.length} adapters (${index2.generated_at})`);
1543
1618
  for (const a of index2.adapters) {
1544
1619
  const installed = isInstalled(a.id, false) ? " [installed]" : "";
1545
1620
  console.log(` ${a.id.padEnd(12)} ${a.name.padEnd(24)} ${a.category}${installed}`);
@@ -1561,7 +1636,7 @@ var adapterCommand = defineCommand19({
1561
1636
  return;
1562
1637
  }
1563
1638
  if (local.length === 0) {
1564
- consola17.info("No adapters installed. Use `apes adapter list --remote` to see available adapters.");
1639
+ consola18.info("No adapters installed. Use `apes adapter list --remote` to see available adapters.");
1565
1640
  return;
1566
1641
  }
1567
1642
  for (const a of local) {
@@ -1569,7 +1644,7 @@ var adapterCommand = defineCommand19({
1569
1644
  }
1570
1645
  }
1571
1646
  }),
1572
- install: defineCommand19({
1647
+ install: defineCommand20({
1573
1648
  meta: {
1574
1649
  name: "install",
1575
1650
  description: "Install an adapter from the registry"
@@ -1598,24 +1673,24 @@ var adapterCommand = defineCommand19({
1598
1673
  for (const id of ids) {
1599
1674
  const entry = findAdapter(index, id);
1600
1675
  if (!entry) {
1601
- consola17.error(`Adapter "${id}" not found in registry. Use \`apes adapter search ${id}\` to search.`);
1676
+ consola18.error(`Adapter "${id}" not found in registry. Use \`apes adapter search ${id}\` to search.`);
1602
1677
  continue;
1603
1678
  }
1604
1679
  const conflicts = findConflictingAdapters(entry.executable, id);
1605
1680
  if (conflicts.length > 0) {
1606
1681
  for (const c of conflicts) {
1607
- consola17.warn(`Conflicting adapter found: ${c.path} (id: ${c.adapterId}, executable: ${c.executable})`);
1608
- consola17.warn(` Remove it with: apes adapter remove ${c.adapterId}`);
1682
+ consola18.warn(`Conflicting adapter found: ${c.path} (id: ${c.adapterId}, executable: ${c.executable})`);
1683
+ consola18.warn(` Remove it with: apes adapter remove ${c.adapterId}`);
1609
1684
  }
1610
1685
  }
1611
1686
  const result = await installAdapter(entry, { local });
1612
1687
  const verb = result.updated ? "Updated" : "Installed";
1613
- consola17.success(`${verb} ${result.id} \u2192 ${result.path}`);
1614
- consola17.info(`Digest: ${result.digest}`);
1688
+ consola18.success(`${verb} ${result.id} \u2192 ${result.path}`);
1689
+ consola18.info(`Digest: ${result.digest}`);
1615
1690
  }
1616
1691
  }
1617
1692
  }),
1618
- remove: defineCommand19({
1693
+ remove: defineCommand20({
1619
1694
  meta: {
1620
1695
  name: "remove",
1621
1696
  description: "Remove an installed adapter"
@@ -1638,9 +1713,9 @@ var adapterCommand = defineCommand19({
1638
1713
  let failed = false;
1639
1714
  for (const id of ids) {
1640
1715
  if (removeAdapter(id, local)) {
1641
- consola17.success(`Removed adapter: ${id}`);
1716
+ consola18.success(`Removed adapter: ${id}`);
1642
1717
  } else {
1643
- consola17.error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
1718
+ consola18.error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
1644
1719
  failed = true;
1645
1720
  }
1646
1721
  }
@@ -1648,7 +1723,7 @@ var adapterCommand = defineCommand19({
1648
1723
  throw new CliError("Some adapters could not be removed");
1649
1724
  }
1650
1725
  }),
1651
- info: defineCommand19({
1726
+ info: defineCommand20({
1652
1727
  meta: {
1653
1728
  name: "info",
1654
1729
  description: "Show detailed adapter information"
@@ -1690,7 +1765,7 @@ var adapterCommand = defineCommand19({
1690
1765
  }
1691
1766
  }
1692
1767
  }),
1693
- search: defineCommand19({
1768
+ search: defineCommand20({
1694
1769
  meta: {
1695
1770
  name: "search",
1696
1771
  description: "Search adapters in the registry"
@@ -1722,7 +1797,7 @@ var adapterCommand = defineCommand19({
1722
1797
  return;
1723
1798
  }
1724
1799
  if (results.length === 0) {
1725
- consola17.info(`No adapters matching "${query}"`);
1800
+ consola18.info(`No adapters matching "${query}"`);
1726
1801
  return;
1727
1802
  }
1728
1803
  for (const a of results) {
@@ -1731,7 +1806,7 @@ var adapterCommand = defineCommand19({
1731
1806
  }
1732
1807
  }
1733
1808
  }),
1734
- update: defineCommand19({
1809
+ update: defineCommand20({
1735
1810
  meta: {
1736
1811
  name: "update",
1737
1812
  description: "Update installed adapters"
@@ -1757,33 +1832,33 @@ var adapterCommand = defineCommand19({
1757
1832
  const targetId = args.id ? String(args.id) : void 0;
1758
1833
  const targets = targetId ? [targetId] : index.adapters.map((a) => a.id).filter((id) => isInstalled(id, false));
1759
1834
  if (targets.length === 0) {
1760
- consola17.info("No adapters installed to update.");
1835
+ consola18.info("No adapters installed to update.");
1761
1836
  return;
1762
1837
  }
1763
1838
  for (const id of targets) {
1764
1839
  const entry = findAdapter(index, id);
1765
1840
  if (!entry) {
1766
- consola17.warn(`${id}: not found in registry, skipping`);
1841
+ consola18.warn(`${id}: not found in registry, skipping`);
1767
1842
  continue;
1768
1843
  }
1769
1844
  const localDigest = getInstalledDigest(id, false);
1770
1845
  if (localDigest === entry.digest) {
1771
- consola17.info(`${id}: already up to date`);
1846
+ consola18.info(`${id}: already up to date`);
1772
1847
  continue;
1773
1848
  }
1774
1849
  if (localDigest && !args.yes) {
1775
- consola17.warn(`${id}: digest will change \u2014 existing grants for this adapter will be invalidated`);
1776
- consola17.info(` Old: ${localDigest}`);
1777
- consola17.info(` New: ${entry.digest}`);
1778
- consola17.info(" Use --yes to confirm");
1850
+ consola18.warn(`${id}: digest will change \u2014 existing grants for this adapter will be invalidated`);
1851
+ consola18.info(` Old: ${localDigest}`);
1852
+ consola18.info(` New: ${entry.digest}`);
1853
+ consola18.info(" Use --yes to confirm");
1779
1854
  continue;
1780
1855
  }
1781
1856
  const result = await installAdapter(entry);
1782
- consola17.success(`Updated ${result.id} \u2192 ${result.path}`);
1857
+ consola18.success(`Updated ${result.id} \u2192 ${result.path}`);
1783
1858
  }
1784
1859
  }
1785
1860
  }),
1786
- verify: defineCommand19({
1861
+ verify: defineCommand20({
1787
1862
  meta: {
1788
1863
  name: "verify",
1789
1864
  description: "Verify installed adapter against registry digest"
@@ -1816,7 +1891,7 @@ var adapterCommand = defineCommand19({
1816
1891
  if (!localDigest)
1817
1892
  throw new Error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
1818
1893
  if (localDigest === entry.digest) {
1819
- consola17.success(`${id}: digest matches registry`);
1894
+ consola18.success(`${id}: digest matches registry`);
1820
1895
  } else {
1821
1896
  console.log(` Local: ${localDigest}`);
1822
1897
  console.log(` Registry: ${entry.digest}`);
@@ -1828,12 +1903,24 @@ var adapterCommand = defineCommand19({
1828
1903
  });
1829
1904
 
1830
1905
  // src/commands/run.ts
1831
- import { execFileSync } from "child_process";
1906
+ import { execFileSync as execFileSync2 } from "child_process";
1832
1907
  import { hostname as hostname3 } from "os";
1833
1908
  import { basename } from "path";
1834
- import { defineCommand as defineCommand20 } from "citty";
1835
- import consola18 from "consola";
1836
- var runCommand = defineCommand20({
1909
+ import { defineCommand as defineCommand21 } from "citty";
1910
+ import consola19 from "consola";
1911
+ function shouldWaitForGrant(args) {
1912
+ return args.wait === true || process.env.APE_WAIT === "1";
1913
+ }
1914
+ function printPendingGrantInfo(grant, idp) {
1915
+ consola19.success(`Grant ${grant.id} erstellt`);
1916
+ console.log(` Approve: ${idp}/grant-approval?grant_id=${grant.id}`);
1917
+ console.log(` Status: apes grants status ${grant.id}`);
1918
+ console.log(` Ausf\xFChren: apes grants run ${grant.id}`);
1919
+ console.log("");
1920
+ console.log(' Tipp: Im Browser "als timed/always approven" w\xE4hlen, um das');
1921
+ console.log(" Kommando ohne erneuten Approval wiederzuverwenden.");
1922
+ }
1923
+ var runCommand = defineCommand21({
1837
1924
  meta: {
1838
1925
  name: "run",
1839
1926
  description: "Execute a grant-secured command"
@@ -1874,6 +1961,11 @@ var runCommand = defineCommand20({
1874
1961
  description: "Shell mode: use session grant with audience ape-shell",
1875
1962
  default: false
1876
1963
  },
1964
+ "wait": {
1965
+ type: "boolean",
1966
+ description: "Block until grant is approved (default: async, print grant info and exit 0). Equivalent to APE_WAIT=1.",
1967
+ default: false
1968
+ },
1877
1969
  "_": {
1878
1970
  type: "positional",
1879
1971
  description: "Command to execute (after --)",
@@ -1920,7 +2012,7 @@ async function runShellMode(command, args) {
1920
2012
  }
1921
2013
  } catch {
1922
2014
  }
1923
- consola18.info(`Requesting ape-shell session grant on ${targetHost}`);
2015
+ consola19.info(`Requesting ape-shell session grant on ${targetHost}`);
1924
2016
  const grant = await apiFetch(grantsUrl, {
1925
2017
  method: "POST",
1926
2018
  body: {
@@ -1932,8 +2024,6 @@ async function runShellMode(command, args) {
1932
2024
  reason: `Shell session: ${command.join(" ").slice(0, 100)}`
1933
2025
  }
1934
2026
  });
1935
- consola18.info(`Grant requested: ${grant.id}`);
1936
- consola18.info("Waiting for approval...");
1937
2027
  notifyGrantPending({
1938
2028
  grantId: grant.id,
1939
2029
  approveUrl: `${idp}/grant-approval?grant_id=${grant.id}`,
@@ -1941,18 +2031,24 @@ async function runShellMode(command, args) {
1941
2031
  audience: "ape-shell",
1942
2032
  host: targetHost
1943
2033
  });
1944
- const maxWait = 3e5;
1945
- const interval = 3e3;
1946
- const start = Date.now();
1947
- while (Date.now() - start < maxWait) {
1948
- const status = await apiFetch(`${grantsUrl}/${grant.id}`);
1949
- if (status.status === "approved")
1950
- break;
1951
- if (status.status === "denied" || status.status === "revoked")
1952
- throw new CliError(`Grant ${status.status}.`);
1953
- await new Promise((r) => setTimeout(r, interval));
2034
+ if (shouldWaitForGrant(args)) {
2035
+ consola19.info(`Grant requested: ${grant.id}`);
2036
+ consola19.info("Waiting for approval...");
2037
+ const maxWait = 3e5;
2038
+ const interval = 3e3;
2039
+ const start = Date.now();
2040
+ while (Date.now() - start < maxWait) {
2041
+ const status = await apiFetch(`${grantsUrl}/${grant.id}`);
2042
+ if (status.status === "approved")
2043
+ break;
2044
+ if (status.status === "denied" || status.status === "revoked")
2045
+ throw new CliError(`Grant ${status.status}.`);
2046
+ await new Promise((r) => setTimeout(r, interval));
2047
+ }
2048
+ execShellCommand(command);
2049
+ return;
1954
2050
  }
1955
- execShellCommand(command);
2051
+ printPendingGrantInfo(grant, idp);
1956
2052
  }
1957
2053
  async function tryAdapterModeFromShell(command, idp, args) {
1958
2054
  const cmdString = extractShellCommandString(command);
@@ -1967,32 +2063,30 @@ async function tryAdapterModeFromShell(command, idp, args) {
1967
2063
  try {
1968
2064
  resolved = await resolveCommand(loaded, [normalizedExecutable, ...parsed.argv]);
1969
2065
  } catch (err) {
1970
- consola18.debug(`ape-shell: adapter resolve failed for "${parsed.raw}":`, err);
2066
+ consola19.debug(`ape-shell: adapter resolve failed for "${parsed.raw}":`, err);
1971
2067
  return false;
1972
2068
  }
1973
2069
  try {
1974
2070
  const existingGrantId = await findExistingGrant(resolved, idp);
1975
2071
  if (existingGrantId) {
1976
- consola18.info(`Reusing grant ${existingGrantId} for: ${resolved.detail.display}`);
1977
- const token2 = await fetchGrantToken(idp, existingGrantId);
1978
- await verifyAndExecute(token2, resolved);
2072
+ consola19.info(`Reusing grant ${existingGrantId} for: ${resolved.detail.display}`);
2073
+ const token = await fetchGrantToken(idp, existingGrantId);
2074
+ await verifyAndExecute(token, resolved);
1979
2075
  return true;
1980
2076
  }
1981
2077
  } catch {
1982
2078
  }
1983
2079
  const approval = args.approval ?? "once";
1984
- consola18.info(`Requesting grant for: ${resolved.detail.display}`);
2080
+ consola19.info(`Requesting grant for: ${resolved.detail.display}`);
1985
2081
  const grant = await createShapesGrant(resolved, {
1986
2082
  idp,
1987
2083
  approval,
1988
2084
  reason: args.reason || `ape-shell: ${resolved.detail.display}`
1989
2085
  });
1990
- consola18.info(`Grant requested: ${grant.id}`);
1991
- consola18.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
1992
2086
  if (grant.similar_grants?.similar_grants?.length) {
1993
2087
  const n = grant.similar_grants.similar_grants.length;
1994
- consola18.info("");
1995
- consola18.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
2088
+ consola19.info("");
2089
+ consola19.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
1996
2090
  }
1997
2091
  notifyGrantPending({
1998
2092
  grantId: grant.id,
@@ -2001,18 +2095,24 @@ async function tryAdapterModeFromShell(command, idp, args) {
2001
2095
  audience: resolved.adapter?.cli?.audience ?? "shapes",
2002
2096
  host: args.host || hostname3()
2003
2097
  });
2004
- const status = await waitForGrantStatus(idp, grant.id);
2005
- if (status !== "approved")
2006
- throw new CliError(`Grant ${status}`);
2007
- const token = await fetchGrantToken(idp, grant.id);
2008
- await verifyAndExecute(token, resolved);
2098
+ if (shouldWaitForGrant(args)) {
2099
+ consola19.info(`Grant requested: ${grant.id}`);
2100
+ consola19.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
2101
+ const status = await waitForGrantStatus(idp, grant.id);
2102
+ if (status !== "approved")
2103
+ throw new CliError(`Grant ${status}`);
2104
+ const token = await fetchGrantToken(idp, grant.id);
2105
+ await verifyAndExecute(token, resolved);
2106
+ return true;
2107
+ }
2108
+ printPendingGrantInfo(grant, idp);
2009
2109
  return true;
2010
2110
  }
2011
2111
  function execShellCommand(command) {
2012
2112
  if (command.length === 0)
2013
2113
  throw new CliError("No command to execute");
2014
2114
  try {
2015
- execFileSync(command[0], command.slice(1), { stdio: "inherit" });
2115
+ execFileSync2(command[0], command.slice(1), { stdio: "inherit" });
2016
2116
  } catch (err) {
2017
2117
  const exitCode = err.status || 1;
2018
2118
  throw new CliExit(exitCode);
@@ -2049,9 +2149,9 @@ async function runAdapterMode(command, rawArgs, args) {
2049
2149
  try {
2050
2150
  const existingGrantId = await findExistingGrant(resolved, idp);
2051
2151
  if (existingGrantId) {
2052
- consola18.info(`Reusing existing grant: ${existingGrantId}`);
2053
- const token2 = await fetchGrantToken(idp, existingGrantId);
2054
- await verifyAndExecute(token2, resolved);
2152
+ consola19.info(`Reusing existing grant: ${existingGrantId}`);
2153
+ const token = await fetchGrantToken(idp, existingGrantId);
2154
+ await verifyAndExecute(token, resolved);
2055
2155
  return;
2056
2156
  }
2057
2157
  } catch {
@@ -2061,23 +2161,27 @@ async function runAdapterMode(command, rawArgs, args) {
2061
2161
  approval,
2062
2162
  ...args.reason ? { reason: args.reason } : {}
2063
2163
  });
2064
- consola18.info(`Grant requested: ${grant.id}`);
2065
- consola18.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
2066
2164
  if (grant.similar_grants?.similar_grants?.length) {
2067
2165
  const n = grant.similar_grants.similar_grants.length;
2068
- consola18.info("");
2069
- consola18.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
2166
+ consola19.info("");
2167
+ consola19.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
2070
2168
  if (grant.similar_grants.widened_details?.length) {
2071
2169
  const wider = grant.similar_grants.widened_details.map((d) => d.permission).join(", ");
2072
- consola18.info(` Broader scope: ${wider}`);
2073
- }
2074
- consola18.info("");
2170
+ consola19.info(` Broader scope: ${wider}`);
2171
+ }
2172
+ consola19.info("");
2173
+ }
2174
+ if (shouldWaitForGrant(args)) {
2175
+ consola19.info(`Grant requested: ${grant.id}`);
2176
+ consola19.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
2177
+ const status = await waitForGrantStatus(idp, grant.id);
2178
+ if (status !== "approved")
2179
+ throw new Error(`Grant ${status}`);
2180
+ const token = await fetchGrantToken(idp, grant.id);
2181
+ await verifyAndExecute(token, resolved);
2182
+ return;
2075
2183
  }
2076
- const status = await waitForGrantStatus(idp, grant.id);
2077
- if (status !== "approved")
2078
- throw new Error(`Grant ${status}`);
2079
- const token = await fetchGrantToken(idp, grant.id);
2080
- await verifyAndExecute(token, resolved);
2184
+ printPendingGrantInfo(grant, idp);
2081
2185
  }
2082
2186
  async function runAudienceMode(audience, action, args) {
2083
2187
  const auth = loadAuth();
@@ -2088,7 +2192,7 @@ async function runAudienceMode(audience, action, args) {
2088
2192
  const grantsUrl = await getGrantsEndpoint(idp);
2089
2193
  const command = action.split(" ");
2090
2194
  const targetHost = args.host || hostname3();
2091
- consola18.info(`Requesting ${audience} grant on ${targetHost}: ${command.join(" ")}`);
2195
+ consola19.info(`Requesting ${audience} grant on ${targetHost}: ${command.join(" ")}`);
2092
2196
  const grant = await apiFetch(grantsUrl, {
2093
2197
  method: "POST",
2094
2198
  body: {
@@ -2101,15 +2205,19 @@ async function runAudienceMode(audience, action, args) {
2101
2205
  ...args.as ? { run_as: args.as } : {}
2102
2206
  }
2103
2207
  });
2104
- consola18.success(`Grant requested: ${grant.id}`);
2105
- consola18.info("Waiting for approval...");
2208
+ if (!shouldWaitForGrant(args)) {
2209
+ printPendingGrantInfo(grant, idp);
2210
+ return;
2211
+ }
2212
+ consola19.success(`Grant requested: ${grant.id}`);
2213
+ consola19.info("Waiting for approval...");
2106
2214
  const maxWait = 3e5;
2107
2215
  const interval = 3e3;
2108
2216
  const start = Date.now();
2109
2217
  while (Date.now() - start < maxWait) {
2110
2218
  const status = await apiFetch(`${grantsUrl}/${grant.id}`);
2111
2219
  if (status.status === "approved") {
2112
- consola18.success("Grant approved!");
2220
+ consola19.success("Grant approved!");
2113
2221
  break;
2114
2222
  }
2115
2223
  if (status.status === "denied" || status.status === "revoked") {
@@ -2117,14 +2225,14 @@ async function runAudienceMode(audience, action, args) {
2117
2225
  }
2118
2226
  await new Promise((r) => setTimeout(r, interval));
2119
2227
  }
2120
- consola18.info("Fetching grant token...");
2228
+ consola19.info("Fetching grant token...");
2121
2229
  const { authz_jwt } = await apiFetch(`${grantsUrl}/${grant.id}/token`, {
2122
2230
  method: "POST"
2123
2231
  });
2124
2232
  if (audience === "escapes") {
2125
- consola18.info(`Executing: ${command.join(" ")}`);
2233
+ consola19.info(`Executing: ${command.join(" ")}`);
2126
2234
  try {
2127
- execFileSync(args["escapes-path"] || "escapes", ["--grant", authz_jwt, "--", ...command], {
2235
+ execFileSync2(args["escapes-path"] || "escapes", ["--grant", authz_jwt, "--", ...command], {
2128
2236
  stdio: "inherit"
2129
2237
  });
2130
2238
  } catch (err) {
@@ -2137,8 +2245,8 @@ async function runAudienceMode(audience, action, args) {
2137
2245
  }
2138
2246
 
2139
2247
  // src/commands/explain.ts
2140
- import { defineCommand as defineCommand21 } from "citty";
2141
- var explainCommand = defineCommand21({
2248
+ import { defineCommand as defineCommand22 } from "citty";
2249
+ var explainCommand = defineCommand22({
2142
2250
  meta: {
2143
2251
  name: "explain",
2144
2252
  description: "Show what permission a command would need"
@@ -2176,9 +2284,9 @@ var explainCommand = defineCommand21({
2176
2284
  });
2177
2285
 
2178
2286
  // src/commands/config/get.ts
2179
- import { defineCommand as defineCommand22 } from "citty";
2180
- import consola19 from "consola";
2181
- var configGetCommand = defineCommand22({
2287
+ import { defineCommand as defineCommand23 } from "citty";
2288
+ import consola20 from "consola";
2289
+ var configGetCommand = defineCommand23({
2182
2290
  meta: {
2183
2291
  name: "get",
2184
2292
  description: "Get a configuration value"
@@ -2198,7 +2306,7 @@ var configGetCommand = defineCommand22({
2198
2306
  if (idp)
2199
2307
  console.log(idp);
2200
2308
  else
2201
- consola19.info("No IdP configured.");
2309
+ consola20.info("No IdP configured.");
2202
2310
  break;
2203
2311
  }
2204
2312
  case "email": {
@@ -2206,7 +2314,7 @@ var configGetCommand = defineCommand22({
2206
2314
  if (auth?.email)
2207
2315
  console.log(auth.email);
2208
2316
  else
2209
- consola19.info("Not logged in.");
2317
+ consola20.info("Not logged in.");
2210
2318
  break;
2211
2319
  }
2212
2320
  default: {
@@ -2219,7 +2327,7 @@ var configGetCommand = defineCommand22({
2219
2327
  if (sectionObj && field in sectionObj) {
2220
2328
  console.log(sectionObj[field]);
2221
2329
  } else {
2222
- consola19.info(`Key "${key}" not set.`);
2330
+ consola20.info(`Key "${key}" not set.`);
2223
2331
  }
2224
2332
  } else {
2225
2333
  throw new CliError(`Unknown key: "${key}". Use: idp, email, defaults.idp, defaults.approval, agent.key, agent.email`);
@@ -2230,9 +2338,9 @@ var configGetCommand = defineCommand22({
2230
2338
  });
2231
2339
 
2232
2340
  // src/commands/config/set.ts
2233
- import { defineCommand as defineCommand23 } from "citty";
2234
- import consola20 from "consola";
2235
- var configSetCommand = defineCommand23({
2341
+ import { defineCommand as defineCommand24 } from "citty";
2342
+ import consola21 from "consola";
2343
+ var configSetCommand = defineCommand24({
2236
2344
  meta: {
2237
2345
  name: "set",
2238
2346
  description: "Set a configuration value"
@@ -2268,12 +2376,12 @@ var configSetCommand = defineCommand23({
2268
2376
  throw new CliError(`Unknown section: "${section}". Use: defaults, agent`);
2269
2377
  }
2270
2378
  saveConfig(config);
2271
- consola20.success(`Set ${key} = ${value}`);
2379
+ consola21.success(`Set ${key} = ${value}`);
2272
2380
  }
2273
2381
  });
2274
2382
 
2275
2383
  // src/commands/fetch/index.ts
2276
- import { defineCommand as defineCommand24 } from "citty";
2384
+ import { defineCommand as defineCommand25 } from "citty";
2277
2385
  async function doRequest(method, url, body, contentType, raw, showHeaders) {
2278
2386
  const token = getAuthToken();
2279
2387
  if (!token) {
@@ -2309,13 +2417,13 @@ async function doRequest(method, url, body, contentType, raw, showHeaders) {
2309
2417
  throw new CliError(`HTTP ${response.status} ${response.statusText}`);
2310
2418
  }
2311
2419
  }
2312
- var fetchCommand = defineCommand24({
2420
+ var fetchCommand = defineCommand25({
2313
2421
  meta: {
2314
2422
  name: "fetch",
2315
2423
  description: "Make authenticated HTTP requests"
2316
2424
  },
2317
2425
  subCommands: {
2318
- get: defineCommand24({
2426
+ get: defineCommand25({
2319
2427
  meta: {
2320
2428
  name: "get",
2321
2429
  description: "GET request with auth token"
@@ -2341,7 +2449,7 @@ var fetchCommand = defineCommand24({
2341
2449
  await doRequest("GET", String(args.url), void 0, "application/json", Boolean(args.raw), Boolean(args.headers));
2342
2450
  }
2343
2451
  }),
2344
- post: defineCommand24({
2452
+ post: defineCommand25({
2345
2453
  meta: {
2346
2454
  name: "post",
2347
2455
  description: "POST request with auth token"
@@ -2380,8 +2488,8 @@ var fetchCommand = defineCommand24({
2380
2488
  });
2381
2489
 
2382
2490
  // src/commands/mcp/index.ts
2383
- import { defineCommand as defineCommand25 } from "citty";
2384
- var mcpCommand = defineCommand25({
2491
+ import { defineCommand as defineCommand26 } from "citty";
2492
+ var mcpCommand = defineCommand26({
2385
2493
  meta: {
2386
2494
  name: "mcp",
2387
2495
  description: "Start MCP server for AI agents"
@@ -2404,7 +2512,7 @@ var mcpCommand = defineCommand25({
2404
2512
  if (transport !== "stdio" && transport !== "sse") {
2405
2513
  throw new Error('Transport must be "stdio" or "sse"');
2406
2514
  }
2407
- const { startMcpServer } = await import("./server-DPNFUTHG.js");
2515
+ const { startMcpServer } = await import("./server-FFOPFICW.js");
2408
2516
  await startMcpServer(transport, port);
2409
2517
  }
2410
2518
  });
@@ -2412,10 +2520,10 @@ var mcpCommand = defineCommand25({
2412
2520
  // src/commands/init/index.ts
2413
2521
  import { existsSync as existsSync3, copyFileSync, writeFileSync } from "fs";
2414
2522
  import { randomBytes } from "crypto";
2415
- import { execFileSync as execFileSync2 } from "child_process";
2523
+ import { execFileSync as execFileSync3 } from "child_process";
2416
2524
  import { join as join2 } from "path";
2417
- import { defineCommand as defineCommand26 } from "citty";
2418
- import consola21 from "consola";
2525
+ import { defineCommand as defineCommand27 } from "citty";
2526
+ import consola22 from "consola";
2419
2527
  var DEFAULT_IDP_URL = "https://id.openape.at";
2420
2528
  async function downloadTemplate(repo, targetDir) {
2421
2529
  const { downloadTemplate: gigetDownload } = await import("giget");
@@ -2424,28 +2532,28 @@ async function downloadTemplate(repo, targetDir) {
2424
2532
  function installDeps(dir) {
2425
2533
  const hasLockFile = (name) => existsSync3(join2(dir, name));
2426
2534
  if (hasLockFile("pnpm-lock.yaml")) {
2427
- execFileSync2("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
2535
+ execFileSync3("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
2428
2536
  } else if (hasLockFile("bun.lockb")) {
2429
- execFileSync2("bun", ["install"], { cwd: dir, stdio: "inherit" });
2537
+ execFileSync3("bun", ["install"], { cwd: dir, stdio: "inherit" });
2430
2538
  } else {
2431
- execFileSync2("npm", ["install"], { cwd: dir, stdio: "inherit" });
2539
+ execFileSync3("npm", ["install"], { cwd: dir, stdio: "inherit" });
2432
2540
  }
2433
2541
  }
2434
2542
  async function promptChoice(message, choices) {
2435
- const result = await consola21.prompt(message, { type: "select", options: choices });
2543
+ const result = await consola22.prompt(message, { type: "select", options: choices });
2436
2544
  if (typeof result === "symbol") {
2437
2545
  throw new CliExit(0);
2438
2546
  }
2439
2547
  return result;
2440
2548
  }
2441
2549
  async function promptText(message, defaultValue) {
2442
- const result = await consola21.prompt(message, { type: "text", default: defaultValue, placeholder: defaultValue });
2550
+ const result = await consola22.prompt(message, { type: "text", default: defaultValue, placeholder: defaultValue });
2443
2551
  if (typeof result === "symbol") {
2444
2552
  throw new CliExit(0);
2445
2553
  }
2446
2554
  return result || defaultValue || "";
2447
2555
  }
2448
- var initCommand = defineCommand26({
2556
+ var initCommand = defineCommand27({
2449
2557
  meta: {
2450
2558
  name: "init",
2451
2559
  description: "Scaffold a new OpenApe project"
@@ -2490,20 +2598,20 @@ async function initSP(targetDir) {
2490
2598
  if (existsSync3(join2(dir, "package.json"))) {
2491
2599
  throw new CliError(`Directory "${dir}" already contains a project.`);
2492
2600
  }
2493
- consola21.start("Scaffolding SP starter...");
2601
+ consola22.start("Scaffolding SP starter...");
2494
2602
  await downloadTemplate("openape-ai/openape-sp-starter", dir);
2495
- consola21.success("Scaffolded from openape-sp-starter");
2496
- consola21.start("Installing dependencies...");
2603
+ consola22.success("Scaffolded from openape-sp-starter");
2604
+ consola22.start("Installing dependencies...");
2497
2605
  installDeps(dir);
2498
- consola21.success("Dependencies installed");
2606
+ consola22.success("Dependencies installed");
2499
2607
  const envExample = join2(dir, ".env.example");
2500
2608
  const envFile = join2(dir, ".env");
2501
2609
  if (existsSync3(envExample) && !existsSync3(envFile)) {
2502
2610
  copyFileSync(envExample, envFile);
2503
- consola21.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
2611
+ consola22.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
2504
2612
  }
2505
2613
  console.log("");
2506
- consola21.box([
2614
+ consola22.box([
2507
2615
  `cd ${dir}`,
2508
2616
  "npm run dev",
2509
2617
  "",
@@ -2522,15 +2630,15 @@ async function initIdP(targetDir) {
2522
2630
  "s3 (S3-compatible)"
2523
2631
  ]);
2524
2632
  const adminEmail = await promptText("Admin email");
2525
- consola21.start("Scaffolding IdP starter...");
2633
+ consola22.start("Scaffolding IdP starter...");
2526
2634
  await downloadTemplate("openape-ai/openape-idp-starter", dir);
2527
- consola21.success("Scaffolded from openape-idp-starter");
2528
- consola21.start("Installing dependencies...");
2635
+ consola22.success("Scaffolded from openape-idp-starter");
2636
+ consola22.start("Installing dependencies...");
2529
2637
  installDeps(dir);
2530
- consola21.success("Dependencies installed");
2638
+ consola22.success("Dependencies installed");
2531
2639
  const sessionSecret = randomBytes(32).toString("hex");
2532
2640
  const managementToken = randomBytes(32).toString("hex");
2533
- consola21.success("Secrets generated");
2641
+ consola22.success("Secrets generated");
2534
2642
  const isLocalhost = domain === "localhost";
2535
2643
  const origin = isLocalhost ? "http://localhost:3000" : `https://${domain}`;
2536
2644
  const envContent = [
@@ -2546,9 +2654,9 @@ async function initIdP(targetDir) {
2546
2654
  ].join("\n");
2547
2655
  writeFileSync(join2(dir, ".env"), `${envContent}
2548
2656
  `, { mode: 384 });
2549
- consola21.success(".env created");
2657
+ consola22.success(".env created");
2550
2658
  console.log("");
2551
- consola21.box([
2659
+ consola22.box([
2552
2660
  `cd ${dir}`,
2553
2661
  "npm run dev",
2554
2662
  "",
@@ -2570,8 +2678,8 @@ import { execFile as execFile2 } from "child_process";
2570
2678
  import { generateKeyPairSync, sign } from "crypto";
2571
2679
  import { dirname, resolve as resolve2 } from "path";
2572
2680
  import { homedir as homedir4 } from "os";
2573
- import { defineCommand as defineCommand27 } from "citty";
2574
- import consola22 from "consola";
2681
+ import { defineCommand as defineCommand28 } from "citty";
2682
+ import consola23 from "consola";
2575
2683
  var DEFAULT_IDP_URL2 = "https://id.openape.at";
2576
2684
  var DEFAULT_KEY_PATH = "~/.ssh/id_ed25519";
2577
2685
  var POLL_INTERVAL = 3e3;
@@ -2656,7 +2764,7 @@ async function pollForEnrollment(idp, agentEmail, keyPath) {
2656
2764
  }
2657
2765
  throw new Error("Enrollment timed out. Please check the browser and try again.");
2658
2766
  }
2659
- var enrollCommand = defineCommand27({
2767
+ var enrollCommand = defineCommand28({
2660
2768
  meta: {
2661
2769
  name: "enroll",
2662
2770
  description: "Enroll an agent with an Identity Provider"
@@ -2676,18 +2784,18 @@ var enrollCommand = defineCommand27({
2676
2784
  }
2677
2785
  },
2678
2786
  async run({ args }) {
2679
- const idp = args.idp || await consola22.prompt("IdP URL", { type: "text", default: DEFAULT_IDP_URL2, placeholder: DEFAULT_IDP_URL2 }).then((r) => {
2787
+ const idp = args.idp || await consola23.prompt("IdP URL", { type: "text", default: DEFAULT_IDP_URL2, placeholder: DEFAULT_IDP_URL2 }).then((r) => {
2680
2788
  if (typeof r === "symbol") throw new CliExit(0);
2681
2789
  return r;
2682
2790
  }) || DEFAULT_IDP_URL2;
2683
- const agentName = args.name || await consola22.prompt("Agent name", { type: "text", placeholder: "deploy-bot" }).then((r) => {
2791
+ const agentName = args.name || await consola23.prompt("Agent name", { type: "text", placeholder: "deploy-bot" }).then((r) => {
2684
2792
  if (typeof r === "symbol") throw new CliExit(0);
2685
2793
  return r;
2686
2794
  });
2687
2795
  if (!agentName) {
2688
2796
  throw new CliError("Agent name is required.");
2689
2797
  }
2690
- const keyPath = args.key || await consola22.prompt("Ed25519 key", { type: "text", default: DEFAULT_KEY_PATH, placeholder: DEFAULT_KEY_PATH }).then((r) => {
2798
+ const keyPath = args.key || await consola23.prompt("Ed25519 key", { type: "text", default: DEFAULT_KEY_PATH, placeholder: DEFAULT_KEY_PATH }).then((r) => {
2691
2799
  if (typeof r === "symbol") throw new CliExit(0);
2692
2800
  return r;
2693
2801
  }) || DEFAULT_KEY_PATH;
@@ -2695,19 +2803,19 @@ var enrollCommand = defineCommand27({
2695
2803
  let publicKey;
2696
2804
  if (existsSync4(resolvedKey)) {
2697
2805
  publicKey = readPublicKey(resolvedKey);
2698
- consola22.success(`Using existing key ${keyPath}`);
2806
+ consola23.success(`Using existing key ${keyPath}`);
2699
2807
  } else {
2700
- consola22.start(`Generating Ed25519 key pair at ${keyPath}...`);
2808
+ consola23.start(`Generating Ed25519 key pair at ${keyPath}...`);
2701
2809
  publicKey = generateAndSaveKey(keyPath);
2702
- consola22.success(`Key pair generated at ${keyPath}`);
2810
+ consola23.success(`Key pair generated at ${keyPath}`);
2703
2811
  }
2704
2812
  const encodedKey = encodeURIComponent(publicKey);
2705
2813
  const enrollUrl = `${idp}/enroll?name=${encodeURIComponent(agentName)}&key=${encodedKey}`;
2706
- consola22.info("Opening browser for enrollment...");
2707
- consola22.info(`\u2192 ${idp}/enroll`);
2814
+ consola23.info("Opening browser for enrollment...");
2815
+ consola23.info(`\u2192 ${idp}/enroll`);
2708
2816
  openBrowser2(enrollUrl);
2709
2817
  console.log("");
2710
- const agentEmail = await consola22.prompt(
2818
+ const agentEmail = await consola23.prompt(
2711
2819
  "Agent email (shown in browser after enrollment)",
2712
2820
  { type: "text", placeholder: `agent+${agentName}@...` }
2713
2821
  ).then((r) => {
@@ -2717,7 +2825,7 @@ var enrollCommand = defineCommand27({
2717
2825
  if (!agentEmail) {
2718
2826
  throw new CliError("Agent email is required to verify enrollment.");
2719
2827
  }
2720
- consola22.start("Verifying enrollment...");
2828
+ consola23.start("Verifying enrollment...");
2721
2829
  const { token, expiresIn } = await pollForEnrollment(idp, agentEmail, keyPath);
2722
2830
  saveAuth({
2723
2831
  idp,
@@ -2729,18 +2837,18 @@ var enrollCommand = defineCommand27({
2729
2837
  config.defaults = { ...config.defaults, idp };
2730
2838
  config.agent = { key: keyPath, email: agentEmail };
2731
2839
  saveConfig(config);
2732
- consola22.success(`Agent enrolled as ${agentEmail}`);
2733
- consola22.success("Config saved to ~/.config/apes/");
2840
+ consola23.success(`Agent enrolled as ${agentEmail}`);
2841
+ consola23.success("Config saved to ~/.config/apes/");
2734
2842
  console.log("");
2735
- consola22.info("Verify with: apes whoami");
2843
+ consola23.info("Verify with: apes whoami");
2736
2844
  }
2737
2845
  });
2738
2846
 
2739
2847
  // src/commands/register-user.ts
2740
2848
  import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
2741
- import { defineCommand as defineCommand28 } from "citty";
2742
- import consola23 from "consola";
2743
- var registerUserCommand = defineCommand28({
2849
+ import { defineCommand as defineCommand29 } from "citty";
2850
+ import consola24 from "consola";
2851
+ var registerUserCommand = defineCommand29({
2744
2852
  meta: {
2745
2853
  name: "register-user",
2746
2854
  description: "Register a sub-user with SSH key"
@@ -2795,15 +2903,15 @@ var registerUserCommand = defineCommand28({
2795
2903
  ...userType ? { type: userType } : {}
2796
2904
  }
2797
2905
  });
2798
- consola23.success(`User registered: ${result.email} (type: ${result.type}, owner: ${result.owner})`);
2906
+ consola24.success(`User registered: ${result.email} (type: ${result.type}, owner: ${result.owner})`);
2799
2907
  }
2800
2908
  });
2801
2909
 
2802
2910
  // src/commands/dns-check.ts
2803
- import { defineCommand as defineCommand29 } from "citty";
2804
- import consola24 from "consola";
2911
+ import { defineCommand as defineCommand30 } from "citty";
2912
+ import consola25 from "consola";
2805
2913
  import { resolveDDISA as resolveDDISA2 } from "@openape/core";
2806
- var dnsCheckCommand = defineCommand29({
2914
+ var dnsCheckCommand = defineCommand30({
2807
2915
  meta: {
2808
2916
  name: "dns-check",
2809
2917
  description: "Validate DDISA DNS TXT records for a domain"
@@ -2817,7 +2925,7 @@ var dnsCheckCommand = defineCommand29({
2817
2925
  },
2818
2926
  async run({ args }) {
2819
2927
  const domain = args.domain;
2820
- consola24.start(`Checking _ddisa.${domain}...`);
2928
+ consola25.start(`Checking _ddisa.${domain}...`);
2821
2929
  try {
2822
2930
  const result = await resolveDDISA2(domain);
2823
2931
  if (!result) {
@@ -2826,7 +2934,7 @@ var dnsCheckCommand = defineCommand29({
2826
2934
  console.log(` _ddisa.${domain} TXT "v=ddisa1 idp=https://id.${domain}"`);
2827
2935
  throw new CliError(`No DDISA record found for ${domain}`);
2828
2936
  }
2829
- consola24.success(`_ddisa.${domain} \u2192 ${result.idp}`);
2937
+ consola25.success(`_ddisa.${domain} \u2192 ${result.idp}`);
2830
2938
  console.log("");
2831
2939
  console.log(` Version: ${result.version || "ddisa1"}`);
2832
2940
  console.log(` IdP URL: ${result.idp}`);
@@ -2835,14 +2943,14 @@ var dnsCheckCommand = defineCommand29({
2835
2943
  if (result.priority !== void 0)
2836
2944
  console.log(` Priority: ${result.priority}`);
2837
2945
  console.log("");
2838
- consola24.start(`Verifying IdP at ${result.idp}...`);
2946
+ consola25.start(`Verifying IdP at ${result.idp}...`);
2839
2947
  const discoResp = await fetch(`${result.idp}/.well-known/openid-configuration`);
2840
2948
  if (!discoResp.ok) {
2841
- consola24.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
2949
+ consola25.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
2842
2950
  return;
2843
2951
  }
2844
2952
  const disco = await discoResp.json();
2845
- consola24.success(`IdP is reachable`);
2953
+ consola25.success(`IdP is reachable`);
2846
2954
  console.log(` Issuer: ${disco.issuer}`);
2847
2955
  console.log(` DDISA: v${disco.ddisa_version || "?"}`);
2848
2956
  if (disco.ddisa_auth_methods_supported) {
@@ -2860,7 +2968,7 @@ var dnsCheckCommand = defineCommand29({
2860
2968
  // src/commands/health.ts
2861
2969
  import { exec } from "child_process";
2862
2970
  import { promisify } from "util";
2863
- import { defineCommand as defineCommand30 } from "citty";
2971
+ import { defineCommand as defineCommand31 } from "citty";
2864
2972
  var execAsync = promisify(exec);
2865
2973
  async function resolveApeShellPath() {
2866
2974
  try {
@@ -2896,7 +3004,7 @@ async function bestEffortGrantCount(idp) {
2896
3004
  }
2897
3005
  }
2898
3006
  async function runHealth(args) {
2899
- const version = true ? "0.8.0" : "0.0.0";
3007
+ const version = true ? "0.9.0" : "0.0.0";
2900
3008
  const auth = loadAuth();
2901
3009
  if (!auth) {
2902
3010
  throw new CliError("Not logged in. Run `apes login` first.", 1);
@@ -2959,7 +3067,7 @@ async function runHealth(args) {
2959
3067
  throw new CliError(`IdP ${auth.idp} unreachable: ${idpProbe.error}`, 1);
2960
3068
  }
2961
3069
  }
2962
- var healthCommand = defineCommand30({
3070
+ var healthCommand = defineCommand31({
2963
3071
  meta: {
2964
3072
  name: "health",
2965
3073
  description: "Report CLI diagnostic state (auth, IdP, grants, binaries)"
@@ -2977,8 +3085,8 @@ var healthCommand = defineCommand30({
2977
3085
  });
2978
3086
 
2979
3087
  // src/commands/workflows.ts
2980
- import { defineCommand as defineCommand31 } from "citty";
2981
- import consola25 from "consola";
3088
+ import { defineCommand as defineCommand32 } from "citty";
3089
+ import consola26 from "consola";
2982
3090
 
2983
3091
  // src/guides/index.ts
2984
3092
  var guides = [
@@ -3028,7 +3136,7 @@ var guides = [
3028
3136
  ];
3029
3137
 
3030
3138
  // src/commands/workflows.ts
3031
- var workflowsCommand = defineCommand31({
3139
+ var workflowsCommand = defineCommand32({
3032
3140
  meta: {
3033
3141
  name: "workflows",
3034
3142
  description: "Discover workflow guides"
@@ -3049,7 +3157,7 @@ var workflowsCommand = defineCommand31({
3049
3157
  if (args.id) {
3050
3158
  const guide = guides.find((g) => g.id === String(args.id));
3051
3159
  if (!guide) {
3052
- consola25.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
3160
+ consola26.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
3053
3161
  throw new CliError(`Guide not found: ${args.id}`);
3054
3162
  }
3055
3163
  if (args.json) {
@@ -3098,10 +3206,10 @@ if (shellRewrite) {
3098
3206
  if (shellRewrite.action === "rewrite") {
3099
3207
  process.argv = shellRewrite.argv;
3100
3208
  } else if (shellRewrite.action === "version") {
3101
- console.log(`ape-shell ${"0.8.0"} (OpenApe DDISA shell wrapper)`);
3209
+ console.log(`ape-shell ${"0.9.0"} (OpenApe DDISA shell wrapper)`);
3102
3210
  process.exit(0);
3103
3211
  } else if (shellRewrite.action === "help") {
3104
- console.log(`ape-shell ${"0.8.0"} \u2014 OpenApe DDISA shell wrapper`);
3212
+ console.log(`ape-shell ${"0.9.0"} \u2014 OpenApe DDISA shell wrapper`);
3105
3213
  console.log("");
3106
3214
  console.log("Usage:");
3107
3215
  console.log(" ape-shell Start interactive grant-mediated REPL");
@@ -3116,7 +3224,7 @@ if (shellRewrite) {
3116
3224
  console.log(" --help, -h Show this help message");
3117
3225
  process.exit(0);
3118
3226
  } else if (shellRewrite.action === "interactive") {
3119
- const { runInteractiveShell } = await import("./orchestrator-FTQW3ZRS.js");
3227
+ const { runInteractiveShell } = await import("./orchestrator-GPNL543L.js");
3120
3228
  await runInteractiveShell();
3121
3229
  process.exit(0);
3122
3230
  } else {
@@ -3125,7 +3233,7 @@ if (shellRewrite) {
3125
3233
  }
3126
3234
  }
3127
3235
  var debug = process.argv.includes("--debug");
3128
- var grantsCommand = defineCommand32({
3236
+ var grantsCommand = defineCommand33({
3129
3237
  meta: {
3130
3238
  name: "grants",
3131
3239
  description: "Grant management"
@@ -3139,13 +3247,14 @@ var grantsCommand = defineCommand32({
3139
3247
  approve: approveCommand,
3140
3248
  deny: denyCommand,
3141
3249
  revoke: revokeCommand,
3250
+ run: runGrantCommand,
3142
3251
  token: tokenCommand,
3143
3252
  delegate: delegateCommand,
3144
3253
  delegations: delegationsCommand,
3145
3254
  "delegation-revoke": delegationRevokeCommand
3146
3255
  }
3147
3256
  });
3148
- var configCommand = defineCommand32({
3257
+ var configCommand = defineCommand33({
3149
3258
  meta: {
3150
3259
  name: "config",
3151
3260
  description: "Configuration management"
@@ -3155,10 +3264,10 @@ var configCommand = defineCommand32({
3155
3264
  set: configSetCommand
3156
3265
  }
3157
3266
  });
3158
- var main = defineCommand32({
3267
+ var main = defineCommand33({
3159
3268
  meta: {
3160
3269
  name: "apes",
3161
- version: "0.8.0",
3270
+ version: "0.9.0",
3162
3271
  description: "Unified CLI for OpenApe"
3163
3272
  },
3164
3273
  subCommands: {
@@ -3186,13 +3295,13 @@ runMain(main).catch((err) => {
3186
3295
  process.exit(err.exitCode);
3187
3296
  }
3188
3297
  if (err instanceof CliError) {
3189
- consola26.error(err.message);
3298
+ consola27.error(err.message);
3190
3299
  process.exit(err.exitCode);
3191
3300
  }
3192
3301
  if (debug) {
3193
- consola26.error(err);
3302
+ consola27.error(err);
3194
3303
  } else {
3195
- consola26.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
3304
+ consola27.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
3196
3305
  }
3197
3306
  process.exit(1);
3198
3307
  });