appduct 0.12.0 → 0.14.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.
Files changed (75) hide show
  1. package/README.md +43 -37
  2. package/dist/bin.js +102 -37
  3. package/dist/cli/command-options.d.ts +7 -17
  4. package/dist/cli/result-types.d.ts +19 -9
  5. package/dist/cli/routes/daemon/index.js +70 -17
  6. package/dist/cli/routes/daemon/run.js +288 -50
  7. package/dist/cli/routes/daemon/start.js +70 -17
  8. package/dist/cli/routes/daemon/status.js +70 -17
  9. package/dist/cli/routes/daemon/stop.js +70 -17
  10. package/dist/cli/routes/doctor.js +70 -17
  11. package/dist/cli/routes/events/index.d.ts +6 -0
  12. package/dist/cli/routes/events/index.js +900 -0
  13. package/dist/cli/routes/events/ls.d.ts +5 -0
  14. package/dist/cli/routes/events/ls.js +1798 -0
  15. package/dist/cli/routes/events/shared-options.d.ts +12 -0
  16. package/dist/cli/routes/events/shared-options.js +102 -0
  17. package/dist/cli/routes/events/since.d.ts +6 -0
  18. package/dist/cli/routes/events/since.js +2034 -0
  19. package/dist/cli/routes/events/tail.d.ts +6 -0
  20. package/dist/cli/routes/{events.js → events/tail.js} +235 -163
  21. package/dist/cli/routes/init.js +72 -19
  22. package/dist/cli/routes/keygen.js +70 -17
  23. package/dist/cli/routes/mcp.js +289 -166
  24. package/dist/cli/routes/sessions/index.d.ts +7 -0
  25. package/dist/cli/routes/sessions/index.js +900 -0
  26. package/dist/cli/routes/sessions/link.d.ts +4 -0
  27. package/dist/cli/routes/{link.js → sessions/link.js} +71 -18
  28. package/dist/cli/routes/sessions/ls.d.ts +4 -0
  29. package/dist/cli/routes/{ls.js → sessions/ls.js} +71 -18
  30. package/dist/cli/routes/sessions/revoke.d.ts +4 -0
  31. package/dist/cli/routes/{revoke.js → sessions/revoke.js} +72 -19
  32. package/dist/cli/routes/tools/call.d.ts +4 -0
  33. package/dist/cli/routes/{invoke.js → tools/call.js} +73 -20
  34. package/dist/cli/routes/tools/describe.d.ts +6 -0
  35. package/dist/cli/routes/tools/describe.js +1894 -0
  36. package/dist/cli/routes/tools/index.d.ts +6 -0
  37. package/dist/cli/routes/tools/index.js +900 -0
  38. package/dist/cli/routes/tools/ls.d.ts +4 -0
  39. package/dist/cli/routes/{tools.js → tools/ls.js} +98 -74
  40. package/dist/cli/routes/tools/shared-options.d.ts +16 -0
  41. package/dist/cli/routes/tools/shared-options.js +122 -0
  42. package/dist/client/app-client.d.ts +96 -37
  43. package/dist/client/index.d.ts +3 -2
  44. package/dist/client/index.js +178 -138
  45. package/dist/commands/events-ls.d.ts +21 -0
  46. package/dist/commands/events.d.ts +31 -14
  47. package/dist/commands/invoke.d.ts +1 -1
  48. package/dist/commands/link.d.ts +1 -1
  49. package/dist/commands/ls.d.ts +1 -1
  50. package/dist/commands/revoke.d.ts +1 -1
  51. package/dist/commands/tools.d.ts +12 -13
  52. package/dist/daemon/calls.d.ts +3 -1
  53. package/dist/daemon/config.d.ts +1 -1
  54. package/dist/daemon/event-bus.d.ts +42 -0
  55. package/dist/daemon/registry.d.ts +20 -12
  56. package/dist/daemon/rpc-errors.d.ts +4 -1
  57. package/dist/daemon/sessions.d.ts +4 -2
  58. package/dist/errors.d.ts +1 -1
  59. package/dist/events/index.d.ts +60 -0
  60. package/dist/index.js +114 -40
  61. package/dist/link.d.ts +1 -1
  62. package/dist/mcp/app-tools.d.ts +22 -2
  63. package/dist/mcp/connect-tool.d.ts +1 -1
  64. package/dist/mcp/events-tool.d.ts +67 -27
  65. package/dist/native-scheme.d.ts +1 -1
  66. package/dist/output.d.ts +29 -6
  67. package/dist/rpc/client.d.ts +1 -1
  68. package/dist/scheme.d.ts +4 -4
  69. package/package.json +2 -2
  70. package/dist/cli/routes/events.d.ts +0 -3
  71. package/dist/cli/routes/invoke.d.ts +0 -3
  72. package/dist/cli/routes/link.d.ts +0 -3
  73. package/dist/cli/routes/ls.d.ts +0 -3
  74. package/dist/cli/routes/revoke.d.ts +0 -3
  75. package/dist/cli/routes/tools.d.ts +0 -3
@@ -0,0 +1,4 @@
1
+ /** Route for `appduct sessions link` — loaded by `routes/sessions/index.ts`'s router only when it
2
+ * runs (issue #96; replaces the removed `appduct link`). */
3
+ import type { Route } from "../../router.js";
4
+ export declare const route: Route;
@@ -2068,6 +2068,7 @@ var formatJson = (value, flags) => {
2068
2068
  import pc from "picocolors";
2069
2069
  import {
2070
2070
  formatAgentWebSocketUrl,
2071
+ renderEventSignature,
2071
2072
  renderToolSignature,
2072
2073
  summarizeToolDescription
2073
2074
  } from "@appduct/shared";
@@ -2163,6 +2164,13 @@ var formatDevice = (device) => {
2163
2164
  const label = parts.length > 0 ? parts.join(" ") : "unknown device";
2164
2165
  return device.os ? `${label} (${device.os})` : label;
2165
2166
  };
2167
+ var SUSPEND_REASON_LABELS = {
2168
+ app_backgrounded: "app in background",
2169
+ connection_lost: "connection lost"
2170
+ };
2171
+ var formatSessionState = (session) => {
2172
+ return session.suspendReason ? `${session.state} (${SUSPEND_REASON_LABELS[session.suspendReason]})` : session.state;
2173
+ };
2166
2174
  var renderLsData = (colors, data, now) => {
2167
2175
  if (data.length === 0) {
2168
2176
  return [colors.dim("Sessions"), " No Appduct sessions are registered."];
@@ -2171,7 +2179,7 @@ var renderLsData = (colors, data, now) => {
2171
2179
  const headers = ["Alias", "State", "Device", "Tools", "Age"];
2172
2180
  const rows = data.map((session) => [
2173
2181
  session.alias,
2174
- session.state,
2182
+ formatSessionState(session),
2175
2183
  formatDevice(session.device),
2176
2184
  String(session.toolCount),
2177
2185
  formatAge(session.claimedAt ?? session.createdAt, nowIso)
@@ -2185,9 +2193,6 @@ var renderLsData = (colors, data, now) => {
2185
2193
  ...rows.map((row) => ` ${row.map((cell, index) => cell.padEnd(widths[index])).join(" ")}`)
2186
2194
  ];
2187
2195
  };
2188
- var isToolsListing = (data) => {
2189
- return typeof data === "object" && data !== null && Array.isArray(data.tools);
2190
- };
2191
2196
  var isToolGroupsListing = (data) => {
2192
2197
  return typeof data === "object" && data !== null && Array.isArray(data.groups) && !Array.isArray(data.tools);
2193
2198
  };
@@ -2205,7 +2210,7 @@ var renderEmptyToolsLine = (data) => {
2205
2210
  }
2206
2211
  if (data.group !== void 0) {
2207
2212
  const match = data.filter === void 0 ? "" : ` match ${JSON.stringify(data.filter)}`;
2208
- return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools --groups\` to see the session's groups.`;
2213
+ return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools ls --groups\` to see the session's groups.`;
2209
2214
  }
2210
2215
  return data.filter === void 0 ? " No tools registered." : ` No tools match ${JSON.stringify(data.filter)}.`;
2211
2216
  };
@@ -2287,7 +2292,7 @@ var renderToolSummaryTable = (colors, data) => {
2287
2292
  ...grouped ? renderGroupedToolLines(colors, data.tools) : data.tools.flatMap((tool) => renderToolSummaryLines(tool, " ")),
2288
2293
  ...renderTruncationLine(data),
2289
2294
  "",
2290
- "Run `appduct tools <name>` for a tool's full schema."
2295
+ "Run `appduct tools describe <name>` for a tool's full schema."
2291
2296
  ];
2292
2297
  };
2293
2298
  var renderToolDetail = (colors, tool, flags) => {
@@ -2339,18 +2344,62 @@ var renderToolGroups = (colors, data) => {
2339
2344
  colors.green("Groups"),
2340
2345
  ...data.groups.map((entry) => ` ${label(entry).padEnd(width)} ${String(entry.total).padStart(countWidth)}`),
2341
2346
  "",
2342
- `${data.total} tool${data.total === 1 ? "" : "s"} in total. ` + (hasAnyGroup(data.groups) ? "Run `appduct tools --group <name>` to list one group's tools." : "No tool declares a group.")
2347
+ `${data.total} tool${data.total === 1 ? "" : "s"} in total. ` + (hasAnyGroup(data.groups) ? "Run `appduct tools ls --group <name>` to list one group's tools." : "No tool declares a group.")
2343
2348
  ];
2344
2349
  };
2345
- var renderToolsData = (colors, data, flags, full) => {
2350
+ var renderToolsListData = (colors, data, flags, full) => {
2346
2351
  if (isToolGroupsListing(data)) {
2347
2352
  return renderToolGroups(colors, data);
2348
2353
  }
2349
- if (!isToolsListing(data)) {
2350
- return renderToolDetail(colors, data, flags);
2351
- }
2352
2354
  return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
2353
2355
  };
2356
+ var renderEventsTruncationLine = (data) => {
2357
+ const offset = data.offset ?? 0;
2358
+ if (data.events.length >= data.total) {
2359
+ return [];
2360
+ }
2361
+ return [
2362
+ "",
2363
+ `Showing ${data.events.length} of ${data.total} events (offset ${offset}). Narrow with --name <glob> or page with --offset <n>.`
2364
+ ];
2365
+ };
2366
+ var renderEventsListData = (colors, data, flags) => {
2367
+ const [only] = data.events;
2368
+ if (data.name !== void 0 && !data.name.includes("*") && only !== void 0) {
2369
+ return renderFields(
2370
+ colors.green(`Event: ${only.name}`),
2371
+ [
2372
+ ["Signature", renderEventSignature(only)],
2373
+ ["Description", only.description],
2374
+ ["Payload schema", only.payload_schema]
2375
+ ],
2376
+ flags
2377
+ );
2378
+ }
2379
+ if (data.events.length === 0 && data.total > 0) {
2380
+ return [
2381
+ colors.green("Events"),
2382
+ ` No events at offset ${data.offset ?? 0}; ${data.total} matching event${data.total === 1 ? "" : "s"} in total.`
2383
+ ];
2384
+ }
2385
+ if (data.events.length === 0) {
2386
+ return [
2387
+ colors.green("Events"),
2388
+ data.name === void 0 ? " No events declared." : ` No events match ${JSON.stringify(data.name)}.`
2389
+ ];
2390
+ }
2391
+ const lines = data.events.flatMap((event) => [
2392
+ ` ${renderEventSignature(event)}`,
2393
+ ` ${summarizeToolDescription(event.description)}`
2394
+ ]);
2395
+ return [
2396
+ colors.green("Events"),
2397
+ ...lines,
2398
+ ...renderEventsTruncationLine(data),
2399
+ "",
2400
+ "Run `appduct events ls --name <name>` for an event's full payload schema."
2401
+ ];
2402
+ };
2354
2403
  var renderInvokeData = (colors, data, flags) => {
2355
2404
  return [colors.green("Result"), formatScalar(data, flags)];
2356
2405
  };
@@ -2534,15 +2583,19 @@ var renderSuccessData = (colors, command, data, options) => {
2534
2583
  return renderInitData(colors, data, flags);
2535
2584
  case "keygen":
2536
2585
  return renderKeygenData(colors, data, flags);
2537
- case "link":
2586
+ case "sessions link":
2538
2587
  return renderLinkData(colors, data, flags, options.qr);
2539
- case "ls":
2588
+ case "sessions ls":
2540
2589
  return renderLsData(colors, data, options.now ?? /* @__PURE__ */ new Date());
2541
- case "tools":
2542
- return renderToolsData(colors, data, flags, options.full);
2543
- case "invoke":
2590
+ case "tools ls":
2591
+ return renderToolsListData(colors, data, flags, options.full);
2592
+ case "tools describe":
2593
+ return renderToolDetail(colors, data, flags);
2594
+ case "events ls":
2595
+ return renderEventsListData(colors, data, flags);
2596
+ case "tools call":
2544
2597
  return renderInvokeData(colors, data, flags);
2545
- case "revoke":
2598
+ case "sessions revoke":
2546
2599
  return renderRevokeData(colors, data);
2547
2600
  case "daemon run":
2548
2601
  return renderDaemonRunData(colors, data, flags);
@@ -2688,7 +2741,7 @@ var guarded = (context) => {
2688
2741
  };
2689
2742
  };
2690
2743
 
2691
- // src/cli/routes/link.ts
2744
+ // src/cli/routes/sessions/link.ts
2692
2745
  var route = async (context) => {
2693
2746
  const { options, stateDir } = context;
2694
2747
  return executeCommand(
@@ -0,0 +1,4 @@
1
+ /** Route for `appduct sessions ls` — loaded by `routes/sessions/index.ts`'s router only when it
2
+ * runs (issue #96; replaces the removed `appduct ls`). */
3
+ import type { Route } from "../../router.js";
4
+ export declare const route: Route;
@@ -1040,6 +1040,7 @@ var formatJson = (value, flags) => {
1040
1040
  import pc from "picocolors";
1041
1041
  import {
1042
1042
  formatAgentWebSocketUrl,
1043
+ renderEventSignature,
1043
1044
  renderToolSignature,
1044
1045
  summarizeToolDescription
1045
1046
  } from "@appduct/shared";
@@ -1135,6 +1136,13 @@ var formatDevice = (device) => {
1135
1136
  const label = parts.length > 0 ? parts.join(" ") : "unknown device";
1136
1137
  return device.os ? `${label} (${device.os})` : label;
1137
1138
  };
1139
+ var SUSPEND_REASON_LABELS = {
1140
+ app_backgrounded: "app in background",
1141
+ connection_lost: "connection lost"
1142
+ };
1143
+ var formatSessionState = (session) => {
1144
+ return session.suspendReason ? `${session.state} (${SUSPEND_REASON_LABELS[session.suspendReason]})` : session.state;
1145
+ };
1138
1146
  var renderLsData = (colors, data, now) => {
1139
1147
  if (data.length === 0) {
1140
1148
  return [colors.dim("Sessions"), " No Appduct sessions are registered."];
@@ -1143,7 +1151,7 @@ var renderLsData = (colors, data, now) => {
1143
1151
  const headers = ["Alias", "State", "Device", "Tools", "Age"];
1144
1152
  const rows = data.map((session) => [
1145
1153
  session.alias,
1146
- session.state,
1154
+ formatSessionState(session),
1147
1155
  formatDevice(session.device),
1148
1156
  String(session.toolCount),
1149
1157
  formatAge(session.claimedAt ?? session.createdAt, nowIso)
@@ -1157,9 +1165,6 @@ var renderLsData = (colors, data, now) => {
1157
1165
  ...rows.map((row) => ` ${row.map((cell, index) => cell.padEnd(widths[index])).join(" ")}`)
1158
1166
  ];
1159
1167
  };
1160
- var isToolsListing = (data) => {
1161
- return typeof data === "object" && data !== null && Array.isArray(data.tools);
1162
- };
1163
1168
  var isToolGroupsListing = (data) => {
1164
1169
  return typeof data === "object" && data !== null && Array.isArray(data.groups) && !Array.isArray(data.tools);
1165
1170
  };
@@ -1177,7 +1182,7 @@ var renderEmptyToolsLine = (data) => {
1177
1182
  }
1178
1183
  if (data.group !== void 0) {
1179
1184
  const match = data.filter === void 0 ? "" : ` match ${JSON.stringify(data.filter)}`;
1180
- return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools --groups\` to see the session's groups.`;
1185
+ return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools ls --groups\` to see the session's groups.`;
1181
1186
  }
1182
1187
  return data.filter === void 0 ? " No tools registered." : ` No tools match ${JSON.stringify(data.filter)}.`;
1183
1188
  };
@@ -1259,7 +1264,7 @@ var renderToolSummaryTable = (colors, data) => {
1259
1264
  ...grouped ? renderGroupedToolLines(colors, data.tools) : data.tools.flatMap((tool) => renderToolSummaryLines(tool, " ")),
1260
1265
  ...renderTruncationLine(data),
1261
1266
  "",
1262
- "Run `appduct tools <name>` for a tool's full schema."
1267
+ "Run `appduct tools describe <name>` for a tool's full schema."
1263
1268
  ];
1264
1269
  };
1265
1270
  var renderToolDetail = (colors, tool, flags) => {
@@ -1311,18 +1316,62 @@ var renderToolGroups = (colors, data) => {
1311
1316
  colors.green("Groups"),
1312
1317
  ...data.groups.map((entry) => ` ${label(entry).padEnd(width)} ${String(entry.total).padStart(countWidth)}`),
1313
1318
  "",
1314
- `${data.total} tool${data.total === 1 ? "" : "s"} in total. ` + (hasAnyGroup(data.groups) ? "Run `appduct tools --group <name>` to list one group's tools." : "No tool declares a group.")
1319
+ `${data.total} tool${data.total === 1 ? "" : "s"} in total. ` + (hasAnyGroup(data.groups) ? "Run `appduct tools ls --group <name>` to list one group's tools." : "No tool declares a group.")
1315
1320
  ];
1316
1321
  };
1317
- var renderToolsData = (colors, data, flags, full) => {
1322
+ var renderToolsListData = (colors, data, flags, full) => {
1318
1323
  if (isToolGroupsListing(data)) {
1319
1324
  return renderToolGroups(colors, data);
1320
1325
  }
1321
- if (!isToolsListing(data)) {
1322
- return renderToolDetail(colors, data, flags);
1323
- }
1324
1326
  return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
1325
1327
  };
1328
+ var renderEventsTruncationLine = (data) => {
1329
+ const offset = data.offset ?? 0;
1330
+ if (data.events.length >= data.total) {
1331
+ return [];
1332
+ }
1333
+ return [
1334
+ "",
1335
+ `Showing ${data.events.length} of ${data.total} events (offset ${offset}). Narrow with --name <glob> or page with --offset <n>.`
1336
+ ];
1337
+ };
1338
+ var renderEventsListData = (colors, data, flags) => {
1339
+ const [only] = data.events;
1340
+ if (data.name !== void 0 && !data.name.includes("*") && only !== void 0) {
1341
+ return renderFields(
1342
+ colors.green(`Event: ${only.name}`),
1343
+ [
1344
+ ["Signature", renderEventSignature(only)],
1345
+ ["Description", only.description],
1346
+ ["Payload schema", only.payload_schema]
1347
+ ],
1348
+ flags
1349
+ );
1350
+ }
1351
+ if (data.events.length === 0 && data.total > 0) {
1352
+ return [
1353
+ colors.green("Events"),
1354
+ ` No events at offset ${data.offset ?? 0}; ${data.total} matching event${data.total === 1 ? "" : "s"} in total.`
1355
+ ];
1356
+ }
1357
+ if (data.events.length === 0) {
1358
+ return [
1359
+ colors.green("Events"),
1360
+ data.name === void 0 ? " No events declared." : ` No events match ${JSON.stringify(data.name)}.`
1361
+ ];
1362
+ }
1363
+ const lines = data.events.flatMap((event) => [
1364
+ ` ${renderEventSignature(event)}`,
1365
+ ` ${summarizeToolDescription(event.description)}`
1366
+ ]);
1367
+ return [
1368
+ colors.green("Events"),
1369
+ ...lines,
1370
+ ...renderEventsTruncationLine(data),
1371
+ "",
1372
+ "Run `appduct events ls --name <name>` for an event's full payload schema."
1373
+ ];
1374
+ };
1326
1375
  var renderInvokeData = (colors, data, flags) => {
1327
1376
  return [colors.green("Result"), formatScalar(data, flags)];
1328
1377
  };
@@ -1506,15 +1555,19 @@ var renderSuccessData = (colors, command, data, options) => {
1506
1555
  return renderInitData(colors, data, flags);
1507
1556
  case "keygen":
1508
1557
  return renderKeygenData(colors, data, flags);
1509
- case "link":
1558
+ case "sessions link":
1510
1559
  return renderLinkData(colors, data, flags, options.qr);
1511
- case "ls":
1560
+ case "sessions ls":
1512
1561
  return renderLsData(colors, data, options.now ?? /* @__PURE__ */ new Date());
1513
- case "tools":
1514
- return renderToolsData(colors, data, flags, options.full);
1515
- case "invoke":
1562
+ case "tools ls":
1563
+ return renderToolsListData(colors, data, flags, options.full);
1564
+ case "tools describe":
1565
+ return renderToolDetail(colors, data, flags);
1566
+ case "events ls":
1567
+ return renderEventsListData(colors, data, flags);
1568
+ case "tools call":
1516
1569
  return renderInvokeData(colors, data, flags);
1517
- case "revoke":
1570
+ case "sessions revoke":
1518
1571
  return renderRevokeData(colors, data);
1519
1572
  case "daemon run":
1520
1573
  return renderDaemonRunData(colors, data, flags);
@@ -1660,7 +1713,7 @@ var guarded = (context) => {
1660
1713
  };
1661
1714
  };
1662
1715
 
1663
- // src/cli/routes/ls.ts
1716
+ // src/cli/routes/sessions/ls.ts
1664
1717
  var route = async (context) => {
1665
1718
  const { stateDir } = context;
1666
1719
  return executeCommand(
@@ -0,0 +1,4 @@
1
+ /** Route for `appduct sessions revoke` — loaded by `routes/sessions/index.ts`'s router only when
2
+ * it runs (issue #96; replaces the removed `appduct revoke`). */
3
+ import type { Route } from "../../router.js";
4
+ export declare const route: Route;
@@ -1051,6 +1051,7 @@ var formatJson = (value, flags) => {
1051
1051
  import pc from "picocolors";
1052
1052
  import {
1053
1053
  formatAgentWebSocketUrl,
1054
+ renderEventSignature,
1054
1055
  renderToolSignature,
1055
1056
  summarizeToolDescription
1056
1057
  } from "@appduct/shared";
@@ -1146,6 +1147,13 @@ var formatDevice = (device) => {
1146
1147
  const label = parts.length > 0 ? parts.join(" ") : "unknown device";
1147
1148
  return device.os ? `${label} (${device.os})` : label;
1148
1149
  };
1150
+ var SUSPEND_REASON_LABELS = {
1151
+ app_backgrounded: "app in background",
1152
+ connection_lost: "connection lost"
1153
+ };
1154
+ var formatSessionState = (session) => {
1155
+ return session.suspendReason ? `${session.state} (${SUSPEND_REASON_LABELS[session.suspendReason]})` : session.state;
1156
+ };
1149
1157
  var renderLsData = (colors, data, now) => {
1150
1158
  if (data.length === 0) {
1151
1159
  return [colors.dim("Sessions"), " No Appduct sessions are registered."];
@@ -1154,7 +1162,7 @@ var renderLsData = (colors, data, now) => {
1154
1162
  const headers = ["Alias", "State", "Device", "Tools", "Age"];
1155
1163
  const rows = data.map((session) => [
1156
1164
  session.alias,
1157
- session.state,
1165
+ formatSessionState(session),
1158
1166
  formatDevice(session.device),
1159
1167
  String(session.toolCount),
1160
1168
  formatAge(session.claimedAt ?? session.createdAt, nowIso)
@@ -1168,9 +1176,6 @@ var renderLsData = (colors, data, now) => {
1168
1176
  ...rows.map((row) => ` ${row.map((cell, index) => cell.padEnd(widths[index])).join(" ")}`)
1169
1177
  ];
1170
1178
  };
1171
- var isToolsListing = (data) => {
1172
- return typeof data === "object" && data !== null && Array.isArray(data.tools);
1173
- };
1174
1179
  var isToolGroupsListing = (data) => {
1175
1180
  return typeof data === "object" && data !== null && Array.isArray(data.groups) && !Array.isArray(data.tools);
1176
1181
  };
@@ -1188,7 +1193,7 @@ var renderEmptyToolsLine = (data) => {
1188
1193
  }
1189
1194
  if (data.group !== void 0) {
1190
1195
  const match = data.filter === void 0 ? "" : ` match ${JSON.stringify(data.filter)}`;
1191
- return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools --groups\` to see the session's groups.`;
1196
+ return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools ls --groups\` to see the session's groups.`;
1192
1197
  }
1193
1198
  return data.filter === void 0 ? " No tools registered." : ` No tools match ${JSON.stringify(data.filter)}.`;
1194
1199
  };
@@ -1270,7 +1275,7 @@ var renderToolSummaryTable = (colors, data) => {
1270
1275
  ...grouped ? renderGroupedToolLines(colors, data.tools) : data.tools.flatMap((tool) => renderToolSummaryLines(tool, " ")),
1271
1276
  ...renderTruncationLine(data),
1272
1277
  "",
1273
- "Run `appduct tools <name>` for a tool's full schema."
1278
+ "Run `appduct tools describe <name>` for a tool's full schema."
1274
1279
  ];
1275
1280
  };
1276
1281
  var renderToolDetail = (colors, tool, flags) => {
@@ -1322,18 +1327,62 @@ var renderToolGroups = (colors, data) => {
1322
1327
  colors.green("Groups"),
1323
1328
  ...data.groups.map((entry) => ` ${label(entry).padEnd(width)} ${String(entry.total).padStart(countWidth)}`),
1324
1329
  "",
1325
- `${data.total} tool${data.total === 1 ? "" : "s"} in total. ` + (hasAnyGroup(data.groups) ? "Run `appduct tools --group <name>` to list one group's tools." : "No tool declares a group.")
1330
+ `${data.total} tool${data.total === 1 ? "" : "s"} in total. ` + (hasAnyGroup(data.groups) ? "Run `appduct tools ls --group <name>` to list one group's tools." : "No tool declares a group.")
1326
1331
  ];
1327
1332
  };
1328
- var renderToolsData = (colors, data, flags, full) => {
1333
+ var renderToolsListData = (colors, data, flags, full) => {
1329
1334
  if (isToolGroupsListing(data)) {
1330
1335
  return renderToolGroups(colors, data);
1331
1336
  }
1332
- if (!isToolsListing(data)) {
1333
- return renderToolDetail(colors, data, flags);
1334
- }
1335
1337
  return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
1336
1338
  };
1339
+ var renderEventsTruncationLine = (data) => {
1340
+ const offset = data.offset ?? 0;
1341
+ if (data.events.length >= data.total) {
1342
+ return [];
1343
+ }
1344
+ return [
1345
+ "",
1346
+ `Showing ${data.events.length} of ${data.total} events (offset ${offset}). Narrow with --name <glob> or page with --offset <n>.`
1347
+ ];
1348
+ };
1349
+ var renderEventsListData = (colors, data, flags) => {
1350
+ const [only] = data.events;
1351
+ if (data.name !== void 0 && !data.name.includes("*") && only !== void 0) {
1352
+ return renderFields(
1353
+ colors.green(`Event: ${only.name}`),
1354
+ [
1355
+ ["Signature", renderEventSignature(only)],
1356
+ ["Description", only.description],
1357
+ ["Payload schema", only.payload_schema]
1358
+ ],
1359
+ flags
1360
+ );
1361
+ }
1362
+ if (data.events.length === 0 && data.total > 0) {
1363
+ return [
1364
+ colors.green("Events"),
1365
+ ` No events at offset ${data.offset ?? 0}; ${data.total} matching event${data.total === 1 ? "" : "s"} in total.`
1366
+ ];
1367
+ }
1368
+ if (data.events.length === 0) {
1369
+ return [
1370
+ colors.green("Events"),
1371
+ data.name === void 0 ? " No events declared." : ` No events match ${JSON.stringify(data.name)}.`
1372
+ ];
1373
+ }
1374
+ const lines = data.events.flatMap((event) => [
1375
+ ` ${renderEventSignature(event)}`,
1376
+ ` ${summarizeToolDescription(event.description)}`
1377
+ ]);
1378
+ return [
1379
+ colors.green("Events"),
1380
+ ...lines,
1381
+ ...renderEventsTruncationLine(data),
1382
+ "",
1383
+ "Run `appduct events ls --name <name>` for an event's full payload schema."
1384
+ ];
1385
+ };
1337
1386
  var renderInvokeData = (colors, data, flags) => {
1338
1387
  return [colors.green("Result"), formatScalar(data, flags)];
1339
1388
  };
@@ -1517,15 +1566,19 @@ var renderSuccessData = (colors, command, data, options) => {
1517
1566
  return renderInitData(colors, data, flags);
1518
1567
  case "keygen":
1519
1568
  return renderKeygenData(colors, data, flags);
1520
- case "link":
1569
+ case "sessions link":
1521
1570
  return renderLinkData(colors, data, flags, options.qr);
1522
- case "ls":
1571
+ case "sessions ls":
1523
1572
  return renderLsData(colors, data, options.now ?? /* @__PURE__ */ new Date());
1524
- case "tools":
1525
- return renderToolsData(colors, data, flags, options.full);
1526
- case "invoke":
1573
+ case "tools ls":
1574
+ return renderToolsListData(colors, data, flags, options.full);
1575
+ case "tools describe":
1576
+ return renderToolDetail(colors, data, flags);
1577
+ case "events ls":
1578
+ return renderEventsListData(colors, data, flags);
1579
+ case "tools call":
1527
1580
  return renderInvokeData(colors, data, flags);
1528
- case "revoke":
1581
+ case "sessions revoke":
1529
1582
  return renderRevokeData(colors, data);
1530
1583
  case "daemon run":
1531
1584
  return renderDaemonRunData(colors, data, flags);
@@ -1671,7 +1724,7 @@ var guarded = (context) => {
1671
1724
  };
1672
1725
  };
1673
1726
 
1674
- // src/cli/routes/revoke.ts
1727
+ // src/cli/routes/sessions/revoke.ts
1675
1728
  var route = async (context) => {
1676
1729
  const { stateDir } = context;
1677
1730
  return executeCommand(
@@ -1679,7 +1732,7 @@ var route = async (context) => {
1679
1732
  // Parsed inside the handler so a usage error renders through the runner instead of escaping
1680
1733
  // the route as an uncaught rejection.
1681
1734
  () => {
1682
- const { selector } = splitOptionalSelector(context.args, "revoke [selector]");
1735
+ const { selector } = splitOptionalSelector(context.args, "sessions revoke [selector]");
1683
1736
  return guarded(context)(() => handleRevokeCommand({ selector }, { stateDir }))();
1684
1737
  },
1685
1738
  context.env
@@ -0,0 +1,4 @@
1
+ /** Route for `appduct tools call` — loaded by `routes/tools/index.ts`'s router only when it runs
2
+ * (issue #96; replaces the removed `appduct invoke`). */
3
+ import type { Route } from "../../router.js";
4
+ export declare const route: Route;