@sideboard-ai/core 0.1.32 → 0.1.34

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.
@@ -0,0 +1,212 @@
1
+ // src/agents/error-detail.ts
2
+ function formatUnknownDetail(err) {
3
+ if (err == null) return "";
4
+ if (typeof err === "string") return err.trim();
5
+ if (err instanceof Error) {
6
+ const base = err.message.trim() || err.name;
7
+ const code = "code" in err && typeof err.code === "string" ? err.code.trim() : "";
8
+ return code && !base.includes(code) ? `${base} (${code})` : base;
9
+ }
10
+ if (typeof err === "object") {
11
+ const o = err;
12
+ const nested = o.error != null && typeof o.error === "object" ? formatUnknownDetail(o.error) : "";
13
+ const message = typeof o.message === "string" ? o.message.trim() : typeof o.error === "string" ? o.error.trim() : typeof o.result === "string" ? o.result.trim() : nested;
14
+ const code = typeof o.code === "string" ? o.code.trim() : "";
15
+ if (message) return code && !message.includes(code) ? `${message} (${code})` : message;
16
+ try {
17
+ const json = JSON.stringify(err);
18
+ if (json && json !== "{}" && json !== "null") return json;
19
+ } catch {
20
+ }
21
+ }
22
+ const fallback = String(err);
23
+ return fallback === "[object Object]" ? "" : fallback;
24
+ }
25
+ function extractJsonErrorMessage(obj) {
26
+ const nested = obj.error != null && typeof obj.error === "object" ? obj.error : null;
27
+ const candidates = [
28
+ typeof obj.message === "string" ? obj.message : null,
29
+ typeof obj.error === "string" ? obj.error : null,
30
+ nested && typeof nested.message === "string" ? nested.message : null,
31
+ typeof obj.result === "string" ? obj.result : null,
32
+ typeof obj.detail === "string" ? obj.detail : null
33
+ ];
34
+ for (const c of candidates) {
35
+ const t = c?.trim();
36
+ if (t) return t;
37
+ }
38
+ if (Array.isArray(obj.errors)) {
39
+ const parts = obj.errors.map((e) => formatUnknownDetail(e)).map((s) => s.trim()).filter(Boolean);
40
+ if (parts.length) return parts.join("; ");
41
+ }
42
+ return null;
43
+ }
44
+ var NODE_VERSION_FOOTER = /^Node\.js v\d+/i;
45
+ function pushTurnStderr(tail, line, maxLines = 12) {
46
+ const trimmed = line.trim();
47
+ if (!trimmed) return;
48
+ if (NODE_VERSION_FOOTER.test(trimmed)) return;
49
+ if (/^reconnecting\.\.\./i.test(trimmed)) return;
50
+ tail.push(trimmed);
51
+ while (tail.length > maxLines) tail.shift();
52
+ }
53
+ function summarizeTurnStderr(tail, maxChars = 500) {
54
+ if (tail.length === 0) return "";
55
+ const joined = tail.slice(-6).join("\n").trim();
56
+ if (joined.length <= maxChars) return joined;
57
+ return joined.slice(joined.length - maxChars);
58
+ }
59
+ function looksLikeAgentFailureMessage(text) {
60
+ const lower = text.trim().toLowerCase();
61
+ if (!lower) return false;
62
+ return /you've hit your|hit your (session|weekly|opus) limit|usage limit/.test(lower) || /credit balance is too low|out of credits|insufficient.?quota|quota.?exceeded/.test(lower) || /invalid user api key|invalid api key|not logged in|not authenticated|unauthorized/.test(
63
+ lower
64
+ ) || /\b429\b|too many requests|rate.?limit/.test(lower) || /prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower);
65
+ }
66
+ function fallbackTurnFailDetail(assistantText) {
67
+ const t = assistantText.trim();
68
+ if (!t) return "";
69
+ if (looksLikeAgentFailureMessage(t)) return t;
70
+ if (t.length <= 400 && !/\n\n/.test(t)) return t;
71
+ return "";
72
+ }
73
+ function humanizeAgentFailDetail(detail) {
74
+ const raw = detail.trim();
75
+ if (!raw) return raw;
76
+ const lower = raw.toLowerCase();
77
+ if (/credit balance is too low|out of credits|insufficient.?quota|quota.?exceeded|billing/.test(lower)) {
78
+ return `${raw} \u2014 add credits or switch auth, then retry.`;
79
+ }
80
+ if (/hit your (session|weekly|opus) limit|usage limit|you've hit your/.test(lower)) {
81
+ return raw.includes("reset") ? raw : `${raw} \u2014 wait for the limit window to reset, then retry.`;
82
+ }
83
+ if (/\b429\b|rate.?limit|too many requests/.test(lower)) {
84
+ return `${raw} \u2014 wait a moment and retry.`;
85
+ }
86
+ if (/invalid user api key|invalid api key|not logged in|not authenticated|unauthorized|authentication|please run.*login|codex login|claude auth|cursor api/.test(
87
+ lower
88
+ )) {
89
+ return `${raw} \u2014 check agent login / API key in Settings.`;
90
+ }
91
+ if (/model .{0,80}(not found|unavailable|unknown|invalid)/.test(lower)) {
92
+ return `${raw} \u2014 pick another model in the agent options.`;
93
+ }
94
+ if (/context.*(too long|exceed)|prompt is too long|conversation too long/.test(lower)) {
95
+ return `${raw} \u2014 start a new chat or compact context, then retry.`;
96
+ }
97
+ return raw;
98
+ }
99
+ function formatTurnExitError(exitCode, stderrSummary) {
100
+ const code = exitCode ?? 1;
101
+ const detail = humanizeAgentFailDetail(stderrSummary);
102
+ if (!detail) {
103
+ return `exit ${code}: agent exited without details (credits, auth, rate limits, or a CLI error)`;
104
+ }
105
+ if (looksLikeAgentFailureMessage(stderrSummary)) return detail;
106
+ return `exit ${code}: ${detail}`;
107
+ }
108
+
109
+ // src/agents/cursor-events.ts
110
+ function usageFromCursor(usage) {
111
+ if (!usage) return null;
112
+ const inputTokens = Number(usage.inputTokens ?? 0);
113
+ const outputTokens = Number(usage.outputTokens ?? 0);
114
+ if (!inputTokens && !outputTokens) return null;
115
+ return {
116
+ inputTokens,
117
+ outputTokens,
118
+ cacheReadTokens: usage.cacheReadTokens ? Number(usage.cacheReadTokens) : void 0,
119
+ cacheWriteTokens: usage.cacheWriteTokens ? Number(usage.cacheWriteTokens) : void 0
120
+ };
121
+ }
122
+ function cursorSdkMessageToEvents(msg) {
123
+ if (!msg?.type) return [];
124
+ if (msg.type === "system" && msg.agent_id) {
125
+ return [{ type: "session_id", data: msg.agent_id }];
126
+ }
127
+ if (msg.type === "thinking" && msg.text) {
128
+ return [{ type: "thinking", data: msg.text }];
129
+ }
130
+ if (msg.type === "assistant" && msg.message?.content?.length) {
131
+ const out = [];
132
+ for (const block of msg.message.content) {
133
+ if (block?.type === "text" && block.text) {
134
+ out.push({ type: "stdout", data: block.text });
135
+ } else if (block?.type === "tool_use" && block.id && block.name) {
136
+ out.push({
137
+ type: "tool_use",
138
+ id: block.id,
139
+ name: block.name,
140
+ input: block.input && typeof block.input === "object" ? block.input : void 0
141
+ });
142
+ }
143
+ }
144
+ return out;
145
+ }
146
+ if (msg.type === "tool_call" && msg.call_id && msg.name) {
147
+ if (msg.status === "running") {
148
+ return [
149
+ {
150
+ type: "tool_use",
151
+ id: msg.call_id,
152
+ name: msg.name,
153
+ input: msg.args && typeof msg.args === "object" ? msg.args : void 0
154
+ }
155
+ ];
156
+ }
157
+ if (msg.status === "completed" || msg.status === "error") {
158
+ const content = typeof msg.result === "string" ? msg.result : msg.result != null ? JSON.stringify(msg.result) : void 0;
159
+ return [
160
+ {
161
+ type: "tool_result",
162
+ id: msg.call_id,
163
+ content,
164
+ isError: msg.status === "error"
165
+ }
166
+ ];
167
+ }
168
+ }
169
+ if (msg.type === "usage") {
170
+ const usage = usageFromCursor(msg.usage);
171
+ if (usage) return [{ type: "usage", data: usage }];
172
+ }
173
+ if (msg.type === "status" && msg.status === "ERROR") {
174
+ const rawMessage = msg.message;
175
+ const detail = (typeof rawMessage === "string" ? rawMessage.trim() : "") || extractJsonErrorMessage(msg) || formatUnknownDetail(msg.error) || msg.text || "Cursor run entered ERROR status";
176
+ return [{ type: "stderr", data: detail }];
177
+ }
178
+ if (msg.type === "error") {
179
+ const detail = extractJsonErrorMessage(msg) || formatUnknownDetail(msg.error) || msg.text || "Cursor run error";
180
+ return [{ type: "stderr", data: detail }];
181
+ }
182
+ return [];
183
+ }
184
+ function parseCursorRunnerLine(line) {
185
+ const trimmed = line.trim();
186
+ if (!trimmed) return null;
187
+ try {
188
+ const obj = JSON.parse(trimmed);
189
+ if (Array.isArray(obj)) return obj;
190
+ if (obj && typeof obj === "object" && "events" in obj && Array.isArray(obj.events)) {
191
+ return obj.events;
192
+ }
193
+ if (obj && typeof obj === "object" && "type" in obj) {
194
+ return obj;
195
+ }
196
+ return null;
197
+ } catch {
198
+ return { type: "stdout", data: line };
199
+ }
200
+ }
201
+
202
+ export {
203
+ formatUnknownDetail,
204
+ extractJsonErrorMessage,
205
+ pushTurnStderr,
206
+ summarizeTurnStderr,
207
+ looksLikeAgentFailureMessage,
208
+ fallbackTurnFailDetail,
209
+ formatTurnExitError,
210
+ cursorSdkMessageToEvents,
211
+ parseCursorRunnerLine
212
+ };
@@ -6,8 +6,11 @@ import {
6
6
  loadBrightsyConfig
7
7
  } from "./chunk-ILQK4P5R.js";
8
8
  import {
9
+ extractJsonErrorMessage,
10
+ formatUnknownDetail,
11
+ looksLikeAgentFailureMessage,
9
12
  parseCursorRunnerLine
10
- } from "./chunk-3DKGI32Q.js";
13
+ } from "./chunk-BSZX63TV.js";
11
14
  import {
12
15
  claudeChromeEnabled,
13
16
  loadAppSettings,
@@ -132,7 +135,7 @@ function parseBrightsyCliLine(line) {
132
135
  return { type: "thinking", data: obj.text };
133
136
  }
134
137
  if (obj.type === "error") {
135
- const msg = String(obj.error ?? trimmed);
138
+ const msg = extractJsonErrorMessage(obj) || formatUnknownDetail(obj.error) || formatUnknownDetail(obj.message) || trimmed;
136
139
  return [
137
140
  { type: "stderr", data: msg },
138
141
  { type: "stdout", data: `Error: ${msg}` }
@@ -169,6 +172,12 @@ function parseBrightsyCliLine(line) {
169
172
  if (trimmed.startsWith("{") && /"type"\s*:\s*"(tool_use|tool_result|tool|text|thinking|usage|done|error)"/.test(trimmed)) {
170
173
  return null;
171
174
  }
175
+ if (/error|failed|unauthorized|quota|limit|not logged in/i.test(trimmed)) {
176
+ return [
177
+ { type: "stderr", data: trimmed },
178
+ { type: "stdout", data: `Error: ${trimmed}` }
179
+ ];
180
+ }
172
181
  return { type: "stdout", data: line };
173
182
  }
174
183
  }
@@ -647,6 +656,30 @@ function usageFromClaude(usage) {
647
656
  cacheWriteTokens: usage.cache_creation_input_tokens ? Number(usage.cache_creation_input_tokens) : void 0
648
657
  };
649
658
  }
659
+ function claudeResultErrorDetail(obj) {
660
+ const isError = Boolean(obj.is_error) || typeof obj.subtype === "string" && /^error/i.test(obj.subtype);
661
+ const fromResult = typeof obj.result === "string" ? obj.result.trim() : "";
662
+ if (fromResult && (isError || looksLikeAgentFailureMessage(fromResult))) {
663
+ return fromResult;
664
+ }
665
+ if (!isError) return null;
666
+ const errors = obj.errors;
667
+ if (Array.isArray(errors)) {
668
+ const parts = errors.map((e) => {
669
+ if (typeof e === "string") return e.trim();
670
+ if (e && typeof e === "object" && typeof e.message === "string") {
671
+ return e.message.trim();
672
+ }
673
+ return "";
674
+ }).filter(Boolean);
675
+ if (parts.length) return parts.join("; ");
676
+ }
677
+ if (typeof obj.error === "string" && obj.error.trim()) return obj.error.trim();
678
+ if (typeof obj.subtype === "string" && obj.subtype) {
679
+ return obj.subtype.replace(/^error[_-]?/i, "").replace(/_/g, " ") || "Claude turn failed";
680
+ }
681
+ return "Claude turn failed";
682
+ }
650
683
  function eventsFromContentBlocks(blocks) {
651
684
  if (!blocks?.length) return [];
652
685
  const out = [];
@@ -858,8 +891,13 @@ var claudeAdapter = {
858
891
  }
859
892
  if (obj.type === "result") {
860
893
  const events = [];
861
- const text = obj.result;
862
- if (typeof text === "string" && text) events.push({ type: "stdout", data: text });
894
+ const errorDetail = claudeResultErrorDetail(obj);
895
+ if (errorDetail) {
896
+ events.push({ type: "stderr", data: errorDetail });
897
+ } else {
898
+ const text = obj.result;
899
+ if (typeof text === "string" && text) events.push({ type: "stdout", data: text });
900
+ }
863
901
  const usage = usageFromClaude(obj.usage);
864
902
  if (usage) events.push({ type: "usage", data: usage });
865
903
  if (events.length === 0) return null;
@@ -1067,23 +1105,49 @@ var codexAdapter = {
1067
1105
  if (!trimmed) return null;
1068
1106
  try {
1069
1107
  const obj = JSON.parse(trimmed);
1070
- const sid = typeof obj.session_id === "string" && obj.session_id || typeof obj.thread_id === "string" && obj.thread_id || typeof obj.session?.id === "string" && obj.session.id;
1071
- if (sid) return { type: "session_id", data: sid };
1072
- if (obj.type === "turn.completed" || obj.type === "turn_completed") {
1073
- const usage = usageFromCodex(obj.usage);
1074
- return usage ? { type: "usage", data: usage } : null;
1108
+ const type = typeof obj.type === "string" ? obj.type : "";
1109
+ if (type === "turn.failed" || type === "turn_failed") {
1110
+ const detail = extractJsonErrorMessage(obj) || extractJsonErrorMessage(obj.error ?? {}) || "Codex turn failed";
1111
+ return { type: "stderr", data: detail };
1112
+ }
1113
+ if (type === "error") {
1114
+ const detail = extractJsonErrorMessage(obj) || trimmed;
1115
+ if (/^reconnecting\.\.\./i.test(detail)) return null;
1116
+ return { type: "stderr", data: detail };
1075
1117
  }
1076
1118
  if (typeof obj.item === "object" && obj.item !== null) {
1077
1119
  const item = obj.item;
1120
+ if (item.type === "error") {
1121
+ const detail = item.message?.trim() || extractJsonErrorMessage(obj) || "Codex item error";
1122
+ return { type: "stderr", data: detail };
1123
+ }
1078
1124
  if (item.type === "agent_message" && item.text) {
1079
1125
  return { type: "stdout", data: item.text };
1080
1126
  }
1127
+ if (item.status === "failed") {
1128
+ const detail = item.message?.trim() || extractJsonErrorMessage(item) || `Codex ${item.type ?? "item"} failed`;
1129
+ return { type: "stderr", data: detail };
1130
+ }
1081
1131
  }
1082
- if (typeof obj.content === "string") {
1132
+ const sid = typeof obj.session_id === "string" && obj.session_id || typeof obj.thread_id === "string" && obj.thread_id || typeof obj.session?.id === "string" && obj.session.id;
1133
+ if (sid && (type === "thread.started" || type === "session" || !type)) {
1134
+ return { type: "session_id", data: sid };
1135
+ }
1136
+ if (sid && type.endsWith(".started")) {
1137
+ return { type: "session_id", data: sid };
1138
+ }
1139
+ if (type === "turn.completed" || type === "turn_completed") {
1140
+ const usage = usageFromCodex(obj.usage);
1141
+ return usage ? { type: "usage", data: usage } : null;
1142
+ }
1143
+ if (typeof obj.content === "string" && obj.content.trim()) {
1083
1144
  return { type: "stdout", data: obj.content };
1084
1145
  }
1085
- return { type: "stdout", data: trimmed };
1146
+ return null;
1086
1147
  } catch {
1148
+ if (/error|failed|unauthorized|quota|limit/i.test(trimmed)) {
1149
+ return { type: "stderr", data: trimmed };
1150
+ }
1087
1151
  return { type: "stdout", data: line };
1088
1152
  }
1089
1153
  },
@@ -1419,6 +1483,10 @@ var opencodeAdapter = {
1419
1483
  if (!trimmed) return null;
1420
1484
  try {
1421
1485
  const obj = JSON.parse(trimmed);
1486
+ if (obj.type === "error") {
1487
+ const detail = extractJsonErrorMessage(obj) || formatUnknownDetail(obj.error) || formatUnknownDetail(obj.message) || trimmed;
1488
+ return { type: "stderr", data: detail };
1489
+ }
1422
1490
  const sid = typeof obj.sessionID === "string" && obj.sessionID || typeof obj.sessionId === "string" && obj.sessionId || typeof obj.session_id === "string" && obj.session_id;
1423
1491
  if (sid) return { type: "session_id", data: sid };
1424
1492
  if (obj.type === "text") {
@@ -1442,12 +1510,6 @@ var opencodeAdapter = {
1442
1510
  content: part?.output ?? part?.content ?? obj.output ?? obj.content
1443
1511
  };
1444
1512
  }
1445
- if (obj.type === "error") {
1446
- return {
1447
- type: "stderr",
1448
- data: String(obj.error ?? trimmed)
1449
- };
1450
- }
1451
1513
  if (obj.type === "step_finish" || obj.type === "step-finish") {
1452
1514
  const part = obj.part;
1453
1515
  const usage = usageFromOpencode(
@@ -1455,8 +1517,11 @@ var opencodeAdapter = {
1455
1517
  );
1456
1518
  return usage ? { type: "usage", data: usage } : null;
1457
1519
  }
1458
- return { type: "stdout", data: trimmed };
1520
+ return null;
1459
1521
  } catch {
1522
+ if (/error|failed|unauthorized|quota|limit/i.test(trimmed)) {
1523
+ return { type: "stderr", data: trimmed };
1524
+ }
1460
1525
  return { type: "stdout", data: line };
1461
1526
  }
1462
1527
  },