oh-my-codex-pennix 0.18.13

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 (3061) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/Cargo.lock +185 -0
  3. package/Cargo.toml +24 -0
  4. package/README.md +445 -0
  5. package/crates/omx-api/Cargo.toml +19 -0
  6. package/crates/omx-api/src/lib.rs +2997 -0
  7. package/crates/omx-api/src/main.rs +10 -0
  8. package/crates/omx-api/tests/cli.rs +558 -0
  9. package/crates/omx-explore/Cargo.toml +14 -0
  10. package/crates/omx-explore/src/main.rs +2972 -0
  11. package/crates/omx-mux/Cargo.toml +11 -0
  12. package/crates/omx-mux/src/lib.rs +91 -0
  13. package/crates/omx-mux/src/tmux.rs +282 -0
  14. package/crates/omx-mux/src/types.rs +306 -0
  15. package/crates/omx-runtime/Cargo.toml +13 -0
  16. package/crates/omx-runtime/src/main.rs +125 -0
  17. package/crates/omx-runtime/tests/execution.rs +212 -0
  18. package/crates/omx-runtime-core/Cargo.toml +13 -0
  19. package/crates/omx-runtime-core/src/authority.rs +239 -0
  20. package/crates/omx-runtime-core/src/dispatch.rs +330 -0
  21. package/crates/omx-runtime-core/src/engine.rs +853 -0
  22. package/crates/omx-runtime-core/src/lib.rs +653 -0
  23. package/crates/omx-runtime-core/src/mailbox.rs +261 -0
  24. package/crates/omx-runtime-core/src/replay.rs +104 -0
  25. package/crates/omx-sparkshell/Cargo.lock +7 -0
  26. package/crates/omx-sparkshell/Cargo.toml +14 -0
  27. package/crates/omx-sparkshell/src/codex_bridge.rs +768 -0
  28. package/crates/omx-sparkshell/src/error.rs +45 -0
  29. package/crates/omx-sparkshell/src/exec.rs +241 -0
  30. package/crates/omx-sparkshell/src/main.rs +1133 -0
  31. package/crates/omx-sparkshell/src/prompt.rs +364 -0
  32. package/crates/omx-sparkshell/src/redaction.rs +241 -0
  33. package/crates/omx-sparkshell/src/registry/c_cpp.rs +9 -0
  34. package/crates/omx-sparkshell/src/registry/csharp.rs +10 -0
  35. package/crates/omx-sparkshell/src/registry/generic_shell.rs +11 -0
  36. package/crates/omx-sparkshell/src/registry/git.rs +10 -0
  37. package/crates/omx-sparkshell/src/registry/go.rs +9 -0
  38. package/crates/omx-sparkshell/src/registry/java_kotlin.rs +9 -0
  39. package/crates/omx-sparkshell/src/registry/mod.rs +85 -0
  40. package/crates/omx-sparkshell/src/registry/node_js.rs +9 -0
  41. package/crates/omx-sparkshell/src/registry/python.rs +9 -0
  42. package/crates/omx-sparkshell/src/registry/ruby.rs +9 -0
  43. package/crates/omx-sparkshell/src/registry/rust.rs +9 -0
  44. package/crates/omx-sparkshell/src/registry/swift.rs +10 -0
  45. package/crates/omx-sparkshell/src/test_support.rs +10 -0
  46. package/crates/omx-sparkshell/src/threshold.rs +75 -0
  47. package/crates/omx-sparkshell/tests/execution.rs +986 -0
  48. package/crates/omx-sparkshell/tests/registry.rs +99 -0
  49. package/dist/adapt/__tests__/foundation.test.d.ts +2 -0
  50. package/dist/adapt/__tests__/foundation.test.d.ts.map +1 -0
  51. package/dist/adapt/__tests__/foundation.test.js +171 -0
  52. package/dist/adapt/__tests__/foundation.test.js.map +1 -0
  53. package/dist/adapt/__tests__/hermes.test.d.ts +2 -0
  54. package/dist/adapt/__tests__/hermes.test.d.ts.map +1 -0
  55. package/dist/adapt/__tests__/hermes.test.js +137 -0
  56. package/dist/adapt/__tests__/hermes.test.js.map +1 -0
  57. package/dist/adapt/contracts.d.ts +157 -0
  58. package/dist/adapt/contracts.d.ts.map +1 -0
  59. package/dist/adapt/contracts.js +10 -0
  60. package/dist/adapt/contracts.js.map +1 -0
  61. package/dist/adapt/hermes.d.ts +83 -0
  62. package/dist/adapt/hermes.d.ts.map +1 -0
  63. package/dist/adapt/hermes.js +371 -0
  64. package/dist/adapt/hermes.js.map +1 -0
  65. package/dist/adapt/index.d.ts +14 -0
  66. package/dist/adapt/index.d.ts.map +1 -0
  67. package/dist/adapt/index.js +293 -0
  68. package/dist/adapt/index.js.map +1 -0
  69. package/dist/adapt/openclaw.d.ts +7 -0
  70. package/dist/adapt/openclaw.d.ts.map +1 -0
  71. package/dist/adapt/openclaw.js +299 -0
  72. package/dist/adapt/openclaw.js.map +1 -0
  73. package/dist/adapt/paths.d.ts +3 -0
  74. package/dist/adapt/paths.d.ts.map +1 -0
  75. package/dist/adapt/paths.js +15 -0
  76. package/dist/adapt/paths.js.map +1 -0
  77. package/dist/adapt/registry.d.ts +4 -0
  78. package/dist/adapt/registry.d.ts.map +1 -0
  79. package/dist/adapt/registry.js +48 -0
  80. package/dist/adapt/registry.js.map +1 -0
  81. package/dist/agents/__tests__/definitions.test.d.ts +2 -0
  82. package/dist/agents/__tests__/definitions.test.d.ts.map +1 -0
  83. package/dist/agents/__tests__/definitions.test.js +96 -0
  84. package/dist/agents/__tests__/definitions.test.js.map +1 -0
  85. package/dist/agents/__tests__/native-config.test.d.ts +2 -0
  86. package/dist/agents/__tests__/native-config.test.d.ts.map +1 -0
  87. package/dist/agents/__tests__/native-config.test.js +398 -0
  88. package/dist/agents/__tests__/native-config.test.js.map +1 -0
  89. package/dist/agents/definitions.d.ts +35 -0
  90. package/dist/agents/definitions.d.ts.map +1 -0
  91. package/dist/agents/definitions.js +371 -0
  92. package/dist/agents/definitions.js.map +1 -0
  93. package/dist/agents/native-config.d.ts +56 -0
  94. package/dist/agents/native-config.d.ts.map +1 -0
  95. package/dist/agents/native-config.js +285 -0
  96. package/dist/agents/native-config.js.map +1 -0
  97. package/dist/agents/policy.d.ts +10 -0
  98. package/dist/agents/policy.d.ts.map +1 -0
  99. package/dist/agents/policy.js +61 -0
  100. package/dist/agents/policy.js.map +1 -0
  101. package/dist/auth/__tests__/config-sessions.test.d.ts +2 -0
  102. package/dist/auth/__tests__/config-sessions.test.d.ts.map +1 -0
  103. package/dist/auth/__tests__/config-sessions.test.js +48 -0
  104. package/dist/auth/__tests__/config-sessions.test.js.map +1 -0
  105. package/dist/auth/__tests__/quota-rotation.test.d.ts +2 -0
  106. package/dist/auth/__tests__/quota-rotation.test.d.ts.map +1 -0
  107. package/dist/auth/__tests__/quota-rotation.test.js +33 -0
  108. package/dist/auth/__tests__/quota-rotation.test.js.map +1 -0
  109. package/dist/auth/__tests__/redact.test.d.ts +2 -0
  110. package/dist/auth/__tests__/redact.test.d.ts.map +1 -0
  111. package/dist/auth/__tests__/redact.test.js +20 -0
  112. package/dist/auth/__tests__/redact.test.js.map +1 -0
  113. package/dist/auth/__tests__/storage.test.d.ts +2 -0
  114. package/dist/auth/__tests__/storage.test.d.ts.map +1 -0
  115. package/dist/auth/__tests__/storage.test.js +108 -0
  116. package/dist/auth/__tests__/storage.test.js.map +1 -0
  117. package/dist/auth/config.d.ts +9 -0
  118. package/dist/auth/config.d.ts.map +1 -0
  119. package/dist/auth/config.js +77 -0
  120. package/dist/auth/config.js.map +1 -0
  121. package/dist/auth/hotswap.d.ts +36 -0
  122. package/dist/auth/hotswap.d.ts.map +1 -0
  123. package/dist/auth/hotswap.js +159 -0
  124. package/dist/auth/hotswap.js.map +1 -0
  125. package/dist/auth/index.d.ts +8 -0
  126. package/dist/auth/index.d.ts.map +1 -0
  127. package/dist/auth/index.js +8 -0
  128. package/dist/auth/index.js.map +1 -0
  129. package/dist/auth/paths.d.ts +12 -0
  130. package/dist/auth/paths.d.ts.map +1 -0
  131. package/dist/auth/paths.js +78 -0
  132. package/dist/auth/paths.js.map +1 -0
  133. package/dist/auth/quota-detector.d.ts +10 -0
  134. package/dist/auth/quota-detector.d.ts.map +1 -0
  135. package/dist/auth/quota-detector.js +40 -0
  136. package/dist/auth/quota-detector.js.map +1 -0
  137. package/dist/auth/redact.d.ts +2 -0
  138. package/dist/auth/redact.d.ts.map +1 -0
  139. package/dist/auth/redact.js +26 -0
  140. package/dist/auth/redact.js.map +1 -0
  141. package/dist/auth/rotation.d.ts +9 -0
  142. package/dist/auth/rotation.d.ts.map +1 -0
  143. package/dist/auth/rotation.js +26 -0
  144. package/dist/auth/rotation.js.map +1 -0
  145. package/dist/auth/sessions.d.ts +15 -0
  146. package/dist/auth/sessions.d.ts.map +1 -0
  147. package/dist/auth/sessions.js +62 -0
  148. package/dist/auth/sessions.js.map +1 -0
  149. package/dist/auth/storage.d.ts +27 -0
  150. package/dist/auth/storage.d.ts.map +1 -0
  151. package/dist/auth/storage.js +111 -0
  152. package/dist/auth/storage.js.map +1 -0
  153. package/dist/autopilot/__tests__/deep-interview-gate.test.d.ts +2 -0
  154. package/dist/autopilot/__tests__/deep-interview-gate.test.d.ts.map +1 -0
  155. package/dist/autopilot/__tests__/deep-interview-gate.test.js +215 -0
  156. package/dist/autopilot/__tests__/deep-interview-gate.test.js.map +1 -0
  157. package/dist/autopilot/__tests__/fsm.test.d.ts +2 -0
  158. package/dist/autopilot/__tests__/fsm.test.d.ts.map +1 -0
  159. package/dist/autopilot/__tests__/fsm.test.js +78 -0
  160. package/dist/autopilot/__tests__/fsm.test.js.map +1 -0
  161. package/dist/autopilot/__tests__/ralplan-gate.test.d.ts +2 -0
  162. package/dist/autopilot/__tests__/ralplan-gate.test.d.ts.map +1 -0
  163. package/dist/autopilot/__tests__/ralplan-gate.test.js +274 -0
  164. package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -0
  165. package/dist/autopilot/completion-gate.d.ts +10 -0
  166. package/dist/autopilot/completion-gate.d.ts.map +1 -0
  167. package/dist/autopilot/completion-gate.js +154 -0
  168. package/dist/autopilot/completion-gate.js.map +1 -0
  169. package/dist/autopilot/deep-interview-gate.d.ts +18 -0
  170. package/dist/autopilot/deep-interview-gate.d.ts.map +1 -0
  171. package/dist/autopilot/deep-interview-gate.js +396 -0
  172. package/dist/autopilot/deep-interview-gate.js.map +1 -0
  173. package/dist/autopilot/fsm.d.ts +13 -0
  174. package/dist/autopilot/fsm.d.ts.map +1 -0
  175. package/dist/autopilot/fsm.js +70 -0
  176. package/dist/autopilot/fsm.js.map +1 -0
  177. package/dist/autopilot/ralplan-gate.d.ts +17 -0
  178. package/dist/autopilot/ralplan-gate.d.ts.map +1 -0
  179. package/dist/autopilot/ralplan-gate.js +68 -0
  180. package/dist/autopilot/ralplan-gate.js.map +1 -0
  181. package/dist/autoresearch/__tests__/contracts.test.d.ts +2 -0
  182. package/dist/autoresearch/__tests__/contracts.test.d.ts.map +1 -0
  183. package/dist/autoresearch/__tests__/contracts.test.js +127 -0
  184. package/dist/autoresearch/__tests__/contracts.test.js.map +1 -0
  185. package/dist/autoresearch/__tests__/runtime-parity-extra.test.d.ts +2 -0
  186. package/dist/autoresearch/__tests__/runtime-parity-extra.test.d.ts.map +1 -0
  187. package/dist/autoresearch/__tests__/runtime-parity-extra.test.js +349 -0
  188. package/dist/autoresearch/__tests__/runtime-parity-extra.test.js.map +1 -0
  189. package/dist/autoresearch/__tests__/runtime.test.d.ts +2 -0
  190. package/dist/autoresearch/__tests__/runtime.test.d.ts.map +1 -0
  191. package/dist/autoresearch/__tests__/runtime.test.js +211 -0
  192. package/dist/autoresearch/__tests__/runtime.test.js.map +1 -0
  193. package/dist/autoresearch/__tests__/skill-validation.test.d.ts +2 -0
  194. package/dist/autoresearch/__tests__/skill-validation.test.d.ts.map +1 -0
  195. package/dist/autoresearch/__tests__/skill-validation.test.js +91 -0
  196. package/dist/autoresearch/__tests__/skill-validation.test.js.map +1 -0
  197. package/dist/autoresearch/contracts.d.ts +31 -0
  198. package/dist/autoresearch/contracts.d.ts.map +1 -0
  199. package/dist/autoresearch/contracts.js +197 -0
  200. package/dist/autoresearch/contracts.js.map +1 -0
  201. package/dist/autoresearch/goal.d.ts +90 -0
  202. package/dist/autoresearch/goal.d.ts.map +1 -0
  203. package/dist/autoresearch/goal.js +237 -0
  204. package/dist/autoresearch/goal.js.map +1 -0
  205. package/dist/autoresearch/runtime.d.ts +132 -0
  206. package/dist/autoresearch/runtime.d.ts.map +1 -0
  207. package/dist/autoresearch/runtime.js +1022 -0
  208. package/dist/autoresearch/runtime.js.map +1 -0
  209. package/dist/autoresearch/skill-validation.d.ts +14 -0
  210. package/dist/autoresearch/skill-validation.d.ts.map +1 -0
  211. package/dist/autoresearch/skill-validation.js +172 -0
  212. package/dist/autoresearch/skill-validation.js.map +1 -0
  213. package/dist/catalog/__tests__/generator.test.d.ts +2 -0
  214. package/dist/catalog/__tests__/generator.test.d.ts.map +1 -0
  215. package/dist/catalog/__tests__/generator.test.js +60 -0
  216. package/dist/catalog/__tests__/generator.test.js.map +1 -0
  217. package/dist/catalog/__tests__/plugin-bundle-ssot.test.d.ts +2 -0
  218. package/dist/catalog/__tests__/plugin-bundle-ssot.test.d.ts.map +1 -0
  219. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +108 -0
  220. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +1 -0
  221. package/dist/catalog/__tests__/schema.test.d.ts +2 -0
  222. package/dist/catalog/__tests__/schema.test.d.ts.map +1 -0
  223. package/dist/catalog/__tests__/schema.test.js +84 -0
  224. package/dist/catalog/__tests__/schema.test.js.map +1 -0
  225. package/dist/catalog/installable.d.ts +5 -0
  226. package/dist/catalog/installable.d.ts.map +1 -0
  227. package/dist/catalog/installable.js +13 -0
  228. package/dist/catalog/installable.js.map +1 -0
  229. package/dist/catalog/reader.d.ts +19 -0
  230. package/dist/catalog/reader.d.ts.map +1 -0
  231. package/dist/catalog/reader.js +63 -0
  232. package/dist/catalog/reader.js.map +1 -0
  233. package/dist/catalog/schema.d.ts +32 -0
  234. package/dist/catalog/schema.d.ts.map +1 -0
  235. package/dist/catalog/schema.js +107 -0
  236. package/dist/catalog/schema.js.map +1 -0
  237. package/dist/catalog/skill-mirror.d.ts +20 -0
  238. package/dist/catalog/skill-mirror.d.ts.map +1 -0
  239. package/dist/catalog/skill-mirror.js +104 -0
  240. package/dist/catalog/skill-mirror.js.map +1 -0
  241. package/dist/cli/__tests__/adapt-help.test.d.ts +2 -0
  242. package/dist/cli/__tests__/adapt-help.test.d.ts.map +1 -0
  243. package/dist/cli/__tests__/adapt-help.test.js +39 -0
  244. package/dist/cli/__tests__/adapt-help.test.js.map +1 -0
  245. package/dist/cli/__tests__/adapt.test.d.ts +2 -0
  246. package/dist/cli/__tests__/adapt.test.d.ts.map +1 -0
  247. package/dist/cli/__tests__/adapt.test.js +62 -0
  248. package/dist/cli/__tests__/adapt.test.js.map +1 -0
  249. package/dist/cli/__tests__/agents-init.test.d.ts +2 -0
  250. package/dist/cli/__tests__/agents-init.test.d.ts.map +1 -0
  251. package/dist/cli/__tests__/agents-init.test.js +184 -0
  252. package/dist/cli/__tests__/agents-init.test.js.map +1 -0
  253. package/dist/cli/__tests__/agents.test.d.ts +2 -0
  254. package/dist/cli/__tests__/agents.test.d.ts.map +1 -0
  255. package/dist/cli/__tests__/agents.test.js +137 -0
  256. package/dist/cli/__tests__/agents.test.js.map +1 -0
  257. package/dist/cli/__tests__/api.test.d.ts +2 -0
  258. package/dist/cli/__tests__/api.test.d.ts.map +1 -0
  259. package/dist/cli/__tests__/api.test.js +175 -0
  260. package/dist/cli/__tests__/api.test.js.map +1 -0
  261. package/dist/cli/__tests__/ask.test.d.ts +2 -0
  262. package/dist/cli/__tests__/ask.test.d.ts.map +1 -0
  263. package/dist/cli/__tests__/ask.test.js +332 -0
  264. package/dist/cli/__tests__/ask.test.js.map +1 -0
  265. package/dist/cli/__tests__/auth.test.d.ts +2 -0
  266. package/dist/cli/__tests__/auth.test.d.ts.map +1 -0
  267. package/dist/cli/__tests__/auth.test.js +203 -0
  268. package/dist/cli/__tests__/auth.test.js.map +1 -0
  269. package/dist/cli/__tests__/autoresearch-goal.test.d.ts +2 -0
  270. package/dist/cli/__tests__/autoresearch-goal.test.d.ts.map +1 -0
  271. package/dist/cli/__tests__/autoresearch-goal.test.js +207 -0
  272. package/dist/cli/__tests__/autoresearch-goal.test.js.map +1 -0
  273. package/dist/cli/__tests__/autoresearch-guided.test.d.ts +2 -0
  274. package/dist/cli/__tests__/autoresearch-guided.test.d.ts.map +1 -0
  275. package/dist/cli/__tests__/autoresearch-guided.test.js +365 -0
  276. package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -0
  277. package/dist/cli/__tests__/autoresearch.test.d.ts +2 -0
  278. package/dist/cli/__tests__/autoresearch.test.d.ts.map +1 -0
  279. package/dist/cli/__tests__/autoresearch.test.js +155 -0
  280. package/dist/cli/__tests__/autoresearch.test.js.map +1 -0
  281. package/dist/cli/__tests__/catalog-contract.test.d.ts +2 -0
  282. package/dist/cli/__tests__/catalog-contract.test.d.ts.map +1 -0
  283. package/dist/cli/__tests__/catalog-contract.test.js +18 -0
  284. package/dist/cli/__tests__/catalog-contract.test.js.map +1 -0
  285. package/dist/cli/__tests__/cleanup.test.d.ts +2 -0
  286. package/dist/cli/__tests__/cleanup.test.d.ts.map +1 -0
  287. package/dist/cli/__tests__/cleanup.test.js +527 -0
  288. package/dist/cli/__tests__/cleanup.test.js.map +1 -0
  289. package/dist/cli/__tests__/codex-feature-probe.test.d.ts +2 -0
  290. package/dist/cli/__tests__/codex-feature-probe.test.d.ts.map +1 -0
  291. package/dist/cli/__tests__/codex-feature-probe.test.js +46 -0
  292. package/dist/cli/__tests__/codex-feature-probe.test.js.map +1 -0
  293. package/dist/cli/__tests__/codex-plugin-layout.test.d.ts +2 -0
  294. package/dist/cli/__tests__/codex-plugin-layout.test.d.ts.map +1 -0
  295. package/dist/cli/__tests__/codex-plugin-layout.test.js +778 -0
  296. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -0
  297. package/dist/cli/__tests__/doctor-context-window-warning.test.d.ts +2 -0
  298. package/dist/cli/__tests__/doctor-context-window-warning.test.d.ts.map +1 -0
  299. package/dist/cli/__tests__/doctor-context-window-warning.test.js +122 -0
  300. package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -0
  301. package/dist/cli/__tests__/doctor-invalid-config.test.d.ts +2 -0
  302. package/dist/cli/__tests__/doctor-invalid-config.test.d.ts.map +1 -0
  303. package/dist/cli/__tests__/doctor-invalid-config.test.js +52 -0
  304. package/dist/cli/__tests__/doctor-invalid-config.test.js.map +1 -0
  305. package/dist/cli/__tests__/doctor-spark-routing.test.d.ts +2 -0
  306. package/dist/cli/__tests__/doctor-spark-routing.test.d.ts.map +1 -0
  307. package/dist/cli/__tests__/doctor-spark-routing.test.js +79 -0
  308. package/dist/cli/__tests__/doctor-spark-routing.test.js.map +1 -0
  309. package/dist/cli/__tests__/doctor-team.test.d.ts +2 -0
  310. package/dist/cli/__tests__/doctor-team.test.d.ts.map +1 -0
  311. package/dist/cli/__tests__/doctor-team.test.js +299 -0
  312. package/dist/cli/__tests__/doctor-team.test.js.map +1 -0
  313. package/dist/cli/__tests__/doctor-warning-copy.test.d.ts +2 -0
  314. package/dist/cli/__tests__/doctor-warning-copy.test.d.ts.map +1 -0
  315. package/dist/cli/__tests__/doctor-warning-copy.test.js +1312 -0
  316. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -0
  317. package/dist/cli/__tests__/error-handling-warnings.test.d.ts +2 -0
  318. package/dist/cli/__tests__/error-handling-warnings.test.d.ts.map +1 -0
  319. package/dist/cli/__tests__/error-handling-warnings.test.js +52 -0
  320. package/dist/cli/__tests__/error-handling-warnings.test.js.map +1 -0
  321. package/dist/cli/__tests__/exec.test.d.ts +2 -0
  322. package/dist/cli/__tests__/exec.test.d.ts.map +1 -0
  323. package/dist/cli/__tests__/exec.test.js +213 -0
  324. package/dist/cli/__tests__/exec.test.js.map +1 -0
  325. package/dist/cli/__tests__/explore-windows-diagnostics.test.d.ts +2 -0
  326. package/dist/cli/__tests__/explore-windows-diagnostics.test.d.ts.map +1 -0
  327. package/dist/cli/__tests__/explore-windows-diagnostics.test.js +17 -0
  328. package/dist/cli/__tests__/explore-windows-diagnostics.test.js.map +1 -0
  329. package/dist/cli/__tests__/explore.test.d.ts +2 -0
  330. package/dist/cli/__tests__/explore.test.d.ts.map +1 -0
  331. package/dist/cli/__tests__/explore.test.js +104 -0
  332. package/dist/cli/__tests__/explore.test.js.map +1 -0
  333. package/dist/cli/__tests__/hooks.test.d.ts +2 -0
  334. package/dist/cli/__tests__/hooks.test.d.ts.map +1 -0
  335. package/dist/cli/__tests__/hooks.test.js +55 -0
  336. package/dist/cli/__tests__/hooks.test.js.map +1 -0
  337. package/dist/cli/__tests__/imagegen-continuation.test.d.ts +2 -0
  338. package/dist/cli/__tests__/imagegen-continuation.test.d.ts.map +1 -0
  339. package/dist/cli/__tests__/imagegen-continuation.test.js +135 -0
  340. package/dist/cli/__tests__/imagegen-continuation.test.js.map +1 -0
  341. package/dist/cli/__tests__/index.test.d.ts +2 -0
  342. package/dist/cli/__tests__/index.test.d.ts.map +1 -0
  343. package/dist/cli/__tests__/index.test.js +3619 -0
  344. package/dist/cli/__tests__/index.test.js.map +1 -0
  345. package/dist/cli/__tests__/install-docs-contract.test.d.ts +2 -0
  346. package/dist/cli/__tests__/install-docs-contract.test.d.ts.map +1 -0
  347. package/dist/cli/__tests__/install-docs-contract.test.js +55 -0
  348. package/dist/cli/__tests__/install-docs-contract.test.js.map +1 -0
  349. package/dist/cli/__tests__/launch-fallback.test.d.ts +2 -0
  350. package/dist/cli/__tests__/launch-fallback.test.d.ts.map +1 -0
  351. package/dist/cli/__tests__/launch-fallback.test.js +1285 -0
  352. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -0
  353. package/dist/cli/__tests__/lifecycle-notifications.test.d.ts +2 -0
  354. package/dist/cli/__tests__/lifecycle-notifications.test.d.ts.map +1 -0
  355. package/dist/cli/__tests__/lifecycle-notifications.test.js +48 -0
  356. package/dist/cli/__tests__/lifecycle-notifications.test.js.map +1 -0
  357. package/dist/cli/__tests__/list.test.d.ts +2 -0
  358. package/dist/cli/__tests__/list.test.d.ts.map +1 -0
  359. package/dist/cli/__tests__/list.test.js +38 -0
  360. package/dist/cli/__tests__/list.test.js.map +1 -0
  361. package/dist/cli/__tests__/mcp-parity.test.d.ts +2 -0
  362. package/dist/cli/__tests__/mcp-parity.test.d.ts.map +1 -0
  363. package/dist/cli/__tests__/mcp-parity.test.js +228 -0
  364. package/dist/cli/__tests__/mcp-parity.test.js.map +1 -0
  365. package/dist/cli/__tests__/mcp-serve.test.d.ts +2 -0
  366. package/dist/cli/__tests__/mcp-serve.test.d.ts.map +1 -0
  367. package/dist/cli/__tests__/mcp-serve.test.js +68 -0
  368. package/dist/cli/__tests__/mcp-serve.test.js.map +1 -0
  369. package/dist/cli/__tests__/native-assets.test.d.ts +2 -0
  370. package/dist/cli/__tests__/native-assets.test.d.ts.map +1 -0
  371. package/dist/cli/__tests__/native-assets.test.js +296 -0
  372. package/dist/cli/__tests__/native-assets.test.js.map +1 -0
  373. package/dist/cli/__tests__/native-hook-dispatch-contract.test.d.ts +2 -0
  374. package/dist/cli/__tests__/native-hook-dispatch-contract.test.d.ts.map +1 -0
  375. package/dist/cli/__tests__/native-hook-dispatch-contract.test.js +11 -0
  376. package/dist/cli/__tests__/native-hook-dispatch-contract.test.js.map +1 -0
  377. package/dist/cli/__tests__/nested-help-routing.test.d.ts +2 -0
  378. package/dist/cli/__tests__/nested-help-routing.test.d.ts.map +1 -0
  379. package/dist/cli/__tests__/nested-help-routing.test.js +63 -0
  380. package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -0
  381. package/dist/cli/__tests__/package-bin-contract.test.d.ts +2 -0
  382. package/dist/cli/__tests__/package-bin-contract.test.d.ts.map +1 -0
  383. package/dist/cli/__tests__/package-bin-contract.test.js +190 -0
  384. package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -0
  385. package/dist/cli/__tests__/packaged-explore-harness-lock.d.ts +3 -0
  386. package/dist/cli/__tests__/packaged-explore-harness-lock.d.ts.map +1 -0
  387. package/dist/cli/__tests__/packaged-explore-harness-lock.js +67 -0
  388. package/dist/cli/__tests__/packaged-explore-harness-lock.js.map +1 -0
  389. package/dist/cli/__tests__/packaged-script-resolution.test.d.ts +2 -0
  390. package/dist/cli/__tests__/packaged-script-resolution.test.d.ts.map +1 -0
  391. package/dist/cli/__tests__/packaged-script-resolution.test.js +19 -0
  392. package/dist/cli/__tests__/packaged-script-resolution.test.js.map +1 -0
  393. package/dist/cli/__tests__/performance-goal.test.d.ts +2 -0
  394. package/dist/cli/__tests__/performance-goal.test.d.ts.map +1 -0
  395. package/dist/cli/__tests__/performance-goal.test.js +144 -0
  396. package/dist/cli/__tests__/performance-goal.test.js.map +1 -0
  397. package/dist/cli/__tests__/prompt-skill-sanitization.test.d.ts +2 -0
  398. package/dist/cli/__tests__/prompt-skill-sanitization.test.d.ts.map +1 -0
  399. package/dist/cli/__tests__/prompt-skill-sanitization.test.js +48 -0
  400. package/dist/cli/__tests__/prompt-skill-sanitization.test.js.map +1 -0
  401. package/dist/cli/__tests__/question.test.d.ts +2 -0
  402. package/dist/cli/__tests__/question.test.d.ts.map +1 -0
  403. package/dist/cli/__tests__/question.test.js +850 -0
  404. package/dist/cli/__tests__/question.test.js.map +1 -0
  405. package/dist/cli/__tests__/ralph-deslop-contract.test.d.ts +2 -0
  406. package/dist/cli/__tests__/ralph-deslop-contract.test.d.ts.map +1 -0
  407. package/dist/cli/__tests__/ralph-deslop-contract.test.js +28 -0
  408. package/dist/cli/__tests__/ralph-deslop-contract.test.js.map +1 -0
  409. package/dist/cli/__tests__/ralph-goal-mode-contract.test.d.ts +2 -0
  410. package/dist/cli/__tests__/ralph-goal-mode-contract.test.d.ts.map +1 -0
  411. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +49 -0
  412. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -0
  413. package/dist/cli/__tests__/ralph-prd-deep-interview.test.d.ts +2 -0
  414. package/dist/cli/__tests__/ralph-prd-deep-interview.test.d.ts.map +1 -0
  415. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js +25 -0
  416. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +1 -0
  417. package/dist/cli/__tests__/ralph-prd-smoke.test.d.ts +2 -0
  418. package/dist/cli/__tests__/ralph-prd-smoke.test.d.ts.map +1 -0
  419. package/dist/cli/__tests__/ralph-prd-smoke.test.js +174 -0
  420. package/dist/cli/__tests__/ralph-prd-smoke.test.js.map +1 -0
  421. package/dist/cli/__tests__/ralph.test.d.ts +2 -0
  422. package/dist/cli/__tests__/ralph.test.d.ts.map +1 -0
  423. package/dist/cli/__tests__/ralph.test.js +256 -0
  424. package/dist/cli/__tests__/ralph.test.js.map +1 -0
  425. package/dist/cli/__tests__/resume.test.d.ts +2 -0
  426. package/dist/cli/__tests__/resume.test.d.ts.map +1 -0
  427. package/dist/cli/__tests__/resume.test.js +133 -0
  428. package/dist/cli/__tests__/resume.test.js.map +1 -0
  429. package/dist/cli/__tests__/session-scoped-runtime.test.d.ts +2 -0
  430. package/dist/cli/__tests__/session-scoped-runtime.test.d.ts.map +1 -0
  431. package/dist/cli/__tests__/session-scoped-runtime.test.js +247 -0
  432. package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -0
  433. package/dist/cli/__tests__/session-search-help.test.d.ts +2 -0
  434. package/dist/cli/__tests__/session-search-help.test.d.ts.map +1 -0
  435. package/dist/cli/__tests__/session-search-help.test.js +37 -0
  436. package/dist/cli/__tests__/session-search-help.test.js.map +1 -0
  437. package/dist/cli/__tests__/session-search.test.d.ts +2 -0
  438. package/dist/cli/__tests__/session-search.test.d.ts.map +1 -0
  439. package/dist/cli/__tests__/session-search.test.js +77 -0
  440. package/dist/cli/__tests__/session-search.test.js.map +1 -0
  441. package/dist/cli/__tests__/setup-agents-overwrite.test.d.ts +2 -0
  442. package/dist/cli/__tests__/setup-agents-overwrite.test.d.ts.map +1 -0
  443. package/dist/cli/__tests__/setup-agents-overwrite.test.js +776 -0
  444. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -0
  445. package/dist/cli/__tests__/setup-gh-star.test.d.ts +2 -0
  446. package/dist/cli/__tests__/setup-gh-star.test.d.ts.map +1 -0
  447. package/dist/cli/__tests__/setup-gh-star.test.js +67 -0
  448. package/dist/cli/__tests__/setup-gh-star.test.js.map +1 -0
  449. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.d.ts +2 -0
  450. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.d.ts.map +1 -0
  451. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +202 -0
  452. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -0
  453. package/dist/cli/__tests__/setup-install-mode.test.d.ts +2 -0
  454. package/dist/cli/__tests__/setup-install-mode.test.d.ts.map +1 -0
  455. package/dist/cli/__tests__/setup-install-mode.test.js +2103 -0
  456. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -0
  457. package/dist/cli/__tests__/setup-prompts-overwrite.test.d.ts +2 -0
  458. package/dist/cli/__tests__/setup-prompts-overwrite.test.d.ts.map +1 -0
  459. package/dist/cli/__tests__/setup-prompts-overwrite.test.js +191 -0
  460. package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +1 -0
  461. package/dist/cli/__tests__/setup-refresh.test.d.ts +2 -0
  462. package/dist/cli/__tests__/setup-refresh.test.d.ts.map +1 -0
  463. package/dist/cli/__tests__/setup-refresh.test.js +779 -0
  464. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -0
  465. package/dist/cli/__tests__/setup-scope.test.d.ts +2 -0
  466. package/dist/cli/__tests__/setup-scope.test.d.ts.map +1 -0
  467. package/dist/cli/__tests__/setup-scope.test.js +367 -0
  468. package/dist/cli/__tests__/setup-scope.test.js.map +1 -0
  469. package/dist/cli/__tests__/setup-skill-validation.test.d.ts +2 -0
  470. package/dist/cli/__tests__/setup-skill-validation.test.d.ts.map +1 -0
  471. package/dist/cli/__tests__/setup-skill-validation.test.js +44 -0
  472. package/dist/cli/__tests__/setup-skill-validation.test.js.map +1 -0
  473. package/dist/cli/__tests__/setup-skills-overwrite.test.d.ts +2 -0
  474. package/dist/cli/__tests__/setup-skills-overwrite.test.d.ts.map +1 -0
  475. package/dist/cli/__tests__/setup-skills-overwrite.test.js +292 -0
  476. package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -0
  477. package/dist/cli/__tests__/sidecar.test.d.ts +2 -0
  478. package/dist/cli/__tests__/sidecar.test.d.ts.map +1 -0
  479. package/dist/cli/__tests__/sidecar.test.js +24 -0
  480. package/dist/cli/__tests__/sidecar.test.js.map +1 -0
  481. package/dist/cli/__tests__/sparkshell-cli.test.d.ts +2 -0
  482. package/dist/cli/__tests__/sparkshell-cli.test.d.ts.map +1 -0
  483. package/dist/cli/__tests__/sparkshell-cli.test.js +471 -0
  484. package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -0
  485. package/dist/cli/__tests__/sparkshell-packaging.test.d.ts +2 -0
  486. package/dist/cli/__tests__/sparkshell-packaging.test.d.ts.map +1 -0
  487. package/dist/cli/__tests__/sparkshell-packaging.test.js +105 -0
  488. package/dist/cli/__tests__/sparkshell-packaging.test.js.map +1 -0
  489. package/dist/cli/__tests__/star-prompt.test.d.ts +2 -0
  490. package/dist/cli/__tests__/star-prompt.test.d.ts.map +1 -0
  491. package/dist/cli/__tests__/star-prompt.test.js +172 -0
  492. package/dist/cli/__tests__/star-prompt.test.js.map +1 -0
  493. package/dist/cli/__tests__/state.test.d.ts +2 -0
  494. package/dist/cli/__tests__/state.test.d.ts.map +1 -0
  495. package/dist/cli/__tests__/state.test.js +160 -0
  496. package/dist/cli/__tests__/state.test.js.map +1 -0
  497. package/dist/cli/__tests__/team-decompose.test.d.ts +2 -0
  498. package/dist/cli/__tests__/team-decompose.test.d.ts.map +1 -0
  499. package/dist/cli/__tests__/team-decompose.test.js +138 -0
  500. package/dist/cli/__tests__/team-decompose.test.js.map +1 -0
  501. package/dist/cli/__tests__/team.test.d.ts +2 -0
  502. package/dist/cli/__tests__/team.test.d.ts.map +1 -0
  503. package/dist/cli/__tests__/team.test.js +2897 -0
  504. package/dist/cli/__tests__/team.test.js.map +1 -0
  505. package/dist/cli/__tests__/ultragoal.test.d.ts +2 -0
  506. package/dist/cli/__tests__/ultragoal.test.d.ts.map +1 -0
  507. package/dist/cli/__tests__/ultragoal.test.js +599 -0
  508. package/dist/cli/__tests__/ultragoal.test.js.map +1 -0
  509. package/dist/cli/__tests__/uninstall.test.d.ts +2 -0
  510. package/dist/cli/__tests__/uninstall.test.d.ts.map +1 -0
  511. package/dist/cli/__tests__/uninstall.test.js +865 -0
  512. package/dist/cli/__tests__/uninstall.test.js.map +1 -0
  513. package/dist/cli/__tests__/update.test.d.ts +2 -0
  514. package/dist/cli/__tests__/update.test.d.ts.map +1 -0
  515. package/dist/cli/__tests__/update.test.js +1182 -0
  516. package/dist/cli/__tests__/update.test.js.map +1 -0
  517. package/dist/cli/__tests__/version-sync-contract.test.d.ts +2 -0
  518. package/dist/cli/__tests__/version-sync-contract.test.d.ts.map +1 -0
  519. package/dist/cli/__tests__/version-sync-contract.test.js +47 -0
  520. package/dist/cli/__tests__/version-sync-contract.test.js.map +1 -0
  521. package/dist/cli/__tests__/version.test.d.ts +2 -0
  522. package/dist/cli/__tests__/version.test.d.ts.map +1 -0
  523. package/dist/cli/__tests__/version.test.js +21 -0
  524. package/dist/cli/__tests__/version.test.js.map +1 -0
  525. package/dist/cli/__tests__/windows-popup-loop-contract.test.d.ts +2 -0
  526. package/dist/cli/__tests__/windows-popup-loop-contract.test.d.ts.map +1 -0
  527. package/dist/cli/__tests__/windows-popup-loop-contract.test.js +31 -0
  528. package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -0
  529. package/dist/cli/adapt.d.ts +6 -0
  530. package/dist/cli/adapt.d.ts.map +1 -0
  531. package/dist/cli/adapt.js +135 -0
  532. package/dist/cli/adapt.js.map +1 -0
  533. package/dist/cli/agents-init.d.ts +14 -0
  534. package/dist/cli/agents-init.d.ts.map +1 -0
  535. package/dist/cli/agents-init.js +274 -0
  536. package/dist/cli/agents-init.js.map +1 -0
  537. package/dist/cli/agents.d.ts +14 -0
  538. package/dist/cli/agents.d.ts.map +1 -0
  539. package/dist/cli/agents.js +267 -0
  540. package/dist/cli/agents.js.map +1 -0
  541. package/dist/cli/api.d.ts +26 -0
  542. package/dist/cli/api.d.ts.map +1 -0
  543. package/dist/cli/api.js +153 -0
  544. package/dist/cli/api.js.map +1 -0
  545. package/dist/cli/ask.d.ts +13 -0
  546. package/dist/cli/ask.d.ts.map +1 -0
  547. package/dist/cli/ask.js +178 -0
  548. package/dist/cli/ask.js.map +1 -0
  549. package/dist/cli/auth.d.ts +4 -0
  550. package/dist/cli/auth.d.ts.map +1 -0
  551. package/dist/cli/auth.js +113 -0
  552. package/dist/cli/auth.js.map +1 -0
  553. package/dist/cli/autoresearch-goal.d.ts +3 -0
  554. package/dist/cli/autoresearch-goal.d.ts.map +1 -0
  555. package/dist/cli/autoresearch-goal.js +175 -0
  556. package/dist/cli/autoresearch-goal.js.map +1 -0
  557. package/dist/cli/autoresearch-guided.d.ts +43 -0
  558. package/dist/cli/autoresearch-guided.d.ts.map +1 -0
  559. package/dist/cli/autoresearch-guided.js +282 -0
  560. package/dist/cli/autoresearch-guided.js.map +1 -0
  561. package/dist/cli/autoresearch-intake.d.ts +62 -0
  562. package/dist/cli/autoresearch-intake.d.ts.map +1 -0
  563. package/dist/cli/autoresearch-intake.js +336 -0
  564. package/dist/cli/autoresearch-intake.js.map +1 -0
  565. package/dist/cli/autoresearch.d.ts +16 -0
  566. package/dist/cli/autoresearch.d.ts.map +1 -0
  567. package/dist/cli/autoresearch.js +91 -0
  568. package/dist/cli/autoresearch.js.map +1 -0
  569. package/dist/cli/catalog-contract.d.ts +10 -0
  570. package/dist/cli/catalog-contract.d.ts.map +1 -0
  571. package/dist/cli/catalog-contract.js +34 -0
  572. package/dist/cli/catalog-contract.js.map +1 -0
  573. package/dist/cli/cleanup.d.ts +58 -0
  574. package/dist/cli/cleanup.d.ts.map +1 -0
  575. package/dist/cli/cleanup.js +444 -0
  576. package/dist/cli/cleanup.js.map +1 -0
  577. package/dist/cli/codex-feature-probe.d.ts +17 -0
  578. package/dist/cli/codex-feature-probe.d.ts.map +1 -0
  579. package/dist/cli/codex-feature-probe.js +50 -0
  580. package/dist/cli/codex-feature-probe.js.map +1 -0
  581. package/dist/cli/codex-home.d.ts +7 -0
  582. package/dist/cli/codex-home.d.ts.map +1 -0
  583. package/dist/cli/codex-home.js +26 -0
  584. package/dist/cli/codex-home.js.map +1 -0
  585. package/dist/cli/constants.d.ts +11 -0
  586. package/dist/cli/constants.d.ts.map +1 -0
  587. package/dist/cli/constants.js +11 -0
  588. package/dist/cli/constants.js.map +1 -0
  589. package/dist/cli/doctor.d.ts +43 -0
  590. package/dist/cli/doctor.d.ts.map +1 -0
  591. package/dist/cli/doctor.js +1956 -0
  592. package/dist/cli/doctor.js.map +1 -0
  593. package/dist/cli/explore.d.ts +14 -0
  594. package/dist/cli/explore.d.ts.map +1 -0
  595. package/dist/cli/explore.js +72 -0
  596. package/dist/cli/explore.js.map +1 -0
  597. package/dist/cli/hooks.d.ts +4 -0
  598. package/dist/cli/hooks.d.ts.map +1 -0
  599. package/dist/cli/hooks.js +201 -0
  600. package/dist/cli/hooks.js.map +1 -0
  601. package/dist/cli/index.d.ts +247 -0
  602. package/dist/cli/index.d.ts.map +1 -0
  603. package/dist/cli/index.js +4590 -0
  604. package/dist/cli/index.js.map +1 -0
  605. package/dist/cli/list.d.ts +2 -0
  606. package/dist/cli/list.d.ts.map +1 -0
  607. package/dist/cli/list.js +40 -0
  608. package/dist/cli/list.js.map +1 -0
  609. package/dist/cli/mcp-parity.d.ts +22 -0
  610. package/dist/cli/mcp-parity.d.ts.map +1 -0
  611. package/dist/cli/mcp-parity.js +251 -0
  612. package/dist/cli/mcp-parity.js.map +1 -0
  613. package/dist/cli/mcp-serve.d.ts +13 -0
  614. package/dist/cli/mcp-serve.d.ts.map +1 -0
  615. package/dist/cli/mcp-serve.js +75 -0
  616. package/dist/cli/mcp-serve.js.map +1 -0
  617. package/dist/cli/native-assets.d.ts +52 -0
  618. package/dist/cli/native-assets.d.ts.map +1 -0
  619. package/dist/cli/native-assets.js +302 -0
  620. package/dist/cli/native-assets.js.map +1 -0
  621. package/dist/cli/omx.d.ts +3 -0
  622. package/dist/cli/omx.d.ts.map +1 -0
  623. package/dist/cli/omx.js +25 -0
  624. package/dist/cli/omx.js.map +1 -0
  625. package/dist/cli/performance-goal.d.ts +3 -0
  626. package/dist/cli/performance-goal.d.ts.map +1 -0
  627. package/dist/cli/performance-goal.js +186 -0
  628. package/dist/cli/performance-goal.js.map +1 -0
  629. package/dist/cli/plugin-marketplace.d.ts +54 -0
  630. package/dist/cli/plugin-marketplace.d.ts.map +1 -0
  631. package/dist/cli/plugin-marketplace.js +369 -0
  632. package/dist/cli/plugin-marketplace.js.map +1 -0
  633. package/dist/cli/question.d.ts +3 -0
  634. package/dist/cli/question.d.ts.map +1 -0
  635. package/dist/cli/question.js +376 -0
  636. package/dist/cli/question.js.map +1 -0
  637. package/dist/cli/ralph.d.ts +17 -0
  638. package/dist/cli/ralph.d.ts.map +1 -0
  639. package/dist/cli/ralph.js +330 -0
  640. package/dist/cli/ralph.js.map +1 -0
  641. package/dist/cli/session-search.d.ts +8 -0
  642. package/dist/cli/session-search.d.ts.map +1 -0
  643. package/dist/cli/session-search.js +133 -0
  644. package/dist/cli/session-search.js.map +1 -0
  645. package/dist/cli/setup-preferences.d.ts +26 -0
  646. package/dist/cli/setup-preferences.d.ts.map +1 -0
  647. package/dist/cli/setup-preferences.js +82 -0
  648. package/dist/cli/setup-preferences.js.map +1 -0
  649. package/dist/cli/setup.d.ts +60 -0
  650. package/dist/cli/setup.d.ts.map +1 -0
  651. package/dist/cli/setup.js +2748 -0
  652. package/dist/cli/setup.js.map +1 -0
  653. package/dist/cli/sparkshell.d.ts +39 -0
  654. package/dist/cli/sparkshell.d.ts.map +1 -0
  655. package/dist/cli/sparkshell.js +299 -0
  656. package/dist/cli/sparkshell.js.map +1 -0
  657. package/dist/cli/star-prompt.d.ts +31 -0
  658. package/dist/cli/star-prompt.d.ts.map +1 -0
  659. package/dist/cli/star-prompt.js +97 -0
  660. package/dist/cli/star-prompt.js.map +1 -0
  661. package/dist/cli/state.d.ts +8 -0
  662. package/dist/cli/state.d.ts.map +1 -0
  663. package/dist/cli/state.js +149 -0
  664. package/dist/cli/state.js.map +1 -0
  665. package/dist/cli/team.d.ts +49 -0
  666. package/dist/cli/team.d.ts.map +1 -0
  667. package/dist/cli/team.js +1453 -0
  668. package/dist/cli/team.js.map +1 -0
  669. package/dist/cli/tmux-hook.d.ts +3 -0
  670. package/dist/cli/tmux-hook.d.ts.map +1 -0
  671. package/dist/cli/tmux-hook.js +403 -0
  672. package/dist/cli/tmux-hook.js.map +1 -0
  673. package/dist/cli/ultragoal.d.ts +3 -0
  674. package/dist/cli/ultragoal.d.ts.map +1 -0
  675. package/dist/cli/ultragoal.js +494 -0
  676. package/dist/cli/ultragoal.js.map +1 -0
  677. package/dist/cli/uninstall.d.ts +15 -0
  678. package/dist/cli/uninstall.d.ts.map +1 -0
  679. package/dist/cli/uninstall.js +476 -0
  680. package/dist/cli/uninstall.js.map +1 -0
  681. package/dist/cli/update.d.ts +86 -0
  682. package/dist/cli/update.d.ts.map +1 -0
  683. package/dist/cli/update.js +754 -0
  684. package/dist/cli/update.js.map +1 -0
  685. package/dist/cli/version.d.ts +2 -0
  686. package/dist/cli/version.d.ts.map +1 -0
  687. package/dist/cli/version.js +13 -0
  688. package/dist/cli/version.js.map +1 -0
  689. package/dist/compat/__tests__/doctor-contract.test.d.ts +2 -0
  690. package/dist/compat/__tests__/doctor-contract.test.d.ts.map +1 -0
  691. package/dist/compat/__tests__/doctor-contract.test.js +122 -0
  692. package/dist/compat/__tests__/doctor-contract.test.js.map +1 -0
  693. package/dist/compat/__tests__/rust-runtime-compat.test.d.ts +2 -0
  694. package/dist/compat/__tests__/rust-runtime-compat.test.d.ts.map +1 -0
  695. package/dist/compat/__tests__/rust-runtime-compat.test.js +218 -0
  696. package/dist/compat/__tests__/rust-runtime-compat.test.js.map +1 -0
  697. package/dist/config/__tests__/codex-feature-flags.test.d.ts +2 -0
  698. package/dist/config/__tests__/codex-feature-flags.test.d.ts.map +1 -0
  699. package/dist/config/__tests__/codex-feature-flags.test.js +45 -0
  700. package/dist/config/__tests__/codex-feature-flags.test.js.map +1 -0
  701. package/dist/config/__tests__/codex-hooks.test.d.ts +2 -0
  702. package/dist/config/__tests__/codex-hooks.test.d.ts.map +1 -0
  703. package/dist/config/__tests__/codex-hooks.test.js +524 -0
  704. package/dist/config/__tests__/codex-hooks.test.js.map +1 -0
  705. package/dist/config/__tests__/commit-lore-guard.test.d.ts +2 -0
  706. package/dist/config/__tests__/commit-lore-guard.test.d.ts.map +1 -0
  707. package/dist/config/__tests__/commit-lore-guard.test.js +20 -0
  708. package/dist/config/__tests__/commit-lore-guard.test.js.map +1 -0
  709. package/dist/config/__tests__/deep-interview.test.d.ts +2 -0
  710. package/dist/config/__tests__/deep-interview.test.d.ts.map +1 -0
  711. package/dist/config/__tests__/deep-interview.test.js +240 -0
  712. package/dist/config/__tests__/deep-interview.test.js.map +1 -0
  713. package/dist/config/__tests__/generator-idempotent.test.d.ts +2 -0
  714. package/dist/config/__tests__/generator-idempotent.test.d.ts.map +1 -0
  715. package/dist/config/__tests__/generator-idempotent.test.js +1150 -0
  716. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -0
  717. package/dist/config/__tests__/generator-notify.test.d.ts +2 -0
  718. package/dist/config/__tests__/generator-notify.test.d.ts.map +1 -0
  719. package/dist/config/__tests__/generator-notify.test.js +512 -0
  720. package/dist/config/__tests__/generator-notify.test.js.map +1 -0
  721. package/dist/config/__tests__/generator-status-line-presets.test.d.ts +2 -0
  722. package/dist/config/__tests__/generator-status-line-presets.test.d.ts.map +1 -0
  723. package/dist/config/__tests__/generator-status-line-presets.test.js +203 -0
  724. package/dist/config/__tests__/generator-status-line-presets.test.js.map +1 -0
  725. package/dist/config/__tests__/mcp-registry.test.d.ts +2 -0
  726. package/dist/config/__tests__/mcp-registry.test.d.ts.map +1 -0
  727. package/dist/config/__tests__/mcp-registry.test.js +190 -0
  728. package/dist/config/__tests__/mcp-registry.test.js.map +1 -0
  729. package/dist/config/__tests__/models.test.d.ts +2 -0
  730. package/dist/config/__tests__/models.test.d.ts.map +1 -0
  731. package/dist/config/__tests__/models.test.js +241 -0
  732. package/dist/config/__tests__/models.test.js.map +1 -0
  733. package/dist/config/__tests__/wiki-config-contract.test.d.ts +2 -0
  734. package/dist/config/__tests__/wiki-config-contract.test.d.ts.map +1 -0
  735. package/dist/config/__tests__/wiki-config-contract.test.js +23 -0
  736. package/dist/config/__tests__/wiki-config-contract.test.js.map +1 -0
  737. package/dist/config/codex-feature-flags.d.ts +25 -0
  738. package/dist/config/codex-feature-flags.d.ts.map +1 -0
  739. package/dist/config/codex-feature-flags.js +60 -0
  740. package/dist/config/codex-feature-flags.js.map +1 -0
  741. package/dist/config/codex-hooks.d.ts +79 -0
  742. package/dist/config/codex-hooks.d.ts.map +1 -0
  743. package/dist/config/codex-hooks.js +578 -0
  744. package/dist/config/codex-hooks.js.map +1 -0
  745. package/dist/config/commit-lore-guard.d.ts +4 -0
  746. package/dist/config/commit-lore-guard.d.ts.map +1 -0
  747. package/dist/config/commit-lore-guard.js +35 -0
  748. package/dist/config/commit-lore-guard.js.map +1 -0
  749. package/dist/config/deep-interview.d.ts +22 -0
  750. package/dist/config/deep-interview.d.ts.map +1 -0
  751. package/dist/config/deep-interview.js +161 -0
  752. package/dist/config/deep-interview.js.map +1 -0
  753. package/dist/config/generator.d.ts +141 -0
  754. package/dist/config/generator.d.ts.map +1 -0
  755. package/dist/config/generator.js +1845 -0
  756. package/dist/config/generator.js.map +1 -0
  757. package/dist/config/mcp-registry.d.ts +35 -0
  758. package/dist/config/mcp-registry.d.ts.map +1 -0
  759. package/dist/config/mcp-registry.js +159 -0
  760. package/dist/config/mcp-registry.js.map +1 -0
  761. package/dist/config/models.d.ts +80 -0
  762. package/dist/config/models.d.ts.map +1 -0
  763. package/dist/config/models.js +251 -0
  764. package/dist/config/models.js.map +1 -0
  765. package/dist/config/omx-first-party-mcp.d.ts +21 -0
  766. package/dist/config/omx-first-party-mcp.d.ts.map +1 -0
  767. package/dist/config/omx-first-party-mcp.js +86 -0
  768. package/dist/config/omx-first-party-mcp.js.map +1 -0
  769. package/dist/config/team-mode.d.ts +12 -0
  770. package/dist/config/team-mode.d.ts.map +1 -0
  771. package/dist/config/team-mode.js +91 -0
  772. package/dist/config/team-mode.js.map +1 -0
  773. package/dist/document-refresh/__tests__/enforcer.test.d.ts +2 -0
  774. package/dist/document-refresh/__tests__/enforcer.test.d.ts.map +1 -0
  775. package/dist/document-refresh/__tests__/enforcer.test.js +128 -0
  776. package/dist/document-refresh/__tests__/enforcer.test.js.map +1 -0
  777. package/dist/document-refresh/config.d.ts +9 -0
  778. package/dist/document-refresh/config.d.ts.map +1 -0
  779. package/dist/document-refresh/config.js +70 -0
  780. package/dist/document-refresh/config.js.map +1 -0
  781. package/dist/document-refresh/enforcer.d.ts +43 -0
  782. package/dist/document-refresh/enforcer.d.ts.map +1 -0
  783. package/dist/document-refresh/enforcer.js +329 -0
  784. package/dist/document-refresh/enforcer.js.map +1 -0
  785. package/dist/exec/followup.d.ts +45 -0
  786. package/dist/exec/followup.d.ts.map +1 -0
  787. package/dist/exec/followup.js +355 -0
  788. package/dist/exec/followup.js.map +1 -0
  789. package/dist/goal-workflows/__tests__/artifacts.test.d.ts +2 -0
  790. package/dist/goal-workflows/__tests__/artifacts.test.d.ts.map +1 -0
  791. package/dist/goal-workflows/__tests__/artifacts.test.js +96 -0
  792. package/dist/goal-workflows/__tests__/artifacts.test.js.map +1 -0
  793. package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.d.ts +2 -0
  794. package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.d.ts.map +1 -0
  795. package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js +75 -0
  796. package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js.map +1 -0
  797. package/dist/goal-workflows/artifacts.d.ts +62 -0
  798. package/dist/goal-workflows/artifacts.d.ts.map +1 -0
  799. package/dist/goal-workflows/artifacts.js +132 -0
  800. package/dist/goal-workflows/artifacts.js.map +1 -0
  801. package/dist/goal-workflows/codex-goal-snapshot.d.ts +32 -0
  802. package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -0
  803. package/dist/goal-workflows/codex-goal-snapshot.js +157 -0
  804. package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -0
  805. package/dist/goal-workflows/handoff.d.ts +10 -0
  806. package/dist/goal-workflows/handoff.d.ts.map +1 -0
  807. package/dist/goal-workflows/handoff.js +31 -0
  808. package/dist/goal-workflows/handoff.js.map +1 -0
  809. package/dist/goal-workflows/validation.d.ts +13 -0
  810. package/dist/goal-workflows/validation.d.ts.map +1 -0
  811. package/dist/goal-workflows/validation.js +36 -0
  812. package/dist/goal-workflows/validation.js.map +1 -0
  813. package/dist/hooks/__tests__/agents-overlay.test.d.ts +8 -0
  814. package/dist/hooks/__tests__/agents-overlay.test.d.ts.map +1 -0
  815. package/dist/hooks/__tests__/agents-overlay.test.js +761 -0
  816. package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -0
  817. package/dist/hooks/__tests__/analyze-routing-contract.test.d.ts +2 -0
  818. package/dist/hooks/__tests__/analyze-routing-contract.test.d.ts.map +1 -0
  819. package/dist/hooks/__tests__/analyze-routing-contract.test.js +45 -0
  820. package/dist/hooks/__tests__/analyze-routing-contract.test.js.map +1 -0
  821. package/dist/hooks/__tests__/analyze-skill-contract.test.d.ts +2 -0
  822. package/dist/hooks/__tests__/analyze-skill-contract.test.d.ts.map +1 -0
  823. package/dist/hooks/__tests__/analyze-skill-contract.test.js +48 -0
  824. package/dist/hooks/__tests__/analyze-skill-contract.test.js.map +1 -0
  825. package/dist/hooks/__tests__/anti-slop-workflow.test.d.ts +2 -0
  826. package/dist/hooks/__tests__/anti-slop-workflow.test.d.ts.map +1 -0
  827. package/dist/hooks/__tests__/anti-slop-workflow.test.js +165 -0
  828. package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -0
  829. package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts +2 -0
  830. package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts.map +1 -0
  831. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +90 -0
  832. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -0
  833. package/dist/hooks/__tests__/best-practice-research-skill.test.d.ts +2 -0
  834. package/dist/hooks/__tests__/best-practice-research-skill.test.d.ts.map +1 -0
  835. package/dist/hooks/__tests__/best-practice-research-skill.test.js +39 -0
  836. package/dist/hooks/__tests__/best-practice-research-skill.test.js.map +1 -0
  837. package/dist/hooks/__tests__/clawhip-event-contract.test.d.ts +2 -0
  838. package/dist/hooks/__tests__/clawhip-event-contract.test.d.ts.map +1 -0
  839. package/dist/hooks/__tests__/clawhip-event-contract.test.js +37 -0
  840. package/dist/hooks/__tests__/clawhip-event-contract.test.js.map +1 -0
  841. package/dist/hooks/__tests__/code-review-skill-contract.test.d.ts +2 -0
  842. package/dist/hooks/__tests__/code-review-skill-contract.test.d.ts.map +1 -0
  843. package/dist/hooks/__tests__/code-review-skill-contract.test.js +77 -0
  844. package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -0
  845. package/dist/hooks/__tests__/codebase-map.test.d.ts +8 -0
  846. package/dist/hooks/__tests__/codebase-map.test.d.ts.map +1 -0
  847. package/dist/hooks/__tests__/codebase-map.test.js +218 -0
  848. package/dist/hooks/__tests__/codebase-map.test.js.map +1 -0
  849. package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts +18 -0
  850. package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts.map +1 -0
  851. package/dist/hooks/__tests__/consensus-execution-handoff.test.js +266 -0
  852. package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -0
  853. package/dist/hooks/__tests__/debugger-log-recency-contract.test.d.ts +2 -0
  854. package/dist/hooks/__tests__/debugger-log-recency-contract.test.d.ts.map +1 -0
  855. package/dist/hooks/__tests__/debugger-log-recency-contract.test.js +20 -0
  856. package/dist/hooks/__tests__/debugger-log-recency-contract.test.js.map +1 -0
  857. package/dist/hooks/__tests__/deep-interview-contract.test.d.ts +2 -0
  858. package/dist/hooks/__tests__/deep-interview-contract.test.d.ts.map +1 -0
  859. package/dist/hooks/__tests__/deep-interview-contract.test.js +309 -0
  860. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -0
  861. package/dist/hooks/__tests__/design-skill.test.d.ts +2 -0
  862. package/dist/hooks/__tests__/design-skill.test.d.ts.map +1 -0
  863. package/dist/hooks/__tests__/design-skill.test.js +55 -0
  864. package/dist/hooks/__tests__/design-skill.test.js.map +1 -0
  865. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.d.ts +2 -0
  866. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.d.ts.map +1 -0
  867. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.js +43 -0
  868. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.js.map +1 -0
  869. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.d.ts +2 -0
  870. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.d.ts.map +1 -0
  871. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.js +38 -0
  872. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.js.map +1 -0
  873. package/dist/hooks/__tests__/explore-routing.test.d.ts +2 -0
  874. package/dist/hooks/__tests__/explore-routing.test.d.ts.map +1 -0
  875. package/dist/hooks/__tests__/explore-routing.test.js +38 -0
  876. package/dist/hooks/__tests__/explore-routing.test.js.map +1 -0
  877. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.d.ts +2 -0
  878. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.d.ts.map +1 -0
  879. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js +67 -0
  880. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js.map +1 -0
  881. package/dist/hooks/__tests__/foreground-isolation-contract.test.d.ts +2 -0
  882. package/dist/hooks/__tests__/foreground-isolation-contract.test.d.ts.map +1 -0
  883. package/dist/hooks/__tests__/foreground-isolation-contract.test.js +28 -0
  884. package/dist/hooks/__tests__/foreground-isolation-contract.test.js.map +1 -0
  885. package/dist/hooks/__tests__/keyword-detector.test.d.ts +2 -0
  886. package/dist/hooks/__tests__/keyword-detector.test.d.ts.map +1 -0
  887. package/dist/hooks/__tests__/keyword-detector.test.js +3323 -0
  888. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -0
  889. package/dist/hooks/__tests__/notify-fallback-watcher.test.d.ts +2 -0
  890. package/dist/hooks/__tests__/notify-fallback-watcher.test.d.ts.map +1 -0
  891. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +3956 -0
  892. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -0
  893. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.d.ts +2 -0
  894. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.d.ts.map +1 -0
  895. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +786 -0
  896. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -0
  897. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.d.ts +2 -0
  898. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.d.ts.map +1 -0
  899. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +2602 -0
  900. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -0
  901. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.d.ts +2 -0
  902. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.d.ts.map +1 -0
  903. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +161 -0
  904. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -0
  905. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.d.ts +2 -0
  906. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.d.ts.map +1 -0
  907. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +1178 -0
  908. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -0
  909. package/dist/hooks/__tests__/notify-hook-modules.test.d.ts +9 -0
  910. package/dist/hooks/__tests__/notify-hook-modules.test.d.ts.map +1 -0
  911. package/dist/hooks/__tests__/notify-hook-modules.test.js +529 -0
  912. package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -0
  913. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.d.ts +2 -0
  914. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.d.ts.map +1 -0
  915. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.js +14 -0
  916. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.js.map +1 -0
  917. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.d.ts +2 -0
  918. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.d.ts.map +1 -0
  919. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +176 -0
  920. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -0
  921. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.d.ts +2 -0
  922. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.d.ts.map +1 -0
  923. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +890 -0
  924. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -0
  925. package/dist/hooks/__tests__/notify-hook-regression-205.test.d.ts +9 -0
  926. package/dist/hooks/__tests__/notify-hook-regression-205.test.d.ts.map +1 -0
  927. package/dist/hooks/__tests__/notify-hook-regression-205.test.js +255 -0
  928. package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -0
  929. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.d.ts +2 -0
  930. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.d.ts.map +1 -0
  931. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js +162 -0
  932. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js.map +1 -0
  933. package/dist/hooks/__tests__/notify-hook-session-scope.test.d.ts +2 -0
  934. package/dist/hooks/__tests__/notify-hook-session-scope.test.d.ts.map +1 -0
  935. package/dist/hooks/__tests__/notify-hook-session-scope.test.js +304 -0
  936. package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -0
  937. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.d.ts +2 -0
  938. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.d.ts.map +1 -0
  939. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +1511 -0
  940. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -0
  941. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.d.ts +2 -0
  942. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.d.ts.map +1 -0
  943. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +2911 -0
  944. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -0
  945. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.d.ts +2 -0
  946. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.d.ts.map +1 -0
  947. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +261 -0
  948. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -0
  949. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts +2 -0
  950. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts.map +1 -0
  951. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js +35 -0
  952. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js.map +1 -0
  953. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.d.ts +2 -0
  954. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.d.ts.map +1 -0
  955. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +1854 -0
  956. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -0
  957. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.d.ts +10 -0
  958. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.d.ts.map +1 -0
  959. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +0 -0
  960. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -0
  961. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.d.ts +11 -0
  962. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.d.ts.map +1 -0
  963. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js +266 -0
  964. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js.map +1 -0
  965. package/dist/hooks/__tests__/notify-hook-worker-idle.test.d.ts +2 -0
  966. package/dist/hooks/__tests__/notify-hook-worker-idle.test.d.ts.map +1 -0
  967. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +895 -0
  968. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -0
  969. package/dist/hooks/__tests__/openclaw-setup-contract.test.d.ts +2 -0
  970. package/dist/hooks/__tests__/openclaw-setup-contract.test.d.ts.map +1 -0
  971. package/dist/hooks/__tests__/openclaw-setup-contract.test.js +61 -0
  972. package/dist/hooks/__tests__/openclaw-setup-contract.test.js.map +1 -0
  973. package/dist/hooks/__tests__/pre-context-gate-skills.test.d.ts +2 -0
  974. package/dist/hooks/__tests__/pre-context-gate-skills.test.d.ts.map +1 -0
  975. package/dist/hooks/__tests__/pre-context-gate-skills.test.js +40 -0
  976. package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -0
  977. package/dist/hooks/__tests__/prometheus-strict-contract.test.d.ts +2 -0
  978. package/dist/hooks/__tests__/prometheus-strict-contract.test.d.ts.map +1 -0
  979. package/dist/hooks/__tests__/prometheus-strict-contract.test.js +320 -0
  980. package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -0
  981. package/dist/hooks/__tests__/prompt-guidance-catalog.test.d.ts +2 -0
  982. package/dist/hooks/__tests__/prompt-guidance-catalog.test.d.ts.map +1 -0
  983. package/dist/hooks/__tests__/prompt-guidance-catalog.test.js +11 -0
  984. package/dist/hooks/__tests__/prompt-guidance-catalog.test.js.map +1 -0
  985. package/dist/hooks/__tests__/prompt-guidance-contract.test.d.ts +2 -0
  986. package/dist/hooks/__tests__/prompt-guidance-contract.test.d.ts.map +1 -0
  987. package/dist/hooks/__tests__/prompt-guidance-contract.test.js +38 -0
  988. package/dist/hooks/__tests__/prompt-guidance-contract.test.js.map +1 -0
  989. package/dist/hooks/__tests__/prompt-guidance-fragments.test.d.ts +2 -0
  990. package/dist/hooks/__tests__/prompt-guidance-fragments.test.d.ts.map +1 -0
  991. package/dist/hooks/__tests__/prompt-guidance-fragments.test.js +48 -0
  992. package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +1 -0
  993. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.d.ts +2 -0
  994. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.d.ts.map +1 -0
  995. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.js +11 -0
  996. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.js.map +1 -0
  997. package/dist/hooks/__tests__/prompt-guidance-test-helpers.d.ts +5 -0
  998. package/dist/hooks/__tests__/prompt-guidance-test-helpers.d.ts.map +1 -0
  999. package/dist/hooks/__tests__/prompt-guidance-test-helpers.js +34 -0
  1000. package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +1 -0
  1001. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.d.ts +2 -0
  1002. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.d.ts.map +1 -0
  1003. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +81 -0
  1004. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -0
  1005. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.d.ts +2 -0
  1006. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.d.ts.map +1 -0
  1007. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.js +38 -0
  1008. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.js.map +1 -0
  1009. package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts +2 -0
  1010. package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts.map +1 -0
  1011. package/dist/hooks/__tests__/prompt-refactor-contract.test.js +22 -0
  1012. package/dist/hooks/__tests__/prompt-refactor-contract.test.js.map +1 -0
  1013. package/dist/hooks/__tests__/prompt-team-routing.test.d.ts +2 -0
  1014. package/dist/hooks/__tests__/prompt-team-routing.test.d.ts.map +1 -0
  1015. package/dist/hooks/__tests__/prompt-team-routing.test.js +49 -0
  1016. package/dist/hooks/__tests__/prompt-team-routing.test.js.map +1 -0
  1017. package/dist/hooks/__tests__/research-workflow-boundaries.test.d.ts +2 -0
  1018. package/dist/hooks/__tests__/research-workflow-boundaries.test.d.ts.map +1 -0
  1019. package/dist/hooks/__tests__/research-workflow-boundaries.test.js +35 -0
  1020. package/dist/hooks/__tests__/research-workflow-boundaries.test.js.map +1 -0
  1021. package/dist/hooks/__tests__/session.test.d.ts +2 -0
  1022. package/dist/hooks/__tests__/session.test.d.ts.map +1 -0
  1023. package/dist/hooks/__tests__/session.test.js +504 -0
  1024. package/dist/hooks/__tests__/session.test.js.map +1 -0
  1025. package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts +2 -0
  1026. package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts.map +1 -0
  1027. package/dist/hooks/__tests__/skill-catalog-hygiene.test.js +84 -0
  1028. package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -0
  1029. package/dist/hooks/__tests__/skill-guidance-contract.test.d.ts +2 -0
  1030. package/dist/hooks/__tests__/skill-guidance-contract.test.d.ts.map +1 -0
  1031. package/dist/hooks/__tests__/skill-guidance-contract.test.js +89 -0
  1032. package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +1 -0
  1033. package/dist/hooks/__tests__/task-size-detector.test.d.ts +2 -0
  1034. package/dist/hooks/__tests__/task-size-detector.test.d.ts.map +1 -0
  1035. package/dist/hooks/__tests__/task-size-detector.test.js +330 -0
  1036. package/dist/hooks/__tests__/task-size-detector.test.js.map +1 -0
  1037. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.d.ts +2 -0
  1038. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.d.ts.map +1 -0
  1039. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js +28 -0
  1040. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js.map +1 -0
  1041. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.d.ts +2 -0
  1042. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.d.ts.map +1 -0
  1043. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.js +24 -0
  1044. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.js.map +1 -0
  1045. package/dist/hooks/__tests__/tmux-hook-engine.test.d.ts +2 -0
  1046. package/dist/hooks/__tests__/tmux-hook-engine.test.d.ts.map +1 -0
  1047. package/dist/hooks/__tests__/tmux-hook-engine.test.js +403 -0
  1048. package/dist/hooks/__tests__/tmux-hook-engine.test.js.map +1 -0
  1049. package/dist/hooks/__tests__/triage-config.test.d.ts +2 -0
  1050. package/dist/hooks/__tests__/triage-config.test.d.ts.map +1 -0
  1051. package/dist/hooks/__tests__/triage-config.test.js +211 -0
  1052. package/dist/hooks/__tests__/triage-config.test.js.map +1 -0
  1053. package/dist/hooks/__tests__/triage-heuristic.test.d.ts +2 -0
  1054. package/dist/hooks/__tests__/triage-heuristic.test.d.ts.map +1 -0
  1055. package/dist/hooks/__tests__/triage-heuristic.test.js +285 -0
  1056. package/dist/hooks/__tests__/triage-heuristic.test.js.map +1 -0
  1057. package/dist/hooks/__tests__/triage-state.test.d.ts +2 -0
  1058. package/dist/hooks/__tests__/triage-state.test.d.ts.map +1 -0
  1059. package/dist/hooks/__tests__/triage-state.test.js +426 -0
  1060. package/dist/hooks/__tests__/triage-state.test.js.map +1 -0
  1061. package/dist/hooks/__tests__/visual-ralph-skill.test.d.ts +2 -0
  1062. package/dist/hooks/__tests__/visual-ralph-skill.test.d.ts.map +1 -0
  1063. package/dist/hooks/__tests__/visual-ralph-skill.test.js +44 -0
  1064. package/dist/hooks/__tests__/visual-ralph-skill.test.js.map +1 -0
  1065. package/dist/hooks/__tests__/visual-verdict-loop.test.d.ts +2 -0
  1066. package/dist/hooks/__tests__/visual-verdict-loop.test.d.ts.map +1 -0
  1067. package/dist/hooks/__tests__/visual-verdict-loop.test.js +31 -0
  1068. package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +1 -0
  1069. package/dist/hooks/__tests__/wiki-docs-contract.test.d.ts +2 -0
  1070. package/dist/hooks/__tests__/wiki-docs-contract.test.d.ts.map +1 -0
  1071. package/dist/hooks/__tests__/wiki-docs-contract.test.js +35 -0
  1072. package/dist/hooks/__tests__/wiki-docs-contract.test.js.map +1 -0
  1073. package/dist/hooks/agents-overlay.d.ts +51 -0
  1074. package/dist/hooks/agents-overlay.d.ts.map +1 -0
  1075. package/dist/hooks/agents-overlay.js +547 -0
  1076. package/dist/hooks/agents-overlay.js.map +1 -0
  1077. package/dist/hooks/code-simplifier/__tests__/index.test.d.ts +2 -0
  1078. package/dist/hooks/code-simplifier/__tests__/index.test.d.ts.map +1 -0
  1079. package/dist/hooks/code-simplifier/__tests__/index.test.js +187 -0
  1080. package/dist/hooks/code-simplifier/__tests__/index.test.js.map +1 -0
  1081. package/dist/hooks/code-simplifier/index.d.ts +80 -0
  1082. package/dist/hooks/code-simplifier/index.d.ts.map +1 -0
  1083. package/dist/hooks/code-simplifier/index.js +172 -0
  1084. package/dist/hooks/code-simplifier/index.js.map +1 -0
  1085. package/dist/hooks/codebase-map.d.ts +23 -0
  1086. package/dist/hooks/codebase-map.d.ts.map +1 -0
  1087. package/dist/hooks/codebase-map.js +234 -0
  1088. package/dist/hooks/codebase-map.js.map +1 -0
  1089. package/dist/hooks/deep-interview-config-instruction.d.ts +3 -0
  1090. package/dist/hooks/deep-interview-config-instruction.d.ts.map +1 -0
  1091. package/dist/hooks/deep-interview-config-instruction.js +47 -0
  1092. package/dist/hooks/deep-interview-config-instruction.js.map +1 -0
  1093. package/dist/hooks/explore-routing.d.ts +5 -0
  1094. package/dist/hooks/explore-routing.d.ts.map +1 -0
  1095. package/dist/hooks/explore-routing.js +37 -0
  1096. package/dist/hooks/explore-routing.js.map +1 -0
  1097. package/dist/hooks/extensibility/__tests__/dispatcher.test.d.ts +2 -0
  1098. package/dist/hooks/extensibility/__tests__/dispatcher.test.d.ts.map +1 -0
  1099. package/dist/hooks/extensibility/__tests__/dispatcher.test.js +265 -0
  1100. package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +1 -0
  1101. package/dist/hooks/extensibility/__tests__/events.test.d.ts +2 -0
  1102. package/dist/hooks/extensibility/__tests__/events.test.d.ts.map +1 -0
  1103. package/dist/hooks/extensibility/__tests__/events.test.js +125 -0
  1104. package/dist/hooks/extensibility/__tests__/events.test.js.map +1 -0
  1105. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.d.ts +2 -0
  1106. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.d.ts.map +1 -0
  1107. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.js +153 -0
  1108. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.js.map +1 -0
  1109. package/dist/hooks/extensibility/__tests__/loader.test.d.ts +2 -0
  1110. package/dist/hooks/extensibility/__tests__/loader.test.d.ts.map +1 -0
  1111. package/dist/hooks/extensibility/__tests__/loader.test.js +254 -0
  1112. package/dist/hooks/extensibility/__tests__/loader.test.js.map +1 -0
  1113. package/dist/hooks/extensibility/__tests__/logging.test.d.ts +2 -0
  1114. package/dist/hooks/extensibility/__tests__/logging.test.d.ts.map +1 -0
  1115. package/dist/hooks/extensibility/__tests__/logging.test.js +74 -0
  1116. package/dist/hooks/extensibility/__tests__/logging.test.js.map +1 -0
  1117. package/dist/hooks/extensibility/__tests__/plugin-runner.test.d.ts +2 -0
  1118. package/dist/hooks/extensibility/__tests__/plugin-runner.test.d.ts.map +1 -0
  1119. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js +344 -0
  1120. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js.map +1 -0
  1121. package/dist/hooks/extensibility/__tests__/runtime.test.d.ts +2 -0
  1122. package/dist/hooks/extensibility/__tests__/runtime.test.d.ts.map +1 -0
  1123. package/dist/hooks/extensibility/__tests__/runtime.test.js +198 -0
  1124. package/dist/hooks/extensibility/__tests__/runtime.test.js.map +1 -0
  1125. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.d.ts +2 -0
  1126. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.d.ts.map +1 -0
  1127. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.js +32 -0
  1128. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.js.map +1 -0
  1129. package/dist/hooks/extensibility/__tests__/sdk.test.d.ts +2 -0
  1130. package/dist/hooks/extensibility/__tests__/sdk.test.d.ts.map +1 -0
  1131. package/dist/hooks/extensibility/__tests__/sdk.test.js +479 -0
  1132. package/dist/hooks/extensibility/__tests__/sdk.test.js.map +1 -0
  1133. package/dist/hooks/extensibility/dispatcher.d.ts +4 -0
  1134. package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -0
  1135. package/dist/hooks/extensibility/dispatcher.js +302 -0
  1136. package/dist/hooks/extensibility/dispatcher.js.map +1 -0
  1137. package/dist/hooks/extensibility/events.d.ts +18 -0
  1138. package/dist/hooks/extensibility/events.d.ts.map +1 -0
  1139. package/dist/hooks/extensibility/events.js +53 -0
  1140. package/dist/hooks/extensibility/events.js.map +1 -0
  1141. package/dist/hooks/extensibility/index.d.ts +6 -0
  1142. package/dist/hooks/extensibility/index.d.ts.map +1 -0
  1143. package/dist/hooks/extensibility/index.js +6 -0
  1144. package/dist/hooks/extensibility/index.js.map +1 -0
  1145. package/dist/hooks/extensibility/loader.d.ts +14 -0
  1146. package/dist/hooks/extensibility/loader.d.ts.map +1 -0
  1147. package/dist/hooks/extensibility/loader.js +117 -0
  1148. package/dist/hooks/extensibility/loader.js.map +1 -0
  1149. package/dist/hooks/extensibility/logging.d.ts +4 -0
  1150. package/dist/hooks/extensibility/logging.d.ts.map +1 -0
  1151. package/dist/hooks/extensibility/logging.js +22 -0
  1152. package/dist/hooks/extensibility/logging.js.map +1 -0
  1153. package/dist/hooks/extensibility/plugin-runner-stdin.d.ts +2 -0
  1154. package/dist/hooks/extensibility/plugin-runner-stdin.d.ts.map +1 -0
  1155. package/dist/hooks/extensibility/plugin-runner-stdin.js +16 -0
  1156. package/dist/hooks/extensibility/plugin-runner-stdin.js.map +1 -0
  1157. package/dist/hooks/extensibility/plugin-runner.d.ts +2 -0
  1158. package/dist/hooks/extensibility/plugin-runner.d.ts.map +1 -0
  1159. package/dist/hooks/extensibility/plugin-runner.js +63 -0
  1160. package/dist/hooks/extensibility/plugin-runner.js.map +1 -0
  1161. package/dist/hooks/extensibility/runtime.d.ts +3 -0
  1162. package/dist/hooks/extensibility/runtime.d.ts.map +1 -0
  1163. package/dist/hooks/extensibility/runtime.js +42 -0
  1164. package/dist/hooks/extensibility/runtime.js.map +1 -0
  1165. package/dist/hooks/extensibility/sdk/logging.d.ts +6 -0
  1166. package/dist/hooks/extensibility/sdk/logging.d.ts.map +1 -0
  1167. package/dist/hooks/extensibility/sdk/logging.js +32 -0
  1168. package/dist/hooks/extensibility/sdk/logging.js.map +1 -0
  1169. package/dist/hooks/extensibility/sdk/paths.d.ts +7 -0
  1170. package/dist/hooks/extensibility/sdk/paths.d.ts.map +1 -0
  1171. package/dist/hooks/extensibility/sdk/paths.js +23 -0
  1172. package/dist/hooks/extensibility/sdk/paths.js.map +1 -0
  1173. package/dist/hooks/extensibility/sdk/plugin-state.d.ts +5 -0
  1174. package/dist/hooks/extensibility/sdk/plugin-state.d.ts.map +1 -0
  1175. package/dist/hooks/extensibility/sdk/plugin-state.js +66 -0
  1176. package/dist/hooks/extensibility/sdk/plugin-state.js.map +1 -0
  1177. package/dist/hooks/extensibility/sdk/runtime-state.d.ts +3 -0
  1178. package/dist/hooks/extensibility/sdk/runtime-state.d.ts.map +1 -0
  1179. package/dist/hooks/extensibility/sdk/runtime-state.js +47 -0
  1180. package/dist/hooks/extensibility/sdk/runtime-state.js.map +1 -0
  1181. package/dist/hooks/extensibility/sdk/tmux.d.ts +10 -0
  1182. package/dist/hooks/extensibility/sdk/tmux.d.ts.map +1 -0
  1183. package/dist/hooks/extensibility/sdk/tmux.js +181 -0
  1184. package/dist/hooks/extensibility/sdk/tmux.js.map +1 -0
  1185. package/dist/hooks/extensibility/sdk.d.ts +11 -0
  1186. package/dist/hooks/extensibility/sdk.d.ts.map +1 -0
  1187. package/dist/hooks/extensibility/sdk.js +21 -0
  1188. package/dist/hooks/extensibility/sdk.js.map +1 -0
  1189. package/dist/hooks/extensibility/types.d.ts +175 -0
  1190. package/dist/hooks/extensibility/types.d.ts.map +1 -0
  1191. package/dist/hooks/extensibility/types.js +2 -0
  1192. package/dist/hooks/extensibility/types.js.map +1 -0
  1193. package/dist/hooks/keyword-detector.d.ts +170 -0
  1194. package/dist/hooks/keyword-detector.d.ts.map +1 -0
  1195. package/dist/hooks/keyword-detector.js +1363 -0
  1196. package/dist/hooks/keyword-detector.js.map +1 -0
  1197. package/dist/hooks/keyword-registry.d.ts +15 -0
  1198. package/dist/hooks/keyword-registry.d.ts.map +1 -0
  1199. package/dist/hooks/keyword-registry.js +56 -0
  1200. package/dist/hooks/keyword-registry.js.map +1 -0
  1201. package/dist/hooks/prompt-guidance-contract.d.ts +20 -0
  1202. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -0
  1203. package/dist/hooks/prompt-guidance-contract.js +380 -0
  1204. package/dist/hooks/prompt-guidance-contract.js.map +1 -0
  1205. package/dist/hooks/session.d.ts +83 -0
  1206. package/dist/hooks/session.d.ts.map +1 -0
  1207. package/dist/hooks/session.js +412 -0
  1208. package/dist/hooks/session.js.map +1 -0
  1209. package/dist/hooks/task-size-detector.d.ts +72 -0
  1210. package/dist/hooks/task-size-detector.d.ts.map +1 -0
  1211. package/dist/hooks/task-size-detector.js +203 -0
  1212. package/dist/hooks/task-size-detector.js.map +1 -0
  1213. package/dist/hooks/triage-config.d.ts +33 -0
  1214. package/dist/hooks/triage-config.d.ts.map +1 -0
  1215. package/dist/hooks/triage-config.js +87 -0
  1216. package/dist/hooks/triage-config.js.map +1 -0
  1217. package/dist/hooks/triage-heuristic.d.ts +20 -0
  1218. package/dist/hooks/triage-heuristic.d.ts.map +1 -0
  1219. package/dist/hooks/triage-heuristic.js +287 -0
  1220. package/dist/hooks/triage-heuristic.js.map +1 -0
  1221. package/dist/hooks/triage-state.d.ts +63 -0
  1222. package/dist/hooks/triage-state.d.ts.map +1 -0
  1223. package/dist/hooks/triage-state.js +139 -0
  1224. package/dist/hooks/triage-state.js.map +1 -0
  1225. package/dist/hud/__tests__/authority.test.d.ts +2 -0
  1226. package/dist/hud/__tests__/authority.test.d.ts.map +1 -0
  1227. package/dist/hud/__tests__/authority.test.js +527 -0
  1228. package/dist/hud/__tests__/authority.test.js.map +1 -0
  1229. package/dist/hud/__tests__/colors.test.d.ts +2 -0
  1230. package/dist/hud/__tests__/colors.test.d.ts.map +1 -0
  1231. package/dist/hud/__tests__/colors.test.js +92 -0
  1232. package/dist/hud/__tests__/colors.test.js.map +1 -0
  1233. package/dist/hud/__tests__/hud-tmux-injection.test.d.ts +10 -0
  1234. package/dist/hud/__tests__/hud-tmux-injection.test.d.ts.map +1 -0
  1235. package/dist/hud/__tests__/hud-tmux-injection.test.js +185 -0
  1236. package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -0
  1237. package/dist/hud/__tests__/index.test.d.ts +2 -0
  1238. package/dist/hud/__tests__/index.test.d.ts.map +1 -0
  1239. package/dist/hud/__tests__/index.test.js +684 -0
  1240. package/dist/hud/__tests__/index.test.js.map +1 -0
  1241. package/dist/hud/__tests__/reconcile.test.d.ts +2 -0
  1242. package/dist/hud/__tests__/reconcile.test.d.ts.map +1 -0
  1243. package/dist/hud/__tests__/reconcile.test.js +1621 -0
  1244. package/dist/hud/__tests__/reconcile.test.js.map +1 -0
  1245. package/dist/hud/__tests__/render.test.d.ts +2 -0
  1246. package/dist/hud/__tests__/render.test.d.ts.map +1 -0
  1247. package/dist/hud/__tests__/render.test.js +983 -0
  1248. package/dist/hud/__tests__/render.test.js.map +1 -0
  1249. package/dist/hud/__tests__/resource-leak-watch.test.d.ts +2 -0
  1250. package/dist/hud/__tests__/resource-leak-watch.test.d.ts.map +1 -0
  1251. package/dist/hud/__tests__/resource-leak-watch.test.js +28 -0
  1252. package/dist/hud/__tests__/resource-leak-watch.test.js.map +1 -0
  1253. package/dist/hud/__tests__/state.test.d.ts +2 -0
  1254. package/dist/hud/__tests__/state.test.d.ts.map +1 -0
  1255. package/dist/hud/__tests__/state.test.js +1212 -0
  1256. package/dist/hud/__tests__/state.test.js.map +1 -0
  1257. package/dist/hud/__tests__/tmux.test.d.ts +2 -0
  1258. package/dist/hud/__tests__/tmux.test.d.ts.map +1 -0
  1259. package/dist/hud/__tests__/tmux.test.js +679 -0
  1260. package/dist/hud/__tests__/tmux.test.js.map +1 -0
  1261. package/dist/hud/__tests__/types.test.d.ts +2 -0
  1262. package/dist/hud/__tests__/types.test.d.ts.map +1 -0
  1263. package/dist/hud/__tests__/types.test.js +79 -0
  1264. package/dist/hud/__tests__/types.test.js.map +1 -0
  1265. package/dist/hud/__tests__/watch.test.d.ts +2 -0
  1266. package/dist/hud/__tests__/watch.test.d.ts.map +1 -0
  1267. package/dist/hud/__tests__/watch.test.js +63 -0
  1268. package/dist/hud/__tests__/watch.test.js.map +1 -0
  1269. package/dist/hud/authority.d.ts +22 -0
  1270. package/dist/hud/authority.d.ts.map +1 -0
  1271. package/dist/hud/authority.js +377 -0
  1272. package/dist/hud/authority.js.map +1 -0
  1273. package/dist/hud/colors.d.ts +20 -0
  1274. package/dist/hud/colors.d.ts.map +1 -0
  1275. package/dist/hud/colors.js +60 -0
  1276. package/dist/hud/colors.js.map +1 -0
  1277. package/dist/hud/constants.d.ts +16 -0
  1278. package/dist/hud/constants.d.ts.map +1 -0
  1279. package/dist/hud/constants.js +25 -0
  1280. package/dist/hud/constants.js.map +1 -0
  1281. package/dist/hud/index.d.ts +79 -0
  1282. package/dist/hud/index.d.ts.map +1 -0
  1283. package/dist/hud/index.js +384 -0
  1284. package/dist/hud/index.js.map +1 -0
  1285. package/dist/hud/reconcile.d.ts +37 -0
  1286. package/dist/hud/reconcile.d.ts.map +1 -0
  1287. package/dist/hud/reconcile.js +326 -0
  1288. package/dist/hud/reconcile.js.map +1 -0
  1289. package/dist/hud/render.d.ts +15 -0
  1290. package/dist/hud/render.d.ts.map +1 -0
  1291. package/dist/hud/render.js +453 -0
  1292. package/dist/hud/render.js.map +1 -0
  1293. package/dist/hud/state.d.ts +27 -0
  1294. package/dist/hud/state.d.ts.map +1 -0
  1295. package/dist/hud/state.js +477 -0
  1296. package/dist/hud/state.js.map +1 -0
  1297. package/dist/hud/tmux.d.ts +87 -0
  1298. package/dist/hud/tmux.d.ts.map +1 -0
  1299. package/dist/hud/tmux.js +572 -0
  1300. package/dist/hud/tmux.js.map +1 -0
  1301. package/dist/hud/types.d.ts +165 -0
  1302. package/dist/hud/types.d.ts.map +1 -0
  1303. package/dist/hud/types.js +14 -0
  1304. package/dist/hud/types.js.map +1 -0
  1305. package/dist/imagegen/continuation.d.ts +44 -0
  1306. package/dist/imagegen/continuation.d.ts.map +1 -0
  1307. package/dist/imagegen/continuation.js +220 -0
  1308. package/dist/imagegen/continuation.js.map +1 -0
  1309. package/dist/index.d.ts +19 -0
  1310. package/dist/index.d.ts.map +1 -0
  1311. package/dist/index.js +19 -0
  1312. package/dist/index.js.map +1 -0
  1313. package/dist/mcp/__tests__/bootstrap.test.d.ts +2 -0
  1314. package/dist/mcp/__tests__/bootstrap.test.d.ts.map +1 -0
  1315. package/dist/mcp/__tests__/bootstrap.test.js +372 -0
  1316. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -0
  1317. package/dist/mcp/__tests__/code-intel-server.test.d.ts +2 -0
  1318. package/dist/mcp/__tests__/code-intel-server.test.d.ts.map +1 -0
  1319. package/dist/mcp/__tests__/code-intel-server.test.js +70 -0
  1320. package/dist/mcp/__tests__/code-intel-server.test.js.map +1 -0
  1321. package/dist/mcp/__tests__/hermes-bridge.test.d.ts +2 -0
  1322. package/dist/mcp/__tests__/hermes-bridge.test.d.ts.map +1 -0
  1323. package/dist/mcp/__tests__/hermes-bridge.test.js +651 -0
  1324. package/dist/mcp/__tests__/hermes-bridge.test.js.map +1 -0
  1325. package/dist/mcp/__tests__/memory-server.test.d.ts +2 -0
  1326. package/dist/mcp/__tests__/memory-server.test.d.ts.map +1 -0
  1327. package/dist/mcp/__tests__/memory-server.test.js +36 -0
  1328. package/dist/mcp/__tests__/memory-server.test.js.map +1 -0
  1329. package/dist/mcp/__tests__/memory-validation.test.d.ts +2 -0
  1330. package/dist/mcp/__tests__/memory-validation.test.d.ts.map +1 -0
  1331. package/dist/mcp/__tests__/memory-validation.test.js +29 -0
  1332. package/dist/mcp/__tests__/memory-validation.test.js.map +1 -0
  1333. package/dist/mcp/__tests__/path-traversal.test.d.ts +2 -0
  1334. package/dist/mcp/__tests__/path-traversal.test.d.ts.map +1 -0
  1335. package/dist/mcp/__tests__/path-traversal.test.js +83 -0
  1336. package/dist/mcp/__tests__/path-traversal.test.js.map +1 -0
  1337. package/dist/mcp/__tests__/server-lifecycle.test.d.ts +2 -0
  1338. package/dist/mcp/__tests__/server-lifecycle.test.d.ts.map +1 -0
  1339. package/dist/mcp/__tests__/server-lifecycle.test.js +308 -0
  1340. package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -0
  1341. package/dist/mcp/__tests__/state-paths.test.d.ts +2 -0
  1342. package/dist/mcp/__tests__/state-paths.test.d.ts.map +1 -0
  1343. package/dist/mcp/__tests__/state-paths.test.js +477 -0
  1344. package/dist/mcp/__tests__/state-paths.test.js.map +1 -0
  1345. package/dist/mcp/__tests__/state-server-ralph-phase.test.d.ts +2 -0
  1346. package/dist/mcp/__tests__/state-server-ralph-phase.test.d.ts.map +1 -0
  1347. package/dist/mcp/__tests__/state-server-ralph-phase.test.js +109 -0
  1348. package/dist/mcp/__tests__/state-server-ralph-phase.test.js.map +1 -0
  1349. package/dist/mcp/__tests__/state-server-schema.test.d.ts +2 -0
  1350. package/dist/mcp/__tests__/state-server-schema.test.d.ts.map +1 -0
  1351. package/dist/mcp/__tests__/state-server-schema.test.js +29 -0
  1352. package/dist/mcp/__tests__/state-server-schema.test.js.map +1 -0
  1353. package/dist/mcp/__tests__/state-server-team-tools.test.d.ts +2 -0
  1354. package/dist/mcp/__tests__/state-server-team-tools.test.d.ts.map +1 -0
  1355. package/dist/mcp/__tests__/state-server-team-tools.test.js +35 -0
  1356. package/dist/mcp/__tests__/state-server-team-tools.test.js.map +1 -0
  1357. package/dist/mcp/__tests__/state-server.test.d.ts +2 -0
  1358. package/dist/mcp/__tests__/state-server.test.d.ts.map +1 -0
  1359. package/dist/mcp/__tests__/state-server.test.js +1318 -0
  1360. package/dist/mcp/__tests__/state-server.test.js.map +1 -0
  1361. package/dist/mcp/__tests__/trace-server.test.d.ts +2 -0
  1362. package/dist/mcp/__tests__/trace-server.test.d.ts.map +1 -0
  1363. package/dist/mcp/__tests__/trace-server.test.js +119 -0
  1364. package/dist/mcp/__tests__/trace-server.test.js.map +1 -0
  1365. package/dist/mcp/__tests__/wiki-server.test.d.ts +2 -0
  1366. package/dist/mcp/__tests__/wiki-server.test.d.ts.map +1 -0
  1367. package/dist/mcp/__tests__/wiki-server.test.js +126 -0
  1368. package/dist/mcp/__tests__/wiki-server.test.js.map +1 -0
  1369. package/dist/mcp/bootstrap.d.ts +44 -0
  1370. package/dist/mcp/bootstrap.d.ts.map +1 -0
  1371. package/dist/mcp/bootstrap.js +520 -0
  1372. package/dist/mcp/bootstrap.js.map +1 -0
  1373. package/dist/mcp/code-intel-server.d.ts +333 -0
  1374. package/dist/mcp/code-intel-server.d.ts.map +1 -0
  1375. package/dist/mcp/code-intel-server.js +605 -0
  1376. package/dist/mcp/code-intel-server.js.map +1 -0
  1377. package/dist/mcp/hermes-bridge.d.ts +124 -0
  1378. package/dist/mcp/hermes-bridge.d.ts.map +1 -0
  1379. package/dist/mcp/hermes-bridge.js +549 -0
  1380. package/dist/mcp/hermes-bridge.js.map +1 -0
  1381. package/dist/mcp/hermes-server.d.ts +374 -0
  1382. package/dist/mcp/hermes-server.d.ts.map +1 -0
  1383. package/dist/mcp/hermes-server.js +158 -0
  1384. package/dist/mcp/hermes-server.js.map +1 -0
  1385. package/dist/mcp/lifecycle-telemetry.d.ts +16 -0
  1386. package/dist/mcp/lifecycle-telemetry.d.ts.map +1 -0
  1387. package/dist/mcp/lifecycle-telemetry.js +95 -0
  1388. package/dist/mcp/lifecycle-telemetry.js.map +1 -0
  1389. package/dist/mcp/memory-server.d.ts +201 -0
  1390. package/dist/mcp/memory-server.d.ts.map +1 -0
  1391. package/dist/mcp/memory-server.js +441 -0
  1392. package/dist/mcp/memory-server.js.map +1 -0
  1393. package/dist/mcp/memory-validation.d.ts +9 -0
  1394. package/dist/mcp/memory-validation.d.ts.map +1 -0
  1395. package/dist/mcp/memory-validation.js +11 -0
  1396. package/dist/mcp/memory-validation.js.map +1 -0
  1397. package/dist/mcp/state-paths.d.ts +91 -0
  1398. package/dist/mcp/state-paths.d.ts.map +1 -0
  1399. package/dist/mcp/state-paths.js +473 -0
  1400. package/dist/mcp/state-paths.js.map +1 -0
  1401. package/dist/mcp/state-server.d.ts +222 -0
  1402. package/dist/mcp/state-server.d.ts.map +1 -0
  1403. package/dist/mcp/state-server.js +181 -0
  1404. package/dist/mcp/state-server.js.map +1 -0
  1405. package/dist/mcp/trace-server.d.ts +81 -0
  1406. package/dist/mcp/trace-server.d.ts.map +1 -0
  1407. package/dist/mcp/trace-server.js +271 -0
  1408. package/dist/mcp/trace-server.js.map +1 -0
  1409. package/dist/mcp/wiki-server.d.ts +181 -0
  1410. package/dist/mcp/wiki-server.d.ts.map +1 -0
  1411. package/dist/mcp/wiki-server.js +244 -0
  1412. package/dist/mcp/wiki-server.js.map +1 -0
  1413. package/dist/modes/__tests__/base-autopilot-gates.test.d.ts +2 -0
  1414. package/dist/modes/__tests__/base-autopilot-gates.test.d.ts.map +1 -0
  1415. package/dist/modes/__tests__/base-autopilot-gates.test.js +154 -0
  1416. package/dist/modes/__tests__/base-autopilot-gates.test.js.map +1 -0
  1417. package/dist/modes/__tests__/base-autoresearch-contract.test.d.ts +2 -0
  1418. package/dist/modes/__tests__/base-autoresearch-contract.test.d.ts.map +1 -0
  1419. package/dist/modes/__tests__/base-autoresearch-contract.test.js +129 -0
  1420. package/dist/modes/__tests__/base-autoresearch-contract.test.js.map +1 -0
  1421. package/dist/modes/__tests__/base-multi-state-compat.test.d.ts +2 -0
  1422. package/dist/modes/__tests__/base-multi-state-compat.test.d.ts.map +1 -0
  1423. package/dist/modes/__tests__/base-multi-state-compat.test.js +38 -0
  1424. package/dist/modes/__tests__/base-multi-state-compat.test.js.map +1 -0
  1425. package/dist/modes/__tests__/base-ralph-contract.test.d.ts +2 -0
  1426. package/dist/modes/__tests__/base-ralph-contract.test.d.ts.map +1 -0
  1427. package/dist/modes/__tests__/base-ralph-contract.test.js +64 -0
  1428. package/dist/modes/__tests__/base-ralph-contract.test.js.map +1 -0
  1429. package/dist/modes/__tests__/base-session-scope.test.d.ts +2 -0
  1430. package/dist/modes/__tests__/base-session-scope.test.d.ts.map +1 -0
  1431. package/dist/modes/__tests__/base-session-scope.test.js +146 -0
  1432. package/dist/modes/__tests__/base-session-scope.test.js.map +1 -0
  1433. package/dist/modes/__tests__/base-tmux-pane.test.d.ts +2 -0
  1434. package/dist/modes/__tests__/base-tmux-pane.test.d.ts.map +1 -0
  1435. package/dist/modes/__tests__/base-tmux-pane.test.js +100 -0
  1436. package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -0
  1437. package/dist/modes/base.d.ts +60 -0
  1438. package/dist/modes/base.d.ts.map +1 -0
  1439. package/dist/modes/base.js +346 -0
  1440. package/dist/modes/base.js.map +1 -0
  1441. package/dist/notifications/__tests__/config.test.d.ts +2 -0
  1442. package/dist/notifications/__tests__/config.test.d.ts.map +1 -0
  1443. package/dist/notifications/__tests__/config.test.js +269 -0
  1444. package/dist/notifications/__tests__/config.test.js.map +1 -0
  1445. package/dist/notifications/__tests__/custom-alias-enablement.test.d.ts +2 -0
  1446. package/dist/notifications/__tests__/custom-alias-enablement.test.d.ts.map +1 -0
  1447. package/dist/notifications/__tests__/custom-alias-enablement.test.js +84 -0
  1448. package/dist/notifications/__tests__/custom-alias-enablement.test.js.map +1 -0
  1449. package/dist/notifications/__tests__/dispatch-cooldown.test.d.ts +5 -0
  1450. package/dist/notifications/__tests__/dispatch-cooldown.test.d.ts.map +1 -0
  1451. package/dist/notifications/__tests__/dispatch-cooldown.test.js +100 -0
  1452. package/dist/notifications/__tests__/dispatch-cooldown.test.js.map +1 -0
  1453. package/dist/notifications/__tests__/dispatcher.test.d.ts +2 -0
  1454. package/dist/notifications/__tests__/dispatcher.test.d.ts.map +1 -0
  1455. package/dist/notifications/__tests__/dispatcher.test.js +202 -0
  1456. package/dist/notifications/__tests__/dispatcher.test.js.map +1 -0
  1457. package/dist/notifications/__tests__/formatter.test.d.ts +2 -0
  1458. package/dist/notifications/__tests__/formatter.test.d.ts.map +1 -0
  1459. package/dist/notifications/__tests__/formatter.test.js +270 -0
  1460. package/dist/notifications/__tests__/formatter.test.js.map +1 -0
  1461. package/dist/notifications/__tests__/hook-config.test.d.ts +5 -0
  1462. package/dist/notifications/__tests__/hook-config.test.d.ts.map +1 -0
  1463. package/dist/notifications/__tests__/hook-config.test.js +139 -0
  1464. package/dist/notifications/__tests__/hook-config.test.js.map +1 -0
  1465. package/dist/notifications/__tests__/http-client-resource.test.d.ts +2 -0
  1466. package/dist/notifications/__tests__/http-client-resource.test.d.ts.map +1 -0
  1467. package/dist/notifications/__tests__/http-client-resource.test.js +41 -0
  1468. package/dist/notifications/__tests__/http-client-resource.test.js.map +1 -0
  1469. package/dist/notifications/__tests__/http-client.test.d.ts +2 -0
  1470. package/dist/notifications/__tests__/http-client.test.d.ts.map +1 -0
  1471. package/dist/notifications/__tests__/http-client.test.js +90 -0
  1472. package/dist/notifications/__tests__/http-client.test.js.map +1 -0
  1473. package/dist/notifications/__tests__/idle-cooldown.test.d.ts +5 -0
  1474. package/dist/notifications/__tests__/idle-cooldown.test.d.ts.map +1 -0
  1475. package/dist/notifications/__tests__/idle-cooldown.test.js +209 -0
  1476. package/dist/notifications/__tests__/idle-cooldown.test.js.map +1 -0
  1477. package/dist/notifications/__tests__/index.test.d.ts +2 -0
  1478. package/dist/notifications/__tests__/index.test.d.ts.map +1 -0
  1479. package/dist/notifications/__tests__/index.test.js +188 -0
  1480. package/dist/notifications/__tests__/index.test.js.map +1 -0
  1481. package/dist/notifications/__tests__/lifecycle-dedupe.test.d.ts +2 -0
  1482. package/dist/notifications/__tests__/lifecycle-dedupe.test.d.ts.map +1 -0
  1483. package/dist/notifications/__tests__/lifecycle-dedupe.test.js +86 -0
  1484. package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +1 -0
  1485. package/dist/notifications/__tests__/notifier.test.d.ts +2 -0
  1486. package/dist/notifications/__tests__/notifier.test.d.ts.map +1 -0
  1487. package/dist/notifications/__tests__/notifier.test.js +201 -0
  1488. package/dist/notifications/__tests__/notifier.test.js.map +1 -0
  1489. package/dist/notifications/__tests__/profiles.test.d.ts +2 -0
  1490. package/dist/notifications/__tests__/profiles.test.d.ts.map +1 -0
  1491. package/dist/notifications/__tests__/profiles.test.js +404 -0
  1492. package/dist/notifications/__tests__/profiles.test.js.map +1 -0
  1493. package/dist/notifications/__tests__/reply-config.test.d.ts +2 -0
  1494. package/dist/notifications/__tests__/reply-config.test.d.ts.map +1 -0
  1495. package/dist/notifications/__tests__/reply-config.test.js +79 -0
  1496. package/dist/notifications/__tests__/reply-config.test.js.map +1 -0
  1497. package/dist/notifications/__tests__/reply-listener.test.d.ts +2 -0
  1498. package/dist/notifications/__tests__/reply-listener.test.d.ts.map +1 -0
  1499. package/dist/notifications/__tests__/reply-listener.test.js +723 -0
  1500. package/dist/notifications/__tests__/reply-listener.test.js.map +1 -0
  1501. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.d.ts +2 -0
  1502. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.d.ts.map +1 -0
  1503. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js +93 -0
  1504. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js.map +1 -0
  1505. package/dist/notifications/__tests__/session-registry.test.d.ts +2 -0
  1506. package/dist/notifications/__tests__/session-registry.test.d.ts.map +1 -0
  1507. package/dist/notifications/__tests__/session-registry.test.js +234 -0
  1508. package/dist/notifications/__tests__/session-registry.test.js.map +1 -0
  1509. package/dist/notifications/__tests__/session-status.test.d.ts +2 -0
  1510. package/dist/notifications/__tests__/session-status.test.d.ts.map +1 -0
  1511. package/dist/notifications/__tests__/session-status.test.js +249 -0
  1512. package/dist/notifications/__tests__/session-status.test.js.map +1 -0
  1513. package/dist/notifications/__tests__/temp-mode.test.d.ts +2 -0
  1514. package/dist/notifications/__tests__/temp-mode.test.d.ts.map +1 -0
  1515. package/dist/notifications/__tests__/temp-mode.test.js +172 -0
  1516. package/dist/notifications/__tests__/temp-mode.test.js.map +1 -0
  1517. package/dist/notifications/__tests__/template-engine.test.d.ts +5 -0
  1518. package/dist/notifications/__tests__/template-engine.test.d.ts.map +1 -0
  1519. package/dist/notifications/__tests__/template-engine.test.js +158 -0
  1520. package/dist/notifications/__tests__/template-engine.test.js.map +1 -0
  1521. package/dist/notifications/__tests__/tmux-detector.test.d.ts +2 -0
  1522. package/dist/notifications/__tests__/tmux-detector.test.d.ts.map +1 -0
  1523. package/dist/notifications/__tests__/tmux-detector.test.js +204 -0
  1524. package/dist/notifications/__tests__/tmux-detector.test.js.map +1 -0
  1525. package/dist/notifications/__tests__/tmux.test.d.ts +2 -0
  1526. package/dist/notifications/__tests__/tmux.test.d.ts.map +1 -0
  1527. package/dist/notifications/__tests__/tmux.test.js +285 -0
  1528. package/dist/notifications/__tests__/tmux.test.js.map +1 -0
  1529. package/dist/notifications/__tests__/verbosity.test.d.ts +2 -0
  1530. package/dist/notifications/__tests__/verbosity.test.d.ts.map +1 -0
  1531. package/dist/notifications/__tests__/verbosity.test.js +257 -0
  1532. package/dist/notifications/__tests__/verbosity.test.js.map +1 -0
  1533. package/dist/notifications/config.d.ts +65 -0
  1534. package/dist/notifications/config.d.ts.map +1 -0
  1535. package/dist/notifications/config.js +615 -0
  1536. package/dist/notifications/config.js.map +1 -0
  1537. package/dist/notifications/dispatch-cooldown.d.ts +36 -0
  1538. package/dist/notifications/dispatch-cooldown.d.ts.map +1 -0
  1539. package/dist/notifications/dispatch-cooldown.js +109 -0
  1540. package/dist/notifications/dispatch-cooldown.js.map +1 -0
  1541. package/dist/notifications/dispatcher.d.ts +15 -0
  1542. package/dist/notifications/dispatcher.d.ts.map +1 -0
  1543. package/dist/notifications/dispatcher.js +385 -0
  1544. package/dist/notifications/dispatcher.js.map +1 -0
  1545. package/dist/notifications/formatter.d.ts +30 -0
  1546. package/dist/notifications/formatter.d.ts.map +1 -0
  1547. package/dist/notifications/formatter.js +234 -0
  1548. package/dist/notifications/formatter.js.map +1 -0
  1549. package/dist/notifications/hook-config-types.d.ts +43 -0
  1550. package/dist/notifications/hook-config-types.d.ts.map +1 -0
  1551. package/dist/notifications/hook-config-types.js +8 -0
  1552. package/dist/notifications/hook-config-types.js.map +1 -0
  1553. package/dist/notifications/hook-config.d.ts +40 -0
  1554. package/dist/notifications/hook-config.d.ts.map +1 -0
  1555. package/dist/notifications/hook-config.js +127 -0
  1556. package/dist/notifications/hook-config.js.map +1 -0
  1557. package/dist/notifications/http-client.d.ts +22 -0
  1558. package/dist/notifications/http-client.d.ts.map +1 -0
  1559. package/dist/notifications/http-client.js +349 -0
  1560. package/dist/notifications/http-client.js.map +1 -0
  1561. package/dist/notifications/idle-cooldown.d.ts +61 -0
  1562. package/dist/notifications/idle-cooldown.d.ts.map +1 -0
  1563. package/dist/notifications/idle-cooldown.js +207 -0
  1564. package/dist/notifications/idle-cooldown.js.map +1 -0
  1565. package/dist/notifications/index.d.ts +40 -0
  1566. package/dist/notifications/index.d.ts.map +1 -0
  1567. package/dist/notifications/index.js +228 -0
  1568. package/dist/notifications/index.js.map +1 -0
  1569. package/dist/notifications/lifecycle-dedupe.d.ts +8 -0
  1570. package/dist/notifications/lifecycle-dedupe.d.ts.map +1 -0
  1571. package/dist/notifications/lifecycle-dedupe.js +112 -0
  1572. package/dist/notifications/lifecycle-dedupe.js.map +1 -0
  1573. package/dist/notifications/notifier.d.ts +45 -0
  1574. package/dist/notifications/notifier.d.ts.map +1 -0
  1575. package/dist/notifications/notifier.js +146 -0
  1576. package/dist/notifications/notifier.js.map +1 -0
  1577. package/dist/notifications/reply-listener.d.ts +123 -0
  1578. package/dist/notifications/reply-listener.d.ts.map +1 -0
  1579. package/dist/notifications/reply-listener.js +846 -0
  1580. package/dist/notifications/reply-listener.js.map +1 -0
  1581. package/dist/notifications/session-registry.d.ts +26 -0
  1582. package/dist/notifications/session-registry.d.ts.map +1 -0
  1583. package/dist/notifications/session-registry.js +293 -0
  1584. package/dist/notifications/session-registry.js.map +1 -0
  1585. package/dist/notifications/session-status.d.ts +25 -0
  1586. package/dist/notifications/session-status.d.ts.map +1 -0
  1587. package/dist/notifications/session-status.js +202 -0
  1588. package/dist/notifications/session-status.js.map +1 -0
  1589. package/dist/notifications/temp-contract.d.ts +22 -0
  1590. package/dist/notifications/temp-contract.d.ts.map +1 -0
  1591. package/dist/notifications/temp-contract.js +147 -0
  1592. package/dist/notifications/temp-contract.js.map +1 -0
  1593. package/dist/notifications/template-engine.d.ts +34 -0
  1594. package/dist/notifications/template-engine.d.ts.map +1 -0
  1595. package/dist/notifications/template-engine.js +249 -0
  1596. package/dist/notifications/template-engine.js.map +1 -0
  1597. package/dist/notifications/tmux-detector.d.ts +59 -0
  1598. package/dist/notifications/tmux-detector.d.ts.map +1 -0
  1599. package/dist/notifications/tmux-detector.js +126 -0
  1600. package/dist/notifications/tmux-detector.js.map +1 -0
  1601. package/dist/notifications/tmux.d.ts +44 -0
  1602. package/dist/notifications/tmux.d.ts.map +1 -0
  1603. package/dist/notifications/tmux.js +293 -0
  1604. package/dist/notifications/tmux.js.map +1 -0
  1605. package/dist/notifications/types.d.ts +226 -0
  1606. package/dist/notifications/types.d.ts.map +1 -0
  1607. package/dist/notifications/types.js +9 -0
  1608. package/dist/notifications/types.js.map +1 -0
  1609. package/dist/openclaw/__tests__/config.test.d.ts +6 -0
  1610. package/dist/openclaw/__tests__/config.test.d.ts.map +1 -0
  1611. package/dist/openclaw/__tests__/config.test.js +344 -0
  1612. package/dist/openclaw/__tests__/config.test.js.map +1 -0
  1613. package/dist/openclaw/__tests__/dispatcher.test.d.ts +5 -0
  1614. package/dist/openclaw/__tests__/dispatcher.test.d.ts.map +1 -0
  1615. package/dist/openclaw/__tests__/dispatcher.test.js +278 -0
  1616. package/dist/openclaw/__tests__/dispatcher.test.js.map +1 -0
  1617. package/dist/openclaw/__tests__/index.test.d.ts +6 -0
  1618. package/dist/openclaw/__tests__/index.test.d.ts.map +1 -0
  1619. package/dist/openclaw/__tests__/index.test.js +382 -0
  1620. package/dist/openclaw/__tests__/index.test.js.map +1 -0
  1621. package/dist/openclaw/config.d.ts +59 -0
  1622. package/dist/openclaw/config.d.ts.map +1 -0
  1623. package/dist/openclaw/config.js +400 -0
  1624. package/dist/openclaw/config.js.map +1 -0
  1625. package/dist/openclaw/dispatcher.d.ts +75 -0
  1626. package/dist/openclaw/dispatcher.d.ts.map +1 -0
  1627. package/dist/openclaw/dispatcher.js +223 -0
  1628. package/dist/openclaw/dispatcher.js.map +1 -0
  1629. package/dist/openclaw/index.d.ts +29 -0
  1630. package/dist/openclaw/index.d.ts.map +1 -0
  1631. package/dist/openclaw/index.js +149 -0
  1632. package/dist/openclaw/index.js.map +1 -0
  1633. package/dist/openclaw/types.d.ts +123 -0
  1634. package/dist/openclaw/types.d.ts.map +1 -0
  1635. package/dist/openclaw/types.js +12 -0
  1636. package/dist/openclaw/types.js.map +1 -0
  1637. package/dist/performance-goal/artifacts.d.ts +76 -0
  1638. package/dist/performance-goal/artifacts.d.ts.map +1 -0
  1639. package/dist/performance-goal/artifacts.js +221 -0
  1640. package/dist/performance-goal/artifacts.js.map +1 -0
  1641. package/dist/pipeline/__tests__/orchestrator.test.d.ts +2 -0
  1642. package/dist/pipeline/__tests__/orchestrator.test.d.ts.map +1 -0
  1643. package/dist/pipeline/__tests__/orchestrator.test.js +645 -0
  1644. package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -0
  1645. package/dist/pipeline/__tests__/stages.test.d.ts +2 -0
  1646. package/dist/pipeline/__tests__/stages.test.d.ts.map +1 -0
  1647. package/dist/pipeline/__tests__/stages.test.js +1638 -0
  1648. package/dist/pipeline/__tests__/stages.test.js.map +1 -0
  1649. package/dist/pipeline/index.d.ts +25 -0
  1650. package/dist/pipeline/index.d.ts.map +1 -0
  1651. package/dist/pipeline/index.js +17 -0
  1652. package/dist/pipeline/index.js.map +1 -0
  1653. package/dist/pipeline/orchestrator.d.ts +52 -0
  1654. package/dist/pipeline/orchestrator.d.ts.map +1 -0
  1655. package/dist/pipeline/orchestrator.js +392 -0
  1656. package/dist/pipeline/orchestrator.js.map +1 -0
  1657. package/dist/pipeline/review-verdict.d.ts +3 -0
  1658. package/dist/pipeline/review-verdict.d.ts.map +1 -0
  1659. package/dist/pipeline/review-verdict.js +14 -0
  1660. package/dist/pipeline/review-verdict.js.map +1 -0
  1661. package/dist/pipeline/stages/code-review.d.ts +35 -0
  1662. package/dist/pipeline/stages/code-review.d.ts.map +1 -0
  1663. package/dist/pipeline/stages/code-review.js +55 -0
  1664. package/dist/pipeline/stages/code-review.js.map +1 -0
  1665. package/dist/pipeline/stages/deep-interview.d.ts +15 -0
  1666. package/dist/pipeline/stages/deep-interview.d.ts.map +1 -0
  1667. package/dist/pipeline/stages/deep-interview.js +32 -0
  1668. package/dist/pipeline/stages/deep-interview.js.map +1 -0
  1669. package/dist/pipeline/stages/ralph-verify.d.ts +53 -0
  1670. package/dist/pipeline/stages/ralph-verify.d.ts.map +1 -0
  1671. package/dist/pipeline/stages/ralph-verify.js +89 -0
  1672. package/dist/pipeline/stages/ralph-verify.js.map +1 -0
  1673. package/dist/pipeline/stages/ralplan.d.ts +26 -0
  1674. package/dist/pipeline/stages/ralplan.d.ts.map +1 -0
  1675. package/dist/pipeline/stages/ralplan.js +151 -0
  1676. package/dist/pipeline/stages/ralplan.js.map +1 -0
  1677. package/dist/pipeline/stages/team-exec.d.ts +52 -0
  1678. package/dist/pipeline/stages/team-exec.d.ts.map +1 -0
  1679. package/dist/pipeline/stages/team-exec.js +266 -0
  1680. package/dist/pipeline/stages/team-exec.js.map +1 -0
  1681. package/dist/pipeline/stages/ultragoal.d.ts +19 -0
  1682. package/dist/pipeline/stages/ultragoal.d.ts.map +1 -0
  1683. package/dist/pipeline/stages/ultragoal.js +38 -0
  1684. package/dist/pipeline/stages/ultragoal.js.map +1 -0
  1685. package/dist/pipeline/stages/ultraqa.d.ts +33 -0
  1686. package/dist/pipeline/stages/ultraqa.d.ts.map +1 -0
  1687. package/dist/pipeline/stages/ultraqa.js +49 -0
  1688. package/dist/pipeline/stages/ultraqa.js.map +1 -0
  1689. package/dist/pipeline/types.d.ts +124 -0
  1690. package/dist/pipeline/types.d.ts.map +1 -0
  1691. package/dist/pipeline/types.js +8 -0
  1692. package/dist/pipeline/types.js.map +1 -0
  1693. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts +2 -0
  1694. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts.map +1 -0
  1695. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js +158 -0
  1696. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -0
  1697. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts +2 -0
  1698. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts.map +1 -0
  1699. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js +440 -0
  1700. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js.map +1 -0
  1701. package/dist/planning/__tests__/artifacts.test.d.ts +2 -0
  1702. package/dist/planning/__tests__/artifacts.test.d.ts.map +1 -0
  1703. package/dist/planning/__tests__/artifacts.test.js +942 -0
  1704. package/dist/planning/__tests__/artifacts.test.js.map +1 -0
  1705. package/dist/planning/__tests__/markdown-structure.test.d.ts +2 -0
  1706. package/dist/planning/__tests__/markdown-structure.test.d.ts.map +1 -0
  1707. package/dist/planning/__tests__/markdown-structure.test.js +459 -0
  1708. package/dist/planning/__tests__/markdown-structure.test.js.map +1 -0
  1709. package/dist/planning/artifact-names.d.ts +13 -0
  1710. package/dist/planning/artifact-names.d.ts.map +1 -0
  1711. package/dist/planning/artifact-names.js +108 -0
  1712. package/dist/planning/artifact-names.js.map +1 -0
  1713. package/dist/planning/artifacts.d.ts +65 -0
  1714. package/dist/planning/artifacts.d.ts.map +1 -0
  1715. package/dist/planning/artifacts.js +561 -0
  1716. package/dist/planning/artifacts.js.map +1 -0
  1717. package/dist/planning/markdown-structure.d.ts +20 -0
  1718. package/dist/planning/markdown-structure.d.ts.map +1 -0
  1719. package/dist/planning/markdown-structure.js +137 -0
  1720. package/dist/planning/markdown-structure.js.map +1 -0
  1721. package/dist/question/__tests__/client.test.d.ts +2 -0
  1722. package/dist/question/__tests__/client.test.d.ts.map +1 -0
  1723. package/dist/question/__tests__/client.test.js +90 -0
  1724. package/dist/question/__tests__/client.test.js.map +1 -0
  1725. package/dist/question/__tests__/deep-interview.test.d.ts +2 -0
  1726. package/dist/question/__tests__/deep-interview.test.d.ts.map +1 -0
  1727. package/dist/question/__tests__/deep-interview.test.js +440 -0
  1728. package/dist/question/__tests__/deep-interview.test.js.map +1 -0
  1729. package/dist/question/__tests__/policy.test.d.ts +2 -0
  1730. package/dist/question/__tests__/policy.test.d.ts.map +1 -0
  1731. package/dist/question/__tests__/policy.test.js +273 -0
  1732. package/dist/question/__tests__/policy.test.js.map +1 -0
  1733. package/dist/question/__tests__/renderer.test.d.ts +2 -0
  1734. package/dist/question/__tests__/renderer.test.d.ts.map +1 -0
  1735. package/dist/question/__tests__/renderer.test.js +1461 -0
  1736. package/dist/question/__tests__/renderer.test.js.map +1 -0
  1737. package/dist/question/__tests__/state.test.d.ts +2 -0
  1738. package/dist/question/__tests__/state.test.d.ts.map +1 -0
  1739. package/dist/question/__tests__/state.test.js +541 -0
  1740. package/dist/question/__tests__/state.test.js.map +1 -0
  1741. package/dist/question/__tests__/types.test.d.ts +2 -0
  1742. package/dist/question/__tests__/types.test.d.ts.map +1 -0
  1743. package/dist/question/__tests__/types.test.js +65 -0
  1744. package/dist/question/__tests__/types.test.js.map +1 -0
  1745. package/dist/question/__tests__/ui.test.d.ts +2 -0
  1746. package/dist/question/__tests__/ui.test.d.ts.map +1 -0
  1747. package/dist/question/__tests__/ui.test.js +483 -0
  1748. package/dist/question/__tests__/ui.test.js.map +1 -0
  1749. package/dist/question/autopilot-wait.d.ts +21 -0
  1750. package/dist/question/autopilot-wait.d.ts.map +1 -0
  1751. package/dist/question/autopilot-wait.js +251 -0
  1752. package/dist/question/autopilot-wait.js.map +1 -0
  1753. package/dist/question/client.d.ts +64 -0
  1754. package/dist/question/client.d.ts.map +1 -0
  1755. package/dist/question/client.js +77 -0
  1756. package/dist/question/client.js.map +1 -0
  1757. package/dist/question/deep-interview.d.ts +33 -0
  1758. package/dist/question/deep-interview.d.ts.map +1 -0
  1759. package/dist/question/deep-interview.js +216 -0
  1760. package/dist/question/deep-interview.js.map +1 -0
  1761. package/dist/question/events.d.ts +53 -0
  1762. package/dist/question/events.d.ts.map +1 -0
  1763. package/dist/question/events.js +201 -0
  1764. package/dist/question/events.js.map +1 -0
  1765. package/dist/question/policy.d.ts +19 -0
  1766. package/dist/question/policy.d.ts.map +1 -0
  1767. package/dist/question/policy.js +95 -0
  1768. package/dist/question/policy.js.map +1 -0
  1769. package/dist/question/renderer.d.ts +66 -0
  1770. package/dist/question/renderer.d.ts.map +1 -0
  1771. package/dist/question/renderer.js +748 -0
  1772. package/dist/question/renderer.js.map +1 -0
  1773. package/dist/question/state.d.ts +56 -0
  1774. package/dist/question/state.d.ts.map +1 -0
  1775. package/dist/question/state.js +432 -0
  1776. package/dist/question/state.js.map +1 -0
  1777. package/dist/question/types.d.ts +92 -0
  1778. package/dist/question/types.d.ts.map +1 -0
  1779. package/dist/question/types.js +117 -0
  1780. package/dist/question/types.js.map +1 -0
  1781. package/dist/question/ui.d.ts +66 -0
  1782. package/dist/question/ui.d.ts.map +1 -0
  1783. package/dist/question/ui.js +458 -0
  1784. package/dist/question/ui.js.map +1 -0
  1785. package/dist/ralph/__tests__/completion-audit.test.d.ts +2 -0
  1786. package/dist/ralph/__tests__/completion-audit.test.d.ts.map +1 -0
  1787. package/dist/ralph/__tests__/completion-audit.test.js +160 -0
  1788. package/dist/ralph/__tests__/completion-audit.test.js.map +1 -0
  1789. package/dist/ralph/__tests__/persistence.test.d.ts +2 -0
  1790. package/dist/ralph/__tests__/persistence.test.d.ts.map +1 -0
  1791. package/dist/ralph/__tests__/persistence.test.js +116 -0
  1792. package/dist/ralph/__tests__/persistence.test.js.map +1 -0
  1793. package/dist/ralph/completion-audit.d.ts +8 -0
  1794. package/dist/ralph/completion-audit.d.ts.map +1 -0
  1795. package/dist/ralph/completion-audit.js +99 -0
  1796. package/dist/ralph/completion-audit.js.map +1 -0
  1797. package/dist/ralph/contract.d.ts +17 -0
  1798. package/dist/ralph/contract.d.ts.map +1 -0
  1799. package/dist/ralph/contract.js +108 -0
  1800. package/dist/ralph/contract.js.map +1 -0
  1801. package/dist/ralph/persistence.d.ts +29 -0
  1802. package/dist/ralph/persistence.d.ts.map +1 -0
  1803. package/dist/ralph/persistence.js +273 -0
  1804. package/dist/ralph/persistence.js.map +1 -0
  1805. package/dist/ralplan/__tests__/consensus-gate.test.d.ts +2 -0
  1806. package/dist/ralplan/__tests__/consensus-gate.test.d.ts.map +1 -0
  1807. package/dist/ralplan/__tests__/consensus-gate.test.js +192 -0
  1808. package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -0
  1809. package/dist/ralplan/__tests__/runtime.test.d.ts +2 -0
  1810. package/dist/ralplan/__tests__/runtime.test.d.ts.map +1 -0
  1811. package/dist/ralplan/__tests__/runtime.test.js +548 -0
  1812. package/dist/ralplan/__tests__/runtime.test.js.map +1 -0
  1813. package/dist/ralplan/consensus-gate.d.ts +37 -0
  1814. package/dist/ralplan/consensus-gate.d.ts.map +1 -0
  1815. package/dist/ralplan/consensus-gate.js +422 -0
  1816. package/dist/ralplan/consensus-gate.js.map +1 -0
  1817. package/dist/ralplan/runtime.d.ts +86 -0
  1818. package/dist/ralplan/runtime.d.ts.map +1 -0
  1819. package/dist/ralplan/runtime.js +365 -0
  1820. package/dist/ralplan/runtime.js.map +1 -0
  1821. package/dist/runtime/__tests__/bridge.test.d.ts +2 -0
  1822. package/dist/runtime/__tests__/bridge.test.d.ts.map +1 -0
  1823. package/dist/runtime/__tests__/bridge.test.js +194 -0
  1824. package/dist/runtime/__tests__/bridge.test.js.map +1 -0
  1825. package/dist/runtime/__tests__/process-tree.test.d.ts +2 -0
  1826. package/dist/runtime/__tests__/process-tree.test.d.ts.map +1 -0
  1827. package/dist/runtime/__tests__/process-tree.test.js +107 -0
  1828. package/dist/runtime/__tests__/process-tree.test.js.map +1 -0
  1829. package/dist/runtime/__tests__/run-loop.test.d.ts +2 -0
  1830. package/dist/runtime/__tests__/run-loop.test.d.ts.map +1 -0
  1831. package/dist/runtime/__tests__/run-loop.test.js +35 -0
  1832. package/dist/runtime/__tests__/run-loop.test.js.map +1 -0
  1833. package/dist/runtime/__tests__/run-outcome.test.d.ts +2 -0
  1834. package/dist/runtime/__tests__/run-outcome.test.d.ts.map +1 -0
  1835. package/dist/runtime/__tests__/run-outcome.test.js +102 -0
  1836. package/dist/runtime/__tests__/run-outcome.test.js.map +1 -0
  1837. package/dist/runtime/__tests__/run-state.test.d.ts +2 -0
  1838. package/dist/runtime/__tests__/run-state.test.d.ts.map +1 -0
  1839. package/dist/runtime/__tests__/run-state.test.js +37 -0
  1840. package/dist/runtime/__tests__/run-state.test.js.map +1 -0
  1841. package/dist/runtime/bridge.d.ts +214 -0
  1842. package/dist/runtime/bridge.d.ts.map +1 -0
  1843. package/dist/runtime/bridge.js +223 -0
  1844. package/dist/runtime/bridge.js.map +1 -0
  1845. package/dist/runtime/process-tree.d.ts +28 -0
  1846. package/dist/runtime/process-tree.d.ts.map +1 -0
  1847. package/dist/runtime/process-tree.js +230 -0
  1848. package/dist/runtime/process-tree.js.map +1 -0
  1849. package/dist/runtime/run-loop.d.ts +45 -0
  1850. package/dist/runtime/run-loop.d.ts.map +1 -0
  1851. package/dist/runtime/run-loop.js +51 -0
  1852. package/dist/runtime/run-loop.js.map +1 -0
  1853. package/dist/runtime/run-outcome.d.ts +46 -0
  1854. package/dist/runtime/run-outcome.d.ts.map +1 -0
  1855. package/dist/runtime/run-outcome.js +285 -0
  1856. package/dist/runtime/run-outcome.js.map +1 -0
  1857. package/dist/runtime/run-state.d.ts +40 -0
  1858. package/dist/runtime/run-state.d.ts.map +1 -0
  1859. package/dist/runtime/run-state.js +120 -0
  1860. package/dist/runtime/run-state.js.map +1 -0
  1861. package/dist/runtime/terminal-lifecycle.d.ts +11 -0
  1862. package/dist/runtime/terminal-lifecycle.d.ts.map +1 -0
  1863. package/dist/runtime/terminal-lifecycle.js +52 -0
  1864. package/dist/runtime/terminal-lifecycle.js.map +1 -0
  1865. package/dist/scripts/__tests__/codex-native-hook.test.d.ts +2 -0
  1866. package/dist/scripts/__tests__/codex-native-hook.test.d.ts.map +1 -0
  1867. package/dist/scripts/__tests__/codex-native-hook.test.js +14253 -0
  1868. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -0
  1869. package/dist/scripts/__tests__/docs-site-contract.test.d.ts +2 -0
  1870. package/dist/scripts/__tests__/docs-site-contract.test.d.ts.map +1 -0
  1871. package/dist/scripts/__tests__/docs-site-contract.test.js +42 -0
  1872. package/dist/scripts/__tests__/docs-site-contract.test.js.map +1 -0
  1873. package/dist/scripts/__tests__/generate-release-body.test.d.ts +2 -0
  1874. package/dist/scripts/__tests__/generate-release-body.test.d.ts.map +1 -0
  1875. package/dist/scripts/__tests__/generate-release-body.test.js +233 -0
  1876. package/dist/scripts/__tests__/generate-release-body.test.js.map +1 -0
  1877. package/dist/scripts/__tests__/hook-derived-watcher.test.d.ts +2 -0
  1878. package/dist/scripts/__tests__/hook-derived-watcher.test.d.ts.map +1 -0
  1879. package/dist/scripts/__tests__/hook-derived-watcher.test.js +227 -0
  1880. package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +1 -0
  1881. package/dist/scripts/__tests__/notify-dispatcher.test.d.ts +2 -0
  1882. package/dist/scripts/__tests__/notify-dispatcher.test.d.ts.map +1 -0
  1883. package/dist/scripts/__tests__/notify-dispatcher.test.js +421 -0
  1884. package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -0
  1885. package/dist/scripts/__tests__/notify-state-io.test.d.ts +2 -0
  1886. package/dist/scripts/__tests__/notify-state-io.test.d.ts.map +1 -0
  1887. package/dist/scripts/__tests__/notify-state-io.test.js +111 -0
  1888. package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -0
  1889. package/dist/scripts/__tests__/notify-tmux-injection.test.d.ts +2 -0
  1890. package/dist/scripts/__tests__/notify-tmux-injection.test.d.ts.map +1 -0
  1891. package/dist/scripts/__tests__/notify-tmux-injection.test.js +57 -0
  1892. package/dist/scripts/__tests__/notify-tmux-injection.test.js.map +1 -0
  1893. package/dist/scripts/__tests__/postinstall.test.d.ts +2 -0
  1894. package/dist/scripts/__tests__/postinstall.test.d.ts.map +1 -0
  1895. package/dist/scripts/__tests__/postinstall.test.js +92 -0
  1896. package/dist/scripts/__tests__/postinstall.test.js.map +1 -0
  1897. package/dist/scripts/__tests__/prompt-inventory.test.d.ts +2 -0
  1898. package/dist/scripts/__tests__/prompt-inventory.test.d.ts.map +1 -0
  1899. package/dist/scripts/__tests__/prompt-inventory.test.js +56 -0
  1900. package/dist/scripts/__tests__/prompt-inventory.test.js.map +1 -0
  1901. package/dist/scripts/__tests__/run-test-files.test.d.ts +2 -0
  1902. package/dist/scripts/__tests__/run-test-files.test.d.ts.map +1 -0
  1903. package/dist/scripts/__tests__/run-test-files.test.js +365 -0
  1904. package/dist/scripts/__tests__/run-test-files.test.js.map +1 -0
  1905. package/dist/scripts/__tests__/smoke-packed-install.test.d.ts +2 -0
  1906. package/dist/scripts/__tests__/smoke-packed-install.test.d.ts.map +1 -0
  1907. package/dist/scripts/__tests__/smoke-packed-install.test.js +160 -0
  1908. package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -0
  1909. package/dist/scripts/__tests__/test-reply-listener-live.test.d.ts +2 -0
  1910. package/dist/scripts/__tests__/test-reply-listener-live.test.d.ts.map +1 -0
  1911. package/dist/scripts/__tests__/test-reply-listener-live.test.js +82 -0
  1912. package/dist/scripts/__tests__/test-reply-listener-live.test.js.map +1 -0
  1913. package/dist/scripts/__tests__/verify-native-agents.test.d.ts +2 -0
  1914. package/dist/scripts/__tests__/verify-native-agents.test.d.ts.map +1 -0
  1915. package/dist/scripts/__tests__/verify-native-agents.test.js +246 -0
  1916. package/dist/scripts/__tests__/verify-native-agents.test.js.map +1 -0
  1917. package/dist/scripts/build-api.d.ts +2 -0
  1918. package/dist/scripts/build-api.d.ts.map +1 -0
  1919. package/dist/scripts/build-api.js +44 -0
  1920. package/dist/scripts/build-api.js.map +1 -0
  1921. package/dist/scripts/build-explore-harness.d.ts +3 -0
  1922. package/dist/scripts/build-explore-harness.d.ts.map +1 -0
  1923. package/dist/scripts/build-explore-harness.js +50 -0
  1924. package/dist/scripts/build-explore-harness.js.map +1 -0
  1925. package/dist/scripts/build-sparkshell.d.ts +2 -0
  1926. package/dist/scripts/build-sparkshell.d.ts.map +1 -0
  1927. package/dist/scripts/build-sparkshell.js +46 -0
  1928. package/dist/scripts/build-sparkshell.js.map +1 -0
  1929. package/dist/scripts/check-runtime-syntax.d.ts +3 -0
  1930. package/dist/scripts/check-runtime-syntax.d.ts.map +1 -0
  1931. package/dist/scripts/check-runtime-syntax.js +57 -0
  1932. package/dist/scripts/check-runtime-syntax.js.map +1 -0
  1933. package/dist/scripts/check-version-sync.d.ts +3 -0
  1934. package/dist/scripts/check-version-sync.d.ts.map +1 -0
  1935. package/dist/scripts/check-version-sync.js +53 -0
  1936. package/dist/scripts/check-version-sync.js.map +1 -0
  1937. package/dist/scripts/cleanup-explore-harness.d.ts +3 -0
  1938. package/dist/scripts/cleanup-explore-harness.d.ts.map +1 -0
  1939. package/dist/scripts/cleanup-explore-harness.js +17 -0
  1940. package/dist/scripts/cleanup-explore-harness.js.map +1 -0
  1941. package/dist/scripts/codex-execution-surface.d.ts +16 -0
  1942. package/dist/scripts/codex-execution-surface.d.ts.map +1 -0
  1943. package/dist/scripts/codex-execution-surface.js +42 -0
  1944. package/dist/scripts/codex-execution-surface.js.map +1 -0
  1945. package/dist/scripts/codex-native-hook.d.ts +26 -0
  1946. package/dist/scripts/codex-native-hook.d.ts.map +1 -0
  1947. package/dist/scripts/codex-native-hook.js +3842 -0
  1948. package/dist/scripts/codex-native-hook.js.map +1 -0
  1949. package/dist/scripts/codex-native-pre-post.d.ts +46 -0
  1950. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -0
  1951. package/dist/scripts/codex-native-pre-post.js +1186 -0
  1952. package/dist/scripts/codex-native-pre-post.js.map +1 -0
  1953. package/dist/scripts/eval/eval-candidate-handoff.d.ts +2 -0
  1954. package/dist/scripts/eval/eval-candidate-handoff.d.ts.map +1 -0
  1955. package/dist/scripts/eval/eval-candidate-handoff.js +11 -0
  1956. package/dist/scripts/eval/eval-candidate-handoff.js.map +1 -0
  1957. package/dist/scripts/eval/eval-cli-discoverability.d.ts +3 -0
  1958. package/dist/scripts/eval/eval-cli-discoverability.d.ts.map +1 -0
  1959. package/dist/scripts/eval/eval-cli-discoverability.js +37 -0
  1960. package/dist/scripts/eval/eval-cli-discoverability.js.map +1 -0
  1961. package/dist/scripts/eval/eval-fresh-run-tagging.d.ts +2 -0
  1962. package/dist/scripts/eval/eval-fresh-run-tagging.d.ts.map +1 -0
  1963. package/dist/scripts/eval/eval-fresh-run-tagging.js +11 -0
  1964. package/dist/scripts/eval/eval-fresh-run-tagging.js.map +1 -0
  1965. package/dist/scripts/eval/eval-help-consistency.d.ts +2 -0
  1966. package/dist/scripts/eval/eval-help-consistency.d.ts.map +1 -0
  1967. package/dist/scripts/eval/eval-help-consistency.js +12 -0
  1968. package/dist/scripts/eval/eval-help-consistency.js.map +1 -0
  1969. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.d.ts +2 -0
  1970. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.d.ts.map +1 -0
  1971. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.js +31 -0
  1972. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.js.map +1 -0
  1973. package/dist/scripts/eval/eval-parity-smoke.d.ts +2 -0
  1974. package/dist/scripts/eval/eval-parity-smoke.d.ts.map +1 -0
  1975. package/dist/scripts/eval/eval-parity-smoke.js +23 -0
  1976. package/dist/scripts/eval/eval-parity-smoke.js.map +1 -0
  1977. package/dist/scripts/eval/eval-parity-sweep.d.ts +2 -0
  1978. package/dist/scripts/eval/eval-parity-sweep.d.ts.map +1 -0
  1979. package/dist/scripts/eval/eval-parity-sweep.js +29 -0
  1980. package/dist/scripts/eval/eval-parity-sweep.js.map +1 -0
  1981. package/dist/scripts/eval/eval-resume-dirty-guard.d.ts +2 -0
  1982. package/dist/scripts/eval/eval-resume-dirty-guard.d.ts.map +1 -0
  1983. package/dist/scripts/eval/eval-resume-dirty-guard.js +11 -0
  1984. package/dist/scripts/eval/eval-resume-dirty-guard.js.map +1 -0
  1985. package/dist/scripts/eval/eval-security-path-traversal.d.ts +3 -0
  1986. package/dist/scripts/eval/eval-security-path-traversal.d.ts.map +1 -0
  1987. package/dist/scripts/eval/eval-security-path-traversal.js +35 -0
  1988. package/dist/scripts/eval/eval-security-path-traversal.js.map +1 -0
  1989. package/dist/scripts/fixtures/ask-advisor-stub.d.ts +3 -0
  1990. package/dist/scripts/fixtures/ask-advisor-stub.d.ts.map +1 -0
  1991. package/dist/scripts/fixtures/ask-advisor-stub.js +13 -0
  1992. package/dist/scripts/fixtures/ask-advisor-stub.js.map +1 -0
  1993. package/dist/scripts/generate-catalog-docs.d.ts +3 -0
  1994. package/dist/scripts/generate-catalog-docs.d.ts.map +1 -0
  1995. package/dist/scripts/generate-catalog-docs.js +99 -0
  1996. package/dist/scripts/generate-catalog-docs.js.map +1 -0
  1997. package/dist/scripts/generate-native-release-manifest.d.ts +3 -0
  1998. package/dist/scripts/generate-native-release-manifest.d.ts.map +1 -0
  1999. package/dist/scripts/generate-native-release-manifest.js +107 -0
  2000. package/dist/scripts/generate-native-release-manifest.js.map +1 -0
  2001. package/dist/scripts/generate-release-body.d.ts +35 -0
  2002. package/dist/scripts/generate-release-body.d.ts.map +1 -0
  2003. package/dist/scripts/generate-release-body.js +278 -0
  2004. package/dist/scripts/generate-release-body.js.map +1 -0
  2005. package/dist/scripts/hook-derived-watcher.d.ts +3 -0
  2006. package/dist/scripts/hook-derived-watcher.d.ts.map +1 -0
  2007. package/dist/scripts/hook-derived-watcher.js +557 -0
  2008. package/dist/scripts/hook-derived-watcher.js.map +1 -0
  2009. package/dist/scripts/hook-payload-guard.d.ts +9 -0
  2010. package/dist/scripts/hook-payload-guard.d.ts.map +1 -0
  2011. package/dist/scripts/hook-payload-guard.js +111 -0
  2012. package/dist/scripts/hook-payload-guard.js.map +1 -0
  2013. package/dist/scripts/notify-dispatcher.d.ts +7 -0
  2014. package/dist/scripts/notify-dispatcher.d.ts.map +1 -0
  2015. package/dist/scripts/notify-dispatcher.js +359 -0
  2016. package/dist/scripts/notify-dispatcher.js.map +1 -0
  2017. package/dist/scripts/notify-fallback-watcher.d.ts +3 -0
  2018. package/dist/scripts/notify-fallback-watcher.d.ts.map +1 -0
  2019. package/dist/scripts/notify-fallback-watcher.js +1771 -0
  2020. package/dist/scripts/notify-fallback-watcher.js.map +1 -0
  2021. package/dist/scripts/notify-hook/__tests__/operational-events.test.d.ts +2 -0
  2022. package/dist/scripts/notify-hook/__tests__/operational-events.test.d.ts.map +1 -0
  2023. package/dist/scripts/notify-hook/__tests__/operational-events.test.js +24 -0
  2024. package/dist/scripts/notify-hook/__tests__/operational-events.test.js.map +1 -0
  2025. package/dist/scripts/notify-hook/__tests__/payload-guard.test.d.ts +2 -0
  2026. package/dist/scripts/notify-hook/__tests__/payload-guard.test.d.ts.map +1 -0
  2027. package/dist/scripts/notify-hook/__tests__/payload-guard.test.js +39 -0
  2028. package/dist/scripts/notify-hook/__tests__/payload-guard.test.js.map +1 -0
  2029. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts +2 -0
  2030. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts.map +1 -0
  2031. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js +153 -0
  2032. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js.map +1 -0
  2033. package/dist/scripts/notify-hook/active-team.d.ts +9 -0
  2034. package/dist/scripts/notify-hook/active-team.d.ts.map +1 -0
  2035. package/dist/scripts/notify-hook/active-team.js +45 -0
  2036. package/dist/scripts/notify-hook/active-team.js.map +1 -0
  2037. package/dist/scripts/notify-hook/auto-nudge.d.ts +96 -0
  2038. package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -0
  2039. package/dist/scripts/notify-hook/auto-nudge.js +698 -0
  2040. package/dist/scripts/notify-hook/auto-nudge.js.map +1 -0
  2041. package/dist/scripts/notify-hook/log.d.ts +6 -0
  2042. package/dist/scripts/notify-hook/log.d.ts.map +1 -0
  2043. package/dist/scripts/notify-hook/log.js +22 -0
  2044. package/dist/scripts/notify-hook/log.js.map +1 -0
  2045. package/dist/scripts/notify-hook/managed-tmux.d.ts +21 -0
  2046. package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -0
  2047. package/dist/scripts/notify-hook/managed-tmux.js +541 -0
  2048. package/dist/scripts/notify-hook/managed-tmux.js.map +1 -0
  2049. package/dist/scripts/notify-hook/operational-events.d.ts +14 -0
  2050. package/dist/scripts/notify-hook/operational-events.d.ts.map +1 -0
  2051. package/dist/scripts/notify-hook/operational-events.js +255 -0
  2052. package/dist/scripts/notify-hook/operational-events.js.map +1 -0
  2053. package/dist/scripts/notify-hook/orchestration-intent.d.ts +17 -0
  2054. package/dist/scripts/notify-hook/orchestration-intent.d.ts.map +1 -0
  2055. package/dist/scripts/notify-hook/orchestration-intent.js +71 -0
  2056. package/dist/scripts/notify-hook/orchestration-intent.js.map +1 -0
  2057. package/dist/scripts/notify-hook/payload-parser.d.ts +13 -0
  2058. package/dist/scripts/notify-hook/payload-parser.d.ts.map +1 -0
  2059. package/dist/scripts/notify-hook/payload-parser.js +134 -0
  2060. package/dist/scripts/notify-hook/payload-parser.js.map +1 -0
  2061. package/dist/scripts/notify-hook/process-runner.d.ts +9 -0
  2062. package/dist/scripts/notify-hook/process-runner.d.ts.map +1 -0
  2063. package/dist/scripts/notify-hook/process-runner.js +74 -0
  2064. package/dist/scripts/notify-hook/process-runner.js.map +1 -0
  2065. package/dist/scripts/notify-hook/ralph-session-resume.d.ts +22 -0
  2066. package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -0
  2067. package/dist/scripts/notify-hook/ralph-session-resume.js +381 -0
  2068. package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -0
  2069. package/dist/scripts/notify-hook/state-io.d.ts +21 -0
  2070. package/dist/scripts/notify-hook/state-io.d.ts.map +1 -0
  2071. package/dist/scripts/notify-hook/state-io.js +169 -0
  2072. package/dist/scripts/notify-hook/state-io.js.map +1 -0
  2073. package/dist/scripts/notify-hook/team-dispatch.d.ts +36 -0
  2074. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -0
  2075. package/dist/scripts/notify-hook/team-dispatch.js +1084 -0
  2076. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -0
  2077. package/dist/scripts/notify-hook/team-leader-nudge.d.ts +21 -0
  2078. package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -0
  2079. package/dist/scripts/notify-hook/team-leader-nudge.js +1029 -0
  2080. package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -0
  2081. package/dist/scripts/notify-hook/team-tmux-guard.d.ts +15 -0
  2082. package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -0
  2083. package/dist/scripts/notify-hook/team-tmux-guard.js +205 -0
  2084. package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -0
  2085. package/dist/scripts/notify-hook/team-worker-posttooluse.d.ts +34 -0
  2086. package/dist/scripts/notify-hook/team-worker-posttooluse.d.ts.map +1 -0
  2087. package/dist/scripts/notify-hook/team-worker-posttooluse.js +434 -0
  2088. package/dist/scripts/notify-hook/team-worker-posttooluse.js.map +1 -0
  2089. package/dist/scripts/notify-hook/team-worker-stop.d.ts +15 -0
  2090. package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -0
  2091. package/dist/scripts/notify-hook/team-worker-stop.js +418 -0
  2092. package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -0
  2093. package/dist/scripts/notify-hook/team-worker.d.ts +33 -0
  2094. package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -0
  2095. package/dist/scripts/notify-hook/team-worker.js +705 -0
  2096. package/dist/scripts/notify-hook/team-worker.js.map +1 -0
  2097. package/dist/scripts/notify-hook/tmux-injection.d.ts +15 -0
  2098. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -0
  2099. package/dist/scripts/notify-hook/tmux-injection.js +673 -0
  2100. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -0
  2101. package/dist/scripts/notify-hook/utils.d.ts +9 -0
  2102. package/dist/scripts/notify-hook/utils.d.ts.map +1 -0
  2103. package/dist/scripts/notify-hook/utils.js +36 -0
  2104. package/dist/scripts/notify-hook/utils.js.map +1 -0
  2105. package/dist/scripts/notify-hook/visual-verdict.d.ts +29 -0
  2106. package/dist/scripts/notify-hook/visual-verdict.d.ts.map +1 -0
  2107. package/dist/scripts/notify-hook/visual-verdict.js +145 -0
  2108. package/dist/scripts/notify-hook/visual-verdict.js.map +1 -0
  2109. package/dist/scripts/notify-hook.d.ts +20 -0
  2110. package/dist/scripts/notify-hook.d.ts.map +1 -0
  2111. package/dist/scripts/notify-hook.js +950 -0
  2112. package/dist/scripts/notify-hook.js.map +1 -0
  2113. package/dist/scripts/postinstall.d.ts +18 -0
  2114. package/dist/scripts/postinstall.d.ts.map +1 -0
  2115. package/dist/scripts/postinstall.js +66 -0
  2116. package/dist/scripts/postinstall.js.map +1 -0
  2117. package/dist/scripts/prompt-inventory.d.ts +29 -0
  2118. package/dist/scripts/prompt-inventory.d.ts.map +1 -0
  2119. package/dist/scripts/prompt-inventory.js +178 -0
  2120. package/dist/scripts/prompt-inventory.js.map +1 -0
  2121. package/dist/scripts/run-provider-advisor.d.ts +3 -0
  2122. package/dist/scripts/run-provider-advisor.d.ts.map +1 -0
  2123. package/dist/scripts/run-provider-advisor.js +177 -0
  2124. package/dist/scripts/run-provider-advisor.js.map +1 -0
  2125. package/dist/scripts/run-test-files.d.ts +2 -0
  2126. package/dist/scripts/run-test-files.d.ts.map +1 -0
  2127. package/dist/scripts/run-test-files.js +340 -0
  2128. package/dist/scripts/run-test-files.js.map +1 -0
  2129. package/dist/scripts/smoke-packed-install.d.ts +21 -0
  2130. package/dist/scripts/smoke-packed-install.d.ts.map +1 -0
  2131. package/dist/scripts/smoke-packed-install.js +221 -0
  2132. package/dist/scripts/smoke-packed-install.js.map +1 -0
  2133. package/dist/scripts/sync-plugin-mirror.d.ts +14 -0
  2134. package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -0
  2135. package/dist/scripts/sync-plugin-mirror.js +306 -0
  2136. package/dist/scripts/sync-plugin-mirror.js.map +1 -0
  2137. package/dist/scripts/sync-prompt-guidance-fragments.d.ts +3 -0
  2138. package/dist/scripts/sync-prompt-guidance-fragments.d.ts.map +1 -0
  2139. package/dist/scripts/sync-prompt-guidance-fragments.js +50 -0
  2140. package/dist/scripts/sync-prompt-guidance-fragments.js.map +1 -0
  2141. package/dist/scripts/team-hardening-benchmark.d.ts +3 -0
  2142. package/dist/scripts/team-hardening-benchmark.d.ts.map +1 -0
  2143. package/dist/scripts/team-hardening-benchmark.js +91 -0
  2144. package/dist/scripts/team-hardening-benchmark.js.map +1 -0
  2145. package/dist/scripts/test-reply-listener-live.d.ts +24 -0
  2146. package/dist/scripts/test-reply-listener-live.d.ts.map +1 -0
  2147. package/dist/scripts/test-reply-listener-live.js +138 -0
  2148. package/dist/scripts/test-reply-listener-live.js.map +1 -0
  2149. package/dist/scripts/test-sparkshell.d.ts +2 -0
  2150. package/dist/scripts/test-sparkshell.d.ts.map +1 -0
  2151. package/dist/scripts/test-sparkshell.js +25 -0
  2152. package/dist/scripts/test-sparkshell.js.map +1 -0
  2153. package/dist/scripts/tmux-hook-engine.d.ts +45 -0
  2154. package/dist/scripts/tmux-hook-engine.d.ts.map +1 -0
  2155. package/dist/scripts/tmux-hook-engine.js +313 -0
  2156. package/dist/scripts/tmux-hook-engine.js.map +1 -0
  2157. package/dist/scripts/verify-native-agents.d.ts +16 -0
  2158. package/dist/scripts/verify-native-agents.d.ts.map +1 -0
  2159. package/dist/scripts/verify-native-agents.js +247 -0
  2160. package/dist/scripts/verify-native-agents.js.map +1 -0
  2161. package/dist/scripts/verify-native-release-assets.d.ts +3 -0
  2162. package/dist/scripts/verify-native-release-assets.d.ts.map +1 -0
  2163. package/dist/scripts/verify-native-release-assets.js +62 -0
  2164. package/dist/scripts/verify-native-release-assets.js.map +1 -0
  2165. package/dist/session-history/__tests__/search.test.d.ts +2 -0
  2166. package/dist/session-history/__tests__/search.test.d.ts.map +1 -0
  2167. package/dist/session-history/__tests__/search.test.js +150 -0
  2168. package/dist/session-history/__tests__/search.test.js.map +1 -0
  2169. package/dist/session-history/search.d.ts +31 -0
  2170. package/dist/session-history/search.d.ts.map +1 -0
  2171. package/dist/session-history/search.js +331 -0
  2172. package/dist/session-history/search.js.map +1 -0
  2173. package/dist/sidecar/__tests__/boundary.test.d.ts +2 -0
  2174. package/dist/sidecar/__tests__/boundary.test.d.ts.map +1 -0
  2175. package/dist/sidecar/__tests__/boundary.test.js +48 -0
  2176. package/dist/sidecar/__tests__/boundary.test.js.map +1 -0
  2177. package/dist/sidecar/__tests__/collector.test.d.ts +2 -0
  2178. package/dist/sidecar/__tests__/collector.test.d.ts.map +1 -0
  2179. package/dist/sidecar/__tests__/collector.test.js +162 -0
  2180. package/dist/sidecar/__tests__/collector.test.js.map +1 -0
  2181. package/dist/sidecar/__tests__/render.test.d.ts +2 -0
  2182. package/dist/sidecar/__tests__/render.test.d.ts.map +1 -0
  2183. package/dist/sidecar/__tests__/render.test.js +67 -0
  2184. package/dist/sidecar/__tests__/render.test.js.map +1 -0
  2185. package/dist/sidecar/__tests__/resource-leak-watch.test.d.ts +2 -0
  2186. package/dist/sidecar/__tests__/resource-leak-watch.test.d.ts.map +1 -0
  2187. package/dist/sidecar/__tests__/resource-leak-watch.test.js +38 -0
  2188. package/dist/sidecar/__tests__/resource-leak-watch.test.js.map +1 -0
  2189. package/dist/sidecar/__tests__/tmux.test.d.ts +2 -0
  2190. package/dist/sidecar/__tests__/tmux.test.d.ts.map +1 -0
  2191. package/dist/sidecar/__tests__/tmux.test.js +30 -0
  2192. package/dist/sidecar/__tests__/tmux.test.js.map +1 -0
  2193. package/dist/sidecar/__tests__/watch.test.d.ts +2 -0
  2194. package/dist/sidecar/__tests__/watch.test.d.ts.map +1 -0
  2195. package/dist/sidecar/__tests__/watch.test.js +42 -0
  2196. package/dist/sidecar/__tests__/watch.test.js.map +1 -0
  2197. package/dist/sidecar/collector.d.ts +4 -0
  2198. package/dist/sidecar/collector.d.ts.map +1 -0
  2199. package/dist/sidecar/collector.js +377 -0
  2200. package/dist/sidecar/collector.js.map +1 -0
  2201. package/dist/sidecar/index.d.ts +25 -0
  2202. package/dist/sidecar/index.d.ts.map +1 -0
  2203. package/dist/sidecar/index.js +182 -0
  2204. package/dist/sidecar/index.js.map +1 -0
  2205. package/dist/sidecar/render.d.ts +3 -0
  2206. package/dist/sidecar/render.d.ts.map +1 -0
  2207. package/dist/sidecar/render.js +72 -0
  2208. package/dist/sidecar/render.js.map +1 -0
  2209. package/dist/sidecar/tmux.d.ts +13 -0
  2210. package/dist/sidecar/tmux.d.ts.map +1 -0
  2211. package/dist/sidecar/tmux.js +44 -0
  2212. package/dist/sidecar/tmux.js.map +1 -0
  2213. package/dist/sidecar/types.d.ts +125 -0
  2214. package/dist/sidecar/types.d.ts.map +1 -0
  2215. package/dist/sidecar/types.js +2 -0
  2216. package/dist/sidecar/types.js.map +1 -0
  2217. package/dist/state/__tests__/mode-state-context.test.d.ts +2 -0
  2218. package/dist/state/__tests__/mode-state-context.test.d.ts.map +1 -0
  2219. package/dist/state/__tests__/mode-state-context.test.js +35 -0
  2220. package/dist/state/__tests__/mode-state-context.test.js.map +1 -0
  2221. package/dist/state/__tests__/operations-ralph-phase.test.d.ts +2 -0
  2222. package/dist/state/__tests__/operations-ralph-phase.test.d.ts.map +1 -0
  2223. package/dist/state/__tests__/operations-ralph-phase.test.js +190 -0
  2224. package/dist/state/__tests__/operations-ralph-phase.test.js.map +1 -0
  2225. package/dist/state/__tests__/operations.test.d.ts +2 -0
  2226. package/dist/state/__tests__/operations.test.d.ts.map +1 -0
  2227. package/dist/state/__tests__/operations.test.js +2753 -0
  2228. package/dist/state/__tests__/operations.test.js.map +1 -0
  2229. package/dist/state/__tests__/path-traversal.test.d.ts +2 -0
  2230. package/dist/state/__tests__/path-traversal.test.d.ts.map +1 -0
  2231. package/dist/state/__tests__/path-traversal.test.js +49 -0
  2232. package/dist/state/__tests__/path-traversal.test.js.map +1 -0
  2233. package/dist/state/__tests__/planning-gate.test.d.ts +2 -0
  2234. package/dist/state/__tests__/planning-gate.test.d.ts.map +1 -0
  2235. package/dist/state/__tests__/planning-gate.test.js +219 -0
  2236. package/dist/state/__tests__/planning-gate.test.js.map +1 -0
  2237. package/dist/state/__tests__/skill-active.test.d.ts +2 -0
  2238. package/dist/state/__tests__/skill-active.test.d.ts.map +1 -0
  2239. package/dist/state/__tests__/skill-active.test.js +314 -0
  2240. package/dist/state/__tests__/skill-active.test.js.map +1 -0
  2241. package/dist/state/__tests__/workflow-transition.test.d.ts +2 -0
  2242. package/dist/state/__tests__/workflow-transition.test.d.ts.map +1 -0
  2243. package/dist/state/__tests__/workflow-transition.test.js +293 -0
  2244. package/dist/state/__tests__/workflow-transition.test.js.map +1 -0
  2245. package/dist/state/mode-state-context.d.ts +14 -0
  2246. package/dist/state/mode-state-context.d.ts.map +1 -0
  2247. package/dist/state/mode-state-context.js +49 -0
  2248. package/dist/state/mode-state-context.js.map +1 -0
  2249. package/dist/state/operations.d.ts +13 -0
  2250. package/dist/state/operations.d.ts.map +1 -0
  2251. package/dist/state/operations.js +544 -0
  2252. package/dist/state/operations.js.map +1 -0
  2253. package/dist/state/paths.d.ts +3 -0
  2254. package/dist/state/paths.d.ts.map +1 -0
  2255. package/dist/state/paths.js +2 -0
  2256. package/dist/state/paths.js.map +1 -0
  2257. package/dist/state/skill-active.d.ts +64 -0
  2258. package/dist/state/skill-active.d.ts.map +1 -0
  2259. package/dist/state/skill-active.js +375 -0
  2260. package/dist/state/skill-active.js.map +1 -0
  2261. package/dist/state/workflow-transition-reconcile.d.ts +22 -0
  2262. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -0
  2263. package/dist/state/workflow-transition-reconcile.js +144 -0
  2264. package/dist/state/workflow-transition-reconcile.js.map +1 -0
  2265. package/dist/state/workflow-transition.d.ts +45 -0
  2266. package/dist/state/workflow-transition.d.ts.map +1 -0
  2267. package/dist/state/workflow-transition.js +268 -0
  2268. package/dist/state/workflow-transition.js.map +1 -0
  2269. package/dist/subagents/__tests__/tracker.test.d.ts +2 -0
  2270. package/dist/subagents/__tests__/tracker.test.d.ts.map +1 -0
  2271. package/dist/subagents/__tests__/tracker.test.js +255 -0
  2272. package/dist/subagents/__tests__/tracker.test.js.map +1 -0
  2273. package/dist/subagents/tracker.d.ts +60 -0
  2274. package/dist/subagents/tracker.d.ts.map +1 -0
  2275. package/dist/subagents/tracker.js +229 -0
  2276. package/dist/subagents/tracker.js.map +1 -0
  2277. package/dist/team/__tests__/allocation-policy.test.d.ts +2 -0
  2278. package/dist/team/__tests__/allocation-policy.test.d.ts.map +1 -0
  2279. package/dist/team/__tests__/allocation-policy.test.js +111 -0
  2280. package/dist/team/__tests__/allocation-policy.test.js.map +1 -0
  2281. package/dist/team/__tests__/api-interop.test.d.ts +2 -0
  2282. package/dist/team/__tests__/api-interop.test.d.ts.map +1 -0
  2283. package/dist/team/__tests__/api-interop.test.js +2321 -0
  2284. package/dist/team/__tests__/api-interop.test.js.map +1 -0
  2285. package/dist/team/__tests__/approved-execution.test.d.ts +2 -0
  2286. package/dist/team/__tests__/approved-execution.test.d.ts.map +1 -0
  2287. package/dist/team/__tests__/approved-execution.test.js +304 -0
  2288. package/dist/team/__tests__/approved-execution.test.js.map +1 -0
  2289. package/dist/team/__tests__/commit-hygiene.test.d.ts +2 -0
  2290. package/dist/team/__tests__/commit-hygiene.test.d.ts.map +1 -0
  2291. package/dist/team/__tests__/commit-hygiene.test.js +93 -0
  2292. package/dist/team/__tests__/commit-hygiene.test.js.map +1 -0
  2293. package/dist/team/__tests__/coordination-protocol.test.d.ts +2 -0
  2294. package/dist/team/__tests__/coordination-protocol.test.d.ts.map +1 -0
  2295. package/dist/team/__tests__/coordination-protocol.test.js +173 -0
  2296. package/dist/team/__tests__/coordination-protocol.test.js.map +1 -0
  2297. package/dist/team/__tests__/cross-rebase-smoke.test.d.ts +2 -0
  2298. package/dist/team/__tests__/cross-rebase-smoke.test.d.ts.map +1 -0
  2299. package/dist/team/__tests__/cross-rebase-smoke.test.js +161 -0
  2300. package/dist/team/__tests__/cross-rebase-smoke.test.js.map +1 -0
  2301. package/dist/team/__tests__/current-task-baseline.test.d.ts +2 -0
  2302. package/dist/team/__tests__/current-task-baseline.test.d.ts.map +1 -0
  2303. package/dist/team/__tests__/current-task-baseline.test.js +87 -0
  2304. package/dist/team/__tests__/current-task-baseline.test.js.map +1 -0
  2305. package/dist/team/__tests__/delegation-policy.test.d.ts +2 -0
  2306. package/dist/team/__tests__/delegation-policy.test.d.ts.map +1 -0
  2307. package/dist/team/__tests__/delegation-policy.test.js +69 -0
  2308. package/dist/team/__tests__/delegation-policy.test.js.map +1 -0
  2309. package/dist/team/__tests__/delivery-e2e-smoke.test.d.ts +2 -0
  2310. package/dist/team/__tests__/delivery-e2e-smoke.test.d.ts.map +1 -0
  2311. package/dist/team/__tests__/delivery-e2e-smoke.test.js +677 -0
  2312. package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -0
  2313. package/dist/team/__tests__/delivery-log.test.d.ts +2 -0
  2314. package/dist/team/__tests__/delivery-log.test.d.ts.map +1 -0
  2315. package/dist/team/__tests__/delivery-log.test.js +62 -0
  2316. package/dist/team/__tests__/delivery-log.test.js.map +1 -0
  2317. package/dist/team/__tests__/events.test.d.ts +2 -0
  2318. package/dist/team/__tests__/events.test.d.ts.map +1 -0
  2319. package/dist/team/__tests__/events.test.js +313 -0
  2320. package/dist/team/__tests__/events.test.js.map +1 -0
  2321. package/dist/team/__tests__/followup-planner.test.d.ts +2 -0
  2322. package/dist/team/__tests__/followup-planner.test.d.ts.map +1 -0
  2323. package/dist/team/__tests__/followup-planner.test.js +100 -0
  2324. package/dist/team/__tests__/followup-planner.test.js.map +1 -0
  2325. package/dist/team/__tests__/hardening-e2e.test.d.ts +2 -0
  2326. package/dist/team/__tests__/hardening-e2e.test.d.ts.map +1 -0
  2327. package/dist/team/__tests__/hardening-e2e.test.js +98 -0
  2328. package/dist/team/__tests__/hardening-e2e.test.js.map +1 -0
  2329. package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts +2 -0
  2330. package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts.map +1 -0
  2331. package/dist/team/__tests__/hook-primary-e2e-contract.test.js +78 -0
  2332. package/dist/team/__tests__/hook-primary-e2e-contract.test.js.map +1 -0
  2333. package/dist/team/__tests__/idle-nudge.test.d.ts +2 -0
  2334. package/dist/team/__tests__/idle-nudge.test.d.ts.map +1 -0
  2335. package/dist/team/__tests__/idle-nudge.test.js +230 -0
  2336. package/dist/team/__tests__/idle-nudge.test.js.map +1 -0
  2337. package/dist/team/__tests__/leader-activity.test.d.ts +2 -0
  2338. package/dist/team/__tests__/leader-activity.test.d.ts.map +1 -0
  2339. package/dist/team/__tests__/leader-activity.test.js +261 -0
  2340. package/dist/team/__tests__/leader-activity.test.js.map +1 -0
  2341. package/dist/team/__tests__/mcp-comm.test.d.ts +2 -0
  2342. package/dist/team/__tests__/mcp-comm.test.d.ts.map +1 -0
  2343. package/dist/team/__tests__/mcp-comm.test.js +289 -0
  2344. package/dist/team/__tests__/mcp-comm.test.js.map +1 -0
  2345. package/dist/team/__tests__/model-contract.test.d.ts +2 -0
  2346. package/dist/team/__tests__/model-contract.test.d.ts.map +1 -0
  2347. package/dist/team/__tests__/model-contract.test.js +187 -0
  2348. package/dist/team/__tests__/model-contract.test.js.map +1 -0
  2349. package/dist/team/__tests__/orchestrator.test.d.ts +2 -0
  2350. package/dist/team/__tests__/orchestrator.test.d.ts.map +1 -0
  2351. package/dist/team/__tests__/orchestrator.test.js +111 -0
  2352. package/dist/team/__tests__/orchestrator.test.js.map +1 -0
  2353. package/dist/team/__tests__/phase-controller.test.d.ts +2 -0
  2354. package/dist/team/__tests__/phase-controller.test.d.ts.map +1 -0
  2355. package/dist/team/__tests__/phase-controller.test.js +50 -0
  2356. package/dist/team/__tests__/phase-controller.test.js.map +1 -0
  2357. package/dist/team/__tests__/rebalance-policy.test.d.ts +2 -0
  2358. package/dist/team/__tests__/rebalance-policy.test.d.ts.map +1 -0
  2359. package/dist/team/__tests__/rebalance-policy.test.js +168 -0
  2360. package/dist/team/__tests__/rebalance-policy.test.js.map +1 -0
  2361. package/dist/team/__tests__/repo-aware-decomposition.test.d.ts +2 -0
  2362. package/dist/team/__tests__/repo-aware-decomposition.test.d.ts.map +1 -0
  2363. package/dist/team/__tests__/repo-aware-decomposition.test.js +156 -0
  2364. package/dist/team/__tests__/repo-aware-decomposition.test.js.map +1 -0
  2365. package/dist/team/__tests__/role-router.test.d.ts +2 -0
  2366. package/dist/team/__tests__/role-router.test.d.ts.map +1 -0
  2367. package/dist/team/__tests__/role-router.test.js +263 -0
  2368. package/dist/team/__tests__/role-router.test.js.map +1 -0
  2369. package/dist/team/__tests__/runtime-boxed-state.test.d.ts +2 -0
  2370. package/dist/team/__tests__/runtime-boxed-state.test.d.ts.map +1 -0
  2371. package/dist/team/__tests__/runtime-boxed-state.test.js +39 -0
  2372. package/dist/team/__tests__/runtime-boxed-state.test.js.map +1 -0
  2373. package/dist/team/__tests__/runtime-cli.test.d.ts +2 -0
  2374. package/dist/team/__tests__/runtime-cli.test.d.ts.map +1 -0
  2375. package/dist/team/__tests__/runtime-cli.test.js +320 -0
  2376. package/dist/team/__tests__/runtime-cli.test.js.map +1 -0
  2377. package/dist/team/__tests__/runtime.test.d.ts +2 -0
  2378. package/dist/team/__tests__/runtime.test.d.ts.map +1 -0
  2379. package/dist/team/__tests__/runtime.test.js +6464 -0
  2380. package/dist/team/__tests__/runtime.test.js.map +1 -0
  2381. package/dist/team/__tests__/scaling.test.d.ts +2 -0
  2382. package/dist/team/__tests__/scaling.test.d.ts.map +1 -0
  2383. package/dist/team/__tests__/scaling.test.js +1664 -0
  2384. package/dist/team/__tests__/scaling.test.js.map +1 -0
  2385. package/dist/team/__tests__/shutdown-fallback.test.d.ts +2 -0
  2386. package/dist/team/__tests__/shutdown-fallback.test.d.ts.map +1 -0
  2387. package/dist/team/__tests__/shutdown-fallback.test.js +125 -0
  2388. package/dist/team/__tests__/shutdown-fallback.test.js.map +1 -0
  2389. package/dist/team/__tests__/state-root.test.d.ts +2 -0
  2390. package/dist/team/__tests__/state-root.test.d.ts.map +1 -0
  2391. package/dist/team/__tests__/state-root.test.js +208 -0
  2392. package/dist/team/__tests__/state-root.test.js.map +1 -0
  2393. package/dist/team/__tests__/state.test.d.ts +2 -0
  2394. package/dist/team/__tests__/state.test.d.ts.map +1 -0
  2395. package/dist/team/__tests__/state.test.js +1942 -0
  2396. package/dist/team/__tests__/state.test.js.map +1 -0
  2397. package/dist/team/__tests__/team-identity.test.d.ts +2 -0
  2398. package/dist/team/__tests__/team-identity.test.d.ts.map +1 -0
  2399. package/dist/team/__tests__/team-identity.test.js +166 -0
  2400. package/dist/team/__tests__/team-identity.test.js.map +1 -0
  2401. package/dist/team/__tests__/team-ops-contract.test.d.ts +2 -0
  2402. package/dist/team/__tests__/team-ops-contract.test.d.ts.map +1 -0
  2403. package/dist/team/__tests__/team-ops-contract.test.js +96 -0
  2404. package/dist/team/__tests__/team-ops-contract.test.js.map +1 -0
  2405. package/dist/team/__tests__/tmux-claude-workers-demo.test.d.ts +2 -0
  2406. package/dist/team/__tests__/tmux-claude-workers-demo.test.d.ts.map +1 -0
  2407. package/dist/team/__tests__/tmux-claude-workers-demo.test.js +191 -0
  2408. package/dist/team/__tests__/tmux-claude-workers-demo.test.js.map +1 -0
  2409. package/dist/team/__tests__/tmux-session.test.d.ts +2 -0
  2410. package/dist/team/__tests__/tmux-session.test.d.ts.map +1 -0
  2411. package/dist/team/__tests__/tmux-session.test.js +4546 -0
  2412. package/dist/team/__tests__/tmux-session.test.js.map +1 -0
  2413. package/dist/team/__tests__/tmux-test-fixture.d.ts +20 -0
  2414. package/dist/team/__tests__/tmux-test-fixture.d.ts.map +1 -0
  2415. package/dist/team/__tests__/tmux-test-fixture.js +148 -0
  2416. package/dist/team/__tests__/tmux-test-fixture.js.map +1 -0
  2417. package/dist/team/__tests__/tmux-test-fixture.test.d.ts +2 -0
  2418. package/dist/team/__tests__/tmux-test-fixture.test.d.ts.map +1 -0
  2419. package/dist/team/__tests__/tmux-test-fixture.test.js +114 -0
  2420. package/dist/team/__tests__/tmux-test-fixture.test.js.map +1 -0
  2421. package/dist/team/__tests__/worker-bootstrap.test.d.ts +2 -0
  2422. package/dist/team/__tests__/worker-bootstrap.test.d.ts.map +1 -0
  2423. package/dist/team/__tests__/worker-bootstrap.test.js +1122 -0
  2424. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -0
  2425. package/dist/team/__tests__/worker-runtime-identity.test.d.ts +2 -0
  2426. package/dist/team/__tests__/worker-runtime-identity.test.d.ts.map +1 -0
  2427. package/dist/team/__tests__/worker-runtime-identity.test.js +258 -0
  2428. package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -0
  2429. package/dist/team/__tests__/worktree.test.d.ts +2 -0
  2430. package/dist/team/__tests__/worktree.test.d.ts.map +1 -0
  2431. package/dist/team/__tests__/worktree.test.js +317 -0
  2432. package/dist/team/__tests__/worktree.test.js.map +1 -0
  2433. package/dist/team/allocation-policy.d.ts +29 -0
  2434. package/dist/team/allocation-policy.d.ts.map +1 -0
  2435. package/dist/team/allocation-policy.js +153 -0
  2436. package/dist/team/allocation-policy.js.map +1 -0
  2437. package/dist/team/api-interop.d.ts +20 -0
  2438. package/dist/team/api-interop.d.ts.map +1 -0
  2439. package/dist/team/api-interop.js +1084 -0
  2440. package/dist/team/api-interop.js.map +1 -0
  2441. package/dist/team/approved-execution.d.ts +64 -0
  2442. package/dist/team/approved-execution.d.ts.map +1 -0
  2443. package/dist/team/approved-execution.js +242 -0
  2444. package/dist/team/approved-execution.js.map +1 -0
  2445. package/dist/team/commit-hygiene.d.ts +79 -0
  2446. package/dist/team/commit-hygiene.d.ts.map +1 -0
  2447. package/dist/team/commit-hygiene.js +364 -0
  2448. package/dist/team/commit-hygiene.js.map +1 -0
  2449. package/dist/team/contracts.d.ts +26 -0
  2450. package/dist/team/contracts.d.ts.map +1 -0
  2451. package/dist/team/contracts.js +103 -0
  2452. package/dist/team/contracts.js.map +1 -0
  2453. package/dist/team/coordination-protocol.d.ts +14 -0
  2454. package/dist/team/coordination-protocol.d.ts.map +1 -0
  2455. package/dist/team/coordination-protocol.js +244 -0
  2456. package/dist/team/coordination-protocol.js.map +1 -0
  2457. package/dist/team/current-task-baseline.d.ts +32 -0
  2458. package/dist/team/current-task-baseline.d.ts.map +1 -0
  2459. package/dist/team/current-task-baseline.js +85 -0
  2460. package/dist/team/current-task-baseline.js.map +1 -0
  2461. package/dist/team/dag-schema.d.ts +38 -0
  2462. package/dist/team/dag-schema.d.ts.map +1 -0
  2463. package/dist/team/dag-schema.js +221 -0
  2464. package/dist/team/dag-schema.js.map +1 -0
  2465. package/dist/team/delegation-policy.d.ts +3 -0
  2466. package/dist/team/delegation-policy.d.ts.map +1 -0
  2467. package/dist/team/delegation-policy.js +82 -0
  2468. package/dist/team/delegation-policy.js.map +1 -0
  2469. package/dist/team/delivery-log.d.ts +14 -0
  2470. package/dist/team/delivery-log.d.ts.map +1 -0
  2471. package/dist/team/delivery-log.js +43 -0
  2472. package/dist/team/delivery-log.js.map +1 -0
  2473. package/dist/team/followup-planner.d.ts +45 -0
  2474. package/dist/team/followup-planner.d.ts.map +1 -0
  2475. package/dist/team/followup-planner.js +200 -0
  2476. package/dist/team/followup-planner.js.map +1 -0
  2477. package/dist/team/goal-workflow.d.ts +20 -0
  2478. package/dist/team/goal-workflow.d.ts.map +1 -0
  2479. package/dist/team/goal-workflow.js +57 -0
  2480. package/dist/team/goal-workflow.js.map +1 -0
  2481. package/dist/team/idle-nudge.d.ts +53 -0
  2482. package/dist/team/idle-nudge.d.ts.map +1 -0
  2483. package/dist/team/idle-nudge.js +141 -0
  2484. package/dist/team/idle-nudge.js.map +1 -0
  2485. package/dist/team/leader-activity.d.ts +15 -0
  2486. package/dist/team/leader-activity.d.ts.map +1 -0
  2487. package/dist/team/leader-activity.js +224 -0
  2488. package/dist/team/leader-activity.js.map +1 -0
  2489. package/dist/team/mcp-comm.d.ts +73 -0
  2490. package/dist/team/mcp-comm.d.ts.map +1 -0
  2491. package/dist/team/mcp-comm.js +314 -0
  2492. package/dist/team/mcp-comm.js.map +1 -0
  2493. package/dist/team/model-contract.d.ts +26 -0
  2494. package/dist/team/model-contract.d.ts.map +1 -0
  2495. package/dist/team/model-contract.js +205 -0
  2496. package/dist/team/model-contract.js.map +1 -0
  2497. package/dist/team/orchestrator.d.ts +47 -0
  2498. package/dist/team/orchestrator.d.ts.map +1 -0
  2499. package/dist/team/orchestrator.js +131 -0
  2500. package/dist/team/orchestrator.js.map +1 -0
  2501. package/dist/team/pane-status.d.ts +149 -0
  2502. package/dist/team/pane-status.d.ts.map +1 -0
  2503. package/dist/team/pane-status.js +558 -0
  2504. package/dist/team/pane-status.js.map +1 -0
  2505. package/dist/team/phase-controller.d.ts +12 -0
  2506. package/dist/team/phase-controller.d.ts.map +1 -0
  2507. package/dist/team/phase-controller.js +142 -0
  2508. package/dist/team/phase-controller.js.map +1 -0
  2509. package/dist/team/progress-evidence.d.ts +2 -0
  2510. package/dist/team/progress-evidence.d.ts.map +1 -0
  2511. package/dist/team/progress-evidence.js +77 -0
  2512. package/dist/team/progress-evidence.js.map +1 -0
  2513. package/dist/team/rebalance-policy.d.ts +19 -0
  2514. package/dist/team/rebalance-policy.d.ts.map +1 -0
  2515. package/dist/team/rebalance-policy.js +48 -0
  2516. package/dist/team/rebalance-policy.js.map +1 -0
  2517. package/dist/team/reminder-intents.d.ts +11 -0
  2518. package/dist/team/reminder-intents.d.ts.map +1 -0
  2519. package/dist/team/reminder-intents.js +40 -0
  2520. package/dist/team/reminder-intents.js.map +1 -0
  2521. package/dist/team/repo-aware-decomposition.d.ts +68 -0
  2522. package/dist/team/repo-aware-decomposition.d.ts.map +1 -0
  2523. package/dist/team/repo-aware-decomposition.js +235 -0
  2524. package/dist/team/repo-aware-decomposition.js.map +1 -0
  2525. package/dist/team/role-router.d.ts +32 -0
  2526. package/dist/team/role-router.d.ts.map +1 -0
  2527. package/dist/team/role-router.js +298 -0
  2528. package/dist/team/role-router.js.map +1 -0
  2529. package/dist/team/runtime-cli.d.ts +78 -0
  2530. package/dist/team/runtime-cli.d.ts.map +1 -0
  2531. package/dist/team/runtime-cli.js +376 -0
  2532. package/dist/team/runtime-cli.js.map +1 -0
  2533. package/dist/team/runtime.d.ts +162 -0
  2534. package/dist/team/runtime.d.ts.map +1 -0
  2535. package/dist/team/runtime.js +4160 -0
  2536. package/dist/team/runtime.js.map +1 -0
  2537. package/dist/team/scaling.d.ts +59 -0
  2538. package/dist/team/scaling.d.ts.map +1 -0
  2539. package/dist/team/scaling.js +650 -0
  2540. package/dist/team/scaling.js.map +1 -0
  2541. package/dist/team/state/approvals.d.ts +25 -0
  2542. package/dist/team/state/approvals.d.ts.map +1 -0
  2543. package/dist/team/state/approvals.js +31 -0
  2544. package/dist/team/state/approvals.js.map +1 -0
  2545. package/dist/team/state/config.d.ts +2 -0
  2546. package/dist/team/state/config.d.ts.map +1 -0
  2547. package/dist/team/state/config.js +2 -0
  2548. package/dist/team/state/config.js.map +1 -0
  2549. package/dist/team/state/dispatch-lock.d.ts +3 -0
  2550. package/dist/team/state/dispatch-lock.d.ts.map +1 -0
  2551. package/dist/team/state/dispatch-lock.js +81 -0
  2552. package/dist/team/state/dispatch-lock.js.map +1 -0
  2553. package/dist/team/state/dispatch.d.ts +67 -0
  2554. package/dist/team/state/dispatch.d.ts.map +1 -0
  2555. package/dist/team/state/dispatch.js +302 -0
  2556. package/dist/team/state/dispatch.js.map +1 -0
  2557. package/dist/team/state/events.d.ts +26 -0
  2558. package/dist/team/state/events.d.ts.map +1 -0
  2559. package/dist/team/state/events.js +145 -0
  2560. package/dist/team/state/events.js.map +1 -0
  2561. package/dist/team/state/index.d.ts +11 -0
  2562. package/dist/team/state/index.d.ts.map +1 -0
  2563. package/dist/team/state/index.js +11 -0
  2564. package/dist/team/state/index.js.map +1 -0
  2565. package/dist/team/state/io.d.ts +2 -0
  2566. package/dist/team/state/io.d.ts.map +1 -0
  2567. package/dist/team/state/io.js +2 -0
  2568. package/dist/team/state/io.js.map +1 -0
  2569. package/dist/team/state/locks.d.ts +16 -0
  2570. package/dist/team/state/locks.d.ts.map +1 -0
  2571. package/dist/team/state/locks.js +201 -0
  2572. package/dist/team/state/locks.js.map +1 -0
  2573. package/dist/team/state/mailbox.d.ts +43 -0
  2574. package/dist/team/state/mailbox.d.ts.map +1 -0
  2575. package/dist/team/state/mailbox.js +222 -0
  2576. package/dist/team/state/mailbox.js.map +1 -0
  2577. package/dist/team/state/monitor.d.ts +108 -0
  2578. package/dist/team/state/monitor.d.ts.map +1 -0
  2579. package/dist/team/state/monitor.js +193 -0
  2580. package/dist/team/state/monitor.js.map +1 -0
  2581. package/dist/team/state/shutdown.d.ts +2 -0
  2582. package/dist/team/state/shutdown.d.ts.map +1 -0
  2583. package/dist/team/state/shutdown.js +2 -0
  2584. package/dist/team/state/shutdown.js.map +1 -0
  2585. package/dist/team/state/summary.d.ts +2 -0
  2586. package/dist/team/state/summary.d.ts.map +1 -0
  2587. package/dist/team/state/summary.js +2 -0
  2588. package/dist/team/state/summary.js.map +1 -0
  2589. package/dist/team/state/tasks.d.ts +53 -0
  2590. package/dist/team/state/tasks.d.ts.map +1 -0
  2591. package/dist/team/state/tasks.js +284 -0
  2592. package/dist/team/state/tasks.js.map +1 -0
  2593. package/dist/team/state/types.d.ts +356 -0
  2594. package/dist/team/state/types.d.ts.map +1 -0
  2595. package/dist/team/state/types.js +3 -0
  2596. package/dist/team/state/types.js.map +1 -0
  2597. package/dist/team/state/workers.d.ts +2 -0
  2598. package/dist/team/state/workers.d.ts.map +1 -0
  2599. package/dist/team/state/workers.js +2 -0
  2600. package/dist/team/state/workers.js.map +1 -0
  2601. package/dist/team/state-root.d.ts +40 -0
  2602. package/dist/team/state-root.d.ts.map +1 -0
  2603. package/dist/team/state-root.js +297 -0
  2604. package/dist/team/state-root.js.map +1 -0
  2605. package/dist/team/state.d.ts +471 -0
  2606. package/dist/team/state.d.ts.map +1 -0
  2607. package/dist/team/state.js +1418 -0
  2608. package/dist/team/state.js.map +1 -0
  2609. package/dist/team/team-identity.d.ts +26 -0
  2610. package/dist/team/team-identity.d.ts.map +1 -0
  2611. package/dist/team/team-identity.js +169 -0
  2612. package/dist/team/team-identity.js.map +1 -0
  2613. package/dist/team/team-ops.d.ts +66 -0
  2614. package/dist/team/team-ops.d.ts.map +1 -0
  2615. package/dist/team/team-ops.js +79 -0
  2616. package/dist/team/team-ops.js.map +1 -0
  2617. package/dist/team/tmux-session.d.ts +190 -0
  2618. package/dist/team/tmux-session.d.ts.map +1 -0
  2619. package/dist/team/tmux-session.js +2071 -0
  2620. package/dist/team/tmux-session.js.map +1 -0
  2621. package/dist/team/ultragoal-context.d.ts +47 -0
  2622. package/dist/team/ultragoal-context.d.ts.map +1 -0
  2623. package/dist/team/ultragoal-context.js +215 -0
  2624. package/dist/team/ultragoal-context.js.map +1 -0
  2625. package/dist/team/worker-bootstrap.d.ts +92 -0
  2626. package/dist/team/worker-bootstrap.d.ts.map +1 -0
  2627. package/dist/team/worker-bootstrap.js +860 -0
  2628. package/dist/team/worker-bootstrap.js.map +1 -0
  2629. package/dist/team/worktree.d.ts +69 -0
  2630. package/dist/team/worktree.d.ts.map +1 -0
  2631. package/dist/team/worktree.js +437 -0
  2632. package/dist/team/worktree.js.map +1 -0
  2633. package/dist/ultragoal/__tests__/artifacts.test.d.ts +2 -0
  2634. package/dist/ultragoal/__tests__/artifacts.test.d.ts.map +1 -0
  2635. package/dist/ultragoal/__tests__/artifacts.test.js +1423 -0
  2636. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -0
  2637. package/dist/ultragoal/__tests__/docs-contract.test.d.ts +2 -0
  2638. package/dist/ultragoal/__tests__/docs-contract.test.d.ts.map +1 -0
  2639. package/dist/ultragoal/__tests__/docs-contract.test.js +132 -0
  2640. package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -0
  2641. package/dist/ultragoal/__tests__/steering-fixtures.d.ts +68 -0
  2642. package/dist/ultragoal/__tests__/steering-fixtures.d.ts.map +1 -0
  2643. package/dist/ultragoal/__tests__/steering-fixtures.js +259 -0
  2644. package/dist/ultragoal/__tests__/steering-fixtures.js.map +1 -0
  2645. package/dist/ultragoal/__tests__/steering-fixtures.test.d.ts +2 -0
  2646. package/dist/ultragoal/__tests__/steering-fixtures.test.d.ts.map +1 -0
  2647. package/dist/ultragoal/__tests__/steering-fixtures.test.js +65 -0
  2648. package/dist/ultragoal/__tests__/steering-fixtures.test.js.map +1 -0
  2649. package/dist/ultragoal/artifacts.d.ts +249 -0
  2650. package/dist/ultragoal/artifacts.d.ts.map +1 -0
  2651. package/dist/ultragoal/artifacts.js +1349 -0
  2652. package/dist/ultragoal/artifacts.js.map +1 -0
  2653. package/dist/utils/__tests__/agents-md.test.d.ts +2 -0
  2654. package/dist/utils/__tests__/agents-md.test.d.ts.map +1 -0
  2655. package/dist/utils/__tests__/agents-md.test.js +96 -0
  2656. package/dist/utils/__tests__/agents-md.test.js.map +1 -0
  2657. package/dist/utils/__tests__/agents-model-table.test.d.ts +2 -0
  2658. package/dist/utils/__tests__/agents-model-table.test.d.ts.map +1 -0
  2659. package/dist/utils/__tests__/agents-model-table.test.js +108 -0
  2660. package/dist/utils/__tests__/agents-model-table.test.js.map +1 -0
  2661. package/dist/utils/__tests__/dep-versions.test.d.ts +2 -0
  2662. package/dist/utils/__tests__/dep-versions.test.d.ts.map +1 -0
  2663. package/dist/utils/__tests__/dep-versions.test.js +46 -0
  2664. package/dist/utils/__tests__/dep-versions.test.js.map +1 -0
  2665. package/dist/utils/__tests__/package.test.d.ts +2 -0
  2666. package/dist/utils/__tests__/package.test.d.ts.map +1 -0
  2667. package/dist/utils/__tests__/package.test.js +21 -0
  2668. package/dist/utils/__tests__/package.test.js.map +1 -0
  2669. package/dist/utils/__tests__/paths.test.d.ts +2 -0
  2670. package/dist/utils/__tests__/paths.test.d.ts.map +1 -0
  2671. package/dist/utils/__tests__/paths.test.js +647 -0
  2672. package/dist/utils/__tests__/paths.test.js.map +1 -0
  2673. package/dist/utils/__tests__/platform-command.test.d.ts +2 -0
  2674. package/dist/utils/__tests__/platform-command.test.d.ts.map +1 -0
  2675. package/dist/utils/__tests__/platform-command.test.js +399 -0
  2676. package/dist/utils/__tests__/platform-command.test.js.map +1 -0
  2677. package/dist/utils/__tests__/repo-deps.test.d.ts +2 -0
  2678. package/dist/utils/__tests__/repo-deps.test.d.ts.map +1 -0
  2679. package/dist/utils/__tests__/repo-deps.test.js +71 -0
  2680. package/dist/utils/__tests__/repo-deps.test.js.map +1 -0
  2681. package/dist/utils/__tests__/sleep-resource.test.d.ts +2 -0
  2682. package/dist/utils/__tests__/sleep-resource.test.d.ts.map +1 -0
  2683. package/dist/utils/__tests__/sleep-resource.test.js +39 -0
  2684. package/dist/utils/__tests__/sleep-resource.test.js.map +1 -0
  2685. package/dist/utils/__tests__/version.test.d.ts +2 -0
  2686. package/dist/utils/__tests__/version.test.d.ts.map +1 -0
  2687. package/dist/utils/__tests__/version.test.js +78 -0
  2688. package/dist/utils/__tests__/version.test.js.map +1 -0
  2689. package/dist/utils/agents-md.d.ts +10 -0
  2690. package/dist/utils/agents-md.d.ts.map +1 -0
  2691. package/dist/utils/agents-md.js +76 -0
  2692. package/dist/utils/agents-md.js.map +1 -0
  2693. package/dist/utils/agents-model-table.d.ts +16 -0
  2694. package/dist/utils/agents-model-table.d.ts.map +1 -0
  2695. package/dist/utils/agents-model-table.js +102 -0
  2696. package/dist/utils/agents-model-table.js.map +1 -0
  2697. package/dist/utils/git-layout.d.ts +8 -0
  2698. package/dist/utils/git-layout.d.ts.map +1 -0
  2699. package/dist/utils/git-layout.js +58 -0
  2700. package/dist/utils/git-layout.js.map +1 -0
  2701. package/dist/utils/package.d.ts +9 -0
  2702. package/dist/utils/package.d.ts.map +1 -0
  2703. package/dist/utils/package.js +31 -0
  2704. package/dist/utils/package.js.map +1 -0
  2705. package/dist/utils/paths.d.ts +101 -0
  2706. package/dist/utils/paths.d.ts.map +1 -0
  2707. package/dist/utils/paths.js +314 -0
  2708. package/dist/utils/paths.js.map +1 -0
  2709. package/dist/utils/platform-command.d.ts +29 -0
  2710. package/dist/utils/platform-command.d.ts.map +1 -0
  2711. package/dist/utils/platform-command.js +239 -0
  2712. package/dist/utils/platform-command.js.map +1 -0
  2713. package/dist/utils/repo-deps.d.ts +20 -0
  2714. package/dist/utils/repo-deps.d.ts.map +1 -0
  2715. package/dist/utils/repo-deps.js +78 -0
  2716. package/dist/utils/repo-deps.js.map +1 -0
  2717. package/dist/utils/safe-json.d.ts +3 -0
  2718. package/dist/utils/safe-json.d.ts.map +1 -0
  2719. package/dist/utils/safe-json.js +19 -0
  2720. package/dist/utils/safe-json.js.map +1 -0
  2721. package/dist/utils/sleep.d.ts +3 -0
  2722. package/dist/utils/sleep.d.ts.map +1 -0
  2723. package/dist/utils/sleep.js +35 -0
  2724. package/dist/utils/sleep.js.map +1 -0
  2725. package/dist/utils/toml.d.ts +4 -0
  2726. package/dist/utils/toml.d.ts.map +1 -0
  2727. package/dist/utils/toml.js +75 -0
  2728. package/dist/utils/toml.js.map +1 -0
  2729. package/dist/utils/version.d.ts +7 -0
  2730. package/dist/utils/version.d.ts.map +1 -0
  2731. package/dist/utils/version.js +72 -0
  2732. package/dist/utils/version.js.map +1 -0
  2733. package/dist/verification/__tests__/ci-rust-gates.test.d.ts +2 -0
  2734. package/dist/verification/__tests__/ci-rust-gates.test.d.ts.map +1 -0
  2735. package/dist/verification/__tests__/ci-rust-gates.test.js +293 -0
  2736. package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -0
  2737. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.d.ts +2 -0
  2738. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.d.ts.map +1 -0
  2739. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +68 -0
  2740. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -0
  2741. package/dist/verification/__tests__/explore-harness-release-workflow.test.d.ts +2 -0
  2742. package/dist/verification/__tests__/explore-harness-release-workflow.test.d.ts.map +1 -0
  2743. package/dist/verification/__tests__/explore-harness-release-workflow.test.js +74 -0
  2744. package/dist/verification/__tests__/explore-harness-release-workflow.test.js.map +1 -0
  2745. package/dist/verification/__tests__/native-release-manifest.test.d.ts +2 -0
  2746. package/dist/verification/__tests__/native-release-manifest.test.d.ts.map +1 -0
  2747. package/dist/verification/__tests__/native-release-manifest.test.js +80 -0
  2748. package/dist/verification/__tests__/native-release-manifest.test.js.map +1 -0
  2749. package/dist/verification/__tests__/pr-check-workflow.test.d.ts +2 -0
  2750. package/dist/verification/__tests__/pr-check-workflow.test.d.ts.map +1 -0
  2751. package/dist/verification/__tests__/pr-check-workflow.test.js +27 -0
  2752. package/dist/verification/__tests__/pr-check-workflow.test.js.map +1 -0
  2753. package/dist/verification/__tests__/ralph-persistence-gate.test.d.ts +2 -0
  2754. package/dist/verification/__tests__/ralph-persistence-gate.test.d.ts.map +1 -0
  2755. package/dist/verification/__tests__/ralph-persistence-gate.test.js +55 -0
  2756. package/dist/verification/__tests__/ralph-persistence-gate.test.js.map +1 -0
  2757. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.d.ts +2 -0
  2758. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.d.ts.map +1 -0
  2759. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.js +32 -0
  2760. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.js.map +1 -0
  2761. package/dist/verification/__tests__/verifier.test.d.ts +2 -0
  2762. package/dist/verification/__tests__/verifier.test.d.ts.map +1 -0
  2763. package/dist/verification/__tests__/verifier.test.js +113 -0
  2764. package/dist/verification/__tests__/verifier.test.js.map +1 -0
  2765. package/dist/verification/verifier.d.ts +37 -0
  2766. package/dist/verification/verifier.d.ts.map +1 -0
  2767. package/dist/verification/verifier.js +100 -0
  2768. package/dist/verification/verifier.js.map +1 -0
  2769. package/dist/visual/__tests__/verdict.test.d.ts +2 -0
  2770. package/dist/visual/__tests__/verdict.test.d.ts.map +1 -0
  2771. package/dist/visual/__tests__/verdict.test.js +81 -0
  2772. package/dist/visual/__tests__/verdict.test.js.map +1 -0
  2773. package/dist/visual/constants.d.ts +4 -0
  2774. package/dist/visual/constants.d.ts.map +1 -0
  2775. package/dist/visual/constants.js +3 -0
  2776. package/dist/visual/constants.js.map +1 -0
  2777. package/dist/visual/verdict.d.ts +17 -0
  2778. package/dist/visual/verdict.d.ts.map +1 -0
  2779. package/dist/visual/verdict.js +61 -0
  2780. package/dist/visual/verdict.js.map +1 -0
  2781. package/dist/wiki/__tests__/cjk-tokenize.test.d.ts +12 -0
  2782. package/dist/wiki/__tests__/cjk-tokenize.test.d.ts.map +1 -0
  2783. package/dist/wiki/__tests__/cjk-tokenize.test.js +139 -0
  2784. package/dist/wiki/__tests__/cjk-tokenize.test.js.map +1 -0
  2785. package/dist/wiki/__tests__/crlf-parse.test.d.ts +2 -0
  2786. package/dist/wiki/__tests__/crlf-parse.test.d.ts.map +1 -0
  2787. package/dist/wiki/__tests__/crlf-parse.test.js +24 -0
  2788. package/dist/wiki/__tests__/crlf-parse.test.js.map +1 -0
  2789. package/dist/wiki/__tests__/escape-newline.test.d.ts +2 -0
  2790. package/dist/wiki/__tests__/escape-newline.test.d.ts.map +1 -0
  2791. package/dist/wiki/__tests__/escape-newline.test.js +45 -0
  2792. package/dist/wiki/__tests__/escape-newline.test.js.map +1 -0
  2793. package/dist/wiki/__tests__/ingest.test.d.ts +5 -0
  2794. package/dist/wiki/__tests__/ingest.test.d.ts.map +1 -0
  2795. package/dist/wiki/__tests__/ingest.test.js +215 -0
  2796. package/dist/wiki/__tests__/ingest.test.js.map +1 -0
  2797. package/dist/wiki/__tests__/lint.test.d.ts +5 -0
  2798. package/dist/wiki/__tests__/lint.test.d.ts.map +1 -0
  2799. package/dist/wiki/__tests__/lint.test.js +176 -0
  2800. package/dist/wiki/__tests__/lint.test.js.map +1 -0
  2801. package/dist/wiki/__tests__/query.test.d.ts +5 -0
  2802. package/dist/wiki/__tests__/query.test.d.ts.map +1 -0
  2803. package/dist/wiki/__tests__/query.test.js +166 -0
  2804. package/dist/wiki/__tests__/query.test.js.map +1 -0
  2805. package/dist/wiki/__tests__/reserved-file-guard.test.d.ts +2 -0
  2806. package/dist/wiki/__tests__/reserved-file-guard.test.d.ts.map +1 -0
  2807. package/dist/wiki/__tests__/reserved-file-guard.test.js +44 -0
  2808. package/dist/wiki/__tests__/reserved-file-guard.test.js.map +1 -0
  2809. package/dist/wiki/__tests__/session-hooks.test.d.ts +5 -0
  2810. package/dist/wiki/__tests__/session-hooks.test.d.ts.map +1 -0
  2811. package/dist/wiki/__tests__/session-hooks.test.js +64 -0
  2812. package/dist/wiki/__tests__/session-hooks.test.js.map +1 -0
  2813. package/dist/wiki/__tests__/slug-nonascii.test.d.ts +2 -0
  2814. package/dist/wiki/__tests__/slug-nonascii.test.d.ts.map +1 -0
  2815. package/dist/wiki/__tests__/slug-nonascii.test.js +30 -0
  2816. package/dist/wiki/__tests__/slug-nonascii.test.js.map +1 -0
  2817. package/dist/wiki/__tests__/storage.test.d.ts +5 -0
  2818. package/dist/wiki/__tests__/storage.test.d.ts.map +1 -0
  2819. package/dist/wiki/__tests__/storage.test.js +318 -0
  2820. package/dist/wiki/__tests__/storage.test.js.map +1 -0
  2821. package/dist/wiki/__tests__/test-helpers.d.ts +31 -0
  2822. package/dist/wiki/__tests__/test-helpers.d.ts.map +1 -0
  2823. package/dist/wiki/__tests__/test-helpers.js +108 -0
  2824. package/dist/wiki/__tests__/test-helpers.js.map +1 -0
  2825. package/dist/wiki/index.d.ts +14 -0
  2826. package/dist/wiki/index.d.ts.map +1 -0
  2827. package/dist/wiki/index.js +17 -0
  2828. package/dist/wiki/index.js.map +1 -0
  2829. package/dist/wiki/ingest.d.ts +20 -0
  2830. package/dist/wiki/ingest.d.ts.map +1 -0
  2831. package/dist/wiki/ingest.js +115 -0
  2832. package/dist/wiki/ingest.js.map +1 -0
  2833. package/dist/wiki/lifecycle.d.ts +25 -0
  2834. package/dist/wiki/lifecycle.d.ts.map +1 -0
  2835. package/dist/wiki/lifecycle.js +239 -0
  2836. package/dist/wiki/lifecycle.js.map +1 -0
  2837. package/dist/wiki/lint.d.ts +25 -0
  2838. package/dist/wiki/lint.d.ts.map +1 -0
  2839. package/dist/wiki/lint.js +170 -0
  2840. package/dist/wiki/lint.js.map +1 -0
  2841. package/dist/wiki/query.d.ts +36 -0
  2842. package/dist/wiki/query.d.ts.map +1 -0
  2843. package/dist/wiki/query.js +139 -0
  2844. package/dist/wiki/query.js.map +1 -0
  2845. package/dist/wiki/storage.d.ts +37 -0
  2846. package/dist/wiki/storage.d.ts.map +1 -0
  2847. package/dist/wiki/storage.js +358 -0
  2848. package/dist/wiki/storage.js.map +1 -0
  2849. package/dist/wiki/types.d.ts +83 -0
  2850. package/dist/wiki/types.d.ts.map +1 -0
  2851. package/dist/wiki/types.js +15 -0
  2852. package/dist/wiki/types.js.map +1 -0
  2853. package/package.json +110 -0
  2854. package/plugins/oh-my-codex/.app.json +3 -0
  2855. package/plugins/oh-my-codex/.codex-plugin/plugin.json +31 -0
  2856. package/plugins/oh-my-codex/.mcp.json +52 -0
  2857. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +420 -0
  2858. package/plugins/oh-my-codex/hooks/hooks.json +76 -0
  2859. package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +148 -0
  2860. package/plugins/oh-my-codex/skills/analyze/SKILL.md +146 -0
  2861. package/plugins/oh-my-codex/skills/ask/SKILL.md +58 -0
  2862. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +215 -0
  2863. package/plugins/oh-my-codex/skills/autoresearch/SKILL.md +72 -0
  2864. package/plugins/oh-my-codex/skills/autoresearch-goal/SKILL.md +36 -0
  2865. package/plugins/oh-my-codex/skills/best-practice-research/SKILL.md +88 -0
  2866. package/plugins/oh-my-codex/skills/cancel/SKILL.md +399 -0
  2867. package/plugins/oh-my-codex/skills/code-review/SKILL.md +292 -0
  2868. package/plugins/oh-my-codex/skills/configure-notifications/SKILL.md +287 -0
  2869. package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +579 -0
  2870. package/plugins/oh-my-codex/skills/design/SKILL.md +180 -0
  2871. package/plugins/oh-my-codex/skills/doctor/SKILL.md +239 -0
  2872. package/plugins/oh-my-codex/skills/hud/SKILL.md +98 -0
  2873. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +135 -0
  2874. package/plugins/oh-my-codex/skills/performance-goal/SKILL.md +65 -0
  2875. package/plugins/oh-my-codex/skills/pipeline/SKILL.md +97 -0
  2876. package/plugins/oh-my-codex/skills/plan/SKILL.md +277 -0
  2877. package/plugins/oh-my-codex/skills/prometheus-strict/README.md +35 -0
  2878. package/plugins/oh-my-codex/skills/prometheus-strict/SKILL.md +219 -0
  2879. package/plugins/oh-my-codex/skills/ralph/SKILL.md +294 -0
  2880. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +203 -0
  2881. package/plugins/oh-my-codex/skills/skill/SKILL.md +836 -0
  2882. package/plugins/oh-my-codex/skills/team/SKILL.md +536 -0
  2883. package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +139 -0
  2884. package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +263 -0
  2885. package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +190 -0
  2886. package/plugins/oh-my-codex/skills/visual-ralph/SKILL.md +161 -0
  2887. package/plugins/oh-my-codex/skills/wiki/SKILL.md +57 -0
  2888. package/plugins/oh-my-codex/skills/worker/SKILL.md +120 -0
  2889. package/prompts/analyst.md +135 -0
  2890. package/prompts/api-reviewer.md +113 -0
  2891. package/prompts/architect.md +111 -0
  2892. package/prompts/build-fixer.md +115 -0
  2893. package/prompts/code-reviewer.md +139 -0
  2894. package/prompts/code-simplifier.md +134 -0
  2895. package/prompts/critic.md +80 -0
  2896. package/prompts/debugger.md +117 -0
  2897. package/prompts/dependency-expert.md +129 -0
  2898. package/prompts/designer.md +126 -0
  2899. package/prompts/executor.md +108 -0
  2900. package/prompts/explore-harness.md +64 -0
  2901. package/prompts/explore.md +85 -0
  2902. package/prompts/git-master.md +114 -0
  2903. package/prompts/information-architect.md +226 -0
  2904. package/prompts/performance-reviewer.md +109 -0
  2905. package/prompts/planner.md +110 -0
  2906. package/prompts/product-analyst.md +304 -0
  2907. package/prompts/product-manager.md +245 -0
  2908. package/prompts/prometheus-strict-metis.md +274 -0
  2909. package/prompts/prometheus-strict-momus.md +82 -0
  2910. package/prompts/prometheus-strict-oracle.md +107 -0
  2911. package/prompts/qa-tester.md +124 -0
  2912. package/prompts/quality-reviewer.md +123 -0
  2913. package/prompts/quality-strategist.md +274 -0
  2914. package/prompts/researcher.md +122 -0
  2915. package/prompts/scholastic.md +11 -0
  2916. package/prompts/security-reviewer.md +143 -0
  2917. package/prompts/sisyphus-lite.md +111 -0
  2918. package/prompts/style-reviewer.md +102 -0
  2919. package/prompts/team-executor.md +57 -0
  2920. package/prompts/team-orchestrator.md +8 -0
  2921. package/prompts/test-engineer.md +130 -0
  2922. package/prompts/ux-researcher.md +327 -0
  2923. package/prompts/verifier.md +85 -0
  2924. package/prompts/vision.md +98 -0
  2925. package/prompts/writer.md +109 -0
  2926. package/skills/ai-slop-cleaner/SKILL.md +148 -0
  2927. package/skills/analyze/SKILL.md +146 -0
  2928. package/skills/ask/SKILL.md +58 -0
  2929. package/skills/ask-claude/SKILL.md +12 -0
  2930. package/skills/ask-gemini/SKILL.md +12 -0
  2931. package/skills/autopilot/SKILL.md +215 -0
  2932. package/skills/autoresearch/SKILL.md +72 -0
  2933. package/skills/autoresearch-goal/SKILL.md +36 -0
  2934. package/skills/best-practice-research/SKILL.md +88 -0
  2935. package/skills/build-fix/SKILL.md +10 -0
  2936. package/skills/cancel/SKILL.md +399 -0
  2937. package/skills/code-review/SKILL.md +292 -0
  2938. package/skills/configure-notifications/SKILL.md +287 -0
  2939. package/skills/deep-interview/SKILL.md +579 -0
  2940. package/skills/deepsearch/SKILL.md +10 -0
  2941. package/skills/design/SKILL.md +180 -0
  2942. package/skills/doctor/SKILL.md +239 -0
  2943. package/skills/ecomode/SKILL.md +114 -0
  2944. package/skills/frontend-ui-ux/SKILL.md +16 -0
  2945. package/skills/git-master/SKILL.md +27 -0
  2946. package/skills/help/SKILL.md +10 -0
  2947. package/skills/hud/SKILL.md +98 -0
  2948. package/skills/note/SKILL.md +10 -0
  2949. package/skills/omx-setup/SKILL.md +135 -0
  2950. package/skills/performance-goal/SKILL.md +65 -0
  2951. package/skills/pipeline/SKILL.md +97 -0
  2952. package/skills/plan/SKILL.md +277 -0
  2953. package/skills/prometheus-strict/README.md +35 -0
  2954. package/skills/prometheus-strict/SKILL.md +219 -0
  2955. package/skills/ralph/SKILL.md +294 -0
  2956. package/skills/ralph-init/SKILL.md +10 -0
  2957. package/skills/ralplan/SKILL.md +203 -0
  2958. package/skills/review/SKILL.md +10 -0
  2959. package/skills/security-review/SKILL.md +10 -0
  2960. package/skills/skill/SKILL.md +836 -0
  2961. package/skills/swarm/SKILL.md +12 -0
  2962. package/skills/tdd/SKILL.md +104 -0
  2963. package/skills/team/SKILL.md +536 -0
  2964. package/skills/trace/SKILL.md +10 -0
  2965. package/skills/ultragoal/SKILL.md +139 -0
  2966. package/skills/ultraqa/SKILL.md +263 -0
  2967. package/skills/ultrawork/SKILL.md +190 -0
  2968. package/skills/visual-ralph/SKILL.md +161 -0
  2969. package/skills/visual-verdict/SKILL.md +10 -0
  2970. package/skills/web-clone/SKILL.md +357 -0
  2971. package/skills/wiki/SKILL.md +57 -0
  2972. package/skills/worker/SKILL.md +120 -0
  2973. package/src/scripts/__tests__/codex-native-hook.test.ts +17173 -0
  2974. package/src/scripts/__tests__/docs-site-contract.test.ts +47 -0
  2975. package/src/scripts/__tests__/generate-release-body.test.ts +275 -0
  2976. package/src/scripts/__tests__/hook-derived-watcher.test.ts +285 -0
  2977. package/src/scripts/__tests__/notify-dispatcher.test.ts +504 -0
  2978. package/src/scripts/__tests__/notify-state-io.test.ts +168 -0
  2979. package/src/scripts/__tests__/notify-tmux-injection.test.ts +82 -0
  2980. package/src/scripts/__tests__/postinstall.test.ts +113 -0
  2981. package/src/scripts/__tests__/prompt-inventory.test.ts +64 -0
  2982. package/src/scripts/__tests__/run-test-files.test.ts +455 -0
  2983. package/src/scripts/__tests__/smoke-packed-install.test.ts +192 -0
  2984. package/src/scripts/__tests__/test-reply-listener-live.test.ts +101 -0
  2985. package/src/scripts/__tests__/verify-native-agents.test.ts +299 -0
  2986. package/src/scripts/ask-claude.sh +17 -0
  2987. package/src/scripts/ask-gemini.sh +14 -0
  2988. package/src/scripts/build-api.ts +48 -0
  2989. package/src/scripts/build-explore-harness.ts +54 -0
  2990. package/src/scripts/build-sparkshell.ts +52 -0
  2991. package/src/scripts/check-runtime-syntax.ts +63 -0
  2992. package/src/scripts/check-version-sync.ts +54 -0
  2993. package/src/scripts/cleanup-explore-harness.ts +18 -0
  2994. package/src/scripts/codex-execution-surface.ts +75 -0
  2995. package/src/scripts/codex-native-hook.ts +4877 -0
  2996. package/src/scripts/codex-native-pre-post.ts +1360 -0
  2997. package/src/scripts/demo-claude-workers.sh +241 -0
  2998. package/src/scripts/demo-team-e2e.sh +184 -0
  2999. package/src/scripts/eval/eval-adaptive-sort-optimization.py +24 -0
  3000. package/src/scripts/eval/eval-candidate-handoff.ts +8 -0
  3001. package/src/scripts/eval/eval-cli-discoverability.ts +40 -0
  3002. package/src/scripts/eval/eval-fresh-run-tagging.ts +8 -0
  3003. package/src/scripts/eval/eval-help-consistency.ts +11 -0
  3004. package/src/scripts/eval/eval-in-action-cat-shellout-demo.ts +31 -0
  3005. package/src/scripts/eval/eval-ml-kaggle-model-optimization.py +29 -0
  3006. package/src/scripts/eval/eval-noisy-bayesopt-highdim.py +44 -0
  3007. package/src/scripts/eval/eval-noisy-latent-subspace-discovery.py +44 -0
  3008. package/src/scripts/eval/eval-parity-smoke.ts +20 -0
  3009. package/src/scripts/eval/eval-parity-sweep.ts +26 -0
  3010. package/src/scripts/eval/eval-resume-dirty-guard.ts +8 -0
  3011. package/src/scripts/eval/eval-security-path-traversal.ts +38 -0
  3012. package/src/scripts/fixtures/ask-advisor-stub.ts +12 -0
  3013. package/src/scripts/generate-catalog-docs.ts +112 -0
  3014. package/src/scripts/generate-native-release-manifest.ts +147 -0
  3015. package/src/scripts/generate-release-body.ts +327 -0
  3016. package/src/scripts/hook-derived-watcher.ts +649 -0
  3017. package/src/scripts/hook-payload-guard.ts +113 -0
  3018. package/src/scripts/notify-dispatcher.ts +408 -0
  3019. package/src/scripts/notify-fallback-watcher.ts +2022 -0
  3020. package/src/scripts/notify-hook/__tests__/operational-events.test.ts +24 -0
  3021. package/src/scripts/notify-hook/__tests__/payload-guard.test.ts +41 -0
  3022. package/src/scripts/notify-hook/__tests__/team-worker-posttooluse.test.ts +180 -0
  3023. package/src/scripts/notify-hook/active-team.ts +55 -0
  3024. package/src/scripts/notify-hook/auto-nudge.ts +758 -0
  3025. package/src/scripts/notify-hook/log.ts +30 -0
  3026. package/src/scripts/notify-hook/managed-tmux.ts +568 -0
  3027. package/src/scripts/notify-hook/operational-events.ts +282 -0
  3028. package/src/scripts/notify-hook/orchestration-intent.ts +80 -0
  3029. package/src/scripts/notify-hook/payload-parser.ts +143 -0
  3030. package/src/scripts/notify-hook/process-runner.ts +75 -0
  3031. package/src/scripts/notify-hook/ralph-session-resume.ts +465 -0
  3032. package/src/scripts/notify-hook/state-io.ts +220 -0
  3033. package/src/scripts/notify-hook/team-dispatch.ts +1162 -0
  3034. package/src/scripts/notify-hook/team-leader-nudge.ts +1068 -0
  3035. package/src/scripts/notify-hook/team-tmux-guard.ts +236 -0
  3036. package/src/scripts/notify-hook/team-worker-posttooluse.ts +536 -0
  3037. package/src/scripts/notify-hook/team-worker-stop.ts +438 -0
  3038. package/src/scripts/notify-hook/team-worker.ts +709 -0
  3039. package/src/scripts/notify-hook/tmux-injection.ts +740 -0
  3040. package/src/scripts/notify-hook/utils.ts +31 -0
  3041. package/src/scripts/notify-hook/visual-verdict.ts +158 -0
  3042. package/src/scripts/notify-hook.ts +1033 -0
  3043. package/src/scripts/postinstall.ts +107 -0
  3044. package/src/scripts/prepare-build.js +83 -0
  3045. package/src/scripts/prompt-inventory.ts +218 -0
  3046. package/src/scripts/run-autoresearch-showcase.sh +75 -0
  3047. package/src/scripts/run-provider-advisor.ts +213 -0
  3048. package/src/scripts/run-test-files.ts +379 -0
  3049. package/src/scripts/smoke-packed-install.ts +268 -0
  3050. package/src/scripts/sync-plugin-mirror.ts +458 -0
  3051. package/src/scripts/sync-prompt-guidance-fragments.ts +55 -0
  3052. package/src/scripts/team-hardening-benchmark.ts +90 -0
  3053. package/src/scripts/test-reply-listener-live.ts +188 -0
  3054. package/src/scripts/test-sparkshell.ts +29 -0
  3055. package/src/scripts/tmux-hook-engine.ts +349 -0
  3056. package/src/scripts/verify-native-agents.ts +311 -0
  3057. package/src/scripts/verify-native-release-assets.ts +68 -0
  3058. package/templates/AGENTS.md +187 -0
  3059. package/templates/catalog-manifest.json +547 -0
  3060. package/templates/model-instructions/explore-lightweight-AGENTS.md +11 -0
  3061. package/templates/model-instructions/sparkshell-lightweight-AGENTS.md +10 -0
@@ -0,0 +1,3956 @@
1
+ import { after, before, describe, it } from 'node:test';
2
+ import { once } from 'node:events';
3
+ import assert from 'node:assert/strict';
4
+ import { appendFile, chmod, mkdtemp, mkdir, readFile, rename, rm, symlink, writeFile } from 'node:fs/promises';
5
+ import { tmpdir } from 'node:os';
6
+ import { join } from 'node:path';
7
+ import { spawn, spawnSync } from 'node:child_process';
8
+ import { randomUUID } from 'node:crypto';
9
+ import { initTeamState, enqueueDispatchRequest, readDispatchRequest } from '../../team/state.js';
10
+ import { buildTmuxSessionName, buildWindowsMsysBackgroundHelperBootstrapScript } from '../../cli/index.js';
11
+ import { writeSessionStart } from '../session.js';
12
+ const DEFAULT_AUTO_NUDGE_RESPONSE = 'continue with the current task only if it is already authorized';
13
+ const INHERITED_OMX_ENV_KEYS = [
14
+ 'OMX_ROOT',
15
+ 'OMX_STATE_ROOT',
16
+ 'OMX_SESSION_ID',
17
+ 'OMX_SOURCE_CWD',
18
+ 'OMX_STARTUP_CWD',
19
+ 'OMX_ENTRY_PATH',
20
+ ];
21
+ const inheritedOmxEnv = new Map();
22
+ before(() => {
23
+ for (const key of INHERITED_OMX_ENV_KEYS) {
24
+ inheritedOmxEnv.set(key, process.env[key]);
25
+ delete process.env[key];
26
+ }
27
+ });
28
+ after(() => {
29
+ for (const key of INHERITED_OMX_ENV_KEYS) {
30
+ const value = inheritedOmxEnv.get(key);
31
+ if (typeof value === 'string')
32
+ process.env[key] = value;
33
+ else
34
+ delete process.env[key];
35
+ }
36
+ });
37
+ async function appendLine(path, line) {
38
+ const prev = await readFile(path, 'utf-8');
39
+ const content = prev + `${JSON.stringify(line)}\n`;
40
+ await writeFile(path, content);
41
+ }
42
+ function todaySessionDir(baseHome) {
43
+ const now = new Date();
44
+ return join(baseHome, '.codex', 'sessions', String(now.getUTCFullYear()), String(now.getUTCMonth() + 1).padStart(2, '0'), String(now.getUTCDate()).padStart(2, '0'));
45
+ }
46
+ async function readLines(path) {
47
+ const content = await readFile(path, 'utf-8').catch(() => '');
48
+ return content.split('\n').map(s => s.trim()).filter(Boolean);
49
+ }
50
+ async function readJsonLines(path) {
51
+ const content = await readFile(path, 'utf-8').catch(() => '');
52
+ return content
53
+ .split('\n')
54
+ .map((line) => line.trim())
55
+ .filter(Boolean)
56
+ .map((line) => JSON.parse(line));
57
+ }
58
+ async function writeCanonicalWatcherTeamFixture(wd, { teamName = 'dispatch-team', sessionId = 'sess-current', ownerSessionId = sessionId, coarseState = 'missing', terminal = false, } = {}) {
59
+ const stateDir = join(wd, '.omx', 'state');
60
+ const teamDir = join(stateDir, 'team', teamName);
61
+ const nowIso = new Date().toISOString();
62
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
63
+ await mkdir(join(teamDir, 'workers'), { recursive: true });
64
+ await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId }, null, 2));
65
+ if (coarseState !== 'missing') {
66
+ await writeFile(join(stateDir, 'team-state.json'), JSON.stringify({
67
+ active: coarseState === 'active',
68
+ team_name: teamName,
69
+ current_phase: terminal ? 'complete' : 'team-exec',
70
+ ...(terminal ? { completed_at: nowIso } : {}),
71
+ }, null, 2));
72
+ }
73
+ await writeFile(join(stateDir, 'hud-state.json'), JSON.stringify({
74
+ last_turn_at: new Date(Date.now() - 300_000).toISOString(),
75
+ turn_count: 3,
76
+ }, null, 2));
77
+ const manifest = {
78
+ schema_version: 2,
79
+ name: teamName,
80
+ task: 'canonical watcher fallback repro',
81
+ leader: {
82
+ session_id: ownerSessionId,
83
+ worker_id: 'leader-fixed',
84
+ role: 'coordinator',
85
+ },
86
+ policy: {
87
+ worker_launch_mode: 'interactive',
88
+ display_mode: 'split_pane',
89
+ dispatch_mode: 'hook_preferred_with_fallback',
90
+ dispatch_ack_timeout_ms: 2000,
91
+ },
92
+ governance: {
93
+ delegation_only: false,
94
+ plan_approval_required: false,
95
+ nested_teams_allowed: false,
96
+ one_team_per_leader_session: true,
97
+ cleanup_requires_all_workers_inactive: true,
98
+ },
99
+ lifecycle_profile: 'default',
100
+ permissions_snapshot: {
101
+ approval_mode: 'never',
102
+ sandbox_mode: 'danger-full-access',
103
+ network_access: true,
104
+ },
105
+ tmux_session: `${teamName}:0`,
106
+ leader_pane_id: '%42',
107
+ hud_pane_id: null,
108
+ resize_hook_name: null,
109
+ resize_hook_target: null,
110
+ worker_count: 1,
111
+ next_task_id: 1,
112
+ workers: [
113
+ { name: 'worker-1', index: 1, pane_id: '%42', role: 'executor' },
114
+ ],
115
+ created_at: nowIso,
116
+ };
117
+ await writeFile(join(teamDir, 'manifest.v2.json'), JSON.stringify(manifest, null, 2));
118
+ await writeFile(join(teamDir, 'config.json'), JSON.stringify({
119
+ name: teamName,
120
+ tmux_session: `${teamName}:0`,
121
+ leader_pane_id: '%42',
122
+ workers: [
123
+ { name: 'worker-1', pane_id: '%42' },
124
+ ],
125
+ }, null, 2));
126
+ await writeFile(join(teamDir, 'phase.json'), JSON.stringify({
127
+ current_phase: terminal ? 'complete' : 'team-exec',
128
+ updated_at: nowIso,
129
+ transitions: terminal ? [{ from: 'team-exec', to: 'complete', at: nowIso }] : [],
130
+ }, null, 2));
131
+ }
132
+ async function sleep(ms) {
133
+ await new Promise(resolve => setTimeout(resolve, ms));
134
+ }
135
+ async function waitFor(predicate, timeoutMs = 3000, stepMs = 50) {
136
+ const deadline = Date.now() + timeoutMs;
137
+ while (Date.now() < deadline) {
138
+ if (await predicate())
139
+ return;
140
+ await sleep(stepMs);
141
+ }
142
+ throw new Error(`waitFor timed out after ${timeoutMs}ms`);
143
+ }
144
+ function isPidAlive(pid) {
145
+ if (!pid || !Number.isFinite(pid) || pid <= 0)
146
+ return false;
147
+ try {
148
+ process.kill(pid, 0);
149
+ return true;
150
+ }
151
+ catch {
152
+ return false;
153
+ }
154
+ }
155
+ async function waitForExit(child, timeoutMs = 4000) {
156
+ if (child.exitCode !== null || child.signalCode !== null)
157
+ return;
158
+ await Promise.race([
159
+ once(child, 'exit'),
160
+ sleep(timeoutMs).then(() => {
161
+ throw new Error(`process ${child.pid ?? 'unknown'} did not exit within ${timeoutMs}ms`);
162
+ }),
163
+ ]);
164
+ }
165
+ function defaultAutoNudgePattern(targetPane) {
166
+ return new RegExp(`send-keys -t ${targetPane} -l ${DEFAULT_AUTO_NUDGE_RESPONSE.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')} \\[OMX_TMUX_INJECT\\]`);
167
+ }
168
+ function buildFakeTmux(tmuxLogPath, options = {}) {
169
+ return `#!/usr/bin/env bash
170
+ set -eu
171
+ echo "$@" >> "${tmuxLogPath}"
172
+ cmd="$1"
173
+ shift || true
174
+ if [[ "$cmd" == "capture-pane" ]]; then
175
+ if [[ -n "\${OMX_TEST_CAPTURE_SEQUENCE_FILE:-}" && -f "\${OMX_TEST_CAPTURE_SEQUENCE_FILE}" ]]; then
176
+ counterFile="\${OMX_TEST_CAPTURE_COUNTER_FILE:-\${OMX_TEST_CAPTURE_SEQUENCE_FILE}.idx}"
177
+ idx=0
178
+ if [[ -f "$counterFile" ]]; then idx="$(cat "$counterFile")"; fi
179
+ lineNo=$((idx + 1))
180
+ line="$(sed -n "\${lineNo}p" "\${OMX_TEST_CAPTURE_SEQUENCE_FILE}" || true)"
181
+ if [[ -z "$line" ]]; then
182
+ line="$(tail -n 1 "\${OMX_TEST_CAPTURE_SEQUENCE_FILE}" || true)"
183
+ fi
184
+ printf "%s\\n" "$line"
185
+ echo "$lineNo" > "$counterFile"
186
+ exit 0
187
+ fi
188
+ if [[ -n "\${OMX_TEST_CAPTURE_FILE:-}" && -f "\${OMX_TEST_CAPTURE_FILE}" ]]; then
189
+ cat "\${OMX_TEST_CAPTURE_FILE}"
190
+ fi
191
+ exit 0
192
+ fi
193
+ if [[ "$cmd" == "display-message" ]]; then
194
+ target=""
195
+ fmt=""
196
+ while [[ "$#" -gt 0 ]]; do
197
+ case "$1" in
198
+ -t)
199
+ shift
200
+ target="$1"
201
+ ;;
202
+ *)
203
+ fmt="$1"
204
+ ;;
205
+ esac
206
+ shift || true
207
+ done
208
+ if [[ "$fmt" == "#{pane_in_mode}" ]]; then
209
+ echo "0"
210
+ exit 0
211
+ fi
212
+ if [[ "$fmt" == "#{pane_id}" ]]; then
213
+ echo "\${target:-%42}"
214
+ exit 0
215
+ fi
216
+ if [[ "$fmt" == "#{pane_current_path}" ]]; then
217
+ dirname "${tmuxLogPath}"
218
+ exit 0
219
+ fi
220
+ if [[ "$fmt" == "#{pane_current_command}" ]]; then
221
+ echo "codex"
222
+ exit 0
223
+ fi
224
+ if [[ "$fmt" == "#S" ]]; then
225
+ echo "\${OMX_TEST_TMUX_SESSION_NAME:-session-test}"
226
+ exit 0
227
+ fi
228
+ exit 0
229
+ fi
230
+ if [[ "$cmd" == "send-keys" ]]; then
231
+ sendKeysArgs="$*"
232
+ if [[ "${options.failSendKeys === true ? '1' : '0'}" == "1" ]]; then
233
+ echo "send failed" >&2
234
+ exit 1
235
+ fi
236
+ if [[ -n "${options.failSendKeysMatch || ''}" && "$sendKeysArgs" == *"${options.failSendKeysMatch || ''}"* ]]; then
237
+ echo "send failed" >&2
238
+ exit 1
239
+ fi
240
+ exit 0
241
+ fi
242
+ if [[ "$cmd" == "list-panes" ]]; then
243
+ target=""
244
+ while [[ "$#" -gt 0 ]]; do
245
+ case "$1" in
246
+ -t)
247
+ shift
248
+ target="$1"
249
+ ;;
250
+ esac
251
+ shift || true
252
+ done
253
+ if [[ -n "$target" ]]; then
254
+ printf "%%42\tcodex\tcodex\n"
255
+ exit 0
256
+ fi
257
+ echo "%42 1"
258
+ exit 0
259
+ fi
260
+ exit 0
261
+ `;
262
+ }
263
+ function buildManagedRalphTmux(tmuxLogPath, options) {
264
+ const { cwd, managedSessionName, anchorPane, livePane, codexPanes, missingAnchor = false } = options;
265
+ const panes = (codexPanes && codexPanes.length > 0)
266
+ ? codexPanes
267
+ : [{ paneId: livePane, active: true, currentCommand: 'codex', startCommand: 'codex' }];
268
+ const listPaneOutput = panes
269
+ .map((pane) => {
270
+ const paneId = pane.paneId;
271
+ const active = pane.active ? '1' : '0';
272
+ const currentCommand = pane.currentCommand || 'codex';
273
+ const startCommand = pane.startCommand || 'codex';
274
+ return `${paneId}\t${active}\t${currentCommand}\t${startCommand}`;
275
+ })
276
+ .join('\n');
277
+ const paneCommandBranches = panes
278
+ .map((pane) => {
279
+ const currentCommand = (pane.currentCommand || 'codex').replace(/"/g, '\\"');
280
+ const startCommand = (pane.startCommand || 'codex').replace(/"/g, '\\"');
281
+ return ` if [[ "$format" == "#{pane_current_command}" && "$target" == "${pane.paneId}" ]]; then
282
+ echo "${currentCommand}"
283
+ exit 0
284
+ fi
285
+ if [[ "$format" == "#{pane_start_command}" && "$target" == "${pane.paneId}" ]]; then
286
+ echo "${startCommand}"
287
+ exit 0
288
+ fi`;
289
+ })
290
+ .join('\n');
291
+ return `#!/usr/bin/env bash
292
+ set -eu
293
+ echo "$@" >> "${tmuxLogPath}"
294
+ cmd="$1"
295
+ shift || true
296
+ if [[ "$cmd" == "display-message" ]]; then
297
+ target=""
298
+ format=""
299
+ while [[ "$#" -gt 0 ]]; do
300
+ case "$1" in
301
+ -p) shift ;;
302
+ -t) target="$2"; shift 2 ;;
303
+ *) format="$1"; shift ;;
304
+ esac
305
+ done
306
+ if [[ "$target" == "${anchorPane}" && "${missingAnchor ? '1' : '0'}" == "1" ]]; then
307
+ echo "pane missing" >&2
308
+ exit 1
309
+ fi
310
+ if [[ "$format" == "#{pane_in_mode}" ]]; then
311
+ echo "0"
312
+ exit 0
313
+ fi
314
+ if [[ "$format" == "#{pane_id}" ]]; then
315
+ echo "$target"
316
+ exit 0
317
+ fi
318
+ if [[ "$format" == "#{pane_current_path}" ]]; then
319
+ echo "${cwd}"
320
+ exit 0
321
+ fi
322
+ ${paneCommandBranches}
323
+ if [[ "$format" == "#S" ]]; then
324
+ if [[ "$target" == "${anchorPane}" || "$target" == "${livePane}" ]]; then
325
+ echo "${managedSessionName}"
326
+ exit 0
327
+ fi
328
+ echo "unknown target" >&2
329
+ exit 1
330
+ fi
331
+ exit 0
332
+ fi
333
+ if [[ "$cmd" == "list-panes" ]]; then
334
+ target=""
335
+ while [[ "$#" -gt 0 ]]; do
336
+ case "$1" in
337
+ -F) shift 2 ;;
338
+ -t) shift; target="$1" ;;
339
+ esac
340
+ shift || true
341
+ done
342
+ if [[ "$target" == "${managedSessionName}" ]]; then
343
+ printf '%s\n' "${listPaneOutput}"
344
+ exit 0
345
+ fi
346
+ echo "can't find session" >&2
347
+ exit 1
348
+ fi
349
+ if [[ "$cmd" == "capture-pane" ]]; then
350
+ exit 0
351
+ fi
352
+ if [[ "$cmd" == "send-keys" ]]; then
353
+ exit 0
354
+ fi
355
+ exit 0
356
+ `;
357
+ }
358
+ function buildCleanNotifyEnv(overrides = {}) {
359
+ return {
360
+ ...process.env,
361
+ OMX_TEAM_WORKER: '',
362
+ OMX_TEAM_STATE_ROOT: '',
363
+ OMX_TEAM_LEADER_CWD: '',
364
+ OMX_MODEL_INSTRUCTIONS_FILE: '',
365
+ OMX_ROOT: '',
366
+ OMX_STATE_ROOT: '',
367
+ OMX_SOURCE_CWD: '',
368
+ OMX_STARTUP_CWD: '',
369
+ TMUX: '',
370
+ TMUX_PANE: '',
371
+ ...overrides,
372
+ };
373
+ }
374
+ describe('notify-fallback watcher', () => {
375
+ it('uses offset-bounded rollout reads instead of re-reading whole tracked files', async () => {
376
+ const source = await readFile(new URL('../../scripts/notify-fallback-watcher.js', import.meta.url), 'utf-8');
377
+ assert.match(source, /async function readFileDelta/);
378
+ assert.match(source, /while \(totalBytesRead < length\)/);
379
+ assert.match(source, /nextOffset: offset \+ totalBytesRead/);
380
+ assert.match(source, /new StringDecoder\('utf8'\)/);
381
+ assert.match(source, /decoder\.write\(bytes\)/);
382
+ assert.match(source, /const fileStat = await stat\(path\)\.catch\(\(\) => null\);\s*if \(!fileStat\)\s*continue;/);
383
+ assert.match(source, /if \(currentSize < meta\.offset\) \{\s*meta\.offset = 0;\s*meta\.partial = '';/);
384
+ assert.doesNotMatch(source, /const content = await readFile\(path, 'utf-8'\)[\s\S]*const delta = content\.slice\(meta\.offset\)/);
385
+ assert.doesNotMatch(source, /stat\(path\)\.catch\(\(\) => \(\{ size: 0 \}\)\)/);
386
+ });
387
+ it('one-shot mode forwards only recent task_complete events', async () => {
388
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-once-'));
389
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-home-'));
390
+ const sid = `test-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
391
+ const sessionDir = todaySessionDir(tempHome);
392
+ const rolloutPath = join(sessionDir, `rollout-test-fallback-once-${sid}.jsonl`);
393
+ try {
394
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
395
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
396
+ await mkdir(sessionDir, { recursive: true });
397
+ const staleIso = new Date(Date.now() - 60_000).toISOString();
398
+ const freshIso = new Date(Date.now() + 2_000).toISOString();
399
+ const threadId = `thread-${sid}`;
400
+ const leaderThreadId = `leader-${sid}`;
401
+ const staleTurn = `turn-stale-${sid}`;
402
+ const freshTurn = `turn-fresh-${sid}`;
403
+ await writeFile(join(wd, '.omx', 'state', 'session.json'), JSON.stringify({ session_id: sid }));
404
+ await writeFile(join(wd, '.omx', 'state', 'subagent-tracking.json'), JSON.stringify({
405
+ schemaVersion: 1,
406
+ sessions: {
407
+ [sid]: {
408
+ session_id: sid,
409
+ leader_thread_id: leaderThreadId,
410
+ updated_at: staleIso,
411
+ threads: {
412
+ [leaderThreadId]: {
413
+ thread_id: leaderThreadId,
414
+ kind: 'leader',
415
+ first_seen_at: staleIso,
416
+ last_seen_at: staleIso,
417
+ turn_count: 1,
418
+ },
419
+ [threadId]: {
420
+ thread_id: threadId,
421
+ kind: 'subagent',
422
+ first_seen_at: staleIso,
423
+ last_seen_at: staleIso,
424
+ turn_count: 1,
425
+ },
426
+ },
427
+ },
428
+ },
429
+ }));
430
+ const lines = [
431
+ {
432
+ timestamp: freshIso,
433
+ type: 'session_meta',
434
+ payload: { id: threadId, cwd: wd },
435
+ },
436
+ {
437
+ timestamp: staleIso,
438
+ type: 'event_msg',
439
+ payload: {
440
+ type: 'task_complete',
441
+ turn_id: staleTurn,
442
+ last_agent_message: 'stale message',
443
+ },
444
+ },
445
+ {
446
+ timestamp: freshIso,
447
+ type: 'event_msg',
448
+ payload: {
449
+ type: 'task_complete',
450
+ turn_id: freshTurn,
451
+ last_agent_message: 'fresh message',
452
+ },
453
+ },
454
+ ];
455
+ await writeFile(rolloutPath, `${lines.map(v => JSON.stringify(v)).join('\n')}\n`);
456
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
457
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
458
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env: buildCleanNotifyEnv({ HOME: tempHome }) });
459
+ assert.equal(result.status, 0, result.stderr || result.stdout);
460
+ const turnLog = join(wd, '.omx', 'logs', `turns-${new Date().toISOString().split('T')[0]}.jsonl`);
461
+ const turnLines = await readLines(turnLog);
462
+ assert.equal(turnLines.length, 1);
463
+ assert.match(turnLines[0], new RegExp(freshTurn));
464
+ assert.doesNotMatch(turnLines[0], new RegExp(staleTurn));
465
+ const fallbackLog = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
466
+ const fallbackEntries = await readJsonLines(fallbackLog);
467
+ assert.deepEqual(fallbackEntries.map((entry) => entry.type), ['fallback_notify']);
468
+ const tracking = JSON.parse(await readFile(join(wd, '.omx', 'state', 'subagent-tracking.json'), 'utf-8'));
469
+ const completedThread = tracking.sessions?.[sid]?.threads?.[threadId];
470
+ assert.equal(completedThread?.completed_at ? true : false, true);
471
+ assert.equal(completedThread?.last_completed_turn_id, freshTurn);
472
+ assert.equal(completedThread?.completion_source, 'notify-fallback-watcher');
473
+ }
474
+ finally {
475
+ await rm(wd, { recursive: true, force: true });
476
+ await rm(tempHome, { recursive: true, force: true });
477
+ await rm(rolloutPath, { force: true });
478
+ }
479
+ });
480
+ it('rotates notify-fallback logs when the size cap is exceeded', async () => {
481
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-once-rotate-'));
482
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-home-'));
483
+ const sid = randomUUID();
484
+ const sessionDir = todaySessionDir(tempHome);
485
+ const rolloutPath = join(sessionDir, `rollout-test-fallback-rotate-${sid}.jsonl`);
486
+ try {
487
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
488
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
489
+ await mkdir(sessionDir, { recursive: true });
490
+ const threadId = `thread-${sid}`;
491
+ const turnIds = ['first', 'second', 'third'].map((label) => `turn-${label}-${sid}`);
492
+ const nowIso = new Date(Date.now() + 2_000).toISOString();
493
+ const lines = [
494
+ {
495
+ timestamp: nowIso,
496
+ type: 'session_meta',
497
+ payload: { id: threadId, cwd: wd },
498
+ },
499
+ ...turnIds.map((turnId) => ({
500
+ timestamp: nowIso,
501
+ type: 'event_msg',
502
+ payload: {
503
+ type: 'task_complete',
504
+ turn_id: turnId,
505
+ last_agent_message: `message for ${turnId}`,
506
+ },
507
+ })),
508
+ ];
509
+ await writeFile(rolloutPath, `${lines.map(v => JSON.stringify(v)).join('\n')}\n`);
510
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
511
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
512
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50', '--log-max-bytes', '1'], { encoding: 'utf-8', env: buildCleanNotifyEnv({ HOME: tempHome }) });
513
+ assert.equal(result.status, 0, result.stderr || result.stdout);
514
+ const fallbackLog = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
515
+ const rotatedLog = `${fallbackLog}.1`;
516
+ const currentEntries = await readJsonLines(fallbackLog);
517
+ const rotatedEntries = await readJsonLines(rotatedLog);
518
+ assert.equal(currentEntries.length, 1);
519
+ assert.equal(rotatedEntries.length, 1);
520
+ assert.equal(currentEntries[0]?.turn_id, turnIds[2]);
521
+ assert.equal(rotatedEntries[0]?.turn_id, turnIds[1]);
522
+ assert.deepEqual(currentEntries.map((entry) => entry.type), ['fallback_notify']);
523
+ assert.deepEqual(rotatedEntries.map((entry) => entry.type), ['fallback_notify']);
524
+ }
525
+ finally {
526
+ await rm(wd, { recursive: true, force: true });
527
+ await rm(tempHome, { recursive: true, force: true });
528
+ await rm(rolloutPath, { force: true });
529
+ }
530
+ });
531
+ it('streaming mode buffers partial JSON lines until the newline arrives', async () => {
532
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-stream-partial-'));
533
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-home-'));
534
+ const sid = randomUUID();
535
+ const sessionDir = todaySessionDir(tempHome);
536
+ const rolloutPath = join(sessionDir, `rollout-test-fallback-stream-partial-${sid}.jsonl`);
537
+ try {
538
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
539
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
540
+ await mkdir(sessionDir, { recursive: true });
541
+ const nowIso = new Date().toISOString();
542
+ const threadId = `thread-${sid}`;
543
+ const partialTurn = `turn-partial-${sid}`;
544
+ await writeFile(rolloutPath, `${JSON.stringify({
545
+ timestamp: nowIso,
546
+ type: 'session_meta',
547
+ payload: { id: threadId, cwd: wd },
548
+ })}
549
+ `);
550
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
551
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
552
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
553
+ const turnLog = join(wd, '.omx', 'logs', `turns-${new Date().toISOString().split('T')[0]}.jsonl`);
554
+ const child = spawn(process.execPath, [watcherScript, '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '75'], { cwd: wd, stdio: 'ignore', env: buildCleanNotifyEnv({ HOME: tempHome }) });
555
+ await waitFor(async () => {
556
+ try {
557
+ const state = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
558
+ return state.tracked_files === 1;
559
+ }
560
+ catch {
561
+ return false;
562
+ }
563
+ });
564
+ const partialPrefix = JSON.stringify({
565
+ timestamp: new Date(Date.now() + 500).toISOString(),
566
+ type: 'event_msg',
567
+ payload: {
568
+ type: 'task_complete',
569
+ turn_id: partialTurn,
570
+ last_agent_message: 'partial message',
571
+ },
572
+ });
573
+ const splitAt = Math.floor(partialPrefix.length / 2);
574
+ await writeFile(rolloutPath, `${await readFile(rolloutPath, 'utf-8')}${partialPrefix.slice(0, splitAt)}`);
575
+ await sleep(250);
576
+ const beforeLines = await readLines(turnLog);
577
+ assert.equal(beforeLines.length, 0, 'partial line should not be emitted before newline completes it');
578
+ await writeFile(rolloutPath, `${await readFile(rolloutPath, 'utf-8')}${partialPrefix.slice(splitAt)}\n`);
579
+ await waitFor(async () => {
580
+ const turnLines = await readLines(turnLog);
581
+ return turnLines.length === 1 && new RegExp(partialTurn).test(turnLines[0] ?? '');
582
+ }, 4000, 75);
583
+ child.kill('SIGTERM');
584
+ await once(child, 'exit');
585
+ const turnLines = await readLines(turnLog);
586
+ assert.equal(turnLines.length, 1);
587
+ assert.match(turnLines[0], new RegExp(partialTurn));
588
+ }
589
+ finally {
590
+ await rm(wd, { recursive: true, force: true });
591
+ await rm(tempHome, { recursive: true, force: true });
592
+ await rm(rolloutPath, { force: true });
593
+ }
594
+ });
595
+ it('streaming mode preserves multibyte text split across polling reads', async () => {
596
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-stream-utf8-'));
597
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-home-'));
598
+ const sid = randomUUID();
599
+ const sessionDir = todaySessionDir(tempHome);
600
+ const rolloutPath = join(sessionDir, `rollout-test-fallback-stream-utf8-${sid}.jsonl`);
601
+ try {
602
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
603
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
604
+ await mkdir(sessionDir, { recursive: true });
605
+ const nowIso = new Date().toISOString();
606
+ const threadId = `thread-${sid}`;
607
+ const utf8Turn = `turn-utf8-${sid}`;
608
+ const emojiMessage = 'split emoji 🧪 preserved';
609
+ await writeFile(rolloutPath, `${JSON.stringify({
610
+ timestamp: nowIso,
611
+ type: 'session_meta',
612
+ payload: { id: threadId, cwd: wd },
613
+ })}\n`);
614
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
615
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
616
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
617
+ const turnLog = join(wd, '.omx', 'logs', `turns-${new Date().toISOString().split('T')[0]}.jsonl`);
618
+ const child = spawn(process.execPath, [watcherScript, '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '75'], { cwd: wd, stdio: 'ignore', env: buildCleanNotifyEnv({ HOME: tempHome }) });
619
+ await waitFor(async () => {
620
+ try {
621
+ const state = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
622
+ return state.tracked_files === 1;
623
+ }
624
+ catch {
625
+ return false;
626
+ }
627
+ });
628
+ const eventLine = `${JSON.stringify({
629
+ timestamp: new Date(Date.now() + 500).toISOString(),
630
+ type: 'event_msg',
631
+ payload: {
632
+ type: 'task_complete',
633
+ turn_id: utf8Turn,
634
+ last_agent_message: emojiMessage,
635
+ },
636
+ })}\n`;
637
+ const bytes = Buffer.from(eventLine, 'utf8');
638
+ const emojiOffset = bytes.indexOf(Buffer.from('🧪', 'utf8'));
639
+ assert.ok(emojiOffset > 0, 'expected test payload to contain emoji bytes');
640
+ await appendFile(rolloutPath, bytes.subarray(0, emojiOffset + 1));
641
+ await sleep(250);
642
+ assert.equal((await readLines(turnLog)).length, 0, 'incomplete UTF-8 and JSON line should not emit');
643
+ const hiddenRolloutPath = `${rolloutPath}.missing`;
644
+ await rename(rolloutPath, hiddenRolloutPath);
645
+ await sleep(250);
646
+ assert.equal((await readLines(turnLog)).length, 0, 'transient missing file should preserve buffered bytes');
647
+ await rename(hiddenRolloutPath, rolloutPath);
648
+ await appendFile(rolloutPath, bytes.subarray(emojiOffset + 1));
649
+ await waitFor(async () => {
650
+ const turnLines = await readLines(turnLog);
651
+ return turnLines.length === 1 && turnLines[0].includes(utf8Turn) && turnLines[0].includes(emojiMessage);
652
+ }, 4000, 75);
653
+ child.kill('SIGTERM');
654
+ await once(child, 'exit');
655
+ const turnLines = await readLines(turnLog);
656
+ assert.equal(turnLines.length, 1);
657
+ assert.match(turnLines[0], new RegExp(utf8Turn));
658
+ assert.match(turnLines[0], /split emoji 🧪 preserved/);
659
+ }
660
+ finally {
661
+ await rm(wd, { recursive: true, force: true });
662
+ await rm(tempHome, { recursive: true, force: true });
663
+ await rm(rolloutPath, { force: true });
664
+ }
665
+ });
666
+ it('streaming mode tails from EOF and does not replay backlog', async () => {
667
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-stream-'));
668
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-home-'));
669
+ const sid = randomUUID();
670
+ const sessionDir = todaySessionDir(tempHome);
671
+ const rolloutPath = join(sessionDir, `rollout-test-fallback-stream-${sid}.jsonl`);
672
+ try {
673
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
674
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
675
+ await mkdir(sessionDir, { recursive: true });
676
+ const nowIso = new Date().toISOString();
677
+ const threadId = `thread-${sid}`;
678
+ const oldTurn = `turn-old-${sid}`;
679
+ const newTurn = `turn-new-${sid}`;
680
+ await writeFile(rolloutPath, `${JSON.stringify({
681
+ timestamp: nowIso,
682
+ type: 'session_meta',
683
+ payload: { id: threadId, cwd: wd },
684
+ })}\n${JSON.stringify({
685
+ timestamp: nowIso,
686
+ type: 'event_msg',
687
+ payload: {
688
+ type: 'task_complete',
689
+ turn_id: oldTurn,
690
+ last_agent_message: 'old message',
691
+ },
692
+ })}\n`);
693
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
694
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
695
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
696
+ const turnLog = join(wd, '.omx', 'logs', `turns-${new Date().toISOString().split('T')[0]}.jsonl`);
697
+ const child = spawn(process.execPath, [watcherScript, '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '75'], {
698
+ cwd: wd,
699
+ stdio: 'ignore',
700
+ env: buildCleanNotifyEnv({ HOME: tempHome }),
701
+ });
702
+ await waitFor(async () => {
703
+ try {
704
+ const state = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
705
+ return state.tracked_files === 1;
706
+ }
707
+ catch {
708
+ return false;
709
+ }
710
+ });
711
+ await appendLine(rolloutPath, {
712
+ timestamp: new Date(Date.now() + 500).toISOString(),
713
+ type: 'event_msg',
714
+ payload: {
715
+ type: 'task_complete',
716
+ turn_id: newTurn,
717
+ last_agent_message: 'new message',
718
+ },
719
+ });
720
+ await waitFor(async () => {
721
+ const turnLines = await readLines(turnLog);
722
+ return turnLines.length === 1 && new RegExp(newTurn).test(turnLines[0] ?? '');
723
+ }, 4000, 75);
724
+ child.kill('SIGTERM');
725
+ await once(child, 'exit');
726
+ const turnLines = await readLines(turnLog);
727
+ assert.equal(turnLines.length, 1);
728
+ assert.match(turnLines[0], new RegExp(newTurn));
729
+ assert.doesNotMatch(turnLines[0], new RegExp(oldTurn));
730
+ }
731
+ finally {
732
+ await rm(wd, { recursive: true, force: true });
733
+ await rm(tempHome, { recursive: true, force: true });
734
+ await rm(rolloutPath, { force: true });
735
+ }
736
+ });
737
+ it('records explicit leader-only dispatch drain state and log visibility in one-shot mode', async () => {
738
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-dispatch-state-'));
739
+ try {
740
+ await initTeamState('dispatch-team', 'task', 'executor', 1, wd);
741
+ await enqueueDispatchRequest('dispatch-team', {
742
+ kind: 'inbox',
743
+ to_worker: 'worker-1',
744
+ worker_index: 1,
745
+ trigger_message: 'dispatch ping',
746
+ }, wd);
747
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
748
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
749
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50', '--dispatch-max-per-tick', '1'], { encoding: 'utf-8', env: buildCleanNotifyEnv() });
750
+ assert.equal(result.status, 0, result.stderr || result.stdout);
751
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
752
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
753
+ assert.equal(watcherState.dispatch_drain?.enabled, true);
754
+ assert.equal(watcherState.dispatch_drain?.leader_only, true);
755
+ assert.equal(watcherState.dispatch_drain?.max_per_tick, 1);
756
+ assert.equal(watcherState.dispatch_drain?.run_count, 1);
757
+ assert.equal(watcherState.dispatch_drain?.last_result?.processed, 1);
758
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
759
+ const logEntries = (await readFile(logPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
760
+ const drainEvent = logEntries.find((entry) => entry.type === 'dispatch_drain_tick');
761
+ assert.ok(drainEvent, 'expected dispatch_drain_tick log event');
762
+ assert.equal(drainEvent.leader_only, true);
763
+ assert.equal(drainEvent.processed, 1);
764
+ }
765
+ finally {
766
+ await rm(wd, { recursive: true, force: true });
767
+ }
768
+ });
769
+ it('suppresses idle no-op lifecycle and control-plane logs during authority-only one-shot ticks', async () => {
770
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-authority-noop-'));
771
+ try {
772
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
773
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
774
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
775
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
776
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--authority-only', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env: buildCleanNotifyEnv() });
777
+ assert.equal(result.status, 0, result.stderr || result.stdout);
778
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
779
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
780
+ assert.equal(watcherState.authority_only, true);
781
+ assert.equal(watcherState.dispatch_drain?.run_count, 1);
782
+ assert.equal(watcherState.dispatch_drain?.last_result?.processed ?? 0, 0);
783
+ assert.equal(watcherState.leader_nudge?.run_count, 1);
784
+ assert.equal(watcherState.leader_nudge?.precomputed_leader_stale, false);
785
+ assert.equal(watcherState.fallback_auto_nudge?.last_reason, 'hud_state_missing');
786
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
787
+ const logContent = await readFile(logPath, 'utf-8').catch(() => '');
788
+ assert.equal(logContent.trim(), '');
789
+ }
790
+ finally {
791
+ await rm(wd, { recursive: true, force: true });
792
+ }
793
+ });
794
+ it('suppresses authority-only control-plane ticks when only skill-active-state carries the deep-interview input lock', async () => {
795
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-authority-skill-lock-'));
796
+ try {
797
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
798
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
799
+ await writeFile(join(wd, '.omx', 'state', 'skill-active-state.json'), JSON.stringify({
800
+ version: 1,
801
+ active: true,
802
+ skill: 'deep-interview',
803
+ keyword: 'deep interview',
804
+ phase: 'planning',
805
+ activated_at: '2026-02-25T00:00:00.000Z',
806
+ updated_at: '2026-02-25T00:00:00.000Z',
807
+ source: 'keyword-detector',
808
+ input_lock: {
809
+ active: true,
810
+ scope: 'deep-interview-auto-approval',
811
+ acquired_at: '2026-02-25T00:00:00.000Z',
812
+ blocked_inputs: ['yes', 'y', 'proceed', 'continue', 'ok', 'sure', 'go ahead', 'next i should'],
813
+ message: 'Deep interview is active; auto-approval shortcuts are blocked until the interview finishes.',
814
+ },
815
+ }, null, 2));
816
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
817
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
818
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--authority-only', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env: buildCleanNotifyEnv() });
819
+ assert.equal(result.status, 0, result.stderr || result.stdout);
820
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
821
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
822
+ assert.equal(watcherState.authority_only, true);
823
+ assert.equal(watcherState.dispatch_drain?.run_count, 1);
824
+ assert.equal(watcherState.leader_nudge?.run_count, 0);
825
+ assert.equal(watcherState.fallback_auto_nudge?.last_reason, 'init');
826
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
827
+ const logContent = await readFile(logPath, 'utf-8').catch(() => '');
828
+ assert.equal(logContent.trim(), '');
829
+ }
830
+ finally {
831
+ await rm(wd, { recursive: true, force: true });
832
+ }
833
+ });
834
+ it('backs off authority-only nudge ticks when the primary watcher is healthy', async () => {
835
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-authority-backed-off-'));
836
+ const fakeBinDir = join(wd, 'fake-bin');
837
+ const tmuxLogPath = join(wd, 'tmux.log');
838
+ const codexHome = join(wd, 'codex-home');
839
+ try {
840
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
841
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
842
+ await mkdir(fakeBinDir, { recursive: true });
843
+ await mkdir(codexHome, { recursive: true });
844
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
845
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
846
+ await writeFile(join(codexHome, '.omx-config.json'), JSON.stringify({
847
+ autoNudge: { enabled: true, delaySec: 0, ttlMs: 30_000 },
848
+ }, null, 2));
849
+ await writeSessionStart(wd, 'sess-managed-fallback');
850
+ await mkdir(join(wd, '.omx', 'state', 'sessions', 'sess-managed-fallback'), { recursive: true });
851
+ await writeFile(join(wd, '.omx', 'state', 'sessions', 'sess-managed-fallback', 'hud-state.json'), JSON.stringify({
852
+ last_turn_at: new Date(Date.now() - 6_000).toISOString(),
853
+ turn_count: 7,
854
+ last_agent_output: 'Keep going and finish the cleanup from here.',
855
+ }, null, 2));
856
+ await writeFile(join(wd, '.omx', 'state', 'notify-fallback.pid'), JSON.stringify({
857
+ pid: process.pid,
858
+ cwd: wd,
859
+ started_at: new Date().toISOString(),
860
+ }, null, 2));
861
+ await writeFile(join(wd, '.omx', 'state', 'notify-fallback-state.json'), JSON.stringify({
862
+ pid: process.pid,
863
+ cwd: wd,
864
+ authority_only: false,
865
+ poll_ms: 250,
866
+ dispatch_drain: { last_tick_at: new Date().toISOString() },
867
+ }, null, 2));
868
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
869
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
870
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--authority-only', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
871
+ encoding: 'utf-8',
872
+ env: buildCleanNotifyEnv({
873
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
874
+ CODEX_HOME: codexHome,
875
+ OMX_SESSION_ID: 'sess-managed-fallback',
876
+ TMUX: '1',
877
+ TMUX_PANE: '%42',
878
+ OMX_NOTIFY_FALLBACK_AUTO_NUDGE_STALL_MS: '5000',
879
+ }),
880
+ });
881
+ assert.equal(result.status, 0, result.stderr || result.stdout);
882
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
883
+ assert.doesNotMatch(tmuxLog, defaultAutoNudgePattern('%42'));
884
+ const watcherState = JSON.parse(await readFile(join(wd, '.omx', 'state', 'notify-fallback-state.json'), 'utf-8'));
885
+ assert.equal(watcherState.pid, process.pid, 'authority backoff should preserve the primary watcher state owner');
886
+ assert.equal(watcherState.authority_only, false, 'authority backoff should not overwrite primary watcher ownership');
887
+ assert.equal(watcherState.authority_backoff?.active, true);
888
+ assert.equal(watcherState.authority_backoff?.reason, 'primary_watcher_healthy');
889
+ assert.equal(watcherState.authority_backoff?.primary_pid, process.pid);
890
+ assert.match(watcherState.dispatch_drain?.last_tick_at ?? '', /^\d{4}-\d{2}-\d{2}T/);
891
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
892
+ const logContent = await readFile(logPath, 'utf-8').catch(() => '');
893
+ assert.equal(logContent.trim(), '');
894
+ }
895
+ finally {
896
+ await rm(wd, { recursive: true, force: true });
897
+ }
898
+ });
899
+ it('treats symlinked cwd aliases as the same primary watcher during authority handoff', async () => {
900
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-cwd-alias-'));
901
+ const aliasWd = `${wd}-alias`;
902
+ const fakeBinDir = join(wd, 'fake-bin');
903
+ const tmuxLogPath = join(wd, 'tmux.log');
904
+ try {
905
+ await symlink(wd, aliasWd, process.platform === 'win32' ? 'junction' : 'dir');
906
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
907
+ await mkdir(fakeBinDir, { recursive: true });
908
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
909
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
910
+ await writeSessionStart(wd, 'sess-cwd-alias');
911
+ await writeFile(join(wd, '.omx', 'state', 'notify-fallback.pid'), JSON.stringify({
912
+ pid: process.pid,
913
+ cwd: wd,
914
+ started_at: new Date().toISOString(),
915
+ }, null, 2));
916
+ await writeFile(join(wd, '.omx', 'state', 'notify-fallback-state.json'), JSON.stringify({
917
+ pid: process.pid,
918
+ cwd: wd,
919
+ authority_only: false,
920
+ poll_ms: 250,
921
+ dispatch_drain: { last_tick_at: new Date().toISOString() },
922
+ }, null, 2));
923
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
924
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
925
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--authority-only', '--cwd', aliasWd, '--notify-script', notifyHook, '--poll-ms', '50'], {
926
+ encoding: 'utf-8',
927
+ env: buildCleanNotifyEnv({
928
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
929
+ OMX_SESSION_ID: 'sess-cwd-alias',
930
+ TMUX: '1',
931
+ TMUX_PANE: '%42',
932
+ }),
933
+ });
934
+ assert.equal(result.status, 0, result.stderr || result.stdout);
935
+ const watcherState = JSON.parse(await readFile(join(wd, '.omx', 'state', 'notify-fallback-state.json'), 'utf-8'));
936
+ assert.equal(watcherState.authority_backoff?.active, true);
937
+ assert.equal(watcherState.authority_backoff?.reason, 'primary_watcher_healthy');
938
+ assert.equal(watcherState.authority_backoff?.primary_pid, process.pid);
939
+ }
940
+ finally {
941
+ await rm(aliasWd, { recursive: true, force: true });
942
+ await rm(wd, { recursive: true, force: true });
943
+ }
944
+ });
945
+ it('disables fallback watcher nudges when deep-interview state is active', async () => {
946
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-deep-interview-suppressed-'));
947
+ const fakeBinDir = join(wd, 'fake-bin');
948
+ const tmuxLogPath = join(wd, 'tmux.log');
949
+ try {
950
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
951
+ await mkdir(join(wd, '.omx', 'state', 'team', 'dispatch-team'), { recursive: true });
952
+ await mkdir(fakeBinDir, { recursive: true });
953
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
954
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
955
+ await writeFile(join(wd, '.omx', 'state', 'deep-interview-state.json'), JSON.stringify({
956
+ active: true,
957
+ mode: 'deep-interview',
958
+ current_phase: 'deep-interview',
959
+ }, null, 2));
960
+ await writeFile(join(wd, '.omx', 'state', 'ralph-state.json'), JSON.stringify({
961
+ active: true,
962
+ current_phase: 'executing',
963
+ tmux_pane_id: '%42',
964
+ }, null, 2));
965
+ await writeFile(join(wd, '.omx', 'state', 'team-state.json'), JSON.stringify({
966
+ active: true,
967
+ team_name: 'dispatch-team',
968
+ current_phase: 'team-exec',
969
+ }, null, 2));
970
+ await writeFile(join(wd, '.omx', 'state', 'hud-state.json'), JSON.stringify({
971
+ last_turn_at: new Date(Date.now() - 300_000).toISOString(),
972
+ turn_count: 3,
973
+ last_agent_output: 'Would you like me to continue?',
974
+ }, null, 2));
975
+ await writeFile(join(wd, '.omx', 'state', 'team', 'dispatch-team', 'config.json'), JSON.stringify({
976
+ name: 'dispatch-team',
977
+ tmux_session: 'omx-team-dispatch-team',
978
+ leader_pane_id: '%42',
979
+ }, null, 2));
980
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
981
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
982
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook], {
983
+ encoding: 'utf-8',
984
+ env: buildCleanNotifyEnv({ PATH: `${fakeBinDir}:${process.env.PATH || ''}` }),
985
+ });
986
+ assert.equal(result.status, 0, result.stderr || result.stdout);
987
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
988
+ assert.doesNotMatch(tmuxLog, /Ralph loop active continue/);
989
+ assert.doesNotMatch(tmuxLog, /Team dispatch-team:/);
990
+ assert.doesNotMatch(tmuxLog, new RegExp(`${DEFAULT_AUTO_NUDGE_RESPONSE.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')} \\[OMX_TMUX_INJECT\\]`));
991
+ }
992
+ finally {
993
+ await rm(wd, { recursive: true, force: true });
994
+ }
995
+ });
996
+ it('disables fallback watcher nudges when only skill-active-state carries the deep-interview input lock', async () => {
997
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-deep-interview-skill-lock-'));
998
+ const fakeBinDir = join(wd, 'fake-bin');
999
+ const tmuxLogPath = join(wd, 'tmux.log');
1000
+ try {
1001
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
1002
+ await mkdir(join(wd, '.omx', 'state', 'team', 'dispatch-team'), { recursive: true });
1003
+ await mkdir(fakeBinDir, { recursive: true });
1004
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1005
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1006
+ await writeFile(join(wd, '.omx', 'state', 'skill-active-state.json'), JSON.stringify({
1007
+ version: 1,
1008
+ active: true,
1009
+ skill: 'deep-interview',
1010
+ keyword: 'deep interview',
1011
+ phase: 'planning',
1012
+ activated_at: '2026-02-25T00:00:00.000Z',
1013
+ updated_at: '2026-02-25T00:00:00.000Z',
1014
+ source: 'keyword-detector',
1015
+ input_lock: {
1016
+ active: true,
1017
+ scope: 'deep-interview-auto-approval',
1018
+ acquired_at: '2026-02-25T00:00:00.000Z',
1019
+ blocked_inputs: ['yes', 'y', 'proceed', 'continue', 'ok', 'sure', 'go ahead', 'next i should'],
1020
+ message: 'Deep interview is active; auto-approval shortcuts are blocked until the interview finishes.',
1021
+ },
1022
+ }, null, 2));
1023
+ await writeFile(join(wd, '.omx', 'state', 'ralph-state.json'), JSON.stringify({
1024
+ active: true,
1025
+ current_phase: 'executing',
1026
+ tmux_pane_id: '%42',
1027
+ }, null, 2));
1028
+ await writeFile(join(wd, '.omx', 'state', 'team-state.json'), JSON.stringify({
1029
+ active: true,
1030
+ team_name: 'dispatch-team',
1031
+ current_phase: 'team-exec',
1032
+ }, null, 2));
1033
+ await writeFile(join(wd, '.omx', 'state', 'hud-state.json'), JSON.stringify({
1034
+ last_turn_at: new Date(Date.now() - 300_000).toISOString(),
1035
+ turn_count: 3,
1036
+ last_agent_output: 'Would you like me to continue?',
1037
+ }, null, 2));
1038
+ await writeFile(join(wd, '.omx', 'state', 'team', 'dispatch-team', 'config.json'), JSON.stringify({
1039
+ name: 'dispatch-team',
1040
+ tmux_session: 'omx-team-dispatch-team',
1041
+ leader_pane_id: '%42',
1042
+ }, null, 2));
1043
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1044
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1045
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook], {
1046
+ encoding: 'utf-8',
1047
+ env: buildCleanNotifyEnv({ PATH: `${fakeBinDir}:${process.env.PATH || ''}` }),
1048
+ });
1049
+ assert.equal(result.status, 0, result.stderr || result.stdout);
1050
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
1051
+ assert.doesNotMatch(tmuxLog, /Ralph loop active continue/);
1052
+ assert.doesNotMatch(tmuxLog, /Team dispatch-team:/);
1053
+ assert.doesNotMatch(tmuxLog, new RegExp(`${DEFAULT_AUTO_NUDGE_RESPONSE.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')} \\[OMX_TMUX_INJECT\\]`));
1054
+ }
1055
+ finally {
1056
+ await rm(wd, { recursive: true, force: true });
1057
+ }
1058
+ });
1059
+ it('runs leader nudge checks from the fallback watcher so stale alerts do not wait for a leader turn', async () => {
1060
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-leader-nudge-'));
1061
+ const fakeBinDir = join(wd, 'fake-bin');
1062
+ const tmuxLogPath = join(wd, 'tmux.log');
1063
+ try {
1064
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
1065
+ await mkdir(join(wd, '.omx', 'state', 'team', 'dispatch-team'), { recursive: true });
1066
+ await mkdir(fakeBinDir, { recursive: true });
1067
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1068
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1069
+ await writeFile(join(wd, '.omx', 'state', 'team-state.json'), JSON.stringify({
1070
+ active: true,
1071
+ team_name: 'dispatch-team',
1072
+ current_phase: 'team-exec',
1073
+ }, null, 2));
1074
+ await writeFile(join(wd, '.omx', 'state', 'hud-state.json'), JSON.stringify({
1075
+ last_turn_at: new Date(Date.now() - 300_000).toISOString(),
1076
+ turn_count: 3,
1077
+ }, null, 2));
1078
+ await writeFile(join(wd, '.omx', 'state', 'team', 'dispatch-team', 'config.json'), JSON.stringify({
1079
+ name: 'dispatch-team',
1080
+ tmux_session: 'omx-team-dispatch-team',
1081
+ leader_pane_id: '%42',
1082
+ }, null, 2));
1083
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1084
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1085
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook], {
1086
+ encoding: 'utf-8',
1087
+ env: buildCleanNotifyEnv({
1088
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
1089
+ OMX_SESSION_ID: 'sess-canonical-inactive',
1090
+ }),
1091
+ });
1092
+ assert.equal(result.status, 0, result.stderr || result.stdout);
1093
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8');
1094
+ assert.match(tmuxLog, /send-keys -t %42 -l Team dispatch-team: leader stale, \d+ worker pane\(s\) still active\./);
1095
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
1096
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
1097
+ assert.equal(watcherState.poll_ms, 250);
1098
+ assert.equal(watcherState.leader_nudge?.enabled, true);
1099
+ assert.equal(watcherState.leader_nudge?.leader_only, true);
1100
+ assert.equal(watcherState.leader_nudge?.run_count, 1);
1101
+ assert.equal(watcherState.leader_nudge?.precomputed_leader_stale, true);
1102
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
1103
+ const logEntries = (await readFile(logPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
1104
+ const nudgeEvent = logEntries.find((entry) => entry.type === 'leader_nudge_tick');
1105
+ assert.ok(nudgeEvent, 'expected leader_nudge_tick log event');
1106
+ assert.equal(nudgeEvent.leader_only, true);
1107
+ assert.equal(nudgeEvent.precomputed_leader_stale, true);
1108
+ const deliveryLogPath = join(wd, '.omx', 'logs', `team-delivery-${new Date().toISOString().slice(0, 10)}.jsonl`);
1109
+ const deliveryEntries = await readJsonLines(deliveryLogPath);
1110
+ assert.ok(deliveryEntries.some((entry) => entry.event === 'nudge_triggered'
1111
+ && entry.source === 'notify_fallback_watcher'
1112
+ && entry.transport === 'send-keys'
1113
+ && entry.result === 'sent'));
1114
+ }
1115
+ finally {
1116
+ await rm(wd, { recursive: true, force: true });
1117
+ }
1118
+ });
1119
+ it('runs leader nudge checks from canonical fallback when coarse team-state is inactive', async () => {
1120
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-leader-nudge-canonical-inactive-'));
1121
+ const fakeBinDir = join(wd, 'fake-bin');
1122
+ const tmuxLogPath = join(wd, 'tmux.log');
1123
+ try {
1124
+ await mkdir(fakeBinDir, { recursive: true });
1125
+ await writeCanonicalWatcherTeamFixture(wd, {
1126
+ teamName: 'dispatch-team',
1127
+ sessionId: 'sess-canonical-inactive',
1128
+ ownerSessionId: 'sess-canonical-inactive',
1129
+ coarseState: 'inactive',
1130
+ });
1131
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1132
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1133
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1134
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1135
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook], {
1136
+ encoding: 'utf-8',
1137
+ env: buildCleanNotifyEnv({
1138
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
1139
+ OMX_SESSION_ID: 'sess-canonical-inactive',
1140
+ }),
1141
+ });
1142
+ assert.equal(result.status, 0, result.stderr || result.stdout);
1143
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8');
1144
+ assert.match(tmuxLog, /send-keys -t %42 -l Team dispatch-team: leader stale, \d+ worker pane\(s\) still active\./);
1145
+ }
1146
+ finally {
1147
+ await rm(wd, { recursive: true, force: true });
1148
+ }
1149
+ });
1150
+ it('ignores invalid session_id before watcher session path joins', async () => {
1151
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-invalid-session-id-'));
1152
+ const fakeBinDir = join(wd, 'fake-bin');
1153
+ const tmuxLogPath = join(wd, 'tmux.log');
1154
+ try {
1155
+ await mkdir(fakeBinDir, { recursive: true });
1156
+ await writeCanonicalWatcherTeamFixture(wd, {
1157
+ teamName: 'dispatch-team',
1158
+ sessionId: 'safe-session',
1159
+ ownerSessionId: 'safe-session',
1160
+ coarseState: 'inactive',
1161
+ });
1162
+ await writeFile(join(wd, '.omx', 'state', 'session.json'), JSON.stringify({
1163
+ session_id: '../escape',
1164
+ cwd: wd,
1165
+ pid: process.pid,
1166
+ started_at: new Date().toISOString(),
1167
+ }, null, 2));
1168
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1169
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1170
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1171
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1172
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook], {
1173
+ encoding: 'utf-8',
1174
+ env: buildCleanNotifyEnv({
1175
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
1176
+ }),
1177
+ });
1178
+ assert.equal(result.status, 0, result.stderr || result.stdout);
1179
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
1180
+ assert.equal(tmuxLog, '', 'invalid session_id should not reach session-scoped or canonical follow-up joins');
1181
+ }
1182
+ finally {
1183
+ await rm(wd, { recursive: true, force: true });
1184
+ }
1185
+ });
1186
+ it('skips fallback watcher leader nudges when the leader is not stale even if mailbox messages exist', async () => {
1187
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-leader-nudge-fresh-'));
1188
+ const fakeBinDir = join(wd, 'fake-bin');
1189
+ const tmuxLogPath = join(wd, 'tmux.log');
1190
+ try {
1191
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
1192
+ await mkdir(join(wd, '.omx', 'state', 'team', 'dispatch-team', 'mailbox'), { recursive: true });
1193
+ await mkdir(fakeBinDir, { recursive: true });
1194
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1195
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1196
+ await writeFile(join(wd, '.omx', 'state', 'team-state.json'), JSON.stringify({
1197
+ active: true,
1198
+ team_name: 'dispatch-team',
1199
+ current_phase: 'team-exec',
1200
+ }, null, 2));
1201
+ await writeFile(join(wd, '.omx', 'state', 'hud-state.json'), JSON.stringify({
1202
+ last_turn_at: new Date().toISOString(),
1203
+ turn_count: 3,
1204
+ }, null, 2));
1205
+ await writeFile(join(wd, '.omx', 'state', 'team', 'dispatch-team', 'config.json'), JSON.stringify({
1206
+ name: 'dispatch-team',
1207
+ tmux_session: 'omx-team-dispatch-team',
1208
+ leader_pane_id: '%42',
1209
+ }, null, 2));
1210
+ await writeFile(join(wd, '.omx', 'state', 'team', 'dispatch-team', 'mailbox', 'leader-fixed.json'), JSON.stringify({
1211
+ worker: 'leader-fixed',
1212
+ messages: [
1213
+ {
1214
+ message_id: 'msg-1',
1215
+ from_worker: 'worker-1',
1216
+ to_worker: 'leader-fixed',
1217
+ body: 'fresh mailbox message',
1218
+ created_at: new Date().toISOString(),
1219
+ },
1220
+ ],
1221
+ }, null, 2));
1222
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1223
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1224
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook], {
1225
+ encoding: 'utf-8',
1226
+ env: buildCleanNotifyEnv({
1227
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
1228
+ OMX_SESSION_ID: 'sess-canonical-inactive',
1229
+ }),
1230
+ });
1231
+ assert.equal(result.status, 0, result.stderr || result.stdout);
1232
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
1233
+ assert.doesNotMatch(tmuxLog, /send-keys -t %42 -l Team dispatch-team:/);
1234
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
1235
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
1236
+ assert.equal(watcherState.leader_nudge?.enabled, true);
1237
+ assert.equal(watcherState.leader_nudge?.leader_only, true);
1238
+ assert.equal(watcherState.leader_nudge?.run_count, 1);
1239
+ assert.equal(watcherState.leader_nudge?.precomputed_leader_stale, false);
1240
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
1241
+ const logEntries = await readJsonLines(logPath);
1242
+ const nudgeEvent = logEntries.find((entry) => entry.type === 'leader_nudge_tick');
1243
+ assert.equal(nudgeEvent, undefined);
1244
+ }
1245
+ finally {
1246
+ await rm(wd, { recursive: true, force: true });
1247
+ }
1248
+ });
1249
+ it('does not run stalled-worker leader nudges from the fallback watcher when the leader is not stale', async () => {
1250
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-worker-stall-nudge-'));
1251
+ const fakeBinDir = join(wd, 'fake-bin');
1252
+ const tmuxLogPath = join(wd, 'tmux.log');
1253
+ try {
1254
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
1255
+ await mkdir(join(wd, '.omx', 'state', 'team', 'dispatch-team', 'workers', 'worker-1'), { recursive: true });
1256
+ await mkdir(join(wd, '.omx', 'state', 'team', 'dispatch-team', 'tasks'), { recursive: true });
1257
+ await mkdir(fakeBinDir, { recursive: true });
1258
+ const tmuxScript = `#!/usr/bin/env bash
1259
+ set -eu
1260
+ echo "$@" >> "${tmuxLogPath}"
1261
+ cmd="$1"
1262
+ shift || true
1263
+ if [[ "$cmd" == "display-message" ]]; then
1264
+ target=""
1265
+ fmt=""
1266
+ while [[ "$#" -gt 0 ]]; do
1267
+ case "$1" in
1268
+ -t)
1269
+ shift
1270
+ target="$1"
1271
+ ;;
1272
+ *)
1273
+ fmt="$1"
1274
+ ;;
1275
+ esac
1276
+ shift || true
1277
+ done
1278
+ if [[ "$fmt" == "#{pane_in_mode}" ]]; then
1279
+ echo "0"
1280
+ exit 0
1281
+ fi
1282
+ if [[ "$fmt" == "#{pane_id}" ]]; then
1283
+ echo "\${target:-%42}"
1284
+ exit 0
1285
+ fi
1286
+ if [[ "$fmt" == "#{pane_current_path}" ]]; then
1287
+ dirname "${tmuxLogPath}"
1288
+ exit 0
1289
+ fi
1290
+ if [[ "$fmt" == "#{pane_current_command}" ]]; then
1291
+ echo "codex"
1292
+ exit 0
1293
+ fi
1294
+ if [[ "$fmt" == "#S" ]]; then
1295
+ echo "omx-team-dispatch-team"
1296
+ exit 0
1297
+ fi
1298
+ exit 0
1299
+ fi
1300
+ if [[ "$cmd" == "send-keys" ]]; then
1301
+ exit 0
1302
+ fi
1303
+ if [[ "$cmd" == "list-panes" ]]; then
1304
+ target=""
1305
+ while [[ "$#" -gt 0 ]]; do
1306
+ case "$1" in
1307
+ -t)
1308
+ shift
1309
+ target="$1"
1310
+ ;;
1311
+ esac
1312
+ shift || true
1313
+ done
1314
+ if [[ -n "$target" ]]; then
1315
+ printf "%%42 12345\n%%10 12346\n%%11 12347\n"
1316
+ exit 0
1317
+ fi
1318
+ echo "%42 1"
1319
+ exit 0
1320
+ fi
1321
+ exit 0
1322
+ `;
1323
+ await writeFile(join(fakeBinDir, 'tmux'), tmuxScript);
1324
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1325
+ const now = Date.now();
1326
+ await writeFile(join(wd, '.omx', 'state', 'team-state.json'), JSON.stringify({
1327
+ active: true,
1328
+ team_name: 'dispatch-team',
1329
+ current_phase: 'team-exec',
1330
+ }, null, 2));
1331
+ await writeFile(join(wd, '.omx', 'state', 'hud-state.json'), JSON.stringify({
1332
+ last_turn_at: new Date().toISOString(),
1333
+ turn_count: 3,
1334
+ }, null, 2));
1335
+ await writeFile(join(wd, '.omx', 'state', 'team', 'dispatch-team', 'config.json'), JSON.stringify({
1336
+ name: 'dispatch-team',
1337
+ tmux_session: 'omx-team-dispatch-team',
1338
+ leader_pane_id: '%42',
1339
+ workers: [
1340
+ { name: 'worker-1', index: 1, pane_id: '%10' },
1341
+ { name: 'worker-2', index: 2, pane_id: '%11' },
1342
+ ],
1343
+ }, null, 2));
1344
+ await writeFile(join(wd, '.omx', 'state', 'team', 'dispatch-team', 'tasks', 'task-1.json'), JSON.stringify({
1345
+ id: '1',
1346
+ subject: 'Pending work',
1347
+ description: 'Needs attention',
1348
+ status: 'pending',
1349
+ created_at: new Date().toISOString(),
1350
+ }, null, 2));
1351
+ await writeFile(join(wd, '.omx', 'state', 'team', 'dispatch-team', 'workers', 'worker-1', 'status.json'), JSON.stringify({
1352
+ state: 'working',
1353
+ current_task_id: '1',
1354
+ updated_at: new Date(now - 180_000).toISOString(),
1355
+ }, null, 2));
1356
+ await writeFile(join(wd, '.omx', 'state', 'team', 'dispatch-team', 'workers', 'worker-1', 'heartbeat.json'), JSON.stringify({
1357
+ alive: true,
1358
+ pid: 101,
1359
+ turn_count: 2,
1360
+ last_turn_at: new Date(now - 180_000).toISOString(),
1361
+ }, null, 2));
1362
+ await writeFile(join(wd, '.omx', 'state', 'team-leader-nudge.json'), JSON.stringify({
1363
+ last_nudged_by_team: {
1364
+ 'dispatch-team': {
1365
+ at: new Date(now - 5_000).toISOString(),
1366
+ last_message_id: '',
1367
+ reason: 'new_mailbox_message',
1368
+ },
1369
+ },
1370
+ progress_by_team: {
1371
+ 'dispatch-team': {
1372
+ signature: JSON.stringify({
1373
+ tasks: [{ id: '1', owner: '', status: 'pending' }],
1374
+ workers: [
1375
+ {
1376
+ worker: 'worker-1',
1377
+ state: 'working',
1378
+ current_task_id: '1',
1379
+ status_missing: false,
1380
+ turn_count: 2,
1381
+ heartbeat_missing: false,
1382
+ },
1383
+ {
1384
+ worker: 'worker-2',
1385
+ state: 'unknown',
1386
+ current_task_id: '',
1387
+ status_missing: true,
1388
+ turn_count: null,
1389
+ heartbeat_missing: true,
1390
+ },
1391
+ ],
1392
+ }),
1393
+ last_progress_at: new Date(now - 180_000).toISOString(),
1394
+ },
1395
+ },
1396
+ }, null, 2));
1397
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1398
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1399
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook], {
1400
+ encoding: 'utf-8',
1401
+ env: buildCleanNotifyEnv({
1402
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
1403
+ OMX_TEAM_LEADER_NUDGE_MS: '30000',
1404
+ OMX_TEAM_LEADER_STALE_MS: '60000',
1405
+ }),
1406
+ });
1407
+ assert.equal(result.status, 0, result.stderr || result.stdout);
1408
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8');
1409
+ assert.doesNotMatch(tmuxLog, /worker panes stalled/);
1410
+ assert.doesNotMatch(tmuxLog, /no progress 3m/);
1411
+ assert.doesNotMatch(tmuxLog, /leader stale/);
1412
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
1413
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
1414
+ assert.equal(watcherState.leader_nudge?.enabled, true);
1415
+ assert.equal(watcherState.leader_nudge?.leader_only, true);
1416
+ assert.equal(watcherState.leader_nudge?.run_count, 1);
1417
+ assert.equal(watcherState.leader_nudge?.precomputed_leader_stale, false);
1418
+ }
1419
+ finally {
1420
+ await rm(wd, { recursive: true, force: true });
1421
+ }
1422
+ });
1423
+ it('auto-nudges stalled session output even when no active mode state exists', async () => {
1424
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-auto-nudge-stalled-'));
1425
+ const fakeBinDir = join(wd, 'fake-bin');
1426
+ const tmuxLogPath = join(wd, 'tmux.log');
1427
+ const codexHome = join(wd, 'codex-home');
1428
+ try {
1429
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
1430
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
1431
+ await mkdir(fakeBinDir, { recursive: true });
1432
+ await mkdir(codexHome, { recursive: true });
1433
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1434
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1435
+ await writeFile(join(codexHome, '.omx-config.json'), JSON.stringify({
1436
+ autoNudge: { enabled: true, delaySec: 0, ttlMs: 30_000 },
1437
+ }, null, 2));
1438
+ await writeSessionStart(wd, 'sess-managed-fallback');
1439
+ await mkdir(join(wd, '.omx', 'state', 'sessions', 'sess-managed-fallback'), { recursive: true });
1440
+ await writeFile(join(wd, '.omx', 'state', 'sessions', 'sess-managed-fallback', 'hud-state.json'), JSON.stringify({
1441
+ last_turn_at: new Date(Date.now() - 6_000).toISOString(),
1442
+ turn_count: 7,
1443
+ last_agent_output: 'Keep going and finish the cleanup from here.',
1444
+ }, null, 2));
1445
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1446
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1447
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
1448
+ encoding: 'utf-8',
1449
+ env: buildCleanNotifyEnv({
1450
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
1451
+ CODEX_HOME: codexHome,
1452
+ OMX_SESSION_ID: 'sess-managed-fallback',
1453
+ OMX_TEST_TMUX_SESSION_NAME: 'omx-fallback-auto-nudge-stalled-managed',
1454
+ TMUX: '1',
1455
+ TMUX_PANE: '%42',
1456
+ OMX_NOTIFY_FALLBACK_AUTO_NUDGE_STALL_MS: '5000',
1457
+ }),
1458
+ });
1459
+ assert.equal(result.status, 0, result.stderr || result.stdout);
1460
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8');
1461
+ assert.match(tmuxLog, defaultAutoNudgePattern('%42'));
1462
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
1463
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
1464
+ assert.equal(watcherState.fallback_auto_nudge?.last_reason, 'sent');
1465
+ assert.equal(watcherState.fallback_auto_nudge?.last_turn_count, 7);
1466
+ assert.match(watcherState.fallback_auto_nudge?.last_nudged_at ?? '', /^\d{4}-\d{2}-\d{2}T/);
1467
+ }
1468
+ finally {
1469
+ await rm(wd, { recursive: true, force: true });
1470
+ }
1471
+ });
1472
+ it('respects `.omx/tmux-hook.json` enabled:false for fallback auto-nudge', async () => {
1473
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-auto-nudge-disabled-'));
1474
+ const fakeBinDir = join(wd, 'fake-bin');
1475
+ const tmuxLogPath = join(wd, 'tmux.log');
1476
+ const codexHome = join(wd, 'codex-home');
1477
+ try {
1478
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
1479
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
1480
+ await mkdir(fakeBinDir, { recursive: true });
1481
+ await mkdir(codexHome, { recursive: true });
1482
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1483
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1484
+ await writeFile(join(codexHome, '.omx-config.json'), JSON.stringify({
1485
+ autoNudge: { enabled: true, delaySec: 0, ttlMs: 30_000 },
1486
+ }, null, 2));
1487
+ await writeFile(join(wd, '.omx', 'tmux-hook.json'), JSON.stringify({
1488
+ enabled: false,
1489
+ target: { type: 'pane', value: '%42' },
1490
+ }, null, 2));
1491
+ await writeSessionStart(wd, 'sess-managed-fallback');
1492
+ await mkdir(join(wd, '.omx', 'state', 'sessions', 'sess-managed-fallback'), { recursive: true });
1493
+ await writeFile(join(wd, '.omx', 'state', 'sessions', 'sess-managed-fallback', 'hud-state.json'), JSON.stringify({
1494
+ last_turn_at: new Date(Date.now() - 6_000).toISOString(),
1495
+ turn_count: 7,
1496
+ last_agent_output: 'Keep going and finish the cleanup from here.',
1497
+ }, null, 2));
1498
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1499
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1500
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
1501
+ encoding: 'utf-8',
1502
+ env: buildCleanNotifyEnv({
1503
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
1504
+ CODEX_HOME: codexHome,
1505
+ OMX_SESSION_ID: 'sess-managed-fallback',
1506
+ TMUX: '1',
1507
+ TMUX_PANE: '%42',
1508
+ OMX_NOTIFY_FALLBACK_AUTO_NUDGE_STALL_MS: '5000',
1509
+ }),
1510
+ });
1511
+ assert.equal(result.status, 0, result.stderr || result.stdout);
1512
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
1513
+ assert.doesNotMatch(tmuxLog, defaultAutoNudgePattern('%42'));
1514
+ }
1515
+ finally {
1516
+ await rm(wd, { recursive: true, force: true });
1517
+ }
1518
+ });
1519
+ it('suppresses fallback unmanaged-session auto-nudge skip logs while idle', async () => {
1520
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-auto-nudge-unmanaged-'));
1521
+ const fakeBinDir = join(wd, 'fake-bin');
1522
+ const tmuxLogPath = join(wd, 'tmux.log');
1523
+ const codexHome = join(wd, 'codex-home');
1524
+ try {
1525
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
1526
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
1527
+ await mkdir(fakeBinDir, { recursive: true });
1528
+ await mkdir(codexHome, { recursive: true });
1529
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1530
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1531
+ await writeFile(join(codexHome, '.omx-config.json'), JSON.stringify({
1532
+ autoNudge: { enabled: true, delaySec: 0, ttlMs: 30_000 },
1533
+ }, null, 2));
1534
+ await writeFile(join(wd, '.omx', 'state', 'hud-state.json'), JSON.stringify({
1535
+ last_turn_at: new Date(Date.now() - 6_000).toISOString(),
1536
+ turn_count: 9,
1537
+ last_agent_output: 'Keep going and finish the cleanup from here.',
1538
+ }, null, 2));
1539
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1540
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1541
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
1542
+ encoding: 'utf-8',
1543
+ env: buildCleanNotifyEnv({
1544
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
1545
+ CODEX_HOME: codexHome,
1546
+ TMUX: '1',
1547
+ TMUX_PANE: '%42',
1548
+ OMX_NOTIFY_FALLBACK_AUTO_NUDGE_STALL_MS: '5000',
1549
+ }),
1550
+ });
1551
+ assert.equal(result.status, 0, result.stderr || result.stdout);
1552
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
1553
+ assert.doesNotMatch(tmuxLog, defaultAutoNudgePattern('%42'));
1554
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
1555
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
1556
+ assert.equal(watcherState.fallback_auto_nudge?.last_reason, 'eligible_but_not_sent');
1557
+ const tmuxHookLogPath = join(wd, '.omx', 'logs', `tmux-hook-${new Date().toISOString().split('T')[0]}.jsonl`);
1558
+ const tmuxHookLog = await readFile(tmuxHookLogPath, 'utf-8').catch(() => '');
1559
+ assert.equal(tmuxHookLog.trim(), '');
1560
+ }
1561
+ finally {
1562
+ await rm(wd, { recursive: true, force: true });
1563
+ }
1564
+ });
1565
+ it('does not auto-nudge stalled-like output when the latest turn is still fresh', async () => {
1566
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-auto-nudge-fresh-'));
1567
+ const fakeBinDir = join(wd, 'fake-bin');
1568
+ const tmuxLogPath = join(wd, 'tmux.log');
1569
+ const codexHome = join(wd, 'codex-home');
1570
+ try {
1571
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
1572
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
1573
+ await mkdir(fakeBinDir, { recursive: true });
1574
+ await mkdir(codexHome, { recursive: true });
1575
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1576
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1577
+ await writeFile(join(codexHome, '.omx-config.json'), JSON.stringify({
1578
+ autoNudge: { enabled: true, delaySec: 0 },
1579
+ }, null, 2));
1580
+ await writeFile(join(wd, '.omx', 'state', 'hud-state.json'), JSON.stringify({
1581
+ last_turn_at: new Date(Date.now() - 1_000).toISOString(),
1582
+ turn_count: 8,
1583
+ last_agent_output: 'Keep going and finish the cleanup from here.',
1584
+ }, null, 2));
1585
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1586
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1587
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
1588
+ encoding: 'utf-8',
1589
+ env: buildCleanNotifyEnv({
1590
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
1591
+ CODEX_HOME: codexHome,
1592
+ TMUX: '1',
1593
+ TMUX_PANE: '%42',
1594
+ OMX_NOTIFY_FALLBACK_AUTO_NUDGE_STALL_MS: '5000',
1595
+ }),
1596
+ });
1597
+ assert.equal(result.status, 0, result.stderr || result.stdout);
1598
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
1599
+ assert.doesNotMatch(tmuxLog, defaultAutoNudgePattern('%42'));
1600
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
1601
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
1602
+ assert.equal(watcherState.fallback_auto_nudge?.last_reason, 'recent_turn_activity');
1603
+ assert.equal(watcherState.fallback_auto_nudge?.last_turn_count, 8);
1604
+ }
1605
+ finally {
1606
+ await rm(wd, { recursive: true, force: true });
1607
+ }
1608
+ });
1609
+ it('does not fallback auto-nudge a stalled hud snapshot that notify-hook already nudged', async () => {
1610
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-auto-nudge-dedup-'));
1611
+ const fakeBinDir = join(wd, 'fake-bin');
1612
+ const tmuxLogPath = join(wd, 'tmux.log');
1613
+ const codexHome = join(wd, 'codex-home');
1614
+ const lastTurnAt = new Date(Date.now() - 6_000).toISOString();
1615
+ const lastMessage = 'Keep going and finish the cleanup from here.';
1616
+ try {
1617
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
1618
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
1619
+ await mkdir(fakeBinDir, { recursive: true });
1620
+ await mkdir(codexHome, { recursive: true });
1621
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1622
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1623
+ await writeFile(join(codexHome, '.omx-config.json'), JSON.stringify({
1624
+ autoNudge: { enabled: true, delaySec: 0 },
1625
+ }, null, 2));
1626
+ await writeFile(join(wd, '.omx', 'state', 'hud-state.json'), JSON.stringify({
1627
+ last_turn_at: lastTurnAt,
1628
+ turn_count: 7,
1629
+ last_agent_output: lastMessage,
1630
+ }, null, 2));
1631
+ await writeFile(join(wd, '.omx', 'state', 'auto-nudge-state.json'), JSON.stringify({
1632
+ nudgeCount: 1,
1633
+ lastNudgeAt: new Date().toISOString(),
1634
+ lastSignature: `hud:7|${lastTurnAt}|stall:proceed_intent`,
1635
+ lastSemanticSignature: 'stall:proceed_intent',
1636
+ }, null, 2));
1637
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1638
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1639
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
1640
+ encoding: 'utf-8',
1641
+ env: buildCleanNotifyEnv({
1642
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
1643
+ CODEX_HOME: codexHome,
1644
+ TMUX: '1',
1645
+ TMUX_PANE: '%42',
1646
+ OMX_NOTIFY_FALLBACK_AUTO_NUDGE_STALL_MS: '5000',
1647
+ }),
1648
+ });
1649
+ assert.equal(result.status, 0, result.stderr || result.stdout);
1650
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
1651
+ assert.doesNotMatch(tmuxLog, defaultAutoNudgePattern('%42'));
1652
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
1653
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
1654
+ assert.equal(watcherState.fallback_auto_nudge?.last_reason, 'already_nudged_for_signature');
1655
+ assert.equal(watcherState.fallback_auto_nudge?.last_turn_count, 7);
1656
+ }
1657
+ finally {
1658
+ await rm(wd, { recursive: true, force: true });
1659
+ }
1660
+ });
1661
+ it('does not fallback auto-nudge the same stalled hud turn again after TTL expiry', async () => {
1662
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-auto-nudge-exact-dedup-'));
1663
+ const fakeBinDir = join(wd, 'fake-bin');
1664
+ const tmuxLogPath = join(wd, 'tmux.log');
1665
+ const codexHome = join(wd, 'codex-home');
1666
+ const lastTurnAt = '2026-03-01T00:00:00.000Z';
1667
+ const lastMessage = 'Keep going and finish the cleanup from here.';
1668
+ try {
1669
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
1670
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
1671
+ await mkdir(fakeBinDir, { recursive: true });
1672
+ await mkdir(codexHome, { recursive: true });
1673
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1674
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1675
+ await writeFile(join(codexHome, '.omx-config.json'), JSON.stringify({
1676
+ autoNudge: { enabled: true, delaySec: 0, ttlMs: 5000 },
1677
+ }, null, 2));
1678
+ await writeFile(join(wd, '.omx', 'state', 'hud-state.json'), JSON.stringify({
1679
+ last_turn_at: lastTurnAt,
1680
+ turn_count: 7,
1681
+ last_agent_output: lastMessage,
1682
+ }, null, 2));
1683
+ await writeFile(join(wd, '.omx', 'state', 'auto-nudge-state.json'), JSON.stringify({
1684
+ nudgeCount: 1,
1685
+ lastNudgeAt: '2026-03-01T00:00:10.000Z',
1686
+ lastSignature: `hud:7|${lastTurnAt}|stall:proceed_intent`,
1687
+ lastSemanticSignature: 'stall:proceed_intent',
1688
+ }, null, 2));
1689
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1690
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1691
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
1692
+ encoding: 'utf-8',
1693
+ env: buildCleanNotifyEnv({
1694
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
1695
+ CODEX_HOME: codexHome,
1696
+ TMUX: '1',
1697
+ TMUX_PANE: '%42',
1698
+ OMX_NOTIFY_FALLBACK_AUTO_NUDGE_STALL_MS: '5000',
1699
+ }),
1700
+ });
1701
+ assert.equal(result.status, 0, result.stderr || result.stdout);
1702
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
1703
+ assert.doesNotMatch(tmuxLog, defaultAutoNudgePattern('%42'));
1704
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
1705
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
1706
+ assert.equal(watcherState.fallback_auto_nudge?.last_reason, 'already_nudged_for_signature');
1707
+ assert.equal(watcherState.fallback_auto_nudge?.last_turn_count, 7);
1708
+ }
1709
+ finally {
1710
+ await rm(wd, { recursive: true, force: true });
1711
+ }
1712
+ });
1713
+ it('runs bounded non-turn team dispatch drain tick in leader context', async () => {
1714
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-dispatch-'));
1715
+ const previousRuntimeBridge = process.env.OMX_RUNTIME_BRIDGE;
1716
+ try {
1717
+ process.env.OMX_RUNTIME_BRIDGE = '0';
1718
+ await initTeamState('dispatch-team', 'task', 'executor', 1, wd);
1719
+ const queued = await enqueueDispatchRequest('dispatch-team', {
1720
+ kind: 'inbox',
1721
+ to_worker: 'worker-1',
1722
+ worker_index: 1,
1723
+ trigger_message: 'dispatch ping',
1724
+ }, wd);
1725
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1726
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1727
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50', '--dispatch-max-per-tick', '1'], { encoding: 'utf-8', env: buildCleanNotifyEnv() });
1728
+ assert.equal(result.status, 0, result.stderr || result.stdout);
1729
+ const request = await readDispatchRequest('dispatch-team', queued.request.request_id, wd);
1730
+ assert.ok(request);
1731
+ assert.notEqual(request?.status, 'pending');
1732
+ }
1733
+ finally {
1734
+ if (typeof previousRuntimeBridge === 'string')
1735
+ process.env.OMX_RUNTIME_BRIDGE = previousRuntimeBridge;
1736
+ else
1737
+ delete process.env.OMX_RUNTIME_BRIDGE;
1738
+ await rm(wd, { recursive: true, force: true });
1739
+ }
1740
+ });
1741
+ it('skips dispatch drain in worker context (leader-only guard)', async () => {
1742
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-dispatch-worker-'));
1743
+ const previousRuntimeBridge = process.env.OMX_RUNTIME_BRIDGE;
1744
+ try {
1745
+ process.env.OMX_RUNTIME_BRIDGE = '0';
1746
+ await initTeamState('dispatch-team', 'task', 'executor', 1, wd);
1747
+ const queued = await enqueueDispatchRequest('dispatch-team', {
1748
+ kind: 'inbox',
1749
+ to_worker: 'worker-1',
1750
+ worker_index: 1,
1751
+ trigger_message: 'dispatch ping',
1752
+ }, wd);
1753
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1754
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1755
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50', '--dispatch-max-per-tick', '1'], { encoding: 'utf-8', env: buildCleanNotifyEnv({ OMX_TEAM_WORKER: 'dispatch-team/worker-1', OMX_TEAM_STATE_ROOT: join(wd, '.omx', 'state') }) });
1756
+ assert.equal(result.status, 0, result.stderr || result.stdout);
1757
+ const request = await readDispatchRequest('dispatch-team', queued.request.request_id, wd);
1758
+ assert.equal(request?.status, 'pending');
1759
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
1760
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
1761
+ assert.equal(watcherState.dispatch_drain?.leader_only, false);
1762
+ assert.equal(watcherState.dispatch_drain?.last_result?.reason, 'worker_context');
1763
+ assert.equal(watcherState.dispatch_drain?.last_result?.processed, 0);
1764
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
1765
+ const logEntries = await readJsonLines(logPath);
1766
+ const drainEvent = logEntries.find((entry) => entry.type === 'dispatch_drain_tick');
1767
+ assert.equal(drainEvent, undefined);
1768
+ }
1769
+ finally {
1770
+ if (typeof previousRuntimeBridge === 'string')
1771
+ process.env.OMX_RUNTIME_BRIDGE = previousRuntimeBridge;
1772
+ else
1773
+ delete process.env.OMX_RUNTIME_BRIDGE;
1774
+ await rm(wd, { recursive: true, force: true });
1775
+ }
1776
+ });
1777
+ it('watcher retry does not retype when pre-capture still contains trigger', async () => {
1778
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-dispatch-cm-'));
1779
+ const fakeBinDir = join(wd, 'fake-bin');
1780
+ const tmuxLogPath = join(wd, 'tmux.log');
1781
+ const captureFile = join(wd, 'capture.txt');
1782
+ const previousRuntimeBridge = process.env.OMX_RUNTIME_BRIDGE;
1783
+ try {
1784
+ process.env.OMX_RUNTIME_BRIDGE = '0';
1785
+ await mkdir(fakeBinDir, { recursive: true });
1786
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1787
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1788
+ await writeFile(captureFile, '... ping ...');
1789
+ await initTeamState('dispatch-team', 'task', 'executor', 1, wd);
1790
+ const queued = await enqueueDispatchRequest('dispatch-team', {
1791
+ kind: 'inbox',
1792
+ to_worker: 'worker-1',
1793
+ worker_index: 1,
1794
+ pane_id: '%42',
1795
+ trigger_message: 'ping',
1796
+ }, wd);
1797
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1798
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1799
+ const env = {
1800
+ ...buildCleanNotifyEnv(),
1801
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
1802
+ OMX_TEST_CAPTURE_FILE: captureFile,
1803
+ };
1804
+ const first = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50', '--dispatch-max-per-tick', '1'], { encoding: 'utf-8', env });
1805
+ assert.equal(first.status, 0, first.stderr || first.stdout);
1806
+ const second = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50', '--dispatch-max-per-tick', '1'], { encoding: 'utf-8', env });
1807
+ assert.equal(second.status, 0, second.stderr || second.stdout);
1808
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8');
1809
+ const typeMatches = tmuxLog.match(/send-keys -t %42 -l ping/g) || [];
1810
+ assert.equal(typeMatches.length, 1, 'fresh attempt should type once; retries with draft should be submit-only');
1811
+ const cmMatches = tmuxLog.match(/send-keys -t %42 C-m/g) || [];
1812
+ assert.ok(cmMatches.length > 0, 'submit should use C-m');
1813
+ assert.ok(!/send-keys[^\n]*-l[^\n]*C-m/.test(tmuxLog), 'must keep -l payload and C-m submits isolated');
1814
+ const request = await readDispatchRequest('dispatch-team', queued.request.request_id, wd);
1815
+ assert.equal(request?.status, 'pending');
1816
+ assert.equal(request?.attempt_count, 2);
1817
+ assert.equal(request?.last_reason, 'tmux_send_keys_unconfirmed');
1818
+ }
1819
+ finally {
1820
+ if (typeof previousRuntimeBridge === 'string')
1821
+ process.env.OMX_RUNTIME_BRIDGE = previousRuntimeBridge;
1822
+ else
1823
+ delete process.env.OMX_RUNTIME_BRIDGE;
1824
+ await rm(wd, { recursive: true, force: true });
1825
+ }
1826
+ });
1827
+ it('sends bounded periodic Ralph continue steer while Ralph state stays active', async () => {
1828
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-active-'));
1829
+ const fakeBinDir = join(wd, 'fake-bin');
1830
+ const stateDir = join(wd, '.omx', 'state');
1831
+ const tmuxLogPath = join(wd, 'tmux.log');
1832
+ const statePath = join(stateDir, 'notify-fallback-state.json');
1833
+ const sharedTimestampPath = join(stateDir, 'ralph-last-steer-at');
1834
+ try {
1835
+ await mkdir(stateDir, { recursive: true });
1836
+ await mkdir(fakeBinDir, { recursive: true });
1837
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1838
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1839
+ await writeFile(join(stateDir, 'ralph-state.json'), JSON.stringify({
1840
+ active: true,
1841
+ current_phase: 'executing',
1842
+ tmux_pane_id: '%42',
1843
+ }, null, 2));
1844
+ await writeFile(join(stateDir, 'hud-state.json'), JSON.stringify({
1845
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
1846
+ }, null, 2));
1847
+ await writeFile(statePath, JSON.stringify({
1848
+ ralph_continue_steer: {
1849
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
1850
+ },
1851
+ }, null, 2));
1852
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1853
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1854
+ const env = {
1855
+ ...buildCleanNotifyEnv(),
1856
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
1857
+ };
1858
+ const first = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env });
1859
+ assert.equal(first.status, 0, first.stderr || first.stdout);
1860
+ const persistedAfterFirst = JSON.parse(await readFile(statePath, 'utf-8'));
1861
+ assert.match(persistedAfterFirst.ralph_continue_steer?.last_sent_at ?? '', /^\d{4}-\d{2}-\d{2}T/, 'successful steer should persist a round-trippable ISO last_sent_at');
1862
+ assert.equal(persistedAfterFirst.ralph_continue_steer?.cooldown_anchor_at, persistedAfterFirst.ralph_continue_steer?.last_sent_at, 'successful steer should advance the fallback cooldown anchor to the real send time');
1863
+ const second = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env });
1864
+ assert.equal(second.status, 0, second.stderr || second.stdout);
1865
+ const boundedLog = await readFile(tmuxLogPath, 'utf8');
1866
+ let sends = boundedLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
1867
+ assert.equal(sends.length, 1, 'cadence should suppress a second Ralph steer inside 60s');
1868
+ const watcherState = JSON.parse(await readFile(statePath, 'utf-8'));
1869
+ const agedIso = new Date(Date.now() - 61_000).toISOString();
1870
+ watcherState.ralph_continue_steer.last_sent_at = agedIso;
1871
+ watcherState.ralph_continue_steer.shared_last_sent_at = agedIso;
1872
+ await writeFile(statePath, JSON.stringify(watcherState, null, 2));
1873
+ await writeFile(sharedTimestampPath, `${agedIso}\n`);
1874
+ const third = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env });
1875
+ assert.equal(third.status, 0, third.stderr || third.stdout);
1876
+ const finalLog = await readFile(tmuxLogPath, 'utf8');
1877
+ sends = finalLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
1878
+ assert.equal(sends.length, 2, 'Ralph steer should fire again once the 60s cadence elapses');
1879
+ }
1880
+ finally {
1881
+ await rm(wd, { recursive: true, force: true });
1882
+ }
1883
+ });
1884
+ it('suppresses Ralph continue steer when hud progress is still fresh after cooldown', async () => {
1885
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-progress-fresh-'));
1886
+ const fakeBinDir = join(wd, 'fake-bin');
1887
+ const stateDir = join(wd, '.omx', 'state');
1888
+ const tmuxLogPath = join(wd, 'tmux.log');
1889
+ const statePath = join(stateDir, 'notify-fallback-state.json');
1890
+ try {
1891
+ await mkdir(stateDir, { recursive: true });
1892
+ await mkdir(fakeBinDir, { recursive: true });
1893
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1894
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1895
+ await writeFile(join(stateDir, 'ralph-state.json'), JSON.stringify({
1896
+ active: true,
1897
+ current_phase: 'executing',
1898
+ tmux_pane_id: '%42',
1899
+ }, null, 2));
1900
+ await writeFile(join(stateDir, 'hud-state.json'), JSON.stringify({
1901
+ last_progress_at: new Date(Date.now() - 5_000).toISOString(),
1902
+ }, null, 2));
1903
+ await writeFile(statePath, JSON.stringify({
1904
+ ralph_continue_steer: {
1905
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
1906
+ },
1907
+ }, null, 2));
1908
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1909
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1910
+ const env = {
1911
+ ...buildCleanNotifyEnv(),
1912
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
1913
+ };
1914
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env });
1915
+ assert.equal(run.status, 0, run.stderr || run.stdout);
1916
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
1917
+ const sends = tmuxLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
1918
+ assert.equal(sends.length, 0, 'fresh progress should suppress continue steer even after cooldown elapses');
1919
+ const watcherState = JSON.parse(await readFile(statePath, 'utf-8'));
1920
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'progress_fresh');
1921
+ }
1922
+ finally {
1923
+ await rm(wd, { recursive: true, force: true });
1924
+ }
1925
+ });
1926
+ it('still sends Ralph continue steer when hud progress is stale after cooldown', async () => {
1927
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-progress-stale-'));
1928
+ const fakeBinDir = join(wd, 'fake-bin');
1929
+ const stateDir = join(wd, '.omx', 'state');
1930
+ const tmuxLogPath = join(wd, 'tmux.log');
1931
+ const statePath = join(stateDir, 'notify-fallback-state.json');
1932
+ try {
1933
+ await mkdir(stateDir, { recursive: true });
1934
+ await mkdir(fakeBinDir, { recursive: true });
1935
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1936
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1937
+ await writeFile(join(stateDir, 'ralph-state.json'), JSON.stringify({
1938
+ active: true,
1939
+ current_phase: 'executing',
1940
+ tmux_pane_id: '%42',
1941
+ }, null, 2));
1942
+ await writeFile(join(stateDir, 'hud-state.json'), JSON.stringify({
1943
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
1944
+ }, null, 2));
1945
+ await writeFile(statePath, JSON.stringify({
1946
+ ralph_continue_steer: {
1947
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
1948
+ },
1949
+ }, null, 2));
1950
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1951
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1952
+ const env = {
1953
+ ...buildCleanNotifyEnv(),
1954
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
1955
+ };
1956
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env });
1957
+ assert.equal(run.status, 0, run.stderr || run.stdout);
1958
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8');
1959
+ const sends = tmuxLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
1960
+ assert.equal(sends.length, 1, 'stale progress should still allow continue steer once cooldown elapses');
1961
+ const watcherState = JSON.parse(await readFile(statePath, 'utf-8'));
1962
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'sent');
1963
+ }
1964
+ finally {
1965
+ await rm(wd, { recursive: true, force: true });
1966
+ }
1967
+ });
1968
+ it('suppresses Ralph continue steer when session-scoped Ralph is stuck in stale starting phase', async () => {
1969
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-starting-stale-'));
1970
+ const fakeBinDir = join(wd, 'fake-bin');
1971
+ const tmuxLogPath = join(wd, 'tmux.log');
1972
+ const stateDir = join(wd, '.omx', 'state');
1973
+ const sessionId = 'sess-starting-stale';
1974
+ const sessionStateDir = join(stateDir, 'sessions', sessionId);
1975
+ const watcherStatePath = join(stateDir, 'notify-fallback-state.json');
1976
+ try {
1977
+ await mkdir(sessionStateDir, { recursive: true });
1978
+ await mkdir(fakeBinDir, { recursive: true });
1979
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1980
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1981
+ await writeSessionStart(wd, sessionId);
1982
+ await writeFile(join(sessionStateDir, 'ralph-state.json'), JSON.stringify({
1983
+ active: true,
1984
+ current_phase: 'starting',
1985
+ started_at: new Date(Date.now() - 180_000).toISOString(),
1986
+ tmux_pane_id: '%42',
1987
+ }, null, 2));
1988
+ await writeFile(join(sessionStateDir, 'hud-state.json'), JSON.stringify({
1989
+ last_progress_at: new Date(Date.now() - 180_000).toISOString(),
1990
+ }, null, 2));
1991
+ await writeFile(watcherStatePath, JSON.stringify({
1992
+ ralph_continue_steer: {
1993
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
1994
+ },
1995
+ }, null, 2));
1996
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
1997
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
1998
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
1999
+ encoding: 'utf-8',
2000
+ env: buildCleanNotifyEnv({
2001
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2002
+ }),
2003
+ });
2004
+ assert.equal(run.status, 0, run.stderr || run.stdout);
2005
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
2006
+ const sends = tmuxLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
2007
+ assert.equal(sends.length, 0, 'stale starting phase should suppress continue steer');
2008
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
2009
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'starting_stale');
2010
+ }
2011
+ finally {
2012
+ await rm(wd, { recursive: true, force: true });
2013
+ }
2014
+ });
2015
+ it('suppresses Ralph continue steer while tracked native subagents are still active', async () => {
2016
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-subagents-active-'));
2017
+ const fakeBinDir = join(wd, 'fake-bin');
2018
+ const stateDir = join(wd, '.omx', 'state');
2019
+ const tmuxLogPath = join(wd, 'tmux.log');
2020
+ const statePath = join(stateDir, 'notify-fallback-state.json');
2021
+ const omxSessionId = 'sess-current';
2022
+ const codexSessionId = 'codex-session-1';
2023
+ try {
2024
+ await mkdir(join(stateDir, 'sessions', omxSessionId), { recursive: true });
2025
+ await mkdir(fakeBinDir, { recursive: true });
2026
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
2027
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2028
+ await writeSessionStart(wd, omxSessionId);
2029
+ await writeFile(join(stateDir, 'sessions', omxSessionId, 'ralph-state.json'), JSON.stringify({
2030
+ active: true,
2031
+ current_phase: 'executing',
2032
+ tmux_pane_id: '%42',
2033
+ owner_omx_session_id: omxSessionId,
2034
+ owner_codex_session_id: codexSessionId,
2035
+ }, null, 2));
2036
+ await writeFile(join(stateDir, 'sessions', omxSessionId, 'hud-state.json'), JSON.stringify({
2037
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
2038
+ }, null, 2));
2039
+ await writeFile(statePath, JSON.stringify({
2040
+ ralph_continue_steer: {
2041
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
2042
+ },
2043
+ }, null, 2));
2044
+ await writeFile(join(stateDir, 'subagent-tracking.json'), JSON.stringify({
2045
+ schemaVersion: 1,
2046
+ sessions: {
2047
+ [codexSessionId]: {
2048
+ session_id: codexSessionId,
2049
+ leader_thread_id: 'leader-thread',
2050
+ updated_at: new Date(Date.now() - 15_000).toISOString(),
2051
+ threads: {
2052
+ 'leader-thread': {
2053
+ thread_id: 'leader-thread',
2054
+ kind: 'leader',
2055
+ first_seen_at: new Date(Date.now() - 30_000).toISOString(),
2056
+ last_seen_at: new Date(Date.now() - 15_000).toISOString(),
2057
+ turn_count: 1,
2058
+ mode: 'ralph',
2059
+ },
2060
+ 'sub-thread-1': {
2061
+ thread_id: 'sub-thread-1',
2062
+ kind: 'subagent',
2063
+ first_seen_at: new Date(Date.now() - 30_000).toISOString(),
2064
+ last_seen_at: new Date(Date.now() - 15_000).toISOString(),
2065
+ turn_count: 1,
2066
+ mode: 'ralph',
2067
+ },
2068
+ },
2069
+ },
2070
+ },
2071
+ }, null, 2));
2072
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2073
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2074
+ const env = {
2075
+ ...buildCleanNotifyEnv(),
2076
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2077
+ };
2078
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env });
2079
+ assert.equal(run.status, 0, run.stderr || run.stdout);
2080
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
2081
+ const sends = tmuxLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
2082
+ assert.equal(sends.length, 0, 'active native subagents should block fallback continue steer');
2083
+ const watcherState = JSON.parse(await readFile(statePath, 'utf-8'));
2084
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'subagents_active');
2085
+ assert.equal(watcherState.ralph_continue_steer?.subagent_session_id, codexSessionId);
2086
+ assert.deepEqual(watcherState.ralph_continue_steer?.active_subagent_thread_ids, ['sub-thread-1']);
2087
+ }
2088
+ finally {
2089
+ await rm(wd, { recursive: true, force: true });
2090
+ }
2091
+ });
2092
+ it('fails closed when Ralph hud progress is missing or invalid', async () => {
2093
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-progress-guard-'));
2094
+ const fakeBinDir = join(wd, 'fake-bin');
2095
+ const stateDir = join(wd, '.omx', 'state');
2096
+ const tmuxLogPath = join(wd, 'tmux.log');
2097
+ const statePath = join(stateDir, 'notify-fallback-state.json');
2098
+ try {
2099
+ await mkdir(stateDir, { recursive: true });
2100
+ await mkdir(fakeBinDir, { recursive: true });
2101
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
2102
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2103
+ await writeFile(join(stateDir, 'ralph-state.json'), JSON.stringify({
2104
+ active: true,
2105
+ current_phase: 'executing',
2106
+ tmux_pane_id: '%42',
2107
+ }, null, 2));
2108
+ await writeFile(statePath, JSON.stringify({
2109
+ ralph_continue_steer: {
2110
+ pane_id: '%7',
2111
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
2112
+ },
2113
+ }, null, 2));
2114
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2115
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2116
+ const env = {
2117
+ ...buildCleanNotifyEnv(),
2118
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2119
+ };
2120
+ const missingRun = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env });
2121
+ assert.equal(missingRun.status, 0, missingRun.stderr || missingRun.stdout);
2122
+ let watcherState = JSON.parse(await readFile(statePath, 'utf-8'));
2123
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'progress_missing');
2124
+ assert.equal(watcherState.ralph_continue_steer?.pane_id, '%42');
2125
+ await writeFile(join(stateDir, 'hud-state.json'), JSON.stringify({
2126
+ last_progress_at: 'not-a-date',
2127
+ }, null, 2));
2128
+ const invalidRun = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env });
2129
+ assert.equal(invalidRun.status, 0, invalidRun.stderr || invalidRun.stdout);
2130
+ watcherState = JSON.parse(await readFile(statePath, 'utf-8'));
2131
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'progress_invalid');
2132
+ assert.equal(watcherState.ralph_continue_steer?.pane_id, '%42');
2133
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
2134
+ const sends = tmuxLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
2135
+ assert.equal(sends.length, 0, 'missing or invalid progress should fail closed without sending steer');
2136
+ }
2137
+ finally {
2138
+ await rm(wd, { recursive: true, force: true });
2139
+ }
2140
+ });
2141
+ it('fails closed when active Ralph state has no bound tmux pane', async () => {
2142
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-pane-missing-'));
2143
+ const fakeBinDir = join(wd, 'fake-bin');
2144
+ const stateDir = join(wd, '.omx', 'state');
2145
+ const tmuxLogPath = join(wd, 'tmux.log');
2146
+ const statePath = join(stateDir, 'notify-fallback-state.json');
2147
+ try {
2148
+ await mkdir(stateDir, { recursive: true });
2149
+ await mkdir(fakeBinDir, { recursive: true });
2150
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
2151
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2152
+ await writeFile(join(stateDir, 'ralph-state.json'), JSON.stringify({
2153
+ active: true,
2154
+ current_phase: 'executing',
2155
+ }, null, 2));
2156
+ await writeFile(join(stateDir, 'hud-state.json'), JSON.stringify({
2157
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
2158
+ }, null, 2));
2159
+ await writeFile(statePath, JSON.stringify({
2160
+ ralph_continue_steer: {
2161
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
2162
+ },
2163
+ }, null, 2));
2164
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2165
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2166
+ const env = {
2167
+ ...buildCleanNotifyEnv(),
2168
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2169
+ };
2170
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env });
2171
+ assert.equal(run.status, 0, run.stderr || run.stdout);
2172
+ const watcherState = JSON.parse(await readFile(statePath, 'utf-8'));
2173
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'pane_missing');
2174
+ assert.equal(watcherState.ralph_continue_steer?.pane_id, '');
2175
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
2176
+ assert.equal(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/.test(tmuxLog), false);
2177
+ assert.equal(/display-message -p -t %42 #{pane_id}/.test(tmuxLog), false, 'watcher should not guess a pane when tmux_pane_id is missing');
2178
+ }
2179
+ finally {
2180
+ await rm(wd, { recursive: true, force: true });
2181
+ }
2182
+ });
2183
+ it('rebinds a stale-but-present session-scoped Ralph shell pane to the live pane before continue steer', async () => {
2184
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-rebind-stale-anchor-'));
2185
+ const fakeBinDir = join(wd, 'fake-bin');
2186
+ const stateDir = join(wd, '.omx', 'state');
2187
+ const tmuxLogPath = join(wd, 'tmux.log');
2188
+ const watcherStatePath = join(stateDir, 'notify-fallback-state.json');
2189
+ const sessionId = 'sess-ralph-rebind';
2190
+ const sessionStateDir = join(stateDir, 'sessions', sessionId);
2191
+ const ralphStatePath = join(sessionStateDir, 'ralph-state.json');
2192
+ const anchorPane = '%99';
2193
+ const livePane = '%42';
2194
+ try {
2195
+ await mkdir(sessionStateDir, { recursive: true });
2196
+ await mkdir(fakeBinDir, { recursive: true });
2197
+ await writeSessionStart(wd, sessionId);
2198
+ const managedSessionName = buildTmuxSessionName(wd, sessionId);
2199
+ await writeFile(join(fakeBinDir, 'tmux'), buildManagedRalphTmux(tmuxLogPath, {
2200
+ cwd: wd,
2201
+ managedSessionName,
2202
+ anchorPane,
2203
+ livePane,
2204
+ codexPanes: [
2205
+ { paneId: anchorPane, active: false, currentCommand: 'sh', startCommand: 'bash' },
2206
+ { paneId: '%41', active: false, currentCommand: 'codex', startCommand: 'codex' },
2207
+ { paneId: livePane, active: true, currentCommand: 'codex', startCommand: 'codex' },
2208
+ ],
2209
+ }));
2210
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2211
+ await writeFile(ralphStatePath, JSON.stringify({
2212
+ active: true,
2213
+ current_phase: 'executing',
2214
+ tmux_pane_id: anchorPane,
2215
+ }, null, 2));
2216
+ await writeFile(join(sessionStateDir, 'hud-state.json'), JSON.stringify({
2217
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
2218
+ }, null, 2));
2219
+ await writeFile(watcherStatePath, JSON.stringify({
2220
+ ralph_continue_steer: {
2221
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
2222
+ },
2223
+ }, null, 2));
2224
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2225
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2226
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
2227
+ encoding: 'utf-8',
2228
+ env: buildCleanNotifyEnv({
2229
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2230
+ }),
2231
+ });
2232
+ assert.equal(run.status, 0, run.stderr || run.stdout);
2233
+ const persistedRalph = JSON.parse(await readFile(ralphStatePath, 'utf-8'));
2234
+ assert.equal(persistedRalph.tmux_pane_id, livePane);
2235
+ assert.match(persistedRalph.tmux_pane_set_at ?? '', /^\d{4}-\d{2}-\d{2}T/);
2236
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
2237
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'sent');
2238
+ assert.equal(watcherState.ralph_continue_steer?.pane_id, livePane);
2239
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8');
2240
+ assert.match(tmuxLog, /send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/);
2241
+ assert.doesNotMatch(tmuxLog, /send-keys -t %99 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/);
2242
+ }
2243
+ finally {
2244
+ await rm(wd, { recursive: true, force: true });
2245
+ }
2246
+ });
2247
+ it('preserves newer Ralph state fields when a pane rebound happens after the state file advances', async () => {
2248
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-rebind-state-merge-'));
2249
+ const fakeBinDir = join(wd, 'fake-bin');
2250
+ const stateDir = join(wd, '.omx', 'state');
2251
+ const tmuxLogPath = join(wd, 'tmux.log');
2252
+ const watcherStatePath = join(stateDir, 'notify-fallback-state.json');
2253
+ const sessionId = 'sess-ralph-rebind-merge';
2254
+ const sessionStateDir = join(stateDir, 'sessions', sessionId);
2255
+ const ralphStatePath = join(sessionStateDir, 'ralph-state.json');
2256
+ const anchorPane = '%99';
2257
+ const livePane = '%42';
2258
+ try {
2259
+ await mkdir(sessionStateDir, { recursive: true });
2260
+ await mkdir(fakeBinDir, { recursive: true });
2261
+ await writeSessionStart(wd, sessionId);
2262
+ const managedSessionName = buildTmuxSessionName(wd, sessionId);
2263
+ const fakeTmux = `#!/usr/bin/env bash
2264
+ set -eu
2265
+ echo "$@" >> "${tmuxLogPath}"
2266
+ cmd="$1"
2267
+ shift || true
2268
+ if [[ "$cmd" == "display-message" ]]; then
2269
+ target=""
2270
+ format=""
2271
+ while [[ "$#" -gt 0 ]]; do
2272
+ case "$1" in
2273
+ -p) shift ;;
2274
+ -t) target="$2"; shift 2 ;;
2275
+ *) format="$1"; shift ;;
2276
+ esac
2277
+ done
2278
+ if [[ "$format" == "#{pane_in_mode}" ]]; then
2279
+ echo "0"
2280
+ exit 0
2281
+ fi
2282
+ if [[ "$format" == "#{pane_id}" ]]; then
2283
+ echo "$target"
2284
+ exit 0
2285
+ fi
2286
+ if [[ "$format" == "#{pane_current_path}" ]]; then
2287
+ echo "${wd}"
2288
+ exit 0
2289
+ fi
2290
+ if [[ "$format" == "#{pane_current_command}" && "$target" == "${anchorPane}" ]]; then
2291
+ echo "sh"
2292
+ exit 0
2293
+ fi
2294
+ if [[ "$format" == "#{pane_start_command}" && "$target" == "${anchorPane}" ]]; then
2295
+ echo "bash"
2296
+ exit 0
2297
+ fi
2298
+ if [[ "$format" == "#S" && "$target" == "${anchorPane}" ]]; then
2299
+ echo "${managedSessionName}"
2300
+ exit 0
2301
+ fi
2302
+ exit 0
2303
+ fi
2304
+ if [[ "$cmd" == "list-panes" ]]; then
2305
+ target=""
2306
+ while [[ "$#" -gt 0 ]]; do
2307
+ case "$1" in
2308
+ -F) shift 2 ;;
2309
+ -t) shift; target="$1" ;;
2310
+ esac
2311
+ shift || true
2312
+ done
2313
+ if [[ "$target" == "${managedSessionName}" ]]; then
2314
+ cat > "${ralphStatePath}" <<'JSON'
2315
+ {
2316
+ "active": true,
2317
+ "current_phase": "reviewing",
2318
+ "iteration": 11,
2319
+ "owner_codex_session_id": "codex-updated-owner",
2320
+ "tmux_pane_id": "%99"
2321
+ }
2322
+ JSON
2323
+ printf "%%99\t0\tsh\tbash\n%%42\t1\tcodex\tcodex\n"
2324
+ exit 0
2325
+ fi
2326
+ echo "can't find session" >&2
2327
+ exit 1
2328
+ fi
2329
+ if [[ "$cmd" == "capture-pane" ]]; then
2330
+ exit 0
2331
+ fi
2332
+ if [[ "$cmd" == "send-keys" ]]; then
2333
+ exit 0
2334
+ fi
2335
+ exit 0
2336
+ `;
2337
+ await writeFile(join(fakeBinDir, 'tmux'), fakeTmux);
2338
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2339
+ await writeFile(ralphStatePath, JSON.stringify({
2340
+ active: true,
2341
+ current_phase: 'executing',
2342
+ iteration: 1,
2343
+ owner_codex_session_id: 'codex-stale-owner',
2344
+ tmux_pane_id: anchorPane,
2345
+ }, null, 2));
2346
+ await writeFile(join(sessionStateDir, 'hud-state.json'), JSON.stringify({
2347
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
2348
+ }, null, 2));
2349
+ await writeFile(watcherStatePath, JSON.stringify({
2350
+ ralph_continue_steer: {
2351
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
2352
+ },
2353
+ }, null, 2));
2354
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2355
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2356
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
2357
+ encoding: 'utf-8',
2358
+ env: buildCleanNotifyEnv({
2359
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2360
+ }),
2361
+ });
2362
+ assert.equal(run.status, 0, run.stderr || run.stdout);
2363
+ const persistedRalph = JSON.parse(await readFile(ralphStatePath, 'utf-8'));
2364
+ assert.equal(persistedRalph.tmux_pane_id, livePane);
2365
+ assert.equal(persistedRalph.current_phase, 'reviewing');
2366
+ assert.equal(persistedRalph.iteration, 11);
2367
+ assert.equal(persistedRalph.owner_codex_session_id, 'codex-updated-owner');
2368
+ assert.match(persistedRalph.tmux_pane_set_at ?? '', /^\d{4}-\d{2}-\d{2}T/);
2369
+ }
2370
+ finally {
2371
+ await rm(wd, { recursive: true, force: true });
2372
+ }
2373
+ });
2374
+ it('keeps the verified Ralph anchor pane when another codex pane is focused in the same managed session', async () => {
2375
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-keep-anchor-pane-'));
2376
+ const fakeBinDir = join(wd, 'fake-bin');
2377
+ const stateDir = join(wd, '.omx', 'state');
2378
+ const tmuxLogPath = join(wd, 'tmux.log');
2379
+ const watcherStatePath = join(stateDir, 'notify-fallback-state.json');
2380
+ const sessionId = 'sess-ralph-keep-anchor';
2381
+ const sessionStateDir = join(stateDir, 'sessions', sessionId);
2382
+ const ralphStatePath = join(sessionStateDir, 'ralph-state.json');
2383
+ const anchorPane = '%99';
2384
+ const livePane = '%42';
2385
+ try {
2386
+ await mkdir(sessionStateDir, { recursive: true });
2387
+ await mkdir(fakeBinDir, { recursive: true });
2388
+ await writeSessionStart(wd, sessionId);
2389
+ const managedSessionName = buildTmuxSessionName(wd, sessionId);
2390
+ await writeFile(join(fakeBinDir, 'tmux'), buildManagedRalphTmux(tmuxLogPath, {
2391
+ cwd: wd,
2392
+ managedSessionName,
2393
+ anchorPane,
2394
+ livePane,
2395
+ codexPanes: [
2396
+ { paneId: anchorPane, active: false, currentCommand: 'codex', startCommand: 'codex' },
2397
+ { paneId: livePane, active: true, currentCommand: 'codex', startCommand: 'codex' },
2398
+ ],
2399
+ }));
2400
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2401
+ await writeFile(ralphStatePath, JSON.stringify({
2402
+ active: true,
2403
+ current_phase: 'executing',
2404
+ tmux_pane_id: anchorPane,
2405
+ }, null, 2));
2406
+ await writeFile(join(sessionStateDir, 'hud-state.json'), JSON.stringify({
2407
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
2408
+ }, null, 2));
2409
+ await writeFile(watcherStatePath, JSON.stringify({
2410
+ ralph_continue_steer: {
2411
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
2412
+ },
2413
+ }, null, 2));
2414
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2415
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2416
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
2417
+ encoding: 'utf-8',
2418
+ env: buildCleanNotifyEnv({
2419
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2420
+ }),
2421
+ });
2422
+ assert.equal(run.status, 0, run.stderr || run.stdout);
2423
+ const persistedRalph = JSON.parse(await readFile(ralphStatePath, 'utf-8'));
2424
+ assert.equal(persistedRalph.tmux_pane_id, anchorPane);
2425
+ assert.equal(typeof persistedRalph.tmux_pane_set_at, 'undefined');
2426
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
2427
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'sent');
2428
+ assert.equal(watcherState.ralph_continue_steer?.pane_id, anchorPane);
2429
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8');
2430
+ assert.match(tmuxLog, /send-keys -t %99 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/);
2431
+ assert.doesNotMatch(tmuxLog, /send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/);
2432
+ }
2433
+ finally {
2434
+ await rm(wd, { recursive: true, force: true });
2435
+ }
2436
+ });
2437
+ it('rebinds a shell-degraded codex anchor to the live pane before continue steer', async () => {
2438
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-rebind-degraded-codex-anchor-'));
2439
+ const fakeBinDir = join(wd, 'fake-bin');
2440
+ const stateDir = join(wd, '.omx', 'state');
2441
+ const tmuxLogPath = join(wd, 'tmux.log');
2442
+ const watcherStatePath = join(stateDir, 'notify-fallback-state.json');
2443
+ const sessionId = 'sess-ralph-degraded-codex-anchor';
2444
+ const sessionStateDir = join(stateDir, 'sessions', sessionId);
2445
+ const ralphStatePath = join(sessionStateDir, 'ralph-state.json');
2446
+ const anchorPane = '%99';
2447
+ const livePane = '%42';
2448
+ try {
2449
+ await mkdir(sessionStateDir, { recursive: true });
2450
+ await mkdir(fakeBinDir, { recursive: true });
2451
+ await writeSessionStart(wd, sessionId);
2452
+ const managedSessionName = buildTmuxSessionName(wd, sessionId);
2453
+ await writeFile(join(fakeBinDir, 'tmux'), buildManagedRalphTmux(tmuxLogPath, {
2454
+ cwd: wd,
2455
+ managedSessionName,
2456
+ anchorPane,
2457
+ livePane,
2458
+ codexPanes: [
2459
+ { paneId: anchorPane, active: true, currentCommand: 'bash', startCommand: 'codex --model gpt-5' },
2460
+ { paneId: livePane, active: false, currentCommand: 'codex', startCommand: 'codex' },
2461
+ ],
2462
+ }));
2463
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2464
+ await writeFile(ralphStatePath, JSON.stringify({
2465
+ active: true,
2466
+ current_phase: 'executing',
2467
+ tmux_pane_id: anchorPane,
2468
+ }, null, 2));
2469
+ await writeFile(join(sessionStateDir, 'hud-state.json'), JSON.stringify({
2470
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
2471
+ }, null, 2));
2472
+ await writeFile(watcherStatePath, JSON.stringify({
2473
+ ralph_continue_steer: {
2474
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
2475
+ },
2476
+ }, null, 2));
2477
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2478
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2479
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
2480
+ encoding: 'utf-8',
2481
+ env: buildCleanNotifyEnv({
2482
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2483
+ }),
2484
+ });
2485
+ assert.equal(run.status, 0, run.stderr || run.stdout);
2486
+ const persistedRalph = JSON.parse(await readFile(ralphStatePath, 'utf-8'));
2487
+ assert.equal(persistedRalph.tmux_pane_id, livePane);
2488
+ assert.match(persistedRalph.tmux_pane_set_at ?? '', /^\d{4}-\d{2}-\d{2}T/);
2489
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
2490
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'sent');
2491
+ assert.equal(watcherState.ralph_continue_steer?.pane_id, livePane);
2492
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8');
2493
+ assert.match(tmuxLog, /send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/);
2494
+ assert.doesNotMatch(tmuxLog, /send-keys -t %99 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/);
2495
+ }
2496
+ finally {
2497
+ await rm(wd, { recursive: true, force: true });
2498
+ }
2499
+ });
2500
+ it('falls back to the current managed session pane when the stored Ralph pane anchor is dead', async () => {
2501
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-rebind-dead-anchor-'));
2502
+ const fakeBinDir = join(wd, 'fake-bin');
2503
+ const stateDir = join(wd, '.omx', 'state');
2504
+ const tmuxLogPath = join(wd, 'tmux.log');
2505
+ const watcherStatePath = join(stateDir, 'notify-fallback-state.json');
2506
+ const sessionId = 'sess-ralph-dead-anchor';
2507
+ const sessionStateDir = join(stateDir, 'sessions', sessionId);
2508
+ const ralphStatePath = join(sessionStateDir, 'ralph-state.json');
2509
+ const anchorPane = '%99';
2510
+ const livePane = '%42';
2511
+ try {
2512
+ await mkdir(sessionStateDir, { recursive: true });
2513
+ await mkdir(fakeBinDir, { recursive: true });
2514
+ await writeSessionStart(wd, sessionId);
2515
+ const managedSessionName = buildTmuxSessionName(wd, sessionId);
2516
+ await writeFile(join(fakeBinDir, 'tmux'), buildManagedRalphTmux(tmuxLogPath, {
2517
+ cwd: wd,
2518
+ managedSessionName,
2519
+ anchorPane,
2520
+ livePane,
2521
+ codexPanes: [
2522
+ { paneId: '%41', active: false, currentCommand: 'codex', startCommand: 'codex' },
2523
+ { paneId: livePane, active: true, currentCommand: 'codex', startCommand: 'codex' },
2524
+ ],
2525
+ missingAnchor: true,
2526
+ }));
2527
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2528
+ await writeFile(ralphStatePath, JSON.stringify({
2529
+ active: true,
2530
+ current_phase: 'executing',
2531
+ tmux_pane_id: anchorPane,
2532
+ }, null, 2));
2533
+ await writeFile(join(sessionStateDir, 'hud-state.json'), JSON.stringify({
2534
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
2535
+ }, null, 2));
2536
+ await writeFile(watcherStatePath, JSON.stringify({
2537
+ ralph_continue_steer: {
2538
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
2539
+ },
2540
+ }, null, 2));
2541
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2542
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2543
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
2544
+ encoding: 'utf-8',
2545
+ env: buildCleanNotifyEnv({
2546
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2547
+ }),
2548
+ });
2549
+ assert.equal(run.status, 0, run.stderr || run.stdout);
2550
+ const persistedRalph = JSON.parse(await readFile(ralphStatePath, 'utf-8'));
2551
+ assert.equal(persistedRalph.tmux_pane_id, livePane);
2552
+ assert.match(persistedRalph.tmux_pane_set_at ?? '', /^\d{4}-\d{2}-\d{2}T/);
2553
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
2554
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'sent');
2555
+ assert.equal(watcherState.ralph_continue_steer?.pane_id, livePane);
2556
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8');
2557
+ assert.match(tmuxLog, /display-message -p -t %99 #S/);
2558
+ assert.match(tmuxLog, /list-panes -s -t .*sess-ralph-dead-anchor/);
2559
+ assert.match(tmuxLog, /send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/);
2560
+ assert.doesNotMatch(tmuxLog, /send-keys -t %99 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/);
2561
+ }
2562
+ finally {
2563
+ await rm(wd, { recursive: true, force: true });
2564
+ }
2565
+ });
2566
+ it('sends the first Ralph continue steer immediately when persisted steer state is empty', async () => {
2567
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-startup-cooldown-'));
2568
+ const fakeBinDir = join(wd, 'fake-bin');
2569
+ const stateDir = join(wd, '.omx', 'state');
2570
+ const tmuxLogPath = join(wd, 'tmux.log');
2571
+ const statePath = join(stateDir, 'notify-fallback-state.json');
2572
+ try {
2573
+ await mkdir(stateDir, { recursive: true });
2574
+ await mkdir(fakeBinDir, { recursive: true });
2575
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
2576
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2577
+ await writeFile(join(stateDir, 'ralph-state.json'), JSON.stringify({
2578
+ active: true,
2579
+ current_phase: 'executing',
2580
+ tmux_pane_id: '%42',
2581
+ }, null, 2));
2582
+ await writeFile(join(stateDir, 'hud-state.json'), JSON.stringify({
2583
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
2584
+ }, null, 2));
2585
+ await writeFile(statePath, JSON.stringify({
2586
+ ralph_continue_steer: {
2587
+ last_sent_at: '',
2588
+ },
2589
+ }, null, 2));
2590
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2591
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2592
+ const env = {
2593
+ ...buildCleanNotifyEnv(),
2594
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2595
+ };
2596
+ const first = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env });
2597
+ assert.equal(first.status, 0, first.stderr || first.stdout);
2598
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
2599
+ const sends = tmuxLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
2600
+ assert.equal(sends.length, 1, 'empty startup state should send the first Ralph steer immediately once progress is stale');
2601
+ const watcherState = JSON.parse(await readFile(statePath, 'utf-8'));
2602
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'sent');
2603
+ assert.match(watcherState.ralph_continue_steer?.last_sent_at ?? '', /^\d{4}-\d{2}-\d{2}T/, 'first steer should persist a real send timestamp for active-state signaling');
2604
+ assert.equal(watcherState.ralph_continue_steer?.cooldown_anchor_at, watcherState.ralph_continue_steer?.last_sent_at, 'first steer should anchor subsequent cooldowns to the real send time');
2605
+ }
2606
+ finally {
2607
+ await rm(wd, { recursive: true, force: true });
2608
+ }
2609
+ });
2610
+ it('falls back to an aged persisted cooldown anchor when last_sent_at is invalid', async () => {
2611
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-invalid-last-sent-'));
2612
+ const fakeBinDir = join(wd, 'fake-bin');
2613
+ const stateDir = join(wd, '.omx', 'state');
2614
+ const tmuxLogPath = join(wd, 'tmux.log');
2615
+ const statePath = join(stateDir, 'notify-fallback-state.json');
2616
+ try {
2617
+ await mkdir(stateDir, { recursive: true });
2618
+ await mkdir(fakeBinDir, { recursive: true });
2619
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
2620
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2621
+ await writeFile(join(stateDir, 'ralph-state.json'), JSON.stringify({
2622
+ active: true,
2623
+ current_phase: 'executing',
2624
+ tmux_pane_id: '%42',
2625
+ }, null, 2));
2626
+ await writeFile(join(stateDir, 'hud-state.json'), JSON.stringify({
2627
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
2628
+ }, null, 2));
2629
+ await writeFile(statePath, JSON.stringify({
2630
+ ralph_continue_steer: {
2631
+ last_sent_at: 'not-a-date',
2632
+ cooldown_anchor_at: new Date(Date.now() - 61_000).toISOString(),
2633
+ },
2634
+ }, null, 2));
2635
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2636
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2637
+ const env = {
2638
+ ...buildCleanNotifyEnv(),
2639
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2640
+ };
2641
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env });
2642
+ assert.equal(run.status, 0, run.stderr || run.stdout);
2643
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8');
2644
+ const sends = tmuxLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
2645
+ assert.equal(sends.length, 1, 'invalid last_sent_at should fall back to the persisted cooldown anchor once 60s have elapsed');
2646
+ const watcherState = JSON.parse(await readFile(statePath, 'utf-8'));
2647
+ assert.match(watcherState.ralph_continue_steer?.last_sent_at ?? '', /^\d{4}-\d{2}-\d{2}T/, 'successful fallback send should replace the invalid last_sent_at with a valid ISO timestamp');
2648
+ assert.equal(watcherState.ralph_continue_steer?.cooldown_anchor_at, watcherState.ralph_continue_steer?.last_sent_at, 'fallback send should also refresh the persisted cooldown anchor');
2649
+ }
2650
+ finally {
2651
+ await rm(wd, { recursive: true, force: true });
2652
+ }
2653
+ });
2654
+ it('treats blocked_on_user as terminal so Ralph continue steer stays off', async () => {
2655
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-blocked-on-user-'));
2656
+ const fakeBinDir = join(wd, 'fake-bin');
2657
+ const tmuxLogPath = join(wd, 'tmux.log');
2658
+ const stateDir = join(wd, '.omx', 'state');
2659
+ const watcherStatePath = join(stateDir, 'notify-fallback-state.json');
2660
+ try {
2661
+ await mkdir(stateDir, { recursive: true });
2662
+ await mkdir(fakeBinDir, { recursive: true });
2663
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
2664
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2665
+ await writeFile(join(stateDir, 'ralph-state.json'), JSON.stringify({
2666
+ active: false,
2667
+ current_phase: 'blocked_on_user',
2668
+ completed_at: new Date().toISOString(),
2669
+ tmux_pane_id: '%42',
2670
+ }, null, 2));
2671
+ await writeFile(join(stateDir, 'hud-state.json'), JSON.stringify({
2672
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
2673
+ }, null, 2));
2674
+ await writeFile(watcherStatePath, JSON.stringify({
2675
+ ralph_continue_steer: {
2676
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
2677
+ },
2678
+ }, null, 2));
2679
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2680
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2681
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
2682
+ encoding: 'utf-8',
2683
+ env: buildCleanNotifyEnv({
2684
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2685
+ }),
2686
+ });
2687
+ assert.equal(run.status, 0, run.stderr || run.stdout);
2688
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
2689
+ const sends = tmuxLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
2690
+ assert.equal(sends.length, 0, 'blocked_on_user should suppress Ralph continue steer');
2691
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
2692
+ assert.equal(watcherState.ralph_continue_steer?.active, false);
2693
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'terminal');
2694
+ }
2695
+ finally {
2696
+ await rm(wd, { recursive: true, force: true });
2697
+ }
2698
+ });
2699
+ it('stops Ralph continue steer immediately once Ralph state is terminal or cleared', async () => {
2700
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-terminal-'));
2701
+ const fakeBinDir = join(wd, 'fake-bin');
2702
+ const tmuxLogPath = join(wd, 'tmux.log');
2703
+ const stateDir = join(wd, '.omx', 'state');
2704
+ const watcherStatePath = join(stateDir, 'notify-fallback-state.json');
2705
+ const ralphStatePath = join(stateDir, 'ralph-state.json');
2706
+ try {
2707
+ await mkdir(stateDir, { recursive: true });
2708
+ await mkdir(fakeBinDir, { recursive: true });
2709
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
2710
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2711
+ await writeFile(ralphStatePath, JSON.stringify({
2712
+ active: true,
2713
+ current_phase: 'executing',
2714
+ tmux_pane_id: '%42',
2715
+ }, null, 2));
2716
+ await writeFile(join(stateDir, 'hud-state.json'), JSON.stringify({
2717
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
2718
+ }, null, 2));
2719
+ await writeFile(watcherStatePath, JSON.stringify({
2720
+ ralph_continue_steer: {
2721
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
2722
+ },
2723
+ }, null, 2));
2724
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2725
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2726
+ const env = {
2727
+ ...buildCleanNotifyEnv(),
2728
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2729
+ };
2730
+ const first = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env });
2731
+ assert.equal(first.status, 0, first.stderr || first.stdout);
2732
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
2733
+ watcherState.ralph_continue_steer.last_sent_at = new Date(Date.now() - 61_000).toISOString();
2734
+ await writeFile(watcherStatePath, JSON.stringify(watcherState, null, 2));
2735
+ await writeFile(join(stateDir, 'hud-state.json'), JSON.stringify({
2736
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
2737
+ }, null, 2));
2738
+ await writeFile(ralphStatePath, JSON.stringify({
2739
+ active: false,
2740
+ current_phase: 'complete',
2741
+ completed_at: new Date().toISOString(),
2742
+ tmux_pane_id: '%42',
2743
+ }, null, 2));
2744
+ const terminalRun = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env });
2745
+ assert.equal(terminalRun.status, 0, terminalRun.stderr || terminalRun.stdout);
2746
+ await rm(ralphStatePath, { force: true });
2747
+ const clearedRun = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { encoding: 'utf-8', env });
2748
+ assert.equal(clearedRun.status, 0, clearedRun.stderr || clearedRun.stdout);
2749
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8');
2750
+ const sends = tmuxLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
2751
+ assert.equal(sends.length, 1, 'terminal/cleared Ralph state must stop additional periodic steer sends');
2752
+ }
2753
+ finally {
2754
+ await rm(wd, { recursive: true, force: true });
2755
+ }
2756
+ });
2757
+ it('treats a long-running starting phase as terminal so Ralph steer stops', async () => {
2758
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-starting-phase-stale-'));
2759
+ const fakeBinDir = join(wd, 'fake-bin');
2760
+ const tmuxLogPath = join(wd, 'tmux.log');
2761
+ const stateDir = join(wd, '.omx', 'state');
2762
+ const watcherStatePath = join(stateDir, 'notify-fallback-state.json');
2763
+ const staleStartedAt = new Date(Date.now() - 3 * 60_000).toISOString();
2764
+ try {
2765
+ await mkdir(stateDir, { recursive: true });
2766
+ await mkdir(fakeBinDir, { recursive: true });
2767
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
2768
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2769
+ await writeFile(join(stateDir, 'ralph-state.json'), JSON.stringify({
2770
+ active: true,
2771
+ current_phase: 'starting',
2772
+ started_at: staleStartedAt,
2773
+ tmux_pane_id: '%42',
2774
+ }, null, 2));
2775
+ await writeFile(join(stateDir, 'hud-state.json'), JSON.stringify({
2776
+ last_progress_at: new Date(Date.now() - 5 * 60_000).toISOString(),
2777
+ }, null, 2));
2778
+ await writeFile(watcherStatePath, JSON.stringify({
2779
+ ralph_continue_steer: {
2780
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
2781
+ },
2782
+ }, null, 2));
2783
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2784
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2785
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
2786
+ encoding: 'utf-8',
2787
+ env: buildCleanNotifyEnv({
2788
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2789
+ }),
2790
+ });
2791
+ assert.equal(run.status, 0, run.stderr || run.stdout);
2792
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
2793
+ const sends = tmuxLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
2794
+ assert.equal(sends.length, 0, 'stale starting phase should block Ralph continue steer');
2795
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
2796
+ assert.equal(watcherState.ralph_continue_steer?.active, false);
2797
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'terminal');
2798
+ }
2799
+ finally {
2800
+ await rm(wd, { recursive: true, force: true });
2801
+ }
2802
+ });
2803
+ it('treats an explicit blocked_on_user run_outcome as terminal for Ralph continue steer', async () => {
2804
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-blocked-on-user-'));
2805
+ const fakeBinDir = join(wd, 'fake-bin');
2806
+ const tmuxLogPath = join(wd, 'tmux.log');
2807
+ const stateDir = join(wd, '.omx', 'state');
2808
+ const watcherStatePath = join(stateDir, 'notify-fallback-state.json');
2809
+ try {
2810
+ await mkdir(stateDir, { recursive: true });
2811
+ await mkdir(fakeBinDir, { recursive: true });
2812
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
2813
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2814
+ await writeFile(join(stateDir, 'ralph-state.json'), JSON.stringify({
2815
+ active: true,
2816
+ current_phase: 'executing',
2817
+ run_outcome: 'blocked_on_user',
2818
+ tmux_pane_id: '%42',
2819
+ }, null, 2));
2820
+ await writeFile(join(stateDir, 'hud-state.json'), JSON.stringify({
2821
+ last_progress_at: new Date(Date.now() - 5 * 60_000).toISOString(),
2822
+ }, null, 2));
2823
+ await writeFile(watcherStatePath, JSON.stringify({
2824
+ ralph_continue_steer: {
2825
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
2826
+ },
2827
+ }, null, 2));
2828
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2829
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2830
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
2831
+ encoding: 'utf-8',
2832
+ env: buildCleanNotifyEnv({
2833
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2834
+ }),
2835
+ });
2836
+ assert.equal(run.status, 0, run.stderr || run.stdout);
2837
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
2838
+ const sends = tmuxLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
2839
+ assert.equal(sends.length, 0, 'blocked_on_user should suppress Ralph continue steer');
2840
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
2841
+ assert.equal(watcherState.ralph_continue_steer?.active, false);
2842
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'terminal');
2843
+ }
2844
+ finally {
2845
+ await rm(wd, { recursive: true, force: true });
2846
+ }
2847
+ });
2848
+ it('globally debounces Ralph continue steer across concurrent watcher instances', async () => {
2849
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-ralph-global-debounce-'));
2850
+ const fakeBinDir = join(wd, 'fake-bin');
2851
+ const tmuxLogPath = join(wd, 'tmux.log');
2852
+ const stateDir = join(wd, '.omx', 'state');
2853
+ const sharedTimestampPath = join(stateDir, 'ralph-last-steer-at');
2854
+ try {
2855
+ await mkdir(stateDir, { recursive: true });
2856
+ await mkdir(fakeBinDir, { recursive: true });
2857
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
2858
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2859
+ await writeFile(join(stateDir, 'ralph-state.json'), JSON.stringify({
2860
+ active: true,
2861
+ current_phase: 'executing',
2862
+ tmux_pane_id: '%42',
2863
+ }, null, 2));
2864
+ await writeFile(join(stateDir, 'hud-state.json'), JSON.stringify({
2865
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
2866
+ }, null, 2));
2867
+ await writeFile(join(stateDir, 'notify-fallback-state.json'), JSON.stringify({
2868
+ ralph_continue_steer: {
2869
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
2870
+ },
2871
+ }, null, 2));
2872
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2873
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2874
+ const env = {
2875
+ ...buildCleanNotifyEnv(),
2876
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2877
+ };
2878
+ const first = spawn(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { cwd: wd, stdio: 'pipe', env });
2879
+ const second = spawn(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], { cwd: wd, stdio: 'pipe', env });
2880
+ await Promise.all([waitForExit(first, 4000), waitForExit(second, 4000)]);
2881
+ assert.equal(first.exitCode, 0);
2882
+ assert.equal(second.exitCode, 0);
2883
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8');
2884
+ const sends = tmuxLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
2885
+ assert.equal(sends.length, 1, 'shared timestamp + lock should allow only one concurrent Ralph steer send');
2886
+ const sharedTimestamp = (await readFile(sharedTimestampPath, 'utf-8')).trim();
2887
+ assert.match(sharedTimestamp, /^\d{4}-\d{2}-\d{2}T/, 'concurrent send winner should persist a shared cooldown timestamp');
2888
+ const watcherState = JSON.parse(await readFile(join(stateDir, 'notify-fallback-state.json'), 'utf-8'));
2889
+ assert.equal(watcherState.ralph_continue_steer?.shared_timestamp_path, sharedTimestampPath);
2890
+ assert.equal(watcherState.ralph_continue_steer?.shared_last_sent_at, sharedTimestamp);
2891
+ assert.match(watcherState.ralph_continue_steer?.last_reason ?? '', /^(sent|global_cooldown|global_lock_busy)$/, 'final watcher state should reflect either the winner or a globally throttled loser');
2892
+ }
2893
+ finally {
2894
+ await rm(wd, { recursive: true, force: true });
2895
+ }
2896
+ });
2897
+ it('keeps team control-plane pumping when Ralph continue steer fails', async () => {
2898
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-control-plane-split-'));
2899
+ const fakeBinDir = join(wd, 'fake-bin');
2900
+ const tmuxLogPath = join(wd, 'tmux.log');
2901
+ const previousRuntimeBridge = process.env.OMX_RUNTIME_BRIDGE;
2902
+ try {
2903
+ process.env.OMX_RUNTIME_BRIDGE = '0';
2904
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
2905
+ await mkdir(fakeBinDir, { recursive: true });
2906
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath, {
2907
+ failSendKeysMatch: 'Ralph loop active continue',
2908
+ }));
2909
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2910
+ await initTeamState('dispatch-team', 'task', 'executor', 1, wd);
2911
+ const queued = await enqueueDispatchRequest('dispatch-team', {
2912
+ kind: 'inbox',
2913
+ to_worker: 'worker-1',
2914
+ worker_index: 1,
2915
+ trigger_message: 'dispatch ping',
2916
+ }, wd);
2917
+ await writeFile(join(wd, '.omx', 'state', 'ralph-state.json'), JSON.stringify({
2918
+ active: true,
2919
+ current_phase: 'executing',
2920
+ tmux_pane_id: '%42',
2921
+ }, null, 2));
2922
+ await writeFile(join(wd, '.omx', 'state', 'hud-state.json'), JSON.stringify({
2923
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
2924
+ }, null, 2));
2925
+ await writeFile(join(wd, '.omx', 'state', 'notify-fallback-state.json'), JSON.stringify({
2926
+ ralph_continue_steer: {
2927
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
2928
+ },
2929
+ }, null, 2));
2930
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2931
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2932
+ const result = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50', '--dispatch-max-per-tick', '1'], {
2933
+ encoding: 'utf-8',
2934
+ env: buildCleanNotifyEnv({
2935
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2936
+ }),
2937
+ });
2938
+ assert.equal(result.status, 0, result.stderr || result.stdout);
2939
+ const request = await readDispatchRequest('dispatch-team', queued.request.request_id, wd);
2940
+ assert.ok(request);
2941
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
2942
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
2943
+ assert.equal(watcherState.dispatch_drain?.run_count, 1);
2944
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'send_failed');
2945
+ assert.match(watcherState.ralph_continue_steer?.last_error ?? '', /send failed/i);
2946
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8');
2947
+ assert.match(tmuxLog, /send-keys -t .* -l dispatch ping/);
2948
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
2949
+ const logEntries = (await readFile(logPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
2950
+ const drainEvent = logEntries.find((entry) => entry.type === 'dispatch_drain_tick');
2951
+ assert.ok(drainEvent, 'expected dispatch_drain_tick log event');
2952
+ const ralphFailureEvent = logEntries.find((entry) => (entry.type === 'ralph_continue_steer' && entry.reason === 'send_failed'));
2953
+ assert.ok(ralphFailureEvent, 'expected Ralph failure to be logged without aborting team control-plane pumping');
2954
+ }
2955
+ finally {
2956
+ if (typeof previousRuntimeBridge === 'string')
2957
+ process.env.OMX_RUNTIME_BRIDGE = previousRuntimeBridge;
2958
+ else
2959
+ delete process.env.OMX_RUNTIME_BRIDGE;
2960
+ await rm(wd, { recursive: true, force: true });
2961
+ }
2962
+ });
2963
+ it('retypes on every retry when trigger is not in narrow input area', async () => {
2964
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-dispatch-cm-fallback-'));
2965
+ const fakeBinDir = join(wd, 'fake-bin');
2966
+ const tmuxLogPath = join(wd, 'tmux.log');
2967
+ const captureSeqFile = join(wd, 'capture-seq.txt');
2968
+ const captureCounterFile = join(wd, 'capture-seq.idx');
2969
+ const previousRuntimeBridge = process.env.OMX_RUNTIME_BRIDGE;
2970
+ try {
2971
+ process.env.OMX_RUNTIME_BRIDGE = '0';
2972
+ await mkdir(fakeBinDir, { recursive: true });
2973
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
2974
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
2975
+ // Shared preflight now adds one 80-line capture per tick before the
2976
+ // narrow retry check. Pre-capture on retries still returns "ready"
2977
+ // (no trigger) so the request is retyped on every retry.
2978
+ await writeFile(captureSeqFile, [
2979
+ // Run 1 (attempt 0): 1 shared preflight + 3 verify rounds × 2 captures = 7
2980
+ 'ready', 'ping', 'ping', 'ping', 'ping', 'ping', 'ping',
2981
+ // Run 2 (attempt 1): 1 shared preflight + 1 pre-capture + 3 verify rounds × 2 captures = 8
2982
+ 'ready', 'ready', 'ping', 'ping', 'ping', 'ping', 'ping', 'ping',
2983
+ // Run 3 (attempt 2): 1 shared preflight + 1 pre-capture + 3 verify rounds × 2 captures = 8
2984
+ 'ready', 'ready', 'ping', 'ping', 'ping', 'ping', 'ping', 'ping',
2985
+ ].join('\n'));
2986
+ await initTeamState('dispatch-team', 'task', 'executor', 1, wd);
2987
+ const queued = await enqueueDispatchRequest('dispatch-team', {
2988
+ kind: 'inbox',
2989
+ to_worker: 'worker-1',
2990
+ worker_index: 1,
2991
+ pane_id: '%42',
2992
+ trigger_message: 'ping',
2993
+ }, wd);
2994
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
2995
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
2996
+ const env = {
2997
+ ...buildCleanNotifyEnv(),
2998
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
2999
+ OMX_TEST_CAPTURE_SEQUENCE_FILE: captureSeqFile,
3000
+ OMX_TEST_CAPTURE_COUNTER_FILE: captureCounterFile,
3001
+ };
3002
+ for (let i = 0; i < 3; i += 1) {
3003
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50', '--dispatch-max-per-tick', '1'], { encoding: 'utf-8', env });
3004
+ assert.equal(run.status, 0, run.stderr || run.stdout);
3005
+ }
3006
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8');
3007
+ const typeMatches = tmuxLog.match(/send-keys -t %42 -l ping/g) || [];
3008
+ assert.equal(typeMatches.length, 3, 'should retype on every retry when trigger not in narrow capture (fresh + 2 retries)');
3009
+ const request = await readDispatchRequest('dispatch-team', queued.request.request_id, wd);
3010
+ assert.equal(request?.status, 'failed');
3011
+ assert.equal(request?.last_reason, 'unconfirmed_after_max_retries');
3012
+ }
3013
+ finally {
3014
+ if (typeof previousRuntimeBridge === 'string')
3015
+ process.env.OMX_RUNTIME_BRIDGE = previousRuntimeBridge;
3016
+ else
3017
+ delete process.env.OMX_RUNTIME_BRIDGE;
3018
+ await rm(wd, { recursive: true, force: true });
3019
+ }
3020
+ });
3021
+ it('exits when the tracked parent pid is gone', async () => {
3022
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-parent-exit-'));
3023
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-parent-home-'));
3024
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
3025
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
3026
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
3027
+ let child;
3028
+ try {
3029
+ const shortLivedParent = spawn(process.execPath, ['-e', 'setTimeout(() => process.exit(0), 10)'], {
3030
+ stdio: 'ignore',
3031
+ });
3032
+ assert.ok(shortLivedParent.pid, 'expected short-lived parent pid');
3033
+ const parentPid = shortLivedParent.pid;
3034
+ await once(shortLivedParent, 'exit');
3035
+ child = spawn(process.execPath, [
3036
+ watcherScript,
3037
+ '--cwd',
3038
+ wd,
3039
+ '--notify-script',
3040
+ notifyHook,
3041
+ '--poll-ms',
3042
+ '50',
3043
+ '--parent-pid',
3044
+ String(parentPid),
3045
+ '--max-lifetime-ms',
3046
+ '5000',
3047
+ ], {
3048
+ cwd: wd,
3049
+ stdio: 'ignore',
3050
+ env: buildCleanNotifyEnv({ HOME: tempHome }),
3051
+ });
3052
+ await waitForExit(child, 4000);
3053
+ assert.equal(child.exitCode, 0);
3054
+ const logEntries = (await readFile(logPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
3055
+ assert.ok(logEntries.some((entry) => (entry.type === 'watcher_stop' && entry.reason === 'parent_gone')));
3056
+ }
3057
+ finally {
3058
+ if (child && isPidAlive(child.pid)) {
3059
+ child.kill('SIGTERM');
3060
+ await waitForExit(child, 4000).catch(() => { });
3061
+ }
3062
+ await rm(wd, { recursive: true, force: true });
3063
+ await rm(tempHome, { recursive: true, force: true });
3064
+ }
3065
+ });
3066
+ it('prints notify script missing errors to stderr for authority-only ticks', async () => {
3067
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-authority-missing-script-'));
3068
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-authority-missing-home-'));
3069
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
3070
+ const missingNotifyHook = join(wd, 'dist', 'scripts', 'missing-notify-hook.js');
3071
+ try {
3072
+ const run = spawnSync(process.execPath, [
3073
+ watcherScript,
3074
+ '--once',
3075
+ '--authority-only',
3076
+ '--cwd',
3077
+ wd,
3078
+ '--notify-script',
3079
+ missingNotifyHook,
3080
+ '--poll-ms',
3081
+ '50',
3082
+ ], {
3083
+ cwd: wd,
3084
+ encoding: 'utf-8',
3085
+ env: buildCleanNotifyEnv({ HOME: tempHome }),
3086
+ });
3087
+ assert.equal(run.status, 1);
3088
+ assert.match(run.stderr, /notify-fallback-watcher: notify script missing:/);
3089
+ assert.match(run.stderr, /missing-notify-hook\.js/);
3090
+ }
3091
+ finally {
3092
+ await rm(wd, { recursive: true, force: true });
3093
+ await rm(tempHome, { recursive: true, force: true });
3094
+ }
3095
+ });
3096
+ it('prints fatal watcher errors to stderr for authority-only ticks', async () => {
3097
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-authority-fatal-'));
3098
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-authority-fatal-home-'));
3099
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
3100
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
3101
+ try {
3102
+ const run = spawnSync(process.execPath, [
3103
+ watcherScript,
3104
+ '--once',
3105
+ '--authority-only',
3106
+ '--cwd',
3107
+ wd,
3108
+ '--notify-script',
3109
+ notifyHook,
3110
+ '--poll-ms',
3111
+ '50',
3112
+ ], {
3113
+ cwd: wd,
3114
+ encoding: 'utf-8',
3115
+ env: buildCleanNotifyEnv({
3116
+ HOME: tempHome,
3117
+ NODE_ENV: 'test',
3118
+ OMX_NOTIFY_FALLBACK_TEST_FATAL: '1',
3119
+ }),
3120
+ });
3121
+ assert.equal(run.status, 1);
3122
+ assert.match(run.stderr, /notify-fallback-watcher: fatal: test fatal notify fallback failure/);
3123
+ }
3124
+ finally {
3125
+ await rm(wd, { recursive: true, force: true });
3126
+ await rm(tempHome, { recursive: true, force: true });
3127
+ }
3128
+ });
3129
+ it('ignores stale session-scoped Ralph state when the current session identity is stale', async () => {
3130
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-stale-session-ralph-'));
3131
+ const fakeBinDir = join(wd, 'fake-bin');
3132
+ const tmuxLogPath = join(wd, 'tmux.log');
3133
+ const stateDir = join(wd, '.omx', 'state');
3134
+ const sessionId = 'sess-stale';
3135
+ const sessionStateDir = join(stateDir, 'sessions', sessionId);
3136
+ const watcherStatePath = join(stateDir, 'notify-fallback-state.json');
3137
+ try {
3138
+ await mkdir(sessionStateDir, { recursive: true });
3139
+ await mkdir(fakeBinDir, { recursive: true });
3140
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
3141
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
3142
+ await writeFile(join(stateDir, 'session.json'), JSON.stringify({
3143
+ session_id: sessionId,
3144
+ started_at: '2026-01-01T00:00:00.000Z',
3145
+ cwd: wd,
3146
+ pid: Number.MAX_SAFE_INTEGER,
3147
+ }, null, 2));
3148
+ await writeFile(join(sessionStateDir, 'ralph-state.json'), JSON.stringify({
3149
+ active: true,
3150
+ current_phase: 'executing',
3151
+ tmux_pane_id: '%42',
3152
+ }, null, 2));
3153
+ await writeFile(watcherStatePath, JSON.stringify({
3154
+ ralph_continue_steer: {
3155
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
3156
+ },
3157
+ }, null, 2));
3158
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
3159
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
3160
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
3161
+ encoding: 'utf-8',
3162
+ env: buildCleanNotifyEnv({
3163
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
3164
+ }),
3165
+ });
3166
+ assert.equal(run.status, 0, run.stderr || run.stdout);
3167
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
3168
+ const sends = tmuxLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
3169
+ assert.equal(sends.length, 0, 'stale current-session identity must block Ralph continue injection');
3170
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
3171
+ assert.equal(watcherState.ralph_continue_steer?.active, false);
3172
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'stale_current_session');
3173
+ }
3174
+ finally {
3175
+ await rm(wd, { recursive: true, force: true });
3176
+ }
3177
+ });
3178
+ it('ignores stale root Ralph state when the current session has not started Ralph', async () => {
3179
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-stale-root-ralph-'));
3180
+ const fakeBinDir = join(wd, 'fake-bin');
3181
+ const tmuxLogPath = join(wd, 'tmux.log');
3182
+ const stateDir = join(wd, '.omx', 'state');
3183
+ const sessionId = 'sess-fresh';
3184
+ const watcherStatePath = join(stateDir, 'notify-fallback-state.json');
3185
+ try {
3186
+ await mkdir(join(stateDir, 'sessions', sessionId), { recursive: true });
3187
+ await mkdir(fakeBinDir, { recursive: true });
3188
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
3189
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
3190
+ await writeSessionStart(wd, sessionId);
3191
+ await writeFile(join(stateDir, 'ralph-state.json'), JSON.stringify({
3192
+ active: true,
3193
+ current_phase: 'executing',
3194
+ tmux_pane_id: '%42',
3195
+ }, null, 2));
3196
+ await writeFile(watcherStatePath, JSON.stringify({
3197
+ ralph_continue_steer: {
3198
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
3199
+ },
3200
+ }, null, 2));
3201
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
3202
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
3203
+ const run = spawnSync(process.execPath, [watcherScript, '--once', '--cwd', wd, '--notify-script', notifyHook, '--poll-ms', '50'], {
3204
+ encoding: 'utf-8',
3205
+ env: buildCleanNotifyEnv({
3206
+ PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
3207
+ }),
3208
+ });
3209
+ assert.equal(run.status, 0, run.stderr || run.stdout);
3210
+ const tmuxLog = await readFile(tmuxLogPath, 'utf8').catch(() => '');
3211
+ const sends = tmuxLog.match(/send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/g) || [];
3212
+ assert.equal(sends.length, 0, 'fresh sessions must ignore stale root Ralph state');
3213
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
3214
+ assert.equal(watcherState.ralph_continue_steer?.active, false);
3215
+ assert.equal(watcherState.ralph_continue_steer?.last_reason, 'blocked_by_current_session');
3216
+ }
3217
+ finally {
3218
+ await rm(wd, { recursive: true, force: true });
3219
+ }
3220
+ });
3221
+ it('keeps ticking for active session-scoped Ralph after parent loss, then stops once Ralph is terminal', async () => {
3222
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-parent-ralph-active-'));
3223
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-parent-ralph-home-'));
3224
+ const fakeBinDir = join(wd, 'fake-bin');
3225
+ const tmuxLogPath = join(wd, 'tmux.log');
3226
+ const stateDir = join(wd, '.omx', 'state');
3227
+ const sessionId = 'sess-active-ralph';
3228
+ const sessionStateDir = join(stateDir, 'sessions', sessionId);
3229
+ const ralphStatePath = join(sessionStateDir, 'ralph-state.json');
3230
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
3231
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
3232
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
3233
+ let child;
3234
+ try {
3235
+ await mkdir(sessionStateDir, { recursive: true });
3236
+ await mkdir(fakeBinDir, { recursive: true });
3237
+ await writeSessionStart(wd, sessionId);
3238
+ await writeFile(ralphStatePath, JSON.stringify({
3239
+ active: true,
3240
+ current_phase: 'executing',
3241
+ tmux_pane_id: '%42',
3242
+ }, null, 2));
3243
+ await writeFile(join(sessionStateDir, 'hud-state.json'), JSON.stringify({
3244
+ last_progress_at: new Date(Date.now() - 61_000).toISOString(),
3245
+ }, null, 2));
3246
+ await writeFile(join(stateDir, 'notify-fallback-state.json'), JSON.stringify({
3247
+ ralph_continue_steer: {
3248
+ last_sent_at: new Date(Date.now() - 61_000).toISOString(),
3249
+ },
3250
+ }, null, 2));
3251
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
3252
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
3253
+ const shortLivedParent = spawn(process.execPath, ['-e', 'setTimeout(() => process.exit(0), 10)'], {
3254
+ stdio: 'ignore',
3255
+ });
3256
+ assert.ok(shortLivedParent.pid, 'expected short-lived parent pid');
3257
+ const parentPid = shortLivedParent.pid;
3258
+ await once(shortLivedParent, 'exit');
3259
+ child = spawn(process.execPath, [
3260
+ watcherScript,
3261
+ '--cwd',
3262
+ wd,
3263
+ '--notify-script',
3264
+ notifyHook,
3265
+ '--poll-ms',
3266
+ '50',
3267
+ '--parent-pid',
3268
+ String(parentPid),
3269
+ '--max-lifetime-ms',
3270
+ '5000',
3271
+ ], {
3272
+ cwd: wd,
3273
+ stdio: 'ignore',
3274
+ env: buildCleanNotifyEnv({ HOME: tempHome, PATH: `${fakeBinDir}:${process.env.PATH || ''}` }),
3275
+ });
3276
+ await waitFor(async () => {
3277
+ const tmuxLog = await readFile(tmuxLogPath, 'utf-8').catch(() => '');
3278
+ return /send-keys -t %42 -l Ralph loop active continue \[OMX_TMUX_INJECT\]/.test(tmuxLog);
3279
+ }, 4000, 50);
3280
+ assert.ok(isPidAlive(child.pid), 'expected watcher to stay alive while Ralph remains active');
3281
+ await writeFile(ralphStatePath, JSON.stringify({
3282
+ active: false,
3283
+ current_phase: 'complete',
3284
+ completed_at: new Date().toISOString(),
3285
+ tmux_pane_id: '%42',
3286
+ }, null, 2));
3287
+ await waitForExit(child, 4000);
3288
+ assert.equal(child.exitCode, 0);
3289
+ const logEntries = (await readFile(logPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
3290
+ assert.ok(logEntries.some((entry) => (entry.type === 'watcher_parent_guard' && entry.reason === 'parent_gone_deferred_for_active_ralph')));
3291
+ assert.ok(logEntries.some((entry) => (entry.type === 'watcher_stop' && entry.reason === 'parent_gone')));
3292
+ }
3293
+ finally {
3294
+ if (child && isPidAlive(child.pid)) {
3295
+ child.kill('SIGTERM');
3296
+ await waitForExit(child, 4000).catch(() => { });
3297
+ }
3298
+ await rm(wd, { recursive: true, force: true });
3299
+ await rm(tempHome, { recursive: true, force: true });
3300
+ }
3301
+ });
3302
+ it('stays alive after parent exit while an active team still has live worker panes', async () => {
3303
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-parent-gone-team-'));
3304
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-parent-gone-team-home-'));
3305
+ const fakeBinDir = join(wd, 'fake-bin');
3306
+ const tmuxLogPath = join(wd, 'tmux.log');
3307
+ const teamStatePath = join(wd, '.omx', 'state', 'team-state.json');
3308
+ let child;
3309
+ try {
3310
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
3311
+ await mkdir(join(wd, '.omx', 'state', 'team', 'dispatch-team'), { recursive: true });
3312
+ await mkdir(fakeBinDir, { recursive: true });
3313
+ await writeFile(teamStatePath, JSON.stringify({
3314
+ active: true,
3315
+ team_name: 'dispatch-team',
3316
+ current_phase: 'team-exec',
3317
+ }, null, 2));
3318
+ await writeFile(join(wd, '.omx', 'state', 'team', 'dispatch-team', 'config.json'), JSON.stringify({
3319
+ name: 'dispatch-team',
3320
+ tmux_session: 'dispatch-team:0',
3321
+ leader_pane_id: '%99',
3322
+ workers: [
3323
+ { name: 'worker-1', pane_id: '%42' },
3324
+ ],
3325
+ }, null, 2));
3326
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
3327
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
3328
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
3329
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
3330
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
3331
+ const shortLivedParent = spawn(process.execPath, ['-e', 'setTimeout(() => process.exit(0), 10)'], {
3332
+ stdio: 'ignore',
3333
+ });
3334
+ assert.ok(shortLivedParent.pid, 'expected short-lived parent pid');
3335
+ const parentPid = shortLivedParent.pid;
3336
+ await once(shortLivedParent, 'exit');
3337
+ child = spawn(process.execPath, [
3338
+ watcherScript,
3339
+ '--cwd',
3340
+ wd,
3341
+ '--notify-script',
3342
+ notifyHook,
3343
+ '--poll-ms',
3344
+ '50',
3345
+ '--parent-pid',
3346
+ String(parentPid),
3347
+ '--max-lifetime-ms',
3348
+ '5000',
3349
+ ], {
3350
+ cwd: wd,
3351
+ stdio: 'ignore',
3352
+ env: buildCleanNotifyEnv({ HOME: tempHome, PATH: `${fakeBinDir}:${process.env.PATH || ''}` }),
3353
+ });
3354
+ await waitFor(async () => isPidAlive(child?.pid), 4000, 50);
3355
+ await waitFor(async () => {
3356
+ const logEntries = (await readFile(logPath, 'utf-8').catch(() => ''))
3357
+ .trim()
3358
+ .split('\n')
3359
+ .filter(Boolean)
3360
+ .map((line) => JSON.parse(line));
3361
+ return logEntries.some((entry) => (entry.type === 'watcher_parent_guard' && entry.reason === 'parent_gone_deferred_for_active_team'));
3362
+ }, 4000, 50);
3363
+ assert.ok(isPidAlive(child.pid), 'expected watcher to stay alive while team worker panes remain active');
3364
+ await writeFile(teamStatePath, JSON.stringify({
3365
+ active: false,
3366
+ team_name: 'dispatch-team',
3367
+ current_phase: 'complete',
3368
+ completed_at: new Date().toISOString(),
3369
+ }, null, 2));
3370
+ await waitForExit(child, 4000);
3371
+ assert.equal(child.exitCode, 0);
3372
+ const logEntries = (await readFile(logPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
3373
+ assert.ok(logEntries.some((entry) => (entry.type === 'watcher_parent_guard' && entry.reason === 'parent_gone_deferred_for_active_team')));
3374
+ assert.ok(logEntries.some((entry) => (entry.type === 'watcher_stop' && entry.reason === 'parent_gone')));
3375
+ }
3376
+ finally {
3377
+ if (child && isPidAlive(child.pid)) {
3378
+ child.kill('SIGTERM');
3379
+ await waitForExit(child, 4000).catch(() => { });
3380
+ }
3381
+ await rm(wd, { recursive: true, force: true });
3382
+ await rm(tempHome, { recursive: true, force: true });
3383
+ }
3384
+ });
3385
+ it('stays alive after parent exit when coarse team-state is missing but canonical team is active for the current session', async () => {
3386
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-parent-gone-canonical-team-'));
3387
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-parent-gone-canonical-home-'));
3388
+ const fakeBinDir = join(wd, 'fake-bin');
3389
+ const tmuxLogPath = join(wd, 'tmux.log');
3390
+ let child;
3391
+ try {
3392
+ await mkdir(fakeBinDir, { recursive: true });
3393
+ await writeCanonicalWatcherTeamFixture(wd, {
3394
+ teamName: 'dispatch-team',
3395
+ sessionId: 'sess-parent-canonical',
3396
+ ownerSessionId: 'sess-parent-canonical',
3397
+ });
3398
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
3399
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
3400
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
3401
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
3402
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
3403
+ const shortLivedParent = spawn(process.execPath, ['-e', 'setTimeout(() => process.exit(0), 10)'], {
3404
+ stdio: 'ignore',
3405
+ });
3406
+ assert.ok(shortLivedParent.pid, 'expected short-lived parent pid');
3407
+ const parentPid = shortLivedParent.pid;
3408
+ await once(shortLivedParent, 'exit');
3409
+ child = spawn(process.execPath, [
3410
+ watcherScript,
3411
+ '--cwd',
3412
+ wd,
3413
+ '--notify-script',
3414
+ notifyHook,
3415
+ '--poll-ms',
3416
+ '50',
3417
+ '--parent-pid',
3418
+ String(parentPid),
3419
+ '--max-lifetime-ms',
3420
+ '5000',
3421
+ ], {
3422
+ cwd: wd,
3423
+ stdio: 'ignore',
3424
+ env: buildCleanNotifyEnv({ HOME: tempHome, PATH: `${fakeBinDir}:${process.env.PATH || ''}` }),
3425
+ });
3426
+ await waitFor(async () => isPidAlive(child?.pid), 4000, 50);
3427
+ await waitFor(async () => {
3428
+ const logEntries = (await readFile(logPath, 'utf-8').catch(() => ''))
3429
+ .trim()
3430
+ .split('\n')
3431
+ .filter(Boolean)
3432
+ .map((line) => JSON.parse(line));
3433
+ return logEntries.some((entry) => (entry.type === 'watcher_parent_guard' && entry.reason === 'parent_gone_deferred_for_active_team'));
3434
+ }, 4000, 50);
3435
+ assert.ok(isPidAlive(child.pid), 'expected watcher to stay alive while canonical team panes remain active');
3436
+ }
3437
+ finally {
3438
+ if (child && isPidAlive(child.pid)) {
3439
+ child.kill('SIGTERM');
3440
+ await waitForExit(child, 4000).catch(() => { });
3441
+ }
3442
+ await rm(wd, { recursive: true, force: true });
3443
+ await rm(tempHome, { recursive: true, force: true });
3444
+ }
3445
+ });
3446
+ it('does not defer parent-loss shutdown when canonical owner session is blank and coarse team-state is missing', async () => {
3447
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-parent-gone-ownerless-team-'));
3448
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-parent-gone-ownerless-home-'));
3449
+ const fakeBinDir = join(wd, 'fake-bin');
3450
+ const tmuxLogPath = join(wd, 'tmux.log');
3451
+ let child;
3452
+ try {
3453
+ await mkdir(fakeBinDir, { recursive: true });
3454
+ await writeCanonicalWatcherTeamFixture(wd, {
3455
+ teamName: 'dispatch-team',
3456
+ sessionId: 'sess-parent-ownerless',
3457
+ ownerSessionId: '',
3458
+ });
3459
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
3460
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
3461
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
3462
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
3463
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
3464
+ const shortLivedParent = spawn(process.execPath, ['-e', 'setTimeout(() => process.exit(0), 10)'], {
3465
+ stdio: 'ignore',
3466
+ });
3467
+ assert.ok(shortLivedParent.pid, 'expected short-lived parent pid');
3468
+ const parentPid = shortLivedParent.pid;
3469
+ await once(shortLivedParent, 'exit');
3470
+ child = spawn(process.execPath, [
3471
+ watcherScript,
3472
+ '--cwd',
3473
+ wd,
3474
+ '--notify-script',
3475
+ notifyHook,
3476
+ '--poll-ms',
3477
+ '50',
3478
+ '--parent-pid',
3479
+ String(parentPid),
3480
+ '--max-lifetime-ms',
3481
+ '5000',
3482
+ ], {
3483
+ cwd: wd,
3484
+ stdio: 'ignore',
3485
+ env: buildCleanNotifyEnv({ HOME: tempHome, PATH: `${fakeBinDir}:${process.env.PATH || ''}` }),
3486
+ });
3487
+ await waitForExit(child, 4000);
3488
+ assert.equal(child.exitCode, 0);
3489
+ const logEntries = (await readFile(logPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
3490
+ assert.ok(logEntries.some((entry) => (entry.type === 'watcher_stop' && entry.reason === 'parent_gone')));
3491
+ assert.ok(!logEntries.some((entry) => (entry.type === 'watcher_parent_guard' && entry.reason === 'parent_gone_deferred_for_active_team')), 'ownerless canonical team must not defer parent-loss shutdown');
3492
+ }
3493
+ finally {
3494
+ if (child && isPidAlive(child.pid)) {
3495
+ child.kill('SIGTERM');
3496
+ await waitForExit(child, 4000).catch(() => { });
3497
+ }
3498
+ await rm(wd, { recursive: true, force: true });
3499
+ await rm(tempHome, { recursive: true, force: true });
3500
+ }
3501
+ });
3502
+ it('rejects invalid session_id before resolving session-scoped team paths', async () => {
3503
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-invalid-session-team-path-'));
3504
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-invalid-session-team-home-'));
3505
+ const fakeBinDir = join(wd, 'fake-bin');
3506
+ const tmuxLogPath = join(wd, 'tmux.log');
3507
+ const stateDir = join(wd, '.omx', 'state');
3508
+ const maliciousTeamDir = join(stateDir, 'team', 'dispatch-team');
3509
+ const sessionPath = join(stateDir, 'session.json');
3510
+ let child;
3511
+ try {
3512
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
3513
+ await mkdir(maliciousTeamDir, { recursive: true });
3514
+ await mkdir(fakeBinDir, { recursive: true });
3515
+ await writeSessionStart(wd, 'sess-valid');
3516
+ const validSession = JSON.parse(await readFile(sessionPath, 'utf-8'));
3517
+ await writeFile(sessionPath, JSON.stringify({
3518
+ ...validSession,
3519
+ session_id: '../team/dispatch-team',
3520
+ }, null, 2));
3521
+ await writeFile(join(maliciousTeamDir, 'team-state.json'), JSON.stringify({
3522
+ active: true,
3523
+ team_name: 'dispatch-team',
3524
+ current_phase: 'team-exec',
3525
+ }, null, 2));
3526
+ await writeFile(join(maliciousTeamDir, 'config.json'), JSON.stringify({
3527
+ name: 'dispatch-team',
3528
+ tmux_session: 'dispatch-team:0',
3529
+ leader_pane_id: '%99',
3530
+ workers: [
3531
+ { name: 'worker-1', pane_id: '%42' },
3532
+ ],
3533
+ }, null, 2));
3534
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
3535
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
3536
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
3537
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
3538
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
3539
+ const shortLivedParent = spawn(process.execPath, ['-e', 'setTimeout(() => process.exit(0), 10)'], {
3540
+ stdio: 'ignore',
3541
+ });
3542
+ assert.ok(shortLivedParent.pid, 'expected short-lived parent pid');
3543
+ const parentPid = shortLivedParent.pid;
3544
+ await once(shortLivedParent, 'exit');
3545
+ child = spawn(process.execPath, [
3546
+ watcherScript,
3547
+ '--cwd',
3548
+ wd,
3549
+ '--notify-script',
3550
+ notifyHook,
3551
+ '--poll-ms',
3552
+ '50',
3553
+ '--parent-pid',
3554
+ String(parentPid),
3555
+ '--max-lifetime-ms',
3556
+ '5000',
3557
+ ], {
3558
+ cwd: wd,
3559
+ stdio: 'ignore',
3560
+ env: buildCleanNotifyEnv({ HOME: tempHome, PATH: `${fakeBinDir}:${process.env.PATH || ''}` }),
3561
+ });
3562
+ await waitForExit(child, 4000);
3563
+ assert.equal(child.exitCode, 0);
3564
+ const logEntries = (await readFile(logPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
3565
+ assert.ok(logEntries.some((entry) => (entry.type === 'watcher_stop' && entry.reason === 'parent_gone')));
3566
+ assert.ok(!logEntries.some((entry) => (entry.type === 'watcher_parent_guard' && entry.reason === 'parent_gone_deferred_for_active_team')), 'invalid session_id must not be used for session-scoped team path resolution');
3567
+ }
3568
+ finally {
3569
+ if (child && isPidAlive(child.pid)) {
3570
+ child.kill('SIGTERM');
3571
+ await waitForExit(child, 4000).catch(() => { });
3572
+ }
3573
+ await rm(wd, { recursive: true, force: true });
3574
+ await rm(tempHome, { recursive: true, force: true });
3575
+ }
3576
+ });
3577
+ it('rejects invalid team_name before resolving watcher team paths', async () => {
3578
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-invalid-team-path-'));
3579
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-invalid-team-home-'));
3580
+ const fakeBinDir = join(wd, 'fake-bin');
3581
+ const tmuxLogPath = join(wd, 'tmux.log');
3582
+ const stateDir = join(wd, '.omx', 'state');
3583
+ const validTeamDir = join(stateDir, 'team', 'dispatch-team');
3584
+ let child;
3585
+ try {
3586
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
3587
+ await mkdir(validTeamDir, { recursive: true });
3588
+ await mkdir(fakeBinDir, { recursive: true });
3589
+ await writeFile(join(stateDir, 'team-state.json'), JSON.stringify({
3590
+ active: true,
3591
+ team_name: '../team/dispatch-team',
3592
+ current_phase: 'team-exec',
3593
+ }, null, 2));
3594
+ await writeFile(join(validTeamDir, 'config.json'), JSON.stringify({
3595
+ name: 'dispatch-team',
3596
+ tmux_session: 'dispatch-team:0',
3597
+ leader_pane_id: '%99',
3598
+ workers: [
3599
+ { name: 'worker-1', pane_id: '%42' },
3600
+ ],
3601
+ }, null, 2));
3602
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
3603
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
3604
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
3605
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
3606
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
3607
+ const shortLivedParent = spawn(process.execPath, ['-e', 'setTimeout(() => process.exit(0), 10)'], {
3608
+ stdio: 'ignore',
3609
+ });
3610
+ assert.ok(shortLivedParent.pid, 'expected short-lived parent pid');
3611
+ const parentPid = shortLivedParent.pid;
3612
+ await once(shortLivedParent, 'exit');
3613
+ child = spawn(process.execPath, [
3614
+ watcherScript,
3615
+ '--cwd',
3616
+ wd,
3617
+ '--notify-script',
3618
+ notifyHook,
3619
+ '--poll-ms',
3620
+ '50',
3621
+ '--parent-pid',
3622
+ String(parentPid),
3623
+ '--max-lifetime-ms',
3624
+ '5000',
3625
+ ], {
3626
+ cwd: wd,
3627
+ stdio: 'ignore',
3628
+ env: buildCleanNotifyEnv({ HOME: tempHome, PATH: `${fakeBinDir}:${process.env.PATH || ''}` }),
3629
+ });
3630
+ await waitForExit(child, 4000);
3631
+ assert.equal(child.exitCode, 0);
3632
+ const logEntries = (await readFile(logPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
3633
+ assert.ok(logEntries.some((entry) => (entry.type === 'watcher_stop' && entry.reason === 'parent_gone')));
3634
+ assert.ok(!logEntries.some((entry) => (entry.type === 'watcher_parent_guard' && entry.reason === 'parent_gone_deferred_for_active_team')), 'invalid team_name must not be used for watcher team path resolution');
3635
+ }
3636
+ finally {
3637
+ if (child && isPidAlive(child.pid)) {
3638
+ child.kill('SIGTERM');
3639
+ await waitForExit(child, 4000).catch(() => { });
3640
+ }
3641
+ await rm(wd, { recursive: true, force: true });
3642
+ await rm(tempHome, { recursive: true, force: true });
3643
+ }
3644
+ });
3645
+ it('does not defer parent-loss shutdown for a team that is already terminal in phase.json', async () => {
3646
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-parent-gone-terminal-team-'));
3647
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-parent-gone-terminal-team-home-'));
3648
+ const fakeBinDir = join(wd, 'fake-bin');
3649
+ const tmuxLogPath = join(wd, 'tmux.log');
3650
+ let child;
3651
+ try {
3652
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
3653
+ await mkdir(join(wd, '.omx', 'state', 'team', 'dispatch-team'), { recursive: true });
3654
+ await mkdir(fakeBinDir, { recursive: true });
3655
+ await writeFile(join(wd, '.omx', 'state', 'team-state.json'), JSON.stringify({
3656
+ active: true,
3657
+ team_name: 'dispatch-team',
3658
+ current_phase: 'team-exec',
3659
+ }, null, 2));
3660
+ await writeFile(join(wd, '.omx', 'state', 'team', 'dispatch-team', 'phase.json'), JSON.stringify({
3661
+ current_phase: 'complete',
3662
+ }, null, 2));
3663
+ await writeFile(join(wd, '.omx', 'state', 'team', 'dispatch-team', 'config.json'), JSON.stringify({
3664
+ name: 'dispatch-team',
3665
+ tmux_session: 'dispatch-team:0',
3666
+ leader_pane_id: '%99',
3667
+ workers: [
3668
+ { name: 'worker-1', pane_id: '%42' },
3669
+ ],
3670
+ }, null, 2));
3671
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
3672
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
3673
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
3674
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
3675
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
3676
+ const shortLivedParent = spawn(process.execPath, ['-e', 'setTimeout(() => process.exit(0), 10)'], {
3677
+ stdio: 'ignore',
3678
+ });
3679
+ assert.ok(shortLivedParent.pid, 'expected short-lived parent pid');
3680
+ const parentPid = shortLivedParent.pid;
3681
+ await once(shortLivedParent, 'exit');
3682
+ child = spawn(process.execPath, [
3683
+ watcherScript,
3684
+ '--cwd',
3685
+ wd,
3686
+ '--notify-script',
3687
+ notifyHook,
3688
+ '--poll-ms',
3689
+ '50',
3690
+ '--parent-pid',
3691
+ String(parentPid),
3692
+ '--max-lifetime-ms',
3693
+ '5000',
3694
+ ], {
3695
+ cwd: wd,
3696
+ stdio: 'ignore',
3697
+ env: buildCleanNotifyEnv({ HOME: tempHome, PATH: `${fakeBinDir}:${process.env.PATH || ''}` }),
3698
+ });
3699
+ await waitForExit(child, 4000);
3700
+ assert.equal(child.exitCode, 0);
3701
+ const logEntries = (await readFile(logPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
3702
+ assert.equal(logEntries.some((entry) => (entry.type === 'watcher_parent_guard' && entry.reason === 'parent_gone_deferred_for_active_team')), false);
3703
+ assert.ok(logEntries.some((entry) => (entry.type === 'watcher_stop' && entry.reason === 'parent_gone')));
3704
+ }
3705
+ finally {
3706
+ if (child && isPidAlive(child.pid)) {
3707
+ child.kill('SIGTERM');
3708
+ await waitForExit(child, 4000).catch(() => { });
3709
+ }
3710
+ await rm(wd, { recursive: true, force: true });
3711
+ await rm(tempHome, { recursive: true, force: true });
3712
+ }
3713
+ });
3714
+ it('replaces a stale watcher from the per-cwd pid file', async () => {
3715
+ const replacementTimeoutMs = 20000; // c8-instrumented Node20 full runs can delay watcher handoff well beyond 8s.
3716
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-stale-pid-'));
3717
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-stale-home-'));
3718
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
3719
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
3720
+ const pidPath = join(wd, '.omx', 'state', 'notify-fallback.pid');
3721
+ let first;
3722
+ let second;
3723
+ try {
3724
+ first = spawn(process.execPath, [
3725
+ watcherScript,
3726
+ '--cwd',
3727
+ wd,
3728
+ '--notify-script',
3729
+ notifyHook,
3730
+ '--poll-ms',
3731
+ '50',
3732
+ '--parent-pid',
3733
+ String(process.pid),
3734
+ '--max-lifetime-ms',
3735
+ '5000',
3736
+ ], {
3737
+ cwd: wd,
3738
+ stdio: 'ignore',
3739
+ env: buildCleanNotifyEnv({ HOME: tempHome }),
3740
+ });
3741
+ assert.ok(first.pid, 'expected first watcher pid');
3742
+ await waitFor(async () => {
3743
+ try {
3744
+ const pidFile = JSON.parse(await readFile(pidPath, 'utf-8'));
3745
+ assert.match(pidFile.owner_token ?? '', /^\d+-\d+-/, 'pid file should include an ownership token');
3746
+ return pidFile.pid === first?.pid;
3747
+ }
3748
+ catch {
3749
+ return false;
3750
+ }
3751
+ }, replacementTimeoutMs, 50);
3752
+ second = spawn(process.execPath, [
3753
+ watcherScript,
3754
+ '--cwd',
3755
+ wd,
3756
+ '--notify-script',
3757
+ notifyHook,
3758
+ '--poll-ms',
3759
+ '50',
3760
+ '--parent-pid',
3761
+ String(process.pid),
3762
+ '--max-lifetime-ms',
3763
+ '5000',
3764
+ ], {
3765
+ cwd: wd,
3766
+ stdio: 'ignore',
3767
+ env: buildCleanNotifyEnv({ HOME: tempHome }),
3768
+ });
3769
+ assert.ok(second.pid, 'expected second watcher pid');
3770
+ await waitForExit(first, replacementTimeoutMs);
3771
+ assert.equal(first.exitCode, 0);
3772
+ await waitFor(async () => {
3773
+ try {
3774
+ const pidFile = JSON.parse(await readFile(pidPath, 'utf-8'));
3775
+ assert.match(pidFile.owner_token ?? '', /^\d+-\d+-/, 'replacement pid file should keep ownership metadata');
3776
+ return pidFile.pid === second?.pid;
3777
+ }
3778
+ catch {
3779
+ return false;
3780
+ }
3781
+ }, replacementTimeoutMs, 50);
3782
+ assert.ok(isPidAlive(second.pid), 'expected replacement watcher to remain alive');
3783
+ }
3784
+ finally {
3785
+ if (second && isPidAlive(second.pid)) {
3786
+ second.kill('SIGTERM');
3787
+ await waitForExit(second, replacementTimeoutMs).catch(() => { });
3788
+ }
3789
+ if (first && isPidAlive(first.pid)) {
3790
+ first.kill('SIGTERM');
3791
+ await waitForExit(first, replacementTimeoutMs).catch(() => { });
3792
+ }
3793
+ await rm(wd, { recursive: true, force: true });
3794
+ await rm(tempHome, { recursive: true, force: true });
3795
+ }
3796
+ });
3797
+ it('backs off idle polling and resets to the base cadence after fresh rollout activity', async () => {
3798
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-idle-backoff-'));
3799
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-idle-backoff-home-'));
3800
+ const sid = randomUUID();
3801
+ const sessionDir = todaySessionDir(tempHome);
3802
+ const rolloutPath = join(sessionDir, `rollout-test-fallback-idle-backoff-${sid}.jsonl`);
3803
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
3804
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
3805
+ const watcherStatePath = join(wd, '.omx', 'state', 'notify-fallback-state.json');
3806
+ const turnLogPath = join(wd, '.omx', 'logs', `turns-${new Date().toISOString().split('T')[0]}.jsonl`);
3807
+ let child;
3808
+ try {
3809
+ await mkdir(join(wd, '.omx', 'logs'), { recursive: true });
3810
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
3811
+ await mkdir(sessionDir, { recursive: true });
3812
+ await writeFile(rolloutPath, `${JSON.stringify({
3813
+ timestamp: new Date().toISOString(),
3814
+ type: 'session_meta',
3815
+ payload: { id: `thread-${sid}`, cwd: wd },
3816
+ })}
3817
+ `);
3818
+ child = spawn(process.execPath, [
3819
+ watcherScript,
3820
+ '--cwd',
3821
+ wd,
3822
+ '--notify-script',
3823
+ notifyHook,
3824
+ '--poll-ms',
3825
+ '50',
3826
+ '--idle-max-poll-ms',
3827
+ '200',
3828
+ '--parent-pid',
3829
+ String(process.pid),
3830
+ '--max-lifetime-ms',
3831
+ '5000',
3832
+ ], {
3833
+ cwd: wd,
3834
+ stdio: 'ignore',
3835
+ env: buildCleanNotifyEnv({ HOME: tempHome, OMX_NOTIFY_FALLBACK_IDLE_MAX_POLL_MS: '200' }),
3836
+ });
3837
+ await waitFor(async () => {
3838
+ try {
3839
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
3840
+ return watcherState.adaptive_poll?.current_ms === 200 && watcherState.adaptive_poll?.idle_streak >= 2;
3841
+ }
3842
+ catch {
3843
+ return false;
3844
+ }
3845
+ }, 4000, 50);
3846
+ const freshTurnId = `turn-fresh-${sid}`;
3847
+ await appendLine(rolloutPath, {
3848
+ timestamp: new Date().toISOString(),
3849
+ type: 'event_msg',
3850
+ payload: {
3851
+ type: 'task_complete',
3852
+ turn_id: freshTurnId,
3853
+ last_agent_message: 'fresh message after idle backoff',
3854
+ },
3855
+ });
3856
+ await waitFor(async () => {
3857
+ const turnLines = await readLines(turnLogPath);
3858
+ if (!turnLines.some((line) => line.includes(freshTurnId)))
3859
+ return false;
3860
+ const watcherState = JSON.parse(await readFile(watcherStatePath, 'utf-8'));
3861
+ return watcherState.adaptive_poll?.current_ms === 50
3862
+ && watcherState.adaptive_poll?.idle_streak === 0
3863
+ && watcherState.adaptive_poll?.last_activity_reason === 'rollout_event';
3864
+ }, 4000, 50);
3865
+ }
3866
+ finally {
3867
+ if (child && isPidAlive(child.pid)) {
3868
+ child.kill('SIGTERM');
3869
+ await waitForExit(child, 4000).catch(() => { });
3870
+ }
3871
+ await rm(wd, { recursive: true, force: true });
3872
+ await rm(tempHome, { recursive: true, force: true });
3873
+ await rm(rolloutPath, { force: true });
3874
+ }
3875
+ });
3876
+ it('exits after the configured max lifetime', async () => {
3877
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-max-life-'));
3878
+ const tempHome = await mkdtemp(join(tmpdir(), 'omx-fallback-max-home-'));
3879
+ const watcherScript = new URL('../../../dist/scripts/notify-fallback-watcher.js', import.meta.url).pathname;
3880
+ const notifyHook = new URL('../../../dist/scripts/notify-hook.js', import.meta.url).pathname;
3881
+ const logPath = join(wd, '.omx', 'logs', `notify-fallback-${new Date().toISOString().split('T')[0]}.jsonl`);
3882
+ let child;
3883
+ try {
3884
+ child = spawn(process.execPath, [
3885
+ watcherScript,
3886
+ '--cwd',
3887
+ wd,
3888
+ '--notify-script',
3889
+ notifyHook,
3890
+ '--poll-ms',
3891
+ '50',
3892
+ '--parent-pid',
3893
+ String(process.pid),
3894
+ '--max-lifetime-ms',
3895
+ '200',
3896
+ ], {
3897
+ cwd: wd,
3898
+ stdio: 'ignore',
3899
+ env: buildCleanNotifyEnv({ HOME: tempHome }),
3900
+ });
3901
+ await waitForExit(child, 4000);
3902
+ assert.equal(child.exitCode, 0);
3903
+ const logEntries = (await readFile(logPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
3904
+ assert.ok(logEntries.some((entry) => (entry.type === 'watcher_stop' && entry.reason === 'max_lifetime_exceeded')));
3905
+ }
3906
+ finally {
3907
+ if (child && isPidAlive(child.pid)) {
3908
+ child.kill('SIGTERM');
3909
+ await waitForExit(child, 4000).catch(() => { });
3910
+ }
3911
+ await rm(wd, { recursive: true, force: true });
3912
+ await rm(tempHome, { recursive: true, force: true });
3913
+ }
3914
+ });
3915
+ it('keeps the detached helper alive after the hidden bootstrap exits', async () => {
3916
+ const wd = await mkdtemp(join(tmpdir(), 'omx-fallback-bootstrap-survival-'));
3917
+ const readyPath = join(wd, 'helper-ready.json');
3918
+ const helperScriptPath = join(wd, 'helper-survival.cjs');
3919
+ try {
3920
+ await writeFile(helperScriptPath, `
3921
+ const fs = require('node:fs');
3922
+ const readyPath = process.argv[2];
3923
+ fs.writeFileSync(readyPath, JSON.stringify({ pid: process.pid, started_at: new Date().toISOString() }));
3924
+ setInterval(() => {}, 1000);
3925
+ `);
3926
+ const bootstrap = spawnSync(process.execPath, [
3927
+ '-e',
3928
+ buildWindowsMsysBackgroundHelperBootstrapScript([helperScriptPath, readyPath], wd),
3929
+ ], {
3930
+ cwd: wd,
3931
+ encoding: 'utf-8',
3932
+ stdio: ['ignore', 'pipe', 'pipe'],
3933
+ windowsHide: true,
3934
+ });
3935
+ assert.equal(bootstrap.status, 0, bootstrap.stderr || bootstrap.stdout);
3936
+ const helperPid = Number.parseInt((bootstrap.stdout || '').trim(), 10);
3937
+ assert.ok(Number.isFinite(helperPid) && helperPid > 0, 'expected detached helper pid from bootstrap');
3938
+ await waitFor(async () => {
3939
+ try {
3940
+ const ready = JSON.parse(await readFile(readyPath, 'utf-8'));
3941
+ return ready.pid === helperPid;
3942
+ }
3943
+ catch {
3944
+ return false;
3945
+ }
3946
+ }, 4000, 50);
3947
+ assert.ok(isPidAlive(helperPid), 'expected detached helper to survive after bootstrap exit');
3948
+ process.kill(helperPid, 'SIGTERM');
3949
+ await waitFor(async () => !isPidAlive(helperPid), 4000, 50);
3950
+ }
3951
+ finally {
3952
+ await rm(wd, { recursive: true, force: true });
3953
+ }
3954
+ });
3955
+ });
3956
+ //# sourceMappingURL=notify-fallback-watcher.test.js.map