oh-my-copilot 5.6.2 → 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 +2 -0
- package/bridge/__pycache__/gyoshu_bridge.cpython-312.pyc +0 -0
- package/bridge/claude-md-coordinator.cjs +2 -2
- package/bridge/cli.cjs +81405 -76559
- package/bridge/mcp-server.cjs +40048 -32187
- package/bridge/runtime-cli.cjs +943 -199
- package/bridge/team-mcp.cjs +716 -125
- package/bridge/team.js +1066 -290
- 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-fail-closed-timeout.test.d.ts +2 -0
- package/dist/__tests__/run-cjs-fail-closed-timeout.test.d.ts.map +1 -0
- package/dist/__tests__/run-cjs-fail-closed-timeout.test.js +68 -0
- package/dist/__tests__/run-cjs-fail-closed-timeout.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/__tests__/session-end-process-exit.test.js +70 -2
- package/dist/__tests__/session-end-process-exit.test.js.map +1 -1
- 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.d.ts +2 -0
- package/dist/cli/commands/__tests__/smoke-tier2.test.d.ts.map +1 -0
- package/dist/cli/commands/__tests__/smoke-tier2.test.js +110 -0
- package/dist/cli/commands/__tests__/smoke-tier2.test.js.map +1 -0
- 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 +36 -0
- package/dist/cli/commands/smoke.d.ts.map +1 -0
- package/dist/cli/commands/smoke.js +169 -0
- package/dist/cli/commands/smoke.js.map +1 -0
- 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 +70 -10
- 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/constants/names.d.ts +1 -0
- package/dist/constants/names.d.ts.map +1 -1
- package/dist/constants/names.js +1 -0
- package/dist/constants/names.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 +2 -3
- package/dist/hooks/session-end/index.d.ts.map +1 -1
- package/dist/hooks/session-end/index.js +11 -13
- 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/wiki-foreground-bootstrap.d.ts +17 -0
- package/dist/hooks/session-end/wiki-foreground-bootstrap.d.ts.map +1 -0
- package/dist/hooks/session-end/wiki-foreground-bootstrap.js +20 -0
- package/dist/hooks/session-end/wiki-foreground-bootstrap.js.map +1 -0
- 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/lib/__tests__/atomic-write.test.js +32 -1
- package/dist/lib/__tests__/atomic-write.test.js.map +1 -1
- package/dist/lib/__tests__/mode-state-lock.test.js +121 -12
- package/dist/lib/__tests__/mode-state-lock.test.js.map +1 -1
- package/dist/lib/atomic-write.d.ts +13 -3
- package/dist/lib/atomic-write.d.ts.map +1 -1
- package/dist/lib/atomic-write.js +29 -15
- package/dist/lib/atomic-write.js.map +1 -1
- package/dist/lib/mode-state-io.d.ts +2 -2
- package/dist/lib/mode-state-io.d.ts.map +1 -1
- package/dist/lib/mode-state-io.js +16 -10
- package/dist/lib/mode-state-io.js.map +1 -1
- package/dist/mcp/__tests__/host-smoke-tool.test.d.ts +2 -0
- package/dist/mcp/__tests__/host-smoke-tool.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/host-smoke-tool.test.js +174 -0
- package/dist/mcp/__tests__/host-smoke-tool.test.js.map +1 -0
- package/dist/mcp/disable-tools.d.ts.map +1 -1
- package/dist/mcp/disable-tools.js +1 -0
- package/dist/mcp/disable-tools.js.map +1 -1
- package/dist/mcp/tool-registry.d.ts.map +1 -1
- package/dist/mcp/tool-registry.js +2 -0
- package/dist/mcp/tool-registry.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.d.ts +2 -0
- package/dist/smoke/__tests__/copilot-sdk-driver.test.d.ts.map +1 -0
- package/dist/smoke/__tests__/copilot-sdk-driver.test.js +591 -0
- package/dist/smoke/__tests__/copilot-sdk-driver.test.js.map +1 -0
- package/dist/smoke/__tests__/copilot-sdk-scenarios.test.d.ts +2 -0
- package/dist/smoke/__tests__/copilot-sdk-scenarios.test.d.ts.map +1 -0
- package/dist/smoke/__tests__/copilot-sdk-scenarios.test.js +362 -0
- package/dist/smoke/__tests__/copilot-sdk-scenarios.test.js.map +1 -0
- package/dist/smoke/__tests__/copilot-session-eval.test.d.ts +2 -0
- package/dist/smoke/__tests__/copilot-session-eval.test.d.ts.map +1 -0
- package/dist/smoke/__tests__/copilot-session-eval.test.js +264 -0
- package/dist/smoke/__tests__/copilot-session-eval.test.js.map +1 -0
- package/dist/smoke/__tests__/copilot-smoke.test.d.ts +2 -0
- package/dist/smoke/__tests__/copilot-smoke.test.d.ts.map +1 -0
- package/dist/smoke/__tests__/copilot-smoke.test.js +482 -0
- package/dist/smoke/__tests__/copilot-smoke.test.js.map +1 -0
- package/dist/smoke/copilot-binary.d.ts +21 -0
- package/dist/smoke/copilot-binary.d.ts.map +1 -0
- package/dist/smoke/copilot-binary.js +46 -0
- package/dist/smoke/copilot-binary.js.map +1 -0
- 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 +189 -0
- package/dist/smoke/copilot-sdk-driver.d.ts.map +1 -0
- package/dist/smoke/copilot-sdk-driver.js +637 -0
- package/dist/smoke/copilot-sdk-driver.js.map +1 -0
- package/dist/smoke/copilot-sdk-scenarios.d.ts +200 -0
- package/dist/smoke/copilot-sdk-scenarios.d.ts.map +1 -0
- package/dist/smoke/copilot-sdk-scenarios.js +620 -0
- package/dist/smoke/copilot-sdk-scenarios.js.map +1 -0
- 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-session-eval.d.ts +90 -0
- package/dist/smoke/copilot-session-eval.d.ts.map +1 -0
- package/dist/smoke/copilot-session-eval.js +323 -0
- package/dist/smoke/copilot-session-eval.js.map +1 -0
- package/dist/smoke/copilot-smoke.d.ts +166 -0
- package/dist/smoke/copilot-smoke.d.ts.map +1 -0
- package/dist/smoke/copilot-smoke.js +688 -0
- package/dist/smoke/copilot-smoke.js.map +1 -0
- package/dist/smoke/process-utils.d.ts +47 -0
- package/dist/smoke/process-utils.d.ts.map +1 -0
- package/dist/smoke/process-utils.js +99 -0
- package/dist/smoke/process-utils.js.map +1 -0
- 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/__tests__/tmux-session.pane-env.test.d.ts +2 -0
- package/dist/team/__tests__/tmux-session.pane-env.test.d.ts.map +1 -0
- package/dist/team/__tests__/tmux-session.pane-env.test.js +52 -0
- package/dist/team/__tests__/tmux-session.pane-env.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/tmux-session.d.ts +7 -0
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +80 -18
- package/dist/team/tmux-session.js.map +1 -1
- 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/dist/tools/host-smoke-tool.d.ts +34 -0
- package/dist/tools/host-smoke-tool.d.ts.map +1 -0
- package/dist/tools/host-smoke-tool.js +133 -0
- package/dist/tools/host-smoke-tool.js.map +1 -0
- package/docs/CLAUDE.md +1 -1
- package/docs/DEVELOPERS.md +122 -0
- package/docs/HOOKS.md +34 -2
- package/docs/MIGRATION.md +194 -3
- package/docs/REFERENCE.md +95 -1
- package/docs/TOOLS.md +32 -1
- package/package.json +11 -2
- package/plugin.json +1 -1
- package/scripts/dev/repro-state-lock.mjs +1 -1
- package/scripts/lib/atomic-write.mjs +4 -2
- package/scripts/lib/state-lock.mjs +21 -12
- package/scripts/run.cjs +141 -18
- package/scripts/session-start.mjs +13 -0
- package/scripts/wiki-session-end.mjs +2 -1
- package/templates/hooks/lib/atomic-write.mjs +4 -2
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);
|
|
@@ -7343,33 +7369,33 @@ function ensureDirSync(dir) {
|
|
|
7343
7369
|
}
|
|
7344
7370
|
}
|
|
7345
7371
|
function verifyPrivateTempFile(fd, tempPath, label, operations) {
|
|
7346
|
-
const fdStats =
|
|
7372
|
+
const fdStats = descriptorStats(fd, operations);
|
|
7347
7373
|
let pathStats;
|
|
7348
7374
|
try {
|
|
7349
|
-
pathStats = (operations
|
|
7375
|
+
pathStats = pathnameStats(tempPath, operations);
|
|
7350
7376
|
} catch {
|
|
7351
7377
|
throw new Error(`${label} temporary file was replaced before rename`);
|
|
7352
7378
|
}
|
|
7353
7379
|
const isWindows = process.platform === "win32";
|
|
7354
|
-
const isPrivateRegularSingleLink = (stats) => stats.isFile() && (isWindows ? stats.nlink <= 1 : stats.nlink === 1) && (isWindows || (stats.mode & 511) === 384);
|
|
7380
|
+
const isPrivateRegularSingleLink = (stats) => stats.isFile() && (isWindows ? Number(stats.nlink) <= 1 : Number(stats.nlink) === 1) && (isWindows || (Number(stats.mode) & 511) === 384);
|
|
7355
7381
|
if (!isPrivateRegularSingleLink(fdStats) || !isPrivateRegularSingleLink(pathStats)) {
|
|
7356
7382
|
throw new Error(
|
|
7357
7383
|
`${label} temporary file must be a private regular single-link file`
|
|
7358
7384
|
);
|
|
7359
7385
|
}
|
|
7360
|
-
if (!sameFileIdentity(fdStats, pathStats)) {
|
|
7386
|
+
if (!sameFileIdentity(fileIdentityOf(fdStats), fileIdentityOf(pathStats))) {
|
|
7361
7387
|
throw new Error(`${label} temporary file was replaced before rename`);
|
|
7362
7388
|
}
|
|
7363
7389
|
}
|
|
7364
7390
|
function verifyPublishedFile(fd, filePath, label, operations) {
|
|
7365
|
-
const fdStats =
|
|
7391
|
+
const fdStats = descriptorStats(fd, operations);
|
|
7366
7392
|
let pathStats;
|
|
7367
7393
|
try {
|
|
7368
|
-
pathStats = (operations
|
|
7394
|
+
pathStats = pathnameStats(filePath, operations);
|
|
7369
7395
|
} catch {
|
|
7370
7396
|
throw new Error(`${label} target was replaced at publication`);
|
|
7371
7397
|
}
|
|
7372
|
-
if (!pathStats.isFile() || !sameFileIdentity(fdStats, pathStats)) {
|
|
7398
|
+
if (!pathStats.isFile() || !sameFileIdentity(fileIdentityOf(fdStats), fileIdentityOf(pathStats))) {
|
|
7373
7399
|
throw new Error(`${label} target was replaced at publication`);
|
|
7374
7400
|
}
|
|
7375
7401
|
}
|
|
@@ -7393,26 +7419,33 @@ function preservePriorTarget(filePath, operations) {
|
|
|
7393
7419
|
return null;
|
|
7394
7420
|
}
|
|
7395
7421
|
}
|
|
7422
|
+
function descriptorStats(fd, operations) {
|
|
7423
|
+
return operations ? fsSync.fstatSync(fd) : fsSync.fstatSync(fd, { bigint: true });
|
|
7424
|
+
}
|
|
7425
|
+
function pathnameStats(filePath, operations) {
|
|
7426
|
+
return operations ? operations.lstat(filePath) : fsSync.lstatSync(filePath, { bigint: true });
|
|
7427
|
+
}
|
|
7428
|
+
function fileIdentityOf(stats) {
|
|
7429
|
+
return { dev: BigInt(stats.dev), ino: BigInt(stats.ino) };
|
|
7430
|
+
}
|
|
7396
7431
|
function sameFileIdentity(a, b) {
|
|
7397
7432
|
if (a.ino !== b.ino) return false;
|
|
7398
7433
|
const isWindows = process.platform === "win32";
|
|
7399
|
-
if (isWindows && (a.dev ===
|
|
7434
|
+
if (isWindows && (a.dev === 0n || b.dev === 0n)) {
|
|
7400
7435
|
return true;
|
|
7401
7436
|
}
|
|
7402
7437
|
return a.dev === b.dev;
|
|
7403
7438
|
}
|
|
7404
7439
|
function currentFileIdentity(filePath, operations) {
|
|
7405
7440
|
try {
|
|
7406
|
-
|
|
7407
|
-
return { dev: stats.dev, ino: stats.ino };
|
|
7441
|
+
return fileIdentityOf(pathnameStats(filePath, operations));
|
|
7408
7442
|
} catch {
|
|
7409
7443
|
return null;
|
|
7410
7444
|
}
|
|
7411
7445
|
}
|
|
7412
|
-
function descriptorIdentity(fd) {
|
|
7446
|
+
function descriptorIdentity(fd, operations) {
|
|
7413
7447
|
try {
|
|
7414
|
-
|
|
7415
|
-
return { dev: stats.dev, ino: stats.ino };
|
|
7448
|
+
return fileIdentityOf(descriptorStats(fd, operations));
|
|
7416
7449
|
} catch {
|
|
7417
7450
|
return null;
|
|
7418
7451
|
}
|
|
@@ -7685,7 +7718,7 @@ function withFileLockSync(lockPath, fn, opts) {
|
|
|
7685
7718
|
}
|
|
7686
7719
|
}
|
|
7687
7720
|
function sleep(ms) {
|
|
7688
|
-
return new Promise((
|
|
7721
|
+
return new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
7689
7722
|
}
|
|
7690
7723
|
async function acquireFileLock(lockPath, opts) {
|
|
7691
7724
|
const staleLockMs = opts?.staleLockMs ?? DEFAULT_STALE_LOCK_MS;
|
|
@@ -7903,7 +7936,7 @@ function canonicalAuthorityDigest(input) {
|
|
|
7903
7936
|
return (0, import_node_crypto5.createHash)("sha256").update(payload, "utf8").digest("hex");
|
|
7904
7937
|
}
|
|
7905
7938
|
function sleep2(ms) {
|
|
7906
|
-
return new Promise((
|
|
7939
|
+
return new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
7907
7940
|
}
|
|
7908
7941
|
function isExactText(value) {
|
|
7909
7942
|
return typeof value === "string" && value.length > 0 && value === value.trim();
|
|
@@ -9261,11 +9294,11 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9261
9294
|
let resolveCompletion;
|
|
9262
9295
|
let resolveWindowsReady;
|
|
9263
9296
|
let resolveWindowsTerminal;
|
|
9264
|
-
const windowsReady = new Promise((
|
|
9265
|
-
resolveWindowsReady =
|
|
9297
|
+
const windowsReady = new Promise((resolve17) => {
|
|
9298
|
+
resolveWindowsReady = resolve17;
|
|
9266
9299
|
});
|
|
9267
|
-
const windowsTerminal = new Promise((
|
|
9268
|
-
resolveWindowsTerminal =
|
|
9300
|
+
const windowsTerminal = new Promise((resolve17) => {
|
|
9301
|
+
resolveWindowsTerminal = resolve17;
|
|
9269
9302
|
});
|
|
9270
9303
|
if (providerGate) {
|
|
9271
9304
|
providerGate.on("error", (error) => {
|
|
@@ -9326,8 +9359,8 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9326
9359
|
}
|
|
9327
9360
|
});
|
|
9328
9361
|
}
|
|
9329
|
-
const completion = new Promise((
|
|
9330
|
-
resolveCompletion =
|
|
9362
|
+
const completion = new Promise((resolve17) => {
|
|
9363
|
+
resolveCompletion = resolve17;
|
|
9331
9364
|
child.once("exit", async (exitCode, signal) => {
|
|
9332
9365
|
if (settled && process.platform === "win32" || childExitObserved) return;
|
|
9333
9366
|
childExitObserved = true;
|
|
@@ -9384,7 +9417,7 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9384
9417
|
written_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
9385
9418
|
}).catch(() => void 0);
|
|
9386
9419
|
await invocation.cleanup().catch(() => void 0);
|
|
9387
|
-
|
|
9420
|
+
resolve17(gateCleanupRequired ? cleanupVerified ? { outcome: "provider_spawn_failed" } : { outcome: "provider_cleanup_unverified" } : cleanupVerified ? { outcome: "ran", exitCode: effectiveExitCode, signal: effectiveSignal } : { outcome: "provider_cleanup_unverified" });
|
|
9388
9421
|
});
|
|
9389
9422
|
child.once("error", async () => {
|
|
9390
9423
|
if (settled) return;
|
|
@@ -9402,7 +9435,7 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9402
9435
|
written_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
9403
9436
|
}).catch(() => void 0);
|
|
9404
9437
|
await invocation.cleanup().catch(() => void 0);
|
|
9405
|
-
|
|
9438
|
+
resolve17({ outcome: "provider_spawn_failed" });
|
|
9406
9439
|
});
|
|
9407
9440
|
});
|
|
9408
9441
|
const terminateProvider = async () => {
|
|
@@ -9434,7 +9467,7 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9434
9467
|
`);
|
|
9435
9468
|
return await Promise.race([
|
|
9436
9469
|
windowsTerminal,
|
|
9437
|
-
new Promise((
|
|
9470
|
+
new Promise((resolve17) => setTimeout(() => resolve17(false), 5e3))
|
|
9438
9471
|
]);
|
|
9439
9472
|
}
|
|
9440
9473
|
if (child.pid && providerStartIdentity && launchGroup) {
|
|
@@ -9446,11 +9479,11 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9446
9479
|
force: true
|
|
9447
9480
|
});
|
|
9448
9481
|
await terminationResult;
|
|
9449
|
-
const completed = await new Promise((
|
|
9450
|
-
const timer = setTimeout(() =>
|
|
9482
|
+
const completed = await new Promise((resolve17) => {
|
|
9483
|
+
const timer = setTimeout(() => resolve17(false), 2e3);
|
|
9451
9484
|
void completion.then((result) => {
|
|
9452
9485
|
clearTimeout(timer);
|
|
9453
|
-
|
|
9486
|
+
resolve17(result.outcome !== "provider_cleanup_unverified");
|
|
9454
9487
|
});
|
|
9455
9488
|
});
|
|
9456
9489
|
return completed;
|
|
@@ -9469,20 +9502,20 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9469
9502
|
if (!providerGate || providerGate.destroyed) return false;
|
|
9470
9503
|
let callbackCalled = false;
|
|
9471
9504
|
let callbackError = false;
|
|
9472
|
-
const closeResultPromise = new Promise((
|
|
9473
|
-
providerGateOperationResolve =
|
|
9505
|
+
const closeResultPromise = new Promise((resolve17) => {
|
|
9506
|
+
providerGateOperationResolve = resolve17;
|
|
9474
9507
|
const finish = (error) => {
|
|
9475
9508
|
providerGateError ??= error ?? null;
|
|
9476
9509
|
providerGateOperationResolve = null;
|
|
9477
9510
|
callbackCalled = true;
|
|
9478
9511
|
callbackError = providerGateError !== null;
|
|
9479
|
-
|
|
9512
|
+
resolve17(!callbackError);
|
|
9480
9513
|
};
|
|
9481
9514
|
try {
|
|
9482
9515
|
providerGate.end(finish);
|
|
9483
9516
|
} catch {
|
|
9484
9517
|
providerGateOperationResolve = null;
|
|
9485
|
-
|
|
9518
|
+
resolve17(false);
|
|
9486
9519
|
}
|
|
9487
9520
|
});
|
|
9488
9521
|
providerGateOperationPromise = closeResultPromise;
|
|
@@ -9506,8 +9539,8 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9506
9539
|
if (providerGateReleased) return providerGateError === null;
|
|
9507
9540
|
if (providerGateReleaseAttempted || providerGateClosed || !providerGate || providerGate.destroyed) return false;
|
|
9508
9541
|
providerGateReleaseAttempted = true;
|
|
9509
|
-
const releasePromise = new Promise((
|
|
9510
|
-
providerGateOperationResolve =
|
|
9542
|
+
const releasePromise = new Promise((resolve17) => {
|
|
9543
|
+
providerGateOperationResolve = resolve17;
|
|
9511
9544
|
try {
|
|
9512
9545
|
providerGate.end("release\n", (error) => {
|
|
9513
9546
|
providerGateError ??= error ?? null;
|
|
@@ -9517,11 +9550,11 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9517
9550
|
providerGateReleased = true;
|
|
9518
9551
|
terminateProviderOnGateError = null;
|
|
9519
9552
|
}
|
|
9520
|
-
|
|
9553
|
+
resolve17(released);
|
|
9521
9554
|
});
|
|
9522
9555
|
} catch {
|
|
9523
9556
|
providerGateOperationResolve = null;
|
|
9524
|
-
|
|
9557
|
+
resolve17(false);
|
|
9525
9558
|
}
|
|
9526
9559
|
});
|
|
9527
9560
|
providerGateOperationPromise = releasePromise;
|
|
@@ -9550,9 +9583,9 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9550
9583
|
for (const signal of cleanupSignals) process.removeListener(signal, onBootstrapSignal);
|
|
9551
9584
|
});
|
|
9552
9585
|
}
|
|
9553
|
-
const spawned = await new Promise((
|
|
9554
|
-
child.once("spawn", () =>
|
|
9555
|
-
child.once("error", () =>
|
|
9586
|
+
const spawned = await new Promise((resolve17) => {
|
|
9587
|
+
child.once("spawn", () => resolve17(true));
|
|
9588
|
+
child.once("error", () => resolve17(false));
|
|
9556
9589
|
});
|
|
9557
9590
|
if (!spawned) {
|
|
9558
9591
|
await completion;
|
|
@@ -9561,7 +9594,7 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9561
9594
|
if (process.platform === "win32") {
|
|
9562
9595
|
const ready = await Promise.race([
|
|
9563
9596
|
windowsReady,
|
|
9564
|
-
new Promise((
|
|
9597
|
+
new Promise((resolve17) => setTimeout(() => resolve17(false), 1e4))
|
|
9565
9598
|
]);
|
|
9566
9599
|
if (!ready || !providerPid || !providerStartIdentity || settled) {
|
|
9567
9600
|
return cleanupProvider("provider_spawn_failed");
|
|
@@ -9596,7 +9629,7 @@ async function runWorkerLaunchBootstrap(value) {
|
|
|
9596
9629
|
if (!await releaseProviderGate() || providerGateError !== null) {
|
|
9597
9630
|
return cleanupProvider("provider_spawn_failed");
|
|
9598
9631
|
}
|
|
9599
|
-
if (!spec.release_after_spawn) await new Promise((
|
|
9632
|
+
if (!spec.release_after_spawn) await new Promise((resolve17) => setTimeout(resolve17, 75));
|
|
9600
9633
|
if (settled) return { completion };
|
|
9601
9634
|
}
|
|
9602
9635
|
if (invocation.completionPath && (0, import_node_fs4.existsSync)(invocation.completionPath)) {
|
|
@@ -10173,7 +10206,8 @@ __export(tmux_session_exports, {
|
|
|
10173
10206
|
waitForPaneReady: () => waitForPaneReady,
|
|
10174
10207
|
waitForStartupPaneReady: () => waitForStartupPaneReady,
|
|
10175
10208
|
workerPaneBelongsToOwnedProviderTarget: () => workerPaneBelongsToOwnedProviderTarget,
|
|
10176
|
-
workerPaneBelongsToProviderTarget: () => workerPaneBelongsToProviderTarget
|
|
10209
|
+
workerPaneBelongsToProviderTarget: () => workerPaneBelongsToProviderTarget,
|
|
10210
|
+
workerPaneShellCommand: () => workerPaneShellCommand
|
|
10177
10211
|
});
|
|
10178
10212
|
function tmuxArgsForIdentity(identity, args) {
|
|
10179
10213
|
return ["-S", identity.socket_path, ...args];
|
|
@@ -11048,23 +11082,66 @@ async function verifyWorkerStartCommandSubmitted(paneId, startCmd, opts = {}) {
|
|
|
11048
11082
|
}
|
|
11049
11083
|
return false;
|
|
11050
11084
|
}
|
|
11085
|
+
function writePaneEnvFile(values) {
|
|
11086
|
+
const directory = (0, import_fs24.mkdtempSync)((0, import_path25.join)((0, import_os8.tmpdir)(), "omc-pane-env-"));
|
|
11087
|
+
const file = (0, import_path25.join)(directory, "env");
|
|
11088
|
+
const body = Object.entries(values).map(([key, value]) => `export ${key}=${shellQuote(value)}
|
|
11089
|
+
`).join("");
|
|
11090
|
+
(0, import_fs24.writeFileSync)(file, body, { mode: 384, flag: "wx" });
|
|
11091
|
+
return file;
|
|
11092
|
+
}
|
|
11093
|
+
function discardPaneEnvFile(envFile) {
|
|
11094
|
+
if (!envFile) return;
|
|
11095
|
+
(0, import_fs24.rmSync)((0, import_path25.dirname)(envFile), { recursive: true, force: true });
|
|
11096
|
+
}
|
|
11051
11097
|
function workerPaneShellCommand() {
|
|
11052
11098
|
if (process.platform === "win32" && !isUnixLikeOnWindows()) {
|
|
11053
|
-
return [getDefaultShell()];
|
|
11099
|
+
return { args: [getDefaultShell()], envFile: null };
|
|
11054
11100
|
}
|
|
11055
|
-
if (process.platform === "win32") return [];
|
|
11101
|
+
if (process.platform === "win32") return { args: [], envFile: null };
|
|
11056
11102
|
const shell = getDefaultShell();
|
|
11057
11103
|
const baseline = buildProviderEnvironment({ SHELL: shell });
|
|
11104
|
+
const inline = buildProviderEnvironment({ SHELL: shell }, process.env, process.platform, []);
|
|
11105
|
+
const passthrough = Object.fromEntries(
|
|
11106
|
+
Object.entries(baseline).filter(([key, value]) => inline[key] !== value)
|
|
11107
|
+
);
|
|
11058
11108
|
const inheritedPaneEnvironment = ["TERM", "TMUX", "TMUX_PANE", "TMUX_TMPDIR", "LANG", "LC_ALL", "LC_CTYPE"].map((key) => `${key}="$${key}"`);
|
|
11109
|
+
const inlineAssignments = Object.entries(inline).map(([key, value]) => `${key}=${shellQuote(value)}`);
|
|
11110
|
+
if (Object.keys(passthrough).length === 0) {
|
|
11111
|
+
const command2 = [
|
|
11112
|
+
"/usr/bin/env",
|
|
11113
|
+
"-i",
|
|
11114
|
+
...inlineAssignments,
|
|
11115
|
+
...inheritedPaneEnvironment,
|
|
11116
|
+
shellQuote(shell),
|
|
11117
|
+
"-l"
|
|
11118
|
+
].join(" ");
|
|
11119
|
+
return { args: [command2], envFile: null };
|
|
11120
|
+
}
|
|
11121
|
+
const envFile = writePaneEnvFile(passthrough);
|
|
11122
|
+
const bootstrap = '. "$OMC_PANE_ENV_FILE" && rm -rf -- "${OMC_PANE_ENV_FILE%/*}" && unset OMC_PANE_ENV_FILE && exec "$SHELL" -l';
|
|
11059
11123
|
const command = [
|
|
11060
11124
|
"/usr/bin/env",
|
|
11061
11125
|
"-i",
|
|
11062
|
-
...
|
|
11126
|
+
...inlineAssignments,
|
|
11127
|
+
`OMC_PANE_ENV_FILE=${shellQuote(envFile)}`,
|
|
11063
11128
|
...inheritedPaneEnvironment,
|
|
11064
|
-
|
|
11065
|
-
"-
|
|
11129
|
+
"/bin/sh",
|
|
11130
|
+
"-c",
|
|
11131
|
+
shellQuote(bootstrap)
|
|
11066
11132
|
].join(" ");
|
|
11067
|
-
return [command];
|
|
11133
|
+
return { args: [command], envFile };
|
|
11134
|
+
}
|
|
11135
|
+
async function runPaneCreationCommand(identity, nativeCommand, paneShell) {
|
|
11136
|
+
let result;
|
|
11137
|
+
try {
|
|
11138
|
+
result = await runGuardedNativeTmuxCommand(identity, nativeCommand);
|
|
11139
|
+
} catch (error) {
|
|
11140
|
+
discardPaneEnvFile(paneShell.envFile);
|
|
11141
|
+
throw error;
|
|
11142
|
+
}
|
|
11143
|
+
if (result.outcome === "not_executed") discardPaneEnvFile(paneShell.envFile);
|
|
11144
|
+
return result;
|
|
11068
11145
|
}
|
|
11069
11146
|
function escapeForCmdSet(value) {
|
|
11070
11147
|
return value.replace(/(["%])/g, "$1$1");
|
|
@@ -11363,6 +11440,7 @@ async function splitTeamWorkerPaneWithEvidence(splitTarget, direction, cwd, prov
|
|
|
11363
11440
|
};
|
|
11364
11441
|
}
|
|
11365
11442
|
const splitType = direction === "right" ? "-h" : "-v";
|
|
11443
|
+
const splitPaneShell = workerPaneShellCommand();
|
|
11366
11444
|
const splitArgs = [
|
|
11367
11445
|
"split-window",
|
|
11368
11446
|
splitType,
|
|
@@ -11374,11 +11452,12 @@ async function splitTeamWorkerPaneWithEvidence(splitTarget, direction, cwd, prov
|
|
|
11374
11452
|
"#{pane_id} #{socket_path} #{pid}",
|
|
11375
11453
|
"-c",
|
|
11376
11454
|
cwd,
|
|
11377
|
-
...
|
|
11455
|
+
...splitPaneShell.args
|
|
11378
11456
|
];
|
|
11379
|
-
const splitResult = await
|
|
11457
|
+
const splitResult = await runPaneCreationCommand(
|
|
11380
11458
|
identity,
|
|
11381
|
-
tmuxCommandString(splitArgs, ["#{pane_id} #{socket_path} #{pid}"])
|
|
11459
|
+
tmuxCommandString(splitArgs, ["#{pane_id} #{socket_path} #{pid}"]),
|
|
11460
|
+
splitPaneShell
|
|
11382
11461
|
);
|
|
11383
11462
|
const parsed = splitResult.outcome === "executed" ? parseTmuxCreationRecord(
|
|
11384
11463
|
splitResult.stdout,
|
|
@@ -11480,6 +11559,7 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
|
|
|
11480
11559
|
sessionMode: "detached-session",
|
|
11481
11560
|
...tmuxServerIdentity ? { tmuxServerIdentity: { ...tmuxServerIdentity } } : {}
|
|
11482
11561
|
});
|
|
11562
|
+
const detachedPaneShell = workerPaneShellCommand();
|
|
11483
11563
|
const detachedArgs = [
|
|
11484
11564
|
"new-session",
|
|
11485
11565
|
"-d",
|
|
@@ -11490,7 +11570,7 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
|
|
|
11490
11570
|
detachedSessionName,
|
|
11491
11571
|
"-c",
|
|
11492
11572
|
cwd,
|
|
11493
|
-
...
|
|
11573
|
+
...detachedPaneShell.args
|
|
11494
11574
|
];
|
|
11495
11575
|
const cleanupFreshDetachedServer = async () => {
|
|
11496
11576
|
if (isPsmux() && freshSocketPathForEvidence) {
|
|
@@ -11519,9 +11599,10 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
|
|
|
11519
11599
|
if (existingDetachedIdentity) {
|
|
11520
11600
|
tmuxServerIdentity = existingDetachedIdentity;
|
|
11521
11601
|
try {
|
|
11522
|
-
detachedResult = await
|
|
11602
|
+
detachedResult = await runPaneCreationCommand(
|
|
11523
11603
|
existingDetachedIdentity,
|
|
11524
|
-
tmuxCommandString(detachedArgs, ["#S:0 #{pane_id} #{socket_path} #{pid}"])
|
|
11604
|
+
tmuxCommandString(detachedArgs, ["#S:0 #{pane_id} #{socket_path} #{pid}"]),
|
|
11605
|
+
detachedPaneShell
|
|
11525
11606
|
);
|
|
11526
11607
|
} catch (error) {
|
|
11527
11608
|
const cleaned = await cleanupDetachedSession();
|
|
@@ -11581,11 +11662,13 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
|
|
|
11581
11662
|
throw new Error("tmux_server_identity_unavailable");
|
|
11582
11663
|
}
|
|
11583
11664
|
freshDetachedServerIdentity = tmuxServerIdentity;
|
|
11584
|
-
detachedResult = await
|
|
11665
|
+
detachedResult = await runPaneCreationCommand(
|
|
11585
11666
|
tmuxServerIdentity,
|
|
11586
|
-
tmuxCommandString(detachedArgs, ["#S:0 #{pane_id} #{socket_path} #{pid}"])
|
|
11667
|
+
tmuxCommandString(detachedArgs, ["#S:0 #{pane_id} #{socket_path} #{pid}"]),
|
|
11668
|
+
detachedPaneShell
|
|
11587
11669
|
);
|
|
11588
11670
|
} catch (error) {
|
|
11671
|
+
discardPaneEnvFile(detachedPaneShell.envFile);
|
|
11589
11672
|
const cleaned = await cleanupDetachedSession();
|
|
11590
11673
|
if (!cleaned && freshDetachedServerStarted) {
|
|
11591
11674
|
throw new TeamSessionCreationError(
|
|
@@ -11765,6 +11848,7 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
|
|
|
11765
11848
|
if (useDedicatedWindow) {
|
|
11766
11849
|
const targetSession = sessionAndWindow.split(":")[0] ?? sessionAndWindow;
|
|
11767
11850
|
const windowName = `omc-${sanitizeName(teamName)}`.slice(0, 32);
|
|
11851
|
+
const newWindowPaneShell = workerPaneShellCommand();
|
|
11768
11852
|
const newWindowArgs = [
|
|
11769
11853
|
"new-window",
|
|
11770
11854
|
"-d",
|
|
@@ -11777,13 +11861,14 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
|
|
|
11777
11861
|
windowName,
|
|
11778
11862
|
"-c",
|
|
11779
11863
|
cwd,
|
|
11780
|
-
...
|
|
11864
|
+
...newWindowPaneShell.args
|
|
11781
11865
|
];
|
|
11782
11866
|
let newWindowResult;
|
|
11783
11867
|
try {
|
|
11784
|
-
newWindowResult = await
|
|
11868
|
+
newWindowResult = await runPaneCreationCommand(
|
|
11785
11869
|
tmuxServerIdentity,
|
|
11786
|
-
tmuxCommandString(newWindowArgs, ["#S:#I #{pane_id} #{socket_path} #{pid}"])
|
|
11870
|
+
tmuxCommandString(newWindowArgs, ["#S:#I #{pane_id} #{socket_path} #{pid}"]),
|
|
11871
|
+
newWindowPaneShell
|
|
11787
11872
|
);
|
|
11788
11873
|
} catch (error) {
|
|
11789
11874
|
const creationError = new TeamSessionCreationError(
|
|
@@ -11933,6 +12018,7 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
|
|
|
11933
12018
|
continue;
|
|
11934
12019
|
}
|
|
11935
12020
|
const splitType = i === 0 ? "-h" : "-v";
|
|
12021
|
+
const splitPaneShell = workerPaneShellCommand();
|
|
11936
12022
|
const splitArgs = [
|
|
11937
12023
|
"split-window",
|
|
11938
12024
|
splitType,
|
|
@@ -11944,11 +12030,12 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
|
|
|
11944
12030
|
"#{pane_id} #{socket_path} #{pid}",
|
|
11945
12031
|
"-c",
|
|
11946
12032
|
cwd,
|
|
11947
|
-
...
|
|
12033
|
+
...splitPaneShell.args
|
|
11948
12034
|
];
|
|
11949
|
-
const splitResult = await
|
|
12035
|
+
const splitResult = await runPaneCreationCommand(
|
|
11950
12036
|
tmuxServerIdentity,
|
|
11951
|
-
tmuxCommandString(splitArgs, ["#{pane_id} #{socket_path} #{pid}"])
|
|
12037
|
+
tmuxCommandString(splitArgs, ["#{pane_id} #{socket_path} #{pid}"]),
|
|
12038
|
+
splitPaneShell
|
|
11952
12039
|
);
|
|
11953
12040
|
if (splitResult.outcome !== "executed") {
|
|
11954
12041
|
const creationError = new TeamSessionCreationError(
|
|
@@ -13240,8 +13327,8 @@ function getPackageDir3() {
|
|
|
13240
13327
|
}
|
|
13241
13328
|
}
|
|
13242
13329
|
try {
|
|
13243
|
-
const
|
|
13244
|
-
const __dirname2 = (0, import_path26.dirname)(
|
|
13330
|
+
const __filename2 = (0, import_url4.fileURLToPath)(importMetaUrl);
|
|
13331
|
+
const __dirname2 = (0, import_path26.dirname)(__filename2);
|
|
13245
13332
|
const currentDirName = (0, import_path26.basename)(__dirname2);
|
|
13246
13333
|
if (currentDirName === "bridge") {
|
|
13247
13334
|
return (0, import_path26.join)(__dirname2, "..");
|
|
@@ -13710,7 +13797,7 @@ async function withDispatchLock(teamName, cwd, fn) {
|
|
|
13710
13797
|
);
|
|
13711
13798
|
}
|
|
13712
13799
|
const jitter = 0.5 + Math.random() * 0.5;
|
|
13713
|
-
await new Promise((
|
|
13800
|
+
await new Promise((resolve17) => setTimeout(resolve17, Math.floor(pollMs * jitter)));
|
|
13714
13801
|
pollMs = Math.min(pollMs * 2, DISPATCH_LOCK_MAX_POLL_MS);
|
|
13715
13802
|
}
|
|
13716
13803
|
}
|
|
@@ -16471,8 +16558,8 @@ async function startMergeOrchestrator(config) {
|
|
|
16471
16558
|
let persisted = { lastShas: {} };
|
|
16472
16559
|
if ((0, import_node_fs10.existsSync)(persistedPath)) {
|
|
16473
16560
|
try {
|
|
16474
|
-
const { readFileSync:
|
|
16475
|
-
persisted = JSON.parse(
|
|
16561
|
+
const { readFileSync: readFileSync24 } = await import("node:fs");
|
|
16562
|
+
persisted = JSON.parse(readFileSync24(persistedPath, "utf-8"));
|
|
16476
16563
|
} catch {
|
|
16477
16564
|
persisted = { lastShas: {} };
|
|
16478
16565
|
}
|
|
@@ -16854,8 +16941,8 @@ ${dirtyFiles.map((f) => `- \`${f}\``).join("\n")}`;
|
|
|
16854
16941
|
return false;
|
|
16855
16942
|
}
|
|
16856
16943
|
})(),
|
|
16857
|
-
new Promise((
|
|
16858
|
-
const t = setTimeout(() =>
|
|
16944
|
+
new Promise((resolve17) => {
|
|
16945
|
+
const t = setTimeout(() => resolve17(false), remaining);
|
|
16859
16946
|
if (typeof t.unref === "function") t.unref();
|
|
16860
16947
|
})
|
|
16861
16948
|
]);
|
|
@@ -16917,8 +17004,8 @@ async function recoverFromRestart(config) {
|
|
|
16917
17004
|
let persistedShasLoaded = 0;
|
|
16918
17005
|
if ((0, import_node_fs10.existsSync)(persistedPath)) {
|
|
16919
17006
|
try {
|
|
16920
|
-
const { readFileSync:
|
|
16921
|
-
const persisted = JSON.parse(
|
|
17007
|
+
const { readFileSync: readFileSync24 } = await import("node:fs");
|
|
17008
|
+
const persisted = JSON.parse(readFileSync24(persistedPath, "utf-8"));
|
|
16922
17009
|
persistedShasLoaded = Object.keys(persisted.lastShas ?? {}).length;
|
|
16923
17010
|
} catch {
|
|
16924
17011
|
persistedShasLoaded = 0;
|
|
@@ -16985,6 +17072,223 @@ var init_merge_orchestrator = __esm({
|
|
|
16985
17072
|
}
|
|
16986
17073
|
});
|
|
16987
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
|
+
|
|
16988
17292
|
// src/team/scaling.ts
|
|
16989
17293
|
function scaleUpFenceBlocks(config) {
|
|
16990
17294
|
const attempt = config.active_scale_up;
|
|
@@ -17010,6 +17314,7 @@ var init_scaling = __esm({
|
|
|
17010
17314
|
init_tmux_session();
|
|
17011
17315
|
init_state_paths();
|
|
17012
17316
|
init_worker_bootstrap();
|
|
17317
|
+
init_sdk_transport();
|
|
17013
17318
|
init_git_worktree();
|
|
17014
17319
|
init_worktree_paths();
|
|
17015
17320
|
init_team_owner_epoch();
|
|
@@ -17053,7 +17358,7 @@ async function runRecoverySaga(input, deps) {
|
|
|
17053
17358
|
const rejected = checks.find((check) => !check.ok);
|
|
17054
17359
|
if (rejected) return finalize(failure(input, rejected.error), "selected", "not_started");
|
|
17055
17360
|
persistPhase("reserved", tasks.length ? "selected" : "none", "not_started");
|
|
17056
|
-
const adoptionTokenHash = (0,
|
|
17361
|
+
const adoptionTokenHash = (0, import_node_crypto9.createHash)("sha256").update(input.adoptionToken).digest("hex");
|
|
17057
17362
|
const sequences = {};
|
|
17058
17363
|
for (const task of tasks) {
|
|
17059
17364
|
const result2 = await deps.requeue(input, task.id, adoptionTokenHash);
|
|
@@ -17105,18 +17410,18 @@ async function runRecoverySaga(input, deps) {
|
|
|
17105
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() };
|
|
17106
17411
|
return finalize(result, tasks.length ? "adopted" : "none", tasks.length ? "adopted" : "not_started", services);
|
|
17107
17412
|
}
|
|
17108
|
-
var
|
|
17413
|
+
var import_node_crypto9;
|
|
17109
17414
|
var init_recovery_saga = __esm({
|
|
17110
17415
|
"src/team/recovery-saga.ts"() {
|
|
17111
17416
|
"use strict";
|
|
17112
|
-
|
|
17417
|
+
import_node_crypto9 = require("node:crypto");
|
|
17113
17418
|
init_recovery_request_store();
|
|
17114
17419
|
}
|
|
17115
17420
|
});
|
|
17116
17421
|
|
|
17117
17422
|
// src/team/worker-activation-gate.ts
|
|
17118
17423
|
async function writeAtomic3(path5, value) {
|
|
17119
|
-
await (0, import_promises18.mkdir)((0,
|
|
17424
|
+
await (0, import_promises18.mkdir)((0, import_node_path13.dirname)(path5), { recursive: true });
|
|
17120
17425
|
const temporary = `${path5}.tmp.${process.pid}.${Date.now()}`;
|
|
17121
17426
|
await (0, import_promises18.writeFile)(temporary, JSON.stringify(value), "utf8");
|
|
17122
17427
|
await (0, import_promises18.rename)(temporary, path5);
|
|
@@ -17129,7 +17434,7 @@ async function waitForRecoveryGateRecord(path5, expected, timeoutMs, pollInterva
|
|
|
17129
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;
|
|
17130
17435
|
} catch {
|
|
17131
17436
|
}
|
|
17132
|
-
await new Promise((
|
|
17437
|
+
await new Promise((resolve17) => setTimeout(resolve17, pollIntervalMs));
|
|
17133
17438
|
}
|
|
17134
17439
|
return false;
|
|
17135
17440
|
}
|
|
@@ -17173,7 +17478,7 @@ async function runWorkerActivationGate(gate) {
|
|
|
17173
17478
|
{ providerEnv }
|
|
17174
17479
|
)
|
|
17175
17480
|
});
|
|
17176
|
-
const child = (0,
|
|
17481
|
+
const child = (0, import_node_child_process7.spawn)(invocation.command, invocation.args, {
|
|
17177
17482
|
cwd: gate.cwd,
|
|
17178
17483
|
env: providerEnv,
|
|
17179
17484
|
stdio: "inherit",
|
|
@@ -17191,7 +17496,7 @@ async function runWorkerActivationGate(gate) {
|
|
|
17191
17496
|
let supervisorTimer;
|
|
17192
17497
|
let terminationResult = null;
|
|
17193
17498
|
let finishCompletion;
|
|
17194
|
-
const completion = new Promise((
|
|
17499
|
+
const completion = new Promise((resolve17) => {
|
|
17195
17500
|
const finish = async (result, terminal) => {
|
|
17196
17501
|
if (settled) return;
|
|
17197
17502
|
settled = true;
|
|
@@ -17207,7 +17512,7 @@ async function runWorkerActivationGate(gate) {
|
|
|
17207
17512
|
} catch {
|
|
17208
17513
|
}
|
|
17209
17514
|
await invocation.cleanup().catch(() => void 0);
|
|
17210
|
-
|
|
17515
|
+
resolve17(result);
|
|
17211
17516
|
};
|
|
17212
17517
|
finishCompletion = finish;
|
|
17213
17518
|
child.once("exit", async (exitCode, signal) => {
|
|
@@ -17238,11 +17543,11 @@ async function runWorkerActivationGate(gate) {
|
|
|
17238
17543
|
force: true
|
|
17239
17544
|
});
|
|
17240
17545
|
const terminated = await terminationResult === "terminated";
|
|
17241
|
-
const completed2 = await new Promise((
|
|
17242
|
-
const timer = setTimeout(() =>
|
|
17546
|
+
const completed2 = await new Promise((resolve17) => {
|
|
17547
|
+
const timer = setTimeout(() => resolve17(false), 2e3);
|
|
17243
17548
|
void completion.then((result) => {
|
|
17244
17549
|
clearTimeout(timer);
|
|
17245
|
-
|
|
17550
|
+
resolve17(result.outcome !== "provider_cleanup_unverified");
|
|
17246
17551
|
});
|
|
17247
17552
|
});
|
|
17248
17553
|
return terminated && completed2;
|
|
@@ -17259,15 +17564,15 @@ async function runWorkerActivationGate(gate) {
|
|
|
17259
17564
|
}
|
|
17260
17565
|
} catch {
|
|
17261
17566
|
}
|
|
17262
|
-
const completed = await new Promise((
|
|
17263
|
-
const timer = setTimeout(() =>
|
|
17567
|
+
const completed = await new Promise((resolve17) => {
|
|
17568
|
+
const timer = setTimeout(() => resolve17(false), 2e3);
|
|
17264
17569
|
void completion.then(() => {
|
|
17265
17570
|
clearTimeout(timer);
|
|
17266
|
-
|
|
17571
|
+
resolve17(true);
|
|
17267
17572
|
});
|
|
17268
17573
|
if (settled) {
|
|
17269
17574
|
clearTimeout(timer);
|
|
17270
|
-
|
|
17575
|
+
resolve17(true);
|
|
17271
17576
|
}
|
|
17272
17577
|
});
|
|
17273
17578
|
return completed;
|
|
@@ -17283,9 +17588,9 @@ async function runWorkerActivationGate(gate) {
|
|
|
17283
17588
|
for (const signal of cleanupSignals) process.removeListener(signal, onGateSignal);
|
|
17284
17589
|
});
|
|
17285
17590
|
}
|
|
17286
|
-
const spawned = await new Promise((
|
|
17287
|
-
child.once("spawn", () =>
|
|
17288
|
-
child.once("error", () =>
|
|
17591
|
+
const spawned = await new Promise((resolve17) => {
|
|
17592
|
+
child.once("spawn", () => resolve17(true));
|
|
17593
|
+
child.once("error", () => resolve17(false));
|
|
17289
17594
|
});
|
|
17290
17595
|
if (!spawned) {
|
|
17291
17596
|
const failed = await completion;
|
|
@@ -17311,7 +17616,7 @@ async function runWorkerActivationGate(gate) {
|
|
|
17311
17616
|
return { outcome: "provider_cleanup_unverified" };
|
|
17312
17617
|
}
|
|
17313
17618
|
}
|
|
17314
|
-
await new Promise((
|
|
17619
|
+
await new Promise((resolve17) => setTimeout(resolve17, 150));
|
|
17315
17620
|
if (settled) return await completion;
|
|
17316
17621
|
const reboundIdentity = getProcessStartIdentitySync(providerPid);
|
|
17317
17622
|
if (!reboundIdentity || reboundIdentity !== providerStartIdentity || !isProcessAlive(providerPid)) {
|
|
@@ -17373,18 +17678,227 @@ async function runWorkerActivationGate(gate) {
|
|
|
17373
17678
|
}
|
|
17374
17679
|
return fenced.value;
|
|
17375
17680
|
}
|
|
17376
|
-
var
|
|
17681
|
+
var import_node_child_process7, import_promises18, import_node_path13;
|
|
17377
17682
|
var init_worker_activation_gate = __esm({
|
|
17378
17683
|
"src/team/worker-activation-gate.ts"() {
|
|
17379
17684
|
"use strict";
|
|
17380
|
-
|
|
17685
|
+
import_node_child_process7 = require("node:child_process");
|
|
17381
17686
|
import_promises18 = require("node:fs/promises");
|
|
17382
|
-
|
|
17687
|
+
import_node_path13 = require("node:path");
|
|
17383
17688
|
init_worker_launch_ack();
|
|
17384
17689
|
init_process_utils();
|
|
17385
17690
|
}
|
|
17386
17691
|
});
|
|
17387
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
|
+
|
|
17388
17902
|
// src/team/runtime-v2.ts
|
|
17389
17903
|
function workerInstructionStateRoot(cwd, teamName) {
|
|
17390
17904
|
return process.platform === "win32" ? teamStateRoot(cwd, teamName) : "$OMC_TEAM_STATE_ROOT";
|
|
@@ -17582,7 +18096,7 @@ async function reconcileCommittedTeamServices(config, cwd) {
|
|
|
17582
18096
|
}
|
|
17583
18097
|
}
|
|
17584
18098
|
function resolveLeaderBranch(cwd) {
|
|
17585
|
-
const out = (0,
|
|
18099
|
+
const out = (0, import_node_child_process8.execFileSync)("git", ["branch", "--show-current"], {
|
|
17586
18100
|
cwd,
|
|
17587
18101
|
encoding: "utf-8",
|
|
17588
18102
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -17624,6 +18138,14 @@ function resolveTaskAssignment(task, resolvedRouting, roleRoutingConfig, fallbac
|
|
|
17624
18138
|
role: canonical
|
|
17625
18139
|
};
|
|
17626
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
|
+
}
|
|
17627
18149
|
function sanitizeTeamName(name) {
|
|
17628
18150
|
const sanitized = name.toLowerCase().replace(/[^a-z0-9-]/g, "").slice(0, 30);
|
|
17629
18151
|
if (!sanitized) throw new Error(`Invalid team name: "${name}" produces empty slug after sanitization`);
|
|
@@ -17635,12 +18157,12 @@ function resolvePreflightBinaryPath(agentType) {
|
|
|
17635
18157
|
return { path: resolveValidatedBinaryPath(agentType) };
|
|
17636
18158
|
}
|
|
17637
18159
|
function tmuxServerIdentityForTarget(providerTarget, identity) {
|
|
17638
|
-
if (providerTarget.startsWith("cmux:")) return void 0;
|
|
18160
|
+
if (providerTarget.startsWith("cmux:") || isSdkTarget(providerTarget)) return void 0;
|
|
17639
18161
|
if (!isValidTmuxServerIdentity(identity)) return void 0;
|
|
17640
18162
|
return identity;
|
|
17641
18163
|
}
|
|
17642
18164
|
function requireTmuxServerIdentity(providerTarget, identity) {
|
|
17643
|
-
if (providerTarget.startsWith("cmux:")) return void 0;
|
|
18165
|
+
if (providerTarget.startsWith("cmux:") || isSdkTarget(providerTarget)) return void 0;
|
|
17644
18166
|
if (!isValidTmuxServerIdentity(identity)) throw new Error("tmux_server_identity_missing");
|
|
17645
18167
|
return identity;
|
|
17646
18168
|
}
|
|
@@ -17648,6 +18170,7 @@ function configuredPaneOwnership(config, worker) {
|
|
|
17648
18170
|
const paneId = worker.pane_id;
|
|
17649
18171
|
const providerTarget = config.tmux_session;
|
|
17650
18172
|
if (!paneId || !providerTarget) return null;
|
|
18173
|
+
if (isSdkTarget(paneId) || isSdkTarget(providerTarget)) return null;
|
|
17651
18174
|
const provider = paneId.startsWith("%") ? "tmux" : "cmux";
|
|
17652
18175
|
const identity = provider === "tmux" ? tmuxServerIdentityForTarget(providerTarget, config.tmux_server_identity) : void 0;
|
|
17653
18176
|
if (provider === "tmux" && !identity) return null;
|
|
@@ -17854,7 +18377,7 @@ async function waitForStartupEvidenceBudget(hasEvidence, budgetMs, delayMs = WOR
|
|
|
17854
18377
|
if (await hasEvidence()) return true;
|
|
17855
18378
|
const remainingMs = deadline - Date.now();
|
|
17856
18379
|
if (remainingMs <= 0) return false;
|
|
17857
|
-
await new Promise((
|
|
18380
|
+
await new Promise((resolve17) => setTimeout(resolve17, Math.min(delayMs, remainingMs)));
|
|
17858
18381
|
}
|
|
17859
18382
|
}
|
|
17860
18383
|
async function waitForWorkerStartupEvidence(teamName, workerName, taskId, cwd, baseline, launchAttemptId, budgetMs, delayMs = WORKER_STARTUP_EVIDENCE_POLL_INTERVAL_MS) {
|
|
@@ -18000,6 +18523,136 @@ async function readUnresolvedStartupLaunch(opts, paneId) {
|
|
|
18000
18523
|
return null;
|
|
18001
18524
|
}
|
|
18002
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
|
+
}
|
|
18003
18656
|
async function spawnV2Worker(opts) {
|
|
18004
18657
|
const splitTarget = opts.existingWorkerPaneIds.length === 0 ? opts.leaderPaneId : opts.existingWorkerPaneIds[opts.existingWorkerPaneIds.length - 1];
|
|
18005
18658
|
const splitDirection = opts.existingWorkerPaneIds.length === 0 ? "right" : "down";
|
|
@@ -18246,8 +18899,8 @@ function validateRecoveryAttemptSecret(value, input, recoveryId, replacementGene
|
|
|
18246
18899
|
async function recordRecoveryPaneRollbackFailure(input, recoveryId, pending, reason, liveness) {
|
|
18247
18900
|
const recordedAt = Date.now();
|
|
18248
18901
|
const path5 = absPath(input.cwd, TeamPaths.recoveryPaneRollbackFailure(input.teamName, recoveryId, pending.paneAttemptId, recordedAt));
|
|
18249
|
-
const candidate = `${path5}.candidate.${process.pid}.${(0,
|
|
18250
|
-
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 });
|
|
18251
18904
|
const handle = await (0, import_promises19.open)(candidate, "wx", 384);
|
|
18252
18905
|
try {
|
|
18253
18906
|
await handle.writeFile(JSON.stringify({
|
|
@@ -18276,8 +18929,8 @@ async function recordRecoveryPaneRollbackFailure(input, recoveryId, pending, rea
|
|
|
18276
18929
|
async function recordUnaddressableRecoveryPaneFailure(input, recoveryId, paneAttemptId, reason, split) {
|
|
18277
18930
|
const recordedAt = Date.now();
|
|
18278
18931
|
const path5 = absPath(input.cwd, TeamPaths.recoveryPaneRollbackFailure(input.teamName, recoveryId, paneAttemptId, recordedAt));
|
|
18279
|
-
const candidate = `${path5}.candidate.${process.pid}.${(0,
|
|
18280
|
-
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 });
|
|
18281
18934
|
const handle = await (0, import_promises19.open)(candidate, "wx", 384);
|
|
18282
18935
|
const boundedSplit = split ? {
|
|
18283
18936
|
...split,
|
|
@@ -18600,11 +19253,11 @@ async function readOrCreateRecoveryAttempt(input, recoveryId, replacementGenerat
|
|
|
18600
19253
|
recovery_id: recoveryId,
|
|
18601
19254
|
worker_name: input.workerName,
|
|
18602
19255
|
replacement_generation: replacementGeneration,
|
|
18603
|
-
adoption_token: (0,
|
|
19256
|
+
adoption_token: (0, import_node_crypto10.randomUUID)(),
|
|
18604
19257
|
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
18605
19258
|
};
|
|
18606
|
-
await (0, import_promises19.mkdir)((0,
|
|
18607
|
-
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)()}`;
|
|
18608
19261
|
const candidateHandle = await (0, import_promises19.open)(candidate, "wx", 384);
|
|
18609
19262
|
try {
|
|
18610
19263
|
await candidateHandle.writeFile(JSON.stringify(secret, null, 2), "utf8");
|
|
@@ -18623,14 +19276,14 @@ async function readOrCreateRecoveryAttempt(input, recoveryId, replacementGenerat
|
|
|
18623
19276
|
}
|
|
18624
19277
|
}
|
|
18625
19278
|
function waitForBootstrapRecoveryEvidence(delayMs, signal) {
|
|
18626
|
-
return new Promise((
|
|
19279
|
+
return new Promise((resolve17, reject) => {
|
|
18627
19280
|
if (signal?.aborted) {
|
|
18628
19281
|
reject(signal.reason ?? new Error("bootstrap_recovery_evidence_aborted"));
|
|
18629
19282
|
return;
|
|
18630
19283
|
}
|
|
18631
19284
|
const timer = setTimeout(() => {
|
|
18632
19285
|
signal?.removeEventListener("abort", onAbort);
|
|
18633
|
-
|
|
19286
|
+
resolve17();
|
|
18634
19287
|
}, delayMs);
|
|
18635
19288
|
const onAbort = () => {
|
|
18636
19289
|
clearTimeout(timer);
|
|
@@ -18673,7 +19326,7 @@ function isCanonicalBootstrapCandidate(value, expectedEpoch) {
|
|
|
18673
19326
|
const candidate = value;
|
|
18674
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;
|
|
18675
19328
|
const { payload_hash, ...unsigned } = candidate;
|
|
18676
|
-
return (0,
|
|
19329
|
+
return (0, import_node_crypto10.createHash)("sha256").update(JSON.stringify(unsigned)).digest("hex") === payload_hash;
|
|
18677
19330
|
}
|
|
18678
19331
|
async function readRecoveryOwnerBootstrapCandidate(teamName, cwd, expectedEpoch, nonce) {
|
|
18679
19332
|
try {
|
|
@@ -18730,7 +19383,7 @@ async function isExactDeadOrphanBootstrapCandidate(teamName, cwd, input, config,
|
|
|
18730
19383
|
function isExactRecoverySidecar(value, task, input, active, replacementGeneration, adoptionToken) {
|
|
18731
19384
|
const sidecar = value;
|
|
18732
19385
|
const persisted = task.recovery_reservation ?? task.recovery_adoption;
|
|
18733
|
-
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;
|
|
18734
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;
|
|
18735
19388
|
if (!sameReservation) return false;
|
|
18736
19389
|
if ("adoption_token_hash" in persisted && persisted.adoption_token_hash !== sidecar.adoption_token_hash) return false;
|
|
@@ -18934,7 +19587,7 @@ async function prepareRecoveryOwnerBootstrap(input, waitOptions) {
|
|
|
18934
19587
|
}
|
|
18935
19588
|
async function executeRecoverDeadWorkerV2Owner(input) {
|
|
18936
19589
|
const reservation = readRecoveryRequestReservation(input.cwd, input.requestId);
|
|
18937
|
-
const recoveryId = reservation?.recovery_id ?? (0,
|
|
19590
|
+
const recoveryId = reservation?.recovery_id ?? (0, import_node_crypto10.randomUUID)();
|
|
18938
19591
|
let ownerBound = false;
|
|
18939
19592
|
try {
|
|
18940
19593
|
if (!isValidTeamInstanceId(input.instanceId)) {
|
|
@@ -19414,7 +20067,7 @@ async function executeRecoverDeadWorkerV2Owner(input) {
|
|
|
19414
20067
|
} catch {
|
|
19415
20068
|
return { ok: false, error: "launch_descriptor_unresolvable" };
|
|
19416
20069
|
}
|
|
19417
|
-
const paneAttemptId = (0,
|
|
20070
|
+
const paneAttemptId = (0, import_node_crypto10.randomUUID)();
|
|
19418
20071
|
const livePaneIds = [];
|
|
19419
20072
|
for (const candidate of config.workers) {
|
|
19420
20073
|
if (!candidate.pane_id || candidate.name === sagaInput2.workerName) continue;
|
|
@@ -19607,7 +20260,7 @@ async function executeRecoverDeadWorkerV2Owner(input) {
|
|
|
19607
20260
|
launch_nonce: pending.startupContext.attempt.nonce,
|
|
19608
20261
|
written_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
19609
20262
|
};
|
|
19610
|
-
await (0, import_promises19.mkdir)((0,
|
|
20263
|
+
await (0, import_promises19.mkdir)((0, import_path38.join)(pending.gate.activatePath, ".."), { recursive: true });
|
|
19611
20264
|
await (0, import_promises19.writeFile)(pending.gate.activatePath, JSON.stringify(record), "utf8");
|
|
19612
20265
|
const adoptedReady = await waitForRecoveryGateRecord(`${pending.gate.readyPath}.adoption-ready`, record, 3e4);
|
|
19613
20266
|
return adoptedReady && await isWorkerLaunchAttemptCurrent(pending.startupContext.attempt) ? { ok: true } : { ok: false, error: "worker_activation_failed" };
|
|
@@ -19734,7 +20387,7 @@ ${recoveryContract}` : ""}`;
|
|
|
19734
20387
|
let providerLive = false;
|
|
19735
20388
|
try {
|
|
19736
20389
|
const launchedRecord = JSON.parse(await (0, import_promises19.readFile)(launchedPath, "utf8"));
|
|
19737
|
-
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(
|
|
19738
20391
|
launchedRecord.provider_pid,
|
|
19739
20392
|
launchedRecord.provider_start_identity,
|
|
19740
20393
|
Date.now() + 1e3
|
|
@@ -19813,7 +20466,7 @@ async function rollbackUnpersistedNativeWorktreeStartup(teamName, cwd, cause, in
|
|
|
19813
20466
|
const recordedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
19814
20467
|
const writeFailureMarker = async (extra = {}) => {
|
|
19815
20468
|
await (0, import_promises19.mkdir)(teamRoot, { recursive: true });
|
|
19816
|
-
await (0, import_promises19.writeFile)((0,
|
|
20469
|
+
await (0, import_promises19.writeFile)((0, import_path38.join)(teamRoot, "startup-failure.json"), JSON.stringify({
|
|
19817
20470
|
reason: "startup_failed_before_config_persisted",
|
|
19818
20471
|
error: errorMessage,
|
|
19819
20472
|
recorded_at: recordedAt,
|
|
@@ -19844,7 +20497,7 @@ async function rollbackUnpersistedNativeWorktreeStartup(teamName, cwd, cause, in
|
|
|
19844
20497
|
}
|
|
19845
20498
|
}
|
|
19846
20499
|
await (0, import_promises19.rm)(teamRoot, { recursive: true, force: true });
|
|
19847
|
-
if ((0,
|
|
20500
|
+
if ((0, import_fs34.existsSync)(teamRoot)) {
|
|
19848
20501
|
await writeFailureMarker({ rollback_error: "startup_state_removal_unverified" });
|
|
19849
20502
|
return false;
|
|
19850
20503
|
}
|
|
@@ -19868,7 +20521,7 @@ async function rollbackUnpersistedNativeWorktreeStartup(teamName, cwd, cause, in
|
|
|
19868
20521
|
async function writeStartedStartupRollbackEvidence(args) {
|
|
19869
20522
|
const teamRoot = absPath(args.cwd, TeamPaths.root(args.teamName));
|
|
19870
20523
|
await (0, import_promises19.mkdir)(teamRoot, { recursive: true });
|
|
19871
|
-
await (0, import_promises19.writeFile)((0,
|
|
20524
|
+
await (0, import_promises19.writeFile)((0, import_path38.join)(teamRoot, "startup-failure.json"), JSON.stringify({
|
|
19872
20525
|
reason: args.markerReason ?? "startup_rollback_cleanup_incomplete",
|
|
19873
20526
|
error: args.cause instanceof Error ? args.cause.message : String(args.cause),
|
|
19874
20527
|
rollback_error: args.reason,
|
|
@@ -19919,7 +20572,12 @@ async function rollbackStartedNativeWorktreeStartup(args) {
|
|
|
19919
20572
|
await writeStartedStartupRollbackEvidence({ ...args, reason: "launch_attempt_identity_unverified", worker: worker.name });
|
|
19920
20573
|
throw new Error(`worker_cleanup_incomplete:${worker.name}:launch_attempt_identity_unverified`);
|
|
19921
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
|
+
}
|
|
19922
20579
|
const cleaned = await retireAndCleanupCurrentWorkerLaunchAttempt(attempt, "startup_rollback", async () => {
|
|
20580
|
+
if (isSdkTarget(worker.paneId)) return true;
|
|
19923
20581
|
const ownership = {
|
|
19924
20582
|
provider: worker.paneId.startsWith("%") ? "tmux" : "cmux",
|
|
19925
20583
|
providerTarget: args.sessionName,
|
|
@@ -19941,7 +20599,7 @@ async function rollbackStartedNativeWorktreeStartup(args) {
|
|
|
19941
20599
|
throw new Error(`worker_cleanup_incomplete:${worker.name}:provider_cleanup_unverified`);
|
|
19942
20600
|
}
|
|
19943
20601
|
}
|
|
19944
|
-
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)) {
|
|
19945
20603
|
const sessionCleaned = await killTeamSession(
|
|
19946
20604
|
args.sessionName,
|
|
19947
20605
|
args.workerPaneIds,
|
|
@@ -20047,12 +20705,17 @@ async function startTeamV2(config) {
|
|
|
20047
20705
|
}
|
|
20048
20706
|
const instance = createTeamInstanceBinding({
|
|
20049
20707
|
teamName: sanitized,
|
|
20050
|
-
cwd: (0,
|
|
20708
|
+
cwd: (0, import_path38.resolve)(config.cwd),
|
|
20051
20709
|
...config.instanceId !== void 0 ? { instanceId: config.instanceId } : {}
|
|
20052
20710
|
});
|
|
20053
20711
|
const leaderCwd = instance.cwd;
|
|
20054
20712
|
const pluginCfg = config.pluginConfig ?? loadConfig();
|
|
20055
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");
|
|
20056
20719
|
let worktreeMode = normalizeTeamWorktreeMode(
|
|
20057
20720
|
process.env.OMC_TEAM_WORKTREE_MODE ?? pluginCfg.team?.ops?.worktreeMode
|
|
20058
20721
|
);
|
|
@@ -20118,21 +20781,33 @@ async function startTeamV2(config) {
|
|
|
20118
20781
|
const workerName = workerNames[i];
|
|
20119
20782
|
const taskIndex = startupByWorker.get(workerName);
|
|
20120
20783
|
const fallbackAgent = agentTypes[i % agentTypes.length] ?? agentTypes[0] ?? "claude";
|
|
20121
|
-
const
|
|
20122
|
-
|
|
20123
|
-
|
|
20124
|
-
|
|
20125
|
-
|
|
20126
|
-
|
|
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
|
+
}
|
|
20127
20793
|
const assignment = {
|
|
20128
20794
|
agentType: resolvedAssignment.agentType,
|
|
20129
20795
|
model: resolvedAssignment.model || resolveDefaultModel(resolvedAssignment.agentType),
|
|
20130
20796
|
reasoningEffort: resolvedAssignment.reasoningEffort,
|
|
20131
|
-
...
|
|
20797
|
+
...role ? { role } : {}
|
|
20132
20798
|
};
|
|
20133
20799
|
startupAssignments.set(workerName, assignment);
|
|
20134
20800
|
effectiveAgentTypes.add(assignment.agentType);
|
|
20135
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
|
+
}
|
|
20136
20811
|
for (const agentType of effectiveAgentTypes) {
|
|
20137
20812
|
try {
|
|
20138
20813
|
resolvedBinaryPaths[agentType] = resolvePreflightBinaryPath(agentType).path;
|
|
@@ -20172,7 +20847,7 @@ async function startTeamV2(config) {
|
|
|
20172
20847
|
try {
|
|
20173
20848
|
const pendingConfig = buildTeamInstancePendingConfig(instance);
|
|
20174
20849
|
const pendingConfigPath = absPath(leaderCwd, TeamPaths.config(sanitized));
|
|
20175
|
-
await (0, import_promises19.mkdir)((0,
|
|
20850
|
+
await (0, import_promises19.mkdir)((0, import_path38.join)(pendingConfigPath, ".."), { recursive: true });
|
|
20176
20851
|
await (0, import_promises19.writeFile)(pendingConfigPath, JSON.stringify(pendingConfig, null, 2), "utf-8");
|
|
20177
20852
|
} catch (error) {
|
|
20178
20853
|
if (!await rollbackBeforeConfig(error)) throw startupCleanupIncompleteError(error);
|
|
@@ -20183,7 +20858,7 @@ async function startTeamV2(config) {
|
|
|
20183
20858
|
try {
|
|
20184
20859
|
await (0, import_promises19.mkdir)(absPath(leaderCwd, TeamPaths.tasks(sanitized)), { recursive: true });
|
|
20185
20860
|
await (0, import_promises19.mkdir)(absPath(leaderCwd, TeamPaths.workers(sanitized)), { recursive: true });
|
|
20186
|
-
await (0, import_promises19.mkdir)((0,
|
|
20861
|
+
await (0, import_promises19.mkdir)((0, import_path38.join)(getOmcRoot(leaderCwd), "state", "team", sanitized, "mailbox"), { recursive: true });
|
|
20187
20862
|
for (let i = 0; i < config.tasks.length; i++) {
|
|
20188
20863
|
const taskId = String(i + 1);
|
|
20189
20864
|
const task = config.tasks[i];
|
|
@@ -20220,7 +20895,7 @@ async function startTeamV2(config) {
|
|
|
20220
20895
|
const assignment = startupAssignments.get(workerName);
|
|
20221
20896
|
if (!assignment) throw new Error(`Missing startup assignment for ${workerName}`);
|
|
20222
20897
|
const worktree = workerWorktrees.get(workerName);
|
|
20223
|
-
const verdictAssignmentId = taskIndex !== void 0 ? (0,
|
|
20898
|
+
const verdictAssignmentId = taskIndex !== void 0 ? (0, import_node_crypto10.randomUUID)() : void 0;
|
|
20224
20899
|
const outputFile = taskIndex !== void 0 && assignment.role && shouldInjectContract(assignment.role, assignment.agentType) ? cliWorkerOutputFilePath(teamStateRoot(leaderCwd, sanitized), workerName, {
|
|
20225
20900
|
taskId: String(taskIndex + 1),
|
|
20226
20901
|
assignmentId: verdictAssignmentId
|
|
@@ -20257,7 +20932,8 @@ async function startTeamV2(config) {
|
|
|
20257
20932
|
if (!await rollbackBeforeConfig(error)) throw startupCleanupIncompleteError(error);
|
|
20258
20933
|
throw error;
|
|
20259
20934
|
}
|
|
20260
|
-
|
|
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) {
|
|
20261
20937
|
process.stderr.write(`${line}
|
|
20262
20938
|
`);
|
|
20263
20939
|
}
|
|
@@ -20294,7 +20970,7 @@ async function startTeamV2(config) {
|
|
|
20294
20970
|
}
|
|
20295
20971
|
let session;
|
|
20296
20972
|
try {
|
|
20297
|
-
session = await createTeamSession(sanitized, 0, leaderCwd, {
|
|
20973
|
+
session = sdkMode ? { sessionName: sdkTeamTarget(sanitized), leaderPaneId: "", workerPaneIds: [], sessionMode: "split-pane" } : await createTeamSession(sanitized, 0, leaderCwd, {
|
|
20298
20974
|
newWindow: Boolean(config.newWindow)
|
|
20299
20975
|
});
|
|
20300
20976
|
} catch (error) {
|
|
@@ -20314,6 +20990,7 @@ async function startTeamV2(config) {
|
|
|
20314
20990
|
role: preparedLaunches.get(wName)?.role ?? config.workerRoles?.[i] ?? (agentTypes[i % agentTypes.length] ?? agentTypes[0] ?? "claude"),
|
|
20315
20991
|
worker_cli: preparedLaunches.get(wName).descriptor.provider,
|
|
20316
20992
|
launch_descriptor: preparedLaunches.get(wName).descriptor,
|
|
20993
|
+
...sdkMode ? { transport: "sdk" } : {},
|
|
20317
20994
|
assigned_tasks: [],
|
|
20318
20995
|
working_dir: worktree?.path ?? leaderCwd,
|
|
20319
20996
|
team_state_root: teamStateRoot(leaderCwd, sanitized),
|
|
@@ -20359,7 +21036,7 @@ async function startTeamV2(config) {
|
|
|
20359
21036
|
service_descriptor: config.autoMerge ? {
|
|
20360
21037
|
schema_version: 1,
|
|
20361
21038
|
service_generation: 1,
|
|
20362
|
-
service_attempt_id: (0,
|
|
21039
|
+
service_attempt_id: (0, import_node_crypto10.randomUUID)(),
|
|
20363
21040
|
auto_merge_enabled: true,
|
|
20364
21041
|
workspace_root: leaderCwd,
|
|
20365
21042
|
leader_branch: autoMergeLeaderBranch,
|
|
@@ -20367,7 +21044,7 @@ async function startTeamV2(config) {
|
|
|
20367
21044
|
} : {
|
|
20368
21045
|
schema_version: 1,
|
|
20369
21046
|
service_generation: 1,
|
|
20370
|
-
service_attempt_id: (0,
|
|
21047
|
+
service_attempt_id: (0, import_node_crypto10.randomUUID)(),
|
|
20371
21048
|
auto_merge_enabled: false,
|
|
20372
21049
|
workspace_root: leaderCwd,
|
|
20373
21050
|
cadence_policy: "disabled"
|
|
@@ -20455,7 +21132,7 @@ async function startTeamV2(config) {
|
|
|
20455
21132
|
if (!prepared) continue;
|
|
20456
21133
|
const workerInfo = workersInfo[workerIndex];
|
|
20457
21134
|
if (!workerInfo) continue;
|
|
20458
|
-
const
|
|
21135
|
+
const spawnOptions = {
|
|
20459
21136
|
sessionName: sessionName2,
|
|
20460
21137
|
...session.tmuxServerIdentity ? { tmuxServerIdentity: session.tmuxServerIdentity } : {},
|
|
20461
21138
|
leaderPaneId,
|
|
@@ -20474,7 +21151,8 @@ async function startTeamV2(config) {
|
|
|
20474
21151
|
autoMerge: Boolean(config.autoMerge),
|
|
20475
21152
|
...prepared.role ? { role: prepared.role } : {},
|
|
20476
21153
|
...prepared.verdictAssignmentId ? { verdictAssignmentId: prepared.verdictAssignmentId } : {}
|
|
20477
|
-
}
|
|
21154
|
+
};
|
|
21155
|
+
const workerLaunch = sdkSettings ? await spawnSdkV2Worker(spawnOptions, sdkSettings) : await spawnV2Worker(spawnOptions);
|
|
20478
21156
|
if (workerLaunch.paneId) {
|
|
20479
21157
|
if (workerLaunch.startupAssigned) workerPaneIds.push(workerLaunch.paneId);
|
|
20480
21158
|
launchedWorkers.push({
|
|
@@ -20649,7 +21327,7 @@ function nonCursorVerdictFileIdentity(stats) {
|
|
|
20649
21327
|
].join("-");
|
|
20650
21328
|
}
|
|
20651
21329
|
function fingerprintCliWorkerVerdictArtifact(raw, stats) {
|
|
20652
|
-
const contentSha256 = (0,
|
|
21330
|
+
const contentSha256 = (0, import_node_crypto10.createHash)("sha256").update(raw, "utf8").digest("hex");
|
|
20653
21331
|
return `${contentSha256}-${nonCursorVerdictFileIdentity(stats)}`;
|
|
20654
21332
|
}
|
|
20655
21333
|
async function readNonCursorVerdictArtifact(outputFile) {
|
|
@@ -20711,7 +21389,7 @@ async function processCliWorkerVerdictsUnderLock(teamName, cwd, expectedInstance
|
|
|
20711
21389
|
"team.runtime-v2.processCliWorkerVerdicts teamMarkTaskCompleted failed"
|
|
20712
21390
|
);
|
|
20713
21391
|
const { rename: rename8 } = await import("fs/promises");
|
|
20714
|
-
const { renameSync: renameSync5, readFileSync:
|
|
21392
|
+
const { renameSync: renameSync5, readFileSync: readFileSync24, existsSync: fsExistsSync } = await import("fs");
|
|
20715
21393
|
const { withFileLockSync: withFileLockSync2 } = await Promise.resolve().then(() => (init_file_lock(), file_lock_exports));
|
|
20716
21394
|
const quarantineNonCursorVerdict = async (outputFile, artifactFingerprint, workerName, taskId, taskVersion, reason) => {
|
|
20717
21395
|
const stalePath = nonCursorVerdictStalePath(outputFile, artifactFingerprint);
|
|
@@ -20744,7 +21422,7 @@ async function processCliWorkerVerdictsUnderLock(teamName, cwd, expectedInstance
|
|
|
20744
21422
|
const outputFile = worker.output_file;
|
|
20745
21423
|
if (!outputFile) continue;
|
|
20746
21424
|
const paneOwnership = configuredPaneOwnership(config, worker);
|
|
20747
|
-
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";
|
|
20748
21426
|
const workerRole = normalizeDelegationRole(worker.role);
|
|
20749
21427
|
const cursorReviewer = worker.worker_cli === "cursor" && CONTRACT_ROLES.has(workerRole);
|
|
20750
21428
|
const liveCursorReviewer = liveness === "alive" && worker.worker_cli === "cursor" && CONTRACT_ROLES.has(workerRole);
|
|
@@ -20792,7 +21470,7 @@ async function processCliWorkerVerdictsUnderLock(teamName, cwd, expectedInstance
|
|
|
20792
21470
|
return;
|
|
20793
21471
|
}
|
|
20794
21472
|
}
|
|
20795
|
-
const raw =
|
|
21473
|
+
const raw = readFileSync24(outputFile, "utf-8");
|
|
20796
21474
|
parseCliWorkerVerdict(raw);
|
|
20797
21475
|
renameSync5(outputFile, processingOutputFile);
|
|
20798
21476
|
verdictFile = processingOutputFile;
|
|
@@ -20956,7 +21634,7 @@ async function processCliWorkerVerdictsUnderLock(teamName, cwd, expectedInstance
|
|
|
20956
21634
|
if (cursorReviewer && verdictFile === processingOutputFile) {
|
|
20957
21635
|
const processedTaskPath = absPath(cwd, TeamPaths.taskFile(sanitized, payload.task_id));
|
|
20958
21636
|
try {
|
|
20959
|
-
const processedTask = JSON.parse(
|
|
21637
|
+
const processedTask = JSON.parse(readFileSync24(processedTaskPath, "utf-8"));
|
|
20960
21638
|
const metadata = processedTask.metadata && typeof processedTask.metadata === "object" ? processedTask.metadata : void 0;
|
|
20961
21639
|
const processedTaskRole = typeof processedTask.role === "string" ? normalizeDelegationRole(processedTask.role) : null;
|
|
20962
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;
|
|
@@ -21298,20 +21976,28 @@ async function monitorTeamV2(teamName, cwd, expectedInstanceId) {
|
|
|
21298
21976
|
const workerScanStartMs = import_perf_hooks.performance.now();
|
|
21299
21977
|
const workerSignals = await Promise.all(
|
|
21300
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
|
+
}
|
|
21301
21988
|
const ownership = configuredPaneOwnership(config, worker);
|
|
21302
21989
|
const liveness = ownership ? await getOwnedWorkerLiveness(ownership) : "unknown";
|
|
21303
|
-
const providerLiveness = await getWorkerProviderLiveness(sanitized, cwd, config.instance_id, worker);
|
|
21304
21990
|
const paneAlive = liveness === "alive";
|
|
21305
21991
|
const [status, heartbeat, paneCapture] = await Promise.all([
|
|
21306
21992
|
readWorkerStatus(sanitized, worker.name, cwd),
|
|
21307
21993
|
readWorkerHeartbeat(sanitized, worker.name, cwd),
|
|
21308
21994
|
paneAlive && ownership ? captureOwnedTeamPane(ownership) : Promise.resolve("")
|
|
21309
21995
|
]);
|
|
21310
|
-
return { worker, alive: paneAlive, liveness, providerLiveness, status, heartbeat, paneCapture };
|
|
21996
|
+
return { worker, alive: paneAlive, liveness, providerLiveness, status, heartbeat, paneCapture, sdkSession: null };
|
|
21311
21997
|
})
|
|
21312
21998
|
);
|
|
21313
21999
|
const workerScanMs = import_perf_hooks.performance.now() - workerScanStartMs;
|
|
21314
|
-
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) {
|
|
21315
22001
|
const currentTask = status.current_task_id ? taskById.get(status.current_task_id) ?? null : null;
|
|
21316
22002
|
const outstandingTask = currentTask ?? findOutstandingWorkerTask(w, taskById, inProgressByOwner);
|
|
21317
22003
|
const expectedTaskId = status.current_task_id ?? outstandingTask?.id ?? w.assigned_tasks[0] ?? "";
|
|
@@ -21334,7 +22020,19 @@ async function monitorTeamV2(teamName, cwd, expectedInstanceId) {
|
|
|
21334
22020
|
worktree_detached: w.worktree_detached,
|
|
21335
22021
|
worktree_created: w.worktree_created,
|
|
21336
22022
|
team_state_root: w.team_state_root,
|
|
21337
|
-
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
|
+
} } : {}
|
|
21338
22036
|
});
|
|
21339
22037
|
if (providerLiveness === "dead") {
|
|
21340
22038
|
deadWorkers.push(w.name);
|
|
@@ -21343,13 +22041,16 @@ async function monitorTeamV2(teamName, cwd, expectedInstanceId) {
|
|
|
21343
22041
|
recommendations.push(`Reassign task-${t.id} from dead ${w.name}`);
|
|
21344
22042
|
}
|
|
21345
22043
|
}
|
|
21346
|
-
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);
|
|
21347
22046
|
const statusFresh = isFreshTimestamp(status.updated_at);
|
|
21348
22047
|
const heartbeatFresh = isFreshTimestamp(heartbeat?.last_turn_at);
|
|
21349
22048
|
const hasWorkStartEvidence = expectedTaskId !== "" && hasWorkerStatusProgress(status, expectedTaskId);
|
|
21350
22049
|
const missingDependencyIds = outstandingTask ? getMissingDependencyIds(outstandingTask, taskById) : [];
|
|
21351
22050
|
let stallReason = null;
|
|
21352
|
-
if (
|
|
22051
|
+
if (sdkCapped) {
|
|
22052
|
+
stallReason = "sdk_credit_cap";
|
|
22053
|
+
} else if (paneSuggestsIdle && missingDependencyIds.length > 0) {
|
|
21353
22054
|
stallReason = "missing_dependency";
|
|
21354
22055
|
} else if (paneSuggestsIdle && expectedTaskId !== "" && !hasWorkStartEvidence) {
|
|
21355
22056
|
stallReason = "no_work_start_evidence";
|
|
@@ -21360,7 +22061,15 @@ async function monitorTeamV2(teamName, cwd, expectedInstanceId) {
|
|
|
21360
22061
|
}
|
|
21361
22062
|
if (stallReason) {
|
|
21362
22063
|
nonReportingWorkers.push(w.name);
|
|
21363
|
-
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") {
|
|
21364
22073
|
recommendations.push(
|
|
21365
22074
|
`Investigate ${w.name}: task-${outstandingTask?.id ?? expectedTaskId} is blocked by missing task ids [${missingDependencyIds.join(", ")}]; pane is idle at prompt`
|
|
21366
22075
|
);
|
|
@@ -21454,7 +22163,7 @@ async function cleanupStaleReservations(teamName, cwd) {
|
|
|
21454
22163
|
cwd,
|
|
21455
22164
|
TeamPaths.teamInstanceReservation(workspaceHash, sanitized)
|
|
21456
22165
|
);
|
|
21457
|
-
if (!(0,
|
|
22166
|
+
if (!(0, import_fs34.existsSync)(reservationPath2)) return;
|
|
21458
22167
|
const contentStr = await (0, import_promises19.readFile)(reservationPath2, "utf-8");
|
|
21459
22168
|
const reservation = JSON.parse(contentStr);
|
|
21460
22169
|
if (!(reservation && typeof reservation === "object" && !Array.isArray(reservation) && "owner" in reservation && typeof reservation.owner === "object")) {
|
|
@@ -21464,6 +22173,7 @@ async function cleanupStaleReservations(teamName, cwd) {
|
|
|
21464
22173
|
if (!(owner && typeof owner === "object" && !Array.isArray(owner) && "pid" in owner && "process_started_at" in owner)) {
|
|
21465
22174
|
return;
|
|
21466
22175
|
}
|
|
22176
|
+
if (reservation.phase === "active") return;
|
|
21467
22177
|
const ownerRecord = owner;
|
|
21468
22178
|
if (isProcessIdentityDead(ownerRecord)) {
|
|
21469
22179
|
await (0, import_promises19.unlink)(reservationPath2);
|
|
@@ -21556,7 +22266,7 @@ async function shutdownTeamV2(teamName, cwd, options = {}) {
|
|
|
21556
22266
|
});
|
|
21557
22267
|
instance = boundInstance;
|
|
21558
22268
|
await assertTeamInstanceUnderLock(boundInstance);
|
|
21559
|
-
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)) {
|
|
21560
22270
|
throw new Error("tmux_server_identity_missing");
|
|
21561
22271
|
}
|
|
21562
22272
|
if (current.config.active_recovery) throw new Error(`shutdown_blocked:active_recovery:${current.config.active_recovery.recovery_id}`);
|
|
@@ -21587,7 +22297,7 @@ async function shutdownTeamV2(teamName, cwd, options = {}) {
|
|
|
21587
22297
|
}
|
|
21588
22298
|
const processStartedAt = currentProcessStartIdentity();
|
|
21589
22299
|
if (!processStartedAt) throw new Error("process_start_identity_unavailable");
|
|
21590
|
-
ownedShutdownNonce = (0,
|
|
22300
|
+
ownedShutdownNonce = (0, import_node_crypto10.randomUUID)();
|
|
21591
22301
|
const nextRevision = current.stateRevision + 1;
|
|
21592
22302
|
const next = {
|
|
21593
22303
|
...current.config,
|
|
@@ -21695,7 +22405,7 @@ async function shutdownTeamV2(teamName, cwd, options = {}) {
|
|
|
21695
22405
|
};
|
|
21696
22406
|
if (!config) {
|
|
21697
22407
|
const cleanupSafety = inspectTeamWorktreeCleanupSafety(sanitized, cwd);
|
|
21698
|
-
if (cleanupSafety.hasEvidence || (0,
|
|
22408
|
+
if (cleanupSafety.hasEvidence || (0, import_fs34.existsSync)(absPath(cwd, TeamPaths.root(sanitized)))) {
|
|
21699
22409
|
process.stderr.write("[team/runtime-v2] preserving team state because config is missing and worktree cleanup evidence remains\n");
|
|
21700
22410
|
return { outcome: "preserved", reason: "config_missing_cleanup_evidence", workers: [] };
|
|
21701
22411
|
}
|
|
@@ -21727,6 +22437,7 @@ Format: {"status":"accept","reason":"ok","updated_at":"<iso>"}
|
|
|
21727
22437
|
Then exit your session.
|
|
21728
22438
|
`;
|
|
21729
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" });
|
|
21730
22441
|
} catch (err) {
|
|
21731
22442
|
process.stderr.write(`[team/runtime-v2] shutdown request failed for ${w.name}: ${err}
|
|
21732
22443
|
`);
|
|
@@ -21767,6 +22478,30 @@ Then exit your session.
|
|
|
21767
22478
|
const providerCleanupFailures = [];
|
|
21768
22479
|
const paneCleanupAlive = [];
|
|
21769
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
|
+
}
|
|
21770
22505
|
for (const worker of config.workers) {
|
|
21771
22506
|
if (!worker.pane_id) {
|
|
21772
22507
|
providerCleanupFailures.push(worker.name);
|
|
@@ -21781,6 +22516,10 @@ Then exit your session.
|
|
|
21781
22516
|
providerCleanupFailures.push(worker.name);
|
|
21782
22517
|
continue;
|
|
21783
22518
|
}
|
|
22519
|
+
if (isSdkTarget(worker.pane_id)) {
|
|
22520
|
+
if (!await (sdkStops.get(worker.name) ?? Promise.resolve(false))) providerCleanupFailures.push(worker.name);
|
|
22521
|
+
continue;
|
|
22522
|
+
}
|
|
21784
22523
|
const initialOwnership = configuredPaneOwnership(config, worker);
|
|
21785
22524
|
const initialPaneLiveness = initialOwnership ? await getOwnedWorkerLiveness(initialOwnership) : "unknown";
|
|
21786
22525
|
let paneOwnership = null;
|
|
@@ -21849,9 +22588,9 @@ Then exit your session.
|
|
|
21849
22588
|
killTeamSession: killOwnedTeamSession
|
|
21850
22589
|
} = await Promise.resolve().then(() => (init_tmux_session(), tmux_session_exports));
|
|
21851
22590
|
const ownsWindow = config.tmux_window_owned === true;
|
|
21852
|
-
const workerPaneIds = recordedWorkerPaneIds;
|
|
22591
|
+
const workerPaneIds = recordedWorkerPaneIds.filter((paneId) => !isSdkTarget(paneId));
|
|
21853
22592
|
const splitPaneMode = Boolean(config.tmux_session && !ownsWindow && config.tmux_session.includes(":"));
|
|
21854
|
-
if (!splitPaneMode && config.tmux_session) {
|
|
22593
|
+
if (!splitPaneMode && config.tmux_session && !isSdkTarget(config.tmux_session)) {
|
|
21855
22594
|
if (!config.leader_pane_id) {
|
|
21856
22595
|
if (!await rollbackShutdownForRetry()) await finalizeAutoMerge();
|
|
21857
22596
|
return { outcome: "preserved", reason: "provider_cleanup_unverified", workers: ["leader-fixed"] };
|
|
@@ -21972,12 +22711,12 @@ Then exit your session.
|
|
|
21972
22711
|
return { outcome: "cleaned" };
|
|
21973
22712
|
});
|
|
21974
22713
|
}
|
|
21975
|
-
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;
|
|
21976
22715
|
var init_runtime_v2 = __esm({
|
|
21977
22716
|
"src/team/runtime-v2.ts"() {
|
|
21978
22717
|
"use strict";
|
|
21979
|
-
|
|
21980
|
-
|
|
22718
|
+
import_path38 = require("path");
|
|
22719
|
+
import_fs34 = require("fs");
|
|
21981
22720
|
import_promises19 = require("fs/promises");
|
|
21982
22721
|
import_perf_hooks = require("perf_hooks");
|
|
21983
22722
|
init_state_paths();
|
|
@@ -22006,10 +22745,10 @@ var init_runtime_v2 = __esm({
|
|
|
22006
22745
|
init_cli_worker_contract();
|
|
22007
22746
|
init_merge_orchestrator();
|
|
22008
22747
|
init_leader_inbox();
|
|
22009
|
-
|
|
22748
|
+
import_node_child_process8 = require("node:child_process");
|
|
22010
22749
|
init_runtime_flags();
|
|
22011
22750
|
init_worker_commit_cadence();
|
|
22012
|
-
|
|
22751
|
+
import_node_crypto10 = require("node:crypto");
|
|
22013
22752
|
init_recovery_request_store();
|
|
22014
22753
|
init_runtime_owner_client();
|
|
22015
22754
|
init_scaling();
|
|
@@ -22021,6 +22760,11 @@ var init_runtime_v2 = __esm({
|
|
|
22021
22760
|
init_team_owner_epoch();
|
|
22022
22761
|
init_worker_activation_gate();
|
|
22023
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();
|
|
22024
22768
|
init_process_utils();
|
|
22025
22769
|
init_team_instance();
|
|
22026
22770
|
init_runtime_flags();
|
|
@@ -22126,10 +22870,10 @@ __export(runtime_cli_exports, {
|
|
|
22126
22870
|
writeResultArtifact: () => writeResultArtifact
|
|
22127
22871
|
});
|
|
22128
22872
|
module.exports = __toCommonJS(runtime_cli_exports);
|
|
22129
|
-
var
|
|
22130
|
-
var
|
|
22873
|
+
var import_node_crypto11 = require("node:crypto");
|
|
22874
|
+
var import_fs35 = require("fs");
|
|
22131
22875
|
var import_promises20 = require("fs/promises");
|
|
22132
|
-
var
|
|
22876
|
+
var import_path39 = require("path");
|
|
22133
22877
|
init_events();
|
|
22134
22878
|
|
|
22135
22879
|
// src/team/leader-nudge-guidance.ts
|
|
@@ -22672,7 +23416,7 @@ async function waitForSentinelReadiness(options = {}) {
|
|
|
22672
23416
|
}
|
|
22673
23417
|
const deadline = startedAt + timeoutMs;
|
|
22674
23418
|
while (Date.now() < deadline) {
|
|
22675
|
-
await new Promise((
|
|
23419
|
+
await new Promise((resolve17) => setTimeout(resolve17, pollIntervalMs));
|
|
22676
23420
|
attempts += 1;
|
|
22677
23421
|
latest = checkSentinelReadiness(options);
|
|
22678
23422
|
if (latest.ready) {
|
|
@@ -22762,10 +23506,10 @@ function areAllAuthoritativeWorkersDead(refresh, workers) {
|
|
|
22762
23506
|
return classifyAllDeadRecoveryEvidence(refresh, workers, true) === "all_dead";
|
|
22763
23507
|
}
|
|
22764
23508
|
function validateCanonicalRecoveryIntent(teamName, cwd, pathRecoveryId, path5) {
|
|
22765
|
-
const intent = parseRecoveryIntent((0,
|
|
23509
|
+
const intent = parseRecoveryIntent((0, import_fs35.readFileSync)(path5, "utf8"));
|
|
22766
23510
|
if (intent.team_name !== teamName || intent.recovery_id !== pathRecoveryId) throw new Error("invalid_persisted_state");
|
|
22767
23511
|
const reservation = readRecoveryRequestReservation(cwd, intent.request_id);
|
|
22768
|
-
const workspaceHash = (0,
|
|
23512
|
+
const workspaceHash = (0, import_node_crypto11.createHash)("sha256").update(cwd).digest("hex");
|
|
22769
23513
|
const expectedPayloadHash = canonicalRecoveryPayloadHash({
|
|
22770
23514
|
operation: "recover-worker",
|
|
22771
23515
|
workspaceHash,
|
|
@@ -22797,14 +23541,14 @@ async function processPendingRecoveryIntents(teamName, cwd, execute = handleReco
|
|
|
22797
23541
|
const root = absPath(cwd, TeamPaths.recoveryIntents(teamName));
|
|
22798
23542
|
let names;
|
|
22799
23543
|
try {
|
|
22800
|
-
names = (0,
|
|
23544
|
+
names = (0, import_fs35.readdirSync)(root).filter((name) => name.endsWith(".json")).sort();
|
|
22801
23545
|
} catch {
|
|
22802
23546
|
return;
|
|
22803
23547
|
}
|
|
22804
23548
|
for (const name of names) {
|
|
22805
|
-
const path5 = (0,
|
|
23549
|
+
const path5 = (0, import_path39.join)(root, name);
|
|
22806
23550
|
try {
|
|
22807
|
-
const pathRecoveryId = (0,
|
|
23551
|
+
const pathRecoveryId = (0, import_path39.basename)(name, ".json");
|
|
22808
23552
|
const intent = validateCanonicalRecoveryIntent(teamName, cwd, pathRecoveryId, path5);
|
|
22809
23553
|
if (intent.instance_id.toLowerCase() !== normalizedExpectedInstanceId) continue;
|
|
22810
23554
|
if (!await assertRuntimeInstance(teamName, cwd, normalizedExpectedInstanceId)) continue;
|
|
@@ -22874,17 +23618,17 @@ async function updateAllDeadRecoveryGrace(teamName, cwd, evidence, nowMs = Date.
|
|
|
22874
23618
|
}
|
|
22875
23619
|
function canonicalRecoveryIntentEntryId(name, path5) {
|
|
22876
23620
|
if (!name.endsWith(".json")) return null;
|
|
22877
|
-
const recoveryId = (0,
|
|
23621
|
+
const recoveryId = (0, import_path39.basename)(name, ".json");
|
|
22878
23622
|
if (name !== `${recoveryId}.json` || !isSafeRecoveryRequestId(recoveryId)) return null;
|
|
22879
23623
|
try {
|
|
22880
|
-
return (0,
|
|
23624
|
+
return (0, import_fs35.lstatSync)(path5).isFile() ? recoveryId : null;
|
|
22881
23625
|
} catch {
|
|
22882
23626
|
return null;
|
|
22883
23627
|
}
|
|
22884
23628
|
}
|
|
22885
23629
|
function hasVerifiedTerminalRepairForMalformedIntent(teamName, cwd, recoveryId, path5) {
|
|
22886
23630
|
try {
|
|
22887
|
-
const raw = JSON.parse((0,
|
|
23631
|
+
const raw = JSON.parse((0, import_fs35.readFileSync)(path5, "utf8"));
|
|
22888
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;
|
|
22889
23633
|
const final = readRecoveryFinalState(cwd, raw.request_id);
|
|
22890
23634
|
return final.kind === "valid" && final.final.recovery_id === recoveryId && final.final.team_name === teamName && final.final.worker_name === raw.worker_name;
|
|
@@ -22894,7 +23638,7 @@ function hasVerifiedTerminalRepairForMalformedIntent(teamName, cwd, recoveryId,
|
|
|
22894
23638
|
}
|
|
22895
23639
|
function malformedIntentMayPredateDeadline(path5, deadlineAt) {
|
|
22896
23640
|
try {
|
|
22897
|
-
const metadata = (0,
|
|
23641
|
+
const metadata = (0, import_fs35.lstatSync)(path5);
|
|
22898
23642
|
if (Number.isFinite(metadata.mtimeMs) && metadata.mtimeMs <= deadlineAt) return true;
|
|
22899
23643
|
if (Number.isFinite(metadata.birthtimeMs) && metadata.birthtimeMs > 0) {
|
|
22900
23644
|
return metadata.birthtimeMs <= deadlineAt;
|
|
@@ -22909,14 +23653,14 @@ function canonicalRecoveryAdmissionEntryId(name, path5) {
|
|
|
22909
23653
|
const requestId = name.slice(0, -".pending.json".length);
|
|
22910
23654
|
if (name !== `${requestId}.pending.json` || !isSafeRecoveryRequestId(requestId)) return null;
|
|
22911
23655
|
try {
|
|
22912
|
-
return (0,
|
|
23656
|
+
return (0, import_fs35.lstatSync)(path5).isFile() ? requestId : null;
|
|
22913
23657
|
} catch {
|
|
22914
23658
|
return null;
|
|
22915
23659
|
}
|
|
22916
23660
|
}
|
|
22917
23661
|
function malformedAdmissionMayPredateDeadline(path5, deadlineAt) {
|
|
22918
23662
|
try {
|
|
22919
|
-
const metadata = (0,
|
|
23663
|
+
const metadata = (0, import_fs35.lstatSync)(path5);
|
|
22920
23664
|
if (!metadata.isFile()) return true;
|
|
22921
23665
|
if (Number.isFinite(metadata.mtimeMs) && metadata.mtimeMs <= deadlineAt) return true;
|
|
22922
23666
|
if (Number.isFinite(metadata.birthtimeMs) && metadata.birthtimeMs > 0) {
|
|
@@ -22933,12 +23677,12 @@ function hasPendingRecoveryIntentBeforeDeadline(teamName, cwd, deadlineAt, expec
|
|
|
22933
23677
|
const root = absPath(cwd, TeamPaths.recoveryIntents(teamName));
|
|
22934
23678
|
let names;
|
|
22935
23679
|
try {
|
|
22936
|
-
names = (0,
|
|
23680
|
+
names = (0, import_fs35.readdirSync)(root).filter((name) => name.endsWith(".json"));
|
|
22937
23681
|
} catch {
|
|
22938
23682
|
return false;
|
|
22939
23683
|
}
|
|
22940
23684
|
for (const name of names) {
|
|
22941
|
-
const path5 = (0,
|
|
23685
|
+
const path5 = (0, import_path39.join)(root, name);
|
|
22942
23686
|
const recoveryId = canonicalRecoveryIntentEntryId(name, path5);
|
|
22943
23687
|
if (!recoveryId) continue;
|
|
22944
23688
|
try {
|
|
@@ -22956,16 +23700,16 @@ function hasPendingRecoveryIntentBeforeDeadline(teamName, cwd, deadlineAt, expec
|
|
|
22956
23700
|
function hasPendingRecoveryAdmissionBeforeDeadline(teamName, cwd, deadlineAt, expectedInstanceId) {
|
|
22957
23701
|
const normalizedExpectedInstanceId = normalizeRuntimeInstanceId(expectedInstanceId);
|
|
22958
23702
|
if (!normalizedExpectedInstanceId) return true;
|
|
22959
|
-
const workspaceHash = (0,
|
|
23703
|
+
const workspaceHash = (0, import_node_crypto11.createHash)("sha256").update(cwd).digest("hex");
|
|
22960
23704
|
const root = absPath(cwd, TeamPaths.recoveryRequestsRoot());
|
|
22961
23705
|
let names;
|
|
22962
23706
|
try {
|
|
22963
|
-
names = (0,
|
|
23707
|
+
names = (0, import_fs35.readdirSync)(root).filter((name) => name.endsWith(".pending.json"));
|
|
22964
23708
|
} catch {
|
|
22965
23709
|
return false;
|
|
22966
23710
|
}
|
|
22967
23711
|
for (const name of names) {
|
|
22968
|
-
const path5 = (0,
|
|
23712
|
+
const path5 = (0, import_path39.join)(root, name);
|
|
22969
23713
|
const requestId = canonicalRecoveryAdmissionEntryId(name, path5);
|
|
22970
23714
|
if (!requestId) continue;
|
|
22971
23715
|
try {
|
|
@@ -23043,7 +23787,7 @@ async function runPersistentRecoveryOwnerLoop(input, options = {}) {
|
|
|
23043
23787
|
const reconcileServices = options.reconcileServices ?? reconcileCommittedTeamServices;
|
|
23044
23788
|
const monitor = options.monitor ?? monitorTeamV2;
|
|
23045
23789
|
const sleep4 = options.sleep ?? (async (ms) => {
|
|
23046
|
-
await new Promise((
|
|
23790
|
+
await new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
23047
23791
|
});
|
|
23048
23792
|
const shutdown = options.shutdown ?? shutdownTeamV2;
|
|
23049
23793
|
let iteration = 0;
|
|
@@ -23184,7 +23928,7 @@ async function writeResultArtifact(output, finishedAt, jobId = process.env.OMC_J
|
|
|
23184
23928
|
if (!output.instanceId || !isValidTeamInstanceId(output.instanceId)) {
|
|
23185
23929
|
throw new Error("result_artifact_instance_identity_missing");
|
|
23186
23930
|
}
|
|
23187
|
-
const resultPath = (0,
|
|
23931
|
+
const resultPath = (0, import_path39.join)(omcJobsDir, `${jobId}-result.json`);
|
|
23188
23932
|
const tmpPath = `${resultPath}.tmp`;
|
|
23189
23933
|
await (0, import_promises20.writeFile)(
|
|
23190
23934
|
tmpPath,
|
|
@@ -23259,7 +24003,7 @@ async function writePanesFile(jobId, instanceId, teamName, cwd, paneIds, leaderP
|
|
|
23259
24003
|
if (authoritativePaneIds.some((paneId) => !paneIds.includes(paneId))) {
|
|
23260
24004
|
throw new Error("pane_artifact_missing_runtime_pane");
|
|
23261
24005
|
}
|
|
23262
|
-
const panesPath = (0,
|
|
24006
|
+
const panesPath = (0, import_path39.join)(omcJobsDir, `${jobId}-panes.json`);
|
|
23263
24007
|
await (0, import_promises20.writeFile)(
|
|
23264
24008
|
panesPath + ".tmp",
|
|
23265
24009
|
JSON.stringify({
|
|
@@ -23297,7 +24041,7 @@ function isTerseFinalSummary(summary) {
|
|
|
23297
24041
|
function readTaskOutputFallback(outputsDir, teamName, taskId) {
|
|
23298
24042
|
let entries;
|
|
23299
24043
|
try {
|
|
23300
|
-
entries = (0,
|
|
24044
|
+
entries = (0, import_fs35.readdirSync)(outputsDir);
|
|
23301
24045
|
} catch {
|
|
23302
24046
|
return null;
|
|
23303
24047
|
}
|
|
@@ -23306,16 +24050,16 @@ function readTaskOutputFallback(outputsDir, teamName, taskId) {
|
|
|
23306
24050
|
if (candidates.length === 0) return null;
|
|
23307
24051
|
let newest = null;
|
|
23308
24052
|
for (const name of candidates) {
|
|
23309
|
-
const full = (0,
|
|
24053
|
+
const full = (0, import_path39.join)(outputsDir, name);
|
|
23310
24054
|
try {
|
|
23311
|
-
const mtime = (0,
|
|
24055
|
+
const mtime = (0, import_fs35.statSync)(full).mtimeMs;
|
|
23312
24056
|
if (!newest || mtime > newest.mtime) newest = { path: full, mtime };
|
|
23313
24057
|
} catch {
|
|
23314
24058
|
}
|
|
23315
24059
|
}
|
|
23316
24060
|
if (!newest) return null;
|
|
23317
24061
|
try {
|
|
23318
|
-
const content = (0,
|
|
24062
|
+
const content = (0, import_fs35.readFileSync)(newest.path, "utf-8").trim();
|
|
23319
24063
|
if (content.length === 0) return null;
|
|
23320
24064
|
return content.length > MAX_FALLBACK_SUMMARY_CHARS ? content.slice(0, MAX_FALLBACK_SUMMARY_CHARS) + "\n... (truncated)" : content;
|
|
23321
24065
|
} catch {
|
|
@@ -23323,14 +24067,14 @@ function readTaskOutputFallback(outputsDir, teamName, taskId) {
|
|
|
23323
24067
|
}
|
|
23324
24068
|
}
|
|
23325
24069
|
function collectTaskResults(stateRoot) {
|
|
23326
|
-
const tasksDir = (0,
|
|
23327
|
-
const teamName = (0,
|
|
23328
|
-
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");
|
|
23329
24073
|
try {
|
|
23330
|
-
const files = (0,
|
|
24074
|
+
const files = (0, import_fs35.readdirSync)(tasksDir).filter((f) => f.endsWith(".json"));
|
|
23331
24075
|
return files.map((f) => {
|
|
23332
24076
|
try {
|
|
23333
|
-
const raw = (0,
|
|
24077
|
+
const raw = (0, import_fs35.readFileSync)((0, import_path39.join)(tasksDir, f), "utf-8");
|
|
23334
24078
|
const task = JSON.parse(raw);
|
|
23335
24079
|
const taskId = task.id ?? f.replace(".json", "");
|
|
23336
24080
|
let summary = task.result ?? task.summary ?? "";
|
|
@@ -23365,8 +24109,8 @@ function createRuntimeStartupShutdownBarrier() {
|
|
|
23365
24109
|
let settled = false;
|
|
23366
24110
|
let requested = false;
|
|
23367
24111
|
let resolveCompletion;
|
|
23368
|
-
const completion = new Promise((
|
|
23369
|
-
resolveCompletion =
|
|
24112
|
+
const completion = new Promise((resolve17) => {
|
|
24113
|
+
resolveCompletion = resolve17;
|
|
23370
24114
|
});
|
|
23371
24115
|
return {
|
|
23372
24116
|
requestShutdown: () => {
|
|
@@ -23674,7 +24418,7 @@ async function main() {
|
|
|
23674
24418
|
if (snap.allTasksTerminal) {
|
|
23675
24419
|
const hasFailures = snap.tasks.failed > 0;
|
|
23676
24420
|
if (!hasFailures) {
|
|
23677
|
-
const sentinelLogPath = (0,
|
|
24421
|
+
const sentinelLogPath = (0, import_path39.join)(cwd, "sentinel_stop.jsonl");
|
|
23678
24422
|
const gateResult = await waitForSentinelReadiness({
|
|
23679
24423
|
workspace: cwd,
|
|
23680
24424
|
logPath: sentinelLogPath,
|