oh-my-copilot 5.12.1 → 5.12.2

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 (478) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/bridge/__pycache__/gyoshu_bridge.cpython-312.pyc +0 -0
  4. package/bridge/claude-md-coordinator.cjs +2 -2
  5. package/bridge/cli.cjs +2302 -436
  6. package/bridge/mcp-server.cjs +384 -46
  7. package/bridge/runtime-cli.cjs +225 -50
  8. package/bridge/team-bridge.cjs +62 -9
  9. package/bridge/team-mcp.cjs +144 -25
  10. package/bridge/team.js +189 -56
  11. package/dist/__tests__/artifact-descriptor-handoff.test.js +1 -1
  12. package/dist/__tests__/artifact-descriptor-handoff.test.js.map +1 -1
  13. package/dist/__tests__/auto-update.test.js +18 -14
  14. package/dist/__tests__/auto-update.test.js.map +1 -1
  15. package/dist/__tests__/config-dir.test.js +12 -3
  16. package/dist/__tests__/config-dir.test.js.map +1 -1
  17. package/dist/__tests__/copilot-file-tool-injection.test.d.ts +2 -0
  18. package/dist/__tests__/copilot-file-tool-injection.test.d.ts.map +1 -0
  19. package/dist/__tests__/copilot-file-tool-injection.test.js +114 -0
  20. package/dist/__tests__/copilot-file-tool-injection.test.js.map +1 -0
  21. package/dist/__tests__/doctor-conflicts.test.js +2 -1
  22. package/dist/__tests__/doctor-conflicts.test.js.map +1 -1
  23. package/dist/__tests__/helpers/platform.d.ts +35 -0
  24. package/dist/__tests__/helpers/platform.d.ts.map +1 -0
  25. package/dist/__tests__/helpers/platform.js +129 -0
  26. package/dist/__tests__/helpers/platform.js.map +1 -0
  27. package/dist/__tests__/helpers/platform.test.d.ts +2 -0
  28. package/dist/__tests__/helpers/platform.test.d.ts.map +1 -0
  29. package/dist/__tests__/helpers/platform.test.js +131 -0
  30. package/dist/__tests__/helpers/platform.test.js.map +1 -0
  31. package/dist/__tests__/hook-bridge-main-module.test.js +2 -1
  32. package/dist/__tests__/hook-bridge-main-module.test.js.map +1 -1
  33. package/dist/__tests__/hooks/learner/bridge.test.js +2 -1
  34. package/dist/__tests__/hooks/learner/bridge.test.js.map +1 -1
  35. package/dist/__tests__/hooks-command-escaping.test.js +4 -1
  36. package/dist/__tests__/hooks-command-escaping.test.js.map +1 -1
  37. package/dist/__tests__/hud/call-counts.test.js +12 -1
  38. package/dist/__tests__/hud/call-counts.test.js.map +1 -1
  39. package/dist/__tests__/hud/state.test.js +3 -3
  40. package/dist/__tests__/hud/state.test.js.map +1 -1
  41. package/dist/__tests__/hud/usage-api-lock.test.js +8 -7
  42. package/dist/__tests__/hud/usage-api-lock.test.js.map +1 -1
  43. package/dist/__tests__/hud/usage-api-stale.test.js +8 -7
  44. package/dist/__tests__/hud/usage-api-stale.test.js.map +1 -1
  45. package/dist/__tests__/hud/usage-api.test.js +67 -66
  46. package/dist/__tests__/hud/usage-api.test.js.map +1 -1
  47. package/dist/__tests__/hud/windows-platform.test.js +5 -1
  48. package/dist/__tests__/hud/windows-platform.test.js.map +1 -1
  49. package/dist/__tests__/hud-api-key-source.test.js +5 -4
  50. package/dist/__tests__/hud-api-key-source.test.js.map +1 -1
  51. package/dist/__tests__/hud-cache-wrapper-4237.test.js +4 -1
  52. package/dist/__tests__/hud-cache-wrapper-4237.test.js.map +1 -1
  53. package/dist/__tests__/hud-cache-wrapper.test.js +8 -5
  54. package/dist/__tests__/hud-cache-wrapper.test.js.map +1 -1
  55. package/dist/__tests__/installer-omc-reference.test.js +2 -1
  56. package/dist/__tests__/installer-omc-reference.test.js.map +1 -1
  57. package/dist/__tests__/jev-shadow-sweep-lock.test.d.ts +2 -0
  58. package/dist/__tests__/jev-shadow-sweep-lock.test.d.ts.map +1 -0
  59. package/dist/__tests__/jev-shadow-sweep-lock.test.js +51 -0
  60. package/dist/__tests__/jev-shadow-sweep-lock.test.js.map +1 -0
  61. package/dist/__tests__/mnemosyne/finder.test.js +1 -1
  62. package/dist/__tests__/mnemosyne/finder.test.js.map +1 -1
  63. package/dist/__tests__/no-committed-build-artifacts.test.js +2 -1
  64. package/dist/__tests__/no-committed-build-artifacts.test.js.map +1 -1
  65. package/dist/__tests__/npm-package-bin-surface.test.js +26 -7
  66. package/dist/__tests__/npm-package-bin-surface.test.js.map +1 -1
  67. package/dist/__tests__/plugin-setup-deps.test.js +14 -5
  68. package/dist/__tests__/plugin-setup-deps.test.js.map +1 -1
  69. package/dist/__tests__/plugin-shipping-surface.test.js +6 -1
  70. package/dist/__tests__/plugin-shipping-surface.test.js.map +1 -1
  71. package/dist/__tests__/pre-tool-enforcer.test.js +3 -1
  72. package/dist/__tests__/pre-tool-enforcer.test.js.map +1 -1
  73. package/dist/__tests__/project-session-manager-review-worktree.test.js +2 -1
  74. package/dist/__tests__/project-session-manager-review-worktree.test.js.map +1 -1
  75. package/dist/__tests__/project-session-manager-worktree-protocol.test.js +10 -9
  76. package/dist/__tests__/project-session-manager-worktree-protocol.test.js.map +1 -1
  77. package/dist/__tests__/purge-stale-cache-relink.test.js +19 -15
  78. package/dist/__tests__/purge-stale-cache-relink.test.js.map +1 -1
  79. package/dist/__tests__/purge-stale-cache-symlink.integration.test.js +25 -21
  80. package/dist/__tests__/purge-stale-cache-symlink.integration.test.js.map +1 -1
  81. package/dist/__tests__/purge-stale-cache-validation.test.js +11 -9
  82. package/dist/__tests__/purge-stale-cache-validation.test.js.map +1 -1
  83. package/dist/__tests__/purge-stale-cache.integration.test.js +10 -8
  84. package/dist/__tests__/purge-stale-cache.integration.test.js.map +1 -1
  85. package/dist/__tests__/purge-stale-cache.test.js +60 -13
  86. package/dist/__tests__/purge-stale-cache.test.js.map +1 -1
  87. package/dist/__tests__/repair-plugin-cache-script.test.js +5 -2
  88. package/dist/__tests__/repair-plugin-cache-script.test.js.map +1 -1
  89. package/dist/__tests__/resolve-node.test.js +7 -4
  90. package/dist/__tests__/resolve-node.test.js.map +1 -1
  91. package/dist/__tests__/resolve-transcript-path.test.js +1 -1
  92. package/dist/__tests__/resolve-transcript-path.test.js.map +1 -1
  93. package/dist/__tests__/run-cjs-generic-timeout.test.js +23 -0
  94. package/dist/__tests__/run-cjs-generic-timeout.test.js.map +1 -1
  95. package/dist/__tests__/session-end-process-exit.test.js +27 -8
  96. package/dist/__tests__/session-end-process-exit.test.js.map +1 -1
  97. package/dist/__tests__/session-start-background-output.test.js +6 -3
  98. package/dist/__tests__/session-start-background-output.test.js.map +1 -1
  99. package/dist/__tests__/session-start-cache-cleanup.test.js +25 -15
  100. package/dist/__tests__/session-start-cache-cleanup.test.js.map +1 -1
  101. package/dist/__tests__/session-start-context-budget.test.js +8 -3
  102. package/dist/__tests__/session-start-context-budget.test.js.map +1 -1
  103. package/dist/__tests__/session-start-precompact-restore.test.js +14 -10
  104. package/dist/__tests__/session-start-precompact-restore.test.js.map +1 -1
  105. package/dist/__tests__/session-start-script-context.test.js +166 -16
  106. package/dist/__tests__/session-start-script-context.test.js.map +1 -1
  107. package/dist/__tests__/setup-claude-md-script.test.js +4 -2
  108. package/dist/__tests__/setup-claude-md-script.test.js.map +1 -1
  109. package/dist/__tests__/setup-progress-script.test.js +2 -1
  110. package/dist/__tests__/setup-progress-script.test.js.map +1 -1
  111. package/dist/__tests__/skills-runtime-probe-laziness.test.d.ts +2 -0
  112. package/dist/__tests__/skills-runtime-probe-laziness.test.d.ts.map +1 -0
  113. package/dist/__tests__/skills-runtime-probe-laziness.test.js +36 -0
  114. package/dist/__tests__/skills-runtime-probe-laziness.test.js.map +1 -0
  115. package/dist/__tests__/state-root-resolution.test.js +6 -2
  116. package/dist/__tests__/state-root-resolution.test.js.map +1 -1
  117. package/dist/__tests__/submodule-state-anchor.test.js +3 -1
  118. package/dist/__tests__/submodule-state-anchor.test.js.map +1 -1
  119. package/dist/__tests__/workflow-profile-activation-script.test.js +15 -5
  120. package/dist/__tests__/workflow-profile-activation-script.test.js.map +1 -1
  121. package/dist/autoresearch/__tests__/contracts.test.js +2 -1
  122. package/dist/autoresearch/__tests__/contracts.test.js.map +1 -1
  123. package/dist/autoresearch/__tests__/runtime-parity-extra.test.js +11 -11
  124. package/dist/autoresearch/__tests__/runtime-parity-extra.test.js.map +1 -1
  125. package/dist/autoresearch/__tests__/runtime.test.js +21 -4
  126. package/dist/autoresearch/__tests__/runtime.test.js.map +1 -1
  127. package/dist/autoresearch/runtime.d.ts.map +1 -1
  128. package/dist/autoresearch/runtime.js +18 -6
  129. package/dist/autoresearch/runtime.js.map +1 -1
  130. package/dist/cli/__tests__/ask.test.js +88 -38
  131. package/dist/cli/__tests__/ask.test.js.map +1 -1
  132. package/dist/cli/__tests__/autoresearch-guided.test.js +11 -9
  133. package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
  134. package/dist/cli/__tests__/autoresearch-intake.test.js +4 -4
  135. package/dist/cli/__tests__/autoresearch-intake.test.js.map +1 -1
  136. package/dist/cli/__tests__/doctor-plugin-dir.test.js +3 -3
  137. package/dist/cli/__tests__/doctor-plugin-dir.test.js.map +1 -1
  138. package/dist/cli/__tests__/launch.test.js +21 -4
  139. package/dist/cli/__tests__/launch.test.js.map +1 -1
  140. package/dist/cli/__tests__/plugin-dir-capture.test.js +5 -5
  141. package/dist/cli/__tests__/plugin-dir-capture.test.js.map +1 -1
  142. package/dist/cli/__tests__/self-improve-paths.test.js +11 -4
  143. package/dist/cli/__tests__/self-improve-paths.test.js.map +1 -1
  144. package/dist/cli/__tests__/tmux-env-forward.integration.test.js +2 -1
  145. package/dist/cli/__tests__/tmux-env-forward.integration.test.js.map +1 -1
  146. package/dist/cli/__tests__/tmux-utils.test.js +9 -1
  147. package/dist/cli/__tests__/tmux-utils.test.js.map +1 -1
  148. package/dist/cli/autoresearch-guided.js +1 -1
  149. package/dist/cli/autoresearch-guided.js.map +1 -1
  150. package/dist/cli/commands/__tests__/progress-cli.test.d.ts +2 -0
  151. package/dist/cli/commands/__tests__/progress-cli.test.d.ts.map +1 -0
  152. package/dist/cli/commands/__tests__/progress-cli.test.js +284 -0
  153. package/dist/cli/commands/__tests__/progress-cli.test.js.map +1 -0
  154. package/dist/cli/commands/__tests__/release-cli.test.d.ts +2 -0
  155. package/dist/cli/commands/__tests__/release-cli.test.d.ts.map +1 -0
  156. package/dist/cli/commands/__tests__/release-cli.test.js +64 -0
  157. package/dist/cli/commands/__tests__/release-cli.test.js.map +1 -0
  158. package/dist/cli/commands/__tests__/teleport.test.js +22 -21
  159. package/dist/cli/commands/__tests__/teleport.test.js.map +1 -1
  160. package/dist/cli/commands/progress.d.ts +55 -0
  161. package/dist/cli/commands/progress.d.ts.map +1 -0
  162. package/dist/cli/commands/progress.js +364 -0
  163. package/dist/cli/commands/progress.js.map +1 -0
  164. package/dist/cli/commands/release.d.ts +14 -0
  165. package/dist/cli/commands/release.d.ts.map +1 -0
  166. package/dist/cli/commands/release.js +135 -0
  167. package/dist/cli/commands/release.js.map +1 -0
  168. package/dist/cli/commands/smoke.d.ts +1 -1
  169. package/dist/cli/commands/smoke.d.ts.map +1 -1
  170. package/dist/cli/commands/smoke.js +1 -1
  171. package/dist/cli/commands/smoke.js.map +1 -1
  172. package/dist/cli/index.d.ts.map +1 -1
  173. package/dist/cli/index.js +5 -1
  174. package/dist/cli/index.js.map +1 -1
  175. package/dist/config/__tests__/loader.test.js +47 -0
  176. package/dist/config/__tests__/loader.test.js.map +1 -1
  177. package/dist/config/__tests__/plan-output.test.js +2 -1
  178. package/dist/config/__tests__/plan-output.test.js.map +1 -1
  179. package/dist/features/builtin-skills/runtime-guidance.d.ts +1 -1
  180. package/dist/features/builtin-skills/runtime-guidance.d.ts.map +1 -1
  181. package/dist/features/builtin-skills/runtime-guidance.js +8 -3
  182. package/dist/features/builtin-skills/runtime-guidance.js.map +1 -1
  183. package/dist/features/builtin-skills/skills.d.ts +2 -1
  184. package/dist/features/builtin-skills/skills.d.ts.map +1 -1
  185. package/dist/features/builtin-skills/skills.js +13 -8
  186. package/dist/features/builtin-skills/skills.js.map +1 -1
  187. package/dist/features/lookout/__tests__/lookout.test.js +8 -2
  188. package/dist/features/lookout/__tests__/lookout.test.js.map +1 -1
  189. package/dist/graph/__tests__/runtime/cli.test.js +20 -5
  190. package/dist/graph/__tests__/runtime/cli.test.js.map +1 -1
  191. package/dist/graph/__tests__/runtime/e2e-crash-recovery.test.js +2 -1
  192. package/dist/graph/__tests__/runtime/e2e-crash-recovery.test.js.map +1 -1
  193. package/dist/graph/__tests__/runtime/fence.test.js +2 -1
  194. package/dist/graph/__tests__/runtime/fence.test.js.map +1 -1
  195. package/dist/graph/__tests__/runtime/journal-epoch.test.js +2 -1
  196. package/dist/graph/__tests__/runtime/journal-epoch.test.js.map +1 -1
  197. package/dist/graph/__tests__/runtime/journal.test.js +2 -1
  198. package/dist/graph/__tests__/runtime/journal.test.js.map +1 -1
  199. package/dist/graph/__tests__/runtime/regression-matrix.test.js +2 -1
  200. package/dist/graph/__tests__/runtime/regression-matrix.test.js.map +1 -1
  201. package/dist/graph/__tests__/runtime/remote-approval.test.js +13 -10
  202. package/dist/graph/__tests__/runtime/remote-approval.test.js.map +1 -1
  203. package/dist/graph/__tests__/runtime/run-dir.test.js +13 -5
  204. package/dist/graph/__tests__/runtime/run-dir.test.js.map +1 -1
  205. package/dist/graph/__tests__/runtime/runner.test.js +2 -1
  206. package/dist/graph/__tests__/runtime/runner.test.js.map +1 -1
  207. package/dist/graph/__tests__/runtime/safe-fs.test.js +15 -12
  208. package/dist/graph/__tests__/runtime/safe-fs.test.js.map +1 -1
  209. package/dist/graph/__tests__/runtime/store.test.js +2 -1
  210. package/dist/graph/__tests__/runtime/store.test.js.map +1 -1
  211. package/dist/graph/runtime/safe-fs.js +2 -2
  212. package/dist/graph/runtime/safe-fs.js.map +1 -1
  213. package/dist/hooks/__tests__/bridge-routing.test.js +3 -0
  214. package/dist/hooks/__tests__/bridge-routing.test.js.map +1 -1
  215. package/dist/hooks/__tests__/bridge.test.js +2 -1
  216. package/dist/hooks/__tests__/bridge.test.js.map +1 -1
  217. package/dist/hooks/__tests__/precompact-restore.test.js +7 -6
  218. package/dist/hooks/__tests__/precompact-restore.test.js.map +1 -1
  219. package/dist/hooks/__tests__/workflow-drift-guard-script.test.js +10 -3
  220. package/dist/hooks/__tests__/workflow-drift-guard-script.test.js.map +1 -1
  221. package/dist/hooks/autopilot/__tests__/cancel.test.js +16 -11
  222. package/dist/hooks/autopilot/__tests__/cancel.test.js.map +1 -1
  223. package/dist/hooks/bridge.d.ts.map +1 -1
  224. package/dist/hooks/bridge.js +7 -0
  225. package/dist/hooks/bridge.js.map +1 -1
  226. package/dist/hooks/mode-registry/__tests__/session-isolation.test.js +5 -4
  227. package/dist/hooks/mode-registry/__tests__/session-isolation.test.js.map +1 -1
  228. package/dist/hooks/persistent-mode/__tests__/ultragoal-persistence.test.js +2 -1
  229. package/dist/hooks/persistent-mode/__tests__/ultragoal-persistence.test.js.map +1 -1
  230. package/dist/hooks/recovery/__tests__/storage.test.js +3 -0
  231. package/dist/hooks/recovery/__tests__/storage.test.js.map +1 -1
  232. package/dist/hooks/session-end/__tests__/callbacks.test.js +11 -9
  233. package/dist/hooks/session-end/__tests__/callbacks.test.js.map +1 -1
  234. package/dist/hooks/session-end/__tests__/cleanup-manifest.test.js +115 -1
  235. package/dist/hooks/session-end/__tests__/cleanup-manifest.test.js.map +1 -1
  236. package/dist/hooks/session-end/__tests__/session-end-timeout.test.js +6 -1
  237. package/dist/hooks/session-end/__tests__/session-end-timeout.test.js.map +1 -1
  238. package/dist/hooks/session-end/cleanup-manifest.d.ts +4 -0
  239. package/dist/hooks/session-end/cleanup-manifest.d.ts.map +1 -1
  240. package/dist/hooks/session-end/cleanup-manifest.js +33 -15
  241. package/dist/hooks/session-end/cleanup-manifest.js.map +1 -1
  242. package/dist/hooks/setup/__tests__/stdin-symlink.test.js +11 -6
  243. package/dist/hooks/setup/__tests__/stdin-symlink.test.js.map +1 -1
  244. package/dist/hooks/skill-bridge.cjs +60 -8
  245. package/dist/hooks/subagent-tracker/__tests__/index.test.js +74 -16
  246. package/dist/hooks/subagent-tracker/__tests__/index.test.js.map +1 -1
  247. package/dist/hooks/subagent-tracker/__tests__/session-isolation.test.js +6 -1
  248. package/dist/hooks/subagent-tracker/__tests__/session-isolation.test.js.map +1 -1
  249. package/dist/hooks/subagent-tracker/__tests__/worktree-evidence.test.js +11 -8
  250. package/dist/hooks/subagent-tracker/__tests__/worktree-evidence.test.js.map +1 -1
  251. package/dist/hud/__tests__/autopilot-profile.test.js +4 -3
  252. package/dist/hud/__tests__/autopilot-profile.test.js.map +1 -1
  253. package/dist/installer/__tests__/claude-md-transaction.test.js +16 -13
  254. package/dist/installer/__tests__/claude-md-transaction.test.js.map +1 -1
  255. package/dist/installer/__tests__/hook-templates.test.js +28 -0
  256. package/dist/installer/__tests__/hook-templates.test.js.map +1 -1
  257. package/dist/installer/__tests__/hud-cache-wrapper.test.js +4 -1
  258. package/dist/installer/__tests__/hud-cache-wrapper.test.js.map +1 -1
  259. package/dist/installer/__tests__/session-start-template.test.js +166 -15
  260. package/dist/installer/__tests__/session-start-template.test.js.map +1 -1
  261. package/dist/installer/__tests__/stale-cleanup.test.js +5 -3
  262. package/dist/installer/__tests__/stale-cleanup.test.js.map +1 -1
  263. package/dist/installer/__tests__/standalone-hook-reconcile.test.js +11 -3
  264. package/dist/installer/__tests__/standalone-hook-reconcile.test.js.map +1 -1
  265. package/dist/installer/index.d.ts.map +1 -1
  266. package/dist/installer/index.js +1 -0
  267. package/dist/installer/index.js.map +1 -1
  268. package/dist/interop/__tests__/mcp-bridge.test.js +4 -3
  269. package/dist/interop/__tests__/mcp-bridge.test.js.map +1 -1
  270. package/dist/lib/__tests__/agent-progress-rotation.test.d.ts +2 -0
  271. package/dist/lib/__tests__/agent-progress-rotation.test.d.ts.map +1 -0
  272. package/dist/lib/__tests__/agent-progress-rotation.test.js +45 -0
  273. package/dist/lib/__tests__/agent-progress-rotation.test.js.map +1 -0
  274. package/dist/lib/__tests__/agent-progress.test.d.ts +2 -0
  275. package/dist/lib/__tests__/agent-progress.test.d.ts.map +1 -0
  276. package/dist/lib/__tests__/agent-progress.test.js +175 -0
  277. package/dist/lib/__tests__/agent-progress.test.js.map +1 -0
  278. package/dist/lib/__tests__/atomic-write.test.js +95 -3
  279. package/dist/lib/__tests__/atomic-write.test.js.map +1 -1
  280. package/dist/lib/__tests__/mode-state-io.test.js +2 -1
  281. package/dist/lib/__tests__/mode-state-io.test.js.map +1 -1
  282. package/dist/lib/__tests__/mode-state-lock.test.js +46 -0
  283. package/dist/lib/__tests__/mode-state-lock.test.js.map +1 -1
  284. package/dist/lib/__tests__/plugin-dir.test.js +1 -1
  285. package/dist/lib/__tests__/plugin-dir.test.js.map +1 -1
  286. package/dist/lib/__tests__/worktree-cleanup-safety.test.js +2 -1
  287. package/dist/lib/__tests__/worktree-cleanup-safety.test.js.map +1 -1
  288. package/dist/lib/__tests__/worktree-paths-foreign-root.test.js +2 -1
  289. package/dist/lib/__tests__/worktree-paths-foreign-root.test.js.map +1 -1
  290. package/dist/lib/__tests__/worktree-paths-superproject-cache.test.js +2 -1
  291. package/dist/lib/__tests__/worktree-paths-superproject-cache.test.js.map +1 -1
  292. package/dist/lib/__tests__/worktree-paths-toplevel-cache.test.js +173 -3
  293. package/dist/lib/__tests__/worktree-paths-toplevel-cache.test.js.map +1 -1
  294. package/dist/lib/agent-progress.d.ts +113 -0
  295. package/dist/lib/agent-progress.d.ts.map +1 -0
  296. package/dist/lib/agent-progress.js +274 -0
  297. package/dist/lib/agent-progress.js.map +1 -0
  298. package/dist/lib/atomic-write.d.ts.map +1 -1
  299. package/dist/lib/atomic-write.js +59 -5
  300. package/dist/lib/atomic-write.js.map +1 -1
  301. package/dist/lib/worktree-paths.d.ts +2 -1
  302. package/dist/lib/worktree-paths.d.ts.map +1 -1
  303. package/dist/lib/worktree-paths.js +92 -9
  304. package/dist/lib/worktree-paths.js.map +1 -1
  305. package/dist/mcp/__tests__/team-server-artifact-convergence.test.js +4 -1
  306. package/dist/mcp/__tests__/team-server-artifact-convergence.test.js.map +1 -1
  307. package/dist/notifications/__tests__/approval-reply.test.js +2 -1
  308. package/dist/notifications/__tests__/approval-reply.test.js.map +1 -1
  309. package/dist/notifications/__tests__/session-registry-durability.test.js +2 -1
  310. package/dist/notifications/__tests__/session-registry-durability.test.js.map +1 -1
  311. package/dist/notifications/__tests__/session-registry.test.js +3 -2
  312. package/dist/notifications/__tests__/session-registry.test.js.map +1 -1
  313. package/dist/openclaw/__tests__/dead-pane-guard.test.js +3 -2
  314. package/dist/openclaw/__tests__/dead-pane-guard.test.js.map +1 -1
  315. package/dist/platform/__tests__/process-utils-pid-reuse.windows.test.d.ts +2 -0
  316. package/dist/platform/__tests__/process-utils-pid-reuse.windows.test.d.ts.map +1 -0
  317. package/dist/platform/__tests__/process-utils-pid-reuse.windows.test.js +87 -0
  318. package/dist/platform/__tests__/process-utils-pid-reuse.windows.test.js.map +1 -0
  319. package/dist/platform/process-utils.d.ts.map +1 -1
  320. package/dist/platform/process-utils.js +8 -2
  321. package/dist/platform/process-utils.js.map +1 -1
  322. package/dist/release/__tests__/checks.test.d.ts +2 -0
  323. package/dist/release/__tests__/checks.test.d.ts.map +1 -0
  324. package/dist/release/__tests__/checks.test.js +142 -0
  325. package/dist/release/__tests__/checks.test.js.map +1 -0
  326. package/dist/release/__tests__/engine.test.d.ts +2 -0
  327. package/dist/release/__tests__/engine.test.d.ts.map +1 -0
  328. package/dist/release/__tests__/engine.test.js +833 -0
  329. package/dist/release/__tests__/engine.test.js.map +1 -0
  330. package/dist/release/checks.d.ts +62 -0
  331. package/dist/release/checks.d.ts.map +1 -0
  332. package/dist/release/checks.js +180 -0
  333. package/dist/release/checks.js.map +1 -0
  334. package/dist/release/engine.d.ts +127 -0
  335. package/dist/release/engine.d.ts.map +1 -0
  336. package/dist/release/engine.js +910 -0
  337. package/dist/release/engine.js.map +1 -0
  338. package/dist/release/progress.d.ts +26 -0
  339. package/dist/release/progress.d.ts.map +1 -0
  340. package/dist/release/progress.js +45 -0
  341. package/dist/release/progress.js.map +1 -0
  342. package/dist/smoke/__tests__/copilot-sdk-driver.test.js +57 -1
  343. package/dist/smoke/__tests__/copilot-sdk-driver.test.js.map +1 -1
  344. package/dist/smoke/__tests__/copilot-sdk-scenarios.test.js +103 -1
  345. package/dist/smoke/__tests__/copilot-sdk-scenarios.test.js.map +1 -1
  346. package/dist/smoke/copilot-sdk-driver.d.ts +18 -1
  347. package/dist/smoke/copilot-sdk-driver.d.ts.map +1 -1
  348. package/dist/smoke/copilot-sdk-driver.js +69 -2
  349. package/dist/smoke/copilot-sdk-driver.js.map +1 -1
  350. package/dist/smoke/copilot-sdk-scenarios.d.ts +79 -5
  351. package/dist/smoke/copilot-sdk-scenarios.d.ts.map +1 -1
  352. package/dist/smoke/copilot-sdk-scenarios.js +209 -5
  353. package/dist/smoke/copilot-sdk-scenarios.js.map +1 -1
  354. package/dist/team/__tests__/api-interop.dispatch.test.js +5 -1
  355. package/dist/team/__tests__/api-interop.dispatch.test.js.map +1 -1
  356. package/dist/team/__tests__/audit-log.test.js +3 -2
  357. package/dist/team/__tests__/audit-log.test.js.map +1 -1
  358. package/dist/team/__tests__/auto-merge.perf.test.js +2 -1
  359. package/dist/team/__tests__/auto-merge.perf.test.js.map +1 -1
  360. package/dist/team/__tests__/git-worktree.test.js +3 -21
  361. package/dist/team/__tests__/git-worktree.test.js.map +1 -1
  362. package/dist/team/__tests__/issue-4412-cmux-startup.test.js +4 -1
  363. package/dist/team/__tests__/issue-4412-cmux-startup.test.js.map +1 -1
  364. package/dist/team/__tests__/leader-inbox.test.js +3 -2
  365. package/dist/team/__tests__/leader-inbox.test.js.map +1 -1
  366. package/dist/team/__tests__/mcp-comm.mailbox-notification.test.js +2 -1
  367. package/dist/team/__tests__/mcp-comm.mailbox-notification.test.js.map +1 -1
  368. package/dist/team/__tests__/recovery-pane-rollback.test.js +61 -31
  369. package/dist/team/__tests__/recovery-pane-rollback.test.js.map +1 -1
  370. package/dist/team/__tests__/runtime-cli.test.js +5 -4
  371. package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
  372. package/dist/team/__tests__/runtime-owner-client.test.js +5 -4
  373. package/dist/team/__tests__/runtime-owner-client.test.js.map +1 -1
  374. package/dist/team/__tests__/runtime-v2.dispatch.test.js +16 -13
  375. package/dist/team/__tests__/runtime-v2.dispatch.test.js.map +1 -1
  376. package/dist/team/__tests__/runtime-v2.shutdown.test.js +3 -1
  377. package/dist/team/__tests__/runtime-v2.shutdown.test.js.map +1 -1
  378. package/dist/team/__tests__/summary-report.test.js +9 -5
  379. package/dist/team/__tests__/summary-report.test.js.map +1 -1
  380. package/dist/team/__tests__/task-storage-integrity.test.js +3 -2
  381. package/dist/team/__tests__/task-storage-integrity.test.js.map +1 -1
  382. package/dist/team/__tests__/team-instance.test.js +4 -3
  383. package/dist/team/__tests__/team-instance.test.js.map +1 -1
  384. package/dist/team/__tests__/team-ops-write-atomic.test.d.ts +2 -0
  385. package/dist/team/__tests__/team-ops-write-atomic.test.d.ts.map +1 -0
  386. package/dist/team/__tests__/team-ops-write-atomic.test.js +62 -0
  387. package/dist/team/__tests__/team-ops-write-atomic.test.js.map +1 -0
  388. package/dist/team/__tests__/teardown-invariant.test.js +7 -3
  389. package/dist/team/__tests__/teardown-invariant.test.js.map +1 -1
  390. package/dist/team/__tests__/tmux-session.create-team.test.js +5 -0
  391. package/dist/team/__tests__/tmux-session.create-team.test.js.map +1 -1
  392. package/dist/team/__tests__/tmux-session.test.js +8 -0
  393. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  394. package/dist/team/__tests__/usage-tracker.test.js +2 -1
  395. package/dist/team/__tests__/usage-tracker.test.js.map +1 -1
  396. package/dist/team/__tests__/worker-activation-gate.test.js +9 -7
  397. package/dist/team/__tests__/worker-activation-gate.test.js.map +1 -1
  398. package/dist/team/__tests__/worker-launch-ack.test.js +356 -39
  399. package/dist/team/__tests__/worker-launch-ack.test.js.map +1 -1
  400. package/dist/team/__tests__/worker-launch-posix-transport.test.js +3 -2
  401. package/dist/team/__tests__/worker-launch-posix-transport.test.js.map +1 -1
  402. package/dist/team/__tests__/worktree-runtime-e2e.test.js +3 -2
  403. package/dist/team/__tests__/worktree-runtime-e2e.test.js.map +1 -1
  404. package/dist/team/runtime-owner-client.d.ts.map +1 -1
  405. package/dist/team/runtime-owner-client.js +3 -0
  406. package/dist/team/runtime-owner-client.js.map +1 -1
  407. package/dist/team/team-ops.d.ts.map +1 -1
  408. package/dist/team/team-ops.js +18 -1
  409. package/dist/team/team-ops.js.map +1 -1
  410. package/dist/team/worker-activation-gate.d.ts.map +1 -1
  411. package/dist/team/worker-activation-gate.js +3 -2
  412. package/dist/team/worker-activation-gate.js.map +1 -1
  413. package/dist/team/worker-launch-ack.d.ts +11 -0
  414. package/dist/team/worker-launch-ack.d.ts.map +1 -1
  415. package/dist/team/worker-launch-ack.js +154 -25
  416. package/dist/team/worker-launch-ack.js.map +1 -1
  417. package/dist/tools/__tests__/deepinit-manifest.test.js +24 -2
  418. package/dist/tools/__tests__/deepinit-manifest.test.js.map +1 -1
  419. package/dist/tools/__tests__/state-tools.test.js +43 -4
  420. package/dist/tools/__tests__/state-tools.test.js.map +1 -1
  421. package/dist/tools/__tests__/wiki-tools-foreign-root.test.js +2 -1
  422. package/dist/tools/__tests__/wiki-tools-foreign-root.test.js.map +1 -1
  423. package/dist/tools/deepinit-manifest.d.ts.map +1 -1
  424. package/dist/tools/deepinit-manifest.js +5 -3
  425. package/dist/tools/deepinit-manifest.js.map +1 -1
  426. package/dist/tools/lsp/__tests__/devcontainer.test.js +7 -2
  427. package/dist/tools/lsp/__tests__/devcontainer.test.js.map +1 -1
  428. package/dist/tools/lsp/devcontainer.d.ts.map +1 -1
  429. package/dist/tools/lsp/devcontainer.js +7 -1
  430. package/dist/tools/lsp/devcontainer.js.map +1 -1
  431. package/dist/tools/python-repl/__tests__/bridge-manager-cleanup.test.js +10 -0
  432. package/dist/tools/python-repl/__tests__/bridge-manager-cleanup.test.js.map +1 -1
  433. package/dist/tools/python-repl/__tests__/python-sandbox.test.js +10 -6
  434. package/dist/tools/python-repl/__tests__/python-sandbox.test.js.map +1 -1
  435. package/dist/tools/python-repl/__tests__/system-python.test.d.ts +2 -0
  436. package/dist/tools/python-repl/__tests__/system-python.test.d.ts.map +1 -0
  437. package/dist/tools/python-repl/__tests__/system-python.test.js +55 -0
  438. package/dist/tools/python-repl/__tests__/system-python.test.js.map +1 -0
  439. package/dist/tools/python-repl/bridge-manager.d.ts +14 -0
  440. package/dist/tools/python-repl/bridge-manager.d.ts.map +1 -1
  441. package/dist/tools/python-repl/bridge-manager.js +49 -8
  442. package/dist/tools/python-repl/bridge-manager.js.map +1 -1
  443. package/dist/utils/__tests__/paths.test.js +14 -13
  444. package/dist/utils/__tests__/paths.test.js.map +1 -1
  445. package/dist/utils/__tests__/plugin-cache-validation.test.d.ts +2 -0
  446. package/dist/utils/__tests__/plugin-cache-validation.test.d.ts.map +1 -0
  447. package/dist/utils/__tests__/plugin-cache-validation.test.js +81 -0
  448. package/dist/utils/__tests__/plugin-cache-validation.test.js.map +1 -0
  449. package/dist/utils/omc-cli-rendering.d.ts +1 -0
  450. package/dist/utils/omc-cli-rendering.d.ts.map +1 -1
  451. package/dist/utils/omc-cli-rendering.js +9 -9
  452. package/dist/utils/omc-cli-rendering.js.map +1 -1
  453. package/dist/utils/paths.d.ts +2 -0
  454. package/dist/utils/paths.d.ts.map +1 -1
  455. package/dist/utils/paths.js +10 -5
  456. package/dist/utils/paths.js.map +1 -1
  457. package/dist/utils/plugin-cache-validation.d.ts +8 -6
  458. package/dist/utils/plugin-cache-validation.d.ts.map +1 -1
  459. package/dist/utils/plugin-cache-validation.js +26 -15
  460. package/dist/utils/plugin-cache-validation.js.map +1 -1
  461. package/docs/CLAUDE.md +1 -1
  462. package/docs/DEVELOPERS.md +1 -0
  463. package/docs/HOOKS.md +1 -1
  464. package/docs/REFERENCE.md +38 -0
  465. package/package.json +2 -2
  466. package/plugin.json +1 -1
  467. package/scripts/lib/jev-shadow.mjs +6 -4
  468. package/scripts/lib/state-lock.mjs +21 -6
  469. package/scripts/lib/tool-input-paths.mjs +24 -0
  470. package/scripts/post-tool-directory-context-injector.mjs +10 -15
  471. package/scripts/post-tool-rules-injector.mjs +11 -16
  472. package/scripts/run-provider-advisor.js +4 -1
  473. package/scripts/run.cjs +9 -4
  474. package/scripts/session-start.mjs +28 -14
  475. package/scripts/verify-epic-3698-closure.mjs +2 -1
  476. package/skills/project-session-manager/lib/session.sh +2 -0
  477. package/skills/project-session-manager/lib/worktree.sh +9 -1
  478. package/templates/hooks/session-start.mjs +28 -14
package/bridge/cli.cjs CHANGED
@@ -3821,13 +3821,21 @@ var init_cache_occupancy = __esm({
3821
3821
  function isOmcPluginCacheIdentity(pluginName, marketplace) {
3822
3822
  return OMC_PLUGIN_CACHE_IDENTITIES.has(`${pluginName}@${marketplace}`.toLowerCase());
3823
3823
  }
3824
+ function identityPart(value) {
3825
+ if (typeof value === "bigint") return value;
3826
+ return Number.isSafeInteger(value) ? BigInt(value) : void 0;
3827
+ }
3824
3828
  function sameFileSystemIdentity(left, right) {
3825
- return typeof left.dev === "number" && typeof left.ino === "number" && left.ino !== 0 && typeof right.dev === "number" && typeof right.ino === "number" && right.ino !== 0 && left.dev === right.dev && left.ino === right.ino;
3829
+ const leftDev = identityPart(left.dev);
3830
+ const leftIno = identityPart(left.ino);
3831
+ const rightDev = identityPart(right.dev);
3832
+ const rightIno = identityPart(right.ino);
3833
+ return leftDev !== void 0 && leftIno !== void 0 && leftIno !== 0n && rightDev !== void 0 && rightIno !== void 0 && rightIno !== 0n && leftDev === rightDev && leftIno === rightIno;
3826
3834
  }
3827
3835
  function hasAncestorWithIdentity(path30, identity) {
3828
3836
  let currentPath = path30;
3829
3837
  while (true) {
3830
- if (sameFileSystemIdentity((0, import_fs2.statSync)(currentPath), identity)) return true;
3838
+ if (sameFileSystemIdentity((0, import_fs2.statSync)(currentPath, { bigint: true }), identity)) return true;
3831
3839
  const parentPath = (0, import_path3.dirname)(currentPath);
3832
3840
  if (parentPath === currentPath) return false;
3833
3841
  currentPath = parentPath;
@@ -3840,7 +3848,7 @@ function firstChildBelowDirectoryIdentity(path30, directoryIdentity) {
3840
3848
  const parentPath = (0, import_path3.dirname)(currentPath);
3841
3849
  if (parentPath === currentPath) return void 0;
3842
3850
  try {
3843
- if (sameFileSystemIdentity((0, import_fs2.statSync)(parentPath), directoryIdentity)) return (0, import_path3.basename)(currentPath);
3851
+ if (sameFileSystemIdentity((0, import_fs2.statSync)(parentPath, { bigint: true }), directoryIdentity)) return (0, import_path3.basename)(currentPath);
3844
3852
  } catch {
3845
3853
  }
3846
3854
  currentPath = parentPath;
@@ -3880,7 +3888,7 @@ function pathTraversesFileSystemIdentity(path30, identity) {
3880
3888
  for (let index = components.length - 1; index >= 0; index--) steps.push(components[index]);
3881
3889
  const activeLinks = /* @__PURE__ */ new Set();
3882
3890
  try {
3883
- if (sameFileSystemIdentity((0, import_fs2.lstatSync)(currentPath), identity)) return true;
3891
+ if (sameFileSystemIdentity((0, import_fs2.lstatSync)(currentPath, { bigint: true }), identity)) return true;
3884
3892
  } catch {
3885
3893
  return false;
3886
3894
  }
@@ -3898,7 +3906,7 @@ function pathTraversesFileSystemIdentity(path30, identity) {
3898
3906
  const nextPath = (0, import_path3.join)(currentPath, step);
3899
3907
  let nextStats;
3900
3908
  try {
3901
- nextStats = (0, import_fs2.lstatSync)(nextPath);
3909
+ nextStats = (0, import_fs2.lstatSync)(nextPath, { bigint: true });
3902
3910
  } catch {
3903
3911
  return false;
3904
3912
  }
@@ -3907,7 +3915,7 @@ function pathTraversesFileSystemIdentity(path30, identity) {
3907
3915
  currentPath = nextPath;
3908
3916
  continue;
3909
3917
  }
3910
- const linkKey = typeof nextStats.dev === "number" && typeof nextStats.ino === "number" && nextStats.ino !== 0 ? `inode:${nextStats.dev}:${nextStats.ino}` : `path:${process.platform === "win32" ? nextPath.toLowerCase() : nextPath}`;
3918
+ const linkKey = nextStats.ino !== 0n ? `inode:${nextStats.dev}:${nextStats.ino}` : `path:${process.platform === "win32" ? nextPath.toLowerCase() : nextPath}`;
3911
3919
  if (activeLinks.has(linkKey)) return false;
3912
3920
  let linkTarget;
3913
3921
  try {
@@ -3991,14 +3999,14 @@ function hasUsableOmcHookTargets(path30, staleVersionIdentity) {
3991
3999
  return true;
3992
4000
  }
3993
4001
  function hasResolvablePluginSymlinks(directory, staleVersionIdentity, ancestors = [], payload) {
3994
- const directoryStats = (0, import_fs2.statSync)(directory);
4002
+ const directoryStats = (0, import_fs2.statSync)(directory, { bigint: true });
3995
4003
  if (ancestors.some((identity) => sameFileSystemIdentity(directoryStats, identity))) return false;
3996
4004
  const branch = [...ancestors, directoryStats];
3997
4005
  const entries = (0, import_fs2.readdirSync)(directory, { withFileTypes: true });
3998
4006
  for (const entry2 of entries) {
3999
4007
  const entryPath = (0, import_path3.join)(directory, entry2.name);
4000
4008
  if (entry2.isSymbolicLink()) {
4001
- const entryStats = (0, import_fs2.statSync)(entryPath);
4009
+ const entryStats = (0, import_fs2.statSync)(entryPath, { bigint: true });
4002
4010
  if (pathTraversesFileSystemIdentity(entryPath, staleVersionIdentity)) return false;
4003
4011
  if (entryStats.isDirectory()) {
4004
4012
  if (branch.some((identity) => sameFileSystemIdentity(entryStats, identity))) continue;
@@ -4228,6 +4236,9 @@ function compareSemverDesc(a, b) {
4228
4236
  }
4229
4237
  return 0;
4230
4238
  }
4239
+ function pickHighestVersionDir(dirs, base = import_path4.basename) {
4240
+ return [...dirs].sort((a, b) => compareSemverDesc(base(a), base(b)))[0];
4241
+ }
4231
4242
  function purgeStalePluginCacheVersions(options) {
4232
4243
  const result = {
4233
4244
  removed: 0,
@@ -4299,7 +4310,7 @@ function purgeStalePluginCacheVersions(options) {
4299
4310
  const lexicalActiveVersionDirsHere = activePathIdentities.filter((ap) => ap.startsWith(pluginDirNorm + "/")).map((ap) => (0, import_path4.join)(pluginDir, ap.slice(pluginDirNorm.length + 1).split("/")[0]));
4300
4311
  const filesystemActiveVersionDirsHere = [];
4301
4312
  try {
4302
- const pluginDirStats = (0, import_fs3.statSync)(pluginDir);
4313
+ const pluginDirStats = (0, import_fs3.statSync)(pluginDir, { bigint: true });
4303
4314
  for (const activePath of activePathsArray) {
4304
4315
  const versionName = firstChildBelowDirectoryIdentity(activePath, pluginDirStats);
4305
4316
  if (versionName) filesystemActiveVersionDirsHere.push((0, import_path4.join)(pluginDir, versionName));
@@ -4360,18 +4371,13 @@ function purgeStalePluginCacheVersions(options) {
4360
4371
  }
4361
4372
  }
4362
4373
  if (activeVersionDirsHere.length > 0) {
4363
- const target = [...activeVersionDirsHere].sort(
4364
- (a, b) => compareSemverDesc(
4365
- a.split("/").pop() ?? a,
4366
- b.split("/").pop() ?? b
4367
- )
4368
- )[0];
4374
+ const target = pickHighestVersionDir(activeVersionDirsHere);
4369
4375
  try {
4370
- const targetStats = (0, import_fs3.statSync)(target);
4376
+ const targetStats = (0, import_fs3.statSync)(target, { bigint: true });
4371
4377
  if (!targetStats.isDirectory()) {
4372
4378
  throw new Error("Registered active plugin target is not a directory");
4373
4379
  }
4374
- const staleVersionStats = (0, import_fs3.statSync)(versionDir);
4380
+ const staleVersionStats = (0, import_fs3.statSync)(versionDir, { bigint: true });
4375
4381
  const resolvedTarget = (0, import_fs3.realpathSync)(target);
4376
4382
  const resolvedStaleVersion = (0, import_fs3.realpathSync)(versionDir);
4377
4383
  const targetPath = comparisonPath(resolvedTarget);
@@ -6361,7 +6367,7 @@ function parseFrontmatter(content) {
6361
6367
  });
6362
6368
  const rootIndent = rootLine === void 0 ? void 0 : rootLine.length - rootLine.trimStart().length;
6363
6369
  let flowDepth = 0;
6364
- let quote2 = null;
6370
+ let quote3 = null;
6365
6371
  for (let lineIndex = 0; lineIndex < lines3.length; lineIndex++) {
6366
6372
  const line = lines3[lineIndex];
6367
6373
  const trimmed = line.trimStart();
@@ -6409,22 +6415,22 @@ function parseFrontmatter(content) {
6409
6415
  }
6410
6416
  for (let i = scanFrom; i < line.length; i++) {
6411
6417
  const char = line[i];
6412
- if (quote2) {
6413
- if (quote2 === '"' && char === "\\") {
6418
+ if (quote3) {
6419
+ if (quote3 === '"' && char === "\\") {
6414
6420
  i++;
6415
6421
  continue;
6416
6422
  }
6417
- if (char === quote2) {
6418
- if (quote2 === "'" && line[i + 1] === "'") {
6423
+ if (char === quote3) {
6424
+ if (quote3 === "'" && line[i + 1] === "'") {
6419
6425
  i++;
6420
6426
  continue;
6421
6427
  }
6422
- quote2 = null;
6428
+ quote3 = null;
6423
6429
  }
6424
6430
  continue;
6425
6431
  }
6426
6432
  if (char === '"' || char === "'") {
6427
- quote2 = char;
6433
+ quote3 = char;
6428
6434
  continue;
6429
6435
  }
6430
6436
  if (char === "#" && (i === 0 || line[i - 1] === " " || line[i - 1] === " ")) {
@@ -6445,20 +6451,20 @@ function parseFrontmatterAliases(rawAliases) {
6445
6451
  function splitFlowSequenceItems(inner) {
6446
6452
  const items = [];
6447
6453
  let current = "";
6448
- let quote2 = null;
6454
+ let quote3 = null;
6449
6455
  for (let i = 0; i < inner.length; i++) {
6450
6456
  const char = inner[i];
6451
- if (quote2) {
6457
+ if (quote3) {
6452
6458
  current += char;
6453
- if (quote2 === '"' && char === "\\" && i + 1 < inner.length) {
6459
+ if (quote3 === '"' && char === "\\" && i + 1 < inner.length) {
6454
6460
  current += inner[++i];
6455
- } else if (quote2 === "'" && char === "'" && inner[i + 1] === "'") {
6461
+ } else if (quote3 === "'" && char === "'" && inner[i + 1] === "'") {
6456
6462
  current += inner[++i];
6457
- } else if (char === quote2) {
6458
- quote2 = null;
6463
+ } else if (char === quote3) {
6464
+ quote3 = null;
6459
6465
  }
6460
6466
  } else if ((char === '"' || char === "'") && current.trim() === "") {
6461
- quote2 = char;
6467
+ quote3 = char;
6462
6468
  current += char;
6463
6469
  } else if (char === ",") {
6464
6470
  items.push(current);
@@ -11381,14 +11387,14 @@ var init_sdk = __esm({
11381
11387
  __callDispose = (stack, error2, hasError) => {
11382
11388
  var E = typeof SuppressedError === "function" ? SuppressedError : function(e, s, m, _) {
11383
11389
  return _ = Error(m), _.name = "SuppressedError", _.error = e, _.suppressed = s, _;
11384
- }, fail6 = (e) => error2 = hasError ? new E(e, error2, "An error was suppressed during disposal") : (hasError = true, e), next = (it) => {
11390
+ }, fail7 = (e) => error2 = hasError ? new E(e, error2, "An error was suppressed during disposal") : (hasError = true, e), next = (it) => {
11385
11391
  while (it = stack.pop()) {
11386
11392
  try {
11387
11393
  var result = it[1] && it[1].call(it[2]);
11388
11394
  if (it[0])
11389
- return Promise.resolve(result).then(next, (e) => (fail6(e), next()));
11395
+ return Promise.resolve(result).then(next, (e) => (fail7(e), next()));
11390
11396
  } catch (e) {
11391
- fail6(e);
11397
+ fail7(e);
11392
11398
  }
11393
11399
  }
11394
11400
  if (hasError)
@@ -32788,7 +32794,12 @@ function containerUriToHostUri(uri, context) {
32788
32794
  if (!context || !uri.startsWith("file://")) {
32789
32795
  return uri;
32790
32796
  }
32791
- return (0, import_url4.pathToFileURL)(containerPathToHostPath((0, import_url4.fileURLToPath)(uri), context)).href;
32797
+ const url = new URL(uri);
32798
+ if (url.host !== "" || /%2f/i.test(url.pathname)) {
32799
+ throw new TypeError(`Invalid container file URI: ${uri}`);
32800
+ }
32801
+ const containerPath = decodeURIComponent(url.pathname);
32802
+ return (0, import_url4.pathToFileURL)(containerPathToHostPath(containerPath, context)).href;
32792
32803
  }
32793
32804
  function resolveDevContainerConfigPath(workspaceRoot) {
32794
32805
  let dir = workspaceRoot;
@@ -33112,11 +33123,11 @@ function runBatchCommand(resolvedPath, args, timeoutMs) {
33112
33123
  const comspec = validatedComspec();
33113
33124
  if (!comspec) return void 0;
33114
33125
  if (!args.every((arg) => SAFE_BATCH_ARG.test(arg))) return void 0;
33115
- const tail2 = [`"${resolvedPath}"`, ...args].join(" ");
33126
+ const tail3 = [`"${resolvedPath}"`, ...args].join(" ");
33116
33127
  try {
33117
33128
  return (0, import_child_process3.spawnSync)(
33118
33129
  comspec,
33119
- ["/d", "/v:off", "/s", "/c", `"${tail2}"`],
33130
+ ["/d", "/v:off", "/s", "/c", `"${tail3}"`],
33120
33131
  {
33121
33132
  timeout: timeoutMs,
33122
33133
  encoding: "utf8",
@@ -34147,8 +34158,8 @@ ${content}`;
34147
34158
  const current = new Promise((resolveCurrent) => {
34148
34159
  release = resolveCurrent;
34149
34160
  });
34150
- const tail2 = previous.catch(() => void 0).then(() => current);
34151
- this.documentOperationTails.set(hostUri, tail2);
34161
+ const tail3 = previous.catch(() => void 0).then(() => current);
34162
+ this.documentOperationTails.set(hostUri, tail3);
34152
34163
  const predecessorCompleted = await Promise.race([
34153
34164
  previous.then(() => true, () => true),
34154
34165
  cancellation.then(() => false)
@@ -34161,7 +34172,7 @@ ${content}`;
34161
34172
  return await operation();
34162
34173
  } finally {
34163
34174
  release();
34164
- if (this.documentOperationTails.get(hostUri) === tail2) {
34175
+ if (this.documentOperationTails.get(hostUri) === tail3) {
34165
34176
  this.documentOperationTails.delete(hostUri);
34166
34177
  }
34167
34178
  }
@@ -35729,6 +35740,16 @@ function gitProbeEnvironmentSignature() {
35729
35740
  const dynamicEntries = Object.keys(process.env).filter((key) => /^GIT_CONFIG_(?:KEY|VALUE)_\d+$/.test(key)).sort().map((key) => JSON.stringify([key, process.env[key] !== void 0, process.env[key] ?? ""]));
35730
35741
  return [...fixedEntries, ...dynamicEntries].join("\0");
35731
35742
  }
35743
+ function projectIdentifierEnvironmentSignature() {
35744
+ const stateDir = process.env.OMC_STATE_DIR;
35745
+ return `${gitProbeEnvironmentSignature()}\0${JSON.stringify(["OMC_STATE_DIR", stateDir !== void 0, stateDir ?? ""])}`;
35746
+ }
35747
+ function isDefinitiveGitExit(error2) {
35748
+ const failure3 = error2;
35749
+ if (typeof failure3?.status !== "number") return false;
35750
+ const stderr = String(failure3.stderr ?? "");
35751
+ return !stderr.includes("dubious ownership") && !stderr.includes("safe.directory");
35752
+ }
35732
35753
  function findWorkspaceRoot(startDir) {
35733
35754
  if (process.env.OMC_DISABLE_MULTIREPO === "1") return null;
35734
35755
  const effectiveStart = startDir || process.cwd();
@@ -35826,8 +35847,8 @@ function resolveSuperprojectRoot(cwd2) {
35826
35847
  completed = true;
35827
35848
  break;
35828
35849
  }
35829
- anchor = superRoot;
35830
- probeCwd = superRoot;
35850
+ anchor = (0, import_path22.resolve)(superRoot);
35851
+ probeCwd = anchor;
35831
35852
  }
35832
35853
  if (completed) {
35833
35854
  if (superprojectCacheMap.size >= MAX_WORKTREE_CACHE_SIZE) {
@@ -36305,16 +36326,16 @@ function getGitTopologySignature(cwd2) {
36305
36326
  }
36306
36327
  return signatures.join("|");
36307
36328
  }
36308
- function createStateRootCacheEntry(cwd2, root2) {
36329
+ function createStateRootCacheEntry(cwd2, root2, environmentSignature = gitProbeEnvironmentSignature) {
36309
36330
  return {
36310
36331
  root: root2,
36311
36332
  metadataSignature: getGitMetadataSnapshot(cwd2)?.signature ?? null,
36312
36333
  topologySignature: getGitTopologySignature(cwd2),
36313
- environmentSignature: gitProbeEnvironmentSignature()
36334
+ environmentSignature: environmentSignature()
36314
36335
  };
36315
36336
  }
36316
- function isStateRootCacheEntryValid(cwd2, entry2) {
36317
- return entry2.metadataSignature === (getGitMetadataSnapshot(cwd2)?.signature ?? null) && entry2.topologySignature === getGitTopologySignature(cwd2) && entry2.environmentSignature === gitProbeEnvironmentSignature();
36337
+ function isStateRootCacheEntryValid(cwd2, entry2, environmentSignature = gitProbeEnvironmentSignature) {
36338
+ return entry2.metadataSignature === (getGitMetadataSnapshot(cwd2)?.signature ?? null) && entry2.topologySignature === getGitTopologySignature(cwd2) && entry2.environmentSignature === environmentSignature();
36318
36339
  }
36319
36340
  function isGitTopLevelCacheEntryValid(cwd2, cached2) {
36320
36341
  const current = getGitMetadataSnapshot(cwd2);
@@ -36352,7 +36373,24 @@ function getGitTopLevel(cwd2) {
36352
36373
  }
36353
36374
  gitTopLevelCacheMap.delete(key);
36354
36375
  }
36376
+ const negative = gitTopLevelNegativeCacheMap.get(key);
36377
+ if (negative) {
36378
+ if (isStateRootCacheEntryValid(effectiveCwd, negative)) {
36379
+ gitTopLevelNegativeCacheMap.delete(key);
36380
+ gitTopLevelNegativeCacheMap.set(key, negative);
36381
+ return null;
36382
+ }
36383
+ gitTopLevelNegativeCacheMap.delete(key);
36384
+ }
36355
36385
  const probe = probeGitTopLevel(effectiveCwd);
36386
+ if (probe.status === "not_a_repository") {
36387
+ if (gitTopLevelNegativeCacheMap.size >= MAX_WORKTREE_CACHE_SIZE) {
36388
+ const oldest = gitTopLevelNegativeCacheMap.keys().next().value;
36389
+ if (oldest !== void 0) gitTopLevelNegativeCacheMap.delete(oldest);
36390
+ }
36391
+ gitTopLevelNegativeCacheMap.set(key, createStateRootCacheEntry(effectiveCwd, null));
36392
+ return null;
36393
+ }
36356
36394
  if (probe.status !== "ok") return null;
36357
36395
  cacheGitTopLevel(key, probe.root, effectiveCwd);
36358
36396
  return probe.root;
@@ -36448,6 +36486,20 @@ function getProjectIdentifier(worktreeRoot) {
36448
36486
  if (scope && scopeKey) scope.projectIdentifiers.set(scopeKey, identifier2);
36449
36487
  return identifier2;
36450
36488
  }
36489
+ const processCacheKey = canonicalizeExistingPath(root2) ?? (0, import_path22.resolve)(root2);
36490
+ const processCached = projectIdentifierCacheMap.get(processCacheKey);
36491
+ if (processCached) {
36492
+ if (isStateRootCacheEntryValid(root2, processCached, projectIdentifierEnvironmentSignature)) {
36493
+ projectIdentifierCacheMap.delete(processCacheKey);
36494
+ projectIdentifierCacheMap.set(processCacheKey, processCached);
36495
+ if (operationScope && operationScopeKey) operationScope.set(operationScopeKey, processCached.identifier);
36496
+ if (scope && scopeKey) scope.projectIdentifiers.set(scopeKey, processCached.identifier);
36497
+ return processCached.identifier;
36498
+ }
36499
+ projectIdentifierCacheMap.delete(processCacheKey);
36500
+ }
36501
+ const processCacheEntry = createStateRootCacheEntry(root2, null, projectIdentifierEnvironmentSignature);
36502
+ let cacheable = processCacheEntry.metadataSignature !== null && process.env.GIT_DIR === void 0;
36451
36503
  let remoteUrl = "";
36452
36504
  try {
36453
36505
  remoteUrl = (0, import_child_process6.execFileSync)("git", ["remote", "get-url", "origin"], {
@@ -36457,7 +36509,8 @@ function getProjectIdentifier(worktreeRoot) {
36457
36509
  windowsHide: true,
36458
36510
  timeout: 5e3
36459
36511
  }).trim();
36460
- } catch {
36512
+ } catch (error2) {
36513
+ if (!isDefinitiveGitExit(error2)) cacheable = false;
36461
36514
  }
36462
36515
  let primaryRoot = root2;
36463
36516
  try {
@@ -36476,12 +36529,20 @@ function getProjectIdentifier(worktreeRoot) {
36476
36529
  primaryRoot = resolved;
36477
36530
  }
36478
36531
  }
36479
- } catch {
36532
+ } catch (error2) {
36533
+ if (!isDefinitiveGitExit(error2)) cacheable = false;
36480
36534
  }
36481
36535
  const source = remoteUrl || primaryRoot;
36482
36536
  const hash = (0, import_crypto5.createHash)("sha256").update(source).digest("hex").slice(0, 16);
36483
36537
  const dirName = (0, import_path22.basename)(primaryRoot).replace(/[^a-zA-Z0-9_-]/g, "_");
36484
36538
  const identifier = `${dirName}-${hash}`;
36539
+ if (cacheable) {
36540
+ if (projectIdentifierCacheMap.size >= MAX_WORKTREE_CACHE_SIZE) {
36541
+ const oldest = projectIdentifierCacheMap.keys().next().value;
36542
+ if (oldest !== void 0) projectIdentifierCacheMap.delete(oldest);
36543
+ }
36544
+ projectIdentifierCacheMap.set(processCacheKey, { ...processCacheEntry, identifier });
36545
+ }
36485
36546
  if (operationScope && operationScopeKey) operationScope.set(operationScopeKey, identifier);
36486
36547
  if (scope && scopeKey) scope.projectIdentifiers.set(scopeKey, identifier);
36487
36548
  return identifier;
@@ -37015,7 +37076,7 @@ function validateWorkingDirectoryOrLinkedWorktree(workingDirectory) {
37015
37076
  }
37016
37077
  return resolution.root;
37017
37078
  }
37018
- var import_crypto5, import_node_async_hooks, import_child_process6, import_fs17, import_os4, import_path22, import_url6, WORKSPACE_MARKER, OmcPaths, MAX_WORKTREE_CACHE_SIZE, worktreeCacheMap, gitTopLevelCacheMap, superprojectCacheMap, canonicalWorkingDirectoryRoots, GIT_PROBE_ENVIRONMENT_KEYS, MAX_GIT_MARKER_BYTES, workspaceCacheMap, SENSITIVE_DIR_BASENAMES, worktreePathRenderScope, projectIdentifierOperationScope, gitShowToplevelProbeForTests, dualDirWarnings, SESSION_ID_REGEX, processSessionId, ForeignWorkingDirectoryError;
37079
+ var import_crypto5, import_node_async_hooks, import_child_process6, import_fs17, import_os4, import_path22, import_url6, WORKSPACE_MARKER, OmcPaths, MAX_WORKTREE_CACHE_SIZE, worktreeCacheMap, gitTopLevelCacheMap, gitTopLevelNegativeCacheMap, superprojectCacheMap, projectIdentifierCacheMap, canonicalWorkingDirectoryRoots, GIT_PROBE_ENVIRONMENT_KEYS, MAX_GIT_MARKER_BYTES, workspaceCacheMap, SENSITIVE_DIR_BASENAMES, worktreePathRenderScope, projectIdentifierOperationScope, gitShowToplevelProbeForTests, dualDirWarnings, SESSION_ID_REGEX, processSessionId, ForeignWorkingDirectoryError;
37019
37080
  var init_worktree_paths = __esm({
37020
37081
  "src/lib/worktree-paths.ts"() {
37021
37082
  "use strict";
@@ -37049,7 +37110,9 @@ var init_worktree_paths = __esm({
37049
37110
  MAX_WORKTREE_CACHE_SIZE = 8;
37050
37111
  worktreeCacheMap = /* @__PURE__ */ new Map();
37051
37112
  gitTopLevelCacheMap = /* @__PURE__ */ new Map();
37113
+ gitTopLevelNegativeCacheMap = /* @__PURE__ */ new Map();
37052
37114
  superprojectCacheMap = /* @__PURE__ */ new Map();
37115
+ projectIdentifierCacheMap = /* @__PURE__ */ new Map();
37053
37116
  canonicalWorkingDirectoryRoots = /* @__PURE__ */ new WeakMap();
37054
37117
  GIT_PROBE_ENVIRONMENT_KEYS = [
37055
37118
  "PATH",
@@ -37967,7 +38030,11 @@ function rollbackPriorTarget(filePath, backupPath, expectedIdentity, operations)
37967
38030
  } else {
37968
38031
  (operations?.rename ?? fsSync.renameSync)(backupPath, filePath);
37969
38032
  }
37970
- } catch {
38033
+ } catch (error2) {
38034
+ try {
38035
+ console.warn(`[omc] atomic write rollback of ${filePath} failed: ${error2.message}`);
38036
+ } catch {
38037
+ }
37971
38038
  }
37972
38039
  }
37973
38040
  function removeBackup(backupPath, operations) {
@@ -38014,6 +38081,10 @@ async function atomicWriteJson(filePath, data, hooks) {
38014
38081
  hooks?.afterRename?.();
38015
38082
  verifyPublishedFile(fd.fd, filePath, "atomic JSON write");
38016
38083
  } catch (error2) {
38084
+ if (process.platform === "win32") {
38085
+ await fd.close().catch(() => void 0);
38086
+ fd = null;
38087
+ }
38017
38088
  rollbackPriorTarget(
38018
38089
  filePath,
38019
38090
  backupPath,
@@ -38022,7 +38093,7 @@ async function atomicWriteJson(filePath, data, hooks) {
38022
38093
  throw error2;
38023
38094
  }
38024
38095
  } finally {
38025
- await fd.close();
38096
+ await fd?.close();
38026
38097
  fd = null;
38027
38098
  }
38028
38099
  success = true;
@@ -38044,6 +38115,18 @@ async function atomicWriteJson(filePath, data, hooks) {
38044
38115
  }
38045
38116
  }
38046
38117
  }
38118
+ function renameSyncRetryingWin32Sharing(rename8, source, destination) {
38119
+ for (let attempt = 0; ; attempt++) {
38120
+ try {
38121
+ rename8(source, destination);
38122
+ return;
38123
+ } catch (error2) {
38124
+ const code = error2.code;
38125
+ if (process.platform !== "win32" || attempt >= 20 || code !== "EPERM" && code !== "EACCES" && code !== "EBUSY") throw error2;
38126
+ Atomics.wait(RENAME_RETRY_WAIT, 0, 0, Math.min(25, 1 + attempt * 2));
38127
+ }
38128
+ }
38129
+ }
38047
38130
  function atomicWriteFileSync(filePath, content, hooks, operations) {
38048
38131
  if (operations && (!filePath || path3.basename(filePath) !== filePath || filePath === "." || filePath === "..")) throw new RangeError("contained atomic write requires a basename");
38049
38132
  const dir = path3.dirname(filePath);
@@ -38060,7 +38143,7 @@ function atomicWriteFileSync(filePath, content, hooks, operations) {
38060
38143
  verifyPrivateTempFile(fd, tempPath, "atomic write", operations);
38061
38144
  backupPath = preservePriorTarget(filePath, operations);
38062
38145
  hooks?.beforeRename?.();
38063
- (operations?.rename ?? fsSync.renameSync)(tempPath, filePath);
38146
+ renameSyncRetryingWin32Sharing(operations?.rename ?? fsSync.renameSync, tempPath, filePath);
38064
38147
  let publishedIdentity = null;
38065
38148
  try {
38066
38149
  verifyPublishedFile(fd, filePath, "atomic write", operations);
@@ -38068,6 +38151,13 @@ function atomicWriteFileSync(filePath, content, hooks, operations) {
38068
38151
  hooks?.afterRename?.();
38069
38152
  verifyPublishedFile(fd, filePath, "atomic write", operations);
38070
38153
  } catch (error2) {
38154
+ if (process.platform === "win32") {
38155
+ try {
38156
+ fsSync.closeSync(fd);
38157
+ } catch {
38158
+ }
38159
+ fd = null;
38160
+ }
38071
38161
  rollbackPriorTarget(
38072
38162
  filePath,
38073
38163
  backupPath,
@@ -38126,7 +38216,7 @@ async function safeReadJson(filePath) {
38126
38216
  return null;
38127
38217
  }
38128
38218
  }
38129
- var fs3, fsSync, path3, crypto3, ATOMIC_BATCH_MAX_CONTENT_BYTES;
38219
+ var fs3, fsSync, path3, crypto3, RENAME_RETRY_WAIT, ATOMIC_BATCH_MAX_CONTENT_BYTES;
38130
38220
  var init_atomic_write = __esm({
38131
38221
  "src/lib/atomic-write.ts"() {
38132
38222
  "use strict";
@@ -38134,6 +38224,7 @@ var init_atomic_write = __esm({
38134
38224
  fsSync = __toESM(require("fs"), 1);
38135
38225
  path3 = __toESM(require("path"), 1);
38136
38226
  crypto3 = __toESM(require("crypto"), 1);
38227
+ RENAME_RETRY_WAIT = new Int32Array(new SharedArrayBuffer(4));
38137
38228
  ATOMIC_BATCH_MAX_CONTENT_BYTES = 1024 * 1024;
38138
38229
  }
38139
38230
  });
@@ -38558,8 +38649,14 @@ async function terminateOwnedProcessTree(options) {
38558
38649
  " if (-not $owned.ContainsKey($parent) -or $owned.ContainsKey($id)) { continue }",
38559
38650
  " try {",
38560
38651
  " $process = [System.Diagnostics.Process]::GetProcessById($id)",
38561
- " $created = ([DateTime]$row.CreationDate).ToUniversalTime().Ticks",
38562
- " if ($process.StartTime.ToUniversalTime().Ticks -ne $created) { continue }",
38652
+ // CIM CreationDate carries microseconds, StartTime 100 ns ticks: compare
38653
+ // at microsecond precision or almost every live child reads as reused.
38654
+ " $created = ([DateTime]$row.CreationDate).ToUniversalTime().Ticks; $started = $process.StartTime.ToUniversalTime().Ticks",
38655
+ " if (($started - $started % 10) -ne ($created - $created % 10)) { continue }",
38656
+ // ParentProcessId is never cleared, so a process created before its owned
38657
+ // "parent" names a dead earlier holder of that reused PID: not a descendant.
38658
+ " $parentStart = $owned[$parent].Process.StartTime.ToUniversalTime().Ticks",
38659
+ " if (($created - $created % 10) -lt ($parentStart - $parentStart % 10)) { continue }",
38563
38660
  " [void][OmcNative]::NtSuspendProcess($process.Handle)",
38564
38661
  " $owned[$id] = @{ Process = $process; Depth = ([int]$owned[$parent].Depth + 1); Suspended = $true }",
38565
38662
  " $added = $true",
@@ -39214,18 +39311,41 @@ function detectExistingPythonEnv(projectRoot) {
39214
39311
  }
39215
39312
  return null;
39216
39313
  }
39314
+ async function resolveSystemPython(platform = process.platform, probe = runPythonProbe) {
39315
+ const useCache = platform === process.platform && probe === runPythonProbe;
39316
+ if (useCache && systemPythonCache !== void 0) return systemPythonCache;
39317
+ const resolved = await probeSystemPython(platform, probe);
39318
+ if (useCache) systemPythonCache = resolved;
39319
+ return resolved;
39320
+ }
39321
+ async function probeSystemPython(platform, probe) {
39322
+ const candidates = platform === "win32" ? [["python3"], ["python"], ["py", "-3"]] : [["python3"]];
39323
+ for (const [command, ...args] of candidates) {
39324
+ try {
39325
+ const stdout = await probe(command, [
39326
+ ...args,
39327
+ "-c",
39328
+ "import sys; assert sys.version_info >= (3,); print(sys.executable)"
39329
+ ]);
39330
+ const executable = stdout.trim();
39331
+ if (executable) return executable;
39332
+ } catch {
39333
+ }
39334
+ }
39335
+ return null;
39336
+ }
39217
39337
  async function ensurePythonEnvironment(projectRoot) {
39218
39338
  const existing = detectExistingPythonEnv(projectRoot);
39219
39339
  if (existing) {
39220
39340
  return existing;
39221
39341
  }
39222
- try {
39223
- await execFileAsync3("python3", ["--version"]);
39224
- return { pythonPath: "python3", type: "venv" };
39225
- } catch {
39342
+ const systemPython = await resolveSystemPython();
39343
+ if (systemPython) {
39344
+ return { pythonPath: systemPython, type: "venv" };
39226
39345
  }
39227
39346
  throw new Error(
39228
- "No Python environment found. Create a virtual environment first:\n python -m venv .venv"
39347
+ `No Python environment found (probed: ${process.platform === "win32" ? "python3, python, py -3" : "python3"}). Create a virtual environment first:
39348
+ python -m venv .venv`
39229
39349
  );
39230
39350
  }
39231
39351
  async function verifyProcessIdentity(meta) {
@@ -39577,7 +39697,7 @@ async function removeFileIfExists(filePath) {
39577
39697
  function sleep2(ms) {
39578
39698
  return new Promise((resolve58) => setTimeout(resolve58, ms));
39579
39699
  }
39580
- var import_child_process9, fs5, fsPromises2, path6, import_url7, import_child_process10, import_util6, execFileAsync3, BRIDGE_SPAWN_TIMEOUT_MS, DEFAULT_GRACE_PERIOD_MS, SIGTERM_GRACE_MS, ownedBridgeSessionIds, USE_TCP_FALLBACK;
39700
+ var import_child_process9, fs5, fsPromises2, path6, import_url7, import_child_process10, import_util6, execFileAsync3, BRIDGE_SPAWN_TIMEOUT_MS, DEFAULT_GRACE_PERIOD_MS, SIGTERM_GRACE_MS, ownedBridgeSessionIds, runPythonProbe, systemPythonCache, USE_TCP_FALLBACK;
39581
39701
  var init_bridge_manager = __esm({
39582
39702
  "src/tools/python-repl/bridge-manager.ts"() {
39583
39703
  "use strict";
@@ -39597,6 +39717,7 @@ var init_bridge_manager = __esm({
39597
39717
  DEFAULT_GRACE_PERIOD_MS = 5e3;
39598
39718
  SIGTERM_GRACE_MS = 2500;
39599
39719
  ownedBridgeSessionIds = /* @__PURE__ */ new Set();
39720
+ runPythonProbe = async (command, args) => (await execFileAsync3(command, args, { timeout: 1e4, windowsHide: true })).stdout;
39600
39721
  USE_TCP_FALLBACK = process.platform === "win32";
39601
39722
  }
39602
39723
  });
@@ -45547,9 +45668,12 @@ function commandExists2(command, env2) {
45547
45668
  });
45548
45669
  return result.status === 0;
45549
45670
  }
45671
+ function isOmcCliAvailable(env2 = process.env) {
45672
+ return commandExists2(OMC_CLI_BINARY, env2);
45673
+ }
45550
45674
  function resolveOmcCliPrefix(options = {}) {
45551
45675
  const env2 = options.env ?? process.env;
45552
- const omcAvailable = options.omcAvailable ?? commandExists2(OMC_CLI_BINARY, env2);
45676
+ const omcAvailable = options.omcAvailable ?? isOmcCliAvailable(env2);
45553
45677
  if (omcAvailable) {
45554
45678
  return OMC_CLI_BINARY;
45555
45679
  }
@@ -45571,13 +45695,8 @@ function rewriteOmcCliInvocations(text, options = {}) {
45571
45695
  if (!text.includes("omc ")) {
45572
45696
  return text;
45573
45697
  }
45574
- return text.replace(/`omc ([^`\r\n]+)`/g, (_match, suffix) => {
45575
- const prefix = resolveInvocationPrefix(suffix, options);
45576
- return `\`${prefix} ${suffix}\``;
45577
- }).replace(/(^|\n)([ \t>*-]*)omc ([^\n]+)/g, (_match, lineStart, leader, suffix) => {
45578
- const prefix = resolveInvocationPrefix(suffix, options);
45579
- return `${lineStart}${leader}${prefix} ${suffix}`;
45580
- });
45698
+ const prefix = resolveOmcCliPrefix(options);
45699
+ return text.replace(/`omc ([^`\r\n]+)`/g, (_match, suffix) => `\`${prefix} ${suffix}\``).replace(/(^|\n)([ \t>*-]*)omc ([^\n]+)/g, (_match, lineStart, leader, suffix) => `${lineStart}${leader}${prefix} ${suffix}`);
45581
45700
  }
45582
45701
  var import_child_process13, OMC_CLI_BINARY, OMC_PLUGIN_BRIDGE_PREFIX;
45583
45702
  var init_omc_cli_rendering = __esm({
@@ -51110,13 +51229,13 @@ var init_directive_detector = __esm({
51110
51229
  function withMutex(projectRoot, fn) {
51111
51230
  const prev = writeMutexes.get(projectRoot) ?? Promise.resolve();
51112
51231
  const next = prev.then(() => fn()).catch(() => fn());
51113
- const tail2 = next.then(
51232
+ const tail3 = next.then(
51114
51233
  () => {
51115
51234
  },
51116
51235
  () => {
51117
51236
  }
51118
51237
  );
51119
- writeMutexes.set(projectRoot, tail2);
51238
+ writeMutexes.set(projectRoot, tail3);
51120
51239
  return next;
51121
51240
  }
51122
51241
  async function addCustomNote(projectRoot, category, content) {
@@ -53205,9 +53324,10 @@ function scanDirectories(projectRoot) {
53205
53324
  return;
53206
53325
  }
53207
53326
  try {
53208
- const stat2 = (0, import_node_fs4.statSync)(absDir);
53209
- if (visitedInodes.has(stat2.ino)) return;
53210
- visitedInodes.add(stat2.ino);
53327
+ const stat2 = (0, import_node_fs4.statSync)(absDir, { bigint: true });
53328
+ const inodeKey = `${stat2.dev}:${stat2.ino}`;
53329
+ if (visitedInodes.has(inodeKey)) return;
53330
+ visitedInodes.add(inodeKey);
53211
53331
  } catch {
53212
53332
  return;
53213
53333
  }
@@ -55391,12 +55511,12 @@ function parseTomlStringArrayFallback(value) {
55391
55511
  }
55392
55512
  return result;
55393
55513
  }
55394
- const quote2 = value[i];
55395
- if (quote2 !== '"' && quote2 !== "'") {
55514
+ const quote3 = value[i];
55515
+ if (quote3 !== '"' && quote3 !== "'") {
55396
55516
  return void 0;
55397
55517
  }
55398
55518
  let member;
55399
- if (quote2 === "'") {
55519
+ if (quote3 === "'") {
55400
55520
  i++;
55401
55521
  const start = i;
55402
55522
  while (i < value.length && value[i] !== "'") {
@@ -55513,8 +55633,8 @@ function parseTomlDottedKey(value) {
55513
55633
  skipWhitespace();
55514
55634
  while (index < value.length) {
55515
55635
  const start = index;
55516
- const quote2 = value[index];
55517
- if (quote2 === '"') {
55636
+ const quote3 = value[index];
55637
+ if (quote3 === '"') {
55518
55638
  index++;
55519
55639
  let closed = false;
55520
55640
  while (index < value.length) {
@@ -55528,7 +55648,7 @@ function parseTomlDottedKey(value) {
55528
55648
  if (!closed) {
55529
55649
  return void 0;
55530
55650
  }
55531
- } else if (quote2 === "'") {
55651
+ } else if (quote3 === "'") {
55532
55652
  index++;
55533
55653
  while (index < value.length && value[index] !== "'") {
55534
55654
  index++;
@@ -55567,29 +55687,29 @@ function parseTomlTableHeader(line) {
55567
55687
  if (!trimmed.startsWith("[") || trimmed.startsWith("[[")) {
55568
55688
  return void 0;
55569
55689
  }
55570
- let quote2;
55690
+ let quote3;
55571
55691
  let escaped = false;
55572
55692
  let closingBracket = -1;
55573
55693
  for (let index = 1; index < trimmed.length; index++) {
55574
55694
  const character = trimmed[index];
55575
- if (quote2 === '"') {
55695
+ if (quote3 === '"') {
55576
55696
  if (escaped) {
55577
55697
  escaped = false;
55578
55698
  } else if (character === "\\") {
55579
55699
  escaped = true;
55580
55700
  } else if (character === '"') {
55581
- quote2 = void 0;
55701
+ quote3 = void 0;
55582
55702
  }
55583
55703
  continue;
55584
55704
  }
55585
- if (quote2 === "'") {
55705
+ if (quote3 === "'") {
55586
55706
  if (character === "'") {
55587
- quote2 = void 0;
55707
+ quote3 = void 0;
55588
55708
  }
55589
55709
  continue;
55590
55710
  }
55591
55711
  if (character === '"' || character === "'") {
55592
- quote2 = character;
55712
+ quote3 = character;
55593
55713
  } else if (character === "]") {
55594
55714
  closingBracket = index;
55595
55715
  break;
@@ -57579,6 +57699,7 @@ export const isExclusiveStateLockingAvailable = canonical.isExclusiveStateLockin
57579
57699
  export const getStateFileLockDiagnostic = canonical.getStateFileLockDiagnostic;
57580
57700
  export const getStateFileLockFailureMessage = canonical.getStateFileLockFailureMessage;
57581
57701
  export const getStateFileLockFailureKind = canonical.getStateFileLockFailureKind;
57702
+ export const getStateFileLockFailureReason = canonical.getStateFileLockFailureReason;
57582
57703
  export const acquireStateFileLockSync = canonical.acquireStateFileLockSync;
57583
57704
  export const acquireStateFileLockAtPathSync = canonical.acquireStateFileLockAtPathSync;
57584
57705
  export const releaseStateFileLockSync = canonical.releaseStateFileLockSync;
@@ -65355,18 +65476,18 @@ function getBackgroundBashPermissionFallback(directory, command) {
65355
65476
  function tokenizeShellCommand(command) {
65356
65477
  const tokens = [];
65357
65478
  let current = "";
65358
- let quote2 = null;
65479
+ let quote3 = null;
65359
65480
  for (const char of command.trim()) {
65360
- if (quote2) {
65361
- if (char === quote2) {
65362
- quote2 = null;
65481
+ if (quote3) {
65482
+ if (char === quote3) {
65483
+ quote3 = null;
65363
65484
  } else {
65364
65485
  current += char;
65365
65486
  }
65366
65487
  continue;
65367
65488
  }
65368
65489
  if (char === '"' || char === "'") {
65369
- quote2 = char;
65490
+ quote3 = char;
65370
65491
  continue;
65371
65492
  }
65372
65493
  if (/\s/.test(char)) {
@@ -65378,7 +65499,7 @@ function tokenizeShellCommand(command) {
65378
65499
  }
65379
65500
  current += char;
65380
65501
  }
65381
- if (quote2) {
65502
+ if (quote3) {
65382
65503
  return null;
65383
65504
  }
65384
65505
  if (current) {
@@ -67666,13 +67787,13 @@ When done, run \`/oh-my-copilot:cancel\` to cleanly exit.
67666
67787
  }
67667
67788
  async function checkPersistentModes(sessionId, directory, stopContext) {
67668
67789
  const result = await resolvePersistentModeBlock(sessionId, directory, stopContext);
67669
- const guarded3 = applyThinkingOnlyStreakGuard(
67790
+ const guarded4 = applyThinkingOnlyStreakGuard(
67670
67791
  result,
67671
67792
  resolveToWorktreeRoot(directory),
67672
67793
  sessionId,
67673
67794
  stopContext
67674
67795
  );
67675
- return applyLoopContinuationShadow({ result: guarded3, sessionId });
67796
+ return applyLoopContinuationShadow({ result: guarded4, sessionId });
67676
67797
  }
67677
67798
  async function resolvePersistentModeBlock(sessionId, directory, stopContext) {
67678
67799
  const workingDir = resolveToWorktreeRoot(directory);
@@ -69700,12 +69821,17 @@ function readSessionEndJob(directory, sessionId) {
69700
69821
  }
69701
69822
  }
69702
69823
  function mutateSessionEndJob(directory, sessionId, expectedRevision, mutate) {
69824
+ const result = mutateAtRevision(directory, sessionId, expectedRevision, mutate);
69825
+ return result === REVISION_MISMATCH ? null : result;
69826
+ }
69827
+ function mutateAtRevision(directory, sessionId, expectedRevision, mutate) {
69703
69828
  let terminal = false;
69704
69829
  try {
69705
69830
  const jobPath = sessionEndJobPath(directory, sessionId);
69706
69831
  const result = withLock(jobPath, () => {
69707
69832
  const current = readPath(jobPath);
69708
- if (!current || current.revision !== expectedRevision) return null;
69833
+ if (!current) return null;
69834
+ if (current.revision !== expectedRevision) return REVISION_MISMATCH;
69709
69835
  mutate(current);
69710
69836
  const next = { ...current, revision: current.revision + 1, updatedAt: nowIso() };
69711
69837
  if (isManifestTerminal(next) && next.phase !== "complete") {
@@ -69718,7 +69844,7 @@ function mutateSessionEndJob(directory, sessionId, expectedRevision, mutate) {
69718
69844
  terminal = reread.phase === "complete";
69719
69845
  return reread;
69720
69846
  });
69721
- if (result && terminal) acknowledgeSessionEndDiscoveryTicket(directory, sessionId);
69847
+ if (result && result !== REVISION_MISMATCH && terminal) acknowledgeSessionEndDiscoveryTicket(directory, sessionId);
69722
69848
  return result;
69723
69849
  } catch {
69724
69850
  return null;
@@ -69732,12 +69858,12 @@ function updateSessionEndActionPayload(directory, sessionId, authority, actionNa
69732
69858
  for (const name of actionNames) job.actions[name].payload = { ...job.actions[name].payload, ...payload };
69733
69859
  });
69734
69860
  }
69735
- function mutateLatest(directory, sessionId, mutate) {
69861
+ function mutateLatest(directory, sessionId, mutate, retryOn = "any-null") {
69736
69862
  for (let i = 0; i < 8; i++) {
69737
69863
  const current = readSessionEndJob(directory, sessionId);
69738
69864
  if (!current) return null;
69739
- const result = mutateSessionEndJob(directory, sessionId, current.revision, mutate);
69740
- if (result) return result;
69865
+ const result = mutateAtRevision(directory, sessionId, current.revision, mutate);
69866
+ if (result !== REVISION_MISMATCH && (result || retryOn === "mismatch")) return result;
69741
69867
  }
69742
69868
  return null;
69743
69869
  }
@@ -69865,15 +69991,13 @@ function claimSessionEndJob(directory, sessionId, nonce, identity, deadlineAt) {
69865
69991
  });
69866
69992
  }
69867
69993
  function renewSessionEndLease(directory, sessionId, nonce, generation, deadlineAt) {
69868
- const current = readSessionEndJob(directory, sessionId);
69869
- if (!current) return null;
69870
- return mutateSessionEndJob(directory, sessionId, current.revision, (job) => {
69994
+ return mutateLatest(directory, sessionId, (job) => {
69871
69995
  const owner = job.owner;
69872
69996
  if (!owner || owner.nonce !== nonce || owner.leaseGeneration !== generation) throw new Error("lease-conflict");
69873
69997
  owner.leaseGeneration++;
69874
69998
  owner.heartbeatAt = nowIso();
69875
69999
  owner.leaseExpiresAt = new Date(Math.min(Date.now() + 750, deadlineAt)).toISOString();
69876
- });
70000
+ }, "mismatch");
69877
70001
  }
69878
70002
  function reapStaleSessionEndOwner(directory, sessionId, expectedNonce, expectedGeneration, liveness) {
69879
70003
  const current = readSessionEndJob(directory, sessionId);
@@ -69895,24 +70019,29 @@ function reapStaleSessionEndOwner(directory, sessionId, expectedNonce, expectedG
69895
70019
  });
69896
70020
  }
69897
70021
  function releaseSessionEndJob(directory, sessionId, nonce, generation, reason = "worker-released") {
69898
- const current = readSessionEndJob(directory, sessionId);
69899
- if (!current) return null;
69900
- return mutateSessionEndJob(directory, sessionId, current.revision, (job) => {
70022
+ return mutateLatest(directory, sessionId, (job) => {
69901
70023
  if (!job.owner || job.owner.nonce !== nonce || job.owner.leaseGeneration !== generation) throw new Error("release-conflict");
70024
+ for (const action of Object.values(job.actions)) {
70025
+ if (action.status === "claimed" && action.claimantNonce === nonce && action.runner?.phase === "reserved" && action.runner.attempt === action.attempts) {
70026
+ action.attempts--;
70027
+ action.status = action.attempts > 0 ? "retryable" : "pending";
70028
+ action.claimantNonce = void 0;
70029
+ action.claimedAt = void 0;
70030
+ action.runner = void 0;
70031
+ }
70032
+ }
69902
70033
  job.owner = null;
69903
70034
  if (job.phase !== "complete") {
69904
70035
  job.phase = "recoverable-failure";
69905
70036
  job.recoverableFailure = { reason, releasedAt: nowIso(), ownerNonce: nonce };
69906
70037
  }
69907
- });
70038
+ }, "mismatch");
69908
70039
  }
69909
70040
  function updateSessionEndJob(directory, sessionId, expectedOwner, mutate) {
69910
- const current = readSessionEndJob(directory, sessionId);
69911
- if (!current) return null;
69912
- return mutateSessionEndJob(directory, sessionId, current.revision, (job) => {
70041
+ return mutateLatest(directory, sessionId, (job) => {
69913
70042
  if (job.owner?.nonce !== expectedOwner || job.phase === "complete") throw new Error("owner-conflict");
69914
70043
  mutate(job);
69915
- });
70044
+ }, "mismatch");
69916
70045
  }
69917
70046
  function claimSessionEndAction(directory, sessionId, ownerNonce, name, deadlineAt) {
69918
70047
  return updateSessionEndJob(directory, sessionId, ownerNonce, (job) => {
@@ -70072,7 +70201,7 @@ function failClosedMissingCoreProducer(directory, sessionId) {
70072
70201
  if (job.phase === "collecting") job.phase = "ready";
70073
70202
  });
70074
70203
  }
70075
- var fs12, path18, import_crypto21, ACTIONS, TEST_PRODUCER_GRACE_ENV, PRODUCER_GRACE_MS, REQUIRED_ACTION_EXECUTION_MS, BEST_EFFORT_ACTION_EXECUTION_MS, REQUIRED_ACTION_MAX_ATTEMPTS, LOCK_WAIT, DISCOVERY_FILE;
70204
+ var fs12, path18, import_crypto21, ACTIONS, TEST_PRODUCER_GRACE_ENV, PRODUCER_GRACE_MS, REQUIRED_ACTION_EXECUTION_MS, BEST_EFFORT_ACTION_EXECUTION_MS, REQUIRED_ACTION_MAX_ATTEMPTS, LOCK_WAIT, DISCOVERY_FILE, REVISION_MISMATCH;
70076
70205
  var init_cleanup_manifest = __esm({
70077
70206
  "src/hooks/session-end/cleanup-manifest.ts"() {
70078
70207
  "use strict";
@@ -70099,6 +70228,7 @@ var init_cleanup_manifest = __esm({
70099
70228
  REQUIRED_ACTION_MAX_ATTEMPTS = 3;
70100
70229
  LOCK_WAIT = new Int32Array(new SharedArrayBuffer(4));
70101
70230
  DISCOVERY_FILE = "discovery.json";
70231
+ REVISION_MISMATCH = /* @__PURE__ */ Symbol("revision-mismatch");
70102
70232
  }
70103
70233
  });
70104
70234
 
@@ -71939,9 +72069,9 @@ function createTelegramProxyConnection(proxyUrl) {
71939
72069
  let tlsSocket;
71940
72070
  let settled = false;
71941
72071
  const handshakeTimer = setTimeout(() => {
71942
- fail6(new Error("Proxy CONNECT timeout"));
72072
+ fail7(new Error("Proxy CONNECT timeout"));
71943
72073
  }, SEND_TIMEOUT_MS);
71944
- const fail6 = (error2) => {
72074
+ const fail7 = (error2) => {
71945
72075
  if (settled) return;
71946
72076
  settled = true;
71947
72077
  clearTimeout(handshakeTimer);
@@ -71949,7 +72079,7 @@ function createTelegramProxyConnection(proxyUrl) {
71949
72079
  tlsSocket?.destroy();
71950
72080
  callback(error2);
71951
72081
  };
71952
- connectSocket.once("error", fail6);
72082
+ connectSocket.once("error", fail7);
71953
72083
  connectSocket.once(proxyUrl.protocol === "https:" ? "secureConnect" : "connect", () => {
71954
72084
  const auth = proxyUrl.username || proxyUrl.password ? `Proxy-Authorization: Basic ${Buffer.from(
71955
72085
  `${decodeURIComponent(proxyUrl.username)}:${decodeURIComponent(proxyUrl.password)}`
@@ -71969,11 +72099,11 @@ Host: ${TELEGRAM_API_HOST}:${TELEGRAM_API_PORT}\r
71969
72099
  const statusLine = response.toString("ascii", 0, headerEnd).split("\r\n")[0] || "";
71970
72100
  const status = /^HTTP\/\d(?:\.\d)?\s+(\d{3})/.exec(statusLine)?.[1];
71971
72101
  if (!status || !status.startsWith("2")) {
71972
- fail6(new Error(`Proxy CONNECT failed: ${status || "unknown"}`));
72102
+ fail7(new Error(`Proxy CONNECT failed: ${status || "unknown"}`));
71973
72103
  return;
71974
72104
  }
71975
72105
  connectSocket.removeAllListeners("data");
71976
- connectSocket.removeListener("error", fail6);
72106
+ connectSocket.removeListener("error", fail7);
71977
72107
  tlsSocket = (0, import_tls.connect)(
71978
72108
  { socket: connectSocket, servername: TELEGRAM_API_HOST },
71979
72109
  () => {
@@ -71983,7 +72113,7 @@ Host: ${TELEGRAM_API_HOST}:${TELEGRAM_API_PORT}\r
71983
72113
  callback(null, tlsSocket);
71984
72114
  }
71985
72115
  );
71986
- tlsSocket.once("error", fail6);
72116
+ tlsSocket.once("error", fail7);
71987
72117
  });
71988
72118
  return void 0;
71989
72119
  });
@@ -72875,16 +73005,20 @@ function renderDeepInterviewRuntimeGuidance(availability) {
72875
73005
  "If Codex becomes unavailable, briefly note that and fall back to the Claude-only recommendations already listed in Phase 5."
72876
73006
  ].join("\n");
72877
73007
  }
73008
+ function resolveAvailability(availability) {
73009
+ if (typeof availability === "function") return availability();
73010
+ return availability ?? detectSkillRuntimeAvailability();
73011
+ }
72878
73012
  function renderSkillRuntimeGuidance(skillName, availability) {
72879
73013
  switch (normalizeSkillName(skillName)) {
72880
73014
  case "deep-interview":
72881
- return renderDeepInterviewRuntimeGuidance(availability ?? detectSkillRuntimeAvailability());
73015
+ return renderDeepInterviewRuntimeGuidance(resolveAvailability(availability));
72882
73016
  case "ralplan":
72883
73017
  case "omc-plan":
72884
73018
  case "plan":
72885
- return renderPlanRuntimeGuidance(availability ?? detectSkillRuntimeAvailability());
73019
+ return renderPlanRuntimeGuidance(resolveAvailability(availability));
72886
73020
  case "ralph":
72887
- return renderRalphRuntimeGuidance(availability ?? detectSkillRuntimeAvailability());
73021
+ return renderRalphRuntimeGuidance(resolveAvailability(availability));
72888
73022
  default:
72889
73023
  return "";
72890
73024
  }
@@ -73011,12 +73145,12 @@ function applyDeepInterviewRuntimeSettings(template) {
73011
73145
  function normalizeSkillNameForRuntimeRendering(skillName) {
73012
73146
  return skillName.trim().toLowerCase().replace(/^oh-my-copilot:/, "").replace(/^omc:/, "");
73013
73147
  }
73014
- function renderBundledSkillBody(skillName, body) {
73148
+ function renderBundledSkillBody(skillName, body, cliOptions) {
73015
73149
  const normalizedSkillName = normalizeSkillNameForRuntimeRendering(skillName);
73016
- const rewrittenBody = rewriteOmcCliInvocations(body.trim());
73150
+ const rewrittenBody = rewriteOmcCliInvocations(body.trim(), cliOptions);
73017
73151
  return normalizedSkillName === "deep-interview" || normalizedSkillName === "deep-dive" ? applyDeepInterviewRuntimeSettings(rewrittenBody) : rewrittenBody;
73018
73152
  }
73019
- function loadSkillFromFile(skillPath, skillName) {
73153
+ function loadSkillFromFile(skillPath, skillName, context) {
73020
73154
  try {
73021
73155
  const content = (0, import_fs72.readFileSync)(skillPath, "utf-8");
73022
73156
  const { metadata, body } = parseFrontmatter(content);
@@ -73024,10 +73158,10 @@ function loadSkillFromFile(skillPath, skillName) {
73024
73158
  const safePrimaryName = toSafeSkillName(resolvedName);
73025
73159
  const pipeline = parseSkillPipelineMetadata(metadata);
73026
73160
  const fullBody = readSkillBodyOverride(skillPath, metadata, body);
73027
- const renderedBody = renderBundledSkillBody(safePrimaryName, fullBody);
73161
+ const renderedBody = renderBundledSkillBody(safePrimaryName, fullBody, context.cliOptions);
73028
73162
  const template = [
73029
73163
  renderedBody,
73030
- renderSkillRuntimeGuidance(safePrimaryName),
73164
+ renderSkillRuntimeGuidance(safePrimaryName, context.runtimeAvailability),
73031
73165
  renderSkillPipelineGuidance(safePrimaryName, pipeline),
73032
73166
  renderSkillResourcesGuidance(skillPath)
73033
73167
  ].filter((section) => section.trim().length > 0).join("\n\n");
@@ -73069,6 +73203,11 @@ function loadSkillsFromDirectory() {
73069
73203
  }
73070
73204
  const skills = [];
73071
73205
  const seenNames = /* @__PURE__ */ new Set();
73206
+ let availability;
73207
+ const context = {
73208
+ cliOptions: { omcAvailable: isOmcCliAvailable() },
73209
+ runtimeAvailability: () => availability ??= detectSkillRuntimeAvailability()
73210
+ };
73072
73211
  try {
73073
73212
  const entries = (0, import_fs72.readdirSync)(SKILLS_DIR2, { withFileTypes: true }).sort((a, b) => {
73074
73213
  if (a.name === "skillify") return -1;
@@ -73082,7 +73221,7 @@ function loadSkillsFromDirectory() {
73082
73221
  }
73083
73222
  const skillPath = (0, import_path85.join)(SKILLS_DIR2, entry2.name, "SKILL.md");
73084
73223
  if ((0, import_fs72.existsSync)(skillPath)) {
73085
- const skillEntries = loadSkillFromFile(skillPath, entry2.name);
73224
+ const skillEntries = loadSkillFromFile(skillPath, entry2.name, context);
73086
73225
  for (const skill of skillEntries) {
73087
73226
  const key = skill.name.toLowerCase();
73088
73227
  if (seenNames.has(key)) continue;
@@ -75285,7 +75424,7 @@ function analyzePaneContent(content) {
75285
75424
  }
75286
75425
  function scanForBlockedPanes(lines3 = 15, stateDir) {
75287
75426
  const panes = listTmuxPanes();
75288
- const blocked = [];
75427
+ const blocked2 = [];
75289
75428
  for (const pane of panes) {
75290
75429
  let content;
75291
75430
  if (stateDir) {
@@ -75296,7 +75435,7 @@ function scanForBlockedPanes(lines3 = 15, stateDir) {
75296
75435
  }
75297
75436
  const analysis = analyzePaneContent(content);
75298
75437
  if (analysis.isBlocked) {
75299
- blocked.push({
75438
+ blocked2.push({
75300
75439
  ...pane,
75301
75440
  analysis,
75302
75441
  firstDetectedAt: /* @__PURE__ */ new Date(),
@@ -75304,7 +75443,7 @@ function scanForBlockedPanes(lines3 = 15, stateDir) {
75304
75443
  });
75305
75444
  }
75306
75445
  }
75307
- return blocked;
75446
+ return blocked2;
75308
75447
  }
75309
75448
  function revalidateBlockedPanes(trackedPanes, lines3 = 15) {
75310
75449
  if (trackedPanes.length === 0) return [];
@@ -80423,7 +80562,17 @@ async function writeAtomic3(path30, data) {
80423
80562
  try {
80424
80563
  await (0, import_promises14.writeFile)(tmp, data, "utf8");
80425
80564
  const { rename: rename8 } = await import("node:fs/promises");
80426
- await rename8(tmp, path30);
80565
+ for (let attempt = 0; ; attempt += 1) {
80566
+ try {
80567
+ await rename8(tmp, path30);
80568
+ break;
80569
+ } catch (error2) {
80570
+ const delay = WIN32_RENAME_RETRY_DELAYS_MS[attempt];
80571
+ const code = error2.code ?? "";
80572
+ if (process.platform !== "win32" || delay === void 0 || !WIN32_RENAME_RETRY_CODES.has(code)) throw error2;
80573
+ await new Promise((resolve58) => setTimeout(resolve58, delay));
80574
+ }
80575
+ }
80427
80576
  } finally {
80428
80577
  await (0, import_promises14.rm)(tmp, { force: true }).catch(() => void 0);
80429
80578
  }
@@ -81260,7 +81409,7 @@ async function teamMarkTaskCompleted(teamName, taskId, cwd2) {
81260
81409
  await writeAtomic3(p, JSON.stringify(next, null, 2));
81261
81410
  }, 5e3);
81262
81411
  }
81263
- var import_node_crypto7, import_node_fs10, import_promises14, import_node_path15;
81412
+ var import_node_crypto7, import_node_fs10, import_promises14, import_node_path15, WIN32_RENAME_RETRY_CODES, WIN32_RENAME_RETRY_DELAYS_MS;
81264
81413
  var init_team_ops = __esm({
81265
81414
  "src/team/team-ops.ts"() {
81266
81415
  "use strict";
@@ -81277,6 +81426,8 @@ var init_team_ops = __esm({
81277
81426
  init_tasks();
81278
81427
  init_task_recovery_checkpoint();
81279
81428
  init_worker_canonicalization();
81429
+ WIN32_RENAME_RETRY_CODES = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY"]);
81430
+ WIN32_RENAME_RETRY_DELAYS_MS = [5, 10, 20, 40, 80, 160, 320];
81280
81431
  }
81281
81432
  });
81282
81433
 
@@ -81657,15 +81808,23 @@ function buildWindowsSupervisorSource() {
81657
81808
  // interactive provider never reaches the pane. Stdin is read through a
81658
81809
  // StreamReader because [Console]::In.ReadLineAsync() blocks on .NET
81659
81810
  // Framework, which hid provider exit until the next control line.
81660
- `public static class O { [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] public struct STARTUPINFO { public int cb; public IntPtr lpReserved; public IntPtr lpDesktop; public IntPtr lpTitle; public int dwX; public int dwY; public int dwXSize; public int dwYSize; public int dwXCountChars; public int dwYCountChars; public int dwFillAttribute; public int dwFlags; public short wShowWindow; public short cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public uint dwProcessId; public uint dwThreadId; } [StructLayout(LayoutKind.Sequential)] public struct JOBOBJECT_BASIC_LIMIT_INFORMATION { public long PerProcessUserTimeLimit; public long PerJobUserTimeLimit; public uint LimitFlags; public UIntPtr MinimumWorkingSetSize; public UIntPtr MaximumWorkingSetSize; public uint ActiveProcessLimit; public UIntPtr Affinity; public uint PriorityClass; public uint SchedulingClass; } [StructLayout(LayoutKind.Sequential)] public struct IO_COUNTERS { public ulong ReadOperationCount; public ulong WriteOperationCount; public ulong OtherOperationCount; public ulong ReadTransferCount; public ulong WriteTransferCount; public ulong OtherTransferCount; } [StructLayout(LayoutKind.Sequential)] public struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION { public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; public IO_COUNTERS IoInfo; public UIntPtr ProcessMemoryLimit; public UIntPtr JobMemoryLimit; public UIntPtr PeakProcessMemoryUsed; public UIntPtr PeakJobMemoryUsed; } [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] public static extern bool CreateProcessW(string app, StringBuilder cmd, IntPtr pa, IntPtr ta, bool inherit, uint flags, IntPtr env, string dir, ref STARTUPINFO si, out PROCESS_INFORMATION pi); [DllImport("kernel32.dll", SetLastError=true)] public static extern IntPtr CreateJobObjectW(IntPtr a, string n); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool SetInformationJobObject(IntPtr j, int c, IntPtr i, uint l); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool AssignProcessToJobObject(IntPtr j, IntPtr p); [DllImport("kernel32.dll", SetLastError=true)] public static extern uint ResumeThread(IntPtr h); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool TerminateJobObject(IntPtr j, uint c); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool TerminateProcess(IntPtr p, uint c); [DllImport("kernel32.dll", SetLastError=true)] public static extern uint WaitForSingleObject(IntPtr h, uint ms); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool GetExitCodeProcess(IntPtr h, out uint code); [DllImport("kernel32.dll")] public static extern bool CloseHandle(IntPtr h); [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] public static extern IntPtr CreateFileW(string n, uint a, uint s, IntPtr sa, uint d, uint f, IntPtr t); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool SetHandleInformation(IntPtr h, uint m, uint f); public static string Quote(string value) { var b = new StringBuilder(); b.Append('"'); int slashes = 0; foreach (var c in value) { if (c == '\\\\') { slashes++; continue; } if (c == '"') { b.Append('\\\\', slashes * 2 + 1); b.Append('"'); slashes = 0; continue; } b.Append('\\\\', slashes); slashes = 0; b.Append(c); } b.Append('\\\\', slashes * 2); b.Append('"'); return b.ToString(); } public static string BuildCommandLine(string[] argv) { var b = new StringBuilder(); for (var i = 0; i < argv.Length; i++) { if (i != 0) b.Append(' '); b.Append(Quote(argv[i])); } return b.ToString(); } }`,
81811
+ // The start identity is read while the provider is still suspended: a
81812
+ // short-lived provider can exit before a slow host reaches the ready
81813
+ // frame, and Get-Process on an exited PID throws, killing the supervisor.
81814
+ `public static class O { [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] public struct STARTUPINFO { public int cb; public IntPtr lpReserved; public IntPtr lpDesktop; public IntPtr lpTitle; public int dwX; public int dwY; public int dwXSize; public int dwYSize; public int dwXCountChars; public int dwYCountChars; public int dwFillAttribute; public int dwFlags; public short wShowWindow; public short cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public uint dwProcessId; public uint dwThreadId; } [StructLayout(LayoutKind.Sequential)] public struct JOBOBJECT_BASIC_LIMIT_INFORMATION { public long PerProcessUserTimeLimit; public long PerJobUserTimeLimit; public uint LimitFlags; public UIntPtr MinimumWorkingSetSize; public UIntPtr MaximumWorkingSetSize; public uint ActiveProcessLimit; public UIntPtr Affinity; public uint PriorityClass; public uint SchedulingClass; } [StructLayout(LayoutKind.Sequential)] public struct IO_COUNTERS { public ulong ReadOperationCount; public ulong WriteOperationCount; public ulong OtherOperationCount; public ulong ReadTransferCount; public ulong WriteTransferCount; public ulong OtherTransferCount; } [StructLayout(LayoutKind.Sequential)] public struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION { public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; public IO_COUNTERS IoInfo; public UIntPtr ProcessMemoryLimit; public UIntPtr JobMemoryLimit; public UIntPtr PeakProcessMemoryUsed; public UIntPtr PeakJobMemoryUsed; } [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] public static extern bool CreateProcessW(string app, StringBuilder cmd, IntPtr pa, IntPtr ta, bool inherit, uint flags, IntPtr env, string dir, ref STARTUPINFO si, out PROCESS_INFORMATION pi); [DllImport("kernel32.dll", SetLastError=true)] public static extern IntPtr CreateJobObjectW(IntPtr a, string n); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool SetInformationJobObject(IntPtr j, int c, IntPtr i, uint l); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool AssignProcessToJobObject(IntPtr j, IntPtr p); [DllImport("kernel32.dll", SetLastError=true)] public static extern uint ResumeThread(IntPtr h); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool TerminateJobObject(IntPtr j, uint c); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool TerminateProcess(IntPtr p, uint c); [DllImport("kernel32.dll", SetLastError=true)] public static extern uint WaitForSingleObject(IntPtr h, uint ms); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool GetExitCodeProcess(IntPtr h, out uint code); [DllImport("kernel32.dll")] public static extern bool CloseHandle(IntPtr h); [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] public static extern IntPtr CreateFileW(string n, uint a, uint s, IntPtr sa, uint d, uint f, IntPtr t); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool SetHandleInformation(IntPtr h, uint m, uint f); public static string Quote(string value) { var b = new StringBuilder(); b.Append('"'); int slashes = 0; foreach (var c in value) { if (c == '\\\\') { slashes++; continue; } if (c == '"') { b.Append('\\\\', slashes * 2 + 1); b.Append('"'); slashes = 0; continue; } b.Append('\\\\', slashes); slashes = 0; b.Append(c); } b.Append('\\\\', slashes * 2); b.Append('"'); return b.ToString(); } public static string BuildCommandLine(string[] argv) { var b = new StringBuilder(); for (var i = 0; i < argv.Length; i++) { if (i != 0) b.Append(' '); b.Append(Quote(argv[i])); } return b.ToString(); } public static string CmdQuote(string value) { var b = new StringBuilder(); b.Append('"'); int slashes = 0; foreach (var c in value) { if (c < ' ') throw new ArgumentException("worker_launch_provider_argv_invalid"); if (c == '\\\\') { slashes++; continue; } if (c == '"') { b.Append('\\\\', slashes * 2); b.Append('"'); b.Append('"'); slashes = 0; continue; } b.Append('\\\\', slashes); slashes = 0; b.Append(c); } b.Append('\\\\', slashes * 2); b.Append('"'); return b.ToString(); } public static string BuildCmdLine(string[] argv) { var b = new StringBuilder(); for (var i = 0; i < argv.Length; i++) { if (i != 0) b.Append(' '); b.Append(CmdQuote(argv[i])); } if (b.Length > ${WINDOWS_PROVIDER_LINE_MAX}) throw new ArgumentException("worker_launch_provider_argv_too_long"); return b.ToString(); } }`,
81661
81815
  '"@',
81662
81816
  "$pi = New-Object O+PROCESS_INFORMATION; $job = [IntPtr]::Zero; $envPtr = [IntPtr]::Zero; $cmd = $null; $conIn = [IntPtr]::Zero; $conOut = [IntPtr]::Zero",
81663
81817
  "try {",
81664
- " $cmd = [O]::BuildCommandLine([string[]]$payload.provider_argv)",
81665
- ' $envPairs = @($payload.provider_env.psobject.Properties | Sort-Object Name | ForEach-Object { "$($_.Name)=$($_.Value)" }); $envText = (($envPairs -join [char]0) + [char]0 + [char]0); $envBytes = [Text.Encoding]::Unicode.GetBytes($envText); $envPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($envBytes.Length); [Runtime.InteropServices.Marshal]::Copy($envBytes, 0, $envPtr, $envBytes.Length)',
81666
- ` $conIn = [O]::CreateFileW('CONIN$', [uint32]3221225472, 3, [IntPtr]::Zero, 3, 0, [IntPtr]::Zero); $conOut = [O]::CreateFileW('CONOUT$', [uint32]3221225472, 3, [IntPtr]::Zero, 3, 0, [IntPtr]::Zero); if ($conIn -eq [IntPtr]::Zero -or $conIn -eq [IntPtr]::new(-1) -or $conOut -eq [IntPtr]::Zero -or $conOut -eq [IntPtr]::new(-1)) { $conIn = [IntPtr]::Zero; $conOut = [IntPtr]::Zero; throw "worker_launch_console_unavailable" }; if (-not [O]::SetHandleInformation($conIn, 1, 1) -or -not [O]::SetHandleInformation($conOut, 1, 1)) { throw "worker_launch_console_unavailable" }; $si = New-Object O+STARTUPINFO; $si.cb = [Runtime.InteropServices.Marshal]::SizeOf($si); $si.dwFlags = 0x00000100; $si.hStdInput = $conIn; $si.hStdOutput = $conOut; $si.hStdError = $conOut; $flags = 0x00000004 -bor 0x00000400; if (-not [O]::CreateProcessW([NullString]::Value, $cmd, [IntPtr]::Zero, [IntPtr]::Zero, $true, $flags, $envPtr, $payload.cwd, [ref]$si, [ref]$pi)) { throw "worker_launch_create_process_failed" }`,
81667
- ' $job = [O]::CreateJobObjectW([IntPtr]::Zero, [NullString]::Value); if ($job -eq [IntPtr]::Zero) { throw "worker_launch_create_job_failed" }; $info = New-Object O+JOBOBJECT_EXTENDED_LIMIT_INFORMATION; $info.BasicLimitInformation.LimitFlags = 0x2000; $ptr = [Runtime.InteropServices.Marshal]::AllocHGlobal([Runtime.InteropServices.Marshal]::SizeOf($info)); try { [Runtime.InteropServices.Marshal]::StructureToPtr($info, $ptr, $false); if (-not [O]::SetInformationJobObject($job, 9, $ptr, [Runtime.InteropServices.Marshal]::SizeOf($info))) { throw "worker_launch_job_config_failed" } } finally { [Runtime.InteropServices.Marshal]::FreeHGlobal($ptr) }; if (-not [O]::AssignProcessToJobObject($job, $pi.hProcess)) { throw "worker_launch_assign_job_failed" }; if ([O]::ResumeThread($pi.hThread) -eq [uint32]::MaxValue) { throw "worker_launch_resume_failed" }',
81668
- ' $ticks = ([DateTime]((Get-Process -Id $pi.dwProcessId).StartTime)).ToUniversalTime().Ticks; $ready = @{ protocol="' + WINDOWS_SUPERVISOR_PROTOCOL + '"; kind="ready"; attempt_id=$payload.identity.attempt_id; instance_id=$payload.identity.instance_id; authority_digest=$payload.authority_digest; containment_nonce=$payload.containment_nonce; pid=$pi.dwProcessId; process_start_identity=("ticks:" + $ticks) } | ConvertTo-Json -Compress; [Console]::Out.WriteLine($ready); [Console]::Out.Flush()',
81818
+ // A .cmd/.bat argv[0] is never handed to CreateProcessW, which would run
81819
+ // it through cmd.exe with the MSVC-quoted line (CVE-2024-27980). cmd.exe
81820
+ // itself is started instead and expands the cmd-quoted line once from
81821
+ // its environment block, clearing the variable before the provider runs.
81822
+ " $argv = [string[]]$payload.provider_argv; $app = [NullString]::Value; $providerLine = $null",
81823
+ ` if ($argv[0] -match '\\.(cmd|bat)[. ]*$') { $providerLine = [O]::BuildCmdLine($argv); $app = Join-Path ([Environment]::SystemDirectory) 'cmd.exe'; $cmd = '"' + $app + '" /d /v:off /s /c "set "${PROVIDER_LINE_VAR}=" & %${PROVIDER_LINE_VAR}%"' } else { $cmd = [O]::BuildCommandLine($argv) }`,
81824
+ ` $envPairs = @($payload.provider_env.psobject.Properties | Where-Object { $_.Name -ne '${PROVIDER_LINE_VAR}' } | ForEach-Object { [pscustomobject]@{ Name = $_.Name; Value = $_.Value } }); if ($null -ne $providerLine) { $envPairs += [pscustomobject]@{ Name = '${PROVIDER_LINE_VAR}'; Value = $providerLine } }; $envPairs = @($envPairs | Sort-Object Name | ForEach-Object { "$($_.Name)=$($_.Value)" }); $envText = (($envPairs -join [char]0) + [char]0 + [char]0); $envBytes = [Text.Encoding]::Unicode.GetBytes($envText); $envPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($envBytes.Length); [Runtime.InteropServices.Marshal]::Copy($envBytes, 0, $envPtr, $envBytes.Length)`,
81825
+ ` $conIn = [O]::CreateFileW('CONIN$', [uint32]3221225472, 3, [IntPtr]::Zero, 3, 0, [IntPtr]::Zero); $conOut = [O]::CreateFileW('CONOUT$', [uint32]3221225472, 3, [IntPtr]::Zero, 3, 0, [IntPtr]::Zero); if ($conIn -eq [IntPtr]::Zero -or $conIn -eq [IntPtr]::new(-1) -or $conOut -eq [IntPtr]::Zero -or $conOut -eq [IntPtr]::new(-1)) { $conIn = [IntPtr]::Zero; $conOut = [IntPtr]::Zero; throw "worker_launch_console_unavailable" }; if (-not [O]::SetHandleInformation($conIn, 1, 1) -or -not [O]::SetHandleInformation($conOut, 1, 1)) { throw "worker_launch_console_unavailable" }; $si = New-Object O+STARTUPINFO; $si.cb = [Runtime.InteropServices.Marshal]::SizeOf($si); $si.dwFlags = 0x00000100; $si.hStdInput = $conIn; $si.hStdOutput = $conOut; $si.hStdError = $conOut; $flags = 0x00000004 -bor 0x00000400; if (-not [O]::CreateProcessW($app, $cmd, [IntPtr]::Zero, [IntPtr]::Zero, $true, $flags, $envPtr, $payload.cwd, [ref]$si, [ref]$pi)) { throw "worker_launch_create_process_failed" }`,
81826
+ ' $job = [O]::CreateJobObjectW([IntPtr]::Zero, [NullString]::Value); if ($job -eq [IntPtr]::Zero) { throw "worker_launch_create_job_failed" }; $info = New-Object O+JOBOBJECT_EXTENDED_LIMIT_INFORMATION; $info.BasicLimitInformation.LimitFlags = 0x2000; $ptr = [Runtime.InteropServices.Marshal]::AllocHGlobal([Runtime.InteropServices.Marshal]::SizeOf($info)); try { [Runtime.InteropServices.Marshal]::StructureToPtr($info, $ptr, $false); if (-not [O]::SetInformationJobObject($job, 9, $ptr, [Runtime.InteropServices.Marshal]::SizeOf($info))) { throw "worker_launch_job_config_failed" } } finally { [Runtime.InteropServices.Marshal]::FreeHGlobal($ptr) }; if (-not [O]::AssignProcessToJobObject($job, $pi.hProcess)) { throw "worker_launch_assign_job_failed" }; $ticks = ([DateTime]((Get-Process -Id $pi.dwProcessId).StartTime)).ToUniversalTime().Ticks; if ([O]::ResumeThread($pi.hThread) -eq [uint32]::MaxValue) { throw "worker_launch_resume_failed" }',
81827
+ ' $ready = @{ protocol="' + WINDOWS_SUPERVISOR_PROTOCOL + '"; kind="ready"; attempt_id=$payload.identity.attempt_id; instance_id=$payload.identity.instance_id; authority_digest=$payload.authority_digest; containment_nonce=$payload.containment_nonce; pid=$pi.dwProcessId; process_start_identity=("ticks:" + $ticks) } | ConvertTo-Json -Compress; [Console]::Out.WriteLine($ready); [Console]::Out.Flush()',
81669
81828
  ' $stdinReader = New-Object IO.StreamReader([Console]::OpenStandardInput()); $readTask = $stdinReader.ReadLineAsync(); while ($true) { if ([O]::WaitForSingleObject($pi.hProcess, 50) -eq 0) { $exitCode = [uint32]0; [O]::GetExitCodeProcess($pi.hProcess, [ref]$exitCode) | Out-Null; if (-not [O]::TerminateJobObject($job, $exitCode)) { throw "worker_launch_job_terminate_failed" }; if ([O]::WaitForSingleObject($job, 5000) -ne 0) { throw "worker_launch_job_cleanup_timeout" }; $terminal = @{ protocol="' + WINDOWS_SUPERVISOR_PROTOCOL + '"; kind="terminal"; attempt_id=$payload.identity.attempt_id; instance_id=$payload.identity.instance_id; authority_digest=$payload.authority_digest; containment_nonce=$payload.containment_nonce; pid=$pi.dwProcessId; outcome="exit"; cleanup_verified=$true; exit_code=$exitCode } | ConvertTo-Json -Compress; [Console]::Out.WriteLine($terminal); [Console]::Out.Flush(); break }; if (-not $readTask.IsCompleted) { continue }; $line = $readTask.Result; if ($null -eq $line) { throw "worker_launch_authority_lost" }; $readTask = $stdinReader.ReadLineAsync(); if ([string]::IsNullOrWhiteSpace($line) -or $line.Length -gt 4096) { continue }; try { $msg = $line | ConvertFrom-Json } catch { continue }; if ($msg.protocol -ne "' + WINDOWS_SUPERVISOR_PROTOCOL + '" -or $msg.attempt_id -ne $payload.identity.attempt_id -or $msg.instance_id -ne $payload.identity.instance_id -or $msg.authority_digest -ne $payload.authority_digest -or $msg.containment_nonce -ne $payload.containment_nonce -or $msg.kind -ne "terminate") { continue }; if (-not [O]::TerminateJobObject($job, 1)) { throw "worker_launch_job_terminate_failed" }; if ([O]::WaitForSingleObject($job, 5000) -ne 0) { throw "worker_launch_job_cleanup_timeout" }; $terminal = @{ protocol="' + WINDOWS_SUPERVISOR_PROTOCOL + '"; kind="terminal"; attempt_id=$payload.identity.attempt_id; instance_id=$payload.identity.instance_id; authority_digest=$payload.authority_digest; containment_nonce=$payload.containment_nonce; pid=$pi.dwProcessId; outcome="terminated"; cleanup_verified=$true } | ConvertTo-Json -Compress; [Console]::Out.WriteLine($terminal); [Console]::Out.Flush(); break }',
81670
81829
  "} catch { if ($pi.hProcess -ne [IntPtr]::Zero) { if ($job -ne [IntPtr]::Zero) { [O]::TerminateJobObject($job, 1) | Out-Null } else { [O]::TerminateProcess($pi.hProcess, 1) | Out-Null }; [O]::WaitForSingleObject($pi.hProcess, 5000) | Out-Null }; throw } finally { if ($envPtr -ne [IntPtr]::Zero) { [Runtime.InteropServices.Marshal]::FreeHGlobal($envPtr) }; if ($conIn -ne [IntPtr]::Zero) { [O]::CloseHandle($conIn) | Out-Null }; if ($conOut -ne [IntPtr]::Zero) { [O]::CloseHandle($conOut) | Out-Null }; if ($pi.hThread -ne [IntPtr]::Zero) { [O]::CloseHandle($pi.hThread) | Out-Null }; if ($pi.hProcess -ne [IntPtr]::Zero) { [O]::CloseHandle($pi.hProcess) | Out-Null }; if ($job -ne [IntPtr]::Zero) { [O]::CloseHandle($job) | Out-Null } }"
81671
81830
  // Fork fix: a real newline. "`n" is only an escape inside PowerShell strings;
@@ -81954,6 +82113,9 @@ async function loadCurrentWorkerLaunchAttempt(input) {
81954
82113
  }
81955
82114
  function buildWorkerLaunchBootstrapSpec(attempt, providerArgv, cwd2, options = {}) {
81956
82115
  if (!isValidIdentity(attempt)) throw new Error("worker_launch_attempt_identity_invalid");
82116
+ if ((options.platform ?? process.platform) === "win32" && providerArgv[0] && isWindowsBatchProvider(providerArgv[0])) {
82117
+ buildWindowsBatchProviderLine(providerArgv);
82118
+ }
81957
82119
  const providerEnv = normalizeProviderEnvironment(options.providerEnv, options.platform ?? process.platform);
81958
82120
  const absoluteCwd = (0, import_node_path16.resolve)(cwd2);
81959
82121
  const containmentNonce = (0, import_node_crypto8.randomUUID)();
@@ -82682,10 +82844,19 @@ function isDeterministicTransportPath(expectedPath, candidate, fileName) {
82682
82844
  return isExactText(candidate) && (0, import_node_path16.resolve)(candidate) === (0, import_node_path16.resolve)((0, import_node_path16.join)((0, import_node_path16.dirname)(expectedPath), fileName));
82683
82845
  }
82684
82846
  function quoteWindowsCmdArgument(value) {
82685
- if (/[\r\n]/.test(value)) throw new Error("worker_launch_provider_argv_invalid");
82686
- return `"${value.replace(/%/g, "%%").replace(/"/g, '""')}"`;
82847
+ if (/[\x00-\x1f]/.test(value)) throw new Error("worker_launch_provider_argv_invalid");
82848
+ const escaped = value.replace(/(\\*)"/g, '$1$1""').replace(/(\\+)$/, "$1$1");
82849
+ return `"${escaped}"`;
82850
+ }
82851
+ function isWindowsBatchProvider(command) {
82852
+ return /\.(cmd|bat)[. ]*$/i.test(command);
82853
+ }
82854
+ function buildWindowsBatchProviderLine(providerArgv) {
82855
+ const line = providerArgv.map(quoteWindowsCmdArgument).join(" ");
82856
+ if (line.length > WINDOWS_PROVIDER_LINE_MAX) throw new Error("worker_launch_provider_argv_too_long");
82857
+ return line;
82687
82858
  }
82688
- var import_node_crypto8, import_node_fs11, import_promises17, import_node_path16, import_node_os2, WORKER_LAUNCH_SCHEMA_VERSION, DEFAULT_ACK_TIMEOUT_MS, DEFAULT_POLL_INTERVAL_MS, DEFAULT_DECISION_TIMEOUT_MS, WORKER_LAUNCH_TRANSPORT_OWNER_KIND, WORKER_LAUNCH_TRANSPORT_CLEANUP_KIND, WORKER_LAUNCH_BOOTSTRAP_DESCRIPTOR_FILE, WORKER_LAUNCH_RECOVERY_GATE_CONTAINED_ENV, WORKER_LAUNCH_INTERNAL_ENV_KEYS, WORKER_LAUNCH_AUTHORITY_PROTOCOL, WINDOWS_SUPERVISOR_PROTOCOL, WINDOWS_RESERVED_ENV_KEYS, SAFE_BASELINE_ENV_KEYS, WINDOWS_BASELINE_ENV_KEYS;
82859
+ var import_node_crypto8, import_node_fs11, import_promises17, import_node_path16, import_node_os2, WORKER_LAUNCH_SCHEMA_VERSION, DEFAULT_ACK_TIMEOUT_MS, DEFAULT_POLL_INTERVAL_MS, DEFAULT_DECISION_TIMEOUT_MS, WORKER_LAUNCH_TRANSPORT_OWNER_KIND, WORKER_LAUNCH_TRANSPORT_CLEANUP_KIND, WORKER_LAUNCH_BOOTSTRAP_DESCRIPTOR_FILE, WORKER_LAUNCH_RECOVERY_GATE_CONTAINED_ENV, WORKER_LAUNCH_INTERNAL_ENV_KEYS, WORKER_LAUNCH_AUTHORITY_PROTOCOL, WINDOWS_SUPERVISOR_PROTOCOL, WINDOWS_RESERVED_ENV_KEYS, SAFE_BASELINE_ENV_KEYS, WINDOWS_BASELINE_ENV_KEYS, WINDOWS_PROVIDER_LINE_MAX, PROVIDER_LINE_VAR;
82689
82860
  var init_worker_launch_ack = __esm({
82690
82861
  "src/team/worker-launch-ack.ts"() {
82691
82862
  "use strict";
@@ -82743,6 +82914,8 @@ var init_worker_launch_ack = __esm({
82743
82914
  "PUBLIC",
82744
82915
  "ALLUSERSPROFILE"
82745
82916
  ];
82917
+ WINDOWS_PROVIDER_LINE_MAX = 8e3;
82918
+ PROVIDER_LINE_VAR = "_OMC_PROVIDER_LINE";
82746
82919
  }
82747
82920
  });
82748
82921
 
@@ -83180,6 +83353,7 @@ function recoveryOwnerBootstrapCandidatePath(cwd2, teamName, expectedEpoch, nonc
83180
83353
  return absPath(cwd2, TeamPaths.recoveryOwnerBootstrapCandidate(teamName, expectedEpoch, nonce));
83181
83354
  }
83182
83355
  async function syncParentDirectory(path30) {
83356
+ if (process.platform === "win32") return;
83183
83357
  const directory = await (0, import_promises18.open)((0, import_node_path17.dirname)(path30), "r");
83184
83358
  try {
83185
83359
  await directory.sync();
@@ -84120,24 +84294,24 @@ async function runGuardedNativeTmuxCommand(identity, nativeCommand) {
84120
84294
  exec: tmuxCmdAsync
84121
84295
  });
84122
84296
  }
84123
- const guarded3 = tmuxGuardedNativeCommand(identity, nativeCommand);
84297
+ const guarded4 = tmuxGuardedNativeCommand(identity, nativeCommand);
84124
84298
  try {
84125
84299
  const result = await tmuxCmdAsync(
84126
84300
  tmuxArgsForIdentity(identity, [
84127
84301
  "if-shell",
84128
- guarded3.condition,
84129
- guarded3.success,
84130
- guarded3.failure
84302
+ guarded4.condition,
84303
+ guarded4.success,
84304
+ guarded4.failure
84131
84305
  ]),
84132
84306
  { timeout: 5e3, stripTmux: true }
84133
84307
  );
84134
84308
  if (result.stderr.trim()) return { outcome: "unknown", stdout: result.stdout, stderr: result.stderr };
84135
84309
  const outputLines = result.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
84136
- const failureMarker = `OMC_TMUX_GUARD_FAIL_${guarded3.marker}`;
84310
+ const failureMarker = `OMC_TMUX_GUARD_FAIL_${guarded4.marker}`;
84137
84311
  if (outputLines.includes(failureMarker)) {
84138
84312
  return { outcome: "not_executed", stdout: result.stdout, stderr: result.stderr };
84139
84313
  }
84140
- if (outputLines.includes(guarded3.marker)) {
84314
+ if (outputLines.includes(guarded4.marker)) {
84141
84315
  return { outcome: "executed", stdout: result.stdout, stderr: result.stderr };
84142
84316
  }
84143
84317
  return { outcome: "unknown", stdout: result.stdout, stderr: result.stderr };
@@ -86173,31 +86347,31 @@ async function killOwnedWorkerPane(ownership) {
86173
86347
  }
86174
86348
  function detectPaneTrustPromptKind(captured, provider) {
86175
86349
  const lines3 = captured.split("\n").map((l) => l.replace(/\r/g, "").trim()).filter((l) => l.length > 0);
86176
- const tail2 = lines3.slice(-12);
86177
- const hasCursorTrustBanner = tail2.some((l) => /Workspace Trust Required/i.test(l));
86178
- const hasCursorTrustHint = tail2.some((l) => /Pass\s+--trust,\s*--yolo,\s*or\s+-f/i.test(l));
86179
- if ((provider === void 0 || provider === "cursor") && hasCursorTrustBanner && (hasCursorTrustHint || tail2.some((l) => /Do you trust the contents of this directory\?/i.test(l)))) {
86350
+ const tail3 = lines3.slice(-12);
86351
+ const hasCursorTrustBanner = tail3.some((l) => /Workspace Trust Required/i.test(l));
86352
+ const hasCursorTrustHint = tail3.some((l) => /Pass\s+--trust,\s*--yolo,\s*or\s+-f/i.test(l));
86353
+ if ((provider === void 0 || provider === "cursor") && hasCursorTrustBanner && (hasCursorTrustHint || tail3.some((l) => /Do you trust the contents of this directory\?/i.test(l)))) {
86180
86354
  return "cursor_workspace_trust";
86181
86355
  }
86182
- const hasClaudeDirectoryQuestion = tail2.some(
86356
+ const hasClaudeDirectoryQuestion = tail3.some(
86183
86357
  (l) => /(?:Do you trust the files in this folder|Quick safety check:\s*Is this a project you created or one you trust)\?/i.test(l)
86184
86358
  );
86185
- const hasClaudeDirectoryNoChoice = tail2.some((l) => /\bNo,\s*exit\b/i.test(l));
86186
- const hasClaudeDirectoryYesChoice = tail2.some((l) => /\bYes,\s*(?:proceed|I trust this folder)\b/i.test(l));
86359
+ const hasClaudeDirectoryNoChoice = tail3.some((l) => /\bNo,\s*exit\b/i.test(l));
86360
+ const hasClaudeDirectoryYesChoice = tail3.some((l) => /\bYes,\s*(?:proceed|I trust this folder)\b/i.test(l));
86187
86361
  if (provider === "claude" && hasClaudeDirectoryQuestion && hasClaudeDirectoryNoChoice && hasClaudeDirectoryYesChoice) {
86188
86362
  return "claude_directory";
86189
86363
  }
86190
- const hasCopilotYesChoice = tail2.some((l) => /\b1\.\s*Yes\s*(?:│|$)/.test(l));
86191
- const hasCopilotNoChoice = tail2.some((l) => /\b3\.\s*No\s*\(Esc\)/i.test(l));
86364
+ const hasCopilotYesChoice = tail3.some((l) => /\b1\.\s*Yes\s*(?:│|$)/.test(l));
86365
+ const hasCopilotNoChoice = tail3.some((l) => /\b3\.\s*No\s*\(Esc\)/i.test(l));
86192
86366
  if (provider === "copilot" && hasClaudeDirectoryQuestion && hasCopilotYesChoice && hasCopilotNoChoice) {
86193
86367
  return "copilot_folder";
86194
86368
  }
86195
- const hasDirectoryQuestion = tail2.some((l) => /Do you trust the contents of this directory\?/i.test(l));
86196
- const hasDirectoryChoices = tail2.some((l) => /Yes,\s*continue|No,\s*quit|Press enter to continue/i.test(l));
86369
+ const hasDirectoryQuestion = tail3.some((l) => /Do you trust the contents of this directory\?/i.test(l));
86370
+ const hasDirectoryChoices = tail3.some((l) => /Yes,\s*continue|No,\s*quit|Press enter to continue/i.test(l));
86197
86371
  if (hasDirectoryQuestion && hasDirectoryChoices) return "directory";
86198
- const hasHookReview = tail2.some((l) => /Hooks need review/i.test(l));
86199
- const hasHookTrustChoice = tail2.some((l) => /Continue without trusting/i.test(l));
86200
- const hasHookConfirm = tail2.some((l) => /Press enter to confirm or esc to go back/i.test(l));
86372
+ const hasHookReview = tail3.some((l) => /Hooks need review/i.test(l));
86373
+ const hasHookTrustChoice = tail3.some((l) => /Continue without trusting/i.test(l));
86374
+ const hasHookConfirm = tail3.some((l) => /Press enter to confirm or esc to go back/i.test(l));
86201
86375
  if (hasHookReview && hasHookTrustChoice && hasHookConfirm) return "codex_hooks";
86202
86376
  return null;
86203
86377
  }
@@ -86225,13 +86399,13 @@ function paneIsBootstrapping(captured, provider) {
86225
86399
  }
86226
86400
  function paneHasActiveTask(captured, provider) {
86227
86401
  const lines3 = captured.split("\n").map((l) => l.replace(/\r/g, "").trim()).filter((l) => l.length > 0);
86228
- const tail2 = lines3.slice(-40);
86229
- if (provider === "cursor" && tail2.some((l) => /ctrl\+c\s+to\s+stop/i.test(l))) return true;
86230
- if (provider === "copilot" && tail2.some((l) => /^\S?\s*Working\b.*\besc\b/u.test(l))) return true;
86231
- if (tail2.some((l) => /\b\d+\s+background terminal running\b/i.test(l))) return true;
86232
- if (tail2.some((l) => /esc to interrupt/i.test(l))) return true;
86233
- if (tail2.some((l) => /\bbackground terminal running\b/i.test(l))) return true;
86234
- if (tail2.some((l) => /^[·✻✢✳✶✽✺✹✸✷*]\s+[A-Za-z][A-Za-z0-9''-]*(?:\s+[A-Za-z][A-Za-z0-9''-]*){0,3}(?:…|\.{3})(?:\s*\(.*\))?$/u.test(l))) return true;
86402
+ const tail3 = lines3.slice(-40);
86403
+ if (provider === "cursor" && tail3.some((l) => /ctrl\+c\s+to\s+stop/i.test(l))) return true;
86404
+ if (provider === "copilot" && tail3.some((l) => /^\S?\s*Working\b.*\besc\b/u.test(l))) return true;
86405
+ if (tail3.some((l) => /\b\d+\s+background terminal running\b/i.test(l))) return true;
86406
+ if (tail3.some((l) => /esc to interrupt/i.test(l))) return true;
86407
+ if (tail3.some((l) => /\bbackground terminal running\b/i.test(l))) return true;
86408
+ if (tail3.some((l) => /^[·✻✢✳✶✽✺✹✸✷*]\s+[A-Za-z][A-Za-z0-9''-]*(?:\s+[A-Za-z][A-Za-z0-9''-]*){0,3}(?:…|\.{3})(?:\s*\(.*\))?$/u.test(l))) return true;
86235
86409
  return false;
86236
86410
  }
86237
86411
  function paneLooksReady(captured, provider) {
@@ -90479,8 +90653,8 @@ async function startMergeOrchestrator(config2) {
90479
90653
  let persisted = { lastShas: {} };
90480
90654
  if ((0, import_node_fs17.existsSync)(persistedPath)) {
90481
90655
  try {
90482
- const { readFileSync: readFileSync141 } = await import("node:fs");
90483
- persisted = JSON.parse(readFileSync141(persistedPath, "utf-8"));
90656
+ const { readFileSync: readFileSync143 } = await import("node:fs");
90657
+ persisted = JSON.parse(readFileSync143(persistedPath, "utf-8"));
90484
90658
  } catch {
90485
90659
  persisted = { lastShas: {} };
90486
90660
  }
@@ -90925,8 +91099,8 @@ async function recoverFromRestart(config2) {
90925
91099
  let persistedShasLoaded = 0;
90926
91100
  if ((0, import_node_fs17.existsSync)(persistedPath)) {
90927
91101
  try {
90928
- const { readFileSync: readFileSync141 } = await import("node:fs");
90929
- const persisted = JSON.parse(readFileSync141(persistedPath, "utf-8"));
91102
+ const { readFileSync: readFileSync143 } = await import("node:fs");
91103
+ const persisted = JSON.parse(readFileSync143(persistedPath, "utf-8"));
90930
91104
  persistedShasLoaded = Object.keys(persisted.lastShas ?? {}).length;
90931
91105
  } catch {
90932
91106
  persistedShasLoaded = 0;
@@ -91674,6 +91848,11 @@ function permitScopedRead(req, ctx) {
91674
91848
  const platform = ctx.platform ?? process.platform;
91675
91849
  return isUnder(req.path, ctx.pluginRoot, platform) || isUnder(req.path, ctx.projectDir, platform);
91676
91850
  }
91851
+ function permitProjectFiles(req, ctx) {
91852
+ const platform = ctx.platform ?? process.platform;
91853
+ const target = req.kind === "read" ? req.path : req.kind === "write" ? req.resolvedPath ?? req.fileName : void 0;
91854
+ return typeof target === "string" && !!target && isUnder((0, import_path115.resolve)(ctx.projectDir, target), ctx.projectDir, platform);
91855
+ }
91677
91856
  function evaluateTeam(run) {
91678
91857
  const team = run.team;
91679
91858
  if (!team) return scenarioCheckIds("team").slice(0, 8).map((id) => ({ id, ok: false, detail: run.error ? `no team evidence: ${excerpt(run.error, 200)}` : "no team evidence collected" }));
@@ -91806,6 +91985,121 @@ function evaluateChain(run) {
91806
91985
  }
91807
91986
  ];
91808
91987
  }
91988
+ function probeHooksJson(node, script, log3) {
91989
+ const hooks = {};
91990
+ for (const e of PROBE_ENTRIES) {
91991
+ (hooks[e.event] ??= []).push({
91992
+ type: "command",
91993
+ ..."matcher" in e ? { matcher: e.matcher } : {},
91994
+ exec: node,
91995
+ args: [script, e.label, log3],
91996
+ timeoutSec: 10
91997
+ });
91998
+ }
91999
+ return { version: 1, hooks };
92000
+ }
92001
+ function fileToolCalls(events) {
92002
+ const done = new Map(events.filter((e) => e.type === "tool.execution_complete").map((e) => [str2(e.data?.toolCallId), e.data?.success === true]));
92003
+ return events.filter((e) => e.type === "tool.execution_start" && [...FILE_READ_TOOLS, ...FILE_WRITE_TOOLS].includes(str2(e.data?.toolName))).map((e) => ({ id: str2(e.data?.toolCallId), name: str2(e.data?.toolName), args: e.data?.arguments, ok: done.get(str2(e.data?.toolCallId)) === true }));
92004
+ }
92005
+ function asObject(value) {
92006
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
92007
+ }
92008
+ function inputPaths(input) {
92009
+ if (typeof input === "string") return [...input.matchAll(PATCH_FILE_LINE)].map((m) => m[1]);
92010
+ const o = asObject(input);
92011
+ const p = o ? str2(o.file_path) || str2(o.path) : "";
92012
+ return p ? [p] : [];
92013
+ }
92014
+ function probeTool(r) {
92015
+ const p = r.payload ?? {};
92016
+ return { name: str2(p.tool_name) || str2(p.toolName), input: p.tool_input ?? p.toolArgs };
92017
+ }
92018
+ function inputKey(input) {
92019
+ if (typeof input === "string") return `text:${input}`;
92020
+ const o = asObject(input);
92021
+ return o ? JSON.stringify(o, Object.keys(o).sort()) : "";
92022
+ }
92023
+ function recordsFor(call, records2, label) {
92024
+ const want = inputKey(call.args);
92025
+ return want ? records2.filter((r) => r.label === label && inputKey(probeTool(r).input) === want) : [];
92026
+ }
92027
+ function toolResultTexts(events, callId) {
92028
+ const out = [];
92029
+ for (const e of events) {
92030
+ if (str2(e.data?.toolCallId) !== callId) continue;
92031
+ if (e.type === "tool.execution_complete") out.push(str2(asObject(e.data?.result)?.content));
92032
+ if (e.type === "model.tool_execution") out.push(str2(asObject(e.data?.toolResult)?.textResultForLlm));
92033
+ }
92034
+ return out.filter(Boolean);
92035
+ }
92036
+ function evaluateFiletools(run) {
92037
+ const ft = run.filetools;
92038
+ const ids = scenarioCheckIds("filetools");
92039
+ if (!ft) return ids.slice(0, 8).map((id) => ({ id, ok: false, detail: run.error ? `no filetools evidence: ${excerpt(run.error, 200)}` : "no filetools evidence collected" }));
92040
+ const calls = fileToolCalls(run.events).filter((c) => c.ok);
92041
+ const reads = calls.filter((c) => FILE_READ_TOOLS.includes(c.name));
92042
+ const writes = calls.filter((c) => FILE_WRITE_TOOLS.includes(c.name));
92043
+ const toolsOk = reads.length > 0 && writes.length > 0 && ft.edited && ft.created;
92044
+ const seen = (claudeLabel, nativeLabel) => {
92045
+ const rows = calls.map((c) => ({ c, claude: recordsFor(c, ft.probe, claudeLabel), native: nativeLabel ? recordsFor(c, ft.probe, nativeLabel) : [] }));
92046
+ const ok = calls.length > 0 && rows.every((r) => r.claude.length > 0 && (!nativeLabel || r.native.length > 0));
92047
+ const names = (recs) => [...new Set(recs.map((x) => probeTool(x).name || "?"))].join("/") || "none";
92048
+ const detail = rows.map((r) => `${r.c.name}\u2192${names(r.claude)}${nativeLabel ? ` (native ${names(r.native)})` : ""}`).join(", ") || "no file tool calls";
92049
+ return { ok, detail, rows };
92050
+ };
92051
+ const pre = seen("PreToolUse", "preToolUse");
92052
+ const post = seen("PostToolUse", "postToolUse");
92053
+ const matcher = seen("PostToolUse:matcher");
92054
+ const claudeNames = new Set(FILE_TOOL_MATCHER.split("|"));
92055
+ const payloadRows = [...pre.rows, ...post.rows];
92056
+ const payloadOk = calls.length > 0 && payloadRows.every((r) => r.claude.every((x) => claudeNames.has(probeTool(x).name) && inputPaths(probeTool(x).input).length > 0) && r.native.every((x) => probeTool(x).name === r.c.name));
92057
+ const shape = (recs) => {
92058
+ if (!recs[0]) return "none";
92059
+ const { name, input } = probeTool(recs[0]);
92060
+ return typeof input === "string" ? `${name} "<patch: ${inputPaths(input).map((p) => p.split(/[\\/]/).slice(-2).join("/")).join(", ")}>"` : `${name} {${Object.keys(asObject(input) ?? {}).join(",")}}`;
92061
+ };
92062
+ const contextCall = (c) => inputPaths(c.args).some((p) => /readme\.md$/i.test(p));
92063
+ const injection = (nonce, from) => {
92064
+ const hookOut = run.events.some((e) => e.type === "hook.end" && e.data?.hookType === "postToolUse" && JSON.stringify(e.data?.output ?? "").includes(nonce));
92065
+ const carrier = from.find((c) => !contextCall(c) && toolResultTexts(run.events, c.id).some((t) => t.includes(nonce)));
92066
+ return {
92067
+ ok: hookOut && !!carrier,
92068
+ detail: `nonce ${hookOut ? "in" : "missing from"} a postToolUse hook.end output; ${carrier ? `in the ${carrier.name} tool result sent to the model` : "in no model-facing tool result"}`
92069
+ };
92070
+ };
92071
+ const read = injection(ft.nonce, reads);
92072
+ const write = injection(ft.writeNonce, writes);
92073
+ const echoed = assistantText2(run.events).includes(ft.nonce);
92074
+ return [
92075
+ {
92076
+ id: "scn.filetools.tools",
92077
+ ok: toolsOk,
92078
+ detail: `${calls.map((c) => c.name).join(", ") || "no file tool calls"} completed; notes.txt ${ft.edited ? "edited" : "unchanged"}, created.txt ${ft.created ? "created" : "missing"}`
92079
+ },
92080
+ hookCheck("scn.filetools.hooks", run.events, ["preToolUse", "postToolUse"]),
92081
+ { id: "scn.filetools.pre", ok: pre.ok, detail: `PreToolUse probe: ${pre.detail}` },
92082
+ { id: "scn.filetools.post", ok: post.ok, detail: `PostToolUse probe: ${post.detail}` },
92083
+ { id: "scn.filetools.matcher", ok: matcher.ok, detail: `PostToolUse matcher ${FILE_TOOL_MATCHER}: ${matcher.detail}` },
92084
+ {
92085
+ id: "scn.filetools.payload",
92086
+ ok: payloadOk,
92087
+ detail: post.rows.map((r) => `${r.c.name}: tool_name ${shape(r.claude)}`).join("; ") || "no file tool calls",
92088
+ ...payloadOk ? {} : { evidence: excerpt(JSON.stringify(payloadRows.map((r) => ({ call: r.c.name, claude: r.claude.map(probeTool), native: r.native.map(probeTool) })))) }
92089
+ },
92090
+ {
92091
+ id: "scn.filetools.injected",
92092
+ ok: read.ok,
92093
+ detail: `${FILETOOLS_FILES.context} ${read.detail}; model ${echoed ? "echoed it" : "did not echo it"}`,
92094
+ ...read.ok ? {} : { evidence: excerpt(assistantText2(run.events)) }
92095
+ },
92096
+ {
92097
+ id: "scn.filetools.injected_write",
92098
+ ok: write.ok,
92099
+ detail: `${FILETOOLS_FILES.writeContext} ${write.detail}`
92100
+ }
92101
+ ];
92102
+ }
91809
92103
  function scenarioExcludedTools(name, mcpServer) {
91810
92104
  return [hostSmokeToolName(mcpServer), ...SCENARIOS[name].excludedTools];
91811
92105
  }
@@ -91815,6 +92109,7 @@ function scenarioCheckIds(name) {
91815
92109
  guardrail: ["denied", "no_push", "hooks"],
91816
92110
  skill: ["invoked"],
91817
92111
  delegate: ["selected", "hooks", "completed"],
92112
+ filetools: ["tools", "hooks", "pre", "post", "matcher", "payload", "injected", "injected_write"],
91818
92113
  chain: ["link1", "spawned", "inherited", "closed", "premium"],
91819
92114
  team: ["started", "completed", "committed", "status", "shutdown", "retained", "duration", "premium"]
91820
92115
  };
@@ -92111,6 +92406,7 @@ function evaluateScenario(run) {
92111
92406
  guardrail: evaluateGuardrail,
92112
92407
  skill: evaluateSkill,
92113
92408
  delegate: evaluateDelegate,
92409
+ filetools: evaluateFiletools,
92114
92410
  chain: evaluateChain,
92115
92411
  team: evaluateTeam
92116
92412
  }[run.name](run);
@@ -92124,7 +92420,7 @@ function chooseModel(listed, requested) {
92124
92420
  if (cheap) return { model: cheap, label: cheap, note: `cheapest-looking of ${ids.length} listed` };
92125
92421
  return { label: "auto", note: `models.list offers ${ids.join(", ") || "nothing"}; no cheap explicit model, runtime auto-routes` };
92126
92422
  }
92127
- var import_fs92, import_path115, ALL_SCENARIOS, OPT_IN_SCENARIOS, KNOWN_SCENARIOS, DEFAULT_SCENARIOS, PLUGIN_NAME2, DELEGATE_AGENT, MIN_PROTOCOL_VERSION, SDK_PACKAGE, SDK_MISSING_DETAIL, NO_SHELL_OR_WRITE_TOOLS, NO_WRITE_TOOLS, denyAll, GUARDRAIL_COMMAND, SCENARIOS, TEAM_FILES, TEAM_WORKERS, TEAM_MAX_PREMIUM_REQUESTS, TEAM_BUDGET_MS, CHAIN_INTENT_ID, CHAIN_SKILL, CHAIN_LINK1_STAGE, CHAIN_LINK2_STAGE, CHAIN_MAX_PREMIUM_REQUESTS, ledgerStr, SDK_STATIC_IDS, RUNTIME_MIN_MAX_CREDITS, CREDIT_CAP_SKIP_DETAIL, NANO, GUARDRAIL_MARKER, CHEAP_MODEL;
92423
+ var import_fs92, import_path115, ALL_SCENARIOS, OPT_IN_SCENARIOS, KNOWN_SCENARIOS, DEFAULT_SCENARIOS, PLUGIN_NAME2, DELEGATE_AGENT, MIN_PROTOCOL_VERSION, SDK_PACKAGE, SDK_MISSING_DETAIL, NO_SHELL_OR_WRITE_TOOLS, NO_WRITE_TOOLS, denyAll, GUARDRAIL_COMMAND, FILETOOLS_DIR, FILETOOLS_FILES, FILETOOLS_MARKER, FILE_TOOL_MATCHER, SCENARIOS, TEAM_FILES, TEAM_WORKERS, TEAM_MAX_PREMIUM_REQUESTS, TEAM_BUDGET_MS, CHAIN_INTENT_ID, CHAIN_SKILL, CHAIN_LINK1_STAGE, CHAIN_LINK2_STAGE, CHAIN_MAX_PREMIUM_REQUESTS, ledgerStr, PROBE_ENTRIES, FILE_READ_TOOLS, FILE_WRITE_TOOLS, PATCH_FILE_LINE, SDK_STATIC_IDS, RUNTIME_MIN_MAX_CREDITS, CREDIT_CAP_SKIP_DETAIL, NANO, GUARDRAIL_MARKER, CHEAP_MODEL;
92128
92424
  var init_copilot_sdk_scenarios = __esm({
92129
92425
  "src/smoke/copilot-sdk-scenarios.ts"() {
92130
92426
  "use strict";
@@ -92132,7 +92428,7 @@ var init_copilot_sdk_scenarios = __esm({
92132
92428
  import_path115 = require("path");
92133
92429
  init_copilot_session_eval();
92134
92430
  ALL_SCENARIOS = ["smoke", "guardrail", "skill", "delegate"];
92135
- OPT_IN_SCENARIOS = ["chain", "team"];
92431
+ OPT_IN_SCENARIOS = ["filetools", "chain", "team"];
92136
92432
  KNOWN_SCENARIOS = [...ALL_SCENARIOS, ...OPT_IN_SCENARIOS];
92137
92433
  DEFAULT_SCENARIOS = ["smoke", "guardrail"];
92138
92434
  PLUGIN_NAME2 = "oh-my-copilot";
@@ -92144,6 +92440,21 @@ var init_copilot_sdk_scenarios = __esm({
92144
92440
  NO_WRITE_TOOLS = ["create", "edit"];
92145
92441
  denyAll = () => false;
92146
92442
  GUARDRAIL_COMMAND = /^\s*git\s+push\s+(--force|-f)\s+origin\s+main\s*$/;
92443
+ FILETOOLS_DIR = "filetools";
92444
+ FILETOOLS_FILES = {
92445
+ notes: `${FILETOOLS_DIR}/notes.txt`,
92446
+ created: `${FILETOOLS_DIR}/new/created.txt`,
92447
+ /**
92448
+ * Picked up by post-tool-directory-context-injector.mjs (README.md, not
92449
+ * AGENTS.md: Copilot loads AGENTS.md itself). The injector sends each
92450
+ * README once per session, so the read (view of notes.txt) and the write
92451
+ * (creating created.txt) each get their own.
92452
+ */
92453
+ context: `${FILETOOLS_DIR}/README.md`,
92454
+ writeContext: `${FILETOOLS_DIR}/new/README.md`
92455
+ };
92456
+ FILETOOLS_MARKER = "Context marker:";
92457
+ FILE_TOOL_MATCHER = "Read|Write|Edit|MultiEdit";
92147
92458
  SCENARIOS = {
92148
92459
  smoke: {
92149
92460
  name: "smoke",
@@ -92173,6 +92484,19 @@ var init_copilot_sdk_scenarios = __esm({
92173
92484
  excludedTools: [...NO_SHELL_OR_WRITE_TOOLS],
92174
92485
  permit: permitScopedRead
92175
92486
  },
92487
+ // The fixture (FILETOOLS_FILES) and the probe plugin are written by the driver.
92488
+ filetools: {
92489
+ name: "filetools",
92490
+ prompt: [
92491
+ `Use only your file tools, never a shell, and touch no file outside the ${FILETOOLS_DIR} directory.`,
92492
+ `1. View ${FILETOOLS_FILES.notes}.`,
92493
+ `2. Edit ${FILETOOLS_FILES.notes} so that the line "status: draft" reads "status: done".`,
92494
+ `3. Create ${FILETOOLS_FILES.created} containing exactly the line "created".`,
92495
+ `Do not open any other file. Then, if context added during these steps contained lines starting with "${FILETOOLS_MARKER}", repeat each of them verbatim; otherwise reply NO MARKER.`
92496
+ ].join("\n"),
92497
+ excludedTools: ["powershell", "shell"],
92498
+ permit: permitProjectFiles
92499
+ },
92176
92500
  // Not an SDK session: the prompt is link 1's, spawned as a real `copilot -p`
92177
92501
  // factory link (copilot-chain-scenario.ts) under the AFK profile.
92178
92502
  chain: {
@@ -92204,6 +92528,16 @@ var init_copilot_sdk_scenarios = __esm({
92204
92528
  CHAIN_LINK2_STAGE = "link-2";
92205
92529
  CHAIN_MAX_PREMIUM_REQUESTS = 2;
92206
92530
  ledgerStr = (ledger, key) => str2(ledger?.[key]);
92531
+ PROBE_ENTRIES = [
92532
+ { event: "PreToolUse", label: "PreToolUse" },
92533
+ { event: "PostToolUse", label: "PostToolUse" },
92534
+ { event: "PostToolUse", label: "PostToolUse:matcher", matcher: FILE_TOOL_MATCHER },
92535
+ { event: "preToolUse", label: "preToolUse" },
92536
+ { event: "postToolUse", label: "postToolUse" }
92537
+ ];
92538
+ FILE_READ_TOOLS = ["view"];
92539
+ FILE_WRITE_TOOLS = ["create", "edit", "str_replace_editor", "apply_patch"];
92540
+ PATCH_FILE_LINE = /^\*\*\* (?:(?:Add|Update|Delete) File|Move to): (.+?)\s*$/gm;
92207
92541
  SDK_STATIC_IDS = ["sdk.available", "sdk.runtime", "sdk.plugins", "sdk.skills", "sdk.agents", "sdk.mcp", "sdk.tools_excluded"];
92208
92542
  RUNTIME_MIN_MAX_CREDITS = 30;
92209
92543
  CREDIT_CAP_SKIP_DETAIL = "skipped: credit cap reached";
@@ -92311,9 +92645,11 @@ __export(copilot_sdk_driver_exports, {
92311
92645
  DEFAULT_SCENARIO_TIMEOUT_MS: () => DEFAULT_SCENARIO_TIMEOUT_MS,
92312
92646
  RUNTIME_WEDGED_DETAIL: () => RUNTIME_WEDGED_DETAIL,
92313
92647
  SDK_MIN_VERSION: () => SDK_MIN_VERSION,
92648
+ collectFiletools: () => collectFiletools,
92314
92649
  globalModuleRoots: () => globalModuleRoots,
92315
92650
  importFromDir: () => importFromDir,
92316
92651
  loadCopilotSdk: () => loadCopilotSdk,
92652
+ prepareFiletools: () => prepareFiletools,
92317
92653
  prepareSdkProject: () => prepareSdkProject,
92318
92654
  resolveShimTarget: () => resolveShimTarget,
92319
92655
  runSdkTier: () => runSdkTier,
@@ -92386,8 +92722,8 @@ function exportPath(target, condition) {
92386
92722
  if (typeof cond === "string") return cond;
92387
92723
  return typeof cond?.default === "string" ? cond.default : void 0;
92388
92724
  }
92389
- function npmRootG(env2, spawnSync17) {
92390
- const res = process.platform === "win32" ? spawnSync17("npm root -g", { env: env2, encoding: "utf8", timeout: 15e3, windowsHide: true, shell: true }) : spawnSync17("npm", ["root", "-g"], { env: env2, encoding: "utf8", timeout: 15e3 });
92725
+ function npmRootG(env2, spawnSync18) {
92726
+ const res = process.platform === "win32" ? spawnSync18("npm root -g", { env: env2, encoding: "utf8", timeout: 15e3, windowsHide: true, shell: true }) : spawnSync18("npm", ["root", "-g"], { env: env2, encoding: "utf8", timeout: 15e3 });
92391
92727
  const out = String(res.stdout ?? "").trim();
92392
92728
  return res.status === 0 && out ? out : null;
92393
92729
  }
@@ -92427,7 +92763,7 @@ function resolveShimTarget(shim, read = (p) => (0, import_fs93.readFileSync)(p,
92427
92763
  }
92428
92764
  return null;
92429
92765
  }
92430
- async function loadCopilotSdk(env2 = process.env, spawnSync17 = import_child_process28.spawnSync) {
92766
+ async function loadCopilotSdk(env2 = process.env, spawnSync18 = import_child_process28.spawnSync) {
92431
92767
  const spec = SDK_PACKAGE;
92432
92768
  try {
92433
92769
  const mod = await import(spec);
@@ -92450,7 +92786,7 @@ async function loadCopilotSdk(env2 = process.env, spawnSync17 = import_child_pro
92450
92786
  const hit = await tryRoot(root2);
92451
92787
  if (hit) return hit;
92452
92788
  }
92453
- return tryRoot(npmRootG(env2, spawnSync17));
92789
+ return tryRoot(npmRootG(env2, spawnSync18));
92454
92790
  }
92455
92791
  function withTimeout(promise, ms, label) {
92456
92792
  let timer;
@@ -92499,8 +92835,8 @@ function pidAlive(pid) {
92499
92835
  return err.code === "EPERM";
92500
92836
  }
92501
92837
  }
92502
- function prepareSdkProject(spawnSync17, projectDir, remoteDir, env2) {
92503
- const git5 = (args, cwd2) => spawnSync17("git", args, { cwd: cwd2, env: env2, encoding: "utf8", timeout: 3e4, windowsHide: true });
92838
+ function prepareSdkProject(spawnSync18, projectDir, remoteDir, env2) {
92839
+ const git5 = (args, cwd2) => spawnSync18("git", args, { cwd: cwd2, env: env2, encoding: "utf8", timeout: 3e4, windowsHide: true });
92504
92840
  (0, import_fs93.mkdirSync)(projectDir, { recursive: true });
92505
92841
  (0, import_fs93.writeFileSync)((0, import_path116.join)(projectDir, "hello.txt"), "omg smoke fixture\n");
92506
92842
  const steps = [
@@ -92517,8 +92853,72 @@ function prepareSdkProject(spawnSync17, projectDir, remoteDir, env2) {
92517
92853
  }
92518
92854
  return null;
92519
92855
  }
92520
- function remoteRefs(spawnSync17, remoteDir, env2) {
92521
- const res = spawnSync17("git", ["--git-dir", remoteDir, "for-each-ref"], { env: env2, encoding: "utf8", timeout: 3e4, windowsHide: true });
92856
+ function prepareFiletools(projectDir, home, node = process.execPath) {
92857
+ const nonce = `omg-dirctx-${(0, import_crypto33.randomBytes)(6).toString("hex")}`;
92858
+ const writeNonce = `omg-dirctx-${(0, import_crypto33.randomBytes)(6).toString("hex")}`;
92859
+ (0, import_fs93.mkdirSync)((0, import_path116.join)(projectDir, (0, import_path116.dirname)(FILETOOLS_FILES.writeContext)), { recursive: true });
92860
+ (0, import_fs93.writeFileSync)((0, import_path116.join)(projectDir, FILETOOLS_FILES.notes), "status: draft\n");
92861
+ (0, import_fs93.writeFileSync)((0, import_path116.join)(projectDir, FILETOOLS_FILES.context), `# Filetools fixture
92862
+
92863
+ ${FILETOOLS_MARKER} ${nonce}
92864
+ `);
92865
+ (0, import_fs93.writeFileSync)((0, import_path116.join)(projectDir, FILETOOLS_FILES.writeContext), `# Filetools new files
92866
+
92867
+ ${FILETOOLS_MARKER} ${writeNonce}
92868
+ `);
92869
+ const probeDir = (0, import_path116.join)(home, "filetools-probe");
92870
+ const probeLog = (0, import_path116.join)(home, "filetools-probe.jsonl");
92871
+ const script = (0, import_path116.join)(probeDir, "probe.cjs");
92872
+ (0, import_fs93.mkdirSync)(probeDir, { recursive: true });
92873
+ (0, import_fs93.writeFileSync)((0, import_path116.join)(probeDir, "plugin.json"), `${JSON.stringify({ name: "omg-smoke-probe", version: "0.0.0", description: "omg smoke filetools hook probe", hooks: "./hooks.json" }, null, 2)}
92874
+ `);
92875
+ (0, import_fs93.writeFileSync)((0, import_path116.join)(probeDir, "hooks.json"), `${JSON.stringify(probeHooksJson(node, script, probeLog), null, 2)}
92876
+ `);
92877
+ (0, import_fs93.writeFileSync)(script, [
92878
+ "'use strict';",
92879
+ "const fs = require('fs');",
92880
+ "const [label, log] = process.argv.slice(2);",
92881
+ "const chunks = [];",
92882
+ "process.stdin.on('data', (c) => chunks.push(c));",
92883
+ "process.stdin.on('end', () => {",
92884
+ " const raw = Buffer.concat(chunks).toString('utf8');",
92885
+ " let payload = null;",
92886
+ " try { payload = JSON.parse(raw); } catch { /* recorded as null */ }",
92887
+ " fs.appendFileSync(log, JSON.stringify({ label, payload }) + '\\n');",
92888
+ "});",
92889
+ ""
92890
+ ].join("\n"));
92891
+ return { nonce, writeNonce, probeDir, probeLog };
92892
+ }
92893
+ function collectFiletools(projectDir, probe) {
92894
+ let records2 = [];
92895
+ try {
92896
+ records2 = (0, import_fs93.readFileSync)(probe.probeLog, "utf-8").split(/\r?\n/).filter(Boolean).flatMap((line) => {
92897
+ try {
92898
+ return [JSON.parse(line)];
92899
+ } catch {
92900
+ return [];
92901
+ }
92902
+ });
92903
+ } catch {
92904
+ }
92905
+ const read = (rel) => {
92906
+ try {
92907
+ return (0, import_fs93.readFileSync)((0, import_path116.join)(projectDir, rel), "utf-8");
92908
+ } catch {
92909
+ return null;
92910
+ }
92911
+ };
92912
+ return {
92913
+ nonce: probe.nonce,
92914
+ writeNonce: probe.writeNonce,
92915
+ probe: records2,
92916
+ edited: /^status: done\s*$/m.test(read(FILETOOLS_FILES.notes) ?? ""),
92917
+ created: read(FILETOOLS_FILES.created) !== null
92918
+ };
92919
+ }
92920
+ function remoteRefs(spawnSync18, remoteDir, env2) {
92921
+ const res = spawnSync18("git", ["--git-dir", remoteDir, "for-each-ref"], { env: env2, encoding: "utf8", timeout: 3e4, windowsHide: true });
92522
92922
  return res.status === 0 ? String(res.stdout ?? "") : null;
92523
92923
  }
92524
92924
  function runtimeCreditCap(maxCredits) {
@@ -92765,7 +93165,9 @@ async function runScenario(client, input, name, model, modelLabel, eventsPath, b
92765
93165
  let wedged = false;
92766
93166
  let spent = 0;
92767
93167
  let error2;
93168
+ let probe;
92768
93169
  try {
93170
+ if (name === "filetools") probe = prepareFiletools(input.projectDir, input.home);
92769
93171
  session = await withTimeout(client.createSession({
92770
93172
  onPermissionRequest: (req) => spec.permit(req, permitCtx) ? { kind: "approve-once" } : reject(`omg smoke ${name}: ${req.kind ?? "request"} not permitted`),
92771
93173
  onEvent: (event) => {
@@ -92778,7 +93180,7 @@ async function runScenario(client, input, name, model, modelLabel, eventsPath, b
92778
93180
  onCap();
92779
93181
  }
92780
93182
  },
92781
- pluginDirectories: [input.root],
93183
+ pluginDirectories: probe ? [input.root, probe.probeDir] : [input.root],
92782
93184
  workingDirectory: input.projectDir,
92783
93185
  disabledMcpServers: ["github-mcp-server"],
92784
93186
  excludedTools: scenarioExcludedTools(name, input.mcpServer),
@@ -92832,6 +93234,7 @@ async function runScenario(client, input, name, model, modelLabel, eventsPath, b
92832
93234
  timeoutMs: input.timeoutMs,
92833
93235
  ...error2 ? { error: error2 } : {},
92834
93236
  ...name === "guardrail" ? { remoteRefs: remoteRefs(input.spawnSync, input.remoteDir, input.env) } : {},
93237
+ ...probe ? { filetools: collectFiletools(input.projectDir, probe) } : {},
92835
93238
  model: modelLabel,
92836
93239
  maxCredits: input.maxCredits,
92837
93240
  budget,
@@ -92839,11 +93242,12 @@ async function runScenario(client, input, name, model, modelLabel, eventsPath, b
92839
93242
  wedged
92840
93243
  };
92841
93244
  }
92842
- var import_child_process28, import_fs93, import_module3, import_path116, import_url14, SDK_MIN_VERSION, DEFAULT_SCENARIO_TIMEOUT_MS, START_TIMEOUT_MS, RPC_TIMEOUT_MS, MCP_CONNECT_WAIT_MS, ABORT_GRACE_MS, SHUTDOWN_GRACE_MS, STOP_TIMEOUT_MS, TimeoutError, sleep6, reject, RUNTIME_WEDGED_DETAIL;
93245
+ var import_child_process28, import_crypto33, import_fs93, import_module3, import_path116, import_url14, SDK_MIN_VERSION, DEFAULT_SCENARIO_TIMEOUT_MS, START_TIMEOUT_MS, RPC_TIMEOUT_MS, MCP_CONNECT_WAIT_MS, ABORT_GRACE_MS, SHUTDOWN_GRACE_MS, STOP_TIMEOUT_MS, TimeoutError, sleep6, reject, RUNTIME_WEDGED_DETAIL;
92843
93246
  var init_copilot_sdk_driver = __esm({
92844
93247
  "src/smoke/copilot-sdk-driver.ts"() {
92845
93248
  "use strict";
92846
93249
  import_child_process28 = require("child_process");
93250
+ import_crypto33 = require("crypto");
92847
93251
  import_fs93 = require("fs");
92848
93252
  import_module3 = require("module");
92849
93253
  import_path116 = require("path");
@@ -96808,7 +97212,7 @@ async function processCliWorkerVerdictsUnderLock(teamName, cwd2, expectedInstanc
96808
97212
  ).catch(logCursorTransitionMarkerFailure);
96809
97213
  };
96810
97214
  const { rename: rename8 } = await import("fs/promises");
96811
- const { renameSync: renameSync19, readFileSync: readFileSync141, existsSync: fsExistsSync } = await import("fs");
97215
+ const { renameSync: renameSync20, readFileSync: readFileSync143, existsSync: fsExistsSync } = await import("fs");
96812
97216
  const { withFileLockSync: withFileLockSync2 } = await Promise.resolve().then(() => (init_file_lock(), file_lock_exports));
96813
97217
  const quarantineNonCursorVerdict = async (outputFile, artifactFingerprint, workerName, taskId, taskVersion, reason) => {
96814
97218
  const stalePath = nonCursorVerdictStalePath(outputFile, artifactFingerprint);
@@ -96881,7 +97285,7 @@ async function processCliWorkerVerdictsUnderLock(teamName, cwd2, expectedInstanc
96881
97285
  if (fsExistsSync(outputFile)) {
96882
97286
  const stalePath = `${processingOutputFile}.stale`;
96883
97287
  try {
96884
- renameSync19(processingOutputFile, stalePath);
97288
+ renameSync20(processingOutputFile, stalePath);
96885
97289
  } catch {
96886
97290
  }
96887
97291
  } else {
@@ -96889,9 +97293,9 @@ async function processCliWorkerVerdictsUnderLock(teamName, cwd2, expectedInstanc
96889
97293
  return;
96890
97294
  }
96891
97295
  }
96892
- const raw = readFileSync141(outputFile, "utf-8");
97296
+ const raw = readFileSync143(outputFile, "utf-8");
96893
97297
  parseCliWorkerVerdict(raw);
96894
- renameSync19(outputFile, processingOutputFile);
97298
+ renameSync20(outputFile, processingOutputFile);
96895
97299
  verdictFile = processingOutputFile;
96896
97300
  });
96897
97301
  }
@@ -98763,7 +99167,7 @@ function readOperationFileNoFollow(operations, name) {
98763
99167
  }
98764
99168
  function writeOperationFileAtomically(operations, name, contents) {
98765
99169
  assertSafeContainedFileName(name);
98766
- const temporary = `${name}.tmp.${(0, import_crypto33.randomBytes)(6).toString("hex")}`;
99170
+ const temporary = `${name}.tmp.${(0, import_crypto34.randomBytes)(6).toString("hex")}`;
98767
99171
  const fd = operations.open(
98768
99172
  temporary,
98769
99173
  import_fs97.constants.O_WRONLY | import_fs97.constants.O_CREAT | import_fs97.constants.O_EXCL | (import_fs97.constants.O_NONBLOCK ?? 0),
@@ -98863,11 +99267,11 @@ function guardedOperations(fd, checkActive) {
98863
99267
  }
98864
99268
  };
98865
99269
  }
98866
- var import_crypto33, import_fs97, import_path121, NO_FOLLOW, UNSAFE_CONTROL, WINDOWS_DEVICE_NAME;
99270
+ var import_crypto34, import_fs97, import_path121, NO_FOLLOW, UNSAFE_CONTROL, WINDOWS_DEVICE_NAME;
98867
99271
  var init_safe_fs = __esm({
98868
99272
  "src/graph/runtime/safe-fs.ts"() {
98869
99273
  "use strict";
98870
- import_crypto33 = require("crypto");
99274
+ import_crypto34 = require("crypto");
98871
99275
  import_fs97 = require("fs");
98872
99276
  import_path121 = require("path");
98873
99277
  init_contained_fd();
@@ -99759,7 +100163,7 @@ function startReplyListener(_config) {
99759
100163
  child.unref();
99760
100164
  const pid = child.pid;
99761
100165
  if (pid) {
99762
- const generation = (0, import_crypto34.randomUUID)();
100166
+ const generation = (0, import_crypto35.randomUUID)();
99763
100167
  writePidFile({ pid, generation });
99764
100168
  const state = {
99765
100169
  isRunning: true,
@@ -99932,7 +100336,7 @@ function processSlackSocketMessage(rawMessage, connectionState, paneId, config2,
99932
100336
  }
99933
100337
  return { injected: success, validation };
99934
100338
  }
99935
- var import_fs99, import_path123, import_url16, import_child_process29, import_crypto34, import_https2, __filename2, SECURE_FILE_MODE2, MAX_LOG_SIZE_BYTES, DAEMON_ENV_ALLOWLIST, DEFAULT_STATE_DIR, PID_FILE_PATH, STATE_FILE_PATH, LOG_FILE_PATH, APPROVAL_APPROVE_WORDS, APPROVAL_DENY_WORDS, RateLimiter, discordBackoffUntil, PRUNE_INTERVAL_MS;
100339
+ var import_fs99, import_path123, import_url16, import_child_process29, import_crypto35, import_https2, __filename2, SECURE_FILE_MODE2, MAX_LOG_SIZE_BYTES, DAEMON_ENV_ALLOWLIST, DEFAULT_STATE_DIR, PID_FILE_PATH, STATE_FILE_PATH, LOG_FILE_PATH, APPROVAL_APPROVE_WORDS, APPROVAL_DENY_WORDS, RateLimiter, discordBackoffUntil, PRUNE_INTERVAL_MS;
99936
100340
  var init_reply_listener = __esm({
99937
100341
  "src/notifications/reply-listener.ts"() {
99938
100342
  "use strict";
@@ -99940,7 +100344,7 @@ var init_reply_listener = __esm({
99940
100344
  import_path123 = require("path");
99941
100345
  import_url16 = require("url");
99942
100346
  import_child_process29 = require("child_process");
99943
- import_crypto34 = require("crypto");
100347
+ import_crypto35 = require("crypto");
99944
100348
  init_tmux_utils();
99945
100349
  import_https2 = require("https");
99946
100350
  init_daemon_module_path();
@@ -100846,7 +101250,7 @@ function reschedulePendingWorker(payload, job) {
100846
101250
  }
100847
101251
  async function processSessionEndWorker(payload) {
100848
101252
  const deadlineAt = Date.now() + MAX_WORKER_MS;
100849
- const nonce = (0, import_crypto35.randomUUID)();
101253
+ const nonce = (0, import_crypto36.randomUUID)();
100850
101254
  const identity = await getProcessStartIdentity(process.pid, Math.min(deadlineAt, Date.now() + 2500));
100851
101255
  if (!identity) return;
100852
101256
  let claimed = claimSessionEndJob(payload.directory, payload.sessionId, nonce, identity, deadlineAt);
@@ -100935,12 +101339,12 @@ function reconcileSessionEndJobs(directory, sessionIds) {
100935
101339
  if (ticket.nonce && !spawned) releaseSessionEndDiscoveryTicket(directory, ticket.sessionId, ticket.nonce, false);
100936
101340
  }
100937
101341
  }
100938
- var import_child_process30, import_crypto35, import_url17, WORKER_ARG, MAX_WORKER_MS, COPILOT_PERMISSION_ENV2, workerIndex;
101342
+ var import_child_process30, import_crypto36, import_url17, WORKER_ARG, MAX_WORKER_MS, COPILOT_PERMISSION_ENV2, workerIndex;
100939
101343
  var init_worker = __esm({
100940
101344
  "src/hooks/session-end/worker.ts"() {
100941
101345
  "use strict";
100942
101346
  import_child_process30 = require("child_process");
100943
- import_crypto35 = require("crypto");
101347
+ import_crypto36 = require("crypto");
100944
101348
  import_url17 = require("url");
100945
101349
  init_cleanup_manifest();
100946
101350
  init_action_runner();
@@ -108561,7 +108965,7 @@ function clearRateLimitBackoff(cache, rateLimitIdentity) {
108561
108965
  return Object.keys(backoffs).length > 0 ? backoffs : void 0;
108562
108966
  }
108563
108967
  function hashCredentialIdentity(identity) {
108564
- return (0, import_crypto39.createHash)("sha256").update(identity).digest("hex");
108968
+ return (0, import_crypto40.createHash)("sha256").update(identity).digest("hex");
108565
108969
  }
108566
108970
  function getOAuthAccountProfileIdentity(credentials) {
108567
108971
  const nestedAccount = credentials.oauthAccount;
@@ -108764,7 +109168,7 @@ function createRateLimitedCacheEntry(source, data, pollIntervalMs, previousCount
108764
109168
  function getKeychainServiceName() {
108765
109169
  const configDir = process.env.COPILOT_HOME;
108766
109170
  if (configDir) {
108767
- const hash = (0, import_crypto39.createHash)("sha256").update(configDir).digest("hex").slice(0, 8);
109171
+ const hash = (0, import_crypto40.createHash)("sha256").update(configDir).digest("hex").slice(0, 8);
108768
109172
  return `Claude Code-credentials-${hash}`;
108769
109173
  }
108770
109174
  return "Claude Code-credentials";
@@ -109956,7 +110360,7 @@ async function getUsage(opts) {
109956
110360
  return { rateLimits: null, error: "network" };
109957
110361
  }
109958
110362
  }
109959
- var import_fs130, import_path156, import_child_process38, import_crypto39, import_os25, import_https3, CACHE_TTL_FAILURE_MS, CACHE_TTL_TRANSIENT_NETWORK_MS, MAX_RATE_LIMITED_BACKOFF_MS, API_TIMEOUT_MS2, MAX_STALE_DATA_MS, TOKEN_REFRESH_URL_HOSTNAME, USAGE_CACHE_LOCK_OPTS, TOKEN_REFRESH_URL_PATH, OMC_USAGE_PROFILE_ID_FIELD, OMC_USAGE_PROFILE_TOKEN_HASH_FIELD, DEFAULT_OAUTH_CLIENT_ID, storedCredentialCache, storedCredentialLookupGeneration, ZAI_UNIT_WEEK, KIMI_USAGE_HOSTNAMES, KIMI_USAGE_PATH, RATE_LIMIT_PROBE_MODEL, KIMI_FIVE_HOUR_WINDOW_MINUTES;
110363
+ var import_fs130, import_path156, import_child_process38, import_crypto40, import_os25, import_https3, CACHE_TTL_FAILURE_MS, CACHE_TTL_TRANSIENT_NETWORK_MS, MAX_RATE_LIMITED_BACKOFF_MS, API_TIMEOUT_MS2, MAX_STALE_DATA_MS, TOKEN_REFRESH_URL_HOSTNAME, USAGE_CACHE_LOCK_OPTS, TOKEN_REFRESH_URL_PATH, OMC_USAGE_PROFILE_ID_FIELD, OMC_USAGE_PROFILE_TOKEN_HASH_FIELD, DEFAULT_OAUTH_CLIENT_ID, storedCredentialCache, storedCredentialLookupGeneration, ZAI_UNIT_WEEK, KIMI_USAGE_HOSTNAMES, KIMI_USAGE_PATH, RATE_LIMIT_PROBE_MODEL, KIMI_FIVE_HOUR_WINDOW_MINUTES;
109960
110364
  var init_usage_api = __esm({
109961
110365
  "src/hud/usage-api.ts"() {
109962
110366
  "use strict";
@@ -109964,7 +110368,7 @@ var init_usage_api = __esm({
109964
110368
  init_config_dir();
109965
110369
  import_path156 = require("path");
109966
110370
  import_child_process38 = require("child_process");
109967
- import_crypto39 = require("crypto");
110371
+ import_crypto40 = require("crypto");
109968
110372
  import_os25 = require("os");
109969
110373
  import_https3 = __toESM(require("https"), 1);
109970
110374
  init_ssrf_guard();
@@ -110554,12 +110958,12 @@ function readTailTotals(path30, size) {
110554
110958
  scanLines(text, scan);
110555
110959
  return scan.totals ? { ...scan.totals, ...scan.model ? { model: scan.model } : {} } : null;
110556
110960
  }
110557
- function toRecord(scan, partial2, now2, tail2 = null) {
110558
- const model = tail2?.model ?? scan.model;
110961
+ function toRecord(scan, partial2, now2, tail3 = null) {
110962
+ const model = tail3?.model ?? scan.model;
110559
110963
  const base = { updatedAt: now2.toISOString(), ...model ? { model } : {}, scan };
110560
- const totals = tail2 ?? scan.totals;
110964
+ const totals = tail3 ?? scan.totals;
110561
110965
  if (totals) {
110562
- return { ...base, premiumRequests: totals.premium, credits: totals.nano / NANO2, source: "measured", detail: `${totals.type}${tail2 ? " (events tail)" : ""}` };
110966
+ return { ...base, premiumRequests: totals.premium, credits: totals.nano / NANO2, source: "measured", detail: `${totals.type}${tail3 ? " (events tail)" : ""}` };
110563
110967
  }
110564
110968
  if (scan.prompts === 0 && !partial2) return null;
110565
110969
  return {
@@ -110593,8 +110997,8 @@ function readCopilotSessionUsage(eventsPath, now2 = /* @__PURE__ */ new Date(),
110593
110997
  scan.offset = end;
110594
110998
  }
110595
110999
  const partial2 = end < size;
110596
- const tail2 = partial2 ? readTailTotals(eventsPath, size) : null;
110597
- return toRecord(scan, partial2, now2, tail2);
111000
+ const tail3 = partial2 ? readTailTotals(eventsPath, size) : null;
111001
+ return toRecord(scan, partial2, now2, tail3);
110598
111002
  }
110599
111003
  var import_node_fs21, import_node_os6, import_node_path28, NANO2, MAX_SCAN_BYTES, TAIL_BYTES, HOOK_LOCK_TIMEOUT_MS, SAFE_KEY, isObject3, EPOCH, baselineKey;
110600
111004
  var init_ledger = __esm({
@@ -110817,8 +111221,8 @@ function refreshEstimates(path30, now2, lock = {}, deadlineMs = REFRESH_DEADLINE
110817
111221
  const mtimeMs = Math.floor(stat2.mtimeMs);
110818
111222
  if (scan.checkedSize === stat2.size && scan.checkedMtimeMs === mtimeMs) continue;
110819
111223
  const checked = { ...scan, checkedSize: stat2.size, checkedMtimeMs: mtimeMs };
110820
- const tail2 = readTailTotals(events, stat2.size);
110821
- const usage = tail2 ? { premiumRequests: tail2.premium, credits: tail2.nano / 1e9, source: "measured", detail: `${tail2.type} (events tail)`, ...tail2.model ? { model: tail2.model } : {}, updatedAt: now2.toISOString(), scan: checked } : { ...record2, scan: checked };
111224
+ const tail3 = readTailTotals(events, stat2.size);
111225
+ const usage = tail3 ? { premiumRequests: tail3.premium, credits: tail3.nano / 1e9, source: "measured", detail: `${tail3.type} (events tail)`, ...tail3.model ? { model: tail3.model } : {}, updatedAt: now2.toISOString(), scan: checked } : { ...record2, scan: checked };
110822
111226
  updates.push({ key, team, usage });
110823
111227
  }
110824
111228
  const cursor = (start + visited) % stale.length;
@@ -111056,9 +111460,9 @@ var init_watchdog = __esm({
111056
111460
  function verifySignature(secret, rawBody, signatureHeader) {
111057
111461
  if (!signatureHeader?.startsWith("sha256=")) return false;
111058
111462
  const provided = signatureHeader.slice("sha256=".length);
111059
- const expected = (0, import_crypto41.createHmac)("sha256", secret).update(rawBody, "utf8").digest("hex");
111463
+ const expected = (0, import_crypto42.createHmac)("sha256", secret).update(rawBody, "utf8").digest("hex");
111060
111464
  if (provided.length !== expected.length) return false;
111061
- return (0, import_crypto41.timingSafeEqual)(Buffer.from(provided, "utf8"), Buffer.from(expected, "utf8"));
111465
+ return (0, import_crypto42.timingSafeEqual)(Buffer.from(provided, "utf8"), Buffer.from(expected, "utf8"));
111062
111466
  }
111063
111467
  function routeTrackerEvent(event, whitelist, table = INTAKE_ROUTE_TABLE) {
111064
111468
  const repo = event.repository?.full_name;
@@ -111132,7 +111536,7 @@ function spawnChainLink(req) {
111132
111536
  req.audit({ kind: "discarded", reason: `guardrail: ${slot.reason}`, detail: slot.detail, intentId: req.intentId });
111133
111537
  return { status: 204, kind: "discarded", detail: `guardrail ${slot.reason}: ${slot.detail}` };
111134
111538
  }
111135
- const nextSessionId = (0, import_crypto41.randomUUID)();
111539
+ const nextSessionId = (0, import_crypto42.randomUUID)();
111136
111540
  const includeUserSettings = process.env[AFK_INCLUDE_USER_SETTINGS_ENV] === "1";
111137
111541
  const args = factoryLinkArgv(req.prompt, nextSessionId, [], [], includeUserSettings, req.config.cwd);
111138
111542
  const command = factoryLinkCommand();
@@ -111220,9 +111624,9 @@ function startListener(config2, deps = {}) {
111220
111624
  }
111221
111625
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
111222
111626
  const host = config2.host || "127.0.0.1";
111223
- let tail2 = Promise.resolve();
111627
+ let tail3 = Promise.resolve();
111224
111628
  const server = (0, import_http.createServer)((req, res) => {
111225
- tail2 = tail2.then(() => handleRequest(req, res, config2, deps, startedAt)).catch(() => {
111629
+ tail3 = tail3.then(() => handleRequest(req, res, config2, deps, startedAt)).catch(() => {
111226
111630
  try {
111227
111631
  res.writeHead(500).end();
111228
111632
  } catch {
@@ -111291,11 +111695,11 @@ async function handleRequest(req, res, config2, deps, startedAt) {
111291
111695
  function hasCheckSuite(event) {
111292
111696
  return event.check_suite !== void 0;
111293
111697
  }
111294
- var import_crypto41, import_http, import_fs137, import_path165, INTAKE_LABEL, INTAKE_ROUTE_TABLE, CI_ROUTE_TABLE, HEAD_BRANCH_PATTERN, ISSUE_URL_PATTERN, MAX_BODY_BYTES;
111698
+ var import_crypto42, import_http, import_fs137, import_path165, INTAKE_LABEL, INTAKE_ROUTE_TABLE, CI_ROUTE_TABLE, HEAD_BRANCH_PATTERN, ISSUE_URL_PATTERN, MAX_BODY_BYTES;
111295
111699
  var init_listener = __esm({
111296
111700
  "src/factory/listener.ts"() {
111297
111701
  "use strict";
111298
- import_crypto41 = require("crypto");
111702
+ import_crypto42 = require("crypto");
111299
111703
  import_http = require("http");
111300
111704
  import_fs137 = require("fs");
111301
111705
  import_path165 = require("path");
@@ -111690,7 +112094,7 @@ async function runChainScenario(input) {
111690
112094
  };
111691
112095
  const prepError = prepareChainProject(input.projectDir);
111692
112096
  if (prepError) return { ...base, events: [], idle: false, timedOut: false, error: `chain setup: ${prepError}` };
111693
- const firstLink = (input.randomUUID ?? import_crypto42.randomUUID)();
112097
+ const firstLink = (input.randomUUID ?? import_crypto43.randomUUID)();
111694
112098
  writeChainLinkLedger(factoryStateDir2(input.projectDir), firstLink, "copilot", {
111695
112099
  intentId: CHAIN_INTENT_ID,
111696
112100
  stage: CHAIN_LINK1_STAGE,
@@ -111734,11 +112138,11 @@ async function runChainScenario(input) {
111734
112138
  chain
111735
112139
  };
111736
112140
  }
111737
- var import_crypto42, import_child_process44, import_fs139, import_path168, CHAIN_ACK_TOKEN, sleep7;
112141
+ var import_crypto43, import_child_process44, import_fs139, import_path168, CHAIN_ACK_TOKEN, sleep7;
111738
112142
  var init_copilot_chain_scenario = __esm({
111739
112143
  "src/smoke/copilot-chain-scenario.ts"() {
111740
112144
  "use strict";
111741
- import_crypto42 = require("crypto");
112145
+ import_crypto43 = require("crypto");
111742
112146
  import_child_process44 = require("child_process");
111743
112147
  import_fs139 = require("fs");
111744
112148
  import_path168 = require("path");
@@ -112625,8 +113029,8 @@ function recordVerdict(state, verdict) {
112625
113029
  }
112626
113030
  const fixRounds = state.fixRounds + 1;
112627
113031
  if (fixRounds > state.maxFixRounds) {
112628
- const blocked = transition({ ...withVerdict, fixRounds }, "blocked", `fix round ${fixRounds} exceeds max ${state.maxFixRounds}`, verdict.at);
112629
- return { ...blocked, blockedReason: `fix-round budget spent (${state.maxFixRounds}); escalate to a human` };
113032
+ const blocked2 = transition({ ...withVerdict, fixRounds }, "blocked", `fix round ${fixRounds} exceeds max ${state.maxFixRounds}`, verdict.at);
113033
+ return { ...blocked2, blockedReason: `fix-round budget spent (${state.maxFixRounds}); escalate to a human` };
112630
113034
  }
112631
113035
  return transition({ ...withVerdict, fixRounds }, "fix", `changes requested by ${verdict.reviewer} (round ${fixRounds}/${state.maxFixRounds})`, verdict.at);
112632
113036
  }
@@ -112637,7 +113041,7 @@ function shipStatePath(repoRoot3, pr) {
112637
113041
  return (0, import_path172.join)(getOmcRoot(repoRoot3), "state", "ship", `${pr}.json`);
112638
113042
  }
112639
113043
  function computeIntegrity(state) {
112640
- return (0, import_crypto43.createHash)("sha256").update(JSON.stringify({ ...state, integrity: void 0 })).digest("hex");
113044
+ return (0, import_crypto44.createHash)("sha256").update(JSON.stringify({ ...state, integrity: void 0 })).digest("hex");
112641
113045
  }
112642
113046
  function sealShipState(state) {
112643
113047
  return { ...state, integrity: computeIntegrity(state) };
@@ -112698,11 +113102,11 @@ function updateShipState(repoRoot3, pr, mutate, options = {}) {
112698
113102
  return next;
112699
113103
  }, { timeoutMs: 5e3 });
112700
113104
  }
112701
- var import_crypto43, import_fs143, import_path172, TRANSITIONS, ShipStateError, PHASES, isStr, isCount;
113105
+ var import_crypto44, import_fs143, import_path172, TRANSITIONS, ShipStateError, PHASES, isStr, isCount;
112702
113106
  var init_state4 = __esm({
112703
113107
  "src/ship/state.ts"() {
112704
113108
  "use strict";
112705
- import_crypto43 = require("crypto");
113109
+ import_crypto44 = require("crypto");
112706
113110
  import_fs143 = require("fs");
112707
113111
  import_path172 = require("path");
112708
113112
  init_atomic_write();
@@ -114170,7 +114574,7 @@ async function runTier1(ctx, bin, opts, cleanup, artifacts) {
114170
114574
  (0, import_fs144.mkdirSync)(home);
114171
114575
  (0, import_fs144.mkdirSync)(projectDir);
114172
114576
  const logDir = (0, import_path173.join)(home, "logs");
114173
- const sessionId = (ctx.deps.randomUUID ?? import_crypto44.randomUUID)();
114577
+ const sessionId = (ctx.deps.randomUUID ?? import_crypto45.randomUUID)();
114174
114578
  const identity = loginIdentity(ctx.deps.userConfigDir ?? getCopilotConfigDir());
114175
114579
  const env2 = buildSessionEnv(ctx.env, home, { session: true, hasLogin: identity.loggedInUsers !== void 0 });
114176
114580
  const config2 = { ...identity, trustedFolders: [projectDir] };
@@ -114412,12 +114816,12 @@ async function runTier2(ctx, bin, binVersion, packageVersion, opts, scenarios, c
114412
114816
  if (logs.path) artifacts.debugLog = logs.path;
114413
114817
  return result;
114414
114818
  }
114415
- var import_child_process47, import_crypto44, import_fs144, import_os28, import_path173, DEFAULT_SMOKE_MODEL, DEFAULT_MAX_CREDITS2, MIN_MAX_CREDITS, DEFAULT_TIER0_TIMEOUT_MS, DEFAULT_TIER1_TIMEOUT_MS, MCP_LIST_TIMEOUT_MS, PLUGIN_NAME3, DELEGATE_AGENT2, DEFAULT_SMOKE_PROMPT, DELEGATE_SMOKE_PROMPT, SMOKE_PERMISSION_FLAGS, TIER0_COPILOT_IDS, LIVE_RUN_REFUSED_DETAIL;
114819
+ var import_child_process47, import_crypto45, import_fs144, import_os28, import_path173, DEFAULT_SMOKE_MODEL, DEFAULT_MAX_CREDITS2, MIN_MAX_CREDITS, DEFAULT_TIER0_TIMEOUT_MS, DEFAULT_TIER1_TIMEOUT_MS, MCP_LIST_TIMEOUT_MS, PLUGIN_NAME3, DELEGATE_AGENT2, DEFAULT_SMOKE_PROMPT, DELEGATE_SMOKE_PROMPT, SMOKE_PERMISSION_FLAGS, TIER0_COPILOT_IDS, LIVE_RUN_REFUSED_DETAIL;
114416
114820
  var init_copilot_smoke = __esm({
114417
114821
  "src/smoke/copilot-smoke.ts"() {
114418
114822
  "use strict";
114419
114823
  import_child_process47 = require("child_process");
114420
- import_crypto44 = require("crypto");
114824
+ import_crypto45 = require("crypto");
114421
114825
  import_fs144 = require("fs");
114422
114826
  import_os28 = require("os");
114423
114827
  import_path173 = require("path");
@@ -114723,7 +115127,7 @@ async function runSdkHost(spec, deps) {
114723
115127
  }).catch(() => false);
114724
115128
  }
114725
115129
  };
114726
- const fail6 = async (outcome2, error2) => {
115130
+ const fail7 = async (outcome2, error2) => {
114727
115131
  session.state = "failed";
114728
115132
  session.last_error = error2;
114729
115133
  mark("closed_at");
@@ -114737,10 +115141,10 @@ async function runSdkHost(spec, deps) {
114737
115141
  mark("ack_at");
114738
115142
  const decision = await waitForDecision(attempt, DECISION_TIMEOUT_MS);
114739
115143
  if (decision !== "accepted") {
114740
- return fail6(decision === "revoked" ? "decision_revoked" : "decision_timeout", `launch decision ${decision}`);
115144
+ return fail7(decision === "revoked" ? "decision_revoked" : "decision_timeout", `launch decision ${decision}`);
114741
115145
  }
114742
115146
  mark("accepted_at");
114743
- if (!startIdentity) return fail6("start_failed", "host process start identity unavailable");
115147
+ if (!startIdentity) return fail7("start_failed", "host process start identity unavailable");
114744
115148
  await writeExclusive(attempt.startedPath, {
114745
115149
  ...identity,
114746
115150
  kind: "worker_launch_provider_started",
@@ -114756,7 +115160,7 @@ async function runSdkHost(spec, deps) {
114756
115160
  } catch {
114757
115161
  loaded2 = null;
114758
115162
  }
114759
- if (!loaded2) return fail6("sdk_missing", "@github/copilot-sdk is not installed (npm i -g @github/copilot-sdk --omit=optional --ignore-scripts)");
115163
+ if (!loaded2) return fail7("sdk_missing", "@github/copilot-sdk is not installed (npm i -g @github/copilot-sdk --omit=optional --ignore-scripts)");
114760
115164
  (0, import_node_fs25.mkdirSync)(files.home, { recursive: true });
114761
115165
  const homeConfig = (0, import_node_path32.join)(files.home, "config.json");
114762
115166
  const ident = loginIdentity(spec.user_config_dir);
@@ -114958,7 +115362,7 @@ async function runSdkHost(spec, deps) {
114958
115362
  } catch {
114959
115363
  }
114960
115364
  removeGuards();
114961
- return fail6("start_failed", errText3(err));
115365
+ return fail7("start_failed", errText3(err));
114962
115366
  }
114963
115367
  const queue = [];
114964
115368
  let offset = 0;
@@ -115086,7 +115490,7 @@ async function runSdkHost(spec, deps) {
115086
115490
  return outcome;
115087
115491
  }
115088
115492
  async function runSdkHostMain(specPath, loadInProcessTools) {
115089
- const { spawnSync: spawnSync17 } = await import("node:child_process");
115493
+ const { spawnSync: spawnSync18 } = await import("node:child_process");
115090
115494
  const { loadCopilotSdk: loadCopilotSdk2 } = await Promise.resolve().then(() => (init_copilot_sdk_driver(), copilot_sdk_driver_exports));
115091
115495
  const { killProcessTree: killProcessTree3 } = await Promise.resolve().then(() => (init_process_utils2(), process_utils_exports2));
115092
115496
  const { getProcessStartIdentitySync: getProcessStartIdentitySync2, isProcessAlive: isProcessAlive3 } = await Promise.resolve().then(() => (init_process_utils(), process_utils_exports));
@@ -115100,11 +115504,11 @@ async function runSdkHostMain(specPath, loadInProcessTools) {
115100
115504
  if (spec?.schema_version !== 1 || !spec.worker_name || !spec.state_root) throw new Error("invalid sdk host spec");
115101
115505
  log3(`start team=${spec.team_name} worker=${spec.worker_name} attempt=${spec.attempt_id}`);
115102
115506
  const outcome = await runSdkHost(spec, {
115103
- loadSdk: () => loadCopilotSdk2(process.env, spawnSync17),
115507
+ loadSdk: () => loadCopilotSdk2(process.env, spawnSync18),
115104
115508
  pid: process.pid,
115105
115509
  startIdentity: (pid) => getProcessStartIdentitySync2(pid),
115106
115510
  isAlive: (pid) => isProcessAlive3(pid),
115107
- killTree: (pid) => killProcessTree3(pid, spawnSync17),
115511
+ killTree: (pid) => killProcessTree3(pid, spawnSync18),
115108
115512
  platform: process.platform,
115109
115513
  pollMs: 250,
115110
115514
  env: process.env,
@@ -117046,7 +117450,7 @@ var init_scheduler = __esm({
117046
117450
  function computeJournalFingerprint(record2) {
117047
117451
  const unsignedRecord = { ...record2 };
117048
117452
  delete unsignedRecord.journal_fingerprint;
117049
- return (0, import_crypto47.createHash)("sha256").update(canonicalJson2(unsignedRecord)).digest("hex");
117453
+ return (0, import_crypto48.createHash)("sha256").update(canonicalJson2(unsignedRecord)).digest("hex");
117050
117454
  }
117051
117455
  function envelopeError(value) {
117052
117456
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
@@ -117070,12 +117474,12 @@ function envelopeError(value) {
117070
117474
  }
117071
117475
  return null;
117072
117476
  }
117073
- var import_fs152, import_crypto47, import_path182, DESCRIPTOR_HASH_PATTERN2, JOURNAL_FINGERPRINT_PATTERN, FileJournal;
117477
+ var import_fs152, import_crypto48, import_path182, DESCRIPTOR_HASH_PATTERN2, JOURNAL_FINGERPRINT_PATTERN, FileJournal;
117074
117478
  var init_journal = __esm({
117075
117479
  "src/graph/runtime/journal.ts"() {
117076
117480
  "use strict";
117077
117481
  import_fs152 = require("fs");
117078
- import_crypto47 = require("crypto");
117482
+ import_crypto48 = require("crypto");
117079
117483
  import_path182 = require("path");
117080
117484
  init_descriptor();
117081
117485
  init_run_dir();
@@ -117268,12 +117672,12 @@ function lstatNoFollow(operations, filePath) {
117268
117672
  }
117269
117673
  return stats;
117270
117674
  }
117271
- var import_fs153, import_crypto48, DEFAULT_STALE_GRACE_MS, LOCK_FILE_NAME, EPOCH_FILE_NAME, FileOwnershipFence;
117675
+ var import_fs153, import_crypto49, DEFAULT_STALE_GRACE_MS, LOCK_FILE_NAME, EPOCH_FILE_NAME, FileOwnershipFence;
117272
117676
  var init_fence = __esm({
117273
117677
  "src/graph/runtime/fence.ts"() {
117274
117678
  "use strict";
117275
117679
  import_fs153 = require("fs");
117276
- import_crypto48 = require("crypto");
117680
+ import_crypto49 = require("crypto");
117277
117681
  init_atomic_write();
117278
117682
  init_platform();
117279
117683
  init_run_dir();
@@ -117364,7 +117768,7 @@ var init_fence = __esm({
117364
117768
  continue;
117365
117769
  }
117366
117770
  this.beforeTakeoverRename?.();
117367
- const tombstone = `${lockPath2}.tomb.${(0, import_crypto48.randomBytes)(6).toString("hex")}`;
117771
+ const tombstone = `${lockPath2}.tomb.${(0, import_crypto49.randomBytes)(6).toString("hex")}`;
117368
117772
  try {
117369
117773
  operations.rename(lockPath2, tombstone);
117370
117774
  } catch {
@@ -117432,7 +117836,7 @@ var init_fence = __esm({
117432
117836
  return false;
117433
117837
  }
117434
117838
  this.beforeReleaseRename?.();
117435
- const tombstone = `${lockPath2}.tomb.${(0, import_crypto48.randomBytes)(6).toString("hex")}`;
117839
+ const tombstone = `${lockPath2}.tomb.${(0, import_crypto49.randomBytes)(6).toString("hex")}`;
117436
117840
  try {
117437
117841
  operations.rename(lockPath2, tombstone);
117438
117842
  } catch (error2) {
@@ -117589,7 +117993,7 @@ var init_fence = __esm({
117589
117993
  /** Remove only a lock inode positively identified as ours after create. */
117590
117994
  cleanupCreatedLock(operations, lockPath2, createdIdentity) {
117591
117995
  if (createdIdentity === null) return;
117592
- const tombstone = `${lockPath2}.tomb.${(0, import_crypto48.randomBytes)(6).toString("hex")}`;
117996
+ const tombstone = `${lockPath2}.tomb.${(0, import_crypto49.randomBytes)(6).toString("hex")}`;
117593
117997
  try {
117594
117998
  operations.rename(lockPath2, tombstone);
117595
117999
  } catch {
@@ -118658,12 +119062,12 @@ async function parseTranscript(transcriptPath, options) {
118658
119062
  lastToolName: null,
118659
119063
  recentTools: []
118660
119064
  };
118661
- if (!transcriptPath || !(0, import_fs156.existsSync)(transcriptPath)) {
119065
+ if (!transcriptPath || !(0, import_fs160.existsSync)(transcriptPath)) {
118662
119066
  return result;
118663
119067
  }
118664
119068
  let cacheKey = null;
118665
119069
  try {
118666
- const stat2 = (0, import_fs156.statSync)(transcriptPath);
119070
+ const stat2 = (0, import_fs160.statSync)(transcriptPath);
118667
119071
  cacheKey = `${transcriptPath}:${stat2.size}:${stat2.mtimeMs}`;
118668
119072
  const cached2 = transcriptCache.get(transcriptPath);
118669
119073
  if (cached2?.cacheKey === cacheKey) {
@@ -118684,7 +119088,7 @@ async function parseTranscript(transcriptPath, options) {
118684
119088
  const observedSessionIds = /* @__PURE__ */ new Set();
118685
119089
  const recentToolMap = /* @__PURE__ */ new Map();
118686
119090
  try {
118687
- const stat2 = (0, import_fs156.statSync)(transcriptPath);
119091
+ const stat2 = (0, import_fs160.statSync)(transcriptPath);
118688
119092
  const fileSize = stat2.size;
118689
119093
  if (fileSize > MAX_TAIL_BYTES) {
118690
119094
  const lines3 = readTailLines(transcriptPath, fileSize, MAX_TAIL_BYTES);
@@ -118708,7 +119112,7 @@ async function parseTranscript(transcriptPath, options) {
118708
119112
  }
118709
119113
  sessionTotalsReliable = sessionTokenTotals.seenUsage;
118710
119114
  } else {
118711
- const fileStream = (0, import_fs156.createReadStream)(transcriptPath);
119115
+ const fileStream = (0, import_fs160.createReadStream)(transcriptPath);
118712
119116
  const rl = (0, import_readline5.createInterface)({
118713
119117
  input: fileStream,
118714
119118
  crlfDelay: Infinity
@@ -118833,12 +119237,12 @@ function finalizeTranscriptResult(result, options, pendingPermissions) {
118833
119237
  function readTailLines(filePath, fileSize, maxBytes) {
118834
119238
  const startOffset = Math.max(0, fileSize - maxBytes);
118835
119239
  const bytesToRead = fileSize - startOffset;
118836
- const fd = (0, import_fs156.openSync)(filePath, "r");
119240
+ const fd = (0, import_fs160.openSync)(filePath, "r");
118837
119241
  const buffer = Buffer.alloc(bytesToRead);
118838
119242
  try {
118839
- (0, import_fs156.readSync)(fd, buffer, 0, bytesToRead, startOffset);
119243
+ (0, import_fs160.readSync)(fd, buffer, 0, bytesToRead, startOffset);
118840
119244
  } finally {
118841
- (0, import_fs156.closeSync)(fd);
119245
+ (0, import_fs160.closeSync)(fd);
118842
119246
  }
118843
119247
  const content = buffer.toString("utf8");
118844
119248
  const lines3 = content.split("\n");
@@ -118882,7 +119286,7 @@ function extractTargetSummary(input, toolName) {
118882
119286
  if (toolName.includes("Edit") || toolName.includes("Write")) {
118883
119287
  const filePath = inp.file_path;
118884
119288
  if (filePath) {
118885
- return (0, import_path187.basename)(filePath) || filePath;
119289
+ return (0, import_path191.basename)(filePath) || filePath;
118886
119290
  }
118887
119291
  }
118888
119292
  if (toolName.includes("Bash")) {
@@ -119149,13 +119553,13 @@ function extractLastRequestTokenUsage(usage) {
119149
119553
  function getNumericUsageValue(value) {
119150
119554
  return typeof value === "number" && Number.isFinite(value) ? value : null;
119151
119555
  }
119152
- var import_fs156, import_readline5, import_path187, MAX_TAIL_BYTES, MAX_AGENT_MAP_SIZE, MAX_RECENT_TOOLS, RECENT_TOOLS_SKIP, PERMISSION_TOOLS, PERMISSION_THRESHOLD_MS, pendingPermissionMap, taskToolStates, TASK_STATUSES, THINKING_PART_TYPES2, THINKING_RECENCY_MS, transcriptCache, TRANSCRIPT_CACHE_MAX_SIZE;
119556
+ var import_fs160, import_readline5, import_path191, MAX_TAIL_BYTES, MAX_AGENT_MAP_SIZE, MAX_RECENT_TOOLS, RECENT_TOOLS_SKIP, PERMISSION_TOOLS, PERMISSION_THRESHOLD_MS, pendingPermissionMap, taskToolStates, TASK_STATUSES, THINKING_PART_TYPES2, THINKING_RECENCY_MS, transcriptCache, TRANSCRIPT_CACHE_MAX_SIZE;
119153
119557
  var init_transcript = __esm({
119154
119558
  "src/hud/transcript.ts"() {
119155
119559
  "use strict";
119156
- import_fs156 = require("fs");
119560
+ import_fs160 = require("fs");
119157
119561
  import_readline5 = require("readline");
119158
- import_path187 = require("path");
119562
+ import_path191 = require("path");
119159
119563
  init_agent_kind();
119160
119564
  MAX_TAIL_BYTES = 4 * 1024 * 1024;
119161
119565
  MAX_AGENT_MAP_SIZE = 100;
@@ -119197,7 +119601,7 @@ var init_transcript = __esm({
119197
119601
  // src/hud/omc-state.ts
119198
119602
  function isStateFileStale(filePath) {
119199
119603
  try {
119200
- const stat2 = (0, import_fs157.statSync)(filePath);
119604
+ const stat2 = (0, import_fs161.statSync)(filePath);
119201
119605
  const age = Date.now() - stat2.mtimeMs;
119202
119606
  return age > MAX_STATE_AGE_MS2;
119203
119607
  } catch {
@@ -119207,21 +119611,21 @@ function isStateFileStale(filePath) {
119207
119611
  function resolveStatePath2(directory, filename, sessionId) {
119208
119612
  const omcRoot = getOmcRoot(directory);
119209
119613
  if (sessionId) {
119210
- const sessionPath = (0, import_path188.join)(omcRoot, "state", "sessions", sessionId, filename);
119211
- return (0, import_fs157.existsSync)(sessionPath) ? sessionPath : null;
119614
+ const sessionPath = (0, import_path192.join)(omcRoot, "state", "sessions", sessionId, filename);
119615
+ return (0, import_fs161.existsSync)(sessionPath) ? sessionPath : null;
119212
119616
  }
119213
119617
  let bestPath = null;
119214
119618
  let bestMtime = 0;
119215
- const sessionsDir = (0, import_path188.join)(omcRoot, "state", "sessions");
119216
- if ((0, import_fs157.existsSync)(sessionsDir)) {
119619
+ const sessionsDir = (0, import_path192.join)(omcRoot, "state", "sessions");
119620
+ if ((0, import_fs161.existsSync)(sessionsDir)) {
119217
119621
  try {
119218
- const entries = (0, import_fs157.readdirSync)(sessionsDir, { withFileTypes: true });
119622
+ const entries = (0, import_fs161.readdirSync)(sessionsDir, { withFileTypes: true });
119219
119623
  for (const entry2 of entries) {
119220
119624
  if (!entry2.isDirectory()) continue;
119221
- const sessionFile = (0, import_path188.join)(sessionsDir, entry2.name, filename);
119222
- if ((0, import_fs157.existsSync)(sessionFile)) {
119625
+ const sessionFile = (0, import_path192.join)(sessionsDir, entry2.name, filename);
119626
+ if ((0, import_fs161.existsSync)(sessionFile)) {
119223
119627
  try {
119224
- const mtime = (0, import_fs157.statSync)(sessionFile).mtimeMs;
119628
+ const mtime = (0, import_fs161.statSync)(sessionFile).mtimeMs;
119225
119629
  if (mtime > bestMtime) {
119226
119630
  bestMtime = mtime;
119227
119631
  bestPath = sessionFile;
@@ -119233,10 +119637,10 @@ function resolveStatePath2(directory, filename, sessionId) {
119233
119637
  } catch {
119234
119638
  }
119235
119639
  }
119236
- const newPath = (0, import_path188.join)(omcRoot, "state", filename);
119237
- if ((0, import_fs157.existsSync)(newPath)) {
119640
+ const newPath = (0, import_path192.join)(omcRoot, "state", filename);
119641
+ if ((0, import_fs161.existsSync)(newPath)) {
119238
119642
  try {
119239
- const mtime = (0, import_fs157.statSync)(newPath).mtimeMs;
119643
+ const mtime = (0, import_fs161.statSync)(newPath).mtimeMs;
119240
119644
  if (mtime > bestMtime) {
119241
119645
  bestMtime = mtime;
119242
119646
  bestPath = newPath;
@@ -119245,10 +119649,10 @@ function resolveStatePath2(directory, filename, sessionId) {
119245
119649
  if (!bestPath) bestPath = newPath;
119246
119650
  }
119247
119651
  }
119248
- const legacyPath = (0, import_path188.join)(omcRoot, filename);
119249
- if ((0, import_fs157.existsSync)(legacyPath)) {
119652
+ const legacyPath = (0, import_path192.join)(omcRoot, filename);
119653
+ if ((0, import_fs161.existsSync)(legacyPath)) {
119250
119654
  try {
119251
- const mtime = (0, import_fs157.statSync)(legacyPath).mtimeMs;
119655
+ const mtime = (0, import_fs161.statSync)(legacyPath).mtimeMs;
119252
119656
  if (mtime > bestMtime) {
119253
119657
  bestPath = legacyPath;
119254
119658
  }
@@ -119267,7 +119671,7 @@ function readRalphStateForHud(directory, sessionId) {
119267
119671
  return null;
119268
119672
  }
119269
119673
  try {
119270
- const content = (0, import_fs157.readFileSync)(stateFile, "utf-8");
119674
+ const content = (0, import_fs161.readFileSync)(stateFile, "utf-8");
119271
119675
  const state = JSON.parse(content);
119272
119676
  if (!state.active) {
119273
119677
  return null;
@@ -119284,15 +119688,15 @@ function readRalphStateForHud(directory, sessionId) {
119284
119688
  }
119285
119689
  }
119286
119690
  function readPrdStateForHud(directory) {
119287
- let prdPath = (0, import_path188.join)(directory, "prd.json");
119288
- if (!(0, import_fs157.existsSync)(prdPath)) {
119289
- prdPath = (0, import_path188.join)(getOmcRoot(directory), "prd.json");
119290
- if (!(0, import_fs157.existsSync)(prdPath)) {
119691
+ let prdPath = (0, import_path192.join)(directory, "prd.json");
119692
+ if (!(0, import_fs161.existsSync)(prdPath)) {
119693
+ prdPath = (0, import_path192.join)(getOmcRoot(directory), "prd.json");
119694
+ if (!(0, import_fs161.existsSync)(prdPath)) {
119291
119695
  return null;
119292
119696
  }
119293
119697
  }
119294
119698
  try {
119295
- const content = (0, import_fs157.readFileSync)(prdPath, "utf-8");
119699
+ const content = (0, import_fs161.readFileSync)(prdPath, "utf-8");
119296
119700
  const prd = JSON.parse(content);
119297
119701
  if (!prd.userStories || !Array.isArray(prd.userStories)) {
119298
119702
  return null;
@@ -119345,7 +119749,7 @@ function readAutopilotStateForHud(directory, sessionId) {
119345
119749
  return null;
119346
119750
  }
119347
119751
  try {
119348
- const content = (0, import_fs157.readFileSync)(stateFile, "utf-8");
119752
+ const content = (0, import_fs161.readFileSync)(stateFile, "utf-8");
119349
119753
  const state = JSON.parse(content);
119350
119754
  if (!state.active) {
119351
119755
  return null;
@@ -119368,12 +119772,12 @@ function readAutopilotStateForHud(directory, sessionId) {
119368
119772
  return null;
119369
119773
  }
119370
119774
  }
119371
- var import_fs157, import_path188, MAX_STATE_AGE_MS2;
119775
+ var import_fs161, import_path192, MAX_STATE_AGE_MS2;
119372
119776
  var init_omc_state = __esm({
119373
119777
  "src/hud/omc-state.ts"() {
119374
119778
  "use strict";
119375
- import_fs157 = require("fs");
119376
- import_path188 = require("path");
119779
+ import_fs161 = require("fs");
119780
+ import_path192 = require("path");
119377
119781
  init_worktree_paths();
119378
119782
  init_named_workflow_resume_validator();
119379
119783
  MAX_STATE_AGE_MS2 = 2 * 60 * 60 * 1e3;
@@ -119382,7 +119786,7 @@ var init_omc_state = __esm({
119382
119786
 
119383
119787
  // src/hud/custom-rate-provider.ts
119384
119788
  function getCachePath2() {
119385
- return (0, import_path189.join)(
119789
+ return (0, import_path193.join)(
119386
119790
  getCopilotConfigDir(),
119387
119791
  "plugins",
119388
119792
  "oh-my-copilot",
@@ -119392,8 +119796,8 @@ function getCachePath2() {
119392
119796
  function readCache2() {
119393
119797
  try {
119394
119798
  const p = getCachePath2();
119395
- if (!(0, import_fs158.existsSync)(p)) return null;
119396
- return JSON.parse((0, import_fs158.readFileSync)(p, "utf-8"));
119799
+ if (!(0, import_fs162.existsSync)(p)) return null;
119800
+ return JSON.parse((0, import_fs162.readFileSync)(p, "utf-8"));
119397
119801
  } catch {
119398
119802
  return null;
119399
119803
  }
@@ -119401,10 +119805,10 @@ function readCache2() {
119401
119805
  function writeCache2(buckets, identity) {
119402
119806
  try {
119403
119807
  const p = getCachePath2();
119404
- const dir = (0, import_path189.dirname)(p);
119405
- if (!(0, import_fs158.existsSync)(dir)) (0, import_fs158.mkdirSync)(dir, { recursive: true });
119808
+ const dir = (0, import_path193.dirname)(p);
119809
+ if (!(0, import_fs162.existsSync)(dir)) (0, import_fs162.mkdirSync)(dir, { recursive: true });
119406
119810
  const cache = { timestamp: Date.now(), buckets, identity };
119407
- (0, import_fs158.writeFileSync)(p, JSON.stringify(cache, null, 2));
119811
+ (0, import_fs162.writeFileSync)(p, JSON.stringify(cache, null, 2));
119408
119812
  } catch {
119409
119813
  }
119410
119814
  }
@@ -119414,7 +119818,7 @@ function isCacheValid2(cache) {
119414
119818
  function spawnWithTimeout(cmd, timeoutMs) {
119415
119819
  return new Promise((resolve58, reject2) => {
119416
119820
  const [executable, ...args] = Array.isArray(cmd) ? cmd : ["sh", "-c", cmd];
119417
- const child = (0, import_child_process54.spawn)(executable, args, {
119821
+ const child = (0, import_child_process55.spawn)(executable, args, {
119418
119822
  stdio: ["ignore", "pipe", "pipe"],
119419
119823
  detached: process.platform !== "win32"
119420
119824
  });
@@ -119522,14 +119926,14 @@ async function executeCustomProvider(config2) {
119522
119926
  return { buckets: [], stale: false, error: "command failed" };
119523
119927
  }
119524
119928
  }
119525
- var import_child_process54, import_node_crypto18, import_fs158, import_path189, CACHE_TTL_MS2, DEFAULT_TIMEOUT_MS4;
119929
+ var import_child_process55, import_node_crypto18, import_fs162, import_path193, CACHE_TTL_MS2, DEFAULT_TIMEOUT_MS4;
119526
119930
  var init_custom_rate_provider = __esm({
119527
119931
  "src/hud/custom-rate-provider.ts"() {
119528
119932
  "use strict";
119529
- import_child_process54 = require("child_process");
119933
+ import_child_process55 = require("child_process");
119530
119934
  import_node_crypto18 = require("node:crypto");
119531
- import_fs158 = require("fs");
119532
- import_path189 = require("path");
119935
+ import_fs162 = require("fs");
119936
+ import_path193 = require("path");
119533
119937
  init_config_dir();
119534
119938
  CACHE_TTL_MS2 = 3e4;
119535
119939
  DEFAULT_TIMEOUT_MS4 = 800;
@@ -120057,7 +120461,7 @@ var init_todos = __esm({
120057
120461
  });
120058
120462
 
120059
120463
  // src/hud/elements/skills.ts
120060
- function truncate2(str4, maxWidth) {
120464
+ function truncate3(str4, maxWidth) {
120061
120465
  return truncateToWidth(str4, maxWidth);
120062
120466
  }
120063
120467
  function getSkillDisplayName(skillName) {
@@ -120079,7 +120483,7 @@ function renderSkills(ultrawork, ralph, lastSkill) {
120079
120483
  parts.push(`${MAGENTA2}ralph${RESET}`);
120080
120484
  }
120081
120485
  if (lastSkill && !isActiveMode(lastSkill.name, ultrawork, ralph)) {
120082
- const argsDisplay = lastSkill.args ? `(${truncate2(lastSkill.args, 15)})` : "";
120486
+ const argsDisplay = lastSkill.args ? `(${truncate3(lastSkill.args, 15)})` : "";
120083
120487
  const displayName = getSkillDisplayName(lastSkill.name);
120084
120488
  parts.push(cyan(`skill:${displayName}${argsDisplay}`));
120085
120489
  }
@@ -120087,7 +120491,7 @@ function renderSkills(ultrawork, ralph, lastSkill) {
120087
120491
  }
120088
120492
  function renderLastSkill(lastSkill) {
120089
120493
  if (!lastSkill) return null;
120090
- const argsDisplay = lastSkill.args ? `(${truncate2(lastSkill.args, 15)})` : "";
120494
+ const argsDisplay = lastSkill.args ? `(${truncate3(lastSkill.args, 15)})` : "";
120091
120495
  const displayName = getSkillDisplayName(lastSkill.name);
120092
120496
  return cyan(`skill:${displayName}${argsDisplay}`);
120093
120497
  }
@@ -121165,8 +121569,8 @@ var init_effort = __esm({
121165
121569
  // src/hud/elements/api-key-source.ts
121166
121570
  function settingsFileHasApiKey(filePath) {
121167
121571
  try {
121168
- if (!(0, import_fs159.existsSync)(filePath)) return false;
121169
- const content = (0, import_fs159.readFileSync)(filePath, "utf-8");
121572
+ if (!(0, import_fs163.existsSync)(filePath)) return false;
121573
+ const content = (0, import_fs163.readFileSync)(filePath, "utf-8");
121170
121574
  const settings = JSON.parse(content);
121171
121575
  const env2 = settings?.env;
121172
121576
  if (typeof env2 !== "object" || env2 === null) return false;
@@ -121177,10 +121581,10 @@ function settingsFileHasApiKey(filePath) {
121177
121581
  }
121178
121582
  function detectApiKeySource(cwd2) {
121179
121583
  if (cwd2) {
121180
- const projectSettings = (0, import_path190.join)(cwd2, ".copilot", "settings.local.json");
121584
+ const projectSettings = (0, import_path194.join)(cwd2, ".copilot", "settings.local.json");
121181
121585
  if (settingsFileHasApiKey(projectSettings)) return "project";
121182
121586
  }
121183
- const globalSettings = (0, import_path190.join)(getCopilotConfigDir(), "settings.json");
121587
+ const globalSettings = (0, import_path194.join)(getCopilotConfigDir(), "settings.json");
121184
121588
  if (settingsFileHasApiKey(globalSettings)) return "global";
121185
121589
  if (process.env.ANTHROPIC_API_KEY) return "env";
121186
121590
  return null;
@@ -121189,12 +121593,12 @@ function renderApiKeySource(source) {
121189
121593
  if (!source) return null;
121190
121594
  return `${dim("key:")}${cyan(source)}`;
121191
121595
  }
121192
- var import_fs159, import_path190;
121596
+ var import_fs163, import_path194;
121193
121597
  var init_api_key_source = __esm({
121194
121598
  "src/hud/elements/api-key-source.ts"() {
121195
121599
  "use strict";
121196
- import_fs159 = require("fs");
121197
- import_path190 = require("path");
121600
+ import_fs163 = require("fs");
121601
+ import_path194 = require("path");
121198
121602
  init_colors();
121199
121603
  init_config_dir();
121200
121604
  }
@@ -121927,7 +122331,7 @@ function findByteBackward(fd, fromExclusive, byte) {
121927
122331
  while (end > 0) {
121928
122332
  const start = Math.max(0, end - SCAN_CHUNK_BYTES);
121929
122333
  const length = end - start;
121930
- (0, import_fs160.readSync)(fd, buffer, 0, length, start);
122334
+ (0, import_fs164.readSync)(fd, buffer, 0, length, start);
121931
122335
  const index = buffer.subarray(0, length).lastIndexOf(byte);
121932
122336
  if (index !== -1) return start + index;
121933
122337
  end = start;
@@ -121939,7 +122343,7 @@ function findByteForward(fd, fromInclusive, size, byte) {
121939
122343
  const buffer = Buffer.allocUnsafe(SCAN_CHUNK_BYTES);
121940
122344
  while (start < size) {
121941
122345
  const length = Math.min(SCAN_CHUNK_BYTES, size - start);
121942
- (0, import_fs160.readSync)(fd, buffer, 0, length, start);
122346
+ (0, import_fs164.readSync)(fd, buffer, 0, length, start);
121943
122347
  const index = buffer.subarray(0, length).indexOf(byte);
121944
122348
  if (index !== -1) return start + index;
121945
122349
  start += length;
@@ -121954,19 +122358,19 @@ function readLineContainingOffset(fd, size, offset) {
121954
122358
  const length = endOffset - startOffset;
121955
122359
  if (length <= 0 || length > MAX_BOUNDARY_LINE_BYTES) return null;
121956
122360
  const line = Buffer.allocUnsafe(length);
121957
- (0, import_fs160.readSync)(fd, line, 0, length, startOffset);
122361
+ (0, import_fs164.readSync)(fd, line, 0, length, startOffset);
121958
122362
  return { line, endOffset };
121959
122363
  }
121960
122364
  function findLastCompactBoundaryEndOffset(transcriptPath, size) {
121961
122365
  if (size <= 0) return null;
121962
- const fd = (0, import_fs160.openSync)(transcriptPath, "r");
122366
+ const fd = (0, import_fs164.openSync)(transcriptPath, "r");
121963
122367
  try {
121964
122368
  let end = size;
121965
122369
  const buffer = Buffer.allocUnsafe(Math.min(SCAN_CHUNK_BYTES, size));
121966
122370
  while (end > 0) {
121967
122371
  const start = Math.max(0, end - SCAN_CHUNK_BYTES);
121968
122372
  const length = end - start;
121969
- (0, import_fs160.readSync)(fd, buffer, 0, length, start);
122373
+ (0, import_fs164.readSync)(fd, buffer, 0, length, start);
121970
122374
  const chunk = buffer.subarray(0, length);
121971
122375
  let index = chunk.lastIndexOf(COMPACT_BOUNDARY_MARKER_BYTES);
121972
122376
  while (index !== -1) {
@@ -121981,13 +122385,13 @@ function findLastCompactBoundaryEndOffset(transcriptPath, size) {
121981
122385
  end = start + COMPACT_BOUNDARY_MARKER_BYTES.length - 1;
121982
122386
  }
121983
122387
  } finally {
121984
- (0, import_fs160.closeSync)(fd);
122388
+ (0, import_fs164.closeSync)(fd);
121985
122389
  }
121986
122390
  return null;
121987
122391
  }
121988
122392
  function countLocalApiRequestRecordBytes(transcriptPath, start, end) {
121989
122393
  if (end <= start) return 0;
121990
- const fd = (0, import_fs160.openSync)(transcriptPath, "r");
122394
+ const fd = (0, import_fs164.openSync)(transcriptPath, "r");
121991
122395
  try {
121992
122396
  const chunk = Buffer.allocUnsafe(SCAN_CHUNK_BYTES);
121993
122397
  const prefix = Buffer.allocUnsafe(LOCAL_API_REQUEST_PREFIX.length);
@@ -121996,7 +122400,7 @@ function countLocalApiRequestRecordBytes(transcriptPath, start, end) {
121996
122400
  const countLine = (lineEndExclusive) => {
121997
122401
  const lineLength = lineEndExclusive - lineStart;
121998
122402
  if (lineLength >= prefix.length) {
121999
- const bytesRead = (0, import_fs160.readSync)(fd, prefix, 0, prefix.length, lineStart);
122403
+ const bytesRead = (0, import_fs164.readSync)(fd, prefix, 0, prefix.length, lineStart);
122000
122404
  if (bytesRead === prefix.length && prefix.equals(LOCAL_API_REQUEST_PREFIX)) {
122001
122405
  excludedBytes += lineLength;
122002
122406
  }
@@ -122006,7 +122410,7 @@ function countLocalApiRequestRecordBytes(transcriptPath, start, end) {
122006
122410
  let position = start;
122007
122411
  while (position < end) {
122008
122412
  const length = Math.min(SCAN_CHUNK_BYTES, end - position);
122009
- (0, import_fs160.readSync)(fd, chunk, 0, length, position);
122413
+ (0, import_fs164.readSync)(fd, chunk, 0, length, position);
122010
122414
  const view = chunk.subarray(0, length);
122011
122415
  let newline = view.indexOf(10);
122012
122416
  while (newline !== -1) {
@@ -122018,7 +122422,7 @@ function countLocalApiRequestRecordBytes(transcriptPath, start, end) {
122018
122422
  if (lineStart < end) countLine(end);
122019
122423
  return excludedBytes;
122020
122424
  } finally {
122021
- (0, import_fs160.closeSync)(fd);
122425
+ (0, import_fs164.closeSync)(fd);
122022
122426
  }
122023
122427
  }
122024
122428
  function estimateTranscriptPayloadBytes(transcriptPath, size) {
@@ -122033,9 +122437,9 @@ function estimateTranscriptPayloadBytes(transcriptPath, size) {
122033
122437
  );
122034
122438
  }
122035
122439
  function estimatePayloadFromTranscriptPath(transcriptPath) {
122036
- if (!transcriptPath || !(0, import_fs160.existsSync)(transcriptPath)) return null;
122440
+ if (!transcriptPath || !(0, import_fs164.existsSync)(transcriptPath)) return null;
122037
122441
  try {
122038
- const stat2 = (0, import_fs160.statSync)(transcriptPath);
122442
+ const stat2 = (0, import_fs164.statSync)(transcriptPath);
122039
122443
  if (!stat2.isFile()) return null;
122040
122444
  return createPayloadEstimate(
122041
122445
  estimateTranscriptPayloadBytes(transcriptPath, stat2.size)
@@ -122044,11 +122448,11 @@ function estimatePayloadFromTranscriptPath(transcriptPath) {
122044
122448
  return null;
122045
122449
  }
122046
122450
  }
122047
- var import_fs160, ANTHROPIC_REQUEST_PAYLOAD_LIMIT_BYTES, PAYLOAD_WARNING_BYTES, PAYLOAD_CRITICAL_BYTES, COMPACT_BOUNDARY_MARKER, COMPACT_BOUNDARY_MARKER_BYTES, LOCAL_API_REQUEST_PREFIX, SCAN_CHUNK_BYTES, MAX_BOUNDARY_LINE_BYTES;
122451
+ var import_fs164, ANTHROPIC_REQUEST_PAYLOAD_LIMIT_BYTES, PAYLOAD_WARNING_BYTES, PAYLOAD_CRITICAL_BYTES, COMPACT_BOUNDARY_MARKER, COMPACT_BOUNDARY_MARKER_BYTES, LOCAL_API_REQUEST_PREFIX, SCAN_CHUNK_BYTES, MAX_BOUNDARY_LINE_BYTES;
122048
122452
  var init_payload_estimate = __esm({
122049
122453
  "src/hud/payload-estimate.ts"() {
122050
122454
  "use strict";
122051
- import_fs160 = require("fs");
122455
+ import_fs164 = require("fs");
122052
122456
  ANTHROPIC_REQUEST_PAYLOAD_LIMIT_BYTES = 32e6;
122053
122457
  PAYLOAD_WARNING_BYTES = 22e6;
122054
122458
  PAYLOAD_CRITICAL_BYTES = 26e6;
@@ -122107,10 +122511,10 @@ function mergeStdinRateLimits(stdinRateLimits, usageResult) {
122107
122511
  };
122108
122512
  }
122109
122513
  function readSessionSummary(stateDir, sessionId) {
122110
- const statePath = (0, import_path191.join)(stateDir, `session-summary-${sessionId}.json`);
122111
- if (!(0, import_fs161.existsSync)(statePath)) return null;
122514
+ const statePath = (0, import_path195.join)(stateDir, `session-summary-${sessionId}.json`);
122515
+ if (!(0, import_fs165.existsSync)(statePath)) return null;
122112
122516
  try {
122113
- return JSON.parse((0, import_fs161.readFileSync)(statePath, "utf-8"));
122517
+ return JSON.parse((0, import_fs165.readFileSync)(statePath, "utf-8"));
122114
122518
  } catch {
122115
122519
  return null;
122116
122520
  }
@@ -122136,22 +122540,22 @@ function spawnSessionSummaryScript(transcriptPath, stateDir, sessionId) {
122136
122540
  return;
122137
122541
  }
122138
122542
  lastSummarySpawnTimestamp = now2;
122139
- const thisDir = (0, import_path191.dirname)((0, import_url23.fileURLToPath)(importMetaUrl));
122140
- const scriptPath = (0, import_path191.join)(
122543
+ const thisDir = (0, import_path195.dirname)((0, import_url24.fileURLToPath)(importMetaUrl));
122544
+ const scriptPath = (0, import_path195.join)(
122141
122545
  thisDir,
122142
122546
  "..",
122143
122547
  "..",
122144
122548
  "scripts",
122145
122549
  "session-summary.mjs"
122146
122550
  );
122147
- if (!(0, import_fs161.existsSync)(scriptPath)) {
122551
+ if (!(0, import_fs165.existsSync)(scriptPath)) {
122148
122552
  if (process.env.OMC_DEBUG) {
122149
122553
  console.error("[HUD] session-summary script not found:", scriptPath);
122150
122554
  }
122151
122555
  return;
122152
122556
  }
122153
122557
  try {
122154
- const child = (0, import_child_process55.spawn)(
122558
+ const child = (0, import_child_process56.spawn)(
122155
122559
  "node",
122156
122560
  [scriptPath, transcriptPath, stateDir, sessionId],
122157
122561
  {
@@ -122183,12 +122587,12 @@ async function calculateSessionHealth(sessionStart, contextPercent) {
122183
122587
  function showDiagnostic() {
122184
122588
  const version3 = getRuntimePackageVersion();
122185
122589
  const configDir = getCopilotConfigDir();
122186
- const hudScript = (0, import_path191.join)(configDir, "hud", HUD_SCRIPT_NAMES[0]);
122187
- const settingsFile = (0, import_path191.join)(configDir, "settings.json");
122188
- const hudExists = HUD_SCRIPT_NAMES.some((name) => (0, import_fs161.existsSync)((0, import_path191.join)(configDir, "hud", name)));
122590
+ const hudScript = (0, import_path195.join)(configDir, "hud", HUD_SCRIPT_NAMES[0]);
122591
+ const settingsFile = (0, import_path195.join)(configDir, "settings.json");
122592
+ const hudExists = HUD_SCRIPT_NAMES.some((name) => (0, import_fs165.existsSync)((0, import_path195.join)(configDir, "hud", name)));
122189
122593
  let statusLineOk = false;
122190
122594
  try {
122191
- const settings = JSON.parse((0, import_fs161.readFileSync)(settingsFile, "utf-8"));
122595
+ const settings = JSON.parse((0, import_fs165.readFileSync)(settingsFile, "utf-8"));
122192
122596
  const sl = settings.statusLine;
122193
122597
  const command = sl && typeof sl === "object" && typeof sl.command === "string" ? sl.command : typeof sl === "string" ? sl : null;
122194
122598
  statusLineOk = command !== null && HUD_COMMAND_MARKERS.some((marker) => command.includes(marker));
@@ -122291,8 +122695,8 @@ async function mainImpl(watchMode = false, skipInit = false) {
122291
122695
  }
122292
122696
  try {
122293
122697
  const updateCacheFile = getUpdateCheckCachePath();
122294
- await (0, import_promises35.access)(updateCacheFile);
122295
- const content = await (0, import_promises35.readFile)(updateCacheFile, "utf-8");
122698
+ await (0, import_promises36.access)(updateCacheFile);
122699
+ const content = await (0, import_promises36.readFile)(updateCacheFile, "utf-8");
122296
122700
  const cached2 = JSON.parse(content);
122297
122701
  if (cached2?.latestVersion && omcVersion && compareVersions2(omcVersion, cached2.latestVersion) < 0) {
122298
122702
  updateAvailable = cached2.latestVersion;
@@ -122314,7 +122718,7 @@ async function mainImpl(watchMode = false, skipInit = false) {
122314
122718
  let sessionSummary = null;
122315
122719
  const sessionSummaryEnabled = config2.elements.sessionSummary ?? false;
122316
122720
  if (sessionSummaryEnabled && resolvedTranscriptPath && currentSessionId) {
122317
- const omcStateDir = (0, import_path191.join)(getOmcRoot(cwd2), "state");
122721
+ const omcStateDir = (0, import_path195.join)(getOmcRoot(cwd2), "state");
122318
122722
  sessionSummary = readSessionSummary(omcStateDir, currentSessionId);
122319
122723
  const shouldSpawn = !sessionSummary?.generatedAt || Date.now() - new Date(sessionSummary.generatedAt).getTime() > 6e4;
122320
122724
  if (shouldSpawn) {
@@ -122372,7 +122776,7 @@ async function mainImpl(watchMode = false, skipInit = false) {
122372
122776
  apiKeyMode: detectApiKeySource(cwd2) !== null,
122373
122777
  subscriptionType: subscriptionInfo.subscriptionType,
122374
122778
  rateLimitTier: subscriptionInfo.rateLimitTier,
122375
- profileName: process.env.COPILOT_HOME ? (0, import_path191.basename)(process.env.COPILOT_HOME).replace(/^\./, "") : null,
122779
+ profileName: process.env.COPILOT_HOME ? (0, import_path195.basename)(process.env.COPILOT_HOME).replace(/^\./, "") : null,
122376
122780
  sessionSummary,
122377
122781
  lastToolName: transcriptData.lastToolName,
122378
122782
  recentTools: transcriptData.recentTools,
@@ -122390,10 +122794,10 @@ async function mainImpl(watchMode = false, skipInit = false) {
122390
122794
  }
122391
122795
  if (config2.contextLimitWarning.autoCompact && context.contextPercent >= config2.contextLimitWarning.threshold) {
122392
122796
  try {
122393
- const omcStateDir = (0, import_path191.join)(getOmcRoot(cwd2), "state");
122394
- (0, import_fs161.mkdirSync)(omcStateDir, { recursive: true });
122395
- const triggerFile = (0, import_path191.join)(omcStateDir, "compact-requested.json");
122396
- (0, import_fs161.writeFileSync)(
122797
+ const omcStateDir = (0, import_path195.join)(getOmcRoot(cwd2), "state");
122798
+ (0, import_fs165.mkdirSync)(omcStateDir, { recursive: true });
122799
+ const triggerFile = (0, import_path195.join)(omcStateDir, "compact-requested.json");
122800
+ (0, import_fs165.writeFileSync)(
122397
122801
  triggerFile,
122398
122802
  JSON.stringify({
122399
122803
  requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -122435,7 +122839,7 @@ async function mainImpl(watchMode = false, skipInit = false) {
122435
122839
  function main2(watchMode = false, skipInit = false) {
122436
122840
  return withWorktreePathRenderScope(() => mainImpl(watchMode, skipInit));
122437
122841
  }
122438
- var import_fs161, import_promises35, import_path191, import_child_process55, import_url23, HUD_SCRIPT_NAMES, HUD_COMMAND_MARKERS, SAME_WINDOW_TOLERANCE_MS, lastSummarySpawnTimestamp, summaryProcessPid;
122842
+ var import_fs165, import_promises36, import_path195, import_child_process56, import_url24, HUD_SCRIPT_NAMES, HUD_COMMAND_MARKERS, SAME_WINDOW_TOLERANCE_MS, lastSummarySpawnTimestamp, summaryProcessPid;
122439
122843
  var init_hud = __esm({
122440
122844
  "src/hud/index.ts"() {
122441
122845
  "use strict";
@@ -122453,11 +122857,11 @@ var init_hud = __esm({
122453
122857
  init_version();
122454
122858
  init_auto_update();
122455
122859
  init_worktree_paths();
122456
- import_fs161 = require("fs");
122457
- import_promises35 = require("fs/promises");
122458
- import_path191 = require("path");
122459
- import_child_process55 = require("child_process");
122460
- import_url23 = require("url");
122860
+ import_fs165 = require("fs");
122861
+ import_promises36 = require("fs/promises");
122862
+ import_path195 = require("path");
122863
+ import_child_process56 = require("child_process");
122864
+ import_url24 = require("url");
122461
122865
  init_worktree_paths();
122462
122866
  init_config_dir();
122463
122867
  HUD_SCRIPT_NAMES = ["omg-hud.mjs", "omcp-hud.mjs", "omcp-hud.js"];
@@ -122478,8 +122882,8 @@ __export(index_exports, {
122478
122882
  module.exports = __toCommonJS(index_exports);
122479
122883
  init_esm();
122480
122884
  init_source();
122481
- var import_path192 = require("path");
122482
- var import_fs162 = require("fs");
122885
+ var import_path196 = require("path");
122886
+ var import_fs166 = require("fs");
122483
122887
  init_config_dir();
122484
122888
  init_env_vars();
122485
122889
  init_loader();
@@ -124296,22 +124700,22 @@ function isEscapedByOddBackslashes(text, index) {
124296
124700
  }
124297
124701
  function findSubstitutionEnd(text, start) {
124298
124702
  let depth = 1;
124299
- let quote2 = null;
124703
+ let quote3 = null;
124300
124704
  let sawCase = false;
124301
124705
  let casePatternPending = false;
124302
124706
  let word = "";
124303
124707
  for (let index = start + 2; index < text.length; index += 1) {
124304
124708
  const character = text[index] ?? "";
124305
- if (quote2 === "'") {
124306
- if (character === "'") quote2 = null;
124709
+ if (quote3 === "'") {
124710
+ if (character === "'") quote3 = null;
124307
124711
  continue;
124308
124712
  }
124309
- if (quote2 === '"') {
124713
+ if (quote3 === '"') {
124310
124714
  if (character === "\\") {
124311
124715
  index += 1;
124312
124716
  continue;
124313
124717
  }
124314
- if (character === '"') quote2 = null;
124718
+ if (character === '"') quote3 = null;
124315
124719
  continue;
124316
124720
  }
124317
124721
  if (character === "\\") {
@@ -124330,7 +124734,7 @@ function findSubstitutionEnd(text, start) {
124330
124734
  continue;
124331
124735
  }
124332
124736
  if (character === "'" || character === '"') {
124333
- quote2 = character;
124737
+ quote3 = character;
124334
124738
  continue;
124335
124739
  }
124336
124740
  if (/[A-Za-z]/.test(character)) {
@@ -124361,25 +124765,25 @@ function findSubstitutionEnd(text, start) {
124361
124765
  function findNestedSubstitutions(clauses) {
124362
124766
  const nested = [];
124363
124767
  for (const clause of clauses) {
124364
- let quote2 = null;
124768
+ let quote3 = null;
124365
124769
  for (let index = 0; index < clause.text.length; index += 1) {
124366
124770
  const character = clause.text[index] ?? "";
124367
- if (quote2 === "'") {
124368
- if (character === "'") quote2 = null;
124771
+ if (quote3 === "'") {
124772
+ if (character === "'") quote3 = null;
124369
124773
  continue;
124370
124774
  }
124371
- if (quote2 === '"') {
124775
+ if (quote3 === '"') {
124372
124776
  if (character === "\\") {
124373
124777
  index += 1;
124374
124778
  continue;
124375
124779
  }
124376
- if (character === '"' && !isEscapedByOddBackslashes(clause.text, index)) quote2 = null;
124780
+ if (character === '"' && !isEscapedByOddBackslashes(clause.text, index)) quote3 = null;
124377
124781
  } else if (character === "'") {
124378
- quote2 = "'";
124782
+ quote3 = "'";
124379
124783
  } else if (character === '"') {
124380
- quote2 = '"';
124784
+ quote3 = '"';
124381
124785
  }
124382
- if (quote2 === "'") continue;
124786
+ if (quote3 === "'") continue;
124383
124787
  if (character === "\\") {
124384
124788
  index += 1;
124385
124789
  continue;
@@ -124394,7 +124798,7 @@ function findNestedSubstitutions(clauses) {
124394
124798
  nested.push({ text: clause.text.slice(index + 2, end), index: clause.index + index + 2 });
124395
124799
  index = end;
124396
124800
  }
124397
- } else if (quote2 === null && (clause.text.startsWith("<(", index) || clause.text.startsWith(">(", index))) {
124801
+ } else if (quote3 === null && (clause.text.startsWith("<(", index) || clause.text.startsWith(">(", index))) {
124398
124802
  const end = findSubstitutionEnd(clause.text, index);
124399
124803
  if (end >= 0) {
124400
124804
  nested.push({ text: clause.text.slice(index + 2, end), index: clause.index + index + 2 });
@@ -124505,22 +124909,22 @@ function tokenizeCommand(segment) {
124505
124909
  while (index < segment.length && /\s/.test(segment[index] ?? "")) index += 1;
124506
124910
  if (index >= segment.length) break;
124507
124911
  const start = index;
124508
- let quote2 = null;
124912
+ let quote3 = null;
124509
124913
  let raw = "";
124510
124914
  while (index < segment.length) {
124511
124915
  const character = segment[index] ?? "";
124512
- if (quote2 !== null) {
124916
+ if (quote3 !== null) {
124513
124917
  raw += character;
124514
- if (quote2 === "'") {
124515
- if (character === "'") quote2 = null;
124918
+ if (quote3 === "'") {
124919
+ if (character === "'") quote3 = null;
124516
124920
  } else if (character === '"' && !isEscapedByOddBackslashes2(segment, index)) {
124517
- quote2 = null;
124921
+ quote3 = null;
124518
124922
  }
124519
124923
  index += 1;
124520
124924
  continue;
124521
124925
  }
124522
124926
  if ((character === '"' || raw.length === 0 || segment.indexOf(character, index + 1) >= 0) && (character === "'" || character === '"')) {
124523
- quote2 = character;
124927
+ quote3 = character;
124524
124928
  raw += character;
124525
124929
  index += 1;
124526
124930
  continue;
@@ -124545,15 +124949,15 @@ function tokenizeCommand(segment) {
124545
124949
  function splitCommandClauses(line) {
124546
124950
  const clauses = [];
124547
124951
  let start = 0;
124548
- let quote2 = null;
124952
+ let quote3 = null;
124549
124953
  let index = 0;
124550
124954
  while (index < line.length) {
124551
124955
  const character = line[index] ?? "";
124552
- if (quote2 !== null) {
124553
- if (quote2 === "'") {
124554
- if (character === "'") quote2 = null;
124956
+ if (quote3 !== null) {
124957
+ if (quote3 === "'") {
124958
+ if (character === "'") quote3 = null;
124555
124959
  } else if (character === '"' && !isEscapedByOddBackslashes2(line, index)) {
124556
- quote2 = null;
124960
+ quote3 = null;
124557
124961
  }
124558
124962
  index += 1;
124559
124963
  continue;
@@ -124563,7 +124967,7 @@ function splitCommandClauses(line) {
124563
124967
  continue;
124564
124968
  }
124565
124969
  if (character === "'" || character === '"') {
124566
- quote2 = character;
124970
+ quote3 = character;
124567
124971
  index += 1;
124568
124972
  continue;
124569
124973
  }
@@ -125309,24 +125713,24 @@ function isExplicitSqlContext(line, end, start) {
125309
125713
  );
125310
125714
  }
125311
125715
  function hasOpenShellQuote(text) {
125312
- let quote2 = null;
125716
+ let quote3 = null;
125313
125717
  for (let index = 0; index < text.length; index += 1) {
125314
125718
  const character = text[index] ?? "";
125315
- if (quote2 === "'") {
125316
- if (character === "'") quote2 = null;
125719
+ if (quote3 === "'") {
125720
+ if (character === "'") quote3 = null;
125317
125721
  continue;
125318
125722
  }
125319
- if (quote2 === '"') {
125723
+ if (quote3 === '"') {
125320
125724
  if (character === "\\") {
125321
125725
  index += 1;
125322
125726
  continue;
125323
125727
  }
125324
- if (character === '"') quote2 = null;
125728
+ if (character === '"') quote3 = null;
125325
125729
  continue;
125326
125730
  }
125327
- if (character === "'" || character === '"') quote2 = character;
125731
+ if (character === "'" || character === '"') quote3 = character;
125328
125732
  }
125329
- return quote2 !== null;
125733
+ return quote3 !== null;
125330
125734
  }
125331
125735
  function hasSqlClientCommandContext(before) {
125332
125736
  const lastNewline = before.lastIndexOf("\n");
@@ -125488,19 +125892,19 @@ function isDocumentationSqlExample(line, index) {
125488
125892
  var HEREDOC_INTERPRETER = /^(?:[\w./@-]+\/)?(?:bash|sh|dash|zsh|ksh|sqlite3|psql|mysql|mariadb|sqlcmd)$/i;
125489
125893
  function findHereDocMarkers(line) {
125490
125894
  const markers = [];
125491
- let quote2 = null;
125895
+ let quote3 = null;
125492
125896
  for (let index = 0; index < line.length; index += 1) {
125493
125897
  const character = line[index] ?? "";
125494
- if (quote2 === "'") {
125495
- if (character === "'") quote2 = null;
125898
+ if (quote3 === "'") {
125899
+ if (character === "'") quote3 = null;
125496
125900
  continue;
125497
125901
  }
125498
- if (quote2 === '"') {
125902
+ if (quote3 === '"') {
125499
125903
  if (character === "\\") {
125500
125904
  index += 1;
125501
125905
  continue;
125502
125906
  }
125503
- if (character === '"') quote2 = null;
125907
+ if (character === '"') quote3 = null;
125504
125908
  continue;
125505
125909
  }
125506
125910
  if (character === "\\") {
@@ -125508,11 +125912,11 @@ function findHereDocMarkers(line) {
125508
125912
  continue;
125509
125913
  }
125510
125914
  if (character === "'") {
125511
- quote2 = "'";
125915
+ quote3 = "'";
125512
125916
  continue;
125513
125917
  }
125514
125918
  if (character === '"') {
125515
- quote2 = '"';
125919
+ quote3 = '"';
125516
125920
  continue;
125517
125921
  }
125518
125922
  if (character === "#" && (index === 0 || /\s/.test(line[index - 1] ?? ""))) return [];
@@ -127405,8 +127809,8 @@ function isConsecutiveCanonicalShareMet(history, threshold = RETIREMENT_POLICY.m
127405
127809
  reason: `insufficient releases: have ${history.length}, need ${requiredConsecutive}`
127406
127810
  };
127407
127811
  }
127408
- const tail2 = history.slice(-requiredConsecutive);
127409
- const evaluated = tail2.map((h) => {
127812
+ const tail3 = history.slice(-requiredConsecutive);
127813
+ const evaluated = tail3.map((h) => {
127410
127814
  const r = isCanonicalShareMet(h.aliasCount, h.canonicalCount, threshold);
127411
127815
  return { share: r.share, met: r.met };
127412
127816
  });
@@ -127568,8 +127972,8 @@ var ENTRYPOINT_RE = /scripts\/([A-Za-z0-9._-]+\.mjs)((?:"|\s)[^"]*)?$/;
127568
127972
  function parseEntrypointCommand(command) {
127569
127973
  const m = ENTRYPOINT_RE.exec(command);
127570
127974
  if (!m) return null;
127571
- const tail2 = (m[2] ?? "").trim();
127572
- const args = tail2.length > 0 ? tail2.split(/\s+/) : [];
127975
+ const tail3 = (m[2] ?? "").trim();
127976
+ const args = tail3.length > 0 ? tail3.split(/\s+/) : [];
127573
127977
  return { entrypoint: m[1], args };
127574
127978
  }
127575
127979
  function riskClassForEntrypoint(entrypoint) {
@@ -130077,6 +130481,9 @@ async function processHookImpl(hookType, rawInput) {
130077
130481
  }
130078
130482
  }
130079
130483
  async function processHook(hookType, rawInput) {
130484
+ if (process.env.DISABLE_OMC === "1" || process.env.DISABLE_OMC === "true") {
130485
+ return { continue: true };
130486
+ }
130080
130487
  const legacyStarted = performance.now();
130081
130488
  const rawRecord = rawInput && typeof rawInput === "object" ? rawInput : {};
130082
130489
  const inputDirectory = typeof rawRecord.cwd === "string" ? rawRecord.cwd : typeof rawRecord.directory === "string" ? rawRecord.directory : void 0;
@@ -130307,7 +130714,7 @@ var import_path131 = require("path");
130307
130714
  init_finder2();
130308
130715
 
130309
130716
  // src/hooks/rules-injector/matcher.ts
130310
- var import_crypto36 = require("crypto");
130717
+ var import_crypto37 = require("crypto");
130311
130718
  var import_path129 = require("path");
130312
130719
 
130313
130720
  // src/hooks/rules-injector/parser.ts
@@ -130548,7 +130955,7 @@ init_config_dir();
130548
130955
  init_atomic_write();
130549
130956
 
130550
130957
  // src/hooks/learner/auto-learner.ts
130551
- var import_crypto37 = require("crypto");
130958
+ var import_crypto38 = require("crypto");
130552
130959
 
130553
130960
  // src/hooks/index.ts
130554
130961
  init_autopilot();
@@ -130561,7 +130968,7 @@ init_pre_compact2();
130561
130968
  // src/hooks/pre-compact/restore.ts
130562
130969
  var import_fs116 = require("fs");
130563
130970
  var import_child_process34 = require("child_process");
130564
- var import_crypto38 = require("crypto");
130971
+ var import_crypto39 = require("crypto");
130565
130972
  var import_path141 = require("path");
130566
130973
  var import_url19 = require("url");
130567
130974
  init_worktree_paths();
@@ -134065,7 +134472,7 @@ async function doctorConflictsCommand(options) {
134065
134472
  }
134066
134473
 
134067
134474
  // src/cli/commands/ralph.ts
134068
- var import_crypto40 = require("crypto");
134475
+ var import_crypto41 = require("crypto");
134069
134476
  var import_child_process43 = require("child_process");
134070
134477
  var import_fs135 = require("fs");
134071
134478
  var import_path162 = require("path");
@@ -134239,8 +134646,8 @@ function enumerateFrontier(mapNumber, records2) {
134239
134646
  if (record2.assignees > 0) continue;
134240
134647
  const parsed = parseBlocked(record2.body);
134241
134648
  const blockers = [...record2.nativeBlockedBy ?? [], ...parsed.blockers];
134242
- const blocked = blockers.some((blocker) => (stateByNumber.get(blocker) ?? "OPEN") !== "CLOSED");
134243
- if (blocked) continue;
134649
+ const blocked2 = blockers.some((blocker) => (stateByNumber.get(blocker) ?? "OPEN") !== "CLOSED");
134650
+ if (blocked2) continue;
134244
134651
  const type = ticketType(record2.labels);
134245
134652
  const ticket = {
134246
134653
  number: record2.number,
@@ -134491,15 +134898,15 @@ function storiesFromPlan(plan, records2) {
134491
134898
  return stories;
134492
134899
  }
134493
134900
  function launchGate(outcomes, records2) {
134494
- const blocked = [];
134901
+ const blocked2 = [];
134495
134902
  for (const outcome of outcomes) {
134496
134903
  if (outcome.action !== "drafted-then-stopped") continue;
134497
134904
  const record2 = records2.find((r) => r.number === outcome.ticket);
134498
134905
  if (criteriaItems(record2?.body ?? "").length === 0) {
134499
- blocked.push({ ticket: outcome.ticket, reason: "drafted criteria not yet accepted (no criteria section on the ticket)" });
134906
+ blocked2.push({ ticket: outcome.ticket, reason: "drafted criteria not yet accepted (no criteria section on the ticket)" });
134500
134907
  }
134501
134908
  }
134502
- return { ok: blocked.length === 0, blocked };
134909
+ return { ok: blocked2.length === 0, blocked: blocked2 };
134503
134910
  }
134504
134911
  function currentBranch2(directory) {
134505
134912
  try {
@@ -134642,7 +135049,7 @@ var RALPH_AFK_FEEDBACK_ENV = "OMC_RALPH_AFK_FEEDBACK";
134642
135049
  function afkFeedbackCommands(verifyCommands) {
134643
135050
  return verifyCommands.filter((command) => command.length <= MAX_VERIFY_COMMAND_LENGTH && VERIFY_COMMAND_PATTERN.test(command)).slice(0, MAX_VERIFY_COMMANDS);
134644
135051
  }
134645
- function ralphAfkArgv(task, verifyCommands = [], sessionId = (0, import_crypto40.randomUUID)()) {
135052
+ function ralphAfkArgv(task, verifyCommands = [], sessionId = (0, import_crypto41.randomUUID)()) {
134646
135053
  const prompt = `/ralph --no-deslop ${task}`;
134647
135054
  const argv = factoryLinkArgv(prompt, sessionId, verifyCommands, RALPH_AFK_READONLY_GIT);
134648
135055
  if (getHostCliType() === "copilot") return [...argv, ...COPILOT_RALPH_AFK_SESSION_FLAGS];
@@ -134699,7 +135106,7 @@ Examples:
134699
135106
  if (materialized?.status === "diverged") {
134700
135107
  console.warn(`warning: ${materialized.path} differs from the bundled ralph skill \u2014 delete it to refresh, or keep it if the divergence is intentional`);
134701
135108
  }
134702
- const sessionId = (0, import_crypto40.randomUUID)();
135109
+ const sessionId = (0, import_crypto41.randomUUID)();
134703
135110
  process.env.OMC_SESSION_ID = sessionId;
134704
135111
  process.env[RALPH_AFK_FEEDBACK_ENV] = JSON.stringify(afkFeedbackCommands(options.verify ?? []));
134705
135112
  const argv = ralphAfkArgv(task, options.verify ?? [], sessionId);
@@ -134782,7 +135189,7 @@ Examples:
134782
135189
  else console.log(renderMapPlan(plan));
134783
135190
  return;
134784
135191
  }
134785
- const sessionId = options.session ?? (0, import_crypto40.randomUUID)();
135192
+ const sessionId = options.session ?? (0, import_crypto41.randomUUID)();
134786
135193
  if (options.launch) {
134787
135194
  try {
134788
135195
  validateSessionId(sessionId);
@@ -135224,7 +135631,7 @@ async function budgetCommand(action, options, cwd2 = process.cwd()) {
135224
135631
  }
135225
135632
 
135226
135633
  // src/cli/commands/capabilities.ts
135227
- var import_crypto45 = require("crypto");
135634
+ var import_crypto46 = require("crypto");
135228
135635
  var import_fs145 = require("fs");
135229
135636
  var import_path175 = require("path");
135230
135637
  init_zod();
@@ -135254,7 +135661,7 @@ function sortJson(value) {
135254
135661
  return value;
135255
135662
  }
135256
135663
  function sha2562(value) {
135257
- return (0, import_crypto45.createHash)("sha256").update(value).digest("hex");
135664
+ return (0, import_crypto46.createHash)("sha256").update(value).digest("hex");
135258
135665
  }
135259
135666
  function resolveLockfilePath(lockfile) {
135260
135667
  return (0, import_path175.resolve)(process.cwd(), lockfile ?? DEFAULT_CAPABILITIES_LOCKFILE);
@@ -140777,7 +141184,7 @@ async function launchCommand(args) {
140777
141184
 
140778
141185
  // src/cli/interop.ts
140779
141186
  var import_child_process50 = require("child_process");
140780
- var import_crypto46 = require("crypto");
141187
+ var import_crypto47 = require("crypto");
140781
141188
  init_tmux_utils();
140782
141189
  init_host_detection();
140783
141190
  init_model_contract();
@@ -140837,7 +141244,7 @@ function launchInteropSession(cwd2 = process.cwd()) {
140837
141244
  console.error("Start tmux first: tmux new-session -s myproject");
140838
141245
  process.exit(1);
140839
141246
  }
140840
- const sessionId = `interop-${(0, import_crypto46.randomUUID)().split("-")[0]}`;
141247
+ const sessionId = `interop-${(0, import_crypto47.randomUUID)().split("-")[0]}`;
140841
141248
  const _config = initInteropSession(sessionId, cwd2, hasCodex ? cwd2 : void 0);
140842
141249
  console.log(`Initializing interop session: ${sessionId}`);
140843
141250
  console.log(`Working directory: ${cwd2}`);
@@ -141278,7 +141685,7 @@ Goal: ${context.descriptor.goal}`;
141278
141685
  interrupt: true
141279
141686
  };
141280
141687
  };
141281
- const collect = async () => {
141688
+ const collect2 = async () => {
141282
141689
  const returned = queryFn({
141283
141690
  prompt,
141284
141691
  options: {
@@ -141317,7 +141724,7 @@ Goal: ${context.descriptor.goal}`;
141317
141724
  }
141318
141725
  return parts.join("\n");
141319
141726
  };
141320
- const work = collect();
141727
+ const work = collect2();
141321
141728
  try {
141322
141729
  const text = await Promise.race([work, timedOut]);
141323
141730
  if (text.trim().length === 0) {
@@ -142582,45 +142989,45 @@ function runPrepare(opts) {
142582
142989
  const steps = [];
142583
142990
  const housekeepingCommits = [];
142584
142991
  const git5 = (...args) => exec3("git", args, { cwd: cwd2 });
142585
- const fail6 = (name, detail, extra = {}) => {
142992
+ const fail7 = (name, detail, extra = {}) => {
142586
142993
  steps.push({ name, status: "failed", detail });
142587
142994
  return { ok: false, steps, housekeepingCommits, blockedReason: `${name}: ${detail.split("\n")[0]}`, ...extra };
142588
142995
  };
142589
142996
  const head = () => git5("rev-parse", "HEAD").stdout.trim();
142590
142997
  for (const [label, name] of [["base", base], ["branch", opts.branch]]) {
142591
142998
  if (!isPlainBranchName(name) || git5("check-ref-format", "--branch", name).status !== 0) {
142592
- return fail6("preflight", `${label} ${JSON.stringify(name)} is not a valid branch name`);
142999
+ return fail7("preflight", `${label} ${JSON.stringify(name)} is not a valid branch name`);
142593
143000
  }
142594
143001
  }
142595
- if (!/^[\w][\w.-]*$/.test(remote)) return fail6("preflight", `remote ${JSON.stringify(remote)} is not a valid remote name`);
142596
- if (!/^[0-9a-f]{40}$/.test(opts.reviewedSha)) return fail6("preflight", `reviewed sha ${JSON.stringify(opts.reviewedSha)} is not a full commit id`);
142597
- if (!/^[0-9a-f]{40}$/.test(baseSha)) return fail6("preflight", `GitHub's base sha ${JSON.stringify(baseSha)} is not a full commit id`);
143002
+ if (!/^[\w][\w.-]*$/.test(remote)) return fail7("preflight", `remote ${JSON.stringify(remote)} is not a valid remote name`);
143003
+ if (!/^[0-9a-f]{40}$/.test(opts.reviewedSha)) return fail7("preflight", `reviewed sha ${JSON.stringify(opts.reviewedSha)} is not a full commit id`);
143004
+ if (!/^[0-9a-f]{40}$/.test(baseSha)) return fail7("preflight", `GitHub's base sha ${JSON.stringify(baseSha)} is not a full commit id`);
142598
143005
  const branch = git5("rev-parse", "--abbrev-ref", "HEAD").stdout.trim();
142599
- if (!branch || branch === "HEAD") return fail6("preflight", "detached HEAD; check out the PR branch");
142600
- if (branch === base || branch === "main" || branch === "master") return fail6("preflight", `refusing to prepare on ${branch}; use the PR branch`);
142601
- if (branch !== opts.branch) return fail6("preflight", `checked out ${branch}, but the ship run is for ${opts.branch}; check out the PR branch`);
143006
+ if (!branch || branch === "HEAD") return fail7("preflight", "detached HEAD; check out the PR branch");
143007
+ if (branch === base || branch === "main" || branch === "master") return fail7("preflight", `refusing to prepare on ${branch}; use the PR branch`);
143008
+ if (branch !== opts.branch) return fail7("preflight", `checked out ${branch}, but the ship run is for ${opts.branch}; check out the PR branch`);
142602
143009
  if (git5("merge-base", "--is-ancestor", opts.reviewedSha, "HEAD").status !== 0) {
142603
- return fail6("preflight", `HEAD does not contain the reviewed commit ${opts.reviewedSha.slice(0, 12)}; pull the PR branch (merge, never rebase) or re-review`);
143010
+ return fail7("preflight", `HEAD does not contain the reviewed commit ${opts.reviewedSha.slice(0, 12)}; pull the PR branch (merge, never rebase) or re-review`);
142604
143011
  }
142605
143012
  for (const [ref, what] of [["MERGE_HEAD", "a merge"], ["CHERRY_PICK_HEAD", "a cherry-pick"], ["REVERT_HEAD", "a revert"]]) {
142606
- if (git5("rev-parse", "-q", "--verify", ref).status === 0) return fail6("preflight", `${what} is in progress; commit or abort it first`);
143013
+ if (git5("rev-parse", "-q", "--verify", ref).status === 0) return fail7("preflight", `${what} is in progress; commit or abort it first`);
142607
143014
  }
142608
143015
  for (const marker of ["rebase-merge", "rebase-apply"]) {
142609
143016
  const p = git5("rev-parse", "--git-path", marker).stdout.trim();
142610
- if (p && exists((0, import_path186.isAbsolute)(p) ? p : (0, import_path186.join)(cwd2, p))) return fail6("preflight", "a rebase is in progress; finish or abort it (ship never rebases)");
143017
+ if (p && exists((0, import_path186.isAbsolute)(p) ? p : (0, import_path186.join)(cwd2, p))) return fail7("preflight", "a rebase is in progress; finish or abort it (ship never rebases)");
142611
143018
  }
142612
143019
  const dirty = git5("status", "--porcelain", "--untracked-files=no").stdout.trim();
142613
- if (dirty) return fail6("preflight", `working tree has uncommitted changes:
143020
+ if (dirty) return fail7("preflight", `working tree has uncommitted changes:
142614
143021
  ${dirty}`);
142615
- if (git5("diff", "--cached", "--quiet").status !== 0) return fail6("preflight", "the index has staged changes; commit or unstage them first");
143022
+ if (git5("diff", "--cached", "--quiet").status !== 0) return fail7("preflight", "the index has staged changes; commit or unstage them first");
142616
143023
  steps.push({ name: "preflight", status: "ok", detail: branch });
142617
143024
  const mismatch = remoteRepoMismatch(exec3, cwd2, remote, opts.repoUrl);
142618
- if (mismatch) return fail6("remote", `${mismatch}; refusing to fetch (fail closed)`);
143025
+ if (mismatch) return fail7("remote", `${mismatch}; refusing to fetch (fail closed)`);
142619
143026
  const fetched = git5("fetch", remote, base);
142620
- if (fetched.status !== 0) return fail6("fetch", tail(fetched.stderr));
143027
+ if (fetched.status !== 0) return fail7("fetch", tail(fetched.stderr));
142621
143028
  const local = git5("rev-parse", "--verify", upstream);
142622
143029
  if (local.status !== 0 || local.stdout.trim() !== baseSha) {
142623
- return fail6("fetch", `${upstream} is ${local.stdout.trim() || "missing"}, but GitHub reports ${base} at ${baseSha}; refusing (fail closed; re-run if ${base} just moved)`);
143030
+ return fail7("fetch", `${upstream} is ${local.stdout.trim() || "missing"}, but GitHub reports ${base} at ${baseSha}; refusing (fail closed; re-run if ${base} just moved)`);
142624
143031
  }
142625
143032
  steps.push({ name: "fetch", status: "ok", detail: `${upstream} = ${baseSha}` });
142626
143033
  if (git5("merge-base", "--is-ancestor", baseSha, "HEAD").status === 0) {
@@ -142631,11 +143038,11 @@ ${dirty}`);
142631
143038
  const conflicts = lines2(git5("diff", "--name-only", "--diff-filter=U").stdout);
142632
143039
  const inventoryOnly = conflicts.length > 0 && conflicts.every((f) => f.startsWith(`${INVENTORY_DIR}/`));
142633
143040
  if (!inventoryOnly) {
142634
- return fail6("merge-base", conflicts.length > 0 ? `conflicts outside ${INVENTORY_DIR}/ need a human or a fix lane: ${conflicts.join(", ")} (resolve and commit, or git merge --abort)` : tail(merged.stderr || merged.stdout), { conflicts });
143041
+ return fail7("merge-base", conflicts.length > 0 ? `conflicts outside ${INVENTORY_DIR}/ need a human or a fix lane: ${conflicts.join(", ")} (resolve and commit, or git merge --abort)` : tail(merged.stderr || merged.stdout), { conflicts });
142635
143042
  }
142636
143043
  for (const args of [["checkout", "--theirs", "--", INVENTORY_DIR], ["add", "--", INVENTORY_DIR], ["commit", "--no-edit", "--no-verify"]]) {
142637
143044
  const r = git5(...args);
142638
- if (r.status !== 0) return fail6("merge-base", `git ${args.join(" ")}: ${tail(r.stderr || r.stdout)}`, { conflicts });
143045
+ if (r.status !== 0) return fail7("merge-base", `git ${args.join(" ")}: ${tail(r.stderr || r.stdout)}`, { conflicts });
142639
143046
  }
142640
143047
  steps.push({ name: "merge-base", status: "ok", detail: `merged ${base} ${baseSha.slice(0, 12)}; inventory conflict resolved with --theirs` });
142641
143048
  } else {
@@ -142659,7 +143066,7 @@ ${dirty}`);
142659
143066
  continue;
142660
143067
  }
142661
143068
  const r = exec3(node, args, { cwd: cwd2 });
142662
- if (r.status !== 0) return fail6(name, tail(`${r.stdout}
143069
+ if (r.status !== 0) return fail7(name, tail(`${r.stdout}
142663
143070
  ${r.stderr}`));
142664
143071
  steps.push({ name, status: "ok", detail: args.slice(1).join(" ").slice(0, 300) });
142665
143072
  }
@@ -142670,22 +143077,22 @@ ${r.stderr}`));
142670
143077
  steps.push({ name: "inventory", status: "skipped", detail: "baseline is current" });
142671
143078
  } else {
142672
143079
  const written = exec3(node, [INVENTORY_SCRIPT, "--write"], { cwd: cwd2 });
142673
- if (written.status !== 0) return fail6("inventory", tail(written.stderr || written.stdout));
143080
+ if (written.status !== 0) return fail7("inventory", tail(written.stderr || written.stdout));
142674
143081
  const added = git5("add", "--", INVENTORY_DIR);
142675
- if (added.status !== 0) return fail6("inventory", `git add -- ${INVENTORY_DIR}: ${tail(added.stderr || added.stdout)}`);
143082
+ if (added.status !== 0) return fail7("inventory", `git add -- ${INVENTORY_DIR}: ${tail(added.stderr || added.stdout)}`);
142676
143083
  if (git5("diff", "--cached", "--quiet", "--", INVENTORY_DIR).status !== 0) {
142677
143084
  const committed = git5("commit", "--no-verify", "-m", INVENTORY_COMMIT_MESSAGE, "--", INVENTORY_DIR);
142678
- if (committed.status !== 0) return fail6("inventory", tail(committed.stderr || committed.stdout));
143085
+ if (committed.status !== 0) return fail7("inventory", tail(committed.stderr || committed.stdout));
142679
143086
  housekeepingCommits.push(head());
142680
143087
  }
142681
143088
  const verified = exec3(node, [INVENTORY_SCRIPT, "--verify"], { cwd: cwd2 });
142682
- if (verified.status !== 0) return fail6("inventory", `regenerated baseline still fails --verify:
143089
+ if (verified.status !== 0) return fail7("inventory", `regenerated baseline still fails --verify:
142683
143090
  ${tail(verified.stderr || verified.stdout)}`);
142684
143091
  steps.push({ name: "inventory", status: "ok", detail: "regenerated as the last commit" });
142685
143092
  }
142686
143093
  if (opts.push) {
142687
143094
  const pushed = git5("push", remote, `HEAD:refs/heads/${opts.branch}`);
142688
- if (pushed.status !== 0) return fail6("push", tail(pushed.stderr));
143095
+ if (pushed.status !== 0) return fail7("push", tail(pushed.stderr));
142689
143096
  steps.push({ name: "push", status: "ok", detail: `${remote} ${opts.branch}` });
142690
143097
  }
142691
143098
  return { ok: true, steps, housekeepingCommits };
@@ -142995,6 +143402,1463 @@ function shipCommand(execImpl = defaultExec, loadShipConfig = shipConfig) {
142995
143402
  return cmd;
142996
143403
  }
142997
143404
 
143405
+ // src/cli/commands/release.ts
143406
+ init_esm();
143407
+ init_source();
143408
+ var import_promises35 = require("readline/promises");
143409
+ init_config4();
143410
+ init_worktree_paths();
143411
+
143412
+ // src/release/checks.ts
143413
+ var VERSION_RE = /^\d+\.\d+\.\d+$/;
143414
+ function parseReleaseVersion(raw) {
143415
+ const v = raw.trim().replace(/^v/, "");
143416
+ if (!VERSION_RE.test(v)) throw new Error(`version must be X.Y.Z, got ${JSON.stringify(raw)}`);
143417
+ return v;
143418
+ }
143419
+ function compareVersions3(a, b) {
143420
+ const pa = parseReleaseVersion(a).split(".").map(Number);
143421
+ const pb = parseReleaseVersion(b).split(".").map(Number);
143422
+ for (let i = 0; i < 3; i++) if (pa[i] !== pb[i]) return pa[i] - pb[i];
143423
+ return 0;
143424
+ }
143425
+ var escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
143426
+ function releaseProseProblems(version3, changelog, releaseBody) {
143427
+ const problems = [];
143428
+ const v = escapeRe(version3);
143429
+ if (changelog === null) problems.push("CHANGELOG.md is missing");
143430
+ else {
143431
+ if (!new RegExp(`^## \\[${v}\\]`, "m").test(changelog)) problems.push(`CHANGELOG.md has no "## [${version3}] - YYYY-MM-DD" section`);
143432
+ if (!new RegExp(`^# .+ v${v}(?:[:\\s]|$)`, "m").test(changelog)) problems.push(`CHANGELOG.md has no "# oh-my-copilot v${version3}" heading (the release boundary greps for it)`);
143433
+ }
143434
+ if (releaseBody === null || releaseBody.trim() === "") problems.push(".github/release-body.md is missing or empty");
143435
+ else if (!releaseBody.includes(version3)) problems.push(`.github/release-body.md does not mention ${version3}`);
143436
+ return problems;
143437
+ }
143438
+ var VERSION_STAMPS = [
143439
+ { file: ".claude-plugin/plugin.json", pattern: /"version": "[^"]*"/, replace: (v) => `"version": "${v}"` },
143440
+ { file: "plugin.json", pattern: /"version": "[^"]*"/, replace: (v) => `"version": "${v}"` },
143441
+ { file: ".claude-plugin/marketplace.json", pattern: /"version": "[^"]*"/g, replace: (v) => `"version": "${v}"` },
143442
+ { file: "docs/CLAUDE.md", pattern: /<!-- OMC:VERSION:[^ ]* -->/g, replace: (v) => `<!-- OMC:VERSION:${v} -->` },
143443
+ { file: "CLAUDE.md", pattern: /<!-- OMC:VERSION:[^ ]* -->/g, replace: (v) => `<!-- OMC:VERSION:${v} -->` },
143444
+ { file: ".github/CLAUDE.md", pattern: /<!-- OMC:VERSION:[^ ]* -->/g, replace: (v) => `<!-- OMC:VERSION:${v} -->` },
143445
+ { file: "tests/fixtures/prompt-projection/claude-managed-block.golden", pattern: /<!-- OMC:VERSION:[^ ]* -->/g, replace: (v) => `<!-- OMC:VERSION:${v} -->` },
143446
+ { file: ".github/upstream-port.json", pattern: /"fork_version": "[^"]*"/g, replace: (v) => `"fork_version": "${v}"` }
143447
+ ];
143448
+ function stampVersion(content, stamp, version3) {
143449
+ const pattern = new RegExp(stamp.pattern.source, stamp.pattern.flags);
143450
+ if (!pattern.test(content)) return null;
143451
+ return content.replace(new RegExp(stamp.pattern.source, stamp.pattern.flags), stamp.replace(version3));
143452
+ }
143453
+ var DIST_OUTPUT = /^dist\/(.+?)\.(?:d\.ts\.map|d\.ts|js\.map|js)$/;
143454
+ var SOURCE_EXTS = [".ts", ".tsx", ".js", ".jsx"];
143455
+ function findDistOrphans(trackedDist, exists) {
143456
+ const orphans = [];
143457
+ for (const raw of trackedDist) {
143458
+ const file = raw.replace(/\\/g, "/");
143459
+ const m = DIST_OUTPUT.exec(file);
143460
+ if (!m) continue;
143461
+ if (!SOURCE_EXTS.some((ext) => exists(`src/${m[1]}${ext}`))) orphans.push(file);
143462
+ }
143463
+ return orphans;
143464
+ }
143465
+ var REPO_DIRS = /(?:^|\/)((?:src|tests|scripts|benchmark|bridge|skills|hooks)\/.+)$/;
143466
+ function repoRelativeTestPath(file) {
143467
+ const norm = file.replace(/\\/g, "/");
143468
+ return REPO_DIRS.exec(norm)?.[1] ?? norm;
143469
+ }
143470
+ function failingTitlesFromVitestJson(text) {
143471
+ const report = JSON.parse(text);
143472
+ if (!Array.isArray(report?.testResults)) throw new Error("not a vitest JSON report (no testResults)");
143473
+ const out = /* @__PURE__ */ new Set();
143474
+ for (const file of report.testResults) {
143475
+ const rel = repoRelativeTestPath(file.name ?? "");
143476
+ const failed2 = (file.assertionResults ?? []).filter((a) => a.status === "failed");
143477
+ for (const a of failed2) out.add(`${rel} > ${a.fullName ?? a.title ?? ""}`);
143478
+ if (failed2.length === 0 && file.status === "failed") out.add(rel);
143479
+ }
143480
+ return [...out].sort();
143481
+ }
143482
+ function parseBaselineTitles(text) {
143483
+ const trimmed = text.trim();
143484
+ if (trimmed.startsWith("{")) return failingTitlesFromVitestJson(trimmed);
143485
+ return trimmed.split(/\r?\n/).map((l) => l.trim()).filter((l) => l && !l.startsWith("#")).map((l) => {
143486
+ const [file, ...rest] = l.split(" > ");
143487
+ return rest.length > 0 ? `${repoRelativeTestPath(file)} > ${rest.join(" > ")}` : repoRelativeTestPath(file);
143488
+ });
143489
+ }
143490
+ function newFailures(failing, baseline) {
143491
+ const known = new Set(baseline);
143492
+ return failing.filter((t) => !known.has(t));
143493
+ }
143494
+ function smokeProblems(stdout) {
143495
+ const start = stdout.indexOf("{");
143496
+ let report;
143497
+ try {
143498
+ report = JSON.parse(start >= 0 ? stdout.slice(start) : stdout);
143499
+ } catch {
143500
+ return ["smoke did not print a JSON report"];
143501
+ }
143502
+ const problems = [];
143503
+ if (typeof report.skipped === "string" && report.skipped) problems.push(`smoke skipped: ${report.skipped}`);
143504
+ const checks = Array.isArray(report.checks) ? report.checks : [];
143505
+ if (checks.length === 0) problems.push("smoke reported no checks");
143506
+ for (const c of checks) if (c.ok !== true) problems.push(`${String(c.id)}: ${String(c.detail ?? "failed")}`);
143507
+ if (report.ok !== true && problems.length === 0) problems.push("smoke report ok=false");
143508
+ return problems;
143509
+ }
143510
+ function remoteTagTarget(lsRemote, tag) {
143511
+ let object3;
143512
+ let peeled;
143513
+ for (const line of lsRemote.split(/\r?\n/)) {
143514
+ const [sha, ref] = line.trim().split(/\s+/);
143515
+ if (ref === `refs/tags/${tag}`) object3 = sha;
143516
+ else if (ref === `refs/tags/${tag}^{}`) peeled = sha;
143517
+ }
143518
+ if (!object3) return null;
143519
+ return { object: object3, commit: peeled ?? object3, annotated: peeled !== void 0 };
143520
+ }
143521
+ function tagTargetProblem(tag, objectType3, peeled, expected) {
143522
+ if (objectType3.trim() !== "tag") return `${tag} is a ${objectType3.trim() || "missing"} object, not an annotated tag`;
143523
+ if (peeled.trim() !== expected) return `${tag}^{} is ${peeled.trim().slice(0, 12) || "unresolved"}, not the main merge commit ${expected.slice(0, 12)}`;
143524
+ return null;
143525
+ }
143526
+
143527
+ // src/release/engine.ts
143528
+ var import_child_process54 = require("child_process");
143529
+ var import_fs156 = require("fs");
143530
+ var import_path187 = require("path");
143531
+ var import_url23 = require("url");
143532
+ init_atomic_write();
143533
+ init_config4();
143534
+ init_exec();
143535
+ var PHASES2 = ["preflight", "bump", "build", "gates", "smoke", "commit", "pr", "promote", "tag", "verify"];
143536
+ function isPhaseId(value) {
143537
+ return PHASES2.includes(value);
143538
+ }
143539
+ var PROSE_FILES = ["CHANGELOG.md", ".github/release-body.md", "README.md", "docs/REFERENCE.md", "docs/MIGRATION.md"];
143540
+ var SHELL_SAFE_ARG = /^[\w@./:=-]+$/;
143541
+ var defaultReleaseExec = (cmd, args, opts) => {
143542
+ const shell = process.platform === "win32" && cmd === "npm";
143543
+ if (shell && !args.every((a) => SHELL_SAFE_ARG.test(a))) {
143544
+ return { status: 1, stdout: "", stderr: `refusing to pass ${JSON.stringify(args)} to npm through cmd.exe` };
143545
+ }
143546
+ const result = (0, import_child_process54.spawnSync)(shell ? ["npm", ...args].join(" ") : cmd, shell ? [] : args, {
143547
+ cwd: opts?.cwd,
143548
+ env: { ...scrubShipEnv(process.env), ...opts?.env },
143549
+ encoding: "utf8",
143550
+ windowsHide: true,
143551
+ maxBuffer: 512 * 1024 * 1024,
143552
+ shell,
143553
+ timeout: opts?.timeoutMs
143554
+ });
143555
+ return {
143556
+ status: result.status ?? 1,
143557
+ stdout: result.stdout ?? "",
143558
+ stderr: `${result.stderr ?? ""}${result.error ? result.error.message : ""}`
143559
+ };
143560
+ };
143561
+ var PhaseStop = class extends Error {
143562
+ constructor(outcome) {
143563
+ super(outcome.note);
143564
+ this.outcome = outcome;
143565
+ }
143566
+ };
143567
+ var fail6 = (note, details) => {
143568
+ throw new PhaseStop({ status: "fail", note, details });
143569
+ };
143570
+ var blocked = (note, details) => {
143571
+ throw new PhaseStop({ status: "blocked", note, details });
143572
+ };
143573
+ function releaseStatePath(stateRoot2, version3) {
143574
+ return (0, import_path187.join)(stateRoot2, "release", `${version3}.json`);
143575
+ }
143576
+ function readReleaseState(stateRoot2, version3) {
143577
+ const path30 = releaseStatePath(stateRoot2, version3);
143578
+ if (!(0, import_fs156.existsSync)(path30)) return null;
143579
+ const parsed = JSON.parse((0, import_fs156.readFileSync)(path30, "utf8"));
143580
+ if (parsed?.version !== 1 || parsed.release !== version3 || typeof parsed.phases !== "object") {
143581
+ throw new Error(`${path30} is not a release state for ${version3}`);
143582
+ }
143583
+ return { ...parsed, reruns: parsed.reruns ?? {} };
143584
+ }
143585
+ function tail2(text, lines3 = 30) {
143586
+ return text.trim().split(/\r?\n/).slice(-lines3);
143587
+ }
143588
+ var FULL_SHA3 = /^[0-9a-f]{40}$/;
143589
+ var RERUN_START_POLLS = 40;
143590
+ var LAND_ROUNDS = 500;
143591
+ function phasePlan(id, v, opts) {
143592
+ const branch = `release/v${v}`;
143593
+ switch (id) {
143594
+ case "preflight":
143595
+ return [
143596
+ `git status --porcelain is empty apart from ${PROSE_FILES.join(", ")}`,
143597
+ `HEAD is ${branch}; git fetch origin dev; origin/dev is an ancestor of HEAD`,
143598
+ `${v} > package.json version on origin/dev and > npm dist-tags.latest`,
143599
+ "gh auth status; no .git/index.lock (holder reported, never deleted)",
143600
+ `tag v${v} absent on origin (git ls-remote --tags origin)`
143601
+ ];
143602
+ case "bump":
143603
+ return [
143604
+ `refuse unless CHANGELOG.md has "## [${v}]" and "# oh-my-copilot v${v}", and .github/release-body.md mentions ${v}`,
143605
+ `npm version ${v} --no-git-tag-version --ignore-scripts --allow-same-version`,
143606
+ `stamp ${v}: ${VERSION_STAMPS.map((s) => s.file).join(", ")}`,
143607
+ "node scripts/generate-prompt-projections.mjs"
143608
+ ];
143609
+ case "build":
143610
+ return [
143611
+ "npm run build",
143612
+ "git add -f dist bridge",
143613
+ `tracked dist .js/.d.ts/.map without a src source -> ${opts.fixOrphans ? "git rm (--fix-orphans)" : "fail (pass --fix-orphans to remove)"}`,
143614
+ "git ls-files --others dist bridge is empty",
143615
+ `probes: import dist/index.js; dist/cli/index.js --version == ${v}; bridge/cli.cjs --version == ${v}; dist/mcp/standalone-server.js starts and exits`
143616
+ ];
143617
+ case "gates":
143618
+ return [
143619
+ "tsc --noEmit",
143620
+ "generate-prompt-projections.mjs --verify; copilot build-hooks.mjs / build-agents.mjs --verify",
143621
+ "node scripts/ci/check-multirepo-paths.mjs",
143622
+ opts.suite === "full" ? `vitest run --reporter=json; fail only on titles not in ${opts.baseline ?? "(no baseline: any failure fails)"}` : opts.suite === "targeted" ? "vitest related --run <src files changed since the last v* tag>" : "suite: none (pass --suite targeted|full)"
143623
+ ];
143624
+ case "smoke":
143625
+ return opts.liveSmoke ? ["OMC_LIVE_SMOKE=2 node bridge/cli.cjs smoke copilot --tier 2 --json (about 2 premium requests); every check must pass"] : ["SKIPPED: live Tier 2 smoke not requested (pass --live-smoke; about 2 premium requests)"];
143626
+ case "commit":
143627
+ return [
143628
+ `git add -f dist bridge; git add -A; git commit -m "chore(release): v${v}"`,
143629
+ "node scripts/generate-inventory-graph.mjs --write; commit inventory/ if changed; --verify",
143630
+ "git status --porcelain is empty"
143631
+ ];
143632
+ case "pr":
143633
+ return [
143634
+ `git push origin HEAD:refs/heads/${branch} until the PR is merged (plain, never forced; a refused push blocks)`,
143635
+ `gh pr create --base dev --head ${branch} (an open one is reused; a merged one when its merge contains HEAD, or the dev tip once a follow-up PR into dev carried HEAD; else blocks)`,
143636
+ "wait for CI under the ship merge rule (ship.advisoryChecks never block); one rerun of failed jobs, awaited until its new attempt starts",
143637
+ "gh pr merge --admin --merge --match-head-commit <head> when the PR head is local HEAD, ship.allowAdminMerge and dev is a trusted base, else print it"
143638
+ ];
143639
+ case "promote":
143640
+ return [
143641
+ "require the release PR merged into dev (gh pr view); use the dev merge recorded by pr",
143642
+ "gh pr create --base main --head dev (reused when one is open)",
143643
+ "same CI gate and merge as pr, merged only when the PR head contains the dev merge; the main merge must contain it too; record it"
143644
+ ];
143645
+ case "tag":
143646
+ return [
143647
+ `the main merge commit contains the dev merge and its package.json is ${v}`,
143648
+ `confirm (${opts.yes ? "--yes given" : "interactive; --yes skips"})`,
143649
+ `git tag -a v${v} -m v${v} <main merge sha>; v${v}^{} must equal it and be an annotated tag`,
143650
+ `git push origin refs/tags/v${v}; git ls-remote confirms the peeled sha`
143651
+ ];
143652
+ case "verify":
143653
+ return [
143654
+ `find the ci.yml push run of v${v} on the main merge commit; wait; one rerun of failed jobs unless ${v} is already on npm, failing test titles printed`,
143655
+ `npm view oh-my-copilot@${v} version dist-tags.latest dist.attestations`,
143656
+ `gh release view v${v}: published, not a draft; the Copilot smoke (tier 2) job succeeded`
143657
+ ];
143658
+ }
143659
+ }
143660
+ var Release = class {
143661
+ constructor(deps, opts, existing) {
143662
+ this.deps = deps;
143663
+ this.opts = opts;
143664
+ this.v = opts.version;
143665
+ const at = new Date(deps.now()).toISOString();
143666
+ this.state = existing ?? { version: 1, release: this.v, createdAt: at, updatedAt: at, phases: {}, reruns: {} };
143667
+ this.deadline = deps.now() + (opts.timeoutMinutes ?? 60) * 6e4;
143668
+ }
143669
+ state;
143670
+ v;
143671
+ deadline;
143672
+ pkgName = "oh-my-copilot";
143673
+ get current() {
143674
+ return this.state;
143675
+ }
143676
+ save(patch) {
143677
+ this.state = { ...this.state, ...patch, updatedAt: new Date(this.deps.now()).toISOString() };
143678
+ const path30 = releaseStatePath(this.deps.stateRoot, this.v);
143679
+ (0, import_fs156.mkdirSync)((0, import_path187.join)(this.deps.stateRoot, "release"), { recursive: true });
143680
+ atomicWriteJsonSync(path30, this.state);
143681
+ }
143682
+ run(cmd, args, opts) {
143683
+ return this.deps.exec(cmd, args, { cwd: this.deps.root, ...opts });
143684
+ }
143685
+ /** Run and require exit 0; the phase fails with the output tail otherwise. */
143686
+ must(cmd, args, what, opts) {
143687
+ const r = this.run(cmd, args, opts);
143688
+ if (r.status !== 0) fail6(`${what ?? `${cmd} ${args.join(" ")}`} failed (exit ${r.status})`, tail2(`${r.stdout}
143689
+ ${r.stderr}`));
143690
+ return r.stdout;
143691
+ }
143692
+ git(...args) {
143693
+ return this.must("git", args).trim();
143694
+ }
143695
+ script(script, ...args) {
143696
+ this.deps.log(` node ${[script, ...args].join(" ")}`);
143697
+ this.must(this.deps.node, [script, ...args], `node ${[script, ...args].join(" ")}`);
143698
+ }
143699
+ file(rel) {
143700
+ const path30 = (0, import_path187.join)(this.deps.root, rel);
143701
+ return (0, import_fs156.existsSync)(path30) ? (0, import_fs156.readFileSync)(path30, "utf8") : null;
143702
+ }
143703
+ readPkgName() {
143704
+ const pkg = this.file("package.json");
143705
+ if (pkg) this.pkgName = JSON.parse(pkg).name ?? this.pkgName;
143706
+ }
143707
+ async phase(id) {
143708
+ this.readPkgName();
143709
+ try {
143710
+ switch (id) {
143711
+ case "preflight":
143712
+ return this.preflight();
143713
+ case "bump":
143714
+ return this.bump();
143715
+ case "build":
143716
+ return this.build();
143717
+ case "gates":
143718
+ return this.gates();
143719
+ case "smoke":
143720
+ return this.smoke();
143721
+ case "commit":
143722
+ return this.commit();
143723
+ case "pr":
143724
+ return await this.pr();
143725
+ case "promote":
143726
+ return await this.promote();
143727
+ case "tag":
143728
+ return await this.tag();
143729
+ case "verify":
143730
+ return await this.verify();
143731
+ }
143732
+ } catch (error2) {
143733
+ if (error2 instanceof PhaseStop) return error2.outcome;
143734
+ return { status: "fail", note: error2 instanceof Error ? error2.message : String(error2) };
143735
+ }
143736
+ }
143737
+ preflight() {
143738
+ const v = this.v;
143739
+ const problems = [];
143740
+ const dirty = this.must("git", ["status", "--porcelain"]).split(/\r?\n/).filter(Boolean).map((l) => l.slice(3)).filter((entry2) => !entry2.split(" -> ").every((p) => PROSE_FILES.includes(p.replace(/^"|"$/g, ""))));
143741
+ if (dirty.length > 0) problems.push(`working tree is not clean: ${dirty.join(", ")}`);
143742
+ const branch = this.git("rev-parse", "--abbrev-ref", "HEAD");
143743
+ if (branch !== `release/v${v}`) problems.push(`HEAD is ${branch}, expected release/v${v} (git checkout -b release/v${v} origin/dev)`);
143744
+ this.must("git", ["fetch", "origin", "dev"]);
143745
+ if (this.run("git", ["merge-base", "--is-ancestor", "refs/remotes/origin/dev", "HEAD"]).status !== 0) {
143746
+ problems.push("HEAD does not contain origin/dev (git merge origin/dev; never rebase)");
143747
+ }
143748
+ const devPkg = this.run("git", ["show", "refs/remotes/origin/dev:package.json"]);
143749
+ const devVersion = devPkg.status === 0 ? JSON.parse(devPkg.stdout).version : void 0;
143750
+ if (!devVersion) problems.push("could not read package.json on origin/dev");
143751
+ else if (compareVersions3(v, devVersion) <= 0) problems.push(`${v} is not above origin/dev's version ${devVersion}`);
143752
+ const latest2 = this.run("npm", ["view", this.pkgName, "dist-tags.latest"]);
143753
+ if (latest2.status === 0) {
143754
+ const published = latest2.stdout.trim();
143755
+ if (published && compareVersions3(v, published) <= 0) problems.push(`${v} is not above npm latest ${published}`);
143756
+ } else if (!/E404/.test(latest2.stderr)) problems.push(`npm view ${this.pkgName} failed: ${tail2(latest2.stderr, 1).join("")}`);
143757
+ if (this.run("gh", ["auth", "status"]).status !== 0) problems.push("gh is not authenticated (gh auth login)");
143758
+ const lockRel = this.git("rev-parse", "--git-path", "index.lock");
143759
+ const lock = (0, import_path187.isAbsolute)(lockRel) ? lockRel : (0, import_path187.join)(this.deps.root, lockRel);
143760
+ if ((0, import_fs156.existsSync)(lock)) {
143761
+ problems.push(`${lock} exists; another git process may hold it (not deleted; remove it only when no git process runs): ${this.gitProcesses()}`);
143762
+ }
143763
+ const remoteTag = this.run("git", ["ls-remote", "--tags", "origin", `refs/tags/v${v}`]);
143764
+ if (remoteTag.status !== 0) problems.push(`git ls-remote --tags origin failed: ${tail2(remoteTag.stderr, 1).join("")}`);
143765
+ else if (remoteTag.stdout.trim()) problems.push(`tag v${v} already exists on origin`);
143766
+ if (problems.length > 0) fail6(`${problems.length} preflight problem(s)`, problems);
143767
+ this.save({ branch, headSha: void 0, devPr: void 0, devMergeSha: void 0, mainPr: void 0, mainMergeSha: void 0, tagRunId: void 0 });
143768
+ return { status: "ok", note: `on release/v${v} over origin/dev ${devVersion}` };
143769
+ }
143770
+ gitProcesses() {
143771
+ const r = process.platform === "win32" ? this.run("tasklist", ["/FI", "IMAGENAME eq git.exe", "/FO", "CSV", "/NH"]) : this.run("ps", ["-eo", "pid,args"]);
143772
+ const lines3 = r.stdout.split(/\r?\n/).filter((l) => /git(?:\.exe)?\b/i.test(l) && !/INFO:/.test(l));
143773
+ return lines3.length > 0 ? lines3.slice(0, 5).join(" | ") : "no running git process found";
143774
+ }
143775
+ bump() {
143776
+ const v = this.v;
143777
+ const prose = releaseProseProblems(v, this.file("CHANGELOG.md"), this.file(".github/release-body.md"));
143778
+ if (prose.length > 0) fail6("release prose is missing (write it, then re-run)", prose);
143779
+ const pkg = JSON.parse(this.file("package.json") ?? "{}");
143780
+ if (pkg.version !== v) this.must("npm", ["version", v, "--no-git-tag-version", "--ignore-scripts", "--allow-same-version"]);
143781
+ const missing = [];
143782
+ for (const stamp of VERSION_STAMPS) {
143783
+ const content = this.file(stamp.file);
143784
+ const next = content === null ? null : stampVersion(content, stamp, v);
143785
+ if (next === null) missing.push(`${stamp.file}: no version stamp`);
143786
+ else if (next !== content) (0, import_fs156.writeFileSync)((0, import_path187.join)(this.deps.root, stamp.file), next);
143787
+ }
143788
+ if (missing.length > 0) fail6("version stamps missing", missing);
143789
+ this.script("scripts/generate-prompt-projections.mjs");
143790
+ return { status: "ok", note: `version ${v} stamped in package.json and ${VERSION_STAMPS.length} files` };
143791
+ }
143792
+ build() {
143793
+ const v = this.v;
143794
+ this.deps.log(" npm run build");
143795
+ this.must("npm", ["run", "build"], "npm run build");
143796
+ this.git("add", "-f", "dist", "bridge");
143797
+ const tracked = this.git("ls-files", "dist").split(/\r?\n/).filter(Boolean);
143798
+ const orphans = findDistOrphans(tracked, (p) => (0, import_fs156.existsSync)((0, import_path187.join)(this.deps.root, p)));
143799
+ if (orphans.length > 0) {
143800
+ if (!this.opts.fixOrphans) fail6(`${orphans.length} dist file(s) without a src source (re-run with --fix-orphans to remove them)`, orphans);
143801
+ for (let i = 0; i < orphans.length; i += 100) this.git("rm", "-q", "--", ...orphans.slice(i, i + 100));
143802
+ }
143803
+ const untracked = this.git("ls-files", "--others", "dist", "bridge");
143804
+ if (untracked) fail6("untracked files under dist/ or bridge/ after git add -f", untracked.split(/\r?\n/));
143805
+ const probes = [];
143806
+ const importProbe = this.run(this.deps.node, ["--input-type=module", "-e", "await import(process.argv[1])", (0, import_url23.pathToFileURL)((0, import_path187.join)(this.deps.root, "dist", "index.js")).href]);
143807
+ if (importProbe.status !== 0) probes.push(`import dist/index.js failed: ${tail2(importProbe.stderr, 3).join(" ")}`);
143808
+ for (const entry2 of ["dist/cli/index.js", "bridge/cli.cjs"]) {
143809
+ const r = this.run(this.deps.node, [entry2, "--version"]);
143810
+ if (r.status !== 0 || r.stdout.trim() !== v) probes.push(`${entry2} --version printed ${JSON.stringify(r.stdout.trim())} (exit ${r.status}), expected ${v}`);
143811
+ }
143812
+ const mcp = this.run(this.deps.node, ["dist/mcp/standalone-server.js"], { timeoutMs: 3e4 });
143813
+ if (mcp.status !== 0) probes.push(`dist/mcp/standalone-server.js did not start and exit cleanly (exit ${mcp.status}): ${tail2(mcp.stderr, 3).join(" ")}`);
143814
+ if (probes.length > 0) fail6("build probes failed", probes);
143815
+ return { status: "ok", note: `built and staged${orphans.length > 0 ? `; removed ${orphans.length} orphan(s)` : ""}` };
143816
+ }
143817
+ gates() {
143818
+ this.script("node_modules/typescript/bin/tsc", "--noEmit");
143819
+ this.script("scripts/generate-prompt-projections.mjs", "--verify");
143820
+ this.script("scripts/copilot/build-hooks.mjs", "--verify");
143821
+ this.script("scripts/copilot/build-agents.mjs", "--verify");
143822
+ this.script("scripts/ci/check-multirepo-paths.mjs");
143823
+ const suite = this.opts.suite ?? "none";
143824
+ if (suite === "targeted") {
143825
+ const tag = this.run("git", ["describe", "--tags", "--abbrev=0", "--match", "v[0-9]*", "HEAD"]);
143826
+ if (tag.status !== 0) fail6("no v* tag reachable from HEAD for --suite targeted", tail2(tag.stderr, 2));
143827
+ const changed = this.git("diff", "--name-only", `${tag.stdout.trim()}...HEAD`, "--", "src").split(/\r?\n/).filter((f) => /\.(?:ts|tsx|mts)$/.test(f) && !f.endsWith(".d.ts") && (0, import_fs156.existsSync)((0, import_path187.join)(this.deps.root, f)));
143828
+ if (changed.length === 0) return { status: "ok", note: `gates green; no src changes since ${tag.stdout.trim()} for the targeted suite` };
143829
+ this.script("node_modules/vitest/vitest.mjs", "related", "--run", "--exclude", "tests/perf/**", ...changed);
143830
+ return { status: "ok", note: `gates green; targeted suite over ${changed.length} changed src file(s)` };
143831
+ }
143832
+ if (suite === "full") {
143833
+ const out = (0, import_path187.join)(this.deps.stateRoot, "release", `${this.v}-vitest.json`);
143834
+ (0, import_fs156.mkdirSync)((0, import_path187.join)(this.deps.stateRoot, "release"), { recursive: true });
143835
+ (0, import_fs156.rmSync)(out, { force: true });
143836
+ this.deps.log(` node node_modules/vitest/vitest.mjs run --reporter=json --outputFile=${out}`);
143837
+ const r = this.run(this.deps.node, ["node_modules/vitest/vitest.mjs", "run", "--exclude", "tests/perf/**", "--reporter=json", `--outputFile=${out}`]);
143838
+ if (!(0, import_fs156.existsSync)(out)) fail6(`vitest wrote no JSON report (exit ${r.status})`, tail2(r.stderr));
143839
+ const failing = failingTitlesFromVitestJson((0, import_fs156.readFileSync)(out, "utf8"));
143840
+ const baseline = this.opts.baseline ? parseBaselineTitles((0, import_fs156.readFileSync)(this.opts.baseline, "utf8")) : [];
143841
+ const fresh = newFailures(failing, baseline);
143842
+ if (fresh.length > 0) fail6(`${fresh.length} failing test(s) not in the baseline (report: ${out})`, fresh);
143843
+ return { status: "ok", note: `gates green; full suite: ${failing.length} failing, all in the baseline` };
143844
+ }
143845
+ return { status: "ok", note: "gates green; no vitest suite (--suite none)" };
143846
+ }
143847
+ smoke() {
143848
+ if (!this.opts.liveSmoke) {
143849
+ this.deps.log(" !! SKIPPED the live Tier 2 smoke. The runbook requires it green before tagging: re-run with --from smoke --live-smoke (about 2 premium requests).");
143850
+ return { status: "skipped", note: "live Tier 2 smoke not run (pass --live-smoke)" };
143851
+ }
143852
+ this.deps.log(" OMC_LIVE_SMOKE=2 node bridge/cli.cjs smoke copilot --tier 2 --json");
143853
+ const r = this.run(this.deps.node, ["bridge/cli.cjs", "smoke", "copilot", "--tier", "2", "--json"], { env: { OMC_LIVE_SMOKE: "2" } });
143854
+ const problems = smokeProblems(r.stdout);
143855
+ if (r.status !== 0 && problems.length === 0) problems.push(`smoke exited ${r.status}${r.status === 2 ? " (copilot binary or SDK missing: not a pass)" : ""}`);
143856
+ if (problems.length > 0) fail6("Tier 2 smoke is not green", problems);
143857
+ return { status: "ok", note: "Tier 2 smoke green" };
143858
+ }
143859
+ staged(paths = []) {
143860
+ return this.run("git", ["diff", "--cached", "--quiet", ...paths.length ? ["--", ...paths] : []]).status !== 0;
143861
+ }
143862
+ commit() {
143863
+ const v = this.v;
143864
+ this.git("add", "-f", "dist", "bridge");
143865
+ this.git("add", "-A");
143866
+ const notes = [];
143867
+ if (this.staged()) {
143868
+ this.git("commit", "-m", `chore(release): v${v}`);
143869
+ notes.push("release commit");
143870
+ }
143871
+ this.script("scripts/generate-inventory-graph.mjs", "--write");
143872
+ this.git("add", "-A", "--", "inventory");
143873
+ if (this.staged(["inventory"])) {
143874
+ this.git("commit", "-m", `chore(release): regenerate inventory for v${v}`, "--", "inventory");
143875
+ notes.push("inventory commit");
143876
+ }
143877
+ this.script("scripts/generate-inventory-graph.mjs", "--verify");
143878
+ const left = this.git("status", "--porcelain");
143879
+ if (left) fail6("working tree is not clean after the release commits", left.split(/\r?\n/));
143880
+ const head = this.git("rev-parse", "HEAD");
143881
+ this.save({ headSha: head });
143882
+ return { status: "ok", note: notes.length > 0 ? `${notes.join(" + ")} at ${head.slice(0, 12)}` : "nothing new to commit" };
143883
+ }
143884
+ /** Exit 1 is "no"; any other non-zero exit (missing object, bad ref) is a git error, never a yes. */
143885
+ isAncestor(ancestor, descendant) {
143886
+ const r = this.run("git", ["merge-base", "--is-ancestor", ancestor, descendant]);
143887
+ if (r.status === 0) return true;
143888
+ if (r.status === 1) return false;
143889
+ return fail6(`git merge-base --is-ancestor ${ancestor} ${descendant} failed (exit ${r.status}): ${r.stderr.trim() || "(no stderr)"}`);
143890
+ }
143891
+ viewPr(pr) {
143892
+ return JSON.parse(this.must("gh", ["pr", "view", String(pr), "--json", "number,state,isDraft,baseRefName,baseRefOid,headRefOid,url,mergeCommit"]));
143893
+ }
143894
+ /** The merge commit of a merged PR, else null. */
143895
+ mergedSha(pr) {
143896
+ const view = this.viewPr(pr);
143897
+ const sha = view.state === "MERGED" ? view.mergeCommit?.oid : void 0;
143898
+ return sha && FULL_SHA3.test(sha) ? sha : null;
143899
+ }
143900
+ /** Why the phases before `start` may not be skipped (empty = they may): the state's checkout, then each phase's postconditions. */
143901
+ skipProblems(start) {
143902
+ const problems = [];
143903
+ const released = !!this.state.mainMergeSha && PHASES2.indexOf(start) >= PHASES2.indexOf("tag");
143904
+ const checks = [
143905
+ ["state", () => released ? null : this.provenanceProblem()],
143906
+ ...PHASES2.slice(0, PHASES2.indexOf(start)).map((id) => [id, () => this.postconditionProblem(id, released)])
143907
+ ];
143908
+ for (const [what, check2] of checks) {
143909
+ try {
143910
+ const problem = check2();
143911
+ if (problem) problems.push(`${what}: ${problem}`);
143912
+ } catch (error2) {
143913
+ problems.push(`${what}: ${error2 instanceof PhaseStop ? error2.outcome.note : error2 instanceof Error ? error2.message : String(error2)}`);
143914
+ }
143915
+ }
143916
+ return problems;
143917
+ }
143918
+ /** Why the recorded state does not belong to this checkout (null = it does). */
143919
+ provenanceProblem() {
143920
+ const { branch, headSha } = this.state;
143921
+ if (branch) {
143922
+ const current = this.run("git", ["rev-parse", "--abbrev-ref", "HEAD"]).stdout.trim();
143923
+ if (current !== branch) return `HEAD is ${current || "(unknown)"}, but this release state was recorded on ${branch}`;
143924
+ }
143925
+ if (headSha && !this.isAncestor(headSha, "HEAD")) return `HEAD does not descend from the recorded release commit ${headSha.slice(0, 12)}`;
143926
+ return null;
143927
+ }
143928
+ /**
143929
+ * Why a phase may not be skipped (null = its recorded result still holds):
143930
+ * it must have passed, and the facts later phases build on are re-checked
143931
+ * cheaply (read-only git / gh).
143932
+ */
143933
+ postconditionProblem(id, released = false) {
143934
+ const s = this.state;
143935
+ const status = s.phases[id]?.status;
143936
+ if (status !== "ok" && status !== "skipped") return `has not passed (run it: --from ${id})`;
143937
+ switch (id) {
143938
+ case "bump": {
143939
+ if (released) return null;
143940
+ const version3 = JSON.parse(this.file("package.json") ?? "{}").version;
143941
+ return version3 === this.v ? null : `package.json version is ${version3 ?? "missing"}, not ${this.v} (--from bump)`;
143942
+ }
143943
+ case "commit": {
143944
+ if (!s.headSha || !FULL_SHA3.test(s.headSha)) return "no release commit recorded (--from commit)";
143945
+ if (released) return null;
143946
+ const head = this.git("rev-parse", "HEAD");
143947
+ return head === s.headSha ? null : `HEAD ${head.slice(0, 12)} is not the recorded release commit ${s.headSha.slice(0, 12)}; new local commits must go back through the gates (--from gates)`;
143948
+ }
143949
+ case "pr": {
143950
+ if (s.devPr === void 0 || !s.devMergeSha) return "no merged release PR into dev recorded (--from pr)";
143951
+ const sha = this.mergedSha(s.devPr);
143952
+ if (!sha) return `PR #${s.devPr} is not merged, not at the recorded ${s.devMergeSha.slice(0, 12)} (--from pr)`;
143953
+ if (!s.headSha) return "no release commit recorded (--from commit)";
143954
+ this.must("git", ["fetch", "origin", "dev"]);
143955
+ if (sha !== s.devMergeSha && !this.isAncestor(sha, s.devMergeSha)) return `PR #${s.devPr} is merged at ${sha.slice(0, 12)}, which the recorded dev merge ${s.devMergeSha.slice(0, 12)} does not contain (--from pr)`;
143956
+ return this.isAncestor(s.headSha, s.devMergeSha) ? null : `the dev merge ${s.devMergeSha.slice(0, 12)} does not contain the release commit ${s.headSha.slice(0, 12)} (--from pr)`;
143957
+ }
143958
+ case "promote": {
143959
+ if (s.mainPr === void 0 || !s.mainMergeSha || !s.devMergeSha) return "no main merge commit recorded (--from promote)";
143960
+ const sha = this.mergedSha(s.mainPr);
143961
+ if (sha !== s.mainMergeSha) return `PR #${s.mainPr} is ${sha ? `merged at ${sha.slice(0, 12)}` : "not merged"}, not at the recorded ${s.mainMergeSha.slice(0, 12)} (--from promote)`;
143962
+ this.must("git", ["fetch", "origin", "dev", "main"]);
143963
+ return this.isAncestor(s.devMergeSha, s.mainMergeSha) ? null : `the main merge ${s.mainMergeSha.slice(0, 12)} does not contain the dev merge ${s.devMergeSha.slice(0, 12)}`;
143964
+ }
143965
+ case "tag": {
143966
+ const remote = remoteTagTarget(this.git("ls-remote", "--tags", "origin", `refs/tags/v${this.v}`, `refs/tags/v${this.v}^{}`), `v${this.v}`);
143967
+ return remote?.annotated && remote.commit === s.mainMergeSha ? null : `v${this.v} on origin does not peel to the main merge commit (--from tag)`;
143968
+ }
143969
+ default:
143970
+ return null;
143971
+ }
143972
+ }
143973
+ findPr(head, base, states) {
143974
+ const out = this.must("gh", ["pr", "list", "--head", head, "--base", base, "--state", states, "--json", "number,state,headRefOid,mergeCommit", "--limit", "10"]);
143975
+ const prs = JSON.parse(out || "[]");
143976
+ const open9 = prs.find((p) => p.state === "OPEN");
143977
+ if (open9) return open9.number;
143978
+ const merged = prs.filter((p) => p.state === "MERGED" && FULL_SHA3.test(p.mergeCommit?.oid ?? ""));
143979
+ if (merged.length === 0) return void 0;
143980
+ this.must("git", ["fetch", "origin", base]);
143981
+ return (merged.find((p) => this.isAncestor("HEAD", p.mergeCommit.oid)) ?? merged[0]).number;
143982
+ }
143983
+ createPr(base, head, title) {
143984
+ const out = this.must("gh", ["pr", "create", "--base", base, "--head", head, "--title", title, "--body-file", ".github/release-body.md"]);
143985
+ const m = /\/pull\/(\d+)/.exec(out);
143986
+ if (!m) fail6(`gh pr create printed no PR url: ${out.trim()}`);
143987
+ return Number(m[1]);
143988
+ }
143989
+ async pr() {
143990
+ const branch = `release/v${this.v}`;
143991
+ if (this.state.devPr === void 0 || this.viewPr(this.state.devPr).state !== "MERGED") {
143992
+ const push = this.run("git", ["push", "origin", `HEAD:refs/heads/${branch}`]);
143993
+ if (push.status !== 0) {
143994
+ blocked(`git push origin HEAD:refs/heads/${branch} was refused; never force: git fetch origin ${branch} && git merge origin/${branch}, then re-run omg release ${this.v} --from pr`, tail2(push.stderr, 5));
143995
+ }
143996
+ if (this.state.devPr === void 0) {
143997
+ const pr = this.findPr(branch, "dev", "all") ?? this.createPr("dev", branch, `chore(release): v${this.v}`);
143998
+ this.save({ devPr: pr });
143999
+ }
144000
+ }
144001
+ const sha = await this.land(this.state.devPr, "dev", "pr", this.git("rev-parse", "HEAD"));
144002
+ this.save({ devMergeSha: sha });
144003
+ return { status: "ok", note: `PR #${this.state.devPr} merged into dev at ${sha.slice(0, 12)}` };
144004
+ }
144005
+ async promote() {
144006
+ const devPr = this.state.devPr;
144007
+ if (devPr === void 0) fail6("no release PR into dev recorded; run the pr phase first");
144008
+ if (!this.mergedSha(devPr)) fail6(`release PR #${devPr} is not merged into dev; re-run omg release ${this.v} --from pr`);
144009
+ const devMerge = this.state.devMergeSha;
144010
+ if (!devMerge || !FULL_SHA3.test(devMerge)) fail6(`no dev merge commit recorded; re-run omg release ${this.v} --from pr`);
144011
+ if (this.state.mainPr === void 0) {
144012
+ const pr = this.findPr("dev", "main", "open") ?? this.createPr("main", "dev", `Release v${this.v}`);
144013
+ this.save({ mainPr: pr });
144014
+ }
144015
+ const sha = await this.land(this.state.mainPr, "main", "promote", void 0, devMerge);
144016
+ this.must("git", ["fetch", "origin", "dev", "main"]);
144017
+ if (!this.isAncestor(devMerge, sha)) fail6(`PR #${this.state.mainPr} merged into main at ${sha.slice(0, 12)}, which does not contain the dev merge ${devMerge.slice(0, 12)}`);
144018
+ this.save({ mainMergeSha: sha });
144019
+ return { status: "ok", note: `PR #${this.state.mainPr} merged into main at ${sha.slice(0, 12)}` };
144020
+ }
144021
+ rerunBudget = {
144022
+ count: (id) => this.state.reruns[id] ?? 0,
144023
+ record: (id) => this.save({ reruns: { ...this.state.reruns, [id]: (this.state.reruns[id] ?? 0) + 1 } })
144024
+ };
144025
+ runAttempt(runId) {
144026
+ return JSON.parse(this.must("gh", ["run", "view", runId, "--json", "attempt"]) || "{}").attempt ?? 0;
144027
+ }
144028
+ /**
144029
+ * Rerun each failed run once (budget spent first) and wait until its new
144030
+ * attempt exists: right after `gh run rerun` the run still reads as the old
144031
+ * failed attempt. True when any rerun was issued.
144032
+ */
144033
+ async rerunOnce(runIds, phase, pollMs) {
144034
+ const ready = runIds.filter((id) => this.rerunBudget.count(id) < 1);
144035
+ for (const id of ready) {
144036
+ const before = this.runAttempt(id);
144037
+ this.rerunBudget.record(id);
144038
+ this.deps.log(` gh run rerun ${id} --failed (the one automatic rerun)`);
144039
+ this.must("gh", ["run", "rerun", id, "--failed"]);
144040
+ for (let polls = 0; this.runAttempt(id) <= before; polls++) {
144041
+ if (polls >= RERUN_START_POLLS || this.deps.now() >= this.deadline) {
144042
+ blocked(`run ${id} was rerun but attempt ${before + 1} has not started; re-run omg release ${this.v} --from ${phase}`);
144043
+ }
144044
+ await this.deps.sleep(pollMs);
144045
+ }
144046
+ }
144047
+ return ready.length > 0;
144048
+ }
144049
+ failingTestsOfJob(jobId) {
144050
+ const log3 = this.run("gh", ["run", "view", "--job", jobId, "--log"]);
144051
+ return log3.status === 0 ? parseFailingTests(log3.stdout).map((t) => t.title ? `${t.file} > ${t.title}` : t.file) : [];
144052
+ }
144053
+ gateDetails(report) {
144054
+ const details = report.failed.map((name) => `failed: ${name}`);
144055
+ for (const check2 of report.checks) {
144056
+ if (check2.class !== "failed" || !check2.jobId) continue;
144057
+ for (const t of this.failingTestsOfJob(check2.jobId)) details.push(` ${check2.name}: ${t}`);
144058
+ }
144059
+ return details;
144060
+ }
144061
+ /**
144062
+ * Wait for the PR's checks under the ship merge rule (advisoryChecks never
144063
+ * block; config from loadShipConfig: user config + the base's committed
144064
+ * config), rerun failed runs once, then admin-merge when the owner allows
144065
+ * it; with `expectedHead`, only when the PR head is that commit (an
144066
+ * already-merged PR only when its merge, or the base tip after a follow-up
144067
+ * PR, contains it), with
144068
+ * `requireAncestor`, only when the PR head contains that commit. Returns
144069
+ * the merge commit sha.
144070
+ */
144071
+ async land(pr, base, phase, expectedHead, requireAncestor) {
144072
+ for (let round = 0; ; round++) {
144073
+ if (round >= LAND_ROUNDS) blocked(`PR #${pr} is still not merged after ${LAND_ROUNDS} rounds of waiting and merging; check it on GitHub, then re-run omg release ${this.v} --from ${phase}`);
144074
+ const view = this.viewPr(pr);
144075
+ if (view.state === "MERGED") {
144076
+ const sha = view.mergeCommit?.oid;
144077
+ if (!sha || !FULL_SHA3.test(sha)) fail6(`PR #${pr} is merged but gh reported no merge commit`);
144078
+ if (expectedHead) {
144079
+ this.must("git", ["fetch", "origin", base]);
144080
+ if (!this.isAncestor(expectedHead, sha)) {
144081
+ const tip = `refs/remotes/origin/${base}`;
144082
+ if (this.isAncestor(expectedHead, tip) && this.isAncestor(sha, tip)) return this.git("rev-parse", tip);
144083
+ blocked(`The release PR #${pr} is merged at ${sha.slice(0, 12)} without commit(s) up to ${expectedHead.slice(0, 12)}. Open a follow-up PR into ${base} for the extra commits and re-run omg release ${this.v} --from ${phase} after it merges (the release then proceeds from the ${base} commit that contains HEAD).`);
144084
+ }
144085
+ }
144086
+ return sha;
144087
+ }
144088
+ if (view.state !== "OPEN") fail6(`PR #${pr} is ${view.state}`);
144089
+ if (view.baseRefName !== base) fail6(`PR #${pr} targets ${view.baseRefName}, expected ${base}`);
144090
+ if (view.isDraft) fail6(`PR #${pr} is a draft`);
144091
+ const config2 = this.deps.loadShipConfig({ exec: this.deps.exec, root: this.deps.root, base, baseSha: view.baseRefOid, repoUrl: prRepoUrl(view.url) });
144092
+ const remainingMin = Math.max(0, (this.deadline - this.deps.now()) / 6e4);
144093
+ if (remainingMin <= 0) blocked(`PR #${pr}: CI still pending at the --timeout; re-run omg release ${this.v} --from ${phase}`);
144094
+ const { report, timedOut } = await watchGates({
144095
+ exec: this.deps.exec,
144096
+ pr,
144097
+ config: { ...config2, watchTimeoutMinutes: Math.min(config2.watchTimeoutMinutes || remainingMin, remainingMin) },
144098
+ known: loadBaseKnownFlaky(this.deps.exec, this.deps.root, config2.trustedBaseCommit, config2.knownFlakyFile),
144099
+ cwd: this.deps.root,
144100
+ headSha: view.headRefOid,
144101
+ watch: true,
144102
+ reruns: this.rerunBudget,
144103
+ sleep: this.deps.sleep,
144104
+ now: this.deps.now,
144105
+ onReport: (r) => this.deps.progress({ phase, status: "heartbeat", note: `PR #${pr} gates ${r.verdict}: ${r.pending.length} pending, ${r.failed.length} failed` })
144106
+ });
144107
+ if (report.verdict === "green") {
144108
+ if (expectedHead && view.headRefOid !== expectedHead) {
144109
+ blocked(`PR #${pr} head is ${view.headRefOid.slice(0, 12)}, not local HEAD ${expectedHead.slice(0, 12)}; push or merge until they match, then re-run omg release ${this.v} --from ${phase}`);
144110
+ }
144111
+ if (requireAncestor) {
144112
+ this.must("git", ["fetch", "origin", "dev", base]);
144113
+ if (!this.isAncestor(requireAncestor, view.headRefOid)) {
144114
+ blocked(`PR #${pr} head ${view.headRefOid.slice(0, 12)} does not contain ${requireAncestor.slice(0, 12)}; update the PR, then re-run omg release ${this.v} --from ${phase}`);
144115
+ }
144116
+ }
144117
+ const command = ["pr", "merge", String(pr), "--admin", "--merge", "--match-head-commit", view.headRefOid];
144118
+ if (!config2.allowAdminMerge || !config2.trustedBases.includes(base)) {
144119
+ blocked(`PR #${pr} is green; ship.allowAdminMerge is off or ${base} is not a trusted base, so run the merge yourself, then re-run omg release ${this.v} --from ${phase}`, [`gh ${command.join(" ")}`]);
144120
+ }
144121
+ this.deps.log(` gh ${command.join(" ")}`);
144122
+ this.must("gh", command);
144123
+ continue;
144124
+ }
144125
+ if (report.verdict === "pending" || timedOut) continue;
144126
+ const failedRuns = [...new Set(report.checks.filter((c) => c.class === "failed" && c.runId).map((c) => c.runId))];
144127
+ const finished = failedRuns.filter((id) => !report.checks.some((c) => c.runId === id && c.class === "pending"));
144128
+ if (finished.length < failedRuns.length) {
144129
+ await this.deps.sleep(config2.pollIntervalSeconds * 1e3);
144130
+ continue;
144131
+ }
144132
+ if (await this.rerunOnce(finished, phase, config2.pollIntervalSeconds * 1e3)) continue;
144133
+ fail6(`PR #${pr}: CI failed after the one automatic rerun`, this.gateDetails(report));
144134
+ }
144135
+ }
144136
+ async tag() {
144137
+ const v = this.v;
144138
+ const tag = `v${v}`;
144139
+ const sha = this.state.mainMergeSha;
144140
+ if (!sha || !FULL_SHA3.test(sha)) fail6("no main merge commit recorded; run the promote phase first");
144141
+ const remote = remoteTagTarget(this.git("ls-remote", "--tags", "origin", `refs/tags/${tag}`, `refs/tags/${tag}^{}`), tag);
144142
+ if (remote) {
144143
+ if (remote.annotated && remote.commit === sha) return { status: "ok", note: `${tag} already on origin at ${sha.slice(0, 12)}` };
144144
+ fail6(`${tag} exists on origin at ${remote.commit.slice(0, 12)}${remote.annotated ? "" : " (lightweight)"}, not the main merge commit ${sha.slice(0, 12)}`);
144145
+ }
144146
+ const devMerge = this.state.devMergeSha;
144147
+ if (!devMerge || !FULL_SHA3.test(devMerge)) fail6("no dev merge commit recorded; run the pr phase first");
144148
+ this.must("git", ["fetch", "origin", "dev", "main"]);
144149
+ if (!this.isAncestor(sha, "refs/remotes/origin/main")) fail6(`${sha.slice(0, 12)} is not on origin/main`);
144150
+ if (!this.isAncestor(devMerge, sha)) fail6(`the main merge ${sha.slice(0, 12)} does not contain the dev merge ${devMerge.slice(0, 12)}`);
144151
+ const pkg = this.run("git", ["show", `${sha}:package.json`]);
144152
+ let tagged;
144153
+ try {
144154
+ tagged = JSON.parse(pkg.stdout).version;
144155
+ } catch {
144156
+ tagged = void 0;
144157
+ }
144158
+ if (pkg.status !== 0 || tagged !== v) fail6(`package.json on the main merge ${sha.slice(0, 12)} is ${tagged ?? "unreadable"}, not ${v}`);
144159
+ const local = this.run("git", ["rev-parse", "-q", "--verify", `refs/tags/${tag}`]);
144160
+ if (local.status === 0) {
144161
+ const problem = tagTargetProblem(tag, this.git("cat-file", "-t", `refs/tags/${tag}`), this.git("rev-parse", `refs/tags/${tag}^{}`), sha);
144162
+ if (problem) fail6(`a local ${tag} already exists and ${problem} (an upstream tag fetched by name?); delete it yourself (git tag -d ${tag}) and re-run`);
144163
+ }
144164
+ const smoke = this.state.phases.smoke?.status;
144165
+ const warn = smoke === "ok" ? "" : ` WARNING: the live Tier 2 smoke ${smoke === "skipped" ? "was skipped" : "has not passed"}.`;
144166
+ const action = local.status === 0 ? "Push the existing local" : "Create and push";
144167
+ if (!this.opts.yes && !await this.deps.confirm(`${action} annotated tag ${tag} on main ${sha.slice(0, 12)}? This publishes ${this.pkgName}@${v} to npm.${warn}`)) {
144168
+ blocked(`${tag} not pushed (confirm, or pass --yes)`);
144169
+ }
144170
+ if (local.status !== 0) {
144171
+ this.git("tag", "-a", tag, "-m", tag, sha);
144172
+ const problem = tagTargetProblem(tag, this.git("cat-file", "-t", `refs/tags/${tag}`), this.git("rev-parse", `refs/tags/${tag}^{}`), sha);
144173
+ if (problem) fail6(problem);
144174
+ }
144175
+ this.git("push", "origin", `refs/tags/${tag}:refs/tags/${tag}`);
144176
+ const pushed = remoteTagTarget(this.git("ls-remote", "--tags", "origin", `refs/tags/${tag}`, `refs/tags/${tag}^{}`), tag);
144177
+ if (!pushed?.annotated || pushed.commit !== sha) fail6(`origin's ${tag} does not peel to ${sha.slice(0, 12)} after the push`);
144178
+ return { status: "ok", note: `${tag} pushed on ${sha.slice(0, 12)}` };
144179
+ }
144180
+ async verify() {
144181
+ const v = this.v;
144182
+ const tag = `v${v}`;
144183
+ const sha = this.state.mainMergeSha;
144184
+ if (!sha || !FULL_SHA3.test(sha)) fail6("no main merge commit recorded; run the promote phase first");
144185
+ let run;
144186
+ for (; ; ) {
144187
+ const runs = JSON.parse(this.must("gh", ["run", "list", "--workflow", "ci.yml", "--event", "push", "--commit", sha, "--json", "databaseId,headBranch,headSha,event,status,conclusion", "--limit", "50"]) || "[]");
144188
+ run = runs.filter((r) => r.headBranch === tag && r.headSha === sha && (r.event ?? "push") === "push").sort((a, b) => b.databaseId - a.databaseId)[0];
144189
+ if (run) this.save({ tagRunId: run.databaseId });
144190
+ if (run?.status === "completed") {
144191
+ if (run.conclusion === "success") break;
144192
+ const jobs2 = JSON.parse(this.must("gh", ["run", "view", String(run.databaseId), "--json", "jobs"])).jobs ?? [];
144193
+ const failedJobs = jobs2.filter((j) => j.conclusion && !["success", "skipped"].includes(j.conclusion));
144194
+ const details = () => failedJobs.flatMap((j) => [`failed job: ${j.name}`, ...this.failingTestsOfJob(String(j.databaseId)).map((t) => ` ${t}`)]);
144195
+ if (this.run("npm", ["view", `${this.pkgName}@${v}`, "version"]).stdout.trim() === v) {
144196
+ fail6(`tag run ${run.databaseId} ${run.conclusion}, but ${this.pkgName}@${v} is already on npm: not rerun`, [
144197
+ `npm view ${this.pkgName}@${v} version dist-tags dist.attestations: if live with provenance, do NOT rerun the run`,
144198
+ `create the GitHub Release with the Release Recovery workflow (release.yml, workflow_dispatch: tag=${tag} sha=${sha}) or gh release create ${tag} --title ${tag} --notes-file .github/release-body.md`,
144199
+ `then re-run omg release ${v} --from verify`,
144200
+ ...details()
144201
+ ]);
144202
+ }
144203
+ if (await this.rerunOnce([String(run.databaseId)], "verify", 3e4)) continue;
144204
+ fail6(`tag run ${run.databaseId} ${run.conclusion} after the one automatic rerun`, details());
144205
+ }
144206
+ if (this.deps.now() >= this.deadline) blocked(`tag run for ${tag} ${run ? `still ${run.status}` : "not found yet"}; re-run omg release ${v} --from verify`);
144207
+ this.deps.progress({ phase: "verify", status: "heartbeat", note: run ? `tag run ${run.databaseId} ${run.status}` : `waiting for the ${tag} tag run` });
144208
+ await this.deps.sleep(3e4);
144209
+ }
144210
+ const runId = run.databaseId;
144211
+ const problems = [];
144212
+ const jobs = JSON.parse(this.must("gh", ["run", "view", String(runId), "--json", "jobs"])).jobs ?? [];
144213
+ const smokeJob = jobs.find((j) => j.name === "Copilot smoke (tier 2)");
144214
+ if (smokeJob?.conclusion !== "success") problems.push(`Copilot smoke (tier 2) job: ${smokeJob?.conclusion ?? "not in the tag run"}`);
144215
+ const npm = this.run("npm", ["view", `${this.pkgName}@${v}`, "version", "dist-tags.latest", "dist.attestations", "--json"]);
144216
+ let info = {};
144217
+ try {
144218
+ info = JSON.parse(npm.stdout || "{}");
144219
+ } catch {
144220
+ info = {};
144221
+ }
144222
+ if (npm.status !== 0 || info.version !== v) problems.push(`npm has no ${this.pkgName}@${v} yet (registry propagation can take ~30 min; re-run --from verify)`);
144223
+ if (info["dist-tags.latest"] !== v) problems.push(`npm dist-tags.latest is ${JSON.stringify(info["dist-tags.latest"])}, not ${v}`);
144224
+ if (!info["dist.attestations"]) problems.push("npm reports no dist.attestations (SLSA provenance)");
144225
+ const rel = this.run("gh", ["release", "view", tag, "--json", "tagName,isDraft"]);
144226
+ const relInfo = rel.status === 0 ? JSON.parse(rel.stdout) : null;
144227
+ if (!relInfo || relInfo.tagName !== tag) problems.push(`gh release view ${tag} found no release`);
144228
+ else if (relInfo.isDraft) problems.push(`GitHub Release ${tag} is a draft`);
144229
+ if (problems.length > 0) fail6(`tag run ${runId} is green, but the release is incomplete`, problems);
144230
+ return { status: "ok", note: `${this.pkgName}@${v} is latest with provenance; GitHub Release ${tag} published` };
144231
+ }
144232
+ };
144233
+ function resumePoint(state, from) {
144234
+ if (from) return from;
144235
+ for (const id of PHASES2) {
144236
+ const s = state?.phases[id]?.status;
144237
+ if (s !== "ok" && s !== "skipped") return id;
144238
+ }
144239
+ return null;
144240
+ }
144241
+ async function runRelease(deps, opts) {
144242
+ const v = opts.version;
144243
+ const statePath = releaseStatePath(deps.stateRoot, v);
144244
+ const existing = readReleaseState(deps.stateRoot, v);
144245
+ const start = resumePoint(existing, opts.from);
144246
+ const last = PHASES2.indexOf(opts.to ?? "verify");
144247
+ if (opts.from && PHASES2.indexOf(opts.from) > last) throw new Error(`--from ${opts.from} comes after --to ${opts.to}`);
144248
+ const selected = start === null ? [] : PHASES2.slice(PHASES2.indexOf(start), last + 1);
144249
+ if (opts.dryRun) {
144250
+ return { ok: true, version: v, dryRun: true, statePath, phases: selected.map((id) => ({ id, status: "planned", note: "", steps: phasePlan(id, v, opts) })) };
144251
+ }
144252
+ const release = new Release(deps, opts, existing);
144253
+ const results = [];
144254
+ if (selected.length === 0) {
144255
+ deps.log(`release ${v}: every selected phase is already ok (state ${statePath}); pass --from <phase> to re-run one`);
144256
+ return { ok: true, version: v, dryRun: false, statePath, phases: [] };
144257
+ }
144258
+ const skip = selected[0] === "preflight" ? [] : release.skipProblems(selected[0]);
144259
+ if (skip.length > 0) {
144260
+ const note = `cannot start at ${selected[0]}: ${skip[0]}${skip.length > 1 ? ` (+${skip.length - 1} more)` : ""}; fix it, or re-run the phase with --from (--from preflight starts over)`;
144261
+ deps.progress({ phase: selected[0], status: "blocked", note });
144262
+ deps.log(`[${selected[0]}] blocked: ${note}`);
144263
+ for (const d of skip) deps.log(` ${d}`);
144264
+ return { ok: false, version: v, dryRun: false, statePath, phases: [{ id: selected[0], status: "blocked", note, details: skip }] };
144265
+ }
144266
+ for (const id of selected) {
144267
+ deps.log(`[${id}] ${phasePlan(id, v, opts)[0]}`);
144268
+ deps.progress({ phase: id, status: "start" });
144269
+ const outcome = await release.phase(id);
144270
+ const record2 = { ...outcome, at: new Date(deps.now()).toISOString() };
144271
+ release.save({ phases: { ...release.current.phases, [id]: record2 } });
144272
+ results.push({ id, ...outcome });
144273
+ deps.progress({ phase: id, status: outcome.status === "skipped" ? "ok" : outcome.status, note: outcome.note });
144274
+ deps.log(`[${id}] ${outcome.status}: ${outcome.note}`);
144275
+ for (const d of outcome.details ?? []) deps.log(` ${d}`);
144276
+ if (outcome.status === "fail" || outcome.status === "blocked") {
144277
+ return { ok: false, version: v, dryRun: false, statePath, phases: results };
144278
+ }
144279
+ }
144280
+ deps.progress({ phase: "release", status: "done", note: `${v}: ${selected[0]}..${selected[selected.length - 1]} ok` });
144281
+ return { ok: true, version: v, dryRun: false, statePath, phases: results };
144282
+ }
144283
+
144284
+ // src/release/progress.ts
144285
+ var import_fs157 = require("fs");
144286
+ var import_path188 = require("path");
144287
+ var BARE_VALUE = /^[A-Za-z0-9._:/@+,%#~-]+$/;
144288
+ var MAX_NOTE = 500;
144289
+ function quote2(value) {
144290
+ if (BARE_VALUE.test(value)) return value;
144291
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t")}"`;
144292
+ }
144293
+ function formatReleaseProgress(input, at = /* @__PURE__ */ new Date()) {
144294
+ const parts = [at.toISOString(), `phase=${quote2(input.phase)}`, `status=${input.status}`];
144295
+ if (input.note !== void 0) parts.push(`note=${quote2(input.note.slice(0, MAX_NOTE))}`);
144296
+ if (input.agent !== void 0) parts.push(`agent=${quote2(input.agent)}`);
144297
+ return parts.join(" ");
144298
+ }
144299
+ function releaseProgressFile(stateRoot2) {
144300
+ return process.env.OMG_PROGRESS_FILE || (0, import_path188.join)(stateRoot2, "progress", "release.log");
144301
+ }
144302
+ function emitReleaseProgress(input, stateRoot2) {
144303
+ try {
144304
+ const path30 = input.file || releaseProgressFile(stateRoot2);
144305
+ (0, import_fs157.mkdirSync)((0, import_path188.dirname)(path30), { recursive: true });
144306
+ (0, import_fs157.appendFileSync)(path30, `${formatReleaseProgress(input)}
144307
+ `, "utf8");
144308
+ return true;
144309
+ } catch {
144310
+ return false;
144311
+ }
144312
+ }
144313
+
144314
+ // src/cli/commands/release.ts
144315
+ var UsageError2 = class extends Error {
144316
+ };
144317
+ function phaseOption(raw, flag) {
144318
+ if (raw === void 0) return void 0;
144319
+ if (!isPhaseId(raw)) throw new UsageError2(`${flag} must be one of ${PHASES2.join(", ")}, got ${JSON.stringify(raw)}`);
144320
+ return raw;
144321
+ }
144322
+ async function ttyConfirm(question) {
144323
+ if (!process.stdin.isTTY) return false;
144324
+ const rl = (0, import_promises35.createInterface)({ input: process.stdin, output: process.stderr });
144325
+ try {
144326
+ return /^y(?:es)?$/i.test((await rl.question(`${question} [y/N] `)).trim());
144327
+ } finally {
144328
+ rl.close();
144329
+ }
144330
+ }
144331
+ function printResult(result) {
144332
+ if (result.dryRun) {
144333
+ console.log(source_default.bold(`omg release ${result.version} --dry-run: plan only, nothing runs (state ${result.statePath})`));
144334
+ for (const p of result.phases) {
144335
+ console.log(`${source_default.cyan(String(PHASES2.indexOf(p.id) + 1).padStart(2))} ${source_default.bold(p.id)}`);
144336
+ for (const s of p.steps ?? []) console.log(` - ${s}`);
144337
+ }
144338
+ return;
144339
+ }
144340
+ const color = result.ok ? source_default.green : source_default.red;
144341
+ console.log(color(`release ${result.version}: ${result.ok ? "ok" : "stopped"} (state ${result.statePath})`));
144342
+ }
144343
+ function releaseCommand(overrides = {}) {
144344
+ const cmd = new Command("release");
144345
+ cmd.description("Maintainer-only release: preflight, bump, build, gates, smoke, commit, PR to dev, promote to main, tag, verify (resumable)").argument("<version>", "Release version X.Y.Z").option("--from <phase>", `Start at this phase (${PHASES2.join(", ")}); default: the first phase not yet ok`).option("--to <phase>", "Stop after this phase").option("--dry-run", "Print the plan for the selected phases without running anything").option("--json", "JSON output").option("--yes", "Create and push the tag without the interactive confirmation").option("--suite <suite>", "gates vitest suite: none, targeted (related to src changed since the last tag) or full", "none").option("--baseline <file>", 'Full-suite baseline (vitest JSON report or one "<file> > <title>" per line); only new failing titles fail').option("--live-smoke", "Run the live Tier 2 smoke (about 2 premium requests); skipped otherwise").option("--fix-orphans", "Remove tracked dist outputs whose src source is gone").option("--timeout <minutes>", "Minutes the pr / promote / verify phases wait on CI per run", "60").action(async (versionRaw, o) => {
144346
+ const json = Boolean(o.json);
144347
+ try {
144348
+ let version3;
144349
+ try {
144350
+ version3 = parseReleaseVersion(versionRaw);
144351
+ } catch (error2) {
144352
+ throw new UsageError2(error2.message);
144353
+ }
144354
+ if (!["none", "targeted", "full"].includes(o.suite)) throw new UsageError2(`--suite must be none, targeted or full, got ${JSON.stringify(o.suite)}`);
144355
+ if (o.baseline && o.suite !== "full") throw new UsageError2("--baseline needs --suite full");
144356
+ const timeoutMinutes = Number(o.timeout);
144357
+ if (!Number.isFinite(timeoutMinutes) || timeoutMinutes <= 0) throw new UsageError2("--timeout must be a positive number of minutes");
144358
+ const from = phaseOption(o.from, "--from");
144359
+ const to = phaseOption(o.to, "--to");
144360
+ if (from && to && PHASES2.indexOf(from) > PHASES2.indexOf(to)) throw new UsageError2(`--from ${from} comes after --to ${to}`);
144361
+ const exec3 = overrides.exec ?? defaultReleaseExec;
144362
+ const root2 = overrides.root ?? (() => {
144363
+ const r = exec3("git", ["rev-parse", "--show-toplevel"]);
144364
+ if (r.status !== 0) throw new UsageError2("omg release must run inside a git repository");
144365
+ return r.stdout.trim();
144366
+ })();
144367
+ const stateRoot2 = overrides.stateRoot ?? getOmcRoot(root2);
144368
+ const deps = {
144369
+ exec: exec3,
144370
+ root: root2,
144371
+ stateRoot: stateRoot2,
144372
+ node: overrides.node ?? process.execPath,
144373
+ loadShipConfig: overrides.loadShipConfig ?? ((ctx) => loadTrustedShipConfig({ ...ctx, ...userConfigLayers() })),
144374
+ progress: overrides.progress ?? ((event) => {
144375
+ emitReleaseProgress({ agent: "release", ...event }, stateRoot2);
144376
+ }),
144377
+ log: overrides.log ?? ((line) => {
144378
+ if (!json) console.error(line);
144379
+ }),
144380
+ confirm: overrides.confirm ?? ttyConfirm,
144381
+ sleep: overrides.sleep ?? ((ms) => new Promise((resolve58) => setTimeout(resolve58, ms))),
144382
+ now: overrides.now ?? (() => Date.now())
144383
+ };
144384
+ const result = await runRelease(deps, {
144385
+ version: version3,
144386
+ from,
144387
+ to,
144388
+ dryRun: o.dryRun,
144389
+ yes: o.yes,
144390
+ suite: o.suite,
144391
+ baseline: o.baseline,
144392
+ liveSmoke: o.liveSmoke,
144393
+ fixOrphans: o.fixOrphans,
144394
+ timeoutMinutes
144395
+ });
144396
+ if (json) console.log(JSON.stringify(result, null, 2));
144397
+ else printResult(result);
144398
+ process.exitCode = result.ok ? 0 : 1;
144399
+ } catch (error2) {
144400
+ const message2 = error2 instanceof Error ? error2.message : String(error2);
144401
+ if (json) console.log(JSON.stringify({ ok: false, error: message2 }, null, 2));
144402
+ else console.error(source_default.red(`Error: ${message2}`));
144403
+ process.exitCode = error2 instanceof UsageError2 ? 2 : 1;
144404
+ }
144405
+ });
144406
+ return cmd;
144407
+ }
144408
+
144409
+ // src/cli/commands/progress.ts
144410
+ init_esm();
144411
+ var import_fs159 = require("fs");
144412
+ var import_path190 = require("path");
144413
+
144414
+ // src/lib/agent-progress.ts
144415
+ var import_fs158 = require("fs");
144416
+ var import_path189 = require("path");
144417
+ init_worktree_paths();
144418
+ var PROGRESS_STATUSES = ["start", "ok", "fail", "blocked", "heartbeat", "done"];
144419
+ var PROGRESS_FILE_ENV = "OMG_PROGRESS_FILE";
144420
+ var PROGRESS_AGENT_ENV = "OMG_PROGRESS_AGENT";
144421
+ var PROGRESS_MAX_BYTES = 1024 * 1024;
144422
+ var PROGRESS_MAX_NOTE = 500;
144423
+ var PROGRESS_MAX_VALUE = 200;
144424
+ var KEY_RE = /^[A-Za-z][A-Za-z0-9_.-]*$/;
144425
+ var BARE_VALUE_RE = /^[A-Za-z0-9._:/@+,%#~-]+$/;
144426
+ var RESERVED_KEYS = /* @__PURE__ */ new Set(["phase", "status", "note", "agent"]);
144427
+ function isProgressStatus(value) {
144428
+ return PROGRESS_STATUSES.includes(value);
144429
+ }
144430
+ function quoteValue(value) {
144431
+ if (BARE_VALUE_RE.test(value)) return value;
144432
+ const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
144433
+ return `"${escaped}"`;
144434
+ }
144435
+ function formatProgressEvent(event) {
144436
+ const parts = [event.ts, `phase=${quoteValue(event.phase)}`, `status=${event.status}`];
144437
+ if (event.note !== void 0) parts.push(`note=${quoteValue(event.note)}`);
144438
+ if (event.agent !== void 0) parts.push(`agent=${quoteValue(event.agent)}`);
144439
+ for (const [key, value] of Object.entries(event.fields ?? {})) {
144440
+ if (KEY_RE.test(key) && !RESERVED_KEYS.has(key)) parts.push(`${key}=${quoteValue(value)}`);
144441
+ }
144442
+ return parts.join(" ");
144443
+ }
144444
+ function parseProgressLine(line) {
144445
+ const text = line.replace(/\r$/, "");
144446
+ const tsMatch = /^(\d{4}-\d{2}-\d{2}T\S*)/.exec(text);
144447
+ if (!tsMatch || !Number.isFinite(Date.parse(tsMatch[1]))) return null;
144448
+ const pairs = [];
144449
+ let i = tsMatch[1].length;
144450
+ while (i < text.length) {
144451
+ while (text[i] === " " || text[i] === " ") i++;
144452
+ if (i >= text.length) break;
144453
+ const keyMatch = /^([A-Za-z][A-Za-z0-9_.-]*)=/.exec(text.slice(i));
144454
+ if (!keyMatch) return null;
144455
+ i += keyMatch[0].length;
144456
+ let value = "";
144457
+ if (text[i] === '"') {
144458
+ i++;
144459
+ let closed = false;
144460
+ while (i < text.length) {
144461
+ const ch = text[i];
144462
+ if (ch === "\\" && i + 1 < text.length) {
144463
+ const next = text[i + 1];
144464
+ value += next === "n" ? "\n" : next === "r" ? "\r" : next === "t" ? " " : next;
144465
+ i += 2;
144466
+ } else if (ch === '"') {
144467
+ i++;
144468
+ closed = true;
144469
+ break;
144470
+ } else {
144471
+ value += ch;
144472
+ i++;
144473
+ }
144474
+ }
144475
+ if (!closed || i < text.length && text[i] !== " " && text[i] !== " ") return null;
144476
+ } else {
144477
+ const end = text.slice(i).search(/[ \t]/);
144478
+ value = end === -1 ? text.slice(i) : text.slice(i, i + end);
144479
+ i += value.length;
144480
+ }
144481
+ pairs.push([keyMatch[1], value]);
144482
+ }
144483
+ const get = (key) => pairs.find(([k]) => k === key)?.[1];
144484
+ const phase = get("phase");
144485
+ const status = get("status");
144486
+ if (!phase || !status || !(isProgressStatus(status) || status === "stalled")) return null;
144487
+ const fields = {};
144488
+ for (const [k, v] of pairs) if (!RESERVED_KEYS.has(k)) fields[k] = v;
144489
+ const event = { ts: tsMatch[1], phase, status, fields };
144490
+ const note = get("note");
144491
+ const agent = get("agent");
144492
+ if (note !== void 0) event.note = note;
144493
+ if (agent !== void 0) event.agent = agent;
144494
+ return event;
144495
+ }
144496
+ function progressAgentFileName(agent) {
144497
+ return `${agent.replace(/[^A-Za-z0-9._-]/g, "_").replace(/^\.+/, "_") || "agent"}.log`;
144498
+ }
144499
+ function agentFromProgressFile(file) {
144500
+ return (0, import_path189.basename)(file).replace(/\.log$/, "");
144501
+ }
144502
+ function defaultProgressDir(cwd2 = process.cwd()) {
144503
+ return (0, import_path189.join)(getOmcRoot(cwd2), "progress");
144504
+ }
144505
+ function resolveProgressFile(agent, file, cwd2) {
144506
+ return file || process.env[PROGRESS_FILE_ENV] || (0, import_path189.join)(defaultProgressDir(cwd2), progressAgentFileName(agent));
144507
+ }
144508
+ function truncate2(value, max) {
144509
+ return value.length <= max ? value : Array.from(value).slice(0, max).join("");
144510
+ }
144511
+ function rotateIfNeeded2(path30) {
144512
+ try {
144513
+ if ((0, import_fs158.statSync)(path30).size < PROGRESS_MAX_BYTES) return;
144514
+ const claimed = `${path30}.${process.pid}.${Date.now()}.rotating`;
144515
+ (0, import_fs158.renameSync)(path30, claimed);
144516
+ if ((0, import_fs158.statSync)(claimed).size >= PROGRESS_MAX_BYTES) {
144517
+ (0, import_fs158.renameSync)(claimed, `${path30}.1`);
144518
+ } else if (!(0, import_fs158.existsSync)(path30)) {
144519
+ (0, import_fs158.renameSync)(claimed, path30);
144520
+ } else {
144521
+ (0, import_fs158.appendFileSync)(path30, (0, import_fs158.readFileSync)(claimed));
144522
+ (0, import_fs158.unlinkSync)(claimed);
144523
+ }
144524
+ } catch {
144525
+ }
144526
+ }
144527
+ function emitProgress(input) {
144528
+ try {
144529
+ if (!input || typeof input.phase !== "string" || input.phase.length === 0 || !isProgressStatus(input.status)) return false;
144530
+ const agent = input.agent || process.env[PROGRESS_AGENT_ENV] || void 0;
144531
+ const path30 = resolveProgressFile(agent ?? "agent", input.file, input.cwd);
144532
+ const fields = {};
144533
+ for (const [k, v] of Object.entries(input.fields ?? {})) fields[k] = truncate2(String(v), PROGRESS_MAX_VALUE);
144534
+ const line = formatProgressEvent({
144535
+ ts: (input.at ?? /* @__PURE__ */ new Date()).toISOString(),
144536
+ phase: truncate2(input.phase, PROGRESS_MAX_VALUE),
144537
+ status: input.status,
144538
+ note: input.note === void 0 ? void 0 : truncate2(input.note, PROGRESS_MAX_NOTE),
144539
+ agent,
144540
+ fields
144541
+ });
144542
+ (0, import_fs158.mkdirSync)((0, import_path189.dirname)(path30), { recursive: true });
144543
+ rotateIfNeeded2(path30);
144544
+ (0, import_fs158.appendFileSync)(path30, `${line}
144545
+ `, "utf8");
144546
+ return true;
144547
+ } catch {
144548
+ return false;
144549
+ }
144550
+ }
144551
+ function classifyProgress(last, now2, opts) {
144552
+ const idleMs = Math.max(0, now2.getTime() - Date.parse(last.ts));
144553
+ switch (last.status) {
144554
+ case "done":
144555
+ return { state: "done", idleMs };
144556
+ case "fail":
144557
+ return { state: "failed", idleMs };
144558
+ case "blocked":
144559
+ return { state: "blocked", idleMs };
144560
+ default:
144561
+ return { state: idleMs > opts.stallMs ? "stalled" : "running", idleMs };
144562
+ }
144563
+ }
144564
+ function summarizeProgress(events, now2, opts) {
144565
+ const latest2 = /* @__PURE__ */ new Map();
144566
+ for (const event of events) {
144567
+ if (event.status === "stalled") continue;
144568
+ const agent = event.agent ?? (event.source ? agentFromProgressFile(event.source) : "agent");
144569
+ const prev = latest2.get(agent);
144570
+ if (!prev || Date.parse(event.ts) >= Date.parse(prev.ts)) latest2.set(agent, event);
144571
+ }
144572
+ return [...latest2.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([agent, last]) => ({ agent, last, ...classifyProgress(last, now2, opts) }));
144573
+ }
144574
+ function parseProgressDuration(raw, defaultUnit = "m") {
144575
+ const match = /^(\d+(?:\.\d+)?)(ms|s|m|h)?$/.exec(raw.trim());
144576
+ if (!match) return null;
144577
+ const unit = match[2] ?? defaultUnit;
144578
+ const factor = unit === "ms" ? 1 : unit === "s" ? 1e3 : unit === "m" ? 6e4 : 36e5;
144579
+ return Number(match[1]) * factor;
144580
+ }
144581
+ function formatProgressDuration(ms) {
144582
+ const s = Math.floor(ms / 1e3);
144583
+ if (s < 60) return `${s}s`;
144584
+ const m = Math.floor(s / 60);
144585
+ if (m < 60) return `${m}m`;
144586
+ return `${Math.floor(m / 60)}h${m % 60 ? `${m % 60}m` : ""}`;
144587
+ }
144588
+
144589
+ // src/cli/commands/progress.ts
144590
+ var UsageError3 = class extends Error {
144591
+ };
144592
+ var defaultDeps = {
144593
+ now: () => /* @__PURE__ */ new Date(),
144594
+ sleep: (ms) => new Promise((resolve58) => setTimeout(resolve58, ms)),
144595
+ out: (line) => process.stdout.write(`${line}
144596
+ `),
144597
+ err: (line) => process.stderr.write(`${line}
144598
+ `),
144599
+ cwd: () => process.cwd()
144600
+ };
144601
+ function resolveSources(o, cwd2) {
144602
+ if (o.file.length > 0) return { files: o.file, dir: null };
144603
+ if (o.dir) return { files: null, dir: o.dir };
144604
+ const envFile = process.env[PROGRESS_FILE_ENV];
144605
+ if (envFile) return { files: [envFile], dir: null };
144606
+ return { files: null, dir: defaultProgressDir(cwd2) };
144607
+ }
144608
+ function listSources(sources) {
144609
+ if (sources.files) return sources.files;
144610
+ try {
144611
+ return (0, import_fs159.readdirSync)(sources.dir).filter((name) => name.endsWith(".log")).sort().map((name) => (0, import_path190.join)(sources.dir, name));
144612
+ } catch {
144613
+ return [];
144614
+ }
144615
+ }
144616
+ function parseStall(raw) {
144617
+ const ms = parseProgressDuration(raw, "m");
144618
+ if (ms === null || ms <= 0) throw new UsageError3(`--stall must be a positive duration like 10m, 90s or 1h, got ${JSON.stringify(raw)}`);
144619
+ return ms;
144620
+ }
144621
+ function parseInterval(raw) {
144622
+ const ms = parseProgressDuration(raw, "ms");
144623
+ if (ms === null || ms < 50) throw new UsageError3(`--interval must be at least 50ms, got ${JSON.stringify(raw)}`);
144624
+ return ms;
144625
+ }
144626
+ function parseUntil(raw) {
144627
+ if (raw !== "done" && raw !== "settled") throw new UsageError3(`--until must be done or settled, got ${JSON.stringify(raw)}`);
144628
+ return raw;
144629
+ }
144630
+ function parseSince(raw, now2) {
144631
+ const ms = parseProgressDuration(raw, "m");
144632
+ if (ms !== null) return now2.getTime() - ms;
144633
+ const at = /^\d{4}-\d{2}-\d{2}T/.test(raw) ? Date.parse(raw) : NaN;
144634
+ if (!Number.isFinite(at)) throw new UsageError3(`--since must be an ISO-8601 time or a duration like 2h, got ${JSON.stringify(raw)}`);
144635
+ return at;
144636
+ }
144637
+ function parseAgents(raw) {
144638
+ const agents = raw.split(",").map((a) => a.trim()).filter(Boolean);
144639
+ if (agents.length === 0) throw new UsageError3(`--agents must list agent names like lane-1,lane-2, got ${JSON.stringify(raw)}`);
144640
+ return agents;
144641
+ }
144642
+ var newTail = () => ({ offset: 0, rest: Buffer.alloc(0), ino: 0, birthtimeMs: 0 });
144643
+ function readFrom(path30, offset, size) {
144644
+ if (size <= offset) return Buffer.alloc(0);
144645
+ const fd = (0, import_fs159.openSync)(path30, "r");
144646
+ try {
144647
+ const chunk = Buffer.alloc(size - offset);
144648
+ return chunk.subarray(0, (0, import_fs159.readSync)(fd, chunk, 0, chunk.length, offset));
144649
+ } finally {
144650
+ (0, import_fs159.closeSync)(fd);
144651
+ }
144652
+ }
144653
+ function tryStat(path30) {
144654
+ try {
144655
+ return (0, import_fs159.statSync)(path30);
144656
+ } catch {
144657
+ return null;
144658
+ }
144659
+ }
144660
+ function readNewLines(path30, tail3, flush) {
144661
+ const st = tryStat(path30);
144662
+ if (!st) return [];
144663
+ const lines3 = [];
144664
+ const known = tail3.ino !== 0 || tail3.birthtimeMs !== 0;
144665
+ const replaced = known && (tail3.ino !== 0 && st.ino !== 0 ? st.ino !== tail3.ino : st.birthtimeMs !== tail3.birthtimeMs);
144666
+ if (replaced || st.size < tail3.offset) {
144667
+ const old = tryStat(`${path30}.1`);
144668
+ const isOldFile = old !== null && (known ? replaced && (tail3.ino !== 0 ? old.ino === tail3.ino : old.birthtimeMs === tail3.birthtimeMs) : old.size >= tail3.offset);
144669
+ if (isOldFile) {
144670
+ try {
144671
+ lines3.push(...Buffer.concat([tail3.rest, readFrom(`${path30}.1`, tail3.offset, old.size)]).toString("utf8").split("\n"));
144672
+ } catch {
144673
+ }
144674
+ }
144675
+ tail3.offset = 0;
144676
+ tail3.rest = Buffer.alloc(0);
144677
+ }
144678
+ tail3.ino = st.ino;
144679
+ tail3.birthtimeMs = st.birthtimeMs;
144680
+ let chunk;
144681
+ try {
144682
+ chunk = readFrom(path30, tail3.offset, st.size);
144683
+ } catch {
144684
+ return lines3;
144685
+ }
144686
+ tail3.offset += chunk.length;
144687
+ const data = Buffer.concat([tail3.rest, chunk]);
144688
+ const lastNewline = data.lastIndexOf(10);
144689
+ const complete = lastNewline === -1 ? Buffer.alloc(0) : data.subarray(0, lastNewline);
144690
+ tail3.rest = lastNewline === -1 ? data : data.subarray(lastNewline + 1);
144691
+ if (lastNewline !== -1) lines3.push(...complete.toString("utf8").split("\n"));
144692
+ if (flush && tail3.rest.length > 0) {
144693
+ lines3.push(tail3.rest.toString("utf8"));
144694
+ tail3.rest = Buffer.alloc(0);
144695
+ }
144696
+ return lines3;
144697
+ }
144698
+ function withAgent(event, path30) {
144699
+ return event.agent ? event : { ...event, agent: agentFromProgressFile(path30) };
144700
+ }
144701
+ function stalledLine(summary, now2) {
144702
+ const idle = formatProgressDuration(summary.idleMs);
144703
+ return formatProgressEvent({
144704
+ ts: now2.toISOString(),
144705
+ phase: summary.last.phase,
144706
+ status: "stalled",
144707
+ note: `no event for ${idle} after status=${summary.last.status}`,
144708
+ agent: summary.agent,
144709
+ fields: { idle, last_ts: summary.last.ts }
144710
+ });
144711
+ }
144712
+ function pendingLine(agent, idleMs, now2) {
144713
+ const idle = formatProgressDuration(idleMs);
144714
+ return formatProgressEvent({
144715
+ ts: now2.toISOString(),
144716
+ phase: "pending",
144717
+ status: "stalled",
144718
+ note: `no event for ${idle} since the watch started`,
144719
+ agent,
144720
+ fields: { idle }
144721
+ });
144722
+ }
144723
+ async function watchProgress(o, deps) {
144724
+ const sources = resolveSources(o, deps.cwd());
144725
+ const tails = /* @__PURE__ */ new Map();
144726
+ const latest2 = /* @__PURE__ */ new Map();
144727
+ const fresh = /* @__PURE__ */ new Set();
144728
+ const freshFiles = /* @__PURE__ */ new Set();
144729
+ const reportedStalls = /* @__PURE__ */ new Set();
144730
+ const reportedPending = /* @__PURE__ */ new Set();
144731
+ const pendingSince = o.sinceMs ?? deps.now().getTime();
144732
+ const reached = (s) => s !== void 0 && (s.state === "done" || o.until === "settled" && (s.state === "failed" || s.state === "blocked"));
144733
+ let first = true;
144734
+ for (; ; ) {
144735
+ const paths = listSources(sources);
144736
+ for (const path30 of paths) {
144737
+ let tail3 = tails.get(path30);
144738
+ if (!tail3) {
144739
+ if (!(0, import_fs159.existsSync)(path30)) continue;
144740
+ tail3 = newTail();
144741
+ tails.set(path30, tail3);
144742
+ }
144743
+ for (const line of readNewLines(path30, tail3, o.once)) {
144744
+ const parsed = parseProgressLine(line);
144745
+ if (!parsed || parsed.status === "stalled") continue;
144746
+ const event = withAgent(parsed, path30);
144747
+ const prev = latest2.get(event.agent);
144748
+ if (!prev || Date.parse(event.ts) >= Date.parse(prev.ts)) latest2.set(event.agent, event);
144749
+ if (!first || o.replay || o.sinceMs !== void 0 && Date.parse(event.ts) >= o.sinceMs) {
144750
+ fresh.add(event.agent);
144751
+ freshFiles.add(path30);
144752
+ }
144753
+ if (!first || o.replay) deps.out(formatProgressEvent(event));
144754
+ }
144755
+ }
144756
+ const now2 = deps.now();
144757
+ const summaries = new Map(summarizeProgress([...latest2.values()], now2, { stallMs: o.stallMs }).map((s) => [s.agent, s]));
144758
+ for (const s of summaries.values()) {
144759
+ const key = `${s.agent}\0${s.last.ts}\0${s.last.phase}\0${s.last.status}`;
144760
+ const tracked2 = first || fresh.has(s.agent) || o.agents.includes(s.agent);
144761
+ if (s.state === "stalled" && tracked2 && !reportedStalls.has(key)) {
144762
+ reportedStalls.add(key);
144763
+ deps.out(stalledLine(s, now2));
144764
+ } else if (first && !o.replay && (s.state === "failed" || s.state === "blocked")) {
144765
+ deps.out(formatProgressEvent(s.last));
144766
+ }
144767
+ }
144768
+ for (const agent of o.agents) {
144769
+ if (fresh.has(agent) || reportedPending.has(agent) || summaries.get(agent)?.state === "stalled") continue;
144770
+ const idleMs = Math.max(0, now2.getTime() - pendingSince);
144771
+ if (idleMs > o.stallMs) {
144772
+ reportedPending.add(agent);
144773
+ deps.out(pendingLine(agent, idleMs, now2));
144774
+ }
144775
+ }
144776
+ first = false;
144777
+ if (o.once) return 0;
144778
+ const tracked = /* @__PURE__ */ new Set([...fresh, ...o.agents]);
144779
+ const filesReady = !sources.files || sources.files.every((f) => freshFiles.has(f));
144780
+ if (tracked.size > 0 && filesReady && [...tracked].every((a) => fresh.has(a) && reached(summaries.get(a)))) return 0;
144781
+ await deps.sleep(o.intervalMs);
144782
+ }
144783
+ }
144784
+ function readAllEvents(sources) {
144785
+ const events = [];
144786
+ for (const path30 of listSources(sources)) {
144787
+ for (const line of readNewLines(path30, newTail(), true)) {
144788
+ const parsed = parseProgressLine(line);
144789
+ if (parsed) events.push(withAgent(parsed, path30));
144790
+ }
144791
+ }
144792
+ return events;
144793
+ }
144794
+ function collect(value, previous) {
144795
+ return [...previous, value];
144796
+ }
144797
+ async function guarded3(deps, fn) {
144798
+ try {
144799
+ process.exitCode = await fn();
144800
+ } catch (error2) {
144801
+ deps.err(`Error: ${error2 instanceof Error ? error2.message : String(error2)}`);
144802
+ process.exitCode = error2 instanceof UsageError3 ? 2 : 1;
144803
+ }
144804
+ }
144805
+ function progressCommand(overrides = {}) {
144806
+ const deps = { ...defaultDeps, ...overrides };
144807
+ const cmd = new Command("progress");
144808
+ cmd.description("Agent progress events: emit phase events, watch them (stall detection) for the Monitor tool, show status");
144809
+ cmd.command("emit <phase> <status>").description("Append one event (status: start|ok|fail|blocked|heartbeat|done) to $OMG_PROGRESS_FILE or <state root>/progress/<agent>.log").option("--note <text>", "Short note (quoted and escaped as needed; truncated at 500 code points)").option("--agent <name>", 'Agent name (default $OMG_PROGRESS_AGENT, else "agent")').option("--file <path>", "Log file (wins over $OMG_PROGRESS_FILE)").option("--field <key=value>", "Extra key=value pair (repeatable)", collect, []).action((phase, status, o) => guarded3(deps, () => {
144810
+ if (!isProgressStatus(status)) throw new UsageError3(`status must be one of start|ok|fail|blocked|heartbeat|done, got ${JSON.stringify(status)}`);
144811
+ if (phase.trim().length === 0) throw new UsageError3("phase must not be empty");
144812
+ const fields = {};
144813
+ for (const raw of o.field) {
144814
+ const eq2 = raw.indexOf("=");
144815
+ const key = eq2 === -1 ? "" : raw.slice(0, eq2);
144816
+ if (!/^[A-Za-z][A-Za-z0-9_.-]*$/.test(key) || ["phase", "status", "note", "agent"].includes(key)) {
144817
+ throw new UsageError3(`--field must be key=value with a key like build_id (not phase/status/note/agent), got ${JSON.stringify(raw)}`);
144818
+ }
144819
+ fields[key] = raw.slice(eq2 + 1);
144820
+ }
144821
+ const ok = emitProgress({ phase, status, note: o.note, agent: o.agent, file: o.file, fields, at: deps.now(), cwd: deps.cwd() });
144822
+ if (!ok) deps.err("omg progress: could not write the progress event (continuing)");
144823
+ return 0;
144824
+ }));
144825
+ cmd.command("watch").description("Stream new events and synthesized status=stalled lines (one per line); exits when every agent with a new event (and every --agents name) is done").option("--file <path>", "Watch this log (repeatable; may not exist yet; each needs one new event before the watch can exit)", collect, []).option("--dir <path>", "Watch every *.log in this directory, including files created later").option("--agents <names>", "Comma-separated agents to wait for, even before their logs exist (stalled after --stall without an event)").option("--until <state>", "Exit when every tracked agent is done, or settled (done, failed or blocked)", "done").option("--since <time>", "Existing events at or after this ISO time or duration ago (e.g. 2h) count as new for exiting").option("--stall <duration>", "Silence after start/heartbeat/ok that counts as a stall (bare number = minutes)", "10m").option("--interval <duration>", "Poll interval (bare number = ms)", "1000").option("--replay", "Also print the events already in the logs (and count them as new)").option("--once", "Read what exists, report it, and exit").action((o) => guarded3(deps, () => watchProgress({
144826
+ file: o.file,
144827
+ dir: o.dir,
144828
+ stallMs: parseStall(o.stall),
144829
+ intervalMs: parseInterval(o.interval),
144830
+ once: Boolean(o.once),
144831
+ replay: Boolean(o.replay),
144832
+ until: parseUntil(o.until),
144833
+ sinceMs: o.since === void 0 ? void 0 : parseSince(o.since, deps.now()),
144834
+ agents: o.agents === void 0 ? [] : parseAgents(o.agents)
144835
+ }, deps)));
144836
+ cmd.command("status").description("Show each agent's latest event and state (running|stalled|failed|blocked|done)").option("--file <path>", "Read this log (repeatable)", collect, []).option("--dir <path>", "Read every *.log in this directory").option("--stall <duration>", "Stall threshold (bare number = minutes)", "10m").option("--json", "JSON output").action((o) => guarded3(deps, () => {
144837
+ const stallMs = parseStall(o.stall);
144838
+ const summaries = summarizeProgress(readAllEvents(resolveSources(o, deps.cwd())), deps.now(), { stallMs });
144839
+ if (o.json) {
144840
+ deps.out(JSON.stringify(summaries, null, 2));
144841
+ return 0;
144842
+ }
144843
+ if (summaries.length === 0) {
144844
+ deps.out("no progress events");
144845
+ return 0;
144846
+ }
144847
+ const rows = [["AGENT", "STATE", "PHASE", "STATUS", "IDLE", "NOTE"], ...summaries.map((s) => [
144848
+ s.agent,
144849
+ s.state,
144850
+ s.last.phase,
144851
+ s.last.status,
144852
+ formatProgressDuration(s.idleMs),
144853
+ s.last.note ?? ""
144854
+ ])];
144855
+ const widths = rows[0].map((_, i) => Math.max(...rows.map((r) => r[i].length)));
144856
+ for (const r of rows) deps.out(r.map((cell, i) => i === r.length - 1 ? cell : cell.padEnd(widths[i])).join(" ").trimEnd());
144857
+ return 0;
144858
+ }));
144859
+ return cmd;
144860
+ }
144861
+
142998
144862
  // src/cli/win32-warning.ts
142999
144863
  init_source();
143000
144864
  init_tmux_utils();
@@ -143228,8 +145092,8 @@ Examples:
143228
145092
  console.log(` User: ${paths.user}`);
143229
145093
  console.log(` Project: ${paths.project}`);
143230
145094
  console.log(source_default.blue("\nFile status:"));
143231
- console.log(` User: ${(0, import_fs162.existsSync)(paths.user) ? source_default.green("exists") : source_default.gray("not found")}`);
143232
- console.log(` Project: ${(0, import_fs162.existsSync)(paths.project) ? source_default.green("exists") : source_default.gray("not found")}`);
145095
+ console.log(` User: ${(0, import_fs166.existsSync)(paths.user) ? source_default.green("exists") : source_default.gray("not found")}`);
145096
+ console.log(` Project: ${(0, import_fs166.existsSync)(paths.project) ? source_default.green("exists") : source_default.gray("not found")}`);
143233
145097
  return;
143234
145098
  }
143235
145099
  const config2 = loadConfig();
@@ -143272,7 +145136,7 @@ Profile types (use with --profile):
143272
145136
  webhook Generic webhook (POST with JSON body)
143273
145137
 
143274
145138
  Examples:
143275
- $ omg config-stop-callback file --enable --path ${(0, import_path192.join)(getCopilotConfigDir(), "logs/{date}.md")}
145139
+ $ omg config-stop-callback file --enable --path ${(0, import_path196.join)(getCopilotConfigDir(), "logs/{date}.md")}
143276
145140
  $ omg config-stop-callback telegram --enable --token <token> --chat <id>
143277
145141
  $ omg config-stop-callback discord --enable --webhook <url>
143278
145142
  $ omg config-stop-callback file --disable
@@ -143398,7 +145262,7 @@ Examples:
143398
145262
  }
143399
145263
  config3.notificationProfiles[profileName] = profile;
143400
145264
  try {
143401
- (0, import_fs162.writeFileSync)(CONFIG_FILE, JSON.stringify(config3, null, 2), "utf-8");
145265
+ (0, import_fs166.writeFileSync)(CONFIG_FILE, JSON.stringify(config3, null, 2), "utf-8");
143402
145266
  console.log(source_default.green(`\u2713 Profile "${profileName}" \u2014 ${type} configured`));
143403
145267
  console.log(JSON.stringify(profile[type], null, 2));
143404
145268
  } catch (error2) {
@@ -143457,7 +145321,7 @@ Examples:
143457
145321
  const current = config2.stopHookCallbacks.file;
143458
145322
  config2.stopHookCallbacks.file = {
143459
145323
  enabled: enabled ?? current?.enabled ?? false,
143460
- path: options.path ?? current?.path ?? (0, import_path192.join)(getCopilotConfigDir(), "session-logs/{session_id}.md"),
145324
+ path: options.path ?? current?.path ?? (0, import_path196.join)(getCopilotConfigDir(), "session-logs/{session_id}.md"),
143461
145325
  format: options.format ?? current?.format ?? "markdown"
143462
145326
  };
143463
145327
  break;
@@ -143511,7 +145375,7 @@ Examples:
143511
145375
  }
143512
145376
  }
143513
145377
  try {
143514
- (0, import_fs162.writeFileSync)(CONFIG_FILE, JSON.stringify(config2, null, 2), "utf-8");
145378
+ (0, import_fs166.writeFileSync)(CONFIG_FILE, JSON.stringify(config2, null, 2), "utf-8");
143515
145379
  console.log(source_default.green(`\u2713 Stop callback '${type}' configured`));
143516
145380
  console.log(JSON.stringify(config2.stopHookCallbacks[type], null, 2));
143517
145381
  } catch (error2) {
@@ -143573,7 +145437,7 @@ Active profile (OMC_NOTIFY_PROFILE): ${activeProfile}`));
143573
145437
  delete config2.notificationProfiles;
143574
145438
  }
143575
145439
  try {
143576
- (0, import_fs162.writeFileSync)(CONFIG_FILE, JSON.stringify(config2, null, 2), "utf-8");
145440
+ (0, import_fs166.writeFileSync)(CONFIG_FILE, JSON.stringify(config2, null, 2), "utf-8");
143577
145441
  console.log(source_default.green(`\u2713 Profile "${name}" deleted`));
143578
145442
  } catch (error2) {
143579
145443
  console.error(source_default.red("Failed to write configuration:"), error2);
@@ -143991,7 +145855,7 @@ Exit code 1 means budget.hardLimit is reached. Configure limits in .copilot/omg.
143991
145855
  process.exit(exitCode);
143992
145856
  });
143993
145857
  var smokeCmd = program2.command("smoke").description("Smoke-test the plugin inside a real host CLI");
143994
- smokeCmd.command("copilot").description("Load-check oh-my-copilot in GitHub Copilot CLI (tier 0: no model call; tier 1: one cheap live session; tier 2: SDK-driven scenarios)").option("--tier <0|1|2>", "Tier 0 = static/load checks only; tier 1 adds one -p session; tier 2 = tier 0 + SDK static checks + scenarios (default 0, or 2 with --scenario/--sdk-static)").option("--plugin-root <dir>", "Plugin directory to load via --plugin-dir (default: this omg package root)").option("--model <id>", "Tiers 1-2 model id (default: tier 1 lets the CLI auto-pick; tier 2 a cheap listed model, else auto)").option("--max-credits <n>", "Tiers 1-2 AI credit cap (default and minimum 30): tier 1 passes --max-ai-credits; tier 2 also aborts a scenario and skips the rest once the run passes it").option("--timeout <ms>", "Tiers 1-2: tier 1 session timeout (default 180000), tier 2 per-scenario timeout (default 120000, then abort); tier 0 per-subprocess timeout (default 60000); the MCP check is fixed at 10 s").option("--keep-home", "Keep the throwaway COPILOT_HOME and project dir for debugging").option("--delegate", "Tier 1: ask for a delegation to oh-my-copilot:architect and check subagent.selected").option("--scenario <list|all>", "Tier 2 scenarios, comma-separated: smoke, guardrail, skill, delegate, or all (default: smoke,guardrail); chain and team (opt-in, never in all) run a real two-link factory chain and a real 2-worker sdk team").option("--sdk-static", "Tier 2 with no scenarios: SDK static checks only, zero model calls").option("--json", "Print the full SmokeReport as JSON (always, also for option errors)").addHelpText("after", `
145858
+ smokeCmd.command("copilot").description("Load-check oh-my-copilot in GitHub Copilot CLI (tier 0: no model call; tier 1: one cheap live session; tier 2: SDK-driven scenarios)").option("--tier <0|1|2>", "Tier 0 = static/load checks only; tier 1 adds one -p session; tier 2 = tier 0 + SDK static checks + scenarios (default 0, or 2 with --scenario/--sdk-static)").option("--plugin-root <dir>", "Plugin directory to load via --plugin-dir (default: this omg package root)").option("--model <id>", "Tiers 1-2 model id (default: tier 1 lets the CLI auto-pick; tier 2 a cheap listed model, else auto)").option("--max-credits <n>", "Tiers 1-2 AI credit cap (default and minimum 30): tier 1 passes --max-ai-credits; tier 2 also aborts a scenario and skips the rest once the run passes it").option("--timeout <ms>", "Tiers 1-2: tier 1 session timeout (default 180000), tier 2 per-scenario timeout (default 120000, then abort); tier 0 per-subprocess timeout (default 60000); the MCP check is fixed at 10 s").option("--keep-home", "Keep the throwaway COPILOT_HOME and project dir for debugging").option("--delegate", "Tier 1: ask for a delegation to oh-my-copilot:architect and check subagent.selected").option("--scenario <list|all>", "Tier 2 scenarios, comma-separated: smoke, guardrail, skill, delegate, or all (default: smoke,guardrail); filetools, chain and team (opt-in, never in all) check the file-tool hooks, run a real two-link factory chain and a real 2-worker sdk team").option("--sdk-static", "Tier 2 with no scenarios: SDK static checks only, zero model calls").option("--json", "Print the full SmokeReport as JSON (always, also for option errors)").addHelpText("after", `
143995
145859
  Exit codes: 0 all checks ok, 1 a check failed or bad options, 2 skipped (copilot binary or
143996
145860
  @github/copilot-sdk not found, no other failure).
143997
145861
 
@@ -144156,6 +146020,8 @@ program2.addCommand(lookoutCommand());
144156
146020
  program2.addCommand(intakeCommand());
144157
146021
  program2.addCommand(factoryCommand());
144158
146022
  program2.addCommand(shipCommand());
146023
+ program2.addCommand(releaseCommand());
146024
+ program2.addCommand(progressCommand());
144159
146025
  function buildProgram() {
144160
146026
  return program2;
144161
146027
  }