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/scripts/run.cjs
CHANGED
|
@@ -270,9 +270,41 @@ function resolveTrustedSessionEndTarget(resolution, extraArgs) {
|
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
+
// Fork (oh-my-copilot): SessionEnd foreground budget per host. Claude Code
|
|
274
|
+
// kills SessionEnd hooks at exit, so upstream caps the foreground at 300ms.
|
|
275
|
+
// Copilot (OMC_HOOK_EVENT=SessionEnd from copilot/hooks.json) fires SessionEnd
|
|
276
|
+
// per turn and waits up to timeoutSec, so 300ms only drops the work under load.
|
|
277
|
+
// 1500ms is chosen (~5x the idle foreground cost), not derived.
|
|
278
|
+
// OMC_SESSION_END_BUDGET_MS overrides both hosts (integer 1..60000); the
|
|
279
|
+
// manifest-derived timeout still caps the result at the call site.
|
|
280
|
+
const SESSION_END_BUDGET_MS = 300;
|
|
281
|
+
const COPILOT_SESSION_END_BUDGET_MS = 1500;
|
|
282
|
+
function resolveSessionEndBudgetMs(env = process.env) {
|
|
283
|
+
// Test-only widening (upstream contract) wins, and only under NODE_ENV=test.
|
|
284
|
+
const requestedTestTimeout = env.NODE_ENV === 'test'
|
|
285
|
+
? Number(env.OMC_SESSION_END_TEST_FOREGROUND_TIMEOUT_MS)
|
|
286
|
+
: NaN;
|
|
287
|
+
if (Number.isFinite(requestedTestTimeout) && requestedTestTimeout > 0) return requestedTestTimeout;
|
|
288
|
+
const override = String(env.OMC_SESSION_END_BUDGET_MS ?? '').trim();
|
|
289
|
+
if (/^\d+$/.test(override)) {
|
|
290
|
+
const value = Number(override);
|
|
291
|
+
if (value >= 1 && value <= MAX_DECLARED_GENERIC_TIMEOUT_MS) return value;
|
|
292
|
+
}
|
|
293
|
+
return env.OMC_HOOK_EVENT === 'SessionEnd' ? COPILOT_SESSION_END_BUDGET_MS : SESSION_END_BUDGET_MS;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
// oh-my-copilot fail-closed contract (fork-only): with OMC_HOOK_FAIL_CLOSED=1
|
|
298
|
+
// a hook timeout exits 124 so the host records a failed hook. Unset keeps the
|
|
299
|
+
// upstream fail-open exit 0.
|
|
300
|
+
const HOOK_TIMEOUT_FAIL_CLOSED_STATUS = 124;
|
|
301
|
+
function hookTimeoutStatus() {
|
|
302
|
+
return process.env.OMC_HOOK_FAIL_CLOSED === '1' ? HOOK_TIMEOUT_FAIL_CLOSED_STATUS : 0;
|
|
303
|
+
}
|
|
273
304
|
|
|
274
305
|
function writeTimeoutDiagnostic(targetPath, manifestHook, timeoutMs, sink) {
|
|
275
|
-
const
|
|
306
|
+
const outcome = hookTimeoutStatus() === 0 ? 'fail-open' : `fail-closed (${HOOK_TIMEOUT_FAIL_CLOSED_STATUS})`;
|
|
307
|
+
const message = `[run.cjs] Hook ${basename(targetPath)} timed out after ${timeoutMs}ms; exiting ${outcome}.\n`;
|
|
276
308
|
if (manifestHook?.event !== 'UserPromptSubmit' || isDebugHooksEnabled()) {
|
|
277
309
|
if (sink) return sink.write(process.stderr, Buffer.from(message));
|
|
278
310
|
try { process.stderr.write(message); } catch { /* protocol dest may already be closed */ }
|
|
@@ -842,7 +874,7 @@ function runGenericChild(targetPath, extraArgs, timeoutMs, manifestHook, options
|
|
|
842
874
|
if (require.main === module) {
|
|
843
875
|
sink.closeDestinations();
|
|
844
876
|
}
|
|
845
|
-
finish(
|
|
877
|
+
finish(hookTimeoutStatus()); // fork: fail-closed contract, see hookTimeoutStatus
|
|
846
878
|
});
|
|
847
879
|
}, timeoutMs);
|
|
848
880
|
|
|
@@ -940,7 +972,80 @@ function gitGuardrailsPreCheck() {
|
|
|
940
972
|
return null;
|
|
941
973
|
}
|
|
942
974
|
|
|
943
|
-
|
|
975
|
+
// Fork (oh-my-copilot): generic hooks that run in a Worker under Copilot
|
|
976
|
+
// (OMC_HOOK_EVENT set by copilot/hooks.json). On win32 the generic child path
|
|
977
|
+
// costs run.cjs -> --generic-child-supervisor -> hook = 3 Node processes
|
|
978
|
+
// (~170 ms for a no-op hook); a Worker costs ~25 ms. Each script was audited:
|
|
979
|
+
// no process.chdir, signal handlers, isMainThread gating, or children that
|
|
980
|
+
// inherit stdio. process.exit ends only the Worker and its code propagates.
|
|
981
|
+
// Add a new upstream hook only after the same audit; the routing test pins
|
|
982
|
+
// this set to the generic entries of copilot/hooks.json.
|
|
983
|
+
//
|
|
984
|
+
// A Worker cannot preempt a hook blocked inside a synchronous call: several
|
|
985
|
+
// of these scripts (context-guard-stop.mjs, workflow-drift-guard.mjs,
|
|
986
|
+
// code-simplifier.mjs, and the shared resolveToWorktreeRoot git probes) make
|
|
987
|
+
// sync spawnSync git calls with their own ~2s timeouts, and `worker.terminate()`
|
|
988
|
+
// only tears the Worker down once that sync call returns; it does not reap
|
|
989
|
+
// any async grandchildren either. The supervised child path's `taskkill /T`
|
|
990
|
+
// can still kill a blocked sync call and its children, so
|
|
991
|
+
// resolveCopilotWorkerTarget below keeps any entry whose own manifest budget
|
|
992
|
+
// is <= COPILOT_WORKER_MIN_TIMEOUT_MS on that child path instead of the
|
|
993
|
+
// Worker, trading its ~90ms Worker saving for a host timeout that cannot be
|
|
994
|
+
// overshot by a hung sync call. See docs/HOOKS.md "Worker routing".
|
|
995
|
+
const COPILOT_WORKER_MIN_TIMEOUT_MS = 3000;
|
|
996
|
+
const COPILOT_WORKER_HOOKS = new Set([
|
|
997
|
+
'session-start.mjs',
|
|
998
|
+
'project-memory-session.mjs',
|
|
999
|
+
'wiki-session-start.mjs',
|
|
1000
|
+
'stale-run-reporter.mjs',
|
|
1001
|
+
'runs-reconciler.mjs',
|
|
1002
|
+
'permission-handler.mjs',
|
|
1003
|
+
'post-tool-directory-context-injector.mjs',
|
|
1004
|
+
'post-tool-use-failure.mjs',
|
|
1005
|
+
'subagent-tracker.mjs',
|
|
1006
|
+
'verify-deliverables.mjs',
|
|
1007
|
+
'pre-compact.mjs',
|
|
1008
|
+
'project-memory-precompact.mjs',
|
|
1009
|
+
'wiki-pre-compact.mjs',
|
|
1010
|
+
'context-guard-stop.mjs',
|
|
1011
|
+
'workflow-drift-guard.mjs',
|
|
1012
|
+
'persistent-mode.mjs',
|
|
1013
|
+
'budget-guard.mjs',
|
|
1014
|
+
'code-simplifier.mjs',
|
|
1015
|
+
]);
|
|
1016
|
+
|
|
1017
|
+
/**
|
|
1018
|
+
* Fork: the manifest hook when this generic hook may run in a Worker under
|
|
1019
|
+
* Copilot, else null (generic child path). Requires OMC_HOOK_EVENT, the
|
|
1020
|
+
* OMC_COPILOT_HOOK_WORKER=0 kill switch unset, an audited script at the exact
|
|
1021
|
+
* canonical trusted-root path, and a manifest entry (with these extra args)
|
|
1022
|
+
* whose event is OMC_HOOK_EVENT. Claude Code never sets OMC_HOOK_EVENT.
|
|
1023
|
+
*/
|
|
1024
|
+
function resolveCopilotWorkerTarget(resolution, extraArgs, env = process.env) {
|
|
1025
|
+
const hookEvent = env.OMC_HOOK_EVENT;
|
|
1026
|
+
const trustedRoot = resolution.trustedPluginRoot;
|
|
1027
|
+
if (!hookEvent || env.OMC_COPILOT_HOOK_WORKER === '0' || !trustedRoot) return null;
|
|
1028
|
+
try {
|
|
1029
|
+
const scriptName = basename(resolution.targetPath);
|
|
1030
|
+
if (!COPILOT_WORKER_HOOKS.has(scriptName)) return null;
|
|
1031
|
+
const canonicalTarget = normalizedComparisonPath(resolution.targetPath);
|
|
1032
|
+
if (!isContainedBy(normalizedComparisonPath(trustedRoot), canonicalTarget)) return null;
|
|
1033
|
+
if (canonicalTarget !== normalizedComparisonPath(join(trustedRoot, 'scripts', scriptName))) return null;
|
|
1034
|
+
const manifestHook = resolveHookTimeoutMsFromRoot(trustedRoot, resolution.targetPath, extraArgs);
|
|
1035
|
+
if (manifestHook?.event !== hookEvent) return null;
|
|
1036
|
+
// See COPILOT_WORKER_MIN_TIMEOUT_MS above: a tight manifest budget stays
|
|
1037
|
+
// on the supervised child path, where a blocked sync call cannot overshoot
|
|
1038
|
+
// the host timeout.
|
|
1039
|
+
if (manifestHook.timeoutMs <= COPILOT_WORKER_MIN_TIMEOUT_MS) return null;
|
|
1040
|
+
return manifestHook;
|
|
1041
|
+
} catch {
|
|
1042
|
+
return null;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
// options (fork): { argv, env } for the Copilot generic Worker path; the
|
|
1047
|
+
// trusted and SessionEnd Worker callers pass none and keep upstream behaviour.
|
|
1048
|
+
async function runWorker(targetPath, manifestHook, timeoutMs, options = {}) {
|
|
944
1049
|
let worker;
|
|
945
1050
|
let terminal = false;
|
|
946
1051
|
let timer;
|
|
@@ -996,7 +1101,8 @@ async function runWorker(targetPath, manifestHook, timeoutMs) {
|
|
|
996
1101
|
}
|
|
997
1102
|
await writeTimeoutDiagnostic(targetPath, manifestHook, timeoutMs, sink);
|
|
998
1103
|
sink.uninstall();
|
|
999
|
-
|
|
1104
|
+
// Also the SessionEnd foreground-budget path. Fork: fail-closed contract, see hookTimeoutStatus.
|
|
1105
|
+
resolve(hookTimeoutStatus());
|
|
1000
1106
|
}, timeoutMs);
|
|
1001
1107
|
|
|
1002
1108
|
try {
|
|
@@ -1005,7 +1111,9 @@ async function runWorker(targetPath, manifestHook, timeoutMs) {
|
|
|
1005
1111
|
stdin: true,
|
|
1006
1112
|
stdout: true,
|
|
1007
1113
|
stderr: true,
|
|
1008
|
-
env: process.env,
|
|
1114
|
+
env: options.env || process.env,
|
|
1115
|
+
// Appended after [worker eval] → argv[1] is the hook path, argv[2..] the extra args.
|
|
1116
|
+
...(options.argv && options.argv.length ? { argv: options.argv } : {}),
|
|
1009
1117
|
workerData: { omcWorkerTarget: pathToFileURL(targetPath).href },
|
|
1010
1118
|
});
|
|
1011
1119
|
if (process.stdin.readableEnded) worker.stdin.end();
|
|
@@ -1059,24 +1167,34 @@ if (require.main === module) {
|
|
|
1059
1167
|
} else {
|
|
1060
1168
|
const sessionEndManifestHook = resolveTrustedSessionEndTarget(resolution, extraArgs);
|
|
1061
1169
|
if (sessionEndManifestHook) {
|
|
1062
|
-
//
|
|
1063
|
-
|
|
1064
|
-
const requestedTestTimeout = process.env.NODE_ENV === 'test'
|
|
1065
|
-
? Number(process.env.OMC_SESSION_END_TEST_FOREGROUND_TIMEOUT_MS)
|
|
1066
|
-
: NaN;
|
|
1067
|
-
const budgetMs = Number.isFinite(requestedTestTimeout) && requestedTestTimeout > 0
|
|
1068
|
-
? requestedTestTimeout
|
|
1069
|
-
: 300;
|
|
1170
|
+
// Fork: 300ms on Claude Code, 1500ms under Copilot; see resolveSessionEndBudgetMs.
|
|
1171
|
+
const budgetMs = resolveSessionEndBudgetMs();
|
|
1070
1172
|
const timeoutMs = Math.min(resolveGenericTimeoutMs(sessionEndManifestHook), budgetMs);
|
|
1071
1173
|
runWorker(resolution.targetPath, sessionEndManifestHook, timeoutMs).then(status => {
|
|
1072
1174
|
process.exitCode = status;
|
|
1073
1175
|
});
|
|
1074
1176
|
} else {
|
|
1075
|
-
const
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1177
|
+
const copilotWorkerHook = resolveCopilotWorkerTarget(resolution, extraArgs);
|
|
1178
|
+
if (copilotWorkerHook) {
|
|
1179
|
+
// Fork: Copilot generic hooks in a Worker, same timeout and owner-pid
|
|
1180
|
+
// env as runGenericChild; see COPILOT_WORKER_HOOKS.
|
|
1181
|
+
const timeoutMs = resolveGenericTimeoutMs(copilotWorkerHook);
|
|
1182
|
+
runWorker(resolution.targetPath, copilotWorkerHook, timeoutMs, {
|
|
1183
|
+
argv: extraArgs,
|
|
1184
|
+
env: {
|
|
1185
|
+
...process.env,
|
|
1186
|
+
OMC_SESSION_OWNER_PID: process.env.OMC_SESSION_OWNER_PID || String(process.ppid),
|
|
1187
|
+
},
|
|
1188
|
+
}).then(status => {
|
|
1189
|
+
process.exitCode = status;
|
|
1190
|
+
});
|
|
1191
|
+
} else {
|
|
1192
|
+
const manifestHook = resolveHookTimeoutMs(resolution.targetPath, extraArgs);
|
|
1193
|
+
const timeoutMs = resolveGenericTimeoutMs(manifestHook);
|
|
1194
|
+
runGenericChild(resolution.targetPath, extraArgs, timeoutMs, manifestHook).then(status => {
|
|
1195
|
+
process.exitCode = status;
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1080
1198
|
}
|
|
1081
1199
|
}
|
|
1082
1200
|
}
|
|
@@ -1109,4 +1227,9 @@ module.exports = {
|
|
|
1109
1227
|
NESTED_INNER_FLOOR_MS,
|
|
1110
1228
|
MAX_DECLARED_GENERIC_TIMEOUT_MS,
|
|
1111
1229
|
resolveTrustedSessionEndTarget,
|
|
1230
|
+
resolveSessionEndBudgetMs,
|
|
1231
|
+
resolveCopilotWorkerTarget,
|
|
1232
|
+
COPILOT_WORKER_HOOKS,
|
|
1233
|
+
COPILOT_WORKER_MIN_TIMEOUT_MS,
|
|
1234
|
+
TRUSTED_WORKER_HOOKS,
|
|
1112
1235
|
};
|
|
@@ -1071,6 +1071,19 @@ async function main() {
|
|
|
1071
1071
|
return;
|
|
1072
1072
|
}
|
|
1073
1073
|
const sessionId = data.session_id || data.sessionId || '';
|
|
1074
|
+
// Factory chain link (Copilot): bind OMC_CHAIN_LINK to this host session
|
|
1075
|
+
// first, so a nested session that inherits the variable cannot end the
|
|
1076
|
+
// link (bindChainLink in src/hooks/session-end/chain-enqueuer.ts). A failed
|
|
1077
|
+
// bind makes this link's SessionEnd reject the claim; the watchdog flags it.
|
|
1078
|
+
if (process.env.OMC_CHAIN_LINK && sessionId) {
|
|
1079
|
+
try {
|
|
1080
|
+
const [{ bindChainLink }, { resolveToWorktreeRoot }] = await Promise.all([
|
|
1081
|
+
import(pathToFileURL(join(__dirname, '..', 'dist', 'hooks', 'session-end', 'chain-enqueuer.js')).href),
|
|
1082
|
+
import(pathToFileURL(join(__dirname, '..', 'dist', 'lib', 'worktree-paths.js')).href),
|
|
1083
|
+
]);
|
|
1084
|
+
bindChainLink(resolveToWorktreeRoot(directory), sessionId);
|
|
1085
|
+
} catch { /* dist unavailable: the link stays unbound */ }
|
|
1086
|
+
}
|
|
1074
1087
|
const omcRoot = await resolveOmcStateRoot(directory);
|
|
1075
1088
|
let messages = [];
|
|
1076
1089
|
const userMessages = [];
|
|
@@ -15,7 +15,8 @@ export async function runWikiSessionEndHook() {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
try {
|
|
18
|
-
|
|
18
|
+
// Lean entry (not index.js): the full SessionEnd graph costs ~100ms of the 300ms budget.
|
|
19
|
+
const { processWikiSessionEnd } = await import('../dist/hooks/session-end/wiki-foreground-bootstrap.js');
|
|
19
20
|
const result = await processWikiSessionEnd(frame.value);
|
|
20
21
|
console.log(JSON.stringify(result));
|
|
21
22
|
} catch (error) {
|
|
@@ -137,9 +137,11 @@ function readEmergencyJournal(path) {
|
|
|
137
137
|
} catch { return null; }
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
// BigInt ids: NTFS file IDs exceed 2^53 once the MFT sequence number reaches
|
|
141
|
+
// 32, and a Number ino rounds distinct files onto the same value.
|
|
140
142
|
function fileIdentity(path) {
|
|
141
143
|
try {
|
|
142
|
-
const stat = statSync(path);
|
|
144
|
+
const stat = statSync(path, { bigint: true });
|
|
143
145
|
return { dev: stat.dev, ino: stat.ino };
|
|
144
146
|
} catch { return null; }
|
|
145
147
|
}
|
|
@@ -157,7 +159,7 @@ function sameFileIdentity(a, b) {
|
|
|
157
159
|
// On Windows, lstat returns dev=0, so skip dev comparison when on Windows
|
|
158
160
|
// unless both are non-zero (indicating a real comparison is possible)
|
|
159
161
|
const isWindows = process.platform === 'win32';
|
|
160
|
-
if (isWindows && (a.dev ===
|
|
162
|
+
if (isWindows && (a.dev === 0n || b.dev === 0n)) {
|
|
161
163
|
return true; // Skip dev comparison on Windows when either is 0
|
|
162
164
|
}
|
|
163
165
|
|