claude-code-controller 0.4.0 → 0.5.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.
@@ -8,7 +8,7 @@ interface InboxMessage {
8
8
  read: boolean;
9
9
  summary?: string;
10
10
  }
11
- type StructuredMessage = TaskAssignmentMessage | ShutdownRequestMessage | ShutdownApprovedMessage | IdleNotificationMessage | PlanApprovalRequestMessage | PlanApprovalResponseMessage | PermissionRequestMessage | PermissionResponseMessage | PlainTextMessage;
11
+ type StructuredMessage = TaskAssignmentMessage | TaskCompletedMessage | ShutdownRequestMessage | ShutdownApprovedMessage | IdleNotificationMessage | PlanApprovalRequestMessage | PlanApprovalResponseMessage | PermissionRequestMessage | PermissionResponseMessage | SandboxPermissionRequestMessage | SandboxPermissionResponseMessage | PlainTextMessage;
12
12
  interface TaskAssignmentMessage {
13
13
  type: "task_assignment";
14
14
  taskId: string;
@@ -37,6 +37,10 @@ interface IdleNotificationMessage {
37
37
  from: string;
38
38
  timestamp: string;
39
39
  idleReason: string;
40
+ summary?: string;
41
+ completedTaskId?: string;
42
+ completedStatus?: string;
43
+ failureReason?: string;
40
44
  }
41
45
  interface PlanApprovalRequestMessage {
42
46
  type: "plan_approval_request";
@@ -71,6 +75,29 @@ interface PermissionResponseMessage {
71
75
  approved: boolean;
72
76
  timestamp: string;
73
77
  }
78
+ interface TaskCompletedMessage {
79
+ type: "task_completed";
80
+ from: string;
81
+ taskId: string;
82
+ taskSubject: string;
83
+ timestamp: string;
84
+ }
85
+ interface SandboxPermissionRequestMessage {
86
+ type: "sandbox_permission_request";
87
+ requestId: string;
88
+ workerId: string;
89
+ workerName: string;
90
+ workerColor?: string;
91
+ hostPattern: string;
92
+ timestamp: string;
93
+ }
94
+ interface SandboxPermissionResponseMessage {
95
+ type: "sandbox_permission_response";
96
+ requestId: string;
97
+ host: string;
98
+ allow: boolean;
99
+ timestamp: string;
100
+ }
74
101
  interface PlainTextMessage {
75
102
  type: "plain_text";
76
103
  text: string;
@@ -88,10 +115,14 @@ interface TeamMember {
88
115
  name: string;
89
116
  agentType: string;
90
117
  model?: string;
118
+ prompt?: string;
119
+ color?: string;
120
+ planModeRequired?: boolean;
91
121
  joinedAt: number;
92
122
  tmuxPaneId?: string;
93
123
  cwd: string;
94
124
  subscriptions?: string[];
125
+ backendType?: string;
95
126
  }
96
127
  interface TaskFile {
97
128
  id: string;
@@ -105,7 +136,7 @@ interface TaskFile {
105
136
  metadata?: Record<string, unknown>;
106
137
  }
107
138
  type TaskStatus = "pending" | "in_progress" | "completed";
108
- type AgentType = "general-purpose" | "Bash" | "Explore" | "Plan" | string;
139
+ type AgentType = "general-purpose" | "Bash" | "Explore" | "Plan" | "claude-code-guide" | "statusline-setup" | string;
109
140
  type PermissionMode = "default" | "acceptEdits" | "bypassPermissions" | "plan" | "dontAsk" | "delegate";
110
141
  interface SpawnAgentOptions {
111
142
  name: string;
@@ -134,7 +165,7 @@ interface ReceiveOptions {
134
165
  }
135
166
  interface ControllerEvents {
136
167
  message: [agentName: string, message: InboxMessage];
137
- idle: [agentName: string];
168
+ idle: [agentName: string, details: IdleNotificationMessage];
138
169
  "shutdown:approved": [agentName: string, message: ShutdownApprovedMessage];
139
170
  "plan:approval_request": [agentName: string, message: PlanApprovalRequestMessage];
140
171
  "permission:request": [agentName: string, message: PermissionRequestMessage];
@@ -393,6 +424,11 @@ declare class ClaudeCodeController extends EventEmitter<ControllerEvents> implem
393
424
  version: string | null;
394
425
  };
395
426
  private handlePollEvents;
427
+ /**
428
+ * Ensure the agent's cwd has a .claude/settings.local.json so the
429
+ * CLI skips the interactive workspace trust prompt.
430
+ */
431
+ private ensureWorkspaceTrusted;
396
432
  private ensureInitialized;
397
433
  }
398
434
 
@@ -632,4 +668,4 @@ declare const claude: typeof claudeCall & {
632
668
  session: (opts?: SessionOptions) => Promise<Session>;
633
669
  };
634
670
 
635
- export { Agent as A, type TeamConfig as B, ClaudeCodeController as C, TeamManager as D, type TeamMember as E, claude as F, type InboxMessage as I, type Logger as L, type PermissionMode as P, type ReceiveOptions as R, type StructuredMessage as S, type TaskAssignmentMessage as T, type LogLevel as a, type AgentEvents as b, AgentHandle as c, type AgentType as d, type AskOptions as e, type ClaudeOptions as f, type ControllerEvents as g, type ControllerOptions as h, type IdleNotificationMessage as i, type PermissionPreset as j, type PermissionRequestInfo as k, type PermissionRequestMessage as l, type PermissionResponseMessage as m, type PlainTextMessage as n, type PlanApprovalRequestMessage as o, type PlanApprovalResponseMessage as p, type PlanRequestInfo as q, Session as r, type SessionAgentOptions as s, type SessionOptions as t, type ShutdownApprovedMessage as u, type ShutdownRequestMessage as v, type SpawnAgentOptions as w, type TaskFile as x, TaskManager as y, type TaskStatus as z };
671
+ export { Agent as A, type TaskFile as B, ClaudeCodeController as C, TaskManager as D, type TaskStatus as E, type TeamConfig as F, TeamManager as G, type TeamMember as H, type InboxMessage as I, claude as J, type Logger as L, type PermissionMode as P, type ReceiveOptions as R, type StructuredMessage as S, type TaskAssignmentMessage as T, type LogLevel as a, type AgentEvents as b, AgentHandle as c, type AgentType as d, type AskOptions as e, type ClaudeOptions as f, type ControllerEvents as g, type ControllerOptions as h, type IdleNotificationMessage as i, type PermissionPreset as j, type PermissionRequestInfo as k, type PermissionRequestMessage as l, type PermissionResponseMessage as m, type PlainTextMessage as n, type PlanApprovalRequestMessage as o, type PlanApprovalResponseMessage as p, type PlanRequestInfo as q, type SandboxPermissionRequestMessage as r, type SandboxPermissionResponseMessage as s, Session as t, type SessionAgentOptions as u, type SessionOptions as v, type ShutdownApprovedMessage as w, type ShutdownRequestMessage as x, type SpawnAgentOptions as y, type TaskCompletedMessage as z };
@@ -8,7 +8,7 @@ interface InboxMessage {
8
8
  read: boolean;
9
9
  summary?: string;
10
10
  }
11
- type StructuredMessage = TaskAssignmentMessage | ShutdownRequestMessage | ShutdownApprovedMessage | IdleNotificationMessage | PlanApprovalRequestMessage | PlanApprovalResponseMessage | PermissionRequestMessage | PermissionResponseMessage | PlainTextMessage;
11
+ type StructuredMessage = TaskAssignmentMessage | TaskCompletedMessage | ShutdownRequestMessage | ShutdownApprovedMessage | IdleNotificationMessage | PlanApprovalRequestMessage | PlanApprovalResponseMessage | PermissionRequestMessage | PermissionResponseMessage | SandboxPermissionRequestMessage | SandboxPermissionResponseMessage | PlainTextMessage;
12
12
  interface TaskAssignmentMessage {
13
13
  type: "task_assignment";
14
14
  taskId: string;
@@ -37,6 +37,10 @@ interface IdleNotificationMessage {
37
37
  from: string;
38
38
  timestamp: string;
39
39
  idleReason: string;
40
+ summary?: string;
41
+ completedTaskId?: string;
42
+ completedStatus?: string;
43
+ failureReason?: string;
40
44
  }
41
45
  interface PlanApprovalRequestMessage {
42
46
  type: "plan_approval_request";
@@ -71,6 +75,29 @@ interface PermissionResponseMessage {
71
75
  approved: boolean;
72
76
  timestamp: string;
73
77
  }
78
+ interface TaskCompletedMessage {
79
+ type: "task_completed";
80
+ from: string;
81
+ taskId: string;
82
+ taskSubject: string;
83
+ timestamp: string;
84
+ }
85
+ interface SandboxPermissionRequestMessage {
86
+ type: "sandbox_permission_request";
87
+ requestId: string;
88
+ workerId: string;
89
+ workerName: string;
90
+ workerColor?: string;
91
+ hostPattern: string;
92
+ timestamp: string;
93
+ }
94
+ interface SandboxPermissionResponseMessage {
95
+ type: "sandbox_permission_response";
96
+ requestId: string;
97
+ host: string;
98
+ allow: boolean;
99
+ timestamp: string;
100
+ }
74
101
  interface PlainTextMessage {
75
102
  type: "plain_text";
76
103
  text: string;
@@ -88,10 +115,14 @@ interface TeamMember {
88
115
  name: string;
89
116
  agentType: string;
90
117
  model?: string;
118
+ prompt?: string;
119
+ color?: string;
120
+ planModeRequired?: boolean;
91
121
  joinedAt: number;
92
122
  tmuxPaneId?: string;
93
123
  cwd: string;
94
124
  subscriptions?: string[];
125
+ backendType?: string;
95
126
  }
96
127
  interface TaskFile {
97
128
  id: string;
@@ -105,7 +136,7 @@ interface TaskFile {
105
136
  metadata?: Record<string, unknown>;
106
137
  }
107
138
  type TaskStatus = "pending" | "in_progress" | "completed";
108
- type AgentType = "general-purpose" | "Bash" | "Explore" | "Plan" | string;
139
+ type AgentType = "general-purpose" | "Bash" | "Explore" | "Plan" | "claude-code-guide" | "statusline-setup" | string;
109
140
  type PermissionMode = "default" | "acceptEdits" | "bypassPermissions" | "plan" | "dontAsk" | "delegate";
110
141
  interface SpawnAgentOptions {
111
142
  name: string;
@@ -134,7 +165,7 @@ interface ReceiveOptions {
134
165
  }
135
166
  interface ControllerEvents {
136
167
  message: [agentName: string, message: InboxMessage];
137
- idle: [agentName: string];
168
+ idle: [agentName: string, details: IdleNotificationMessage];
138
169
  "shutdown:approved": [agentName: string, message: ShutdownApprovedMessage];
139
170
  "plan:approval_request": [agentName: string, message: PlanApprovalRequestMessage];
140
171
  "permission:request": [agentName: string, message: PermissionRequestMessage];
@@ -393,6 +424,11 @@ declare class ClaudeCodeController extends EventEmitter<ControllerEvents> implem
393
424
  version: string | null;
394
425
  };
395
426
  private handlePollEvents;
427
+ /**
428
+ * Ensure the agent's cwd has a .claude/settings.local.json so the
429
+ * CLI skips the interactive workspace trust prompt.
430
+ */
431
+ private ensureWorkspaceTrusted;
396
432
  private ensureInitialized;
397
433
  }
398
434
 
@@ -632,4 +668,4 @@ declare const claude: typeof claudeCall & {
632
668
  session: (opts?: SessionOptions) => Promise<Session>;
633
669
  };
634
670
 
635
- export { Agent as A, type TeamConfig as B, ClaudeCodeController as C, TeamManager as D, type TeamMember as E, claude as F, type InboxMessage as I, type Logger as L, type PermissionMode as P, type ReceiveOptions as R, type StructuredMessage as S, type TaskAssignmentMessage as T, type LogLevel as a, type AgentEvents as b, AgentHandle as c, type AgentType as d, type AskOptions as e, type ClaudeOptions as f, type ControllerEvents as g, type ControllerOptions as h, type IdleNotificationMessage as i, type PermissionPreset as j, type PermissionRequestInfo as k, type PermissionRequestMessage as l, type PermissionResponseMessage as m, type PlainTextMessage as n, type PlanApprovalRequestMessage as o, type PlanApprovalResponseMessage as p, type PlanRequestInfo as q, Session as r, type SessionAgentOptions as s, type SessionOptions as t, type ShutdownApprovedMessage as u, type ShutdownRequestMessage as v, type SpawnAgentOptions as w, type TaskFile as x, TaskManager as y, type TaskStatus as z };
671
+ export { Agent as A, type TaskFile as B, ClaudeCodeController as C, TaskManager as D, type TaskStatus as E, type TeamConfig as F, TeamManager as G, type TeamMember as H, type InboxMessage as I, claude as J, type Logger as L, type PermissionMode as P, type ReceiveOptions as R, type StructuredMessage as S, type TaskAssignmentMessage as T, type LogLevel as a, type AgentEvents as b, AgentHandle as c, type AgentType as d, type AskOptions as e, type ClaudeOptions as f, type ControllerEvents as g, type ControllerOptions as h, type IdleNotificationMessage as i, type PermissionPreset as j, type PermissionRequestInfo as k, type PermissionRequestMessage as l, type PermissionResponseMessage as m, type PlainTextMessage as n, type PlanApprovalRequestMessage as o, type PlanApprovalResponseMessage as p, type PlanRequestInfo as q, type SandboxPermissionRequestMessage as r, type SandboxPermissionResponseMessage as s, Session as t, type SessionAgentOptions as u, type SessionOptions as v, type ShutdownApprovedMessage as w, type ShutdownRequestMessage as x, type SpawnAgentOptions as y, type TaskCompletedMessage as z };
package/dist/index.cjs CHANGED
@@ -54,6 +54,8 @@ var import_node_crypto3 = require("crypto");
54
54
  var import_node_events = require("events");
55
55
  var import_node_child_process3 = require("child_process");
56
56
  var import_node_crypto2 = require("crypto");
57
+ var import_node_fs4 = require("fs");
58
+ var import_node_path3 = require("path");
57
59
 
58
60
  // src/team-manager.ts
59
61
  var import_promises = require("fs/promises");
@@ -386,6 +388,8 @@ if pid == 0:
386
388
  else:
387
389
  signal.signal(signal.SIGTERM, lambda *a: (os.kill(pid, signal.SIGTERM), sys.exit(0)))
388
390
  signal.signal(signal.SIGINT, lambda *a: (os.kill(pid, signal.SIGTERM), sys.exit(0)))
391
+ buf = b""
392
+ trust_sent = False
389
393
  try:
390
394
  while True:
391
395
  r, _, _ = select.select([fd, 0], [], [], 1.0)
@@ -395,6 +399,12 @@ else:
395
399
  if not data:
396
400
  break
397
401
  os.write(1, data)
402
+ if not trust_sent:
403
+ buf += data
404
+ if b"Yes" in buf and b"trust" in buf:
405
+ os.write(fd, b"\\r")
406
+ trust_sent = True
407
+ buf = b""
398
408
  except OSError:
399
409
  break
400
410
  if 0 in r:
@@ -420,6 +430,7 @@ else:
420
430
  stdio: ["pipe", "pipe", "pipe"],
421
431
  env: {
422
432
  ...process.env,
433
+ CLAUDECODE: "1",
423
434
  CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "1",
424
435
  ...opts.env
425
436
  }
@@ -753,7 +764,10 @@ var silentLogger = {
753
764
  var PROTOCOL_ONLY_TYPES = /* @__PURE__ */ new Set([
754
765
  "shutdown_approved",
755
766
  "plan_approval_response",
756
- "permission_response"
767
+ "permission_response",
768
+ "task_completed",
769
+ "sandbox_permission_request",
770
+ "sandbox_permission_response"
757
771
  ]);
758
772
  var AGENT_COLORS = [
759
773
  "#00FF00",
@@ -861,12 +875,17 @@ var ClaudeCodeController = class extends import_node_events.EventEmitter {
861
875
  name: opts.name,
862
876
  agentType: opts.type || "general-purpose",
863
877
  model: opts.model,
878
+ prompt: opts.prompt,
879
+ color,
880
+ planModeRequired: false,
881
+ backendType: "in-process",
864
882
  joinedAt: Date.now(),
865
883
  tmuxPaneId: "",
866
884
  cwd,
867
885
  subscriptions: []
868
886
  };
869
887
  await this.team.addMember(member);
888
+ this.ensureWorkspaceTrusted(cwd);
870
889
  const env = Object.keys(this.defaultEnv).length > 0 || opts.env ? { ...this.defaultEnv, ...opts.env } : void 0;
871
890
  const proc = this.processes.spawn({
872
891
  teamName: this.teamName,
@@ -1103,7 +1122,7 @@ var ClaudeCodeController = class extends import_node_events.EventEmitter {
1103
1122
  const { raw, parsed } = event;
1104
1123
  switch (parsed.type) {
1105
1124
  case "idle_notification":
1106
- this.emit("idle", raw.from);
1125
+ this.emit("idle", raw.from, parsed);
1107
1126
  break;
1108
1127
  case "shutdown_approved":
1109
1128
  this.log.info(
@@ -1123,6 +1142,9 @@ var ClaudeCodeController = class extends import_node_events.EventEmitter {
1123
1142
  );
1124
1143
  this.emit("permission:request", raw.from, parsed);
1125
1144
  break;
1145
+ case "task_completed":
1146
+ this.emit("message", raw.from, raw);
1147
+ break;
1126
1148
  case "plain_text":
1127
1149
  this.emit("message", raw.from, raw);
1128
1150
  break;
@@ -1131,6 +1153,19 @@ var ClaudeCodeController = class extends import_node_events.EventEmitter {
1131
1153
  }
1132
1154
  }
1133
1155
  }
1156
+ /**
1157
+ * Ensure the agent's cwd has a .claude/settings.local.json so the
1158
+ * CLI skips the interactive workspace trust prompt.
1159
+ */
1160
+ ensureWorkspaceTrusted(cwd) {
1161
+ const claudeDir = (0, import_node_path3.join)(cwd, ".claude");
1162
+ const settingsPath = (0, import_node_path3.join)(claudeDir, "settings.local.json");
1163
+ if (!(0, import_node_fs4.existsSync)(settingsPath)) {
1164
+ (0, import_node_fs4.mkdirSync)(claudeDir, { recursive: true });
1165
+ (0, import_node_fs4.writeFileSync)(settingsPath, "{}\n");
1166
+ this.log.debug(`Created ${settingsPath} for workspace trust`);
1167
+ }
1168
+ }
1134
1169
  ensureInitialized() {
1135
1170
  if (!this.initialized) {
1136
1171
  throw new Error(
@@ -1177,7 +1212,7 @@ function waitForReady(controller, agentName, timeoutMs = 15e3) {
1177
1212
  )
1178
1213
  );
1179
1214
  }, timeoutMs);
1180
- const onReady = (name) => {
1215
+ const onReady = (name, ..._rest) => {
1181
1216
  if (name === agentName && !settled) {
1182
1217
  settled = true;
1183
1218
  cleanup();
@@ -1308,14 +1343,22 @@ var Agent = class _Agent extends import_node_events2.EventEmitter {
1308
1343
  this.ensureNotDisposed();
1309
1344
  const timeout = opts?.timeout ?? 12e4;
1310
1345
  const responsePromise = new Promise((resolve, reject) => {
1346
+ let gotMessage = false;
1311
1347
  const timer = setTimeout(() => {
1312
1348
  cleanup();
1313
1349
  reject(new Error(`Timeout (${timeout}ms) waiting for response`));
1314
1350
  }, timeout);
1315
1351
  const onMsg = (text) => {
1352
+ gotMessage = true;
1316
1353
  cleanup();
1317
1354
  resolve(text);
1318
1355
  };
1356
+ const onIdle = () => {
1357
+ if (!gotMessage) {
1358
+ cleanup();
1359
+ resolve("");
1360
+ }
1361
+ };
1319
1362
  const onExit = (code) => {
1320
1363
  cleanup();
1321
1364
  reject(new Error(`Agent exited (code=${code}) before responding`));
@@ -1323,9 +1366,11 @@ var Agent = class _Agent extends import_node_events2.EventEmitter {
1323
1366
  const cleanup = () => {
1324
1367
  clearTimeout(timer);
1325
1368
  this.removeListener("message", onMsg);
1369
+ this.removeListener("idle", onIdle);
1326
1370
  this.removeListener("exit", onExit);
1327
1371
  };
1328
1372
  this.on("message", onMsg);
1373
+ this.on("idle", onIdle);
1329
1374
  this.on("exit", onExit);
1330
1375
  });
1331
1376
  const wrapped = `${question}
@@ -1344,14 +1389,22 @@ IMPORTANT: You MUST send your complete answer back using the SendMessage tool. D
1344
1389
  this.ensureNotDisposed();
1345
1390
  const timeout = opts?.timeout ?? 12e4;
1346
1391
  return new Promise((resolve, reject) => {
1392
+ let gotMessage = false;
1347
1393
  const timer = setTimeout(() => {
1348
1394
  cleanup();
1349
1395
  reject(new Error(`Timeout (${timeout}ms) waiting for response`));
1350
1396
  }, timeout);
1351
1397
  const onMsg = (text) => {
1398
+ gotMessage = true;
1352
1399
  cleanup();
1353
1400
  resolve(text);
1354
1401
  };
1402
+ const onIdle = () => {
1403
+ if (!gotMessage) {
1404
+ cleanup();
1405
+ resolve("");
1406
+ }
1407
+ };
1355
1408
  const onExit = (code) => {
1356
1409
  cleanup();
1357
1410
  reject(new Error(`Agent exited (code=${code}) before responding`));
@@ -1359,9 +1412,11 @@ IMPORTANT: You MUST send your complete answer back using the SendMessage tool. D
1359
1412
  const cleanup = () => {
1360
1413
  clearTimeout(timer);
1361
1414
  this.removeListener("message", onMsg);
1415
+ this.removeListener("idle", onIdle);
1362
1416
  this.removeListener("exit", onExit);
1363
1417
  };
1364
1418
  this.on("message", onMsg);
1419
+ this.on("idle", onIdle);
1365
1420
  this.on("exit", onExit);
1366
1421
  });
1367
1422
  }
@@ -1392,7 +1447,7 @@ IMPORTANT: You MUST send your complete answer back using the SendMessage tool. D
1392
1447
  const onMessage = (name, msg) => {
1393
1448
  if (name === agentName) this.emit("message", msg.text);
1394
1449
  };
1395
- const onIdle = (name) => {
1450
+ const onIdle = (name, _details) => {
1396
1451
  if (name === agentName) this.emit("idle");
1397
1452
  };
1398
1453
  const onPermission = (name, parsed) => {