oh-my-codex 0.12.4 → 0.12.6

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 (475) hide show
  1. package/Cargo.lock +5 -5
  2. package/Cargo.toml +1 -1
  3. package/README.md +27 -3
  4. package/dist/cli/__tests__/ask.test.js +26 -0
  5. package/dist/cli/__tests__/ask.test.js.map +1 -1
  6. package/dist/cli/__tests__/doctor-warning-copy.test.js +28 -0
  7. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  8. package/dist/cli/__tests__/explore.test.js +95 -8
  9. package/dist/cli/__tests__/explore.test.js.map +1 -1
  10. package/dist/cli/__tests__/index.test.js +102 -4
  11. package/dist/cli/__tests__/index.test.js.map +1 -1
  12. package/dist/cli/__tests__/launch-fallback.test.js +169 -0
  13. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  14. package/dist/cli/__tests__/mcp-parity.test.js +31 -0
  15. package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
  16. package/dist/cli/__tests__/setup-agents-overwrite.test.js +66 -2
  17. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
  18. package/dist/cli/__tests__/setup-refresh.test.js +51 -1
  19. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  20. package/dist/cli/__tests__/team.test.js +148 -3
  21. package/dist/cli/__tests__/team.test.js.map +1 -1
  22. package/dist/cli/__tests__/uninstall.test.js +14 -1
  23. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  24. package/dist/cli/cleanup.js +1 -1
  25. package/dist/cli/cleanup.js.map +1 -1
  26. package/dist/cli/constants.d.ts +1 -0
  27. package/dist/cli/constants.d.ts.map +1 -1
  28. package/dist/cli/constants.js +1 -0
  29. package/dist/cli/constants.js.map +1 -1
  30. package/dist/cli/doctor.d.ts.map +1 -1
  31. package/dist/cli/doctor.js +15 -0
  32. package/dist/cli/doctor.js.map +1 -1
  33. package/dist/cli/explore.d.ts +1 -0
  34. package/dist/cli/explore.d.ts.map +1 -1
  35. package/dist/cli/explore.js +49 -1
  36. package/dist/cli/explore.js.map +1 -1
  37. package/dist/cli/index.d.ts +2 -1
  38. package/dist/cli/index.d.ts.map +1 -1
  39. package/dist/cli/index.js +127 -14
  40. package/dist/cli/index.js.map +1 -1
  41. package/dist/cli/mcp-parity.d.ts +1 -1
  42. package/dist/cli/mcp-parity.d.ts.map +1 -1
  43. package/dist/cli/mcp-parity.js +24 -0
  44. package/dist/cli/mcp-parity.js.map +1 -1
  45. package/dist/cli/setup.d.ts.map +1 -1
  46. package/dist/cli/setup.js +17 -5
  47. package/dist/cli/setup.js.map +1 -1
  48. package/dist/cli/team.d.ts.map +1 -1
  49. package/dist/cli/team.js +80 -6
  50. package/dist/cli/team.js.map +1 -1
  51. package/dist/cli/uninstall.d.ts.map +1 -1
  52. package/dist/cli/uninstall.js +1 -0
  53. package/dist/cli/uninstall.js.map +1 -1
  54. package/dist/config/__tests__/generator-idempotent.test.js +60 -0
  55. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  56. package/dist/config/__tests__/mcp-registry.test.js +61 -0
  57. package/dist/config/__tests__/mcp-registry.test.js.map +1 -1
  58. package/dist/config/__tests__/wiki-config-contract.test.d.ts +2 -0
  59. package/dist/config/__tests__/wiki-config-contract.test.d.ts.map +1 -0
  60. package/dist/config/__tests__/wiki-config-contract.test.js +19 -0
  61. package/dist/config/__tests__/wiki-config-contract.test.js.map +1 -0
  62. package/dist/config/generator.d.ts +1 -0
  63. package/dist/config/generator.d.ts.map +1 -1
  64. package/dist/config/generator.js +88 -3
  65. package/dist/config/generator.js.map +1 -1
  66. package/dist/config/mcp-registry.d.ts +2 -0
  67. package/dist/config/mcp-registry.d.ts.map +1 -1
  68. package/dist/config/mcp-registry.js +12 -0
  69. package/dist/config/mcp-registry.js.map +1 -1
  70. package/dist/hooks/__tests__/agents-overlay.test.js +39 -0
  71. package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
  72. package/dist/hooks/__tests__/keyword-detector.test.js +297 -4
  73. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  74. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +392 -22
  75. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  76. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +166 -67
  77. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  78. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +112 -2
  79. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
  80. package/dist/hooks/__tests__/notify-hook-modules.test.js +52 -12
  81. package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -1
  82. package/dist/hooks/__tests__/notify-hook-regression-205.test.d.ts +2 -3
  83. package/dist/hooks/__tests__/notify-hook-regression-205.test.d.ts.map +1 -1
  84. package/dist/hooks/__tests__/notify-hook-regression-205.test.js +18 -23
  85. package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
  86. package/dist/hooks/__tests__/notify-hook-session-scope.test.js +33 -0
  87. package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
  88. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +176 -1
  89. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
  90. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +355 -7
  91. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  92. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +90 -2
  93. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  94. package/dist/hooks/__tests__/session.test.js +142 -2
  95. package/dist/hooks/__tests__/session.test.js.map +1 -1
  96. package/dist/hooks/__tests__/wiki-docs-contract.test.d.ts +2 -0
  97. package/dist/hooks/__tests__/wiki-docs-contract.test.d.ts.map +1 -0
  98. package/dist/hooks/__tests__/wiki-docs-contract.test.js +34 -0
  99. package/dist/hooks/__tests__/wiki-docs-contract.test.js.map +1 -0
  100. package/dist/hooks/agents-overlay.d.ts.map +1 -1
  101. package/dist/hooks/agents-overlay.js +0 -1
  102. package/dist/hooks/agents-overlay.js.map +1 -1
  103. package/dist/hooks/extensibility/__tests__/dispatcher.test.js +32 -0
  104. package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +1 -1
  105. package/dist/hooks/extensibility/__tests__/runtime.test.js +31 -0
  106. package/dist/hooks/extensibility/__tests__/runtime.test.js.map +1 -1
  107. package/dist/hooks/extensibility/__tests__/sdk.test.js +33 -3
  108. package/dist/hooks/extensibility/__tests__/sdk.test.js.map +1 -1
  109. package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
  110. package/dist/hooks/extensibility/dispatcher.js +41 -0
  111. package/dist/hooks/extensibility/dispatcher.js.map +1 -1
  112. package/dist/hooks/extensibility/sdk/runtime-state.d.ts.map +1 -1
  113. package/dist/hooks/extensibility/sdk/runtime-state.js +7 -1
  114. package/dist/hooks/extensibility/sdk/runtime-state.js.map +1 -1
  115. package/dist/hooks/extensibility/types.d.ts +1 -0
  116. package/dist/hooks/extensibility/types.d.ts.map +1 -1
  117. package/dist/hooks/keyword-detector.d.ts +6 -1
  118. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  119. package/dist/hooks/keyword-detector.js +207 -10
  120. package/dist/hooks/keyword-detector.js.map +1 -1
  121. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  122. package/dist/hooks/keyword-registry.js +3 -0
  123. package/dist/hooks/keyword-registry.js.map +1 -1
  124. package/dist/hooks/session.d.ts +14 -2
  125. package/dist/hooks/session.d.ts.map +1 -1
  126. package/dist/hooks/session.js +120 -16
  127. package/dist/hooks/session.js.map +1 -1
  128. package/dist/hud/__tests__/state.test.js +111 -2
  129. package/dist/hud/__tests__/state.test.js.map +1 -1
  130. package/dist/hud/state.d.ts.map +1 -1
  131. package/dist/hud/state.js +18 -21
  132. package/dist/hud/state.js.map +1 -1
  133. package/dist/mcp/__tests__/bootstrap.test.js +88 -1
  134. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
  135. package/dist/mcp/__tests__/server-lifecycle.test.js +3 -0
  136. package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
  137. package/dist/mcp/__tests__/state-paths.test.js +30 -2
  138. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  139. package/dist/mcp/__tests__/state-server.test.js +415 -0
  140. package/dist/mcp/__tests__/state-server.test.js.map +1 -1
  141. package/dist/mcp/__tests__/wiki-server.test.d.ts +2 -0
  142. package/dist/mcp/__tests__/wiki-server.test.d.ts.map +1 -0
  143. package/dist/mcp/__tests__/wiki-server.test.js +30 -0
  144. package/dist/mcp/__tests__/wiki-server.test.js.map +1 -0
  145. package/dist/mcp/bootstrap.d.ts +19 -1
  146. package/dist/mcp/bootstrap.d.ts.map +1 -1
  147. package/dist/mcp/bootstrap.js +185 -0
  148. package/dist/mcp/bootstrap.js.map +1 -1
  149. package/dist/mcp/state-paths.d.ts +5 -0
  150. package/dist/mcp/state-paths.d.ts.map +1 -1
  151. package/dist/mcp/state-paths.js +41 -11
  152. package/dist/mcp/state-paths.js.map +1 -1
  153. package/dist/mcp/state-server.d.ts +4 -4
  154. package/dist/mcp/state-server.d.ts.map +1 -1
  155. package/dist/mcp/state-server.js +49 -2
  156. package/dist/mcp/state-server.js.map +1 -1
  157. package/dist/mcp/wiki-server.d.ts +181 -0
  158. package/dist/mcp/wiki-server.d.ts.map +1 -0
  159. package/dist/mcp/wiki-server.js +235 -0
  160. package/dist/mcp/wiki-server.js.map +1 -0
  161. package/dist/modes/__tests__/base-autoresearch-contract.test.js +74 -2
  162. package/dist/modes/__tests__/base-autoresearch-contract.test.js.map +1 -1
  163. package/dist/modes/__tests__/base-multi-state-compat.test.d.ts +2 -0
  164. package/dist/modes/__tests__/base-multi-state-compat.test.d.ts.map +1 -0
  165. package/dist/modes/__tests__/base-multi-state-compat.test.js +38 -0
  166. package/dist/modes/__tests__/base-multi-state-compat.test.js.map +1 -0
  167. package/dist/modes/__tests__/base-tmux-pane.test.js +1 -1
  168. package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
  169. package/dist/modes/base.d.ts +2 -1
  170. package/dist/modes/base.d.ts.map +1 -1
  171. package/dist/modes/base.js +55 -31
  172. package/dist/modes/base.js.map +1 -1
  173. package/dist/notifications/__tests__/formatter.test.js +11 -0
  174. package/dist/notifications/__tests__/formatter.test.js.map +1 -1
  175. package/dist/notifications/__tests__/idle-cooldown.test.js +32 -1
  176. package/dist/notifications/__tests__/idle-cooldown.test.js.map +1 -1
  177. package/dist/notifications/__tests__/index.test.d.ts +2 -0
  178. package/dist/notifications/__tests__/index.test.d.ts.map +1 -0
  179. package/dist/notifications/__tests__/index.test.js +113 -0
  180. package/dist/notifications/__tests__/index.test.js.map +1 -0
  181. package/dist/notifications/__tests__/lifecycle-dedupe.test.d.ts +2 -0
  182. package/dist/notifications/__tests__/lifecycle-dedupe.test.d.ts.map +1 -0
  183. package/dist/notifications/__tests__/lifecycle-dedupe.test.js +86 -0
  184. package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +1 -0
  185. package/dist/notifications/__tests__/reply-listener.test.js +174 -0
  186. package/dist/notifications/__tests__/reply-listener.test.js.map +1 -1
  187. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.d.ts +2 -0
  188. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.d.ts.map +1 -0
  189. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js +93 -0
  190. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js.map +1 -0
  191. package/dist/notifications/__tests__/session-registry.test.js +48 -1
  192. package/dist/notifications/__tests__/session-registry.test.js.map +1 -1
  193. package/dist/notifications/__tests__/session-status.test.d.ts +2 -0
  194. package/dist/notifications/__tests__/session-status.test.d.ts.map +1 -0
  195. package/dist/notifications/__tests__/session-status.test.js +159 -0
  196. package/dist/notifications/__tests__/session-status.test.js.map +1 -0
  197. package/dist/notifications/__tests__/tmux.test.js +58 -1
  198. package/dist/notifications/__tests__/tmux.test.js.map +1 -1
  199. package/dist/notifications/idle-cooldown.d.ts +11 -0
  200. package/dist/notifications/idle-cooldown.d.ts.map +1 -1
  201. package/dist/notifications/idle-cooldown.js +42 -8
  202. package/dist/notifications/idle-cooldown.js.map +1 -1
  203. package/dist/notifications/index.d.ts +1 -1
  204. package/dist/notifications/index.d.ts.map +1 -1
  205. package/dist/notifications/index.js +41 -8
  206. package/dist/notifications/index.js.map +1 -1
  207. package/dist/notifications/lifecycle-dedupe.d.ts +8 -0
  208. package/dist/notifications/lifecycle-dedupe.d.ts.map +1 -0
  209. package/dist/notifications/lifecycle-dedupe.js +112 -0
  210. package/dist/notifications/lifecycle-dedupe.js.map +1 -0
  211. package/dist/notifications/reply-listener.d.ts +10 -1
  212. package/dist/notifications/reply-listener.d.ts.map +1 -1
  213. package/dist/notifications/reply-listener.js +49 -11
  214. package/dist/notifications/reply-listener.js.map +1 -1
  215. package/dist/notifications/session-registry.d.ts.map +1 -1
  216. package/dist/notifications/session-registry.js +7 -1
  217. package/dist/notifications/session-registry.js.map +1 -1
  218. package/dist/notifications/session-status.d.ts +23 -0
  219. package/dist/notifications/session-status.d.ts.map +1 -0
  220. package/dist/notifications/session-status.js +187 -0
  221. package/dist/notifications/session-status.js.map +1 -0
  222. package/dist/notifications/tmux.d.ts +10 -0
  223. package/dist/notifications/tmux.d.ts.map +1 -1
  224. package/dist/notifications/tmux.js +59 -5
  225. package/dist/notifications/tmux.js.map +1 -1
  226. package/dist/notifications/types.d.ts +2 -0
  227. package/dist/notifications/types.d.ts.map +1 -1
  228. package/dist/openclaw/__tests__/index.test.js +84 -0
  229. package/dist/openclaw/__tests__/index.test.js.map +1 -1
  230. package/dist/openclaw/index.d.ts.map +1 -1
  231. package/dist/openclaw/index.js +7 -14
  232. package/dist/openclaw/index.js.map +1 -1
  233. package/dist/openclaw/types.d.ts +2 -2
  234. package/dist/openclaw/types.d.ts.map +1 -1
  235. package/dist/scripts/__tests__/codex-native-hook.test.js +692 -40
  236. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  237. package/dist/scripts/__tests__/hook-derived-watcher.test.d.ts +2 -0
  238. package/dist/scripts/__tests__/hook-derived-watcher.test.d.ts.map +1 -0
  239. package/dist/scripts/__tests__/hook-derived-watcher.test.js +87 -0
  240. package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +1 -0
  241. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  242. package/dist/scripts/codex-native-hook.js +309 -77
  243. package/dist/scripts/codex-native-hook.js.map +1 -1
  244. package/dist/scripts/hook-derived-watcher.js +43 -1
  245. package/dist/scripts/hook-derived-watcher.js.map +1 -1
  246. package/dist/scripts/notify-fallback-watcher.js +95 -21
  247. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  248. package/dist/scripts/notify-hook/active-team.d.ts +9 -0
  249. package/dist/scripts/notify-hook/active-team.d.ts.map +1 -0
  250. package/dist/scripts/notify-hook/active-team.js +44 -0
  251. package/dist/scripts/notify-hook/active-team.js.map +1 -0
  252. package/dist/scripts/notify-hook/auto-nudge.d.ts +5 -3
  253. package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
  254. package/dist/scripts/notify-hook/auto-nudge.js +121 -78
  255. package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
  256. package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
  257. package/dist/scripts/notify-hook/managed-tmux.js +18 -4
  258. package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
  259. package/dist/scripts/notify-hook/operational-events.d.ts.map +1 -1
  260. package/dist/scripts/notify-hook/operational-events.js +21 -0
  261. package/dist/scripts/notify-hook/operational-events.js.map +1 -1
  262. package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
  263. package/dist/scripts/notify-hook/ralph-session-resume.js +3 -2
  264. package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
  265. package/dist/scripts/notify-hook/state-io.d.ts +10 -1
  266. package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
  267. package/dist/scripts/notify-hook/state-io.js +56 -12
  268. package/dist/scripts/notify-hook/state-io.js.map +1 -1
  269. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
  270. package/dist/scripts/notify-hook/team-dispatch.js +305 -167
  271. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  272. package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
  273. package/dist/scripts/notify-hook/team-leader-nudge.js +87 -15
  274. package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
  275. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
  276. package/dist/scripts/notify-hook/tmux-injection.js +11 -2
  277. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  278. package/dist/scripts/notify-hook.js +26 -16
  279. package/dist/scripts/notify-hook.js.map +1 -1
  280. package/dist/scripts/run-provider-advisor.js +20 -2
  281. package/dist/scripts/run-provider-advisor.js.map +1 -1
  282. package/dist/scripts/smoke-packed-install.d.ts +1 -8
  283. package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
  284. package/dist/scripts/smoke-packed-install.js +12 -68
  285. package/dist/scripts/smoke-packed-install.js.map +1 -1
  286. package/dist/state/__tests__/operations.test.js +113 -0
  287. package/dist/state/__tests__/operations.test.js.map +1 -1
  288. package/dist/state/__tests__/skill-active.test.js +35 -0
  289. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  290. package/dist/state/__tests__/workflow-transition.test.d.ts +2 -0
  291. package/dist/state/__tests__/workflow-transition.test.d.ts.map +1 -0
  292. package/dist/state/__tests__/workflow-transition.test.js +56 -0
  293. package/dist/state/__tests__/workflow-transition.test.js.map +1 -0
  294. package/dist/state/operations.d.ts +1 -1
  295. package/dist/state/operations.d.ts.map +1 -1
  296. package/dist/state/operations.js +88 -2
  297. package/dist/state/operations.js.map +1 -1
  298. package/dist/state/skill-active.d.ts +2 -2
  299. package/dist/state/skill-active.d.ts.map +1 -1
  300. package/dist/state/skill-active.js +119 -33
  301. package/dist/state/skill-active.js.map +1 -1
  302. package/dist/state/workflow-transition-reconcile.d.ts +15 -0
  303. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -0
  304. package/dist/state/workflow-transition-reconcile.js +100 -0
  305. package/dist/state/workflow-transition-reconcile.js.map +1 -0
  306. package/dist/state/workflow-transition.d.ts +22 -0
  307. package/dist/state/workflow-transition.d.ts.map +1 -0
  308. package/dist/state/workflow-transition.js +188 -0
  309. package/dist/state/workflow-transition.js.map +1 -0
  310. package/dist/team/__tests__/api-interop.test.js +90 -0
  311. package/dist/team/__tests__/api-interop.test.js.map +1 -1
  312. package/dist/team/__tests__/current-task-baseline.test.d.ts +2 -0
  313. package/dist/team/__tests__/current-task-baseline.test.d.ts.map +1 -0
  314. package/dist/team/__tests__/current-task-baseline.test.js +87 -0
  315. package/dist/team/__tests__/current-task-baseline.test.js.map +1 -0
  316. package/dist/team/__tests__/hardening-e2e.test.js +17 -0
  317. package/dist/team/__tests__/hardening-e2e.test.js.map +1 -1
  318. package/dist/team/__tests__/runtime.test.js +673 -65
  319. package/dist/team/__tests__/runtime.test.js.map +1 -1
  320. package/dist/team/__tests__/shutdown-fallback.test.js +11 -1
  321. package/dist/team/__tests__/shutdown-fallback.test.js.map +1 -1
  322. package/dist/team/__tests__/tmux-session.test.js +447 -4
  323. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  324. package/dist/team/api-interop.d.ts.map +1 -1
  325. package/dist/team/api-interop.js +10 -1
  326. package/dist/team/api-interop.js.map +1 -1
  327. package/dist/team/current-task-baseline.d.ts +32 -0
  328. package/dist/team/current-task-baseline.d.ts.map +1 -0
  329. package/dist/team/current-task-baseline.js +85 -0
  330. package/dist/team/current-task-baseline.js.map +1 -0
  331. package/dist/team/delivery-log.d.ts +1 -1
  332. package/dist/team/delivery-log.d.ts.map +1 -1
  333. package/dist/team/delivery-log.js.map +1 -1
  334. package/dist/team/leader-activity.d.ts +1 -0
  335. package/dist/team/leader-activity.d.ts.map +1 -1
  336. package/dist/team/leader-activity.js +4 -2
  337. package/dist/team/leader-activity.js.map +1 -1
  338. package/dist/team/progress-evidence.d.ts +2 -0
  339. package/dist/team/progress-evidence.d.ts.map +1 -0
  340. package/dist/team/progress-evidence.js +77 -0
  341. package/dist/team/progress-evidence.js.map +1 -0
  342. package/dist/team/runtime.d.ts.map +1 -1
  343. package/dist/team/runtime.js +269 -64
  344. package/dist/team/runtime.js.map +1 -1
  345. package/dist/team/scaling.d.ts.map +1 -1
  346. package/dist/team/scaling.js +1 -1
  347. package/dist/team/scaling.js.map +1 -1
  348. package/dist/team/state.d.ts.map +1 -1
  349. package/dist/team/state.js +2 -13
  350. package/dist/team/state.js.map +1 -1
  351. package/dist/team/tmux-session.d.ts +12 -3
  352. package/dist/team/tmux-session.d.ts.map +1 -1
  353. package/dist/team/tmux-session.js +174 -20
  354. package/dist/team/tmux-session.js.map +1 -1
  355. package/dist/team/worktree.d.ts +6 -1
  356. package/dist/team/worktree.d.ts.map +1 -1
  357. package/dist/team/worktree.js +28 -4
  358. package/dist/team/worktree.js.map +1 -1
  359. package/dist/utils/__tests__/agents-md.test.js +21 -1
  360. package/dist/utils/__tests__/agents-md.test.js.map +1 -1
  361. package/dist/utils/__tests__/repo-deps.test.d.ts +2 -0
  362. package/dist/utils/__tests__/repo-deps.test.d.ts.map +1 -0
  363. package/dist/utils/__tests__/repo-deps.test.js +71 -0
  364. package/dist/utils/__tests__/repo-deps.test.js.map +1 -0
  365. package/dist/utils/agents-md.d.ts +1 -0
  366. package/dist/utils/agents-md.d.ts.map +1 -1
  367. package/dist/utils/agents-md.js +7 -3
  368. package/dist/utils/agents-md.js.map +1 -1
  369. package/dist/utils/paths.d.ts +4 -0
  370. package/dist/utils/paths.d.ts.map +1 -1
  371. package/dist/utils/paths.js +20 -0
  372. package/dist/utils/paths.js.map +1 -1
  373. package/dist/utils/repo-deps.d.ts +20 -0
  374. package/dist/utils/repo-deps.d.ts.map +1 -0
  375. package/dist/utils/repo-deps.js +78 -0
  376. package/dist/utils/repo-deps.js.map +1 -0
  377. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.d.ts +2 -0
  378. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.d.ts.map +1 -0
  379. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +54 -0
  380. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -0
  381. package/dist/wiki/__tests__/cjk-tokenize.test.d.ts +12 -0
  382. package/dist/wiki/__tests__/cjk-tokenize.test.d.ts.map +1 -0
  383. package/dist/wiki/__tests__/cjk-tokenize.test.js +139 -0
  384. package/dist/wiki/__tests__/cjk-tokenize.test.js.map +1 -0
  385. package/dist/wiki/__tests__/crlf-parse.test.d.ts +2 -0
  386. package/dist/wiki/__tests__/crlf-parse.test.d.ts.map +1 -0
  387. package/dist/wiki/__tests__/crlf-parse.test.js +24 -0
  388. package/dist/wiki/__tests__/crlf-parse.test.js.map +1 -0
  389. package/dist/wiki/__tests__/escape-newline.test.d.ts +2 -0
  390. package/dist/wiki/__tests__/escape-newline.test.d.ts.map +1 -0
  391. package/dist/wiki/__tests__/escape-newline.test.js +45 -0
  392. package/dist/wiki/__tests__/escape-newline.test.js.map +1 -0
  393. package/dist/wiki/__tests__/ingest.test.d.ts +5 -0
  394. package/dist/wiki/__tests__/ingest.test.d.ts.map +1 -0
  395. package/dist/wiki/__tests__/ingest.test.js +181 -0
  396. package/dist/wiki/__tests__/ingest.test.js.map +1 -0
  397. package/dist/wiki/__tests__/lint.test.d.ts +5 -0
  398. package/dist/wiki/__tests__/lint.test.d.ts.map +1 -0
  399. package/dist/wiki/__tests__/lint.test.js +163 -0
  400. package/dist/wiki/__tests__/lint.test.js.map +1 -0
  401. package/dist/wiki/__tests__/query.test.d.ts +5 -0
  402. package/dist/wiki/__tests__/query.test.d.ts.map +1 -0
  403. package/dist/wiki/__tests__/query.test.js +141 -0
  404. package/dist/wiki/__tests__/query.test.js.map +1 -0
  405. package/dist/wiki/__tests__/reserved-file-guard.test.d.ts +2 -0
  406. package/dist/wiki/__tests__/reserved-file-guard.test.d.ts.map +1 -0
  407. package/dist/wiki/__tests__/reserved-file-guard.test.js +44 -0
  408. package/dist/wiki/__tests__/reserved-file-guard.test.js.map +1 -0
  409. package/dist/wiki/__tests__/session-hooks.test.d.ts +5 -0
  410. package/dist/wiki/__tests__/session-hooks.test.d.ts.map +1 -0
  411. package/dist/wiki/__tests__/session-hooks.test.js +36 -0
  412. package/dist/wiki/__tests__/session-hooks.test.js.map +1 -0
  413. package/dist/wiki/__tests__/slug-nonascii.test.d.ts +2 -0
  414. package/dist/wiki/__tests__/slug-nonascii.test.d.ts.map +1 -0
  415. package/dist/wiki/__tests__/slug-nonascii.test.js +24 -0
  416. package/dist/wiki/__tests__/slug-nonascii.test.js.map +1 -0
  417. package/dist/wiki/__tests__/storage.test.d.ts +5 -0
  418. package/dist/wiki/__tests__/storage.test.d.ts.map +1 -0
  419. package/dist/wiki/__tests__/storage.test.js +278 -0
  420. package/dist/wiki/__tests__/storage.test.js.map +1 -0
  421. package/dist/wiki/__tests__/test-helpers.d.ts +31 -0
  422. package/dist/wiki/__tests__/test-helpers.d.ts.map +1 -0
  423. package/dist/wiki/__tests__/test-helpers.js +108 -0
  424. package/dist/wiki/__tests__/test-helpers.js.map +1 -0
  425. package/dist/wiki/index.d.ts +14 -0
  426. package/dist/wiki/index.d.ts.map +1 -0
  427. package/dist/wiki/index.js +17 -0
  428. package/dist/wiki/index.js.map +1 -0
  429. package/dist/wiki/ingest.d.ts +20 -0
  430. package/dist/wiki/ingest.d.ts.map +1 -0
  431. package/dist/wiki/ingest.js +115 -0
  432. package/dist/wiki/ingest.js.map +1 -0
  433. package/dist/wiki/lifecycle.d.ts +20 -0
  434. package/dist/wiki/lifecycle.d.ts.map +1 -0
  435. package/dist/wiki/lifecycle.js +212 -0
  436. package/dist/wiki/lifecycle.js.map +1 -0
  437. package/dist/wiki/lint.d.ts +25 -0
  438. package/dist/wiki/lint.d.ts.map +1 -0
  439. package/dist/wiki/lint.js +166 -0
  440. package/dist/wiki/lint.js.map +1 -0
  441. package/dist/wiki/query.d.ts +36 -0
  442. package/dist/wiki/query.d.ts.map +1 -0
  443. package/dist/wiki/query.js +138 -0
  444. package/dist/wiki/query.js.map +1 -0
  445. package/dist/wiki/storage.d.ts +33 -0
  446. package/dist/wiki/storage.d.ts.map +1 -0
  447. package/dist/wiki/storage.js +321 -0
  448. package/dist/wiki/storage.js.map +1 -0
  449. package/dist/wiki/types.d.ts +83 -0
  450. package/dist/wiki/types.d.ts.map +1 -0
  451. package/dist/wiki/types.js +15 -0
  452. package/dist/wiki/types.js.map +1 -0
  453. package/package.json +3 -1
  454. package/skills/configure-notifications/SKILL.md +1 -0
  455. package/skills/doctor/SKILL.md +11 -0
  456. package/skills/omx-setup/SKILL.md +1 -1
  457. package/skills/wiki/SKILL.md +57 -0
  458. package/src/scripts/__tests__/codex-native-hook.test.ts +920 -56
  459. package/src/scripts/__tests__/hook-derived-watcher.test.ts +111 -0
  460. package/src/scripts/codex-native-hook.ts +377 -83
  461. package/src/scripts/hook-derived-watcher.ts +43 -1
  462. package/src/scripts/notify-fallback-watcher.ts +99 -20
  463. package/src/scripts/notify-hook/active-team.ts +54 -0
  464. package/src/scripts/notify-hook/auto-nudge.ts +132 -79
  465. package/src/scripts/notify-hook/managed-tmux.ts +22 -4
  466. package/src/scripts/notify-hook/operational-events.ts +21 -0
  467. package/src/scripts/notify-hook/ralph-session-resume.ts +3 -2
  468. package/src/scripts/notify-hook/state-io.ts +89 -12
  469. package/src/scripts/notify-hook/team-dispatch.ts +326 -168
  470. package/src/scripts/notify-hook/team-leader-nudge.ts +91 -14
  471. package/src/scripts/notify-hook/tmux-injection.ts +11 -2
  472. package/src/scripts/notify-hook.ts +36 -22
  473. package/src/scripts/run-provider-advisor.ts +20 -2
  474. package/src/scripts/smoke-packed-install.ts +16 -83
  475. package/templates/AGENTS.md +3 -4
@@ -5,13 +5,15 @@
5
5
 
6
6
  import { readFile, writeFile, mkdir, appendFile, readdir } from 'fs/promises';
7
7
  import { existsSync } from 'fs';
8
- import { join } from 'path';
8
+ import { join, resolve } from 'path';
9
+ import { readUsableSessionState } from '../../hooks/session.js';
9
10
  import { asNumber, safeString, isTerminalPhase } from './utils.js';
10
11
  import { readJsonIfExists, getScopedStateDirsForCurrentSession } from './state-io.js';
11
12
  import { runProcess } from './process-runner.js';
12
13
  import { logTmuxHookEvent } from './log.js';
13
14
  import { evaluatePaneInjectionReadiness, sendPaneInput } from './team-tmux-guard.js';
14
15
  import { resolvePaneTarget } from './tmux-injection.js';
16
+ import { listNotifyCanonicalActiveTeams } from './active-team.js';
15
17
  import {
16
18
  classifyLeaderActionState,
17
19
  resolveLeaderNudgeIntent,
@@ -20,8 +22,10 @@ import { DEFAULT_MARKER } from '../tmux-hook-engine.js';
20
22
  import { isLeaderRuntimeStale } from '../../team/leader-activity.js';
21
23
  import { appendTeamDeliveryLog } from '../../team/delivery-log.js';
22
24
  import { writeTeamLeaderAttention } from '../../team/state.js';
25
+ import { readLatestTeamProgressEvidenceMs } from '../../team/progress-evidence.js';
23
26
  const LEADER_PANE_MISSING_NO_INJECTION_REASON = 'leader_pane_missing_no_injection';
24
27
  const LEADER_PANE_SHELL_NO_INJECTION_REASON = 'leader_pane_shell_no_injection';
28
+ const LEADER_PANE_SAME_CLASSIFIED_STATE_SUPPRESSED_REASON = 'pane_already_shows_same_classified_state';
25
29
  const LEADER_NOTIFICATION_DEFERRED_TYPE = 'leader_notification_deferred';
26
30
  const ACK_WITHOUT_START_EVIDENCE_REASON = 'ack_without_start_evidence';
27
31
  const ACK_LIKE_PATTERNS = [
@@ -248,16 +252,7 @@ async function resolveCurrentSessionId(stateDir) {
248
252
  || '',
249
253
  ).trim();
250
254
  if (fromEnv) return fromEnv;
251
-
252
- const sessionPath = join(stateDir, 'session.json');
253
- try {
254
- if (!existsSync(sessionPath)) return '';
255
- const parsed = JSON.parse(await readFile(sessionPath, 'utf-8'));
256
- const sessionId = safeString(parsed && parsed.session_id ? parsed.session_id : '').trim();
257
- return sessionId;
258
- } catch {
259
- return '';
260
- }
255
+ return safeString((await readUsableSessionState(resolve(stateDir, '..', '..')))?.session_id).trim();
261
256
  }
262
257
 
263
258
  async function readWorkerStatusSnapshot(stateDir, teamName, workerName) {
@@ -445,6 +440,27 @@ function formatMailboxBodyForLeader(body, maxLength = 40) {
445
440
  return `${normalized.slice(0, maxLength - 1)}…`;
446
441
  }
447
442
 
443
+ function normalizeVisibleLeaderStateText(text) {
444
+ return safeString(text)
445
+ .toLowerCase()
446
+ .replace(/\[omx_tmux_inject\]/g, ' ')
447
+ .replace(/\[omx_intent:[^\]]+\]/g, ' ')
448
+ .replace(/said\s+"[^"]*"/g, 'said "<content>"')
449
+ .replace(/said\s+'[^']*'/g, 'said "<content>"')
450
+ .replace(/\b\d+[smhd](?:\s+\d+[smhd])*\b/g, '<duration>')
451
+ .replace(/\b\d+\b/g, '<n>')
452
+ .replace(/\s+/g, ' ')
453
+ .trim();
454
+ }
455
+
456
+ function paneAlreadyShowsVisibleLeaderState(paneCapture, visibleText) {
457
+ const normalizedVisibleText = normalizeVisibleLeaderStateText(visibleText);
458
+ if (!normalizedVisibleText) return false;
459
+ const normalizedPaneCapture = normalizeVisibleLeaderStateText(paneCapture);
460
+ if (!normalizedPaneCapture) return false;
461
+ return normalizedPaneCapture.includes(normalizedVisibleText);
462
+ }
463
+
448
464
  async function workerHasOwnedStartedTask(stateDir, teamName, workerName) {
449
465
  const tasksDir = join(stateDir, 'team', teamName, 'tasks');
450
466
  if (!existsSync(tasksDir)) return false;
@@ -601,6 +617,11 @@ export async function maybeNudgeTeamLeader({
601
617
  // Non-critical
602
618
  }
603
619
 
620
+ const canonicalFallbackTeams = await listNotifyCanonicalActiveTeams(cwd, currentSessionId).catch(() => []);
621
+ for (const team of canonicalFallbackTeams) {
622
+ candidateTeamNames.add(team.teamName);
623
+ }
624
+
604
625
  // Use pre-computed staleness (captured before HUD state was updated this turn)
605
626
  const leaderStale = typeof preComputedLeaderStale === 'boolean' ? preComputedLeaderStale : false;
606
627
 
@@ -676,11 +697,15 @@ export async function maybeNudgeTeamLeader({
676
697
  const workerTurnProgress = hasWorkerTurnProgress(progressSnapshot.workerSnapshot, previousTurnCounts);
677
698
  const hasTrackableTurnSignals = hasTrackableActiveWorkerTurns(progressSnapshot.workerSnapshot, previousTurnCounts);
678
699
  const progressChanged = !previousSignature || previousSignature !== progressSnapshot.signature || workerTurnProgress;
700
+ const extraProgressEvidenceMs = await readLatestTeamProgressEvidenceMs(cwd, teamName).catch(() => Number.NaN);
679
701
  const effectiveProgressAtMs = progressChanged || !Number.isFinite(previousProgressAtMs)
680
702
  ? nowMs
681
703
  : previousProgressAtMs;
682
- const effectiveProgressAtIso = new Date(effectiveProgressAtMs).toISOString();
683
- const stalledForMs = Math.max(0, nowMs - effectiveProgressAtMs);
704
+ const latestProgressEvidenceMs = Number.isFinite(extraProgressEvidenceMs)
705
+ ? Math.max(effectiveProgressAtMs, extraProgressEvidenceMs)
706
+ : effectiveProgressAtMs;
707
+ const effectiveProgressAtIso = new Date(latestProgressEvidenceMs).toISOString();
708
+ const stalledForMs = Math.max(0, nowMs - latestProgressEvidenceMs);
684
709
  const stallThresholdMs = hasTrackableTurnSignals ? workerTurnStallThresholdMs : fallbackProgressStallThresholdMs;
685
710
  const teamProgressStalled =
686
711
  progressSnapshot.workRemaining
@@ -688,6 +713,9 @@ export async function maybeNudgeTeamLeader({
688
713
  && !allWorkersIdle
689
714
  && !progressChanged
690
715
  && stalledForMs >= stallThresholdMs;
716
+ const hasFreshProgressEvidence =
717
+ progressSnapshot.workRemaining
718
+ && stalledForMs < stallThresholdMs;
691
719
  const leaderActionState = classifyLeaderActionState({
692
720
  allWorkersIdle,
693
721
  workerPanesAlive: paneStatus.alive,
@@ -724,7 +752,7 @@ export async function maybeNudgeTeamLeader({
724
752
 
725
753
  // Stale-leader follow-up is the only periodic visible nudge path.
726
754
  // This keeps the leader pane quieter when the leader is not actually stale.
727
- const stalePanesNudge = paneStatus.alive && leaderStale;
755
+ const stalePanesNudge = paneStatus.alive && leaderStale && !hasFreshProgressEvidence;
728
756
  const previousStalledTeamNudge = prevReason === 'stuck_waiting_on_leader';
729
757
  const stalledTeamNudge = teamProgressStalled && (dueByTime || !previousStalledTeamNudge);
730
758
  const staleFollowupDue = stalePanesNudge && dueByTime;
@@ -925,6 +953,55 @@ export async function maybeNudgeTeamLeader({
925
953
  continue;
926
954
  }
927
955
 
956
+ if (paneAlreadyShowsVisibleLeaderState(paneGuard.paneCapture, capped)) {
957
+ nudgeState.last_nudged_by_team[teamName] = {
958
+ at: nowIso,
959
+ last_message_id: newestId || prevMsgId || '',
960
+ reason: nudgeReason,
961
+ orchestration_intent: orchestrationIntent,
962
+ };
963
+ if (shouldSendAllIdleNudge) {
964
+ nudgeState.last_idle_nudged_by_team[teamName] = {
965
+ at: nowIso,
966
+ worker_count: workerNames.length,
967
+ orchestration_intent: orchestrationIntent,
968
+ };
969
+ }
970
+
971
+ await emitTeamNudgeEvent(cwd, teamName, nudgeReason, orchestrationIntent, nowIso);
972
+
973
+ try {
974
+ await logTmuxHookEvent(logsDir, {
975
+ timestamp: nowIso,
976
+ type: 'team_leader_nudge',
977
+ team: teamName,
978
+ tmux_target: tmuxTarget,
979
+ reason: nudgeReason,
980
+ orchestration_intent: orchestrationIntent,
981
+ pane_count: paneStatus.paneCount,
982
+ leader_stale: leaderStale,
983
+ message_count: messages.length,
984
+ stalled_for_ms: teamProgressStalled ? stalledForMs : undefined,
985
+ missing_signal_workers: progressSnapshot.missingSignalWorkers,
986
+ visible_injection_suppressed: true,
987
+ suppression_reason: LEADER_PANE_SAME_CLASSIFIED_STATE_SUPPRESSED_REASON,
988
+ });
989
+ } catch { /* ignore */ }
990
+ await appendTeamDeliveryLog(logsDir, {
991
+ event: 'nudge_triggered',
992
+ source,
993
+ team: teamName,
994
+ to_worker: 'leader-fixed',
995
+ transport: 'send-keys',
996
+ result: 'suppressed',
997
+ reason: nudgeReason,
998
+ orchestration_intent: orchestrationIntent,
999
+ visible_injection_suppressed: true,
1000
+ suppression_reason: LEADER_PANE_SAME_CLASSIFIED_STATE_SUPPRESSED_REASON,
1001
+ }).catch(() => {});
1002
+ continue;
1003
+ }
1004
+
928
1005
  try {
929
1006
  const sendResult = await sendPaneInput({
930
1007
  paneTarget: tmuxTarget,
@@ -8,6 +8,7 @@ import { readFile, writeFile } from 'fs/promises';
8
8
  import { existsSync } from 'fs';
9
9
  import { join, resolve as resolvePath } from 'path';
10
10
  import { safeString, asNumber } from './utils.js';
11
+ import { sameFilePath } from '../../utils/paths.js';
11
12
  import {
12
13
  readJsonIfExists,
13
14
  normalizeTmuxState,
@@ -35,7 +36,7 @@ async function resolvePaneCwdMismatch(paneId: string, expectedCwd: any): Promise
35
36
  try {
36
37
  const paneCwdResult = await runProcess('tmux', ['display-message', '-p', '-t', paneId, '#{pane_current_path}']);
37
38
  const paneCwd = safeString(paneCwdResult.stdout).trim();
38
- if (paneCwd && resolvePath(paneCwd) !== resolvePath(expectedCwd)) {
39
+ if (paneCwd && !sameFilePath(paneCwd, expectedCwd)) {
39
40
  return {
40
41
  paneTarget: null,
41
42
  reason: 'pane_cwd_mismatch',
@@ -210,7 +211,15 @@ export async function resolvePaneTarget(target: any, expectedCwd: any, modePane:
210
211
  const expectedSessionTarget = safeString(managedContext.expectedTmuxSessionName).trim();
211
212
  const sessionIdTarget = safeString(managedContext.invocationSessionId).trim();
212
213
  const stateSessionTarget = safeString(managedContext.sessionState?.session_id).trim();
213
- const allowedSessionTargets = new Set([expectedSessionTarget, sessionIdTarget, stateSessionTarget].filter(Boolean));
214
+ const nativeSessionTarget = safeString(managedContext.nativeSessionId).trim();
215
+ const canonicalSessionTarget = safeString(managedContext.canonicalSessionId).trim();
216
+ const allowedSessionTargets = new Set([
217
+ expectedSessionTarget,
218
+ sessionIdTarget,
219
+ stateSessionTarget,
220
+ nativeSessionTarget,
221
+ canonicalSessionTarget,
222
+ ].filter(Boolean));
214
223
  if (!allowedSessionTargets.has(explicitSessionTarget)) {
215
224
  return { paneTarget: null, reason: 'target_session_not_managed' };
216
225
  }
@@ -20,7 +20,7 @@
20
20
 
21
21
  import { writeFile, appendFile, mkdir, readFile } from 'fs/promises';
22
22
  import { existsSync } from 'fs';
23
- import { join } from 'path';
23
+ import { dirname, join } from 'path';
24
24
 
25
25
  import { safeString, asNumber } from './notify-hook/utils.js';
26
26
  import {
@@ -29,7 +29,9 @@ import {
29
29
  normalizeInputMessages,
30
30
  } from './notify-hook/payload-parser.js';
31
31
  import {
32
- readJsonIfExists,
32
+ getScopedStatePath,
33
+ readCurrentSessionId,
34
+ readScopedJsonIfExists,
33
35
  getScopedStateDirsForCurrentSession,
34
36
  normalizeNotifyState,
35
37
  pruneRecentTurns,
@@ -181,10 +183,12 @@ async function main() {
181
183
  const logsDir = join(cwd, '.omx', 'logs');
182
184
  const omxDir = join(cwd, '.omx');
183
185
  let currentOmxSessionId = '';
186
+ const getEffectiveSessionId = () => currentOmxSessionId || payloadSessionId;
184
187
 
185
188
  // Ensure directories exist
186
189
  await mkdir(logsDir, { recursive: true }).catch(() => {});
187
190
  await mkdir(stateDir, { recursive: true }).catch(() => {});
191
+ currentOmxSessionId = await readCurrentSessionId(stateDir).catch(() => '') || '';
188
192
 
189
193
  // Turn-level dedupe prevents double-processing when native notify and fallback
190
194
  // watcher both emit the same completed turn.
@@ -195,14 +199,18 @@ async function main() {
195
199
  const threadId = safeString(payload['thread-id'] || payload.thread_id || '');
196
200
  const eventType = safeString(payload.type || 'agent-turn-complete');
197
201
  const key = `${threadId || 'no-thread'}|${turnId}|${eventType}`;
198
- const dedupeStatePath = join(stateDir, 'notify-hook-state.json');
199
- const dedupeState = normalizeNotifyState(await readJsonIfExists(dedupeStatePath, null));
202
+ const dedupeSessionId = getEffectiveSessionId();
203
+ const dedupeStatePath = await getScopedStatePath(stateDir, 'notify-hook-state.json', dedupeSessionId);
204
+ const dedupeState = normalizeNotifyState(
205
+ await readScopedJsonIfExists(stateDir, 'notify-hook-state.json', dedupeSessionId, null),
206
+ );
200
207
  dedupeState.recent_turns = pruneRecentTurns(dedupeState.recent_turns, now);
201
208
  if (dedupeState.recent_turns[key]) {
202
209
  process.exit(0);
203
210
  }
204
211
  dedupeState.recent_turns[key] = now;
205
212
  dedupeState.last_event_at = new Date().toISOString();
213
+ await mkdir(dirname(dedupeStatePath), { recursive: true }).catch(() => {});
206
214
  await writeFile(dedupeStatePath, JSON.stringify(dedupeState, null, 2)).catch(() => {});
207
215
  }
208
216
  } catch {
@@ -214,10 +222,10 @@ async function main() {
214
222
  try {
215
223
  const threadId = safeString(payload['thread-id'] || payload.thread_id || '');
216
224
  const turnId = safeString(payload['turn-id'] || payload.turn_id || '');
217
- if (payloadSessionId && threadId) {
225
+ if (getEffectiveSessionId() && threadId) {
218
226
  const { recordSubagentTurnForSession } = await import('../subagents/tracker.js');
219
227
  await recordSubagentTurnForSession(cwd, {
220
- sessionId: payloadSessionId,
228
+ sessionId: getEffectiveSessionId(),
221
229
  threadId,
222
230
  ...(turnId ? { turnId } : {}),
223
231
  timestamp: new Date().toISOString(),
@@ -417,18 +425,20 @@ async function main() {
417
425
 
418
426
  // 4. Write HUD state summary for `omx hud` (lead session only)
419
427
  if (!isTeamWorker) {
420
- const hudStatePath = join(stateDir, 'hud-state.json');
421
428
  try {
422
- let hudState = { last_turn_at: '', turn_count: 0 };
423
- if (existsSync(hudStatePath)) {
424
- hudState = JSON.parse(await readFile(hudStatePath, 'utf-8'));
425
- }
429
+ const scopedSessionId = getEffectiveSessionId();
430
+ const hudStatePath = await getScopedStatePath(stateDir, 'hud-state.json', scopedSessionId);
431
+ let hudState = await readScopedJsonIfExists(stateDir, 'hud-state.json', scopedSessionId, {
432
+ last_turn_at: '',
433
+ turn_count: 0,
434
+ });
426
435
  const nowIso = new Date().toISOString();
427
436
  hudState.last_turn_at = nowIso;
428
437
  (hudState as any).last_progress_at = nowIso;
429
438
  hudState.turn_count = (hudState.turn_count || 0) + 1;
430
439
  (hudState as any).last_agent_output = (payload['last-assistant-message'] || payload.last_assistant_message || '')
431
440
  .slice(0, 100);
441
+ await mkdir(dirname(hudStatePath), { recursive: true }).catch(() => {});
432
442
  await writeFile(hudStatePath, JSON.stringify(hudState, null, 2));
433
443
  } catch {
434
444
  // Non-critical
@@ -451,19 +461,19 @@ async function main() {
451
461
  try {
452
462
  const { recordSkillActivation } = await import('../hooks/keyword-detector.js');
453
463
  if (latestUserInput) {
454
- await recordSkillActivation({
455
- stateDir,
456
- text: latestUserInput,
457
- sessionId: payloadSessionId,
458
- threadId: payloadThreadId,
459
- turnId: safeString(payload['turn-id'] || payload.turn_id || ''),
460
- });
464
+ await recordSkillActivation({
465
+ stateDir,
466
+ text: latestUserInput,
467
+ sessionId: getEffectiveSessionId(),
468
+ threadId: payloadThreadId,
469
+ turnId: safeString(payload['turn-id'] || payload.turn_id || ''),
470
+ });
461
471
  }
462
472
  } catch {
463
473
  // Non-fatal: keyword detector module may not be built yet
464
474
  }
465
475
 
466
- const deepInterviewStateActive = await isDeepInterviewStateActive(stateDir);
476
+ const deepInterviewStateActive = await isDeepInterviewStateActive(stateDir, getEffectiveSessionId());
467
477
 
468
478
  // 4.55. Notify leader when individual worker transitions to idle (worker session only)
469
479
  if (isTeamWorker && parsedTeamWorker && !deepInterviewStateActive) {
@@ -515,7 +525,7 @@ async function main() {
515
525
  try {
516
526
  const { buildNativeHookEvent, buildDerivedHookEvent } = await import('../hooks/extensibility/events.js');
517
527
  const { dispatchHookEvent } = await import('../hooks/extensibility/dispatcher.js');
518
- const sessionIdForHooks = safeString(payload.session_id || payload['session-id'] || '');
528
+ const sessionIdForHooks = getEffectiveSessionId();
519
529
  const threadIdForHooks = safeString(payload['thread-id'] || payload.thread_id || '');
520
530
  const turnIdForHooks = safeString(payload['turn-id'] || payload.turn_id || '');
521
531
  const modeForHooks = safeString(payload.mode || '');
@@ -525,6 +535,8 @@ async function main() {
525
535
  type: safeString(payload.type || 'agent-turn-complete'),
526
536
  input_messages: normalizeInputMessages(payload),
527
537
  output_preview: outputPreview,
538
+ native_session_id: payloadSessionId || null,
539
+ omx_session_id: sessionIdForHooks || null,
528
540
  ...readRepositoryMetadata(cwd),
529
541
  session_name: resolveOperationalSessionName(cwd, sessionIdForHooks),
530
542
  project_path: cwd,
@@ -546,6 +558,8 @@ async function main() {
546
558
  status: signal.normalized_event,
547
559
  errorSummary: signal.error_summary,
548
560
  extra: {
561
+ native_session_id: payloadSessionId || null,
562
+ omx_session_id: sessionIdForHooks || null,
549
563
  source_event: safeString(payload.type || 'agent-turn-complete'),
550
564
  },
551
565
  }), {
@@ -650,7 +664,7 @@ async function main() {
650
664
  payload,
651
665
  stateDir,
652
666
  logsDir,
653
- sessionId: currentOmxSessionId || payloadSessionId,
667
+ sessionId: getEffectiveSessionId(),
654
668
  turnId: safeString(payload['turn-id'] || payload.turn_id || ''),
655
669
  });
656
670
  } catch (err) {
@@ -660,7 +674,7 @@ async function main() {
660
674
  level: 'warn',
661
675
  type: 'visual_verdict_import_failure',
662
676
  error: (err as any)?.message || String(err),
663
- session_id: payloadSessionId,
677
+ session_id: getEffectiveSessionId(),
664
678
  turn_id: safeString(payload['turn-id'] || payload.turn_id || ''),
665
679
  });
666
680
  const warnFile = join(logsDir, `notify-hook-${new Date().toISOString().split('T')[0]}.jsonl`);
@@ -3,12 +3,18 @@ import { mkdir, writeFile } from 'fs/promises';
3
3
  import { join } from 'path';
4
4
  import process from 'process';
5
5
  import { spawnSync } from 'child_process';
6
+ import { CLAUDE_SKIP_PERMISSIONS_FLAG } from '../cli/constants.js';
6
7
 
7
8
  const PROVIDER_BINARIES: Record<string, string> = {
8
9
  claude: 'claude',
9
10
  gemini: 'gemini',
10
11
  };
11
12
  const ASK_ORIGINAL_TASK_ENV = 'OMX_ASK_ORIGINAL_TASK';
13
+ const ISSUE_WORK_PROMPT_PATTERNS = [
14
+ /\bgh\s+issue\b/i,
15
+ /\b(?:fix|work on|work|investigate|implement|triage|debug|review|handle)\s+issue\s*#?\d+\b/i,
16
+ /\bissue\s*#\d+\b/i,
17
+ ];
12
18
 
13
19
  function usage(): void {
14
20
  console.error('Usage: omx ask <claude|gemini> "<prompt>"');
@@ -70,6 +76,13 @@ function ensureBinary(binary: string): void {
70
76
  }
71
77
  }
72
78
 
79
+ function shouldUseClaudeIssuePermissionsBypass(provider: string, prompt: string): boolean {
80
+ if (provider !== 'claude') return false;
81
+ const trimmed = prompt.trim();
82
+ if (trimmed === '') return false;
83
+ return ISSUE_WORK_PROMPT_PATTERNS.some((pattern) => pattern.test(trimmed));
84
+ }
85
+
73
86
  function buildSummary(exitCode: number, output: string): string {
74
87
  if (exitCode === 0) {
75
88
  return 'Provider completed successfully. Review the raw output for details.';
@@ -148,10 +161,15 @@ async function writeArtifact({ provider, originalTask, finalPrompt, rawOutput, e
148
161
  async function main(): Promise<void> {
149
162
  const { provider, prompt } = parseArgs(process.argv.slice(2));
150
163
  const binary = PROVIDER_BINARIES[provider];
164
+ const originalTask = process.env[ASK_ORIGINAL_TASK_ENV] ?? prompt;
151
165
 
152
166
  ensureBinary(binary);
153
167
 
154
- const run = spawnSync(binary, ['-p', prompt], {
168
+ const launchArgs = shouldUseClaudeIssuePermissionsBypass(provider, originalTask)
169
+ ? [CLAUDE_SKIP_PERMISSIONS_FLAG, '-p', prompt]
170
+ : ['-p', prompt];
171
+
172
+ const run = spawnSync(binary, launchArgs, {
155
173
  encoding: 'utf8',
156
174
  maxBuffer: 10 * 1024 * 1024,
157
175
  windowsHide: true,
@@ -164,7 +182,7 @@ async function main(): Promise<void> {
164
182
 
165
183
  const artifactPath = await writeArtifact({
166
184
  provider,
167
- originalTask: process.env[ASK_ORIGINAL_TASK_ENV] ?? prompt,
185
+ originalTask,
168
186
  finalPrompt: prompt,
169
187
  rawOutput,
170
188
  exitCode,
@@ -1,22 +1,21 @@
1
1
  import {
2
- existsSync,
3
- lstatSync,
4
2
  mkdtempSync,
5
3
  rmSync,
6
- symlinkSync,
7
4
  } from 'node:fs';
8
5
  import { mkdirSync } from 'node:fs';
9
6
  import { tmpdir } from 'node:os';
10
- import { basename, dirname, join, resolve } from 'node:path';
7
+ import { join } from 'node:path';
11
8
  import { spawnSync } from 'node:child_process';
12
9
  import { pathToFileURL } from 'node:url';
10
+ import {
11
+ ensureReusableNodeModules,
12
+ } from '../utils/repo-deps.js';
13
13
 
14
- const REQUIRED_NODE_MODULE_MARKERS = [
15
- join('typescript', 'package.json'),
16
- join('@iarna', 'toml', 'package.json'),
17
- join('@modelcontextprotocol', 'sdk', 'package.json'),
18
- join('zod', 'package.json'),
19
- ];
14
+ export {
15
+ hasUsableNodeModules,
16
+ resolveGitCommonDir,
17
+ resolveReusableNodeModulesSource,
18
+ } from '../utils/repo-deps.js';
20
19
 
21
20
  export const PACKED_INSTALL_SMOKE_CORE_COMMANDS = [
22
21
  ['--help'],
@@ -32,41 +31,10 @@ function usage(): string {
32
31
  ].join('\n');
33
32
  }
34
33
 
35
- function hasNodeModulesPath(nodeModulesPath: string): boolean {
36
- try {
37
- lstatSync(nodeModulesPath);
38
- return true;
39
- } catch {
40
- return false;
41
- }
42
- }
43
-
44
- export function hasUsableNodeModules(repoRoot: string): boolean {
45
- return REQUIRED_NODE_MODULE_MARKERS.every((marker) => existsSync(join(repoRoot, 'node_modules', marker)));
46
- }
47
-
48
- export function resolveGitCommonDir(cwd: string, gitRunner = spawnSync): string | null {
49
- const result = gitRunner('git', ['rev-parse', '--git-common-dir'], {
50
- cwd,
51
- encoding: 'utf-8',
52
- });
53
- if (result.status !== 0) {
54
- return null;
55
- }
56
- const value = (result.stdout || '').trim();
57
- if (!value) {
58
- return null;
59
- }
60
- return resolve(cwd, value);
61
- }
62
-
63
34
  interface EnsureRepoDepsOptions {
64
35
  gitRunner?: typeof spawnSync;
65
36
  install?: (cwd: string) => void;
66
- remove?: typeof rmSync;
67
- symlink?: typeof symlinkSync;
68
37
  log?: (message: string) => void;
69
- platformName?: string;
70
38
  }
71
39
 
72
40
  interface EnsureRepoDepsResult {
@@ -75,24 +43,6 @@ interface EnsureRepoDepsResult {
75
43
  sourceNodeModulesPath?: string;
76
44
  }
77
45
 
78
- export function resolveReusableNodeModulesSource(repoRoot: string, gitRunner = spawnSync): string | null {
79
- const commonDir = resolveGitCommonDir(repoRoot, gitRunner);
80
- if (!commonDir || basename(commonDir) !== '.git') {
81
- return null;
82
- }
83
-
84
- const primaryRepoRoot = dirname(commonDir);
85
- if (resolve(primaryRepoRoot) === resolve(repoRoot)) {
86
- return null;
87
- }
88
-
89
- if (!hasUsableNodeModules(primaryRepoRoot)) {
90
- return null;
91
- }
92
-
93
- return join(primaryRepoRoot, 'node_modules');
94
- }
95
-
96
46
  function formatCommandFailure(cmd: string, args: string[], result: { stdout?: string; stderr?: string }): string {
97
47
  return [
98
48
  `Command failed: ${cmd} ${args.join(' ')}`,
@@ -114,40 +64,23 @@ export function ensureRepoDependencies(repoRoot: string, options: EnsureRepoDeps
114
64
  throw new Error(formatCommandFailure('npm', ['ci'], result));
115
65
  }
116
66
  },
117
- remove = rmSync,
118
- symlink = symlinkSync,
119
67
  log = () => {},
120
- platformName = process.platform,
121
68
  } = options;
122
69
 
123
- if (hasUsableNodeModules(repoRoot)) {
124
- return {
125
- strategy: 'existing',
126
- nodeModulesPath: join(repoRoot, 'node_modules'),
127
- };
70
+ const reusable = ensureReusableNodeModules(repoRoot, { gitRunner });
71
+ if (reusable.strategy === 'existing') {
72
+ return reusable;
128
73
  }
129
-
130
- const targetNodeModules = join(repoRoot, 'node_modules');
131
- if (hasNodeModulesPath(targetNodeModules)) {
132
- remove(targetNodeModules, { recursive: true, force: true });
133
- }
134
-
135
- const reusableNodeModules = resolveReusableNodeModulesSource(repoRoot, gitRunner);
136
- if (reusableNodeModules) {
137
- symlink(reusableNodeModules, targetNodeModules, platformName === 'win32' ? 'junction' : 'dir');
138
- log(`[smoke:packed-install] Reusing node_modules from ${reusableNodeModules}`);
139
- return {
140
- strategy: 'symlink',
141
- nodeModulesPath: targetNodeModules,
142
- sourceNodeModulesPath: reusableNodeModules,
143
- };
74
+ if (reusable.strategy === 'symlink') {
75
+ log(`[smoke:packed-install] Reusing node_modules from ${reusable.sourceNodeModulesPath}`);
76
+ return reusable;
144
77
  }
145
78
 
146
79
  log('[smoke:packed-install] Installing repo dependencies with npm ci');
147
80
  install(repoRoot);
148
81
  return {
149
82
  strategy: 'installed',
150
- nodeModulesPath: targetNodeModules,
83
+ nodeModulesPath: join(repoRoot, 'node_modules'),
151
84
  };
152
85
  }
153
86
 
@@ -168,7 +168,7 @@ Rules:
168
168
  <invocation_conventions>
169
169
  - `$name` — invoke a workflow skill
170
170
  - `/skills` — browse available skills
171
- - `/prompts:name` advanced specialist role surface when the task already needs a specific agent
171
+ - Prefer skill invocation and keyword routing as the primary user-facing workflow surface
172
172
  </invocation_conventions>
173
173
 
174
174
  <model_routing>
@@ -191,7 +191,7 @@ Key roles:
191
191
  - `executor` — implementation and refactoring
192
192
  - `verifier` — completion evidence and validation
193
193
 
194
- Specialists remain available through advanced role surfaces such as `/prompts:*` when the task clearly benefits from them.
194
+ Specialists remain available through the role catalog and native child-agent surfaces when the task clearly benefits from them.
195
195
  </agent_catalog>
196
196
 
197
197
  ---
@@ -208,7 +208,7 @@ The `deep-interview` skill is the Socratic deep interview workflow and includes
208
208
  Runtime availability gate:
209
209
  - Treat `autopilot`, `ralph`, `ultrawork`, `ultraqa`, `team`/`swarm`, and `ecomode` as **OMX runtime workflows**, not generic prompt aliases.
210
210
  - Auto-activate those runtime workflows only when the current session is actually running under OMX CLI/runtime (for example, launched via `omx`, with OMX session overlay/runtime state available, or when the user explicitly asks to run `omx ...` in the shell).
211
- - In Codex App or plain Codex sessions without OMX runtime, do **not** treat those keywords alone as activation. Explain that they require OMX CLI runtime support, and continue with the nearest App-safe surface (`deep-interview`, `ralplan`, `plan`, `/prompts:*`, or native subagents) unless the user explicitly wants you to launch OMX from the shell.
211
+ - In Codex App or plain Codex sessions without OMX runtime, do **not** treat those keywords alone as activation. Explain that they require OMX CLI runtime support, and continue with the nearest App-safe surface (`deep-interview`, `ralplan`, `plan`, or native subagents) unless the user explicitly wants you to launch OMX from the shell.
212
212
 
213
213
  | Keyword(s) | Skill | Action |
214
214
  |-------------|-------|--------|
@@ -234,7 +234,6 @@ Detection rules:
234
234
  - Explicit `$name` invocations run left-to-right and override non-explicit keyword resolution.
235
235
  - If multiple non-explicit keywords match, use the most specific match.
236
236
  - Runtime-only keywords must pass the runtime availability gate before activation.
237
- - If the user explicitly invokes `/prompts:<name>`, do not auto-activate keyword skills unless explicit `$name` tokens are also present.
238
237
  - The rest of the user message becomes the task description.
239
238
 
240
239
  Ralph / Ralplan execution gate: