runcastle 1.2.1 → 1.2.3
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 +45 -11
- package/index.js +45 -11
- package/package.json +1 -1
- package/web/assets/index-BhOja4Fc.js +142 -0
- package/web/index.html +1 -1
- package/web/assets/index-Co7aViQi.js +0 -142
package/bin/runcastle.js
CHANGED
|
@@ -914,6 +914,23 @@ var init_resolve_executable = __esm(() => {
|
|
|
914
914
|
};
|
|
915
915
|
});
|
|
916
916
|
|
|
917
|
+
// src/pty/kill-tree.ts
|
|
918
|
+
import { execFile } from "child_process";
|
|
919
|
+
import { promisify } from "util";
|
|
920
|
+
async function killProcessTree(pid) {
|
|
921
|
+
try {
|
|
922
|
+
if (process.platform === "win32") {
|
|
923
|
+
await execFileAsync("taskkill", ["/pid", String(pid), "/T", "/F"], { windowsHide: true });
|
|
924
|
+
} else {
|
|
925
|
+
process.kill(-pid, "SIGTERM");
|
|
926
|
+
}
|
|
927
|
+
} catch {}
|
|
928
|
+
}
|
|
929
|
+
var execFileAsync;
|
|
930
|
+
var init_kill_tree = __esm(() => {
|
|
931
|
+
execFileAsync = promisify(execFile);
|
|
932
|
+
});
|
|
933
|
+
|
|
917
934
|
// src/pty/pty-sidecar.ts
|
|
918
935
|
import { spawn } from "child_process";
|
|
919
936
|
import { createRequire } from "module";
|
|
@@ -1095,6 +1112,9 @@ ${why.replace(/\n/g, `\r
|
|
|
1095
1112
|
}
|
|
1096
1113
|
}, 500);
|
|
1097
1114
|
},
|
|
1115
|
+
killTree() {
|
|
1116
|
+
return killProcessTree(process.platform === "win32" ? child.pid ?? pid : pid);
|
|
1117
|
+
},
|
|
1098
1118
|
get pid() {
|
|
1099
1119
|
return pid;
|
|
1100
1120
|
},
|
|
@@ -1107,6 +1127,7 @@ var HOST_PATH;
|
|
|
1107
1127
|
var init_pty_sidecar = __esm(() => {
|
|
1108
1128
|
init_asset_paths();
|
|
1109
1129
|
init_resolve_executable();
|
|
1130
|
+
init_kill_tree();
|
|
1110
1131
|
HOST_PATH = resolveAsset(ASSET_ENV.ptyHost, fileURLToPath(new URL("./pty-host.cjs", import.meta.url)));
|
|
1111
1132
|
});
|
|
1112
1133
|
|
|
@@ -1193,6 +1214,9 @@ function createNativePtySession(cmd, args, opts) {
|
|
|
1193
1214
|
proc.kill();
|
|
1194
1215
|
} catch {}
|
|
1195
1216
|
},
|
|
1217
|
+
killTree() {
|
|
1218
|
+
return killProcessTree(proc.pid);
|
|
1219
|
+
},
|
|
1196
1220
|
get pid() {
|
|
1197
1221
|
return proc.pid;
|
|
1198
1222
|
},
|
|
@@ -1204,6 +1228,7 @@ function createNativePtySession(cmd, args, opts) {
|
|
|
1204
1228
|
var cached = null, BACKEND_LOGGED;
|
|
1205
1229
|
var init_pty = __esm(() => {
|
|
1206
1230
|
init_resolve_executable();
|
|
1231
|
+
init_kill_tree();
|
|
1207
1232
|
init_pty_sidecar();
|
|
1208
1233
|
BACKEND_LOGGED = Symbol.for("runcastle.pty.backend.logged");
|
|
1209
1234
|
});
|
|
@@ -1855,18 +1880,24 @@ function devPaneLive(paneId) {
|
|
|
1855
1880
|
const entry = ptyRegistry().get(paneId);
|
|
1856
1881
|
return !!entry && !entry.exited;
|
|
1857
1882
|
}
|
|
1858
|
-
function
|
|
1883
|
+
function killTreeBounded(pty) {
|
|
1884
|
+
return new Promise((resolve4) => {
|
|
1885
|
+
const timer = setTimeout(resolve4, KILL_TREE_TIMEOUT_MS);
|
|
1886
|
+
pty.killTree().catch(() => {}).then(() => {
|
|
1887
|
+
clearTimeout(timer);
|
|
1888
|
+
resolve4();
|
|
1889
|
+
});
|
|
1890
|
+
});
|
|
1891
|
+
}
|
|
1892
|
+
async function stopDevPane(paneId) {
|
|
1859
1893
|
const reg = ptyRegistry();
|
|
1860
1894
|
const entry = reg.get(paneId);
|
|
1861
|
-
if (entry && !entry.exited
|
|
1862
|
-
|
|
1863
|
-
process.kill(-entry.pty.pid, "SIGTERM");
|
|
1864
|
-
} catch {}
|
|
1865
|
-
}
|
|
1895
|
+
if (entry && !entry.exited)
|
|
1896
|
+
await killTreeBounded(entry.pty);
|
|
1866
1897
|
reg.kill(paneId);
|
|
1867
1898
|
reg.remove(paneId);
|
|
1868
1899
|
}
|
|
1869
|
-
var DRIVE_PREFIX = "drive:", SNIFF_WINDOW = 8192;
|
|
1900
|
+
var DRIVE_PREFIX = "drive:", SNIFF_WINDOW = 8192, KILL_TREE_TIMEOUT_MS = 5000;
|
|
1870
1901
|
var init_dev_pane = __esm(() => {
|
|
1871
1902
|
init_events();
|
|
1872
1903
|
init_registry();
|
|
@@ -2795,7 +2826,7 @@ async function testDrive(ctx, project, feature, action) {
|
|
|
2795
2826
|
const detachedWorktree2 = testDriveState.detachedWorktree;
|
|
2796
2827
|
const devPaneId = testDriveState.devPaneId;
|
|
2797
2828
|
if (devPaneId)
|
|
2798
|
-
stopDevPane(devPaneId);
|
|
2829
|
+
await stopDevPane(devPaneId);
|
|
2799
2830
|
const teardown = await runDriveHookStep(ctx, scope, project.repoPath, "teardown", project.driveStopCommand, driveEnvFor(ctx, project, { slug: feature.slug, branch }, scope).env);
|
|
2800
2831
|
const carriedChanges = await dirtyPaths(g);
|
|
2801
2832
|
await g.checkout(previousBranch2);
|
|
@@ -2935,7 +2966,7 @@ async function startDryRun(ctx, project) {
|
|
|
2935
2966
|
async function stopDryRun(ctx, project, state) {
|
|
2936
2967
|
const scope = { projectId: project.id };
|
|
2937
2968
|
if (state.devPaneId)
|
|
2938
|
-
stopDevPane(state.devPaneId);
|
|
2969
|
+
await stopDevPane(state.devPaneId);
|
|
2939
2970
|
const teardown = await runDriveHookStep(ctx, scope, project.repoPath, "teardown", project.driveStopCommand, state.env);
|
|
2940
2971
|
state.observed.teardownOk = teardown?.result.ok;
|
|
2941
2972
|
testDriveState = undefined;
|
|
@@ -3430,7 +3461,7 @@ function landProjectSession(ctx, session) {
|
|
|
3430
3461
|
data: { sessionId: session.id, branch: PROJECT_BRANCH, ...data }
|
|
3431
3462
|
});
|
|
3432
3463
|
};
|
|
3433
|
-
landProjectBranch(project).then((res) => {
|
|
3464
|
+
const landing = landProjectBranch(project).then((res) => {
|
|
3434
3465
|
if (!res)
|
|
3435
3466
|
return;
|
|
3436
3467
|
if (res.landed) {
|
|
@@ -3443,6 +3474,8 @@ function landProjectSession(ctx, session) {
|
|
|
3443
3474
|
}).catch((e) => {
|
|
3444
3475
|
report("project.land_failed", `could not land the project session's work onto ${project.mainBranch}: ${e instanceof Error ? e.message : String(e)} \u2014 ${kept}`, { error: e instanceof Error ? e.message : String(e) });
|
|
3445
3476
|
});
|
|
3477
|
+
inFlightLandings.add(landing);
|
|
3478
|
+
landing.finally(() => inFlightLandings.delete(landing));
|
|
3446
3479
|
}
|
|
3447
3480
|
function markSessionEnded(ctx, id) {
|
|
3448
3481
|
const existing = getSessionRow(ctx, id);
|
|
@@ -3471,7 +3504,7 @@ function mostRecentLiveSession(ctx) {
|
|
|
3471
3504
|
const row = ctx.db.select().from(sessions).where(eq5(sessions.status, "live")).orderBy(desc3(sql2`rowid`)).limit(1).get();
|
|
3472
3505
|
return row ? rowToSession(row) : null;
|
|
3473
3506
|
}
|
|
3474
|
-
var KICKOFF_DELAY_MS = 1500, KICKOFF_SUBMIT_DELAY_MS = 350, KICKOFF_CONFIRM_MS = 12000, KICKOFF_MAX_ATTEMPTS = 3, CLEAR_INPUT = "\x15", SESSION_READY_TIMEOUT_MS = 25000, CONVERGE_KICKOFF_LINE, KICKOFF_LINES, RESUME_KICKOFF_PREFIX, pendingKickoffOverrides, deliveries, MATCH_PREFIX = 40, landedProjectSessions;
|
|
3507
|
+
var KICKOFF_DELAY_MS = 1500, KICKOFF_SUBMIT_DELAY_MS = 350, KICKOFF_CONFIRM_MS = 12000, KICKOFF_MAX_ATTEMPTS = 3, CLEAR_INPUT = "\x15", SESSION_READY_TIMEOUT_MS = 25000, CONVERGE_KICKOFF_LINE, KICKOFF_LINES, RESUME_KICKOFF_PREFIX, pendingKickoffOverrides, deliveries, MATCH_PREFIX = 40, landedProjectSessions, inFlightLandings;
|
|
3475
3508
|
var init_sessions = __esm(() => {
|
|
3476
3509
|
init_src();
|
|
3477
3510
|
init_schema();
|
|
@@ -3494,6 +3527,7 @@ var init_sessions = __esm(() => {
|
|
|
3494
3527
|
pendingKickoffOverrides = new Map;
|
|
3495
3528
|
deliveries = new Map;
|
|
3496
3529
|
landedProjectSessions = new Set;
|
|
3530
|
+
inFlightLandings = new Set;
|
|
3497
3531
|
});
|
|
3498
3532
|
|
|
3499
3533
|
// src/launcher/reconcile.ts
|
package/index.js
CHANGED
|
@@ -913,6 +913,23 @@ var init_resolve_executable = __esm(() => {
|
|
|
913
913
|
};
|
|
914
914
|
});
|
|
915
915
|
|
|
916
|
+
// src/pty/kill-tree.ts
|
|
917
|
+
import { execFile } from "child_process";
|
|
918
|
+
import { promisify } from "util";
|
|
919
|
+
async function killProcessTree(pid) {
|
|
920
|
+
try {
|
|
921
|
+
if (process.platform === "win32") {
|
|
922
|
+
await execFileAsync("taskkill", ["/pid", String(pid), "/T", "/F"], { windowsHide: true });
|
|
923
|
+
} else {
|
|
924
|
+
process.kill(-pid, "SIGTERM");
|
|
925
|
+
}
|
|
926
|
+
} catch {}
|
|
927
|
+
}
|
|
928
|
+
var execFileAsync;
|
|
929
|
+
var init_kill_tree = __esm(() => {
|
|
930
|
+
execFileAsync = promisify(execFile);
|
|
931
|
+
});
|
|
932
|
+
|
|
916
933
|
// src/pty/pty-sidecar.ts
|
|
917
934
|
import { spawn } from "child_process";
|
|
918
935
|
import { createRequire } from "module";
|
|
@@ -1094,6 +1111,9 @@ ${why.replace(/\n/g, `\r
|
|
|
1094
1111
|
}
|
|
1095
1112
|
}, 500);
|
|
1096
1113
|
},
|
|
1114
|
+
killTree() {
|
|
1115
|
+
return killProcessTree(process.platform === "win32" ? child.pid ?? pid : pid);
|
|
1116
|
+
},
|
|
1097
1117
|
get pid() {
|
|
1098
1118
|
return pid;
|
|
1099
1119
|
},
|
|
@@ -1106,6 +1126,7 @@ var HOST_PATH;
|
|
|
1106
1126
|
var init_pty_sidecar = __esm(() => {
|
|
1107
1127
|
init_asset_paths();
|
|
1108
1128
|
init_resolve_executable();
|
|
1129
|
+
init_kill_tree();
|
|
1109
1130
|
HOST_PATH = resolveAsset(ASSET_ENV.ptyHost, fileURLToPath(new URL("./pty-host.cjs", import.meta.url)));
|
|
1110
1131
|
});
|
|
1111
1132
|
|
|
@@ -1192,6 +1213,9 @@ function createNativePtySession(cmd, args, opts) {
|
|
|
1192
1213
|
proc.kill();
|
|
1193
1214
|
} catch {}
|
|
1194
1215
|
},
|
|
1216
|
+
killTree() {
|
|
1217
|
+
return killProcessTree(proc.pid);
|
|
1218
|
+
},
|
|
1195
1219
|
get pid() {
|
|
1196
1220
|
return proc.pid;
|
|
1197
1221
|
},
|
|
@@ -1203,6 +1227,7 @@ function createNativePtySession(cmd, args, opts) {
|
|
|
1203
1227
|
var cached = null, BACKEND_LOGGED;
|
|
1204
1228
|
var init_pty = __esm(() => {
|
|
1205
1229
|
init_resolve_executable();
|
|
1230
|
+
init_kill_tree();
|
|
1206
1231
|
init_pty_sidecar();
|
|
1207
1232
|
BACKEND_LOGGED = Symbol.for("runcastle.pty.backend.logged");
|
|
1208
1233
|
});
|
|
@@ -1854,18 +1879,24 @@ function devPaneLive(paneId) {
|
|
|
1854
1879
|
const entry = ptyRegistry().get(paneId);
|
|
1855
1880
|
return !!entry && !entry.exited;
|
|
1856
1881
|
}
|
|
1857
|
-
function
|
|
1882
|
+
function killTreeBounded(pty) {
|
|
1883
|
+
return new Promise((resolve4) => {
|
|
1884
|
+
const timer = setTimeout(resolve4, KILL_TREE_TIMEOUT_MS);
|
|
1885
|
+
pty.killTree().catch(() => {}).then(() => {
|
|
1886
|
+
clearTimeout(timer);
|
|
1887
|
+
resolve4();
|
|
1888
|
+
});
|
|
1889
|
+
});
|
|
1890
|
+
}
|
|
1891
|
+
async function stopDevPane(paneId) {
|
|
1858
1892
|
const reg = ptyRegistry();
|
|
1859
1893
|
const entry = reg.get(paneId);
|
|
1860
|
-
if (entry && !entry.exited
|
|
1861
|
-
|
|
1862
|
-
process.kill(-entry.pty.pid, "SIGTERM");
|
|
1863
|
-
} catch {}
|
|
1864
|
-
}
|
|
1894
|
+
if (entry && !entry.exited)
|
|
1895
|
+
await killTreeBounded(entry.pty);
|
|
1865
1896
|
reg.kill(paneId);
|
|
1866
1897
|
reg.remove(paneId);
|
|
1867
1898
|
}
|
|
1868
|
-
var DRIVE_PREFIX = "drive:", SNIFF_WINDOW = 8192;
|
|
1899
|
+
var DRIVE_PREFIX = "drive:", SNIFF_WINDOW = 8192, KILL_TREE_TIMEOUT_MS = 5000;
|
|
1869
1900
|
var init_dev_pane = __esm(() => {
|
|
1870
1901
|
init_events();
|
|
1871
1902
|
init_registry();
|
|
@@ -2794,7 +2825,7 @@ async function testDrive(ctx, project, feature, action) {
|
|
|
2794
2825
|
const detachedWorktree2 = testDriveState.detachedWorktree;
|
|
2795
2826
|
const devPaneId = testDriveState.devPaneId;
|
|
2796
2827
|
if (devPaneId)
|
|
2797
|
-
stopDevPane(devPaneId);
|
|
2828
|
+
await stopDevPane(devPaneId);
|
|
2798
2829
|
const teardown = await runDriveHookStep(ctx, scope, project.repoPath, "teardown", project.driveStopCommand, driveEnvFor(ctx, project, { slug: feature.slug, branch }, scope).env);
|
|
2799
2830
|
const carriedChanges = await dirtyPaths(g);
|
|
2800
2831
|
await g.checkout(previousBranch2);
|
|
@@ -2934,7 +2965,7 @@ async function startDryRun(ctx, project) {
|
|
|
2934
2965
|
async function stopDryRun(ctx, project, state) {
|
|
2935
2966
|
const scope = { projectId: project.id };
|
|
2936
2967
|
if (state.devPaneId)
|
|
2937
|
-
stopDevPane(state.devPaneId);
|
|
2968
|
+
await stopDevPane(state.devPaneId);
|
|
2938
2969
|
const teardown = await runDriveHookStep(ctx, scope, project.repoPath, "teardown", project.driveStopCommand, state.env);
|
|
2939
2970
|
state.observed.teardownOk = teardown?.result.ok;
|
|
2940
2971
|
testDriveState = undefined;
|
|
@@ -3429,7 +3460,7 @@ function landProjectSession(ctx, session) {
|
|
|
3429
3460
|
data: { sessionId: session.id, branch: PROJECT_BRANCH, ...data }
|
|
3430
3461
|
});
|
|
3431
3462
|
};
|
|
3432
|
-
landProjectBranch(project).then((res) => {
|
|
3463
|
+
const landing = landProjectBranch(project).then((res) => {
|
|
3433
3464
|
if (!res)
|
|
3434
3465
|
return;
|
|
3435
3466
|
if (res.landed) {
|
|
@@ -3442,6 +3473,8 @@ function landProjectSession(ctx, session) {
|
|
|
3442
3473
|
}).catch((e) => {
|
|
3443
3474
|
report("project.land_failed", `could not land the project session's work onto ${project.mainBranch}: ${e instanceof Error ? e.message : String(e)} \u2014 ${kept}`, { error: e instanceof Error ? e.message : String(e) });
|
|
3444
3475
|
});
|
|
3476
|
+
inFlightLandings.add(landing);
|
|
3477
|
+
landing.finally(() => inFlightLandings.delete(landing));
|
|
3445
3478
|
}
|
|
3446
3479
|
function markSessionEnded(ctx, id) {
|
|
3447
3480
|
const existing = getSessionRow(ctx, id);
|
|
@@ -3470,7 +3503,7 @@ function mostRecentLiveSession(ctx) {
|
|
|
3470
3503
|
const row = ctx.db.select().from(sessions).where(eq5(sessions.status, "live")).orderBy(desc3(sql2`rowid`)).limit(1).get();
|
|
3471
3504
|
return row ? rowToSession(row) : null;
|
|
3472
3505
|
}
|
|
3473
|
-
var KICKOFF_DELAY_MS = 1500, KICKOFF_SUBMIT_DELAY_MS = 350, KICKOFF_CONFIRM_MS = 12000, KICKOFF_MAX_ATTEMPTS = 3, CLEAR_INPUT = "\x15", SESSION_READY_TIMEOUT_MS = 25000, CONVERGE_KICKOFF_LINE, KICKOFF_LINES, RESUME_KICKOFF_PREFIX, pendingKickoffOverrides, deliveries, MATCH_PREFIX = 40, landedProjectSessions;
|
|
3506
|
+
var KICKOFF_DELAY_MS = 1500, KICKOFF_SUBMIT_DELAY_MS = 350, KICKOFF_CONFIRM_MS = 12000, KICKOFF_MAX_ATTEMPTS = 3, CLEAR_INPUT = "\x15", SESSION_READY_TIMEOUT_MS = 25000, CONVERGE_KICKOFF_LINE, KICKOFF_LINES, RESUME_KICKOFF_PREFIX, pendingKickoffOverrides, deliveries, MATCH_PREFIX = 40, landedProjectSessions, inFlightLandings;
|
|
3474
3507
|
var init_sessions = __esm(() => {
|
|
3475
3508
|
init_src();
|
|
3476
3509
|
init_schema();
|
|
@@ -3493,6 +3526,7 @@ var init_sessions = __esm(() => {
|
|
|
3493
3526
|
pendingKickoffOverrides = new Map;
|
|
3494
3527
|
deliveries = new Map;
|
|
3495
3528
|
landedProjectSessions = new Set;
|
|
3529
|
+
inFlightLandings = new Set;
|
|
3496
3530
|
});
|
|
3497
3531
|
|
|
3498
3532
|
// src/launcher/reconcile.ts
|