claude-code-controller 0.5.1 → 0.6.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.
@@ -102,6 +102,48 @@ interface PlainTextMessage {
102
102
  type: "plain_text";
103
103
  text: string;
104
104
  }
105
+ /** JSON data sent by Claude Code to the statusLine command via stdin. */
106
+ interface StatusLineData {
107
+ model?: {
108
+ id?: string;
109
+ display_name?: string;
110
+ };
111
+ session_id?: string;
112
+ context_window?: {
113
+ used_percentage?: number;
114
+ remaining_percentage?: number;
115
+ total_input_tokens?: number;
116
+ total_output_tokens?: number;
117
+ context_window_size?: number;
118
+ current_usage?: {
119
+ input_tokens?: number;
120
+ output_tokens?: number;
121
+ cache_creation_input_tokens?: number;
122
+ cache_read_input_tokens?: number;
123
+ };
124
+ };
125
+ cost?: {
126
+ total_cost_usd?: number;
127
+ total_duration_ms?: number;
128
+ total_api_duration_ms?: number;
129
+ total_lines_added?: number;
130
+ total_lines_removed?: number;
131
+ };
132
+ workspace?: {
133
+ current_dir?: string;
134
+ project_dir?: string;
135
+ };
136
+ cwd?: string;
137
+ agent?: {
138
+ name?: string;
139
+ };
140
+ vim?: {
141
+ mode?: string;
142
+ };
143
+ output_style?: {
144
+ name?: string;
145
+ };
146
+ }
105
147
  interface TeamConfig {
106
148
  name: string;
107
149
  description?: string;
@@ -172,6 +214,7 @@ interface ControllerEvents {
172
214
  "task:completed": [task: TaskFile];
173
215
  "agent:spawned": [agentName: string, pid: number];
174
216
  "agent:exited": [agentName: string, code: number | null];
217
+ "agent:statusline": [agentName: string, data: StatusLineData];
175
218
  error: [error: Error];
176
219
  }
177
220
  type LogLevel = "debug" | "info" | "warn" | "error" | "silent";
@@ -326,6 +369,7 @@ declare class ClaudeCodeController extends EventEmitter<ControllerEvents> implem
326
369
  readonly tasks: TaskManager;
327
370
  private processes;
328
371
  private poller;
372
+ private statusLineWatcher;
329
373
  private log;
330
374
  private cwd;
331
375
  private claudeBinary;
@@ -427,6 +471,7 @@ declare class ClaudeCodeController extends EventEmitter<ControllerEvents> implem
427
471
  /**
428
472
  * Ensure the agent's cwd has a .claude/settings.local.json so the
429
473
  * CLI skips the interactive workspace trust prompt.
474
+ * Also injects statusLine capture configuration.
430
475
  */
431
476
  private ensureWorkspaceTrusted;
432
477
  private ensureInitialized;
@@ -562,6 +607,7 @@ interface PlanRequestInfo {
562
607
  interface AgentEvents {
563
608
  message: [text: string];
564
609
  idle: [];
610
+ statusline: [data: StatusLineData];
565
611
  permission: [request: PermissionRequestInfo];
566
612
  plan: [request: PlanRequestInfo];
567
613
  exit: [code: number | null];
@@ -668,4 +714,4 @@ declare const claude: typeof claudeCall & {
668
714
  session: (opts?: SessionOptions) => Promise<Session>;
669
715
  };
670
716
 
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 };
717
+ export { Agent as A, type TaskCompletedMessage as B, ClaudeCodeController as C, type TaskFile as D, TaskManager as E, type TaskStatus as F, type TeamConfig as G, TeamManager as H, type InboxMessage as I, type TeamMember as J, claude as K, type Logger as L, type PermissionMode as P, type ReceiveOptions as R, type StructuredMessage as S, type TaskAssignmentMessage as T, type StatusLineData as a, type LogLevel as b, type AgentEvents as c, AgentHandle as d, type AgentType as e, type AskOptions as f, type ClaudeOptions as g, type ControllerEvents as h, type ControllerOptions as i, type IdleNotificationMessage as j, type PermissionPreset as k, type PermissionRequestInfo as l, type PermissionRequestMessage as m, type PermissionResponseMessage as n, type PlainTextMessage as o, type PlanApprovalRequestMessage as p, type PlanApprovalResponseMessage as q, type PlanRequestInfo as r, type SandboxPermissionRequestMessage as s, type SandboxPermissionResponseMessage as t, Session as u, type SessionAgentOptions as v, type SessionOptions as w, type ShutdownApprovedMessage as x, type ShutdownRequestMessage as y, type SpawnAgentOptions as z };
@@ -102,6 +102,48 @@ interface PlainTextMessage {
102
102
  type: "plain_text";
103
103
  text: string;
104
104
  }
105
+ /** JSON data sent by Claude Code to the statusLine command via stdin. */
106
+ interface StatusLineData {
107
+ model?: {
108
+ id?: string;
109
+ display_name?: string;
110
+ };
111
+ session_id?: string;
112
+ context_window?: {
113
+ used_percentage?: number;
114
+ remaining_percentage?: number;
115
+ total_input_tokens?: number;
116
+ total_output_tokens?: number;
117
+ context_window_size?: number;
118
+ current_usage?: {
119
+ input_tokens?: number;
120
+ output_tokens?: number;
121
+ cache_creation_input_tokens?: number;
122
+ cache_read_input_tokens?: number;
123
+ };
124
+ };
125
+ cost?: {
126
+ total_cost_usd?: number;
127
+ total_duration_ms?: number;
128
+ total_api_duration_ms?: number;
129
+ total_lines_added?: number;
130
+ total_lines_removed?: number;
131
+ };
132
+ workspace?: {
133
+ current_dir?: string;
134
+ project_dir?: string;
135
+ };
136
+ cwd?: string;
137
+ agent?: {
138
+ name?: string;
139
+ };
140
+ vim?: {
141
+ mode?: string;
142
+ };
143
+ output_style?: {
144
+ name?: string;
145
+ };
146
+ }
105
147
  interface TeamConfig {
106
148
  name: string;
107
149
  description?: string;
@@ -172,6 +214,7 @@ interface ControllerEvents {
172
214
  "task:completed": [task: TaskFile];
173
215
  "agent:spawned": [agentName: string, pid: number];
174
216
  "agent:exited": [agentName: string, code: number | null];
217
+ "agent:statusline": [agentName: string, data: StatusLineData];
175
218
  error: [error: Error];
176
219
  }
177
220
  type LogLevel = "debug" | "info" | "warn" | "error" | "silent";
@@ -326,6 +369,7 @@ declare class ClaudeCodeController extends EventEmitter<ControllerEvents> implem
326
369
  readonly tasks: TaskManager;
327
370
  private processes;
328
371
  private poller;
372
+ private statusLineWatcher;
329
373
  private log;
330
374
  private cwd;
331
375
  private claudeBinary;
@@ -427,6 +471,7 @@ declare class ClaudeCodeController extends EventEmitter<ControllerEvents> implem
427
471
  /**
428
472
  * Ensure the agent's cwd has a .claude/settings.local.json so the
429
473
  * CLI skips the interactive workspace trust prompt.
474
+ * Also injects statusLine capture configuration.
430
475
  */
431
476
  private ensureWorkspaceTrusted;
432
477
  private ensureInitialized;
@@ -562,6 +607,7 @@ interface PlanRequestInfo {
562
607
  interface AgentEvents {
563
608
  message: [text: string];
564
609
  idle: [];
610
+ statusline: [data: StatusLineData];
565
611
  permission: [request: PermissionRequestInfo];
566
612
  plan: [request: PlanRequestInfo];
567
613
  exit: [code: number | null];
@@ -668,4 +714,4 @@ declare const claude: typeof claudeCall & {
668
714
  session: (opts?: SessionOptions) => Promise<Session>;
669
715
  };
670
716
 
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 };
717
+ export { Agent as A, type TaskCompletedMessage as B, ClaudeCodeController as C, type TaskFile as D, TaskManager as E, type TaskStatus as F, type TeamConfig as G, TeamManager as H, type InboxMessage as I, type TeamMember as J, claude as K, type Logger as L, type PermissionMode as P, type ReceiveOptions as R, type StructuredMessage as S, type TaskAssignmentMessage as T, type StatusLineData as a, type LogLevel as b, type AgentEvents as c, AgentHandle as d, type AgentType as e, type AskOptions as f, type ClaudeOptions as g, type ControllerEvents as h, type ControllerOptions as i, type IdleNotificationMessage as j, type PermissionPreset as k, type PermissionRequestInfo as l, type PermissionRequestMessage as m, type PermissionResponseMessage as n, type PlainTextMessage as o, type PlanApprovalRequestMessage as p, type PlanApprovalResponseMessage as q, type PlanRequestInfo as r, type SandboxPermissionRequestMessage as s, type SandboxPermissionResponseMessage as t, Session as u, type SessionAgentOptions as v, type SessionOptions as w, type ShutdownApprovedMessage as x, type ShutdownRequestMessage as y, type SpawnAgentOptions as z };
package/dist/index.cjs CHANGED
@@ -26,8 +26,11 @@ __export(index_exports, {
26
26
  InboxPoller: () => InboxPoller,
27
27
  ProcessManager: () => ProcessManager,
28
28
  Session: () => Session,
29
+ StatusLineWatcher: () => StatusLineWatcher,
29
30
  TaskManager: () => TaskManager,
30
31
  TeamManager: () => TeamManager,
32
+ buildStatusLineCommand: () => buildStatusLineCommand,
33
+ buildStatusLineSettings: () => buildStatusLineSettings,
31
34
  claude: () => claude,
32
35
  createLogger: () => createLogger,
33
36
  inboxPath: () => inboxPath,
@@ -36,6 +39,8 @@ __export(index_exports, {
36
39
  readInbox: () => readInbox,
37
40
  readUnread: () => readUnread,
38
41
  silentLogger: () => silentLogger,
42
+ statusLineDir: () => statusLineDir,
43
+ statusLineLogPath: () => statusLineLogPath,
39
44
  taskPath: () => taskPath,
40
45
  tasksBaseDir: () => tasksBaseDir,
41
46
  tasksDir: () => tasksDir,
@@ -47,15 +52,15 @@ __export(index_exports, {
47
52
  module.exports = __toCommonJS(index_exports);
48
53
 
49
54
  // src/claude.ts
50
- var import_node_events2 = require("events");
55
+ var import_node_events3 = require("events");
51
56
  var import_node_crypto3 = require("crypto");
52
57
 
53
58
  // src/controller.ts
54
- var import_node_events = require("events");
59
+ var import_node_events2 = require("events");
55
60
  var import_node_child_process3 = require("child_process");
56
61
  var import_node_crypto2 = require("crypto");
57
- var import_node_fs4 = require("fs");
58
- var import_node_path3 = require("path");
62
+ var import_node_fs5 = require("fs");
63
+ var import_node_path4 = require("path");
59
64
 
60
65
  // src/team-manager.ts
61
66
  var import_promises = require("fs/promises");
@@ -760,6 +765,135 @@ var silentLogger = {
760
765
  }
761
766
  };
762
767
 
768
+ // src/statusline-capture.ts
769
+ var import_node_events = require("events");
770
+ var import_node_fs4 = require("fs");
771
+ var import_node_path3 = require("path");
772
+ function statusLineDir(teamName) {
773
+ return (0, import_node_path3.join)(teamDir(teamName), "statusline");
774
+ }
775
+ function statusLineLogPath(teamName, agentName) {
776
+ return (0, import_node_path3.join)(statusLineDir(teamName), `${agentName}.jsonl`);
777
+ }
778
+ function buildStatusLineCommand(logFilePath) {
779
+ const escapedPath = logFilePath.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
780
+ return [
781
+ "python3 -c",
782
+ `'import sys,json;`,
783
+ `d=json.load(sys.stdin);`,
784
+ `open("${escapedPath}","a").write(json.dumps(d)+"\\n");`,
785
+ `print(d.get("model",{}).get("display_name",""))'`
786
+ ].join(" ");
787
+ }
788
+ function buildStatusLineSettings(logFilePath) {
789
+ return {
790
+ statusLine: {
791
+ type: "command",
792
+ command: buildStatusLineCommand(logFilePath)
793
+ }
794
+ };
795
+ }
796
+ var StatusLineWatcher = class extends import_node_events.EventEmitter {
797
+ teamName;
798
+ log;
799
+ watchers = /* @__PURE__ */ new Map();
800
+ fileOffsets = /* @__PURE__ */ new Map();
801
+ stopped = false;
802
+ constructor(teamName, logger) {
803
+ super();
804
+ this.teamName = teamName;
805
+ this.log = logger;
806
+ }
807
+ /**
808
+ * Ensure the statusline directory exists.
809
+ */
810
+ ensureDir() {
811
+ const dir = statusLineDir(this.teamName);
812
+ if (!(0, import_node_fs4.existsSync)(dir)) {
813
+ (0, import_node_fs4.mkdirSync)(dir, { recursive: true });
814
+ }
815
+ }
816
+ /**
817
+ * Start watching a specific agent's statusLine log file.
818
+ */
819
+ watchAgent(agentName) {
820
+ if (this.stopped) return;
821
+ const filePath = statusLineLogPath(this.teamName, agentName);
822
+ if (!(0, import_node_fs4.existsSync)(filePath)) {
823
+ (0, import_node_fs4.writeFileSync)(filePath, "");
824
+ }
825
+ try {
826
+ const stats = (0, import_node_fs4.readFileSync)(filePath);
827
+ this.fileOffsets.set(filePath, stats.length);
828
+ } catch {
829
+ this.fileOffsets.set(filePath, 0);
830
+ }
831
+ try {
832
+ const watcher = (0, import_node_fs4.watch)(filePath, (eventType) => {
833
+ if (eventType === "change") {
834
+ this.readNewLines(agentName, filePath);
835
+ }
836
+ });
837
+ this.watchers.set(agentName, watcher);
838
+ this.log.debug(`Watching statusLine for agent "${agentName}" at ${filePath}`);
839
+ } catch (err) {
840
+ this.log.error(`Failed to watch statusLine for "${agentName}": ${err}`);
841
+ }
842
+ }
843
+ /**
844
+ * Stop watching a specific agent.
845
+ */
846
+ unwatchAgent(agentName) {
847
+ const watcher = this.watchers.get(agentName);
848
+ if (watcher) {
849
+ watcher.close();
850
+ this.watchers.delete(agentName);
851
+ }
852
+ const filePath = statusLineLogPath(this.teamName, agentName);
853
+ this.fileOffsets.delete(filePath);
854
+ }
855
+ /**
856
+ * Stop all watchers.
857
+ */
858
+ stop() {
859
+ this.stopped = true;
860
+ for (const [, watcher] of this.watchers) {
861
+ watcher.close();
862
+ }
863
+ this.watchers.clear();
864
+ this.fileOffsets.clear();
865
+ }
866
+ /**
867
+ * Read new lines appended to the log file since last read.
868
+ */
869
+ readNewLines(agentName, filePath) {
870
+ try {
871
+ const content = (0, import_node_fs4.readFileSync)(filePath, "utf-8");
872
+ const offset = this.fileOffsets.get(filePath) ?? 0;
873
+ const newContent = content.slice(offset);
874
+ this.fileOffsets.set(filePath, content.length);
875
+ if (!newContent.trim()) return;
876
+ const lines = newContent.trim().split("\n");
877
+ for (const line of lines) {
878
+ if (!line.trim()) continue;
879
+ try {
880
+ const data = JSON.parse(line);
881
+ const event = {
882
+ agentName,
883
+ data,
884
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
885
+ };
886
+ this.emit("update", event);
887
+ } catch (parseErr) {
888
+ this.log.debug(`Failed to parse statusLine JSON: ${line}`);
889
+ }
890
+ }
891
+ } catch (err) {
892
+ this.log.debug(`Error reading statusLine file: ${err}`);
893
+ }
894
+ }
895
+ };
896
+
763
897
  // src/controller.ts
764
898
  var PROTOCOL_ONLY_TYPES = /* @__PURE__ */ new Set([
765
899
  "shutdown_approved",
@@ -779,12 +913,13 @@ var AGENT_COLORS = [
779
913
  "#FF69B4",
780
914
  "#7B68EE"
781
915
  ];
782
- var ClaudeCodeController = class extends import_node_events.EventEmitter {
916
+ var ClaudeCodeController = class extends import_node_events2.EventEmitter {
783
917
  teamName;
784
918
  team;
785
919
  tasks;
786
920
  processes;
787
921
  poller;
922
+ statusLineWatcher;
788
923
  log;
789
924
  cwd;
790
925
  claudeBinary;
@@ -806,7 +941,11 @@ var ClaudeCodeController = class extends import_node_events.EventEmitter {
806
941
  "controller",
807
942
  this.log
808
943
  );
944
+ this.statusLineWatcher = new StatusLineWatcher(this.teamName, this.log);
809
945
  this.poller.onMessages((events) => this.handlePollEvents(events));
946
+ this.statusLineWatcher.on("update", (event) => {
947
+ this.emit("agent:statusline", event.agentName, event.data);
948
+ });
810
949
  }
811
950
  // ─── Lifecycle ───────────────────────────────────────────────────────
812
951
  /**
@@ -817,6 +956,7 @@ var ClaudeCodeController = class extends import_node_events.EventEmitter {
817
956
  if (this.initialized) return this;
818
957
  await this.team.create({ cwd: this.cwd });
819
958
  await this.tasks.init();
959
+ this.statusLineWatcher.ensureDir();
820
960
  this.poller.start();
821
961
  this.initialized = true;
822
962
  this.log.info(
@@ -857,6 +997,7 @@ var ClaudeCodeController = class extends import_node_events.EventEmitter {
857
997
  }
858
998
  await this.processes.killAll();
859
999
  this.poller.stop();
1000
+ this.statusLineWatcher.stop();
860
1001
  await this.team.destroy();
861
1002
  this.initialized = false;
862
1003
  this.log.info("Controller shut down");
@@ -885,7 +1026,8 @@ var ClaudeCodeController = class extends import_node_events.EventEmitter {
885
1026
  subscriptions: []
886
1027
  };
887
1028
  await this.team.addMember(member);
888
- this.ensureWorkspaceTrusted(cwd);
1029
+ this.ensureWorkspaceTrusted(cwd, opts.name);
1030
+ this.statusLineWatcher.watchAgent(opts.name);
889
1031
  const env = Object.keys(this.defaultEnv).length > 0 || opts.env ? { ...this.defaultEnv, ...opts.env } : void 0;
890
1032
  const proc = this.processes.spawn({
891
1033
  teamName: this.teamName,
@@ -1092,6 +1234,7 @@ var ClaudeCodeController = class extends import_node_events.EventEmitter {
1092
1234
  * Kill a specific agent.
1093
1235
  */
1094
1236
  async killAgent(name) {
1237
+ this.statusLineWatcher.unwatchAgent(name);
1095
1238
  await this.processes.kill(name);
1096
1239
  await this.team.removeMember(name);
1097
1240
  }
@@ -1156,15 +1299,28 @@ var ClaudeCodeController = class extends import_node_events.EventEmitter {
1156
1299
  /**
1157
1300
  * Ensure the agent's cwd has a .claude/settings.local.json so the
1158
1301
  * CLI skips the interactive workspace trust prompt.
1302
+ * Also injects statusLine capture configuration.
1159
1303
  */
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`);
1304
+ ensureWorkspaceTrusted(cwd, agentName) {
1305
+ const claudeDir = (0, import_node_path4.join)(cwd, ".claude");
1306
+ const settingsPath = (0, import_node_path4.join)(claudeDir, "settings.local.json");
1307
+ (0, import_node_fs5.mkdirSync)(claudeDir, { recursive: true });
1308
+ let settings = {};
1309
+ if ((0, import_node_fs5.existsSync)(settingsPath)) {
1310
+ try {
1311
+ settings = JSON.parse((0, import_node_fs5.readFileSync)(settingsPath, "utf-8"));
1312
+ } catch {
1313
+ settings = {};
1314
+ }
1167
1315
  }
1316
+ if (agentName && !settings.statusLine) {
1317
+ const logPath = statusLineLogPath(this.teamName, agentName);
1318
+ const statusLineSettings = buildStatusLineSettings(logPath);
1319
+ settings = { ...settings, ...statusLineSettings };
1320
+ this.log.debug(`Injected statusLine capture for "${agentName}"`);
1321
+ }
1322
+ (0, import_node_fs5.writeFileSync)(settingsPath, JSON.stringify(settings, null, 2) + "\n");
1323
+ this.log.debug(`Updated ${settingsPath}`);
1168
1324
  }
1169
1325
  ensureInitialized() {
1170
1326
  if (!this.initialized) {
@@ -1250,7 +1406,7 @@ function waitForReady(controller, agentName, timeoutMs = 15e3) {
1250
1406
  controller.on("agent:exited", onExit);
1251
1407
  });
1252
1408
  }
1253
- var Agent = class _Agent extends import_node_events2.EventEmitter {
1409
+ var Agent = class _Agent extends import_node_events3.EventEmitter {
1254
1410
  controller;
1255
1411
  handle;
1256
1412
  ownsController;
@@ -1450,6 +1606,9 @@ IMPORTANT: You MUST send your complete answer back using the SendMessage tool. D
1450
1606
  const onIdle = (name, _details) => {
1451
1607
  if (name === agentName) this.emit("idle");
1452
1608
  };
1609
+ const onStatusLine = (name, data) => {
1610
+ if (name === agentName) this.emit("statusline", data);
1611
+ };
1453
1612
  const onPermission = (name, parsed) => {
1454
1613
  if (name !== agentName) return;
1455
1614
  let handled = false;
@@ -1498,6 +1657,7 @@ IMPORTANT: You MUST send your complete answer back using the SendMessage tool. D
1498
1657
  };
1499
1658
  this.controller.on("message", onMessage);
1500
1659
  this.controller.on("idle", onIdle);
1660
+ this.controller.on("agent:statusline", onStatusLine);
1501
1661
  this.controller.on("permission:request", onPermission);
1502
1662
  this.controller.on("plan:approval_request", onPlan);
1503
1663
  this.controller.on("agent:exited", onExit);
@@ -1505,6 +1665,7 @@ IMPORTANT: You MUST send your complete answer back using the SendMessage tool. D
1505
1665
  this.boundListeners = [
1506
1666
  { event: "message", fn: onMessage },
1507
1667
  { event: "idle", fn: onIdle },
1668
+ { event: "agent:statusline", fn: onStatusLine },
1508
1669
  { event: "permission:request", fn: onPermission },
1509
1670
  { event: "plan:approval_request", fn: onPlan },
1510
1671
  { event: "agent:exited", fn: onExit },
@@ -1651,8 +1812,11 @@ var claude = Object.assign(claudeCall, {
1651
1812
  InboxPoller,
1652
1813
  ProcessManager,
1653
1814
  Session,
1815
+ StatusLineWatcher,
1654
1816
  TaskManager,
1655
1817
  TeamManager,
1818
+ buildStatusLineCommand,
1819
+ buildStatusLineSettings,
1656
1820
  claude,
1657
1821
  createLogger,
1658
1822
  inboxPath,
@@ -1661,6 +1825,8 @@ var claude = Object.assign(claudeCall, {
1661
1825
  readInbox,
1662
1826
  readUnread,
1663
1827
  silentLogger,
1828
+ statusLineDir,
1829
+ statusLineLogPath,
1664
1830
  taskPath,
1665
1831
  tasksBaseDir,
1666
1832
  tasksDir,