@openape/apes 0.8.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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";
@@ -537,6 +538,14 @@ var inboxCommand = defineCommand5({
537
538
 
538
539
  // src/commands/grants/status.ts
539
540
  import { defineCommand as defineCommand6 } from "citty";
541
+ function formatTs(ts) {
542
+ if (ts === void 0 || ts === null)
543
+ return void 0;
544
+ const ms = ts * 1e3;
545
+ if (!Number.isFinite(ms))
546
+ return void 0;
547
+ return new Date(ms).toISOString();
548
+ }
540
549
  var statusCommand = defineCommand6({
541
550
  meta: {
542
551
  name: "status",
@@ -564,23 +573,32 @@ var statusCommand = defineCommand6({
564
573
  }
565
574
  console.log(`Grant: ${grant.id}`);
566
575
  console.log(`Status: ${grant.status}`);
567
- console.log(`Type: ${grant.type}`);
568
- console.log(`Requester: ${grant.requester}`);
569
- console.log(`Owner: ${grant.owner}`);
570
- if (grant.approver)
571
- console.log(`Approver: ${grant.approver}`);
576
+ if (grant.request?.audience)
577
+ console.log(`Audience: ${grant.request.audience}`);
578
+ if (grant.request?.requester)
579
+ console.log(`Requester: ${grant.request.requester}`);
580
+ if (grant.request?.target_host)
581
+ console.log(`Host: ${grant.request.target_host}`);
572
582
  if (grant.request?.command)
573
583
  console.log(`Command: ${grant.request.command.join(" ")}`);
574
584
  if (grant.request?.grant_type)
575
585
  console.log(`Approval: ${grant.request.grant_type}`);
576
586
  if (grant.request?.reason)
577
587
  console.log(`Reason: ${grant.request.reason}`);
588
+ const createdAt = formatTs(grant.created_at);
589
+ if (createdAt)
590
+ console.log(`Created: ${createdAt}`);
578
591
  if (grant.decided_by)
579
592
  console.log(`Decided by: ${grant.decided_by}`);
580
- if (grant.decided_at)
581
- console.log(`Decided at: ${grant.decided_at}`);
582
- if (grant.expires_at)
583
- console.log(`Expires: ${grant.expires_at}`);
593
+ const decidedAt = formatTs(grant.decided_at);
594
+ if (decidedAt)
595
+ console.log(`Decided at: ${decidedAt}`);
596
+ const usedAt = formatTs(grant.used_at);
597
+ if (usedAt)
598
+ console.log(`Used at: ${usedAt}`);
599
+ const expiresAt = formatTs(grant.expires_at);
600
+ if (expiresAt)
601
+ console.log(`Expires: ${expiresAt}`);
584
602
  }
585
603
  });
586
604
 
@@ -1041,9 +1059,83 @@ var revokeCommand = defineCommand11({
1041
1059
  }
1042
1060
  });
1043
1061
 
1044
- // src/commands/grants/token.ts
1062
+ // src/commands/grants/run.ts
1063
+ import { execFileSync } from "child_process";
1045
1064
  import { defineCommand as defineCommand12 } from "citty";
1046
- var tokenCommand = defineCommand12({
1065
+ import consola12 from "consola";
1066
+ var runGrantCommand = defineCommand12({
1067
+ meta: {
1068
+ name: "run",
1069
+ description: "Execute a previously-approved grant by ID"
1070
+ },
1071
+ args: {
1072
+ id: {
1073
+ type: "positional",
1074
+ description: "Grant ID",
1075
+ required: true
1076
+ },
1077
+ "escapes-path": {
1078
+ type: "string",
1079
+ description: "Path to escapes binary (audience=escapes only)",
1080
+ default: "escapes"
1081
+ }
1082
+ },
1083
+ async run({ args }) {
1084
+ const idp = getIdpUrl();
1085
+ if (!idp)
1086
+ throw new CliError("No IdP URL configured. Run `apes login` first or pass --idp.");
1087
+ const grantsUrl = await getGrantsEndpoint(idp);
1088
+ const grant = await apiFetch(`${grantsUrl}/${args.id}`);
1089
+ if (grant.status === "pending")
1090
+ throw new CliError(`Grant ${grant.id} is still pending. Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
1091
+ if (grant.status === "denied" || grant.status === "revoked")
1092
+ throw new CliError(`Grant ${grant.id} is ${grant.status}. Request a new one.`);
1093
+ if (grant.status === "used")
1094
+ throw new CliError(`Grant ${grant.id} has already been used. Request a new one (single-use grants cannot be re-executed).`);
1095
+ if (grant.status !== "approved")
1096
+ throw new CliError(`Grant ${grant.id} has unexpected status: ${grant.status}`);
1097
+ const audience = grant.request?.audience;
1098
+ const authDetails = grant.request?.authorization_details ?? [];
1099
+ const hasOpenApeCliDetail = authDetails.some((d) => d?.type === "openape_cli");
1100
+ const isShapesGrant = hasOpenApeCliDetail || audience === "shapes";
1101
+ if (isShapesGrant) {
1102
+ let resolved;
1103
+ try {
1104
+ resolved = await resolveFromGrant(grant);
1105
+ } catch (err) {
1106
+ const msg = err instanceof Error ? err.message : String(err);
1107
+ throw new CliError(`Cannot re-resolve grant: ${msg}`);
1108
+ }
1109
+ const token = await fetchGrantToken(idp, grant.id);
1110
+ await verifyAndExecute(token, resolved);
1111
+ return;
1112
+ }
1113
+ if (audience === "escapes") {
1114
+ const { authz_jwt } = await apiFetch(`${grantsUrl}/${grant.id}/token`, { method: "POST" });
1115
+ const command = grant.request?.command ?? [];
1116
+ if (command.length === 0)
1117
+ throw new CliError(`Grant ${grant.id} has no command to execute.`);
1118
+ consola12.info(`Executing via escapes: ${command.join(" ")}`);
1119
+ try {
1120
+ execFileSync(args["escapes-path"], ["--grant", authz_jwt, "--", ...command], { stdio: "inherit" });
1121
+ } catch (err) {
1122
+ const exitCode = err.status || 1;
1123
+ throw new CliExit(exitCode);
1124
+ }
1125
+ return;
1126
+ }
1127
+ if (audience === "ape-shell") {
1128
+ throw new CliError(
1129
+ `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.`
1130
+ );
1131
+ }
1132
+ throw new CliError(`Grant ${grant.id} has unsupported audience "${audience}" \u2014 no execution path available.`);
1133
+ }
1134
+ });
1135
+
1136
+ // src/commands/grants/token.ts
1137
+ import { defineCommand as defineCommand13 } from "citty";
1138
+ var tokenCommand = defineCommand13({
1047
1139
  meta: {
1048
1140
  name: "token",
1049
1141
  description: "Get grant token JWT"
@@ -1069,9 +1161,9 @@ var tokenCommand = defineCommand12({
1069
1161
  });
1070
1162
 
1071
1163
  // src/commands/grants/delegate.ts
1072
- import { defineCommand as defineCommand13 } from "citty";
1073
- import consola12 from "consola";
1074
- var delegateCommand = defineCommand13({
1164
+ import { defineCommand as defineCommand14 } from "citty";
1165
+ import consola13 from "consola";
1166
+ var delegateCommand = defineCommand14({
1075
1167
  meta: {
1076
1168
  name: "delegate",
1077
1169
  description: "Create a delegation"
@@ -1123,7 +1215,7 @@ var delegateCommand = defineCommand13({
1123
1215
  method: "POST",
1124
1216
  body
1125
1217
  });
1126
- consola12.success(`Delegation created: ${result.id}`);
1218
+ consola13.success(`Delegation created: ${result.id}`);
1127
1219
  console.log(` Delegate: ${args.to}`);
1128
1220
  console.log(` Audience: ${args.at}`);
1129
1221
  if (args.scopes)
@@ -1135,9 +1227,9 @@ var delegateCommand = defineCommand13({
1135
1227
  });
1136
1228
 
1137
1229
  // src/commands/grants/delegations.ts
1138
- import { defineCommand as defineCommand14 } from "citty";
1139
- import consola13 from "consola";
1140
- var delegationsCommand = defineCommand14({
1230
+ import { defineCommand as defineCommand15 } from "citty";
1231
+ import consola14 from "consola";
1232
+ var delegationsCommand = defineCommand15({
1141
1233
  meta: {
1142
1234
  name: "delegations",
1143
1235
  description: "List delegations"
@@ -1159,7 +1251,7 @@ var delegationsCommand = defineCommand14({
1159
1251
  return;
1160
1252
  }
1161
1253
  if (delegations.length === 0) {
1162
- consola13.info("No delegations found.");
1254
+ consola14.info("No delegations found.");
1163
1255
  return;
1164
1256
  }
1165
1257
  for (const d of delegations) {
@@ -1171,9 +1263,9 @@ var delegationsCommand = defineCommand14({
1171
1263
  });
1172
1264
 
1173
1265
  // src/commands/grants/delegation-revoke.ts
1174
- import { defineCommand as defineCommand15 } from "citty";
1175
- import consola14 from "consola";
1176
- var delegationRevokeCommand = defineCommand15({
1266
+ import { defineCommand as defineCommand16 } from "citty";
1267
+ import consola15 from "consola";
1268
+ var delegationRevokeCommand = defineCommand16({
1177
1269
  meta: {
1178
1270
  name: "delegation-revoke",
1179
1271
  description: "Revoke a delegation"
@@ -1196,16 +1288,16 @@ var delegationRevokeCommand = defineCommand15({
1196
1288
  `${delegationsUrl}/${id}`,
1197
1289
  { method: "DELETE" }
1198
1290
  );
1199
- consola14.success(`Delegation ${result.id} revoked.`);
1291
+ consola15.success(`Delegation ${result.id} revoked.`);
1200
1292
  }
1201
1293
  });
1202
1294
 
1203
1295
  // src/commands/admin/index.ts
1204
- import { defineCommand as defineCommand18 } from "citty";
1296
+ import { defineCommand as defineCommand19 } from "citty";
1205
1297
 
1206
1298
  // src/commands/admin/users.ts
1207
- import { defineCommand as defineCommand16 } from "citty";
1208
- import consola15 from "consola";
1299
+ import { defineCommand as defineCommand17 } from "citty";
1300
+ import consola16 from "consola";
1209
1301
  function getManagementToken() {
1210
1302
  const token = process.env.APES_MANAGEMENT_TOKEN;
1211
1303
  if (!token) {
@@ -1213,7 +1305,7 @@ function getManagementToken() {
1213
1305
  }
1214
1306
  return token;
1215
1307
  }
1216
- var usersListCommand = defineCommand16({
1308
+ var usersListCommand = defineCommand17({
1217
1309
  meta: {
1218
1310
  name: "list",
1219
1311
  description: "List all users"
@@ -1255,7 +1347,7 @@ var usersListCommand = defineCommand16({
1255
1347
  return;
1256
1348
  }
1257
1349
  if (result.data.length === 0) {
1258
- consola15.info("No users found.");
1350
+ consola16.info("No users found.");
1259
1351
  return;
1260
1352
  }
1261
1353
  for (const u of result.data) {
@@ -1264,11 +1356,11 @@ var usersListCommand = defineCommand16({
1264
1356
  console.log(`${u.email} ${u.name}${owner}${active}`);
1265
1357
  }
1266
1358
  if (result.pagination.has_more) {
1267
- consola15.info(`More results available. Use --cursor="${result.pagination.cursor}" to see next page.`);
1359
+ consola16.info(`More results available. Use --cursor="${result.pagination.cursor}" to see next page.`);
1268
1360
  }
1269
1361
  }
1270
1362
  });
1271
- var usersCreateCommand = defineCommand16({
1363
+ var usersCreateCommand = defineCommand17({
1272
1364
  meta: {
1273
1365
  name: "create",
1274
1366
  description: "Create a user"
@@ -1299,10 +1391,10 @@ var usersCreateCommand = defineCommand16({
1299
1391
  token
1300
1392
  }
1301
1393
  );
1302
- consola15.success(`User created: ${result.email} (${result.name})`);
1394
+ consola16.success(`User created: ${result.email} (${result.name})`);
1303
1395
  }
1304
1396
  });
1305
- var usersDeleteCommand = defineCommand16({
1397
+ var usersDeleteCommand = defineCommand17({
1306
1398
  meta: {
1307
1399
  name: "delete",
1308
1400
  description: "Delete a user"
@@ -1325,7 +1417,7 @@ var usersDeleteCommand = defineCommand16({
1325
1417
  method: "DELETE",
1326
1418
  token
1327
1419
  });
1328
- consola15.success(`User deleted: ${email}`);
1420
+ consola16.success(`User deleted: ${email}`);
1329
1421
  }
1330
1422
  });
1331
1423
 
@@ -1333,8 +1425,8 @@ var usersDeleteCommand = defineCommand16({
1333
1425
  import { existsSync as existsSync2, readFileSync } from "fs";
1334
1426
  import { resolve } from "path";
1335
1427
  import { homedir as homedir3 } from "os";
1336
- import { defineCommand as defineCommand17 } from "citty";
1337
- import consola16 from "consola";
1428
+ import { defineCommand as defineCommand18 } from "citty";
1429
+ import consola17 from "consola";
1338
1430
  function getManagementToken2() {
1339
1431
  const token = process.env.APES_MANAGEMENT_TOKEN;
1340
1432
  if (!token) {
@@ -1342,7 +1434,7 @@ function getManagementToken2() {
1342
1434
  }
1343
1435
  return token;
1344
1436
  }
1345
- var sshKeysListCommand = defineCommand17({
1437
+ var sshKeysListCommand = defineCommand18({
1346
1438
  meta: {
1347
1439
  name: "list",
1348
1440
  description: "List SSH keys for a user"
@@ -1375,7 +1467,7 @@ var sshKeysListCommand = defineCommand17({
1375
1467
  return;
1376
1468
  }
1377
1469
  if (keys.length === 0) {
1378
- consola16.info(`No SSH keys found for ${email}.`);
1470
+ consola17.info(`No SSH keys found for ${email}.`);
1379
1471
  return;
1380
1472
  }
1381
1473
  for (const k of keys) {
@@ -1383,7 +1475,7 @@ var sshKeysListCommand = defineCommand17({
1383
1475
  }
1384
1476
  }
1385
1477
  });
1386
- var sshKeysAddCommand = defineCommand17({
1478
+ var sshKeysAddCommand = defineCommand18({
1387
1479
  meta: {
1388
1480
  name: "add",
1389
1481
  description: "Add an SSH key for a user"
@@ -1427,10 +1519,10 @@ var sshKeysAddCommand = defineCommand17({
1427
1519
  token
1428
1520
  }
1429
1521
  );
1430
- consola16.success(`SSH key added: ${result.keyId} (${result.name})`);
1522
+ consola17.success(`SSH key added: ${result.keyId} (${result.name})`);
1431
1523
  }
1432
1524
  });
1433
- var sshKeysDeleteCommand = defineCommand17({
1525
+ var sshKeysDeleteCommand = defineCommand18({
1434
1526
  meta: {
1435
1527
  name: "delete",
1436
1528
  description: "Delete an SSH key"
@@ -1461,12 +1553,12 @@ var sshKeysDeleteCommand = defineCommand17({
1461
1553
  token
1462
1554
  }
1463
1555
  );
1464
- consola16.success(`SSH key deleted: ${keyId}`);
1556
+ consola17.success(`SSH key deleted: ${keyId}`);
1465
1557
  }
1466
1558
  });
1467
1559
 
1468
1560
  // src/commands/admin/index.ts
1469
- var usersCommand = defineCommand18({
1561
+ var usersCommand = defineCommand19({
1470
1562
  meta: {
1471
1563
  name: "users",
1472
1564
  description: "Manage users"
@@ -1477,7 +1569,7 @@ var usersCommand = defineCommand18({
1477
1569
  delete: usersDeleteCommand
1478
1570
  }
1479
1571
  });
1480
- var sshKeysCommand = defineCommand18({
1572
+ var sshKeysCommand = defineCommand19({
1481
1573
  meta: {
1482
1574
  name: "ssh-keys",
1483
1575
  description: "Manage SSH keys"
@@ -1488,7 +1580,7 @@ var sshKeysCommand = defineCommand18({
1488
1580
  delete: sshKeysDeleteCommand
1489
1581
  }
1490
1582
  });
1491
- var adminCommand = defineCommand18({
1583
+ var adminCommand = defineCommand19({
1492
1584
  meta: {
1493
1585
  name: "admin",
1494
1586
  description: "Admin commands (requires APES_MANAGEMENT_TOKEN)"
@@ -1500,15 +1592,15 @@ var adminCommand = defineCommand18({
1500
1592
  });
1501
1593
 
1502
1594
  // src/commands/adapter/index.ts
1503
- import { defineCommand as defineCommand19 } from "citty";
1504
- import consola17 from "consola";
1505
- var adapterCommand = defineCommand19({
1595
+ import { defineCommand as defineCommand20 } from "citty";
1596
+ import consola18 from "consola";
1597
+ var adapterCommand = defineCommand20({
1506
1598
  meta: {
1507
1599
  name: "adapter",
1508
1600
  description: "Manage CLI adapters"
1509
1601
  },
1510
1602
  subCommands: {
1511
- list: defineCommand19({
1603
+ list: defineCommand20({
1512
1604
  meta: {
1513
1605
  name: "list",
1514
1606
  description: "List available adapters"
@@ -1539,7 +1631,7 @@ var adapterCommand = defineCommand19({
1539
1631
  `);
1540
1632
  return;
1541
1633
  }
1542
- consola17.info(`Registry: ${index2.adapters.length} adapters (${index2.generated_at})`);
1634
+ consola18.info(`Registry: ${index2.adapters.length} adapters (${index2.generated_at})`);
1543
1635
  for (const a of index2.adapters) {
1544
1636
  const installed = isInstalled(a.id, false) ? " [installed]" : "";
1545
1637
  console.log(` ${a.id.padEnd(12)} ${a.name.padEnd(24)} ${a.category}${installed}`);
@@ -1561,7 +1653,7 @@ var adapterCommand = defineCommand19({
1561
1653
  return;
1562
1654
  }
1563
1655
  if (local.length === 0) {
1564
- consola17.info("No adapters installed. Use `apes adapter list --remote` to see available adapters.");
1656
+ consola18.info("No adapters installed. Use `apes adapter list --remote` to see available adapters.");
1565
1657
  return;
1566
1658
  }
1567
1659
  for (const a of local) {
@@ -1569,7 +1661,7 @@ var adapterCommand = defineCommand19({
1569
1661
  }
1570
1662
  }
1571
1663
  }),
1572
- install: defineCommand19({
1664
+ install: defineCommand20({
1573
1665
  meta: {
1574
1666
  name: "install",
1575
1667
  description: "Install an adapter from the registry"
@@ -1598,24 +1690,24 @@ var adapterCommand = defineCommand19({
1598
1690
  for (const id of ids) {
1599
1691
  const entry = findAdapter(index, id);
1600
1692
  if (!entry) {
1601
- consola17.error(`Adapter "${id}" not found in registry. Use \`apes adapter search ${id}\` to search.`);
1693
+ consola18.error(`Adapter "${id}" not found in registry. Use \`apes adapter search ${id}\` to search.`);
1602
1694
  continue;
1603
1695
  }
1604
1696
  const conflicts = findConflictingAdapters(entry.executable, id);
1605
1697
  if (conflicts.length > 0) {
1606
1698
  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}`);
1699
+ consola18.warn(`Conflicting adapter found: ${c.path} (id: ${c.adapterId}, executable: ${c.executable})`);
1700
+ consola18.warn(` Remove it with: apes adapter remove ${c.adapterId}`);
1609
1701
  }
1610
1702
  }
1611
1703
  const result = await installAdapter(entry, { local });
1612
1704
  const verb = result.updated ? "Updated" : "Installed";
1613
- consola17.success(`${verb} ${result.id} \u2192 ${result.path}`);
1614
- consola17.info(`Digest: ${result.digest}`);
1705
+ consola18.success(`${verb} ${result.id} \u2192 ${result.path}`);
1706
+ consola18.info(`Digest: ${result.digest}`);
1615
1707
  }
1616
1708
  }
1617
1709
  }),
1618
- remove: defineCommand19({
1710
+ remove: defineCommand20({
1619
1711
  meta: {
1620
1712
  name: "remove",
1621
1713
  description: "Remove an installed adapter"
@@ -1638,9 +1730,9 @@ var adapterCommand = defineCommand19({
1638
1730
  let failed = false;
1639
1731
  for (const id of ids) {
1640
1732
  if (removeAdapter(id, local)) {
1641
- consola17.success(`Removed adapter: ${id}`);
1733
+ consola18.success(`Removed adapter: ${id}`);
1642
1734
  } else {
1643
- consola17.error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
1735
+ consola18.error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
1644
1736
  failed = true;
1645
1737
  }
1646
1738
  }
@@ -1648,7 +1740,7 @@ var adapterCommand = defineCommand19({
1648
1740
  throw new CliError("Some adapters could not be removed");
1649
1741
  }
1650
1742
  }),
1651
- info: defineCommand19({
1743
+ info: defineCommand20({
1652
1744
  meta: {
1653
1745
  name: "info",
1654
1746
  description: "Show detailed adapter information"
@@ -1690,7 +1782,7 @@ var adapterCommand = defineCommand19({
1690
1782
  }
1691
1783
  }
1692
1784
  }),
1693
- search: defineCommand19({
1785
+ search: defineCommand20({
1694
1786
  meta: {
1695
1787
  name: "search",
1696
1788
  description: "Search adapters in the registry"
@@ -1722,7 +1814,7 @@ var adapterCommand = defineCommand19({
1722
1814
  return;
1723
1815
  }
1724
1816
  if (results.length === 0) {
1725
- consola17.info(`No adapters matching "${query}"`);
1817
+ consola18.info(`No adapters matching "${query}"`);
1726
1818
  return;
1727
1819
  }
1728
1820
  for (const a of results) {
@@ -1731,7 +1823,7 @@ var adapterCommand = defineCommand19({
1731
1823
  }
1732
1824
  }
1733
1825
  }),
1734
- update: defineCommand19({
1826
+ update: defineCommand20({
1735
1827
  meta: {
1736
1828
  name: "update",
1737
1829
  description: "Update installed adapters"
@@ -1757,33 +1849,33 @@ var adapterCommand = defineCommand19({
1757
1849
  const targetId = args.id ? String(args.id) : void 0;
1758
1850
  const targets = targetId ? [targetId] : index.adapters.map((a) => a.id).filter((id) => isInstalled(id, false));
1759
1851
  if (targets.length === 0) {
1760
- consola17.info("No adapters installed to update.");
1852
+ consola18.info("No adapters installed to update.");
1761
1853
  return;
1762
1854
  }
1763
1855
  for (const id of targets) {
1764
1856
  const entry = findAdapter(index, id);
1765
1857
  if (!entry) {
1766
- consola17.warn(`${id}: not found in registry, skipping`);
1858
+ consola18.warn(`${id}: not found in registry, skipping`);
1767
1859
  continue;
1768
1860
  }
1769
1861
  const localDigest = getInstalledDigest(id, false);
1770
1862
  if (localDigest === entry.digest) {
1771
- consola17.info(`${id}: already up to date`);
1863
+ consola18.info(`${id}: already up to date`);
1772
1864
  continue;
1773
1865
  }
1774
1866
  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");
1867
+ consola18.warn(`${id}: digest will change \u2014 existing grants for this adapter will be invalidated`);
1868
+ consola18.info(` Old: ${localDigest}`);
1869
+ consola18.info(` New: ${entry.digest}`);
1870
+ consola18.info(" Use --yes to confirm");
1779
1871
  continue;
1780
1872
  }
1781
1873
  const result = await installAdapter(entry);
1782
- consola17.success(`Updated ${result.id} \u2192 ${result.path}`);
1874
+ consola18.success(`Updated ${result.id} \u2192 ${result.path}`);
1783
1875
  }
1784
1876
  }
1785
1877
  }),
1786
- verify: defineCommand19({
1878
+ verify: defineCommand20({
1787
1879
  meta: {
1788
1880
  name: "verify",
1789
1881
  description: "Verify installed adapter against registry digest"
@@ -1816,7 +1908,7 @@ var adapterCommand = defineCommand19({
1816
1908
  if (!localDigest)
1817
1909
  throw new Error(`Adapter "${id}" is not installed${local ? " locally" : ""}`);
1818
1910
  if (localDigest === entry.digest) {
1819
- consola17.success(`${id}: digest matches registry`);
1911
+ consola18.success(`${id}: digest matches registry`);
1820
1912
  } else {
1821
1913
  console.log(` Local: ${localDigest}`);
1822
1914
  console.log(` Registry: ${entry.digest}`);
@@ -1828,12 +1920,24 @@ var adapterCommand = defineCommand19({
1828
1920
  });
1829
1921
 
1830
1922
  // src/commands/run.ts
1831
- import { execFileSync } from "child_process";
1923
+ import { execFileSync as execFileSync2 } from "child_process";
1832
1924
  import { hostname as hostname3 } from "os";
1833
1925
  import { basename } from "path";
1834
- import { defineCommand as defineCommand20 } from "citty";
1835
- import consola18 from "consola";
1836
- var runCommand = defineCommand20({
1926
+ import { defineCommand as defineCommand21 } from "citty";
1927
+ import consola19 from "consola";
1928
+ function shouldWaitForGrant(args) {
1929
+ return args.wait === true || process.env.APE_WAIT === "1";
1930
+ }
1931
+ function printPendingGrantInfo(grant, idp) {
1932
+ consola19.success(`Grant ${grant.id} erstellt`);
1933
+ console.log(` Approve: ${idp}/grant-approval?grant_id=${grant.id}`);
1934
+ console.log(` Status: apes grants status ${grant.id}`);
1935
+ console.log(` Ausf\xFChren: apes grants run ${grant.id}`);
1936
+ console.log("");
1937
+ console.log(' Tipp: Im Browser "als timed/always approven" w\xE4hlen, um das');
1938
+ console.log(" Kommando ohne erneuten Approval wiederzuverwenden.");
1939
+ }
1940
+ var runCommand = defineCommand21({
1837
1941
  meta: {
1838
1942
  name: "run",
1839
1943
  description: "Execute a grant-secured command"
@@ -1874,6 +1978,11 @@ var runCommand = defineCommand20({
1874
1978
  description: "Shell mode: use session grant with audience ape-shell",
1875
1979
  default: false
1876
1980
  },
1981
+ "wait": {
1982
+ type: "boolean",
1983
+ description: "Block until grant is approved (default: async, print grant info and exit 0). Equivalent to APE_WAIT=1.",
1984
+ default: false
1985
+ },
1877
1986
  "_": {
1878
1987
  type: "positional",
1879
1988
  description: "Command to execute (after --)",
@@ -1920,7 +2029,7 @@ async function runShellMode(command, args) {
1920
2029
  }
1921
2030
  } catch {
1922
2031
  }
1923
- consola18.info(`Requesting ape-shell session grant on ${targetHost}`);
2032
+ consola19.info(`Requesting ape-shell session grant on ${targetHost}`);
1924
2033
  const grant = await apiFetch(grantsUrl, {
1925
2034
  method: "POST",
1926
2035
  body: {
@@ -1932,8 +2041,6 @@ async function runShellMode(command, args) {
1932
2041
  reason: `Shell session: ${command.join(" ").slice(0, 100)}`
1933
2042
  }
1934
2043
  });
1935
- consola18.info(`Grant requested: ${grant.id}`);
1936
- consola18.info("Waiting for approval...");
1937
2044
  notifyGrantPending({
1938
2045
  grantId: grant.id,
1939
2046
  approveUrl: `${idp}/grant-approval?grant_id=${grant.id}`,
@@ -1941,18 +2048,24 @@ async function runShellMode(command, args) {
1941
2048
  audience: "ape-shell",
1942
2049
  host: targetHost
1943
2050
  });
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));
2051
+ if (shouldWaitForGrant(args)) {
2052
+ consola19.info(`Grant requested: ${grant.id}`);
2053
+ consola19.info("Waiting for approval...");
2054
+ const maxWait = 3e5;
2055
+ const interval = 3e3;
2056
+ const start = Date.now();
2057
+ while (Date.now() - start < maxWait) {
2058
+ const status = await apiFetch(`${grantsUrl}/${grant.id}`);
2059
+ if (status.status === "approved")
2060
+ break;
2061
+ if (status.status === "denied" || status.status === "revoked")
2062
+ throw new CliError(`Grant ${status.status}.`);
2063
+ await new Promise((r) => setTimeout(r, interval));
2064
+ }
2065
+ execShellCommand(command);
2066
+ return;
1954
2067
  }
1955
- execShellCommand(command);
2068
+ printPendingGrantInfo(grant, idp);
1956
2069
  }
1957
2070
  async function tryAdapterModeFromShell(command, idp, args) {
1958
2071
  const cmdString = extractShellCommandString(command);
@@ -1967,32 +2080,30 @@ async function tryAdapterModeFromShell(command, idp, args) {
1967
2080
  try {
1968
2081
  resolved = await resolveCommand(loaded, [normalizedExecutable, ...parsed.argv]);
1969
2082
  } catch (err) {
1970
- consola18.debug(`ape-shell: adapter resolve failed for "${parsed.raw}":`, err);
2083
+ consola19.debug(`ape-shell: adapter resolve failed for "${parsed.raw}":`, err);
1971
2084
  return false;
1972
2085
  }
1973
2086
  try {
1974
2087
  const existingGrantId = await findExistingGrant(resolved, idp);
1975
2088
  if (existingGrantId) {
1976
- consola18.info(`Reusing grant ${existingGrantId} for: ${resolved.detail.display}`);
1977
- const token2 = await fetchGrantToken(idp, existingGrantId);
1978
- await verifyAndExecute(token2, resolved);
2089
+ consola19.info(`Reusing grant ${existingGrantId} for: ${resolved.detail.display}`);
2090
+ const token = await fetchGrantToken(idp, existingGrantId);
2091
+ await verifyAndExecute(token, resolved);
1979
2092
  return true;
1980
2093
  }
1981
2094
  } catch {
1982
2095
  }
1983
2096
  const approval = args.approval ?? "once";
1984
- consola18.info(`Requesting grant for: ${resolved.detail.display}`);
2097
+ consola19.info(`Requesting grant for: ${resolved.detail.display}`);
1985
2098
  const grant = await createShapesGrant(resolved, {
1986
2099
  idp,
1987
2100
  approval,
1988
2101
  reason: args.reason || `ape-shell: ${resolved.detail.display}`
1989
2102
  });
1990
- consola18.info(`Grant requested: ${grant.id}`);
1991
- consola18.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
1992
2103
  if (grant.similar_grants?.similar_grants?.length) {
1993
2104
  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.`);
2105
+ consola19.info("");
2106
+ consola19.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
1996
2107
  }
1997
2108
  notifyGrantPending({
1998
2109
  grantId: grant.id,
@@ -2001,18 +2112,24 @@ async function tryAdapterModeFromShell(command, idp, args) {
2001
2112
  audience: resolved.adapter?.cli?.audience ?? "shapes",
2002
2113
  host: args.host || hostname3()
2003
2114
  });
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);
2115
+ if (shouldWaitForGrant(args)) {
2116
+ consola19.info(`Grant requested: ${grant.id}`);
2117
+ consola19.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
2118
+ const status = await waitForGrantStatus(idp, grant.id);
2119
+ if (status !== "approved")
2120
+ throw new CliError(`Grant ${status}`);
2121
+ const token = await fetchGrantToken(idp, grant.id);
2122
+ await verifyAndExecute(token, resolved);
2123
+ return true;
2124
+ }
2125
+ printPendingGrantInfo(grant, idp);
2009
2126
  return true;
2010
2127
  }
2011
2128
  function execShellCommand(command) {
2012
2129
  if (command.length === 0)
2013
2130
  throw new CliError("No command to execute");
2014
2131
  try {
2015
- execFileSync(command[0], command.slice(1), { stdio: "inherit" });
2132
+ execFileSync2(command[0], command.slice(1), { stdio: "inherit" });
2016
2133
  } catch (err) {
2017
2134
  const exitCode = err.status || 1;
2018
2135
  throw new CliExit(exitCode);
@@ -2049,9 +2166,9 @@ async function runAdapterMode(command, rawArgs, args) {
2049
2166
  try {
2050
2167
  const existingGrantId = await findExistingGrant(resolved, idp);
2051
2168
  if (existingGrantId) {
2052
- consola18.info(`Reusing existing grant: ${existingGrantId}`);
2053
- const token2 = await fetchGrantToken(idp, existingGrantId);
2054
- await verifyAndExecute(token2, resolved);
2169
+ consola19.info(`Reusing existing grant: ${existingGrantId}`);
2170
+ const token = await fetchGrantToken(idp, existingGrantId);
2171
+ await verifyAndExecute(token, resolved);
2055
2172
  return;
2056
2173
  }
2057
2174
  } catch {
@@ -2061,23 +2178,27 @@ async function runAdapterMode(command, rawArgs, args) {
2061
2178
  approval,
2062
2179
  ...args.reason ? { reason: args.reason } : {}
2063
2180
  });
2064
- consola18.info(`Grant requested: ${grant.id}`);
2065
- consola18.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
2066
2181
  if (grant.similar_grants?.similar_grants?.length) {
2067
2182
  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.`);
2183
+ consola19.info("");
2184
+ consola19.info(` Similar grant(s) found (${n}). Your approver can extend an existing grant to cover this request.`);
2070
2185
  if (grant.similar_grants.widened_details?.length) {
2071
2186
  const wider = grant.similar_grants.widened_details.map((d) => d.permission).join(", ");
2072
- consola18.info(` Broader scope: ${wider}`);
2073
- }
2074
- consola18.info("");
2187
+ consola19.info(` Broader scope: ${wider}`);
2188
+ }
2189
+ consola19.info("");
2190
+ }
2191
+ if (shouldWaitForGrant(args)) {
2192
+ consola19.info(`Grant requested: ${grant.id}`);
2193
+ consola19.info(`Approve at: ${idp}/grant-approval?grant_id=${grant.id}`);
2194
+ const status = await waitForGrantStatus(idp, grant.id);
2195
+ if (status !== "approved")
2196
+ throw new Error(`Grant ${status}`);
2197
+ const token = await fetchGrantToken(idp, grant.id);
2198
+ await verifyAndExecute(token, resolved);
2199
+ return;
2075
2200
  }
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);
2201
+ printPendingGrantInfo(grant, idp);
2081
2202
  }
2082
2203
  async function runAudienceMode(audience, action, args) {
2083
2204
  const auth = loadAuth();
@@ -2088,7 +2209,7 @@ async function runAudienceMode(audience, action, args) {
2088
2209
  const grantsUrl = await getGrantsEndpoint(idp);
2089
2210
  const command = action.split(" ");
2090
2211
  const targetHost = args.host || hostname3();
2091
- consola18.info(`Requesting ${audience} grant on ${targetHost}: ${command.join(" ")}`);
2212
+ consola19.info(`Requesting ${audience} grant on ${targetHost}: ${command.join(" ")}`);
2092
2213
  const grant = await apiFetch(grantsUrl, {
2093
2214
  method: "POST",
2094
2215
  body: {
@@ -2101,15 +2222,19 @@ async function runAudienceMode(audience, action, args) {
2101
2222
  ...args.as ? { run_as: args.as } : {}
2102
2223
  }
2103
2224
  });
2104
- consola18.success(`Grant requested: ${grant.id}`);
2105
- consola18.info("Waiting for approval...");
2225
+ if (!shouldWaitForGrant(args)) {
2226
+ printPendingGrantInfo(grant, idp);
2227
+ return;
2228
+ }
2229
+ consola19.success(`Grant requested: ${grant.id}`);
2230
+ consola19.info("Waiting for approval...");
2106
2231
  const maxWait = 3e5;
2107
2232
  const interval = 3e3;
2108
2233
  const start = Date.now();
2109
2234
  while (Date.now() - start < maxWait) {
2110
2235
  const status = await apiFetch(`${grantsUrl}/${grant.id}`);
2111
2236
  if (status.status === "approved") {
2112
- consola18.success("Grant approved!");
2237
+ consola19.success("Grant approved!");
2113
2238
  break;
2114
2239
  }
2115
2240
  if (status.status === "denied" || status.status === "revoked") {
@@ -2117,14 +2242,14 @@ async function runAudienceMode(audience, action, args) {
2117
2242
  }
2118
2243
  await new Promise((r) => setTimeout(r, interval));
2119
2244
  }
2120
- consola18.info("Fetching grant token...");
2245
+ consola19.info("Fetching grant token...");
2121
2246
  const { authz_jwt } = await apiFetch(`${grantsUrl}/${grant.id}/token`, {
2122
2247
  method: "POST"
2123
2248
  });
2124
2249
  if (audience === "escapes") {
2125
- consola18.info(`Executing: ${command.join(" ")}`);
2250
+ consola19.info(`Executing: ${command.join(" ")}`);
2126
2251
  try {
2127
- execFileSync(args["escapes-path"] || "escapes", ["--grant", authz_jwt, "--", ...command], {
2252
+ execFileSync2(args["escapes-path"] || "escapes", ["--grant", authz_jwt, "--", ...command], {
2128
2253
  stdio: "inherit"
2129
2254
  });
2130
2255
  } catch (err) {
@@ -2137,8 +2262,8 @@ async function runAudienceMode(audience, action, args) {
2137
2262
  }
2138
2263
 
2139
2264
  // src/commands/explain.ts
2140
- import { defineCommand as defineCommand21 } from "citty";
2141
- var explainCommand = defineCommand21({
2265
+ import { defineCommand as defineCommand22 } from "citty";
2266
+ var explainCommand = defineCommand22({
2142
2267
  meta: {
2143
2268
  name: "explain",
2144
2269
  description: "Show what permission a command would need"
@@ -2176,9 +2301,9 @@ var explainCommand = defineCommand21({
2176
2301
  });
2177
2302
 
2178
2303
  // src/commands/config/get.ts
2179
- import { defineCommand as defineCommand22 } from "citty";
2180
- import consola19 from "consola";
2181
- var configGetCommand = defineCommand22({
2304
+ import { defineCommand as defineCommand23 } from "citty";
2305
+ import consola20 from "consola";
2306
+ var configGetCommand = defineCommand23({
2182
2307
  meta: {
2183
2308
  name: "get",
2184
2309
  description: "Get a configuration value"
@@ -2198,7 +2323,7 @@ var configGetCommand = defineCommand22({
2198
2323
  if (idp)
2199
2324
  console.log(idp);
2200
2325
  else
2201
- consola19.info("No IdP configured.");
2326
+ consola20.info("No IdP configured.");
2202
2327
  break;
2203
2328
  }
2204
2329
  case "email": {
@@ -2206,7 +2331,7 @@ var configGetCommand = defineCommand22({
2206
2331
  if (auth?.email)
2207
2332
  console.log(auth.email);
2208
2333
  else
2209
- consola19.info("Not logged in.");
2334
+ consola20.info("Not logged in.");
2210
2335
  break;
2211
2336
  }
2212
2337
  default: {
@@ -2219,7 +2344,7 @@ var configGetCommand = defineCommand22({
2219
2344
  if (sectionObj && field in sectionObj) {
2220
2345
  console.log(sectionObj[field]);
2221
2346
  } else {
2222
- consola19.info(`Key "${key}" not set.`);
2347
+ consola20.info(`Key "${key}" not set.`);
2223
2348
  }
2224
2349
  } else {
2225
2350
  throw new CliError(`Unknown key: "${key}". Use: idp, email, defaults.idp, defaults.approval, agent.key, agent.email`);
@@ -2230,9 +2355,9 @@ var configGetCommand = defineCommand22({
2230
2355
  });
2231
2356
 
2232
2357
  // src/commands/config/set.ts
2233
- import { defineCommand as defineCommand23 } from "citty";
2234
- import consola20 from "consola";
2235
- var configSetCommand = defineCommand23({
2358
+ import { defineCommand as defineCommand24 } from "citty";
2359
+ import consola21 from "consola";
2360
+ var configSetCommand = defineCommand24({
2236
2361
  meta: {
2237
2362
  name: "set",
2238
2363
  description: "Set a configuration value"
@@ -2268,12 +2393,12 @@ var configSetCommand = defineCommand23({
2268
2393
  throw new CliError(`Unknown section: "${section}". Use: defaults, agent`);
2269
2394
  }
2270
2395
  saveConfig(config);
2271
- consola20.success(`Set ${key} = ${value}`);
2396
+ consola21.success(`Set ${key} = ${value}`);
2272
2397
  }
2273
2398
  });
2274
2399
 
2275
2400
  // src/commands/fetch/index.ts
2276
- import { defineCommand as defineCommand24 } from "citty";
2401
+ import { defineCommand as defineCommand25 } from "citty";
2277
2402
  async function doRequest(method, url, body, contentType, raw, showHeaders) {
2278
2403
  const token = getAuthToken();
2279
2404
  if (!token) {
@@ -2309,13 +2434,13 @@ async function doRequest(method, url, body, contentType, raw, showHeaders) {
2309
2434
  throw new CliError(`HTTP ${response.status} ${response.statusText}`);
2310
2435
  }
2311
2436
  }
2312
- var fetchCommand = defineCommand24({
2437
+ var fetchCommand = defineCommand25({
2313
2438
  meta: {
2314
2439
  name: "fetch",
2315
2440
  description: "Make authenticated HTTP requests"
2316
2441
  },
2317
2442
  subCommands: {
2318
- get: defineCommand24({
2443
+ get: defineCommand25({
2319
2444
  meta: {
2320
2445
  name: "get",
2321
2446
  description: "GET request with auth token"
@@ -2341,7 +2466,7 @@ var fetchCommand = defineCommand24({
2341
2466
  await doRequest("GET", String(args.url), void 0, "application/json", Boolean(args.raw), Boolean(args.headers));
2342
2467
  }
2343
2468
  }),
2344
- post: defineCommand24({
2469
+ post: defineCommand25({
2345
2470
  meta: {
2346
2471
  name: "post",
2347
2472
  description: "POST request with auth token"
@@ -2380,8 +2505,8 @@ var fetchCommand = defineCommand24({
2380
2505
  });
2381
2506
 
2382
2507
  // src/commands/mcp/index.ts
2383
- import { defineCommand as defineCommand25 } from "citty";
2384
- var mcpCommand = defineCommand25({
2508
+ import { defineCommand as defineCommand26 } from "citty";
2509
+ var mcpCommand = defineCommand26({
2385
2510
  meta: {
2386
2511
  name: "mcp",
2387
2512
  description: "Start MCP server for AI agents"
@@ -2404,7 +2529,7 @@ var mcpCommand = defineCommand25({
2404
2529
  if (transport !== "stdio" && transport !== "sse") {
2405
2530
  throw new Error('Transport must be "stdio" or "sse"');
2406
2531
  }
2407
- const { startMcpServer } = await import("./server-DPNFUTHG.js");
2532
+ const { startMcpServer } = await import("./server-3COSVPBQ.js");
2408
2533
  await startMcpServer(transport, port);
2409
2534
  }
2410
2535
  });
@@ -2412,10 +2537,10 @@ var mcpCommand = defineCommand25({
2412
2537
  // src/commands/init/index.ts
2413
2538
  import { existsSync as existsSync3, copyFileSync, writeFileSync } from "fs";
2414
2539
  import { randomBytes } from "crypto";
2415
- import { execFileSync as execFileSync2 } from "child_process";
2540
+ import { execFileSync as execFileSync3 } from "child_process";
2416
2541
  import { join as join2 } from "path";
2417
- import { defineCommand as defineCommand26 } from "citty";
2418
- import consola21 from "consola";
2542
+ import { defineCommand as defineCommand27 } from "citty";
2543
+ import consola22 from "consola";
2419
2544
  var DEFAULT_IDP_URL = "https://id.openape.at";
2420
2545
  async function downloadTemplate(repo, targetDir) {
2421
2546
  const { downloadTemplate: gigetDownload } = await import("giget");
@@ -2424,28 +2549,28 @@ async function downloadTemplate(repo, targetDir) {
2424
2549
  function installDeps(dir) {
2425
2550
  const hasLockFile = (name) => existsSync3(join2(dir, name));
2426
2551
  if (hasLockFile("pnpm-lock.yaml")) {
2427
- execFileSync2("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
2552
+ execFileSync3("pnpm", ["install"], { cwd: dir, stdio: "inherit" });
2428
2553
  } else if (hasLockFile("bun.lockb")) {
2429
- execFileSync2("bun", ["install"], { cwd: dir, stdio: "inherit" });
2554
+ execFileSync3("bun", ["install"], { cwd: dir, stdio: "inherit" });
2430
2555
  } else {
2431
- execFileSync2("npm", ["install"], { cwd: dir, stdio: "inherit" });
2556
+ execFileSync3("npm", ["install"], { cwd: dir, stdio: "inherit" });
2432
2557
  }
2433
2558
  }
2434
2559
  async function promptChoice(message, choices) {
2435
- const result = await consola21.prompt(message, { type: "select", options: choices });
2560
+ const result = await consola22.prompt(message, { type: "select", options: choices });
2436
2561
  if (typeof result === "symbol") {
2437
2562
  throw new CliExit(0);
2438
2563
  }
2439
2564
  return result;
2440
2565
  }
2441
2566
  async function promptText(message, defaultValue) {
2442
- const result = await consola21.prompt(message, { type: "text", default: defaultValue, placeholder: defaultValue });
2567
+ const result = await consola22.prompt(message, { type: "text", default: defaultValue, placeholder: defaultValue });
2443
2568
  if (typeof result === "symbol") {
2444
2569
  throw new CliExit(0);
2445
2570
  }
2446
2571
  return result || defaultValue || "";
2447
2572
  }
2448
- var initCommand = defineCommand26({
2573
+ var initCommand = defineCommand27({
2449
2574
  meta: {
2450
2575
  name: "init",
2451
2576
  description: "Scaffold a new OpenApe project"
@@ -2490,20 +2615,20 @@ async function initSP(targetDir) {
2490
2615
  if (existsSync3(join2(dir, "package.json"))) {
2491
2616
  throw new CliError(`Directory "${dir}" already contains a project.`);
2492
2617
  }
2493
- consola21.start("Scaffolding SP starter...");
2618
+ consola22.start("Scaffolding SP starter...");
2494
2619
  await downloadTemplate("openape-ai/openape-sp-starter", dir);
2495
- consola21.success("Scaffolded from openape-sp-starter");
2496
- consola21.start("Installing dependencies...");
2620
+ consola22.success("Scaffolded from openape-sp-starter");
2621
+ consola22.start("Installing dependencies...");
2497
2622
  installDeps(dir);
2498
- consola21.success("Dependencies installed");
2623
+ consola22.success("Dependencies installed");
2499
2624
  const envExample = join2(dir, ".env.example");
2500
2625
  const envFile = join2(dir, ".env");
2501
2626
  if (existsSync3(envExample) && !existsSync3(envFile)) {
2502
2627
  copyFileSync(envExample, envFile);
2503
- consola21.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
2628
+ consola22.success(`\`.env\` created (using Free IdP at ${DEFAULT_IDP_URL})`);
2504
2629
  }
2505
2630
  console.log("");
2506
- consola21.box([
2631
+ consola22.box([
2507
2632
  `cd ${dir}`,
2508
2633
  "npm run dev",
2509
2634
  "",
@@ -2522,15 +2647,15 @@ async function initIdP(targetDir) {
2522
2647
  "s3 (S3-compatible)"
2523
2648
  ]);
2524
2649
  const adminEmail = await promptText("Admin email");
2525
- consola21.start("Scaffolding IdP starter...");
2650
+ consola22.start("Scaffolding IdP starter...");
2526
2651
  await downloadTemplate("openape-ai/openape-idp-starter", dir);
2527
- consola21.success("Scaffolded from openape-idp-starter");
2528
- consola21.start("Installing dependencies...");
2652
+ consola22.success("Scaffolded from openape-idp-starter");
2653
+ consola22.start("Installing dependencies...");
2529
2654
  installDeps(dir);
2530
- consola21.success("Dependencies installed");
2655
+ consola22.success("Dependencies installed");
2531
2656
  const sessionSecret = randomBytes(32).toString("hex");
2532
2657
  const managementToken = randomBytes(32).toString("hex");
2533
- consola21.success("Secrets generated");
2658
+ consola22.success("Secrets generated");
2534
2659
  const isLocalhost = domain === "localhost";
2535
2660
  const origin = isLocalhost ? "http://localhost:3000" : `https://${domain}`;
2536
2661
  const envContent = [
@@ -2546,9 +2671,9 @@ async function initIdP(targetDir) {
2546
2671
  ].join("\n");
2547
2672
  writeFileSync(join2(dir, ".env"), `${envContent}
2548
2673
  `, { mode: 384 });
2549
- consola21.success(".env created");
2674
+ consola22.success(".env created");
2550
2675
  console.log("");
2551
- consola21.box([
2676
+ consola22.box([
2552
2677
  `cd ${dir}`,
2553
2678
  "npm run dev",
2554
2679
  "",
@@ -2570,8 +2695,8 @@ import { execFile as execFile2 } from "child_process";
2570
2695
  import { generateKeyPairSync, sign } from "crypto";
2571
2696
  import { dirname, resolve as resolve2 } from "path";
2572
2697
  import { homedir as homedir4 } from "os";
2573
- import { defineCommand as defineCommand27 } from "citty";
2574
- import consola22 from "consola";
2698
+ import { defineCommand as defineCommand28 } from "citty";
2699
+ import consola23 from "consola";
2575
2700
  var DEFAULT_IDP_URL2 = "https://id.openape.at";
2576
2701
  var DEFAULT_KEY_PATH = "~/.ssh/id_ed25519";
2577
2702
  var POLL_INTERVAL = 3e3;
@@ -2656,7 +2781,7 @@ async function pollForEnrollment(idp, agentEmail, keyPath) {
2656
2781
  }
2657
2782
  throw new Error("Enrollment timed out. Please check the browser and try again.");
2658
2783
  }
2659
- var enrollCommand = defineCommand27({
2784
+ var enrollCommand = defineCommand28({
2660
2785
  meta: {
2661
2786
  name: "enroll",
2662
2787
  description: "Enroll an agent with an Identity Provider"
@@ -2676,18 +2801,18 @@ var enrollCommand = defineCommand27({
2676
2801
  }
2677
2802
  },
2678
2803
  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) => {
2804
+ const idp = args.idp || await consola23.prompt("IdP URL", { type: "text", default: DEFAULT_IDP_URL2, placeholder: DEFAULT_IDP_URL2 }).then((r) => {
2680
2805
  if (typeof r === "symbol") throw new CliExit(0);
2681
2806
  return r;
2682
2807
  }) || DEFAULT_IDP_URL2;
2683
- const agentName = args.name || await consola22.prompt("Agent name", { type: "text", placeholder: "deploy-bot" }).then((r) => {
2808
+ const agentName = args.name || await consola23.prompt("Agent name", { type: "text", placeholder: "deploy-bot" }).then((r) => {
2684
2809
  if (typeof r === "symbol") throw new CliExit(0);
2685
2810
  return r;
2686
2811
  });
2687
2812
  if (!agentName) {
2688
2813
  throw new CliError("Agent name is required.");
2689
2814
  }
2690
- const keyPath = args.key || await consola22.prompt("Ed25519 key", { type: "text", default: DEFAULT_KEY_PATH, placeholder: DEFAULT_KEY_PATH }).then((r) => {
2815
+ const keyPath = args.key || await consola23.prompt("Ed25519 key", { type: "text", default: DEFAULT_KEY_PATH, placeholder: DEFAULT_KEY_PATH }).then((r) => {
2691
2816
  if (typeof r === "symbol") throw new CliExit(0);
2692
2817
  return r;
2693
2818
  }) || DEFAULT_KEY_PATH;
@@ -2695,19 +2820,19 @@ var enrollCommand = defineCommand27({
2695
2820
  let publicKey;
2696
2821
  if (existsSync4(resolvedKey)) {
2697
2822
  publicKey = readPublicKey(resolvedKey);
2698
- consola22.success(`Using existing key ${keyPath}`);
2823
+ consola23.success(`Using existing key ${keyPath}`);
2699
2824
  } else {
2700
- consola22.start(`Generating Ed25519 key pair at ${keyPath}...`);
2825
+ consola23.start(`Generating Ed25519 key pair at ${keyPath}...`);
2701
2826
  publicKey = generateAndSaveKey(keyPath);
2702
- consola22.success(`Key pair generated at ${keyPath}`);
2827
+ consola23.success(`Key pair generated at ${keyPath}`);
2703
2828
  }
2704
2829
  const encodedKey = encodeURIComponent(publicKey);
2705
2830
  const enrollUrl = `${idp}/enroll?name=${encodeURIComponent(agentName)}&key=${encodedKey}`;
2706
- consola22.info("Opening browser for enrollment...");
2707
- consola22.info(`\u2192 ${idp}/enroll`);
2831
+ consola23.info("Opening browser for enrollment...");
2832
+ consola23.info(`\u2192 ${idp}/enroll`);
2708
2833
  openBrowser2(enrollUrl);
2709
2834
  console.log("");
2710
- const agentEmail = await consola22.prompt(
2835
+ const agentEmail = await consola23.prompt(
2711
2836
  "Agent email (shown in browser after enrollment)",
2712
2837
  { type: "text", placeholder: `agent+${agentName}@...` }
2713
2838
  ).then((r) => {
@@ -2717,7 +2842,7 @@ var enrollCommand = defineCommand27({
2717
2842
  if (!agentEmail) {
2718
2843
  throw new CliError("Agent email is required to verify enrollment.");
2719
2844
  }
2720
- consola22.start("Verifying enrollment...");
2845
+ consola23.start("Verifying enrollment...");
2721
2846
  const { token, expiresIn } = await pollForEnrollment(idp, agentEmail, keyPath);
2722
2847
  saveAuth({
2723
2848
  idp,
@@ -2729,18 +2854,18 @@ var enrollCommand = defineCommand27({
2729
2854
  config.defaults = { ...config.defaults, idp };
2730
2855
  config.agent = { key: keyPath, email: agentEmail };
2731
2856
  saveConfig(config);
2732
- consola22.success(`Agent enrolled as ${agentEmail}`);
2733
- consola22.success("Config saved to ~/.config/apes/");
2857
+ consola23.success(`Agent enrolled as ${agentEmail}`);
2858
+ consola23.success("Config saved to ~/.config/apes/");
2734
2859
  console.log("");
2735
- consola22.info("Verify with: apes whoami");
2860
+ consola23.info("Verify with: apes whoami");
2736
2861
  }
2737
2862
  });
2738
2863
 
2739
2864
  // src/commands/register-user.ts
2740
2865
  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({
2866
+ import { defineCommand as defineCommand29 } from "citty";
2867
+ import consola24 from "consola";
2868
+ var registerUserCommand = defineCommand29({
2744
2869
  meta: {
2745
2870
  name: "register-user",
2746
2871
  description: "Register a sub-user with SSH key"
@@ -2795,15 +2920,15 @@ var registerUserCommand = defineCommand28({
2795
2920
  ...userType ? { type: userType } : {}
2796
2921
  }
2797
2922
  });
2798
- consola23.success(`User registered: ${result.email} (type: ${result.type}, owner: ${result.owner})`);
2923
+ consola24.success(`User registered: ${result.email} (type: ${result.type}, owner: ${result.owner})`);
2799
2924
  }
2800
2925
  });
2801
2926
 
2802
2927
  // src/commands/dns-check.ts
2803
- import { defineCommand as defineCommand29 } from "citty";
2804
- import consola24 from "consola";
2928
+ import { defineCommand as defineCommand30 } from "citty";
2929
+ import consola25 from "consola";
2805
2930
  import { resolveDDISA as resolveDDISA2 } from "@openape/core";
2806
- var dnsCheckCommand = defineCommand29({
2931
+ var dnsCheckCommand = defineCommand30({
2807
2932
  meta: {
2808
2933
  name: "dns-check",
2809
2934
  description: "Validate DDISA DNS TXT records for a domain"
@@ -2817,7 +2942,7 @@ var dnsCheckCommand = defineCommand29({
2817
2942
  },
2818
2943
  async run({ args }) {
2819
2944
  const domain = args.domain;
2820
- consola24.start(`Checking _ddisa.${domain}...`);
2945
+ consola25.start(`Checking _ddisa.${domain}...`);
2821
2946
  try {
2822
2947
  const result = await resolveDDISA2(domain);
2823
2948
  if (!result) {
@@ -2826,7 +2951,7 @@ var dnsCheckCommand = defineCommand29({
2826
2951
  console.log(` _ddisa.${domain} TXT "v=ddisa1 idp=https://id.${domain}"`);
2827
2952
  throw new CliError(`No DDISA record found for ${domain}`);
2828
2953
  }
2829
- consola24.success(`_ddisa.${domain} \u2192 ${result.idp}`);
2954
+ consola25.success(`_ddisa.${domain} \u2192 ${result.idp}`);
2830
2955
  console.log("");
2831
2956
  console.log(` Version: ${result.version || "ddisa1"}`);
2832
2957
  console.log(` IdP URL: ${result.idp}`);
@@ -2835,14 +2960,14 @@ var dnsCheckCommand = defineCommand29({
2835
2960
  if (result.priority !== void 0)
2836
2961
  console.log(` Priority: ${result.priority}`);
2837
2962
  console.log("");
2838
- consola24.start(`Verifying IdP at ${result.idp}...`);
2963
+ consola25.start(`Verifying IdP at ${result.idp}...`);
2839
2964
  const discoResp = await fetch(`${result.idp}/.well-known/openid-configuration`);
2840
2965
  if (!discoResp.ok) {
2841
- consola24.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
2966
+ consola25.warn(`IdP discovery failed (${discoResp.status}). Is the IdP running at ${result.idp}?`);
2842
2967
  return;
2843
2968
  }
2844
2969
  const disco = await discoResp.json();
2845
- consola24.success(`IdP is reachable`);
2970
+ consola25.success(`IdP is reachable`);
2846
2971
  console.log(` Issuer: ${disco.issuer}`);
2847
2972
  console.log(` DDISA: v${disco.ddisa_version || "?"}`);
2848
2973
  if (disco.ddisa_auth_methods_supported) {
@@ -2860,7 +2985,7 @@ var dnsCheckCommand = defineCommand29({
2860
2985
  // src/commands/health.ts
2861
2986
  import { exec } from "child_process";
2862
2987
  import { promisify } from "util";
2863
- import { defineCommand as defineCommand30 } from "citty";
2988
+ import { defineCommand as defineCommand31 } from "citty";
2864
2989
  var execAsync = promisify(exec);
2865
2990
  async function resolveApeShellPath() {
2866
2991
  try {
@@ -2896,7 +3021,7 @@ async function bestEffortGrantCount(idp) {
2896
3021
  }
2897
3022
  }
2898
3023
  async function runHealth(args) {
2899
- const version = true ? "0.8.0" : "0.0.0";
3024
+ const version = true ? "0.9.1" : "0.0.0";
2900
3025
  const auth = loadAuth();
2901
3026
  if (!auth) {
2902
3027
  throw new CliError("Not logged in. Run `apes login` first.", 1);
@@ -2959,7 +3084,7 @@ async function runHealth(args) {
2959
3084
  throw new CliError(`IdP ${auth.idp} unreachable: ${idpProbe.error}`, 1);
2960
3085
  }
2961
3086
  }
2962
- var healthCommand = defineCommand30({
3087
+ var healthCommand = defineCommand31({
2963
3088
  meta: {
2964
3089
  name: "health",
2965
3090
  description: "Report CLI diagnostic state (auth, IdP, grants, binaries)"
@@ -2977,8 +3102,8 @@ var healthCommand = defineCommand30({
2977
3102
  });
2978
3103
 
2979
3104
  // src/commands/workflows.ts
2980
- import { defineCommand as defineCommand31 } from "citty";
2981
- import consola25 from "consola";
3105
+ import { defineCommand as defineCommand32 } from "citty";
3106
+ import consola26 from "consola";
2982
3107
 
2983
3108
  // src/guides/index.ts
2984
3109
  var guides = [
@@ -3028,7 +3153,7 @@ var guides = [
3028
3153
  ];
3029
3154
 
3030
3155
  // src/commands/workflows.ts
3031
- var workflowsCommand = defineCommand31({
3156
+ var workflowsCommand = defineCommand32({
3032
3157
  meta: {
3033
3158
  name: "workflows",
3034
3159
  description: "Discover workflow guides"
@@ -3049,7 +3174,7 @@ var workflowsCommand = defineCommand31({
3049
3174
  if (args.id) {
3050
3175
  const guide = guides.find((g) => g.id === String(args.id));
3051
3176
  if (!guide) {
3052
- consola25.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
3177
+ consola26.info(`Available: ${guides.map((g) => g.id).join(", ")}`);
3053
3178
  throw new CliError(`Guide not found: ${args.id}`);
3054
3179
  }
3055
3180
  if (args.json) {
@@ -3098,10 +3223,10 @@ if (shellRewrite) {
3098
3223
  if (shellRewrite.action === "rewrite") {
3099
3224
  process.argv = shellRewrite.argv;
3100
3225
  } else if (shellRewrite.action === "version") {
3101
- console.log(`ape-shell ${"0.8.0"} (OpenApe DDISA shell wrapper)`);
3226
+ console.log(`ape-shell ${"0.9.1"} (OpenApe DDISA shell wrapper)`);
3102
3227
  process.exit(0);
3103
3228
  } else if (shellRewrite.action === "help") {
3104
- console.log(`ape-shell ${"0.8.0"} \u2014 OpenApe DDISA shell wrapper`);
3229
+ console.log(`ape-shell ${"0.9.1"} \u2014 OpenApe DDISA shell wrapper`);
3105
3230
  console.log("");
3106
3231
  console.log("Usage:");
3107
3232
  console.log(" ape-shell Start interactive grant-mediated REPL");
@@ -3116,7 +3241,7 @@ if (shellRewrite) {
3116
3241
  console.log(" --help, -h Show this help message");
3117
3242
  process.exit(0);
3118
3243
  } else if (shellRewrite.action === "interactive") {
3119
- const { runInteractiveShell } = await import("./orchestrator-FTQW3ZRS.js");
3244
+ const { runInteractiveShell } = await import("./orchestrator-GPNL543L.js");
3120
3245
  await runInteractiveShell();
3121
3246
  process.exit(0);
3122
3247
  } else {
@@ -3125,7 +3250,7 @@ if (shellRewrite) {
3125
3250
  }
3126
3251
  }
3127
3252
  var debug = process.argv.includes("--debug");
3128
- var grantsCommand = defineCommand32({
3253
+ var grantsCommand = defineCommand33({
3129
3254
  meta: {
3130
3255
  name: "grants",
3131
3256
  description: "Grant management"
@@ -3139,13 +3264,14 @@ var grantsCommand = defineCommand32({
3139
3264
  approve: approveCommand,
3140
3265
  deny: denyCommand,
3141
3266
  revoke: revokeCommand,
3267
+ run: runGrantCommand,
3142
3268
  token: tokenCommand,
3143
3269
  delegate: delegateCommand,
3144
3270
  delegations: delegationsCommand,
3145
3271
  "delegation-revoke": delegationRevokeCommand
3146
3272
  }
3147
3273
  });
3148
- var configCommand = defineCommand32({
3274
+ var configCommand = defineCommand33({
3149
3275
  meta: {
3150
3276
  name: "config",
3151
3277
  description: "Configuration management"
@@ -3155,10 +3281,10 @@ var configCommand = defineCommand32({
3155
3281
  set: configSetCommand
3156
3282
  }
3157
3283
  });
3158
- var main = defineCommand32({
3284
+ var main = defineCommand33({
3159
3285
  meta: {
3160
3286
  name: "apes",
3161
- version: "0.8.0",
3287
+ version: "0.9.1",
3162
3288
  description: "Unified CLI for OpenApe"
3163
3289
  },
3164
3290
  subCommands: {
@@ -3186,13 +3312,13 @@ runMain(main).catch((err) => {
3186
3312
  process.exit(err.exitCode);
3187
3313
  }
3188
3314
  if (err instanceof CliError) {
3189
- consola26.error(err.message);
3315
+ consola27.error(err.message);
3190
3316
  process.exit(err.exitCode);
3191
3317
  }
3192
3318
  if (debug) {
3193
- consola26.error(err);
3319
+ consola27.error(err);
3194
3320
  } else {
3195
- consola26.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
3321
+ consola27.error(err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err));
3196
3322
  }
3197
3323
  process.exit(1);
3198
3324
  });