@sideboard-ai/core 0.1.98 → 0.1.99
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 +47 -2
- package/dist/agents/cursor-runner.js +47 -2
- package/dist/index.cjs +448 -372
- package/dist/index.d.cts +14 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +165 -98
- package/dist/mcp/run-stdio.cjs +193 -142
- package/dist/mcp/run-stdio.js +113 -63
- package/package.json +1 -1
package/dist/mcp/run-stdio.js
CHANGED
|
@@ -1745,6 +1745,41 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
1745
1745
|
return { repoPath, workspace };
|
|
1746
1746
|
}
|
|
1747
1747
|
|
|
1748
|
+
// src/store/desktop-host.ts
|
|
1749
|
+
import { readFileSync as readFileSync4, unlinkSync, writeFileSync } from "fs";
|
|
1750
|
+
import { join as join7 } from "path";
|
|
1751
|
+
function desktopHostPidPath() {
|
|
1752
|
+
return join7(appDataDir(), "desktop-host.pid");
|
|
1753
|
+
}
|
|
1754
|
+
function readDesktopHostPid() {
|
|
1755
|
+
try {
|
|
1756
|
+
const pid = Number.parseInt(readFileSync4(desktopHostPidPath(), "utf8").trim(), 10);
|
|
1757
|
+
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
1758
|
+
return pid;
|
|
1759
|
+
} catch {
|
|
1760
|
+
return null;
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
function pidAlive(pid) {
|
|
1764
|
+
try {
|
|
1765
|
+
process.kill(pid, 0);
|
|
1766
|
+
return true;
|
|
1767
|
+
} catch {
|
|
1768
|
+
return false;
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
function isDesktopHostAlive() {
|
|
1772
|
+
const pid = readDesktopHostPid();
|
|
1773
|
+
return pid != null && pidAlive(pid);
|
|
1774
|
+
}
|
|
1775
|
+
function isThisProcessDesktopHost() {
|
|
1776
|
+
return readDesktopHostPid() === process.pid && pidAlive(process.pid);
|
|
1777
|
+
}
|
|
1778
|
+
function thisProcessShouldDrainAgentQueues() {
|
|
1779
|
+
if (isThisProcessDesktopHost()) return true;
|
|
1780
|
+
return !isDesktopHostAlive();
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1748
1783
|
// src/threads/create.ts
|
|
1749
1784
|
import { existsSync as existsSync6 } from "fs";
|
|
1750
1785
|
|
|
@@ -2251,8 +2286,8 @@ function forkChatTab(input) {
|
|
|
2251
2286
|
|
|
2252
2287
|
// src/review/request-review.ts
|
|
2253
2288
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2254
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as
|
|
2255
|
-
import { dirname as dirname2, join as
|
|
2289
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
|
|
2290
|
+
import { dirname as dirname2, join as join8 } from "path";
|
|
2256
2291
|
|
|
2257
2292
|
// src/review/review-request-template.ts
|
|
2258
2293
|
var REVIEW_REQUEST_TEMPLATE = `# Review guidelines:
|
|
@@ -2399,20 +2434,20 @@ function shouldRefreshReviewRequestTemplate(content) {
|
|
|
2399
2434
|
function readTextIfPresent(abs) {
|
|
2400
2435
|
if (!existsSync7(abs)) return null;
|
|
2401
2436
|
try {
|
|
2402
|
-
const content =
|
|
2437
|
+
const content = readFileSync5(abs, "utf8");
|
|
2403
2438
|
return content.trim() ? content : null;
|
|
2404
2439
|
} catch {
|
|
2405
2440
|
return null;
|
|
2406
2441
|
}
|
|
2407
2442
|
}
|
|
2408
2443
|
function ensureAttachmentsGitignore(worktreePath) {
|
|
2409
|
-
const gitignoreAbs =
|
|
2444
|
+
const gitignoreAbs = join8(worktreePath, ATTACHMENTS_DIR, ".gitignore");
|
|
2410
2445
|
if (existsSync7(gitignoreAbs)) return;
|
|
2411
2446
|
mkdirSync2(dirname2(gitignoreAbs), { recursive: true });
|
|
2412
|
-
|
|
2447
|
+
writeFileSync2(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
|
|
2413
2448
|
}
|
|
2414
2449
|
function resolveReviewGuidelines(worktreePath) {
|
|
2415
|
-
const repoAbs =
|
|
2450
|
+
const repoAbs = join8(worktreePath, REPO_REVIEW_PATH);
|
|
2416
2451
|
const repoContent = readTextIfPresent(repoAbs);
|
|
2417
2452
|
if (repoContent) {
|
|
2418
2453
|
return {
|
|
@@ -2422,7 +2457,7 @@ function resolveReviewGuidelines(worktreePath) {
|
|
|
2422
2457
|
source: "repo"
|
|
2423
2458
|
};
|
|
2424
2459
|
}
|
|
2425
|
-
const localAbs =
|
|
2460
|
+
const localAbs = join8(worktreePath, REVIEW_REQUEST_PATH);
|
|
2426
2461
|
const localContent = readTextIfPresent(localAbs);
|
|
2427
2462
|
if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
|
|
2428
2463
|
return {
|
|
@@ -2432,7 +2467,7 @@ function resolveReviewGuidelines(worktreePath) {
|
|
|
2432
2467
|
source: "local"
|
|
2433
2468
|
};
|
|
2434
2469
|
}
|
|
2435
|
-
const legacyAbs =
|
|
2470
|
+
const legacyAbs = join8(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
|
|
2436
2471
|
const legacyContent = readTextIfPresent(legacyAbs);
|
|
2437
2472
|
if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
|
|
2438
2473
|
return {
|
|
@@ -2444,7 +2479,7 @@ function resolveReviewGuidelines(worktreePath) {
|
|
|
2444
2479
|
}
|
|
2445
2480
|
ensureAttachmentsGitignore(worktreePath);
|
|
2446
2481
|
mkdirSync2(dirname2(localAbs), { recursive: true });
|
|
2447
|
-
|
|
2482
|
+
writeFileSync2(localAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
|
|
2448
2483
|
return {
|
|
2449
2484
|
path: REVIEW_REQUEST_PATH,
|
|
2450
2485
|
name: REVIEW_REQUEST_NAME,
|
|
@@ -2643,20 +2678,20 @@ import {
|
|
|
2643
2678
|
existsSync as existsSync8,
|
|
2644
2679
|
mkdtempSync,
|
|
2645
2680
|
readdirSync as readdirSync3,
|
|
2646
|
-
readFileSync as
|
|
2681
|
+
readFileSync as readFileSync6,
|
|
2647
2682
|
rmSync
|
|
2648
2683
|
} from "fs";
|
|
2649
2684
|
import { tmpdir } from "os";
|
|
2650
|
-
import { join as
|
|
2685
|
+
import { join as join9 } from "path";
|
|
2651
2686
|
import { createRequire } from "module";
|
|
2652
|
-
var CONDUCTOR_APP_SUPPORT =
|
|
2687
|
+
var CONDUCTOR_APP_SUPPORT = join9(
|
|
2653
2688
|
process.env.HOME ?? "",
|
|
2654
2689
|
"Library",
|
|
2655
2690
|
"Application Support",
|
|
2656
2691
|
"com.conductor.app"
|
|
2657
2692
|
);
|
|
2658
|
-
var CONDUCTOR_DB =
|
|
2659
|
-
var CURSOR_SDK_STORE =
|
|
2693
|
+
var CONDUCTOR_DB = join9(CONDUCTOR_APP_SUPPORT, "conductor.db");
|
|
2694
|
+
var CURSOR_SDK_STORE = join9(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
|
|
2660
2695
|
function openReadonlySqlite(file) {
|
|
2661
2696
|
const req = createRequire(import.meta.url);
|
|
2662
2697
|
const Database = req("better-sqlite3");
|
|
@@ -2683,11 +2718,11 @@ function resolveConductorCursorAgentId(workspacePath) {
|
|
|
2683
2718
|
return null;
|
|
2684
2719
|
}
|
|
2685
2720
|
for (const hash of hashes) {
|
|
2686
|
-
const agentsFile =
|
|
2721
|
+
const agentsFile = join9(CURSOR_SDK_STORE, hash, "agents.ndjson");
|
|
2687
2722
|
if (!existsSync8(agentsFile)) continue;
|
|
2688
2723
|
let text3;
|
|
2689
2724
|
try {
|
|
2690
|
-
text3 =
|
|
2725
|
+
text3 = readFileSync6(agentsFile, "utf8");
|
|
2691
2726
|
} catch {
|
|
2692
2727
|
continue;
|
|
2693
2728
|
}
|
|
@@ -2738,8 +2773,8 @@ function listConductorWorkspaces() {
|
|
|
2738
2773
|
if (!existsSync8(CONDUCTOR_DB)) {
|
|
2739
2774
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
2740
2775
|
}
|
|
2741
|
-
const tmp = mkdtempSync(
|
|
2742
|
-
const snapshot =
|
|
2776
|
+
const tmp = mkdtempSync(join9(tmpdir(), "sideboard-conductor-"));
|
|
2777
|
+
const snapshot = join9(tmp, "conductor.db");
|
|
2743
2778
|
try {
|
|
2744
2779
|
copyFileSync2(CONDUCTOR_DB, snapshot);
|
|
2745
2780
|
for (const suffix of ["-wal", "-shm"]) {
|
|
@@ -2829,8 +2864,8 @@ function importConductorWorkspace(workspaceId) {
|
|
|
2829
2864
|
if (!existsSync8(CONDUCTOR_DB)) {
|
|
2830
2865
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
2831
2866
|
}
|
|
2832
|
-
const tmp = mkdtempSync(
|
|
2833
|
-
const snapshot =
|
|
2867
|
+
const tmp = mkdtempSync(join9(tmpdir(), "sideboard-conductor-"));
|
|
2868
|
+
const snapshot = join9(tmp, "conductor.db");
|
|
2834
2869
|
try {
|
|
2835
2870
|
copyFileSync2(CONDUCTOR_DB, snapshot);
|
|
2836
2871
|
for (const suffix of ["-wal", "-shm"]) {
|
|
@@ -3210,8 +3245,8 @@ async function createPrStack(input, onSetupLine) {
|
|
|
3210
3245
|
}
|
|
3211
3246
|
|
|
3212
3247
|
// src/diff/diff.ts
|
|
3213
|
-
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as
|
|
3214
|
-
import { dirname as dirname3, join as
|
|
3248
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync7, statSync as statSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
3249
|
+
import { dirname as dirname3, join as join10 } from "path";
|
|
3215
3250
|
async function inspectGitWorktree(worktreePath) {
|
|
3216
3251
|
if (!worktreePath || !existsSync10(worktreePath)) return "missing_worktree";
|
|
3217
3252
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
@@ -3357,11 +3392,11 @@ new file mode 100644
|
|
|
3357
3392
|
};
|
|
3358
3393
|
}
|
|
3359
3394
|
async function untrackedPatch(worktreePath, path, maxHunk) {
|
|
3360
|
-
const abs =
|
|
3395
|
+
const abs = join10(worktreePath, path);
|
|
3361
3396
|
try {
|
|
3362
3397
|
const st = statSync2(abs);
|
|
3363
3398
|
if (st.isFile() && st.size > maxHunk) {
|
|
3364
|
-
const buf =
|
|
3399
|
+
const buf = readFileSync7(abs).subarray(0, maxHunk);
|
|
3365
3400
|
return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
|
|
3366
3401
|
}
|
|
3367
3402
|
} catch {
|
|
@@ -3862,7 +3897,7 @@ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
|
|
|
3862
3897
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
3863
3898
|
assertSafeRelativePath(relativePath);
|
|
3864
3899
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
3865
|
-
const abs =
|
|
3900
|
+
const abs = join10(worktreePath, relativePath);
|
|
3866
3901
|
const st = statSync2(abs);
|
|
3867
3902
|
if (!st.isFile()) {
|
|
3868
3903
|
throw new Error(`Not a file: ${relativePath}`);
|
|
@@ -3872,7 +3907,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
3872
3907
|
`File too large to upload (${st.size} bytes; max ${maxBytes})`
|
|
3873
3908
|
);
|
|
3874
3909
|
}
|
|
3875
|
-
const buf =
|
|
3910
|
+
const buf = readFileSync7(abs);
|
|
3876
3911
|
return {
|
|
3877
3912
|
path: relativePath,
|
|
3878
3913
|
contentBase64: buf.toString("base64"),
|
|
@@ -3882,12 +3917,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
3882
3917
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
3883
3918
|
assertSafeRelativePath(relativePath);
|
|
3884
3919
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
3885
|
-
const abs =
|
|
3920
|
+
const abs = join10(worktreePath, relativePath);
|
|
3886
3921
|
const st = statSync2(abs);
|
|
3887
3922
|
if (!st.isFile()) {
|
|
3888
3923
|
throw new Error(`Not a file: ${relativePath}`);
|
|
3889
3924
|
}
|
|
3890
|
-
const buf =
|
|
3925
|
+
const buf = readFileSync7(abs);
|
|
3891
3926
|
if (isImageRelativePath(relativePath)) {
|
|
3892
3927
|
const maxImageBytes = Math.max(maxBytes, 15e6);
|
|
3893
3928
|
const truncated2 = buf.length > maxImageBytes;
|
|
@@ -3930,9 +3965,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
3930
3965
|
}
|
|
3931
3966
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
3932
3967
|
assertSafeRelativePath(relativePath);
|
|
3933
|
-
const abs =
|
|
3968
|
+
const abs = join10(worktreePath, relativePath);
|
|
3934
3969
|
mkdirSync3(dirname3(abs), { recursive: true });
|
|
3935
|
-
|
|
3970
|
+
writeFileSync3(abs, content, "utf8");
|
|
3936
3971
|
return { path: relativePath };
|
|
3937
3972
|
}
|
|
3938
3973
|
async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
@@ -4035,9 +4070,9 @@ async function confirmLand(thread, opts) {
|
|
|
4035
4070
|
}
|
|
4036
4071
|
|
|
4037
4072
|
// src/skills/discover.ts
|
|
4038
|
-
import { existsSync as existsSync11, readdirSync as readdirSync4, readFileSync as
|
|
4073
|
+
import { existsSync as existsSync11, readdirSync as readdirSync4, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
4039
4074
|
import { homedir } from "os";
|
|
4040
|
-
import { join as
|
|
4075
|
+
import { join as join11 } from "path";
|
|
4041
4076
|
function toCommand(name) {
|
|
4042
4077
|
return name.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
4043
4078
|
}
|
|
@@ -4069,7 +4104,7 @@ function parseFrontmatter(content) {
|
|
|
4069
4104
|
}
|
|
4070
4105
|
function readSkill(skillMd, source) {
|
|
4071
4106
|
try {
|
|
4072
|
-
const content =
|
|
4107
|
+
const content = readFileSync8(skillMd, "utf8");
|
|
4073
4108
|
const { name: fmName, description } = parseFrontmatter(content);
|
|
4074
4109
|
const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
|
|
4075
4110
|
const name = fmName || dirName;
|
|
@@ -4097,7 +4132,7 @@ function scanSkillsDir(dir, source, out) {
|
|
|
4097
4132
|
}
|
|
4098
4133
|
for (const entry of entries) {
|
|
4099
4134
|
if (entry.startsWith(".")) continue;
|
|
4100
|
-
const skillMd =
|
|
4135
|
+
const skillMd = join11(dir, entry, "SKILL.md");
|
|
4101
4136
|
if (!existsSync11(skillMd)) continue;
|
|
4102
4137
|
try {
|
|
4103
4138
|
if (!statSync3(skillMd).isFile()) continue;
|
|
@@ -4119,12 +4154,12 @@ function scanClaudePluginSkills(pluginsRoot, out) {
|
|
|
4119
4154
|
return;
|
|
4120
4155
|
}
|
|
4121
4156
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
4122
|
-
const skill = readSkill(
|
|
4157
|
+
const skill = readSkill(join11(dir, "SKILL.md"), "cli");
|
|
4123
4158
|
if (skill) out.push(skill);
|
|
4124
4159
|
}
|
|
4125
4160
|
for (const entry of entries) {
|
|
4126
4161
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
4127
|
-
const full =
|
|
4162
|
+
const full = join11(dir, entry);
|
|
4128
4163
|
try {
|
|
4129
4164
|
if (!statSync3(full).isDirectory()) continue;
|
|
4130
4165
|
} catch {
|
|
@@ -4144,17 +4179,17 @@ function discoverSkills(worktreePath) {
|
|
|
4144
4179
|
const home = homedir();
|
|
4145
4180
|
const collected = [];
|
|
4146
4181
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
4147
|
-
scanSkillsDir(
|
|
4182
|
+
scanSkillsDir(join11(worktreePath, rel), "workspace", collected);
|
|
4148
4183
|
}
|
|
4149
4184
|
for (const abs of [
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4185
|
+
join11(home, ".claude/skills"),
|
|
4186
|
+
join11(home, ".cursor/skills"),
|
|
4187
|
+
join11(home, ".sideboard/skills"),
|
|
4188
|
+
join11(home, ".brightsy/skills")
|
|
4154
4189
|
]) {
|
|
4155
4190
|
scanSkillsDir(abs, "user", collected);
|
|
4156
4191
|
}
|
|
4157
|
-
scanClaudePluginSkills(
|
|
4192
|
+
scanClaudePluginSkills(join11(home, ".claude/plugins"), collected);
|
|
4158
4193
|
const rank = { workspace: 0, user: 1, cli: 2 };
|
|
4159
4194
|
const byCommand = /* @__PURE__ */ new Map();
|
|
4160
4195
|
for (const skill of collected) {
|
|
@@ -4166,7 +4201,7 @@ function discoverSkills(worktreePath) {
|
|
|
4166
4201
|
return [...byCommand.values()].sort((a, b) => a.command.localeCompare(b.command));
|
|
4167
4202
|
}
|
|
4168
4203
|
function readSkillBody(skillPath, maxChars = 12e3) {
|
|
4169
|
-
const raw =
|
|
4204
|
+
const raw = readFileSync8(skillPath, "utf8");
|
|
4170
4205
|
if (raw.startsWith("---")) {
|
|
4171
4206
|
const end = raw.indexOf("\n---", 3);
|
|
4172
4207
|
if (end >= 0) {
|
|
@@ -4259,8 +4294,8 @@ function expandComposerPrompt(worktreePath, prompt, opts) {
|
|
|
4259
4294
|
}
|
|
4260
4295
|
|
|
4261
4296
|
// src/composer/stage-files.ts
|
|
4262
|
-
import { copyFileSync as copyFileSync3, existsSync as existsSync12, mkdirSync as mkdirSync4, readFileSync as
|
|
4263
|
-
import { basename as basename3, extname, join as
|
|
4297
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync12, mkdirSync as mkdirSync4, readFileSync as readFileSync9, statSync as statSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
4298
|
+
import { basename as basename3, extname, join as join12 } from "path";
|
|
4264
4299
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
4265
4300
|
var IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
|
|
4266
4301
|
"png",
|
|
@@ -4295,22 +4330,22 @@ function imageMimeType(filePath) {
|
|
|
4295
4330
|
return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
|
|
4296
4331
|
}
|
|
4297
4332
|
function ensureAttachmentsDir(worktreePath) {
|
|
4298
|
-
const dir =
|
|
4333
|
+
const dir = join12(worktreePath, ATTACHMENTS_DIR);
|
|
4299
4334
|
mkdirSync4(dir, { recursive: true });
|
|
4300
|
-
const gi =
|
|
4335
|
+
const gi = join12(dir, ".gitignore");
|
|
4301
4336
|
if (!existsSync12(gi)) {
|
|
4302
|
-
|
|
4337
|
+
writeFileSync4(gi, attachmentsGitignoreBody(), "utf8");
|
|
4303
4338
|
}
|
|
4304
4339
|
return dir;
|
|
4305
4340
|
}
|
|
4306
4341
|
function uniqueAttachmentName(dir, originalName) {
|
|
4307
4342
|
const safe = originalName.replace(/[/\\]/g, "_") || "file";
|
|
4308
|
-
if (!existsSync12(
|
|
4343
|
+
if (!existsSync12(join12(dir, safe))) return safe;
|
|
4309
4344
|
const ext = extname(safe);
|
|
4310
4345
|
const stem = ext ? safe.slice(0, -ext.length) : safe;
|
|
4311
4346
|
for (let i = 1; i < 1e4; i++) {
|
|
4312
4347
|
const candidate = `${stem}-${i}${ext}`;
|
|
4313
|
-
if (!existsSync12(
|
|
4348
|
+
if (!existsSync12(join12(dir, candidate))) return candidate;
|
|
4314
4349
|
}
|
|
4315
4350
|
return `${stem}-${randomUUID4()}${ext}`;
|
|
4316
4351
|
}
|
|
@@ -4371,10 +4406,10 @@ function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
|
4371
4406
|
const st = statSync4(abs);
|
|
4372
4407
|
if (!st.isFile()) continue;
|
|
4373
4408
|
const name = uniqueAttachmentName(dir, originalName);
|
|
4374
|
-
const destAbs =
|
|
4409
|
+
const destAbs = join12(dir, name);
|
|
4375
4410
|
copyFileSync3(abs, destAbs);
|
|
4376
4411
|
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
4377
|
-
const buf =
|
|
4412
|
+
const buf = readFileSync9(destAbs);
|
|
4378
4413
|
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
4379
4414
|
} catch (err) {
|
|
4380
4415
|
out.push({
|
|
@@ -4396,8 +4431,8 @@ function stageBuffersAsAttachments(worktreePath, buffers) {
|
|
|
4396
4431
|
try {
|
|
4397
4432
|
const buf = Buffer.from(item.dataBase64, "base64");
|
|
4398
4433
|
const name = uniqueAttachmentName(dir, originalName);
|
|
4399
|
-
const destAbs =
|
|
4400
|
-
|
|
4434
|
+
const destAbs = join12(dir, name);
|
|
4435
|
+
writeFileSync4(destAbs, buf);
|
|
4401
4436
|
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
4402
4437
|
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
4403
4438
|
} catch (err) {
|
|
@@ -4425,10 +4460,10 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
|
4425
4460
|
}
|
|
4426
4461
|
const name = basename3(rel);
|
|
4427
4462
|
try {
|
|
4428
|
-
const abs =
|
|
4463
|
+
const abs = join12(worktreePath, rel);
|
|
4429
4464
|
const st = statSync4(abs);
|
|
4430
4465
|
if (!st.isFile()) continue;
|
|
4431
|
-
const buf =
|
|
4466
|
+
const buf = readFileSync9(abs);
|
|
4432
4467
|
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
4433
4468
|
} catch (err) {
|
|
4434
4469
|
out.push({
|
|
@@ -4443,8 +4478,8 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
|
4443
4478
|
}
|
|
4444
4479
|
|
|
4445
4480
|
// src/agents/instructions.ts
|
|
4446
|
-
import { existsSync as existsSync13, readFileSync as
|
|
4447
|
-
import { join as
|
|
4481
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10, statSync as statSync5 } from "fs";
|
|
4482
|
+
import { join as join13 } from "path";
|
|
4448
4483
|
function normPath(p) {
|
|
4449
4484
|
return p.replace(/\/+$/, "");
|
|
4450
4485
|
}
|
|
@@ -4961,7 +4996,9 @@ var Orchestrator = class {
|
|
|
4961
4996
|
updateThread(thread.id, patch);
|
|
4962
4997
|
this.emit({ type: "queue_changed", threadId: thread.id, queue });
|
|
4963
4998
|
this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
|
|
4964
|
-
|
|
4999
|
+
if (thisProcessShouldDrainAgentQueues()) {
|
|
5000
|
+
void this.drainQueue(thread.id);
|
|
5001
|
+
}
|
|
4965
5002
|
return this.requireThread(thread.id);
|
|
4966
5003
|
});
|
|
4967
5004
|
}
|
|
@@ -5014,10 +5051,10 @@ var Orchestrator = class {
|
|
|
5014
5051
|
async sendQueuedMessageNow(threadRef, index) {
|
|
5015
5052
|
const thread = this.requireThread(threadRef);
|
|
5016
5053
|
const promoted = await withThreadLock(thread.id, async () => {
|
|
5017
|
-
const
|
|
5018
|
-
if (index < 0 || index >=
|
|
5019
|
-
const item =
|
|
5020
|
-
const rest =
|
|
5054
|
+
const current2 = this.requireThread(thread.id);
|
|
5055
|
+
if (index < 0 || index >= current2.queue.length) return false;
|
|
5056
|
+
const item = current2.queue[index];
|
|
5057
|
+
const rest = current2.queue.filter((_, i) => i !== index);
|
|
5021
5058
|
const queue = [item, ...rest];
|
|
5022
5059
|
this.haltDrain.delete(thread.id);
|
|
5023
5060
|
updateThread(thread.id, { queue });
|
|
@@ -5025,10 +5062,16 @@ var Orchestrator = class {
|
|
|
5025
5062
|
return true;
|
|
5026
5063
|
});
|
|
5027
5064
|
if (!promoted) return this.requireThread(thread.id);
|
|
5065
|
+
const current = this.requireThread(thread.id);
|
|
5028
5066
|
const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id);
|
|
5067
|
+
const livePid = current.agentPid;
|
|
5068
|
+
const foreignLive = !inFlight && typeof livePid === "number" && livePid > 0 && isPidAlive(livePid);
|
|
5029
5069
|
if (inFlight) {
|
|
5030
5070
|
this.stop(thread.id, { clearQueue: false, continueQueue: true });
|
|
5031
5071
|
} else {
|
|
5072
|
+
if (foreignLive) {
|
|
5073
|
+
this.stop(thread.id, { clearQueue: false, continueQueue: true });
|
|
5074
|
+
}
|
|
5032
5075
|
void this.drainQueue(thread.id);
|
|
5033
5076
|
}
|
|
5034
5077
|
return this.requireThread(thread.id);
|
|
@@ -5463,6 +5506,13 @@ var Orchestrator = class {
|
|
|
5463
5506
|
if (handle) handle.kill();
|
|
5464
5507
|
const proc = this.processes.get(`${thread.id}:agent`);
|
|
5465
5508
|
if (proc) proc.kill();
|
|
5509
|
+
const pid = thread.agentPid;
|
|
5510
|
+
if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) {
|
|
5511
|
+
try {
|
|
5512
|
+
process.kill(pid, "SIGTERM");
|
|
5513
|
+
} catch {
|
|
5514
|
+
}
|
|
5515
|
+
}
|
|
5466
5516
|
const stopped = writeLiveStatus(thread.id, "stopped") ?? readThread(thread.id) ?? thread;
|
|
5467
5517
|
if (stopped.status === "stopped") {
|
|
5468
5518
|
this.emit({ type: "status_changed", threadId: thread.id, status: "stopped" });
|