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
@@ -0,0 +1,6 @@
1
+ /** Route for `appduct events tail` — loaded by `routes/events/index.ts`'s router only when it
2
+ * runs (issue #96; replaces the removed `appduct events` streaming form). `--follow` is accepted
3
+ * (declared at the `events` noun level in `create-cli.ts`) but never read here: the default
4
+ * behavior already follows, so the flag exists only for script readability. */
5
+ import type { Route } from "../../router.js";
6
+ export declare const route: Route;
@@ -1015,12 +1015,14 @@ var handleEventsSinceCommand = async (options, context) => {
1015
1015
  try {
1016
1016
  const since = await stream.call(RPC_METHODS2.eventsSince, {
1017
1017
  selector: options.selector,
1018
- since: options.since
1018
+ since: options.since,
1019
+ name: options.name,
1020
+ payloadMaxBytes: options.payloadMaxBytes
1019
1021
  });
1020
1022
  for (const event of since.events) {
1021
1023
  context.onEvent(event);
1022
1024
  }
1023
- context.onCursor?.(since.cursor);
1025
+ context.onCursor?.({ cursor: since.cursor, dropped: since.dropped, remaining: since.remaining });
1024
1026
  } finally {
1025
1027
  stream.close();
1026
1028
  }
@@ -1035,7 +1037,9 @@ var handleEventsCommand = async (options, context) => {
1035
1037
  try {
1036
1038
  await stream.call(RPC_METHODS2.eventsSubscribe, {
1037
1039
  sessionSelector: options.selector,
1038
- kinds: ["app_event"]
1040
+ kinds: ["app_event"],
1041
+ name: options.name,
1042
+ payloadMaxBytes: options.payloadMaxBytes
1039
1043
  });
1040
1044
  } catch (error) {
1041
1045
  stream.close();
@@ -1071,124 +1075,6 @@ var handleEventsCommand = async (options, context) => {
1071
1075
  };
1072
1076
  };
1073
1077
 
1074
- // src/errors.ts
1075
- var EXIT_CODE_BY_ERROR_TYPE = {
1076
- usage_error: 64,
1077
- validation_error: 65,
1078
- // EX_NOINPUT (66): "an input file did not exist or was not readable" — `doctor` throws this for a
1079
- // missing external tool or an unreadable/corrupt artifact, deliberately distinct from every other
1080
- // code here so a release pipeline can't mistake "we couldn't tell" for either a clean pass or an
1081
- // assertion failure (docs/tasks/08-appduct-doctor.md).
1082
- inspection_error: 66,
1083
- connection_error: 70,
1084
- session_error: 71,
1085
- tool_error: 72,
1086
- permission_error: 77,
1087
- internal_error: 1,
1088
- // `doctor --assert-present`/`--assert-absent`: the artifact was inspected successfully and the
1089
- // assertion did not hold. Distinct from `inspection_error` (66) — this means the answer is known
1090
- // and it's "no", not "couldn't tell" — and distinct from `internal_error` (1) so a caller can't
1091
- // conflate a normal assertion failure with an unexpected crash.
1092
- assertion_error: 3
1093
- };
1094
- var RPC_ERROR_EXIT_CLASS = {
1095
- no_session: "session_error",
1096
- ambiguous_session: "session_error",
1097
- unknown_session: "session_error",
1098
- session_not_active: "session_error",
1099
- session_suspended: "session_error",
1100
- tool_not_found: "tool_error",
1101
- tool_input_validation_error: "tool_error",
1102
- tool_output_validation_error: "tool_error",
1103
- tool_execution_error: "tool_error",
1104
- tool_serialization_error: "tool_error",
1105
- tool_timeout: "tool_error",
1106
- tool_cancelled: "tool_error",
1107
- policy_denied: "permission_error",
1108
- invalid_request: "validation_error"
1109
- };
1110
- var AppductCliError = class extends Error {
1111
- type;
1112
- details;
1113
- constructor(type, message, details) {
1114
- super(message);
1115
- this.name = "AppductCliError";
1116
- this.type = type;
1117
- this.details = details;
1118
- }
1119
- };
1120
- var usageError = (message, details) => {
1121
- return new AppductCliError("usage_error", message, details);
1122
- };
1123
- var isAppductCliError = (value) => {
1124
- return value instanceof AppductCliError;
1125
- };
1126
- var rpcErrorClass = (error) => {
1127
- const type = error.data?.type;
1128
- return type ? RPC_ERROR_EXIT_CLASS[type] : void 0;
1129
- };
1130
- var toCliError = (error) => {
1131
- if (isAppductCliError(error)) {
1132
- return {
1133
- type: error.type,
1134
- message: error.message,
1135
- details: error.details
1136
- };
1137
- }
1138
- if (error instanceof DaemonVersionMismatchError) {
1139
- return {
1140
- type: "connection_error",
1141
- message: error.message,
1142
- details: {
1143
- daemon_version: error.daemonVersion,
1144
- client_version: error.clientVersion,
1145
- session_count: error.sessionCount,
1146
- pending_link_count: error.pendingLinkCount
1147
- }
1148
- };
1149
- }
1150
- if (error instanceof DaemonRpcError && error.data?.type) {
1151
- return {
1152
- type: error.data.type,
1153
- message: error.message,
1154
- details: error.data.details
1155
- };
1156
- }
1157
- if (isDaemonUnreachableError(error)) {
1158
- return {
1159
- type: "connection_error",
1160
- message: error instanceof Error ? error.message : "The Appduct daemon is unreachable."
1161
- };
1162
- }
1163
- if (error instanceof Error) {
1164
- return {
1165
- type: "internal_error",
1166
- message: error.message
1167
- };
1168
- }
1169
- return {
1170
- type: "internal_error",
1171
- message: "An unexpected error occurred.",
1172
- details: error
1173
- };
1174
- };
1175
- var getExitCodeForError = (error) => {
1176
- if (isAppductCliError(error)) {
1177
- return EXIT_CODE_BY_ERROR_TYPE[error.type];
1178
- }
1179
- if (error instanceof DaemonVersionMismatchError) {
1180
- return EXIT_CODE_BY_ERROR_TYPE.connection_error;
1181
- }
1182
- if (error instanceof DaemonRpcError) {
1183
- const cliErrorClass = rpcErrorClass(error);
1184
- return EXIT_CODE_BY_ERROR_TYPE[cliErrorClass ?? "internal_error"];
1185
- }
1186
- if (isDaemonUnreachableError(error)) {
1187
- return EXIT_CODE_BY_ERROR_TYPE.connection_error;
1188
- }
1189
- return EXIT_CODE_BY_ERROR_TYPE.internal_error;
1190
- };
1191
-
1192
1078
  // src/output.ts
1193
1079
  import pc from "picocolors";
1194
1080
  import {
@@ -1315,9 +1201,6 @@ var renderLsData = (colors, data, now) => {
1315
1201
  ...rows.map((row) => ` ${row.map((cell, index) => cell.padEnd(widths[index])).join(" ")}`)
1316
1202
  ];
1317
1203
  };
1318
- var isToolsListing = (data) => {
1319
- return typeof data === "object" && data !== null && Array.isArray(data.tools);
1320
- };
1321
1204
  var isToolGroupsListing = (data) => {
1322
1205
  return typeof data === "object" && data !== null && Array.isArray(data.groups) && !Array.isArray(data.tools);
1323
1206
  };
@@ -1335,7 +1218,7 @@ var renderEmptyToolsLine = (data) => {
1335
1218
  }
1336
1219
  if (data.group !== void 0) {
1337
1220
  const match = data.filter === void 0 ? "" : ` match ${JSON.stringify(data.filter)}`;
1338
- return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools --groups\` to see the session's groups.`;
1221
+ return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools ls --groups\` to see the session's groups.`;
1339
1222
  }
1340
1223
  return data.filter === void 0 ? " No tools registered." : ` No tools match ${JSON.stringify(data.filter)}.`;
1341
1224
  };
@@ -1417,7 +1300,7 @@ var renderToolSummaryTable = (colors, data) => {
1417
1300
  ...grouped ? renderGroupedToolLines(colors, data.tools) : data.tools.flatMap((tool) => renderToolSummaryLines(tool, " ")),
1418
1301
  ...renderTruncationLine(data),
1419
1302
  "",
1420
- "Run `appduct tools <name>` for a tool's full schema."
1303
+ "Run `appduct tools describe <name>` for a tool's full schema."
1421
1304
  ];
1422
1305
  };
1423
1306
  var renderToolDetail = (colors, tool, flags) => {
@@ -1469,16 +1352,13 @@ var renderToolGroups = (colors, data) => {
1469
1352
  colors.green("Groups"),
1470
1353
  ...data.groups.map((entry) => ` ${label(entry).padEnd(width)} ${String(entry.total).padStart(countWidth)}`),
1471
1354
  "",
1472
- `${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.")
1355
+ `${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.")
1473
1356
  ];
1474
1357
  };
1475
- var renderToolsData = (colors, data, flags, full) => {
1358
+ var renderToolsListData = (colors, data, flags, full) => {
1476
1359
  if (isToolGroupsListing(data)) {
1477
1360
  return renderToolGroups(colors, data);
1478
1361
  }
1479
- if (!isToolsListing(data)) {
1480
- return renderToolDetail(colors, data, flags);
1481
- }
1482
1362
  return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
1483
1363
  };
1484
1364
  var renderInvokeData = (colors, data, flags) => {
@@ -1664,15 +1544,17 @@ var renderSuccessData = (colors, command, data, options) => {
1664
1544
  return renderInitData(colors, data, flags);
1665
1545
  case "keygen":
1666
1546
  return renderKeygenData(colors, data, flags);
1667
- case "link":
1547
+ case "sessions link":
1668
1548
  return renderLinkData(colors, data, flags, options.qr);
1669
- case "ls":
1549
+ case "sessions ls":
1670
1550
  return renderLsData(colors, data, options.now ?? /* @__PURE__ */ new Date());
1671
- case "tools":
1672
- return renderToolsData(colors, data, flags, options.full);
1673
- case "invoke":
1551
+ case "tools ls":
1552
+ return renderToolsListData(colors, data, flags, options.full);
1553
+ case "tools describe":
1554
+ return renderToolDetail(colors, data, flags);
1555
+ case "tools call":
1674
1556
  return renderInvokeData(colors, data, flags);
1675
- case "revoke":
1557
+ case "sessions revoke":
1676
1558
  return renderRevokeData(colors, data);
1677
1559
  case "daemon run":
1678
1560
  return renderDaemonRunData(colors, data, flags);
@@ -1742,25 +1624,158 @@ var renderEventLine = (event, flags) => {
1742
1624
  const dataSuffix = event.data === void 0 ? "" : ` ${formatJson(event.data, flags)}`;
1743
1625
  return `${colors.dim(timestamp)} ${colors.green(event.kind)}${target ? ` ${target}` : ""}${dataSuffix}`;
1744
1626
  };
1745
- var renderEventsCursorLine = (cursor, flags) => {
1746
- if (flags.json) {
1747
- return JSON.stringify({ cursor });
1627
+
1628
+ // src/errors.ts
1629
+ var EXIT_CODE_BY_ERROR_TYPE = {
1630
+ usage_error: 64,
1631
+ validation_error: 65,
1632
+ // EX_NOINPUT (66): "an input file did not exist or was not readable" — `doctor` throws this for a
1633
+ // missing external tool or an unreadable/corrupt artifact, deliberately distinct from every other
1634
+ // code here so a release pipeline can't mistake "we couldn't tell" for either a clean pass or an
1635
+ // assertion failure (docs/tasks/08-appduct-doctor.md).
1636
+ inspection_error: 66,
1637
+ connection_error: 70,
1638
+ session_error: 71,
1639
+ tool_error: 72,
1640
+ permission_error: 77,
1641
+ internal_error: 1,
1642
+ // `doctor --assert-present`/`--assert-absent`: the artifact was inspected successfully and the
1643
+ // assertion did not hold. Distinct from `inspection_error` (66) — this means the answer is known
1644
+ // and it's "no", not "couldn't tell" — and distinct from `internal_error` (1) so a caller can't
1645
+ // conflate a normal assertion failure with an unexpected crash.
1646
+ assertion_error: 3
1647
+ };
1648
+ var RPC_ERROR_EXIT_CLASS = {
1649
+ no_session: "session_error",
1650
+ ambiguous_session: "session_error",
1651
+ unknown_session: "session_error",
1652
+ session_not_active: "session_error",
1653
+ session_suspended: "session_error",
1654
+ tool_not_found: "tool_error",
1655
+ tool_input_validation_error: "tool_error",
1656
+ tool_output_validation_error: "tool_error",
1657
+ tool_execution_error: "tool_error",
1658
+ tool_serialization_error: "tool_error",
1659
+ tool_timeout: "tool_error",
1660
+ tool_cancelled: "tool_error",
1661
+ policy_denied: "permission_error",
1662
+ invalid_request: "validation_error"
1663
+ };
1664
+ var AppductCliError = class extends Error {
1665
+ type;
1666
+ details;
1667
+ constructor(type, message, details) {
1668
+ super(message);
1669
+ this.name = "AppductCliError";
1670
+ this.type = type;
1671
+ this.details = details;
1748
1672
  }
1749
- const colors = pc.createColors(flags.color);
1750
- return colors.dim(`cursor: ${cursor} (pass --since ${cursor} to resume from here)`);
1673
+ };
1674
+ var usageError = (message, details) => {
1675
+ return new AppductCliError("usage_error", message, details);
1676
+ };
1677
+ var isAppductCliError = (value) => {
1678
+ return value instanceof AppductCliError;
1679
+ };
1680
+ var rpcErrorClass = (error) => {
1681
+ const type = error.data?.type;
1682
+ return type ? RPC_ERROR_EXIT_CLASS[type] : void 0;
1683
+ };
1684
+ var toCliError = (error) => {
1685
+ if (isAppductCliError(error)) {
1686
+ return {
1687
+ type: error.type,
1688
+ message: error.message,
1689
+ details: error.details
1690
+ };
1691
+ }
1692
+ if (error instanceof DaemonVersionMismatchError) {
1693
+ return {
1694
+ type: "connection_error",
1695
+ message: error.message,
1696
+ details: {
1697
+ daemon_version: error.daemonVersion,
1698
+ client_version: error.clientVersion,
1699
+ session_count: error.sessionCount,
1700
+ pending_link_count: error.pendingLinkCount
1701
+ }
1702
+ };
1703
+ }
1704
+ if (error instanceof DaemonRpcError && error.data?.type) {
1705
+ return {
1706
+ type: error.data.type,
1707
+ message: error.message,
1708
+ details: error.data.details
1709
+ };
1710
+ }
1711
+ if (isDaemonUnreachableError(error)) {
1712
+ return {
1713
+ type: "connection_error",
1714
+ message: error instanceof Error ? error.message : "The Appduct daemon is unreachable."
1715
+ };
1716
+ }
1717
+ if (error instanceof Error) {
1718
+ return {
1719
+ type: "internal_error",
1720
+ message: error.message
1721
+ };
1722
+ }
1723
+ return {
1724
+ type: "internal_error",
1725
+ message: "An unexpected error occurred.",
1726
+ details: error
1727
+ };
1728
+ };
1729
+ var getExitCodeForError = (error) => {
1730
+ if (isAppductCliError(error)) {
1731
+ return EXIT_CODE_BY_ERROR_TYPE[error.type];
1732
+ }
1733
+ if (error instanceof DaemonVersionMismatchError) {
1734
+ return EXIT_CODE_BY_ERROR_TYPE.connection_error;
1735
+ }
1736
+ if (error instanceof DaemonRpcError) {
1737
+ const cliErrorClass = rpcErrorClass(error);
1738
+ return EXIT_CODE_BY_ERROR_TYPE[cliErrorClass ?? "internal_error"];
1739
+ }
1740
+ if (isDaemonUnreachableError(error)) {
1741
+ return EXIT_CODE_BY_ERROR_TYPE.connection_error;
1742
+ }
1743
+ return EXIT_CODE_BY_ERROR_TYPE.internal_error;
1751
1744
  };
1752
1745
 
1753
1746
  // src/cli/command-options.ts
1754
- var parseNonNegativeIntegerOption = (value, flagName) => {
1747
+ var parsePositiveIntegerOption = (value, flagName) => {
1755
1748
  if (value === void 0) {
1756
1749
  return void 0;
1757
1750
  }
1758
1751
  const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : Number.NaN;
1759
- if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed < 0) {
1760
- throw usageError(`"${flagName}" must be a non-negative integer.`);
1752
+ if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed <= 0) {
1753
+ throw usageError(`"${flagName}" must be a positive integer.`);
1761
1754
  }
1762
1755
  return parsed;
1763
1756
  };
1757
+ var readTextOption = (argv, value, flagName) => {
1758
+ if (value === void 0) {
1759
+ return void 0;
1760
+ }
1761
+ if (typeof value === "boolean") {
1762
+ throw usageError(`"${flagName}" requires a value.`);
1763
+ }
1764
+ let raw;
1765
+ for (let index = 0; index < argv.length; index += 1) {
1766
+ const token = argv[index];
1767
+ if (token === "--") {
1768
+ break;
1769
+ }
1770
+ if (token === flagName && index + 1 < argv.length) {
1771
+ raw = argv[index + 1];
1772
+ index += 1;
1773
+ } else if (token.startsWith(`${flagName}=`)) {
1774
+ raw = token.slice(flagName.length + 1);
1775
+ }
1776
+ }
1777
+ return raw ?? String(Array.isArray(value) ? value.at(-1) : value);
1778
+ };
1764
1779
  var splitOptionalSelector = (args, commandUsage) => {
1765
1780
  if (args.length > 1) {
1766
1781
  throw usageError(`Usage: ${commandUsage} (too many arguments).`);
@@ -1874,33 +1889,33 @@ var guarded = (context) => {
1874
1889
  };
1875
1890
  };
1876
1891
 
1877
- // src/cli/routes/events.ts
1892
+ // src/cli/routes/events/shared-options.ts
1893
+ var parseEventsFilterFlags = (context) => {
1894
+ const { options } = context;
1895
+ return {
1896
+ name: readTextOption(context.argv, options.name, "--name"),
1897
+ payloadMaxBytes: parsePositiveIntegerOption(options.payloadMaxBytes, "--payload-max-bytes")
1898
+ };
1899
+ };
1900
+
1901
+ // src/cli/routes/events/tail.ts
1878
1902
  var route = async (context) => {
1879
- const { options, stateDir, env } = context;
1880
- const follow = Boolean(options.follow);
1903
+ const { stateDir, env } = context;
1881
1904
  return executeHostedCommand(
1882
1905
  commandName(context),
1883
- // All argument parsing happens inside the handler (not the route body) so
1884
- // `executeHostedCommand`'s own try/catch renders a bad argument as a normal usage_error
1885
- // instead of an uncaught rejection, and before the version check so a typo never waits on
1886
- // the daemon.
1906
+ // Argument parsing runs inside the handler (not the route body) so `executeHostedCommand`'s
1907
+ // own try/catch renders a bad argument as a normal usage_error instead of an uncaught
1908
+ // rejection, and before the version check so a typo never waits on the daemon.
1887
1909
  () => {
1888
- const { selector } = splitOptionalSelector(context.args, "events [selector]");
1889
- const since = parseNonNegativeIntegerOption(options.since, "--since");
1890
- if (since !== void 0 && follow) {
1891
- throw usageError('"--since" is a one-shot pull and cannot be combined with "--follow".');
1892
- }
1910
+ const { selector } = splitOptionalSelector(context.args, "events tail [selector]");
1911
+ const { name, payloadMaxBytes } = parseEventsFilterFlags(context);
1893
1912
  return guarded(context)(
1894
1913
  () => handleEventsCommand(
1895
- { selector, since },
1914
+ { selector, name, payloadMaxBytes },
1896
1915
  {
1897
1916
  stateDir,
1898
1917
  onEvent: (event) => {
1899
1918
  env.stdout.write(`${renderEventLine(event, env.flags)}
1900
- `);
1901
- },
1902
- onCursor: (cursor) => {
1903
- env.stdout.write(`${renderEventsCursorLine(cursor, env.flags)}
1904
1919
  `);
1905
1920
  }
1906
1921
  }
@@ -841,10 +841,10 @@ Run \`appduct init --scheme <scheme>\` with the scheme your app registers for de
841
841
  nextSteps: [
842
842
  'Add `import "@appduct/react-native/auto";` to your app entry (index.js / App.tsx) \u2014 it is what starts the in-app agent endpoint.',
843
843
  `Add the Appduct MCP server entry to your agent's MCP config. "--scheme ${scheme}" keeps that entry self-contained; ${SCHEME_ENV_VAR} and this ${PROJECT_CONFIG_RELATIVE_PATH} work too.`,
844
- "With the app running, pair a device: `appduct link --open ios-sim` (or `--open android`).",
844
+ "With the app running, pair a device: `appduct sessions link --open ios-sim` (or `--open android`).",
845
845
  ...origin === void 0 ? [] : [`Scheme "${scheme}" was read from ${origin}.`],
846
846
  ...iosAppId === void 0 && androidAppId === void 0 ? [
847
- "Delivering to a physical iPhone (`--open ios-device`) or an Android device/emulator (`--open android`) needs the installed app's id: run `appduct init --ios-app-id <id> --android-app-id <id>`, or pass --app-id on `appduct link`."
847
+ "Delivering to a physical iPhone (`--open ios-device`) or an Android device/emulator (`--open android`) needs the installed app's id: run `appduct init --ios-app-id <id> --android-app-id <id>`, or pass --app-id on `appduct sessions link`."
848
848
  ] : [],
849
849
  `This file is safe to commit \u2014 it holds only "scheme" and "appId". Do not point --state-dir at this directory: the state dir holds the daemon's private key and audit log, which must never be committed.`
850
850
  ]
@@ -978,9 +978,6 @@ var renderLsData = (colors, data, now) => {
978
978
  ...rows.map((row) => ` ${row.map((cell, index) => cell.padEnd(widths[index])).join(" ")}`)
979
979
  ];
980
980
  };
981
- var isToolsListing = (data) => {
982
- return typeof data === "object" && data !== null && Array.isArray(data.tools);
983
- };
984
981
  var isToolGroupsListing = (data) => {
985
982
  return typeof data === "object" && data !== null && Array.isArray(data.groups) && !Array.isArray(data.tools);
986
983
  };
@@ -998,7 +995,7 @@ var renderEmptyToolsLine = (data) => {
998
995
  }
999
996
  if (data.group !== void 0) {
1000
997
  const match = data.filter === void 0 ? "" : ` match ${JSON.stringify(data.filter)}`;
1001
- return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools --groups\` to see the session's groups.`;
998
+ return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools ls --groups\` to see the session's groups.`;
1002
999
  }
1003
1000
  return data.filter === void 0 ? " No tools registered." : ` No tools match ${JSON.stringify(data.filter)}.`;
1004
1001
  };
@@ -1080,7 +1077,7 @@ var renderToolSummaryTable = (colors, data) => {
1080
1077
  ...grouped ? renderGroupedToolLines(colors, data.tools) : data.tools.flatMap((tool) => renderToolSummaryLines(tool, " ")),
1081
1078
  ...renderTruncationLine(data),
1082
1079
  "",
1083
- "Run `appduct tools <name>` for a tool's full schema."
1080
+ "Run `appduct tools describe <name>` for a tool's full schema."
1084
1081
  ];
1085
1082
  };
1086
1083
  var renderToolDetail = (colors, tool, flags) => {
@@ -1132,16 +1129,13 @@ var renderToolGroups = (colors, data) => {
1132
1129
  colors.green("Groups"),
1133
1130
  ...data.groups.map((entry) => ` ${label(entry).padEnd(width)} ${String(entry.total).padStart(countWidth)}`),
1134
1131
  "",
1135
- `${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.")
1132
+ `${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.")
1136
1133
  ];
1137
1134
  };
1138
- var renderToolsData = (colors, data, flags, full) => {
1135
+ var renderToolsListData = (colors, data, flags, full) => {
1139
1136
  if (isToolGroupsListing(data)) {
1140
1137
  return renderToolGroups(colors, data);
1141
1138
  }
1142
- if (!isToolsListing(data)) {
1143
- return renderToolDetail(colors, data, flags);
1144
- }
1145
1139
  return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
1146
1140
  };
1147
1141
  var renderInvokeData = (colors, data, flags) => {
@@ -1327,15 +1321,17 @@ var renderSuccessData = (colors, command, data, options) => {
1327
1321
  return renderInitData(colors, data, flags);
1328
1322
  case "keygen":
1329
1323
  return renderKeygenData(colors, data, flags);
1330
- case "link":
1324
+ case "sessions link":
1331
1325
  return renderLinkData(colors, data, flags, options.qr);
1332
- case "ls":
1326
+ case "sessions ls":
1333
1327
  return renderLsData(colors, data, options.now ?? /* @__PURE__ */ new Date());
1334
- case "tools":
1335
- return renderToolsData(colors, data, flags, options.full);
1336
- case "invoke":
1328
+ case "tools ls":
1329
+ return renderToolsListData(colors, data, flags, options.full);
1330
+ case "tools describe":
1331
+ return renderToolDetail(colors, data, flags);
1332
+ case "tools call":
1337
1333
  return renderInvokeData(colors, data, flags);
1338
- case "revoke":
1334
+ case "sessions revoke":
1339
1335
  return renderRevokeData(colors, data);
1340
1336
  case "daemon run":
1341
1337
  return renderDaemonRunData(colors, data, flags);
@@ -427,9 +427,6 @@ var renderLsData = (colors, data, now) => {
427
427
  ...rows.map((row) => ` ${row.map((cell, index) => cell.padEnd(widths[index])).join(" ")}`)
428
428
  ];
429
429
  };
430
- var isToolsListing = (data) => {
431
- return typeof data === "object" && data !== null && Array.isArray(data.tools);
432
- };
433
430
  var isToolGroupsListing = (data) => {
434
431
  return typeof data === "object" && data !== null && Array.isArray(data.groups) && !Array.isArray(data.tools);
435
432
  };
@@ -447,7 +444,7 @@ var renderEmptyToolsLine = (data) => {
447
444
  }
448
445
  if (data.group !== void 0) {
449
446
  const match = data.filter === void 0 ? "" : ` match ${JSON.stringify(data.filter)}`;
450
- return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools --groups\` to see the session's groups.`;
447
+ return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools ls --groups\` to see the session's groups.`;
451
448
  }
452
449
  return data.filter === void 0 ? " No tools registered." : ` No tools match ${JSON.stringify(data.filter)}.`;
453
450
  };
@@ -529,7 +526,7 @@ var renderToolSummaryTable = (colors, data) => {
529
526
  ...grouped ? renderGroupedToolLines(colors, data.tools) : data.tools.flatMap((tool) => renderToolSummaryLines(tool, " ")),
530
527
  ...renderTruncationLine(data),
531
528
  "",
532
- "Run `appduct tools <name>` for a tool's full schema."
529
+ "Run `appduct tools describe <name>` for a tool's full schema."
533
530
  ];
534
531
  };
535
532
  var renderToolDetail = (colors, tool, flags) => {
@@ -581,16 +578,13 @@ var renderToolGroups = (colors, data) => {
581
578
  colors.green("Groups"),
582
579
  ...data.groups.map((entry) => ` ${label(entry).padEnd(width)} ${String(entry.total).padStart(countWidth)}`),
583
580
  "",
584
- `${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.")
581
+ `${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.")
585
582
  ];
586
583
  };
587
- var renderToolsData = (colors, data, flags, full) => {
584
+ var renderToolsListData = (colors, data, flags, full) => {
588
585
  if (isToolGroupsListing(data)) {
589
586
  return renderToolGroups(colors, data);
590
587
  }
591
- if (!isToolsListing(data)) {
592
- return renderToolDetail(colors, data, flags);
593
- }
594
588
  return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
595
589
  };
596
590
  var renderInvokeData = (colors, data, flags) => {
@@ -776,15 +770,17 @@ var renderSuccessData = (colors, command, data, options) => {
776
770
  return renderInitData(colors, data, flags);
777
771
  case "keygen":
778
772
  return renderKeygenData(colors, data, flags);
779
- case "link":
773
+ case "sessions link":
780
774
  return renderLinkData(colors, data, flags, options.qr);
781
- case "ls":
775
+ case "sessions ls":
782
776
  return renderLsData(colors, data, options.now ?? /* @__PURE__ */ new Date());
783
- case "tools":
784
- return renderToolsData(colors, data, flags, options.full);
785
- case "invoke":
777
+ case "tools ls":
778
+ return renderToolsListData(colors, data, flags, options.full);
779
+ case "tools describe":
780
+ return renderToolDetail(colors, data, flags);
781
+ case "tools call":
786
782
  return renderInvokeData(colors, data, flags);
787
- case "revoke":
783
+ case "sessions revoke":
788
784
  return renderRevokeData(colors, data);
789
785
  case "daemon run":
790
786
  return renderDaemonRunData(colors, data, flags);