claude-code-controller 0.5.0 → 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.
- package/dist/api/index.cjs +204 -4
- package/dist/api/index.cjs.map +1 -1
- package/dist/api/index.d.cts +1 -1
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.js +204 -4
- package/dist/api/index.js.map +1 -1
- package/dist/{claude-CSXlMCvP.d.cts → claude-B7-oBjuE.d.cts} +52 -1
- package/dist/{claude-CSXlMCvP.d.ts → claude-B7-oBjuE.d.ts} +52 -1
- package/dist/index.cjs +214 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -4
- package/dist/index.d.ts +60 -4
- package/dist/index.js +209 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { L as Logger, I as InboxMessage, S as StructuredMessage, a as LogLevel } from './claude-
|
|
2
|
-
export { A as Agent,
|
|
1
|
+
import { L as Logger, I as InboxMessage, S as StructuredMessage, a as StatusLineData, b as LogLevel } from './claude-B7-oBjuE.js';
|
|
2
|
+
export { A as Agent, c as AgentEvents, d as AgentHandle, e as AgentType, f as AskOptions, C as ClaudeCodeController, g as ClaudeOptions, h as ControllerEvents, i as ControllerOptions, j as IdleNotificationMessage, P as PermissionMode, k as PermissionPreset, l as PermissionRequestInfo, m as PermissionRequestMessage, n as PermissionResponseMessage, o as PlainTextMessage, p as PlanApprovalRequestMessage, q as PlanApprovalResponseMessage, r as PlanRequestInfo, R as ReceiveOptions, s as SandboxPermissionRequestMessage, t as SandboxPermissionResponseMessage, u as Session, v as SessionAgentOptions, w as SessionOptions, x as ShutdownApprovedMessage, y as ShutdownRequestMessage, z as SpawnAgentOptions, T as TaskAssignmentMessage, B as TaskCompletedMessage, D as TaskFile, E as TaskManager, F as TaskStatus, G as TeamConfig, H as TeamManager, J as TeamMember, K as claude } from './claude-B7-oBjuE.js';
|
|
3
3
|
import { ChildProcess } from 'node:child_process';
|
|
4
|
-
import 'node:events';
|
|
4
|
+
import { EventEmitter } from 'node:events';
|
|
5
5
|
|
|
6
6
|
interface SpawnOptions {
|
|
7
7
|
teamName: string;
|
|
@@ -117,6 +117,62 @@ declare function readUnread(teamName: string, agentName: string): Promise<InboxM
|
|
|
117
117
|
*/
|
|
118
118
|
declare function parseMessage(msg: InboxMessage): StructuredMessage;
|
|
119
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Directory where statusLine JSON logs are written per agent.
|
|
122
|
+
*/
|
|
123
|
+
declare function statusLineDir(teamName: string): string;
|
|
124
|
+
declare function statusLineLogPath(teamName: string, agentName: string): string;
|
|
125
|
+
interface StatusLineEvent {
|
|
126
|
+
agentName: string;
|
|
127
|
+
data: StatusLineData;
|
|
128
|
+
timestamp: string;
|
|
129
|
+
}
|
|
130
|
+
interface StatusLineCaptureEvents {
|
|
131
|
+
update: [event: StatusLineEvent];
|
|
132
|
+
error: [error: Error];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Generates the statusLine capture script.
|
|
136
|
+
* This script receives JSON from Claude Code via stdin and appends it to a log file.
|
|
137
|
+
* It also outputs a minimal display for the TUI statusline bar.
|
|
138
|
+
*/
|
|
139
|
+
declare function buildStatusLineCommand(logFilePath: string): string;
|
|
140
|
+
/**
|
|
141
|
+
* Generates the settings.local.json content with statusLine configuration.
|
|
142
|
+
*/
|
|
143
|
+
declare function buildStatusLineSettings(logFilePath: string): Record<string, unknown>;
|
|
144
|
+
/**
|
|
145
|
+
* Watches statusLine log files for a team and emits parsed events.
|
|
146
|
+
*/
|
|
147
|
+
declare class StatusLineWatcher extends EventEmitter<StatusLineCaptureEvents> {
|
|
148
|
+
private teamName;
|
|
149
|
+
private log;
|
|
150
|
+
private watchers;
|
|
151
|
+
private fileOffsets;
|
|
152
|
+
private stopped;
|
|
153
|
+
constructor(teamName: string, logger: Logger);
|
|
154
|
+
/**
|
|
155
|
+
* Ensure the statusline directory exists.
|
|
156
|
+
*/
|
|
157
|
+
ensureDir(): void;
|
|
158
|
+
/**
|
|
159
|
+
* Start watching a specific agent's statusLine log file.
|
|
160
|
+
*/
|
|
161
|
+
watchAgent(agentName: string): void;
|
|
162
|
+
/**
|
|
163
|
+
* Stop watching a specific agent.
|
|
164
|
+
*/
|
|
165
|
+
unwatchAgent(agentName: string): void;
|
|
166
|
+
/**
|
|
167
|
+
* Stop all watchers.
|
|
168
|
+
*/
|
|
169
|
+
stop(): void;
|
|
170
|
+
/**
|
|
171
|
+
* Read new lines appended to the log file since last read.
|
|
172
|
+
*/
|
|
173
|
+
private readNewLines;
|
|
174
|
+
}
|
|
175
|
+
|
|
120
176
|
declare function teamsDir(): string;
|
|
121
177
|
declare function teamDir(teamName: string): string;
|
|
122
178
|
declare function teamConfigPath(teamName: string): string;
|
|
@@ -129,4 +185,4 @@ declare function taskPath(teamName: string, taskId: string): string;
|
|
|
129
185
|
declare function createLogger(level?: LogLevel): Logger;
|
|
130
186
|
declare const silentLogger: Logger;
|
|
131
187
|
|
|
132
|
-
export { InboxMessage, InboxPoller, LogLevel, Logger, ProcessManager, StructuredMessage, createLogger, inboxPath, inboxesDir, parseMessage, readInbox, readUnread, silentLogger, taskPath, tasksBaseDir, tasksDir, teamConfigPath, teamDir, teamsDir, writeInbox };
|
|
188
|
+
export { InboxMessage, InboxPoller, LogLevel, Logger, ProcessManager, type StatusLineCaptureEvents, StatusLineData, type StatusLineEvent, StatusLineWatcher, StructuredMessage, buildStatusLineCommand, buildStatusLineSettings, createLogger, inboxPath, inboxesDir, parseMessage, readInbox, readUnread, silentLogger, statusLineDir, statusLineLogPath, taskPath, tasksBaseDir, tasksDir, teamConfigPath, teamDir, teamsDir, writeInbox };
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// src/claude.ts
|
|
2
|
-
import { EventEmitter as
|
|
2
|
+
import { EventEmitter as EventEmitter3 } from "events";
|
|
3
3
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
4
4
|
|
|
5
5
|
// src/controller.ts
|
|
6
|
-
import { EventEmitter } from "events";
|
|
6
|
+
import { EventEmitter as EventEmitter2 } from "events";
|
|
7
7
|
import { execSync as execSync2 } from "child_process";
|
|
8
8
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
9
|
+
import { mkdirSync as mkdirSync2, existsSync as existsSync5, writeFileSync as writeFileSync2, readFileSync as readFileSync2 } from "fs";
|
|
10
|
+
import { join as join3 } from "path";
|
|
9
11
|
|
|
10
12
|
// src/team-manager.ts
|
|
11
13
|
import { readFile, writeFile, mkdir, rm } from "fs/promises";
|
|
@@ -338,6 +340,8 @@ if pid == 0:
|
|
|
338
340
|
else:
|
|
339
341
|
signal.signal(signal.SIGTERM, lambda *a: (os.kill(pid, signal.SIGTERM), sys.exit(0)))
|
|
340
342
|
signal.signal(signal.SIGINT, lambda *a: (os.kill(pid, signal.SIGTERM), sys.exit(0)))
|
|
343
|
+
buf = b""
|
|
344
|
+
trust_sent = False
|
|
341
345
|
try:
|
|
342
346
|
while True:
|
|
343
347
|
r, _, _ = select.select([fd, 0], [], [], 1.0)
|
|
@@ -347,6 +351,12 @@ else:
|
|
|
347
351
|
if not data:
|
|
348
352
|
break
|
|
349
353
|
os.write(1, data)
|
|
354
|
+
if not trust_sent:
|
|
355
|
+
buf += data
|
|
356
|
+
if b"Yes" in buf and b"trust" in buf:
|
|
357
|
+
os.write(fd, b"\\r")
|
|
358
|
+
trust_sent = True
|
|
359
|
+
buf = b""
|
|
350
360
|
except OSError:
|
|
351
361
|
break
|
|
352
362
|
if 0 in r:
|
|
@@ -702,6 +712,135 @@ var silentLogger = {
|
|
|
702
712
|
}
|
|
703
713
|
};
|
|
704
714
|
|
|
715
|
+
// src/statusline-capture.ts
|
|
716
|
+
import { EventEmitter } from "events";
|
|
717
|
+
import { watch, existsSync as existsSync4, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
718
|
+
import { join as join2 } from "path";
|
|
719
|
+
function statusLineDir(teamName) {
|
|
720
|
+
return join2(teamDir(teamName), "statusline");
|
|
721
|
+
}
|
|
722
|
+
function statusLineLogPath(teamName, agentName) {
|
|
723
|
+
return join2(statusLineDir(teamName), `${agentName}.jsonl`);
|
|
724
|
+
}
|
|
725
|
+
function buildStatusLineCommand(logFilePath) {
|
|
726
|
+
const escapedPath = logFilePath.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
727
|
+
return [
|
|
728
|
+
"python3 -c",
|
|
729
|
+
`'import sys,json;`,
|
|
730
|
+
`d=json.load(sys.stdin);`,
|
|
731
|
+
`open("${escapedPath}","a").write(json.dumps(d)+"\\n");`,
|
|
732
|
+
`print(d.get("model",{}).get("display_name",""))'`
|
|
733
|
+
].join(" ");
|
|
734
|
+
}
|
|
735
|
+
function buildStatusLineSettings(logFilePath) {
|
|
736
|
+
return {
|
|
737
|
+
statusLine: {
|
|
738
|
+
type: "command",
|
|
739
|
+
command: buildStatusLineCommand(logFilePath)
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
var StatusLineWatcher = class extends EventEmitter {
|
|
744
|
+
teamName;
|
|
745
|
+
log;
|
|
746
|
+
watchers = /* @__PURE__ */ new Map();
|
|
747
|
+
fileOffsets = /* @__PURE__ */ new Map();
|
|
748
|
+
stopped = false;
|
|
749
|
+
constructor(teamName, logger) {
|
|
750
|
+
super();
|
|
751
|
+
this.teamName = teamName;
|
|
752
|
+
this.log = logger;
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Ensure the statusline directory exists.
|
|
756
|
+
*/
|
|
757
|
+
ensureDir() {
|
|
758
|
+
const dir = statusLineDir(this.teamName);
|
|
759
|
+
if (!existsSync4(dir)) {
|
|
760
|
+
mkdirSync(dir, { recursive: true });
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Start watching a specific agent's statusLine log file.
|
|
765
|
+
*/
|
|
766
|
+
watchAgent(agentName) {
|
|
767
|
+
if (this.stopped) return;
|
|
768
|
+
const filePath = statusLineLogPath(this.teamName, agentName);
|
|
769
|
+
if (!existsSync4(filePath)) {
|
|
770
|
+
writeFileSync(filePath, "");
|
|
771
|
+
}
|
|
772
|
+
try {
|
|
773
|
+
const stats = readFileSync(filePath);
|
|
774
|
+
this.fileOffsets.set(filePath, stats.length);
|
|
775
|
+
} catch {
|
|
776
|
+
this.fileOffsets.set(filePath, 0);
|
|
777
|
+
}
|
|
778
|
+
try {
|
|
779
|
+
const watcher = watch(filePath, (eventType) => {
|
|
780
|
+
if (eventType === "change") {
|
|
781
|
+
this.readNewLines(agentName, filePath);
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
this.watchers.set(agentName, watcher);
|
|
785
|
+
this.log.debug(`Watching statusLine for agent "${agentName}" at ${filePath}`);
|
|
786
|
+
} catch (err) {
|
|
787
|
+
this.log.error(`Failed to watch statusLine for "${agentName}": ${err}`);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* Stop watching a specific agent.
|
|
792
|
+
*/
|
|
793
|
+
unwatchAgent(agentName) {
|
|
794
|
+
const watcher = this.watchers.get(agentName);
|
|
795
|
+
if (watcher) {
|
|
796
|
+
watcher.close();
|
|
797
|
+
this.watchers.delete(agentName);
|
|
798
|
+
}
|
|
799
|
+
const filePath = statusLineLogPath(this.teamName, agentName);
|
|
800
|
+
this.fileOffsets.delete(filePath);
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* Stop all watchers.
|
|
804
|
+
*/
|
|
805
|
+
stop() {
|
|
806
|
+
this.stopped = true;
|
|
807
|
+
for (const [, watcher] of this.watchers) {
|
|
808
|
+
watcher.close();
|
|
809
|
+
}
|
|
810
|
+
this.watchers.clear();
|
|
811
|
+
this.fileOffsets.clear();
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Read new lines appended to the log file since last read.
|
|
815
|
+
*/
|
|
816
|
+
readNewLines(agentName, filePath) {
|
|
817
|
+
try {
|
|
818
|
+
const content = readFileSync(filePath, "utf-8");
|
|
819
|
+
const offset = this.fileOffsets.get(filePath) ?? 0;
|
|
820
|
+
const newContent = content.slice(offset);
|
|
821
|
+
this.fileOffsets.set(filePath, content.length);
|
|
822
|
+
if (!newContent.trim()) return;
|
|
823
|
+
const lines = newContent.trim().split("\n");
|
|
824
|
+
for (const line of lines) {
|
|
825
|
+
if (!line.trim()) continue;
|
|
826
|
+
try {
|
|
827
|
+
const data = JSON.parse(line);
|
|
828
|
+
const event = {
|
|
829
|
+
agentName,
|
|
830
|
+
data,
|
|
831
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
832
|
+
};
|
|
833
|
+
this.emit("update", event);
|
|
834
|
+
} catch (parseErr) {
|
|
835
|
+
this.log.debug(`Failed to parse statusLine JSON: ${line}`);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
} catch (err) {
|
|
839
|
+
this.log.debug(`Error reading statusLine file: ${err}`);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
};
|
|
843
|
+
|
|
705
844
|
// src/controller.ts
|
|
706
845
|
var PROTOCOL_ONLY_TYPES = /* @__PURE__ */ new Set([
|
|
707
846
|
"shutdown_approved",
|
|
@@ -721,12 +860,13 @@ var AGENT_COLORS = [
|
|
|
721
860
|
"#FF69B4",
|
|
722
861
|
"#7B68EE"
|
|
723
862
|
];
|
|
724
|
-
var ClaudeCodeController = class extends
|
|
863
|
+
var ClaudeCodeController = class extends EventEmitter2 {
|
|
725
864
|
teamName;
|
|
726
865
|
team;
|
|
727
866
|
tasks;
|
|
728
867
|
processes;
|
|
729
868
|
poller;
|
|
869
|
+
statusLineWatcher;
|
|
730
870
|
log;
|
|
731
871
|
cwd;
|
|
732
872
|
claudeBinary;
|
|
@@ -748,7 +888,11 @@ var ClaudeCodeController = class extends EventEmitter {
|
|
|
748
888
|
"controller",
|
|
749
889
|
this.log
|
|
750
890
|
);
|
|
891
|
+
this.statusLineWatcher = new StatusLineWatcher(this.teamName, this.log);
|
|
751
892
|
this.poller.onMessages((events) => this.handlePollEvents(events));
|
|
893
|
+
this.statusLineWatcher.on("update", (event) => {
|
|
894
|
+
this.emit("agent:statusline", event.agentName, event.data);
|
|
895
|
+
});
|
|
752
896
|
}
|
|
753
897
|
// ─── Lifecycle ───────────────────────────────────────────────────────
|
|
754
898
|
/**
|
|
@@ -759,6 +903,7 @@ var ClaudeCodeController = class extends EventEmitter {
|
|
|
759
903
|
if (this.initialized) return this;
|
|
760
904
|
await this.team.create({ cwd: this.cwd });
|
|
761
905
|
await this.tasks.init();
|
|
906
|
+
this.statusLineWatcher.ensureDir();
|
|
762
907
|
this.poller.start();
|
|
763
908
|
this.initialized = true;
|
|
764
909
|
this.log.info(
|
|
@@ -799,6 +944,7 @@ var ClaudeCodeController = class extends EventEmitter {
|
|
|
799
944
|
}
|
|
800
945
|
await this.processes.killAll();
|
|
801
946
|
this.poller.stop();
|
|
947
|
+
this.statusLineWatcher.stop();
|
|
802
948
|
await this.team.destroy();
|
|
803
949
|
this.initialized = false;
|
|
804
950
|
this.log.info("Controller shut down");
|
|
@@ -827,6 +973,8 @@ var ClaudeCodeController = class extends EventEmitter {
|
|
|
827
973
|
subscriptions: []
|
|
828
974
|
};
|
|
829
975
|
await this.team.addMember(member);
|
|
976
|
+
this.ensureWorkspaceTrusted(cwd, opts.name);
|
|
977
|
+
this.statusLineWatcher.watchAgent(opts.name);
|
|
830
978
|
const env = Object.keys(this.defaultEnv).length > 0 || opts.env ? { ...this.defaultEnv, ...opts.env } : void 0;
|
|
831
979
|
const proc = this.processes.spawn({
|
|
832
980
|
teamName: this.teamName,
|
|
@@ -1033,6 +1181,7 @@ var ClaudeCodeController = class extends EventEmitter {
|
|
|
1033
1181
|
* Kill a specific agent.
|
|
1034
1182
|
*/
|
|
1035
1183
|
async killAgent(name) {
|
|
1184
|
+
this.statusLineWatcher.unwatchAgent(name);
|
|
1036
1185
|
await this.processes.kill(name);
|
|
1037
1186
|
await this.team.removeMember(name);
|
|
1038
1187
|
}
|
|
@@ -1094,6 +1243,32 @@ var ClaudeCodeController = class extends EventEmitter {
|
|
|
1094
1243
|
}
|
|
1095
1244
|
}
|
|
1096
1245
|
}
|
|
1246
|
+
/**
|
|
1247
|
+
* Ensure the agent's cwd has a .claude/settings.local.json so the
|
|
1248
|
+
* CLI skips the interactive workspace trust prompt.
|
|
1249
|
+
* Also injects statusLine capture configuration.
|
|
1250
|
+
*/
|
|
1251
|
+
ensureWorkspaceTrusted(cwd, agentName) {
|
|
1252
|
+
const claudeDir = join3(cwd, ".claude");
|
|
1253
|
+
const settingsPath = join3(claudeDir, "settings.local.json");
|
|
1254
|
+
mkdirSync2(claudeDir, { recursive: true });
|
|
1255
|
+
let settings = {};
|
|
1256
|
+
if (existsSync5(settingsPath)) {
|
|
1257
|
+
try {
|
|
1258
|
+
settings = JSON.parse(readFileSync2(settingsPath, "utf-8"));
|
|
1259
|
+
} catch {
|
|
1260
|
+
settings = {};
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
if (agentName && !settings.statusLine) {
|
|
1264
|
+
const logPath = statusLineLogPath(this.teamName, agentName);
|
|
1265
|
+
const statusLineSettings = buildStatusLineSettings(logPath);
|
|
1266
|
+
settings = { ...settings, ...statusLineSettings };
|
|
1267
|
+
this.log.debug(`Injected statusLine capture for "${agentName}"`);
|
|
1268
|
+
}
|
|
1269
|
+
writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
1270
|
+
this.log.debug(`Updated ${settingsPath}`);
|
|
1271
|
+
}
|
|
1097
1272
|
ensureInitialized() {
|
|
1098
1273
|
if (!this.initialized) {
|
|
1099
1274
|
throw new Error(
|
|
@@ -1178,7 +1353,7 @@ function waitForReady(controller, agentName, timeoutMs = 15e3) {
|
|
|
1178
1353
|
controller.on("agent:exited", onExit);
|
|
1179
1354
|
});
|
|
1180
1355
|
}
|
|
1181
|
-
var Agent = class _Agent extends
|
|
1356
|
+
var Agent = class _Agent extends EventEmitter3 {
|
|
1182
1357
|
controller;
|
|
1183
1358
|
handle;
|
|
1184
1359
|
ownsController;
|
|
@@ -1271,14 +1446,22 @@ var Agent = class _Agent extends EventEmitter2 {
|
|
|
1271
1446
|
this.ensureNotDisposed();
|
|
1272
1447
|
const timeout = opts?.timeout ?? 12e4;
|
|
1273
1448
|
const responsePromise = new Promise((resolve, reject) => {
|
|
1449
|
+
let gotMessage = false;
|
|
1274
1450
|
const timer = setTimeout(() => {
|
|
1275
1451
|
cleanup();
|
|
1276
1452
|
reject(new Error(`Timeout (${timeout}ms) waiting for response`));
|
|
1277
1453
|
}, timeout);
|
|
1278
1454
|
const onMsg = (text) => {
|
|
1455
|
+
gotMessage = true;
|
|
1279
1456
|
cleanup();
|
|
1280
1457
|
resolve(text);
|
|
1281
1458
|
};
|
|
1459
|
+
const onIdle = () => {
|
|
1460
|
+
if (!gotMessage) {
|
|
1461
|
+
cleanup();
|
|
1462
|
+
resolve("");
|
|
1463
|
+
}
|
|
1464
|
+
};
|
|
1282
1465
|
const onExit = (code) => {
|
|
1283
1466
|
cleanup();
|
|
1284
1467
|
reject(new Error(`Agent exited (code=${code}) before responding`));
|
|
@@ -1286,9 +1469,11 @@ var Agent = class _Agent extends EventEmitter2 {
|
|
|
1286
1469
|
const cleanup = () => {
|
|
1287
1470
|
clearTimeout(timer);
|
|
1288
1471
|
this.removeListener("message", onMsg);
|
|
1472
|
+
this.removeListener("idle", onIdle);
|
|
1289
1473
|
this.removeListener("exit", onExit);
|
|
1290
1474
|
};
|
|
1291
1475
|
this.on("message", onMsg);
|
|
1476
|
+
this.on("idle", onIdle);
|
|
1292
1477
|
this.on("exit", onExit);
|
|
1293
1478
|
});
|
|
1294
1479
|
const wrapped = `${question}
|
|
@@ -1307,14 +1492,22 @@ IMPORTANT: You MUST send your complete answer back using the SendMessage tool. D
|
|
|
1307
1492
|
this.ensureNotDisposed();
|
|
1308
1493
|
const timeout = opts?.timeout ?? 12e4;
|
|
1309
1494
|
return new Promise((resolve, reject) => {
|
|
1495
|
+
let gotMessage = false;
|
|
1310
1496
|
const timer = setTimeout(() => {
|
|
1311
1497
|
cleanup();
|
|
1312
1498
|
reject(new Error(`Timeout (${timeout}ms) waiting for response`));
|
|
1313
1499
|
}, timeout);
|
|
1314
1500
|
const onMsg = (text) => {
|
|
1501
|
+
gotMessage = true;
|
|
1315
1502
|
cleanup();
|
|
1316
1503
|
resolve(text);
|
|
1317
1504
|
};
|
|
1505
|
+
const onIdle = () => {
|
|
1506
|
+
if (!gotMessage) {
|
|
1507
|
+
cleanup();
|
|
1508
|
+
resolve("");
|
|
1509
|
+
}
|
|
1510
|
+
};
|
|
1318
1511
|
const onExit = (code) => {
|
|
1319
1512
|
cleanup();
|
|
1320
1513
|
reject(new Error(`Agent exited (code=${code}) before responding`));
|
|
@@ -1322,9 +1515,11 @@ IMPORTANT: You MUST send your complete answer back using the SendMessage tool. D
|
|
|
1322
1515
|
const cleanup = () => {
|
|
1323
1516
|
clearTimeout(timer);
|
|
1324
1517
|
this.removeListener("message", onMsg);
|
|
1518
|
+
this.removeListener("idle", onIdle);
|
|
1325
1519
|
this.removeListener("exit", onExit);
|
|
1326
1520
|
};
|
|
1327
1521
|
this.on("message", onMsg);
|
|
1522
|
+
this.on("idle", onIdle);
|
|
1328
1523
|
this.on("exit", onExit);
|
|
1329
1524
|
});
|
|
1330
1525
|
}
|
|
@@ -1358,6 +1553,9 @@ IMPORTANT: You MUST send your complete answer back using the SendMessage tool. D
|
|
|
1358
1553
|
const onIdle = (name, _details) => {
|
|
1359
1554
|
if (name === agentName) this.emit("idle");
|
|
1360
1555
|
};
|
|
1556
|
+
const onStatusLine = (name, data) => {
|
|
1557
|
+
if (name === agentName) this.emit("statusline", data);
|
|
1558
|
+
};
|
|
1361
1559
|
const onPermission = (name, parsed) => {
|
|
1362
1560
|
if (name !== agentName) return;
|
|
1363
1561
|
let handled = false;
|
|
@@ -1406,6 +1604,7 @@ IMPORTANT: You MUST send your complete answer back using the SendMessage tool. D
|
|
|
1406
1604
|
};
|
|
1407
1605
|
this.controller.on("message", onMessage);
|
|
1408
1606
|
this.controller.on("idle", onIdle);
|
|
1607
|
+
this.controller.on("agent:statusline", onStatusLine);
|
|
1409
1608
|
this.controller.on("permission:request", onPermission);
|
|
1410
1609
|
this.controller.on("plan:approval_request", onPlan);
|
|
1411
1610
|
this.controller.on("agent:exited", onExit);
|
|
@@ -1413,6 +1612,7 @@ IMPORTANT: You MUST send your complete answer back using the SendMessage tool. D
|
|
|
1413
1612
|
this.boundListeners = [
|
|
1414
1613
|
{ event: "message", fn: onMessage },
|
|
1415
1614
|
{ event: "idle", fn: onIdle },
|
|
1615
|
+
{ event: "agent:statusline", fn: onStatusLine },
|
|
1416
1616
|
{ event: "permission:request", fn: onPermission },
|
|
1417
1617
|
{ event: "plan:approval_request", fn: onPlan },
|
|
1418
1618
|
{ event: "agent:exited", fn: onExit },
|
|
@@ -1558,8 +1758,11 @@ export {
|
|
|
1558
1758
|
InboxPoller,
|
|
1559
1759
|
ProcessManager,
|
|
1560
1760
|
Session,
|
|
1761
|
+
StatusLineWatcher,
|
|
1561
1762
|
TaskManager,
|
|
1562
1763
|
TeamManager,
|
|
1764
|
+
buildStatusLineCommand,
|
|
1765
|
+
buildStatusLineSettings,
|
|
1563
1766
|
claude,
|
|
1564
1767
|
createLogger,
|
|
1565
1768
|
inboxPath,
|
|
@@ -1568,6 +1771,8 @@ export {
|
|
|
1568
1771
|
readInbox,
|
|
1569
1772
|
readUnread,
|
|
1570
1773
|
silentLogger,
|
|
1774
|
+
statusLineDir,
|
|
1775
|
+
statusLineLogPath,
|
|
1571
1776
|
taskPath,
|
|
1572
1777
|
tasksBaseDir,
|
|
1573
1778
|
tasksDir,
|