@sideboard-ai/core 0.1.127 → 0.1.132
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/agents/cursor-runner.js +1 -1
- package/dist/{agents-X2I3RNCY.js → agents-CI6NGKRO.js} +4 -3
- package/dist/{agents-7BUQY2WX.js → agents-LGJLZMM3.js} +3 -2
- package/dist/chunk-AQESMTCZ.js +129 -0
- package/dist/{chunk-IUJOI7KK.js → chunk-FSCQXMGI.js} +35 -4
- package/dist/{chunk-YMRT2DU6.js → chunk-LLX3OMHU.js} +25 -50
- package/dist/{chunk-NV73AO7Q.js → chunk-MGYCQAZ6.js} +17 -5
- package/dist/{chunk-ZMUOPTKZ.js → chunk-PK4PQUPU.js} +51 -8
- package/dist/chunk-R7FGPBKL.js +126 -0
- package/dist/{chunk-EKIDHL2T.js → chunk-SIPDL62B.js} +32 -55
- package/dist/{chunk-DLM5LSQW.js → chunk-SMWJAE74.js} +109 -16
- package/dist/{chunk-T7KJQJAX.js → chunk-VFXZTSAD.js} +111 -17
- package/dist/{connected-teams-O6D4PM7A.js → connected-teams-3BWNJIRY.js} +2 -1
- package/dist/{connected-teams-ZCOU6KCD.js → connected-teams-S6E3D5C7.js} +2 -1
- package/dist/index.cjs +343 -106
- package/dist/index.d.cts +54 -4
- package/dist/index.d.ts +54 -4
- package/dist/index.js +64 -72
- package/dist/mcp/run-stdio.cjs +301 -76
- package/dist/mcp/run-stdio.js +34 -39
- package/dist/oauth-43NNH6C6.js +12 -0
- package/dist/oauth-FT7EL2PY.js +10 -0
- package/dist/{orchestrator-6GUCE4LY.js → orchestrator-5TN2DJWO.js} +5 -4
- package/dist/{orchestrator-3JLPPTCF.js → orchestrator-JA65XKB6.js} +4 -3
- package/package.json +1 -1
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
brightsyAccessTokenNeedsRefresh,
|
|
3
|
+
ensureBrightsyLocalConfigFresh,
|
|
4
|
+
loadBrightsyConfig,
|
|
5
|
+
refreshBrightsyAccessToken,
|
|
6
|
+
saveBrightsyConfig
|
|
7
|
+
} from "./chunk-AQESMTCZ.js";
|
|
1
8
|
import {
|
|
2
9
|
appDataDir
|
|
3
10
|
} from "./chunk-QZQEXME2.js";
|
|
@@ -6,37 +13,12 @@ import {
|
|
|
6
13
|
} from "./chunk-DVM4ID64.js";
|
|
7
14
|
|
|
8
15
|
// src/brightsy/connected-teams.ts
|
|
9
|
-
import { existsSync
|
|
10
|
-
import { join as join2 } from "path";
|
|
11
|
-
|
|
12
|
-
// src/brightsy/config.ts
|
|
13
|
-
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
14
|
-
import { homedir } from "os";
|
|
16
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
15
17
|
import { join } from "path";
|
|
16
|
-
function brightsyConfigPath() {
|
|
17
|
-
return join(homedir(), ".brightsy", "config.json");
|
|
18
|
-
}
|
|
19
|
-
function loadBrightsyConfig() {
|
|
20
|
-
const path = brightsyConfigPath();
|
|
21
|
-
if (!existsSync(path)) {
|
|
22
|
-
throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
|
|
23
|
-
}
|
|
24
|
-
const raw = JSON.parse(readFileSync(path, "utf8"));
|
|
25
|
-
if (!raw.access_token || !raw.account_id) {
|
|
26
|
-
throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
|
|
27
|
-
}
|
|
28
|
-
return raw;
|
|
29
|
-
}
|
|
30
|
-
function saveBrightsyConfig(cfg) {
|
|
31
|
-
writeFileSync(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
|
|
32
|
-
`, {
|
|
33
|
-
mode: 384
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
18
|
|
|
37
19
|
// src/brightsy/accounts.ts
|
|
38
20
|
async function loadConnectedTeams() {
|
|
39
|
-
const { listConnectedBrightsyTeams: listConnectedBrightsyTeams2 } = await import("./connected-teams-
|
|
21
|
+
const { listConnectedBrightsyTeams: listConnectedBrightsyTeams2 } = await import("./connected-teams-S6E3D5C7.js");
|
|
40
22
|
return listConnectedBrightsyTeams2();
|
|
41
23
|
}
|
|
42
24
|
async function runBrightsyTeamsJson(args) {
|
|
@@ -64,11 +46,15 @@ async function listBrightsyAccounts() {
|
|
|
64
46
|
}
|
|
65
47
|
async function getBrightsySession() {
|
|
66
48
|
try {
|
|
49
|
+
const { ensureBrightsyLocalConfigFresh: ensureBrightsyLocalConfigFresh2 } = await import("./oauth-FT7EL2PY.js");
|
|
50
|
+
const { ensureConnectedBrightsyTeamTokens: ensureConnectedBrightsyTeamTokens2 } = await import("./connected-teams-S6E3D5C7.js");
|
|
51
|
+
await ensureBrightsyLocalConfigFresh2();
|
|
52
|
+
await ensureConnectedBrightsyTeamTokens2();
|
|
67
53
|
loadBrightsyConfig();
|
|
68
54
|
const data = await runBrightsyTeamsJson([]);
|
|
69
55
|
const accounts = Array.isArray(data.teams) ? data.teams : [];
|
|
70
56
|
const active = data.active ?? accounts.find((a) => a.active) ?? null;
|
|
71
|
-
const { ensureCliTeamTracked: ensureCliTeamTracked2 } = await import("./connected-teams-
|
|
57
|
+
const { ensureCliTeamTracked: ensureCliTeamTracked2 } = await import("./connected-teams-S6E3D5C7.js");
|
|
72
58
|
const connectedTeams = ensureCliTeamTracked2(
|
|
73
59
|
active ? { id: active.id, slug: active.slug, name: active.name } : void 0
|
|
74
60
|
);
|
|
@@ -108,20 +94,20 @@ async function performBrightsyAccountSwitch(accountIdOrSlug) {
|
|
|
108
94
|
return { cfg, target: data.active };
|
|
109
95
|
}
|
|
110
96
|
async function switchBrightsyAccount(accountIdOrSlug) {
|
|
111
|
-
const { connectBrightsyTeam: connectBrightsyTeam2 } = await import("./connected-teams-
|
|
97
|
+
const { connectBrightsyTeam: connectBrightsyTeam2 } = await import("./connected-teams-S6E3D5C7.js");
|
|
112
98
|
await connectBrightsyTeam2(accountIdOrSlug);
|
|
113
99
|
return getBrightsySession();
|
|
114
100
|
}
|
|
115
101
|
|
|
116
102
|
// src/brightsy/connected-teams.ts
|
|
117
103
|
function storePath() {
|
|
118
|
-
return
|
|
104
|
+
return join(appDataDir(), "brightsy-teams.json");
|
|
119
105
|
}
|
|
120
106
|
function readStore() {
|
|
121
107
|
const path = storePath();
|
|
122
|
-
if (!
|
|
108
|
+
if (!existsSync(path)) return [];
|
|
123
109
|
try {
|
|
124
|
-
const parsed = JSON.parse(
|
|
110
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
125
111
|
return Array.isArray(parsed.teams) ? parsed.teams : [];
|
|
126
112
|
} catch {
|
|
127
113
|
return [];
|
|
@@ -130,7 +116,7 @@ function readStore() {
|
|
|
130
116
|
function writeStore(teams) {
|
|
131
117
|
mkdirSync(appDataDir(), { recursive: true });
|
|
132
118
|
const path = storePath();
|
|
133
|
-
|
|
119
|
+
writeFileSync(path, `${JSON.stringify({ teams }, null, 2)}
|
|
134
120
|
`, {
|
|
135
121
|
mode: 384
|
|
136
122
|
});
|
|
@@ -166,7 +152,6 @@ function applyConnectedTeamToCli(team) {
|
|
|
166
152
|
}
|
|
167
153
|
async function refreshTeamToken(team) {
|
|
168
154
|
if (!team.refresh_token) return team;
|
|
169
|
-
const endpoint = (team.endpoint || "https://brightsy.ai").replace(/\/$/, "");
|
|
170
155
|
const cfg = (() => {
|
|
171
156
|
try {
|
|
172
157
|
return loadBrightsyConfig();
|
|
@@ -174,39 +159,34 @@ async function refreshTeamToken(team) {
|
|
|
174
159
|
return null;
|
|
175
160
|
}
|
|
176
161
|
})();
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
body: new URLSearchParams({
|
|
182
|
-
grant_type: "refresh_token",
|
|
183
|
-
refresh_token: team.refresh_token,
|
|
184
|
-
client_id: clientId
|
|
185
|
-
})
|
|
162
|
+
const grant = await refreshBrightsyAccessToken({
|
|
163
|
+
endpoint: team.endpoint || "https://brightsy.ai",
|
|
164
|
+
refreshToken: team.refresh_token,
|
|
165
|
+
clientId: cfg?.oauth_client_id
|
|
186
166
|
});
|
|
187
|
-
if (!
|
|
188
|
-
const data = await res.json();
|
|
189
|
-
if (!data.access_token) return team;
|
|
167
|
+
if (!grant) return team;
|
|
190
168
|
return {
|
|
191
169
|
...team,
|
|
192
|
-
access_token:
|
|
193
|
-
refresh_token:
|
|
194
|
-
expires_at:
|
|
170
|
+
access_token: grant.access_token,
|
|
171
|
+
refresh_token: grant.refresh_token || team.refresh_token,
|
|
172
|
+
expires_at: grant.expires_at ?? team.expires_at
|
|
195
173
|
};
|
|
196
174
|
}
|
|
197
175
|
async function ensureConnectedBrightsyTeamTokens() {
|
|
176
|
+
await ensureBrightsyLocalConfigFresh().catch(() => null);
|
|
198
177
|
const teams = readStore();
|
|
199
178
|
if (teams.length === 0) return [];
|
|
200
179
|
const next = [];
|
|
201
180
|
let changed = false;
|
|
202
181
|
for (const team of teams) {
|
|
203
|
-
|
|
204
|
-
if (!expired) {
|
|
182
|
+
if (!team.refresh_token || !brightsyAccessTokenNeedsRefresh(team.expires_at)) {
|
|
205
183
|
next.push(team);
|
|
206
184
|
continue;
|
|
207
185
|
}
|
|
208
186
|
const refreshed = await refreshTeamToken(team);
|
|
209
|
-
if (refreshed.access_token !== team.access_token
|
|
187
|
+
if (refreshed.access_token !== team.access_token || refreshed.refresh_token !== team.refresh_token || refreshed.expires_at !== team.expires_at) {
|
|
188
|
+
changed = true;
|
|
189
|
+
}
|
|
210
190
|
next.push(refreshed);
|
|
211
191
|
}
|
|
212
192
|
if (changed) writeStore(next);
|
|
@@ -294,9 +274,6 @@ function brightsyMcpServerName(slug) {
|
|
|
294
274
|
}
|
|
295
275
|
|
|
296
276
|
export {
|
|
297
|
-
brightsyConfigPath,
|
|
298
|
-
loadBrightsyConfig,
|
|
299
|
-
saveBrightsyConfig,
|
|
300
277
|
listBrightsyAccounts,
|
|
301
278
|
getBrightsySession,
|
|
302
279
|
switchBrightsyAccount,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
contextTokens,
|
|
9
9
|
fallbackTurnFailDetail,
|
|
10
10
|
finalizeParts,
|
|
11
|
+
formatAgentErrorContinuePrompt,
|
|
11
12
|
formatTurnExitError,
|
|
12
13
|
getAdapter,
|
|
13
14
|
isBrightsyNdjsonLine,
|
|
@@ -23,13 +24,14 @@ import {
|
|
|
23
24
|
partsToAssistantText,
|
|
24
25
|
pushTurnStderr,
|
|
25
26
|
resolveQuotaFallbackAgent,
|
|
27
|
+
shouldFeedErrorBackToAgent,
|
|
26
28
|
shouldRetryFailedAgentTurn,
|
|
27
29
|
stripBrightsyNdjsonNoise,
|
|
28
30
|
sumUsageList,
|
|
29
31
|
summarizeTurnStderr,
|
|
30
32
|
toolDescription,
|
|
31
33
|
turnFailChatText
|
|
32
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-PK4PQUPU.js";
|
|
33
35
|
import {
|
|
34
36
|
addWorkspace,
|
|
35
37
|
ensureWorkspace,
|
|
@@ -380,7 +382,7 @@ async function continueSourceThread(threadId, prompt) {
|
|
|
380
382
|
await continueOnReply(threadId, prompt);
|
|
381
383
|
return;
|
|
382
384
|
}
|
|
383
|
-
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-
|
|
385
|
+
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-JA65XKB6.js");
|
|
384
386
|
await getOrchestrator2().send(threadId, prompt);
|
|
385
387
|
} catch {
|
|
386
388
|
}
|
|
@@ -2288,7 +2290,49 @@ function isMergedPrState(prUrl, prState) {
|
|
|
2288
2290
|
if (!prUrl?.trim()) return false;
|
|
2289
2291
|
return (prState ?? "").trim().toUpperCase() === "MERGED";
|
|
2290
2292
|
}
|
|
2291
|
-
|
|
2293
|
+
var DEFAULT_WORKTREE_SORT = "created";
|
|
2294
|
+
function groupCreatedAt(group) {
|
|
2295
|
+
let min = group[0]?.createdAt ?? "";
|
|
2296
|
+
for (const t of group) {
|
|
2297
|
+
if (t.createdAt && t.createdAt < min) min = t.createdAt;
|
|
2298
|
+
}
|
|
2299
|
+
return min;
|
|
2300
|
+
}
|
|
2301
|
+
function groupUpdatedAt(group) {
|
|
2302
|
+
let max = group[0]?.updatedAt ?? "";
|
|
2303
|
+
for (const t of group) {
|
|
2304
|
+
if (t.updatedAt && t.updatedAt > max) max = t.updatedAt;
|
|
2305
|
+
}
|
|
2306
|
+
return max;
|
|
2307
|
+
}
|
|
2308
|
+
function sortThreadsInWorktree(list) {
|
|
2309
|
+
return [...list].sort((a, b) => {
|
|
2310
|
+
const created = a.createdAt.localeCompare(b.createdAt);
|
|
2311
|
+
if (created !== 0) return created;
|
|
2312
|
+
return a.id.localeCompare(b.id);
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2315
|
+
function compareWorktreeGroups(a, b, mode, labelOf) {
|
|
2316
|
+
if (mode === "name") {
|
|
2317
|
+
const named = (labelOf?.(a) ?? a[0]?.id ?? "").localeCompare(
|
|
2318
|
+
labelOf?.(b) ?? b[0]?.id ?? "",
|
|
2319
|
+
void 0,
|
|
2320
|
+
{ sensitivity: "base" }
|
|
2321
|
+
);
|
|
2322
|
+
if (named !== 0) return named;
|
|
2323
|
+
} else if (mode === "activity") {
|
|
2324
|
+
const activity = groupUpdatedAt(b).localeCompare(groupUpdatedAt(a));
|
|
2325
|
+
if (activity !== 0) return activity;
|
|
2326
|
+
} else {
|
|
2327
|
+
const created = groupCreatedAt(b).localeCompare(groupCreatedAt(a));
|
|
2328
|
+
if (created !== 0) return created;
|
|
2329
|
+
}
|
|
2330
|
+
return (a[0]?.id ?? "").localeCompare(b[0]?.id ?? "");
|
|
2331
|
+
}
|
|
2332
|
+
function defaultWorktreeGroupLabel(group) {
|
|
2333
|
+
return worktreeDisplayLabelForGroup(group);
|
|
2334
|
+
}
|
|
2335
|
+
function groupHomeBoardWorktrees(threads, sort = DEFAULT_WORKTREE_SORT, labelOf = defaultWorktreeGroupLabel) {
|
|
2292
2336
|
const map = /* @__PURE__ */ new Map();
|
|
2293
2337
|
for (const t of threads) {
|
|
2294
2338
|
const key = normalizeWorktreePath(t.worktreePath);
|
|
@@ -2296,7 +2340,7 @@ function groupHomeBoardWorktrees(threads) {
|
|
|
2296
2340
|
list.push(t);
|
|
2297
2341
|
map.set(key, list);
|
|
2298
2342
|
}
|
|
2299
|
-
return [...map.values()].map((list) => list.sort((a, b) =>
|
|
2343
|
+
return [...map.values()].map((list) => sortThreadsInWorktree(list)).sort((a, b) => compareWorktreeGroups(a, b, sort, labelOf));
|
|
2300
2344
|
}
|
|
2301
2345
|
function classifyWorktreeColumn(group) {
|
|
2302
2346
|
if (group.some((t) => isMergedPrState(t.prUrl, t.prState))) return "done";
|
|
@@ -2597,8 +2641,7 @@ function assembleHomeBoard(input) {
|
|
|
2597
2641
|
const kind = input.kind ?? "all";
|
|
2598
2642
|
const limit = Math.max(1, input.limit ?? BOARD_PAGE_SIZE);
|
|
2599
2643
|
const wsName = input.workspaceName ?? (() => "");
|
|
2600
|
-
const
|
|
2601
|
-
const live = input.threads.filter((t) => t.status !== "archived" && isHomeBoardThread(t)).sort(byUpdated);
|
|
2644
|
+
const live = input.threads.filter((t) => t.status !== "archived" && isHomeBoardThread(t));
|
|
2602
2645
|
const columns = emptyColumns();
|
|
2603
2646
|
const hidden = emptyHidden();
|
|
2604
2647
|
const totals = {
|
|
@@ -2796,7 +2839,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
2796
2839
|
return readThread(thread.id) ?? thread;
|
|
2797
2840
|
}
|
|
2798
2841
|
async function listLinearIssues(agent, repoPath) {
|
|
2799
|
-
const { getAdapter: getAdapter2 } = await import("./agents-
|
|
2842
|
+
const { getAdapter: getAdapter2 } = await import("./agents-LGJLZMM3.js");
|
|
2800
2843
|
await requireAgent(agent, { requireLinear: true });
|
|
2801
2844
|
const adapter = getAdapter2(agent);
|
|
2802
2845
|
if (!adapter.listLinearIssues) {
|
|
@@ -5054,7 +5097,8 @@ function formatArtifactDirective() {
|
|
|
5054
5097
|
"```html",
|
|
5055
5098
|
"<!DOCTYPE html><html><head><title>Demo</title></head><body><h1>Hi</h1></body></html>",
|
|
5056
5099
|
"```",
|
|
5057
|
-
"2) Or call Sideboard MCP `present_artifact` with title, type (html|svg|markdown), and content \u2014 not both a fence and this tool for the same body.",
|
|
5100
|
+
"2) Or call Sideboard MCP `present_artifact` with title, type (html|svg|markdown|react|log), and content \u2014 not both a fence and this tool for the same body.",
|
|
5101
|
+
" type=log is append-only: same `artifact_id`, `content` = new lines only (plus optional status/phase). Do not resend the full log or wrap it in HTML.",
|
|
5058
5102
|
"CMS / JSON Schema forms & tables (Brightsy or any schema+schemaUi source):",
|
|
5059
5103
|
"3) Call Sideboard MCP `present_schema` when the user needs to filter, edit, publish, or persist rows \u2014 including after you already showed a markdown table, if they then ask for an editable table. If they only need to read the data, a markdown table is enough. When you do call it, pass title, mode (table|form), and either:",
|
|
5060
5104
|
" - datasource=brightsy + resource_id (record type UUID) after fetching types via Brightsy MCP, or",
|
|
@@ -5069,7 +5113,7 @@ function formatArtifactDirective() {
|
|
|
5069
5113
|
].join("\n");
|
|
5070
5114
|
}
|
|
5071
5115
|
function formatUiReminder() {
|
|
5072
|
-
return "Sideboard UI: markdown table is enough to read data; present_schema if they ask to edit/filter (even after markdown); present_files for the file manager. html fence or present_artifact, not both for the same document. ask_user only for a real multiple-choice (not hellos or \u201Cwhat next?\u201D) \u2014 reply in chat. Do not say artifacts/CMS UI are unavailable.";
|
|
5116
|
+
return "Sideboard UI: markdown table is enough to read data; present_schema if they ask to edit/filter (even after markdown); present_files for the file manager. html fence or present_artifact, not both for the same document. type=log appends (same artifact_id, new lines only). ask_user only for a real multiple-choice (not hellos or \u201Cwhat next?\u201D) \u2014 reply in chat. Do not say artifacts/CMS UI are unavailable.";
|
|
5073
5117
|
}
|
|
5074
5118
|
|
|
5075
5119
|
// src/threads/sync-branch.ts
|
|
@@ -5340,7 +5384,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
5340
5384
|
${prompt}`;
|
|
5341
5385
|
}
|
|
5342
5386
|
async function defaultDeps() {
|
|
5343
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
5387
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-JA65XKB6.js");
|
|
5344
5388
|
const orch = getOrchestrator2();
|
|
5345
5389
|
return {
|
|
5346
5390
|
findThread: (id) => findThreadByRef(id),
|
|
@@ -5491,6 +5535,11 @@ var Orchestrator = class {
|
|
|
5491
5535
|
turnBaselines = /* @__PURE__ */ new Map();
|
|
5492
5536
|
/** Timers for orchestration session-quota auto-resume. */
|
|
5493
5537
|
quotaResumeTimers = /* @__PURE__ */ new Map();
|
|
5538
|
+
/**
|
|
5539
|
+
* Threads that already got a crash-continue turn. Cleared on a successful
|
|
5540
|
+
* finish or a user send so a later crash can recover again.
|
|
5541
|
+
*/
|
|
5542
|
+
crashContinued = /* @__PURE__ */ new Set();
|
|
5494
5543
|
maxConcurrent;
|
|
5495
5544
|
runningCount = 0;
|
|
5496
5545
|
constructor(opts) {
|
|
@@ -5704,6 +5753,29 @@ var Orchestrator = class {
|
|
|
5704
5753
|
);
|
|
5705
5754
|
}
|
|
5706
5755
|
}
|
|
5756
|
+
/**
|
|
5757
|
+
* Cursor-style recovery: after a runner crash, feed the error back as the
|
|
5758
|
+
* next prompt so the same agent can continue instead of sitting on lastError.
|
|
5759
|
+
*/
|
|
5760
|
+
maybeEnqueueCrashContinue(threadId, opts) {
|
|
5761
|
+
if (this.crashContinued.has(threadId)) return;
|
|
5762
|
+
if (this.haltDrain.has(threadId)) return;
|
|
5763
|
+
if (!shouldFeedErrorBackToAgent({
|
|
5764
|
+
detail: opts.detail,
|
|
5765
|
+
assistantText: opts.assistantText,
|
|
5766
|
+
partsCount: opts.partsCount
|
|
5767
|
+
})) {
|
|
5768
|
+
return;
|
|
5769
|
+
}
|
|
5770
|
+
const thread = readThread(threadId);
|
|
5771
|
+
if (!thread || thread.status === "archived") return;
|
|
5772
|
+
this.crashContinued.add(threadId);
|
|
5773
|
+
const prompt = formatAgentErrorContinuePrompt(opts.detail);
|
|
5774
|
+
const queue = [prompt, ...thread.queue];
|
|
5775
|
+
updateThread(threadId, { queue });
|
|
5776
|
+
this.emit({ type: "queue_changed", threadId, queue });
|
|
5777
|
+
this.haltDrain.delete(threadId);
|
|
5778
|
+
}
|
|
5707
5779
|
getThreads(includeArchived = false) {
|
|
5708
5780
|
return listThreads({ includeArchived });
|
|
5709
5781
|
}
|
|
@@ -5803,15 +5875,20 @@ var Orchestrator = class {
|
|
|
5803
5875
|
throw new Error(`Thread is archived: ${thread.id}`);
|
|
5804
5876
|
}
|
|
5805
5877
|
const queue = [...current.queue, prompt];
|
|
5878
|
+
this.crashContinued.delete(thread.id);
|
|
5806
5879
|
this.haltDrain.delete(thread.id);
|
|
5807
|
-
const
|
|
5880
|
+
const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
|
|
5881
|
+
const patch = { queue };
|
|
5882
|
+
if (!inFlight) patch.status = "queued";
|
|
5808
5883
|
const pid = current.agentPid;
|
|
5809
5884
|
if (typeof pid === "number" && pid > 0 && !isPidAlive(pid)) {
|
|
5810
5885
|
patch.agentPid = null;
|
|
5811
5886
|
}
|
|
5812
5887
|
updateThread(thread.id, patch);
|
|
5813
5888
|
this.emit({ type: "queue_changed", threadId: thread.id, queue });
|
|
5814
|
-
|
|
5889
|
+
if (!inFlight) {
|
|
5890
|
+
this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
|
|
5891
|
+
}
|
|
5815
5892
|
if (thisProcessShouldDrainAgentQueues()) {
|
|
5816
5893
|
void this.drainQueue(thread.id);
|
|
5817
5894
|
}
|
|
@@ -6132,7 +6209,7 @@ var Orchestrator = class {
|
|
|
6132
6209
|
let parts = result.parts;
|
|
6133
6210
|
let usage = result.usage ?? void 0;
|
|
6134
6211
|
let exitCode = result.exitCode;
|
|
6135
|
-
if (this.requireThread(threadId).agent === "cursor" && exitCode !== 0 && !assistantText && parts.length === 0) {
|
|
6212
|
+
if (!this.stoppedTurns.has(threadId) && this.requireThread(threadId).agent === "cursor" && exitCode !== 0 && !assistantText && parts.length === 0) {
|
|
6136
6213
|
const sessionId = result.sessionId || this.requireThread(threadId).sessionId || "";
|
|
6137
6214
|
if (sessionId) {
|
|
6138
6215
|
const { recoverFinishedCursorRun } = await import("./cursor-recover-NOQYOFRF.js");
|
|
@@ -6153,7 +6230,7 @@ var Orchestrator = class {
|
|
|
6153
6230
|
}
|
|
6154
6231
|
let lastStderr = summarizeTurnStderr(stderrTail);
|
|
6155
6232
|
let detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
6156
|
-
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) &&
|
|
6233
|
+
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) && shouldRetryFailedAgentTurn(detail, {
|
|
6157
6234
|
hasSession: Boolean(this.requireThread(threadId).sessionId)
|
|
6158
6235
|
})) {
|
|
6159
6236
|
updateThread(threadId, { sessionId: null });
|
|
@@ -6249,7 +6326,11 @@ var Orchestrator = class {
|
|
|
6249
6326
|
)) {
|
|
6250
6327
|
updateThread(threadId, { sessionId: null });
|
|
6251
6328
|
}
|
|
6252
|
-
|
|
6329
|
+
if (this.stoppedTurns.has(threadId)) {
|
|
6330
|
+
void syncThreadBranchFromGit(threadId).catch(() => void 0);
|
|
6331
|
+
} else {
|
|
6332
|
+
await syncThreadBranchFromGit(threadId);
|
|
6333
|
+
}
|
|
6253
6334
|
if (this.stoppedTurns.has(threadId)) {
|
|
6254
6335
|
const stopped = writeLiveStatus(threadId, "stopped");
|
|
6255
6336
|
if (stopped?.status === "stopped") {
|
|
@@ -6273,9 +6354,16 @@ var Orchestrator = class {
|
|
|
6273
6354
|
});
|
|
6274
6355
|
}
|
|
6275
6356
|
this.emit({ type: "turn_finished", threadId, exitCode });
|
|
6276
|
-
if (exitCode
|
|
6357
|
+
if (exitCode === 0) {
|
|
6358
|
+
this.crashContinued.delete(threadId);
|
|
6359
|
+
} else {
|
|
6277
6360
|
const blob = [chatText, detail].filter(Boolean).join("\n");
|
|
6278
6361
|
void this.maybeHandleOrchestrationQuotaFailover(threadId, blob);
|
|
6362
|
+
this.maybeEnqueueCrashContinue(threadId, {
|
|
6363
|
+
detail: detail || failDetail,
|
|
6364
|
+
assistantText: chatText,
|
|
6365
|
+
partsCount: parts.length
|
|
6366
|
+
});
|
|
6279
6367
|
}
|
|
6280
6368
|
}
|
|
6281
6369
|
} catch (err) {
|
|
@@ -6295,6 +6383,11 @@ var Orchestrator = class {
|
|
|
6295
6383
|
}
|
|
6296
6384
|
this.emit({ type: "turn_finished", threadId, exitCode: 1 });
|
|
6297
6385
|
void this.maybeHandleOrchestrationQuotaFailover(threadId, message);
|
|
6386
|
+
this.maybeEnqueueCrashContinue(threadId, {
|
|
6387
|
+
detail: message,
|
|
6388
|
+
assistantText: "",
|
|
6389
|
+
partsCount: 0
|
|
6390
|
+
});
|
|
6298
6391
|
}
|
|
6299
6392
|
} finally {
|
|
6300
6393
|
this.startingTurns.delete(threadId);
|