@ashx-j/lunr 0.2.19 → 0.2.20

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 (170) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +2 -2
  3. package/dist/builtin-extensions/index.d.ts.map +1 -1
  4. package/dist/builtin-extensions/index.js +0 -2
  5. package/dist/builtin-extensions/index.js.map +1 -1
  6. package/dist/builtin-extensions/pi-intercom/broker/spawn.d.ts +6 -4
  7. package/dist/builtin-extensions/pi-intercom/broker/spawn.d.ts.map +1 -1
  8. package/dist/builtin-extensions/pi-intercom/broker/spawn.js +93 -49
  9. package/dist/builtin-extensions/pi-intercom/broker/spawn.js.map +1 -1
  10. package/dist/builtin-extensions/pi-intercom/index.d.ts.map +1 -1
  11. package/dist/builtin-extensions/pi-intercom/index.js +351 -351
  12. package/dist/builtin-extensions/pi-intercom/index.js.map +1 -1
  13. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +2 -1
  14. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  15. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +80 -43
  16. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  17. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts +18 -8
  18. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
  19. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +36 -11
  20. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
  21. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +4 -3
  22. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
  23. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +21 -12
  24. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
  25. package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.d.ts +7 -1
  26. package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.d.ts.map +1 -1
  27. package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js +225 -15
  28. package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js.map +1 -1
  29. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.d.ts +29 -0
  30. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.d.ts.map +1 -0
  31. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.js +179 -0
  32. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.js.map +1 -0
  33. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.d.ts +89 -0
  34. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.d.ts.map +1 -0
  35. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.js +541 -0
  36. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.js.map +1 -0
  37. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts +9 -1
  38. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts.map +1 -1
  39. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js +34 -9
  40. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js.map +1 -1
  41. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.d.ts.map +1 -1
  42. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.js +1 -2
  43. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.js.map +1 -1
  44. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts +2 -1
  45. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts.map +1 -1
  46. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js +35 -8
  47. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js.map +1 -1
  48. package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.d.ts +1 -1
  49. package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.d.ts.map +1 -1
  50. package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.js +3 -3
  51. package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.js.map +1 -1
  52. package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.d.ts +1 -0
  53. package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.d.ts.map +1 -1
  54. package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.js +54 -38
  55. package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.js.map +1 -1
  56. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts +3 -6
  57. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts.map +1 -1
  58. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js +64 -5
  59. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js.map +1 -1
  60. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.d.ts.map +1 -1
  61. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js +1 -0
  62. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js.map +1 -1
  63. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
  64. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +21 -8
  65. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
  66. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  67. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +62 -16
  68. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
  69. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts +2 -0
  70. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts.map +1 -1
  71. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js +75 -18
  72. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js.map +1 -1
  73. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts +13 -1
  74. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts.map +1 -1
  75. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js +67 -11
  76. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js.map +1 -1
  77. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts.map +1 -1
  78. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js +5 -2
  79. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js.map +1 -1
  80. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
  81. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js +13 -3
  82. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
  83. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts +3 -0
  84. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts.map +1 -1
  85. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js +68 -11
  86. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js.map +1 -1
  87. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts +12 -1
  88. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts.map +1 -1
  89. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js +21 -2
  90. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js.map +1 -1
  91. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +16 -4
  92. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
  93. package/dist/builtin-extensions/pi-subagents/src/shared/types.js +1 -1
  94. package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
  95. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts +2 -0
  96. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
  97. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +24 -6
  98. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
  99. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +44 -4
  100. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
  101. package/dist/builtin-extensions/pi-subagents/src/tui/render.js +227 -133
  102. package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
  103. package/dist/builtin-extensions/pi-subagents/src/watchdog/register-main.d.ts.map +1 -1
  104. package/dist/builtin-extensions/pi-subagents/src/watchdog/register-main.js +1 -1
  105. package/dist/builtin-extensions/pi-subagents/src/watchdog/register-main.js.map +1 -1
  106. package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.d.ts +2 -13
  107. package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.d.ts.map +1 -1
  108. package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.js +5 -91
  109. package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.js.map +1 -1
  110. package/dist/core/permissions.d.ts +1 -0
  111. package/dist/core/permissions.d.ts.map +1 -1
  112. package/dist/core/permissions.js +8 -4
  113. package/dist/core/permissions.js.map +1 -1
  114. package/dist/core/plan-mode.d.ts.map +1 -1
  115. package/dist/core/plan-mode.js +0 -5
  116. package/dist/core/plan-mode.js.map +1 -1
  117. package/dist/core/runtime-bridges.d.ts.map +1 -1
  118. package/dist/core/runtime-bridges.js +0 -2
  119. package/dist/core/runtime-bridges.js.map +1 -1
  120. package/dist/core/subagent-cancellation.d.ts +21 -0
  121. package/dist/core/subagent-cancellation.d.ts.map +1 -0
  122. package/dist/core/subagent-cancellation.js +53 -0
  123. package/dist/core/subagent-cancellation.js.map +1 -0
  124. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  125. package/dist/modes/interactive/components/assistant-message.js +12 -18
  126. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  127. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  128. package/dist/modes/interactive/components/tool-execution.js +12 -0
  129. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  130. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  131. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  132. package/dist/modes/interactive/interactive-mode.js +29 -0
  133. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  134. package/dist/node-runtime/{agent-session-services-35WNVGMR.js → agent-session-services-75JKASCW.js} +3 -3
  135. package/dist/node-runtime/{builtin-extensions-322XDDEM.js → builtin-extensions-X4JMM4ZS.js} +2 -2
  136. package/dist/node-runtime/{chunk-XATUM2HK.js → chunk-25I2BHAA.js} +1 -1
  137. package/dist/node-runtime/{chunk-MCUNIRD5.js → chunk-46ECNOLF.js} +477 -246
  138. package/dist/node-runtime/{chunk-J26TSGDL.js → chunk-6N22HULO.js} +8 -5
  139. package/dist/node-runtime/{chunk-TFBIJTM3.js → chunk-AL2FMKKM.js} +7 -7
  140. package/dist/node-runtime/chunk-AOFXZQKA.js +24 -0
  141. package/dist/node-runtime/chunk-BBUVIEZB.js +51 -0
  142. package/dist/node-runtime/{chunk-ZRCBN365.js → chunk-ELWEXVO5.js} +7 -7
  143. package/dist/node-runtime/{chunk-ATGA2WLC.js → chunk-JYNNB7DU.js} +397 -34
  144. package/dist/node-runtime/{chunk-4FX25LWP.js → chunk-K3646JTM.js} +16 -117
  145. package/dist/node-runtime/{chunk-PNJSG3IZ.js → chunk-LTYWTR3V.js} +1 -369
  146. package/dist/node-runtime/{chunk-TXHKBRHZ.js → chunk-QKFMBRAL.js} +45 -31
  147. package/dist/node-runtime/{command-DWUM5X3U.js → command-RBTRL55A.js} +1 -1
  148. package/dist/node-runtime/{gateway-UZXMFGWY.js → gateway-L4ANRTVE.js} +2 -2
  149. package/dist/node-runtime/index.js +9 -8
  150. package/dist/node-runtime/{interactive-mode-QT5IKGQ5.js → interactive-mode-HPUNH7SV.js} +5 -4
  151. package/dist/node-runtime/{lunr-cron-QPBTKBGI.js → lunr-cron-NNYTWTGF.js} +2 -2
  152. package/dist/node-runtime/main.js +7 -7
  153. package/dist/node-runtime/{pi-intercom-EEMBGQID.js → pi-intercom-DDQMRNPJ.js} +96 -76
  154. package/dist/node-runtime/{pi-subagents-7YJ3I4VE.js → pi-subagents-T5WMMLBB.js} +1040 -318
  155. package/dist/node-runtime/rpc-entry.js +7 -7
  156. package/dist/node-runtime/{runtime-bridges-3RKBDLNA.js → runtime-bridges-NJQERQ72.js} +2 -4
  157. package/dist/node-runtime/{subagent-executor-5Q5A4HJ2.js → subagent-executor-SRFC26SJ.js} +168 -249
  158. package/docs/features.md +17 -3
  159. package/docs/keybindings.md +3 -1
  160. package/docs/settings.md +1 -1
  161. package/package.json +4 -4
  162. package/dist/builtin-extensions/lunr-settings-tools.d.ts +0 -4
  163. package/dist/builtin-extensions/lunr-settings-tools.d.ts.map +0 -1
  164. package/dist/builtin-extensions/lunr-settings-tools.js +0 -120
  165. package/dist/builtin-extensions/lunr-settings-tools.js.map +0 -1
  166. package/dist/core/settings-tools-bridge.d.ts +0 -35
  167. package/dist/core/settings-tools-bridge.d.ts.map +0 -1
  168. package/dist/core/settings-tools-bridge.js +0 -56
  169. package/dist/core/settings-tools-bridge.js.map +0 -1
  170. package/dist/node-runtime/chunk-3NMWLTPV.js +0 -64
@@ -3,7 +3,7 @@ import { randomUUID } from "crypto";
3
3
  import { Type } from "typebox";
4
4
  import { Text } from "@ashx-j/lunr-tui";
5
5
  import { IntercomClient } from "./broker/client.js";
6
- import { spawnBrokerIfNeeded } from "./broker/spawn.js";
6
+ import { isNativeSupervisorChannelActive, spawnBrokerIfNeeded } from "./broker/spawn.js";
7
7
  import { SessionListOverlay } from "./ui/session-list.js";
8
8
  import { ComposeOverlay } from "./ui/compose.js";
9
9
  import { InlineMessageComponent } from "./ui/inline-message.js";
@@ -875,6 +875,9 @@ export default function piIntercomExtension(pi) {
875
875
  agentRunning = false;
876
876
  activeTools.clear();
877
877
  startNamePoll();
878
+ if (isNativeSupervisorChannelActive()) {
879
+ return;
880
+ }
878
881
  const startupGeneration = runtimeGeneration;
879
882
  startupConnectTimer = setTimeout(() => {
880
883
  startupConnectTimer = null;
@@ -899,67 +902,62 @@ export default function piIntercomExtension(pi) {
899
902
  ...(error ? { error: getErrorMessage(error) } : {}),
900
903
  });
901
904
  }
905
+ const resultDeliveries = new Map();
906
+ const acknowledgedResults = [];
902
907
  function relaySubagentIntercomPayload(payload, options) {
903
908
  const parsed = parseSubagentIntercomPayload(payload);
904
909
  if (!parsed)
905
910
  return;
906
911
  const relayGeneration = runtimeGeneration;
907
- void (async () => {
908
- const relayStillLive = () => !runtimeStarted || Boolean(getLiveContext(runtimeContext, relayGeneration));
909
- if (!relayStillLive()) {
910
- return;
911
- }
912
- if (currentSessionTargetMatches(parsed.to)) {
913
- deliverLocalSubagentRelayMessage(options.sender, options.status, parsed.message);
914
- if (options.acknowledge)
915
- emitResultDelivery(parsed.requestId, true);
916
- return;
917
- }
918
- let activeClient;
919
- let target;
920
- try {
921
- activeClient = await ensureConnected("background");
922
- target = await resolveSessionTarget(activeClient, parsed.to) ?? parsed.to;
923
- }
924
- catch (error) {
925
- if (!relayStillLive())
926
- return;
927
- recordSubagentDeliveryError(options.errorEntryType, parsed.to, parsed.message, error);
928
- if (options.acknowledge)
929
- emitResultDelivery(parsed.requestId, false, error);
930
- return;
931
- }
932
- if (!relayStillLive()) {
933
- return;
934
- }
935
- if (currentSessionTargetMatches(parsed.to, target, activeClient)) {
936
- deliverLocalSubagentRelayMessage(options.sender, options.status, parsed.message);
937
- if (options.acknowledge)
938
- emitResultDelivery(parsed.requestId, true);
939
- return;
940
- }
941
- try {
942
- const result = await activeClient.send(target, { text: parsed.message });
943
- if (!relayStillLive())
944
- return;
945
- if (!result.delivered) {
946
- const error = new Error(result.reason ?? "Session may not exist or has disconnected.");
947
- recordSubagentDeliveryError(options.errorEntryType, parsed.to, parsed.message, error);
948
- if (options.acknowledge)
949
- emitResultDelivery(parsed.requestId, false, error);
950
- return;
912
+ const key = options.acknowledge && parsed.requestId ? `${relayGeneration}:${parsed.requestId}` : undefined;
913
+ let delivery = key ? resultDeliveries.get(key) : undefined;
914
+ if (!delivery) {
915
+ delivery = (async () => {
916
+ const relayStillLive = () => !runtimeStarted || Boolean(getLiveContext(runtimeContext, relayGeneration));
917
+ try {
918
+ if (!relayStillLive())
919
+ return false;
920
+ if (currentSessionTargetMatches(parsed.to)) {
921
+ deliverLocalSubagentRelayMessage(options.sender, options.status, parsed.message);
922
+ return true;
923
+ }
924
+ const activeClient = await ensureConnected("background");
925
+ const target = await resolveSessionTarget(activeClient, parsed.to) ?? parsed.to;
926
+ if (!relayStillLive())
927
+ return false;
928
+ if (currentSessionTargetMatches(parsed.to, target, activeClient)) {
929
+ deliverLocalSubagentRelayMessage(options.sender, options.status, parsed.message);
930
+ return true;
931
+ }
932
+ const result = await activeClient.send(target, { text: parsed.message });
933
+ if (!result.delivered)
934
+ throw new Error(result.reason ?? "Session may not exist or has disconnected.");
935
+ return true;
951
936
  }
952
- if (options.acknowledge)
953
- emitResultDelivery(parsed.requestId, true);
954
- }
955
- catch (error) {
956
- if (!relayStillLive())
957
- return;
958
- recordSubagentDeliveryError(options.errorEntryType, parsed.to, parsed.message, error);
959
- if (options.acknowledge)
960
- emitResultDelivery(parsed.requestId, false, error);
937
+ catch (error) {
938
+ if (relayStillLive())
939
+ recordSubagentDeliveryError(options.errorEntryType, parsed.to, parsed.message, error);
940
+ return false;
941
+ }
942
+ })();
943
+ if (key) {
944
+ resultDeliveries.set(key, delivery);
945
+ void delivery.then((delivered) => {
946
+ if (!delivered) {
947
+ if (resultDeliveries.get(key) === delivery)
948
+ resultDeliveries.delete(key);
949
+ return;
950
+ }
951
+ acknowledgedResults.push(key);
952
+ while (acknowledgedResults.length > 1024)
953
+ resultDeliveries.delete(acknowledgedResults.shift());
954
+ });
961
955
  }
962
- })();
956
+ }
957
+ void delivery.then((delivered) => {
958
+ if (options.acknowledge)
959
+ emitResultDelivery(parsed.requestId, delivered);
960
+ });
963
961
  }
964
962
  const unsubscribeSubagentControlIntercom = pi.events.on(SUBAGENT_CONTROL_INTERCOM_EVENT, (payload) => {
965
963
  relaySubagentIntercomPayload(payload, {
@@ -1100,7 +1098,8 @@ export default function piIntercomExtension(pi) {
1100
1098
  }
1101
1099
  });
1102
1100
  const childOrchestratorMetadata = readChildOrchestratorMetadata();
1103
- if (childOrchestratorMetadata) {
1101
+ const nativeSupervisorChannel = isNativeSupervisorChannelActive();
1102
+ if (childOrchestratorMetadata && !nativeSupervisorChannel) {
1104
1103
  pi.registerTool({
1105
1104
  name: "contact_supervisor",
1106
1105
  label: "Contact Supervisor",
@@ -1361,10 +1360,11 @@ export default function piIntercomExtension(pi) {
1361
1360
  },
1362
1361
  });
1363
1362
  }
1364
- pi.registerTool({
1365
- name: "intercom",
1366
- label: "Intercom",
1367
- description: `Send a message to another pi session running on this machine.
1363
+ if (!nativeSupervisorChannel)
1364
+ pi.registerTool({
1365
+ name: "intercom",
1366
+ label: "Intercom",
1367
+ description: `Send a message to another pi session running on this machine.
1368
1368
  Use this to communicate findings, request help, or coordinate work with other sessions.
1369
1369
 
1370
1370
  Usage:
@@ -1374,158 +1374,131 @@ Usage:
1374
1374
  intercom({ action: "reply", message: "..." }) → Reply to the active/single pending ask
1375
1375
  intercom({ action: "pending" }) → List unresolved inbound asks
1376
1376
  intercom({ action: "status" }) → Show connection status`,
1377
- promptSnippet: "Use to coordinate with other local pi sessions: list peers, send updates, ask for help, or check intercom connectivity.",
1378
- parameters: Type.Object({
1379
- action: StringEnum(["list", "send", "ask", "reply", "pending", "status"], {
1380
- description: "Action: 'list', 'send', 'ask', 'reply', 'pending', or 'status'",
1377
+ promptSnippet: "Use to coordinate with other local pi sessions: list peers, send updates, ask for help, or check intercom connectivity.",
1378
+ parameters: Type.Object({
1379
+ action: StringEnum(["list", "send", "ask", "reply", "pending", "status"], {
1380
+ description: "Action: 'list', 'send', 'ask', 'reply', 'pending', or 'status'",
1381
+ }),
1382
+ to: Type.Optional(Type.String({
1383
+ description: "Target session name or ID (for 'send', 'ask', or disambiguating 'reply')",
1384
+ })),
1385
+ message: Type.Optional(Type.String({
1386
+ description: "Message to send (for 'send', 'ask', or 'reply' action)",
1387
+ })),
1388
+ attachments: Type.Optional(Type.Array(Type.Object({
1389
+ type: StringEnum(["file", "snippet", "context"]),
1390
+ name: Type.String(),
1391
+ content: Type.String(),
1392
+ language: Type.Optional(Type.String()),
1393
+ }))),
1394
+ replyTo: Type.Optional(Type.String({
1395
+ description: "Message ID to reply to (for threading or responding to an 'ask')",
1396
+ })),
1381
1397
  }),
1382
- to: Type.Optional(Type.String({
1383
- description: "Target session name or ID (for 'send', 'ask', or disambiguating 'reply')",
1384
- })),
1385
- message: Type.Optional(Type.String({
1386
- description: "Message to send (for 'send', 'ask', or 'reply' action)",
1387
- })),
1388
- attachments: Type.Optional(Type.Array(Type.Object({
1389
- type: StringEnum(["file", "snippet", "context"]),
1390
- name: Type.String(),
1391
- content: Type.String(),
1392
- language: Type.Optional(Type.String()),
1393
- }))),
1394
- replyTo: Type.Optional(Type.String({
1395
- description: "Message ID to reply to (for threading or responding to an 'ask')",
1396
- })),
1397
- }),
1398
- async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
1399
- let connectedClient;
1400
- try {
1401
- connectedClient = await ensureConnected("tool");
1402
- }
1403
- catch (error) {
1404
- return {
1405
- content: [{ type: "text", text: `Intercom not connected: ${getErrorMessage(error)}` }],
1406
- details: { error: true },
1407
- };
1408
- }
1409
- syncPresenceIdentity(ctx.sessionManager.getSessionId());
1410
- const { action, to, message, attachments, replyTo } = params;
1411
- switch (action) {
1412
- case "list": {
1413
- try {
1414
- const mySessionId = connectedClient.sessionId;
1415
- const sessions = await connectedClient.listSessions();
1416
- const currentSession = sessions.find(s => s.id === mySessionId);
1417
- const otherSessions = sessions.filter(s => s.id !== mySessionId);
1418
- if (!currentSession) {
1398
+ async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
1399
+ let connectedClient;
1400
+ try {
1401
+ connectedClient = await ensureConnected("tool");
1402
+ }
1403
+ catch (error) {
1404
+ return {
1405
+ content: [{ type: "text", text: `Intercom not connected: ${getErrorMessage(error)}` }],
1406
+ details: { error: true },
1407
+ };
1408
+ }
1409
+ syncPresenceIdentity(ctx.sessionManager.getSessionId());
1410
+ const { action, to, message, attachments, replyTo } = params;
1411
+ switch (action) {
1412
+ case "list": {
1413
+ try {
1414
+ const mySessionId = connectedClient.sessionId;
1415
+ const sessions = await connectedClient.listSessions();
1416
+ const currentSession = sessions.find(s => s.id === mySessionId);
1417
+ const otherSessions = sessions.filter(s => s.id !== mySessionId);
1418
+ if (!currentSession) {
1419
+ return {
1420
+ content: [{ type: "text", text: "Current session is missing from intercom session list." }],
1421
+ details: { error: true },
1422
+ };
1423
+ }
1424
+ const currentSection = `**Current session:**\n${formatSessionListRow(currentSession, currentSession.cwd, true)}`;
1425
+ const otherSection = otherSessions.length === 0
1426
+ ? "**Other sessions:**\nNo other sessions connected."
1427
+ : `**Other sessions:**\n${otherSessions.map(s => formatSessionListRow(s, currentSession.cwd, false)).join("\n")}`;
1428
+ return {
1429
+ content: [{ type: "text", text: `${currentSection}\n\n${otherSection}` }],
1430
+ details: {},
1431
+ };
1432
+ }
1433
+ catch (error) {
1419
1434
  return {
1420
- content: [{ type: "text", text: "Current session is missing from intercom session list." }],
1435
+ content: [{ type: "text", text: `Failed to list sessions: ${getErrorMessage(error)}` }],
1421
1436
  details: { error: true },
1422
1437
  };
1423
1438
  }
1424
- const currentSection = `**Current session:**\n${formatSessionListRow(currentSession, currentSession.cwd, true)}`;
1425
- const otherSection = otherSessions.length === 0
1426
- ? "**Other sessions:**\nNo other sessions connected."
1427
- : `**Other sessions:**\n${otherSessions.map(s => formatSessionListRow(s, currentSession.cwd, false)).join("\n")}`;
1428
- return {
1429
- content: [{ type: "text", text: `${currentSection}\n\n${otherSection}` }],
1430
- details: {},
1431
- };
1432
- }
1433
- catch (error) {
1434
- return {
1435
- content: [{ type: "text", text: `Failed to list sessions: ${getErrorMessage(error)}` }],
1436
- details: { error: true },
1437
- };
1438
- }
1439
- }
1440
- case "send": {
1441
- if (!to || !message) {
1442
- return {
1443
- content: [{ type: "text", text: "Missing 'to' or 'message' parameter" }],
1444
- details: { error: true },
1445
- };
1446
1439
  }
1447
- try {
1448
- const sendTo = await resolveSessionTarget(connectedClient, to) ?? to;
1449
- if (sendTo === connectedClient.sessionId) {
1440
+ case "send": {
1441
+ if (!to || !message) {
1450
1442
  return {
1451
- content: [{ type: "text", text: "Cannot message the current session" }],
1443
+ content: [{ type: "text", text: "Missing 'to' or 'message' parameter" }],
1452
1444
  details: { error: true },
1453
1445
  };
1454
1446
  }
1455
- if (!replyTo && config.confirmSend && ctx.hasUI) {
1456
- const attachmentText = attachments?.length ? formatAttachments(attachments) : "";
1457
- const confirmed = await ctx.ui.confirm("Send Message", `Send to "${to}":\n\n${message}${attachmentText}`);
1458
- if (!confirmed) {
1447
+ try {
1448
+ const sendTo = await resolveSessionTarget(connectedClient, to) ?? to;
1449
+ if (sendTo === connectedClient.sessionId) {
1459
1450
  return {
1460
- content: [{ type: "text", text: "Message cancelled by user" }],
1461
- details: {},
1451
+ content: [{ type: "text", text: "Cannot message the current session" }],
1452
+ details: { error: true },
1462
1453
  };
1463
1454
  }
1464
- }
1465
- const result = await connectedClient.send(sendTo, {
1466
- text: message,
1467
- attachments,
1468
- replyTo,
1469
- });
1470
- if (!result.delivered) {
1471
- const errorText = result.reason ?? "Session may not exist or has disconnected.";
1455
+ if (!replyTo && config.confirmSend && ctx.hasUI) {
1456
+ const attachmentText = attachments?.length ? formatAttachments(attachments) : "";
1457
+ const confirmed = await ctx.ui.confirm("Send Message", `Send to "${to}":\n\n${message}${attachmentText}`);
1458
+ if (!confirmed) {
1459
+ return {
1460
+ content: [{ type: "text", text: "Message cancelled by user" }],
1461
+ details: {},
1462
+ };
1463
+ }
1464
+ }
1465
+ const result = await connectedClient.send(sendTo, {
1466
+ text: message,
1467
+ attachments,
1468
+ replyTo,
1469
+ });
1470
+ if (!result.delivered) {
1471
+ const errorText = result.reason ?? "Session may not exist or has disconnected.";
1472
+ return {
1473
+ content: [{ type: "text", text: `Message to "${to}" was not delivered: ${errorText}` }],
1474
+ details: { messageId: result.id, delivered: false, reason: result.reason },
1475
+ };
1476
+ }
1477
+ pi.appendEntry("intercom_sent", {
1478
+ to,
1479
+ message: { text: message, attachments, replyTo },
1480
+ messageId: result.id,
1481
+ timestamp: Date.now(),
1482
+ });
1483
+ if (replyTo) {
1484
+ replyTracker.markReplied(replyTo);
1485
+ }
1472
1486
  return {
1473
- content: [{ type: "text", text: `Message to "${to}" was not delivered: ${errorText}` }],
1474
- details: { messageId: result.id, delivered: false, reason: result.reason },
1487
+ content: [{ type: "text", text: `Message sent to ${to}` }],
1488
+ details: { messageId: result.id, delivered: true },
1475
1489
  };
1476
1490
  }
1477
- pi.appendEntry("intercom_sent", {
1478
- to,
1479
- message: { text: message, attachments, replyTo },
1480
- messageId: result.id,
1481
- timestamp: Date.now(),
1482
- });
1483
- if (replyTo) {
1484
- replyTracker.markReplied(replyTo);
1485
- }
1486
- return {
1487
- content: [{ type: "text", text: `Message sent to ${to}` }],
1488
- details: { messageId: result.id, delivered: true },
1489
- };
1490
- }
1491
- catch (error) {
1492
- return {
1493
- content: [{ type: "text", text: `Failed to send: ${getErrorMessage(error)}` }],
1494
- details: { error: true },
1495
- };
1496
- }
1497
- }
1498
- case "ask": {
1499
- if (!to || !message) {
1500
- return {
1501
- content: [{ type: "text", text: "Missing 'to' or 'message' parameter" }],
1502
- details: { error: true },
1503
- };
1504
- }
1505
- if (replyWaiter) {
1506
- return {
1507
- content: [{ type: "text", text: "Already waiting for a reply" }],
1508
- details: { error: true },
1509
- };
1510
- }
1511
- if (_signal?.aborted) {
1512
- return {
1513
- content: [{ type: "text", text: "Cancelled" }],
1514
- details: { error: true },
1515
- };
1516
- }
1517
- let replyPromise = null;
1518
- try {
1519
- const sendTo = await resolveSessionTarget(connectedClient, to) ?? to;
1520
- if (_signal?.aborted) {
1491
+ catch (error) {
1521
1492
  return {
1522
- content: [{ type: "text", text: "Cancelled" }],
1493
+ content: [{ type: "text", text: `Failed to send: ${getErrorMessage(error)}` }],
1523
1494
  details: { error: true },
1524
1495
  };
1525
1496
  }
1526
- if (sendTo === connectedClient.sessionId) {
1497
+ }
1498
+ case "ask": {
1499
+ if (!to || !message) {
1527
1500
  return {
1528
- content: [{ type: "text", text: "Cannot message the current session" }],
1501
+ content: [{ type: "text", text: "Missing 'to' or 'message' parameter" }],
1529
1502
  details: { error: true },
1530
1503
  };
1531
1504
  }
@@ -1535,198 +1508,225 @@ Usage:
1535
1508
  details: { error: true },
1536
1509
  };
1537
1510
  }
1538
- const questionId = randomUUID();
1539
- replyPromise = waitForReply(sendTo, questionId, _signal, () => connectedClient.cancelAsk(questionId));
1540
- replyPromise.catch(() => undefined);
1541
- const sendResult = await connectedClient.send(sendTo, {
1542
- messageId: questionId,
1543
- text: message,
1544
- attachments,
1545
- replyTo,
1546
- expectsReply: true,
1547
- });
1548
- if (!sendResult.delivered) {
1549
- const errorText = sendResult.reason ?? "Session may not exist or has disconnected.";
1550
- rejectReplyWaiter(new Error(`Message to "${to}" was not delivered: ${errorText}`));
1511
+ if (_signal?.aborted) {
1512
+ return {
1513
+ content: [{ type: "text", text: "Cancelled" }],
1514
+ details: { error: true },
1515
+ };
1516
+ }
1517
+ let replyPromise = null;
1518
+ try {
1519
+ const sendTo = await resolveSessionTarget(connectedClient, to) ?? to;
1520
+ if (_signal?.aborted) {
1521
+ return {
1522
+ content: [{ type: "text", text: "Cancelled" }],
1523
+ details: { error: true },
1524
+ };
1525
+ }
1526
+ if (sendTo === connectedClient.sessionId) {
1527
+ return {
1528
+ content: [{ type: "text", text: "Cannot message the current session" }],
1529
+ details: { error: true },
1530
+ };
1531
+ }
1532
+ if (replyWaiter) {
1533
+ return {
1534
+ content: [{ type: "text", text: "Already waiting for a reply" }],
1535
+ details: { error: true },
1536
+ };
1537
+ }
1538
+ const questionId = randomUUID();
1539
+ replyPromise = waitForReply(sendTo, questionId, _signal, () => connectedClient.cancelAsk(questionId));
1540
+ replyPromise.catch(() => undefined);
1541
+ const sendResult = await connectedClient.send(sendTo, {
1542
+ messageId: questionId,
1543
+ text: message,
1544
+ attachments,
1545
+ replyTo,
1546
+ expectsReply: true,
1547
+ });
1548
+ if (!sendResult.delivered) {
1549
+ const errorText = sendResult.reason ?? "Session may not exist or has disconnected.";
1550
+ rejectReplyWaiter(new Error(`Message to "${to}" was not delivered: ${errorText}`));
1551
+ if (replyPromise) {
1552
+ try {
1553
+ await replyPromise;
1554
+ }
1555
+ catch {
1556
+ // The waiter was already rejected above. Keep the delivery failure as the only error here.
1557
+ }
1558
+ }
1559
+ return {
1560
+ content: [{ type: "text", text: `Message to "${to}" was not delivered: ${errorText}` }],
1561
+ details: { error: true },
1562
+ };
1563
+ }
1564
+ pi.appendEntry("intercom_sent", {
1565
+ to,
1566
+ message: { text: message, attachments, replyTo },
1567
+ messageId: sendResult.id,
1568
+ timestamp: Date.now(),
1569
+ });
1570
+ const replyMessage = await replyPromise;
1571
+ const replyText = replyMessage.content.text;
1572
+ const replyAttachments = replyMessage.content.attachments?.length
1573
+ ? formatAttachments(replyMessage.content.attachments)
1574
+ : "";
1575
+ pi.appendEntry("intercom_received", {
1576
+ from: to,
1577
+ message: { text: replyText, attachments: replyMessage.content.attachments },
1578
+ messageId: replyMessage.id,
1579
+ timestamp: replyMessage.timestamp,
1580
+ });
1581
+ return {
1582
+ content: [{ type: "text", text: `**Reply from ${to}:**\n${replyText}${replyAttachments}` }],
1583
+ details: {},
1584
+ };
1585
+ }
1586
+ catch (error) {
1587
+ rejectReplyWaiter(toError(error));
1551
1588
  if (replyPromise) {
1552
1589
  try {
1553
1590
  await replyPromise;
1554
1591
  }
1555
1592
  catch {
1556
- // The waiter was already rejected above. Keep the delivery failure as the only error here.
1593
+ // The waiter is cleanup-only on this path. The real failure is the one from the outer catch.
1557
1594
  }
1558
1595
  }
1559
1596
  return {
1560
- content: [{ type: "text", text: `Message to "${to}" was not delivered: ${errorText}` }],
1597
+ content: [{ type: "text", text: `Failed: ${getErrorMessage(error)}` }],
1561
1598
  details: { error: true },
1562
1599
  };
1563
1600
  }
1564
- pi.appendEntry("intercom_sent", {
1565
- to,
1566
- message: { text: message, attachments, replyTo },
1567
- messageId: sendResult.id,
1568
- timestamp: Date.now(),
1569
- });
1570
- const replyMessage = await replyPromise;
1571
- const replyText = replyMessage.content.text;
1572
- const replyAttachments = replyMessage.content.attachments?.length
1573
- ? formatAttachments(replyMessage.content.attachments)
1574
- : "";
1575
- pi.appendEntry("intercom_received", {
1576
- from: to,
1577
- message: { text: replyText, attachments: replyMessage.content.attachments },
1578
- messageId: replyMessage.id,
1579
- timestamp: replyMessage.timestamp,
1580
- });
1581
- return {
1582
- content: [{ type: "text", text: `**Reply from ${to}:**\n${replyText}${replyAttachments}` }],
1583
- details: {},
1584
- };
1585
1601
  }
1586
- catch (error) {
1587
- rejectReplyWaiter(toError(error));
1588
- if (replyPromise) {
1589
- try {
1590
- await replyPromise;
1602
+ case "reply": {
1603
+ if (!message) {
1604
+ return {
1605
+ content: [{ type: "text", text: "Missing 'message' parameter" }],
1606
+ details: { error: true },
1607
+ };
1608
+ }
1609
+ try {
1610
+ const target = replyTracker.resolveReplyTarget({ to, replyTo });
1611
+ if (target.from.id === connectedClient.sessionId) {
1612
+ return {
1613
+ content: [{ type: "text", text: "Cannot message the current session" }],
1614
+ details: { error: true },
1615
+ };
1591
1616
  }
1592
- catch {
1593
- // The waiter is cleanup-only on this path. The real failure is the one from the outer catch.
1617
+ const result = await connectedClient.send(target.from.id, {
1618
+ text: message,
1619
+ replyTo: target.message.id,
1620
+ });
1621
+ if (!result.delivered) {
1622
+ const errorText = result.reason ?? "Session may not exist or has disconnected.";
1623
+ if (result.reason === "Session not found") {
1624
+ replyTracker.dismissPendingAsk(target.message.id);
1625
+ }
1626
+ return {
1627
+ content: [{ type: "text", text: `Reply to "${target.from.name || target.from.id}" was not delivered: ${errorText}` }],
1628
+ details: { messageId: result.id, delivered: false, reason: result.reason },
1629
+ };
1594
1630
  }
1631
+ replyTracker.markReplied(target.message.id);
1632
+ pi.appendEntry("intercom_sent", {
1633
+ to: target.from.name || target.from.id,
1634
+ message: { text: message, replyTo: target.message.id },
1635
+ messageId: result.id,
1636
+ timestamp: Date.now(),
1637
+ });
1638
+ return {
1639
+ content: [{ type: "text", text: `Reply sent to ${target.from.name || target.from.id}` }],
1640
+ details: { messageId: result.id, delivered: true, replyTo: target.message.id },
1641
+ };
1595
1642
  }
1596
- return {
1597
- content: [{ type: "text", text: `Failed: ${getErrorMessage(error)}` }],
1598
- details: { error: true },
1599
- };
1600
- }
1601
- }
1602
- case "reply": {
1603
- if (!message) {
1604
- return {
1605
- content: [{ type: "text", text: "Missing 'message' parameter" }],
1606
- details: { error: true },
1607
- };
1608
- }
1609
- try {
1610
- const target = replyTracker.resolveReplyTarget({ to, replyTo });
1611
- if (target.from.id === connectedClient.sessionId) {
1643
+ catch (error) {
1612
1644
  return {
1613
- content: [{ type: "text", text: "Cannot message the current session" }],
1645
+ content: [{ type: "text", text: `Failed to reply: ${getErrorMessage(error)}` }],
1614
1646
  details: { error: true },
1615
1647
  };
1616
1648
  }
1617
- const result = await connectedClient.send(target.from.id, {
1618
- text: message,
1619
- replyTo: target.message.id,
1620
- });
1621
- if (!result.delivered) {
1622
- const errorText = result.reason ?? "Session may not exist or has disconnected.";
1623
- if (result.reason === "Session not found") {
1624
- replyTracker.dismissPendingAsk(target.message.id);
1625
- }
1649
+ }
1650
+ case "pending": {
1651
+ const pendingAsks = replyTracker.listPending();
1652
+ if (pendingAsks.length === 0) {
1626
1653
  return {
1627
- content: [{ type: "text", text: `Reply to "${target.from.name || target.from.id}" was not delivered: ${errorText}` }],
1628
- details: { messageId: result.id, delivered: false, reason: result.reason },
1654
+ content: [{ type: "text", text: "No unresolved inbound asks." }],
1655
+ details: {},
1629
1656
  };
1630
1657
  }
1631
- replyTracker.markReplied(target.message.id);
1632
- pi.appendEntry("intercom_sent", {
1633
- to: target.from.name || target.from.id,
1634
- message: { text: message, replyTo: target.message.id },
1635
- messageId: result.id,
1636
- timestamp: Date.now(),
1658
+ const now = Date.now();
1659
+ const lines = pendingAsks.map(({ from, message, receivedAt }) => {
1660
+ const preview = message.content.text.replace(/\s+/g, " ").slice(0, 80);
1661
+ const elapsedSeconds = Math.max(0, Math.floor((now - receivedAt) / 1000));
1662
+ return `- ${from.name || from.id} · ${message.id} · ${elapsedSeconds}s ago · ${preview}`;
1637
1663
  });
1638
1664
  return {
1639
- content: [{ type: "text", text: `Reply sent to ${target.from.name || target.from.id}` }],
1640
- details: { messageId: result.id, delivered: true, replyTo: target.message.id },
1641
- };
1642
- }
1643
- catch (error) {
1644
- return {
1645
- content: [{ type: "text", text: `Failed to reply: ${getErrorMessage(error)}` }],
1646
- details: { error: true },
1647
- };
1648
- }
1649
- }
1650
- case "pending": {
1651
- const pendingAsks = replyTracker.listPending();
1652
- if (pendingAsks.length === 0) {
1653
- return {
1654
- content: [{ type: "text", text: "No unresolved inbound asks." }],
1665
+ content: [{ type: "text", text: `**Pending asks:**\n${lines.join("\n")}` }],
1655
1666
  details: {},
1656
1667
  };
1657
1668
  }
1658
- const now = Date.now();
1659
- const lines = pendingAsks.map(({ from, message, receivedAt }) => {
1660
- const preview = message.content.text.replace(/\s+/g, " ").slice(0, 80);
1661
- const elapsedSeconds = Math.max(0, Math.floor((now - receivedAt) / 1000));
1662
- return `- ${from.name || from.id} · ${message.id} · ${elapsedSeconds}s ago · ${preview}`;
1663
- });
1664
- return {
1665
- content: [{ type: "text", text: `**Pending asks:**\n${lines.join("\n")}` }],
1666
- details: {},
1667
- };
1668
- }
1669
- case "status": {
1670
- try {
1671
- const mySessionId = connectedClient.sessionId;
1672
- const sessions = await connectedClient.listSessions();
1673
- return {
1674
- content: [{
1675
- type: "text",
1676
- text: `**Intercom Status:**\nConnected: Yes\nSession ID: ${mySessionId}\nActive sessions: ${sessions.length}`,
1677
- }],
1678
- details: {},
1679
- };
1669
+ case "status": {
1670
+ try {
1671
+ const mySessionId = connectedClient.sessionId;
1672
+ const sessions = await connectedClient.listSessions();
1673
+ return {
1674
+ content: [{
1675
+ type: "text",
1676
+ text: `**Intercom Status:**\nConnected: Yes\nSession ID: ${mySessionId}\nActive sessions: ${sessions.length}`,
1677
+ }],
1678
+ details: {},
1679
+ };
1680
+ }
1681
+ catch (error) {
1682
+ return {
1683
+ content: [{ type: "text", text: `Failed to get status: ${getErrorMessage(error)}` }],
1684
+ details: { error: true },
1685
+ };
1686
+ }
1680
1687
  }
1681
- catch (error) {
1688
+ default:
1682
1689
  return {
1683
- content: [{ type: "text", text: `Failed to get status: ${getErrorMessage(error)}` }],
1690
+ content: [{ type: "text", text: `Unknown action: ${action}` }],
1684
1691
  details: { error: true },
1685
1692
  };
1686
- }
1687
1693
  }
1688
- default:
1689
- return {
1690
- content: [{ type: "text", text: `Unknown action: ${action}` }],
1691
- details: { error: true },
1692
- };
1693
- }
1694
- },
1695
- renderCall(args, theme) {
1696
- const action = typeof args.action === "string" ? args.action : "intercom";
1697
- const target = typeof args.to === "string" && args.to.trim() ? args.to.trim() : undefined;
1698
- const messagePreview = previewText(args.message, 96);
1699
- const attachmentCount = Array.isArray(args.attachments) ? args.attachments.length : 0;
1700
- let text = theme.fg("toolTitle", theme.bold("intercom "));
1701
- text += theme.fg(action === "ask" ? "warning" : action === "reply" ? "success" : "accent", action);
1702
- if (target) {
1703
- text += " " + theme.fg("muted", "→") + " " + theme.fg("accent", target);
1704
- }
1705
- if (attachmentCount > 0) {
1706
- text += " " + theme.fg("dim", `(${attachmentCount} attachment${attachmentCount === 1 ? "" : "s"})`);
1707
- }
1708
- if (messagePreview) {
1709
- text += "\n " + theme.fg("dim", messagePreview);
1710
- }
1711
- return new Text(text, 0, 0);
1712
- },
1713
- renderResult(result, { isPartial }, theme, context) {
1714
- if (isPartial) {
1715
- return new Text(theme.fg("warning", "Intercom working..."), 0, 0);
1716
- }
1717
- const details = result.details;
1718
- const failed = Boolean(context.isError || details?.error === true || details?.delivered === false);
1719
- let text = failed ? theme.fg("error", "✗ ") : theme.fg("success", "✓ ");
1720
- text += theme.fg(failed ? "error" : "text", firstTextContent(result));
1721
- if (details?.messageId && !context.expanded) {
1722
- text += theme.fg("dim", ` (${details.messageId.slice(0, 8)})`);
1723
- }
1724
- if (details?.reason && context.expanded) {
1725
- text += "\n" + theme.fg("dim", `Reason: ${details.reason}`);
1726
- }
1727
- return new Text(text, 0, 0);
1728
- },
1729
- });
1694
+ },
1695
+ renderCall(args, theme) {
1696
+ const action = typeof args.action === "string" ? args.action : "intercom";
1697
+ const target = typeof args.to === "string" && args.to.trim() ? args.to.trim() : undefined;
1698
+ const messagePreview = previewText(args.message, 96);
1699
+ const attachmentCount = Array.isArray(args.attachments) ? args.attachments.length : 0;
1700
+ let text = theme.fg("toolTitle", theme.bold("intercom "));
1701
+ text += theme.fg(action === "ask" ? "warning" : action === "reply" ? "success" : "accent", action);
1702
+ if (target) {
1703
+ text += " " + theme.fg("muted", "→") + " " + theme.fg("accent", target);
1704
+ }
1705
+ if (attachmentCount > 0) {
1706
+ text += " " + theme.fg("dim", `(${attachmentCount} attachment${attachmentCount === 1 ? "" : "s"})`);
1707
+ }
1708
+ if (messagePreview) {
1709
+ text += "\n " + theme.fg("dim", messagePreview);
1710
+ }
1711
+ return new Text(text, 0, 0);
1712
+ },
1713
+ renderResult(result, { isPartial }, theme, context) {
1714
+ if (isPartial) {
1715
+ return new Text(theme.fg("warning", "Intercom working..."), 0, 0);
1716
+ }
1717
+ const details = result.details;
1718
+ const failed = Boolean(context.isError || details?.error === true || details?.delivered === false);
1719
+ let text = failed ? theme.fg("error", "✗ ") : theme.fg("success", "✓ ");
1720
+ text += theme.fg(failed ? "error" : "text", firstTextContent(result));
1721
+ if (details?.messageId && !context.expanded) {
1722
+ text += theme.fg("dim", ` (${details.messageId.slice(0, 8)})`);
1723
+ }
1724
+ if (details?.reason && context.expanded) {
1725
+ text += "\n" + theme.fg("dim", `Reason: ${details.reason}`);
1726
+ }
1727
+ return new Text(text, 0, 0);
1728
+ },
1729
+ });
1730
1730
  async function openIntercomOverlay(ctx) {
1731
1731
  const overlayGeneration = runtimeGeneration;
1732
1732
  const liveContext = getLiveContext(ctx, overlayGeneration);