@agenticmail/claudecode 0.1.5 → 0.1.6

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.
@@ -2,7 +2,7 @@ import {
2
2
  listAccounts,
3
3
  renderPersonaBody,
4
4
  resolveConfig
5
- } from "./chunk-W2R3GH54.js";
5
+ } from "./chunk-YWSO3QOQ.js";
6
6
 
7
7
  // src/persona-loader.ts
8
8
  import { existsSync, readFileSync } from "fs";
@@ -59,7 +59,7 @@ function rememberBounded(set, item) {
59
59
  }
60
60
  }
61
61
  var DEFAULT_MAX_CONCURRENT = 10;
62
- var DEFAULT_SYNC_INTERVAL_MS = 6e4;
62
+ var DEFAULT_SYNC_INTERVAL_MS = 5e3;
63
63
  var DEFAULT_RECONNECT_BASE_MS = 2e3;
64
64
  var DEFAULT_RECONNECT_MAX_MS = 6e4;
65
65
  var TASK_MAIL_SUPPRESS_WINDOW_MS = 3e4;
@@ -94,6 +94,7 @@ async function runWorker(query, persona, userPrompt, agent, mcpServerName, mcpCo
94
94
  `mcp__${mcpServerName}__list_agents`,
95
95
  `mcp__${mcpServerName}__message_agent`,
96
96
  `mcp__${mcpServerName}__call_agent`,
97
+ `mcp__${mcpServerName}__wait_for_email`,
97
98
  `mcp__${mcpServerName}__check_tasks`,
98
99
  `mcp__${mcpServerName}__claim_task`,
99
100
  `mcp__${mcpServerName}__submit_result`,
@@ -143,13 +144,55 @@ function newMailPrompt(agent, event) {
143
144
  `- Subject: ${subject}`,
144
145
  uid ? `- UID: ${uid}` : "",
145
146
  ``,
146
- `Open it (with read_email if a UID was given, or list_inbox otherwise), decide what to do as ${agent.name} would, and act:`,
147
- ` - if it's a question or request \u2192 reply with reply_email`,
148
- ` - if it requires research \u2192 use call_agent to ask the right teammate, then reply`,
149
- ` - if it's an FYI \u2192 archive (mark_read) and move on`,
150
- ` - if it's spam-looking \u2192 trust the auto-spam-filter; only intervene if it slipped through`,
147
+ `## Thread-aware coordination protocol`,
151
148
  ``,
152
- `When you've handled it, return a one-line summary of what you did.`
149
+ `You are ${agent.name}. Multiple agents may be CC'd on the same thread \u2014`,
150
+ `that is intentional: a thread is the shared workspace, and turn-taking is`,
151
+ `implicit from context (who was addressed last, whose stage of the workflow`,
152
+ `is next, who was @mentioned). Follow these steps in order:`,
153
+ ``,
154
+ `1. **Read this message.** read_email({ uid: ${uid ?? "<uid>"}, _account: "${agent.name}" }).`,
155
+ ``,
156
+ `2. **If this is a reply (Subject starts with "Re:" or an In-Reply-To header is present), load the rest of the thread.**`,
157
+ ` Use search_emails({ subject: "<core subject without Re:>", _account: "${agent.name}" })`,
158
+ ` to surface earlier messages in the thread, then read_email each prior UID.`,
159
+ ` You MUST read the full thread before deciding what to do.`,
160
+ ``,
161
+ `3. **Identify the participants.** Look at To + CC across the thread. Those`,
162
+ ` are your collaborators. Their names map to AgenticMail agents at`,
163
+ ` <name>@localhost. They will each be woken on every reply-all the same way you were.`,
164
+ ``,
165
+ `4. **Decide: is it MY turn?** Yes if any of:`,
166
+ ` - The latest message addresses you by name ("Vesper, please \u2026", "@${agent.name} \u2026").`,
167
+ ` - The previous-stage handoff is to your role (e.g. designer \u2192 developer, and you are the developer).`,
168
+ ` - You were directly asked a question and nobody has answered yet.`,
169
+ ` No if:`,
170
+ ` - The current ask is targeted at a teammate (their turn, not yours).`,
171
+ ` - You have nothing substantive to add right now.`,
172
+ ` When in doubt, stay silent \u2014 over-replying creates noise. Better to let`,
173
+ ` the right teammate take the turn than to step on theirs.`,
174
+ ``,
175
+ `5. **If it's your turn \u2014 reply-all so the whole thread sees it.**`,
176
+ ` reply_email({ uid: ${uid ?? "<uid>"}, replyAll: true, text: "...", _account: "${agent.name}" })`,
177
+ ` Sign with your name. Be substantive but concise. If you are handing off`,
178
+ ` to the next teammate, name them explicitly in your reply ("Orion \u2014 over to you, please \u2026").`,
179
+ ``,
180
+ `6. **If you need additional help from a teammate not yet on the thread,**`,
181
+ ` include them by CC'ing in your reply-all \u2014 DO NOT spin up a separate`,
182
+ ` call_agent / message_agent side-channel. The thread is the workspace;`,
183
+ ` everyone stays in context.`,
184
+ ``,
185
+ `7. **If it's NOT your turn,** mark the message read with mark_read and return.`,
186
+ ` Do not reply just to acknowledge. Silence IS a valid contribution.`,
187
+ ``,
188
+ `When you finish, return a one-line summary of what you did:`,
189
+ ` "Contributed: <one-line description>" OR "Stayed silent \u2014 not my turn."`,
190
+ ``,
191
+ `## Fallback for non-thread mail`,
192
+ ``,
193
+ `If this is a fresh standalone email (not part of a thread, only addressed`,
194
+ `to you), handle it directly: answer the question, do the work, reply.`,
195
+ `Spam: trust the auto-filter unless something obviously slipped through.`
153
196
  ].filter(Boolean).join("\n");
154
197
  }
155
198
  function taskPrompt(agent, event) {
@@ -248,6 +291,29 @@ var Dispatcher = class {
248
291
  return;
249
292
  }
250
293
  }
294
+ /**
295
+ * Should the dispatcher own a wake-channel for this account?
296
+ *
297
+ * We skip the bridge agent (default name "claudecode"). The bridge is
298
+ * the host session's own inbox proxy — when mail lands there, the
299
+ * HOST Claude Code session reads it via MCP (`list_inbox` /
300
+ * `wait_for_email` / `read_email`), NOT via a separately-spawned
301
+ * dispatcher worker. Spawning a worker for the bridge would:
302
+ * 1. Compete with the host (two Claude instances trying to "be"
303
+ * Claude Code, both potentially replying autonomously).
304
+ * 2. Waste tokens — the host is already aware via its MCP polling.
305
+ * 3. Send the bridge into an autonomous loop if it ever replies-all
306
+ * (because that mail would wake it again, ad infinitum).
307
+ *
308
+ * Role="bridge" is also skipped for symmetry with selectExposableAgents
309
+ * in install.ts — anything tagged as a bridge is host-managed.
310
+ */
311
+ shouldWatch(account) {
312
+ const bridgeName = this.cfg.bridgeAgentName.toLowerCase();
313
+ if (account.name.toLowerCase() === bridgeName) return false;
314
+ if (account.role === "bridge") return false;
315
+ return true;
316
+ }
251
317
  /** Re-fetch /accounts; open SSE for new ones, close for vanished ones. */
252
318
  async syncAccounts() {
253
319
  let accounts;
@@ -257,6 +323,7 @@ var Dispatcher = class {
257
323
  this.log("warn", `[dispatcher] could not list accounts: ${err.message}`);
258
324
  return;
259
325
  }
326
+ accounts = accounts.filter((a) => this.shouldWatch(a));
260
327
  const liveIds = new Set(accounts.map((a) => a.id));
261
328
  for (const [id, ch] of this.channels) {
262
329
  if (!liveIds.has(id)) {
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  install
3
- } from "./chunk-4JURQ6QD.js";
3
+ } from "./chunk-WP2ELPRM.js";
4
4
  import {
5
5
  status
6
- } from "./chunk-UZZNLWBR.js";
6
+ } from "./chunk-UC63VEBP.js";
7
7
  import {
8
8
  uninstall
9
- } from "./chunk-5S377IWV.js";
9
+ } from "./chunk-XGBVWZ3M.js";
10
10
  import {
11
11
  AgenticMailApiError
12
- } from "./chunk-W2R3GH54.js";
12
+ } from "./chunk-YWSO3QOQ.js";
13
13
 
14
14
  // src/http-routes.ts
15
15
  import { Router } from "express";
@@ -7,7 +7,7 @@ import {
7
7
  MANAGED_BY_MARKER,
8
8
  getAccountByName,
9
9
  resolveConfig
10
- } from "./chunk-W2R3GH54.js";
10
+ } from "./chunk-YWSO3QOQ.js";
11
11
 
12
12
  // src/status.ts
13
13
  import { existsSync, readFileSync, readdirSync } from "fs";
@@ -9,7 +9,7 @@ import {
9
9
  listAccounts,
10
10
  renderSubagentMarkdown,
11
11
  resolveConfig
12
- } from "./chunk-W2R3GH54.js";
12
+ } from "./chunk-YWSO3QOQ.js";
13
13
 
14
14
  // src/install.ts
15
15
  import { existsSync, mkdirSync, readdirSync, writeFileSync, readFileSync, unlinkSync } from "fs";
@@ -7,7 +7,7 @@ import {
7
7
  deleteAccount,
8
8
  getAccountByName,
9
9
  resolveConfig
10
- } from "./chunk-W2R3GH54.js";
10
+ } from "./chunk-YWSO3QOQ.js";
11
11
 
12
12
  // src/uninstall.ts
13
13
  import { existsSync, readdirSync, readFileSync, unlinkSync } from "fs";
@@ -130,12 +130,16 @@ var ESSENTIAL_TOOL_NAMES = [
130
130
  "search_emails",
131
131
  "list_agents",
132
132
  "message_agent",
133
- // call_agent is the synchronous RPC primitive — fire a task at another
134
- // AgenticMail agent and get back a structured result. It is the reason
135
- // multi-agent setups work, so it MUST be pre-loaded; making subagents
136
- // call request_tools just to discover it would be a usability disaster
137
- // for the most common coordination pattern.
133
+ // call_agent is the one-shot RPC primitive — sync request, sync answer.
134
+ // For multi-step coordination use the thread pattern (send_email with
135
+ // CC + reply_email with replyAll) instead.
138
136
  "call_agent",
137
+ // wait_for_email is the thread-coordination primitive: block until a
138
+ // specific reply lands in your inbox (filter by from / subject /
139
+ // inReplyTo / participants). Essential for delegate-then-wait flows;
140
+ // making subagents discover it via request_tools would be a usability
141
+ // disaster for the most common coordination pattern.
142
+ "wait_for_email",
139
143
  "check_tasks",
140
144
  // Meta-tools — these unlock the other ~50 tools on demand.
141
145
  "request_tools",
@@ -201,7 +205,16 @@ function renderPersonaBody(input) {
201
205
  `${tool("whoami")}({ _account: "${agent.name}" })`,
202
206
  "```",
203
207
  "",
204
- `**Coordination tip:** When you need another agent to *do work and report back*, prefer \`${tool("call_agent")}\` over \`${tool("message_agent")}\`. message_agent just delivers an email and returns immediately; call_agent runs the AgenticMail RPC pipeline \u2014 the target agent gets the task, processes it, and the structured result flows back into your call. That is the entire reason this platform has multiple agents.`,
208
+ `**Coordination \u2014 the thread is the workspace.** When you wake on new mail and it's part of a thread (Subject starts with "Re:" or an In-Reply-To header is present):`,
209
+ "",
210
+ ` 1. Read the new message with \`${tool("read_email")}\`.`,
211
+ ` 2. Load the rest of the thread with \`${tool("search_emails")}({ subject: "<core subject>", _account: "${agent.name}" })\` and read each prior message. You MUST have full thread context before acting.`,
212
+ ` 3. Look at To + CC across the thread \u2014 those are your teammates. They will each be woken on every reply-all just like you were.`,
213
+ ` 4. Decide if it's YOUR turn: are you addressed by name? Is the previous-stage handoff to your role? Is a question pending for you? When in doubt, stay silent \u2014 over-replying creates noise.`,
214
+ ` 5. If yes: \`${tool("reply_email")}({ uid, replyAll: true, text: "...", _account: "${agent.name}" })\`. Sign with your name. If you're handing off, name the next teammate explicitly ("Orion \u2014 over to you, please \u2026"). To bring a new teammate in, just add them to CC.`,
215
+ ` 6. If no: \`mark_read\` and return. Silence IS a valid contribution.`,
216
+ "",
217
+ `**When to use \`${tool("call_agent")}\` instead:** only when you need ONE structured answer from ONE teammate, inline in your current turn \u2014 e.g. "give me a JSON list of X". For multi-step / multi-agent work, the thread pattern above is the right primitive.`,
205
218
  "",
206
219
  `On-demand (via invoke) examples \u2014 anything NOT in the pre-loaded list:`,
207
220
  "",
package/dist/cli.js CHANGED
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  install
4
- } from "./chunk-4JURQ6QD.js";
4
+ } from "./chunk-WP2ELPRM.js";
5
5
  import {
6
6
  status
7
- } from "./chunk-UZZNLWBR.js";
7
+ } from "./chunk-UC63VEBP.js";
8
8
  import {
9
9
  uninstall
10
- } from "./chunk-5S377IWV.js";
10
+ } from "./chunk-XGBVWZ3M.js";
11
11
  import "./chunk-US5FT2UB.js";
12
12
  import {
13
13
  AgenticMailApiError
14
- } from "./chunk-W2R3GH54.js";
14
+ } from "./chunk-YWSO3QOQ.js";
15
15
 
16
16
  // src/cli.ts
17
17
  var GREEN = (s) => `\x1B[32m${s}\x1B[0m`;
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  Dispatcher
4
- } from "./chunk-3ULRGCUI.js";
5
- import "./chunk-W2R3GH54.js";
4
+ } from "./chunk-5M43V6CB.js";
5
+ import "./chunk-YWSO3QOQ.js";
6
6
 
7
7
  // src/dispatcher-bin.ts
8
8
  async function main() {
@@ -111,6 +111,24 @@ declare class Dispatcher {
111
111
  stop(): Promise<void>;
112
112
  /** Public for tests — directly hand an event to the routing path. */
113
113
  handleEvent(account: AgenticMailAccount, event: SSEEvent): Promise<void>;
114
+ /**
115
+ * Should the dispatcher own a wake-channel for this account?
116
+ *
117
+ * We skip the bridge agent (default name "claudecode"). The bridge is
118
+ * the host session's own inbox proxy — when mail lands there, the
119
+ * HOST Claude Code session reads it via MCP (`list_inbox` /
120
+ * `wait_for_email` / `read_email`), NOT via a separately-spawned
121
+ * dispatcher worker. Spawning a worker for the bridge would:
122
+ * 1. Compete with the host (two Claude instances trying to "be"
123
+ * Claude Code, both potentially replying autonomously).
124
+ * 2. Waste tokens — the host is already aware via its MCP polling.
125
+ * 3. Send the bridge into an autonomous loop if it ever replies-all
126
+ * (because that mail would wake it again, ad infinitum).
127
+ *
128
+ * Role="bridge" is also skipped for symmetry with selectExposableAgents
129
+ * in install.ts — anything tagged as a bridge is host-managed.
130
+ */
131
+ private shouldWatch;
114
132
  /** Re-fetch /accounts; open SSE for new ones, close for vanished ones. */
115
133
  private syncAccounts;
116
134
  /** Watch one account's SSE stream forever; reconnect with backoff on drop. */
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Dispatcher
3
- } from "./chunk-3ULRGCUI.js";
4
- import "./chunk-W2R3GH54.js";
3
+ } from "./chunk-5M43V6CB.js";
4
+ import "./chunk-YWSO3QOQ.js";
5
5
  export {
6
6
  Dispatcher
7
7
  };
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createIntegrationRoutes
3
- } from "./chunk-OZPRB336.js";
4
- import "./chunk-4JURQ6QD.js";
5
- import "./chunk-UZZNLWBR.js";
6
- import "./chunk-5S377IWV.js";
3
+ } from "./chunk-N43A7EQB.js";
4
+ import "./chunk-WP2ELPRM.js";
5
+ import "./chunk-UC63VEBP.js";
6
+ import "./chunk-XGBVWZ3M.js";
7
7
  import "./chunk-US5FT2UB.js";
8
- import "./chunk-W2R3GH54.js";
8
+ import "./chunk-YWSO3QOQ.js";
9
9
  export {
10
10
  createIntegrationRoutes
11
11
  };
package/dist/index.js CHANGED
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  Dispatcher,
3
3
  loadPersonaForAgent
4
- } from "./chunk-3ULRGCUI.js";
4
+ } from "./chunk-5M43V6CB.js";
5
5
  import {
6
6
  createIntegrationRoutes
7
- } from "./chunk-OZPRB336.js";
7
+ } from "./chunk-N43A7EQB.js";
8
8
  import {
9
9
  install
10
- } from "./chunk-4JURQ6QD.js";
10
+ } from "./chunk-WP2ELPRM.js";
11
11
  import {
12
12
  status
13
- } from "./chunk-UZZNLWBR.js";
13
+ } from "./chunk-UC63VEBP.js";
14
14
  import {
15
15
  uninstall
16
- } from "./chunk-5S377IWV.js";
16
+ } from "./chunk-XGBVWZ3M.js";
17
17
  import "./chunk-US5FT2UB.js";
18
18
  import {
19
19
  AgenticMailApiError,
@@ -26,7 +26,7 @@ import {
26
26
  renderPersonaBody,
27
27
  renderSubagentMarkdown,
28
28
  resolveConfig
29
- } from "./chunk-W2R3GH54.js";
29
+ } from "./chunk-YWSO3QOQ.js";
30
30
  export {
31
31
  AgenticMailApiError,
32
32
  Dispatcher,
package/dist/install.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  install,
3
3
  selectExposableAgents
4
- } from "./chunk-4JURQ6QD.js";
4
+ } from "./chunk-WP2ELPRM.js";
5
5
  import "./chunk-US5FT2UB.js";
6
- import "./chunk-W2R3GH54.js";
6
+ import "./chunk-YWSO3QOQ.js";
7
7
  export {
8
8
  install,
9
9
  selectExposableAgents
package/dist/status.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  status
3
- } from "./chunk-UZZNLWBR.js";
3
+ } from "./chunk-UC63VEBP.js";
4
4
  import "./chunk-US5FT2UB.js";
5
- import "./chunk-W2R3GH54.js";
5
+ import "./chunk-YWSO3QOQ.js";
6
6
  export {
7
7
  status
8
8
  };
package/dist/uninstall.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  uninstall
3
- } from "./chunk-5S377IWV.js";
3
+ } from "./chunk-XGBVWZ3M.js";
4
4
  import "./chunk-US5FT2UB.js";
5
- import "./chunk-W2R3GH54.js";
5
+ import "./chunk-YWSO3QOQ.js";
6
6
  export {
7
7
  uninstall
8
8
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/claudecode",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Claude Code integration for AgenticMail — surfaces every AgenticMail agent as a native Claude Code subagent so any Claude Code session can delegate to them with the Agent tool",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",