@sideboard-ai/core 0.1.218 → 0.1.220
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-YABJUV3V.js → agents-6UOWJLXX.js} +4 -4
- package/dist/{agents-NWJ7DFJD.js → agents-DYSZ2JFY.js} +4 -4
- package/dist/{chunk-FSIJGLSV.js → chunk-3Y4FIARC.js} +39 -11
- package/dist/{chunk-JWBPSD7Q.js → chunk-ALDVGAIO.js} +8 -8
- package/dist/{chunk-SRFFIFW6.js → chunk-B73KKJQB.js} +9 -9
- package/dist/{chunk-OPYBLX4V.js → chunk-N2VST3NL.js} +49 -2
- package/dist/chunk-P2BSMNHB.js +179 -0
- package/dist/{chunk-MW57SKKR.js → chunk-P2EAAM3H.js} +49 -2
- package/dist/{chunk-IILG7DPX.js → chunk-QILV2BRW.js} +31 -18
- package/dist/chunk-ROPGQRPU.js +178 -0
- package/dist/{chunk-SVXIJ2IC.js → chunk-UNMMKZ4Q.js} +26 -13
- package/dist/{chunk-XRHTRXZN.js → chunk-YG2X34EF.js} +39 -11
- package/dist/{connected-teams-LX5DLL2I.js → connected-teams-PRHZS6B4.js} +2 -2
- package/dist/{connected-teams-PQETXUWV.js → connected-teams-YOIB42RB.js} +2 -2
- package/dist/{coordinator-prompt-5V7GEPBG.js → coordinator-prompt-JLMQVORO.js} +1 -1
- package/dist/{coordinator-prompt-J4QSNTKE.js → coordinator-prompt-VZ7OSRLD.js} +1 -1
- package/dist/{global-workspace-4TEMLESD.js → global-workspace-3FDAUNN2.js} +1 -1
- package/dist/{global-workspace-XPTFHMKL.js → global-workspace-QPSJEXGR.js} +1 -1
- package/dist/index.cjs +216 -43
- package/dist/index.d.cts +40 -2
- package/dist/index.d.ts +40 -2
- package/dist/index.js +17 -5
- package/dist/mcp/run-stdio.cjs +196 -41
- package/dist/mcp/run-stdio.js +5 -5
- package/dist/oauth-K6CWZEQO.js +23 -0
- package/dist/oauth-S3M7B475.js +21 -0
- package/dist/{orchestrator-SWRTYFHX.js → orchestrator-P4KNHFHG.js} +5 -5
- package/dist/{orchestrator-HKW3VLGX.js → orchestrator-Y5IDLJ7D.js} +5 -5
- package/dist/{workspaces-BCBBMMXB.js → workspaces-76W7IEKR.js} +3 -1
- package/dist/{workspaces-2HQP654Q.js → workspaces-TDBA64II.js} +3 -1
- package/package.json +1 -1
- package/dist/chunk-AN3THU7F.js +0 -103
- package/dist/chunk-Y4MIXGPA.js +0 -104
- package/dist/oauth-6ZQ4Q4XN.js +0 -11
- package/dist/oauth-O7UGLZOY.js +0 -13
|
@@ -44,13 +44,13 @@ import {
|
|
|
44
44
|
resolveLoginCommand,
|
|
45
45
|
resolveQuotaFallbackAgent,
|
|
46
46
|
whichOnPath
|
|
47
|
-
} from "./chunk-
|
|
48
|
-
import "./chunk-
|
|
47
|
+
} from "./chunk-YG2X34EF.js";
|
|
48
|
+
import "./chunk-N2VST3NL.js";
|
|
49
49
|
import "./chunk-KTZESHYH.js";
|
|
50
50
|
import "./chunk-6K64FJDD.js";
|
|
51
51
|
import "./chunk-PO4M4JAJ.js";
|
|
52
|
-
import "./chunk-
|
|
53
|
-
import "./chunk-
|
|
52
|
+
import "./chunk-QILV2BRW.js";
|
|
53
|
+
import "./chunk-ROPGQRPU.js";
|
|
54
54
|
import "./chunk-N7WZ6NIN.js";
|
|
55
55
|
import {
|
|
56
56
|
cursorSdkMessageToEvents,
|
|
@@ -50,10 +50,10 @@ import {
|
|
|
50
50
|
resolveQuotaFallbackAgent,
|
|
51
51
|
turnCostUsdFromCursorUsage,
|
|
52
52
|
whichOnPath
|
|
53
|
-
} from "./chunk-
|
|
54
|
-
import "./chunk-
|
|
55
|
-
import "./chunk-
|
|
56
|
-
import "./chunk-
|
|
53
|
+
} from "./chunk-3Y4FIARC.js";
|
|
54
|
+
import "./chunk-P2EAAM3H.js";
|
|
55
|
+
import "./chunk-UNMMKZ4Q.js";
|
|
56
|
+
import "./chunk-P2BSMNHB.js";
|
|
57
57
|
import "./chunk-VKQGAWHY.js";
|
|
58
58
|
import "./chunk-NFWPDEN4.js";
|
|
59
59
|
import "./chunk-D6JWYJ4P.js";
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
isOrchestratorThread
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-P2EAAM3H.js";
|
|
6
6
|
import {
|
|
7
7
|
applyConnectedTeamToCli,
|
|
8
8
|
brightsyMcpServerName,
|
|
9
9
|
ensureCliTeamTracked,
|
|
10
10
|
ensureConnectedBrightsyTeamTokens
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-UNMMKZ4Q.js";
|
|
12
12
|
import {
|
|
13
13
|
loadBrightsyConfig
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-P2BSMNHB.js";
|
|
15
15
|
import {
|
|
16
16
|
httpFetch
|
|
17
17
|
} from "./chunk-VKQGAWHY.js";
|
|
@@ -1313,6 +1313,7 @@ function teamEnv(team) {
|
|
|
1313
1313
|
return {
|
|
1314
1314
|
BRIGHTSY_API_TOKEN: team.access_token,
|
|
1315
1315
|
...team.refresh_token ? { BRIGHTSY_REFRESH_TOKEN: team.refresh_token } : {},
|
|
1316
|
+
...team.oauth_client_id ? { BRIGHTSY_OAUTH_CLIENT_ID: team.oauth_client_id } : {},
|
|
1316
1317
|
BRIGHTSY_ACCOUNT_ID: team.id,
|
|
1317
1318
|
BRIGHTSY_API_URL: endpoint
|
|
1318
1319
|
};
|
|
@@ -1496,8 +1497,16 @@ function toOpencodeMcpConfigContent(servers, opts) {
|
|
|
1496
1497
|
}
|
|
1497
1498
|
return JSON.stringify({ mcp });
|
|
1498
1499
|
}
|
|
1499
|
-
function
|
|
1500
|
-
|
|
1500
|
+
function stripElectronFromUserMcpEntry(entry) {
|
|
1501
|
+
const next = { ...entry };
|
|
1502
|
+
const env = next.env;
|
|
1503
|
+
if (!env || typeof env !== "object" || Array.isArray(env)) return next;
|
|
1504
|
+
const cleaned = { ...env };
|
|
1505
|
+
delete cleaned.ELECTRON_RUN_AS_NODE;
|
|
1506
|
+
next.env = cleaned;
|
|
1507
|
+
return next;
|
|
1508
|
+
}
|
|
1509
|
+
function writeMcpServersConfig(servers, extraServers) {
|
|
1501
1510
|
const mcpServers = {};
|
|
1502
1511
|
for (const s of servers) {
|
|
1503
1512
|
const env = mcpSpawnEnv(s.env);
|
|
@@ -1507,6 +1516,14 @@ function writeMcpServersConfig(servers) {
|
|
|
1507
1516
|
...env ? { env } : {}
|
|
1508
1517
|
};
|
|
1509
1518
|
}
|
|
1519
|
+
if (extraServers) {
|
|
1520
|
+
for (const [rawName, entry] of Object.entries(extraServers)) {
|
|
1521
|
+
const name = rawName.trim();
|
|
1522
|
+
if (!name || mcpServers[name] || !entry) continue;
|
|
1523
|
+
mcpServers[name] = stripElectronFromUserMcpEntry(entry);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
if (Object.keys(mcpServers).length === 0) return null;
|
|
1510
1527
|
const dir = mkdtempSync(join4(tmpdir(), "sideboard-mcp-"));
|
|
1511
1528
|
const cfgPath = join4(dir, "mcp.json");
|
|
1512
1529
|
writeFileSync2(cfgPath, JSON.stringify({ mcpServers }, null, 2));
|
|
@@ -1593,10 +1610,20 @@ function listUserOpencodeMcpNames(home = homedir3()) {
|
|
|
1593
1610
|
}
|
|
1594
1611
|
return names;
|
|
1595
1612
|
}
|
|
1596
|
-
function
|
|
1613
|
+
function userClaudeMcpConfigObject(home = homedir3()) {
|
|
1597
1614
|
const claudePath = home === homedir3() ? userClaudeMcpConfigPath() : join6(home, ".claude.json");
|
|
1598
|
-
if (!existsSync7(claudePath)) return
|
|
1599
|
-
return
|
|
1615
|
+
if (!existsSync7(claudePath)) return {};
|
|
1616
|
+
return asObject(asObject(readJsonObject(claudePath)).mcpServers);
|
|
1617
|
+
}
|
|
1618
|
+
function listUserClaudeMcpServerEntries(home = homedir3()) {
|
|
1619
|
+
const out = {};
|
|
1620
|
+
for (const [rawName, value] of Object.entries(userClaudeMcpConfigObject(home))) {
|
|
1621
|
+
const name = rawName.trim();
|
|
1622
|
+
if (!name || isInjectedOrchMcpName(name)) continue;
|
|
1623
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
1624
|
+
out[name] = value;
|
|
1625
|
+
}
|
|
1626
|
+
return out;
|
|
1600
1627
|
}
|
|
1601
1628
|
function toCodexDisableUserMcpArgs(names) {
|
|
1602
1629
|
const args = [];
|
|
@@ -2511,7 +2538,7 @@ var claudeAdapter = {
|
|
|
2511
2538
|
);
|
|
2512
2539
|
}
|
|
2513
2540
|
const mode = permissionMode(thread);
|
|
2514
|
-
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-
|
|
2541
|
+
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-QPSJEXGR.js");
|
|
2515
2542
|
const isOrchestrator = isOrchestratorThread2(thread);
|
|
2516
2543
|
const injectedServers = await buildInjectedMcpServers({
|
|
2517
2544
|
includeSideboard: true,
|
|
@@ -2522,6 +2549,7 @@ var claudeAdapter = {
|
|
|
2522
2549
|
});
|
|
2523
2550
|
const injectedBrightsyNames = injectedServers.filter((s) => s.name === "brightsy" || s.name.startsWith("brightsy_")).map((s) => s.name);
|
|
2524
2551
|
const chromeOn = claudeChromeEnabled();
|
|
2552
|
+
const userMcpEntries = isOrchestrator ? {} : listUserClaudeMcpServerEntries();
|
|
2525
2553
|
let allowedTools;
|
|
2526
2554
|
if (isOrchestrator) {
|
|
2527
2555
|
allowedTools = [
|
|
@@ -2532,7 +2560,7 @@ var claudeAdapter = {
|
|
|
2532
2560
|
} else {
|
|
2533
2561
|
allowedTools = [
|
|
2534
2562
|
...BASE_ALLOWED_TOOLS,
|
|
2535
|
-
...mcpAllowToolsFromNames(
|
|
2563
|
+
...mcpAllowToolsFromNames(Object.keys(userMcpEntries)),
|
|
2536
2564
|
...sideboardWorktreeAllowedTools({
|
|
2537
2565
|
github: true,
|
|
2538
2566
|
linear: isLinearConnected(),
|
|
@@ -2557,7 +2585,7 @@ var claudeAdapter = {
|
|
|
2557
2585
|
if (systemPrompt) {
|
|
2558
2586
|
args.push("--append-system-prompt", systemPrompt);
|
|
2559
2587
|
}
|
|
2560
|
-
const mcpConfigPath = writeMcpServersConfig(injectedServers);
|
|
2588
|
+
const mcpConfigPath = writeMcpServersConfig(injectedServers, userMcpEntries);
|
|
2561
2589
|
if (mcpConfigPath) {
|
|
2562
2590
|
args.push("--mcp-config", mcpConfigPath);
|
|
2563
2591
|
args.push("--strict-mcp-config");
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
summarizeTurnStderr,
|
|
43
43
|
toolDescription,
|
|
44
44
|
turnFailChatText
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-3Y4FIARC.js";
|
|
46
46
|
import {
|
|
47
47
|
SLACK_REPLY_FORMATTING,
|
|
48
48
|
addWorkspace,
|
|
@@ -65,7 +65,7 @@ import {
|
|
|
65
65
|
stageAbsolutePathsAsAttachments,
|
|
66
66
|
stageBuffersAsAttachments,
|
|
67
67
|
syncWorkspacesFromThreads
|
|
68
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-P2EAAM3H.js";
|
|
69
69
|
import {
|
|
70
70
|
addPrStackLayer,
|
|
71
71
|
allocateTeamName,
|
|
@@ -418,7 +418,7 @@ async function continueSourceThread(threadId, prompt) {
|
|
|
418
418
|
await continueOnReply(threadId, prompt);
|
|
419
419
|
return;
|
|
420
420
|
}
|
|
421
|
-
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-
|
|
421
|
+
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-P4KNHFHG.js");
|
|
422
422
|
await getOrchestrator2().send(threadId, prompt);
|
|
423
423
|
} catch {
|
|
424
424
|
}
|
|
@@ -895,9 +895,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
895
895
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
896
896
|
);
|
|
897
897
|
}
|
|
898
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
898
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-QPSJEXGR.js");
|
|
899
899
|
if (isGlobalThread2(thread)) {
|
|
900
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
900
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-VZ7OSRLD.js");
|
|
901
901
|
ensureGlobalCoordinatorCwd2(
|
|
902
902
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
903
903
|
);
|
|
@@ -4482,7 +4482,7 @@ async function adoptThread(input) {
|
|
|
4482
4482
|
messages: input.messages ?? []
|
|
4483
4483
|
});
|
|
4484
4484
|
writeThread(thread);
|
|
4485
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
4485
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-TDBA64II.js");
|
|
4486
4486
|
await ensureWorkspace2(repoPath);
|
|
4487
4487
|
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-K7QK4RI5.js");
|
|
4488
4488
|
await ensureWorktreeSideboardIgnored2(input.worktreePath);
|
|
@@ -6957,7 +6957,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
6957
6957
|
${prompt}`;
|
|
6958
6958
|
}
|
|
6959
6959
|
async function defaultDeps() {
|
|
6960
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
6960
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-P4KNHFHG.js");
|
|
6961
6961
|
const orch = getOrchestrator2();
|
|
6962
6962
|
return {
|
|
6963
6963
|
findThread: (id) => findThreadByRef(id),
|
|
@@ -9231,7 +9231,7 @@ var Orchestrator = class {
|
|
|
9231
9231
|
this.enforceHistoryRetention();
|
|
9232
9232
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
9233
9233
|
try {
|
|
9234
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
9234
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-TDBA64II.js");
|
|
9235
9235
|
await ensureWorkspace2(thread.repoPath);
|
|
9236
9236
|
} catch {
|
|
9237
9237
|
}
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
resolveQuotaFallbackAgent,
|
|
25
25
|
stripBrightsyNdjsonNoise,
|
|
26
26
|
toolDescription
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-YG2X34EF.js";
|
|
28
28
|
import {
|
|
29
29
|
SLACK_REPLY_FORMATTING,
|
|
30
30
|
addWorkspace,
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
stageAbsolutePathsAsAttachments,
|
|
48
48
|
stageBuffersAsAttachments,
|
|
49
49
|
syncWorkspacesFromThreads
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-N2VST3NL.js";
|
|
51
51
|
import {
|
|
52
52
|
addPrStackLayer,
|
|
53
53
|
allocateTeamName,
|
|
@@ -482,7 +482,7 @@ async function continueSourceThread(threadId, prompt) {
|
|
|
482
482
|
await continueOnReply(threadId, prompt);
|
|
483
483
|
return;
|
|
484
484
|
}
|
|
485
|
-
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-
|
|
485
|
+
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-Y5IDLJ7D.js");
|
|
486
486
|
await getOrchestrator2().send(threadId, prompt);
|
|
487
487
|
} catch {
|
|
488
488
|
}
|
|
@@ -900,9 +900,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
900
900
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
901
901
|
);
|
|
902
902
|
}
|
|
903
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
903
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-3FDAUNN2.js");
|
|
904
904
|
if (isGlobalThread2(thread)) {
|
|
905
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
905
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-JLMQVORO.js");
|
|
906
906
|
ensureGlobalCoordinatorCwd2(
|
|
907
907
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
908
908
|
);
|
|
@@ -4178,7 +4178,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
4178
4178
|
return readThread(thread.id) ?? thread;
|
|
4179
4179
|
}
|
|
4180
4180
|
async function listLinearIssues(agent, repoPath) {
|
|
4181
|
-
const { getAdapter: getAdapter2 } = await import("./agents-
|
|
4181
|
+
const { getAdapter: getAdapter2 } = await import("./agents-6UOWJLXX.js");
|
|
4182
4182
|
await requireAgent(agent, { requireLinear: true });
|
|
4183
4183
|
const adapter = getAdapter2(agent);
|
|
4184
4184
|
if (!adapter.listLinearIssues) {
|
|
@@ -4651,7 +4651,7 @@ async function adoptThread(input) {
|
|
|
4651
4651
|
messages: input.messages ?? []
|
|
4652
4652
|
});
|
|
4653
4653
|
writeThread(thread);
|
|
4654
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
4654
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-76W7IEKR.js");
|
|
4655
4655
|
await ensureWorkspace2(repoPath);
|
|
4656
4656
|
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-L32WEBX6.js");
|
|
4657
4657
|
await ensureWorktreeSideboardIgnored2(input.worktreePath);
|
|
@@ -7332,7 +7332,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
7332
7332
|
${prompt}`;
|
|
7333
7333
|
}
|
|
7334
7334
|
async function defaultDeps() {
|
|
7335
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
7335
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-Y5IDLJ7D.js");
|
|
7336
7336
|
const orch = getOrchestrator2();
|
|
7337
7337
|
return {
|
|
7338
7338
|
findThread: (id) => findThreadByRef(id),
|
|
@@ -9606,7 +9606,7 @@ var Orchestrator = class {
|
|
|
9606
9606
|
this.enforceHistoryRetention();
|
|
9607
9607
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
9608
9608
|
try {
|
|
9609
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
9609
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-76W7IEKR.js");
|
|
9610
9610
|
await ensureWorkspace2(thread.repoPath);
|
|
9611
9611
|
} catch {
|
|
9612
9612
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
allocateTeamName,
|
|
3
|
+
canonicalizeRepoPath,
|
|
3
4
|
ensureGhPreferOrigin,
|
|
4
5
|
resolveGithubRepoSlug,
|
|
5
6
|
resolveRepoRoot,
|
|
@@ -853,6 +854,29 @@ function isLinkedWorktreeOf(path, mainRepo) {
|
|
|
853
854
|
return false;
|
|
854
855
|
}
|
|
855
856
|
}
|
|
857
|
+
function primaryCheckoutFromLinkedWorktree(path) {
|
|
858
|
+
if (!path) return null;
|
|
859
|
+
const git = join3(path, ".git");
|
|
860
|
+
try {
|
|
861
|
+
if (!existsSync2(git) || statSync2(git).isDirectory()) return null;
|
|
862
|
+
const text = readFileSync3(git, "utf8");
|
|
863
|
+
const match = /^\s*gitdir:\s*(.+)$/m.exec(text);
|
|
864
|
+
if (!match) return null;
|
|
865
|
+
const gitdir = match[1].trim().replace(/\/+$/, "");
|
|
866
|
+
const worktrees = gitdir.lastIndexOf("/.git/worktrees/");
|
|
867
|
+
const root = worktrees > 0 ? gitdir.slice(0, worktrees) : gitdir.endsWith("/.git") ? gitdir.slice(0, -5) : null;
|
|
868
|
+
if (!root) return null;
|
|
869
|
+
return canonicalizeRepoPath(root);
|
|
870
|
+
} catch {
|
|
871
|
+
return null;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
function resolveSyncWorkspacePath(path) {
|
|
875
|
+
if (!path || path === "/") return null;
|
|
876
|
+
const primary = primaryCheckoutFromLinkedWorktree(path);
|
|
877
|
+
if (primary) return primary;
|
|
878
|
+
return canonicalizeRepoPath(path);
|
|
879
|
+
}
|
|
856
880
|
async function addWorkspace(repoPath) {
|
|
857
881
|
const root = await resolveRepoRoot(repoPath);
|
|
858
882
|
if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
|
|
@@ -881,9 +905,24 @@ async function ensureWorkspace(repoPath) {
|
|
|
881
905
|
function syncWorkspacesFromThreads(repoPaths) {
|
|
882
906
|
const current = readAll();
|
|
883
907
|
const removed = readRemoved();
|
|
884
|
-
const byPath = new Map(
|
|
908
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
885
909
|
let dirty = false;
|
|
886
|
-
for (const
|
|
910
|
+
for (const w of current) {
|
|
911
|
+
const resolved = resolveSyncWorkspacePath(w.path) ?? w.path;
|
|
912
|
+
if (resolved !== w.path) dirty = true;
|
|
913
|
+
if (!resolved || resolved === "/" || isGlobalRepoPath(resolved) || removed.has(resolved)) {
|
|
914
|
+
dirty = true;
|
|
915
|
+
continue;
|
|
916
|
+
}
|
|
917
|
+
if (!byPath.has(resolved)) {
|
|
918
|
+
byPath.set(
|
|
919
|
+
resolved,
|
|
920
|
+
resolved === w.path ? w : { ...w, path: resolved, name: basename2(resolved) }
|
|
921
|
+
);
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
for (const raw of repoPaths) {
|
|
925
|
+
const path = resolveSyncWorkspacePath(raw);
|
|
887
926
|
if (!path || path === "/" || isGlobalRepoPath(path) || byPath.has(path) || removed.has(path)) {
|
|
888
927
|
continue;
|
|
889
928
|
}
|
|
@@ -896,6 +935,13 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
896
935
|
byPath.set(path, ws);
|
|
897
936
|
dirty = true;
|
|
898
937
|
}
|
|
938
|
+
for (const [path] of byPath) {
|
|
939
|
+
const mains = [...byPath.keys()];
|
|
940
|
+
if (mains.some((main) => isLinkedWorktreeOf(path, main))) {
|
|
941
|
+
byPath.delete(path);
|
|
942
|
+
dirty = true;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
899
945
|
const next = [...byPath.values()];
|
|
900
946
|
if (dirty) writeAll(next);
|
|
901
947
|
return next.sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -916,6 +962,7 @@ export {
|
|
|
916
962
|
persistPendingFileAttachments,
|
|
917
963
|
attachmentsFromWorktreePaths,
|
|
918
964
|
listWorkspaces,
|
|
965
|
+
primaryCheckoutFromLinkedWorktree,
|
|
919
966
|
addWorkspace,
|
|
920
967
|
removeWorkspace,
|
|
921
968
|
ensureWorkspace,
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
formatFetchError
|
|
5
|
+
} from "./chunk-VKQGAWHY.js";
|
|
6
|
+
|
|
7
|
+
// src/brightsy/config.ts
|
|
8
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
9
|
+
import { homedir } from "os";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
function brightsyConfigPath() {
|
|
12
|
+
const override = process.env.BRIGHTSY_CONFIG?.trim();
|
|
13
|
+
if (override) return override;
|
|
14
|
+
return join(homedir(), ".brightsy", "config.json");
|
|
15
|
+
}
|
|
16
|
+
function loadBrightsyConfig() {
|
|
17
|
+
const path = brightsyConfigPath();
|
|
18
|
+
if (!existsSync(path)) {
|
|
19
|
+
throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
|
|
20
|
+
}
|
|
21
|
+
const raw = JSON.parse(readFileSync(path, "utf8"));
|
|
22
|
+
if (!raw.access_token || !raw.account_id) {
|
|
23
|
+
throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
|
|
24
|
+
}
|
|
25
|
+
return raw;
|
|
26
|
+
}
|
|
27
|
+
function saveBrightsyConfig(cfg) {
|
|
28
|
+
writeFileSync(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
|
|
29
|
+
`, {
|
|
30
|
+
mode: 384
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/brightsy/oauth.ts
|
|
35
|
+
var REFRESH_SKEW_MS = 6e4;
|
|
36
|
+
var BRIGHTSY_OAUTH_CLIENT_ID = "sideboard";
|
|
37
|
+
var BRIGHTSY_OAUTH_REDIRECT = "http://127.0.0.1:19850/callback";
|
|
38
|
+
function defaultFetch(fetchImpl) {
|
|
39
|
+
return fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
40
|
+
}
|
|
41
|
+
function normalizeBrightsyEndpoint(endpoint) {
|
|
42
|
+
return (endpoint || "https://brightsy.ai").replace(/\/$/, "");
|
|
43
|
+
}
|
|
44
|
+
function brightsyAccessTokenNeedsRefresh(expiresAt, now = Date.now()) {
|
|
45
|
+
if (typeof expiresAt !== "number" || !Number.isFinite(expiresAt) || expiresAt <= 0) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
return now >= expiresAt - REFRESH_SKEW_MS;
|
|
49
|
+
}
|
|
50
|
+
function applyGrant(current, grant) {
|
|
51
|
+
return {
|
|
52
|
+
access_token: grant.access_token,
|
|
53
|
+
refresh_token: grant.refresh_token || current.refresh_token,
|
|
54
|
+
expires_at: grant.expires_at ?? current.expires_at
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async function registerBrightsyOAuthClient(opts) {
|
|
58
|
+
const endpoint = normalizeBrightsyEndpoint(opts.endpoint);
|
|
59
|
+
const url = `${endpoint}/oauth/register`;
|
|
60
|
+
const clientId = (opts.clientId || BRIGHTSY_OAUTH_CLIENT_ID).trim();
|
|
61
|
+
const redirectUri = opts.redirectUri || BRIGHTSY_OAUTH_REDIRECT;
|
|
62
|
+
const fetchImpl = defaultFetch(opts.fetchImpl);
|
|
63
|
+
let res;
|
|
64
|
+
try {
|
|
65
|
+
res = await fetchImpl(url, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
headers: { "Content-Type": "application/json" },
|
|
68
|
+
body: JSON.stringify({
|
|
69
|
+
client_id: clientId,
|
|
70
|
+
client_name: "Sideboard",
|
|
71
|
+
description: "Sideboard desktop Brightsy MCP client",
|
|
72
|
+
redirect_uris: [redirectUri],
|
|
73
|
+
scope: "brightsy:api",
|
|
74
|
+
grant_types: ["authorization_code", "refresh_token"],
|
|
75
|
+
response_types: ["code"],
|
|
76
|
+
token_endpoint_auth_method: "none"
|
|
77
|
+
})
|
|
78
|
+
});
|
|
79
|
+
} catch (err) {
|
|
80
|
+
throw new Error(formatFetchError(err, url));
|
|
81
|
+
}
|
|
82
|
+
if (!res.ok) return null;
|
|
83
|
+
const data = await res.json();
|
|
84
|
+
if (!data.client_id?.trim()) return null;
|
|
85
|
+
return {
|
|
86
|
+
client_id: data.client_id.trim(),
|
|
87
|
+
client_secret: data.client_secret?.trim() || void 0
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
async function ensureBrightsyOAuthClientId(opts) {
|
|
91
|
+
const existing = opts.clientId?.trim();
|
|
92
|
+
if (existing) return existing;
|
|
93
|
+
const registered = await registerBrightsyOAuthClient({
|
|
94
|
+
endpoint: opts.endpoint,
|
|
95
|
+
fetchImpl: opts.fetchImpl
|
|
96
|
+
});
|
|
97
|
+
return registered?.client_id || BRIGHTSY_OAUTH_CLIENT_ID;
|
|
98
|
+
}
|
|
99
|
+
async function refreshBrightsyAccessToken(opts) {
|
|
100
|
+
const endpoint = normalizeBrightsyEndpoint(opts.endpoint);
|
|
101
|
+
const url = `${endpoint}/oauth/token`;
|
|
102
|
+
const fetchImpl = defaultFetch(opts.fetchImpl);
|
|
103
|
+
const clientId = opts.clientId?.trim() || BRIGHTSY_OAUTH_CLIENT_ID;
|
|
104
|
+
let res;
|
|
105
|
+
try {
|
|
106
|
+
res = await fetchImpl(url, {
|
|
107
|
+
method: "POST",
|
|
108
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
109
|
+
body: new URLSearchParams({
|
|
110
|
+
grant_type: "refresh_token",
|
|
111
|
+
refresh_token: opts.refreshToken,
|
|
112
|
+
client_id: clientId
|
|
113
|
+
})
|
|
114
|
+
});
|
|
115
|
+
} catch (err) {
|
|
116
|
+
throw new Error(formatFetchError(err, url));
|
|
117
|
+
}
|
|
118
|
+
if (!res.ok) return null;
|
|
119
|
+
const data = await res.json();
|
|
120
|
+
if (!data.access_token) return null;
|
|
121
|
+
return {
|
|
122
|
+
access_token: data.access_token,
|
|
123
|
+
refresh_token: data.refresh_token,
|
|
124
|
+
expires_at: data.expires_in ? Date.now() + data.expires_in * 1e3 : void 0
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
var refreshInFlight = null;
|
|
128
|
+
async function ensureBrightsyLocalConfigFreshOnce(opts) {
|
|
129
|
+
let cfg;
|
|
130
|
+
try {
|
|
131
|
+
cfg = loadBrightsyConfig();
|
|
132
|
+
} catch {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
const refreshToken = cfg.refresh_token;
|
|
136
|
+
if (!refreshToken || !brightsyAccessTokenNeedsRefresh(cfg.expires_at)) {
|
|
137
|
+
return cfg;
|
|
138
|
+
}
|
|
139
|
+
const endpoint = normalizeBrightsyEndpoint(cfg.endpoint);
|
|
140
|
+
const clientId = await ensureBrightsyOAuthClientId({
|
|
141
|
+
endpoint,
|
|
142
|
+
clientId: cfg.oauth_client_id,
|
|
143
|
+
fetchImpl: opts?.fetchImpl
|
|
144
|
+
});
|
|
145
|
+
if (clientId !== cfg.oauth_client_id) {
|
|
146
|
+
cfg = { ...cfg, oauth_client_id: clientId };
|
|
147
|
+
saveBrightsyConfig(cfg);
|
|
148
|
+
}
|
|
149
|
+
const grant = await refreshBrightsyAccessToken({
|
|
150
|
+
endpoint,
|
|
151
|
+
refreshToken,
|
|
152
|
+
clientId,
|
|
153
|
+
fetchImpl: opts?.fetchImpl
|
|
154
|
+
});
|
|
155
|
+
if (!grant) return cfg;
|
|
156
|
+
const next = { ...cfg, ...applyGrant(cfg, grant), oauth_client_id: clientId };
|
|
157
|
+
saveBrightsyConfig(next);
|
|
158
|
+
return next;
|
|
159
|
+
}
|
|
160
|
+
async function ensureBrightsyLocalConfigFresh(opts) {
|
|
161
|
+
if (refreshInFlight) return refreshInFlight;
|
|
162
|
+
refreshInFlight = ensureBrightsyLocalConfigFreshOnce(opts).finally(() => {
|
|
163
|
+
refreshInFlight = null;
|
|
164
|
+
});
|
|
165
|
+
return refreshInFlight;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export {
|
|
169
|
+
loadBrightsyConfig,
|
|
170
|
+
saveBrightsyConfig,
|
|
171
|
+
BRIGHTSY_OAUTH_CLIENT_ID,
|
|
172
|
+
BRIGHTSY_OAUTH_REDIRECT,
|
|
173
|
+
normalizeBrightsyEndpoint,
|
|
174
|
+
brightsyAccessTokenNeedsRefresh,
|
|
175
|
+
registerBrightsyOAuthClient,
|
|
176
|
+
ensureBrightsyOAuthClientId,
|
|
177
|
+
refreshBrightsyAccessToken,
|
|
178
|
+
ensureBrightsyLocalConfigFresh
|
|
179
|
+
};
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
allocateTeamName,
|
|
5
|
+
canonicalizeRepoPath,
|
|
5
6
|
ensureGhPreferOrigin,
|
|
6
7
|
resolveGithubRepoSlug,
|
|
7
8
|
resolveRepoRoot,
|
|
@@ -808,6 +809,29 @@ function isLinkedWorktreeOf(path, mainRepo) {
|
|
|
808
809
|
return false;
|
|
809
810
|
}
|
|
810
811
|
}
|
|
812
|
+
function primaryCheckoutFromLinkedWorktree(path) {
|
|
813
|
+
if (!path) return null;
|
|
814
|
+
const git = join3(path, ".git");
|
|
815
|
+
try {
|
|
816
|
+
if (!existsSync2(git) || statSync2(git).isDirectory()) return null;
|
|
817
|
+
const text = readFileSync3(git, "utf8");
|
|
818
|
+
const match = /^\s*gitdir:\s*(.+)$/m.exec(text);
|
|
819
|
+
if (!match) return null;
|
|
820
|
+
const gitdir = match[1].trim().replace(/\/+$/, "");
|
|
821
|
+
const worktrees = gitdir.lastIndexOf("/.git/worktrees/");
|
|
822
|
+
const root = worktrees > 0 ? gitdir.slice(0, worktrees) : gitdir.endsWith("/.git") ? gitdir.slice(0, -5) : null;
|
|
823
|
+
if (!root) return null;
|
|
824
|
+
return canonicalizeRepoPath(root);
|
|
825
|
+
} catch {
|
|
826
|
+
return null;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
function resolveSyncWorkspacePath(path) {
|
|
830
|
+
if (!path || path === "/") return null;
|
|
831
|
+
const primary = primaryCheckoutFromLinkedWorktree(path);
|
|
832
|
+
if (primary) return primary;
|
|
833
|
+
return canonicalizeRepoPath(path);
|
|
834
|
+
}
|
|
811
835
|
async function addWorkspace(repoPath) {
|
|
812
836
|
const root = await resolveRepoRoot(repoPath);
|
|
813
837
|
if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
|
|
@@ -836,9 +860,24 @@ async function ensureWorkspace(repoPath) {
|
|
|
836
860
|
function syncWorkspacesFromThreads(repoPaths) {
|
|
837
861
|
const current = readAll();
|
|
838
862
|
const removed = readRemoved();
|
|
839
|
-
const byPath = new Map(
|
|
863
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
840
864
|
let dirty = false;
|
|
841
|
-
for (const
|
|
865
|
+
for (const w of current) {
|
|
866
|
+
const resolved = resolveSyncWorkspacePath(w.path) ?? w.path;
|
|
867
|
+
if (resolved !== w.path) dirty = true;
|
|
868
|
+
if (!resolved || resolved === "/" || isGlobalRepoPath(resolved) || removed.has(resolved)) {
|
|
869
|
+
dirty = true;
|
|
870
|
+
continue;
|
|
871
|
+
}
|
|
872
|
+
if (!byPath.has(resolved)) {
|
|
873
|
+
byPath.set(
|
|
874
|
+
resolved,
|
|
875
|
+
resolved === w.path ? w : { ...w, path: resolved, name: basename2(resolved) }
|
|
876
|
+
);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
for (const raw of repoPaths) {
|
|
880
|
+
const path = resolveSyncWorkspacePath(raw);
|
|
842
881
|
if (!path || path === "/" || isGlobalRepoPath(path) || byPath.has(path) || removed.has(path)) {
|
|
843
882
|
continue;
|
|
844
883
|
}
|
|
@@ -851,6 +890,13 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
851
890
|
byPath.set(path, ws);
|
|
852
891
|
dirty = true;
|
|
853
892
|
}
|
|
893
|
+
for (const [path] of byPath) {
|
|
894
|
+
const mains = [...byPath.keys()];
|
|
895
|
+
if (mains.some((main) => isLinkedWorktreeOf(path, main))) {
|
|
896
|
+
byPath.delete(path);
|
|
897
|
+
dirty = true;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
854
900
|
const next = [...byPath.values()];
|
|
855
901
|
if (dirty) writeAll(next);
|
|
856
902
|
return next.sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -862,6 +908,7 @@ export {
|
|
|
862
908
|
persistPendingFileAttachments,
|
|
863
909
|
attachmentsFromWorktreePaths,
|
|
864
910
|
listWorkspaces,
|
|
911
|
+
primaryCheckoutFromLinkedWorktree,
|
|
865
912
|
addWorkspace,
|
|
866
913
|
removeWorkspace,
|
|
867
914
|
ensureWorkspace,
|