claude-code-controller 0.2.0 → 0.4.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.
- package/README.md +285 -302
- package/dist/api/index.cjs +510 -53
- package/dist/api/index.cjs.map +1 -1
- package/dist/api/index.d.cts +36 -8
- package/dist/api/index.d.ts +36 -8
- package/dist/api/index.js +510 -53
- package/dist/api/index.js.map +1 -1
- package/dist/{controller-C9bh_59H.d.cts → claude-DectLQVR.d.cts} +239 -1
- package/dist/{controller-C9bh_59H.d.ts → claude-DectLQVR.d.ts} +239 -1
- package/dist/index.cjs +467 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +464 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -20,12 +20,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
Agent: () => Agent,
|
|
23
24
|
AgentHandle: () => AgentHandle,
|
|
24
25
|
ClaudeCodeController: () => ClaudeCodeController,
|
|
25
26
|
InboxPoller: () => InboxPoller,
|
|
26
27
|
ProcessManager: () => ProcessManager,
|
|
28
|
+
Session: () => Session,
|
|
27
29
|
TaskManager: () => TaskManager,
|
|
28
30
|
TeamManager: () => TeamManager,
|
|
31
|
+
claude: () => claude,
|
|
29
32
|
createLogger: () => createLogger,
|
|
30
33
|
inboxPath: () => inboxPath,
|
|
31
34
|
inboxesDir: () => inboxesDir,
|
|
@@ -43,6 +46,10 @@ __export(index_exports, {
|
|
|
43
46
|
});
|
|
44
47
|
module.exports = __toCommonJS(index_exports);
|
|
45
48
|
|
|
49
|
+
// src/claude.ts
|
|
50
|
+
var import_node_events2 = require("events");
|
|
51
|
+
var import_node_crypto3 = require("crypto");
|
|
52
|
+
|
|
46
53
|
// src/controller.ts
|
|
47
54
|
var import_node_events = require("events");
|
|
48
55
|
var import_node_child_process3 = require("child_process");
|
|
@@ -357,6 +364,9 @@ var ProcessManager = class {
|
|
|
357
364
|
if (opts.model) {
|
|
358
365
|
claudeArgs.push("--model", opts.model);
|
|
359
366
|
}
|
|
367
|
+
if (opts.permissionMode) {
|
|
368
|
+
claudeArgs.push("--permission-mode", opts.permissionMode);
|
|
369
|
+
}
|
|
360
370
|
if (opts.permissions) {
|
|
361
371
|
for (const perm of opts.permissions) {
|
|
362
372
|
claudeArgs.push("--allowedTools", perm);
|
|
@@ -740,6 +750,11 @@ var silentLogger = {
|
|
|
740
750
|
};
|
|
741
751
|
|
|
742
752
|
// src/controller.ts
|
|
753
|
+
var PROTOCOL_ONLY_TYPES = /* @__PURE__ */ new Set([
|
|
754
|
+
"shutdown_approved",
|
|
755
|
+
"plan_approval_response",
|
|
756
|
+
"permission_response"
|
|
757
|
+
]);
|
|
743
758
|
var AGENT_COLORS = [
|
|
744
759
|
"#00FF00",
|
|
745
760
|
"#00BFFF",
|
|
@@ -864,6 +879,7 @@ var ClaudeCodeController = class extends import_node_events.EventEmitter {
|
|
|
864
879
|
color,
|
|
865
880
|
claudeBinary: this.claudeBinary,
|
|
866
881
|
permissions: opts.permissions,
|
|
882
|
+
permissionMode: opts.permissionMode,
|
|
867
883
|
env
|
|
868
884
|
});
|
|
869
885
|
this.emit("agent:spawned", opts.name, proc.pid ?? 0);
|
|
@@ -932,11 +948,7 @@ var ClaudeCodeController = class extends import_node_events.EventEmitter {
|
|
|
932
948
|
const unread = await readUnread(this.teamName, "controller");
|
|
933
949
|
const fromAgent = unread.filter((m) => m.from === agentName);
|
|
934
950
|
if (fromAgent.length > 0) {
|
|
935
|
-
const PROTOCOL_TYPES =
|
|
936
|
-
"shutdown_approved",
|
|
937
|
-
"plan_approval_response",
|
|
938
|
-
"permission_response"
|
|
939
|
-
]);
|
|
951
|
+
const PROTOCOL_TYPES = PROTOCOL_ONLY_TYPES;
|
|
940
952
|
const meaningful = fromAgent.filter((m) => {
|
|
941
953
|
const parsed = parseMessage(m);
|
|
942
954
|
return parsed.type !== "idle_notification" && !PROTOCOL_TYPES.has(parsed.type);
|
|
@@ -969,7 +981,7 @@ var ClaudeCodeController = class extends import_node_events.EventEmitter {
|
|
|
969
981
|
const unread = await readUnread(this.teamName, "controller");
|
|
970
982
|
const meaningful = unread.filter((m) => {
|
|
971
983
|
const parsed = parseMessage(m);
|
|
972
|
-
return parsed.type !== "idle_notification";
|
|
984
|
+
return parsed.type !== "idle_notification" && !PROTOCOL_ONLY_TYPES.has(parsed.type);
|
|
973
985
|
});
|
|
974
986
|
if (meaningful.length > 0) {
|
|
975
987
|
return meaningful[0];
|
|
@@ -1130,14 +1142,463 @@ var ClaudeCodeController = class extends import_node_events.EventEmitter {
|
|
|
1130
1142
|
function sleep2(ms) {
|
|
1131
1143
|
return new Promise((r) => setTimeout(r, ms));
|
|
1132
1144
|
}
|
|
1145
|
+
|
|
1146
|
+
// src/claude.ts
|
|
1147
|
+
Symbol.asyncDispose ??= /* @__PURE__ */ Symbol("Symbol.asyncDispose");
|
|
1148
|
+
function buildEnv(opts) {
|
|
1149
|
+
const env = { ...opts.env };
|
|
1150
|
+
if (opts.apiKey) env.ANTHROPIC_AUTH_TOKEN = opts.apiKey;
|
|
1151
|
+
if (opts.baseUrl) env.ANTHROPIC_BASE_URL = opts.baseUrl;
|
|
1152
|
+
if (opts.timeout != null) env.API_TIMEOUT_MS = String(opts.timeout);
|
|
1153
|
+
return env;
|
|
1154
|
+
}
|
|
1155
|
+
function resolvePermissions(preset) {
|
|
1156
|
+
switch (preset) {
|
|
1157
|
+
case "edit":
|
|
1158
|
+
return { permissionMode: "acceptEdits" };
|
|
1159
|
+
case "plan":
|
|
1160
|
+
return { permissionMode: "plan" };
|
|
1161
|
+
case "ask":
|
|
1162
|
+
return { permissionMode: "default" };
|
|
1163
|
+
case "full":
|
|
1164
|
+
default:
|
|
1165
|
+
return { permissionMode: void 0 };
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
function waitForReady(controller, agentName, timeoutMs = 15e3) {
|
|
1169
|
+
return new Promise((resolve, reject) => {
|
|
1170
|
+
let settled = false;
|
|
1171
|
+
const timer = setTimeout(() => {
|
|
1172
|
+
if (settled) return;
|
|
1173
|
+
cleanup();
|
|
1174
|
+
reject(
|
|
1175
|
+
new Error(
|
|
1176
|
+
`Agent "${agentName}" did not become ready within ${timeoutMs}ms`
|
|
1177
|
+
)
|
|
1178
|
+
);
|
|
1179
|
+
}, timeoutMs);
|
|
1180
|
+
const onReady = (name) => {
|
|
1181
|
+
if (name === agentName && !settled) {
|
|
1182
|
+
settled = true;
|
|
1183
|
+
cleanup();
|
|
1184
|
+
resolve();
|
|
1185
|
+
}
|
|
1186
|
+
};
|
|
1187
|
+
const onExit = (name, code) => {
|
|
1188
|
+
if (name === agentName && !settled) {
|
|
1189
|
+
settled = true;
|
|
1190
|
+
cleanup();
|
|
1191
|
+
reject(
|
|
1192
|
+
new Error(
|
|
1193
|
+
`Agent "${agentName}" exited before becoming ready (code=${code})`
|
|
1194
|
+
)
|
|
1195
|
+
);
|
|
1196
|
+
}
|
|
1197
|
+
};
|
|
1198
|
+
const onSpawned = (name) => {
|
|
1199
|
+
if (name === agentName && !settled) {
|
|
1200
|
+
settled = true;
|
|
1201
|
+
cleanup();
|
|
1202
|
+
resolve();
|
|
1203
|
+
}
|
|
1204
|
+
};
|
|
1205
|
+
const cleanup = () => {
|
|
1206
|
+
clearTimeout(timer);
|
|
1207
|
+
controller.removeListener("idle", onReady);
|
|
1208
|
+
controller.removeListener("message", onReady);
|
|
1209
|
+
controller.removeListener("agent:spawned", onSpawned);
|
|
1210
|
+
controller.removeListener("agent:exited", onExit);
|
|
1211
|
+
};
|
|
1212
|
+
controller.on("idle", onReady);
|
|
1213
|
+
controller.on("message", onReady);
|
|
1214
|
+
controller.on("agent:spawned", onSpawned);
|
|
1215
|
+
controller.on("agent:exited", onExit);
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
var Agent = class _Agent extends import_node_events2.EventEmitter {
|
|
1219
|
+
controller;
|
|
1220
|
+
handle;
|
|
1221
|
+
ownsController;
|
|
1222
|
+
disposed = false;
|
|
1223
|
+
boundListeners = [];
|
|
1224
|
+
constructor(controller, handle, ownsController, behavior) {
|
|
1225
|
+
super();
|
|
1226
|
+
this.controller = controller;
|
|
1227
|
+
this.handle = handle;
|
|
1228
|
+
this.ownsController = ownsController;
|
|
1229
|
+
this.wireEvents();
|
|
1230
|
+
this.wireBehavior(behavior);
|
|
1231
|
+
}
|
|
1232
|
+
/** Create a standalone agent (owns its own controller). */
|
|
1233
|
+
static async create(opts = {}) {
|
|
1234
|
+
const name = opts.name ?? `agent-${(0, import_node_crypto3.randomUUID)().slice(0, 8)}`;
|
|
1235
|
+
const env = buildEnv(opts);
|
|
1236
|
+
const { permissionMode } = resolvePermissions(opts.permissions);
|
|
1237
|
+
const controller = new ClaudeCodeController({
|
|
1238
|
+
teamName: `claude-${(0, import_node_crypto3.randomUUID)().slice(0, 8)}`,
|
|
1239
|
+
cwd: opts.cwd,
|
|
1240
|
+
claudeBinary: opts.claudeBinary,
|
|
1241
|
+
env,
|
|
1242
|
+
logLevel: opts.logLevel ?? "warn",
|
|
1243
|
+
logger: opts.logger
|
|
1244
|
+
});
|
|
1245
|
+
await controller.init();
|
|
1246
|
+
const ready = waitForReady(controller, name, opts.readyTimeout);
|
|
1247
|
+
try {
|
|
1248
|
+
const handle = await controller.spawnAgent({
|
|
1249
|
+
name,
|
|
1250
|
+
type: opts.type ?? "general-purpose",
|
|
1251
|
+
model: opts.model,
|
|
1252
|
+
cwd: opts.cwd,
|
|
1253
|
+
permissionMode
|
|
1254
|
+
});
|
|
1255
|
+
const agent = new _Agent(controller, handle, true, {
|
|
1256
|
+
autoApprove: opts.autoApprove,
|
|
1257
|
+
onPermission: opts.onPermission,
|
|
1258
|
+
onPlan: opts.onPlan
|
|
1259
|
+
});
|
|
1260
|
+
await ready;
|
|
1261
|
+
return agent;
|
|
1262
|
+
} catch (err) {
|
|
1263
|
+
await controller.shutdown().catch(() => {
|
|
1264
|
+
});
|
|
1265
|
+
throw err;
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
/** Create an agent within an existing session (session owns the controller). */
|
|
1269
|
+
static async createInSession(controller, name, opts = {}) {
|
|
1270
|
+
const { permissionMode } = resolvePermissions(opts.permissions);
|
|
1271
|
+
const ready = waitForReady(controller, name, opts.readyTimeout);
|
|
1272
|
+
const handle = await controller.spawnAgent({
|
|
1273
|
+
name,
|
|
1274
|
+
type: opts.type ?? "general-purpose",
|
|
1275
|
+
model: opts.model,
|
|
1276
|
+
cwd: opts.cwd,
|
|
1277
|
+
permissionMode,
|
|
1278
|
+
env: opts.env
|
|
1279
|
+
});
|
|
1280
|
+
const agent = new _Agent(controller, handle, false, {
|
|
1281
|
+
autoApprove: opts.autoApprove,
|
|
1282
|
+
onPermission: opts.onPermission,
|
|
1283
|
+
onPlan: opts.onPlan
|
|
1284
|
+
});
|
|
1285
|
+
await ready;
|
|
1286
|
+
return agent;
|
|
1287
|
+
}
|
|
1288
|
+
/** The agent's name. */
|
|
1289
|
+
get name() {
|
|
1290
|
+
return this.handle.name;
|
|
1291
|
+
}
|
|
1292
|
+
/** The agent process PID. */
|
|
1293
|
+
get pid() {
|
|
1294
|
+
return this.handle.pid;
|
|
1295
|
+
}
|
|
1296
|
+
/** Whether the agent process is still running. */
|
|
1297
|
+
get isRunning() {
|
|
1298
|
+
return this.handle.isRunning;
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* Send a message and wait for the response.
|
|
1302
|
+
*
|
|
1303
|
+
* Uses event-based waiting (via the controller's InboxPoller) instead of
|
|
1304
|
+
* polling `readUnread()` directly, which avoids a race condition where the
|
|
1305
|
+
* poller marks inbox messages as read before `receive()` can see them.
|
|
1306
|
+
*/
|
|
1307
|
+
async ask(question, opts) {
|
|
1308
|
+
this.ensureNotDisposed();
|
|
1309
|
+
const timeout = opts?.timeout ?? 12e4;
|
|
1310
|
+
const responsePromise = new Promise((resolve, reject) => {
|
|
1311
|
+
const timer = setTimeout(() => {
|
|
1312
|
+
cleanup();
|
|
1313
|
+
reject(new Error(`Timeout (${timeout}ms) waiting for response`));
|
|
1314
|
+
}, timeout);
|
|
1315
|
+
const onMsg = (text) => {
|
|
1316
|
+
cleanup();
|
|
1317
|
+
resolve(text);
|
|
1318
|
+
};
|
|
1319
|
+
const onExit = (code) => {
|
|
1320
|
+
cleanup();
|
|
1321
|
+
reject(new Error(`Agent exited (code=${code}) before responding`));
|
|
1322
|
+
};
|
|
1323
|
+
const cleanup = () => {
|
|
1324
|
+
clearTimeout(timer);
|
|
1325
|
+
this.removeListener("message", onMsg);
|
|
1326
|
+
this.removeListener("exit", onExit);
|
|
1327
|
+
};
|
|
1328
|
+
this.on("message", onMsg);
|
|
1329
|
+
this.on("exit", onExit);
|
|
1330
|
+
});
|
|
1331
|
+
const wrapped = `${question}
|
|
1332
|
+
|
|
1333
|
+
IMPORTANT: You MUST send your complete answer back using the SendMessage tool. Do NOT just think your answer \u2014 use the SendMessage tool to reply.`;
|
|
1334
|
+
await this.handle.send(wrapped);
|
|
1335
|
+
return responsePromise;
|
|
1336
|
+
}
|
|
1337
|
+
/** Send a message without waiting for a response. */
|
|
1338
|
+
async send(message) {
|
|
1339
|
+
this.ensureNotDisposed();
|
|
1340
|
+
return this.handle.send(message);
|
|
1341
|
+
}
|
|
1342
|
+
/** Wait for the next response from this agent. */
|
|
1343
|
+
async receive(opts) {
|
|
1344
|
+
this.ensureNotDisposed();
|
|
1345
|
+
const timeout = opts?.timeout ?? 12e4;
|
|
1346
|
+
return new Promise((resolve, reject) => {
|
|
1347
|
+
const timer = setTimeout(() => {
|
|
1348
|
+
cleanup();
|
|
1349
|
+
reject(new Error(`Timeout (${timeout}ms) waiting for response`));
|
|
1350
|
+
}, timeout);
|
|
1351
|
+
const onMsg = (text) => {
|
|
1352
|
+
cleanup();
|
|
1353
|
+
resolve(text);
|
|
1354
|
+
};
|
|
1355
|
+
const onExit = (code) => {
|
|
1356
|
+
cleanup();
|
|
1357
|
+
reject(new Error(`Agent exited (code=${code}) before responding`));
|
|
1358
|
+
};
|
|
1359
|
+
const cleanup = () => {
|
|
1360
|
+
clearTimeout(timer);
|
|
1361
|
+
this.removeListener("message", onMsg);
|
|
1362
|
+
this.removeListener("exit", onExit);
|
|
1363
|
+
};
|
|
1364
|
+
this.on("message", onMsg);
|
|
1365
|
+
this.on("exit", onExit);
|
|
1366
|
+
});
|
|
1367
|
+
}
|
|
1368
|
+
/**
|
|
1369
|
+
* Close this agent. If standalone, shuts down the entire controller.
|
|
1370
|
+
* If session-owned, kills only this agent's process.
|
|
1371
|
+
*/
|
|
1372
|
+
async close() {
|
|
1373
|
+
if (this.disposed) return;
|
|
1374
|
+
this.disposed = true;
|
|
1375
|
+
this.unwireEvents();
|
|
1376
|
+
if (this.ownsController) {
|
|
1377
|
+
await this.controller.shutdown();
|
|
1378
|
+
} else {
|
|
1379
|
+
await this.handle.kill();
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
/** Mark as disposed (used by Session when it closes). */
|
|
1383
|
+
markDisposed() {
|
|
1384
|
+
this.disposed = true;
|
|
1385
|
+
this.unwireEvents();
|
|
1386
|
+
}
|
|
1387
|
+
async [Symbol.asyncDispose]() {
|
|
1388
|
+
await this.close();
|
|
1389
|
+
}
|
|
1390
|
+
wireEvents() {
|
|
1391
|
+
const agentName = this.handle.name;
|
|
1392
|
+
const onMessage = (name, msg) => {
|
|
1393
|
+
if (name === agentName) this.emit("message", msg.text);
|
|
1394
|
+
};
|
|
1395
|
+
const onIdle = (name) => {
|
|
1396
|
+
if (name === agentName) this.emit("idle");
|
|
1397
|
+
};
|
|
1398
|
+
const onPermission = (name, parsed) => {
|
|
1399
|
+
if (name !== agentName) return;
|
|
1400
|
+
let handled = false;
|
|
1401
|
+
const guard = (fn) => () => {
|
|
1402
|
+
if (handled) return Promise.resolve();
|
|
1403
|
+
handled = true;
|
|
1404
|
+
return fn();
|
|
1405
|
+
};
|
|
1406
|
+
this.emit("permission", {
|
|
1407
|
+
requestId: parsed.requestId,
|
|
1408
|
+
toolName: parsed.toolName,
|
|
1409
|
+
description: parsed.description,
|
|
1410
|
+
input: parsed.input,
|
|
1411
|
+
approve: guard(
|
|
1412
|
+
() => this.controller.sendPermissionResponse(agentName, parsed.requestId, true)
|
|
1413
|
+
),
|
|
1414
|
+
reject: guard(
|
|
1415
|
+
() => this.controller.sendPermissionResponse(agentName, parsed.requestId, false)
|
|
1416
|
+
)
|
|
1417
|
+
});
|
|
1418
|
+
};
|
|
1419
|
+
const onPlan = (name, parsed) => {
|
|
1420
|
+
if (name !== agentName) return;
|
|
1421
|
+
let handled = false;
|
|
1422
|
+
const guard = (fn) => (...args) => {
|
|
1423
|
+
if (handled) return Promise.resolve();
|
|
1424
|
+
handled = true;
|
|
1425
|
+
return fn(...args);
|
|
1426
|
+
};
|
|
1427
|
+
this.emit("plan", {
|
|
1428
|
+
requestId: parsed.requestId,
|
|
1429
|
+
planContent: parsed.planContent,
|
|
1430
|
+
approve: guard(
|
|
1431
|
+
(feedback) => this.controller.sendPlanApproval(agentName, parsed.requestId, true, feedback)
|
|
1432
|
+
),
|
|
1433
|
+
reject: guard(
|
|
1434
|
+
(feedback) => this.controller.sendPlanApproval(agentName, parsed.requestId, false, feedback)
|
|
1435
|
+
)
|
|
1436
|
+
});
|
|
1437
|
+
};
|
|
1438
|
+
const onExit = (name, code) => {
|
|
1439
|
+
if (name === agentName) this.emit("exit", code);
|
|
1440
|
+
};
|
|
1441
|
+
const onError = (err) => {
|
|
1442
|
+
this.emit("error", err);
|
|
1443
|
+
};
|
|
1444
|
+
this.controller.on("message", onMessage);
|
|
1445
|
+
this.controller.on("idle", onIdle);
|
|
1446
|
+
this.controller.on("permission:request", onPermission);
|
|
1447
|
+
this.controller.on("plan:approval_request", onPlan);
|
|
1448
|
+
this.controller.on("agent:exited", onExit);
|
|
1449
|
+
this.controller.on("error", onError);
|
|
1450
|
+
this.boundListeners = [
|
|
1451
|
+
{ event: "message", fn: onMessage },
|
|
1452
|
+
{ event: "idle", fn: onIdle },
|
|
1453
|
+
{ event: "permission:request", fn: onPermission },
|
|
1454
|
+
{ event: "plan:approval_request", fn: onPlan },
|
|
1455
|
+
{ event: "agent:exited", fn: onExit },
|
|
1456
|
+
{ event: "error", fn: onError }
|
|
1457
|
+
];
|
|
1458
|
+
}
|
|
1459
|
+
unwireEvents() {
|
|
1460
|
+
for (const { event, fn } of this.boundListeners) {
|
|
1461
|
+
this.controller.removeListener(event, fn);
|
|
1462
|
+
}
|
|
1463
|
+
this.boundListeners = [];
|
|
1464
|
+
}
|
|
1465
|
+
wireBehavior(behavior) {
|
|
1466
|
+
if (!behavior) return;
|
|
1467
|
+
const { autoApprove, onPermission, onPlan } = behavior;
|
|
1468
|
+
if (autoApprove != null) {
|
|
1469
|
+
this.on("permission", (req) => {
|
|
1470
|
+
if (autoApprove === true) {
|
|
1471
|
+
req.approve();
|
|
1472
|
+
} else if (Array.isArray(autoApprove)) {
|
|
1473
|
+
autoApprove.includes(req.toolName) ? req.approve() : req.reject();
|
|
1474
|
+
}
|
|
1475
|
+
});
|
|
1476
|
+
if (autoApprove === true) {
|
|
1477
|
+
this.on("plan", (req) => req.approve());
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
if (onPermission) {
|
|
1481
|
+
this.on("permission", onPermission);
|
|
1482
|
+
}
|
|
1483
|
+
if (onPlan) {
|
|
1484
|
+
this.on("plan", onPlan);
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
ensureNotDisposed() {
|
|
1488
|
+
if (this.disposed) {
|
|
1489
|
+
throw new Error("Agent has been closed");
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
};
|
|
1493
|
+
var Session = class _Session {
|
|
1494
|
+
controller;
|
|
1495
|
+
defaults;
|
|
1496
|
+
agents = /* @__PURE__ */ new Map();
|
|
1497
|
+
disposed = false;
|
|
1498
|
+
constructor(controller, defaults) {
|
|
1499
|
+
this.controller = controller;
|
|
1500
|
+
this.defaults = defaults;
|
|
1501
|
+
}
|
|
1502
|
+
static async create(opts = {}) {
|
|
1503
|
+
const env = buildEnv(opts);
|
|
1504
|
+
const controller = new ClaudeCodeController({
|
|
1505
|
+
teamName: opts.teamName ?? `session-${(0, import_node_crypto3.randomUUID)().slice(0, 8)}`,
|
|
1506
|
+
cwd: opts.cwd,
|
|
1507
|
+
claudeBinary: opts.claudeBinary,
|
|
1508
|
+
env,
|
|
1509
|
+
logLevel: opts.logLevel ?? "warn",
|
|
1510
|
+
logger: opts.logger
|
|
1511
|
+
});
|
|
1512
|
+
await controller.init();
|
|
1513
|
+
return new _Session(controller, opts);
|
|
1514
|
+
}
|
|
1515
|
+
/** Spawn a named agent in this session. Inherits session defaults. */
|
|
1516
|
+
async agent(name, opts = {}) {
|
|
1517
|
+
this.ensureNotDisposed();
|
|
1518
|
+
const merged = {
|
|
1519
|
+
model: this.defaults.model,
|
|
1520
|
+
cwd: this.defaults.cwd,
|
|
1521
|
+
permissions: this.defaults.permissions,
|
|
1522
|
+
readyTimeout: this.defaults.readyTimeout,
|
|
1523
|
+
autoApprove: this.defaults.autoApprove,
|
|
1524
|
+
onPermission: this.defaults.onPermission,
|
|
1525
|
+
onPlan: this.defaults.onPlan,
|
|
1526
|
+
...opts
|
|
1527
|
+
};
|
|
1528
|
+
const agent = await Agent.createInSession(
|
|
1529
|
+
this.controller,
|
|
1530
|
+
name,
|
|
1531
|
+
merged
|
|
1532
|
+
);
|
|
1533
|
+
this.agents.set(name, agent);
|
|
1534
|
+
return agent;
|
|
1535
|
+
}
|
|
1536
|
+
/** Get an existing agent by name. */
|
|
1537
|
+
get(name) {
|
|
1538
|
+
return this.agents.get(name);
|
|
1539
|
+
}
|
|
1540
|
+
/** Close all agents and shut down the session. */
|
|
1541
|
+
async close() {
|
|
1542
|
+
if (this.disposed) return;
|
|
1543
|
+
this.disposed = true;
|
|
1544
|
+
for (const agent of this.agents.values()) {
|
|
1545
|
+
agent.markDisposed();
|
|
1546
|
+
}
|
|
1547
|
+
await this.controller.shutdown();
|
|
1548
|
+
}
|
|
1549
|
+
async [Symbol.asyncDispose]() {
|
|
1550
|
+
await this.close();
|
|
1551
|
+
}
|
|
1552
|
+
ensureNotDisposed() {
|
|
1553
|
+
if (this.disposed) {
|
|
1554
|
+
throw new Error("Session has been closed");
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
};
|
|
1558
|
+
async function claudeCall(prompt, opts = {}) {
|
|
1559
|
+
const agent = await Agent.create(opts);
|
|
1560
|
+
try {
|
|
1561
|
+
return await agent.ask(prompt, { timeout: opts.timeout ?? 12e4 });
|
|
1562
|
+
} finally {
|
|
1563
|
+
await agent.close();
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
var claude = Object.assign(claudeCall, {
|
|
1567
|
+
/**
|
|
1568
|
+
* Create a persistent agent for multi-turn conversations.
|
|
1569
|
+
*
|
|
1570
|
+
* @example
|
|
1571
|
+
* ```ts
|
|
1572
|
+
* const agent = await claude.agent({ model: "sonnet" });
|
|
1573
|
+
* const answer = await agent.ask("What is 2+2?");
|
|
1574
|
+
* await agent.close();
|
|
1575
|
+
* ```
|
|
1576
|
+
*/
|
|
1577
|
+
agent: (opts) => Agent.create(opts),
|
|
1578
|
+
/**
|
|
1579
|
+
* Create a multi-agent session.
|
|
1580
|
+
*
|
|
1581
|
+
* @example
|
|
1582
|
+
* ```ts
|
|
1583
|
+
* const session = await claude.session({ model: "sonnet" });
|
|
1584
|
+
* const reviewer = await session.agent("reviewer", { model: "opus" });
|
|
1585
|
+
* const coder = await session.agent("coder");
|
|
1586
|
+
* await session.close();
|
|
1587
|
+
* ```
|
|
1588
|
+
*/
|
|
1589
|
+
session: (opts) => Session.create(opts)
|
|
1590
|
+
});
|
|
1133
1591
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1134
1592
|
0 && (module.exports = {
|
|
1593
|
+
Agent,
|
|
1135
1594
|
AgentHandle,
|
|
1136
1595
|
ClaudeCodeController,
|
|
1137
1596
|
InboxPoller,
|
|
1138
1597
|
ProcessManager,
|
|
1598
|
+
Session,
|
|
1139
1599
|
TaskManager,
|
|
1140
1600
|
TeamManager,
|
|
1601
|
+
claude,
|
|
1141
1602
|
createLogger,
|
|
1142
1603
|
inboxPath,
|
|
1143
1604
|
inboxesDir,
|