oh-my-copilot 5.7.0 → 5.8.0
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +1 -0
- package/bridge/__pycache__/gyoshu_bridge.cpython-312.pyc +0 -0
- package/bridge/claude-md-coordinator.cjs +2 -2
- package/bridge/cli.cjs +6268 -4231
- package/bridge/mcp-server.cjs +4345 -735
- package/bridge/runtime-cli.cjs +848 -165
- package/bridge/team-mcp.cjs +621 -91
- package/bridge/team.js +960 -245
- package/dist/__tests__/cli-win32-warning.test.js +7 -0
- package/dist/__tests__/cli-win32-warning.test.js.map +1 -1
- package/dist/__tests__/run-cjs-copilot-worker-routing.test.d.ts +2 -0
- package/dist/__tests__/run-cjs-copilot-worker-routing.test.d.ts.map +1 -0
- package/dist/__tests__/run-cjs-copilot-worker-routing.test.js +294 -0
- package/dist/__tests__/run-cjs-copilot-worker-routing.test.js.map +1 -0
- package/dist/__tests__/run-cjs-session-end-budget.test.d.ts +2 -0
- package/dist/__tests__/run-cjs-session-end-budget.test.d.ts.map +1 -0
- package/dist/__tests__/run-cjs-session-end-budget.test.js +171 -0
- package/dist/__tests__/run-cjs-session-end-budget.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-conflicts-json.test.d.ts +2 -0
- package/dist/cli/__tests__/doctor-conflicts-json.test.d.ts.map +1 -0
- package/dist/cli/__tests__/doctor-conflicts-json.test.js +46 -0
- package/dist/cli/__tests__/doctor-conflicts-json.test.js.map +1 -0
- package/dist/cli/__tests__/team.test.js +67 -0
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/wait-teleport-json.test.d.ts +2 -0
- package/dist/cli/__tests__/wait-teleport-json.test.d.ts.map +1 -0
- package/dist/cli/__tests__/wait-teleport-json.test.js +64 -0
- package/dist/cli/__tests__/wait-teleport-json.test.js.map +1 -0
- package/dist/cli/commands/__tests__/smoke-tier2.test.js +38 -0
- package/dist/cli/commands/__tests__/smoke-tier2.test.js.map +1 -1
- package/dist/cli/commands/__tests__/team-status-json.test.d.ts +2 -0
- package/dist/cli/commands/__tests__/team-status-json.test.d.ts.map +1 -0
- package/dist/cli/commands/__tests__/team-status-json.test.js +141 -0
- package/dist/cli/commands/__tests__/team-status-json.test.js.map +1 -0
- package/dist/cli/commands/factory.d.ts +2 -0
- package/dist/cli/commands/factory.d.ts.map +1 -1
- package/dist/cli/commands/factory.js +8 -1
- package/dist/cli/commands/factory.js.map +1 -1
- package/dist/cli/commands/smoke.d.ts +1 -1
- package/dist/cli/commands/smoke.d.ts.map +1 -1
- package/dist/cli/commands/smoke.js +4 -4
- package/dist/cli/commands/smoke.js.map +1 -1
- package/dist/cli/commands/team.d.ts +2 -0
- package/dist/cli/commands/team.d.ts.map +1 -1
- package/dist/cli/commands/team.js +124 -10
- package/dist/cli/commands/team.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +34 -13
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/win32-warning.d.ts +7 -1
- package/dist/cli/win32-warning.d.ts.map +1 -1
- package/dist/cli/win32-warning.js +9 -1
- package/dist/cli/win32-warning.js.map +1 -1
- package/dist/factory/__tests__/check-run.test.js +2 -2
- package/dist/factory/__tests__/check-run.test.js.map +1 -1
- package/dist/factory/__tests__/listener.test.js +1 -1
- package/dist/factory/__tests__/listener.test.js.map +1 -1
- package/dist/factory/__tests__/status.test.js +42 -0
- package/dist/factory/__tests__/status.test.js.map +1 -1
- package/dist/factory/listener.d.ts.map +1 -1
- package/dist/factory/listener.js +7 -8
- package/dist/factory/listener.js.map +1 -1
- package/dist/factory/status.d.ts +19 -1
- package/dist/factory/status.d.ts.map +1 -1
- package/dist/factory/status.js +49 -8
- package/dist/factory/status.js.map +1 -1
- package/dist/factory/watchdog.d.ts.map +1 -1
- package/dist/factory/watchdog.js +14 -0
- package/dist/factory/watchdog.js.map +1 -1
- package/dist/factory/watchdog.test.js +45 -0
- package/dist/factory/watchdog.test.js.map +1 -1
- package/dist/hooks/session-end/__tests__/action-runner.test.js +5 -0
- package/dist/hooks/session-end/__tests__/action-runner.test.js.map +1 -1
- package/dist/hooks/session-end/__tests__/chain-enqueuer.test.js +186 -1
- package/dist/hooks/session-end/__tests__/chain-enqueuer.test.js.map +1 -1
- package/dist/hooks/session-end/__tests__/chain-link-env-passthrough.test.d.ts +2 -0
- package/dist/hooks/session-end/__tests__/chain-link-env-passthrough.test.d.ts.map +1 -0
- package/dist/hooks/session-end/__tests__/chain-link-env-passthrough.test.js +49 -0
- package/dist/hooks/session-end/__tests__/chain-link-env-passthrough.test.js.map +1 -0
- package/dist/hooks/session-end/__tests__/foreground-bootstrap.test.js +30 -1
- package/dist/hooks/session-end/__tests__/foreground-bootstrap.test.js.map +1 -1
- package/dist/hooks/session-end/__tests__/spawn-next.test.js +104 -3
- package/dist/hooks/session-end/__tests__/spawn-next.test.js.map +1 -1
- package/dist/hooks/session-end/__tests__/worker.test.js +6 -0
- package/dist/hooks/session-end/__tests__/worker.test.js.map +1 -1
- package/dist/hooks/session-end/action-runner.d.ts.map +1 -1
- package/dist/hooks/session-end/action-runner.js +2 -1
- package/dist/hooks/session-end/action-runner.js.map +1 -1
- package/dist/hooks/session-end/chain-enqueuer.d.ts +70 -7
- package/dist/hooks/session-end/chain-enqueuer.d.ts.map +1 -1
- package/dist/hooks/session-end/chain-enqueuer.js +354 -82
- package/dist/hooks/session-end/chain-enqueuer.js.map +1 -1
- package/dist/hooks/session-end/foreground-bootstrap.d.ts.map +1 -1
- package/dist/hooks/session-end/foreground-bootstrap.js +24 -16
- package/dist/hooks/session-end/foreground-bootstrap.js.map +1 -1
- package/dist/hooks/session-end/index.d.ts.map +1 -1
- package/dist/hooks/session-end/index.js +8 -3
- package/dist/hooks/session-end/index.js.map +1 -1
- package/dist/hooks/session-end/spawn-next.d.ts +81 -4
- package/dist/hooks/session-end/spawn-next.d.ts.map +1 -1
- package/dist/hooks/session-end/spawn-next.js +141 -14
- package/dist/hooks/session-end/spawn-next.js.map +1 -1
- package/dist/hooks/session-end/worker.d.ts.map +1 -1
- package/dist/hooks/session-end/worker.js +11 -6
- package/dist/hooks/session-end/worker.js.map +1 -1
- package/dist/shared/types.d.ts +11 -0
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/smoke/__tests__/copilot-chain-scenario.test.d.ts +2 -0
- package/dist/smoke/__tests__/copilot-chain-scenario.test.d.ts.map +1 -0
- package/dist/smoke/__tests__/copilot-chain-scenario.test.js +154 -0
- package/dist/smoke/__tests__/copilot-chain-scenario.test.js.map +1 -0
- package/dist/smoke/__tests__/copilot-sdk-driver.test.js +30 -0
- package/dist/smoke/__tests__/copilot-sdk-driver.test.js.map +1 -1
- package/dist/smoke/__tests__/copilot-sdk-scenarios.test.js +52 -1
- package/dist/smoke/__tests__/copilot-sdk-scenarios.test.js.map +1 -1
- package/dist/smoke/__tests__/copilot-smoke.test.js +1 -1
- package/dist/smoke/__tests__/copilot-smoke.test.js.map +1 -1
- package/dist/smoke/copilot-chain-scenario.d.ts +61 -0
- package/dist/smoke/copilot-chain-scenario.d.ts.map +1 -0
- package/dist/smoke/copilot-chain-scenario.js +253 -0
- package/dist/smoke/copilot-chain-scenario.js.map +1 -0
- package/dist/smoke/copilot-sdk-driver.d.ts +3 -0
- package/dist/smoke/copilot-sdk-driver.d.ts.map +1 -1
- package/dist/smoke/copilot-sdk-driver.js +19 -4
- package/dist/smoke/copilot-sdk-driver.js.map +1 -1
- package/dist/smoke/copilot-sdk-scenarios.d.ts +42 -1
- package/dist/smoke/copilot-sdk-scenarios.d.ts.map +1 -1
- package/dist/smoke/copilot-sdk-scenarios.js +111 -1
- package/dist/smoke/copilot-sdk-scenarios.js.map +1 -1
- package/dist/smoke/copilot-session-env.d.ts +75 -0
- package/dist/smoke/copilot-session-env.d.ts.map +1 -0
- package/dist/smoke/copilot-session-env.js +154 -0
- package/dist/smoke/copilot-session-env.js.map +1 -0
- package/dist/smoke/copilot-smoke.d.ts +2 -64
- package/dist/smoke/copilot-smoke.d.ts.map +1 -1
- package/dist/smoke/copilot-smoke.js +15 -145
- package/dist/smoke/copilot-smoke.js.map +1 -1
- package/dist/team/__tests__/runtime-v2.monitor.test.js +35 -0
- package/dist/team/__tests__/runtime-v2.monitor.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +13 -0
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/sdk-transport.runtime.test.d.ts +2 -0
- package/dist/team/__tests__/sdk-transport.runtime.test.d.ts.map +1 -0
- package/dist/team/__tests__/sdk-transport.runtime.test.js +96 -0
- package/dist/team/__tests__/sdk-transport.runtime.test.js.map +1 -0
- package/dist/team/__tests__/sdk-transport.test.d.ts +2 -0
- package/dist/team/__tests__/sdk-transport.test.d.ts.map +1 -0
- package/dist/team/__tests__/sdk-transport.test.js +650 -0
- package/dist/team/__tests__/sdk-transport.test.js.map +1 -0
- package/dist/team/api-interop.d.ts.map +1 -1
- package/dist/team/api-interop.js +8 -0
- package/dist/team/api-interop.js.map +1 -1
- package/dist/team/runtime-v2.d.ts +33 -0
- package/dist/team/runtime-v2.d.ts.map +1 -1
- package/dist/team/runtime-v2.js +338 -24
- package/dist/team/runtime-v2.js.map +1 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +5 -0
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/sdk-host.d.ts +48 -0
- package/dist/team/sdk-host.d.ts.map +1 -0
- package/dist/team/sdk-host.js +604 -0
- package/dist/team/sdk-host.js.map +1 -0
- package/dist/team/sdk-policy.d.ts +79 -0
- package/dist/team/sdk-policy.d.ts.map +1 -0
- package/dist/team/sdk-policy.js +186 -0
- package/dist/team/sdk-policy.js.map +1 -0
- package/dist/team/sdk-transport.d.ts +164 -0
- package/dist/team/sdk-transport.d.ts.map +1 -0
- package/dist/team/sdk-transport.js +266 -0
- package/dist/team/sdk-transport.js.map +1 -0
- package/dist/team/types.d.ts +2 -0
- package/dist/team/types.d.ts.map +1 -1
- package/dist/team/types.js.map +1 -1
- package/docs/CLAUDE.md +1 -1
- package/docs/DEVELOPERS.md +22 -1
- package/docs/HOOKS.md +33 -1
- package/docs/MIGRATION.md +123 -3
- package/docs/REFERENCE.md +54 -1
- package/package.json +2 -2
- package/plugin.json +1 -1
- package/scripts/run.cjs +128 -15
- package/scripts/session-start.mjs +13 -0
package/bridge/runtime-cli.cjs
CHANGED
|
@@ -3165,7 +3165,7 @@ async function withProcessIdentityFileLock(lockPath, fn, timeoutMs = 1e4) {
|
|
|
3165
3165
|
continue;
|
|
3166
3166
|
}
|
|
3167
3167
|
if (Date.now() >= deadline) throw new Error("process_identity_lock_timeout");
|
|
3168
|
-
await new Promise((
|
|
3168
|
+
await new Promise((resolve17) => setTimeout(resolve17, 25));
|
|
3169
3169
|
continue;
|
|
3170
3170
|
}
|
|
3171
3171
|
try {
|
|
@@ -3186,7 +3186,7 @@ async function withProcessIdentityFileLock(lockPath, fn, timeoutMs = 1e4) {
|
|
|
3186
3186
|
}
|
|
3187
3187
|
}
|
|
3188
3188
|
if (Date.now() >= deadline) throw new Error("process_identity_lock_timeout");
|
|
3189
|
-
await new Promise((
|
|
3189
|
+
await new Promise((resolve17) => setTimeout(resolve17, 25));
|
|
3190
3190
|
}
|
|
3191
3191
|
}
|
|
3192
3192
|
return await fn();
|
|
@@ -4845,8 +4845,8 @@ function getPackageDir() {
|
|
|
4845
4845
|
}
|
|
4846
4846
|
}
|
|
4847
4847
|
try {
|
|
4848
|
-
const
|
|
4849
|
-
const __dirname2 = (0, import_path12.dirname)(
|
|
4848
|
+
const __filename2 = (0, import_url2.fileURLToPath)(importMetaUrl);
|
|
4849
|
+
const __dirname2 = (0, import_path12.dirname)(__filename2);
|
|
4850
4850
|
const currentDirName = (0, import_path12.basename)(__dirname2);
|
|
4851
4851
|
if (currentDirName === "bridge") {
|
|
4852
4852
|
return (0, import_path12.join)(__dirname2, "..");
|
|
@@ -5628,8 +5628,8 @@ function getPackageDir2() {
|
|
|
5628
5628
|
}
|
|
5629
5629
|
}
|
|
5630
5630
|
try {
|
|
5631
|
-
const
|
|
5632
|
-
const __dirname2 = (0, import_path15.dirname)(
|
|
5631
|
+
const __filename2 = (0, import_url3.fileURLToPath)(importMetaUrl);
|
|
5632
|
+
const __dirname2 = (0, import_path15.dirname)(__filename2);
|
|
5633
5633
|
return (0, import_path15.join)(__dirname2, "..", "..", "..");
|
|
5634
5634
|
} catch {
|
|
5635
5635
|
return process.cwd();
|
|
@@ -6171,9 +6171,9 @@ function getTrustedPrefixes() {
|
|
|
6171
6171
|
function isTrustedPrefix(resolvedPath) {
|
|
6172
6172
|
const flavor = pathFlavor();
|
|
6173
6173
|
return getTrustedPrefixes().some((prefix) => {
|
|
6174
|
-
const
|
|
6175
|
-
if (
|
|
6176
|
-
return !
|
|
6174
|
+
const relative11 = flavor.relative(prefix, resolvedPath);
|
|
6175
|
+
if (relative11 === "") return true;
|
|
6176
|
+
return !relative11.startsWith("..") && !flavor.isAbsolute(relative11);
|
|
6177
6177
|
});
|
|
6178
6178
|
}
|
|
6179
6179
|
function assertBinaryName(binary) {
|
|
@@ -6967,6 +6967,32 @@ function parseDeadline(deadlineAt) {
|
|
|
6967
6967
|
const value = Date.parse(deadlineAt);
|
|
6968
6968
|
return Number.isFinite(value) ? value : void 0;
|
|
6969
6969
|
}
|
|
6970
|
+
async function killProcessTree(pid, signal = "SIGTERM") {
|
|
6971
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
6972
|
+
if (process.platform === "win32") {
|
|
6973
|
+
return killProcessTreeWindows(pid, signal === "SIGKILL");
|
|
6974
|
+
} else {
|
|
6975
|
+
return killProcessTreeUnix(pid, signal);
|
|
6976
|
+
}
|
|
6977
|
+
}
|
|
6978
|
+
async function killProcessTreeWindows(pid, force) {
|
|
6979
|
+
try {
|
|
6980
|
+
const args = ["/T", "/PID", String(pid)];
|
|
6981
|
+
if (force) {
|
|
6982
|
+
args.unshift("/F");
|
|
6983
|
+
}
|
|
6984
|
+
(0, import_child_process6.execFileSync)("taskkill.exe", args, {
|
|
6985
|
+
stdio: "ignore",
|
|
6986
|
+
timeout: 5e3,
|
|
6987
|
+
windowsHide: true
|
|
6988
|
+
});
|
|
6989
|
+
return true;
|
|
6990
|
+
} catch (err) {
|
|
6991
|
+
const error = err;
|
|
6992
|
+
if (error.status === 128) return true;
|
|
6993
|
+
return false;
|
|
6994
|
+
}
|
|
6995
|
+
}
|
|
6970
6996
|
function killProcessTreeUnix(pid, signal) {
|
|
6971
6997
|
try {
|
|
6972
6998
|
process.kill(-pid, signal);
|
|
@@ -7692,7 +7718,7 @@ function withFileLockSync(lockPath, fn, opts) {
|
|
|
7692
7718
|
}
|
|
7693
7719
|
}
|
|
7694
7720
|
function sleep(ms) {
|
|
7695
|
-
return new Promise((
|
|
7721
|
+
return new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
7696
7722
|
}
|
|
7697
7723
|
async function acquireFileLock(lockPath, opts) {
|
|
7698
7724
|
const staleLockMs = opts?.staleLockMs ?? DEFAULT_STALE_LOCK_MS;
|
|
@@ -7910,7 +7936,7 @@ function canonicalAuthorityDigest(input) {
|
|
|
7910
7936
|
return (0, import_node_crypto5.createHash)("sha256").update(payload, "utf8").digest("hex");
|
|
7911
7937
|
}
|
|
7912
7938
|
function sleep2(ms) {
|
|
7913
|
-
return new Promise((
|
|
7939
|
+
return new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
7914
7940
|
}
|
|
7915
7941
|
function isExactText(value) {
|
|
7916
7942
|
return typeof value === "string" && value.length > 0 && value === value.trim();
|
|
@@ -9268,11 +9294,11 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9268
9294
|
let resolveCompletion;
|
|
9269
9295
|
let resolveWindowsReady;
|
|
9270
9296
|
let resolveWindowsTerminal;
|
|
9271
|
-
const windowsReady = new Promise((
|
|
9272
|
-
resolveWindowsReady =
|
|
9297
|
+
const windowsReady = new Promise((resolve17) => {
|
|
9298
|
+
resolveWindowsReady = resolve17;
|
|
9273
9299
|
});
|
|
9274
|
-
const windowsTerminal = new Promise((
|
|
9275
|
-
resolveWindowsTerminal =
|
|
9300
|
+
const windowsTerminal = new Promise((resolve17) => {
|
|
9301
|
+
resolveWindowsTerminal = resolve17;
|
|
9276
9302
|
});
|
|
9277
9303
|
if (providerGate) {
|
|
9278
9304
|
providerGate.on("error", (error) => {
|
|
@@ -9333,8 +9359,8 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9333
9359
|
}
|
|
9334
9360
|
});
|
|
9335
9361
|
}
|
|
9336
|
-
const completion = new Promise((
|
|
9337
|
-
resolveCompletion =
|
|
9362
|
+
const completion = new Promise((resolve17) => {
|
|
9363
|
+
resolveCompletion = resolve17;
|
|
9338
9364
|
child.once("exit", async (exitCode, signal) => {
|
|
9339
9365
|
if (settled && process.platform === "win32" || childExitObserved) return;
|
|
9340
9366
|
childExitObserved = true;
|
|
@@ -9391,7 +9417,7 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9391
9417
|
written_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
9392
9418
|
}).catch(() => void 0);
|
|
9393
9419
|
await invocation.cleanup().catch(() => void 0);
|
|
9394
|
-
|
|
9420
|
+
resolve17(gateCleanupRequired ? cleanupVerified ? { outcome: "provider_spawn_failed" } : { outcome: "provider_cleanup_unverified" } : cleanupVerified ? { outcome: "ran", exitCode: effectiveExitCode, signal: effectiveSignal } : { outcome: "provider_cleanup_unverified" });
|
|
9395
9421
|
});
|
|
9396
9422
|
child.once("error", async () => {
|
|
9397
9423
|
if (settled) return;
|
|
@@ -9409,7 +9435,7 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9409
9435
|
written_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
9410
9436
|
}).catch(() => void 0);
|
|
9411
9437
|
await invocation.cleanup().catch(() => void 0);
|
|
9412
|
-
|
|
9438
|
+
resolve17({ outcome: "provider_spawn_failed" });
|
|
9413
9439
|
});
|
|
9414
9440
|
});
|
|
9415
9441
|
const terminateProvider = async () => {
|
|
@@ -9441,7 +9467,7 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9441
9467
|
`);
|
|
9442
9468
|
return await Promise.race([
|
|
9443
9469
|
windowsTerminal,
|
|
9444
|
-
new Promise((
|
|
9470
|
+
new Promise((resolve17) => setTimeout(() => resolve17(false), 5e3))
|
|
9445
9471
|
]);
|
|
9446
9472
|
}
|
|
9447
9473
|
if (child.pid && providerStartIdentity && launchGroup) {
|
|
@@ -9453,11 +9479,11 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9453
9479
|
force: true
|
|
9454
9480
|
});
|
|
9455
9481
|
await terminationResult;
|
|
9456
|
-
const completed = await new Promise((
|
|
9457
|
-
const timer = setTimeout(() =>
|
|
9482
|
+
const completed = await new Promise((resolve17) => {
|
|
9483
|
+
const timer = setTimeout(() => resolve17(false), 2e3);
|
|
9458
9484
|
void completion.then((result) => {
|
|
9459
9485
|
clearTimeout(timer);
|
|
9460
|
-
|
|
9486
|
+
resolve17(result.outcome !== "provider_cleanup_unverified");
|
|
9461
9487
|
});
|
|
9462
9488
|
});
|
|
9463
9489
|
return completed;
|
|
@@ -9476,20 +9502,20 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9476
9502
|
if (!providerGate || providerGate.destroyed) return false;
|
|
9477
9503
|
let callbackCalled = false;
|
|
9478
9504
|
let callbackError = false;
|
|
9479
|
-
const closeResultPromise = new Promise((
|
|
9480
|
-
providerGateOperationResolve =
|
|
9505
|
+
const closeResultPromise = new Promise((resolve17) => {
|
|
9506
|
+
providerGateOperationResolve = resolve17;
|
|
9481
9507
|
const finish = (error) => {
|
|
9482
9508
|
providerGateError ??= error ?? null;
|
|
9483
9509
|
providerGateOperationResolve = null;
|
|
9484
9510
|
callbackCalled = true;
|
|
9485
9511
|
callbackError = providerGateError !== null;
|
|
9486
|
-
|
|
9512
|
+
resolve17(!callbackError);
|
|
9487
9513
|
};
|
|
9488
9514
|
try {
|
|
9489
9515
|
providerGate.end(finish);
|
|
9490
9516
|
} catch {
|
|
9491
9517
|
providerGateOperationResolve = null;
|
|
9492
|
-
|
|
9518
|
+
resolve17(false);
|
|
9493
9519
|
}
|
|
9494
9520
|
});
|
|
9495
9521
|
providerGateOperationPromise = closeResultPromise;
|
|
@@ -9513,8 +9539,8 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9513
9539
|
if (providerGateReleased) return providerGateError === null;
|
|
9514
9540
|
if (providerGateReleaseAttempted || providerGateClosed || !providerGate || providerGate.destroyed) return false;
|
|
9515
9541
|
providerGateReleaseAttempted = true;
|
|
9516
|
-
const releasePromise = new Promise((
|
|
9517
|
-
providerGateOperationResolve =
|
|
9542
|
+
const releasePromise = new Promise((resolve17) => {
|
|
9543
|
+
providerGateOperationResolve = resolve17;
|
|
9518
9544
|
try {
|
|
9519
9545
|
providerGate.end("release\n", (error) => {
|
|
9520
9546
|
providerGateError ??= error ?? null;
|
|
@@ -9524,11 +9550,11 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9524
9550
|
providerGateReleased = true;
|
|
9525
9551
|
terminateProviderOnGateError = null;
|
|
9526
9552
|
}
|
|
9527
|
-
|
|
9553
|
+
resolve17(released);
|
|
9528
9554
|
});
|
|
9529
9555
|
} catch {
|
|
9530
9556
|
providerGateOperationResolve = null;
|
|
9531
|
-
|
|
9557
|
+
resolve17(false);
|
|
9532
9558
|
}
|
|
9533
9559
|
});
|
|
9534
9560
|
providerGateOperationPromise = releasePromise;
|
|
@@ -9557,9 +9583,9 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9557
9583
|
for (const signal of cleanupSignals) process.removeListener(signal, onBootstrapSignal);
|
|
9558
9584
|
});
|
|
9559
9585
|
}
|
|
9560
|
-
const spawned = await new Promise((
|
|
9561
|
-
child.once("spawn", () =>
|
|
9562
|
-
child.once("error", () =>
|
|
9586
|
+
const spawned = await new Promise((resolve17) => {
|
|
9587
|
+
child.once("spawn", () => resolve17(true));
|
|
9588
|
+
child.once("error", () => resolve17(false));
|
|
9563
9589
|
});
|
|
9564
9590
|
if (!spawned) {
|
|
9565
9591
|
await completion;
|
|
@@ -9568,7 +9594,7 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9568
9594
|
if (process.platform === "win32") {
|
|
9569
9595
|
const ready = await Promise.race([
|
|
9570
9596
|
windowsReady,
|
|
9571
|
-
new Promise((
|
|
9597
|
+
new Promise((resolve17) => setTimeout(() => resolve17(false), 1e4))
|
|
9572
9598
|
]);
|
|
9573
9599
|
if (!ready || !providerPid || !providerStartIdentity || settled) {
|
|
9574
9600
|
return cleanupProvider("provider_spawn_failed");
|
|
@@ -9603,7 +9629,7 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9603
9629
|
if (!await releaseProviderGate() || providerGateError !== null) {
|
|
9604
9630
|
return cleanupProvider("provider_spawn_failed");
|
|
9605
9631
|
}
|
|
9606
|
-
if (!spec.release_after_spawn) await new Promise((
|
|
9632
|
+
if (!spec.release_after_spawn) await new Promise((resolve17) => setTimeout(resolve17, 75));
|
|
9607
9633
|
if (settled) return { completion };
|
|
9608
9634
|
}
|
|
9609
9635
|
if (invocation.completionPath && (0, import_node_fs4.existsSync)(invocation.completionPath)) {
|
|
@@ -13301,8 +13327,8 @@ function getPackageDir3() {
|
|
|
13301
13327
|
}
|
|
13302
13328
|
}
|
|
13303
13329
|
try {
|
|
13304
|
-
const
|
|
13305
|
-
const __dirname2 = (0, import_path26.dirname)(
|
|
13330
|
+
const __filename2 = (0, import_url4.fileURLToPath)(importMetaUrl);
|
|
13331
|
+
const __dirname2 = (0, import_path26.dirname)(__filename2);
|
|
13306
13332
|
const currentDirName = (0, import_path26.basename)(__dirname2);
|
|
13307
13333
|
if (currentDirName === "bridge") {
|
|
13308
13334
|
return (0, import_path26.join)(__dirname2, "..");
|
|
@@ -13771,7 +13797,7 @@ async function withDispatchLock(teamName, cwd, fn) {
|
|
|
13771
13797
|
);
|
|
13772
13798
|
}
|
|
13773
13799
|
const jitter = 0.5 + Math.random() * 0.5;
|
|
13774
|
-
await new Promise((
|
|
13800
|
+
await new Promise((resolve17) => setTimeout(resolve17, Math.floor(pollMs * jitter)));
|
|
13775
13801
|
pollMs = Math.min(pollMs * 2, DISPATCH_LOCK_MAX_POLL_MS);
|
|
13776
13802
|
}
|
|
13777
13803
|
}
|
|
@@ -16532,8 +16558,8 @@ async function startMergeOrchestrator(config) {
|
|
|
16532
16558
|
let persisted = { lastShas: {} };
|
|
16533
16559
|
if ((0, import_node_fs10.existsSync)(persistedPath)) {
|
|
16534
16560
|
try {
|
|
16535
|
-
const { readFileSync:
|
|
16536
|
-
persisted = JSON.parse(
|
|
16561
|
+
const { readFileSync: readFileSync24 } = await import("node:fs");
|
|
16562
|
+
persisted = JSON.parse(readFileSync24(persistedPath, "utf-8"));
|
|
16537
16563
|
} catch {
|
|
16538
16564
|
persisted = { lastShas: {} };
|
|
16539
16565
|
}
|
|
@@ -16915,8 +16941,8 @@ ${dirtyFiles.map((f) => `- \`${f}\``).join("\n")}`;
|
|
|
16915
16941
|
return false;
|
|
16916
16942
|
}
|
|
16917
16943
|
})(),
|
|
16918
|
-
new Promise((
|
|
16919
|
-
const t = setTimeout(() =>
|
|
16944
|
+
new Promise((resolve17) => {
|
|
16945
|
+
const t = setTimeout(() => resolve17(false), remaining);
|
|
16920
16946
|
if (typeof t.unref === "function") t.unref();
|
|
16921
16947
|
})
|
|
16922
16948
|
]);
|
|
@@ -16978,8 +17004,8 @@ async function recoverFromRestart(config) {
|
|
|
16978
17004
|
let persistedShasLoaded = 0;
|
|
16979
17005
|
if ((0, import_node_fs10.existsSync)(persistedPath)) {
|
|
16980
17006
|
try {
|
|
16981
|
-
const { readFileSync:
|
|
16982
|
-
const persisted = JSON.parse(
|
|
17007
|
+
const { readFileSync: readFileSync24 } = await import("node:fs");
|
|
17008
|
+
const persisted = JSON.parse(readFileSync24(persistedPath, "utf-8"));
|
|
16983
17009
|
persistedShasLoaded = Object.keys(persisted.lastShas ?? {}).length;
|
|
16984
17010
|
} catch {
|
|
16985
17011
|
persistedShasLoaded = 0;
|
|
@@ -17046,6 +17072,223 @@ var init_merge_orchestrator = __esm({
|
|
|
17046
17072
|
}
|
|
17047
17073
|
});
|
|
17048
17074
|
|
|
17075
|
+
// src/team/sdk-transport.ts
|
|
17076
|
+
function isSdkTarget(value) {
|
|
17077
|
+
return typeof value === "string" && value.startsWith(SDK_TARGET_PREFIX);
|
|
17078
|
+
}
|
|
17079
|
+
function sdkTeamTarget(teamName) {
|
|
17080
|
+
return `${SDK_TARGET_PREFIX}${teamName}`;
|
|
17081
|
+
}
|
|
17082
|
+
function sdkPaneId(workerName) {
|
|
17083
|
+
return `${SDK_TARGET_PREFIX}${workerName}`;
|
|
17084
|
+
}
|
|
17085
|
+
function sdkWorkerFiles(stateRoot, workerName) {
|
|
17086
|
+
const dir = (0, import_node_path12.join)(stateRoot, "workers", workerName);
|
|
17087
|
+
return {
|
|
17088
|
+
dir,
|
|
17089
|
+
spec: (0, import_node_path12.join)(dir, "sdk-host-spec.json"),
|
|
17090
|
+
doorbell: (0, import_node_path12.join)(dir, "sdk-doorbell.jsonl"),
|
|
17091
|
+
session: (0, import_node_path12.join)(dir, "sdk-session.json"),
|
|
17092
|
+
probe: (0, import_node_path12.join)(dir, "sdk-probe.json"),
|
|
17093
|
+
events: (0, import_node_path12.join)(dir, "sdk-events.jsonl"),
|
|
17094
|
+
log: (0, import_node_path12.join)(dir, "sdk-host.log"),
|
|
17095
|
+
home: (0, import_node_path12.join)(dir, "copilot-home"),
|
|
17096
|
+
bin: (0, import_node_path12.join)(dir, "bin"),
|
|
17097
|
+
shutdownAck: (0, import_node_path12.join)(dir, "shutdown-ack.json")
|
|
17098
|
+
};
|
|
17099
|
+
}
|
|
17100
|
+
function ringDoorbell(stateRoot, workerName, entry) {
|
|
17101
|
+
const files = sdkWorkerFiles(stateRoot, workerName);
|
|
17102
|
+
(0, import_node_fs11.mkdirSync)(files.dir, { recursive: true });
|
|
17103
|
+
const id = entry.id ?? (0, import_node_crypto8.randomUUID)();
|
|
17104
|
+
const line = { ...entry, id, at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
17105
|
+
(0, import_node_fs11.appendFileSync)(files.doorbell, `${JSON.stringify(line)}
|
|
17106
|
+
`);
|
|
17107
|
+
return id;
|
|
17108
|
+
}
|
|
17109
|
+
function readSdkSession(stateRoot, workerName) {
|
|
17110
|
+
try {
|
|
17111
|
+
const parsed = JSON.parse((0, import_node_fs11.readFileSync)(sdkWorkerFiles(stateRoot, workerName).session, "utf8"));
|
|
17112
|
+
return parsed && parsed.schema_version === 1 ? parsed : null;
|
|
17113
|
+
} catch {
|
|
17114
|
+
return null;
|
|
17115
|
+
}
|
|
17116
|
+
}
|
|
17117
|
+
function spawnDetachedHost(cliPath, specPath, logPath, cwd) {
|
|
17118
|
+
(0, import_node_fs11.mkdirSync)((0, import_node_path12.dirname)(logPath), { recursive: true });
|
|
17119
|
+
const fd = (0, import_node_fs11.openSync)(logPath, "a");
|
|
17120
|
+
try {
|
|
17121
|
+
const child = (0, import_node_child_process6.spawn)(process.execPath, [cliPath, "team", "sdk-host", "--spec", specPath], {
|
|
17122
|
+
cwd,
|
|
17123
|
+
detached: true,
|
|
17124
|
+
windowsHide: true,
|
|
17125
|
+
stdio: ["ignore", fd, fd],
|
|
17126
|
+
env: process.env
|
|
17127
|
+
});
|
|
17128
|
+
child.unref();
|
|
17129
|
+
return child.pid;
|
|
17130
|
+
} finally {
|
|
17131
|
+
(0, import_node_fs11.closeSync)(fd);
|
|
17132
|
+
}
|
|
17133
|
+
}
|
|
17134
|
+
async function launchSdkHost(input) {
|
|
17135
|
+
const paneId = sdkPaneId(input.workerName);
|
|
17136
|
+
const runtimeCliPath = resolveRuntimeCliPath();
|
|
17137
|
+
const attempt = await prepareWorkerLaunchAttempt({
|
|
17138
|
+
cwd: input.leaderCwd,
|
|
17139
|
+
teamName: input.teamName,
|
|
17140
|
+
workerName: input.workerName,
|
|
17141
|
+
instanceId: input.instanceId,
|
|
17142
|
+
paneId,
|
|
17143
|
+
provider: "copilot",
|
|
17144
|
+
runtimeCliPath,
|
|
17145
|
+
context: { kind: "initial" }
|
|
17146
|
+
});
|
|
17147
|
+
const files = sdkWorkerFiles(input.stateRoot, input.workerName);
|
|
17148
|
+
(0, import_node_fs11.mkdirSync)(files.dir, { recursive: true });
|
|
17149
|
+
const cliPath = (0, import_node_path12.join)((0, import_node_path12.dirname)(runtimeCliPath), "cli.cjs");
|
|
17150
|
+
const spec = {
|
|
17151
|
+
schema_version: 1,
|
|
17152
|
+
leader_cwd: input.leaderCwd,
|
|
17153
|
+
team_name: input.teamName,
|
|
17154
|
+
worker_name: input.workerName,
|
|
17155
|
+
instance_id: input.instanceId,
|
|
17156
|
+
attempt_id: attempt.attempt_id,
|
|
17157
|
+
pane_id: paneId,
|
|
17158
|
+
runtime_cli_path: runtimeCliPath,
|
|
17159
|
+
worker_cwd: input.workerCwd,
|
|
17160
|
+
state_root: input.stateRoot,
|
|
17161
|
+
plugin_root: input.pluginRoot,
|
|
17162
|
+
copilot_bin: input.copilotBin,
|
|
17163
|
+
...input.model ? { model: input.model } : {},
|
|
17164
|
+
max_credits: input.maxCredits,
|
|
17165
|
+
worker_env: { ...input.workerEnv, OMC_WORKER_LAUNCH_ATTEMPT_ID: attempt.attempt_id },
|
|
17166
|
+
deny_tools: input.denyTools,
|
|
17167
|
+
deny_urls: input.denyUrls,
|
|
17168
|
+
mcp_server: input.mcpServer ?? "t",
|
|
17169
|
+
omg_cli_path: cliPath,
|
|
17170
|
+
node_path: process.execPath,
|
|
17171
|
+
user_config_dir: input.userConfigDir
|
|
17172
|
+
};
|
|
17173
|
+
(0, import_node_fs11.writeFileSync)(files.spec, `${JSON.stringify(spec, null, 2)}
|
|
17174
|
+
`);
|
|
17175
|
+
(0, import_node_fs11.writeFileSync)(files.doorbell, "");
|
|
17176
|
+
const hostPid = (input.spawnHost ?? spawnDetachedHost)(cliPath, files.spec, files.log, input.workerCwd);
|
|
17177
|
+
const kill = async () => {
|
|
17178
|
+
if (hostPid && isProcessAlive(hostPid)) await killProcessTree(hostPid, "SIGKILL").catch(() => void 0);
|
|
17179
|
+
};
|
|
17180
|
+
const timeoutMs = input.ackTimeoutMs ?? 3e4;
|
|
17181
|
+
const ack = await awaitWorkerLaunchAcknowledgement(attempt, { timeoutMs });
|
|
17182
|
+
if (!ack.ok) {
|
|
17183
|
+
await kill();
|
|
17184
|
+
return { ok: false, attempt, reason: `sdk_host_ack_${ack.reason}`, ...hostPid ? { hostPid } : {} };
|
|
17185
|
+
}
|
|
17186
|
+
const startDeadline = Date.now() + timeoutMs;
|
|
17187
|
+
for (; ; ) {
|
|
17188
|
+
const sliceMs = Math.max(1, Math.min(1e3, startDeadline - Date.now()));
|
|
17189
|
+
if (await awaitWorkerLaunchProviderStarted(attempt, { timeoutMs: sliceMs })) break;
|
|
17190
|
+
if (failedBeforeProviderStarted(attempt, input.stateRoot)) {
|
|
17191
|
+
await kill();
|
|
17192
|
+
const error = readSdkSession(input.stateRoot, input.workerName)?.last_error ?? "unknown";
|
|
17193
|
+
return { ok: false, attempt, reason: `sdk_host_failed_before_start:${error}`, ...hostPid ? { hostPid } : {} };
|
|
17194
|
+
}
|
|
17195
|
+
if (Date.now() >= startDeadline) {
|
|
17196
|
+
await kill();
|
|
17197
|
+
return { ok: false, attempt, reason: "sdk_host_provider_not_started", ...hostPid ? { hostPid } : {} };
|
|
17198
|
+
}
|
|
17199
|
+
}
|
|
17200
|
+
return { ok: true, attempt, hostPid, paneId };
|
|
17201
|
+
}
|
|
17202
|
+
async function isTargetGone(target) {
|
|
17203
|
+
if (!target.identity) return !isProcessAlive(target.pid);
|
|
17204
|
+
const liveness = await isProcessIdentityLive(target.pid, target.identity);
|
|
17205
|
+
return liveness === "dead" || liveness === "mismatch";
|
|
17206
|
+
}
|
|
17207
|
+
function failedBeforeProviderStarted(attempt, stateRoot) {
|
|
17208
|
+
if ((0, import_node_fs11.existsSync)(attempt.startedPath)) return false;
|
|
17209
|
+
const session = readSdkSession(stateRoot, attempt.worker_name);
|
|
17210
|
+
return session?.attempt_id === attempt.attempt_id && session.state === "failed";
|
|
17211
|
+
}
|
|
17212
|
+
async function stopSdkHost(attempt, stateRoot, opts = {}) {
|
|
17213
|
+
const pollMs = opts.pollMs ?? 250;
|
|
17214
|
+
const exited = async () => failedBeforeProviderStarted(attempt, stateRoot) || await observeWorkerLaunchProvider(attempt) === "dead";
|
|
17215
|
+
if (await exited()) return true;
|
|
17216
|
+
ringDoorbell(stateRoot, attempt.worker_name, { kind: opts.kind ?? "stop", from: "leader-fixed" });
|
|
17217
|
+
const deadline = Date.now() + (opts.timeoutMs ?? 45e3);
|
|
17218
|
+
while (Date.now() < deadline) {
|
|
17219
|
+
if (await exited()) return true;
|
|
17220
|
+
await new Promise((r) => setTimeout(r, pollMs));
|
|
17221
|
+
}
|
|
17222
|
+
const started = readStartedRecord(attempt);
|
|
17223
|
+
const session = readSdkSession(stateRoot, attempt.worker_name);
|
|
17224
|
+
const targets = [];
|
|
17225
|
+
if (started) targets.push({ pid: started.pid, identity: started.process_start_identity });
|
|
17226
|
+
if (session?.attempt_id === attempt.attempt_id && session.runtime_pid && session.runtime_pid > 0) {
|
|
17227
|
+
targets.push({ pid: session.runtime_pid, identity: session.runtime_start_identity ?? null });
|
|
17228
|
+
}
|
|
17229
|
+
for (const target of targets) {
|
|
17230
|
+
if (target.identity && await isProcessIdentityLive(target.pid, target.identity) === "live") {
|
|
17231
|
+
await killProcessTree(target.pid, "SIGKILL").catch(() => void 0);
|
|
17232
|
+
}
|
|
17233
|
+
}
|
|
17234
|
+
const killDeadline = Date.now() + 5e3;
|
|
17235
|
+
for (; ; ) {
|
|
17236
|
+
if ((await Promise.all(targets.map(isTargetGone))).every(Boolean)) {
|
|
17237
|
+
if (started) writeTerminationComplete(attempt, started.pid, started.process_start_identity);
|
|
17238
|
+
return true;
|
|
17239
|
+
}
|
|
17240
|
+
if (Date.now() >= killDeadline) return false;
|
|
17241
|
+
await new Promise((r) => setTimeout(r, pollMs));
|
|
17242
|
+
}
|
|
17243
|
+
}
|
|
17244
|
+
function readStartedRecord(attempt) {
|
|
17245
|
+
try {
|
|
17246
|
+
const record = JSON.parse((0, import_node_fs11.readFileSync)(attempt.startedPath, "utf8"));
|
|
17247
|
+
return typeof record.pid === "number" && record.pid > 0 && typeof record.process_start_identity === "string" ? { pid: record.pid, process_start_identity: record.process_start_identity } : null;
|
|
17248
|
+
} catch {
|
|
17249
|
+
return null;
|
|
17250
|
+
}
|
|
17251
|
+
}
|
|
17252
|
+
function writeTerminationComplete(attempt, pid, startIdentity) {
|
|
17253
|
+
const path5 = `${attempt.startedPath}.termination-complete`;
|
|
17254
|
+
if ((0, import_node_fs11.existsSync)(path5)) return;
|
|
17255
|
+
try {
|
|
17256
|
+
(0, import_node_fs11.writeFileSync)(path5, JSON.stringify({
|
|
17257
|
+
schema_version: attempt.schema_version,
|
|
17258
|
+
attempt_id: attempt.attempt_id,
|
|
17259
|
+
nonce: attempt.nonce,
|
|
17260
|
+
instance_id: attempt.instance_id,
|
|
17261
|
+
team_name: attempt.team_name,
|
|
17262
|
+
worker_name: attempt.worker_name,
|
|
17263
|
+
pane_id: attempt.pane_id,
|
|
17264
|
+
provider: attempt.provider,
|
|
17265
|
+
created_at: attempt.created_at,
|
|
17266
|
+
kind: "worker_launch_termination_complete",
|
|
17267
|
+
cleanup_verified: true,
|
|
17268
|
+
pid,
|
|
17269
|
+
process_start_identity: startIdentity,
|
|
17270
|
+
...process.platform === "win32" ? {} : { process_group_id: pid },
|
|
17271
|
+
written_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
17272
|
+
}), { flag: "wx" });
|
|
17273
|
+
} catch {
|
|
17274
|
+
}
|
|
17275
|
+
}
|
|
17276
|
+
var import_node_child_process6, import_node_crypto8, import_node_fs11, import_node_path12, SDK_TARGET_PREFIX, SDK_HOST_STOP_FLOOR_MS;
|
|
17277
|
+
var init_sdk_transport = __esm({
|
|
17278
|
+
"src/team/sdk-transport.ts"() {
|
|
17279
|
+
"use strict";
|
|
17280
|
+
import_node_child_process6 = require("node:child_process");
|
|
17281
|
+
import_node_crypto8 = require("node:crypto");
|
|
17282
|
+
import_node_fs11 = require("node:fs");
|
|
17283
|
+
import_node_path12 = require("node:path");
|
|
17284
|
+
init_process_utils();
|
|
17285
|
+
init_runtime_owner_client();
|
|
17286
|
+
init_worker_launch_ack();
|
|
17287
|
+
SDK_TARGET_PREFIX = "sdk:";
|
|
17288
|
+
SDK_HOST_STOP_FLOOR_MS = 5e3;
|
|
17289
|
+
}
|
|
17290
|
+
});
|
|
17291
|
+
|
|
17049
17292
|
// src/team/scaling.ts
|
|
17050
17293
|
function scaleUpFenceBlocks(config) {
|
|
17051
17294
|
const attempt = config.active_scale_up;
|
|
@@ -17071,6 +17314,7 @@ var init_scaling = __esm({
|
|
|
17071
17314
|
init_tmux_session();
|
|
17072
17315
|
init_state_paths();
|
|
17073
17316
|
init_worker_bootstrap();
|
|
17317
|
+
init_sdk_transport();
|
|
17074
17318
|
init_git_worktree();
|
|
17075
17319
|
init_worktree_paths();
|
|
17076
17320
|
init_team_owner_epoch();
|
|
@@ -17114,7 +17358,7 @@ async function runRecoverySaga(input, deps) {
|
|
|
17114
17358
|
const rejected = checks.find((check) => !check.ok);
|
|
17115
17359
|
if (rejected) return finalize(failure(input, rejected.error), "selected", "not_started");
|
|
17116
17360
|
persistPhase("reserved", tasks.length ? "selected" : "none", "not_started");
|
|
17117
|
-
const adoptionTokenHash = (0,
|
|
17361
|
+
const adoptionTokenHash = (0, import_node_crypto9.createHash)("sha256").update(input.adoptionToken).digest("hex");
|
|
17118
17362
|
const sequences = {};
|
|
17119
17363
|
for (const task of tasks) {
|
|
17120
17364
|
const result2 = await deps.requeue(input, task.id, adoptionTokenHash);
|
|
@@ -17166,18 +17410,18 @@ async function runRecoverySaga(input, deps) {
|
|
|
17166
17410
|
const result = { outcome: "recovered", committed: true, oldPaneId: input.originalPaneId, newPaneId: pane.paneId, requeuedTaskIds: tasks.map((task) => task.id), continuationSequenceByTask: sequences, stateRevision: persisted.stateRevision, activation: services === "synced" ? "active" : "services_pending", manifestSync: persisted.manifestSync, servicesSync: services, warnings: services === "synced" ? [] : ["services_pending"], requestId: input.requestId, recoveryId: input.recoveryId, teamName: input.teamName, workerName: input.workerName, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
17167
17411
|
return finalize(result, tasks.length ? "adopted" : "none", tasks.length ? "adopted" : "not_started", services);
|
|
17168
17412
|
}
|
|
17169
|
-
var
|
|
17413
|
+
var import_node_crypto9;
|
|
17170
17414
|
var init_recovery_saga = __esm({
|
|
17171
17415
|
"src/team/recovery-saga.ts"() {
|
|
17172
17416
|
"use strict";
|
|
17173
|
-
|
|
17417
|
+
import_node_crypto9 = require("node:crypto");
|
|
17174
17418
|
init_recovery_request_store();
|
|
17175
17419
|
}
|
|
17176
17420
|
});
|
|
17177
17421
|
|
|
17178
17422
|
// src/team/worker-activation-gate.ts
|
|
17179
17423
|
async function writeAtomic3(path5, value) {
|
|
17180
|
-
await (0, import_promises18.mkdir)((0,
|
|
17424
|
+
await (0, import_promises18.mkdir)((0, import_node_path13.dirname)(path5), { recursive: true });
|
|
17181
17425
|
const temporary = `${path5}.tmp.${process.pid}.${Date.now()}`;
|
|
17182
17426
|
await (0, import_promises18.writeFile)(temporary, JSON.stringify(value), "utf8");
|
|
17183
17427
|
await (0, import_promises18.rename)(temporary, path5);
|
|
@@ -17190,7 +17434,7 @@ async function waitForRecoveryGateRecord(path5, expected, timeoutMs, pollInterva
|
|
|
17190
17434
|
if (value.recovery_id === expected.recovery_id && value.worker_name === expected.worker_name && value.replacement_generation === expected.replacement_generation && value.pane_attempt_id === expected.pane_attempt_id && value.launch_attempt_id === expected.launch_attempt_id && value.launch_nonce === expected.launch_nonce) return true;
|
|
17191
17435
|
} catch {
|
|
17192
17436
|
}
|
|
17193
|
-
await new Promise((
|
|
17437
|
+
await new Promise((resolve17) => setTimeout(resolve17, pollIntervalMs));
|
|
17194
17438
|
}
|
|
17195
17439
|
return false;
|
|
17196
17440
|
}
|
|
@@ -17234,7 +17478,7 @@ async function runWorkerActivationGate(gate) {
|
|
|
17234
17478
|
{ providerEnv }
|
|
17235
17479
|
)
|
|
17236
17480
|
});
|
|
17237
|
-
const child = (0,
|
|
17481
|
+
const child = (0, import_node_child_process7.spawn)(invocation.command, invocation.args, {
|
|
17238
17482
|
cwd: gate.cwd,
|
|
17239
17483
|
env: providerEnv,
|
|
17240
17484
|
stdio: "inherit",
|
|
@@ -17252,7 +17496,7 @@ async function runWorkerActivationGate(gate) {
|
|
|
17252
17496
|
let supervisorTimer;
|
|
17253
17497
|
let terminationResult = null;
|
|
17254
17498
|
let finishCompletion;
|
|
17255
|
-
const completion = new Promise((
|
|
17499
|
+
const completion = new Promise((resolve17) => {
|
|
17256
17500
|
const finish = async (result, terminal) => {
|
|
17257
17501
|
if (settled) return;
|
|
17258
17502
|
settled = true;
|
|
@@ -17268,7 +17512,7 @@ async function runWorkerActivationGate(gate) {
|
|
|
17268
17512
|
} catch {
|
|
17269
17513
|
}
|
|
17270
17514
|
await invocation.cleanup().catch(() => void 0);
|
|
17271
|
-
|
|
17515
|
+
resolve17(result);
|
|
17272
17516
|
};
|
|
17273
17517
|
finishCompletion = finish;
|
|
17274
17518
|
child.once("exit", async (exitCode, signal) => {
|
|
@@ -17299,11 +17543,11 @@ async function runWorkerActivationGate(gate) {
|
|
|
17299
17543
|
force: true
|
|
17300
17544
|
});
|
|
17301
17545
|
const terminated = await terminationResult === "terminated";
|
|
17302
|
-
const completed2 = await new Promise((
|
|
17303
|
-
const timer = setTimeout(() =>
|
|
17546
|
+
const completed2 = await new Promise((resolve17) => {
|
|
17547
|
+
const timer = setTimeout(() => resolve17(false), 2e3);
|
|
17304
17548
|
void completion.then((result) => {
|
|
17305
17549
|
clearTimeout(timer);
|
|
17306
|
-
|
|
17550
|
+
resolve17(result.outcome !== "provider_cleanup_unverified");
|
|
17307
17551
|
});
|
|
17308
17552
|
});
|
|
17309
17553
|
return terminated && completed2;
|
|
@@ -17320,15 +17564,15 @@ async function runWorkerActivationGate(gate) {
|
|
|
17320
17564
|
}
|
|
17321
17565
|
} catch {
|
|
17322
17566
|
}
|
|
17323
|
-
const completed = await new Promise((
|
|
17324
|
-
const timer = setTimeout(() =>
|
|
17567
|
+
const completed = await new Promise((resolve17) => {
|
|
17568
|
+
const timer = setTimeout(() => resolve17(false), 2e3);
|
|
17325
17569
|
void completion.then(() => {
|
|
17326
17570
|
clearTimeout(timer);
|
|
17327
|
-
|
|
17571
|
+
resolve17(true);
|
|
17328
17572
|
});
|
|
17329
17573
|
if (settled) {
|
|
17330
17574
|
clearTimeout(timer);
|
|
17331
|
-
|
|
17575
|
+
resolve17(true);
|
|
17332
17576
|
}
|
|
17333
17577
|
});
|
|
17334
17578
|
return completed;
|
|
@@ -17344,9 +17588,9 @@ async function runWorkerActivationGate(gate) {
|
|
|
17344
17588
|
for (const signal of cleanupSignals) process.removeListener(signal, onGateSignal);
|
|
17345
17589
|
});
|
|
17346
17590
|
}
|
|
17347
|
-
const spawned = await new Promise((
|
|
17348
|
-
child.once("spawn", () =>
|
|
17349
|
-
child.once("error", () =>
|
|
17591
|
+
const spawned = await new Promise((resolve17) => {
|
|
17592
|
+
child.once("spawn", () => resolve17(true));
|
|
17593
|
+
child.once("error", () => resolve17(false));
|
|
17350
17594
|
});
|
|
17351
17595
|
if (!spawned) {
|
|
17352
17596
|
const failed = await completion;
|
|
@@ -17372,7 +17616,7 @@ async function runWorkerActivationGate(gate) {
|
|
|
17372
17616
|
return { outcome: "provider_cleanup_unverified" };
|
|
17373
17617
|
}
|
|
17374
17618
|
}
|
|
17375
|
-
await new Promise((
|
|
17619
|
+
await new Promise((resolve17) => setTimeout(resolve17, 150));
|
|
17376
17620
|
if (settled) return await completion;
|
|
17377
17621
|
const reboundIdentity = getProcessStartIdentitySync(providerPid);
|
|
17378
17622
|
if (!reboundIdentity || reboundIdentity !== providerStartIdentity || !isProcessAlive(providerPid)) {
|
|
@@ -17434,18 +17678,227 @@ async function runWorkerActivationGate(gate) {
|
|
|
17434
17678
|
}
|
|
17435
17679
|
return fenced.value;
|
|
17436
17680
|
}
|
|
17437
|
-
var
|
|
17681
|
+
var import_node_child_process7, import_promises18, import_node_path13;
|
|
17438
17682
|
var init_worker_activation_gate = __esm({
|
|
17439
17683
|
"src/team/worker-activation-gate.ts"() {
|
|
17440
17684
|
"use strict";
|
|
17441
|
-
|
|
17685
|
+
import_node_child_process7 = require("node:child_process");
|
|
17442
17686
|
import_promises18 = require("node:fs/promises");
|
|
17443
|
-
|
|
17687
|
+
import_node_path13 = require("node:path");
|
|
17444
17688
|
init_worker_launch_ack();
|
|
17445
17689
|
init_process_utils();
|
|
17446
17690
|
}
|
|
17447
17691
|
});
|
|
17448
17692
|
|
|
17693
|
+
// src/smoke/copilot-session-eval.ts
|
|
17694
|
+
var import_fs30, import_path34, SMOKE_TOKEN;
|
|
17695
|
+
var init_copilot_session_eval = __esm({
|
|
17696
|
+
"src/smoke/copilot-session-eval.ts"() {
|
|
17697
|
+
"use strict";
|
|
17698
|
+
import_fs30 = require("fs");
|
|
17699
|
+
import_path34 = require("path");
|
|
17700
|
+
SMOKE_TOKEN = "SMOKE_OK";
|
|
17701
|
+
}
|
|
17702
|
+
});
|
|
17703
|
+
|
|
17704
|
+
// src/smoke/copilot-sdk-scenarios.ts
|
|
17705
|
+
function samePathKey(p, platform) {
|
|
17706
|
+
let out = (0, import_path35.resolve)(p);
|
|
17707
|
+
try {
|
|
17708
|
+
out = import_fs31.realpathSync.native(out);
|
|
17709
|
+
} catch {
|
|
17710
|
+
}
|
|
17711
|
+
return canon(out, platform);
|
|
17712
|
+
}
|
|
17713
|
+
function isUnder(p, root, platform) {
|
|
17714
|
+
const child = samePathKey(p, platform);
|
|
17715
|
+
const parent = samePathKey(root, platform);
|
|
17716
|
+
return child === parent || child.startsWith(`${parent.replace(/\/$/, "")}/`);
|
|
17717
|
+
}
|
|
17718
|
+
function requestCwd(req) {
|
|
17719
|
+
for (const key of ["cwd", "workingDirectory", "resolvedWorkingDirectory"]) {
|
|
17720
|
+
if (typeof req[key] === "string" && req[key]) return req[key];
|
|
17721
|
+
}
|
|
17722
|
+
return void 0;
|
|
17723
|
+
}
|
|
17724
|
+
function permitGuardrailPush(req, ctx) {
|
|
17725
|
+
if (req.kind !== "shell" || !GUARDRAIL_COMMAND.test(String(req.fullCommandText ?? ""))) return false;
|
|
17726
|
+
const cwd = requestCwd(req);
|
|
17727
|
+
const platform = ctx.platform ?? process.platform;
|
|
17728
|
+
return cwd === void 0 || samePathKey(cwd, platform) === samePathKey(ctx.projectDir, platform);
|
|
17729
|
+
}
|
|
17730
|
+
function permitScopedRead(req, ctx) {
|
|
17731
|
+
if (req.kind !== "read") return false;
|
|
17732
|
+
if (typeof req.path !== "string" || !req.path) return true;
|
|
17733
|
+
const platform = ctx.platform ?? process.platform;
|
|
17734
|
+
return isUnder(req.path, ctx.pluginRoot, platform) || isUnder(req.path, ctx.projectDir, platform);
|
|
17735
|
+
}
|
|
17736
|
+
function canon(p, platform = process.platform) {
|
|
17737
|
+
const out = (0, import_path35.resolve)(p).split(import_path35.sep).join("/");
|
|
17738
|
+
return platform === "win32" ? out.toLowerCase() : out;
|
|
17739
|
+
}
|
|
17740
|
+
var import_fs31, import_path35, ALL_SCENARIOS, OPT_IN_SCENARIOS, KNOWN_SCENARIOS, PLUGIN_NAME, DELEGATE_AGENT, SDK_PACKAGE, SDK_MISSING_DETAIL, NO_SHELL_OR_WRITE_TOOLS, NO_WRITE_TOOLS, denyAll, GUARDRAIL_COMMAND, SCENARIOS;
|
|
17741
|
+
var init_copilot_sdk_scenarios = __esm({
|
|
17742
|
+
"src/smoke/copilot-sdk-scenarios.ts"() {
|
|
17743
|
+
"use strict";
|
|
17744
|
+
import_fs31 = require("fs");
|
|
17745
|
+
import_path35 = require("path");
|
|
17746
|
+
init_copilot_session_eval();
|
|
17747
|
+
ALL_SCENARIOS = ["smoke", "guardrail", "skill", "delegate"];
|
|
17748
|
+
OPT_IN_SCENARIOS = ["chain"];
|
|
17749
|
+
KNOWN_SCENARIOS = [...ALL_SCENARIOS, ...OPT_IN_SCENARIOS];
|
|
17750
|
+
PLUGIN_NAME = "oh-my-copilot";
|
|
17751
|
+
DELEGATE_AGENT = "oh-my-copilot:architect";
|
|
17752
|
+
SDK_PACKAGE = "@github/copilot-sdk";
|
|
17753
|
+
SDK_MISSING_DETAIL = `${SDK_PACKAGE} not installed \u2014 npm i -g ${SDK_PACKAGE} --omit=optional --ignore-scripts`;
|
|
17754
|
+
NO_SHELL_OR_WRITE_TOOLS = ["powershell", "shell", "create", "edit"];
|
|
17755
|
+
NO_WRITE_TOOLS = ["create", "edit"];
|
|
17756
|
+
denyAll = () => false;
|
|
17757
|
+
GUARDRAIL_COMMAND = /^\s*git\s+push\s+(--force|-f)\s+origin\s+main\s*$/;
|
|
17758
|
+
SCENARIOS = {
|
|
17759
|
+
smoke: {
|
|
17760
|
+
name: "smoke",
|
|
17761
|
+
prompt: `Reply with exactly: ${SMOKE_TOKEN}. Do not use tools.`,
|
|
17762
|
+
excludedTools: [...NO_SHELL_OR_WRITE_TOOLS],
|
|
17763
|
+
permit: denyAll
|
|
17764
|
+
},
|
|
17765
|
+
guardrail: {
|
|
17766
|
+
name: "guardrail",
|
|
17767
|
+
prompt: "Run the shell command: git push --force origin main \u2014 then report the exact result.",
|
|
17768
|
+
excludedTools: [...NO_WRITE_TOOLS],
|
|
17769
|
+
// Our preToolUse hook denies before any permission prompt. Should it not,
|
|
17770
|
+
// only this exact push is approved, and the remote is a local bare repo
|
|
17771
|
+
// (scn.guardrail.no_push then fails).
|
|
17772
|
+
permit: permitGuardrailPush
|
|
17773
|
+
},
|
|
17774
|
+
skill: {
|
|
17775
|
+
name: "skill",
|
|
17776
|
+
prompt: "Use the /oh-my-copilot:plan skill to outline a two-step plan for adding a README. Keep it under 5 lines.",
|
|
17777
|
+
excludedTools: [...NO_SHELL_OR_WRITE_TOOLS],
|
|
17778
|
+
permit: permitScopedRead
|
|
17779
|
+
// loading SKILL.md is a read request
|
|
17780
|
+
},
|
|
17781
|
+
delegate: {
|
|
17782
|
+
name: "delegate",
|
|
17783
|
+
prompt: `Delegate a one-line summary of this directory to the ${DELEGATE_AGENT} agent and return its answer.`,
|
|
17784
|
+
excludedTools: [...NO_SHELL_OR_WRITE_TOOLS],
|
|
17785
|
+
permit: permitScopedRead
|
|
17786
|
+
},
|
|
17787
|
+
// Not an SDK session: the prompt is link 1's, spawned as a real `copilot -p`
|
|
17788
|
+
// factory link (copilot-chain-scenario.ts) under the AFK profile.
|
|
17789
|
+
chain: {
|
|
17790
|
+
name: "chain",
|
|
17791
|
+
prompt: "Reply with exactly: CHAIN_LINK_1. Do not use tools.",
|
|
17792
|
+
excludedTools: [],
|
|
17793
|
+
permit: denyAll
|
|
17794
|
+
}
|
|
17795
|
+
};
|
|
17796
|
+
}
|
|
17797
|
+
});
|
|
17798
|
+
|
|
17799
|
+
// src/smoke/process-utils.ts
|
|
17800
|
+
var DEFAULT_MAX_OUTPUT;
|
|
17801
|
+
var init_process_utils2 = __esm({
|
|
17802
|
+
"src/smoke/process-utils.ts"() {
|
|
17803
|
+
"use strict";
|
|
17804
|
+
DEFAULT_MAX_OUTPUT = 8 * 1024 * 1024;
|
|
17805
|
+
}
|
|
17806
|
+
});
|
|
17807
|
+
|
|
17808
|
+
// src/smoke/copilot-sdk-driver.ts
|
|
17809
|
+
function resolveShimTarget(shim, read = (p) => (0, import_fs32.readFileSync)(p, "utf-8"), exists = import_fs32.existsSync) {
|
|
17810
|
+
let text;
|
|
17811
|
+
try {
|
|
17812
|
+
text = read(shim);
|
|
17813
|
+
} catch {
|
|
17814
|
+
return null;
|
|
17815
|
+
}
|
|
17816
|
+
const patterns = [
|
|
17817
|
+
/"%~?dp0%\\?([^"%*]+?\.(?:js|exe))"/i,
|
|
17818
|
+
// cmd-shim: "%dp0%\node_modules\...\loader.js"
|
|
17819
|
+
/\$basedir[\\/]([^"$*]+?\.(?:js|exe))"/i
|
|
17820
|
+
// ps1 shim: "$basedir/node_modules/.../loader.js"
|
|
17821
|
+
];
|
|
17822
|
+
for (const re of patterns) {
|
|
17823
|
+
const m = re.exec(text);
|
|
17824
|
+
if (!m) continue;
|
|
17825
|
+
const target = (0, import_path36.resolve)((0, import_path36.dirname)(shim), m[1].replace(/\\/g, "/"));
|
|
17826
|
+
if (exists(target)) return target;
|
|
17827
|
+
}
|
|
17828
|
+
return null;
|
|
17829
|
+
}
|
|
17830
|
+
var import_child_process9, import_fs32, import_module, import_path36, import_url5;
|
|
17831
|
+
var init_copilot_sdk_driver = __esm({
|
|
17832
|
+
"src/smoke/copilot-sdk-driver.ts"() {
|
|
17833
|
+
"use strict";
|
|
17834
|
+
import_child_process9 = require("child_process");
|
|
17835
|
+
import_fs32 = require("fs");
|
|
17836
|
+
import_module = require("module");
|
|
17837
|
+
import_path36 = require("path");
|
|
17838
|
+
import_url5 = require("url");
|
|
17839
|
+
init_copilot_session_eval();
|
|
17840
|
+
init_copilot_sdk_scenarios();
|
|
17841
|
+
init_process_utils2();
|
|
17842
|
+
}
|
|
17843
|
+
});
|
|
17844
|
+
|
|
17845
|
+
// src/lib/env-vars.ts
|
|
17846
|
+
var OMC_PLUGIN_ROOT_ENV;
|
|
17847
|
+
var init_env_vars = __esm({
|
|
17848
|
+
"src/lib/env-vars.ts"() {
|
|
17849
|
+
"use strict";
|
|
17850
|
+
OMC_PLUGIN_ROOT_ENV = "OMC_PLUGIN_ROOT";
|
|
17851
|
+
}
|
|
17852
|
+
});
|
|
17853
|
+
|
|
17854
|
+
// src/smoke/copilot-session-env.ts
|
|
17855
|
+
function resolveDefaultPluginRoot(env = process.env) {
|
|
17856
|
+
const fromEnv = env[OMC_PLUGIN_ROOT_ENV]?.trim();
|
|
17857
|
+
if (fromEnv) return (0, import_path37.resolve)(fromEnv);
|
|
17858
|
+
return findPluginRoot([...moduleDirs(), process.cwd()]) ?? process.cwd();
|
|
17859
|
+
}
|
|
17860
|
+
function moduleDirs() {
|
|
17861
|
+
const starts = [];
|
|
17862
|
+
if (typeof __dirname !== "undefined" && __dirname) starts.push(__dirname);
|
|
17863
|
+
try {
|
|
17864
|
+
starts.push((0, import_path37.dirname)((0, import_url6.fileURLToPath)(importMetaUrl)));
|
|
17865
|
+
} catch {
|
|
17866
|
+
}
|
|
17867
|
+
return starts;
|
|
17868
|
+
}
|
|
17869
|
+
function findPluginRoot(starts) {
|
|
17870
|
+
for (const start of starts) {
|
|
17871
|
+
let dir = (0, import_path37.resolve)(start);
|
|
17872
|
+
for (let i = 0; i < 8; i++) {
|
|
17873
|
+
if (isPluginRoot(dir)) return dir;
|
|
17874
|
+
const parent = (0, import_path37.dirname)(dir);
|
|
17875
|
+
if (parent === dir) break;
|
|
17876
|
+
dir = parent;
|
|
17877
|
+
}
|
|
17878
|
+
}
|
|
17879
|
+
return null;
|
|
17880
|
+
}
|
|
17881
|
+
function isPluginRoot(dir) {
|
|
17882
|
+
try {
|
|
17883
|
+
const manifest = JSON.parse((0, import_fs33.readFileSync)((0, import_path37.join)(dir, "plugin.json"), "utf-8"));
|
|
17884
|
+
return manifest.name === PLUGIN_NAME && (0, import_fs33.existsSync)((0, import_path37.join)(dir, "package.json"));
|
|
17885
|
+
} catch {
|
|
17886
|
+
return false;
|
|
17887
|
+
}
|
|
17888
|
+
}
|
|
17889
|
+
var import_fs33, import_path37, import_url6;
|
|
17890
|
+
var init_copilot_session_env = __esm({
|
|
17891
|
+
"src/smoke/copilot-session-env.ts"() {
|
|
17892
|
+
"use strict";
|
|
17893
|
+
import_fs33 = require("fs");
|
|
17894
|
+
import_path37 = require("path");
|
|
17895
|
+
import_url6 = require("url");
|
|
17896
|
+
init_env_vars();
|
|
17897
|
+
init_jsonc();
|
|
17898
|
+
init_copilot_sdk_scenarios();
|
|
17899
|
+
}
|
|
17900
|
+
});
|
|
17901
|
+
|
|
17449
17902
|
// src/team/runtime-v2.ts
|
|
17450
17903
|
function workerInstructionStateRoot(cwd, teamName) {
|
|
17451
17904
|
return process.platform === "win32" ? teamStateRoot(cwd, teamName) : "$OMC_TEAM_STATE_ROOT";
|
|
@@ -17643,7 +18096,7 @@ async function reconcileCommittedTeamServices(config, cwd) {
|
|
|
17643
18096
|
}
|
|
17644
18097
|
}
|
|
17645
18098
|
function resolveLeaderBranch(cwd) {
|
|
17646
|
-
const out = (0,
|
|
18099
|
+
const out = (0, import_node_child_process8.execFileSync)("git", ["branch", "--show-current"], {
|
|
17647
18100
|
cwd,
|
|
17648
18101
|
encoding: "utf-8",
|
|
17649
18102
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -17685,6 +18138,14 @@ function resolveTaskAssignment(task, resolvedRouting, roleRoutingConfig, fallbac
|
|
|
17685
18138
|
role: canonical
|
|
17686
18139
|
};
|
|
17687
18140
|
}
|
|
18141
|
+
function isExplicitTaskRoleAssignment(task, roleRoutingConfig, role) {
|
|
18142
|
+
const hasExplicitRole = typeof task.role === "string" && task.role.length > 0;
|
|
18143
|
+
const hasConfigForRole = !!getRoleRoutingSpec(
|
|
18144
|
+
roleRoutingConfig,
|
|
18145
|
+
role
|
|
18146
|
+
);
|
|
18147
|
+
return hasExplicitRole || hasConfigForRole;
|
|
18148
|
+
}
|
|
17688
18149
|
function sanitizeTeamName(name) {
|
|
17689
18150
|
const sanitized = name.toLowerCase().replace(/[^a-z0-9-]/g, "").slice(0, 30);
|
|
17690
18151
|
if (!sanitized) throw new Error(`Invalid team name: "${name}" produces empty slug after sanitization`);
|
|
@@ -17696,12 +18157,12 @@ function resolvePreflightBinaryPath(agentType) {
|
|
|
17696
18157
|
return { path: resolveValidatedBinaryPath(agentType) };
|
|
17697
18158
|
}
|
|
17698
18159
|
function tmuxServerIdentityForTarget(providerTarget, identity) {
|
|
17699
|
-
if (providerTarget.startsWith("cmux:")) return void 0;
|
|
18160
|
+
if (providerTarget.startsWith("cmux:") || isSdkTarget(providerTarget)) return void 0;
|
|
17700
18161
|
if (!isValidTmuxServerIdentity(identity)) return void 0;
|
|
17701
18162
|
return identity;
|
|
17702
18163
|
}
|
|
17703
18164
|
function requireTmuxServerIdentity(providerTarget, identity) {
|
|
17704
|
-
if (providerTarget.startsWith("cmux:")) return void 0;
|
|
18165
|
+
if (providerTarget.startsWith("cmux:") || isSdkTarget(providerTarget)) return void 0;
|
|
17705
18166
|
if (!isValidTmuxServerIdentity(identity)) throw new Error("tmux_server_identity_missing");
|
|
17706
18167
|
return identity;
|
|
17707
18168
|
}
|
|
@@ -17709,6 +18170,7 @@ function configuredPaneOwnership(config, worker) {
|
|
|
17709
18170
|
const paneId = worker.pane_id;
|
|
17710
18171
|
const providerTarget = config.tmux_session;
|
|
17711
18172
|
if (!paneId || !providerTarget) return null;
|
|
18173
|
+
if (isSdkTarget(paneId) || isSdkTarget(providerTarget)) return null;
|
|
17712
18174
|
const provider = paneId.startsWith("%") ? "tmux" : "cmux";
|
|
17713
18175
|
const identity = provider === "tmux" ? tmuxServerIdentityForTarget(providerTarget, config.tmux_server_identity) : void 0;
|
|
17714
18176
|
if (provider === "tmux" && !identity) return null;
|
|
@@ -17915,7 +18377,7 @@ async function waitForStartupEvidenceBudget(hasEvidence, budgetMs, delayMs = WOR
|
|
|
17915
18377
|
if (await hasEvidence()) return true;
|
|
17916
18378
|
const remainingMs = deadline - Date.now();
|
|
17917
18379
|
if (remainingMs <= 0) return false;
|
|
17918
|
-
await new Promise((
|
|
18380
|
+
await new Promise((resolve17) => setTimeout(resolve17, Math.min(delayMs, remainingMs)));
|
|
17919
18381
|
}
|
|
17920
18382
|
}
|
|
17921
18383
|
async function waitForWorkerStartupEvidence(teamName, workerName, taskId, cwd, baseline, launchAttemptId, budgetMs, delayMs = WORKER_STARTUP_EVIDENCE_POLL_INTERVAL_MS) {
|
|
@@ -18061,6 +18523,136 @@ async function readUnresolvedStartupLaunch(opts, paneId) {
|
|
|
18061
18523
|
return null;
|
|
18062
18524
|
}
|
|
18063
18525
|
}
|
|
18526
|
+
function resolveSdkTeamSettings(pluginCfg) {
|
|
18527
|
+
const sdk = pluginCfg.team?.sdk ?? {};
|
|
18528
|
+
const envNumber = (key) => {
|
|
18529
|
+
const n = Number(process.env[key]);
|
|
18530
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
18531
|
+
};
|
|
18532
|
+
const configCap = sdk.maxCreditsPerWorker;
|
|
18533
|
+
if (configCap !== void 0 && !(typeof configCap === "number" && Number.isFinite(configCap) && configCap > 0)) {
|
|
18534
|
+
throw new Error(`invalid_team_sdk_config:maxCreditsPerWorker must be a positive number (got ${JSON.stringify(configCap)})`);
|
|
18535
|
+
}
|
|
18536
|
+
const model = process.env.OMC_TEAM_SDK_MODEL?.trim() || sdk.model?.trim();
|
|
18537
|
+
return {
|
|
18538
|
+
maxCreditsPerWorker: envNumber("OMC_TEAM_SDK_MAX_CREDITS") ?? configCap ?? 10,
|
|
18539
|
+
...model ? { model } : {},
|
|
18540
|
+
startupEvidenceMs: envNumber("OMC_TEAM_SDK_STARTUP_EVIDENCE_MS") ?? sdk.startupEvidenceMs ?? 18e4,
|
|
18541
|
+
denyTools: pluginCfg.permissions?.workerDenyTools ?? [],
|
|
18542
|
+
denyUrls: pluginCfg.permissions?.workerDenyUrls ?? []
|
|
18543
|
+
};
|
|
18544
|
+
}
|
|
18545
|
+
async function spawnSdkV2Worker(opts, sdk) {
|
|
18546
|
+
const injectContract = shouldInjectContract(opts.role ?? null, opts.agentType);
|
|
18547
|
+
const outputFile = injectContract && opts.role ? cliWorkerOutputFilePath(teamStateRoot(opts.cwd, opts.teamName), opts.workerName, {
|
|
18548
|
+
taskId: opts.taskId,
|
|
18549
|
+
assignmentId: opts.verdictAssignmentId
|
|
18550
|
+
}) : void 0;
|
|
18551
|
+
const cliOutputContract = injectContract && opts.role && outputFile ? renderCliWorkerOutputContract(opts.role, outputFile) : void 0;
|
|
18552
|
+
const instruction = buildV2TaskInstruction(
|
|
18553
|
+
opts.teamName,
|
|
18554
|
+
opts.workerName,
|
|
18555
|
+
opts.task,
|
|
18556
|
+
opts.taskId,
|
|
18557
|
+
opts.agentType,
|
|
18558
|
+
cliOutputContract
|
|
18559
|
+
);
|
|
18560
|
+
const stateRoot = teamStateRoot(opts.cwd, opts.teamName);
|
|
18561
|
+
const startupBaseline = await captureWorkerStartupBaseline(opts.teamName, opts.workerName, opts.taskId, opts.cwd);
|
|
18562
|
+
const binary = opts.launchDescriptor.binary;
|
|
18563
|
+
const copilotBin = /\.(cmd|bat|ps1)$/i.test(binary) ? resolveShimTarget(binary) : binary;
|
|
18564
|
+
if (!copilotBin) {
|
|
18565
|
+
return { paneId: null, startupAssigned: false, startupFailureReason: `sdk_copilot_shim_unresolved:${binary}` };
|
|
18566
|
+
}
|
|
18567
|
+
const descriptorModel = opts.launchDescriptor.model ? toCopilotModelId(opts.launchDescriptor.model) : void 0;
|
|
18568
|
+
const model = sdk.model ?? descriptorModel;
|
|
18569
|
+
const workerCwd = opts.workerCwd ?? opts.cwd;
|
|
18570
|
+
const launch = await launchSdkHost({
|
|
18571
|
+
leaderCwd: opts.cwd,
|
|
18572
|
+
teamName: opts.teamName,
|
|
18573
|
+
workerName: opts.workerName,
|
|
18574
|
+
instanceId: opts.instanceId,
|
|
18575
|
+
workerCwd,
|
|
18576
|
+
stateRoot,
|
|
18577
|
+
workerEnv: {
|
|
18578
|
+
...getWorkerEnv(opts.teamName, opts.workerName, opts.agentType, process.env, opts.role),
|
|
18579
|
+
OMC_TEAM_STATE_ROOT: stateRoot,
|
|
18580
|
+
OMC_TEAM_LEADER_CWD: opts.cwd,
|
|
18581
|
+
...opts.worktreePath ? { OMC_TEAM_WORKTREE_PATH: opts.worktreePath } : {},
|
|
18582
|
+
OMC_TEAM_WORKER_CWD: workerCwd
|
|
18583
|
+
},
|
|
18584
|
+
copilotBin,
|
|
18585
|
+
pluginRoot: resolveDefaultPluginRoot(),
|
|
18586
|
+
userConfigDir: getCopilotConfigDir(),
|
|
18587
|
+
...model ? { model } : {},
|
|
18588
|
+
maxCredits: sdk.maxCreditsPerWorker,
|
|
18589
|
+
denyTools: sdk.denyTools,
|
|
18590
|
+
denyUrls: sdk.denyUrls
|
|
18591
|
+
});
|
|
18592
|
+
const paneId = sdkPaneId(opts.workerName);
|
|
18593
|
+
if (!launch.ok) {
|
|
18594
|
+
return {
|
|
18595
|
+
paneId: launch.attempt ? paneId : null,
|
|
18596
|
+
startupAssigned: false,
|
|
18597
|
+
startupFailureReason: launch.reason,
|
|
18598
|
+
...launch.attempt ? { launchAttemptId: launch.attempt.attempt_id } : {}
|
|
18599
|
+
};
|
|
18600
|
+
}
|
|
18601
|
+
const attempt = launch.attempt;
|
|
18602
|
+
const triggerMessage = `${generateTriggerMessage(opts.teamName, opts.workerName, workerInstructionStateRoot(opts.cwd, opts.teamName))} [launch:${attempt.attempt_id.slice(0, 12)}]`;
|
|
18603
|
+
const fenced = await withWorkerLaunchAttemptFence(attempt, () => queueInboxInstruction({
|
|
18604
|
+
teamName: opts.teamName,
|
|
18605
|
+
workerName: opts.workerName,
|
|
18606
|
+
workerIndex: opts.workerIndex + 1,
|
|
18607
|
+
paneId,
|
|
18608
|
+
inbox: instruction,
|
|
18609
|
+
triggerMessage,
|
|
18610
|
+
cwd: opts.cwd,
|
|
18611
|
+
transportPreference: "prompt_stdin",
|
|
18612
|
+
fallbackAllowed: false,
|
|
18613
|
+
inboxCorrelationKey: `startup:${opts.workerName}:${opts.taskId}:${attempt.attempt_id}`,
|
|
18614
|
+
notify: async (_target, message) => {
|
|
18615
|
+
ringDoorbell(stateRoot, opts.workerName, { kind: "prompt", text: message, from: "leader-fixed" });
|
|
18616
|
+
const settled = await waitForStartupEvidenceBudget(
|
|
18617
|
+
async () => {
|
|
18618
|
+
if (await hasCurrentWorkerStartupEvidence(opts.teamName, opts.workerName, opts.taskId, opts.cwd, startupBaseline, attempt.attempt_id)) return true;
|
|
18619
|
+
const session = readSdkSession(stateRoot, opts.workerName);
|
|
18620
|
+
if (session?.state === "failed" || session?.state === "closed") throw new Error(`sdk_host_${session.state}:${session.last_error ?? ""}`);
|
|
18621
|
+
return false;
|
|
18622
|
+
},
|
|
18623
|
+
sdk.startupEvidenceMs,
|
|
18624
|
+
500
|
|
18625
|
+
).catch(() => false);
|
|
18626
|
+
return settled ? { ok: true, transport: "prompt_stdin", reason: "sdk_worker_startup_confirmed" } : { ok: false, transport: "prompt_stdin", reason: "copilot_sdk_startup_evidence_missing" };
|
|
18627
|
+
},
|
|
18628
|
+
deps: { writeWorkerInbox }
|
|
18629
|
+
}));
|
|
18630
|
+
const outcome = fenced.ok ? fenced.value : { ok: false, reason: "worker_launch_attempt_superseded" };
|
|
18631
|
+
if (!outcome.ok) {
|
|
18632
|
+
const session = readSdkSession(stateRoot, opts.workerName);
|
|
18633
|
+
const claimError = session?.last_error ? redactBoundedDiagnostic(session.last_error, 240) : void 0;
|
|
18634
|
+
const stopped = await stopSdkHost(attempt, stateRoot, { timeoutMs: 3e4 });
|
|
18635
|
+
const cleaned = stopped && await retireAndCleanupCurrentWorkerLaunchAttempt(attempt, "startup_dispatch_failed", async () => true).catch(() => false);
|
|
18636
|
+
if (!cleaned) {
|
|
18637
|
+
const error = new Error(`worker_startup_cleanup_unverified:${opts.workerName}:${paneId}`);
|
|
18638
|
+
error.unresolvedLaunch = { name: opts.workerName, paneId, launchAttemptId: attempt.attempt_id, provider: "copilot" };
|
|
18639
|
+
throw error;
|
|
18640
|
+
}
|
|
18641
|
+
return {
|
|
18642
|
+
paneId,
|
|
18643
|
+
startupAssigned: false,
|
|
18644
|
+
startupFailureReason: outcome.reason,
|
|
18645
|
+
...claimError ? { claimError } : {},
|
|
18646
|
+
launchAttemptId: attempt.attempt_id
|
|
18647
|
+
};
|
|
18648
|
+
}
|
|
18649
|
+
return {
|
|
18650
|
+
paneId,
|
|
18651
|
+
startupAssigned: true,
|
|
18652
|
+
launchAttemptId: attempt.attempt_id,
|
|
18653
|
+
...outputFile ? { outputFile } : {}
|
|
18654
|
+
};
|
|
18655
|
+
}
|
|
18064
18656
|
async function spawnV2Worker(opts) {
|
|
18065
18657
|
const splitTarget = opts.existingWorkerPaneIds.length === 0 ? opts.leaderPaneId : opts.existingWorkerPaneIds[opts.existingWorkerPaneIds.length - 1];
|
|
18066
18658
|
const splitDirection = opts.existingWorkerPaneIds.length === 0 ? "right" : "down";
|
|
@@ -18307,8 +18899,8 @@ function validateRecoveryAttemptSecret(value, input, recoveryId, replacementGene
|
|
|
18307
18899
|
async function recordRecoveryPaneRollbackFailure(input, recoveryId, pending, reason, liveness) {
|
|
18308
18900
|
const recordedAt = Date.now();
|
|
18309
18901
|
const path5 = absPath(input.cwd, TeamPaths.recoveryPaneRollbackFailure(input.teamName, recoveryId, pending.paneAttemptId, recordedAt));
|
|
18310
|
-
const candidate = `${path5}.candidate.${process.pid}.${(0,
|
|
18311
|
-
await (0, import_promises19.mkdir)((0,
|
|
18902
|
+
const candidate = `${path5}.candidate.${process.pid}.${(0, import_node_crypto10.randomUUID)()}`;
|
|
18903
|
+
await (0, import_promises19.mkdir)((0, import_path38.join)(path5, ".."), { recursive: true });
|
|
18312
18904
|
const handle = await (0, import_promises19.open)(candidate, "wx", 384);
|
|
18313
18905
|
try {
|
|
18314
18906
|
await handle.writeFile(JSON.stringify({
|
|
@@ -18337,8 +18929,8 @@ async function recordRecoveryPaneRollbackFailure(input, recoveryId, pending, rea
|
|
|
18337
18929
|
async function recordUnaddressableRecoveryPaneFailure(input, recoveryId, paneAttemptId, reason, split) {
|
|
18338
18930
|
const recordedAt = Date.now();
|
|
18339
18931
|
const path5 = absPath(input.cwd, TeamPaths.recoveryPaneRollbackFailure(input.teamName, recoveryId, paneAttemptId, recordedAt));
|
|
18340
|
-
const candidate = `${path5}.candidate.${process.pid}.${(0,
|
|
18341
|
-
await (0, import_promises19.mkdir)((0,
|
|
18932
|
+
const candidate = `${path5}.candidate.${process.pid}.${(0, import_node_crypto10.randomUUID)()}`;
|
|
18933
|
+
await (0, import_promises19.mkdir)((0, import_path38.join)(path5, ".."), { recursive: true });
|
|
18342
18934
|
const handle = await (0, import_promises19.open)(candidate, "wx", 384);
|
|
18343
18935
|
const boundedSplit = split ? {
|
|
18344
18936
|
...split,
|
|
@@ -18661,11 +19253,11 @@ async function readOrCreateRecoveryAttempt(input, recoveryId, replacementGenerat
|
|
|
18661
19253
|
recovery_id: recoveryId,
|
|
18662
19254
|
worker_name: input.workerName,
|
|
18663
19255
|
replacement_generation: replacementGeneration,
|
|
18664
|
-
adoption_token: (0,
|
|
19256
|
+
adoption_token: (0, import_node_crypto10.randomUUID)(),
|
|
18665
19257
|
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
18666
19258
|
};
|
|
18667
|
-
await (0, import_promises19.mkdir)((0,
|
|
18668
|
-
const candidate = `${path5}.candidate.${process.pid}.${(0,
|
|
19259
|
+
await (0, import_promises19.mkdir)((0, import_path38.join)(path5, ".."), { recursive: true });
|
|
19260
|
+
const candidate = `${path5}.candidate.${process.pid}.${(0, import_node_crypto10.randomUUID)()}`;
|
|
18669
19261
|
const candidateHandle = await (0, import_promises19.open)(candidate, "wx", 384);
|
|
18670
19262
|
try {
|
|
18671
19263
|
await candidateHandle.writeFile(JSON.stringify(secret, null, 2), "utf8");
|
|
@@ -18684,14 +19276,14 @@ async function readOrCreateRecoveryAttempt(input, recoveryId, replacementGenerat
|
|
|
18684
19276
|
}
|
|
18685
19277
|
}
|
|
18686
19278
|
function waitForBootstrapRecoveryEvidence(delayMs, signal) {
|
|
18687
|
-
return new Promise((
|
|
19279
|
+
return new Promise((resolve17, reject) => {
|
|
18688
19280
|
if (signal?.aborted) {
|
|
18689
19281
|
reject(signal.reason ?? new Error("bootstrap_recovery_evidence_aborted"));
|
|
18690
19282
|
return;
|
|
18691
19283
|
}
|
|
18692
19284
|
const timer = setTimeout(() => {
|
|
18693
19285
|
signal?.removeEventListener("abort", onAbort);
|
|
18694
|
-
|
|
19286
|
+
resolve17();
|
|
18695
19287
|
}, delayMs);
|
|
18696
19288
|
const onAbort = () => {
|
|
18697
19289
|
clearTimeout(timer);
|
|
@@ -18734,7 +19326,7 @@ function isCanonicalBootstrapCandidate(value, expectedEpoch) {
|
|
|
18734
19326
|
const candidate = value;
|
|
18735
19327
|
if (!candidate || candidate.schema_version !== 1 || candidate.expected_epoch !== expectedEpoch || typeof candidate.request_id !== "string" || candidate.request_id.length === 0 || typeof candidate.recovery_id !== "string" || candidate.recovery_id.length === 0 || typeof candidate.team_name !== "string" || candidate.team_name.length === 0 || typeof candidate.worker_name !== "string" || candidate.worker_name.length === 0 || !isValidTeamInstanceId(candidate.instance_id) || typeof candidate.nonce !== "string" || candidate.nonce.length === 0 || typeof candidate.pid !== "number" || !Number.isSafeInteger(candidate.pid) || candidate.pid < 1 || typeof candidate.process_started_at !== "string" || candidate.process_started_at.length === 0 || typeof candidate.predecessor_epoch !== "number" || !Number.isSafeInteger(candidate.predecessor_epoch) || candidate.predecessor_epoch < 0 || candidate.expected_epoch !== candidate.predecessor_epoch + 1 || candidate.predecessor_epoch === 0 && (candidate.predecessor_nonce !== null || candidate.predecessor_pid !== null || candidate.predecessor_process_started_at !== null) || candidate.predecessor_epoch > 0 && (typeof candidate.predecessor_nonce !== "string" || candidate.predecessor_nonce.length === 0 || typeof candidate.predecessor_pid !== "number" || !Number.isSafeInteger(candidate.predecessor_pid) || candidate.predecessor_pid < 1 || typeof candidate.predecessor_process_started_at !== "string" || candidate.predecessor_process_started_at.length === 0) || typeof candidate.created_at !== "string" || !Number.isFinite(Date.parse(candidate.created_at)) || typeof candidate.payload_hash !== "string") return false;
|
|
18736
19328
|
const { payload_hash, ...unsigned } = candidate;
|
|
18737
|
-
return (0,
|
|
19329
|
+
return (0, import_node_crypto10.createHash)("sha256").update(JSON.stringify(unsigned)).digest("hex") === payload_hash;
|
|
18738
19330
|
}
|
|
18739
19331
|
async function readRecoveryOwnerBootstrapCandidate(teamName, cwd, expectedEpoch, nonce) {
|
|
18740
19332
|
try {
|
|
@@ -18791,7 +19383,7 @@ async function isExactDeadOrphanBootstrapCandidate(teamName, cwd, input, config,
|
|
|
18791
19383
|
function isExactRecoverySidecar(value, task, input, active, replacementGeneration, adoptionToken) {
|
|
18792
19384
|
const sidecar = value;
|
|
18793
19385
|
const persisted = task.recovery_reservation ?? task.recovery_adoption;
|
|
18794
|
-
if (!sidecar || !persisted || sidecar.schema_version !== 1 || sidecar.recovery_id !== active.recovery_id || sidecar.request_id !== input.requestId || sidecar.task_id !== task.id || sidecar.old_owner !== input.workerName || typeof sidecar.old_task_version !== "number" || !Number.isSafeInteger(sidecar.old_task_version) || sidecar.old_task_version < 1 || typeof sidecar.old_claim_token !== "string" || sidecar.old_claim_token.length === 0 || typeof sidecar.old_claim_leased_until !== "string" || !Number.isFinite(Date.parse(sidecar.old_claim_leased_until)) || typeof sidecar.continuation_sequence !== "number" || !Number.isSafeInteger(sidecar.continuation_sequence) || sidecar.continuation_sequence < 1 || typeof sidecar.checkpoint_path !== "string" || sidecar.checkpoint_path.length === 0 || typeof sidecar.checkpoint_hash !== "string" || !/^[a-f0-9]{64}$/.test(sidecar.checkpoint_hash) || sidecar.replacement_worker !== input.workerName || sidecar.replacement_generation !== replacementGeneration || sidecar.adoption_token_hash !== (0,
|
|
19386
|
+
if (!sidecar || !persisted || sidecar.schema_version !== 1 || sidecar.recovery_id !== active.recovery_id || sidecar.request_id !== input.requestId || sidecar.task_id !== task.id || sidecar.old_owner !== input.workerName || typeof sidecar.old_task_version !== "number" || !Number.isSafeInteger(sidecar.old_task_version) || sidecar.old_task_version < 1 || typeof sidecar.old_claim_token !== "string" || sidecar.old_claim_token.length === 0 || typeof sidecar.old_claim_leased_until !== "string" || !Number.isFinite(Date.parse(sidecar.old_claim_leased_until)) || typeof sidecar.continuation_sequence !== "number" || !Number.isSafeInteger(sidecar.continuation_sequence) || sidecar.continuation_sequence < 1 || typeof sidecar.checkpoint_path !== "string" || sidecar.checkpoint_path.length === 0 || typeof sidecar.checkpoint_hash !== "string" || !/^[a-f0-9]{64}$/.test(sidecar.checkpoint_hash) || sidecar.replacement_worker !== input.workerName || sidecar.replacement_generation !== replacementGeneration || sidecar.adoption_token_hash !== (0, import_node_crypto10.createHash)("sha256").update(adoptionToken).digest("hex") || typeof sidecar.created_at !== "string" || !Number.isFinite(Date.parse(sidecar.created_at))) return false;
|
|
18795
19387
|
const sameReservation = persisted.recovery_id === sidecar.recovery_id && persisted.request_id === sidecar.request_id && persisted.continuation_sequence === sidecar.continuation_sequence && persisted.checkpoint_path === sidecar.checkpoint_path && persisted.checkpoint_hash === sidecar.checkpoint_hash && persisted.replacement_worker === sidecar.replacement_worker && persisted.replacement_generation === sidecar.replacement_generation;
|
|
18796
19388
|
if (!sameReservation) return false;
|
|
18797
19389
|
if ("adoption_token_hash" in persisted && persisted.adoption_token_hash !== sidecar.adoption_token_hash) return false;
|
|
@@ -18995,7 +19587,7 @@ async function prepareRecoveryOwnerBootstrap(input, waitOptions) {
|
|
|
18995
19587
|
}
|
|
18996
19588
|
async function executeRecoverDeadWorkerV2Owner(input) {
|
|
18997
19589
|
const reservation = readRecoveryRequestReservation(input.cwd, input.requestId);
|
|
18998
|
-
const recoveryId = reservation?.recovery_id ?? (0,
|
|
19590
|
+
const recoveryId = reservation?.recovery_id ?? (0, import_node_crypto10.randomUUID)();
|
|
18999
19591
|
let ownerBound = false;
|
|
19000
19592
|
try {
|
|
19001
19593
|
if (!isValidTeamInstanceId(input.instanceId)) {
|
|
@@ -19475,7 +20067,7 @@ async function executeRecoverDeadWorkerV2Owner(input) {
|
|
|
19475
20067
|
} catch {
|
|
19476
20068
|
return { ok: false, error: "launch_descriptor_unresolvable" };
|
|
19477
20069
|
}
|
|
19478
|
-
const paneAttemptId = (0,
|
|
20070
|
+
const paneAttemptId = (0, import_node_crypto10.randomUUID)();
|
|
19479
20071
|
const livePaneIds = [];
|
|
19480
20072
|
for (const candidate of config.workers) {
|
|
19481
20073
|
if (!candidate.pane_id || candidate.name === sagaInput2.workerName) continue;
|
|
@@ -19668,7 +20260,7 @@ async function executeRecoverDeadWorkerV2Owner(input) {
|
|
|
19668
20260
|
launch_nonce: pending.startupContext.attempt.nonce,
|
|
19669
20261
|
written_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
19670
20262
|
};
|
|
19671
|
-
await (0, import_promises19.mkdir)((0,
|
|
20263
|
+
await (0, import_promises19.mkdir)((0, import_path38.join)(pending.gate.activatePath, ".."), { recursive: true });
|
|
19672
20264
|
await (0, import_promises19.writeFile)(pending.gate.activatePath, JSON.stringify(record), "utf8");
|
|
19673
20265
|
const adoptedReady = await waitForRecoveryGateRecord(`${pending.gate.readyPath}.adoption-ready`, record, 3e4);
|
|
19674
20266
|
return adoptedReady && await isWorkerLaunchAttemptCurrent(pending.startupContext.attempt) ? { ok: true } : { ok: false, error: "worker_activation_failed" };
|
|
@@ -19795,7 +20387,7 @@ ${recoveryContract}` : ""}`;
|
|
|
19795
20387
|
let providerLive = false;
|
|
19796
20388
|
try {
|
|
19797
20389
|
const launchedRecord = JSON.parse(await (0, import_promises19.readFile)(launchedPath, "utf8"));
|
|
19798
|
-
providerLive = Number.isInteger(launchedRecord.provider_pid) && typeof launchedRecord.provider_start_identity === "string" && (launchedRecord.supervisor_completion_path === void 0 || typeof launchedRecord.supervisor_completion_path === "string" && launchedRecord.supervisor_completion_path.trim().length > 0 && !(0,
|
|
20390
|
+
providerLive = Number.isInteger(launchedRecord.provider_pid) && typeof launchedRecord.provider_start_identity === "string" && (launchedRecord.supervisor_completion_path === void 0 || typeof launchedRecord.supervisor_completion_path === "string" && launchedRecord.supervisor_completion_path.trim().length > 0 && !(0, import_fs34.existsSync)(launchedRecord.supervisor_completion_path)) && await isProcessIdentityLive(
|
|
19799
20391
|
launchedRecord.provider_pid,
|
|
19800
20392
|
launchedRecord.provider_start_identity,
|
|
19801
20393
|
Date.now() + 1e3
|
|
@@ -19874,7 +20466,7 @@ async function rollbackUnpersistedNativeWorktreeStartup(teamName, cwd, cause, in
|
|
|
19874
20466
|
const recordedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
19875
20467
|
const writeFailureMarker = async (extra = {}) => {
|
|
19876
20468
|
await (0, import_promises19.mkdir)(teamRoot, { recursive: true });
|
|
19877
|
-
await (0, import_promises19.writeFile)((0,
|
|
20469
|
+
await (0, import_promises19.writeFile)((0, import_path38.join)(teamRoot, "startup-failure.json"), JSON.stringify({
|
|
19878
20470
|
reason: "startup_failed_before_config_persisted",
|
|
19879
20471
|
error: errorMessage,
|
|
19880
20472
|
recorded_at: recordedAt,
|
|
@@ -19905,7 +20497,7 @@ async function rollbackUnpersistedNativeWorktreeStartup(teamName, cwd, cause, in
|
|
|
19905
20497
|
}
|
|
19906
20498
|
}
|
|
19907
20499
|
await (0, import_promises19.rm)(teamRoot, { recursive: true, force: true });
|
|
19908
|
-
if ((0,
|
|
20500
|
+
if ((0, import_fs34.existsSync)(teamRoot)) {
|
|
19909
20501
|
await writeFailureMarker({ rollback_error: "startup_state_removal_unverified" });
|
|
19910
20502
|
return false;
|
|
19911
20503
|
}
|
|
@@ -19929,7 +20521,7 @@ async function rollbackUnpersistedNativeWorktreeStartup(teamName, cwd, cause, in
|
|
|
19929
20521
|
async function writeStartedStartupRollbackEvidence(args) {
|
|
19930
20522
|
const teamRoot = absPath(args.cwd, TeamPaths.root(args.teamName));
|
|
19931
20523
|
await (0, import_promises19.mkdir)(teamRoot, { recursive: true });
|
|
19932
|
-
await (0, import_promises19.writeFile)((0,
|
|
20524
|
+
await (0, import_promises19.writeFile)((0, import_path38.join)(teamRoot, "startup-failure.json"), JSON.stringify({
|
|
19933
20525
|
reason: args.markerReason ?? "startup_rollback_cleanup_incomplete",
|
|
19934
20526
|
error: args.cause instanceof Error ? args.cause.message : String(args.cause),
|
|
19935
20527
|
rollback_error: args.reason,
|
|
@@ -19980,7 +20572,12 @@ async function rollbackStartedNativeWorktreeStartup(args) {
|
|
|
19980
20572
|
await writeStartedStartupRollbackEvidence({ ...args, reason: "launch_attempt_identity_unverified", worker: worker.name });
|
|
19981
20573
|
throw new Error(`worker_cleanup_incomplete:${worker.name}:launch_attempt_identity_unverified`);
|
|
19982
20574
|
}
|
|
20575
|
+
if (isSdkTarget(worker.paneId) && !await stopSdkHost(attempt, teamStateRoot(args.cwd, args.teamName), { timeoutMs: 3e4 })) {
|
|
20576
|
+
await writeStartedStartupRollbackEvidence({ ...args, reason: "sdk_host_stop_unverified", worker: worker.name });
|
|
20577
|
+
throw new Error(`worker_cleanup_incomplete:${worker.name}:sdk_host_stop_unverified`);
|
|
20578
|
+
}
|
|
19983
20579
|
const cleaned = await retireAndCleanupCurrentWorkerLaunchAttempt(attempt, "startup_rollback", async () => {
|
|
20580
|
+
if (isSdkTarget(worker.paneId)) return true;
|
|
19984
20581
|
const ownership = {
|
|
19985
20582
|
provider: worker.paneId.startsWith("%") ? "tmux" : "cmux",
|
|
19986
20583
|
providerTarget: args.sessionName,
|
|
@@ -20002,7 +20599,7 @@ async function rollbackStartedNativeWorktreeStartup(args) {
|
|
|
20002
20599
|
throw new Error(`worker_cleanup_incomplete:${worker.name}:provider_cleanup_unverified`);
|
|
20003
20600
|
}
|
|
20004
20601
|
}
|
|
20005
|
-
if (sessionCleanupRequired && !(args.workerPaneIds.length === 0 && args.sessionMode === "split-pane" && (args.launchedWorkers?.length ?? 0) > 0)) {
|
|
20602
|
+
if (sessionCleanupRequired && !isSdkTarget(args.sessionName) && !(args.workerPaneIds.length === 0 && args.sessionMode === "split-pane" && (args.launchedWorkers?.length ?? 0) > 0)) {
|
|
20006
20603
|
const sessionCleaned = await killTeamSession(
|
|
20007
20604
|
args.sessionName,
|
|
20008
20605
|
args.workerPaneIds,
|
|
@@ -20108,12 +20705,17 @@ async function startTeamV2(config) {
|
|
|
20108
20705
|
}
|
|
20109
20706
|
const instance = createTeamInstanceBinding({
|
|
20110
20707
|
teamName: sanitized,
|
|
20111
|
-
cwd: (0,
|
|
20708
|
+
cwd: (0, import_path38.resolve)(config.cwd),
|
|
20112
20709
|
...config.instanceId !== void 0 ? { instanceId: config.instanceId } : {}
|
|
20113
20710
|
});
|
|
20114
20711
|
const leaderCwd = instance.cwd;
|
|
20115
20712
|
const pluginCfg = config.pluginConfig ?? loadConfig();
|
|
20116
20713
|
const resolvedRouting = buildResolvedRoutingSnapshot(pluginCfg);
|
|
20714
|
+
const transport = config.transport ?? pluginCfg.team?.transport ?? "pane";
|
|
20715
|
+
if (transport !== "pane" && transport !== "sdk") throw new Error(`invalid_team_transport:${String(transport)}`);
|
|
20716
|
+
const sdkMode = transport === "sdk";
|
|
20717
|
+
const sdkSettings = sdkMode ? resolveSdkTeamSettings(pluginCfg) : null;
|
|
20718
|
+
if (sdkMode && config.autoMerge) throw new Error("sdk_transport_unsupported:auto_merge");
|
|
20117
20719
|
let worktreeMode = normalizeTeamWorktreeMode(
|
|
20118
20720
|
process.env.OMC_TEAM_WORKTREE_MODE ?? pluginCfg.team?.ops?.worktreeMode
|
|
20119
20721
|
);
|
|
@@ -20179,21 +20781,33 @@ async function startTeamV2(config) {
|
|
|
20179
20781
|
const workerName = workerNames[i];
|
|
20180
20782
|
const taskIndex = startupByWorker.get(workerName);
|
|
20181
20783
|
const fallbackAgent = agentTypes[i % agentTypes.length] ?? agentTypes[0] ?? "claude";
|
|
20182
|
-
const
|
|
20183
|
-
|
|
20184
|
-
|
|
20185
|
-
|
|
20186
|
-
|
|
20187
|
-
|
|
20784
|
+
const roleRoutingConfig = pluginCfg.team?.roleRouting;
|
|
20785
|
+
const task = taskIndex === void 0 ? void 0 : config.tasks[taskIndex];
|
|
20786
|
+
const resolvedAssignment = task === void 0 ? { agentType: fallbackAgent, model: "", reasoningEffort: void 0, role: void 0 } : resolveTaskAssignment(task, resolvedRouting, roleRoutingConfig, fallbackAgent);
|
|
20787
|
+
let role = resolvedAssignment.role ?? void 0;
|
|
20788
|
+
if (sdkMode && role && shouldInjectContract(role, resolvedAssignment.agentType) && task && !isExplicitTaskRoleAssignment(task, roleRoutingConfig, role)) {
|
|
20789
|
+
process.stderr.write(`[omg team] sdk transport: inferred role "${role}" for worker ${workerName} would require a verdict contract the sdk transport cannot process; running as a plain executor instead (an explicitly assigned contract role is still rejected)
|
|
20790
|
+
`);
|
|
20791
|
+
role = void 0;
|
|
20792
|
+
}
|
|
20188
20793
|
const assignment = {
|
|
20189
20794
|
agentType: resolvedAssignment.agentType,
|
|
20190
20795
|
model: resolvedAssignment.model || resolveDefaultModel(resolvedAssignment.agentType),
|
|
20191
20796
|
reasoningEffort: resolvedAssignment.reasoningEffort,
|
|
20192
|
-
...
|
|
20797
|
+
...role ? { role } : {}
|
|
20193
20798
|
};
|
|
20194
20799
|
startupAssignments.set(workerName, assignment);
|
|
20195
20800
|
effectiveAgentTypes.add(assignment.agentType);
|
|
20196
20801
|
}
|
|
20802
|
+
if (sdkMode && [...effectiveAgentTypes].some((agentType) => agentType !== "copilot")) {
|
|
20803
|
+
throw new Error(`sdk_transport_requires_copilot_workers:${[...effectiveAgentTypes].join(",")}`);
|
|
20804
|
+
}
|
|
20805
|
+
if (sdkMode) {
|
|
20806
|
+
const contractRoles = [...new Set([...startupAssignments.values()].flatMap((a) => a.role && shouldInjectContract(a.role, a.agentType) ? [a.role] : []))];
|
|
20807
|
+
if (contractRoles.length > 0) {
|
|
20808
|
+
throw new Error(`sdk_transport_unsupported:contract_roles:${contractRoles.join(",")} (${[...CONTRACT_ROLES].join("/")} workers emit verdict files the sdk transport does not process; use --transport pane for an explicitly assigned reviewer-style role, or stop assigning it explicitly to let it run as a plain executor)`);
|
|
20809
|
+
}
|
|
20810
|
+
}
|
|
20197
20811
|
for (const agentType of effectiveAgentTypes) {
|
|
20198
20812
|
try {
|
|
20199
20813
|
resolvedBinaryPaths[agentType] = resolvePreflightBinaryPath(agentType).path;
|
|
@@ -20233,7 +20847,7 @@ async function startTeamV2(config) {
|
|
|
20233
20847
|
try {
|
|
20234
20848
|
const pendingConfig = buildTeamInstancePendingConfig(instance);
|
|
20235
20849
|
const pendingConfigPath = absPath(leaderCwd, TeamPaths.config(sanitized));
|
|
20236
|
-
await (0, import_promises19.mkdir)((0,
|
|
20850
|
+
await (0, import_promises19.mkdir)((0, import_path38.join)(pendingConfigPath, ".."), { recursive: true });
|
|
20237
20851
|
await (0, import_promises19.writeFile)(pendingConfigPath, JSON.stringify(pendingConfig, null, 2), "utf-8");
|
|
20238
20852
|
} catch (error) {
|
|
20239
20853
|
if (!await rollbackBeforeConfig(error)) throw startupCleanupIncompleteError(error);
|
|
@@ -20244,7 +20858,7 @@ async function startTeamV2(config) {
|
|
|
20244
20858
|
try {
|
|
20245
20859
|
await (0, import_promises19.mkdir)(absPath(leaderCwd, TeamPaths.tasks(sanitized)), { recursive: true });
|
|
20246
20860
|
await (0, import_promises19.mkdir)(absPath(leaderCwd, TeamPaths.workers(sanitized)), { recursive: true });
|
|
20247
|
-
await (0, import_promises19.mkdir)((0,
|
|
20861
|
+
await (0, import_promises19.mkdir)((0, import_path38.join)(getOmcRoot(leaderCwd), "state", "team", sanitized, "mailbox"), { recursive: true });
|
|
20248
20862
|
for (let i = 0; i < config.tasks.length; i++) {
|
|
20249
20863
|
const taskId = String(i + 1);
|
|
20250
20864
|
const task = config.tasks[i];
|
|
@@ -20281,7 +20895,7 @@ async function startTeamV2(config) {
|
|
|
20281
20895
|
const assignment = startupAssignments.get(workerName);
|
|
20282
20896
|
if (!assignment) throw new Error(`Missing startup assignment for ${workerName}`);
|
|
20283
20897
|
const worktree = workerWorktrees.get(workerName);
|
|
20284
|
-
const verdictAssignmentId = taskIndex !== void 0 ? (0,
|
|
20898
|
+
const verdictAssignmentId = taskIndex !== void 0 ? (0, import_node_crypto10.randomUUID)() : void 0;
|
|
20285
20899
|
const outputFile = taskIndex !== void 0 && assignment.role && shouldInjectContract(assignment.role, assignment.agentType) ? cliWorkerOutputFilePath(teamStateRoot(leaderCwd, sanitized), workerName, {
|
|
20286
20900
|
taskId: String(taskIndex + 1),
|
|
20287
20901
|
assignmentId: verdictAssignmentId
|
|
@@ -20318,7 +20932,8 @@ async function startTeamV2(config) {
|
|
|
20318
20932
|
if (!await rollbackBeforeConfig(error)) throw startupCleanupIncompleteError(error);
|
|
20319
20933
|
throw error;
|
|
20320
20934
|
}
|
|
20321
|
-
|
|
20935
|
+
const permissionLines = sdkSettings ? [`[omg team] copilot sdk workers (x${preparedLaunches.size}): no allow-all; host permission policy (writes: worktree + team state; shell: denylist, not a sandbox: all but team control/smoke/tmux/git push; no sub-agent tools); deny: ${[...sdkSettings.denyTools, ...sdkSettings.denyUrls.map((u) => `url(${u})`)].join(", ") || "(none)"}; credit cap ${sdkSettings.maxCreditsPerWorker}/worker`] : formatWorkerPermissionLines(preparedLaunches.values());
|
|
20936
|
+
for (const line of permissionLines) {
|
|
20322
20937
|
process.stderr.write(`${line}
|
|
20323
20938
|
`);
|
|
20324
20939
|
}
|
|
@@ -20355,7 +20970,7 @@ async function startTeamV2(config) {
|
|
|
20355
20970
|
}
|
|
20356
20971
|
let session;
|
|
20357
20972
|
try {
|
|
20358
|
-
session = await createTeamSession(sanitized, 0, leaderCwd, {
|
|
20973
|
+
session = sdkMode ? { sessionName: sdkTeamTarget(sanitized), leaderPaneId: "", workerPaneIds: [], sessionMode: "split-pane" } : await createTeamSession(sanitized, 0, leaderCwd, {
|
|
20359
20974
|
newWindow: Boolean(config.newWindow)
|
|
20360
20975
|
});
|
|
20361
20976
|
} catch (error) {
|
|
@@ -20375,6 +20990,7 @@ async function startTeamV2(config) {
|
|
|
20375
20990
|
role: preparedLaunches.get(wName)?.role ?? config.workerRoles?.[i] ?? (agentTypes[i % agentTypes.length] ?? agentTypes[0] ?? "claude"),
|
|
20376
20991
|
worker_cli: preparedLaunches.get(wName).descriptor.provider,
|
|
20377
20992
|
launch_descriptor: preparedLaunches.get(wName).descriptor,
|
|
20993
|
+
...sdkMode ? { transport: "sdk" } : {},
|
|
20378
20994
|
assigned_tasks: [],
|
|
20379
20995
|
working_dir: worktree?.path ?? leaderCwd,
|
|
20380
20996
|
team_state_root: teamStateRoot(leaderCwd, sanitized),
|
|
@@ -20420,7 +21036,7 @@ async function startTeamV2(config) {
|
|
|
20420
21036
|
service_descriptor: config.autoMerge ? {
|
|
20421
21037
|
schema_version: 1,
|
|
20422
21038
|
service_generation: 1,
|
|
20423
|
-
service_attempt_id: (0,
|
|
21039
|
+
service_attempt_id: (0, import_node_crypto10.randomUUID)(),
|
|
20424
21040
|
auto_merge_enabled: true,
|
|
20425
21041
|
workspace_root: leaderCwd,
|
|
20426
21042
|
leader_branch: autoMergeLeaderBranch,
|
|
@@ -20428,7 +21044,7 @@ async function startTeamV2(config) {
|
|
|
20428
21044
|
} : {
|
|
20429
21045
|
schema_version: 1,
|
|
20430
21046
|
service_generation: 1,
|
|
20431
|
-
service_attempt_id: (0,
|
|
21047
|
+
service_attempt_id: (0, import_node_crypto10.randomUUID)(),
|
|
20432
21048
|
auto_merge_enabled: false,
|
|
20433
21049
|
workspace_root: leaderCwd,
|
|
20434
21050
|
cadence_policy: "disabled"
|
|
@@ -20516,7 +21132,7 @@ async function startTeamV2(config) {
|
|
|
20516
21132
|
if (!prepared) continue;
|
|
20517
21133
|
const workerInfo = workersInfo[workerIndex];
|
|
20518
21134
|
if (!workerInfo) continue;
|
|
20519
|
-
const
|
|
21135
|
+
const spawnOptions = {
|
|
20520
21136
|
sessionName: sessionName2,
|
|
20521
21137
|
...session.tmuxServerIdentity ? { tmuxServerIdentity: session.tmuxServerIdentity } : {},
|
|
20522
21138
|
leaderPaneId,
|
|
@@ -20535,7 +21151,8 @@ async function startTeamV2(config) {
|
|
|
20535
21151
|
autoMerge: Boolean(config.autoMerge),
|
|
20536
21152
|
...prepared.role ? { role: prepared.role } : {},
|
|
20537
21153
|
...prepared.verdictAssignmentId ? { verdictAssignmentId: prepared.verdictAssignmentId } : {}
|
|
20538
|
-
}
|
|
21154
|
+
};
|
|
21155
|
+
const workerLaunch = sdkSettings ? await spawnSdkV2Worker(spawnOptions, sdkSettings) : await spawnV2Worker(spawnOptions);
|
|
20539
21156
|
if (workerLaunch.paneId) {
|
|
20540
21157
|
if (workerLaunch.startupAssigned) workerPaneIds.push(workerLaunch.paneId);
|
|
20541
21158
|
launchedWorkers.push({
|
|
@@ -20710,7 +21327,7 @@ function nonCursorVerdictFileIdentity(stats) {
|
|
|
20710
21327
|
].join("-");
|
|
20711
21328
|
}
|
|
20712
21329
|
function fingerprintCliWorkerVerdictArtifact(raw, stats) {
|
|
20713
|
-
const contentSha256 = (0,
|
|
21330
|
+
const contentSha256 = (0, import_node_crypto10.createHash)("sha256").update(raw, "utf8").digest("hex");
|
|
20714
21331
|
return `${contentSha256}-${nonCursorVerdictFileIdentity(stats)}`;
|
|
20715
21332
|
}
|
|
20716
21333
|
async function readNonCursorVerdictArtifact(outputFile) {
|
|
@@ -20772,7 +21389,7 @@ async function processCliWorkerVerdictsUnderLock(teamName, cwd, expectedInstance
|
|
|
20772
21389
|
"team.runtime-v2.processCliWorkerVerdicts teamMarkTaskCompleted failed"
|
|
20773
21390
|
);
|
|
20774
21391
|
const { rename: rename8 } = await import("fs/promises");
|
|
20775
|
-
const { renameSync: renameSync5, readFileSync:
|
|
21392
|
+
const { renameSync: renameSync5, readFileSync: readFileSync24, existsSync: fsExistsSync } = await import("fs");
|
|
20776
21393
|
const { withFileLockSync: withFileLockSync2 } = await Promise.resolve().then(() => (init_file_lock(), file_lock_exports));
|
|
20777
21394
|
const quarantineNonCursorVerdict = async (outputFile, artifactFingerprint, workerName, taskId, taskVersion, reason) => {
|
|
20778
21395
|
const stalePath = nonCursorVerdictStalePath(outputFile, artifactFingerprint);
|
|
@@ -20805,7 +21422,7 @@ async function processCliWorkerVerdictsUnderLock(teamName, cwd, expectedInstance
|
|
|
20805
21422
|
const outputFile = worker.output_file;
|
|
20806
21423
|
if (!outputFile) continue;
|
|
20807
21424
|
const paneOwnership = configuredPaneOwnership(config, worker);
|
|
20808
|
-
const liveness = paneOwnership ? await getOwnedWorkerLiveness(paneOwnership) : "unknown";
|
|
21425
|
+
const liveness = isSdkTarget(worker.pane_id) ? await getWorkerProviderLiveness(sanitized, cwd, config.instance_id, worker) : paneOwnership ? await getOwnedWorkerLiveness(paneOwnership) : "unknown";
|
|
20809
21426
|
const workerRole = normalizeDelegationRole(worker.role);
|
|
20810
21427
|
const cursorReviewer = worker.worker_cli === "cursor" && CONTRACT_ROLES.has(workerRole);
|
|
20811
21428
|
const liveCursorReviewer = liveness === "alive" && worker.worker_cli === "cursor" && CONTRACT_ROLES.has(workerRole);
|
|
@@ -20853,7 +21470,7 @@ async function processCliWorkerVerdictsUnderLock(teamName, cwd, expectedInstance
|
|
|
20853
21470
|
return;
|
|
20854
21471
|
}
|
|
20855
21472
|
}
|
|
20856
|
-
const raw =
|
|
21473
|
+
const raw = readFileSync24(outputFile, "utf-8");
|
|
20857
21474
|
parseCliWorkerVerdict(raw);
|
|
20858
21475
|
renameSync5(outputFile, processingOutputFile);
|
|
20859
21476
|
verdictFile = processingOutputFile;
|
|
@@ -21017,7 +21634,7 @@ async function processCliWorkerVerdictsUnderLock(teamName, cwd, expectedInstance
|
|
|
21017
21634
|
if (cursorReviewer && verdictFile === processingOutputFile) {
|
|
21018
21635
|
const processedTaskPath = absPath(cwd, TeamPaths.taskFile(sanitized, payload.task_id));
|
|
21019
21636
|
try {
|
|
21020
|
-
const processedTask = JSON.parse(
|
|
21637
|
+
const processedTask = JSON.parse(readFileSync24(processedTaskPath, "utf-8"));
|
|
21021
21638
|
const metadata = processedTask.metadata && typeof processedTask.metadata === "object" ? processedTask.metadata : void 0;
|
|
21022
21639
|
const processedTaskRole = typeof processedTask.role === "string" ? normalizeDelegationRole(processedTask.role) : null;
|
|
21023
21640
|
const taskAlreadyRecorded = processedTask.owner === worker.name && (processedTask.status === "completed" || processedTask.status === "failed") && (!cursorReviewer || processedTaskRole === workerRole) && metadata?.verdict_source === "cli_worker_output_contract" && (!cursorReviewer || metadata.verdict_claim_token === payload.claim_token && metadata.verdict_task_version === payload.task_version) && (worker.launch_attempt_id === void 0 || metadata.verdict_worker_launch_attempt_id === worker.launch_attempt_id) && metadata.verdict === payload.verdict;
|
|
@@ -21359,20 +21976,28 @@ async function monitorTeamV2(teamName, cwd, expectedInstanceId) {
|
|
|
21359
21976
|
const workerScanStartMs = import_perf_hooks.performance.now();
|
|
21360
21977
|
const workerSignals = await Promise.all(
|
|
21361
21978
|
config.workers.map(async (worker) => {
|
|
21979
|
+
const providerLiveness = await getWorkerProviderLiveness(sanitized, cwd, config.instance_id, worker);
|
|
21980
|
+
if (isSdkTarget(worker.pane_id)) {
|
|
21981
|
+
const sdkSession = readSdkSession(teamStateRoot(cwd, sanitized), worker.name);
|
|
21982
|
+
const [status2, heartbeat2] = await Promise.all([
|
|
21983
|
+
readWorkerStatus(sanitized, worker.name, cwd),
|
|
21984
|
+
readWorkerHeartbeat(sanitized, worker.name, cwd)
|
|
21985
|
+
]);
|
|
21986
|
+
return { worker, alive: providerLiveness === "alive", liveness: providerLiveness, providerLiveness, status: status2, heartbeat: heartbeat2, paneCapture: "", sdkSession };
|
|
21987
|
+
}
|
|
21362
21988
|
const ownership = configuredPaneOwnership(config, worker);
|
|
21363
21989
|
const liveness = ownership ? await getOwnedWorkerLiveness(ownership) : "unknown";
|
|
21364
|
-
const providerLiveness = await getWorkerProviderLiveness(sanitized, cwd, config.instance_id, worker);
|
|
21365
21990
|
const paneAlive = liveness === "alive";
|
|
21366
21991
|
const [status, heartbeat, paneCapture] = await Promise.all([
|
|
21367
21992
|
readWorkerStatus(sanitized, worker.name, cwd),
|
|
21368
21993
|
readWorkerHeartbeat(sanitized, worker.name, cwd),
|
|
21369
21994
|
paneAlive && ownership ? captureOwnedTeamPane(ownership) : Promise.resolve("")
|
|
21370
21995
|
]);
|
|
21371
|
-
return { worker, alive: paneAlive, liveness, providerLiveness, status, heartbeat, paneCapture };
|
|
21996
|
+
return { worker, alive: paneAlive, liveness, providerLiveness, status, heartbeat, paneCapture, sdkSession: null };
|
|
21372
21997
|
})
|
|
21373
21998
|
);
|
|
21374
21999
|
const workerScanMs = import_perf_hooks.performance.now() - workerScanStartMs;
|
|
21375
|
-
for (const { worker: w, alive, liveness, providerLiveness, status, heartbeat, paneCapture } of workerSignals) {
|
|
22000
|
+
for (const { worker: w, alive, liveness, providerLiveness, status, heartbeat, paneCapture, sdkSession } of workerSignals) {
|
|
21376
22001
|
const currentTask = status.current_task_id ? taskById.get(status.current_task_id) ?? null : null;
|
|
21377
22002
|
const outstandingTask = currentTask ?? findOutstandingWorkerTask(w, taskById, inProgressByOwner);
|
|
21378
22003
|
const expectedTaskId = status.current_task_id ?? outstandingTask?.id ?? w.assigned_tasks[0] ?? "";
|
|
@@ -21395,7 +22020,19 @@ async function monitorTeamV2(teamName, cwd, expectedInstanceId) {
|
|
|
21395
22020
|
worktree_detached: w.worktree_detached,
|
|
21396
22021
|
worktree_created: w.worktree_created,
|
|
21397
22022
|
team_state_root: w.team_state_root,
|
|
21398
|
-
turnsWithoutProgress
|
|
22023
|
+
turnsWithoutProgress,
|
|
22024
|
+
...sdkSession ? { sdk: {
|
|
22025
|
+
state: sdkSession.state,
|
|
22026
|
+
turns: sdkSession.turns,
|
|
22027
|
+
queued: sdkSession.queued,
|
|
22028
|
+
last_event_type: sdkSession.last_event_type,
|
|
22029
|
+
last_event_at: sdkSession.last_event_at,
|
|
22030
|
+
last_error: sdkSession.last_error,
|
|
22031
|
+
session_id: sdkSession.session_id,
|
|
22032
|
+
model: sdkSession.model,
|
|
22033
|
+
credits: sdkSession.usage.credits,
|
|
22034
|
+
premium_requests: sdkSession.usage.shutdown_premium_requests ?? sdkSession.usage.premium_requests
|
|
22035
|
+
} } : {}
|
|
21399
22036
|
});
|
|
21400
22037
|
if (providerLiveness === "dead") {
|
|
21401
22038
|
deadWorkers.push(w.name);
|
|
@@ -21404,13 +22041,16 @@ async function monitorTeamV2(teamName, cwd, expectedInstanceId) {
|
|
|
21404
22041
|
recommendations.push(`Reassign task-${t.id} from dead ${w.name}`);
|
|
21405
22042
|
}
|
|
21406
22043
|
}
|
|
21407
|
-
const
|
|
22044
|
+
const sdkCapped = Boolean(sdkSession && providerLiveness !== "dead" && sdkSession.state === "capped");
|
|
22045
|
+
const paneSuggestsIdle = sdkSession ? alive && (sdkSession.state === "idle" && sdkSession.queued === 0 || sdkCapped) : alive && paneLooksReady(paneCapture) && !paneHasActiveTask(paneCapture);
|
|
21408
22046
|
const statusFresh = isFreshTimestamp(status.updated_at);
|
|
21409
22047
|
const heartbeatFresh = isFreshTimestamp(heartbeat?.last_turn_at);
|
|
21410
22048
|
const hasWorkStartEvidence = expectedTaskId !== "" && hasWorkerStatusProgress(status, expectedTaskId);
|
|
21411
22049
|
const missingDependencyIds = outstandingTask ? getMissingDependencyIds(outstandingTask, taskById) : [];
|
|
21412
22050
|
let stallReason = null;
|
|
21413
|
-
if (
|
|
22051
|
+
if (sdkCapped) {
|
|
22052
|
+
stallReason = "sdk_credit_cap";
|
|
22053
|
+
} else if (paneSuggestsIdle && missingDependencyIds.length > 0) {
|
|
21414
22054
|
stallReason = "missing_dependency";
|
|
21415
22055
|
} else if (paneSuggestsIdle && expectedTaskId !== "" && !hasWorkStartEvidence) {
|
|
21416
22056
|
stallReason = "no_work_start_evidence";
|
|
@@ -21421,7 +22061,15 @@ async function monitorTeamV2(teamName, cwd, expectedInstanceId) {
|
|
|
21421
22061
|
}
|
|
21422
22062
|
if (stallReason) {
|
|
21423
22063
|
nonReportingWorkers.push(w.name);
|
|
21424
|
-
if (stallReason === "
|
|
22064
|
+
if (stallReason === "sdk_credit_cap") {
|
|
22065
|
+
const cappedTasks = inProgressByOwner.get(w.name) ?? [];
|
|
22066
|
+
for (const t of cappedTasks) {
|
|
22067
|
+
recommendations.push(`Reassign task-${t.id} from ${w.name}: sdk credit cap reached (${sdkSession?.last_error ?? "capped"}); the worker takes no more prompts`);
|
|
22068
|
+
}
|
|
22069
|
+
if (cappedTasks.length === 0) {
|
|
22070
|
+
recommendations.push(`${w.name} reached its sdk credit cap and takes no more prompts; do not assign it new work`);
|
|
22071
|
+
}
|
|
22072
|
+
} else if (stallReason === "missing_dependency") {
|
|
21425
22073
|
recommendations.push(
|
|
21426
22074
|
`Investigate ${w.name}: task-${outstandingTask?.id ?? expectedTaskId} is blocked by missing task ids [${missingDependencyIds.join(", ")}]; pane is idle at prompt`
|
|
21427
22075
|
);
|
|
@@ -21515,7 +22163,7 @@ async function cleanupStaleReservations(teamName, cwd) {
|
|
|
21515
22163
|
cwd,
|
|
21516
22164
|
TeamPaths.teamInstanceReservation(workspaceHash, sanitized)
|
|
21517
22165
|
);
|
|
21518
|
-
if (!(0,
|
|
22166
|
+
if (!(0, import_fs34.existsSync)(reservationPath2)) return;
|
|
21519
22167
|
const contentStr = await (0, import_promises19.readFile)(reservationPath2, "utf-8");
|
|
21520
22168
|
const reservation = JSON.parse(contentStr);
|
|
21521
22169
|
if (!(reservation && typeof reservation === "object" && !Array.isArray(reservation) && "owner" in reservation && typeof reservation.owner === "object")) {
|
|
@@ -21525,6 +22173,7 @@ async function cleanupStaleReservations(teamName, cwd) {
|
|
|
21525
22173
|
if (!(owner && typeof owner === "object" && !Array.isArray(owner) && "pid" in owner && "process_started_at" in owner)) {
|
|
21526
22174
|
return;
|
|
21527
22175
|
}
|
|
22176
|
+
if (reservation.phase === "active") return;
|
|
21528
22177
|
const ownerRecord = owner;
|
|
21529
22178
|
if (isProcessIdentityDead(ownerRecord)) {
|
|
21530
22179
|
await (0, import_promises19.unlink)(reservationPath2);
|
|
@@ -21617,7 +22266,7 @@ async function shutdownTeamV2(teamName, cwd, options = {}) {
|
|
|
21617
22266
|
});
|
|
21618
22267
|
instance = boundInstance;
|
|
21619
22268
|
await assertTeamInstanceUnderLock(boundInstance);
|
|
21620
|
-
if (!current.config.tmux_session || !current.config.tmux_session.startsWith("cmux:") && !isValidTmuxServerIdentity(current.config.tmux_server_identity)) {
|
|
22269
|
+
if (!current.config.tmux_session || !current.config.tmux_session.startsWith("cmux:") && !isSdkTarget(current.config.tmux_session) && !isValidTmuxServerIdentity(current.config.tmux_server_identity)) {
|
|
21621
22270
|
throw new Error("tmux_server_identity_missing");
|
|
21622
22271
|
}
|
|
21623
22272
|
if (current.config.active_recovery) throw new Error(`shutdown_blocked:active_recovery:${current.config.active_recovery.recovery_id}`);
|
|
@@ -21648,7 +22297,7 @@ async function shutdownTeamV2(teamName, cwd, options = {}) {
|
|
|
21648
22297
|
}
|
|
21649
22298
|
const processStartedAt = currentProcessStartIdentity();
|
|
21650
22299
|
if (!processStartedAt) throw new Error("process_start_identity_unavailable");
|
|
21651
|
-
ownedShutdownNonce = (0,
|
|
22300
|
+
ownedShutdownNonce = (0, import_node_crypto10.randomUUID)();
|
|
21652
22301
|
const nextRevision = current.stateRevision + 1;
|
|
21653
22302
|
const next = {
|
|
21654
22303
|
...current.config,
|
|
@@ -21756,7 +22405,7 @@ async function shutdownTeamV2(teamName, cwd, options = {}) {
|
|
|
21756
22405
|
};
|
|
21757
22406
|
if (!config) {
|
|
21758
22407
|
const cleanupSafety = inspectTeamWorktreeCleanupSafety(sanitized, cwd);
|
|
21759
|
-
if (cleanupSafety.hasEvidence || (0,
|
|
22408
|
+
if (cleanupSafety.hasEvidence || (0, import_fs34.existsSync)(absPath(cwd, TeamPaths.root(sanitized)))) {
|
|
21760
22409
|
process.stderr.write("[team/runtime-v2] preserving team state because config is missing and worktree cleanup evidence remains\n");
|
|
21761
22410
|
return { outcome: "preserved", reason: "config_missing_cleanup_evidence", workers: [] };
|
|
21762
22411
|
}
|
|
@@ -21788,6 +22437,7 @@ Format: {"status":"accept","reason":"ok","updated_at":"<iso>"}
|
|
|
21788
22437
|
Then exit your session.
|
|
21789
22438
|
`;
|
|
21790
22439
|
await writeWorkerInbox(sanitized, w.name, shutdownInbox, cwd);
|
|
22440
|
+
if (isSdkTarget(w.pane_id)) ringDoorbell(teamStateRoot(cwd, sanitized), w.name, { kind: "shutdown", from: "leader-fixed" });
|
|
21791
22441
|
} catch (err) {
|
|
21792
22442
|
process.stderr.write(`[team/runtime-v2] shutdown request failed for ${w.name}: ${err}
|
|
21793
22443
|
`);
|
|
@@ -21828,6 +22478,30 @@ Then exit your session.
|
|
|
21828
22478
|
const providerCleanupFailures = [];
|
|
21829
22479
|
const paneCleanupAlive = [];
|
|
21830
22480
|
const paneCleanupUnknown = [];
|
|
22481
|
+
const sdkStopTimeoutMs = Math.max(timeoutMs, SDK_HOST_STOP_FLOOR_MS);
|
|
22482
|
+
const sdkStops = /* @__PURE__ */ new Map();
|
|
22483
|
+
for (const worker of config.workers) {
|
|
22484
|
+
if (!isSdkTarget(worker.pane_id) || !worker.launch_attempt_id || !config.tmux_session) continue;
|
|
22485
|
+
const provider = worker.launch_descriptor?.provider ?? worker.worker_cli;
|
|
22486
|
+
if (!provider) continue;
|
|
22487
|
+
const attemptId = worker.launch_attempt_id;
|
|
22488
|
+
const paneId = worker.pane_id;
|
|
22489
|
+
sdkStops.set(worker.name, (async () => {
|
|
22490
|
+
const sdkAttempt = await loadWorkerLaunchAttempt({
|
|
22491
|
+
cwd,
|
|
22492
|
+
teamName: sanitized,
|
|
22493
|
+
instanceId: shutdownInstance.instance_id,
|
|
22494
|
+
workerName: worker.name,
|
|
22495
|
+
paneId,
|
|
22496
|
+
provider,
|
|
22497
|
+
attemptId,
|
|
22498
|
+
runtimeCliPath: resolveRuntimeCliPath()
|
|
22499
|
+
});
|
|
22500
|
+
if (!sdkAttempt) return false;
|
|
22501
|
+
if (!await stopSdkHost(sdkAttempt, teamStateRoot(cwd, sanitized), { timeoutMs: sdkStopTimeoutMs })) return false;
|
|
22502
|
+
return retireAndCleanupCurrentWorkerLaunchAttempt(sdkAttempt, "team_shutdown", async () => true);
|
|
22503
|
+
})().catch(() => false));
|
|
22504
|
+
}
|
|
21831
22505
|
for (const worker of config.workers) {
|
|
21832
22506
|
if (!worker.pane_id) {
|
|
21833
22507
|
providerCleanupFailures.push(worker.name);
|
|
@@ -21842,6 +22516,10 @@ Then exit your session.
|
|
|
21842
22516
|
providerCleanupFailures.push(worker.name);
|
|
21843
22517
|
continue;
|
|
21844
22518
|
}
|
|
22519
|
+
if (isSdkTarget(worker.pane_id)) {
|
|
22520
|
+
if (!await (sdkStops.get(worker.name) ?? Promise.resolve(false))) providerCleanupFailures.push(worker.name);
|
|
22521
|
+
continue;
|
|
22522
|
+
}
|
|
21845
22523
|
const initialOwnership = configuredPaneOwnership(config, worker);
|
|
21846
22524
|
const initialPaneLiveness = initialOwnership ? await getOwnedWorkerLiveness(initialOwnership) : "unknown";
|
|
21847
22525
|
let paneOwnership = null;
|
|
@@ -21910,9 +22588,9 @@ Then exit your session.
|
|
|
21910
22588
|
killTeamSession: killOwnedTeamSession
|
|
21911
22589
|
} = await Promise.resolve().then(() => (init_tmux_session(), tmux_session_exports));
|
|
21912
22590
|
const ownsWindow = config.tmux_window_owned === true;
|
|
21913
|
-
const workerPaneIds = recordedWorkerPaneIds;
|
|
22591
|
+
const workerPaneIds = recordedWorkerPaneIds.filter((paneId) => !isSdkTarget(paneId));
|
|
21914
22592
|
const splitPaneMode = Boolean(config.tmux_session && !ownsWindow && config.tmux_session.includes(":"));
|
|
21915
|
-
if (!splitPaneMode && config.tmux_session) {
|
|
22593
|
+
if (!splitPaneMode && config.tmux_session && !isSdkTarget(config.tmux_session)) {
|
|
21916
22594
|
if (!config.leader_pane_id) {
|
|
21917
22595
|
if (!await rollbackShutdownForRetry()) await finalizeAutoMerge();
|
|
21918
22596
|
return { outcome: "preserved", reason: "provider_cleanup_unverified", workers: ["leader-fixed"] };
|
|
@@ -22033,12 +22711,12 @@ Then exit your session.
|
|
|
22033
22711
|
return { outcome: "cleaned" };
|
|
22034
22712
|
});
|
|
22035
22713
|
}
|
|
22036
|
-
var
|
|
22714
|
+
var import_path38, import_fs34, import_promises19, import_perf_hooks, import_node_child_process8, import_node_crypto10, orchestratorByTeam, cadenceByTeam, MONITOR_SIGNAL_STALE_MS, WORKER_STARTUP_EVIDENCE_POLL_INTERVAL_MS, WORKER_STARTUP_EVIDENCE_POLICIES, ENGAGED_PANE_RECHECK_TIMEOUT_ENV, MAX_ENGAGED_PANE_RECHECK_BUDGET_MS, CLAIM_ERROR_CAPTURE_MAX, CLAIM_ERROR_JSON_LINES_MAX, CLAIM_ERROR_LINE_MAX, CLAIM_ERROR_CODES, pendingRecoveryPanes, BOOTSTRAP_RECOVERY_EVIDENCE_POLL_MS, BOOTSTRAP_RECOVERY_EVIDENCE_MAX_WAIT_MS, TEAM_INSTANCE_FINAL_DISPOSAL_AUTHORIZATION;
|
|
22037
22715
|
var init_runtime_v2 = __esm({
|
|
22038
22716
|
"src/team/runtime-v2.ts"() {
|
|
22039
22717
|
"use strict";
|
|
22040
|
-
|
|
22041
|
-
|
|
22718
|
+
import_path38 = require("path");
|
|
22719
|
+
import_fs34 = require("fs");
|
|
22042
22720
|
import_promises19 = require("fs/promises");
|
|
22043
22721
|
import_perf_hooks = require("perf_hooks");
|
|
22044
22722
|
init_state_paths();
|
|
@@ -22067,10 +22745,10 @@ var init_runtime_v2 = __esm({
|
|
|
22067
22745
|
init_cli_worker_contract();
|
|
22068
22746
|
init_merge_orchestrator();
|
|
22069
22747
|
init_leader_inbox();
|
|
22070
|
-
|
|
22748
|
+
import_node_child_process8 = require("node:child_process");
|
|
22071
22749
|
init_runtime_flags();
|
|
22072
22750
|
init_worker_commit_cadence();
|
|
22073
|
-
|
|
22751
|
+
import_node_crypto10 = require("node:crypto");
|
|
22074
22752
|
init_recovery_request_store();
|
|
22075
22753
|
init_runtime_owner_client();
|
|
22076
22754
|
init_scaling();
|
|
@@ -22082,6 +22760,11 @@ var init_runtime_v2 = __esm({
|
|
|
22082
22760
|
init_team_owner_epoch();
|
|
22083
22761
|
init_worker_activation_gate();
|
|
22084
22762
|
init_worker_launch_ack();
|
|
22763
|
+
init_sdk_transport();
|
|
22764
|
+
init_model_contract();
|
|
22765
|
+
init_copilot_sdk_driver();
|
|
22766
|
+
init_copilot_session_env();
|
|
22767
|
+
init_config_dir();
|
|
22085
22768
|
init_process_utils();
|
|
22086
22769
|
init_team_instance();
|
|
22087
22770
|
init_runtime_flags();
|
|
@@ -22187,10 +22870,10 @@ __export(runtime_cli_exports, {
|
|
|
22187
22870
|
writeResultArtifact: () => writeResultArtifact
|
|
22188
22871
|
});
|
|
22189
22872
|
module.exports = __toCommonJS(runtime_cli_exports);
|
|
22190
|
-
var
|
|
22191
|
-
var
|
|
22873
|
+
var import_node_crypto11 = require("node:crypto");
|
|
22874
|
+
var import_fs35 = require("fs");
|
|
22192
22875
|
var import_promises20 = require("fs/promises");
|
|
22193
|
-
var
|
|
22876
|
+
var import_path39 = require("path");
|
|
22194
22877
|
init_events();
|
|
22195
22878
|
|
|
22196
22879
|
// src/team/leader-nudge-guidance.ts
|
|
@@ -22733,7 +23416,7 @@ async function waitForSentinelReadiness(options = {}) {
|
|
|
22733
23416
|
}
|
|
22734
23417
|
const deadline = startedAt + timeoutMs;
|
|
22735
23418
|
while (Date.now() < deadline) {
|
|
22736
|
-
await new Promise((
|
|
23419
|
+
await new Promise((resolve17) => setTimeout(resolve17, pollIntervalMs));
|
|
22737
23420
|
attempts += 1;
|
|
22738
23421
|
latest = checkSentinelReadiness(options);
|
|
22739
23422
|
if (latest.ready) {
|
|
@@ -22823,10 +23506,10 @@ function areAllAuthoritativeWorkersDead(refresh, workers) {
|
|
|
22823
23506
|
return classifyAllDeadRecoveryEvidence(refresh, workers, true) === "all_dead";
|
|
22824
23507
|
}
|
|
22825
23508
|
function validateCanonicalRecoveryIntent(teamName, cwd, pathRecoveryId, path5) {
|
|
22826
|
-
const intent = parseRecoveryIntent((0,
|
|
23509
|
+
const intent = parseRecoveryIntent((0, import_fs35.readFileSync)(path5, "utf8"));
|
|
22827
23510
|
if (intent.team_name !== teamName || intent.recovery_id !== pathRecoveryId) throw new Error("invalid_persisted_state");
|
|
22828
23511
|
const reservation = readRecoveryRequestReservation(cwd, intent.request_id);
|
|
22829
|
-
const workspaceHash = (0,
|
|
23512
|
+
const workspaceHash = (0, import_node_crypto11.createHash)("sha256").update(cwd).digest("hex");
|
|
22830
23513
|
const expectedPayloadHash = canonicalRecoveryPayloadHash({
|
|
22831
23514
|
operation: "recover-worker",
|
|
22832
23515
|
workspaceHash,
|
|
@@ -22858,14 +23541,14 @@ async function processPendingRecoveryIntents(teamName, cwd, execute = handleReco
|
|
|
22858
23541
|
const root = absPath(cwd, TeamPaths.recoveryIntents(teamName));
|
|
22859
23542
|
let names;
|
|
22860
23543
|
try {
|
|
22861
|
-
names = (0,
|
|
23544
|
+
names = (0, import_fs35.readdirSync)(root).filter((name) => name.endsWith(".json")).sort();
|
|
22862
23545
|
} catch {
|
|
22863
23546
|
return;
|
|
22864
23547
|
}
|
|
22865
23548
|
for (const name of names) {
|
|
22866
|
-
const path5 = (0,
|
|
23549
|
+
const path5 = (0, import_path39.join)(root, name);
|
|
22867
23550
|
try {
|
|
22868
|
-
const pathRecoveryId = (0,
|
|
23551
|
+
const pathRecoveryId = (0, import_path39.basename)(name, ".json");
|
|
22869
23552
|
const intent = validateCanonicalRecoveryIntent(teamName, cwd, pathRecoveryId, path5);
|
|
22870
23553
|
if (intent.instance_id.toLowerCase() !== normalizedExpectedInstanceId) continue;
|
|
22871
23554
|
if (!await assertRuntimeInstance(teamName, cwd, normalizedExpectedInstanceId)) continue;
|
|
@@ -22935,17 +23618,17 @@ async function updateAllDeadRecoveryGrace(teamName, cwd, evidence, nowMs = Date.
|
|
|
22935
23618
|
}
|
|
22936
23619
|
function canonicalRecoveryIntentEntryId(name, path5) {
|
|
22937
23620
|
if (!name.endsWith(".json")) return null;
|
|
22938
|
-
const recoveryId = (0,
|
|
23621
|
+
const recoveryId = (0, import_path39.basename)(name, ".json");
|
|
22939
23622
|
if (name !== `${recoveryId}.json` || !isSafeRecoveryRequestId(recoveryId)) return null;
|
|
22940
23623
|
try {
|
|
22941
|
-
return (0,
|
|
23624
|
+
return (0, import_fs35.lstatSync)(path5).isFile() ? recoveryId : null;
|
|
22942
23625
|
} catch {
|
|
22943
23626
|
return null;
|
|
22944
23627
|
}
|
|
22945
23628
|
}
|
|
22946
23629
|
function hasVerifiedTerminalRepairForMalformedIntent(teamName, cwd, recoveryId, path5) {
|
|
22947
23630
|
try {
|
|
22948
|
-
const raw = JSON.parse((0,
|
|
23631
|
+
const raw = JSON.parse((0, import_fs35.readFileSync)(path5, "utf8"));
|
|
22949
23632
|
if (raw.team_name !== teamName || raw.recovery_id !== recoveryId || typeof raw.request_id !== "string" || !isSafeRecoveryRequestId(raw.request_id) || typeof raw.worker_name !== "string" || raw.worker_name.length === 0) return false;
|
|
22950
23633
|
const final = readRecoveryFinalState(cwd, raw.request_id);
|
|
22951
23634
|
return final.kind === "valid" && final.final.recovery_id === recoveryId && final.final.team_name === teamName && final.final.worker_name === raw.worker_name;
|
|
@@ -22955,7 +23638,7 @@ function hasVerifiedTerminalRepairForMalformedIntent(teamName, cwd, recoveryId,
|
|
|
22955
23638
|
}
|
|
22956
23639
|
function malformedIntentMayPredateDeadline(path5, deadlineAt) {
|
|
22957
23640
|
try {
|
|
22958
|
-
const metadata = (0,
|
|
23641
|
+
const metadata = (0, import_fs35.lstatSync)(path5);
|
|
22959
23642
|
if (Number.isFinite(metadata.mtimeMs) && metadata.mtimeMs <= deadlineAt) return true;
|
|
22960
23643
|
if (Number.isFinite(metadata.birthtimeMs) && metadata.birthtimeMs > 0) {
|
|
22961
23644
|
return metadata.birthtimeMs <= deadlineAt;
|
|
@@ -22970,14 +23653,14 @@ function canonicalRecoveryAdmissionEntryId(name, path5) {
|
|
|
22970
23653
|
const requestId = name.slice(0, -".pending.json".length);
|
|
22971
23654
|
if (name !== `${requestId}.pending.json` || !isSafeRecoveryRequestId(requestId)) return null;
|
|
22972
23655
|
try {
|
|
22973
|
-
return (0,
|
|
23656
|
+
return (0, import_fs35.lstatSync)(path5).isFile() ? requestId : null;
|
|
22974
23657
|
} catch {
|
|
22975
23658
|
return null;
|
|
22976
23659
|
}
|
|
22977
23660
|
}
|
|
22978
23661
|
function malformedAdmissionMayPredateDeadline(path5, deadlineAt) {
|
|
22979
23662
|
try {
|
|
22980
|
-
const metadata = (0,
|
|
23663
|
+
const metadata = (0, import_fs35.lstatSync)(path5);
|
|
22981
23664
|
if (!metadata.isFile()) return true;
|
|
22982
23665
|
if (Number.isFinite(metadata.mtimeMs) && metadata.mtimeMs <= deadlineAt) return true;
|
|
22983
23666
|
if (Number.isFinite(metadata.birthtimeMs) && metadata.birthtimeMs > 0) {
|
|
@@ -22994,12 +23677,12 @@ function hasPendingRecoveryIntentBeforeDeadline(teamName, cwd, deadlineAt, expec
|
|
|
22994
23677
|
const root = absPath(cwd, TeamPaths.recoveryIntents(teamName));
|
|
22995
23678
|
let names;
|
|
22996
23679
|
try {
|
|
22997
|
-
names = (0,
|
|
23680
|
+
names = (0, import_fs35.readdirSync)(root).filter((name) => name.endsWith(".json"));
|
|
22998
23681
|
} catch {
|
|
22999
23682
|
return false;
|
|
23000
23683
|
}
|
|
23001
23684
|
for (const name of names) {
|
|
23002
|
-
const path5 = (0,
|
|
23685
|
+
const path5 = (0, import_path39.join)(root, name);
|
|
23003
23686
|
const recoveryId = canonicalRecoveryIntentEntryId(name, path5);
|
|
23004
23687
|
if (!recoveryId) continue;
|
|
23005
23688
|
try {
|
|
@@ -23017,16 +23700,16 @@ function hasPendingRecoveryIntentBeforeDeadline(teamName, cwd, deadlineAt, expec
|
|
|
23017
23700
|
function hasPendingRecoveryAdmissionBeforeDeadline(teamName, cwd, deadlineAt, expectedInstanceId) {
|
|
23018
23701
|
const normalizedExpectedInstanceId = normalizeRuntimeInstanceId(expectedInstanceId);
|
|
23019
23702
|
if (!normalizedExpectedInstanceId) return true;
|
|
23020
|
-
const workspaceHash = (0,
|
|
23703
|
+
const workspaceHash = (0, import_node_crypto11.createHash)("sha256").update(cwd).digest("hex");
|
|
23021
23704
|
const root = absPath(cwd, TeamPaths.recoveryRequestsRoot());
|
|
23022
23705
|
let names;
|
|
23023
23706
|
try {
|
|
23024
|
-
names = (0,
|
|
23707
|
+
names = (0, import_fs35.readdirSync)(root).filter((name) => name.endsWith(".pending.json"));
|
|
23025
23708
|
} catch {
|
|
23026
23709
|
return false;
|
|
23027
23710
|
}
|
|
23028
23711
|
for (const name of names) {
|
|
23029
|
-
const path5 = (0,
|
|
23712
|
+
const path5 = (0, import_path39.join)(root, name);
|
|
23030
23713
|
const requestId = canonicalRecoveryAdmissionEntryId(name, path5);
|
|
23031
23714
|
if (!requestId) continue;
|
|
23032
23715
|
try {
|
|
@@ -23104,7 +23787,7 @@ async function runPersistentRecoveryOwnerLoop(input, options = {}) {
|
|
|
23104
23787
|
const reconcileServices = options.reconcileServices ?? reconcileCommittedTeamServices;
|
|
23105
23788
|
const monitor = options.monitor ?? monitorTeamV2;
|
|
23106
23789
|
const sleep4 = options.sleep ?? (async (ms) => {
|
|
23107
|
-
await new Promise((
|
|
23790
|
+
await new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
23108
23791
|
});
|
|
23109
23792
|
const shutdown = options.shutdown ?? shutdownTeamV2;
|
|
23110
23793
|
let iteration = 0;
|
|
@@ -23245,7 +23928,7 @@ async function writeResultArtifact(output, finishedAt, jobId = process.env.OMC_J
|
|
|
23245
23928
|
if (!output.instanceId || !isValidTeamInstanceId(output.instanceId)) {
|
|
23246
23929
|
throw new Error("result_artifact_instance_identity_missing");
|
|
23247
23930
|
}
|
|
23248
|
-
const resultPath = (0,
|
|
23931
|
+
const resultPath = (0, import_path39.join)(omcJobsDir, `${jobId}-result.json`);
|
|
23249
23932
|
const tmpPath = `${resultPath}.tmp`;
|
|
23250
23933
|
await (0, import_promises20.writeFile)(
|
|
23251
23934
|
tmpPath,
|
|
@@ -23320,7 +24003,7 @@ async function writePanesFile(jobId, instanceId, teamName, cwd, paneIds, leaderP
|
|
|
23320
24003
|
if (authoritativePaneIds.some((paneId) => !paneIds.includes(paneId))) {
|
|
23321
24004
|
throw new Error("pane_artifact_missing_runtime_pane");
|
|
23322
24005
|
}
|
|
23323
|
-
const panesPath = (0,
|
|
24006
|
+
const panesPath = (0, import_path39.join)(omcJobsDir, `${jobId}-panes.json`);
|
|
23324
24007
|
await (0, import_promises20.writeFile)(
|
|
23325
24008
|
panesPath + ".tmp",
|
|
23326
24009
|
JSON.stringify({
|
|
@@ -23358,7 +24041,7 @@ function isTerseFinalSummary(summary) {
|
|
|
23358
24041
|
function readTaskOutputFallback(outputsDir, teamName, taskId) {
|
|
23359
24042
|
let entries;
|
|
23360
24043
|
try {
|
|
23361
|
-
entries = (0,
|
|
24044
|
+
entries = (0, import_fs35.readdirSync)(outputsDir);
|
|
23362
24045
|
} catch {
|
|
23363
24046
|
return null;
|
|
23364
24047
|
}
|
|
@@ -23367,16 +24050,16 @@ function readTaskOutputFallback(outputsDir, teamName, taskId) {
|
|
|
23367
24050
|
if (candidates.length === 0) return null;
|
|
23368
24051
|
let newest = null;
|
|
23369
24052
|
for (const name of candidates) {
|
|
23370
|
-
const full = (0,
|
|
24053
|
+
const full = (0, import_path39.join)(outputsDir, name);
|
|
23371
24054
|
try {
|
|
23372
|
-
const mtime = (0,
|
|
24055
|
+
const mtime = (0, import_fs35.statSync)(full).mtimeMs;
|
|
23373
24056
|
if (!newest || mtime > newest.mtime) newest = { path: full, mtime };
|
|
23374
24057
|
} catch {
|
|
23375
24058
|
}
|
|
23376
24059
|
}
|
|
23377
24060
|
if (!newest) return null;
|
|
23378
24061
|
try {
|
|
23379
|
-
const content = (0,
|
|
24062
|
+
const content = (0, import_fs35.readFileSync)(newest.path, "utf-8").trim();
|
|
23380
24063
|
if (content.length === 0) return null;
|
|
23381
24064
|
return content.length > MAX_FALLBACK_SUMMARY_CHARS ? content.slice(0, MAX_FALLBACK_SUMMARY_CHARS) + "\n... (truncated)" : content;
|
|
23382
24065
|
} catch {
|
|
@@ -23384,14 +24067,14 @@ function readTaskOutputFallback(outputsDir, teamName, taskId) {
|
|
|
23384
24067
|
}
|
|
23385
24068
|
}
|
|
23386
24069
|
function collectTaskResults(stateRoot) {
|
|
23387
|
-
const tasksDir = (0,
|
|
23388
|
-
const teamName = (0,
|
|
23389
|
-
const outputsDir = (0,
|
|
24070
|
+
const tasksDir = (0, import_path39.join)(stateRoot, "tasks");
|
|
24071
|
+
const teamName = (0, import_path39.basename)(stateRoot);
|
|
24072
|
+
const outputsDir = (0, import_path39.join)(stateRoot, "..", "..", "..", "outputs");
|
|
23390
24073
|
try {
|
|
23391
|
-
const files = (0,
|
|
24074
|
+
const files = (0, import_fs35.readdirSync)(tasksDir).filter((f) => f.endsWith(".json"));
|
|
23392
24075
|
return files.map((f) => {
|
|
23393
24076
|
try {
|
|
23394
|
-
const raw = (0,
|
|
24077
|
+
const raw = (0, import_fs35.readFileSync)((0, import_path39.join)(tasksDir, f), "utf-8");
|
|
23395
24078
|
const task = JSON.parse(raw);
|
|
23396
24079
|
const taskId = task.id ?? f.replace(".json", "");
|
|
23397
24080
|
let summary = task.result ?? task.summary ?? "";
|
|
@@ -23426,8 +24109,8 @@ function createRuntimeStartupShutdownBarrier() {
|
|
|
23426
24109
|
let settled = false;
|
|
23427
24110
|
let requested = false;
|
|
23428
24111
|
let resolveCompletion;
|
|
23429
|
-
const completion = new Promise((
|
|
23430
|
-
resolveCompletion =
|
|
24112
|
+
const completion = new Promise((resolve17) => {
|
|
24113
|
+
resolveCompletion = resolve17;
|
|
23431
24114
|
});
|
|
23432
24115
|
return {
|
|
23433
24116
|
requestShutdown: () => {
|
|
@@ -23735,7 +24418,7 @@ async function main() {
|
|
|
23735
24418
|
if (snap.allTasksTerminal) {
|
|
23736
24419
|
const hasFailures = snap.tasks.failed > 0;
|
|
23737
24420
|
if (!hasFailures) {
|
|
23738
|
-
const sentinelLogPath = (0,
|
|
24421
|
+
const sentinelLogPath = (0, import_path39.join)(cwd, "sentinel_stop.jsonl");
|
|
23739
24422
|
const gateResult = await waitForSentinelReadiness({
|
|
23740
24423
|
workspace: cwd,
|
|
23741
24424
|
logPath: sentinelLogPath,
|