runcastle 1.4.7 → 1.4.8
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/bin/runcastle.js +120 -73
- package/index.js +120 -73
- package/package.json +1 -1
- package/web/assets/{index-e056iqcB.js → index-CUoLAKY6.js} +25 -25
- package/web/index.html +1 -1
package/bin/runcastle.js
CHANGED
|
@@ -4640,6 +4640,63 @@ var init_git = __esm(() => {
|
|
|
4640
4640
|
];
|
|
4641
4641
|
});
|
|
4642
4642
|
|
|
4643
|
+
// src/doctor/system-exec.ts
|
|
4644
|
+
import { spawn as spawn4 } from "child_process";
|
|
4645
|
+
function createSystemExec(opts = {}) {
|
|
4646
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_EXEC_TIMEOUT_MS;
|
|
4647
|
+
const containFn = opts.containFn ?? containHostProcess;
|
|
4648
|
+
return (command, args) => new Promise((resolve4) => {
|
|
4649
|
+
const { file, args: spawnArgs } = resolveSpawnTarget(command, args);
|
|
4650
|
+
let stdout = "";
|
|
4651
|
+
let stderr = "";
|
|
4652
|
+
let settled = false;
|
|
4653
|
+
const settle = (outcome) => {
|
|
4654
|
+
if (settled)
|
|
4655
|
+
return;
|
|
4656
|
+
settled = true;
|
|
4657
|
+
clearTimeout(timer);
|
|
4658
|
+
resolve4(outcome);
|
|
4659
|
+
};
|
|
4660
|
+
const child = spawn4(file, spawnArgs, { cwd: opts.cwd, windowsHide: true });
|
|
4661
|
+
const containment = child.pid === undefined ? null : containFn(child.pid);
|
|
4662
|
+
const timer = setTimeout(() => {
|
|
4663
|
+
if (containment)
|
|
4664
|
+
containment.kill();
|
|
4665
|
+
else if (child.pid !== undefined)
|
|
4666
|
+
killProcessTree(child.pid);
|
|
4667
|
+
const note = `${command} ${args.join(" ")} timed out after ${Math.round(timeoutMs / 1000)}s`;
|
|
4668
|
+
settle({
|
|
4669
|
+
ok: true,
|
|
4670
|
+
code: null,
|
|
4671
|
+
stdout,
|
|
4672
|
+
stderr: stderr ? `${stderr}
|
|
4673
|
+
${note}` : note,
|
|
4674
|
+
timedOut: true
|
|
4675
|
+
});
|
|
4676
|
+
}, timeoutMs);
|
|
4677
|
+
child.stdout?.on("data", (d) => {
|
|
4678
|
+
stdout += d.toString();
|
|
4679
|
+
});
|
|
4680
|
+
child.stderr?.on("data", (d) => {
|
|
4681
|
+
stderr += d.toString();
|
|
4682
|
+
});
|
|
4683
|
+
child.on("error", (err) => {
|
|
4684
|
+
containment?.kill();
|
|
4685
|
+
settle({ ok: false, code: null, stdout, stderr: stderr || String(err) });
|
|
4686
|
+
});
|
|
4687
|
+
child.on("close", (code) => {
|
|
4688
|
+
containment?.kill();
|
|
4689
|
+
settle({ ok: true, code: code ?? 0, stdout, stderr });
|
|
4690
|
+
});
|
|
4691
|
+
});
|
|
4692
|
+
}
|
|
4693
|
+
var DEFAULT_EXEC_TIMEOUT_MS = 60000;
|
|
4694
|
+
var init_system_exec = __esm(() => {
|
|
4695
|
+
init_kill_tree();
|
|
4696
|
+
init_contain_host();
|
|
4697
|
+
init_resolve_executable();
|
|
4698
|
+
});
|
|
4699
|
+
|
|
4643
4700
|
// src/launcher/edit-guard.ts
|
|
4644
4701
|
import { isAbsolute, relative, resolve as resolve4 } from "path";
|
|
4645
4702
|
function guardsEdits(kind) {
|
|
@@ -5520,8 +5577,27 @@ function buildClaudeArgs(input) {
|
|
|
5520
5577
|
...input.kickoffLine ? [input.kickoffLine] : []
|
|
5521
5578
|
];
|
|
5522
5579
|
}
|
|
5523
|
-
|
|
5580
|
+
function findBackgroundSessionIn(listing, ccSessionId) {
|
|
5581
|
+
if (!Array.isArray(listing))
|
|
5582
|
+
return;
|
|
5583
|
+
const held = listing.find((entry) => typeof entry === "object" && entry !== null && entry.sessionId === ccSessionId && entry.kind === "background");
|
|
5584
|
+
if (!held)
|
|
5585
|
+
return;
|
|
5586
|
+
return { sessionId: ccSessionId, shortId: typeof held.id === "string" ? held.id : ccSessionId.slice(0, 8) };
|
|
5587
|
+
}
|
|
5588
|
+
async function listClaudeAgents() {
|
|
5589
|
+
try {
|
|
5590
|
+
const out = await createSystemExec({ timeoutMs: AGENTS_LISTING_TIMEOUT_MS })(CLAUDE_BIN, ["agents", "--json"]);
|
|
5591
|
+
if (!out.ok || out.timedOut)
|
|
5592
|
+
return;
|
|
5593
|
+
return JSON.parse(out.stdout);
|
|
5594
|
+
} catch {
|
|
5595
|
+
return;
|
|
5596
|
+
}
|
|
5597
|
+
}
|
|
5598
|
+
var CC_NESTING_ENV, KICKOFF_LINES, AGENTS_LISTING_TIMEOUT_MS = 1e4, CLAUDE_BIN = "claude", claudeRuntime;
|
|
5524
5599
|
var init_claude = __esm(() => {
|
|
5600
|
+
init_system_exec();
|
|
5525
5601
|
init_resolve_executable();
|
|
5526
5602
|
init_artifacts();
|
|
5527
5603
|
init_skills_root();
|
|
@@ -5571,13 +5647,17 @@ var init_claude = __esm(() => {
|
|
|
5571
5647
|
}),
|
|
5572
5648
|
env: {
|
|
5573
5649
|
RUNCASTLE_SESSION_ID: input.session.id,
|
|
5574
|
-
RUNCASTLE_SERVER_URL: input.serverUrl
|
|
5650
|
+
RUNCASTLE_SERVER_URL: input.serverUrl,
|
|
5651
|
+
CLAUDE_CODE_DISABLE_AGENT_VIEW: "1"
|
|
5575
5652
|
},
|
|
5576
5653
|
envScrub: CC_NESTING_ENV
|
|
5577
5654
|
};
|
|
5578
5655
|
},
|
|
5579
5656
|
kickoffLine(kind) {
|
|
5580
5657
|
return KICKOFF_LINES[kind];
|
|
5658
|
+
},
|
|
5659
|
+
async findBackgroundSession(ccSessionId) {
|
|
5660
|
+
return findBackgroundSessionIn(await listClaudeAgents(), ccSessionId);
|
|
5581
5661
|
}
|
|
5582
5662
|
};
|
|
5583
5663
|
});
|
|
@@ -8224,7 +8304,7 @@ var init_chat_branch = __esm(() => {
|
|
|
8224
8304
|
});
|
|
8225
8305
|
|
|
8226
8306
|
// src/workflows/kill-registry.ts
|
|
8227
|
-
import { spawn as
|
|
8307
|
+
import { spawn as spawn5 } from "child_process";
|
|
8228
8308
|
function log2(msg) {
|
|
8229
8309
|
console.error(`[kill-registry] ${msg}`);
|
|
8230
8310
|
}
|
|
@@ -8241,7 +8321,7 @@ function runDockerCommand(args) {
|
|
|
8241
8321
|
const timer = setTimeout(() => settle(false), DOCKER_COMMAND_TIMEOUT_MS);
|
|
8242
8322
|
timer.unref?.();
|
|
8243
8323
|
try {
|
|
8244
|
-
const child =
|
|
8324
|
+
const child = spawn5("docker", args, { windowsHide: true, stdio: "ignore" });
|
|
8245
8325
|
child.on("exit", (code) => settle(code === 0));
|
|
8246
8326
|
child.on("close", (code) => settle(code === 0));
|
|
8247
8327
|
child.on("error", () => settle(false));
|
|
@@ -8372,63 +8452,6 @@ var init_kill_registry = __esm(() => {
|
|
|
8372
8452
|
REGISTRY_KEY2 = Symbol.for("runcastle.kill.registry");
|
|
8373
8453
|
});
|
|
8374
8454
|
|
|
8375
|
-
// src/doctor/system-exec.ts
|
|
8376
|
-
import { spawn as spawn5 } from "child_process";
|
|
8377
|
-
function createSystemExec(opts = {}) {
|
|
8378
|
-
const timeoutMs = opts.timeoutMs ?? DEFAULT_EXEC_TIMEOUT_MS;
|
|
8379
|
-
const containFn = opts.containFn ?? containHostProcess;
|
|
8380
|
-
return (command, args) => new Promise((resolve9) => {
|
|
8381
|
-
const { file, args: spawnArgs } = resolveSpawnTarget(command, args);
|
|
8382
|
-
let stdout = "";
|
|
8383
|
-
let stderr = "";
|
|
8384
|
-
let settled = false;
|
|
8385
|
-
const settle = (outcome) => {
|
|
8386
|
-
if (settled)
|
|
8387
|
-
return;
|
|
8388
|
-
settled = true;
|
|
8389
|
-
clearTimeout(timer);
|
|
8390
|
-
resolve9(outcome);
|
|
8391
|
-
};
|
|
8392
|
-
const child = spawn5(file, spawnArgs, { cwd: opts.cwd, windowsHide: true });
|
|
8393
|
-
const containment = child.pid === undefined ? null : containFn(child.pid);
|
|
8394
|
-
const timer = setTimeout(() => {
|
|
8395
|
-
if (containment)
|
|
8396
|
-
containment.kill();
|
|
8397
|
-
else if (child.pid !== undefined)
|
|
8398
|
-
killProcessTree(child.pid);
|
|
8399
|
-
const note = `${command} ${args.join(" ")} timed out after ${Math.round(timeoutMs / 1000)}s`;
|
|
8400
|
-
settle({
|
|
8401
|
-
ok: true,
|
|
8402
|
-
code: null,
|
|
8403
|
-
stdout,
|
|
8404
|
-
stderr: stderr ? `${stderr}
|
|
8405
|
-
${note}` : note,
|
|
8406
|
-
timedOut: true
|
|
8407
|
-
});
|
|
8408
|
-
}, timeoutMs);
|
|
8409
|
-
child.stdout?.on("data", (d) => {
|
|
8410
|
-
stdout += d.toString();
|
|
8411
|
-
});
|
|
8412
|
-
child.stderr?.on("data", (d) => {
|
|
8413
|
-
stderr += d.toString();
|
|
8414
|
-
});
|
|
8415
|
-
child.on("error", (err) => {
|
|
8416
|
-
containment?.kill();
|
|
8417
|
-
settle({ ok: false, code: null, stdout, stderr: stderr || String(err) });
|
|
8418
|
-
});
|
|
8419
|
-
child.on("close", (code) => {
|
|
8420
|
-
containment?.kill();
|
|
8421
|
-
settle({ ok: true, code: code ?? 0, stdout, stderr });
|
|
8422
|
-
});
|
|
8423
|
-
});
|
|
8424
|
-
}
|
|
8425
|
-
var DEFAULT_EXEC_TIMEOUT_MS = 60000;
|
|
8426
|
-
var init_system_exec = __esm(() => {
|
|
8427
|
-
init_kill_tree();
|
|
8428
|
-
init_contain_host();
|
|
8429
|
-
init_resolve_executable();
|
|
8430
|
-
});
|
|
8431
|
-
|
|
8432
8455
|
// src/services/settings.ts
|
|
8433
8456
|
import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
|
|
8434
8457
|
import { dirname as dirname6 } from "path";
|
|
@@ -57734,7 +57757,8 @@ function runCommand2(bin, args2) {
|
|
|
57734
57757
|
const timer = setTimeout(() => settle(false), COMMAND_TIMEOUT_MS);
|
|
57735
57758
|
timer.unref?.();
|
|
57736
57759
|
try {
|
|
57737
|
-
const
|
|
57760
|
+
const target = spawnTargetFor(bin, [...args2]);
|
|
57761
|
+
const child = spawn8(target.file, target.args, { windowsHide: true, stdio: "ignore" });
|
|
57738
57762
|
child.on("exit", (code) => settle(code === 0));
|
|
57739
57763
|
child.on("close", (code) => settle(code === 0));
|
|
57740
57764
|
child.on("error", () => settle(false));
|
|
@@ -57800,6 +57824,7 @@ async function reapRecorder(ticketId, options = {}) {
|
|
|
57800
57824
|
var AGENT_BROWSER_BIN = "agent-browser", DEFAULT_TIMEOUT_MS2 = 1e4, POLL_INTERVAL_MS = 100, COMMAND_TIMEOUT_MS = 5000, REAL_DEPS2;
|
|
57801
57825
|
var init_recorder_reap = __esm(() => {
|
|
57802
57826
|
init_paths();
|
|
57827
|
+
init_resolve_executable();
|
|
57803
57828
|
REAL_DEPS2 = {
|
|
57804
57829
|
findBrowser: () => findOnPath(AGENT_BROWSER_BIN),
|
|
57805
57830
|
fileExists: existsSync16,
|
|
@@ -58410,7 +58435,10 @@ function couldNotReview(ticket, reason, digest) {
|
|
|
58410
58435
|
**${headline2}**` : `**${headline2}**`
|
|
58411
58436
|
};
|
|
58412
58437
|
}
|
|
58413
|
-
var FFMPEG_BIN = "ffmpeg", spawnVersion = (path2) =>
|
|
58438
|
+
var FFMPEG_BIN = "ffmpeg", spawnVersion = (path2) => {
|
|
58439
|
+
const { file, args: args2 } = spawnTargetFor(path2, ["--version"]);
|
|
58440
|
+
return spawnSync(file, args2, { timeout: 3000, stdio: "ignore", windowsHide: true });
|
|
58441
|
+
}, withheldDrives, DECLARATION, REVIEW_DIRECTORY_FS;
|
|
58414
58442
|
var init_review_ticket = __esm(() => {
|
|
58415
58443
|
init_src();
|
|
58416
58444
|
init_paths();
|
|
@@ -58420,6 +58448,7 @@ var init_review_ticket = __esm(() => {
|
|
|
58420
58448
|
init_agent_stream();
|
|
58421
58449
|
init_git();
|
|
58422
58450
|
init_review_findings();
|
|
58451
|
+
init_resolve_executable();
|
|
58423
58452
|
init_kill_registry();
|
|
58424
58453
|
init_recorder_reap();
|
|
58425
58454
|
init_recorder_reap();
|
|
@@ -65398,16 +65427,17 @@ function handlePtyExit(ctx, feature, session, meta, exitCode) {
|
|
|
65398
65427
|
if (session.runtime === "codex" && feature) {
|
|
65399
65428
|
noteResolvedMerge(ctx, session, feature).catch(() => {});
|
|
65400
65429
|
}
|
|
65430
|
+
let resumeFailureReported;
|
|
65401
65431
|
if (diedBeforeLive && meta.resumeSessionId) {
|
|
65402
|
-
|
|
65403
|
-
|
|
65404
|
-
|
|
65405
|
-
|
|
65406
|
-
|
|
65407
|
-
|
|
65408
|
-
|
|
65409
|
-
|
|
65410
|
-
}
|
|
65432
|
+
const resumeSessionId = meta.resumeSessionId;
|
|
65433
|
+
const report = (background) => emitResumeFailed(ctx, session, resumeSessionId, exitCode, background);
|
|
65434
|
+
if (meta.findBackgroundSession) {
|
|
65435
|
+
resumeFailureReported = meta.findBackgroundSession(resumeSessionId).catch(() => {
|
|
65436
|
+
return;
|
|
65437
|
+
}).then(report);
|
|
65438
|
+
} else {
|
|
65439
|
+
report(undefined);
|
|
65440
|
+
}
|
|
65411
65441
|
}
|
|
65412
65442
|
if (session.purpose === "self-plan" && feature) {
|
|
65413
65443
|
const current2 = getFeatureRow(ctx, feature.id);
|
|
@@ -65423,19 +65453,36 @@ function handlePtyExit(ctx, feature, session, meta, exitCode) {
|
|
|
65423
65453
|
message: ptyExitMessage(exitCode),
|
|
65424
65454
|
data: { sessionId: session.id, exitCode: exitCode ?? null }
|
|
65425
65455
|
});
|
|
65456
|
+
return resumeFailureReported;
|
|
65457
|
+
}
|
|
65458
|
+
function emitResumeFailed(ctx, session, resumeSessionId, exitCode, background) {
|
|
65459
|
+
const exited = `resume failed for ${session.kind} \u2014 the session exited before starting (code ${exitCode ?? "unknown"})`;
|
|
65460
|
+
const short = background?.shortId;
|
|
65461
|
+
emitForSession(ctx, session, {
|
|
65462
|
+
type: "session.resume_failed",
|
|
65463
|
+
message: short ? `${exited}: its conversation is running as a Claude Code background session (${short}), which cannot be resumed here. ` + `Run \`claude attach ${short}\` to look at it, then \`claude stop ${short}\` (stopping keeps the conversation), then relaunch.` : `${exited}; the previous conversation is still resumable`,
|
|
65464
|
+
data: {
|
|
65465
|
+
sessionId: session.id,
|
|
65466
|
+
resumeSessionId,
|
|
65467
|
+
exitCode: exitCode ?? null,
|
|
65468
|
+
...short ? { backgroundSessionId: short } : {}
|
|
65469
|
+
}
|
|
65470
|
+
});
|
|
65426
65471
|
}
|
|
65427
65472
|
function spawnEmbeddedPty(ctx, feature, session, worktreePath, runtime5, spec, meta = {}) {
|
|
65428
65473
|
const { file, args: args2 } = spawnTargetFor(runtime5.resolveBinary(), spec.argv);
|
|
65429
65474
|
const env = { ...process.env, ...spec.env };
|
|
65430
65475
|
for (const key of spec.envScrub)
|
|
65431
65476
|
delete env[key];
|
|
65477
|
+
const findBackgroundSession = runtime5.findBackgroundSession?.bind(runtime5);
|
|
65478
|
+
const exitMeta = findBackgroundSession ? { ...meta, findBackgroundSession } : meta;
|
|
65432
65479
|
try {
|
|
65433
65480
|
const entry = ptyRegistry().create({
|
|
65434
65481
|
sessionId: session.id,
|
|
65435
65482
|
cmd: file,
|
|
65436
65483
|
args: args2,
|
|
65437
65484
|
opts: { cwd: worktreePath, env, cols: 80, rows: 24, useConpty: true },
|
|
65438
|
-
onExit: ({ exitCode }) => handlePtyExit(ctx, feature, session,
|
|
65485
|
+
onExit: ({ exitCode }) => void handlePtyExit(ctx, feature, session, exitMeta, exitCode)
|
|
65439
65486
|
});
|
|
65440
65487
|
if (feature)
|
|
65441
65488
|
startDocsWatch(ctx, feature);
|
package/index.js
CHANGED
|
@@ -4639,6 +4639,63 @@ var init_git = __esm(() => {
|
|
|
4639
4639
|
];
|
|
4640
4640
|
});
|
|
4641
4641
|
|
|
4642
|
+
// src/doctor/system-exec.ts
|
|
4643
|
+
import { spawn as spawn4 } from "child_process";
|
|
4644
|
+
function createSystemExec(opts = {}) {
|
|
4645
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_EXEC_TIMEOUT_MS;
|
|
4646
|
+
const containFn = opts.containFn ?? containHostProcess;
|
|
4647
|
+
return (command, args) => new Promise((resolve4) => {
|
|
4648
|
+
const { file, args: spawnArgs } = resolveSpawnTarget(command, args);
|
|
4649
|
+
let stdout = "";
|
|
4650
|
+
let stderr = "";
|
|
4651
|
+
let settled = false;
|
|
4652
|
+
const settle = (outcome) => {
|
|
4653
|
+
if (settled)
|
|
4654
|
+
return;
|
|
4655
|
+
settled = true;
|
|
4656
|
+
clearTimeout(timer);
|
|
4657
|
+
resolve4(outcome);
|
|
4658
|
+
};
|
|
4659
|
+
const child = spawn4(file, spawnArgs, { cwd: opts.cwd, windowsHide: true });
|
|
4660
|
+
const containment = child.pid === undefined ? null : containFn(child.pid);
|
|
4661
|
+
const timer = setTimeout(() => {
|
|
4662
|
+
if (containment)
|
|
4663
|
+
containment.kill();
|
|
4664
|
+
else if (child.pid !== undefined)
|
|
4665
|
+
killProcessTree(child.pid);
|
|
4666
|
+
const note = `${command} ${args.join(" ")} timed out after ${Math.round(timeoutMs / 1000)}s`;
|
|
4667
|
+
settle({
|
|
4668
|
+
ok: true,
|
|
4669
|
+
code: null,
|
|
4670
|
+
stdout,
|
|
4671
|
+
stderr: stderr ? `${stderr}
|
|
4672
|
+
${note}` : note,
|
|
4673
|
+
timedOut: true
|
|
4674
|
+
});
|
|
4675
|
+
}, timeoutMs);
|
|
4676
|
+
child.stdout?.on("data", (d) => {
|
|
4677
|
+
stdout += d.toString();
|
|
4678
|
+
});
|
|
4679
|
+
child.stderr?.on("data", (d) => {
|
|
4680
|
+
stderr += d.toString();
|
|
4681
|
+
});
|
|
4682
|
+
child.on("error", (err) => {
|
|
4683
|
+
containment?.kill();
|
|
4684
|
+
settle({ ok: false, code: null, stdout, stderr: stderr || String(err) });
|
|
4685
|
+
});
|
|
4686
|
+
child.on("close", (code) => {
|
|
4687
|
+
containment?.kill();
|
|
4688
|
+
settle({ ok: true, code: code ?? 0, stdout, stderr });
|
|
4689
|
+
});
|
|
4690
|
+
});
|
|
4691
|
+
}
|
|
4692
|
+
var DEFAULT_EXEC_TIMEOUT_MS = 60000;
|
|
4693
|
+
var init_system_exec = __esm(() => {
|
|
4694
|
+
init_kill_tree();
|
|
4695
|
+
init_contain_host();
|
|
4696
|
+
init_resolve_executable();
|
|
4697
|
+
});
|
|
4698
|
+
|
|
4642
4699
|
// src/launcher/edit-guard.ts
|
|
4643
4700
|
import { isAbsolute, relative, resolve as resolve4 } from "path";
|
|
4644
4701
|
function guardsEdits(kind) {
|
|
@@ -5519,8 +5576,27 @@ function buildClaudeArgs(input) {
|
|
|
5519
5576
|
...input.kickoffLine ? [input.kickoffLine] : []
|
|
5520
5577
|
];
|
|
5521
5578
|
}
|
|
5522
|
-
|
|
5579
|
+
function findBackgroundSessionIn(listing, ccSessionId) {
|
|
5580
|
+
if (!Array.isArray(listing))
|
|
5581
|
+
return;
|
|
5582
|
+
const held = listing.find((entry) => typeof entry === "object" && entry !== null && entry.sessionId === ccSessionId && entry.kind === "background");
|
|
5583
|
+
if (!held)
|
|
5584
|
+
return;
|
|
5585
|
+
return { sessionId: ccSessionId, shortId: typeof held.id === "string" ? held.id : ccSessionId.slice(0, 8) };
|
|
5586
|
+
}
|
|
5587
|
+
async function listClaudeAgents() {
|
|
5588
|
+
try {
|
|
5589
|
+
const out = await createSystemExec({ timeoutMs: AGENTS_LISTING_TIMEOUT_MS })(CLAUDE_BIN, ["agents", "--json"]);
|
|
5590
|
+
if (!out.ok || out.timedOut)
|
|
5591
|
+
return;
|
|
5592
|
+
return JSON.parse(out.stdout);
|
|
5593
|
+
} catch {
|
|
5594
|
+
return;
|
|
5595
|
+
}
|
|
5596
|
+
}
|
|
5597
|
+
var CC_NESTING_ENV, KICKOFF_LINES, AGENTS_LISTING_TIMEOUT_MS = 1e4, CLAUDE_BIN = "claude", claudeRuntime;
|
|
5523
5598
|
var init_claude = __esm(() => {
|
|
5599
|
+
init_system_exec();
|
|
5524
5600
|
init_resolve_executable();
|
|
5525
5601
|
init_artifacts();
|
|
5526
5602
|
init_skills_root();
|
|
@@ -5570,13 +5646,17 @@ var init_claude = __esm(() => {
|
|
|
5570
5646
|
}),
|
|
5571
5647
|
env: {
|
|
5572
5648
|
RUNCASTLE_SESSION_ID: input.session.id,
|
|
5573
|
-
RUNCASTLE_SERVER_URL: input.serverUrl
|
|
5649
|
+
RUNCASTLE_SERVER_URL: input.serverUrl,
|
|
5650
|
+
CLAUDE_CODE_DISABLE_AGENT_VIEW: "1"
|
|
5574
5651
|
},
|
|
5575
5652
|
envScrub: CC_NESTING_ENV
|
|
5576
5653
|
};
|
|
5577
5654
|
},
|
|
5578
5655
|
kickoffLine(kind) {
|
|
5579
5656
|
return KICKOFF_LINES[kind];
|
|
5657
|
+
},
|
|
5658
|
+
async findBackgroundSession(ccSessionId) {
|
|
5659
|
+
return findBackgroundSessionIn(await listClaudeAgents(), ccSessionId);
|
|
5580
5660
|
}
|
|
5581
5661
|
};
|
|
5582
5662
|
});
|
|
@@ -8223,7 +8303,7 @@ var init_chat_branch = __esm(() => {
|
|
|
8223
8303
|
});
|
|
8224
8304
|
|
|
8225
8305
|
// src/workflows/kill-registry.ts
|
|
8226
|
-
import { spawn as
|
|
8306
|
+
import { spawn as spawn5 } from "child_process";
|
|
8227
8307
|
function log2(msg) {
|
|
8228
8308
|
console.error(`[kill-registry] ${msg}`);
|
|
8229
8309
|
}
|
|
@@ -8240,7 +8320,7 @@ function runDockerCommand(args) {
|
|
|
8240
8320
|
const timer = setTimeout(() => settle(false), DOCKER_COMMAND_TIMEOUT_MS);
|
|
8241
8321
|
timer.unref?.();
|
|
8242
8322
|
try {
|
|
8243
|
-
const child =
|
|
8323
|
+
const child = spawn5("docker", args, { windowsHide: true, stdio: "ignore" });
|
|
8244
8324
|
child.on("exit", (code) => settle(code === 0));
|
|
8245
8325
|
child.on("close", (code) => settle(code === 0));
|
|
8246
8326
|
child.on("error", () => settle(false));
|
|
@@ -8371,63 +8451,6 @@ var init_kill_registry = __esm(() => {
|
|
|
8371
8451
|
REGISTRY_KEY2 = Symbol.for("runcastle.kill.registry");
|
|
8372
8452
|
});
|
|
8373
8453
|
|
|
8374
|
-
// src/doctor/system-exec.ts
|
|
8375
|
-
import { spawn as spawn5 } from "child_process";
|
|
8376
|
-
function createSystemExec(opts = {}) {
|
|
8377
|
-
const timeoutMs = opts.timeoutMs ?? DEFAULT_EXEC_TIMEOUT_MS;
|
|
8378
|
-
const containFn = opts.containFn ?? containHostProcess;
|
|
8379
|
-
return (command, args) => new Promise((resolve9) => {
|
|
8380
|
-
const { file, args: spawnArgs } = resolveSpawnTarget(command, args);
|
|
8381
|
-
let stdout = "";
|
|
8382
|
-
let stderr = "";
|
|
8383
|
-
let settled = false;
|
|
8384
|
-
const settle = (outcome) => {
|
|
8385
|
-
if (settled)
|
|
8386
|
-
return;
|
|
8387
|
-
settled = true;
|
|
8388
|
-
clearTimeout(timer);
|
|
8389
|
-
resolve9(outcome);
|
|
8390
|
-
};
|
|
8391
|
-
const child = spawn5(file, spawnArgs, { cwd: opts.cwd, windowsHide: true });
|
|
8392
|
-
const containment = child.pid === undefined ? null : containFn(child.pid);
|
|
8393
|
-
const timer = setTimeout(() => {
|
|
8394
|
-
if (containment)
|
|
8395
|
-
containment.kill();
|
|
8396
|
-
else if (child.pid !== undefined)
|
|
8397
|
-
killProcessTree(child.pid);
|
|
8398
|
-
const note = `${command} ${args.join(" ")} timed out after ${Math.round(timeoutMs / 1000)}s`;
|
|
8399
|
-
settle({
|
|
8400
|
-
ok: true,
|
|
8401
|
-
code: null,
|
|
8402
|
-
stdout,
|
|
8403
|
-
stderr: stderr ? `${stderr}
|
|
8404
|
-
${note}` : note,
|
|
8405
|
-
timedOut: true
|
|
8406
|
-
});
|
|
8407
|
-
}, timeoutMs);
|
|
8408
|
-
child.stdout?.on("data", (d) => {
|
|
8409
|
-
stdout += d.toString();
|
|
8410
|
-
});
|
|
8411
|
-
child.stderr?.on("data", (d) => {
|
|
8412
|
-
stderr += d.toString();
|
|
8413
|
-
});
|
|
8414
|
-
child.on("error", (err) => {
|
|
8415
|
-
containment?.kill();
|
|
8416
|
-
settle({ ok: false, code: null, stdout, stderr: stderr || String(err) });
|
|
8417
|
-
});
|
|
8418
|
-
child.on("close", (code) => {
|
|
8419
|
-
containment?.kill();
|
|
8420
|
-
settle({ ok: true, code: code ?? 0, stdout, stderr });
|
|
8421
|
-
});
|
|
8422
|
-
});
|
|
8423
|
-
}
|
|
8424
|
-
var DEFAULT_EXEC_TIMEOUT_MS = 60000;
|
|
8425
|
-
var init_system_exec = __esm(() => {
|
|
8426
|
-
init_kill_tree();
|
|
8427
|
-
init_contain_host();
|
|
8428
|
-
init_resolve_executable();
|
|
8429
|
-
});
|
|
8430
|
-
|
|
8431
8454
|
// src/services/settings.ts
|
|
8432
8455
|
import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
|
|
8433
8456
|
import { dirname as dirname6 } from "path";
|
|
@@ -57733,7 +57756,8 @@ function runCommand2(bin, args2) {
|
|
|
57733
57756
|
const timer = setTimeout(() => settle(false), COMMAND_TIMEOUT_MS);
|
|
57734
57757
|
timer.unref?.();
|
|
57735
57758
|
try {
|
|
57736
|
-
const
|
|
57759
|
+
const target = spawnTargetFor(bin, [...args2]);
|
|
57760
|
+
const child = spawn8(target.file, target.args, { windowsHide: true, stdio: "ignore" });
|
|
57737
57761
|
child.on("exit", (code) => settle(code === 0));
|
|
57738
57762
|
child.on("close", (code) => settle(code === 0));
|
|
57739
57763
|
child.on("error", () => settle(false));
|
|
@@ -57799,6 +57823,7 @@ async function reapRecorder(ticketId, options = {}) {
|
|
|
57799
57823
|
var AGENT_BROWSER_BIN = "agent-browser", DEFAULT_TIMEOUT_MS2 = 1e4, POLL_INTERVAL_MS = 100, COMMAND_TIMEOUT_MS = 5000, REAL_DEPS2;
|
|
57800
57824
|
var init_recorder_reap = __esm(() => {
|
|
57801
57825
|
init_paths();
|
|
57826
|
+
init_resolve_executable();
|
|
57802
57827
|
REAL_DEPS2 = {
|
|
57803
57828
|
findBrowser: () => findOnPath(AGENT_BROWSER_BIN),
|
|
57804
57829
|
fileExists: existsSync16,
|
|
@@ -58409,7 +58434,10 @@ function couldNotReview(ticket, reason, digest) {
|
|
|
58409
58434
|
**${headline2}**` : `**${headline2}**`
|
|
58410
58435
|
};
|
|
58411
58436
|
}
|
|
58412
|
-
var FFMPEG_BIN = "ffmpeg", spawnVersion = (path2) =>
|
|
58437
|
+
var FFMPEG_BIN = "ffmpeg", spawnVersion = (path2) => {
|
|
58438
|
+
const { file, args: args2 } = spawnTargetFor(path2, ["--version"]);
|
|
58439
|
+
return spawnSync(file, args2, { timeout: 3000, stdio: "ignore", windowsHide: true });
|
|
58440
|
+
}, withheldDrives, DECLARATION, REVIEW_DIRECTORY_FS;
|
|
58413
58441
|
var init_review_ticket = __esm(() => {
|
|
58414
58442
|
init_src();
|
|
58415
58443
|
init_paths();
|
|
@@ -58419,6 +58447,7 @@ var init_review_ticket = __esm(() => {
|
|
|
58419
58447
|
init_agent_stream();
|
|
58420
58448
|
init_git();
|
|
58421
58449
|
init_review_findings();
|
|
58450
|
+
init_resolve_executable();
|
|
58422
58451
|
init_kill_registry();
|
|
58423
58452
|
init_recorder_reap();
|
|
58424
58453
|
init_recorder_reap();
|
|
@@ -65397,16 +65426,17 @@ function handlePtyExit(ctx, feature, session, meta, exitCode) {
|
|
|
65397
65426
|
if (session.runtime === "codex" && feature) {
|
|
65398
65427
|
noteResolvedMerge(ctx, session, feature).catch(() => {});
|
|
65399
65428
|
}
|
|
65429
|
+
let resumeFailureReported;
|
|
65400
65430
|
if (diedBeforeLive && meta.resumeSessionId) {
|
|
65401
|
-
|
|
65402
|
-
|
|
65403
|
-
|
|
65404
|
-
|
|
65405
|
-
|
|
65406
|
-
|
|
65407
|
-
|
|
65408
|
-
|
|
65409
|
-
}
|
|
65431
|
+
const resumeSessionId = meta.resumeSessionId;
|
|
65432
|
+
const report = (background) => emitResumeFailed(ctx, session, resumeSessionId, exitCode, background);
|
|
65433
|
+
if (meta.findBackgroundSession) {
|
|
65434
|
+
resumeFailureReported = meta.findBackgroundSession(resumeSessionId).catch(() => {
|
|
65435
|
+
return;
|
|
65436
|
+
}).then(report);
|
|
65437
|
+
} else {
|
|
65438
|
+
report(undefined);
|
|
65439
|
+
}
|
|
65410
65440
|
}
|
|
65411
65441
|
if (session.purpose === "self-plan" && feature) {
|
|
65412
65442
|
const current2 = getFeatureRow(ctx, feature.id);
|
|
@@ -65422,19 +65452,36 @@ function handlePtyExit(ctx, feature, session, meta, exitCode) {
|
|
|
65422
65452
|
message: ptyExitMessage(exitCode),
|
|
65423
65453
|
data: { sessionId: session.id, exitCode: exitCode ?? null }
|
|
65424
65454
|
});
|
|
65455
|
+
return resumeFailureReported;
|
|
65456
|
+
}
|
|
65457
|
+
function emitResumeFailed(ctx, session, resumeSessionId, exitCode, background) {
|
|
65458
|
+
const exited = `resume failed for ${session.kind} \u2014 the session exited before starting (code ${exitCode ?? "unknown"})`;
|
|
65459
|
+
const short = background?.shortId;
|
|
65460
|
+
emitForSession(ctx, session, {
|
|
65461
|
+
type: "session.resume_failed",
|
|
65462
|
+
message: short ? `${exited}: its conversation is running as a Claude Code background session (${short}), which cannot be resumed here. ` + `Run \`claude attach ${short}\` to look at it, then \`claude stop ${short}\` (stopping keeps the conversation), then relaunch.` : `${exited}; the previous conversation is still resumable`,
|
|
65463
|
+
data: {
|
|
65464
|
+
sessionId: session.id,
|
|
65465
|
+
resumeSessionId,
|
|
65466
|
+
exitCode: exitCode ?? null,
|
|
65467
|
+
...short ? { backgroundSessionId: short } : {}
|
|
65468
|
+
}
|
|
65469
|
+
});
|
|
65425
65470
|
}
|
|
65426
65471
|
function spawnEmbeddedPty(ctx, feature, session, worktreePath, runtime5, spec, meta = {}) {
|
|
65427
65472
|
const { file, args: args2 } = spawnTargetFor(runtime5.resolveBinary(), spec.argv);
|
|
65428
65473
|
const env = { ...process.env, ...spec.env };
|
|
65429
65474
|
for (const key of spec.envScrub)
|
|
65430
65475
|
delete env[key];
|
|
65476
|
+
const findBackgroundSession = runtime5.findBackgroundSession?.bind(runtime5);
|
|
65477
|
+
const exitMeta = findBackgroundSession ? { ...meta, findBackgroundSession } : meta;
|
|
65431
65478
|
try {
|
|
65432
65479
|
const entry = ptyRegistry().create({
|
|
65433
65480
|
sessionId: session.id,
|
|
65434
65481
|
cmd: file,
|
|
65435
65482
|
args: args2,
|
|
65436
65483
|
opts: { cwd: worktreePath, env, cols: 80, rows: 24, useConpty: true },
|
|
65437
|
-
onExit: ({ exitCode }) => handlePtyExit(ctx, feature, session,
|
|
65484
|
+
onExit: ({ exitCode }) => void handlePtyExit(ctx, feature, session, exitMeta, exitCode)
|
|
65438
65485
|
});
|
|
65439
65486
|
if (feature)
|
|
65440
65487
|
startDocsWatch(ctx, feature);
|