@slock-ai/daemon 0.28.0 → 0.28.1-alpha.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.
Files changed (2) hide show
  1. package/dist/index.js +105 -6
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -434,6 +434,19 @@ var ClaudeDriver = class {
434
434
  return [];
435
435
  }
436
436
  const events = [];
437
+ const pushResultError = (message, fallback) => {
438
+ const parts = [];
439
+ if (Array.isArray(message.errors)) {
440
+ for (const err of message.errors) {
441
+ if (typeof err === "string" && err.trim()) parts.push(err.trim());
442
+ }
443
+ }
444
+ if (typeof message.result === "string" && message.result.trim()) {
445
+ parts.push(message.result.trim());
446
+ }
447
+ const detail = parts.join(" | ") || fallback;
448
+ events.push({ kind: "error", message: detail });
449
+ };
437
450
  switch (event.type) {
438
451
  case "system":
439
452
  if (event.subtype === "init" && event.session_id) {
@@ -456,6 +469,29 @@ var ClaudeDriver = class {
456
469
  break;
457
470
  }
458
471
  case "result": {
472
+ const subtype = typeof event.subtype === "string" ? event.subtype : "success";
473
+ const stopReason = typeof event.stop_reason === "string" ? event.stop_reason : null;
474
+ switch (subtype) {
475
+ case "success":
476
+ if (event.is_error && stopReason !== "max_tokens") {
477
+ pushResultError(event, "Execution failed");
478
+ }
479
+ break;
480
+ case "error_during_execution":
481
+ if (stopReason !== "max_tokens") {
482
+ pushResultError(event, "Execution failed");
483
+ }
484
+ break;
485
+ case "error_max_budget_usd":
486
+ pushResultError(event, "Budget limit exceeded");
487
+ break;
488
+ case "error_max_turns":
489
+ pushResultError(event, "Max turns exceeded");
490
+ break;
491
+ case "error_max_structured_output_retries":
492
+ pushResultError(event, "Structured output retries exceeded");
493
+ break;
494
+ }
459
495
  events.push({ kind: "turn_end", sessionId: event.session_id });
460
496
  break;
461
497
  }
@@ -822,6 +858,44 @@ function buildUnreadSummary(messages, excludeChannel) {
822
858
  }
823
859
  var MAX_TRAJECTORY_TEXT = 2e3;
824
860
  var ACTIVITY_HEARTBEAT_MS = 6e4;
861
+ var MAX_STDERR_LINES = 8;
862
+ var MAX_STDERR_LINE_LENGTH = 240;
863
+ function pushRecentStderr(lines, chunk) {
864
+ const next = [...lines];
865
+ for (const rawLine of chunk.split(/\r?\n/)) {
866
+ const text = rawLine.trim();
867
+ if (!text) continue;
868
+ next.push(
869
+ text.length > MAX_STDERR_LINE_LENGTH ? `${text.slice(0, MAX_STDERR_LINE_LENGTH)}...` : text
870
+ );
871
+ }
872
+ return next.slice(-MAX_STDERR_LINES);
873
+ }
874
+ function formatCrashReason(code, signal, ap) {
875
+ const parts = [];
876
+ if (signal) {
877
+ parts.push(`signal ${signal}`);
878
+ } else if (typeof code === "number") {
879
+ parts.push(`exit code ${code}`);
880
+ } else {
881
+ parts.push("unknown exit");
882
+ }
883
+ if (ap.spawnError) {
884
+ parts.push(`spawn error: ${ap.spawnError}`);
885
+ }
886
+ if (ap.lastRuntimeError) {
887
+ parts.push(`runtime error: ${ap.lastRuntimeError}`);
888
+ }
889
+ if (ap.recentStderr.length > 0) {
890
+ parts.push(`stderr: ${ap.recentStderr.join(" | ")}`);
891
+ }
892
+ return parts.join(" | ");
893
+ }
894
+ function summarizeCrash(code, signal) {
895
+ if (signal) return `signal ${signal}`;
896
+ if (typeof code === "number") return `exit code ${code}`;
897
+ return "unknown exit";
898
+ }
825
899
  function getMessageDeliveryText(supportsStdinNotification) {
826
900
  return supportsStdinNotification ? "New messages will be delivered to you automatically via stdin." : "The daemon will automatically restart you when new messages arrive.";
827
901
  }
@@ -950,7 +1024,12 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
950
1024
  pendingNotificationCount: 0,
951
1025
  activityHeartbeat: null,
952
1026
  lastActivity: "",
953
- lastActivityDetail: ""
1027
+ lastActivityDetail: "",
1028
+ recentStderr: [],
1029
+ lastRuntimeError: null,
1030
+ spawnError: null,
1031
+ exitCode: null,
1032
+ exitSignal: null
954
1033
  };
955
1034
  this.startingInboxes.delete(agentId);
956
1035
  this.agents.set(agentId, agentProcess);
@@ -972,10 +1051,26 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
972
1051
  const text = chunk.toString().trim();
973
1052
  if (!text) return;
974
1053
  if (/Reconnecting\.\.\.|Falling back from WebSockets/i.test(text)) return;
1054
+ const current = this.agents.get(agentId);
1055
+ if (current) {
1056
+ current.recentStderr = pushRecentStderr(current.recentStderr, text);
1057
+ }
975
1058
  console.error(`[Agent ${agentId} stderr]: ${text}`);
976
1059
  });
977
- proc.on("exit", (code) => {
978
- console.log(`[Agent ${agentId}] Process exited with code ${code}`);
1060
+ proc.on("error", (err) => {
1061
+ const current = this.agents.get(agentId);
1062
+ if (current) current.spawnError = err.message;
1063
+ console.error(`[Agent ${agentId}] Process error: ${err.message}`);
1064
+ });
1065
+ proc.on("exit", (code, signal) => {
1066
+ const current = this.agents.get(agentId);
1067
+ if (current && current.process === proc) {
1068
+ current.exitCode = code;
1069
+ current.exitSignal = signal;
1070
+ }
1071
+ console.log(`[Agent ${agentId}] Process exited with code ${code}${signal ? ` (signal ${signal})` : ""}`);
1072
+ });
1073
+ proc.on("close", (code, signal) => {
979
1074
  if (this.agents.has(agentId)) {
980
1075
  const ap = this.agents.get(agentId);
981
1076
  if (ap.process !== proc) return;
@@ -986,7 +1081,9 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
986
1081
  clearInterval(ap.activityHeartbeat);
987
1082
  }
988
1083
  this.agents.delete(agentId);
989
- if (code === 0) {
1084
+ const finalCode = ap.exitCode ?? code;
1085
+ const finalSignal = ap.exitSignal ?? signal;
1086
+ if (finalCode === 0) {
990
1087
  const queuedWakeMessage = !ap.driver.supportsStdinNotification ? ap.inbox.shift() : void 0;
991
1088
  const unreadSummary2 = queuedWakeMessage ? buildUnreadSummary(ap.inbox, formatChannelLabel(queuedWakeMessage)) : void 0;
992
1089
  if (queuedWakeMessage) {
@@ -1014,10 +1111,11 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
1014
1111
  this.broadcastActivity(agentId, "online", "Process idle");
1015
1112
  } else {
1016
1113
  this.idleAgentConfigs.delete(agentId);
1017
- const reason = code === null ? "killed by signal" : `exit code ${code}`;
1114
+ const reason = formatCrashReason(finalCode, finalSignal, ap);
1115
+ const summary = summarizeCrash(finalCode, finalSignal);
1018
1116
  console.error(`[Agent ${agentId}] Process crashed (${reason}) \u2014 marking inactive`);
1019
1117
  this.sendToServer({ type: "agent:status", agentId, status: "inactive" });
1020
- this.broadcastActivity(agentId, "offline", `Crashed (${reason})`);
1118
+ this.broadcastActivity(agentId, "offline", `Crashed (${summary})`);
1021
1119
  }
1022
1120
  }
1023
1121
  });
@@ -1399,6 +1497,7 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
1399
1497
  }
1400
1498
  break;
1401
1499
  case "error": {
1500
+ if (ap) ap.lastRuntimeError = event.message;
1402
1501
  const currentActivity = ap?.lastActivity || "working";
1403
1502
  const currentDetail = ap?.lastActivityDetail || "";
1404
1503
  this.sendToServer({ type: "agent:activity", agentId, activity: currentActivity, detail: currentDetail, entries: [{ kind: "text", text: `Error: ${event.message}` }] });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slock-ai/daemon",
3
- "version": "0.28.0",
3
+ "version": "0.28.1-alpha.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "slock-daemon": "dist/index.js"