@sideboard-ai/core 0.1.130 → 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-FMBLOOAO.js → chunk-SMWJAE74.js} +106 -14
- package/dist/{chunk-YALVX3UE.js → chunk-VFXZTSAD.js} +108 -15
- 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 +312 -92
- package/dist/index.d.cts +54 -4
- package/dist/index.d.ts +54 -4
- package/dist/index.js +36 -60
- package/dist/mcp/run-stdio.cjs +270 -62
- package/dist/mcp/run-stdio.js +6 -27
- package/dist/oauth-43NNH6C6.js +12 -0
- package/dist/oauth-FT7EL2PY.js +10 -0
- package/dist/{orchestrator-G6DU3AF3.js → orchestrator-5TN2DJWO.js} +5 -4
- package/dist/{orchestrator-3ZSFTG72.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) {
|
|
@@ -5341,7 +5384,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
5341
5384
|
${prompt}`;
|
|
5342
5385
|
}
|
|
5343
5386
|
async function defaultDeps() {
|
|
5344
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
5387
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-JA65XKB6.js");
|
|
5345
5388
|
const orch = getOrchestrator2();
|
|
5346
5389
|
return {
|
|
5347
5390
|
findThread: (id) => findThreadByRef(id),
|
|
@@ -5492,6 +5535,11 @@ var Orchestrator = class {
|
|
|
5492
5535
|
turnBaselines = /* @__PURE__ */ new Map();
|
|
5493
5536
|
/** Timers for orchestration session-quota auto-resume. */
|
|
5494
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();
|
|
5495
5543
|
maxConcurrent;
|
|
5496
5544
|
runningCount = 0;
|
|
5497
5545
|
constructor(opts) {
|
|
@@ -5705,6 +5753,29 @@ var Orchestrator = class {
|
|
|
5705
5753
|
);
|
|
5706
5754
|
}
|
|
5707
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
|
+
}
|
|
5708
5779
|
getThreads(includeArchived = false) {
|
|
5709
5780
|
return listThreads({ includeArchived });
|
|
5710
5781
|
}
|
|
@@ -5804,15 +5875,20 @@ var Orchestrator = class {
|
|
|
5804
5875
|
throw new Error(`Thread is archived: ${thread.id}`);
|
|
5805
5876
|
}
|
|
5806
5877
|
const queue = [...current.queue, prompt];
|
|
5878
|
+
this.crashContinued.delete(thread.id);
|
|
5807
5879
|
this.haltDrain.delete(thread.id);
|
|
5808
|
-
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";
|
|
5809
5883
|
const pid = current.agentPid;
|
|
5810
5884
|
if (typeof pid === "number" && pid > 0 && !isPidAlive(pid)) {
|
|
5811
5885
|
patch.agentPid = null;
|
|
5812
5886
|
}
|
|
5813
5887
|
updateThread(thread.id, patch);
|
|
5814
5888
|
this.emit({ type: "queue_changed", threadId: thread.id, queue });
|
|
5815
|
-
|
|
5889
|
+
if (!inFlight) {
|
|
5890
|
+
this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
|
|
5891
|
+
}
|
|
5816
5892
|
if (thisProcessShouldDrainAgentQueues()) {
|
|
5817
5893
|
void this.drainQueue(thread.id);
|
|
5818
5894
|
}
|
|
@@ -6133,7 +6209,7 @@ var Orchestrator = class {
|
|
|
6133
6209
|
let parts = result.parts;
|
|
6134
6210
|
let usage = result.usage ?? void 0;
|
|
6135
6211
|
let exitCode = result.exitCode;
|
|
6136
|
-
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) {
|
|
6137
6213
|
const sessionId = result.sessionId || this.requireThread(threadId).sessionId || "";
|
|
6138
6214
|
if (sessionId) {
|
|
6139
6215
|
const { recoverFinishedCursorRun } = await import("./cursor-recover-NOQYOFRF.js");
|
|
@@ -6154,7 +6230,7 @@ var Orchestrator = class {
|
|
|
6154
6230
|
}
|
|
6155
6231
|
let lastStderr = summarizeTurnStderr(stderrTail);
|
|
6156
6232
|
let detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
6157
|
-
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, {
|
|
6158
6234
|
hasSession: Boolean(this.requireThread(threadId).sessionId)
|
|
6159
6235
|
})) {
|
|
6160
6236
|
updateThread(threadId, { sessionId: null });
|
|
@@ -6250,7 +6326,11 @@ var Orchestrator = class {
|
|
|
6250
6326
|
)) {
|
|
6251
6327
|
updateThread(threadId, { sessionId: null });
|
|
6252
6328
|
}
|
|
6253
|
-
|
|
6329
|
+
if (this.stoppedTurns.has(threadId)) {
|
|
6330
|
+
void syncThreadBranchFromGit(threadId).catch(() => void 0);
|
|
6331
|
+
} else {
|
|
6332
|
+
await syncThreadBranchFromGit(threadId);
|
|
6333
|
+
}
|
|
6254
6334
|
if (this.stoppedTurns.has(threadId)) {
|
|
6255
6335
|
const stopped = writeLiveStatus(threadId, "stopped");
|
|
6256
6336
|
if (stopped?.status === "stopped") {
|
|
@@ -6274,9 +6354,16 @@ var Orchestrator = class {
|
|
|
6274
6354
|
});
|
|
6275
6355
|
}
|
|
6276
6356
|
this.emit({ type: "turn_finished", threadId, exitCode });
|
|
6277
|
-
if (exitCode
|
|
6357
|
+
if (exitCode === 0) {
|
|
6358
|
+
this.crashContinued.delete(threadId);
|
|
6359
|
+
} else {
|
|
6278
6360
|
const blob = [chatText, detail].filter(Boolean).join("\n");
|
|
6279
6361
|
void this.maybeHandleOrchestrationQuotaFailover(threadId, blob);
|
|
6362
|
+
this.maybeEnqueueCrashContinue(threadId, {
|
|
6363
|
+
detail: detail || failDetail,
|
|
6364
|
+
assistantText: chatText,
|
|
6365
|
+
partsCount: parts.length
|
|
6366
|
+
});
|
|
6280
6367
|
}
|
|
6281
6368
|
}
|
|
6282
6369
|
} catch (err) {
|
|
@@ -6296,6 +6383,11 @@ var Orchestrator = class {
|
|
|
6296
6383
|
}
|
|
6297
6384
|
this.emit({ type: "turn_finished", threadId, exitCode: 1 });
|
|
6298
6385
|
void this.maybeHandleOrchestrationQuotaFailover(threadId, message);
|
|
6386
|
+
this.maybeEnqueueCrashContinue(threadId, {
|
|
6387
|
+
detail: message,
|
|
6388
|
+
assistantText: "",
|
|
6389
|
+
partsCount: 0
|
|
6390
|
+
});
|
|
6299
6391
|
}
|
|
6300
6392
|
} finally {
|
|
6301
6393
|
this.startingTurns.delete(threadId);
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
stripBrightsyNdjsonNoise,
|
|
19
19
|
sumUsageList,
|
|
20
20
|
toolDescription
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-MGYCQAZ6.js";
|
|
22
22
|
import {
|
|
23
23
|
addWorkspace,
|
|
24
24
|
ensureWorkspace,
|
|
@@ -56,15 +56,17 @@ import {
|
|
|
56
56
|
import {
|
|
57
57
|
applyAgentRunnerHeapEnv,
|
|
58
58
|
fallbackTurnFailDetail,
|
|
59
|
+
formatAgentErrorContinuePrompt,
|
|
59
60
|
formatTurnExitError,
|
|
60
61
|
looksLikeAgentFailureMessage,
|
|
61
62
|
looksLikeInvalidAgentSession,
|
|
62
63
|
looksLikeV8Oom,
|
|
63
64
|
pushTurnStderr,
|
|
65
|
+
shouldFeedErrorBackToAgent,
|
|
64
66
|
shouldRetryFailedAgentTurn,
|
|
65
67
|
summarizeTurnStderr,
|
|
66
68
|
turnFailChatText
|
|
67
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-FSCQXMGI.js";
|
|
68
70
|
import {
|
|
69
71
|
releaseCaffeinateHoldForThread
|
|
70
72
|
} from "./chunk-DCOZABNT.js";
|
|
@@ -441,7 +443,7 @@ async function continueSourceThread(threadId, prompt) {
|
|
|
441
443
|
await continueOnReply(threadId, prompt);
|
|
442
444
|
return;
|
|
443
445
|
}
|
|
444
|
-
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-
|
|
446
|
+
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-5TN2DJWO.js");
|
|
445
447
|
await getOrchestrator2().send(threadId, prompt);
|
|
446
448
|
} catch {
|
|
447
449
|
}
|
|
@@ -2320,7 +2322,49 @@ function isMergedPrState(prUrl, prState) {
|
|
|
2320
2322
|
if (!prUrl?.trim()) return false;
|
|
2321
2323
|
return (prState ?? "").trim().toUpperCase() === "MERGED";
|
|
2322
2324
|
}
|
|
2323
|
-
|
|
2325
|
+
var DEFAULT_WORKTREE_SORT = "created";
|
|
2326
|
+
function groupCreatedAt(group) {
|
|
2327
|
+
let min = group[0]?.createdAt ?? "";
|
|
2328
|
+
for (const t of group) {
|
|
2329
|
+
if (t.createdAt && t.createdAt < min) min = t.createdAt;
|
|
2330
|
+
}
|
|
2331
|
+
return min;
|
|
2332
|
+
}
|
|
2333
|
+
function groupUpdatedAt(group) {
|
|
2334
|
+
let max = group[0]?.updatedAt ?? "";
|
|
2335
|
+
for (const t of group) {
|
|
2336
|
+
if (t.updatedAt && t.updatedAt > max) max = t.updatedAt;
|
|
2337
|
+
}
|
|
2338
|
+
return max;
|
|
2339
|
+
}
|
|
2340
|
+
function sortThreadsInWorktree(list) {
|
|
2341
|
+
return [...list].sort((a, b) => {
|
|
2342
|
+
const created = a.createdAt.localeCompare(b.createdAt);
|
|
2343
|
+
if (created !== 0) return created;
|
|
2344
|
+
return a.id.localeCompare(b.id);
|
|
2345
|
+
});
|
|
2346
|
+
}
|
|
2347
|
+
function compareWorktreeGroups(a, b, mode, labelOf) {
|
|
2348
|
+
if (mode === "name") {
|
|
2349
|
+
const named = (labelOf?.(a) ?? a[0]?.id ?? "").localeCompare(
|
|
2350
|
+
labelOf?.(b) ?? b[0]?.id ?? "",
|
|
2351
|
+
void 0,
|
|
2352
|
+
{ sensitivity: "base" }
|
|
2353
|
+
);
|
|
2354
|
+
if (named !== 0) return named;
|
|
2355
|
+
} else if (mode === "activity") {
|
|
2356
|
+
const activity = groupUpdatedAt(b).localeCompare(groupUpdatedAt(a));
|
|
2357
|
+
if (activity !== 0) return activity;
|
|
2358
|
+
} else {
|
|
2359
|
+
const created = groupCreatedAt(b).localeCompare(groupCreatedAt(a));
|
|
2360
|
+
if (created !== 0) return created;
|
|
2361
|
+
}
|
|
2362
|
+
return (a[0]?.id ?? "").localeCompare(b[0]?.id ?? "");
|
|
2363
|
+
}
|
|
2364
|
+
function defaultWorktreeGroupLabel(group) {
|
|
2365
|
+
return worktreeDisplayLabelForGroup(group);
|
|
2366
|
+
}
|
|
2367
|
+
function groupHomeBoardWorktrees(threads, sort = DEFAULT_WORKTREE_SORT, labelOf = defaultWorktreeGroupLabel) {
|
|
2324
2368
|
const map = /* @__PURE__ */ new Map();
|
|
2325
2369
|
for (const t of threads) {
|
|
2326
2370
|
const key = normalizeWorktreePath(t.worktreePath);
|
|
@@ -2328,7 +2372,7 @@ function groupHomeBoardWorktrees(threads) {
|
|
|
2328
2372
|
list.push(t);
|
|
2329
2373
|
map.set(key, list);
|
|
2330
2374
|
}
|
|
2331
|
-
return [...map.values()].map((list) => list.sort((a, b) =>
|
|
2375
|
+
return [...map.values()].map((list) => sortThreadsInWorktree(list)).sort((a, b) => compareWorktreeGroups(a, b, sort, labelOf));
|
|
2332
2376
|
}
|
|
2333
2377
|
function classifyWorktreeColumn(group) {
|
|
2334
2378
|
if (group.some((t) => isMergedPrState(t.prUrl, t.prState))) return "done";
|
|
@@ -2636,8 +2680,7 @@ function assembleHomeBoard(input) {
|
|
|
2636
2680
|
const kind = input.kind ?? "all";
|
|
2637
2681
|
const limit = Math.max(1, input.limit ?? BOARD_PAGE_SIZE);
|
|
2638
2682
|
const wsName = input.workspaceName ?? (() => "");
|
|
2639
|
-
const
|
|
2640
|
-
const live = input.threads.filter((t) => t.status !== "archived" && isHomeBoardThread(t)).sort(byUpdated);
|
|
2683
|
+
const live = input.threads.filter((t) => t.status !== "archived" && isHomeBoardThread(t));
|
|
2641
2684
|
const columns = emptyColumns();
|
|
2642
2685
|
const hidden = emptyHidden();
|
|
2643
2686
|
const totals = {
|
|
@@ -2835,7 +2878,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
2835
2878
|
return readThread(thread.id) ?? thread;
|
|
2836
2879
|
}
|
|
2837
2880
|
async function listLinearIssues(agent, repoPath) {
|
|
2838
|
-
const { getAdapter: getAdapter2 } = await import("./agents-
|
|
2881
|
+
const { getAdapter: getAdapter2 } = await import("./agents-CI6NGKRO.js");
|
|
2839
2882
|
await requireAgent(agent, { requireLinear: true });
|
|
2840
2883
|
const adapter = getAdapter2(agent);
|
|
2841
2884
|
if (!adapter.listLinearIssues) {
|
|
@@ -5506,7 +5549,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
5506
5549
|
${prompt}`;
|
|
5507
5550
|
}
|
|
5508
5551
|
async function defaultDeps() {
|
|
5509
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
5552
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-5TN2DJWO.js");
|
|
5510
5553
|
const orch = getOrchestrator2();
|
|
5511
5554
|
return {
|
|
5512
5555
|
findThread: (id) => findThreadByRef(id),
|
|
@@ -5657,6 +5700,11 @@ var Orchestrator = class {
|
|
|
5657
5700
|
turnBaselines = /* @__PURE__ */ new Map();
|
|
5658
5701
|
/** Timers for orchestration session-quota auto-resume. */
|
|
5659
5702
|
quotaResumeTimers = /* @__PURE__ */ new Map();
|
|
5703
|
+
/**
|
|
5704
|
+
* Threads that already got a crash-continue turn. Cleared on a successful
|
|
5705
|
+
* finish or a user send so a later crash can recover again.
|
|
5706
|
+
*/
|
|
5707
|
+
crashContinued = /* @__PURE__ */ new Set();
|
|
5660
5708
|
maxConcurrent;
|
|
5661
5709
|
runningCount = 0;
|
|
5662
5710
|
constructor(opts) {
|
|
@@ -5870,6 +5918,29 @@ var Orchestrator = class {
|
|
|
5870
5918
|
);
|
|
5871
5919
|
}
|
|
5872
5920
|
}
|
|
5921
|
+
/**
|
|
5922
|
+
* Cursor-style recovery: after a runner crash, feed the error back as the
|
|
5923
|
+
* next prompt so the same agent can continue instead of sitting on lastError.
|
|
5924
|
+
*/
|
|
5925
|
+
maybeEnqueueCrashContinue(threadId, opts) {
|
|
5926
|
+
if (this.crashContinued.has(threadId)) return;
|
|
5927
|
+
if (this.haltDrain.has(threadId)) return;
|
|
5928
|
+
if (!shouldFeedErrorBackToAgent({
|
|
5929
|
+
detail: opts.detail,
|
|
5930
|
+
assistantText: opts.assistantText,
|
|
5931
|
+
partsCount: opts.partsCount
|
|
5932
|
+
})) {
|
|
5933
|
+
return;
|
|
5934
|
+
}
|
|
5935
|
+
const thread = readThread(threadId);
|
|
5936
|
+
if (!thread || thread.status === "archived") return;
|
|
5937
|
+
this.crashContinued.add(threadId);
|
|
5938
|
+
const prompt = formatAgentErrorContinuePrompt(opts.detail);
|
|
5939
|
+
const queue = [prompt, ...thread.queue];
|
|
5940
|
+
updateThread(threadId, { queue });
|
|
5941
|
+
this.emit({ type: "queue_changed", threadId, queue });
|
|
5942
|
+
this.haltDrain.delete(threadId);
|
|
5943
|
+
}
|
|
5873
5944
|
getThreads(includeArchived = false) {
|
|
5874
5945
|
return listThreads({ includeArchived });
|
|
5875
5946
|
}
|
|
@@ -5969,15 +6040,20 @@ var Orchestrator = class {
|
|
|
5969
6040
|
throw new Error(`Thread is archived: ${thread.id}`);
|
|
5970
6041
|
}
|
|
5971
6042
|
const queue = [...current.queue, prompt];
|
|
6043
|
+
this.crashContinued.delete(thread.id);
|
|
5972
6044
|
this.haltDrain.delete(thread.id);
|
|
5973
|
-
const
|
|
6045
|
+
const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
|
|
6046
|
+
const patch = { queue };
|
|
6047
|
+
if (!inFlight) patch.status = "queued";
|
|
5974
6048
|
const pid = current.agentPid;
|
|
5975
6049
|
if (typeof pid === "number" && pid > 0 && !isPidAlive(pid)) {
|
|
5976
6050
|
patch.agentPid = null;
|
|
5977
6051
|
}
|
|
5978
6052
|
updateThread(thread.id, patch);
|
|
5979
6053
|
this.emit({ type: "queue_changed", threadId: thread.id, queue });
|
|
5980
|
-
|
|
6054
|
+
if (!inFlight) {
|
|
6055
|
+
this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
|
|
6056
|
+
}
|
|
5981
6057
|
if (thisProcessShouldDrainAgentQueues()) {
|
|
5982
6058
|
void this.drainQueue(thread.id);
|
|
5983
6059
|
}
|
|
@@ -6298,7 +6374,7 @@ var Orchestrator = class {
|
|
|
6298
6374
|
let parts = result.parts;
|
|
6299
6375
|
let usage = result.usage ?? void 0;
|
|
6300
6376
|
let exitCode = result.exitCode;
|
|
6301
|
-
if (this.requireThread(threadId).agent === "cursor" && exitCode !== 0 && !assistantText && parts.length === 0) {
|
|
6377
|
+
if (!this.stoppedTurns.has(threadId) && this.requireThread(threadId).agent === "cursor" && exitCode !== 0 && !assistantText && parts.length === 0) {
|
|
6302
6378
|
const sessionId = result.sessionId || this.requireThread(threadId).sessionId || "";
|
|
6303
6379
|
if (sessionId) {
|
|
6304
6380
|
const { recoverFinishedCursorRun } = await import("./cursor-recover-QSLWEZNA.js");
|
|
@@ -6319,7 +6395,7 @@ var Orchestrator = class {
|
|
|
6319
6395
|
}
|
|
6320
6396
|
let lastStderr = summarizeTurnStderr(stderrTail);
|
|
6321
6397
|
let detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
6322
|
-
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) &&
|
|
6398
|
+
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) && shouldRetryFailedAgentTurn(detail, {
|
|
6323
6399
|
hasSession: Boolean(this.requireThread(threadId).sessionId)
|
|
6324
6400
|
})) {
|
|
6325
6401
|
updateThread(threadId, { sessionId: null });
|
|
@@ -6415,7 +6491,11 @@ var Orchestrator = class {
|
|
|
6415
6491
|
)) {
|
|
6416
6492
|
updateThread(threadId, { sessionId: null });
|
|
6417
6493
|
}
|
|
6418
|
-
|
|
6494
|
+
if (this.stoppedTurns.has(threadId)) {
|
|
6495
|
+
void syncThreadBranchFromGit(threadId).catch(() => void 0);
|
|
6496
|
+
} else {
|
|
6497
|
+
await syncThreadBranchFromGit(threadId);
|
|
6498
|
+
}
|
|
6419
6499
|
if (this.stoppedTurns.has(threadId)) {
|
|
6420
6500
|
const stopped = writeLiveStatus(threadId, "stopped");
|
|
6421
6501
|
if (stopped?.status === "stopped") {
|
|
@@ -6439,9 +6519,16 @@ var Orchestrator = class {
|
|
|
6439
6519
|
});
|
|
6440
6520
|
}
|
|
6441
6521
|
this.emit({ type: "turn_finished", threadId, exitCode });
|
|
6442
|
-
if (exitCode
|
|
6522
|
+
if (exitCode === 0) {
|
|
6523
|
+
this.crashContinued.delete(threadId);
|
|
6524
|
+
} else {
|
|
6443
6525
|
const blob = [chatText, detail].filter(Boolean).join("\n");
|
|
6444
6526
|
void this.maybeHandleOrchestrationQuotaFailover(threadId, blob);
|
|
6527
|
+
this.maybeEnqueueCrashContinue(threadId, {
|
|
6528
|
+
detail: detail || failDetail,
|
|
6529
|
+
assistantText: chatText,
|
|
6530
|
+
partsCount: parts.length
|
|
6531
|
+
});
|
|
6445
6532
|
}
|
|
6446
6533
|
}
|
|
6447
6534
|
} catch (err) {
|
|
@@ -6461,6 +6548,11 @@ var Orchestrator = class {
|
|
|
6461
6548
|
}
|
|
6462
6549
|
this.emit({ type: "turn_finished", threadId, exitCode: 1 });
|
|
6463
6550
|
void this.maybeHandleOrchestrationQuotaFailover(threadId, message);
|
|
6551
|
+
this.maybeEnqueueCrashContinue(threadId, {
|
|
6552
|
+
detail: message,
|
|
6553
|
+
assistantText: "",
|
|
6554
|
+
partsCount: 0
|
|
6555
|
+
});
|
|
6464
6556
|
}
|
|
6465
6557
|
} finally {
|
|
6466
6558
|
this.startingTurns.delete(threadId);
|
|
@@ -7593,6 +7685,7 @@ export {
|
|
|
7593
7685
|
isHomeBoardThread,
|
|
7594
7686
|
BOARD_COLUMN_DEFS,
|
|
7595
7687
|
HOME_BOARD_CACHE_TTL_MS,
|
|
7688
|
+
DEFAULT_WORKTREE_SORT,
|
|
7596
7689
|
groupHomeBoardWorktrees,
|
|
7597
7690
|
classifyWorktreeColumn,
|
|
7598
7691
|
worktreeBoardStatus,
|
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
ensureConnectedBrightsyTeamTokens,
|
|
10
10
|
getConnectedBrightsyTeamsRaw,
|
|
11
11
|
listConnectedBrightsyTeams
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-LLX3OMHU.js";
|
|
13
|
+
import "./chunk-R7FGPBKL.js";
|
|
13
14
|
import "./chunk-KPIYENTF.js";
|
|
14
15
|
import "./chunk-BD2ICC4D.js";
|
|
15
16
|
export {
|