@ctliz/agent-intercom-claude 0.14.1 → 0.15.1
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/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +9 -1
- package/README.md +14 -3
- package/broker/broker.ts +3 -2
- package/broker/client.ts +5 -2
- package/claude/inbox.ts +3 -1
- package/claude/mcp-protocol.ts +31 -9
- package/claude/named-team-membership.ts +124 -0
- package/claude/named-teams.ts +11 -0
- package/claude/native-bridge.ts +13 -4
- package/claude/reply-context.ts +49 -0
- package/claude/runtime.ts +45 -31
- package/claude/team-guidance.ts +13 -0
- package/claude/worker-daemon.ts +4 -0
- package/commands/intercom-create.md +4 -2
- package/commands/intercom-join.md +1 -1
- package/dist/broker.mjs +3 -2
- package/dist/cci.mjs +23 -8
- package/dist/ccim.mjs +23 -8
- package/dist/claude-server.mjs +247 -85
- package/dist/inbox-monitor.mjs +2 -1
- package/dist/worker-daemon.mjs +11 -5
- package/package.json +1 -1
- package/skills/claude-intercom/SKILL.md +8 -8
- package/types.ts +1 -0
package/dist/worker-daemon.mjs
CHANGED
|
@@ -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 (
|
|
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.
|
|
3
|
+
"version": "0.15.1",
|
|
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`:
|
|
33
|
-
- `intercom_join`: list, join, or create
|
|
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.
|
|
@@ -41,12 +41,12 @@ proxy-backed Claude profiles; `ccim` safe mode intentionally does not.
|
|
|
41
41
|
|
|
42
42
|
## Workflow
|
|
43
43
|
|
|
44
|
-
1.
|
|
45
|
-
2.
|
|
46
|
-
3.
|
|
47
|
-
4. Use `intercom_send` for non-blocking updates and handoffs.
|
|
44
|
+
1. For a known recipient, call `intercom_send` directly. Do not run `intercom_whoami`, `intercom_team`, `intercom_list`, or `intercom_status` as routine preflight checks. If the host requires tool discovery, discover only the selected tool and reuse its definition while it remains in context.
|
|
45
|
+
2. Discover peers only when the recipient is unknown, missing, or ambiguous: use `intercom_team` for managed or approved teammates, otherwise `intercom_list`. Check `intercom_status` only for connection errors. Use `intercom_set_summary` only when peers need to discover your role or a meaningful status change.
|
|
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
|
-
6.
|
|
49
|
+
6. Check `intercom_pending` at natural work boundaries when expecting a response or handling inbound messages, then reply with the original selectors and team. A standalone successful send does not require a pending/identity/status check or a resend. Delivery is not task completion; diagnose uncertain delivery before retrying, and never poll in a tight loop.
|
|
50
50
|
|
|
51
51
|
## Patterns
|
|
52
52
|
|
|
@@ -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
|
-
|
|
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." })
|