codedeck 0.7.1 → 0.7.2

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,55 +8,18 @@ export class RunAgentError extends Error {
8
8
  this.name = this.constructor.name;
9
9
  }
10
10
  }
11
- export class AgentNotInstalledError extends RunAgentError {
12
- constructor(agent) {
13
- super(`Agent "${agent}" is not installed`, "AGENT_NOT_INSTALLED", { agent });
14
- }
15
- }
16
- export class AgentAuthenticationRequiredError extends RunAgentError {
17
- constructor(agent) {
18
- super(`Agent "${agent}" requires authentication`, "AGENT_AUTH_REQUIRED", { agent });
19
- }
20
- }
21
- export class AgentStartFailedError extends RunAgentError {
22
- constructor(agent, cause) {
23
- super(`Failed to start agent "${agent}"`, "AGENT_START_FAILED", { agent, cause });
24
- }
25
- }
26
11
  export class SessionNotFoundError extends RunAgentError {
27
12
  constructor(id) {
28
13
  super(`Session "${id}" not found`, "SESSION_NOT_FOUND", { id });
29
14
  }
30
15
  }
31
- export class SessionNotRunningError extends RunAgentError {
32
- constructor(id) {
33
- super(`Session "${id}" is not running`, "SESSION_NOT_RUNNING", { id });
34
- }
35
- }
36
- export class CapabilityNotSupportedError extends RunAgentError {
37
- constructor(agent, capability) {
38
- super(`Agent "${agent}" does not support "${capability}"`, "CAPABILITY_NOT_SUPPORTED", { agent, capability });
39
- }
40
- }
41
- export class RepositoryNotFoundError extends RunAgentError {
42
- constructor(cwd) {
43
- super(`No git repository found at "${cwd}"`, "REPOSITORY_NOT_FOUND", { cwd });
44
- }
45
- }
46
16
  export class WorktreeCreationFailedError extends RunAgentError {
47
17
  constructor(cause) {
48
18
  super("Failed to create git worktree", "WORKTREE_CREATION_FAILED", { cause });
49
19
  }
50
20
  }
51
- export class DaemonUnavailableError extends RunAgentError {
52
- constructor(cause) {
53
- super("CodeDeck daemon is unavailable", "DAEMON_UNAVAILABLE", { cause });
54
- }
55
- }
56
- export class ProtocolError extends RunAgentError {
57
- constructor(message, cause) {
58
- super(message, "PROTOCOL_ERROR", { cause });
59
- }
21
+ export function errorMessage(e) {
22
+ return e instanceof Error ? e.message : String(e);
60
23
  }
61
24
  // Order matters: the most specific signatures first. "EPIPE" alone is LAST —
62
25
  // it is a substring task output can legitimately contain (e.g. a test grepping
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"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"}
@@ -21,7 +21,7 @@ import { readSessionProcessMetadata } from "../drivers/session-runtime.js";
21
21
  import { loadConfig, resolveDefaultSandbox } from "../config/config.js";
22
22
  import { invalidWebHostMessage, resolveWebHost } from "../config/web-host.js";
23
23
  import { invalidWebPortMessage, resolveWebPort } from "../config/web-port.js";
24
- import { classifyFailure, isStoreBusy, RunAgentError } from "../core/errors.js";
24
+ import { classifyFailure, errorMessage, isStoreBusy, RunAgentError } from "../core/errors.js";
25
25
  import { parseRole } from "../core/roles.js";
26
26
  import { getCachedOrDiscoverModels } from "../core/models.js";
27
27
  import { aggregateRunUsage } from "../core/run-usage.js";
@@ -97,6 +97,7 @@ class Daemon {
97
97
  nativeLinks;
98
98
  registry = getRegistry();
99
99
  server;
100
+ boundPaths;
100
101
  subscribers = new Map(); // sessionId -> sockets
101
102
  startTime = Date.now();
102
103
  startupReconcilePromise = Promise.resolve();
@@ -261,7 +262,7 @@ class Daemon {
261
262
  queueReleasedTranscriptCursorCleanup(sessionId) {
262
263
  queueMicrotask(() => {
263
264
  void this.cleanupReleasedTranscriptCursors(sessionId).catch((error) => {
264
- const detail = error instanceof Error ? error.message : String(error);
265
+ const detail = errorMessage(error);
265
266
  try {
266
267
  fs.appendFileSync(getPaths().daemonLog, `[${new Date().toISOString()}] usage cursor cleanup failed session=${sessionId}: ${detail}\n`);
267
268
  }
@@ -315,7 +316,7 @@ class Daemon {
315
316
  await this.handleRequest(req, socket);
316
317
  }
317
318
  catch (e) {
318
- const res = { id: req.id, error: { code: "INTERNAL", message: e instanceof Error ? e.message : String(e) } };
319
+ const res = { id: req.id, error: { code: "INTERNAL", message: errorMessage(e) } };
319
320
  try {
320
321
  socket.write(JSON.stringify(res) + "\n");
321
322
  }
@@ -326,6 +327,10 @@ class Daemon {
326
327
  this.server.listen(paths.daemonSock, () => resolve());
327
328
  this.server.on("error", reject);
328
329
  });
330
+ this.boundPaths = {
331
+ sock: paths.daemonSock,
332
+ pid: paths.daemonPid,
333
+ };
329
334
  // Write pid file
330
335
  try {
331
336
  fs.writeFileSync(paths.daemonPid, String(process.pid), "utf-8");
@@ -554,7 +559,7 @@ class Daemon {
554
559
  this.sessions.update(sessionId, { completedAt: heal.endedAt });
555
560
  }
556
561
  catch (error) {
557
- appendDaemonLog(`heal timestamps for ${sessionId} failed: ${error instanceof Error ? error.message : String(error)}`);
562
+ appendDaemonLog(`heal timestamps for ${sessionId} failed: ${errorMessage(error)}`);
558
563
  }
559
564
  }
560
565
  async reconcileOpenUsage(sessionId, nativeIds) {
@@ -605,7 +610,7 @@ class Daemon {
605
610
  return true;
606
611
  }
607
612
  catch (error) {
608
- const detail = error instanceof Error ? error.message : String(error);
613
+ const detail = errorMessage(error);
609
614
  try {
610
615
  fs.appendFileSync(getPaths().daemonLog, `[${new Date().toISOString()}] usage reconcile failed session=${sessionId}: ${detail}\n`);
611
616
  }
@@ -626,6 +631,23 @@ class Daemon {
626
631
  releaseSessionId(sessionId) {
627
632
  this.reservedSessionIds.delete(sessionId);
628
633
  }
634
+ resolveRegisteredAgent(rawAgent) {
635
+ const agent = (normalizeAgentId(rawAgent) ?? rawAgent);
636
+ return { agent, registered: this.registry.has(agent) };
637
+ }
638
+ handleClaimRequest(requestedSessionId, operation, result, send) {
639
+ try {
640
+ const sessionId = this.sessions.get(requestedSessionId)?.id ?? requestedSessionId;
641
+ send(result(operation(sessionId)));
642
+ }
643
+ catch (error) {
644
+ if (error instanceof RunAgentError) {
645
+ send({ error: { code: error.code, message: error.message, details: error.details } });
646
+ return;
647
+ }
648
+ throw error;
649
+ }
650
+ }
629
651
  async handleRequest(req, socket) {
630
652
  const { id, method, params } = req;
631
653
  const send = (res) => {
@@ -634,11 +656,13 @@ class Daemon {
634
656
  }
635
657
  catch { }
636
658
  };
659
+ const sendSessionNotFound = (sessionId) => send({ error: { code: "SESSION_NOT_FOUND", message: `Session ${sessionId} not found` } });
660
+ const sendShuttingDown = () => send({ error: { code: "SERVICE_UNAVAILABLE", message: "daemon is shutting down" } });
637
661
  // Power-shutdown guard: while draining, refuse new work so a send/stop
638
662
  // cannot race the interrupted persist. daemon.stop is the shutdown
639
663
  // trigger itself, so it stays admitted (idempotent via handleShutdown).
640
664
  if (this.shuttingDown && method !== "daemon.stop") {
641
- send({ error: { code: "SERVICE_UNAVAILABLE", message: "daemon is shutting down" } });
665
+ sendShuttingDown();
642
666
  return;
643
667
  }
644
668
  try {
@@ -653,8 +677,8 @@ class Daemon {
653
677
  const cwdIn = p.cwd || process.cwd();
654
678
  const cfg = loadConfig();
655
679
  const rawAgent = p.agent || cfg.defaultAgent || "claude";
656
- let agent = (normalizeAgentId(rawAgent) ?? rawAgent);
657
- if (!this.registry.has(agent)) {
680
+ const { agent, registered } = this.resolveRegisteredAgent(rawAgent);
681
+ if (!registered) {
658
682
  send({ error: { code: "AGENT_NOT_FOUND", message: `Unknown agent ${agent}` } });
659
683
  return;
660
684
  }
@@ -682,7 +706,7 @@ class Daemon {
682
706
  }
683
707
  if (this.shuttingDown) {
684
708
  this.releaseSessionId(sessionId);
685
- send({ error: { code: "SERVICE_UNAVAILABLE", message: "daemon is shutting down" } });
709
+ sendShuttingDown();
686
710
  return;
687
711
  }
688
712
  if (gitInfo)
@@ -694,7 +718,7 @@ class Daemon {
694
718
  const wt = await createWorktree({ repoRoot: gitInfo.root, sessionId, prompt, name: p.name });
695
719
  if (this.shuttingDown) {
696
720
  this.releaseSessionId(sessionId);
697
- send({ error: { code: "SERVICE_UNAVAILABLE", message: "daemon is shutting down" } });
721
+ sendShuttingDown();
698
722
  return;
699
723
  }
700
724
  worktree = wt.path;
@@ -704,7 +728,7 @@ class Daemon {
704
728
  }
705
729
  catch (e) {
706
730
  this.releaseSessionId(sessionId);
707
- send({ error: { code: "WORKTREE_FAILED", message: e instanceof Error ? e.message : String(e) } });
731
+ send({ error: { code: "WORKTREE_FAILED", message: errorMessage(e) } });
708
732
  return;
709
733
  }
710
734
  }
@@ -741,13 +765,12 @@ class Daemon {
741
765
  this.releaseSessionId(sessionId);
742
766
  }
743
767
  // Start driver async (don't block response too long)
744
- // But we need to start before returning? Return quickly then start
745
768
  send({ result: { session } });
746
769
  // Now start driver in background
747
770
  this.startDriverForSession(sessionId, prompt, p.model).catch((e) => {
748
771
  if (this.shuttingDown)
749
772
  return;
750
- const msg = e instanceof Error ? e.message : String(e);
773
+ const msg = errorMessage(e);
751
774
  const failure = classifyFailure(msg);
752
775
  const failEv = {
753
776
  type: "session.failed",
@@ -769,8 +792,8 @@ class Daemon {
769
792
  const p = params;
770
793
  const cwdIn = p.cwd || process.cwd();
771
794
  const rawAgent = p.agent || "claude";
772
- const agent = (normalizeAgentId(rawAgent) ?? rawAgent);
773
- if (!this.registry.has(agent)) {
795
+ const { agent, registered } = this.resolveRegisteredAgent(rawAgent);
796
+ if (!registered) {
774
797
  send({ error: { code: "AGENT_NOT_FOUND", message: `Unknown agent ${agent}` } });
775
798
  return;
776
799
  }
@@ -779,7 +802,7 @@ class Daemon {
779
802
  let baseCommit = p.baseCommit;
780
803
  const gitInfo = await getGitInfo(cwd);
781
804
  if (this.shuttingDown) {
782
- send({ error: { code: "SERVICE_UNAVAILABLE", message: "daemon is shutting down" } });
805
+ sendShuttingDown();
783
806
  return;
784
807
  }
785
808
  const matchingSession = typeof p.resume === "string" && p.resume.length > 0
@@ -808,8 +831,7 @@ class Daemon {
808
831
  agent,
809
832
  nativeSessionId: p.resume,
810
833
  };
811
- this.events.append(revived.id, event);
812
- this.broadcast(revived.id, event);
834
+ this.emit(revived.id, event);
813
835
  send({ result: { session: revived } });
814
836
  break;
815
837
  }
@@ -851,7 +873,7 @@ class Daemon {
851
873
  const p = params;
852
874
  const s = this.sessions.get(p.id);
853
875
  if (!s) {
854
- send({ error: { code: "SESSION_NOT_FOUND", message: `Session ${p.id} not found` } });
876
+ sendSessionNotFound(p.id);
855
877
  return;
856
878
  }
857
879
  let pidStartTime = p.pidStartTime;
@@ -884,7 +906,7 @@ class Daemon {
884
906
  }
885
907
  const session = this.sessions.get(p.id);
886
908
  if (!session) {
887
- send({ error: { code: "SESSION_NOT_FOUND", message: `Session ${p.id} not found` } });
909
+ sendSessionNotFound(p.id);
888
910
  return;
889
911
  }
890
912
  if (session.origin !== "open") {
@@ -901,7 +923,7 @@ class Daemon {
901
923
  const p = params;
902
924
  const s = this.sessions.get(p.id);
903
925
  if (!s) {
904
- send({ error: { code: "SESSION_NOT_FOUND", message: `Session ${p.id} not found` } });
926
+ sendSessionNotFound(p.id);
905
927
  return;
906
928
  }
907
929
  // Release owns the terminal outcome: a queued message must not
@@ -953,8 +975,7 @@ class Daemon {
953
975
  timestamp: new Date().toISOString(),
954
976
  reason: "released",
955
977
  };
956
- this.events.append(s.id, ev);
957
- this.broadcast(s.id, ev);
978
+ this.emit(s.id, ev);
958
979
  const updated = this.sessions.get(s.id);
959
980
  send({ result: { session: updated } });
960
981
  break;
@@ -964,7 +985,6 @@ class Daemon {
964
985
  const all = p?.all;
965
986
  const list = this.sessions.list(100, all).map(withLiveStatus);
966
987
  const hidden = all ? 0 : this.sessions.countHiddenByWindow();
967
- // Enrich with last event?
968
988
  send({ result: { sessions: list, hidden } });
969
989
  break;
970
990
  }
@@ -972,7 +992,7 @@ class Daemon {
972
992
  const p = params;
973
993
  const stored = this.sessions.get(p.id);
974
994
  if (!stored) {
975
- send({ error: { code: "SESSION_NOT_FOUND", message: `Session ${p.id} not found` } });
995
+ sendSessionNotFound(p.id);
976
996
  return;
977
997
  }
978
998
  const s = withLiveStatus(stored);
@@ -985,7 +1005,7 @@ class Daemon {
985
1005
  const p = params;
986
1006
  const s = this.sessions.get(p.id);
987
1007
  if (!s) {
988
- send({ error: { code: "SESSION_NOT_FOUND", message: `Session ${p.id} not found` } });
1008
+ sendSessionNotFound(p.id);
989
1009
  return;
990
1010
  }
991
1011
  if (!p.name || !p.name.trim()) {
@@ -1006,7 +1026,7 @@ class Daemon {
1006
1026
  const message = validated.message;
1007
1027
  const s = this.sessions.get(p.id);
1008
1028
  if (!s) {
1009
- send({ error: { code: "SESSION_NOT_FOUND", message: `Session ${p.id} not found` } });
1029
+ sendSessionNotFound(p.id);
1010
1030
  return;
1011
1031
  }
1012
1032
  if (s.origin === "open") {
@@ -1053,7 +1073,7 @@ class Daemon {
1053
1073
  this.sessions.update(s.id, { pendingMessage: message, pendingAt });
1054
1074
  }
1055
1075
  catch (e) {
1056
- send({ error: { code: "SEND_FAILED", message: e instanceof Error ? e.message : String(e) } });
1076
+ send({ error: { code: "SEND_FAILED", message: errorMessage(e) } });
1057
1077
  return;
1058
1078
  }
1059
1079
  const queuedEvent = {
@@ -1089,7 +1109,7 @@ class Daemon {
1089
1109
  send({ result: { ok: true, queued: false } });
1090
1110
  }
1091
1111
  catch (e) {
1092
- const errText = e instanceof Error ? e.message : String(e);
1112
+ const errText = errorMessage(e);
1093
1113
  const code = e instanceof Error && e.code === "SERVICE_UNAVAILABLE"
1094
1114
  ? "SERVICE_UNAVAILABLE"
1095
1115
  : this.shuttingDown ? "SERVICE_UNAVAILABLE" : "SEND_FAILED";
@@ -1113,7 +1133,7 @@ class Daemon {
1113
1133
  const p = params;
1114
1134
  const s = this.sessions.get(p.id);
1115
1135
  if (!s) {
1116
- send({ error: { code: "SESSION_NOT_FOUND", message: `Session ${p.id} not found` } });
1136
+ sendSessionNotFound(p.id);
1117
1137
  return;
1118
1138
  }
1119
1139
  // Stop cancels a queued message on every exit (explicit cancel),
@@ -1126,10 +1146,7 @@ class Daemon {
1126
1146
  }
1127
1147
  const handle = driver.getHandle?.(s.id);
1128
1148
  const hasRuntime = handle !== undefined;
1129
- const liveIdentity = s.pid != null &&
1130
- s.pidStartTime != null &&
1131
- processAlive(s.pid) &&
1132
- processStartTime(s.pid) === s.pidStartTime;
1149
+ const liveIdentity = livePidIdentity(s);
1133
1150
  if (isTerminalStatus(s.status) && !hasRuntime && !liveIdentity) {
1134
1151
  send({ error: { code: "SESSION_NOT_RUNNING", message: `Session ${s.id} is ${s.status}` } });
1135
1152
  return;
@@ -1155,7 +1172,7 @@ class Daemon {
1155
1172
  pidStartTime: s.pidStartTime,
1156
1173
  });
1157
1174
  if (this.shuttingDown) {
1158
- send({ error: { code: "SERVICE_UNAVAILABLE", message: "daemon is shutting down" } });
1175
+ sendShuttingDown();
1159
1176
  return;
1160
1177
  }
1161
1178
  const last = this.events.last(s.id);
@@ -1177,8 +1194,7 @@ class Daemon {
1177
1194
  reason: "stopped",
1178
1195
  exitCode: 130,
1179
1196
  };
1180
- this.events.append(s.id, ev);
1181
- this.broadcast(s.id, ev);
1197
+ this.emit(s.id, ev);
1182
1198
  }
1183
1199
  // A send may have persisted a slot after the entry clear (it saw a
1184
1200
  // live turn before this stop took the lock): stop wins, clear again.
@@ -1187,14 +1203,14 @@ class Daemon {
1187
1203
  }
1188
1204
  catch (e) {
1189
1205
  if (this.shuttingDown) {
1190
- send({ error: { code: "SERVICE_UNAVAILABLE", message: "daemon is shutting down" } });
1206
+ sendShuttingDown();
1191
1207
  return;
1192
1208
  }
1193
1209
  try {
1194
1210
  this.sessions.setStatus(s.id, previousStatus);
1195
1211
  }
1196
1212
  catch { }
1197
- send({ error: { code: "STOP_FAILED", message: e instanceof Error ? e.message : String(e) } });
1213
+ send({ error: { code: "STOP_FAILED", message: errorMessage(e) } });
1198
1214
  }
1199
1215
  finally {
1200
1216
  if (!this.shuttingDown)
@@ -1206,7 +1222,7 @@ class Daemon {
1206
1222
  const p = params;
1207
1223
  const s = this.sessions.get(p.id);
1208
1224
  if (!s) {
1209
- send({ error: { code: "SESSION_NOT_FOUND", message: `Session ${p.id} not found` } });
1225
+ sendSessionNotFound(p.id);
1210
1226
  return;
1211
1227
  }
1212
1228
  if (p.follow) {
@@ -1230,7 +1246,7 @@ class Daemon {
1230
1246
  const p = params;
1231
1247
  const s = this.sessions.get(p.id);
1232
1248
  if (!s) {
1233
- send({ error: { code: "SESSION_NOT_FOUND", message: `Session ${p.id} not found` } });
1249
+ sendSessionNotFound(p.id);
1234
1250
  return;
1235
1251
  }
1236
1252
  // A late subscriber must not wait forever for a broadcast that already
@@ -1250,23 +1266,14 @@ class Daemon {
1250
1266
  catch { }
1251
1267
  return;
1252
1268
  }
1253
- // Send buffered events first?
1254
- // Then keep streaming
1255
1269
  this.addSubscriber(s.id, socket);
1256
- // Send ack? keep open
1257
- // Optionally send done when session terminal? We'll handle via broadcast.
1258
- // Don't send immediate response; just keep socket open for events
1259
- // But we should send an initial ack to confirm subscription?
1260
- // Use a separate message to indicate subscription started
1261
- // Let's not send anything; client will just wait for events
1262
- // Keep socket open
1263
1270
  return;
1264
1271
  }
1265
1272
  case "session.diff": {
1266
1273
  const p = params;
1267
1274
  const s = this.sessions.get(p.id);
1268
1275
  if (!s) {
1269
- send({ error: { code: "SESSION_NOT_FOUND", message: `Session ${p.id} not found` } });
1276
+ sendSessionNotFound(p.id);
1270
1277
  return;
1271
1278
  }
1272
1279
  const diff = await getDiff({ cwd: s.cwd, worktree: s.worktree, baseCommit: s.baseCommit, repository: s.repository });
@@ -1275,56 +1282,17 @@ class Daemon {
1275
1282
  }
1276
1283
  case "claims.add": {
1277
1284
  const p = params;
1278
- try {
1279
- const sessionId = this.sessions.get(p.sessionId)?.id ?? p.sessionId;
1280
- const claim = this.claims.add(sessionId, p.pathGlob, p.reason);
1281
- send({ result: { claim } });
1282
- }
1283
- catch (error) {
1284
- if (error instanceof RunAgentError) {
1285
- send({ error: { code: error.code, message: error.message, details: error.details } });
1286
- return;
1287
- }
1288
- throw error;
1289
- }
1285
+ this.handleClaimRequest(p.sessionId, (sessionId) => this.claims.add(sessionId, p.pathGlob, p.reason), (claim) => ({ result: { claim } }), send);
1290
1286
  break;
1291
1287
  }
1292
1288
  case "claims.query": {
1293
1289
  const p = params;
1294
- try {
1295
- const sessionId = this.sessions.get(p.sessionId)?.id ?? p.sessionId;
1296
- const claims = this.claims.query(sessionId, p.path);
1297
- send({ result: { claims } });
1298
- }
1299
- catch (error) {
1300
- if (error instanceof RunAgentError) {
1301
- send({ error: { code: error.code, message: error.message, details: error.details } });
1302
- return;
1303
- }
1304
- throw error;
1305
- }
1290
+ this.handleClaimRequest(p.sessionId, (sessionId) => this.claims.query(sessionId, p.path), (claims) => ({ result: { claims } }), send);
1306
1291
  break;
1307
1292
  }
1308
1293
  case "claims.release": {
1309
1294
  const p = params;
1310
- try {
1311
- const sessionId = this.sessions.get(p.sessionId)?.id ?? p.sessionId;
1312
- const claim = this.claims.release(sessionId, p.claimId);
1313
- send({ result: { claim } });
1314
- }
1315
- catch (error) {
1316
- if (error instanceof RunAgentError) {
1317
- send({ error: { code: error.code, message: error.message, details: error.details } });
1318
- return;
1319
- }
1320
- throw error;
1321
- }
1322
- break;
1323
- }
1324
- case "daemon.status": {
1325
- const paths = getPaths();
1326
- let uptime = Date.now() - this.startTime;
1327
- send({ result: { running: true, pid: process.pid, uptime, db: paths.db } });
1295
+ this.handleClaimRequest(p.sessionId, (sessionId) => this.claims.release(sessionId, p.claimId), (claim) => ({ result: { claim } }), send);
1328
1296
  break;
1329
1297
  }
1330
1298
  case "doctor": {
@@ -1461,7 +1429,7 @@ class Daemon {
1461
1429
  send({ result });
1462
1430
  }
1463
1431
  catch (error) {
1464
- send({ error: { code: "USAGE_QUERY_ERROR", message: error instanceof Error ? error.message : String(error) } });
1432
+ send({ error: { code: "USAGE_QUERY_ERROR", message: errorMessage(error) } });
1465
1433
  }
1466
1434
  break;
1467
1435
  }
@@ -1475,7 +1443,7 @@ class Daemon {
1475
1443
  send({ error: { code: error.code, message: error.message, ...(error.details ? { details: error.details } : {}) } });
1476
1444
  }
1477
1445
  else {
1478
- send({ error: { code: "WEB_START_FAILED", message: error instanceof Error ? error.message : String(error) } });
1446
+ send({ error: { code: "WEB_START_FAILED", message: errorMessage(error) } });
1479
1447
  }
1480
1448
  }
1481
1449
  break;
@@ -1531,6 +1499,10 @@ class Daemon {
1531
1499
  }
1532
1500
  }
1533
1501
  }
1502
+ emit(sessionId, event) {
1503
+ this.events.append(sessionId, event);
1504
+ this.broadcast(sessionId, event);
1505
+ }
1534
1506
  webHost() {
1535
1507
  this.web ??= new WebSupervisor({ log: appendDaemonLog, spawnChild: this.spawnWebChild });
1536
1508
  return this.web;
@@ -1549,7 +1521,7 @@ class Daemon {
1549
1521
  appendDaemonLog(invalidWebHostMessage(invalidHost));
1550
1522
  this.webHost()
1551
1523
  .ensure({ preferredPort: port, preferredHost: host })
1552
- .catch((error) => appendDaemonLog(`web autostart failed: ${error instanceof Error ? error.message : String(error)}`));
1524
+ .catch((error) => appendDaemonLog(`web autostart failed: ${errorMessage(error)}`));
1553
1525
  }
1554
1526
  async startDriverForSession(sessionId, prompt, model) {
1555
1527
  if (this.shuttingDown)
@@ -1564,8 +1536,7 @@ class Daemon {
1564
1536
  return;
1565
1537
  this.sessions.update(sessionId, { status: "working" });
1566
1538
  const turnEvent = { type: "turn.started", sessionId, timestamp: new Date().toISOString(), prompt };
1567
- this.events.append(sessionId, turnEvent);
1568
- this.broadcast(sessionId, turnEvent);
1539
+ this.emit(sessionId, turnEvent);
1569
1540
  const drvSession = await driver.start({
1570
1541
  sessionId,
1571
1542
  prompt,
@@ -1632,10 +1603,10 @@ class Daemon {
1632
1603
  catch { }
1633
1604
  }
1634
1605
  /**
1635
- + * Starts a resumed turn; caller MUST hold sessionLocks for the session.
1636
- + * Shared by session.send (immediate) and tryDispatch (queued) so both
1637
- + * paths emit the same frames in the same order.
1638
- + */
1606
+ * Starts a resumed turn; caller MUST hold sessionLocks for the session.
1607
+ * Shared by session.send (immediate) and tryDispatch (queued) so both
1608
+ * paths emit the same frames in the same order.
1609
+ */
1639
1610
  async runResumeTurn(s, message) {
1640
1611
  const driver = this.registry.get(s.agent);
1641
1612
  if (this.shuttingDown) {
@@ -1650,8 +1621,7 @@ class Daemon {
1650
1621
  timestamp: new Date().toISOString(),
1651
1622
  prompt: message,
1652
1623
  };
1653
- this.events.append(s.id, turnEvent);
1654
- this.broadcast(s.id, turnEvent);
1624
+ this.emit(s.id, turnEvent);
1655
1625
  const drvSession = {
1656
1626
  id: s.id,
1657
1627
  runId: s.runId ?? undefined,
@@ -1756,7 +1726,7 @@ class Daemon {
1756
1726
  return true;
1757
1727
  }
1758
1728
  catch (e) {
1759
- const errText = e instanceof Error ? e.message : String(e);
1729
+ const errText = errorMessage(e);
1760
1730
  const unavailable = e?.code === "SERVICE_UNAVAILABLE" || this.shuttingDown;
1761
1731
  if (!unavailable) {
1762
1732
  const failure = classifyFailure(errText);
@@ -1859,7 +1829,7 @@ class Daemon {
1859
1829
  return;
1860
1830
  // A driver exception mid-stream is a harness/pipe failure, not task
1861
1831
  // output — classify so agents can retry instead of blaming the work.
1862
- const msg = e instanceof Error ? e.message : String(e);
1832
+ const msg = errorMessage(e);
1863
1833
  const failure = classifyFailure(msg);
1864
1834
  const errEv = {
1865
1835
  type: "session.failed",
@@ -1869,8 +1839,7 @@ class Daemon {
1869
1839
  failure,
1870
1840
  raw: e,
1871
1841
  };
1872
- this.events.append(sessionId, errEv);
1873
- this.broadcast(sessionId, errEv);
1842
+ this.emit(sessionId, errEv);
1874
1843
  this.sessions.setStatus(sessionId, "failed", { lastEvent: msg.slice(0, 200), failure });
1875
1844
  return;
1876
1845
  }
@@ -1902,8 +1871,7 @@ class Daemon {
1902
1871
  };
1903
1872
  const error = sess.lastEvent || "event stream ended without a terminal event";
1904
1873
  const errEv = { type: "session.failed", sessionId, timestamp: new Date().toISOString(), error, failure };
1905
- this.events.append(sessionId, errEv);
1906
- this.broadcast(sessionId, errEv);
1874
+ this.emit(sessionId, errEv);
1907
1875
  this.sessions.setStatus(sessionId, "failed", { lastEvent: error.slice(0, 200), failure });
1908
1876
  }
1909
1877
  }
@@ -2068,25 +2036,23 @@ class Daemon {
2068
2036
  handle.exec("PRAGMA wal_checkpoint(TRUNCATE)");
2069
2037
  }
2070
2038
  catch { }
2071
- try {
2072
- const paths = getPaths();
2073
- try {
2074
- fs.unlinkSync(paths.daemonSock);
2075
- }
2076
- catch { }
2077
- try {
2078
- fs.unlinkSync(paths.daemonPid);
2079
- }
2080
- catch { }
2039
+ if (this.boundPaths) {
2081
2040
  try {
2082
- this.server?.close();
2041
+ fs.unlinkSync(this.boundPaths.sock);
2083
2042
  }
2084
2043
  catch { }
2085
2044
  try {
2086
- this.db.close();
2045
+ fs.unlinkSync(this.boundPaths.pid);
2087
2046
  }
2088
2047
  catch { }
2089
2048
  }
2049
+ try {
2050
+ this.server?.close();
2051
+ }
2052
+ catch { }
2053
+ try {
2054
+ this.db.close();
2055
+ }
2090
2056
  catch { }
2091
2057
  }
2092
2058
  safeListActive() {
@@ -2152,8 +2118,7 @@ class Daemon {
2152
2118
  failure,
2153
2119
  raw: { reason },
2154
2120
  };
2155
- this.events.append(s.id, event);
2156
- this.broadcast(s.id, event);
2121
+ this.emit(s.id, event);
2157
2122
  this.sessions.setStatus(s.id, "interrupted", { lastEvent: detail.slice(0, 200), failure });
2158
2123
  }
2159
2124
  catch { }