@ctliz/agent-intercom-pi 0.14.3 → 0.14.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -44,6 +44,8 @@ The package includes an `intercom-send` executable. Install the alias globally f
44
44
  npm exec --yes --package=@ctliz/agent-intercom-pi@0.14.3 -- intercom-send worker 'Tests passed.'
45
45
  ```
46
46
 
47
+ The default command disconnects after delivery and cannot receive a later reply. For a shell handoff requiring an acknowledgement, use `intercom-send --wait-reply 60 worker 'Please acknowledge this task.'`. It keeps its independent identity connected until the first message from that recipient or the timeout, prints delivery and reply as separate JSON lines, and exits with code 2 if no reply arrives. The recipient can use either `send` or a correlated reply. For ongoing delegation, use a persistent Codex MCP/`coi` session so questions and completion reports remain reachable after the acknowledgement. Do not send a task from a temporary `IntercomClient` and immediately disconnect when you expect responses.
48
+
47
49
  It prints one JSON result with `accepted`, `delivered`, `messageId`, and optional failure `code`/`reason`. Exit status is zero only for acknowledged delivery. It inherits the routing scope, but never inherits `PI_INTERCOM_SESSION_ID` or `AGENT_INTERCOM_SESSION_ID`: every invocation registers an independent sender, leaves running Pi sessions intact, and disconnects after sending. It is send-only; use the session tools for reply-tracked asks.
48
50
 
49
51
  When a second runtime claims the same stable session ID, Intercom reports `SESSION_ID_IN_USE`, pauses automatic reconnect, and preserves the original owner. Switch to a different session, or release the duplicate owner and `/reload`. `intercom_status` exposes the conflict as structured data rather than silently treating it as a temporary outage. Updating this adapter does not require restarting a compatible v4 broker.
package/cli-send.ts CHANGED
@@ -2,18 +2,31 @@ import { randomUUID } from "node:crypto";
2
2
  import { IntercomClient } from "./broker/client.ts";
3
3
  import { spawnBrokerIfNeeded } from "./broker/spawn.ts";
4
4
  import { loadConfig } from "./config.ts";
5
+ import type { Message, SessionInfo } from "./types.ts";
5
6
 
6
7
  async function main(): Promise<void> {
7
- const [to, ...parts] = process.argv.slice(2);
8
+ const args = process.argv.slice(2);
9
+ let waitMs = 0;
10
+ if (args[0] === "--wait-reply") {
11
+ args.shift();
12
+ const seconds = Number(args.shift());
13
+ if (!Number.isFinite(seconds) || seconds <= 0 || seconds > 86400) {
14
+ throw new Error("--wait-reply requires a timeout in seconds (0 < seconds <= 86400)");
15
+ }
16
+ waitMs = seconds * 1000;
17
+ }
18
+ const [to, ...parts] = args;
8
19
  const message = parts.join(" ");
9
20
  if (!to?.trim() || !message.trim()) {
10
- throw new Error("Usage: intercom-send <session-name-or-id> <message>");
21
+ throw new Error("Usage: intercom-send [--wait-reply <seconds>] <session-name-or-id> <message>");
11
22
  }
12
23
  const config = loadConfig();
13
24
  if (!config.enabled) throw new Error("Intercom disabled");
14
25
  await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs);
15
26
  const client = new IntercomClient();
27
+ const messageId = randomUUID();
16
28
  const now = Date.now();
29
+ let timer: NodeJS.Timeout | undefined;
17
30
  try {
18
31
  // Never inherit the calling Pi's session ID or take over its mailbox.
19
32
  await client.connect({
@@ -25,10 +38,35 @@ async function main(): Promise<void> {
25
38
  lastActivity: now,
26
39
  runtimeInstanceId: randomUUID(),
27
40
  });
28
- const result = await client.send(to, { text: message });
41
+ let reply: Promise<{ from: SessionInfo; message: Message } | null> | undefined;
42
+ let target = to;
43
+ if (waitMs) {
44
+ const sessions = await client.listSessions();
45
+ const matches = sessions.filter((session) => session.id === to || session.name?.toLowerCase() === to.toLowerCase());
46
+ if (matches.length !== 1) throw new Error(matches.length ? "Ambiguous target; use the session ID" : "Session not found");
47
+ target = matches[0]!.id;
48
+ reply = new Promise((resolve) => {
49
+ timer = setTimeout(() => resolve(null), waitMs);
50
+ client.on("message", (from: SessionInfo, incoming: Message, deliveryId: string) => {
51
+ if (from.id !== target || (incoming.replyTo && incoming.replyTo !== messageId)) return;
52
+ client.acknowledgeMessage(deliveryId);
53
+ resolve({ from, message: incoming });
54
+ });
55
+ client.once("disconnected", () => resolve(null));
56
+ });
57
+ }
58
+ const result = await client.send(target, { text: message, messageId, ...(waitMs ? { expectsReply: true } : {}) });
29
59
  console.log(JSON.stringify({ messageId: result.id, ...result }));
30
60
  if (!result.delivered) process.exitCode = 1;
61
+ else if (reply) {
62
+ const response = await reply;
63
+ console.log(JSON.stringify(response
64
+ ? { type: "reply", ...response }
65
+ : { type: "reply_wait_failed", code: client.isConnected() ? "REPLY_TIMEOUT" : "DISCONNECTED", messageId: result.id }));
66
+ if (!response) process.exitCode = 2;
67
+ }
31
68
  } finally {
69
+ clearTimeout(timer);
32
70
  await client.disconnect();
33
71
  }
34
72
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctliz/agent-intercom-pi",
3
- "version": "0.14.3",
3
+ "version": "0.14.4",
4
4
  "description": "Pi coding-agent intercom for local messaging with Codex, Claude Code, OpenCode, Grok Build, and AGY agents.",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "type": "module",
@@ -91,6 +91,8 @@ A deferred ask has `ok: true` and `data.pending: true`; it is not a failure. Do
91
91
 
92
92
  For shell notifications, use `intercom-send <session-name-or-id> <message>`. It registers an independent send-only identity and prints JSON; it does not take over the current Pi session or track replies.
93
93
 
94
+ For a shell handoff requiring an acknowledgement, use `intercom-send --wait-reply 60 <recipient> <message>` to keep the sender connected until the first response or timeout. Use a persistent agent session for ongoing questions and completion reports. A temporary sender that disconnects after delivery cannot receive replies; `Session not found` on the return path does not mean the original task was undelivered.
95
+
94
96
  ## Core Patterns
95
97
 
96
98
  ### Pattern 1: Planner-Worker Delegation