appduct 0.12.0 → 0.13.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 (69) hide show
  1. package/README.md +41 -36
  2. package/dist/bin.js +44 -36
  3. package/dist/cli/command-options.d.ts +7 -17
  4. package/dist/cli/result-types.d.ts +11 -8
  5. package/dist/cli/routes/daemon/index.js +12 -16
  6. package/dist/cli/routes/daemon/run.js +136 -28
  7. package/dist/cli/routes/daemon/start.js +12 -16
  8. package/dist/cli/routes/daemon/status.js +12 -16
  9. package/dist/cli/routes/daemon/stop.js +12 -16
  10. package/dist/cli/routes/doctor.js +12 -16
  11. package/dist/cli/routes/events/index.d.ts +9 -0
  12. package/dist/cli/routes/events/index.js +842 -0
  13. package/dist/cli/routes/events/shared-options.d.ts +12 -0
  14. package/dist/cli/routes/events/shared-options.js +102 -0
  15. package/dist/cli/routes/events/since.d.ts +6 -0
  16. package/dist/cli/routes/events/since.js +1977 -0
  17. package/dist/cli/routes/events/tail.d.ts +6 -0
  18. package/dist/cli/routes/{events.js → events/tail.js} +177 -162
  19. package/dist/cli/routes/init.js +14 -18
  20. package/dist/cli/routes/keygen.js +12 -16
  21. package/dist/cli/routes/mcp.js +181 -165
  22. package/dist/cli/routes/sessions/index.d.ts +7 -0
  23. package/dist/cli/routes/sessions/index.js +843 -0
  24. package/dist/cli/routes/sessions/link.d.ts +4 -0
  25. package/dist/cli/routes/{link.js → sessions/link.js} +13 -17
  26. package/dist/cli/routes/sessions/ls.d.ts +4 -0
  27. package/dist/cli/routes/{ls.js → sessions/ls.js} +13 -17
  28. package/dist/cli/routes/sessions/revoke.d.ts +4 -0
  29. package/dist/cli/routes/{revoke.js → sessions/revoke.js} +14 -18
  30. package/dist/cli/routes/tools/call.d.ts +4 -0
  31. package/dist/cli/routes/{invoke.js → tools/call.js} +15 -19
  32. package/dist/cli/routes/tools/describe.d.ts +6 -0
  33. package/dist/cli/routes/tools/describe.js +1837 -0
  34. package/dist/cli/routes/tools/index.d.ts +6 -0
  35. package/dist/cli/routes/tools/index.js +843 -0
  36. package/dist/cli/routes/tools/ls.d.ts +4 -0
  37. package/dist/cli/routes/{tools.js → tools/ls.js} +40 -73
  38. package/dist/cli/routes/tools/shared-options.d.ts +16 -0
  39. package/dist/cli/routes/tools/shared-options.js +122 -0
  40. package/dist/client/app-client.d.ts +96 -37
  41. package/dist/client/index.d.ts +3 -2
  42. package/dist/client/index.js +178 -138
  43. package/dist/commands/events.d.ts +31 -14
  44. package/dist/commands/invoke.d.ts +1 -1
  45. package/dist/commands/link.d.ts +1 -1
  46. package/dist/commands/ls.d.ts +1 -1
  47. package/dist/commands/revoke.d.ts +1 -1
  48. package/dist/commands/tools.d.ts +12 -13
  49. package/dist/daemon/config.d.ts +1 -1
  50. package/dist/daemon/event-bus.d.ts +32 -0
  51. package/dist/daemon/rpc-errors.d.ts +1 -1
  52. package/dist/errors.d.ts +1 -1
  53. package/dist/events/index.d.ts +60 -0
  54. package/dist/index.js +56 -39
  55. package/dist/link.d.ts +1 -1
  56. package/dist/mcp/app-tools.d.ts +3 -2
  57. package/dist/mcp/connect-tool.d.ts +1 -1
  58. package/dist/mcp/events-tool.d.ts +28 -27
  59. package/dist/native-scheme.d.ts +1 -1
  60. package/dist/output.d.ts +29 -6
  61. package/dist/rpc/client.d.ts +1 -1
  62. package/dist/scheme.d.ts +4 -4
  63. package/package.json +2 -2
  64. package/dist/cli/routes/events.d.ts +0 -3
  65. package/dist/cli/routes/invoke.d.ts +0 -3
  66. package/dist/cli/routes/link.d.ts +0 -3
  67. package/dist/cli/routes/ls.d.ts +0 -3
  68. package/dist/cli/routes/revoke.d.ts +0 -3
  69. package/dist/cli/routes/tools.d.ts +0 -3
@@ -614,6 +614,71 @@ var createCallsManager = (options) => {
614
614
 
615
615
  // src/daemon/event-bus.ts
616
616
  var TERMINAL_EVENT_KINDS = /* @__PURE__ */ new Set(["session_expired", "session_revoked"]);
617
+ var utf8ByteLength = (text) => Buffer.byteLength(text, "utf8");
618
+ var truncateToUtf8Bytes = (text, maxBytes) => {
619
+ const encoded = Buffer.from(text, "utf8");
620
+ if (encoded.length <= maxBytes) {
621
+ return text;
622
+ }
623
+ const decoder = new TextDecoder("utf-8", { fatal: true });
624
+ for (let end = maxBytes; end > 0; end--) {
625
+ try {
626
+ return decoder.decode(encoded.subarray(0, end));
627
+ } catch {
628
+ }
629
+ }
630
+ return "";
631
+ };
632
+ var matchesNameGlob = (pattern, name) => {
633
+ const pieces = pattern.split("*");
634
+ const first = pieces[0] ?? "";
635
+ if (pieces.length === 1) {
636
+ return name === first;
637
+ }
638
+ const last = pieces[pieces.length - 1] ?? "";
639
+ if (first.length + last.length > name.length || !name.startsWith(first) || !name.endsWith(last)) {
640
+ return false;
641
+ }
642
+ const end = name.length - last.length;
643
+ let position = first.length;
644
+ for (const piece of pieces.slice(1, -1)) {
645
+ const found = name.indexOf(piece, position);
646
+ if (found === -1 || found + piece.length > end) {
647
+ return false;
648
+ }
649
+ position = found + piece.length;
650
+ }
651
+ return true;
652
+ };
653
+ var projectAppEvent = (event, options = {}) => {
654
+ if (event.kind !== "app_event") {
655
+ return event;
656
+ }
657
+ const data = event.data;
658
+ if (options.name !== void 0 && !(typeof data.name === "string" && matchesNameGlob(options.name, data.name))) {
659
+ return void 0;
660
+ }
661
+ if (options.payloadMaxBytes === void 0 || !("payload" in data)) {
662
+ return event;
663
+ }
664
+ const payloadJson = JSON.stringify(data.payload);
665
+ if (payloadJson === void 0) {
666
+ return event;
667
+ }
668
+ const payloadBytes = utf8ByteLength(payloadJson);
669
+ if (payloadBytes <= options.payloadMaxBytes) {
670
+ return event;
671
+ }
672
+ return {
673
+ ...event,
674
+ data: {
675
+ name: data.name,
676
+ payloadPreview: truncateToUtf8Bytes(payloadJson, options.payloadMaxBytes),
677
+ truncated: true,
678
+ payloadBytes
679
+ }
680
+ };
681
+ };
617
682
  var createEventBus = (options = {}) => {
618
683
  const clock = options.clock ?? { now: () => /* @__PURE__ */ new Date() };
619
684
  const bufferSize = options.bufferSize ?? 256;
@@ -631,8 +696,9 @@ var createEventBus = (options = {}) => {
631
696
  return {
632
697
  emit: (event) => {
633
698
  const sessionId = event.sessionId;
634
- const seq = sessionId !== void 0 ? (cursors.get(sessionId) ?? 0) + 1 : 0;
635
- if (sessionId !== void 0) {
699
+ let seq = 0;
700
+ if (sessionId !== void 0 && event.kind === "app_event") {
701
+ seq = (cursors.get(sessionId) ?? 0) + 1;
636
702
  cursors.set(sessionId, seq);
637
703
  }
638
704
  const notification = {
@@ -664,15 +730,26 @@ var createEventBus = (options = {}) => {
664
730
  since: (sessionId, query = {}) => {
665
731
  const buffer = buffers.get(sessionId) ?? [];
666
732
  const sessionCursor = cursors.get(sessionId) ?? 0;
667
- let events = buffer.slice();
733
+ const sinceValue = query.since ?? 0;
734
+ const oldestRetainedSeq = buffer.length > 0 ? buffer[0].seq : void 0;
735
+ const dropped = oldestRetainedSeq !== void 0 ? Math.max(0, oldestRetainedSeq - sinceValue - 1) : 0;
736
+ let matching = buffer.slice();
668
737
  if (query.since !== void 0) {
669
- events = events.filter((event) => event.seq > query.since);
738
+ matching = matching.filter((event) => event.seq > query.since);
739
+ }
740
+ if (query.name !== void 0) {
741
+ matching = matching.filter((event) => projectAppEvent(event, { name: query.name }) !== void 0);
670
742
  }
743
+ let events = matching;
671
744
  if (query.limit !== void 0 && events.length > query.limit) {
672
745
  events = events.slice(0, query.limit);
673
746
  }
747
+ const remaining = matching.length - events.length;
674
748
  const cursor = events.length > 0 ? events[events.length - 1].seq : sessionCursor;
675
- return { events, cursor };
749
+ if (query.payloadMaxBytes !== void 0) {
750
+ events = events.map((event) => projectAppEvent(event, { payloadMaxBytes: query.payloadMaxBytes }));
751
+ }
752
+ return { events, cursor, dropped, remaining };
676
753
  },
677
754
  drop: (sessionId) => {
678
755
  buffers.delete(sessionId);
@@ -2072,7 +2149,26 @@ var asEventsSubscribeParams = (params) => {
2072
2149
  }
2073
2150
  kinds = kindsRaw;
2074
2151
  }
2075
- return { sessionSelector, kinds };
2152
+ const name = record.name;
2153
+ if (name !== void 0 && typeof name !== "string") {
2154
+ throw new RpcApplicationError("invalid_request", '"name" must be a string.');
2155
+ }
2156
+ const payloadMaxBytes = asPayloadMaxBytes(record.payloadMaxBytes);
2157
+ return {
2158
+ sessionSelector,
2159
+ kinds,
2160
+ name,
2161
+ payloadMaxBytes
2162
+ };
2163
+ };
2164
+ var asPayloadMaxBytes = (value) => {
2165
+ if (value === void 0) {
2166
+ return void 0;
2167
+ }
2168
+ if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
2169
+ throw new RpcApplicationError("invalid_request", '"payloadMaxBytes" must be a positive integer.');
2170
+ }
2171
+ return value;
2076
2172
  };
2077
2173
  var asEventsSinceParams = (params) => {
2078
2174
  const record = asRecordParams(params);
@@ -2088,10 +2184,17 @@ var asEventsSinceParams = (params) => {
2088
2184
  if (limit !== void 0 && (typeof limit !== "number" || !Number.isInteger(limit) || limit <= 0)) {
2089
2185
  throw new RpcApplicationError("invalid_request", '"limit" must be a positive integer.');
2090
2186
  }
2187
+ const name = record.name;
2188
+ if (name !== void 0 && typeof name !== "string") {
2189
+ throw new RpcApplicationError("invalid_request", '"name" must be a string.');
2190
+ }
2191
+ const payloadMaxBytes = asPayloadMaxBytes(record.payloadMaxBytes);
2091
2192
  return {
2092
2193
  selector,
2093
2194
  since,
2094
- limit
2195
+ limit,
2196
+ name,
2197
+ payloadMaxBytes
2095
2198
  };
2096
2199
  };
2097
2200
  var asLinkCreateParams = (params) => {
@@ -2238,10 +2341,17 @@ var startDaemon = async (options) => {
2238
2341
  if (subscription.kinds && !subscription.kinds.has(event.kind)) {
2239
2342
  continue;
2240
2343
  }
2344
+ const projected = projectAppEvent(event, {
2345
+ name: subscription.name,
2346
+ payloadMaxBytes: subscription.payloadMaxBytes
2347
+ });
2348
+ if (projected === void 0) {
2349
+ continue;
2350
+ }
2241
2351
  if (subscription.sessionSelector !== void 0 && event.sessionId !== subscription.sessionSelector && event.alias !== subscription.sessionSelector) {
2242
2352
  continue;
2243
2353
  }
2244
- server?.notify(connection, event);
2354
+ server?.notify(connection, projected);
2245
2355
  }
2246
2356
  });
2247
2357
  server = await startRpcServer({
@@ -2420,17 +2530,19 @@ var startDaemon = async (options) => {
2420
2530
  return { cancelled };
2421
2531
  },
2422
2532
  [RPC_METHODS.eventsSubscribe]: (params, context) => {
2423
- const { sessionSelector, kinds } = asEventsSubscribeParams(params);
2533
+ const { sessionSelector, kinds, name, payloadMaxBytes } = asEventsSubscribeParams(params);
2424
2534
  context.connection.state.eventSubscription = {
2425
2535
  sessionSelector,
2426
- kinds: kinds ? new Set(kinds) : void 0
2536
+ kinds: kinds ? new Set(kinds) : void 0,
2537
+ name,
2538
+ payloadMaxBytes
2427
2539
  };
2428
2540
  return { ok: true };
2429
2541
  },
2430
2542
  [RPC_METHODS.eventsSince]: (params) => {
2431
- const { selector, since, limit } = asEventsSinceParams(params);
2543
+ const { selector, since, limit, name, payloadMaxBytes } = asEventsSinceParams(params);
2432
2544
  const resolved = activeSessionManager.describe(selector);
2433
- return activeEventBus.since(resolved.sessionId, { since, limit });
2545
+ return activeEventBus.since(resolved.sessionId, { since, limit, name, payloadMaxBytes });
2434
2546
  }
2435
2547
  }
2436
2548
  });
@@ -2791,9 +2903,6 @@ var renderLsData = (colors, data, now) => {
2791
2903
  ...rows.map((row) => ` ${row.map((cell, index) => cell.padEnd(widths[index])).join(" ")}`)
2792
2904
  ];
2793
2905
  };
2794
- var isToolsListing = (data) => {
2795
- return typeof data === "object" && data !== null && Array.isArray(data.tools);
2796
- };
2797
2906
  var isToolGroupsListing = (data) => {
2798
2907
  return typeof data === "object" && data !== null && Array.isArray(data.groups) && !Array.isArray(data.tools);
2799
2908
  };
@@ -2811,7 +2920,7 @@ var renderEmptyToolsLine = (data) => {
2811
2920
  }
2812
2921
  if (data.group !== void 0) {
2813
2922
  const match = data.filter === void 0 ? "" : ` match ${JSON.stringify(data.filter)}`;
2814
- return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools --groups\` to see the session's groups.`;
2923
+ return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools ls --groups\` to see the session's groups.`;
2815
2924
  }
2816
2925
  return data.filter === void 0 ? " No tools registered." : ` No tools match ${JSON.stringify(data.filter)}.`;
2817
2926
  };
@@ -2893,7 +3002,7 @@ var renderToolSummaryTable = (colors, data) => {
2893
3002
  ...grouped ? renderGroupedToolLines(colors, data.tools) : data.tools.flatMap((tool) => renderToolSummaryLines(tool, " ")),
2894
3003
  ...renderTruncationLine(data),
2895
3004
  "",
2896
- "Run `appduct tools <name>` for a tool's full schema."
3005
+ "Run `appduct tools describe <name>` for a tool's full schema."
2897
3006
  ];
2898
3007
  };
2899
3008
  var renderToolDetail = (colors, tool, flags) => {
@@ -2945,16 +3054,13 @@ var renderToolGroups = (colors, data) => {
2945
3054
  colors.green("Groups"),
2946
3055
  ...data.groups.map((entry) => ` ${label(entry).padEnd(width)} ${String(entry.total).padStart(countWidth)}`),
2947
3056
  "",
2948
- `${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.")
3057
+ `${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.")
2949
3058
  ];
2950
3059
  };
2951
- var renderToolsData = (colors, data, flags, full) => {
3060
+ var renderToolsListData = (colors, data, flags, full) => {
2952
3061
  if (isToolGroupsListing(data)) {
2953
3062
  return renderToolGroups(colors, data);
2954
3063
  }
2955
- if (!isToolsListing(data)) {
2956
- return renderToolDetail(colors, data, flags);
2957
- }
2958
3064
  return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
2959
3065
  };
2960
3066
  var renderInvokeData = (colors, data, flags) => {
@@ -3140,15 +3246,17 @@ var renderSuccessData = (colors, command, data, options) => {
3140
3246
  return renderInitData(colors, data, flags);
3141
3247
  case "keygen":
3142
3248
  return renderKeygenData(colors, data, flags);
3143
- case "link":
3249
+ case "sessions link":
3144
3250
  return renderLinkData(colors, data, flags, options.qr);
3145
- case "ls":
3251
+ case "sessions ls":
3146
3252
  return renderLsData(colors, data, options.now ?? /* @__PURE__ */ new Date());
3147
- case "tools":
3148
- return renderToolsData(colors, data, flags, options.full);
3149
- case "invoke":
3253
+ case "tools ls":
3254
+ return renderToolsListData(colors, data, flags, options.full);
3255
+ case "tools describe":
3256
+ return renderToolDetail(colors, data, flags);
3257
+ case "tools call":
3150
3258
  return renderInvokeData(colors, data, flags);
3151
- case "revoke":
3259
+ case "sessions revoke":
3152
3260
  return renderRevokeData(colors, data);
3153
3261
  case "daemon run":
3154
3262
  return renderDaemonRunData(colors, data, flags);
@@ -1166,9 +1166,6 @@ var renderLsData = (colors, data, now) => {
1166
1166
  ...rows.map((row) => ` ${row.map((cell, index) => cell.padEnd(widths[index])).join(" ")}`)
1167
1167
  ];
1168
1168
  };
1169
- var isToolsListing = (data) => {
1170
- return typeof data === "object" && data !== null && Array.isArray(data.tools);
1171
- };
1172
1169
  var isToolGroupsListing = (data) => {
1173
1170
  return typeof data === "object" && data !== null && Array.isArray(data.groups) && !Array.isArray(data.tools);
1174
1171
  };
@@ -1186,7 +1183,7 @@ var renderEmptyToolsLine = (data) => {
1186
1183
  }
1187
1184
  if (data.group !== void 0) {
1188
1185
  const match = data.filter === void 0 ? "" : ` match ${JSON.stringify(data.filter)}`;
1189
- return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools --groups\` to see the session's groups.`;
1186
+ return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools ls --groups\` to see the session's groups.`;
1190
1187
  }
1191
1188
  return data.filter === void 0 ? " No tools registered." : ` No tools match ${JSON.stringify(data.filter)}.`;
1192
1189
  };
@@ -1268,7 +1265,7 @@ var renderToolSummaryTable = (colors, data) => {
1268
1265
  ...grouped ? renderGroupedToolLines(colors, data.tools) : data.tools.flatMap((tool) => renderToolSummaryLines(tool, " ")),
1269
1266
  ...renderTruncationLine(data),
1270
1267
  "",
1271
- "Run `appduct tools <name>` for a tool's full schema."
1268
+ "Run `appduct tools describe <name>` for a tool's full schema."
1272
1269
  ];
1273
1270
  };
1274
1271
  var renderToolDetail = (colors, tool, flags) => {
@@ -1320,16 +1317,13 @@ var renderToolGroups = (colors, data) => {
1320
1317
  colors.green("Groups"),
1321
1318
  ...data.groups.map((entry) => ` ${label(entry).padEnd(width)} ${String(entry.total).padStart(countWidth)}`),
1322
1319
  "",
1323
- `${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.")
1320
+ `${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.")
1324
1321
  ];
1325
1322
  };
1326
- var renderToolsData = (colors, data, flags, full) => {
1323
+ var renderToolsListData = (colors, data, flags, full) => {
1327
1324
  if (isToolGroupsListing(data)) {
1328
1325
  return renderToolGroups(colors, data);
1329
1326
  }
1330
- if (!isToolsListing(data)) {
1331
- return renderToolDetail(colors, data, flags);
1332
- }
1333
1327
  return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
1334
1328
  };
1335
1329
  var renderInvokeData = (colors, data, flags) => {
@@ -1515,15 +1509,17 @@ var renderSuccessData = (colors, command, data, options) => {
1515
1509
  return renderInitData(colors, data, flags);
1516
1510
  case "keygen":
1517
1511
  return renderKeygenData(colors, data, flags);
1518
- case "link":
1512
+ case "sessions link":
1519
1513
  return renderLinkData(colors, data, flags, options.qr);
1520
- case "ls":
1514
+ case "sessions ls":
1521
1515
  return renderLsData(colors, data, options.now ?? /* @__PURE__ */ new Date());
1522
- case "tools":
1523
- return renderToolsData(colors, data, flags, options.full);
1524
- case "invoke":
1516
+ case "tools ls":
1517
+ return renderToolsListData(colors, data, flags, options.full);
1518
+ case "tools describe":
1519
+ return renderToolDetail(colors, data, flags);
1520
+ case "tools call":
1525
1521
  return renderInvokeData(colors, data, flags);
1526
- case "revoke":
1522
+ case "sessions revoke":
1527
1523
  return renderRevokeData(colors, data);
1528
1524
  case "daemon run":
1529
1525
  return renderDaemonRunData(colors, data, flags);
@@ -1195,9 +1195,6 @@ var renderLsData = (colors, data, now) => {
1195
1195
  ...rows.map((row) => ` ${row.map((cell, index) => cell.padEnd(widths[index])).join(" ")}`)
1196
1196
  ];
1197
1197
  };
1198
- var isToolsListing = (data) => {
1199
- return typeof data === "object" && data !== null && Array.isArray(data.tools);
1200
- };
1201
1198
  var isToolGroupsListing = (data) => {
1202
1199
  return typeof data === "object" && data !== null && Array.isArray(data.groups) && !Array.isArray(data.tools);
1203
1200
  };
@@ -1215,7 +1212,7 @@ var renderEmptyToolsLine = (data) => {
1215
1212
  }
1216
1213
  if (data.group !== void 0) {
1217
1214
  const match = data.filter === void 0 ? "" : ` match ${JSON.stringify(data.filter)}`;
1218
- return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools --groups\` to see the session's groups.`;
1215
+ return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools ls --groups\` to see the session's groups.`;
1219
1216
  }
1220
1217
  return data.filter === void 0 ? " No tools registered." : ` No tools match ${JSON.stringify(data.filter)}.`;
1221
1218
  };
@@ -1297,7 +1294,7 @@ var renderToolSummaryTable = (colors, data) => {
1297
1294
  ...grouped ? renderGroupedToolLines(colors, data.tools) : data.tools.flatMap((tool) => renderToolSummaryLines(tool, " ")),
1298
1295
  ...renderTruncationLine(data),
1299
1296
  "",
1300
- "Run `appduct tools <name>` for a tool's full schema."
1297
+ "Run `appduct tools describe <name>` for a tool's full schema."
1301
1298
  ];
1302
1299
  };
1303
1300
  var renderToolDetail = (colors, tool, flags) => {
@@ -1349,16 +1346,13 @@ var renderToolGroups = (colors, data) => {
1349
1346
  colors.green("Groups"),
1350
1347
  ...data.groups.map((entry) => ` ${label(entry).padEnd(width)} ${String(entry.total).padStart(countWidth)}`),
1351
1348
  "",
1352
- `${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.")
1349
+ `${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.")
1353
1350
  ];
1354
1351
  };
1355
- var renderToolsData = (colors, data, flags, full) => {
1352
+ var renderToolsListData = (colors, data, flags, full) => {
1356
1353
  if (isToolGroupsListing(data)) {
1357
1354
  return renderToolGroups(colors, data);
1358
1355
  }
1359
- if (!isToolsListing(data)) {
1360
- return renderToolDetail(colors, data, flags);
1361
- }
1362
1356
  return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
1363
1357
  };
1364
1358
  var renderInvokeData = (colors, data, flags) => {
@@ -1544,15 +1538,17 @@ var renderSuccessData = (colors, command, data, options) => {
1544
1538
  return renderInitData(colors, data, flags);
1545
1539
  case "keygen":
1546
1540
  return renderKeygenData(colors, data, flags);
1547
- case "link":
1541
+ case "sessions link":
1548
1542
  return renderLinkData(colors, data, flags, options.qr);
1549
- case "ls":
1543
+ case "sessions ls":
1550
1544
  return renderLsData(colors, data, options.now ?? /* @__PURE__ */ new Date());
1551
- case "tools":
1552
- return renderToolsData(colors, data, flags, options.full);
1553
- case "invoke":
1545
+ case "tools ls":
1546
+ return renderToolsListData(colors, data, flags, options.full);
1547
+ case "tools describe":
1548
+ return renderToolDetail(colors, data, flags);
1549
+ case "tools call":
1554
1550
  return renderInvokeData(colors, data, flags);
1555
- case "revoke":
1551
+ case "sessions revoke":
1556
1552
  return renderRevokeData(colors, data);
1557
1553
  case "daemon run":
1558
1554
  return renderDaemonRunData(colors, data, flags);
@@ -1165,9 +1165,6 @@ var renderLsData = (colors, data, now) => {
1165
1165
  ...rows.map((row) => ` ${row.map((cell, index) => cell.padEnd(widths[index])).join(" ")}`)
1166
1166
  ];
1167
1167
  };
1168
- var isToolsListing = (data) => {
1169
- return typeof data === "object" && data !== null && Array.isArray(data.tools);
1170
- };
1171
1168
  var isToolGroupsListing = (data) => {
1172
1169
  return typeof data === "object" && data !== null && Array.isArray(data.groups) && !Array.isArray(data.tools);
1173
1170
  };
@@ -1185,7 +1182,7 @@ var renderEmptyToolsLine = (data) => {
1185
1182
  }
1186
1183
  if (data.group !== void 0) {
1187
1184
  const match = data.filter === void 0 ? "" : ` match ${JSON.stringify(data.filter)}`;
1188
- 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.`;
1189
1186
  }
1190
1187
  return data.filter === void 0 ? " No tools registered." : ` No tools match ${JSON.stringify(data.filter)}.`;
1191
1188
  };
@@ -1267,7 +1264,7 @@ var renderToolSummaryTable = (colors, data) => {
1267
1264
  ...grouped ? renderGroupedToolLines(colors, data.tools) : data.tools.flatMap((tool) => renderToolSummaryLines(tool, " ")),
1268
1265
  ...renderTruncationLine(data),
1269
1266
  "",
1270
- "Run `appduct tools <name>` for a tool's full schema."
1267
+ "Run `appduct tools describe <name>` for a tool's full schema."
1271
1268
  ];
1272
1269
  };
1273
1270
  var renderToolDetail = (colors, tool, flags) => {
@@ -1319,16 +1316,13 @@ var renderToolGroups = (colors, data) => {
1319
1316
  colors.green("Groups"),
1320
1317
  ...data.groups.map((entry) => ` ${label(entry).padEnd(width)} ${String(entry.total).padStart(countWidth)}`),
1321
1318
  "",
1322
- `${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.")
1323
1320
  ];
1324
1321
  };
1325
- var renderToolsData = (colors, data, flags, full) => {
1322
+ var renderToolsListData = (colors, data, flags, full) => {
1326
1323
  if (isToolGroupsListing(data)) {
1327
1324
  return renderToolGroups(colors, data);
1328
1325
  }
1329
- if (!isToolsListing(data)) {
1330
- return renderToolDetail(colors, data, flags);
1331
- }
1332
1326
  return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
1333
1327
  };
1334
1328
  var renderInvokeData = (colors, data, flags) => {
@@ -1514,15 +1508,17 @@ var renderSuccessData = (colors, command, data, options) => {
1514
1508
  return renderInitData(colors, data, flags);
1515
1509
  case "keygen":
1516
1510
  return renderKeygenData(colors, data, flags);
1517
- case "link":
1511
+ case "sessions link":
1518
1512
  return renderLinkData(colors, data, flags, options.qr);
1519
- case "ls":
1513
+ case "sessions ls":
1520
1514
  return renderLsData(colors, data, options.now ?? /* @__PURE__ */ new Date());
1521
- case "tools":
1522
- return renderToolsData(colors, data, flags, options.full);
1523
- case "invoke":
1515
+ case "tools ls":
1516
+ return renderToolsListData(colors, data, flags, options.full);
1517
+ case "tools describe":
1518
+ return renderToolDetail(colors, data, flags);
1519
+ case "tools call":
1524
1520
  return renderInvokeData(colors, data, flags);
1525
- case "revoke":
1521
+ case "sessions revoke":
1526
1522
  return renderRevokeData(colors, data);
1527
1523
  case "daemon run":
1528
1524
  return renderDaemonRunData(colors, data, flags);
@@ -575,9 +575,6 @@ var renderLsData = (colors, data, now) => {
575
575
  ...rows.map((row) => ` ${row.map((cell, index) => cell.padEnd(widths[index])).join(" ")}`)
576
576
  ];
577
577
  };
578
- var isToolsListing = (data) => {
579
- return typeof data === "object" && data !== null && Array.isArray(data.tools);
580
- };
581
578
  var isToolGroupsListing = (data) => {
582
579
  return typeof data === "object" && data !== null && Array.isArray(data.groups) && !Array.isArray(data.tools);
583
580
  };
@@ -595,7 +592,7 @@ var renderEmptyToolsLine = (data) => {
595
592
  }
596
593
  if (data.group !== void 0) {
597
594
  const match = data.filter === void 0 ? "" : ` match ${JSON.stringify(data.filter)}`;
598
- return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools --groups\` to see the session's groups.`;
595
+ return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools ls --groups\` to see the session's groups.`;
599
596
  }
600
597
  return data.filter === void 0 ? " No tools registered." : ` No tools match ${JSON.stringify(data.filter)}.`;
601
598
  };
@@ -677,7 +674,7 @@ var renderToolSummaryTable = (colors, data) => {
677
674
  ...grouped ? renderGroupedToolLines(colors, data.tools) : data.tools.flatMap((tool) => renderToolSummaryLines(tool, " ")),
678
675
  ...renderTruncationLine(data),
679
676
  "",
680
- "Run `appduct tools <name>` for a tool's full schema."
677
+ "Run `appduct tools describe <name>` for a tool's full schema."
681
678
  ];
682
679
  };
683
680
  var renderToolDetail = (colors, tool, flags) => {
@@ -729,16 +726,13 @@ var renderToolGroups = (colors, data) => {
729
726
  colors.green("Groups"),
730
727
  ...data.groups.map((entry) => ` ${label(entry).padEnd(width)} ${String(entry.total).padStart(countWidth)}`),
731
728
  "",
732
- `${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.")
729
+ `${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.")
733
730
  ];
734
731
  };
735
- var renderToolsData = (colors, data, flags, full) => {
732
+ var renderToolsListData = (colors, data, flags, full) => {
736
733
  if (isToolGroupsListing(data)) {
737
734
  return renderToolGroups(colors, data);
738
735
  }
739
- if (!isToolsListing(data)) {
740
- return renderToolDetail(colors, data, flags);
741
- }
742
736
  return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
743
737
  };
744
738
  var renderInvokeData = (colors, data, flags) => {
@@ -924,15 +918,17 @@ var renderSuccessData = (colors, command, data, options) => {
924
918
  return renderInitData(colors, data, flags);
925
919
  case "keygen":
926
920
  return renderKeygenData(colors, data, flags);
927
- case "link":
921
+ case "sessions link":
928
922
  return renderLinkData(colors, data, flags, options.qr);
929
- case "ls":
923
+ case "sessions ls":
930
924
  return renderLsData(colors, data, options.now ?? /* @__PURE__ */ new Date());
931
- case "tools":
932
- return renderToolsData(colors, data, flags, options.full);
933
- case "invoke":
925
+ case "tools ls":
926
+ return renderToolsListData(colors, data, flags, options.full);
927
+ case "tools describe":
928
+ return renderToolDetail(colors, data, flags);
929
+ case "tools call":
934
930
  return renderInvokeData(colors, data, flags);
935
- case "revoke":
931
+ case "sessions revoke":
936
932
  return renderRevokeData(colors, data);
937
933
  case "daemon run":
938
934
  return renderDaemonRunData(colors, data, flags);
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Route for `appduct events` — itself a router over the events verbs, so `events tail` loads only
3
+ * `tail.ts` (issue #96). cac matches only the noun (`cli/create-cli.ts`), so the verb arrives here
4
+ * as the first positional rather than as a cac command of its own.
5
+ *
6
+ * `ls` is reserved for the catalog issue #95 adds; until it lands, `events ls` falls through to
7
+ * `unknown` below like any other unrecognized verb, naming `tail`/`since` as the ones that exist.
8
+ */
9
+ export declare const route: import("../../router.js").Route;