oh-my-copilot 5.6.2 → 5.7.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.
Files changed (127) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +1 -0
  4. package/bridge/__pycache__/gyoshu_bridge.cpython-312.pyc +0 -0
  5. package/bridge/claude-md-coordinator.cjs +2 -2
  6. package/bridge/cli.cjs +78578 -75769
  7. package/bridge/mcp-server.cjs +36510 -32259
  8. package/bridge/runtime-cli.cjs +95 -34
  9. package/bridge/team-mcp.cjs +95 -34
  10. package/bridge/team.js +131 -70
  11. package/dist/__tests__/run-cjs-fail-closed-timeout.test.d.ts +2 -0
  12. package/dist/__tests__/run-cjs-fail-closed-timeout.test.d.ts.map +1 -0
  13. package/dist/__tests__/run-cjs-fail-closed-timeout.test.js +68 -0
  14. package/dist/__tests__/run-cjs-fail-closed-timeout.test.js.map +1 -0
  15. package/dist/__tests__/session-end-process-exit.test.js +70 -2
  16. package/dist/__tests__/session-end-process-exit.test.js.map +1 -1
  17. package/dist/cli/commands/__tests__/smoke-tier2.test.d.ts +2 -0
  18. package/dist/cli/commands/__tests__/smoke-tier2.test.d.ts.map +1 -0
  19. package/dist/cli/commands/__tests__/smoke-tier2.test.js +72 -0
  20. package/dist/cli/commands/__tests__/smoke-tier2.test.js.map +1 -0
  21. package/dist/cli/commands/smoke.d.ts +36 -0
  22. package/dist/cli/commands/smoke.d.ts.map +1 -0
  23. package/dist/cli/commands/smoke.js +169 -0
  24. package/dist/cli/commands/smoke.js.map +1 -0
  25. package/dist/cli/index.d.ts.map +1 -1
  26. package/dist/cli/index.js +39 -0
  27. package/dist/cli/index.js.map +1 -1
  28. package/dist/constants/names.d.ts +1 -0
  29. package/dist/constants/names.d.ts.map +1 -1
  30. package/dist/constants/names.js +1 -0
  31. package/dist/constants/names.js.map +1 -1
  32. package/dist/hooks/session-end/index.d.ts +2 -3
  33. package/dist/hooks/session-end/index.d.ts.map +1 -1
  34. package/dist/hooks/session-end/index.js +3 -10
  35. package/dist/hooks/session-end/index.js.map +1 -1
  36. package/dist/hooks/session-end/wiki-foreground-bootstrap.d.ts +17 -0
  37. package/dist/hooks/session-end/wiki-foreground-bootstrap.d.ts.map +1 -0
  38. package/dist/hooks/session-end/wiki-foreground-bootstrap.js +20 -0
  39. package/dist/hooks/session-end/wiki-foreground-bootstrap.js.map +1 -0
  40. package/dist/lib/__tests__/atomic-write.test.js +32 -1
  41. package/dist/lib/__tests__/atomic-write.test.js.map +1 -1
  42. package/dist/lib/__tests__/mode-state-lock.test.js +121 -12
  43. package/dist/lib/__tests__/mode-state-lock.test.js.map +1 -1
  44. package/dist/lib/atomic-write.d.ts +13 -3
  45. package/dist/lib/atomic-write.d.ts.map +1 -1
  46. package/dist/lib/atomic-write.js +29 -15
  47. package/dist/lib/atomic-write.js.map +1 -1
  48. package/dist/lib/mode-state-io.d.ts +2 -2
  49. package/dist/lib/mode-state-io.d.ts.map +1 -1
  50. package/dist/lib/mode-state-io.js +16 -10
  51. package/dist/lib/mode-state-io.js.map +1 -1
  52. package/dist/mcp/__tests__/host-smoke-tool.test.d.ts +2 -0
  53. package/dist/mcp/__tests__/host-smoke-tool.test.d.ts.map +1 -0
  54. package/dist/mcp/__tests__/host-smoke-tool.test.js +174 -0
  55. package/dist/mcp/__tests__/host-smoke-tool.test.js.map +1 -0
  56. package/dist/mcp/disable-tools.d.ts.map +1 -1
  57. package/dist/mcp/disable-tools.js +1 -0
  58. package/dist/mcp/disable-tools.js.map +1 -1
  59. package/dist/mcp/tool-registry.d.ts.map +1 -1
  60. package/dist/mcp/tool-registry.js +2 -0
  61. package/dist/mcp/tool-registry.js.map +1 -1
  62. package/dist/smoke/__tests__/copilot-sdk-driver.test.d.ts +2 -0
  63. package/dist/smoke/__tests__/copilot-sdk-driver.test.d.ts.map +1 -0
  64. package/dist/smoke/__tests__/copilot-sdk-driver.test.js +561 -0
  65. package/dist/smoke/__tests__/copilot-sdk-driver.test.js.map +1 -0
  66. package/dist/smoke/__tests__/copilot-sdk-scenarios.test.d.ts +2 -0
  67. package/dist/smoke/__tests__/copilot-sdk-scenarios.test.d.ts.map +1 -0
  68. package/dist/smoke/__tests__/copilot-sdk-scenarios.test.js +311 -0
  69. package/dist/smoke/__tests__/copilot-sdk-scenarios.test.js.map +1 -0
  70. package/dist/smoke/__tests__/copilot-session-eval.test.d.ts +2 -0
  71. package/dist/smoke/__tests__/copilot-session-eval.test.d.ts.map +1 -0
  72. package/dist/smoke/__tests__/copilot-session-eval.test.js +264 -0
  73. package/dist/smoke/__tests__/copilot-session-eval.test.js.map +1 -0
  74. package/dist/smoke/__tests__/copilot-smoke.test.d.ts +2 -0
  75. package/dist/smoke/__tests__/copilot-smoke.test.d.ts.map +1 -0
  76. package/dist/smoke/__tests__/copilot-smoke.test.js +482 -0
  77. package/dist/smoke/__tests__/copilot-smoke.test.js.map +1 -0
  78. package/dist/smoke/copilot-binary.d.ts +21 -0
  79. package/dist/smoke/copilot-binary.d.ts.map +1 -0
  80. package/dist/smoke/copilot-binary.js +46 -0
  81. package/dist/smoke/copilot-binary.js.map +1 -0
  82. package/dist/smoke/copilot-sdk-driver.d.ts +186 -0
  83. package/dist/smoke/copilot-sdk-driver.d.ts.map +1 -0
  84. package/dist/smoke/copilot-sdk-driver.js +622 -0
  85. package/dist/smoke/copilot-sdk-driver.js.map +1 -0
  86. package/dist/smoke/copilot-sdk-scenarios.d.ts +159 -0
  87. package/dist/smoke/copilot-sdk-scenarios.d.ts.map +1 -0
  88. package/dist/smoke/copilot-sdk-scenarios.js +510 -0
  89. package/dist/smoke/copilot-sdk-scenarios.js.map +1 -0
  90. package/dist/smoke/copilot-session-eval.d.ts +90 -0
  91. package/dist/smoke/copilot-session-eval.d.ts.map +1 -0
  92. package/dist/smoke/copilot-session-eval.js +323 -0
  93. package/dist/smoke/copilot-session-eval.js.map +1 -0
  94. package/dist/smoke/copilot-smoke.d.ts +228 -0
  95. package/dist/smoke/copilot-smoke.d.ts.map +1 -0
  96. package/dist/smoke/copilot-smoke.js +818 -0
  97. package/dist/smoke/copilot-smoke.js.map +1 -0
  98. package/dist/smoke/process-utils.d.ts +47 -0
  99. package/dist/smoke/process-utils.d.ts.map +1 -0
  100. package/dist/smoke/process-utils.js +99 -0
  101. package/dist/smoke/process-utils.js.map +1 -0
  102. package/dist/team/__tests__/tmux-session.pane-env.test.d.ts +2 -0
  103. package/dist/team/__tests__/tmux-session.pane-env.test.d.ts.map +1 -0
  104. package/dist/team/__tests__/tmux-session.pane-env.test.js +52 -0
  105. package/dist/team/__tests__/tmux-session.pane-env.test.js.map +1 -0
  106. package/dist/team/tmux-session.d.ts +7 -0
  107. package/dist/team/tmux-session.d.ts.map +1 -1
  108. package/dist/team/tmux-session.js +80 -18
  109. package/dist/team/tmux-session.js.map +1 -1
  110. package/dist/tools/host-smoke-tool.d.ts +34 -0
  111. package/dist/tools/host-smoke-tool.d.ts.map +1 -0
  112. package/dist/tools/host-smoke-tool.js +133 -0
  113. package/dist/tools/host-smoke-tool.js.map +1 -0
  114. package/docs/CLAUDE.md +1 -1
  115. package/docs/DEVELOPERS.md +101 -0
  116. package/docs/HOOKS.md +1 -1
  117. package/docs/MIGRATION.md +71 -0
  118. package/docs/REFERENCE.md +42 -1
  119. package/docs/TOOLS.md +32 -1
  120. package/package.json +11 -2
  121. package/plugin.json +1 -1
  122. package/scripts/dev/repro-state-lock.mjs +1 -1
  123. package/scripts/lib/atomic-write.mjs +4 -2
  124. package/scripts/lib/state-lock.mjs +21 -12
  125. package/scripts/run.cjs +13 -3
  126. package/scripts/wiki-session-end.mjs +2 -1
  127. package/templates/hooks/lib/atomic-write.mjs +4 -2
package/bridge/team.js CHANGED
@@ -9197,33 +9197,33 @@ function ensureDirSync(dir) {
9197
9197
  }
9198
9198
  }
9199
9199
  function verifyPrivateTempFile(fd, tempPath, label, operations) {
9200
- const fdStats = fsSync.fstatSync(fd);
9200
+ const fdStats = descriptorStats(fd, operations);
9201
9201
  let pathStats;
9202
9202
  try {
9203
- pathStats = (operations?.lstat ?? fsSync.lstatSync)(tempPath);
9203
+ pathStats = pathnameStats(tempPath, operations);
9204
9204
  } catch {
9205
9205
  throw new Error(`${label} temporary file was replaced before rename`);
9206
9206
  }
9207
9207
  const isWindows = process.platform === "win32";
9208
- const isPrivateRegularSingleLink = (stats) => stats.isFile() && (isWindows ? stats.nlink <= 1 : stats.nlink === 1) && (isWindows || (stats.mode & 511) === 384);
9208
+ const isPrivateRegularSingleLink = (stats) => stats.isFile() && (isWindows ? Number(stats.nlink) <= 1 : Number(stats.nlink) === 1) && (isWindows || (Number(stats.mode) & 511) === 384);
9209
9209
  if (!isPrivateRegularSingleLink(fdStats) || !isPrivateRegularSingleLink(pathStats)) {
9210
9210
  throw new Error(
9211
9211
  `${label} temporary file must be a private regular single-link file`
9212
9212
  );
9213
9213
  }
9214
- if (!sameFileIdentity(fdStats, pathStats)) {
9214
+ if (!sameFileIdentity(fileIdentityOf(fdStats), fileIdentityOf(pathStats))) {
9215
9215
  throw new Error(`${label} temporary file was replaced before rename`);
9216
9216
  }
9217
9217
  }
9218
9218
  function verifyPublishedFile(fd, filePath, label, operations) {
9219
- const fdStats = fsSync.fstatSync(fd);
9219
+ const fdStats = descriptorStats(fd, operations);
9220
9220
  let pathStats;
9221
9221
  try {
9222
- pathStats = (operations?.lstat ?? fsSync.lstatSync)(filePath);
9222
+ pathStats = pathnameStats(filePath, operations);
9223
9223
  } catch {
9224
9224
  throw new Error(`${label} target was replaced at publication`);
9225
9225
  }
9226
- if (!pathStats.isFile() || !sameFileIdentity(fdStats, pathStats)) {
9226
+ if (!pathStats.isFile() || !sameFileIdentity(fileIdentityOf(fdStats), fileIdentityOf(pathStats))) {
9227
9227
  throw new Error(`${label} target was replaced at publication`);
9228
9228
  }
9229
9229
  }
@@ -9247,26 +9247,33 @@ function preservePriorTarget(filePath, operations) {
9247
9247
  return null;
9248
9248
  }
9249
9249
  }
9250
+ function descriptorStats(fd, operations) {
9251
+ return operations ? fsSync.fstatSync(fd) : fsSync.fstatSync(fd, { bigint: true });
9252
+ }
9253
+ function pathnameStats(filePath, operations) {
9254
+ return operations ? operations.lstat(filePath) : fsSync.lstatSync(filePath, { bigint: true });
9255
+ }
9256
+ function fileIdentityOf(stats) {
9257
+ return { dev: BigInt(stats.dev), ino: BigInt(stats.ino) };
9258
+ }
9250
9259
  function sameFileIdentity(a, b) {
9251
9260
  if (a.ino !== b.ino) return false;
9252
9261
  const isWindows = process.platform === "win32";
9253
- if (isWindows && (a.dev === 0 || b.dev === 0)) {
9262
+ if (isWindows && (a.dev === 0n || b.dev === 0n)) {
9254
9263
  return true;
9255
9264
  }
9256
9265
  return a.dev === b.dev;
9257
9266
  }
9258
9267
  function currentFileIdentity(filePath, operations) {
9259
9268
  try {
9260
- const stats = (operations?.lstat ?? fsSync.lstatSync)(filePath);
9261
- return { dev: stats.dev, ino: stats.ino };
9269
+ return fileIdentityOf(pathnameStats(filePath, operations));
9262
9270
  } catch {
9263
9271
  return null;
9264
9272
  }
9265
9273
  }
9266
- function descriptorIdentity(fd) {
9274
+ function descriptorIdentity(fd, operations) {
9267
9275
  try {
9268
- const stats = fsSync.fstatSync(fd);
9269
- return { dev: stats.dev, ino: stats.ino };
9276
+ return fileIdentityOf(descriptorStats(fd, operations));
9270
9277
  } catch {
9271
9278
  return null;
9272
9279
  }
@@ -11768,13 +11775,14 @@ __export(tmux_session_exports, {
11768
11775
  waitForPaneReady: () => waitForPaneReady,
11769
11776
  waitForStartupPaneReady: () => waitForStartupPaneReady,
11770
11777
  workerPaneBelongsToOwnedProviderTarget: () => workerPaneBelongsToOwnedProviderTarget,
11771
- workerPaneBelongsToProviderTarget: () => workerPaneBelongsToProviderTarget
11778
+ workerPaneBelongsToProviderTarget: () => workerPaneBelongsToProviderTarget,
11779
+ workerPaneShellCommand: () => workerPaneShellCommand
11772
11780
  });
11773
- import { existsSync as existsSync23, statSync as statSync4 } from "fs";
11781
+ import { existsSync as existsSync23, mkdtempSync, rmSync as rmSync2, statSync as statSync4, writeFileSync as writeFileSync6 } from "fs";
11774
11782
  import { createHash as createHash10, randomUUID as randomUUID14 } from "crypto";
11775
11783
  import { execFile as execFile3 } from "child_process";
11776
11784
  import { promisify as promisify3 } from "util";
11777
- import { join as join25, basename as basename12, isAbsolute as isAbsolute7, win32 as win323 } from "path";
11785
+ import { join as join25, basename as basename12, dirname as dirname22, isAbsolute as isAbsolute7, win32 as win323 } from "path";
11778
11786
  import { tmpdir as tmpdir3 } from "os";
11779
11787
  function tmuxArgsForIdentity(identity, args) {
11780
11788
  return ["-S", identity.socket_path, ...args];
@@ -12649,23 +12657,66 @@ async function verifyWorkerStartCommandSubmitted(paneId, startCmd, opts = {}) {
12649
12657
  }
12650
12658
  return false;
12651
12659
  }
12660
+ function writePaneEnvFile(values) {
12661
+ const directory = mkdtempSync(join25(tmpdir3(), "omc-pane-env-"));
12662
+ const file = join25(directory, "env");
12663
+ const body = Object.entries(values).map(([key, value]) => `export ${key}=${shellQuote(value)}
12664
+ `).join("");
12665
+ writeFileSync6(file, body, { mode: 384, flag: "wx" });
12666
+ return file;
12667
+ }
12668
+ function discardPaneEnvFile(envFile) {
12669
+ if (!envFile) return;
12670
+ rmSync2(dirname22(envFile), { recursive: true, force: true });
12671
+ }
12652
12672
  function workerPaneShellCommand() {
12653
12673
  if (process.platform === "win32" && !isUnixLikeOnWindows()) {
12654
- return [getDefaultShell()];
12674
+ return { args: [getDefaultShell()], envFile: null };
12655
12675
  }
12656
- if (process.platform === "win32") return [];
12676
+ if (process.platform === "win32") return { args: [], envFile: null };
12657
12677
  const shell = getDefaultShell();
12658
12678
  const baseline = buildProviderEnvironment({ SHELL: shell });
12679
+ const inline = buildProviderEnvironment({ SHELL: shell }, process.env, process.platform, []);
12680
+ const passthrough = Object.fromEntries(
12681
+ Object.entries(baseline).filter(([key, value]) => inline[key] !== value)
12682
+ );
12659
12683
  const inheritedPaneEnvironment = ["TERM", "TMUX", "TMUX_PANE", "TMUX_TMPDIR", "LANG", "LC_ALL", "LC_CTYPE"].map((key) => `${key}="$${key}"`);
12684
+ const inlineAssignments = Object.entries(inline).map(([key, value]) => `${key}=${shellQuote(value)}`);
12685
+ if (Object.keys(passthrough).length === 0) {
12686
+ const command2 = [
12687
+ "/usr/bin/env",
12688
+ "-i",
12689
+ ...inlineAssignments,
12690
+ ...inheritedPaneEnvironment,
12691
+ shellQuote(shell),
12692
+ "-l"
12693
+ ].join(" ");
12694
+ return { args: [command2], envFile: null };
12695
+ }
12696
+ const envFile = writePaneEnvFile(passthrough);
12697
+ const bootstrap = '. "$OMC_PANE_ENV_FILE" && rm -rf -- "${OMC_PANE_ENV_FILE%/*}" && unset OMC_PANE_ENV_FILE && exec "$SHELL" -l';
12660
12698
  const command = [
12661
12699
  "/usr/bin/env",
12662
12700
  "-i",
12663
- ...Object.entries(baseline).map(([key, value]) => `${key}=${shellQuote(value)}`),
12701
+ ...inlineAssignments,
12702
+ `OMC_PANE_ENV_FILE=${shellQuote(envFile)}`,
12664
12703
  ...inheritedPaneEnvironment,
12665
- shellQuote(shell),
12666
- "-l"
12704
+ "/bin/sh",
12705
+ "-c",
12706
+ shellQuote(bootstrap)
12667
12707
  ].join(" ");
12668
- return [command];
12708
+ return { args: [command], envFile };
12709
+ }
12710
+ async function runPaneCreationCommand(identity, nativeCommand, paneShell) {
12711
+ let result;
12712
+ try {
12713
+ result = await runGuardedNativeTmuxCommand(identity, nativeCommand);
12714
+ } catch (error) {
12715
+ discardPaneEnvFile(paneShell.envFile);
12716
+ throw error;
12717
+ }
12718
+ if (result.outcome === "not_executed") discardPaneEnvFile(paneShell.envFile);
12719
+ return result;
12669
12720
  }
12670
12721
  function escapeForCmdSet(value) {
12671
12722
  return value.replace(/(["%])/g, "$1$1");
@@ -12964,6 +13015,7 @@ async function splitTeamWorkerPaneWithEvidence(splitTarget, direction, cwd, prov
12964
13015
  };
12965
13016
  }
12966
13017
  const splitType = direction === "right" ? "-h" : "-v";
13018
+ const splitPaneShell = workerPaneShellCommand();
12967
13019
  const splitArgs = [
12968
13020
  "split-window",
12969
13021
  splitType,
@@ -12975,11 +13027,12 @@ async function splitTeamWorkerPaneWithEvidence(splitTarget, direction, cwd, prov
12975
13027
  "#{pane_id} #{socket_path} #{pid}",
12976
13028
  "-c",
12977
13029
  cwd,
12978
- ...workerPaneShellCommand()
13030
+ ...splitPaneShell.args
12979
13031
  ];
12980
- const splitResult = await runGuardedNativeTmuxCommand(
13032
+ const splitResult = await runPaneCreationCommand(
12981
13033
  identity,
12982
- tmuxCommandString(splitArgs, ["#{pane_id} #{socket_path} #{pid}"])
13034
+ tmuxCommandString(splitArgs, ["#{pane_id} #{socket_path} #{pid}"]),
13035
+ splitPaneShell
12983
13036
  );
12984
13037
  const parsed = splitResult.outcome === "executed" ? parseTmuxCreationRecord(
12985
13038
  splitResult.stdout,
@@ -13081,6 +13134,7 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
13081
13134
  sessionMode: "detached-session",
13082
13135
  ...tmuxServerIdentity ? { tmuxServerIdentity: { ...tmuxServerIdentity } } : {}
13083
13136
  });
13137
+ const detachedPaneShell = workerPaneShellCommand();
13084
13138
  const detachedArgs = [
13085
13139
  "new-session",
13086
13140
  "-d",
@@ -13091,7 +13145,7 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
13091
13145
  detachedSessionName,
13092
13146
  "-c",
13093
13147
  cwd,
13094
- ...workerPaneShellCommand()
13148
+ ...detachedPaneShell.args
13095
13149
  ];
13096
13150
  const cleanupFreshDetachedServer = async () => {
13097
13151
  if (isPsmux() && freshSocketPathForEvidence) {
@@ -13120,9 +13174,10 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
13120
13174
  if (existingDetachedIdentity) {
13121
13175
  tmuxServerIdentity = existingDetachedIdentity;
13122
13176
  try {
13123
- detachedResult = await runGuardedNativeTmuxCommand(
13177
+ detachedResult = await runPaneCreationCommand(
13124
13178
  existingDetachedIdentity,
13125
- tmuxCommandString(detachedArgs, ["#S:0 #{pane_id} #{socket_path} #{pid}"])
13179
+ tmuxCommandString(detachedArgs, ["#S:0 #{pane_id} #{socket_path} #{pid}"]),
13180
+ detachedPaneShell
13126
13181
  );
13127
13182
  } catch (error) {
13128
13183
  const cleaned = await cleanupDetachedSession();
@@ -13182,11 +13237,13 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
13182
13237
  throw new Error("tmux_server_identity_unavailable");
13183
13238
  }
13184
13239
  freshDetachedServerIdentity = tmuxServerIdentity;
13185
- detachedResult = await runGuardedNativeTmuxCommand(
13240
+ detachedResult = await runPaneCreationCommand(
13186
13241
  tmuxServerIdentity,
13187
- tmuxCommandString(detachedArgs, ["#S:0 #{pane_id} #{socket_path} #{pid}"])
13242
+ tmuxCommandString(detachedArgs, ["#S:0 #{pane_id} #{socket_path} #{pid}"]),
13243
+ detachedPaneShell
13188
13244
  );
13189
13245
  } catch (error) {
13246
+ discardPaneEnvFile(detachedPaneShell.envFile);
13190
13247
  const cleaned = await cleanupDetachedSession();
13191
13248
  if (!cleaned && freshDetachedServerStarted) {
13192
13249
  throw new TeamSessionCreationError(
@@ -13366,6 +13423,7 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
13366
13423
  if (useDedicatedWindow) {
13367
13424
  const targetSession = sessionAndWindow.split(":")[0] ?? sessionAndWindow;
13368
13425
  const windowName = `omc-${sanitizeName(teamName)}`.slice(0, 32);
13426
+ const newWindowPaneShell = workerPaneShellCommand();
13369
13427
  const newWindowArgs = [
13370
13428
  "new-window",
13371
13429
  "-d",
@@ -13378,13 +13436,14 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
13378
13436
  windowName,
13379
13437
  "-c",
13380
13438
  cwd,
13381
- ...workerPaneShellCommand()
13439
+ ...newWindowPaneShell.args
13382
13440
  ];
13383
13441
  let newWindowResult;
13384
13442
  try {
13385
- newWindowResult = await runGuardedNativeTmuxCommand(
13443
+ newWindowResult = await runPaneCreationCommand(
13386
13444
  tmuxServerIdentity,
13387
- tmuxCommandString(newWindowArgs, ["#S:#I #{pane_id} #{socket_path} #{pid}"])
13445
+ tmuxCommandString(newWindowArgs, ["#S:#I #{pane_id} #{socket_path} #{pid}"]),
13446
+ newWindowPaneShell
13388
13447
  );
13389
13448
  } catch (error) {
13390
13449
  const creationError = new TeamSessionCreationError(
@@ -13534,6 +13593,7 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
13534
13593
  continue;
13535
13594
  }
13536
13595
  const splitType = i === 0 ? "-h" : "-v";
13596
+ const splitPaneShell = workerPaneShellCommand();
13537
13597
  const splitArgs = [
13538
13598
  "split-window",
13539
13599
  splitType,
@@ -13545,11 +13605,12 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
13545
13605
  "#{pane_id} #{socket_path} #{pid}",
13546
13606
  "-c",
13547
13607
  cwd,
13548
- ...workerPaneShellCommand()
13608
+ ...splitPaneShell.args
13549
13609
  ];
13550
- const splitResult = await runGuardedNativeTmuxCommand(
13610
+ const splitResult = await runPaneCreationCommand(
13551
13611
  tmuxServerIdentity,
13552
- tmuxCommandString(splitArgs, ["#{pane_id} #{socket_path} #{pid}"])
13612
+ tmuxCommandString(splitArgs, ["#{pane_id} #{socket_path} #{pid}"]),
13613
+ splitPaneShell
13553
13614
  );
13554
13615
  if (splitResult.outcome !== "executed") {
13555
13616
  const creationError = new TeamSessionCreationError(
@@ -14824,7 +14885,7 @@ var init_tmux_session = __esm({
14824
14885
 
14825
14886
  // src/team/mcp-comm.ts
14826
14887
  import { realpathSync as realpathSync4 } from "node:fs";
14827
- import { basename as basename13, dirname as dirname22, join as join26 } from "node:path";
14888
+ import { basename as basename13, dirname as dirname23, join as join26 } from "node:path";
14828
14889
  function isConfirmedNotification(outcome) {
14829
14890
  if (!outcome.ok) return false;
14830
14891
  if (outcome.transport !== "hook") return true;
@@ -14850,7 +14911,7 @@ function canonicalNotificationLockIdentity(lockPath) {
14850
14911
  return realpathSync4(lockPath);
14851
14912
  } catch {
14852
14913
  try {
14853
- return join26(realpathSync4(dirname22(lockPath)), basename13(lockPath));
14914
+ return join26(realpathSync4(dirname23(lockPath)), basename13(lockPath));
14854
14915
  } catch {
14855
14916
  return lockPath;
14856
14917
  }
@@ -15316,12 +15377,12 @@ var init_mcp_comm = __esm({
15316
15377
 
15317
15378
  // src/agents/prompt-helpers.ts
15318
15379
  import { readdirSync as readdirSync10 } from "fs";
15319
- import { join as join27, dirname as dirname23, basename as basename14 } from "path";
15380
+ import { join as join27, dirname as dirname24, basename as basename14 } from "path";
15320
15381
  import { fileURLToPath as fileURLToPath4 } from "url";
15321
15382
  function getPackageDir3() {
15322
15383
  if (typeof __dirname !== "undefined" && __dirname) {
15323
15384
  const currentDirName = basename14(__dirname);
15324
- const parentDirName = basename14(dirname23(__dirname));
15385
+ const parentDirName = basename14(dirname24(__dirname));
15325
15386
  if (currentDirName === "bridge") {
15326
15387
  return join27(__dirname, "..");
15327
15388
  }
@@ -15331,7 +15392,7 @@ function getPackageDir3() {
15331
15392
  }
15332
15393
  try {
15333
15394
  const __filename = fileURLToPath4(import.meta.url);
15334
- const __dirname2 = dirname23(__filename);
15395
+ const __dirname2 = dirname24(__filename);
15335
15396
  const currentDirName = basename14(__dirname2);
15336
15397
  if (currentDirName === "bridge") {
15337
15398
  return join27(__dirname2, "..");
@@ -15385,7 +15446,7 @@ var init_prompt_helpers = __esm({
15385
15446
 
15386
15447
  // src/team/worker-bootstrap.ts
15387
15448
  import { mkdir as mkdir9, writeFile as writeFile7, appendFile as appendFile2 } from "fs/promises";
15388
- import { join as join28, dirname as dirname24 } from "path";
15449
+ import { join as join28, dirname as dirname25 } from "path";
15389
15450
  function buildInstructionPath(...parts) {
15390
15451
  return join28(...parts).replaceAll("\\", "/");
15391
15452
  }
@@ -15655,7 +15716,7 @@ ${bootstrapInstructions}
15655
15716
  }
15656
15717
  async function composeInitialInbox(teamName, workerName, content, cwd, cliOutputContract) {
15657
15718
  const inboxPath = join28(teamStateRoot(cwd, sanitizeName(teamName)), "workers", sanitizeName(workerName), "inbox.md");
15658
- await mkdir9(dirname24(inboxPath), { recursive: true });
15719
+ await mkdir9(dirname25(inboxPath), { recursive: true });
15659
15720
  const finalContent = cliOutputContract && !content.includes(cliOutputContract) ? `${content}
15660
15721
  ${cliOutputContract}` : content;
15661
15722
  await writeFile7(inboxPath, finalContent, "utf-8");
@@ -15665,7 +15726,7 @@ async function appendToInbox(teamName, workerName, message, cwd) {
15665
15726
  const safeWorker = sanitizeName(workerName);
15666
15727
  const inboxPath = join28(teamStateRoot(cwd, safeTeam), "workers", safeWorker, "inbox.md");
15667
15728
  validateResolvedPath(inboxPath, teamStateRoot(cwd, safeTeam));
15668
- await mkdir9(dirname24(inboxPath), { recursive: true });
15729
+ await mkdir9(dirname25(inboxPath), { recursive: true });
15669
15730
  await appendFile2(inboxPath, `
15670
15731
 
15671
15732
  ---
@@ -15684,7 +15745,7 @@ async function writeWorkerOverlay(params) {
15684
15745
  const { teamName, workerName, cwd } = params;
15685
15746
  const overlay = generateWorkerOverlay(params);
15686
15747
  const overlayPath = join28(teamStateRoot(cwd, sanitizeName(teamName)), "workers", sanitizeName(workerName), "AGENTS.md");
15687
- await mkdir9(dirname24(overlayPath), { recursive: true });
15748
+ await mkdir9(dirname25(overlayPath), { recursive: true });
15688
15749
  await writeFile7(overlayPath, overlay, "utf-8");
15689
15750
  return overlayPath;
15690
15751
  }
@@ -15884,7 +15945,7 @@ var init_mailbox_outstanding = __esm({
15884
15945
 
15885
15946
  // src/team/events.ts
15886
15947
  import { randomUUID as randomUUID15 } from "crypto";
15887
- import { dirname as dirname25 } from "path";
15948
+ import { dirname as dirname26 } from "path";
15888
15949
  import { mkdir as mkdir10, readFile as readFile12, appendFile as appendFile3 } from "fs/promises";
15889
15950
  import { existsSync as existsSync25 } from "fs";
15890
15951
  async function appendTeamEvent(teamName, event, cwd) {
@@ -15895,7 +15956,7 @@ async function appendTeamEvent(teamName, event, cwd) {
15895
15956
  ...event
15896
15957
  };
15897
15958
  const p = absPath(cwd, TeamPaths.events(teamName));
15898
- await mkdir10(dirname25(p), { recursive: true });
15959
+ await mkdir10(dirname26(p), { recursive: true });
15899
15960
  await appendFile3(p, `${JSON.stringify(full)}
15900
15961
  `, "utf8");
15901
15962
  return full;
@@ -15938,7 +15999,7 @@ async function emitMonitorDerivedEvents(teamName, tasks, workers, previousSnapsh
15938
15999
  }, cwd).catch(logDerivedEventFailure);
15939
16000
  }
15940
16001
  if (prevState === "working" && worker.status.state === "idle") {
15941
- const mailboxDir = dirname25(absPath(cwd, TeamPaths.mailbox(teamName, worker.name)));
16002
+ const mailboxDir = dirname26(absPath(cwd, TeamPaths.mailbox(teamName, worker.name)));
15942
16003
  const outstanding = await countOutstandingForWorker(mailboxDir, worker.name);
15943
16004
  await appendTeamEvent(teamName, {
15944
16005
  type: "worker_idle",
@@ -16091,7 +16152,7 @@ var init_worktree_cleanup_safety = __esm({
16091
16152
  });
16092
16153
 
16093
16154
  // src/team/git-worktree.ts
16094
- import { existsSync as existsSync27, realpathSync as realpathSync6, readFileSync as readFileSync18, readdirSync as readdirSync11, rmSync as rmSync2, unlinkSync as unlinkSync9, writeFileSync as writeFileSync6 } from "node:fs";
16155
+ import { existsSync as existsSync27, realpathSync as realpathSync6, readFileSync as readFileSync18, readdirSync as readdirSync11, rmSync as rmSync3, unlinkSync as unlinkSync9, writeFileSync as writeFileSync7 } from "node:fs";
16095
16156
  import { join as join31, resolve as resolve10 } from "node:path";
16096
16157
  import { execFileSync as execFileSync5 } from "node:child_process";
16097
16158
  function getWorktreePath(repoRoot, teamName, workerName) {
@@ -16240,7 +16301,7 @@ function installWorktreeRootAgents(teamName, workerName, repoRoot, worktreePath,
16240
16301
  installedAt: (/* @__PURE__ */ new Date()).toISOString()
16241
16302
  };
16242
16303
  atomicWriteJson(backupPath, backup);
16243
- writeFileSync6(agentsPath, overlayContent, "utf-8");
16304
+ writeFileSync7(agentsPath, overlayContent, "utf-8");
16244
16305
  }
16245
16306
  function restoreWorktreeRootAgents(teamName, workerName, repoRoot, worktreePath) {
16246
16307
  const omcRoot = getOmcRoot(repoRoot);
@@ -16265,7 +16326,7 @@ function restoreWorktreeRootAgents(teamName, workerName, repoRoot, worktreePath)
16265
16326
  return { restored: false, reason: "agents_dirty" };
16266
16327
  }
16267
16328
  if (backup.hadOriginal) {
16268
- writeFileSync6(agentsPath, backup.originalContent ?? "", "utf-8");
16329
+ writeFileSync7(agentsPath, backup.originalContent ?? "", "utf-8");
16269
16330
  } else if (existsSync27(agentsPath)) {
16270
16331
  unlinkSync9(agentsPath);
16271
16332
  }
@@ -16489,7 +16550,7 @@ function removeWorkerWorktree(teamName, workerName, repoRoot) {
16489
16550
  expectedRoots: [join31(getOmcRoot(repoRoot), "team", sanitizeName(teamName), "worktrees")],
16490
16551
  mainRepoRoots: [repoRoot]
16491
16552
  });
16492
- rmSync2(wtPath, { recursive: true, force: true });
16553
+ rmSync3(wtPath, { recursive: true, force: true });
16493
16554
  }
16494
16555
  forgetMetadataUnlocked(repoRoot, teamName, workerName);
16495
16556
  });
@@ -17182,7 +17243,7 @@ var init_merge_coordinator = __esm({
17182
17243
  // src/team/leader-inbox.ts
17183
17244
  import { appendFile as appendFile4, mkdir as mkdir11, writeFile as writeFile8 } from "fs/promises";
17184
17245
  import { existsSync as existsSync28 } from "fs";
17185
- import { dirname as dirname26, join as join33 } from "path";
17246
+ import { dirname as dirname27, join as join33 } from "path";
17186
17247
  function leaderInboxPath(teamName, cwd) {
17187
17248
  const safe = sanitizeName(teamName);
17188
17249
  return join33(teamStateRoot(cwd, safe), "leader", "inbox.md");
@@ -17190,7 +17251,7 @@ function leaderInboxPath(teamName, cwd) {
17190
17251
  async function ensureLeaderInbox(teamName, cwd) {
17191
17252
  const inboxPath = leaderInboxPath(teamName, cwd);
17192
17253
  validateResolvedPath(inboxPath, teamStateRoot(cwd, sanitizeName(teamName)));
17193
- await mkdir11(dirname26(inboxPath), { recursive: true });
17254
+ await mkdir11(dirname27(inboxPath), { recursive: true });
17194
17255
  if (!existsSync28(inboxPath)) {
17195
17256
  await writeFile8(inboxPath, LEADER_INBOX_HEADER, "utf-8");
17196
17257
  }
@@ -17199,7 +17260,7 @@ async function ensureLeaderInbox(teamName, cwd) {
17199
17260
  async function appendToLeaderInbox(teamName, message, cwd) {
17200
17261
  const inboxPath = leaderInboxPath(teamName, cwd);
17201
17262
  validateResolvedPath(inboxPath, teamStateRoot(cwd, sanitizeName(teamName)));
17202
- await mkdir11(dirname26(inboxPath), { recursive: true });
17263
+ await mkdir11(dirname27(inboxPath), { recursive: true });
17203
17264
  await appendFile4(inboxPath, `
17204
17265
 
17205
17266
  ---
@@ -17289,7 +17350,7 @@ var init_conflict_mailbox = __esm({
17289
17350
  // src/team/worker-commit-cadence.ts
17290
17351
  import { existsSync as existsSync29, watch as fsWatch } from "fs";
17291
17352
  import { readFile as readFile13, writeFile as writeFile9, mkdir as mkdir12, unlink as unlink6 } from "fs/promises";
17292
- import { join as join34, dirname as dirname27 } from "path";
17353
+ import { join as join34, dirname as dirname28 } from "path";
17293
17354
  import { exec } from "child_process";
17294
17355
  function ownsCadence(ctx) {
17295
17356
  const current = cadenceOwners.get(ctx.worktreePath);
@@ -17356,7 +17417,7 @@ async function installPostToolUseHook(worktreePath, workerName) {
17356
17417
  }
17357
17418
  async function pauseHookViaSentinel(worktreePath) {
17358
17419
  const sentinelPath = join34(worktreePath, SENTINEL_FILENAME);
17359
- await mkdir12(dirname27(sentinelPath), { recursive: true });
17420
+ await mkdir12(dirname28(sentinelPath), { recursive: true });
17360
17421
  await writeFile9(sentinelPath, "", "utf-8");
17361
17422
  }
17362
17423
  async function resumeHookViaSentinel(worktreePath) {
@@ -17467,7 +17528,7 @@ var init_worker_commit_cadence = __esm({
17467
17528
  import { execFileSync as execFileSync7 } from "node:child_process";
17468
17529
  import { existsSync as existsSync30 } from "node:fs";
17469
17530
  import { mkdir as mkdir13, appendFile as appendFile5 } from "node:fs/promises";
17470
- import { dirname as dirname28, join as join35 } from "node:path";
17531
+ import { dirname as dirname29, join as join35 } from "node:path";
17471
17532
  function mergerWorktreePathFor(repoRoot, teamName) {
17472
17533
  return join35(getOmcRoot(repoRoot), "team", sanitizeName(teamName), "merger");
17473
17534
  }
@@ -17511,7 +17572,7 @@ function assertRuntimeV2Gate() {
17511
17572
  }
17512
17573
  async function appendEvent(repoRoot, teamName, event) {
17513
17574
  const path5 = orchestratorEventLogPath(repoRoot, teamName);
17514
- await mkdir13(dirname28(path5), { recursive: true });
17575
+ await mkdir13(dirname29(path5), { recursive: true });
17515
17576
  const full = {
17516
17577
  ts: (/* @__PURE__ */ new Date()).toISOString(),
17517
17578
  team: teamName,
@@ -17570,7 +17631,7 @@ function isWorktreeRegistered(repoRoot, wtPath) {
17570
17631
  return false;
17571
17632
  }
17572
17633
  function ensureMergerWorktree(repoRoot, mergerPath, leaderBranch) {
17573
- ensureDirWithMode(dirname28(mergerPath));
17634
+ ensureDirWithMode(dirname29(mergerPath));
17574
17635
  if (existsSync30(mergerPath) && isWorktreeRegistered(repoRoot, mergerPath)) {
17575
17636
  return;
17576
17637
  }
@@ -18025,7 +18086,7 @@ ${dirtyFiles.map((f) => `- \`${f}\``).join("\n")}`;
18025
18086
  } catch {
18026
18087
  }
18027
18088
  const auditPath = teardownAuditPath(config.repoRoot, config.teamName);
18028
- await mkdir13(dirname28(auditPath), { recursive: true });
18089
+ await mkdir13(dirname29(auditPath), { recursive: true });
18029
18090
  for (const u of unmerged) {
18030
18091
  const row = JSON.stringify({
18031
18092
  type: "unmerged_at_shutdown",
@@ -23279,10 +23340,10 @@ import {
23279
23340
  readFileSync as readFileSync22,
23280
23341
  renameSync as renameSync5,
23281
23342
  unlinkSync as unlinkSync10,
23282
- writeFileSync as writeFileSync7
23343
+ writeFileSync as writeFileSync8
23283
23344
  } from "fs";
23284
23345
  import { readFile as readFile18 } from "fs/promises";
23285
- import { dirname as dirname30, join as join41, resolve as resolve13 } from "path";
23346
+ import { dirname as dirname31, join as join41, resolve as resolve13 } from "path";
23286
23347
  import { fileURLToPath as fileURLToPath5 } from "url";
23287
23348
 
23288
23349
  // src/team/api-interop.ts
@@ -23302,7 +23363,7 @@ init_git_worktree();
23302
23363
  init_swallowed_error();
23303
23364
  init_types();
23304
23365
  import { existsSync as existsSync32, readFileSync as readFileSync20 } from "node:fs";
23305
- import { dirname as dirname29, join as join38, resolve as resolvePath } from "node:path";
23366
+ import { dirname as dirname30, join as join38, resolve as resolvePath } from "node:path";
23306
23367
  var TEAM_UPDATE_TASK_MUTABLE_FIELDS = /* @__PURE__ */ new Set(["subject", "description", "blocked_by", "requires_code_change", "delegation"]);
23307
23368
  var TEAM_UPDATE_TASK_REQUEST_FIELDS = /* @__PURE__ */ new Set(["team_name", "task_id", "workingDirectory", ...TEAM_UPDATE_TASK_MUTABLE_FIELDS]);
23308
23369
  var RECOVER_WORKER_REQUEST_FIELDS = /* @__PURE__ */ new Set(["team_name", "worker", "request_id", "timeout_ms"]);
@@ -23536,7 +23597,7 @@ function stateRootToWorkingDirectory(stateRoot2) {
23536
23597
  if (idx >= 0) {
23537
23598
  const workspaceRoot = absolute.slice(0, idx);
23538
23599
  if (workspaceRoot && workspaceRoot !== "/") return workspaceRoot;
23539
- return dirname29(dirname29(dirname29(dirname29(absolute))));
23600
+ return dirname30(dirname30(dirname30(dirname30(absolute))));
23540
23601
  }
23541
23602
  }
23542
23603
  for (const marker of ["/.omg/state", "/.omx/state"]) {
@@ -23544,10 +23605,10 @@ function stateRootToWorkingDirectory(stateRoot2) {
23544
23605
  if (idx >= 0) {
23545
23606
  const workspaceRoot = absolute.slice(0, idx);
23546
23607
  if (workspaceRoot && workspaceRoot !== "/") return workspaceRoot;
23547
- return dirname29(dirname29(absolute));
23608
+ return dirname30(dirname30(absolute));
23548
23609
  }
23549
23610
  }
23550
- return dirname29(dirname29(absolute));
23611
+ return dirname30(dirname30(absolute));
23551
23612
  }
23552
23613
  function resolveTeamWorkingDirectoryFromMetadata(teamName, candidateCwd, workerContext) {
23553
23614
  const teamRoot = join38(getOmcRoot(candidateCwd), "state", "team", teamName);
@@ -23590,7 +23651,7 @@ function resolveTeamWorkingDirectory(teamName, preferredCwd) {
23590
23651
  if (teamStateExists(normalizedTeamName, cursor)) {
23591
23652
  return resolveTeamWorkingDirectoryFromMetadata(normalizedTeamName, cursor, workerContext) ?? cursor;
23592
23653
  }
23593
- const parent = dirname29(cursor);
23654
+ const parent = dirname30(cursor);
23594
23655
  if (!parent || parent === cursor) break;
23595
23656
  cursor = parent;
23596
23657
  }
@@ -24836,7 +24897,7 @@ function resolveRuntimeCliPath2(env = process.env) {
24836
24897
  if (env.OMC_RUNTIME_CLI_PATH) {
24837
24898
  return env.OMC_RUNTIME_CLI_PATH;
24838
24899
  }
24839
- const moduleDir = dirname30(fileURLToPath5(import.meta.url));
24900
+ const moduleDir = dirname31(fileURLToPath5(import.meta.url));
24840
24901
  return join41(moduleDir, "../../bridge/runtime-cli.cjs");
24841
24902
  }
24842
24903
  function ensureJobsDir(jobsDir) {
@@ -24961,7 +25022,7 @@ function writeJobToDiskUnlocked(jobId, job, jobsDir) {
24961
25022
  const targetPath = jobPath(jobsDir, jobId);
24962
25023
  const tempPath = `${targetPath}.tmp.${process.pid}.${randomUUID17()}`;
24963
25024
  try {
24964
- writeFileSync7(tempPath, JSON.stringify(job), { encoding: "utf-8", mode: 384 });
25025
+ writeFileSync8(tempPath, JSON.stringify(job), { encoding: "utf-8", mode: 384 });
24965
25026
  renameSync5(tempPath, targetPath);
24966
25027
  } finally {
24967
25028
  try {
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=run-cjs-fail-closed-timeout.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-cjs-fail-closed-timeout.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/run-cjs-fail-closed-timeout.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,68 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
2
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'fs';
3
+ import { tmpdir } from 'os';
4
+ import { join } from 'path';
5
+ import { spawnSync } from 'child_process';
6
+ /**
7
+ * The fork's fail-closed contract in scripts/run.cjs: with OMC_HOOK_FAIL_CLOSED=1
8
+ * a hook timeout exits 124 (generic child, trusted Worker, and the SessionEnd
9
+ * foreground budget); without it the runner stays fail-open (exit 0).
10
+ */
11
+ const RUN_CJS_PATH = join(__dirname, '..', '..', 'scripts', 'run.cjs');
12
+ const NODE = process.execPath;
13
+ const HANG = 'setTimeout(() => process.exit(0), 20000);';
14
+ describe('run.cjs — OMC_HOOK_FAIL_CLOSED hook timeouts', () => {
15
+ let tmpDir;
16
+ beforeEach(() => {
17
+ tmpDir = mkdtempSync(join(tmpdir(), 'omc-run-cjs-fail-closed-'));
18
+ });
19
+ afterEach(() => {
20
+ rmSync(tmpDir, { recursive: true, force: true });
21
+ });
22
+ function plugin(name, script, event, timeoutSec) {
23
+ const root = join(tmpDir, `${name}-root`);
24
+ mkdirSync(join(root, 'scripts'), { recursive: true });
25
+ mkdirSync(join(root, 'hooks'), { recursive: true });
26
+ writeFileSync(join(root, 'scripts', 'run.cjs'), '// plugin-root marker');
27
+ writeFileSync(join(root, 'scripts', name), script);
28
+ writeFileSync(join(root, 'hooks', 'hooks.json'), JSON.stringify({
29
+ hooks: {
30
+ [event]: [{ matcher: '', hooks: [{
31
+ type: 'command',
32
+ command: `node "$CLAUDE_PLUGIN_ROOT"/scripts/run.cjs "$CLAUDE_PLUGIN_ROOT"/scripts/${name}`,
33
+ timeout: timeoutSec,
34
+ }] }],
35
+ },
36
+ }));
37
+ return join(root, 'scripts', name);
38
+ }
39
+ function run(target, failClosed, extraEnv = {}) {
40
+ const env = { ...process.env, CLAUDE_PLUGIN_ROOT: join(target, '..', '..'), ...extraEnv };
41
+ delete env.OMC_HOOK_FAIL_CLOSED;
42
+ if (failClosed)
43
+ env.OMC_HOOK_FAIL_CLOSED = '1';
44
+ const result = spawnSync(NODE, [RUN_CJS_PATH, target], { encoding: 'utf-8', env, input: '{}', timeout: 30_000 });
45
+ return { status: result.status, stderr: result.stderr || '' };
46
+ }
47
+ it.each([
48
+ ['generic child', 'slow-stop.cjs', HANG, 'Stop'],
49
+ ['trusted Worker', 'pre-tool-enforcer.mjs', HANG, 'PreToolUse'],
50
+ ])('%s: timeout exits 124 when fail-closed, 0 otherwise', (_label, name, script, event) => {
51
+ const target = plugin(name, script, event, 2);
52
+ const closed = run(target, true);
53
+ expect(closed.status, closed.stderr).toBe(124);
54
+ expect(closed.stderr).toContain('exiting fail-closed (124).');
55
+ const open = run(target, false);
56
+ expect(open.status, open.stderr).toBe(0);
57
+ expect(open.stderr).toContain('exiting fail-open.');
58
+ });
59
+ it('SessionEnd foreground budget: timeout exits 124 when fail-closed, 0 otherwise', () => {
60
+ const target = plugin('session-end.mjs', 'await new Promise((r) => setTimeout(r, 20000));', 'SessionEnd', 5);
61
+ const env = { NODE_ENV: 'test', OMC_SESSION_END_TEST_FOREGROUND_TIMEOUT_MS: '500' };
62
+ const closed = run(target, true, env);
63
+ expect(closed.status, closed.stderr).toBe(124);
64
+ const open = run(target, false, env);
65
+ expect(open.status, open.stderr).toBe(0);
66
+ });
67
+ });
68
+ //# sourceMappingURL=run-cjs-fail-closed-timeout.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-cjs-fail-closed-timeout.test.js","sourceRoot":"","sources":["../../src/__tests__/run-cjs-fail-closed-timeout.test.ts"],"names":[],"mappings":"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"}