@agenticmail/claudecode 0.2.8 → 0.2.10
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/dist/{chunk-JOK76WRC.js → chunk-APRMWXZB.js} +8 -2
- package/dist/chunk-B5JDOV32.js +73 -0
- package/dist/{chunk-2RVJ2Q3W.js → chunk-BIP2TBJ5.js} +1 -1
- package/dist/{chunk-Q5BA2J2C.js → chunk-KB2EHQW7.js} +1 -1
- package/dist/{chunk-TV7VG7YM.js → chunk-THUNXHMQ.js} +6 -6
- package/dist/{chunk-OUYPF4ER.js → chunk-TSLDSGOD.js} +11 -3
- package/dist/{chunk-4VQP57SO.js → chunk-WTAITYZR.js} +10 -0
- package/dist/cli.js +119 -12
- package/dist/dispatcher-bin.js +14 -9
- package/dist/dispatcher-tuning.d.ts +79 -0
- package/dist/dispatcher-tuning.js +10 -0
- package/dist/dispatcher.js +2 -2
- package/dist/http-routes.js +5 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +17 -9
- package/dist/install.js +2 -2
- package/dist/status.js +2 -2
- package/dist/uninstall.js +2 -2
- package/package.json +3 -3
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
listPendingTasksForAgent,
|
|
5
5
|
renderPersonaBody,
|
|
6
6
|
resolveConfig
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-WTAITYZR.js";
|
|
8
8
|
|
|
9
9
|
// src/persona-loader.ts
|
|
10
10
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -840,6 +840,9 @@ var Dispatcher = class {
|
|
|
840
840
|
const bridgeName = this.cfg.bridgeAgentName.toLowerCase();
|
|
841
841
|
if (account.name.toLowerCase() === bridgeName) return false;
|
|
842
842
|
if (account.role === "bridge") return false;
|
|
843
|
+
const meta = account.metadata;
|
|
844
|
+
if (meta && meta.bridge === true) return false;
|
|
845
|
+
if (meta && typeof meta.host === "string" && meta.host.length > 0) return false;
|
|
843
846
|
return true;
|
|
844
847
|
}
|
|
845
848
|
/** Re-fetch /accounts; open SSE for new ones, close for vanished ones. */
|
|
@@ -1205,7 +1208,10 @@ var Dispatcher = class {
|
|
|
1205
1208
|
async fireWakeImmediately(account, event, threadId) {
|
|
1206
1209
|
const verdict = this.chargeWake(account.id, threadId);
|
|
1207
1210
|
if (!verdict.ok) {
|
|
1208
|
-
this.log(
|
|
1211
|
+
this.log(
|
|
1212
|
+
"warn",
|
|
1213
|
+
`[dispatcher] wake-budget exhausted for "${account.name}" on thread "${threadId}" \u2014 dropped uid=${event.uid} (cap=${this.maxWakesPerThread} per ${Math.round(this.wakeWindowMs / 6e4)}min; raise with AGENTICMAIL_DISPATCHER_MAX_WAKES_PER_THREAD env var, or via ~/.agenticmail/dispatcher.json)`
|
|
1214
|
+
);
|
|
1209
1215
|
this.postSkipped(account, event, "budget-exhausted", `wake budget exhausted for thread "${threadId}" (count=${verdict.count}, cap=${this.maxWakesPerThread})`);
|
|
1210
1216
|
return;
|
|
1211
1217
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// src/dispatcher-tuning.ts
|
|
2
|
+
import { readFileSync, existsSync, writeFileSync, mkdirSync, renameSync } from "fs";
|
|
3
|
+
import { join, dirname } from "path";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
function defaultDispatcherConfigPath() {
|
|
6
|
+
return join(homedir(), ".agenticmail", "dispatcher.json");
|
|
7
|
+
}
|
|
8
|
+
function positiveInt(s) {
|
|
9
|
+
if (s === void 0 || s === null || s === "") return void 0;
|
|
10
|
+
const n = typeof s === "number" ? s : parseInt(String(s), 10);
|
|
11
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
12
|
+
}
|
|
13
|
+
function readTuningFile(path) {
|
|
14
|
+
if (!existsSync(path)) return {};
|
|
15
|
+
try {
|
|
16
|
+
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
17
|
+
if (!parsed || typeof parsed !== "object") return {};
|
|
18
|
+
if (parsed.version !== 1) return {};
|
|
19
|
+
return {
|
|
20
|
+
maxConcurrentWorkers: positiveInt(parsed.maxConcurrentWorkers),
|
|
21
|
+
maxWakesPerThread: positiveInt(parsed.maxWakesPerThread),
|
|
22
|
+
wakeWindowMs: positiveInt(parsed.wakeWindowMs),
|
|
23
|
+
wakeCoalesceMs: positiveInt(parsed.wakeCoalesceMs),
|
|
24
|
+
accountSyncIntervalMs: positiveInt(parsed.accountSyncIntervalMs)
|
|
25
|
+
};
|
|
26
|
+
} catch {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function resolveDispatcherTuning(opts = {}) {
|
|
31
|
+
const env = opts.env ?? process.env;
|
|
32
|
+
const configPath = opts.configPath ?? defaultDispatcherConfigPath();
|
|
33
|
+
const fileLayer = readTuningFile(configPath);
|
|
34
|
+
const envLayer = {
|
|
35
|
+
maxConcurrentWorkers: positiveInt(env.AGENTICMAIL_DISPATCHER_MAX),
|
|
36
|
+
maxWakesPerThread: positiveInt(env.AGENTICMAIL_DISPATCHER_MAX_WAKES_PER_THREAD),
|
|
37
|
+
wakeWindowMs: positiveInt(env.AGENTICMAIL_DISPATCHER_WAKE_WINDOW_MS),
|
|
38
|
+
wakeCoalesceMs: positiveInt(env.AGENTICMAIL_DISPATCHER_COALESCE_MS),
|
|
39
|
+
accountSyncIntervalMs: positiveInt(env.AGENTICMAIL_DISPATCHER_SYNC)
|
|
40
|
+
};
|
|
41
|
+
const explicit = opts.explicit ?? {};
|
|
42
|
+
return {
|
|
43
|
+
maxConcurrentWorkers: explicit.maxConcurrentWorkers ?? envLayer.maxConcurrentWorkers ?? fileLayer.maxConcurrentWorkers,
|
|
44
|
+
maxWakesPerThread: explicit.maxWakesPerThread ?? envLayer.maxWakesPerThread ?? fileLayer.maxWakesPerThread,
|
|
45
|
+
wakeWindowMs: explicit.wakeWindowMs ?? envLayer.wakeWindowMs ?? fileLayer.wakeWindowMs,
|
|
46
|
+
wakeCoalesceMs: explicit.wakeCoalesceMs ?? envLayer.wakeCoalesceMs ?? fileLayer.wakeCoalesceMs,
|
|
47
|
+
accountSyncIntervalMs: explicit.accountSyncIntervalMs ?? envLayer.accountSyncIntervalMs ?? fileLayer.accountSyncIntervalMs
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function writeDispatcherTuning(patch, configPath = defaultDispatcherConfigPath()) {
|
|
51
|
+
const current = readTuningFile(configPath);
|
|
52
|
+
const merged = {
|
|
53
|
+
version: 1,
|
|
54
|
+
updatedAtMs: Date.now(),
|
|
55
|
+
maxConcurrentWorkers: positiveInt(patch.maxConcurrentWorkers) ?? current.maxConcurrentWorkers,
|
|
56
|
+
maxWakesPerThread: positiveInt(patch.maxWakesPerThread) ?? current.maxWakesPerThread,
|
|
57
|
+
wakeWindowMs: positiveInt(patch.wakeWindowMs) ?? current.wakeWindowMs,
|
|
58
|
+
wakeCoalesceMs: positiveInt(patch.wakeCoalesceMs) ?? current.wakeCoalesceMs,
|
|
59
|
+
accountSyncIntervalMs: positiveInt(patch.accountSyncIntervalMs) ?? current.accountSyncIntervalMs
|
|
60
|
+
};
|
|
61
|
+
const dir = dirname(configPath);
|
|
62
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
63
|
+
const tmp = `${configPath}.tmp`;
|
|
64
|
+
writeFileSync(tmp, JSON.stringify(merged, null, 2));
|
|
65
|
+
renameSync(tmp, configPath);
|
|
66
|
+
return merged;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export {
|
|
70
|
+
defaultDispatcherConfigPath,
|
|
71
|
+
resolveDispatcherTuning,
|
|
72
|
+
writeDispatcherTuning
|
|
73
|
+
};
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
status
|
|
3
|
+
} from "./chunk-KB2EHQW7.js";
|
|
1
4
|
import {
|
|
2
5
|
uninstall
|
|
3
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-BIP2TBJ5.js";
|
|
4
7
|
import {
|
|
5
8
|
install
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import {
|
|
8
|
-
status
|
|
9
|
-
} from "./chunk-Q5BA2J2C.js";
|
|
9
|
+
} from "./chunk-TSLDSGOD.js";
|
|
10
10
|
import {
|
|
11
11
|
AgenticMailApiError
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-WTAITYZR.js";
|
|
13
13
|
|
|
14
14
|
// src/http-routes.ts
|
|
15
15
|
import { Router } from "express";
|
|
@@ -11,8 +11,9 @@ import {
|
|
|
11
11
|
ensureAccount,
|
|
12
12
|
listAccounts,
|
|
13
13
|
renderSubagentMarkdown,
|
|
14
|
-
resolveConfig
|
|
15
|
-
|
|
14
|
+
resolveConfig,
|
|
15
|
+
setAccountRole
|
|
16
|
+
} from "./chunk-WTAITYZR.js";
|
|
16
17
|
|
|
17
18
|
// src/install.ts
|
|
18
19
|
import { existsSync, mkdirSync, readdirSync, writeFileSync, readFileSync, unlinkSync } from "fs";
|
|
@@ -98,7 +99,14 @@ async function install(opts = {}) {
|
|
|
98
99
|
"AgenticMail master key not found. Run `agenticmail setup` first to generate one, or pass { masterKey } to install() explicitly."
|
|
99
100
|
);
|
|
100
101
|
}
|
|
101
|
-
|
|
102
|
+
let bridge = await ensureAccount(cfg.apiUrl, cfg.masterKey, cfg.bridgeAgentName, "bridge");
|
|
103
|
+
if (bridge.role && bridge.role !== "bridge") {
|
|
104
|
+
try {
|
|
105
|
+
await setAccountRole(cfg.apiUrl, cfg.masterKey, bridge.id, "bridge");
|
|
106
|
+
bridge = { ...bridge, role: "bridge" };
|
|
107
|
+
} catch {
|
|
108
|
+
}
|
|
109
|
+
}
|
|
102
110
|
const everyAccount = await listAccounts(cfg.apiUrl, cfg.masterKey);
|
|
103
111
|
const exposable = selectExposableAgents(everyAccount, cfg);
|
|
104
112
|
const accountKeys = {};
|
|
@@ -82,6 +82,15 @@ async function ensureAccount(apiUrl, masterKey, name, role = "assistant") {
|
|
|
82
82
|
async function deleteAccount(apiUrl, masterKey, id) {
|
|
83
83
|
await request(apiUrl, masterKey, `/accounts/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
84
84
|
}
|
|
85
|
+
async function setAccountRole(apiUrl, masterKey, id, role) {
|
|
86
|
+
const updated = await request(
|
|
87
|
+
apiUrl,
|
|
88
|
+
masterKey,
|
|
89
|
+
`/accounts/${encodeURIComponent(id)}/role`,
|
|
90
|
+
{ method: "PATCH", body: { role } }
|
|
91
|
+
);
|
|
92
|
+
return updated ?? { role };
|
|
93
|
+
}
|
|
85
94
|
async function listInboxForAgent(apiUrl, agentApiKey, opts = {}) {
|
|
86
95
|
const limit = Math.max(1, Math.min(opts.limit ?? 50, 100));
|
|
87
96
|
const url = `${apiUrl.replace(/\/$/, "")}/api/agenticmail/mail/inbox?limit=${limit}`;
|
|
@@ -282,6 +291,7 @@ export {
|
|
|
282
291
|
getAccountByName,
|
|
283
292
|
ensureAccount,
|
|
284
293
|
deleteAccount,
|
|
294
|
+
setAccountRole,
|
|
285
295
|
listInboxForAgent,
|
|
286
296
|
listPendingTasksForAgent,
|
|
287
297
|
resolveConfig,
|
package/dist/cli.js
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
defaultDispatcherConfigPath,
|
|
4
|
+
resolveDispatcherTuning,
|
|
5
|
+
writeDispatcherTuning
|
|
6
|
+
} from "./chunk-B5JDOV32.js";
|
|
7
|
+
import {
|
|
8
|
+
status
|
|
9
|
+
} from "./chunk-KB2EHQW7.js";
|
|
2
10
|
import {
|
|
3
11
|
uninstall
|
|
4
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-BIP2TBJ5.js";
|
|
5
13
|
import {
|
|
6
14
|
install
|
|
7
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-TSLDSGOD.js";
|
|
8
16
|
import "./chunk-LO5EQSQA.js";
|
|
9
|
-
import {
|
|
10
|
-
status
|
|
11
|
-
} from "./chunk-Q5BA2J2C.js";
|
|
12
17
|
import "./chunk-US5FT2UB.js";
|
|
13
18
|
import {
|
|
14
19
|
AgenticMailApiError
|
|
15
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-WTAITYZR.js";
|
|
16
21
|
|
|
17
22
|
// src/cli.ts
|
|
18
23
|
var GREEN = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
@@ -42,17 +47,31 @@ function usage() {
|
|
|
42
47
|
print(` install Register AgenticMail with Claude Code (default)`);
|
|
43
48
|
print(` uninstall Remove the registration`);
|
|
44
49
|
print(` status Show what's currently installed`);
|
|
50
|
+
print(` tune View / change dispatcher tuning knobs (rate limits, concurrency)`);
|
|
45
51
|
print("");
|
|
46
52
|
print(` ${BOLD("Flags:")}`);
|
|
47
|
-
print(` --json (status) Emit machine-readable JSON instead of prose`);
|
|
53
|
+
print(` --json (status / tune) Emit machine-readable JSON instead of prose`);
|
|
48
54
|
print(` --purge-bridge (uninstall) Also delete the AgenticMail bridge agent`);
|
|
55
|
+
print("");
|
|
56
|
+
print(` ${BOLD("Tune flags:")}`);
|
|
57
|
+
print(` --max-concurrent N Cap total simultaneous workers across all agents (default 50)`);
|
|
58
|
+
print(` --max-wakes-per-thread N Wakes a single (agent, thread) pair gets per window (default 10)`);
|
|
59
|
+
print(` --wake-window-ms N Rolling window for the above counter, ms (default 86400000 = 24h)`);
|
|
60
|
+
print(` --wake-coalesce-ms N Burst-debounce \u2014 collapse rapid replies into one wake (default 30000 = 30s, set 0 to disable)`);
|
|
61
|
+
print(` --sync-ms N How often the dispatcher polls /accounts for new agents (default 30000)`);
|
|
62
|
+
print(` --reset Delete ~/.agenticmail/dispatcher.json, return to defaults`);
|
|
49
63
|
print(` -h, --help Show this help and exit`);
|
|
50
64
|
print("");
|
|
51
|
-
print(` ${BOLD("Environment overrides:")}`);
|
|
52
|
-
print(` AGENTICMAIL_API_URL
|
|
53
|
-
print(` AGENTICMAIL_MASTER_KEY
|
|
54
|
-
print(` CLAUDE_CODE_CONFIG_PATH
|
|
55
|
-
print(` CLAUDE_CODE_AGENTS_DIR
|
|
65
|
+
print(` ${BOLD("Environment overrides (same effect as the flags above, for PM2 setups):")}`);
|
|
66
|
+
print(` AGENTICMAIL_API_URL Override AgenticMail master API URL`);
|
|
67
|
+
print(` AGENTICMAIL_MASTER_KEY Override master key`);
|
|
68
|
+
print(` CLAUDE_CODE_CONFIG_PATH Override Claude Code config path`);
|
|
69
|
+
print(` CLAUDE_CODE_AGENTS_DIR Override Claude Code agents dir`);
|
|
70
|
+
print(` AGENTICMAIL_DISPATCHER_MAX Same as --max-concurrent`);
|
|
71
|
+
print(` AGENTICMAIL_DISPATCHER_MAX_WAKES_PER_THREAD Same as --max-wakes-per-thread`);
|
|
72
|
+
print(` AGENTICMAIL_DISPATCHER_WAKE_WINDOW_MS Same as --wake-window-ms`);
|
|
73
|
+
print(` AGENTICMAIL_DISPATCHER_COALESCE_MS Same as --wake-coalesce-ms`);
|
|
74
|
+
print(` AGENTICMAIL_DISPATCHER_SYNC Same as --sync-ms`);
|
|
56
75
|
print("");
|
|
57
76
|
}
|
|
58
77
|
function envOptions() {
|
|
@@ -148,6 +167,92 @@ async function runStatus(asJson) {
|
|
|
148
167
|
return 2;
|
|
149
168
|
}
|
|
150
169
|
}
|
|
170
|
+
function argNum(args, flag) {
|
|
171
|
+
for (let i = 0; i < args.length; i++) {
|
|
172
|
+
const a = args[i];
|
|
173
|
+
if (a === flag && i + 1 < args.length) {
|
|
174
|
+
const n = parseInt(args[i + 1], 10);
|
|
175
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
176
|
+
}
|
|
177
|
+
if (a.startsWith(`${flag}=`)) {
|
|
178
|
+
const n = parseInt(a.slice(flag.length + 1), 10);
|
|
179
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return void 0;
|
|
183
|
+
}
|
|
184
|
+
async function runTune(args) {
|
|
185
|
+
const { existsSync, unlinkSync } = await import("fs");
|
|
186
|
+
const path = defaultDispatcherConfigPath();
|
|
187
|
+
const asJson = args.includes("--json");
|
|
188
|
+
if (args.includes("--reset")) {
|
|
189
|
+
try {
|
|
190
|
+
if (existsSync(path)) unlinkSync(path);
|
|
191
|
+
} catch {
|
|
192
|
+
}
|
|
193
|
+
if (asJson) {
|
|
194
|
+
print(JSON.stringify({ reset: true, path }, null, 2));
|
|
195
|
+
} else {
|
|
196
|
+
print("");
|
|
197
|
+
print(` ${PINK("\u{1F380} Dispatcher tuning")}`);
|
|
198
|
+
print("");
|
|
199
|
+
ok(`Reset: deleted ${path}`);
|
|
200
|
+
print(` ${DIM("The dispatcher will use built-in defaults until you re-tune.")}`);
|
|
201
|
+
print("");
|
|
202
|
+
}
|
|
203
|
+
return 0;
|
|
204
|
+
}
|
|
205
|
+
const patch = {
|
|
206
|
+
maxConcurrentWorkers: argNum(args, "--max-concurrent"),
|
|
207
|
+
maxWakesPerThread: argNum(args, "--max-wakes-per-thread"),
|
|
208
|
+
wakeWindowMs: argNum(args, "--wake-window-ms"),
|
|
209
|
+
wakeCoalesceMs: argNum(args, "--wake-coalesce-ms"),
|
|
210
|
+
accountSyncIntervalMs: argNum(args, "--sync-ms")
|
|
211
|
+
};
|
|
212
|
+
const anyFlag = Object.values(patch).some((v) => v !== void 0);
|
|
213
|
+
if (anyFlag) {
|
|
214
|
+
const merged = writeDispatcherTuning(patch);
|
|
215
|
+
if (asJson) {
|
|
216
|
+
print(JSON.stringify(merged, null, 2));
|
|
217
|
+
return 0;
|
|
218
|
+
}
|
|
219
|
+
print("");
|
|
220
|
+
print(` ${PINK("\u{1F380} Dispatcher tuning saved")}`);
|
|
221
|
+
print("");
|
|
222
|
+
ok(`Wrote ${path}`);
|
|
223
|
+
dim(` maxConcurrentWorkers: ${merged.maxConcurrentWorkers ?? "(default)"}`);
|
|
224
|
+
dim(` maxWakesPerThread: ${merged.maxWakesPerThread ?? "(default)"}`);
|
|
225
|
+
dim(` wakeWindowMs: ${merged.wakeWindowMs ?? "(default)"}`);
|
|
226
|
+
dim(` wakeCoalesceMs: ${merged.wakeCoalesceMs ?? "(default)"}`);
|
|
227
|
+
dim(` accountSyncIntervalMs: ${merged.accountSyncIntervalMs ?? "(default)"}`);
|
|
228
|
+
print("");
|
|
229
|
+
print(` ${BOLD("Next:")} restart the dispatcher daemon to apply.`);
|
|
230
|
+
print(` ${DIM("pm2 restart agenticmail-claudecode-dispatcher")}`);
|
|
231
|
+
print("");
|
|
232
|
+
return 0;
|
|
233
|
+
}
|
|
234
|
+
const resolved = resolveDispatcherTuning();
|
|
235
|
+
if (asJson) {
|
|
236
|
+
print(JSON.stringify({ resolved, path }, null, 2));
|
|
237
|
+
return 0;
|
|
238
|
+
}
|
|
239
|
+
print("");
|
|
240
|
+
print(` ${PINK("\u{1F380} Dispatcher tuning (current)")}`);
|
|
241
|
+
print("");
|
|
242
|
+
print(` Config file: ${path}`);
|
|
243
|
+
print("");
|
|
244
|
+
print(` ${BOLD("Effective values (env > file > built-in default):")}`);
|
|
245
|
+
dim(` maxConcurrentWorkers: ${resolved.maxConcurrentWorkers ?? "50 (default)"}`);
|
|
246
|
+
dim(` maxWakesPerThread: ${resolved.maxWakesPerThread ?? "10 (default)"}`);
|
|
247
|
+
dim(` wakeWindowMs: ${resolved.wakeWindowMs ?? "86400000 (default \u2014 24h)"}`);
|
|
248
|
+
dim(` wakeCoalesceMs: ${resolved.wakeCoalesceMs ?? "30000 (default \u2014 30s)"}`);
|
|
249
|
+
dim(` accountSyncIntervalMs: ${resolved.accountSyncIntervalMs ?? "30000 (default)"}`);
|
|
250
|
+
print("");
|
|
251
|
+
print(` ${BOLD("Change with flags, e.g.:")}`);
|
|
252
|
+
dim(` agenticmail-claudecode tune --max-wakes-per-thread 100 --max-concurrent 200`);
|
|
253
|
+
print("");
|
|
254
|
+
return 0;
|
|
255
|
+
}
|
|
151
256
|
async function main() {
|
|
152
257
|
const args = process.argv.slice(2);
|
|
153
258
|
if (args.includes("-h") || args.includes("--help") || args[0] === "help") {
|
|
@@ -163,6 +268,8 @@ async function main() {
|
|
|
163
268
|
return runUninstall(args.includes("--purge-bridge"));
|
|
164
269
|
case "status":
|
|
165
270
|
return runStatus(args.includes("--json"));
|
|
271
|
+
case "tune":
|
|
272
|
+
return runTune(args);
|
|
166
273
|
default:
|
|
167
274
|
fail(`Unknown command: ${command}`);
|
|
168
275
|
usage();
|
package/dist/dispatcher-bin.js
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
resolveDispatcherTuning
|
|
4
|
+
} from "./chunk-B5JDOV32.js";
|
|
2
5
|
import {
|
|
3
6
|
Dispatcher
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-APRMWXZB.js";
|
|
8
|
+
import "./chunk-WTAITYZR.js";
|
|
6
9
|
|
|
7
10
|
// src/dispatcher-bin.ts
|
|
8
11
|
async function main() {
|
|
12
|
+
const tuning = resolveDispatcherTuning();
|
|
13
|
+
console.error(
|
|
14
|
+
`[dispatcher-bin] tuning: maxConcurrentWorkers=${tuning.maxConcurrentWorkers ?? "(default)"} maxWakesPerThread=${tuning.maxWakesPerThread ?? "(default)"} wakeWindowMs=${tuning.wakeWindowMs ?? "(default)"} wakeCoalesceMs=${tuning.wakeCoalesceMs ?? "(default)"} accountSyncIntervalMs=${tuning.accountSyncIntervalMs ?? "(default)"}`
|
|
15
|
+
);
|
|
9
16
|
const dispatcher = new Dispatcher({
|
|
10
17
|
apiUrl: process.env.AGENTICMAIL_API_URL,
|
|
11
18
|
masterKey: process.env.AGENTICMAIL_MASTER_KEY,
|
|
12
19
|
agentsDir: process.env.CLAUDE_CODE_AGENTS_DIR,
|
|
13
|
-
maxConcurrentWorkers:
|
|
14
|
-
|
|
20
|
+
maxConcurrentWorkers: tuning.maxConcurrentWorkers,
|
|
21
|
+
maxWakesPerThread: tuning.maxWakesPerThread,
|
|
22
|
+
wakeWindowMs: tuning.wakeWindowMs,
|
|
23
|
+
wakeCoalesceMs: tuning.wakeCoalesceMs,
|
|
24
|
+
accountSyncIntervalMs: tuning.accountSyncIntervalMs
|
|
15
25
|
});
|
|
16
26
|
const shutdown = async (sig) => {
|
|
17
27
|
console.error(`[dispatcher-bin] received ${sig} \u2014 shutting down`);
|
|
@@ -32,11 +42,6 @@ async function main() {
|
|
|
32
42
|
});
|
|
33
43
|
await dispatcher.start();
|
|
34
44
|
}
|
|
35
|
-
function positiveInt(s) {
|
|
36
|
-
if (!s) return void 0;
|
|
37
|
-
const n = parseInt(s, 10);
|
|
38
|
-
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
39
|
-
}
|
|
40
45
|
main().catch((err) => {
|
|
41
46
|
console.error(`[dispatcher-bin] fatal: ${err.message}`);
|
|
42
47
|
process.exit(1);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tuning knobs for the dispatcher daemon.
|
|
3
|
+
*
|
|
4
|
+
* # Why this exists
|
|
5
|
+
*
|
|
6
|
+
* The dispatcher has several rate-limit / concurrency knobs that need
|
|
7
|
+
* to be tunable WITHOUT a code change:
|
|
8
|
+
*
|
|
9
|
+
* - `maxConcurrentWorkers` — global worker cap (default 50)
|
|
10
|
+
* - `maxWakesPerThread` — wakes per (agent, thread) per window (default 10)
|
|
11
|
+
* - `wakeWindowMs` — the window itself (default 24h)
|
|
12
|
+
* - `wakeCoalesceMs` — burst-debounce window (default 30s)
|
|
13
|
+
* - `accountSyncIntervalMs` — how often to poll /accounts (default 30s)
|
|
14
|
+
*
|
|
15
|
+
* The DEFAULTS are conservative — protect a fresh install from runaway
|
|
16
|
+
* cost. Power users running active coordination on a single thread
|
|
17
|
+
* routinely hit the 10/24h wake cap and need it raised. Today (before
|
|
18
|
+
* this module) the only way to do that was edit dispatcher.ts and rebuild,
|
|
19
|
+
* which is absurd.
|
|
20
|
+
*
|
|
21
|
+
* # Three input sources, in precedence order
|
|
22
|
+
*
|
|
23
|
+
* 1. Explicit constructor args (programmatic callers, tests)
|
|
24
|
+
* 2. Env vars (PM2 ecosystem.config.cjs lives here)
|
|
25
|
+
* 3. `~/.agenticmail/dispatcher.json` (persistent operator preference,
|
|
26
|
+
* written by the CLI's `agenticmail dispatcher tune` command)
|
|
27
|
+
* 4. Hard-coded defaults
|
|
28
|
+
*
|
|
29
|
+
* Earlier sources win.
|
|
30
|
+
*
|
|
31
|
+
* # File format
|
|
32
|
+
*
|
|
33
|
+
* { "version": 1,
|
|
34
|
+
* "maxConcurrentWorkers": 200,
|
|
35
|
+
* "maxWakesPerThread": 50,
|
|
36
|
+
* "wakeWindowMs": 86400000,
|
|
37
|
+
* "wakeCoalesceMs": 30000,
|
|
38
|
+
* "accountSyncIntervalMs": 30000 }
|
|
39
|
+
*
|
|
40
|
+
* Missing keys fall through to the next precedence level. All values
|
|
41
|
+
* are integers; non-positive / non-finite values fall through (so a
|
|
42
|
+
* broken edit produces a slightly-stale config, not a broken
|
|
43
|
+
* dispatcher).
|
|
44
|
+
*/
|
|
45
|
+
interface DispatcherTuning {
|
|
46
|
+
maxConcurrentWorkers?: number;
|
|
47
|
+
maxWakesPerThread?: number;
|
|
48
|
+
wakeWindowMs?: number;
|
|
49
|
+
wakeCoalesceMs?: number;
|
|
50
|
+
accountSyncIntervalMs?: number;
|
|
51
|
+
}
|
|
52
|
+
declare function defaultDispatcherConfigPath(): string;
|
|
53
|
+
/**
|
|
54
|
+
* Resolve final tuning values by merging the three precedence layers:
|
|
55
|
+
* explicit args > env vars > file > defaults (left to the consumer).
|
|
56
|
+
*
|
|
57
|
+
* Returns ONLY the keys that were explicitly set — the caller passes
|
|
58
|
+
* the result through to the Dispatcher constructor, whose defaults
|
|
59
|
+
* fill in anything still undefined.
|
|
60
|
+
*/
|
|
61
|
+
declare function resolveDispatcherTuning(opts?: {
|
|
62
|
+
explicit?: DispatcherTuning;
|
|
63
|
+
env?: NodeJS.ProcessEnv;
|
|
64
|
+
configPath?: string;
|
|
65
|
+
}): DispatcherTuning;
|
|
66
|
+
/**
|
|
67
|
+
* Persist the operator's preferences to ~/.agenticmail/dispatcher.json
|
|
68
|
+
* atomically (.tmp + rename) so a power outage mid-write never produces
|
|
69
|
+
* a half-written config. Only writes the keys that are explicitly set
|
|
70
|
+
* in the patch — preserves keys the user already configured.
|
|
71
|
+
*
|
|
72
|
+
* Returns the resulting on-disk shape so the caller can echo it back.
|
|
73
|
+
*/
|
|
74
|
+
declare function writeDispatcherTuning(patch: DispatcherTuning, configPath?: string): DispatcherTuning & {
|
|
75
|
+
version: number;
|
|
76
|
+
updatedAtMs: number;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export { type DispatcherTuning, defaultDispatcherConfigPath, resolveDispatcherTuning, writeDispatcherTuning };
|
package/dist/dispatcher.js
CHANGED
package/dist/http-routes.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createIntegrationRoutes
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-THUNXHMQ.js";
|
|
4
|
+
import "./chunk-KB2EHQW7.js";
|
|
5
|
+
import "./chunk-BIP2TBJ5.js";
|
|
6
|
+
import "./chunk-TSLDSGOD.js";
|
|
6
7
|
import "./chunk-LO5EQSQA.js";
|
|
7
|
-
import "./chunk-Q5BA2J2C.js";
|
|
8
8
|
import "./chunk-US5FT2UB.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-WTAITYZR.js";
|
|
10
10
|
export {
|
|
11
11
|
createIntegrationRoutes
|
|
12
12
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { A as AgenticMailAccount } from './config-CXW3gXFC.js';
|
|
|
5
5
|
export { C as ClaudeCodeIntegrationConfig, I as InstallResult, a as InstallStatus, R as ResolveConfigOptions, U as UninstallResult, r as resolveConfig } from './config-CXW3gXFC.js';
|
|
6
6
|
export { createIntegrationRoutes } from './http-routes.js';
|
|
7
7
|
export { Dispatcher, DispatcherOptions, QueryFn } from './dispatcher.js';
|
|
8
|
+
export { DispatcherTuning, defaultDispatcherConfigPath, resolveDispatcherTuning, writeDispatcherTuning } from './dispatcher-tuning.js';
|
|
8
9
|
import 'express';
|
|
9
10
|
|
|
10
11
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultDispatcherConfigPath,
|
|
3
|
+
resolveDispatcherTuning,
|
|
4
|
+
writeDispatcherTuning
|
|
5
|
+
} from "./chunk-B5JDOV32.js";
|
|
1
6
|
import {
|
|
2
7
|
Dispatcher,
|
|
3
8
|
loadPersonaForAgent
|
|
4
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-APRMWXZB.js";
|
|
5
10
|
import {
|
|
6
11
|
createIntegrationRoutes
|
|
7
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-THUNXHMQ.js";
|
|
13
|
+
import {
|
|
14
|
+
status
|
|
15
|
+
} from "./chunk-KB2EHQW7.js";
|
|
8
16
|
import {
|
|
9
17
|
uninstall
|
|
10
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-BIP2TBJ5.js";
|
|
11
19
|
import {
|
|
12
20
|
install
|
|
13
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-TSLDSGOD.js";
|
|
14
22
|
import "./chunk-LO5EQSQA.js";
|
|
15
|
-
import {
|
|
16
|
-
status
|
|
17
|
-
} from "./chunk-Q5BA2J2C.js";
|
|
18
23
|
import "./chunk-US5FT2UB.js";
|
|
19
24
|
import {
|
|
20
25
|
AgenticMailApiError,
|
|
@@ -27,13 +32,14 @@ import {
|
|
|
27
32
|
renderPersonaBody,
|
|
28
33
|
renderSubagentMarkdown,
|
|
29
34
|
resolveConfig
|
|
30
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-WTAITYZR.js";
|
|
31
36
|
export {
|
|
32
37
|
AgenticMailApiError,
|
|
33
38
|
Dispatcher,
|
|
34
39
|
MANAGED_BY_MARKER,
|
|
35
40
|
checkApiHealth,
|
|
36
41
|
createIntegrationRoutes,
|
|
42
|
+
defaultDispatcherConfigPath,
|
|
37
43
|
deleteAccount,
|
|
38
44
|
ensureAccount,
|
|
39
45
|
getAccountByName,
|
|
@@ -43,6 +49,8 @@ export {
|
|
|
43
49
|
renderPersonaBody,
|
|
44
50
|
renderSubagentMarkdown,
|
|
45
51
|
resolveConfig,
|
|
52
|
+
resolveDispatcherTuning,
|
|
46
53
|
status,
|
|
47
|
-
uninstall
|
|
54
|
+
uninstall,
|
|
55
|
+
writeDispatcherTuning
|
|
48
56
|
};
|
package/dist/install.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
install,
|
|
3
3
|
selectExposableAgents
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-TSLDSGOD.js";
|
|
5
5
|
import "./chunk-LO5EQSQA.js";
|
|
6
6
|
import "./chunk-US5FT2UB.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-WTAITYZR.js";
|
|
8
8
|
export {
|
|
9
9
|
install,
|
|
10
10
|
selectExposableAgents
|
package/dist/status.js
CHANGED
package/dist/uninstall.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agenticmail/claudecode",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
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",
|
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
"LICENSE"
|
|
42
42
|
],
|
|
43
43
|
"scripts": {
|
|
44
|
-
"build": "tsup src/index.ts src/cli.ts src/install.ts src/uninstall.ts src/status.ts src/http-routes.ts src/dispatcher.ts src/dispatcher-bin.ts src/mail-hook.ts --format esm --dts --clean",
|
|
44
|
+
"build": "tsup src/index.ts src/cli.ts src/install.ts src/uninstall.ts src/status.ts src/http-routes.ts src/dispatcher.ts src/dispatcher-bin.ts src/dispatcher-tuning.ts src/mail-hook.ts --format esm --dts --clean",
|
|
45
45
|
"test": "vitest run --passWithNoTests",
|
|
46
46
|
"preuninstall": "node scripts/uninstall.mjs",
|
|
47
47
|
"prepublishOnly": "npm run build"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@agenticmail/core": "^0.9.
|
|
50
|
+
"@agenticmail/core": "^0.9.3",
|
|
51
51
|
"@agenticmail/mcp": "^0.9.2",
|
|
52
52
|
"@anthropic-ai/claude-agent-sdk": "^0.2.140"
|
|
53
53
|
},
|