@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
package/dist/mcp/run-stdio.cjs
CHANGED
|
@@ -1553,11 +1553,40 @@ function humanizeAgentFailDetail(detail) {
|
|
|
1553
1553
|
}
|
|
1554
1554
|
function turnFailChatText(opts) {
|
|
1555
1555
|
const chat = opts.assistantText.trim();
|
|
1556
|
-
if (
|
|
1557
|
-
if (opts.exitCode === 0) return "";
|
|
1556
|
+
if (opts.exitCode === 0) return chat;
|
|
1558
1557
|
const detail = opts.detail.trim();
|
|
1559
|
-
|
|
1560
|
-
|
|
1558
|
+
const fail4 = detail ? humanizeAgentFailDetail(detail) : formatTurnExitError(opts.exitCode ?? 1, "");
|
|
1559
|
+
if (!chat) return fail4;
|
|
1560
|
+
const failCore = fail4.replace(/^exit\s*\d+:\s*/i, "").trim();
|
|
1561
|
+
if (looksLikeAgentFailureMessage(chat) || failCore && chat.includes(failCore) || chat.includes(fail4)) {
|
|
1562
|
+
return chat;
|
|
1563
|
+
}
|
|
1564
|
+
return `${chat}
|
|
1565
|
+
|
|
1566
|
+
${fail4}`;
|
|
1567
|
+
}
|
|
1568
|
+
function shouldFeedErrorBackToAgent(opts) {
|
|
1569
|
+
const detail = opts.detail.trim();
|
|
1570
|
+
const chat = (opts.assistantText ?? "").trim();
|
|
1571
|
+
if (looksLikeAgentFailureMessage(detail) || looksLikeAgentFailureMessage(chat)) {
|
|
1572
|
+
return false;
|
|
1573
|
+
}
|
|
1574
|
+
if (looksLikeInvalidAgentSession(detail) || looksLikeV8Oom(detail) || looksLikeRetryableRunnerCrash(detail)) {
|
|
1575
|
+
return true;
|
|
1576
|
+
}
|
|
1577
|
+
if (/without details|segfault|sig(?:segv|abrt|ill)|fatal error/i.test(detail)) {
|
|
1578
|
+
return true;
|
|
1579
|
+
}
|
|
1580
|
+
return !chat && (opts.partsCount ?? 0) === 0;
|
|
1581
|
+
}
|
|
1582
|
+
function formatAgentErrorContinuePrompt(detail) {
|
|
1583
|
+
const fail4 = humanizeAgentFailDetail(detail.trim()) || "the agent process exited without details";
|
|
1584
|
+
return [
|
|
1585
|
+
"The previous agent process ended before it finished. Error:",
|
|
1586
|
+
fail4,
|
|
1587
|
+
"",
|
|
1588
|
+
"Continue from where you left off. Use the error to recover \u2014 do not restart the whole task unless the error requires it. If you cannot continue, say why."
|
|
1589
|
+
].join("\n");
|
|
1561
1590
|
}
|
|
1562
1591
|
function formatTurnExitError(exitCode, stderrSummary) {
|
|
1563
1592
|
const code = exitCode ?? 1;
|
|
@@ -6163,6 +6192,8 @@ var init_global_workspace = __esm({
|
|
|
6163
6192
|
|
|
6164
6193
|
// src/brightsy/config.ts
|
|
6165
6194
|
function brightsyConfigPath() {
|
|
6195
|
+
const override = process.env.BRIGHTSY_CONFIG?.trim();
|
|
6196
|
+
if (override) return override;
|
|
6166
6197
|
return (0, import_node_path19.join)((0, import_node_os6.homedir)(), ".brightsy", "config.json");
|
|
6167
6198
|
}
|
|
6168
6199
|
function loadBrightsyConfig() {
|
|
@@ -6201,6 +6232,108 @@ var init_accounts = __esm({
|
|
|
6201
6232
|
}
|
|
6202
6233
|
});
|
|
6203
6234
|
|
|
6235
|
+
// src/http/fetch.ts
|
|
6236
|
+
function formatFetchError(err, url) {
|
|
6237
|
+
if (!(err instanceof Error)) return `${String(err)} (${url})`;
|
|
6238
|
+
const cause = err.cause;
|
|
6239
|
+
let detail = "";
|
|
6240
|
+
if (cause instanceof Error) {
|
|
6241
|
+
const code = typeof cause.code === "string" ? cause.code : void 0;
|
|
6242
|
+
detail = code ? ` [${code}: ${cause.message}]` : ` [${cause.message}]`;
|
|
6243
|
+
} else if (cause != null) {
|
|
6244
|
+
detail = ` [${String(cause)}]`;
|
|
6245
|
+
}
|
|
6246
|
+
return `${err.message}${detail} (${url})`;
|
|
6247
|
+
}
|
|
6248
|
+
async function httpFetch(input, init) {
|
|
6249
|
+
const url = typeof input === "string" ? input : input.href;
|
|
6250
|
+
const fn = injected ?? globalThis.fetch.bind(globalThis);
|
|
6251
|
+
try {
|
|
6252
|
+
return await fn(url, init);
|
|
6253
|
+
} catch (err) {
|
|
6254
|
+
throw new Error(formatFetchError(err, url));
|
|
6255
|
+
}
|
|
6256
|
+
}
|
|
6257
|
+
var injected;
|
|
6258
|
+
var init_fetch = __esm({
|
|
6259
|
+
"src/http/fetch.ts"() {
|
|
6260
|
+
"use strict";
|
|
6261
|
+
injected = null;
|
|
6262
|
+
}
|
|
6263
|
+
});
|
|
6264
|
+
|
|
6265
|
+
// src/brightsy/oauth.ts
|
|
6266
|
+
function brightsyAccessTokenNeedsRefresh(expiresAt, now = Date.now()) {
|
|
6267
|
+
if (typeof expiresAt !== "number" || !Number.isFinite(expiresAt) || expiresAt <= 0) {
|
|
6268
|
+
return true;
|
|
6269
|
+
}
|
|
6270
|
+
return now >= expiresAt - REFRESH_SKEW_MS;
|
|
6271
|
+
}
|
|
6272
|
+
function applyGrant(current, grant) {
|
|
6273
|
+
return {
|
|
6274
|
+
access_token: grant.access_token,
|
|
6275
|
+
refresh_token: grant.refresh_token || current.refresh_token,
|
|
6276
|
+
expires_at: grant.expires_at ?? current.expires_at
|
|
6277
|
+
};
|
|
6278
|
+
}
|
|
6279
|
+
async function refreshBrightsyAccessToken(opts) {
|
|
6280
|
+
const endpoint = (opts.endpoint || "https://brightsy.ai").replace(/\/$/, "");
|
|
6281
|
+
const url = `${endpoint}/oauth/token`;
|
|
6282
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
6283
|
+
let res;
|
|
6284
|
+
try {
|
|
6285
|
+
res = await fetchImpl(url, {
|
|
6286
|
+
method: "POST",
|
|
6287
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
6288
|
+
body: new URLSearchParams({
|
|
6289
|
+
grant_type: "refresh_token",
|
|
6290
|
+
refresh_token: opts.refreshToken,
|
|
6291
|
+
client_id: opts.clientId || "brightsy-cli"
|
|
6292
|
+
})
|
|
6293
|
+
});
|
|
6294
|
+
} catch (err) {
|
|
6295
|
+
throw new Error(formatFetchError(err, url));
|
|
6296
|
+
}
|
|
6297
|
+
if (!res.ok) return null;
|
|
6298
|
+
const data = await res.json();
|
|
6299
|
+
if (!data.access_token) return null;
|
|
6300
|
+
return {
|
|
6301
|
+
access_token: data.access_token,
|
|
6302
|
+
refresh_token: data.refresh_token,
|
|
6303
|
+
expires_at: data.expires_in ? Date.now() + data.expires_in * 1e3 : void 0
|
|
6304
|
+
};
|
|
6305
|
+
}
|
|
6306
|
+
async function ensureBrightsyLocalConfigFresh(opts) {
|
|
6307
|
+
let cfg;
|
|
6308
|
+
try {
|
|
6309
|
+
cfg = loadBrightsyConfig();
|
|
6310
|
+
} catch {
|
|
6311
|
+
return null;
|
|
6312
|
+
}
|
|
6313
|
+
if (!cfg.refresh_token || !brightsyAccessTokenNeedsRefresh(cfg.expires_at)) {
|
|
6314
|
+
return cfg;
|
|
6315
|
+
}
|
|
6316
|
+
const grant = await refreshBrightsyAccessToken({
|
|
6317
|
+
endpoint: cfg.endpoint || "https://brightsy.ai",
|
|
6318
|
+
refreshToken: cfg.refresh_token,
|
|
6319
|
+
clientId: cfg.oauth_client_id,
|
|
6320
|
+
fetchImpl: opts?.fetchImpl
|
|
6321
|
+
});
|
|
6322
|
+
if (!grant) return cfg;
|
|
6323
|
+
const next = { ...cfg, ...applyGrant(cfg, grant) };
|
|
6324
|
+
saveBrightsyConfig(next);
|
|
6325
|
+
return next;
|
|
6326
|
+
}
|
|
6327
|
+
var REFRESH_SKEW_MS;
|
|
6328
|
+
var init_oauth = __esm({
|
|
6329
|
+
"src/brightsy/oauth.ts"() {
|
|
6330
|
+
"use strict";
|
|
6331
|
+
init_fetch();
|
|
6332
|
+
init_config();
|
|
6333
|
+
REFRESH_SKEW_MS = 6e4;
|
|
6334
|
+
}
|
|
6335
|
+
});
|
|
6336
|
+
|
|
6204
6337
|
// src/brightsy/connected-teams.ts
|
|
6205
6338
|
function storePath4() {
|
|
6206
6339
|
return (0, import_node_path20.join)(appDataDir(), "brightsy-teams.json");
|
|
@@ -6251,7 +6384,6 @@ function applyConnectedTeamToCli(team) {
|
|
|
6251
6384
|
}
|
|
6252
6385
|
async function refreshTeamToken(team) {
|
|
6253
6386
|
if (!team.refresh_token) return team;
|
|
6254
|
-
const endpoint = (team.endpoint || "https://brightsy.ai").replace(/\/$/, "");
|
|
6255
6387
|
const cfg = (() => {
|
|
6256
6388
|
try {
|
|
6257
6389
|
return loadBrightsyConfig();
|
|
@@ -6259,39 +6391,34 @@ async function refreshTeamToken(team) {
|
|
|
6259
6391
|
return null;
|
|
6260
6392
|
}
|
|
6261
6393
|
})();
|
|
6262
|
-
const
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
body: new URLSearchParams({
|
|
6267
|
-
grant_type: "refresh_token",
|
|
6268
|
-
refresh_token: team.refresh_token,
|
|
6269
|
-
client_id: clientId
|
|
6270
|
-
})
|
|
6394
|
+
const grant = await refreshBrightsyAccessToken({
|
|
6395
|
+
endpoint: team.endpoint || "https://brightsy.ai",
|
|
6396
|
+
refreshToken: team.refresh_token,
|
|
6397
|
+
clientId: cfg?.oauth_client_id
|
|
6271
6398
|
});
|
|
6272
|
-
if (!
|
|
6273
|
-
const data = await res.json();
|
|
6274
|
-
if (!data.access_token) return team;
|
|
6399
|
+
if (!grant) return team;
|
|
6275
6400
|
return {
|
|
6276
6401
|
...team,
|
|
6277
|
-
access_token:
|
|
6278
|
-
refresh_token:
|
|
6279
|
-
expires_at:
|
|
6402
|
+
access_token: grant.access_token,
|
|
6403
|
+
refresh_token: grant.refresh_token || team.refresh_token,
|
|
6404
|
+
expires_at: grant.expires_at ?? team.expires_at
|
|
6280
6405
|
};
|
|
6281
6406
|
}
|
|
6282
6407
|
async function ensureConnectedBrightsyTeamTokens() {
|
|
6408
|
+
await ensureBrightsyLocalConfigFresh().catch(() => null);
|
|
6283
6409
|
const teams = readStore4();
|
|
6284
6410
|
if (teams.length === 0) return [];
|
|
6285
6411
|
const next = [];
|
|
6286
6412
|
let changed = false;
|
|
6287
6413
|
for (const team of teams) {
|
|
6288
|
-
|
|
6289
|
-
if (!expired) {
|
|
6414
|
+
if (!team.refresh_token || !brightsyAccessTokenNeedsRefresh(team.expires_at)) {
|
|
6290
6415
|
next.push(team);
|
|
6291
6416
|
continue;
|
|
6292
6417
|
}
|
|
6293
6418
|
const refreshed = await refreshTeamToken(team);
|
|
6294
|
-
if (refreshed.access_token !== team.access_token
|
|
6419
|
+
if (refreshed.access_token !== team.access_token || refreshed.refresh_token !== team.refresh_token || refreshed.expires_at !== team.expires_at) {
|
|
6420
|
+
changed = true;
|
|
6421
|
+
}
|
|
6295
6422
|
next.push(refreshed);
|
|
6296
6423
|
}
|
|
6297
6424
|
if (changed) writeStore2(next);
|
|
@@ -6339,6 +6466,7 @@ var init_connected_teams = __esm({
|
|
|
6339
6466
|
init_paths();
|
|
6340
6467
|
init_accounts();
|
|
6341
6468
|
init_config();
|
|
6469
|
+
init_oauth();
|
|
6342
6470
|
}
|
|
6343
6471
|
});
|
|
6344
6472
|
|
|
@@ -7610,6 +7738,7 @@ function teamEnv(team) {
|
|
|
7610
7738
|
const endpoint = (team.endpoint || "https://brightsy.ai").replace(/\/$/, "");
|
|
7611
7739
|
return {
|
|
7612
7740
|
BRIGHTSY_API_TOKEN: team.access_token,
|
|
7741
|
+
...team.refresh_token ? { BRIGHTSY_REFRESH_TOKEN: team.refresh_token } : {},
|
|
7613
7742
|
BRIGHTSY_ACCOUNT_ID: team.id,
|
|
7614
7743
|
BRIGHTSY_API_URL: endpoint
|
|
7615
7744
|
};
|
|
@@ -7889,10 +8018,15 @@ var init_types = __esm({
|
|
|
7889
8018
|
|
|
7890
8019
|
// src/agents/claude.ts
|
|
7891
8020
|
async function loadMcpServers() {
|
|
8021
|
+
if (mcpListCache && Date.now() - mcpListCache.at < 3e4) {
|
|
8022
|
+
return mcpListCache.servers;
|
|
8023
|
+
}
|
|
7892
8024
|
const claude = resolveClaudeExecutable();
|
|
7893
8025
|
const mcpText = await run(claude, ["mcp", "list"], { reject: false });
|
|
7894
|
-
|
|
8026
|
+
const servers = parseMcpList(`${mcpText.stdout}
|
|
7895
8027
|
${mcpText.stderr}`);
|
|
8028
|
+
mcpListCache = { at: Date.now(), servers };
|
|
8029
|
+
return servers;
|
|
7896
8030
|
}
|
|
7897
8031
|
function usageFromClaude(usage) {
|
|
7898
8032
|
if (!usage) return null;
|
|
@@ -8106,7 +8240,7 @@ function parseIssuesJson(raw) {
|
|
|
8106
8240
|
}
|
|
8107
8241
|
return [];
|
|
8108
8242
|
}
|
|
8109
|
-
var import_node_fs22, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
|
|
8243
|
+
var import_node_fs22, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
|
|
8110
8244
|
var init_claude = __esm({
|
|
8111
8245
|
"src/agents/claude.ts"() {
|
|
8112
8246
|
"use strict";
|
|
@@ -8144,6 +8278,7 @@ var init_claude = __esm({
|
|
|
8144
8278
|
"Skill(claude-in-chrome)"
|
|
8145
8279
|
];
|
|
8146
8280
|
CLAUDE_PROMPT_ARG_MAX = 2e5;
|
|
8281
|
+
mcpListCache = null;
|
|
8147
8282
|
claudeAdapter = {
|
|
8148
8283
|
kind: "claude",
|
|
8149
8284
|
async detect() {
|
|
@@ -9522,10 +9657,13 @@ var init_opencode = __esm({
|
|
|
9522
9657
|
const part = obj.part;
|
|
9523
9658
|
const id = part?.tool_use_id ?? part?.id ?? obj.tool_use_id ?? obj.id;
|
|
9524
9659
|
if (!id) return null;
|
|
9660
|
+
const flagged = obj.isError === true || obj.is_error === true;
|
|
9661
|
+
const errText2 = formatUnknownDetail(obj.error);
|
|
9525
9662
|
return {
|
|
9526
9663
|
type: "tool_result",
|
|
9527
9664
|
id,
|
|
9528
|
-
content: part?.output ?? part?.content ?? obj.output ?? obj.content
|
|
9665
|
+
content: part?.output ?? part?.content ?? obj.output ?? obj.content ?? (errText2 || void 0),
|
|
9666
|
+
isError: flagged || Boolean(errText2)
|
|
9529
9667
|
};
|
|
9530
9668
|
}
|
|
9531
9669
|
if (obj.type === "step_finish" || obj.type === "step-finish") {
|
|
@@ -12021,7 +12159,48 @@ function isMergedPrState(prUrl, prState) {
|
|
|
12021
12159
|
if (!prUrl?.trim()) return false;
|
|
12022
12160
|
return (prState ?? "").trim().toUpperCase() === "MERGED";
|
|
12023
12161
|
}
|
|
12024
|
-
function
|
|
12162
|
+
function groupCreatedAt(group) {
|
|
12163
|
+
let min = group[0]?.createdAt ?? "";
|
|
12164
|
+
for (const t of group) {
|
|
12165
|
+
if (t.createdAt && t.createdAt < min) min = t.createdAt;
|
|
12166
|
+
}
|
|
12167
|
+
return min;
|
|
12168
|
+
}
|
|
12169
|
+
function groupUpdatedAt(group) {
|
|
12170
|
+
let max = group[0]?.updatedAt ?? "";
|
|
12171
|
+
for (const t of group) {
|
|
12172
|
+
if (t.updatedAt && t.updatedAt > max) max = t.updatedAt;
|
|
12173
|
+
}
|
|
12174
|
+
return max;
|
|
12175
|
+
}
|
|
12176
|
+
function sortThreadsInWorktree(list) {
|
|
12177
|
+
return [...list].sort((a, b) => {
|
|
12178
|
+
const created = a.createdAt.localeCompare(b.createdAt);
|
|
12179
|
+
if (created !== 0) return created;
|
|
12180
|
+
return a.id.localeCompare(b.id);
|
|
12181
|
+
});
|
|
12182
|
+
}
|
|
12183
|
+
function compareWorktreeGroups(a, b, mode, labelOf) {
|
|
12184
|
+
if (mode === "name") {
|
|
12185
|
+
const named = (labelOf?.(a) ?? a[0]?.id ?? "").localeCompare(
|
|
12186
|
+
labelOf?.(b) ?? b[0]?.id ?? "",
|
|
12187
|
+
void 0,
|
|
12188
|
+
{ sensitivity: "base" }
|
|
12189
|
+
);
|
|
12190
|
+
if (named !== 0) return named;
|
|
12191
|
+
} else if (mode === "activity") {
|
|
12192
|
+
const activity = groupUpdatedAt(b).localeCompare(groupUpdatedAt(a));
|
|
12193
|
+
if (activity !== 0) return activity;
|
|
12194
|
+
} else {
|
|
12195
|
+
const created = groupCreatedAt(b).localeCompare(groupCreatedAt(a));
|
|
12196
|
+
if (created !== 0) return created;
|
|
12197
|
+
}
|
|
12198
|
+
return (a[0]?.id ?? "").localeCompare(b[0]?.id ?? "");
|
|
12199
|
+
}
|
|
12200
|
+
function defaultWorktreeGroupLabel(group) {
|
|
12201
|
+
return worktreeDisplayLabelForGroup(group);
|
|
12202
|
+
}
|
|
12203
|
+
function groupHomeBoardWorktrees(threads, sort = DEFAULT_WORKTREE_SORT, labelOf = defaultWorktreeGroupLabel) {
|
|
12025
12204
|
const map = /* @__PURE__ */ new Map();
|
|
12026
12205
|
for (const t of threads) {
|
|
12027
12206
|
const key = normalizeWorktreePath(t.worktreePath);
|
|
@@ -12029,7 +12208,7 @@ function groupHomeBoardWorktrees(threads) {
|
|
|
12029
12208
|
list.push(t);
|
|
12030
12209
|
map.set(key, list);
|
|
12031
12210
|
}
|
|
12032
|
-
return [...map.values()].map((list) => list.sort((a, b) =>
|
|
12211
|
+
return [...map.values()].map((list) => sortThreadsInWorktree(list)).sort((a, b) => compareWorktreeGroups(a, b, sort, labelOf));
|
|
12033
12212
|
}
|
|
12034
12213
|
function classifyWorktreeColumn(group) {
|
|
12035
12214
|
if (group.some((t) => isMergedPrState(t.prUrl, t.prState))) return "done";
|
|
@@ -12328,8 +12507,7 @@ function assembleHomeBoard(input) {
|
|
|
12328
12507
|
const kind = input.kind ?? "all";
|
|
12329
12508
|
const limit = Math.max(1, input.limit ?? BOARD_PAGE_SIZE);
|
|
12330
12509
|
const wsName = input.workspaceName ?? (() => "");
|
|
12331
|
-
const
|
|
12332
|
-
const live = input.threads.filter((t) => t.status !== "archived" && isHomeBoardThread(t)).sort(byUpdated);
|
|
12510
|
+
const live = input.threads.filter((t) => t.status !== "archived" && isHomeBoardThread(t));
|
|
12333
12511
|
const columns = emptyColumns();
|
|
12334
12512
|
const hidden = emptyHidden();
|
|
12335
12513
|
const totals = {
|
|
@@ -12384,7 +12562,7 @@ function assembleHomeBoard(input) {
|
|
|
12384
12562
|
}
|
|
12385
12563
|
return { columns, hidden, totals };
|
|
12386
12564
|
}
|
|
12387
|
-
var GLOBAL_WORKSPACE_ID2, BOARD_COLUMN_DEFS, HOME_BOARD_CACHE_TTL_MS, DEFAULTISH_BRANCH, BOARD_PAGE_SIZE, HOME_BOARD_AGENT_HINT;
|
|
12565
|
+
var GLOBAL_WORKSPACE_ID2, BOARD_COLUMN_DEFS, HOME_BOARD_CACHE_TTL_MS, DEFAULT_WORKTREE_SORT, DEFAULTISH_BRANCH, BOARD_PAGE_SIZE, HOME_BOARD_AGENT_HINT;
|
|
12388
12566
|
var init_home_board = __esm({
|
|
12389
12567
|
"src/board/home-board.ts"() {
|
|
12390
12568
|
"use strict";
|
|
@@ -12397,6 +12575,7 @@ var init_home_board = __esm({
|
|
|
12397
12575
|
{ id: "done", title: "Merged" }
|
|
12398
12576
|
];
|
|
12399
12577
|
HOME_BOARD_CACHE_TTL_MS = 15 * 60 * 1e3;
|
|
12578
|
+
DEFAULT_WORKTREE_SORT = "created";
|
|
12400
12579
|
DEFAULTISH_BRANCH = /^(main|master|develop|development|trunk|default|head)$/;
|
|
12401
12580
|
BOARD_PAGE_SIZE = 40;
|
|
12402
12581
|
HOME_BOARD_AGENT_HINT = "Home is a Kanban of worktrees (one card per checkout; sibling chat tabs nest as inner cards). create_thread reuses a live worktree for the same ticket, PR, or named branch \u2014 do not recreate it. Columns are the path to merge: New (no PR) \u2192 Draft (draft PR) \u2192 Review (open PR) \u2192 Merged. Archive removes the card to Settings \u2192 History. Queued/running are activity on the card, not columns. Orchestration chats stay in the sidebar. Do not invent status.";
|
|
@@ -14901,7 +15080,8 @@ function formatArtifactDirective() {
|
|
|
14901
15080
|
"```html",
|
|
14902
15081
|
"<!DOCTYPE html><html><head><title>Demo</title></head><body><h1>Hi</h1></body></html>",
|
|
14903
15082
|
"```",
|
|
14904
|
-
"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.",
|
|
15083
|
+
"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.",
|
|
15084
|
+
" 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.",
|
|
14905
15085
|
"CMS / JSON Schema forms & tables (Brightsy or any schema+schemaUi source):",
|
|
14906
15086
|
"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:",
|
|
14907
15087
|
" - datasource=brightsy + resource_id (record type UUID) after fetching types via Brightsy MCP, or",
|
|
@@ -14916,7 +15096,7 @@ function formatArtifactDirective() {
|
|
|
14916
15096
|
].join("\n");
|
|
14917
15097
|
}
|
|
14918
15098
|
function formatUiReminder() {
|
|
14919
|
-
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.";
|
|
15099
|
+
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.";
|
|
14920
15100
|
}
|
|
14921
15101
|
var import_node_fs40, import_node_path37;
|
|
14922
15102
|
var init_instructions = __esm({
|
|
@@ -15899,6 +16079,11 @@ var init_orchestrator = __esm({
|
|
|
15899
16079
|
turnBaselines = /* @__PURE__ */ new Map();
|
|
15900
16080
|
/** Timers for orchestration session-quota auto-resume. */
|
|
15901
16081
|
quotaResumeTimers = /* @__PURE__ */ new Map();
|
|
16082
|
+
/**
|
|
16083
|
+
* Threads that already got a crash-continue turn. Cleared on a successful
|
|
16084
|
+
* finish or a user send so a later crash can recover again.
|
|
16085
|
+
*/
|
|
16086
|
+
crashContinued = /* @__PURE__ */ new Set();
|
|
15902
16087
|
maxConcurrent;
|
|
15903
16088
|
runningCount = 0;
|
|
15904
16089
|
constructor(opts) {
|
|
@@ -16112,6 +16297,29 @@ var init_orchestrator = __esm({
|
|
|
16112
16297
|
);
|
|
16113
16298
|
}
|
|
16114
16299
|
}
|
|
16300
|
+
/**
|
|
16301
|
+
* Cursor-style recovery: after a runner crash, feed the error back as the
|
|
16302
|
+
* next prompt so the same agent can continue instead of sitting on lastError.
|
|
16303
|
+
*/
|
|
16304
|
+
maybeEnqueueCrashContinue(threadId, opts) {
|
|
16305
|
+
if (this.crashContinued.has(threadId)) return;
|
|
16306
|
+
if (this.haltDrain.has(threadId)) return;
|
|
16307
|
+
if (!shouldFeedErrorBackToAgent({
|
|
16308
|
+
detail: opts.detail,
|
|
16309
|
+
assistantText: opts.assistantText,
|
|
16310
|
+
partsCount: opts.partsCount
|
|
16311
|
+
})) {
|
|
16312
|
+
return;
|
|
16313
|
+
}
|
|
16314
|
+
const thread = readThread(threadId);
|
|
16315
|
+
if (!thread || thread.status === "archived") return;
|
|
16316
|
+
this.crashContinued.add(threadId);
|
|
16317
|
+
const prompt = formatAgentErrorContinuePrompt(opts.detail);
|
|
16318
|
+
const queue = [prompt, ...thread.queue];
|
|
16319
|
+
updateThread(threadId, { queue });
|
|
16320
|
+
this.emit({ type: "queue_changed", threadId, queue });
|
|
16321
|
+
this.haltDrain.delete(threadId);
|
|
16322
|
+
}
|
|
16115
16323
|
getThreads(includeArchived = false) {
|
|
16116
16324
|
return listThreads({ includeArchived });
|
|
16117
16325
|
}
|
|
@@ -16211,15 +16419,20 @@ var init_orchestrator = __esm({
|
|
|
16211
16419
|
throw new Error(`Thread is archived: ${thread.id}`);
|
|
16212
16420
|
}
|
|
16213
16421
|
const queue = [...current.queue, prompt];
|
|
16422
|
+
this.crashContinued.delete(thread.id);
|
|
16214
16423
|
this.haltDrain.delete(thread.id);
|
|
16215
|
-
const
|
|
16424
|
+
const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
|
|
16425
|
+
const patch = { queue };
|
|
16426
|
+
if (!inFlight) patch.status = "queued";
|
|
16216
16427
|
const pid = current.agentPid;
|
|
16217
16428
|
if (typeof pid === "number" && pid > 0 && !isPidAlive(pid)) {
|
|
16218
16429
|
patch.agentPid = null;
|
|
16219
16430
|
}
|
|
16220
16431
|
updateThread(thread.id, patch);
|
|
16221
16432
|
this.emit({ type: "queue_changed", threadId: thread.id, queue });
|
|
16222
|
-
|
|
16433
|
+
if (!inFlight) {
|
|
16434
|
+
this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
|
|
16435
|
+
}
|
|
16223
16436
|
if (thisProcessShouldDrainAgentQueues()) {
|
|
16224
16437
|
void this.drainQueue(thread.id);
|
|
16225
16438
|
}
|
|
@@ -16540,7 +16753,7 @@ var init_orchestrator = __esm({
|
|
|
16540
16753
|
let parts = result.parts;
|
|
16541
16754
|
let usage = result.usage ?? void 0;
|
|
16542
16755
|
let exitCode = result.exitCode;
|
|
16543
|
-
if (this.requireThread(threadId).agent === "cursor" && exitCode !== 0 && !assistantText && parts.length === 0) {
|
|
16756
|
+
if (!this.stoppedTurns.has(threadId) && this.requireThread(threadId).agent === "cursor" && exitCode !== 0 && !assistantText && parts.length === 0) {
|
|
16544
16757
|
const sessionId = result.sessionId || this.requireThread(threadId).sessionId || "";
|
|
16545
16758
|
if (sessionId) {
|
|
16546
16759
|
const { recoverFinishedCursorRun: recoverFinishedCursorRun2 } = await Promise.resolve().then(() => (init_cursor_recover(), cursor_recover_exports));
|
|
@@ -16561,7 +16774,7 @@ var init_orchestrator = __esm({
|
|
|
16561
16774
|
}
|
|
16562
16775
|
let lastStderr = summarizeTurnStderr(stderrTail);
|
|
16563
16776
|
let detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
16564
|
-
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) &&
|
|
16777
|
+
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) && shouldRetryFailedAgentTurn(detail, {
|
|
16565
16778
|
hasSession: Boolean(this.requireThread(threadId).sessionId)
|
|
16566
16779
|
})) {
|
|
16567
16780
|
updateThread(threadId, { sessionId: null });
|
|
@@ -16657,7 +16870,11 @@ var init_orchestrator = __esm({
|
|
|
16657
16870
|
)) {
|
|
16658
16871
|
updateThread(threadId, { sessionId: null });
|
|
16659
16872
|
}
|
|
16660
|
-
|
|
16873
|
+
if (this.stoppedTurns.has(threadId)) {
|
|
16874
|
+
void syncThreadBranchFromGit(threadId).catch(() => void 0);
|
|
16875
|
+
} else {
|
|
16876
|
+
await syncThreadBranchFromGit(threadId);
|
|
16877
|
+
}
|
|
16661
16878
|
if (this.stoppedTurns.has(threadId)) {
|
|
16662
16879
|
const stopped = writeLiveStatus(threadId, "stopped");
|
|
16663
16880
|
if (stopped?.status === "stopped") {
|
|
@@ -16681,9 +16898,16 @@ var init_orchestrator = __esm({
|
|
|
16681
16898
|
});
|
|
16682
16899
|
}
|
|
16683
16900
|
this.emit({ type: "turn_finished", threadId, exitCode });
|
|
16684
|
-
if (exitCode
|
|
16901
|
+
if (exitCode === 0) {
|
|
16902
|
+
this.crashContinued.delete(threadId);
|
|
16903
|
+
} else {
|
|
16685
16904
|
const blob = [chatText, detail].filter(Boolean).join("\n");
|
|
16686
16905
|
void this.maybeHandleOrchestrationQuotaFailover(threadId, blob);
|
|
16906
|
+
this.maybeEnqueueCrashContinue(threadId, {
|
|
16907
|
+
detail: detail || failDetail,
|
|
16908
|
+
assistantText: chatText,
|
|
16909
|
+
partsCount: parts.length
|
|
16910
|
+
});
|
|
16687
16911
|
}
|
|
16688
16912
|
}
|
|
16689
16913
|
} catch (err) {
|
|
@@ -16703,6 +16927,11 @@ var init_orchestrator = __esm({
|
|
|
16703
16927
|
}
|
|
16704
16928
|
this.emit({ type: "turn_finished", threadId, exitCode: 1 });
|
|
16705
16929
|
void this.maybeHandleOrchestrationQuotaFailover(threadId, message);
|
|
16930
|
+
this.maybeEnqueueCrashContinue(threadId, {
|
|
16931
|
+
detail: message,
|
|
16932
|
+
assistantText: "",
|
|
16933
|
+
partsCount: 0
|
|
16934
|
+
});
|
|
16706
16935
|
}
|
|
16707
16936
|
} finally {
|
|
16708
16937
|
this.startingTurns.delete(threadId);
|
|
@@ -17676,34 +17905,14 @@ init_worktree();
|
|
|
17676
17905
|
init_run();
|
|
17677
17906
|
init_app_settings();
|
|
17678
17907
|
|
|
17679
|
-
// src/
|
|
17680
|
-
|
|
17681
|
-
function formatFetchError(err, url) {
|
|
17682
|
-
if (!(err instanceof Error)) return `${String(err)} (${url})`;
|
|
17683
|
-
const cause = err.cause;
|
|
17684
|
-
let detail = "";
|
|
17685
|
-
if (cause instanceof Error) {
|
|
17686
|
-
const code = typeof cause.code === "string" ? cause.code : void 0;
|
|
17687
|
-
detail = code ? ` [${code}: ${cause.message}]` : ` [${cause.message}]`;
|
|
17688
|
-
} else if (cause != null) {
|
|
17689
|
-
detail = ` [${String(cause)}]`;
|
|
17690
|
-
}
|
|
17691
|
-
return `${err.message}${detail} (${url})`;
|
|
17692
|
-
}
|
|
17693
|
-
async function httpFetch(input, init) {
|
|
17694
|
-
const url = typeof input === "string" ? input : input.href;
|
|
17695
|
-
const fn = injected ?? globalThis.fetch.bind(globalThis);
|
|
17696
|
-
try {
|
|
17697
|
-
return await fn(url, init);
|
|
17698
|
-
} catch (err) {
|
|
17699
|
-
throw new Error(formatFetchError(err, url));
|
|
17700
|
-
}
|
|
17701
|
-
}
|
|
17908
|
+
// src/integrations/linear.ts
|
|
17909
|
+
init_fetch();
|
|
17702
17910
|
|
|
17703
17911
|
// src/integrations/linear-oauth.ts
|
|
17704
17912
|
var import_node_crypto9 = require("crypto");
|
|
17705
17913
|
var import_node_http = require("http");
|
|
17706
17914
|
init_app_settings();
|
|
17915
|
+
init_fetch();
|
|
17707
17916
|
|
|
17708
17917
|
// src/integrations/linear-app.ts
|
|
17709
17918
|
var BAKED_LINEAR_CLIENT_ID = "39a15abc7ea5bea17c47f47f85ff5fd0";
|
|
@@ -17712,7 +17921,7 @@ var BAKED_LINEAR_CLIENT_ID = "39a15abc7ea5bea17c47f47f85ff5fd0";
|
|
|
17712
17921
|
var LINEAR_OAUTH_PORT = 19848;
|
|
17713
17922
|
var LINEAR_OAUTH_REDIRECT = `http://127.0.0.1:${LINEAR_OAUTH_PORT}/callback`;
|
|
17714
17923
|
var LINEAR_TOKEN = "https://api.linear.app/oauth/token";
|
|
17715
|
-
var
|
|
17924
|
+
var REFRESH_SKEW_MS2 = 5 * 6e4;
|
|
17716
17925
|
function linearOAuthCredentials() {
|
|
17717
17926
|
const settings = loadAppSettings();
|
|
17718
17927
|
const clientId = process.env.SIDEBOARD_LINEAR_CLIENT_ID?.trim() || settings.integrations.linearClientId?.trim() || BAKED_LINEAR_CLIENT_ID.trim();
|
|
@@ -17780,7 +17989,7 @@ async function getLinearAuthToken(settings = loadAppSettings()) {
|
|
|
17780
17989
|
const refresh = settings.integrations.linearRefreshToken?.trim() || "";
|
|
17781
17990
|
const expiresAt = settings.integrations.linearTokenExpiresAt ?? 0;
|
|
17782
17991
|
const apiKey = settings.integrations.linearApiKey?.trim() || "";
|
|
17783
|
-
if (access && (!refresh || Date.now() < expiresAt -
|
|
17992
|
+
if (access && (!refresh || Date.now() < expiresAt - REFRESH_SKEW_MS2)) {
|
|
17784
17993
|
return access;
|
|
17785
17994
|
}
|
|
17786
17995
|
if (refresh) {
|
|
@@ -17799,6 +18008,16 @@ async function getLinearAuthToken(settings = loadAppSettings()) {
|
|
|
17799
18008
|
|
|
17800
18009
|
// src/integrations/linear.ts
|
|
17801
18010
|
var LINEAR_GRAPHQL = "https://api.linear.app/graphql";
|
|
18011
|
+
var LIST_ISSUE_FIELDS = `
|
|
18012
|
+
id
|
|
18013
|
+
identifier
|
|
18014
|
+
title
|
|
18015
|
+
url
|
|
18016
|
+
assignee { id name }
|
|
18017
|
+
team { id key }
|
|
18018
|
+
labels(first: 10) { nodes { name } }
|
|
18019
|
+
cycle { name number startsAt endsAt completedAt }
|
|
18020
|
+
`;
|
|
17802
18021
|
var ISSUE_FIELDS = `
|
|
17803
18022
|
id
|
|
17804
18023
|
identifier
|
|
@@ -17808,9 +18027,9 @@ var ISSUE_FIELDS = `
|
|
|
17808
18027
|
priority
|
|
17809
18028
|
state { id name type }
|
|
17810
18029
|
assignee { id name }
|
|
17811
|
-
team { id key name states { nodes { id name type } } }
|
|
17812
|
-
labels { nodes { name } }
|
|
17813
|
-
cycle {
|
|
18030
|
+
team { id key name states(first: 50) { nodes { id name type } } }
|
|
18031
|
+
labels(first: 50) { nodes { name } }
|
|
18032
|
+
cycle { name number startsAt endsAt completedAt }
|
|
17814
18033
|
`;
|
|
17815
18034
|
var ASSIGNED_ISSUES_QUERY = `
|
|
17816
18035
|
query SideboardAssignedIssues($first: Int!) {
|
|
@@ -17822,7 +18041,7 @@ query SideboardAssignedIssues($first: Int!) {
|
|
|
17822
18041
|
orderBy: updatedAt
|
|
17823
18042
|
filter: { state: { type: { nin: ["completed", "canceled"] } } }
|
|
17824
18043
|
) {
|
|
17825
|
-
nodes { ${
|
|
18044
|
+
nodes { ${LIST_ISSUE_FIELDS} }
|
|
17826
18045
|
}
|
|
17827
18046
|
}
|
|
17828
18047
|
}
|
|
@@ -17835,7 +18054,7 @@ query SideboardTeams {
|
|
|
17835
18054
|
id
|
|
17836
18055
|
key
|
|
17837
18056
|
name
|
|
17838
|
-
states { nodes { id name type } }
|
|
18057
|
+
states(first: 50) { nodes { id name type } }
|
|
17839
18058
|
}
|
|
17840
18059
|
}
|
|
17841
18060
|
}
|
|
@@ -19490,25 +19709,31 @@ async function startMcpServer() {
|
|
|
19490
19709
|
}
|
|
19491
19710
|
server.tool(
|
|
19492
19711
|
"present_artifact",
|
|
19493
|
-
"Show
|
|
19712
|
+
"Show a document or live log in Sideboard\u2019s side column. For html/svg/markdown/react, pass the FULL document and do not also fence that same body in chat. For type=log, pass only NEW lines (same artifact_id appends). Prefer type=log for long-running job output \u2014 do not resend HTML. type=react is a single default-export component (JSX/TSX); only react/react-dom imports.",
|
|
19494
19713
|
{
|
|
19495
19714
|
title: import_zod4.z.string().describe("Short title shown in the artifact pane header"),
|
|
19496
|
-
type: import_zod4.z.enum(["html", "svg", "markdown", "react"]).describe(
|
|
19497
|
-
"
|
|
19715
|
+
type: import_zod4.z.enum(["html", "svg", "markdown", "react", "log"]).describe(
|
|
19716
|
+
"html/svg/markdown/react replace the pane. log appends content to the same artifact_id (new lines only)."
|
|
19498
19717
|
),
|
|
19499
19718
|
content: import_zod4.z.string().describe(
|
|
19500
|
-
"
|
|
19719
|
+
"html/svg/markdown/react: full document. log: only the new lines since the last call (empty is ok for a status-only update)."
|
|
19501
19720
|
),
|
|
19502
|
-
artifact_id: import_zod4.z.string().optional().describe("Stable id
|
|
19721
|
+
artifact_id: import_zod4.z.string().optional().describe("Stable id. Required for type=log so later calls append to the same pane."),
|
|
19722
|
+
status: import_zod4.z.enum(["running", "ok", "failed", "idle"]).optional().describe("Log header pill: running (working), ok (done), failed, idle"),
|
|
19723
|
+
phase: import_zod4.z.string().optional().describe("Log subtitle (Signing, Notarizing, \u2026)"),
|
|
19724
|
+
mode: import_zod4.z.enum(["append", "replace"]).optional().describe("log only: append (default) or replace the buffer")
|
|
19503
19725
|
},
|
|
19504
|
-
async ({ title, type, artifact_id }) => {
|
|
19726
|
+
async ({ title, type, artifact_id, status, phase, mode }) => {
|
|
19505
19727
|
const id = artifact_id?.trim() || `artifact_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
19506
19728
|
const payload = {
|
|
19507
19729
|
ok: true,
|
|
19508
19730
|
artifact_id: id,
|
|
19509
19731
|
title,
|
|
19510
19732
|
type,
|
|
19511
|
-
|
|
19733
|
+
status,
|
|
19734
|
+
phase,
|
|
19735
|
+
mode: type === "log" ? mode ?? "append" : void 0,
|
|
19736
|
+
message: type === "log" ? "Log accepted. Same artifact_id appends; send only new lines next time." : "Artifact accepted. Sideboard desktop opens it in the side column beside chat."
|
|
19512
19737
|
};
|
|
19513
19738
|
return { content: [{ type: "text", text: JSON.stringify(payload) }] };
|
|
19514
19739
|
}
|