@sideboard-ai/core 0.1.98 → 0.1.100
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.cjs +69 -24
- package/dist/agents/cursor-runner.js +48 -3
- package/dist/{agents-ESJKIQQA.js → agents-CLP5BG4O.js} +3 -3
- package/dist/{agents-3MWWWSMF.js → agents-OXZDMPSE.js} +4 -4
- package/dist/{chunk-FYS2BULQ.js → chunk-EQPQTLW6.js} +209 -59
- package/dist/{chunk-FO67IJTY.js → chunk-GR4JKWR4.js} +1 -1
- package/dist/{chunk-GXSYI7FH.js → chunk-HUKCGRAT.js} +209 -59
- package/dist/{chunk-XUWDLRAE.js → chunk-HYKZEP5A.js} +2 -2
- package/dist/{chunk-XH2GS2LO.js → chunk-IFHKPZHA.js} +2 -2
- package/dist/{chunk-UYQYK2RY.js → chunk-MHJV4WS3.js} +1 -1
- package/dist/{chunk-OANJQTVG.js → chunk-MRBKGFTL.js} +1 -1
- package/dist/{chunk-MBP3XG57.js → chunk-OXC3MEFI.js} +3 -3
- package/dist/{chunk-HI2OTFFR.js → chunk-WQTTUC4N.js} +1 -1
- package/dist/{coordinator-prompt-AKEY4WSO.js → coordinator-prompt-HHRKQWCX.js} +1 -1
- package/dist/{coordinator-prompt-OQOOD5ET.js → coordinator-prompt-OOBSQCWQ.js} +1 -1
- package/dist/{global-workspace-RSQXRLT7.js → global-workspace-KYEBFWKB.js} +2 -2
- package/dist/{global-workspace-WMF3BJP5.js → global-workspace-YZWYHLQY.js} +2 -2
- package/dist/index.cjs +662 -440
- package/dist/index.d.cts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +194 -128
- package/dist/mcp/run-stdio.cjs +424 -227
- package/dist/mcp/run-stdio.js +141 -92
- package/dist/{workspaces-MZVQHRSJ.js → workspaces-ENVUDK6C.js} +3 -3
- package/dist/{workspaces-4ZY4QPWQ.js → workspaces-NNPD7QVV.js} +3 -3
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
listWorkspaces,
|
|
5
5
|
removeWorkspace,
|
|
6
6
|
syncWorkspacesFromThreads
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-MHJV4WS3.js";
|
|
8
8
|
import {
|
|
9
9
|
BRIGHTSY_MCP_ALLOWED_TOOLS,
|
|
10
10
|
CLAUDE_MODEL_CATALOG,
|
|
@@ -65,7 +65,7 @@ import {
|
|
|
65
65
|
threadRequestsBrightsyMcp,
|
|
66
66
|
totalTokens,
|
|
67
67
|
writeInjectedMcpConfig
|
|
68
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-OXC3MEFI.js";
|
|
69
69
|
import {
|
|
70
70
|
CLOUD_COORDINATOR_BUSY_REPLY,
|
|
71
71
|
CLOUD_COORDINATOR_STOPPED_REPLY,
|
|
@@ -93,7 +93,7 @@ import {
|
|
|
93
93
|
parseForceStopMessage,
|
|
94
94
|
slackCoordinatorSourceRef,
|
|
95
95
|
takenTeamSlugsForOrchestration
|
|
96
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-GR4JKWR4.js";
|
|
97
97
|
import {
|
|
98
98
|
COORDINATOR_TOOL_PLAYBOOK,
|
|
99
99
|
SLACK_REPLY_FORMATTING,
|
|
@@ -102,7 +102,7 @@ import {
|
|
|
102
102
|
enrichWorkspacesWithGithub,
|
|
103
103
|
ensureGlobalCoordinatorCwd,
|
|
104
104
|
formatWorkspaceInventory
|
|
105
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-HYKZEP5A.js";
|
|
106
106
|
import {
|
|
107
107
|
brightsyConfigPath,
|
|
108
108
|
brightsyMcpServerName,
|
|
@@ -133,13 +133,14 @@ import {
|
|
|
133
133
|
cursorSdkMessageToEvents,
|
|
134
134
|
fallbackTurnFailDetail,
|
|
135
135
|
formatTurnExitError,
|
|
136
|
-
humanizeAgentFailDetail,
|
|
137
136
|
looksLikeAgentFailureMessage,
|
|
138
137
|
looksLikeInvalidAgentSession,
|
|
139
138
|
parseCursorRunnerLine,
|
|
140
139
|
pushTurnStderr,
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
shouldRetryFailedAgentTurn,
|
|
141
|
+
summarizeTurnStderr,
|
|
142
|
+
turnFailChatText
|
|
143
|
+
} from "./chunk-HUKCGRAT.js";
|
|
143
144
|
import {
|
|
144
145
|
caffeinateHoldPath,
|
|
145
146
|
getCaffeinateHold,
|
|
@@ -367,6 +368,52 @@ import {
|
|
|
367
368
|
withExportedPath
|
|
368
369
|
} from "./chunk-LGXBYZZA.js";
|
|
369
370
|
|
|
371
|
+
// src/store/desktop-host.ts
|
|
372
|
+
import { readFileSync, unlinkSync, writeFileSync } from "fs";
|
|
373
|
+
import { join } from "path";
|
|
374
|
+
function desktopHostPidPath() {
|
|
375
|
+
return join(appDataDir(), "desktop-host.pid");
|
|
376
|
+
}
|
|
377
|
+
function claimDesktopHost(pid = process.pid) {
|
|
378
|
+
writeFileSync(desktopHostPidPath(), `${pid}
|
|
379
|
+
`, "utf8");
|
|
380
|
+
}
|
|
381
|
+
function releaseDesktopHost(pid = process.pid) {
|
|
382
|
+
if (readDesktopHostPid() !== pid) return;
|
|
383
|
+
try {
|
|
384
|
+
unlinkSync(desktopHostPidPath());
|
|
385
|
+
} catch {
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
function readDesktopHostPid() {
|
|
389
|
+
try {
|
|
390
|
+
const pid = Number.parseInt(readFileSync(desktopHostPidPath(), "utf8").trim(), 10);
|
|
391
|
+
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
392
|
+
return pid;
|
|
393
|
+
} catch {
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function pidAlive(pid) {
|
|
398
|
+
try {
|
|
399
|
+
process.kill(pid, 0);
|
|
400
|
+
return true;
|
|
401
|
+
} catch {
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
function isDesktopHostAlive() {
|
|
406
|
+
const pid = readDesktopHostPid();
|
|
407
|
+
return pid != null && pidAlive(pid);
|
|
408
|
+
}
|
|
409
|
+
function isThisProcessDesktopHost() {
|
|
410
|
+
return readDesktopHostPid() === process.pid && pidAlive(process.pid);
|
|
411
|
+
}
|
|
412
|
+
function thisProcessShouldDrainAgentQueues() {
|
|
413
|
+
if (isThisProcessDesktopHost()) return true;
|
|
414
|
+
return !isDesktopHostAlive();
|
|
415
|
+
}
|
|
416
|
+
|
|
370
417
|
// src/git/agent-git-actions.ts
|
|
371
418
|
var AGENT_GIT_ACTIONS = [
|
|
372
419
|
"commit-push",
|
|
@@ -1339,9 +1386,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
1339
1386
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
1340
1387
|
);
|
|
1341
1388
|
}
|
|
1342
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
1389
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-KYEBFWKB.js");
|
|
1343
1390
|
if (isGlobalThread2(thread)) {
|
|
1344
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
1391
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-HHRKQWCX.js");
|
|
1345
1392
|
ensureGlobalCoordinatorCwd2(
|
|
1346
1393
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
1347
1394
|
);
|
|
@@ -1452,8 +1499,8 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
1452
1499
|
}
|
|
1453
1500
|
|
|
1454
1501
|
// src/agents/instructions.ts
|
|
1455
|
-
import { existsSync, readFileSync, statSync } from "fs";
|
|
1456
|
-
import { join } from "path";
|
|
1502
|
+
import { existsSync, readFileSync as readFileSync2, statSync } from "fs";
|
|
1503
|
+
import { join as join2 } from "path";
|
|
1457
1504
|
function normPath(p) {
|
|
1458
1505
|
return p.replace(/\/+$/, "");
|
|
1459
1506
|
}
|
|
@@ -1622,11 +1669,11 @@ function loadAgentInstructions(worktreePath, agent) {
|
|
|
1622
1669
|
const out = [];
|
|
1623
1670
|
for (const rel of candidates) {
|
|
1624
1671
|
if (seenPaths.has(rel)) continue;
|
|
1625
|
-
const abs =
|
|
1672
|
+
const abs = join2(worktreePath, rel);
|
|
1626
1673
|
if (!existsSync(abs)) continue;
|
|
1627
1674
|
try {
|
|
1628
1675
|
if (!statSync(abs).isFile()) continue;
|
|
1629
|
-
let content =
|
|
1676
|
+
let content = readFileSync2(abs, "utf8");
|
|
1630
1677
|
if (!content.trim()) continue;
|
|
1631
1678
|
if (content.length > MAX_CHARS_PER_FILE) {
|
|
1632
1679
|
content = `${content.slice(0, MAX_CHARS_PER_FILE)}
|
|
@@ -1706,10 +1753,10 @@ import {
|
|
|
1706
1753
|
existsSync as existsSync2,
|
|
1707
1754
|
mkdirSync,
|
|
1708
1755
|
readdirSync,
|
|
1709
|
-
readFileSync as
|
|
1756
|
+
readFileSync as readFileSync3
|
|
1710
1757
|
} from "fs";
|
|
1711
1758
|
import { createServer as createServer2 } from "net";
|
|
1712
|
-
import { basename, dirname, join as
|
|
1759
|
+
import { basename, dirname, join as join3 } from "path";
|
|
1713
1760
|
import { execa as execa2 } from "execa";
|
|
1714
1761
|
import { createInterface as createInterface2 } from "readline";
|
|
1715
1762
|
var PORT_RANGE_SIZE = 10;
|
|
@@ -1718,9 +1765,9 @@ function matchSimpleGlob(pattern, name) {
|
|
|
1718
1765
|
return new RegExp(`^${escaped}$`).test(name);
|
|
1719
1766
|
}
|
|
1720
1767
|
function readWorktreeInclude(repoPath) {
|
|
1721
|
-
const path2 =
|
|
1768
|
+
const path2 = join3(repoPath, ".worktreeinclude");
|
|
1722
1769
|
if (!existsSync2(path2)) return [];
|
|
1723
|
-
return
|
|
1770
|
+
return readFileSync3(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
1724
1771
|
}
|
|
1725
1772
|
function resolveFilesToCopy(repoPath) {
|
|
1726
1773
|
const fromInclude = readWorktreeInclude(repoPath);
|
|
@@ -1759,9 +1806,9 @@ function copyConfiguredFiles(repoPath, worktreePath) {
|
|
|
1759
1806
|
const patterns = resolveFilesToCopy(repoPath);
|
|
1760
1807
|
const copied = [];
|
|
1761
1808
|
for (const rel of patterns) {
|
|
1762
|
-
const src =
|
|
1809
|
+
const src = join3(repoPath, rel);
|
|
1763
1810
|
if (!existsSync2(src)) continue;
|
|
1764
|
-
const dest =
|
|
1811
|
+
const dest = join3(worktreePath, rel);
|
|
1765
1812
|
mkdirSync(dirname(dest), { recursive: true });
|
|
1766
1813
|
copyFileSync(src, dest);
|
|
1767
1814
|
copied.push(rel);
|
|
@@ -2056,8 +2103,8 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
|
|
|
2056
2103
|
}
|
|
2057
2104
|
|
|
2058
2105
|
// src/diff/diff.ts
|
|
2059
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as
|
|
2060
|
-
import { dirname as dirname2, join as
|
|
2106
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync4, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
2107
|
+
import { dirname as dirname2, join as join4 } from "path";
|
|
2061
2108
|
async function inspectGitWorktree(worktreePath) {
|
|
2062
2109
|
if (!worktreePath || !existsSync3(worktreePath)) return "missing_worktree";
|
|
2063
2110
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
@@ -2203,11 +2250,11 @@ new file mode 100644
|
|
|
2203
2250
|
};
|
|
2204
2251
|
}
|
|
2205
2252
|
async function untrackedPatch(worktreePath, path2, maxHunk) {
|
|
2206
|
-
const abs =
|
|
2253
|
+
const abs = join4(worktreePath, path2);
|
|
2207
2254
|
try {
|
|
2208
2255
|
const st = statSync2(abs);
|
|
2209
2256
|
if (st.isFile() && st.size > maxHunk) {
|
|
2210
|
-
const buf =
|
|
2257
|
+
const buf = readFileSync4(abs).subarray(0, maxHunk);
|
|
2211
2258
|
return syntheticAddPatch(path2, buf.toString("utf8"), maxHunk);
|
|
2212
2259
|
}
|
|
2213
2260
|
} catch {
|
|
@@ -2708,7 +2755,7 @@ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
|
|
|
2708
2755
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
2709
2756
|
assertSafeRelativePath(relativePath);
|
|
2710
2757
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
2711
|
-
const abs =
|
|
2758
|
+
const abs = join4(worktreePath, relativePath);
|
|
2712
2759
|
const st = statSync2(abs);
|
|
2713
2760
|
if (!st.isFile()) {
|
|
2714
2761
|
throw new Error(`Not a file: ${relativePath}`);
|
|
@@ -2718,7 +2765,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
2718
2765
|
`File too large to upload (${st.size} bytes; max ${maxBytes})`
|
|
2719
2766
|
);
|
|
2720
2767
|
}
|
|
2721
|
-
const buf =
|
|
2768
|
+
const buf = readFileSync4(abs);
|
|
2722
2769
|
return {
|
|
2723
2770
|
path: relativePath,
|
|
2724
2771
|
contentBase64: buf.toString("base64"),
|
|
@@ -2728,12 +2775,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
2728
2775
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
2729
2776
|
assertSafeRelativePath(relativePath);
|
|
2730
2777
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
2731
|
-
const abs =
|
|
2778
|
+
const abs = join4(worktreePath, relativePath);
|
|
2732
2779
|
const st = statSync2(abs);
|
|
2733
2780
|
if (!st.isFile()) {
|
|
2734
2781
|
throw new Error(`Not a file: ${relativePath}`);
|
|
2735
2782
|
}
|
|
2736
|
-
const buf =
|
|
2783
|
+
const buf = readFileSync4(abs);
|
|
2737
2784
|
if (isImageRelativePath(relativePath)) {
|
|
2738
2785
|
const maxImageBytes = Math.max(maxBytes, 15e6);
|
|
2739
2786
|
const truncated2 = buf.length > maxImageBytes;
|
|
@@ -2776,9 +2823,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
2776
2823
|
}
|
|
2777
2824
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
2778
2825
|
assertSafeRelativePath(relativePath);
|
|
2779
|
-
const abs =
|
|
2826
|
+
const abs = join4(worktreePath, relativePath);
|
|
2780
2827
|
mkdirSync2(dirname2(abs), { recursive: true });
|
|
2781
|
-
|
|
2828
|
+
writeFileSync2(abs, content, "utf8");
|
|
2782
2829
|
return { path: relativePath };
|
|
2783
2830
|
}
|
|
2784
2831
|
async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
@@ -2797,9 +2844,9 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
|
2797
2844
|
}
|
|
2798
2845
|
|
|
2799
2846
|
// src/skills/discover.ts
|
|
2800
|
-
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as
|
|
2847
|
+
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
|
|
2801
2848
|
import { homedir } from "os";
|
|
2802
|
-
import { join as
|
|
2849
|
+
import { join as join5 } from "path";
|
|
2803
2850
|
function toCommand(name) {
|
|
2804
2851
|
return name.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
2805
2852
|
}
|
|
@@ -2831,7 +2878,7 @@ function parseFrontmatter(content) {
|
|
|
2831
2878
|
}
|
|
2832
2879
|
function readSkill(skillMd, source) {
|
|
2833
2880
|
try {
|
|
2834
|
-
const content =
|
|
2881
|
+
const content = readFileSync5(skillMd, "utf8");
|
|
2835
2882
|
const { name: fmName, description } = parseFrontmatter(content);
|
|
2836
2883
|
const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
|
|
2837
2884
|
const name = fmName || dirName;
|
|
@@ -2859,7 +2906,7 @@ function scanSkillsDir(dir, source, out) {
|
|
|
2859
2906
|
}
|
|
2860
2907
|
for (const entry of entries) {
|
|
2861
2908
|
if (entry.startsWith(".")) continue;
|
|
2862
|
-
const skillMd =
|
|
2909
|
+
const skillMd = join5(dir, entry, "SKILL.md");
|
|
2863
2910
|
if (!existsSync4(skillMd)) continue;
|
|
2864
2911
|
try {
|
|
2865
2912
|
if (!statSync3(skillMd).isFile()) continue;
|
|
@@ -2881,12 +2928,12 @@ function scanClaudePluginSkills(pluginsRoot, out) {
|
|
|
2881
2928
|
return;
|
|
2882
2929
|
}
|
|
2883
2930
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
2884
|
-
const skill = readSkill(
|
|
2931
|
+
const skill = readSkill(join5(dir, "SKILL.md"), "cli");
|
|
2885
2932
|
if (skill) out.push(skill);
|
|
2886
2933
|
}
|
|
2887
2934
|
for (const entry of entries) {
|
|
2888
2935
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
2889
|
-
const full =
|
|
2936
|
+
const full = join5(dir, entry);
|
|
2890
2937
|
try {
|
|
2891
2938
|
if (!statSync3(full).isDirectory()) continue;
|
|
2892
2939
|
} catch {
|
|
@@ -2906,17 +2953,17 @@ function discoverSkills(worktreePath) {
|
|
|
2906
2953
|
const home = homedir();
|
|
2907
2954
|
const collected = [];
|
|
2908
2955
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
2909
|
-
scanSkillsDir(
|
|
2956
|
+
scanSkillsDir(join5(worktreePath, rel), "workspace", collected);
|
|
2910
2957
|
}
|
|
2911
2958
|
for (const abs of [
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2959
|
+
join5(home, ".claude/skills"),
|
|
2960
|
+
join5(home, ".cursor/skills"),
|
|
2961
|
+
join5(home, ".sideboard/skills"),
|
|
2962
|
+
join5(home, ".brightsy/skills")
|
|
2916
2963
|
]) {
|
|
2917
2964
|
scanSkillsDir(abs, "user", collected);
|
|
2918
2965
|
}
|
|
2919
|
-
scanClaudePluginSkills(
|
|
2966
|
+
scanClaudePluginSkills(join5(home, ".claude/plugins"), collected);
|
|
2920
2967
|
const rank = { workspace: 0, user: 1, cli: 2 };
|
|
2921
2968
|
const byCommand = /* @__PURE__ */ new Map();
|
|
2922
2969
|
for (const skill of collected) {
|
|
@@ -2928,7 +2975,7 @@ function discoverSkills(worktreePath) {
|
|
|
2928
2975
|
return [...byCommand.values()].sort((a, b) => a.command.localeCompare(b.command));
|
|
2929
2976
|
}
|
|
2930
2977
|
function readSkillBody(skillPath, maxChars = 12e3) {
|
|
2931
|
-
const raw =
|
|
2978
|
+
const raw = readFileSync5(skillPath, "utf8");
|
|
2932
2979
|
if (raw.startsWith("---")) {
|
|
2933
2980
|
const end = raw.indexOf("\n---", 3);
|
|
2934
2981
|
if (end >= 0) {
|
|
@@ -3069,8 +3116,8 @@ function buildDiffCommentAttachment(input) {
|
|
|
3069
3116
|
}
|
|
3070
3117
|
|
|
3071
3118
|
// src/composer/stage-files.ts
|
|
3072
|
-
import { copyFileSync as copyFileSync2, existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as
|
|
3073
|
-
import { basename as basename2, extname, join as
|
|
3119
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync6, statSync as statSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
3120
|
+
import { basename as basename2, extname, join as join6 } from "path";
|
|
3074
3121
|
import { randomUUID } from "crypto";
|
|
3075
3122
|
var IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
|
|
3076
3123
|
"png",
|
|
@@ -3105,22 +3152,22 @@ function imageMimeType(filePath) {
|
|
|
3105
3152
|
return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
|
|
3106
3153
|
}
|
|
3107
3154
|
function ensureAttachmentsDir(worktreePath) {
|
|
3108
|
-
const dir =
|
|
3155
|
+
const dir = join6(worktreePath, ATTACHMENTS_DIR);
|
|
3109
3156
|
mkdirSync3(dir, { recursive: true });
|
|
3110
|
-
const gi =
|
|
3157
|
+
const gi = join6(dir, ".gitignore");
|
|
3111
3158
|
if (!existsSync5(gi)) {
|
|
3112
|
-
|
|
3159
|
+
writeFileSync3(gi, attachmentsGitignoreBody(), "utf8");
|
|
3113
3160
|
}
|
|
3114
3161
|
return dir;
|
|
3115
3162
|
}
|
|
3116
3163
|
function uniqueAttachmentName(dir, originalName) {
|
|
3117
3164
|
const safe = originalName.replace(/[/\\]/g, "_") || "file";
|
|
3118
|
-
if (!existsSync5(
|
|
3165
|
+
if (!existsSync5(join6(dir, safe))) return safe;
|
|
3119
3166
|
const ext = extname(safe);
|
|
3120
3167
|
const stem = ext ? safe.slice(0, -ext.length) : safe;
|
|
3121
3168
|
for (let i = 1; i < 1e4; i++) {
|
|
3122
3169
|
const candidate = `${stem}-${i}${ext}`;
|
|
3123
|
-
if (!existsSync5(
|
|
3170
|
+
if (!existsSync5(join6(dir, candidate))) return candidate;
|
|
3124
3171
|
}
|
|
3125
3172
|
return `${stem}-${randomUUID()}${ext}`;
|
|
3126
3173
|
}
|
|
@@ -3183,7 +3230,7 @@ function attachmentFromAbsolutePath(absolutePath) {
|
|
|
3183
3230
|
content: `(not a file: ${absolutePath})`
|
|
3184
3231
|
};
|
|
3185
3232
|
}
|
|
3186
|
-
const buf =
|
|
3233
|
+
const buf = readFileSync6(absolutePath);
|
|
3187
3234
|
return attachmentFromBuffer(name, buf, { sourceLabel: absolutePath });
|
|
3188
3235
|
} catch (err) {
|
|
3189
3236
|
return {
|
|
@@ -3204,10 +3251,10 @@ function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
|
3204
3251
|
const st = statSync4(abs);
|
|
3205
3252
|
if (!st.isFile()) continue;
|
|
3206
3253
|
const name = uniqueAttachmentName(dir, originalName);
|
|
3207
|
-
const destAbs =
|
|
3254
|
+
const destAbs = join6(dir, name);
|
|
3208
3255
|
copyFileSync2(abs, destAbs);
|
|
3209
3256
|
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
3210
|
-
const buf =
|
|
3257
|
+
const buf = readFileSync6(destAbs);
|
|
3211
3258
|
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
3212
3259
|
} catch (err) {
|
|
3213
3260
|
out.push({
|
|
@@ -3229,8 +3276,8 @@ function stageBuffersAsAttachments(worktreePath, buffers) {
|
|
|
3229
3276
|
try {
|
|
3230
3277
|
const buf = Buffer.from(item.dataBase64, "base64");
|
|
3231
3278
|
const name = uniqueAttachmentName(dir, originalName);
|
|
3232
|
-
const destAbs =
|
|
3233
|
-
|
|
3279
|
+
const destAbs = join6(dir, name);
|
|
3280
|
+
writeFileSync3(destAbs, buf);
|
|
3234
3281
|
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
3235
3282
|
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
3236
3283
|
} catch (err) {
|
|
@@ -3274,10 +3321,10 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
|
3274
3321
|
}
|
|
3275
3322
|
const name = basename2(rel);
|
|
3276
3323
|
try {
|
|
3277
|
-
const abs =
|
|
3324
|
+
const abs = join6(worktreePath, rel);
|
|
3278
3325
|
const st = statSync4(abs);
|
|
3279
3326
|
if (!st.isFile()) continue;
|
|
3280
|
-
const buf =
|
|
3327
|
+
const buf = readFileSync6(abs);
|
|
3281
3328
|
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
3282
3329
|
} catch (err) {
|
|
3283
3330
|
out.push({
|
|
@@ -3834,7 +3881,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3834
3881
|
return readThread(thread.id) ?? thread;
|
|
3835
3882
|
}
|
|
3836
3883
|
async function listLinearIssues(agent, repoPath) {
|
|
3837
|
-
const { getAdapter: getAdapter2 } = await import("./agents-
|
|
3884
|
+
const { getAdapter: getAdapter2 } = await import("./agents-OXZDMPSE.js");
|
|
3838
3885
|
await requireAgent(agent, { requireLinear: true });
|
|
3839
3886
|
const adapter = getAdapter2(agent);
|
|
3840
3887
|
if (!adapter.listLinearIssues) {
|
|
@@ -4300,20 +4347,20 @@ import {
|
|
|
4300
4347
|
existsSync as existsSync8,
|
|
4301
4348
|
mkdtempSync,
|
|
4302
4349
|
readdirSync as readdirSync3,
|
|
4303
|
-
readFileSync as
|
|
4350
|
+
readFileSync as readFileSync7,
|
|
4304
4351
|
rmSync
|
|
4305
4352
|
} from "fs";
|
|
4306
4353
|
import { tmpdir } from "os";
|
|
4307
|
-
import { join as
|
|
4354
|
+
import { join as join7 } from "path";
|
|
4308
4355
|
import { createRequire } from "module";
|
|
4309
|
-
var CONDUCTOR_APP_SUPPORT =
|
|
4356
|
+
var CONDUCTOR_APP_SUPPORT = join7(
|
|
4310
4357
|
process.env.HOME ?? "",
|
|
4311
4358
|
"Library",
|
|
4312
4359
|
"Application Support",
|
|
4313
4360
|
"com.conductor.app"
|
|
4314
4361
|
);
|
|
4315
|
-
var CONDUCTOR_DB =
|
|
4316
|
-
var CURSOR_SDK_STORE =
|
|
4362
|
+
var CONDUCTOR_DB = join7(CONDUCTOR_APP_SUPPORT, "conductor.db");
|
|
4363
|
+
var CURSOR_SDK_STORE = join7(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
|
|
4317
4364
|
function openReadonlySqlite(file) {
|
|
4318
4365
|
const req = createRequire(import.meta.url);
|
|
4319
4366
|
const Database = req("better-sqlite3");
|
|
@@ -4340,11 +4387,11 @@ function resolveConductorCursorAgentId(workspacePath) {
|
|
|
4340
4387
|
return null;
|
|
4341
4388
|
}
|
|
4342
4389
|
for (const hash of hashes) {
|
|
4343
|
-
const agentsFile =
|
|
4390
|
+
const agentsFile = join7(CURSOR_SDK_STORE, hash, "agents.ndjson");
|
|
4344
4391
|
if (!existsSync8(agentsFile)) continue;
|
|
4345
4392
|
let text3;
|
|
4346
4393
|
try {
|
|
4347
|
-
text3 =
|
|
4394
|
+
text3 = readFileSync7(agentsFile, "utf8");
|
|
4348
4395
|
} catch {
|
|
4349
4396
|
continue;
|
|
4350
4397
|
}
|
|
@@ -4387,7 +4434,7 @@ async function adoptThread(input) {
|
|
|
4387
4434
|
messages: input.messages ?? []
|
|
4388
4435
|
});
|
|
4389
4436
|
writeThread(thread);
|
|
4390
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
4437
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-NNPD7QVV.js");
|
|
4391
4438
|
await ensureWorkspace2(repoPath);
|
|
4392
4439
|
return thread;
|
|
4393
4440
|
}
|
|
@@ -4398,8 +4445,8 @@ function listConductorWorkspaces() {
|
|
|
4398
4445
|
if (!existsSync8(CONDUCTOR_DB)) {
|
|
4399
4446
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
4400
4447
|
}
|
|
4401
|
-
const tmp = mkdtempSync(
|
|
4402
|
-
const snapshot =
|
|
4448
|
+
const tmp = mkdtempSync(join7(tmpdir(), "sideboard-conductor-"));
|
|
4449
|
+
const snapshot = join7(tmp, "conductor.db");
|
|
4403
4450
|
try {
|
|
4404
4451
|
copyFileSync3(CONDUCTOR_DB, snapshot);
|
|
4405
4452
|
for (const suffix of ["-wal", "-shm"]) {
|
|
@@ -4489,8 +4536,8 @@ function importConductorWorkspace(workspaceId) {
|
|
|
4489
4536
|
if (!existsSync8(CONDUCTOR_DB)) {
|
|
4490
4537
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
4491
4538
|
}
|
|
4492
|
-
const tmp = mkdtempSync(
|
|
4493
|
-
const snapshot =
|
|
4539
|
+
const tmp = mkdtempSync(join7(tmpdir(), "sideboard-conductor-"));
|
|
4540
|
+
const snapshot = join7(tmp, "conductor.db");
|
|
4494
4541
|
try {
|
|
4495
4542
|
copyFileSync3(CONDUCTOR_DB, snapshot);
|
|
4496
4543
|
for (const suffix of ["-wal", "-shm"]) {
|
|
@@ -4589,8 +4636,8 @@ async function importConductorWorkspaceAsync(workspaceId) {
|
|
|
4589
4636
|
import { EventEmitter } from "events";
|
|
4590
4637
|
|
|
4591
4638
|
// src/slack/outbound-watch.ts
|
|
4592
|
-
import { existsSync as existsSync10, readFileSync as
|
|
4593
|
-
import { join as
|
|
4639
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
|
|
4640
|
+
import { join as join10 } from "path";
|
|
4594
4641
|
|
|
4595
4642
|
// src/slack/api.ts
|
|
4596
4643
|
var SLACK_API = "https://slack.com/api";
|
|
@@ -4632,16 +4679,16 @@ async function slackAuthTest(token) {
|
|
|
4632
4679
|
}
|
|
4633
4680
|
|
|
4634
4681
|
// src/slack/reply-target.ts
|
|
4635
|
-
import { existsSync as existsSync9, readFileSync as
|
|
4636
|
-
import { join as
|
|
4682
|
+
import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
|
|
4683
|
+
import { join as join8 } from "path";
|
|
4637
4684
|
function storePath() {
|
|
4638
|
-
return
|
|
4685
|
+
return join8(appDataDir(), "slack-reply-to.json");
|
|
4639
4686
|
}
|
|
4640
4687
|
function readStore() {
|
|
4641
4688
|
const path2 = storePath();
|
|
4642
4689
|
if (!existsSync9(path2)) return {};
|
|
4643
4690
|
try {
|
|
4644
|
-
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse(
|
|
4691
|
+
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse(readFileSync8(path2, "utf8"));
|
|
4645
4692
|
return parsed?.targets && typeof parsed.targets === "object" ? parsed.targets : {};
|
|
4646
4693
|
} catch {
|
|
4647
4694
|
return {};
|
|
@@ -4658,9 +4705,9 @@ function getSlackReplyTarget(threadId) {
|
|
|
4658
4705
|
}
|
|
4659
4706
|
|
|
4660
4707
|
// src/slack/workspaces.ts
|
|
4661
|
-
import { join as
|
|
4708
|
+
import { join as join9 } from "path";
|
|
4662
4709
|
function storePath2() {
|
|
4663
|
-
return
|
|
4710
|
+
return join9(appDataDir(), "slack-workspaces.json");
|
|
4664
4711
|
}
|
|
4665
4712
|
function readStore2() {
|
|
4666
4713
|
try {
|
|
@@ -4776,7 +4823,7 @@ var POLL_INTERVAL_MS = 12e3;
|
|
|
4776
4823
|
var lastPollMs = 0;
|
|
4777
4824
|
var nameCache = /* @__PURE__ */ new Map();
|
|
4778
4825
|
function storePath3() {
|
|
4779
|
-
return
|
|
4826
|
+
return join10(appDataDir(), "slack-outbound-watch.json");
|
|
4780
4827
|
}
|
|
4781
4828
|
function watchId(teamId, channelId, ts) {
|
|
4782
4829
|
return `${teamId}:${channelId}:${ts}`;
|
|
@@ -4808,7 +4855,7 @@ function readStore3() {
|
|
|
4808
4855
|
const path2 = storePath3();
|
|
4809
4856
|
if (!existsSync10(path2)) return [];
|
|
4810
4857
|
try {
|
|
4811
|
-
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse(
|
|
4858
|
+
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse(readFileSync9(path2, "utf8"));
|
|
4812
4859
|
return Array.isArray(parsed?.watches) ? parsed.watches : [];
|
|
4813
4860
|
} catch {
|
|
4814
4861
|
return [];
|
|
@@ -5171,7 +5218,7 @@ function shouldAutoArchiveOnPrMerge(opts) {
|
|
|
5171
5218
|
|
|
5172
5219
|
// src/git/orphan-cleanup.ts
|
|
5173
5220
|
import { existsSync as existsSync11, readdirSync as readdirSync4, statSync as statSync5 } from "fs";
|
|
5174
|
-
import { join as
|
|
5221
|
+
import { join as join11 } from "path";
|
|
5175
5222
|
function isSideboardWorktreePath(path2) {
|
|
5176
5223
|
return path2.includes("/.sideboard/worktrees/") || path2.includes("/sideboard/workspaces/");
|
|
5177
5224
|
}
|
|
@@ -5218,9 +5265,9 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
5218
5265
|
if (existsSync11(root)) {
|
|
5219
5266
|
for (const entry of readdirSync4(root, { withFileTypes: true })) {
|
|
5220
5267
|
if (!entry.isDirectory()) continue;
|
|
5221
|
-
const path2 =
|
|
5268
|
+
const path2 = join11(root, entry.name).replace(/\/$/, "");
|
|
5222
5269
|
if (known.has(path2) || seen.has(path2)) continue;
|
|
5223
|
-
if (!existsSync11(
|
|
5270
|
+
if (!existsSync11(join11(path2, ".git"))) continue;
|
|
5224
5271
|
seen.add(path2);
|
|
5225
5272
|
let mtimeMs = 0;
|
|
5226
5273
|
try {
|
|
@@ -5370,7 +5417,7 @@ async function applyThreadIntoMain(thread, opts) {
|
|
|
5370
5417
|
|
|
5371
5418
|
// src/git/clone-repo.ts
|
|
5372
5419
|
import { existsSync as existsSync12 } from "fs";
|
|
5373
|
-
import { basename as basename3, join as
|
|
5420
|
+
import { basename as basename3, join as join12 } from "path";
|
|
5374
5421
|
import { execa as execa4 } from "execa";
|
|
5375
5422
|
async function cloneRepoIntoSideboard(opts) {
|
|
5376
5423
|
const url = opts.url.trim();
|
|
@@ -5381,7 +5428,7 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
5381
5428
|
name = leaf || "repo";
|
|
5382
5429
|
}
|
|
5383
5430
|
name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
|
|
5384
|
-
const dest =
|
|
5431
|
+
const dest = join12(sideboardReposDir(), name);
|
|
5385
5432
|
if (existsSync12(dest)) {
|
|
5386
5433
|
const repoPath2 = await resolveRepoRoot(dest);
|
|
5387
5434
|
const workspace2 = await ensureWorkspace(repoPath2);
|
|
@@ -5400,8 +5447,8 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
5400
5447
|
|
|
5401
5448
|
// src/review/request-review.ts
|
|
5402
5449
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
5403
|
-
import { existsSync as existsSync13, mkdirSync as mkdirSync4, readFileSync as
|
|
5404
|
-
import { dirname as dirname3, join as
|
|
5450
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync4, readFileSync as readFileSync10, writeFileSync as writeFileSync4 } from "fs";
|
|
5451
|
+
import { dirname as dirname3, join as join13 } from "path";
|
|
5405
5452
|
|
|
5406
5453
|
// src/review/review-request-template.ts
|
|
5407
5454
|
var REVIEW_REQUEST_TEMPLATE = `# Review guidelines:
|
|
@@ -5548,20 +5595,20 @@ function shouldRefreshReviewRequestTemplate(content) {
|
|
|
5548
5595
|
function readTextIfPresent(abs) {
|
|
5549
5596
|
if (!existsSync13(abs)) return null;
|
|
5550
5597
|
try {
|
|
5551
|
-
const content =
|
|
5598
|
+
const content = readFileSync10(abs, "utf8");
|
|
5552
5599
|
return content.trim() ? content : null;
|
|
5553
5600
|
} catch {
|
|
5554
5601
|
return null;
|
|
5555
5602
|
}
|
|
5556
5603
|
}
|
|
5557
5604
|
function ensureAttachmentsGitignore(worktreePath) {
|
|
5558
|
-
const gitignoreAbs =
|
|
5605
|
+
const gitignoreAbs = join13(worktreePath, ATTACHMENTS_DIR, ".gitignore");
|
|
5559
5606
|
if (existsSync13(gitignoreAbs)) return;
|
|
5560
5607
|
mkdirSync4(dirname3(gitignoreAbs), { recursive: true });
|
|
5561
|
-
|
|
5608
|
+
writeFileSync4(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
|
|
5562
5609
|
}
|
|
5563
5610
|
function resolveReviewGuidelines(worktreePath) {
|
|
5564
|
-
const repoAbs =
|
|
5611
|
+
const repoAbs = join13(worktreePath, REPO_REVIEW_PATH);
|
|
5565
5612
|
const repoContent = readTextIfPresent(repoAbs);
|
|
5566
5613
|
if (repoContent) {
|
|
5567
5614
|
return {
|
|
@@ -5571,7 +5618,7 @@ function resolveReviewGuidelines(worktreePath) {
|
|
|
5571
5618
|
source: "repo"
|
|
5572
5619
|
};
|
|
5573
5620
|
}
|
|
5574
|
-
const localAbs =
|
|
5621
|
+
const localAbs = join13(worktreePath, REVIEW_REQUEST_PATH);
|
|
5575
5622
|
const localContent = readTextIfPresent(localAbs);
|
|
5576
5623
|
if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
|
|
5577
5624
|
return {
|
|
@@ -5581,7 +5628,7 @@ function resolveReviewGuidelines(worktreePath) {
|
|
|
5581
5628
|
source: "local"
|
|
5582
5629
|
};
|
|
5583
5630
|
}
|
|
5584
|
-
const legacyAbs =
|
|
5631
|
+
const legacyAbs = join13(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
|
|
5585
5632
|
const legacyContent = readTextIfPresent(legacyAbs);
|
|
5586
5633
|
if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
|
|
5587
5634
|
return {
|
|
@@ -5593,7 +5640,7 @@ function resolveReviewGuidelines(worktreePath) {
|
|
|
5593
5640
|
}
|
|
5594
5641
|
ensureAttachmentsGitignore(worktreePath);
|
|
5595
5642
|
mkdirSync4(dirname3(localAbs), { recursive: true });
|
|
5596
|
-
|
|
5643
|
+
writeFileSync4(localAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
|
|
5597
5644
|
return {
|
|
5598
5645
|
path: REVIEW_REQUEST_PATH,
|
|
5599
5646
|
name: REVIEW_REQUEST_NAME,
|
|
@@ -5602,7 +5649,7 @@ function resolveReviewGuidelines(worktreePath) {
|
|
|
5602
5649
|
};
|
|
5603
5650
|
}
|
|
5604
5651
|
function ensureReviewRequestFile(worktreePath) {
|
|
5605
|
-
const repoAbs =
|
|
5652
|
+
const repoAbs = join13(worktreePath, REPO_REVIEW_PATH);
|
|
5606
5653
|
const repoContent = readTextIfPresent(repoAbs);
|
|
5607
5654
|
if (repoContent) {
|
|
5608
5655
|
return {
|
|
@@ -5612,8 +5659,8 @@ function ensureReviewRequestFile(worktreePath) {
|
|
|
5612
5659
|
source: "repo"
|
|
5613
5660
|
};
|
|
5614
5661
|
}
|
|
5615
|
-
const localAbs =
|
|
5616
|
-
const localContent = readTextIfPresent(localAbs) ?? readTextIfPresent(
|
|
5662
|
+
const localAbs = join13(worktreePath, REVIEW_REQUEST_PATH);
|
|
5663
|
+
const localContent = readTextIfPresent(localAbs) ?? readTextIfPresent(join13(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
|
|
5617
5664
|
if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
|
|
5618
5665
|
const path2 = existsSync13(localAbs) ? REVIEW_REQUEST_PATH : LEGACY_REVIEW_REQUEST_PATH;
|
|
5619
5666
|
return {
|
|
@@ -5624,7 +5671,7 @@ function ensureReviewRequestFile(worktreePath) {
|
|
|
5624
5671
|
};
|
|
5625
5672
|
}
|
|
5626
5673
|
mkdirSync4(dirname3(repoAbs), { recursive: true });
|
|
5627
|
-
|
|
5674
|
+
writeFileSync4(repoAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
|
|
5628
5675
|
return {
|
|
5629
5676
|
path: REPO_REVIEW_PATH,
|
|
5630
5677
|
name: REPO_REVIEW_NAME,
|
|
@@ -5644,7 +5691,7 @@ function buildReviewRequestAttachment(content, opts) {
|
|
|
5644
5691
|
};
|
|
5645
5692
|
}
|
|
5646
5693
|
function readExistingReviewRequestFile(worktreePath) {
|
|
5647
|
-
return readTextIfPresent(
|
|
5694
|
+
return readTextIfPresent(join13(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent(join13(worktreePath, REVIEW_REQUEST_PATH)) ?? readTextIfPresent(join13(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
|
|
5648
5695
|
}
|
|
5649
5696
|
async function requestReview(threadRef, send2) {
|
|
5650
5697
|
const from = findThreadByRef(threadRef);
|
|
@@ -6145,7 +6192,9 @@ var Orchestrator = class {
|
|
|
6145
6192
|
updateThread(thread.id, patch);
|
|
6146
6193
|
this.emit({ type: "queue_changed", threadId: thread.id, queue });
|
|
6147
6194
|
this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
|
|
6148
|
-
|
|
6195
|
+
if (thisProcessShouldDrainAgentQueues()) {
|
|
6196
|
+
void this.drainQueue(thread.id);
|
|
6197
|
+
}
|
|
6149
6198
|
return this.requireThread(thread.id);
|
|
6150
6199
|
});
|
|
6151
6200
|
}
|
|
@@ -6198,10 +6247,10 @@ var Orchestrator = class {
|
|
|
6198
6247
|
async sendQueuedMessageNow(threadRef, index) {
|
|
6199
6248
|
const thread = this.requireThread(threadRef);
|
|
6200
6249
|
const promoted = await withThreadLock(thread.id, async () => {
|
|
6201
|
-
const
|
|
6202
|
-
if (index < 0 || index >=
|
|
6203
|
-
const item =
|
|
6204
|
-
const rest =
|
|
6250
|
+
const current2 = this.requireThread(thread.id);
|
|
6251
|
+
if (index < 0 || index >= current2.queue.length) return false;
|
|
6252
|
+
const item = current2.queue[index];
|
|
6253
|
+
const rest = current2.queue.filter((_, i) => i !== index);
|
|
6205
6254
|
const queue = [item, ...rest];
|
|
6206
6255
|
this.haltDrain.delete(thread.id);
|
|
6207
6256
|
updateThread(thread.id, { queue });
|
|
@@ -6209,10 +6258,16 @@ var Orchestrator = class {
|
|
|
6209
6258
|
return true;
|
|
6210
6259
|
});
|
|
6211
6260
|
if (!promoted) return this.requireThread(thread.id);
|
|
6261
|
+
const current = this.requireThread(thread.id);
|
|
6212
6262
|
const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id);
|
|
6263
|
+
const livePid = current.agentPid;
|
|
6264
|
+
const foreignLive = !inFlight && typeof livePid === "number" && livePid > 0 && isPidAlive(livePid);
|
|
6213
6265
|
if (inFlight) {
|
|
6214
6266
|
this.stop(thread.id, { clearQueue: false, continueQueue: true });
|
|
6215
6267
|
} else {
|
|
6268
|
+
if (foreignLive) {
|
|
6269
|
+
this.stop(thread.id, { clearQueue: false, continueQueue: true });
|
|
6270
|
+
}
|
|
6216
6271
|
void this.drainQueue(thread.id);
|
|
6217
6272
|
}
|
|
6218
6273
|
return this.requireThread(thread.id);
|
|
@@ -6463,19 +6518,16 @@ var Orchestrator = class {
|
|
|
6463
6518
|
}
|
|
6464
6519
|
let lastStderr = summarizeTurnStderr(stderrTail);
|
|
6465
6520
|
let detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
6466
|
-
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) &&
|
|
6521
|
+
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) && this.requireThread(threadId).agent !== "brightsy" && shouldRetryFailedAgentTurn(detail, {
|
|
6522
|
+
hasSession: Boolean(this.requireThread(threadId).sessionId)
|
|
6523
|
+
})) {
|
|
6467
6524
|
updateThread(threadId, { sessionId: null });
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
"Agent session missing \u2014 starting a fresh session"
|
|
6471
|
-
);
|
|
6525
|
+
const retryNote = looksLikeInvalidAgentSession(detail) ? "Agent session missing \u2014 starting a fresh session" : "Agent runner crashed \u2014 restarting Node once";
|
|
6526
|
+
pushTurnStderr(stderrTail, retryNote);
|
|
6472
6527
|
this.emit({
|
|
6473
6528
|
type: "turn_output",
|
|
6474
6529
|
threadId,
|
|
6475
|
-
event: {
|
|
6476
|
-
type: "stderr",
|
|
6477
|
-
data: "Agent session missing \u2014 starting a fresh session"
|
|
6478
|
-
}
|
|
6530
|
+
event: { type: "stderr", data: retryNote }
|
|
6479
6531
|
});
|
|
6480
6532
|
const retryThread = this.requireThread(threadId);
|
|
6481
6533
|
const prior = retryThread.messages.slice(0, -1);
|
|
@@ -6524,10 +6576,7 @@ var Orchestrator = class {
|
|
|
6524
6576
|
lastStderr = summarizeTurnStderr(stderrTail);
|
|
6525
6577
|
detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
6526
6578
|
}
|
|
6527
|
-
let chatText = assistantText;
|
|
6528
|
-
if (exitCode !== 0 && !chatText && looksLikeAgentFailureMessage(detail)) {
|
|
6529
|
-
chatText = humanizeAgentFailDetail(detail);
|
|
6530
|
-
}
|
|
6579
|
+
let chatText = this.stoppedTurns.has(threadId) ? assistantText : turnFailChatText({ exitCode, assistantText, detail });
|
|
6531
6580
|
if (chatText || parts.length > 0) {
|
|
6532
6581
|
appendMessage(threadId, {
|
|
6533
6582
|
role: "agent",
|
|
@@ -6647,6 +6696,13 @@ var Orchestrator = class {
|
|
|
6647
6696
|
if (handle) handle.kill();
|
|
6648
6697
|
const proc = this.processes.get(`${thread.id}:agent`);
|
|
6649
6698
|
if (proc) proc.kill();
|
|
6699
|
+
const pid = thread.agentPid;
|
|
6700
|
+
if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) {
|
|
6701
|
+
try {
|
|
6702
|
+
process.kill(pid, "SIGTERM");
|
|
6703
|
+
} catch {
|
|
6704
|
+
}
|
|
6705
|
+
}
|
|
6650
6706
|
const stopped = writeLiveStatus(thread.id, "stopped") ?? readThread(thread.id) ?? thread;
|
|
6651
6707
|
if (stopped.status === "stopped") {
|
|
6652
6708
|
this.emit({ type: "status_changed", threadId: thread.id, status: "stopped" });
|
|
@@ -6928,10 +6984,13 @@ var Orchestrator = class {
|
|
|
6928
6984
|
getTurnResult(threadRef) {
|
|
6929
6985
|
const thread = this.requireThread(threadRef);
|
|
6930
6986
|
const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
|
|
6987
|
+
const lastError = thread.lastError ?? null;
|
|
6988
|
+
const text3 = (lastAgent?.text ?? "").trim() || (thread.status === "error" ? lastError ?? "" : "");
|
|
6931
6989
|
return {
|
|
6932
|
-
text:
|
|
6990
|
+
text: text3,
|
|
6933
6991
|
status: thread.status,
|
|
6934
|
-
sessionId: thread.sessionId
|
|
6992
|
+
sessionId: thread.sessionId,
|
|
6993
|
+
lastError
|
|
6935
6994
|
};
|
|
6936
6995
|
}
|
|
6937
6996
|
assertNotGlobal(thread, action) {
|
|
@@ -7385,7 +7444,7 @@ var Orchestrator = class {
|
|
|
7385
7444
|
this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
|
|
7386
7445
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
7387
7446
|
try {
|
|
7388
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
7447
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-NNPD7QVV.js");
|
|
7389
7448
|
await ensureWorkspace2(thread.repoPath);
|
|
7390
7449
|
} catch {
|
|
7391
7450
|
}
|
|
@@ -8696,7 +8755,7 @@ async function startMcpServer() {
|
|
|
8696
8755
|
);
|
|
8697
8756
|
server.tool(
|
|
8698
8757
|
"wait_for_turn",
|
|
8699
|
-
"Block until the thread finishes its current/queued turn (avoids polling). Use after send_to_thread or ask_git
|
|
8758
|
+
"Block until the thread finishes its current/queued turn (avoids polling). Use after send_to_thread or ask_git. Returns status, text, and lastError. If status is error, lastError/text is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success.",
|
|
8700
8759
|
{
|
|
8701
8760
|
ref: z3.string(),
|
|
8702
8761
|
timeoutMs: z3.number().optional()
|
|
@@ -8711,7 +8770,8 @@ async function startMcpServer() {
|
|
|
8711
8770
|
text: JSON.stringify({
|
|
8712
8771
|
id: thread.id,
|
|
8713
8772
|
status: result.status,
|
|
8714
|
-
text: result.text
|
|
8773
|
+
text: result.text,
|
|
8774
|
+
lastError: result.lastError
|
|
8715
8775
|
})
|
|
8716
8776
|
}
|
|
8717
8777
|
]
|
|
@@ -8720,7 +8780,7 @@ async function startMcpServer() {
|
|
|
8720
8780
|
);
|
|
8721
8781
|
server.tool(
|
|
8722
8782
|
"get_turn_result",
|
|
8723
|
-
"Final assistant message
|
|
8783
|
+
"Final assistant message (and lastError when the turn failed). Not the full transcript.",
|
|
8724
8784
|
{ ref: z3.string() },
|
|
8725
8785
|
async ({ ref }) => {
|
|
8726
8786
|
const result = orch.getTurnResult(ref);
|
|
@@ -9632,14 +9692,14 @@ async function runCloudConnect(opts) {
|
|
|
9632
9692
|
}
|
|
9633
9693
|
|
|
9634
9694
|
// src/agents/user-mcp-config.ts
|
|
9635
|
-
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as
|
|
9695
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "fs";
|
|
9636
9696
|
import { homedir as homedir2 } from "os";
|
|
9637
|
-
import { dirname as dirname4, join as
|
|
9697
|
+
import { dirname as dirname4, join as join14 } from "path";
|
|
9638
9698
|
function userCursorMcpConfigPath() {
|
|
9639
|
-
return
|
|
9699
|
+
return join14(homedir2(), ".cursor", "mcp.json");
|
|
9640
9700
|
}
|
|
9641
9701
|
function userClaudeMcpConfigPath() {
|
|
9642
|
-
return
|
|
9702
|
+
return join14(homedir2(), ".claude.json");
|
|
9643
9703
|
}
|
|
9644
9704
|
function asObject(value) {
|
|
9645
9705
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
@@ -9668,14 +9728,14 @@ function writeMergedMcpServersJson(configPath, sideboard) {
|
|
|
9668
9728
|
let existing = {};
|
|
9669
9729
|
if (existsSync15(configPath)) {
|
|
9670
9730
|
try {
|
|
9671
|
-
existing = JSON.parse(
|
|
9731
|
+
existing = JSON.parse(readFileSync11(configPath, "utf8"));
|
|
9672
9732
|
} catch {
|
|
9673
9733
|
existing = {};
|
|
9674
9734
|
}
|
|
9675
9735
|
}
|
|
9676
9736
|
const next = mergeSideboardIntoMcpServersJson(existing, sideboard);
|
|
9677
9737
|
mkdirSync5(dirname4(configPath), { recursive: true });
|
|
9678
|
-
|
|
9738
|
+
writeFileSync5(configPath, `${JSON.stringify(next, null, 2)}
|
|
9679
9739
|
`);
|
|
9680
9740
|
}
|
|
9681
9741
|
function launchFromResolved(server) {
|
|
@@ -11492,6 +11552,7 @@ export {
|
|
|
11492
11552
|
captureTurnBaseline,
|
|
11493
11553
|
checkoutPrStackLayer,
|
|
11494
11554
|
childEnvWithAppSettings,
|
|
11555
|
+
claimDesktopHost,
|
|
11495
11556
|
claudeAdapter,
|
|
11496
11557
|
claudeChromeEnabled,
|
|
11497
11558
|
claudeUserSettingsPath,
|
|
@@ -11530,6 +11591,7 @@ export {
|
|
|
11530
11591
|
decodeBrightsyTarget,
|
|
11531
11592
|
deleteBranchOnPurgeEnabled,
|
|
11532
11593
|
deleteThreadRecord,
|
|
11594
|
+
desktopHostPidPath,
|
|
11533
11595
|
detectAgents,
|
|
11534
11596
|
detectGhStack,
|
|
11535
11597
|
detectLocalMergeConflicts,
|
|
@@ -11655,6 +11717,7 @@ export {
|
|
|
11655
11717
|
isConductorBundledCli,
|
|
11656
11718
|
isCursorAutoModel,
|
|
11657
11719
|
isDefaultishSourceRef,
|
|
11720
|
+
isDesktopHostAlive,
|
|
11658
11721
|
isDirty,
|
|
11659
11722
|
isGhRateLimitError,
|
|
11660
11723
|
isGlobalRepoPath,
|
|
@@ -11676,6 +11739,7 @@ export {
|
|
|
11676
11739
|
isSlackExternalReplyPrompt,
|
|
11677
11740
|
isSlackOAuthCancelled,
|
|
11678
11741
|
isThinkingEffort,
|
|
11742
|
+
isThisProcessDesktopHost,
|
|
11679
11743
|
isThreadCaffeinated,
|
|
11680
11744
|
isWorkspaceScratchPath,
|
|
11681
11745
|
linearAuthorizationHeader,
|
|
@@ -11777,6 +11841,7 @@ export {
|
|
|
11777
11841
|
refreshSlackReplyBadges,
|
|
11778
11842
|
registerPackagedUserMcpClients,
|
|
11779
11843
|
releaseCaffeinateHoldForThread,
|
|
11844
|
+
releaseDesktopHost,
|
|
11780
11845
|
removeWorkspace,
|
|
11781
11846
|
removeWorktree,
|
|
11782
11847
|
repoSlug,
|
|
@@ -11877,6 +11942,7 @@ export {
|
|
|
11877
11942
|
taskMessageText,
|
|
11878
11943
|
thinkingEffortBars,
|
|
11879
11944
|
thinkingEffortLabel,
|
|
11945
|
+
thisProcessShouldDrainAgentQueues,
|
|
11880
11946
|
threadDisplayLabel,
|
|
11881
11947
|
threadFilePath,
|
|
11882
11948
|
threadLockPath,
|