@ctliz/agent-intercom-claude 0.14.0 → 0.15.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.
@@ -1190,14 +1190,15 @@ function isMessage(value) {
1190
1190
  }
1191
1191
  if (message.replyTo !== void 0 || message.expectsReply !== void 0) return false;
1192
1192
  }
1193
- if (!hasExactDataKeys(message.content, ["text"], ["attachments"])) {
1193
+ if (!hasExactDataKeys(message.content, ["text"], ["attachments", "team"])) {
1194
1194
  return false;
1195
1195
  }
1196
1196
  const content = message.content;
1197
1197
  if (typeof content.text !== "string") {
1198
1198
  return false;
1199
1199
  }
1200
- if (message.control !== void 0 && (content.text !== "" || content.attachments !== void 0)) return false;
1200
+ if (content.team !== void 0 && (typeof content.team !== "string" || !/^[A-Za-z][A-Za-z0-9_-]{0,31}$/.test(content.team))) return false;
1201
+ if (message.control !== void 0 && (content.text !== "" || content.attachments !== void 0 || content.team !== void 0)) return false;
1201
1202
  return content.attachments === void 0 || isDenseArrayOf(content.attachments, isAttachment);
1202
1203
  }
1203
1204
  function isSessionInfo(value) {
@@ -1820,6 +1821,7 @@ var IntercomClient = class extends EventEmitter {
1820
1821
  ...options.control === void 0 ? {} : { control: options.control },
1821
1822
  content: {
1822
1823
  text: options.text,
1824
+ ...options.team === void 0 ? {} : { team: options.team },
1823
1825
  ...options.attachments === void 0 ? {} : { attachments: options.attachments }
1824
1826
  }
1825
1827
  };
@@ -2479,6 +2481,7 @@ ${agent.instructions}` : "";
2479
2481
  return [
2480
2482
  `Intercom message for ${agent.name}.`,
2481
2483
  `From: ${formatSessionDisplay(from)} (${from.id})`,
2484
+ ...message.content.team ? [`[Team: ${message.content.team}]`] : [],
2482
2485
  `Message id: ${message.id}`,
2483
2486
  "",
2484
2487
  message.content.text,
@@ -2631,7 +2634,8 @@ var VirtualClaudeAgent = class {
2631
2634
  if (message.expectsReply) {
2632
2635
  void this.client.send(from.id, {
2633
2636
  text: "This worker is rate limited (too many wakes this minute). Please try again shortly.",
2634
- replyTo: message.id
2637
+ replyTo: message.id,
2638
+ ...message.content.team === void 0 ? {} : { team: message.content.team }
2635
2639
  }).catch((error) => {
2636
2640
  process.stderr.write(`worker ${this.agent.id}: rate-limit reply failed: ${error instanceof Error ? error.message : String(error)}
2637
2641
  `);
@@ -2693,7 +2697,8 @@ var VirtualClaudeAgent = class {
2693
2697
  if (message.expectsReply) {
2694
2698
  await this.client.send(from.id, {
2695
2699
  text: result.result || "(the worker finished without a final message)",
2696
- replyTo: message.id
2700
+ replyTo: message.id,
2701
+ ...message.content.team === void 0 ? {} : { team: message.content.team }
2697
2702
  });
2698
2703
  process.stderr.write(`worker ${this.agent.id}: replied to ${from.name || from.id} (session ${this.sessionId ?? "none"})
2699
2704
  `);
@@ -2705,7 +2710,8 @@ var VirtualClaudeAgent = class {
2705
2710
  if (message.expectsReply) {
2706
2711
  await this.client.send(from.id, {
2707
2712
  text: `Worker error: ${text}`,
2708
- replyTo: message.id
2713
+ replyTo: message.id,
2714
+ ...message.content.team === void 0 ? {} : { team: message.content.team }
2709
2715
  }).catch((sendError) => {
2710
2716
  process.stderr.write(`worker ${this.agent.id}: error reply failed: ${sendError instanceof Error ? sendError.message : String(sendError)}
2711
2717
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctliz/agent-intercom-claude",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "Claude Code MCP plugin and wakeable worker for local messaging with Pi, Codex, OpenCode, Grok Build, and AGY agents.",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "type": "module",
@@ -29,8 +29,8 @@ proxy-backed Claude profiles; `ccim` safe mode intentionally does not.
29
29
  ## Tools
30
30
 
31
31
  - `intercom_whoami`: show this session's intercom ID, name, cwd, and model.
32
- - `intercom_team`: show the current orchestrator manager and live same-manager coworkers.
33
- - `intercom_join`: list, join, or create a named team without tmux (`create: true` joins as manager).
32
+ - `intercom_team({ team? })`: inspect one task team or list all memberships; falls back to managed-team discovery.
33
+ - `intercom_join({ name?, create?, members?, work? })`: list, join, or create an additive task team; the manager adds connected peers in one call.
34
34
  - `intercom_status`: connection, active session count, unread messages, pending asks.
35
35
  - `intercom_list`: list connected Pi, Codex, and Claude sessions.
36
36
  - `intercom_set_summary`: publish a short discoverable status.
@@ -43,8 +43,8 @@ proxy-backed Claude profiles; `ccim` safe mode intentionally does not.
43
43
 
44
44
  1. Call `intercom_status` or `intercom_whoami` to confirm this session is connected.
45
45
  2. Call `intercom_set_summary` with a concise status so peers can discover your role.
46
- 3. If this is an orchestrator-owned coworker, call `intercom_team` to get the manager and sibling targets without searching globally. To form a team without tmux, call `intercom_join({ name: "billing", create: true })` in one session and `intercom_join({ name: "billing" })` in the others. Otherwise use `intercom_list`.
47
- 4. Use `intercom_send` for non-blocking updates and handoffs.
46
+ 3. When the user delegates to named peers and this task has no approved team, ask once whether to form a team with you and those peers. Wait for approval. An explicit create/join request is approval; never ask again for an approved task or inbound team message. After approval, discover peers and call `intercom_join({ name: "billing", create: true, members: ["front", "writer"], work: "Current task" })`. Do not ask the user to join each terminal manually. Reuse the approved team for the same task; new tasks may need new teams. Joining preserves all previous memberships and each team's manager/member roles.
47
+ 4. Use `intercom_send` for non-blocking updates and handoffs. Include `team` for task messages, especially when multiple teams are shared. Without a shared team, omit `team` for initial ungrouped contact; unrelated memberships do not block contact or silently create teams.
48
48
  5. Use `intercom_ask` only when you need the answer before continuing. Assignments, progress/status checkpoints, notifications, and completion reports use `intercom_send`.
49
49
  6. Call `intercom_pending` before ending a coordination turn, then answer blocking asks with `intercom_reply`.
50
50
 
@@ -75,7 +75,7 @@ intercom_pending({ mark_read: false })
75
75
  intercom_reply({ message: "Use GET/PUT/DELETE only, max 3 retries." })
76
76
  ```
77
77
 
78
- When multiple asks are pending, select the sender with `to`. If that sender has multiple unresolved asks, select `oldest` or `latest` without using protocol IDs:
78
+ Replies inherit the original message's team, never a mutable current team. Prefer `askId` or `contextId` returned by `intercom_pending` (contextId also selects ordinary messages). Mixed-team pending contexts require explicit selection; `team` cannot override the original. Within one task, `to` plus `oldest`/`latest` also selects an ask:
79
79
 
80
80
  ```typescript
81
81
  intercom_reply({ to: "planner", which: "oldest", message: "Proceed." })
package/types.ts CHANGED
@@ -64,6 +64,7 @@ export interface Message {
64
64
  control?: BossControlEnvelope;
65
65
  content: {
66
66
  text: string;
67
+ team?: string;
67
68
  attachments?: Attachment[];
68
69
  };
69
70
  }