oh-my-codex 0.6.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (417) hide show
  1. package/README.md +19 -9
  2. package/bin/omx.js +3 -5
  3. package/dist/agents/__tests__/definitions.test.d.ts +2 -0
  4. package/dist/agents/__tests__/definitions.test.d.ts.map +1 -0
  5. package/dist/agents/__tests__/definitions.test.js +35 -0
  6. package/dist/agents/__tests__/definitions.test.js.map +1 -0
  7. package/dist/agents/__tests__/native-config.test.d.ts +2 -0
  8. package/dist/agents/__tests__/native-config.test.d.ts.map +1 -0
  9. package/dist/agents/__tests__/native-config.test.js +48 -0
  10. package/dist/agents/__tests__/native-config.test.js.map +1 -0
  11. package/dist/catalog/__tests__/schema.test.js +15 -0
  12. package/dist/catalog/__tests__/schema.test.js.map +1 -1
  13. package/dist/catalog/schema.d.ts.map +1 -1
  14. package/dist/catalog/schema.js +6 -0
  15. package/dist/catalog/schema.js.map +1 -1
  16. package/dist/cli/__tests__/catalog-contract.test.d.ts +2 -0
  17. package/dist/cli/__tests__/catalog-contract.test.d.ts.map +1 -0
  18. package/dist/cli/__tests__/catalog-contract.test.js +18 -0
  19. package/dist/cli/__tests__/catalog-contract.test.js.map +1 -0
  20. package/dist/cli/__tests__/doctor-team.test.js +3 -2
  21. package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
  22. package/dist/cli/__tests__/error-handling-warnings.test.d.ts +2 -0
  23. package/dist/cli/__tests__/error-handling-warnings.test.d.ts.map +1 -0
  24. package/dist/cli/__tests__/error-handling-warnings.test.js +35 -0
  25. package/dist/cli/__tests__/error-handling-warnings.test.js.map +1 -0
  26. package/dist/cli/__tests__/index.test.js +81 -8
  27. package/dist/cli/__tests__/index.test.js.map +1 -1
  28. package/dist/cli/__tests__/setup-agents-overwrite.test.d.ts +2 -0
  29. package/dist/cli/__tests__/setup-agents-overwrite.test.d.ts.map +1 -0
  30. package/dist/cli/__tests__/setup-agents-overwrite.test.js +124 -0
  31. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -0
  32. package/dist/cli/__tests__/setup-scope.test.js +79 -21
  33. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  34. package/dist/cli/__tests__/setup-skills-overwrite.test.d.ts +2 -0
  35. package/dist/cli/__tests__/setup-skills-overwrite.test.d.ts.map +1 -0
  36. package/dist/cli/__tests__/setup-skills-overwrite.test.js +32 -0
  37. package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -0
  38. package/dist/cli/__tests__/star-prompt.test.js +74 -0
  39. package/dist/cli/__tests__/star-prompt.test.js.map +1 -1
  40. package/dist/cli/__tests__/team.test.js +8 -0
  41. package/dist/cli/__tests__/team.test.js.map +1 -1
  42. package/dist/cli/doctor.d.ts.map +1 -1
  43. package/dist/cli/doctor.js +75 -18
  44. package/dist/cli/doctor.js.map +1 -1
  45. package/dist/cli/index.d.ts +10 -1
  46. package/dist/cli/index.d.ts.map +1 -1
  47. package/dist/cli/index.js +153 -45
  48. package/dist/cli/index.js.map +1 -1
  49. package/dist/cli/setup.d.ts +2 -1
  50. package/dist/cli/setup.d.ts.map +1 -1
  51. package/dist/cli/setup.js +104 -60
  52. package/dist/cli/setup.js.map +1 -1
  53. package/dist/cli/star-prompt.d.ts +21 -1
  54. package/dist/cli/star-prompt.d.ts.map +1 -1
  55. package/dist/cli/star-prompt.js +34 -13
  56. package/dist/cli/star-prompt.js.map +1 -1
  57. package/dist/cli/team.d.ts.map +1 -1
  58. package/dist/cli/team.js +10 -3
  59. package/dist/cli/team.js.map +1 -1
  60. package/dist/cli/update.d.ts.map +1 -1
  61. package/dist/cli/update.js.map +1 -1
  62. package/dist/config/__tests__/generator-notify.test.js +16 -0
  63. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  64. package/dist/config/__tests__/models.test.js +9 -1
  65. package/dist/config/__tests__/models.test.js.map +1 -1
  66. package/dist/config/generator.js +9 -10
  67. package/dist/config/generator.js.map +1 -1
  68. package/dist/config/models.d.ts +8 -1
  69. package/dist/config/models.d.ts.map +1 -1
  70. package/dist/config/models.js +27 -5
  71. package/dist/config/models.js.map +1 -1
  72. package/dist/hooks/__tests__/agents-overlay.test.js +24 -0
  73. package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
  74. package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts +18 -0
  75. package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts.map +1 -0
  76. package/dist/hooks/__tests__/consensus-execution-handoff.test.js +204 -0
  77. package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -0
  78. package/dist/hooks/__tests__/emulator.test.d.ts +2 -0
  79. package/dist/hooks/__tests__/emulator.test.d.ts.map +1 -0
  80. package/dist/hooks/__tests__/emulator.test.js +47 -0
  81. package/dist/hooks/__tests__/emulator.test.js.map +1 -0
  82. package/dist/hooks/__tests__/keyword-detector.test.js +330 -4
  83. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  84. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +101 -0
  85. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  86. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +13 -7
  87. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
  88. package/dist/hooks/__tests__/notify-hook-modules.test.js +61 -0
  89. package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -1
  90. package/dist/hooks/__tests__/notify-hook-session-scope.test.js +47 -0
  91. package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
  92. package/dist/hooks/__tests__/notify-hook-worker-idle.test.d.ts +2 -0
  93. package/dist/hooks/__tests__/notify-hook-worker-idle.test.d.ts.map +1 -0
  94. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +560 -0
  95. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -0
  96. package/dist/hooks/__tests__/session.test.d.ts +2 -0
  97. package/dist/hooks/__tests__/session.test.d.ts.map +1 -0
  98. package/dist/hooks/__tests__/session.test.js +161 -0
  99. package/dist/hooks/__tests__/session.test.js.map +1 -0
  100. package/dist/hooks/__tests__/task-size-detector.test.d.ts +2 -0
  101. package/dist/hooks/__tests__/task-size-detector.test.d.ts.map +1 -0
  102. package/dist/hooks/__tests__/task-size-detector.test.js +336 -0
  103. package/dist/hooks/__tests__/task-size-detector.test.js.map +1 -0
  104. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.d.ts +2 -0
  105. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.d.ts.map +1 -0
  106. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.js +24 -0
  107. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.js.map +1 -0
  108. package/dist/hooks/agents-overlay.d.ts.map +1 -1
  109. package/dist/hooks/agents-overlay.js +46 -2
  110. package/dist/hooks/agents-overlay.js.map +1 -1
  111. package/dist/hooks/code-simplifier/__tests__/index.test.js +67 -15
  112. package/dist/hooks/code-simplifier/__tests__/index.test.js.map +1 -1
  113. package/dist/hooks/code-simplifier/index.d.ts +10 -4
  114. package/dist/hooks/code-simplifier/index.d.ts.map +1 -1
  115. package/dist/hooks/code-simplifier/index.js +38 -12
  116. package/dist/hooks/code-simplifier/index.js.map +1 -1
  117. package/dist/hooks/codebase-map.d.ts.map +1 -1
  118. package/dist/hooks/codebase-map.js +5 -32
  119. package/dist/hooks/codebase-map.js.map +1 -1
  120. package/dist/hooks/emulator.d.ts.map +1 -1
  121. package/dist/hooks/emulator.js +11 -18
  122. package/dist/hooks/emulator.js.map +1 -1
  123. package/dist/hooks/extensibility/__tests__/dispatcher.test.js +59 -1
  124. package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +1 -1
  125. package/dist/hooks/extensibility/__tests__/loader.test.js +19 -0
  126. package/dist/hooks/extensibility/__tests__/loader.test.js.map +1 -1
  127. package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
  128. package/dist/hooks/extensibility/dispatcher.js +51 -39
  129. package/dist/hooks/extensibility/dispatcher.js.map +1 -1
  130. package/dist/hooks/extensibility/loader.d.ts.map +1 -1
  131. package/dist/hooks/extensibility/loader.js +25 -13
  132. package/dist/hooks/extensibility/loader.js.map +1 -1
  133. package/dist/hooks/extensibility/logging.d.ts.map +1 -1
  134. package/dist/hooks/extensibility/logging.js +6 -1
  135. package/dist/hooks/extensibility/logging.js.map +1 -1
  136. package/dist/hooks/extensibility/sdk.js.map +1 -1
  137. package/dist/hooks/keyword-detector.d.ts +87 -0
  138. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  139. package/dist/hooks/keyword-detector.js +235 -23
  140. package/dist/hooks/keyword-detector.js.map +1 -1
  141. package/dist/hooks/keyword-registry.d.ts +15 -0
  142. package/dist/hooks/keyword-registry.d.ts.map +1 -0
  143. package/dist/hooks/keyword-registry.js +41 -0
  144. package/dist/hooks/keyword-registry.js.map +1 -0
  145. package/dist/hooks/session.d.ts +18 -2
  146. package/dist/hooks/session.d.ts.map +1 -1
  147. package/dist/hooks/session.js +84 -11
  148. package/dist/hooks/session.js.map +1 -1
  149. package/dist/hooks/task-size-detector.d.ts +72 -0
  150. package/dist/hooks/task-size-detector.d.ts.map +1 -0
  151. package/dist/hooks/task-size-detector.js +204 -0
  152. package/dist/hooks/task-size-detector.js.map +1 -0
  153. package/dist/hud/__tests__/colors.test.js +1 -103
  154. package/dist/hud/__tests__/colors.test.js.map +1 -1
  155. package/dist/hud/__tests__/index.test.d.ts +2 -0
  156. package/dist/hud/__tests__/index.test.d.ts.map +1 -0
  157. package/dist/hud/__tests__/index.test.js +131 -0
  158. package/dist/hud/__tests__/index.test.js.map +1 -0
  159. package/dist/hud/__tests__/render.test.js +53 -0
  160. package/dist/hud/__tests__/render.test.js.map +1 -1
  161. package/dist/hud/__tests__/watch.test.d.ts +2 -0
  162. package/dist/hud/__tests__/watch.test.d.ts.map +1 -0
  163. package/dist/hud/__tests__/watch.test.js +63 -0
  164. package/dist/hud/__tests__/watch.test.js.map +1 -0
  165. package/dist/hud/colors.d.ts +2 -9
  166. package/dist/hud/colors.d.ts.map +1 -1
  167. package/dist/hud/colors.js +19 -34
  168. package/dist/hud/colors.js.map +1 -1
  169. package/dist/hud/constants.d.ts +1 -0
  170. package/dist/hud/constants.d.ts.map +1 -1
  171. package/dist/hud/constants.js +1 -0
  172. package/dist/hud/constants.js.map +1 -1
  173. package/dist/hud/index.d.ts +27 -0
  174. package/dist/hud/index.d.ts.map +1 -1
  175. package/dist/hud/index.js +149 -9
  176. package/dist/hud/index.js.map +1 -1
  177. package/dist/hud/render.d.ts.map +1 -1
  178. package/dist/hud/render.js +20 -7
  179. package/dist/hud/render.js.map +1 -1
  180. package/dist/mcp/__tests__/bootstrap.test.d.ts +2 -0
  181. package/dist/mcp/__tests__/bootstrap.test.d.ts.map +1 -0
  182. package/dist/mcp/__tests__/bootstrap.test.js +25 -0
  183. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -0
  184. package/dist/mcp/__tests__/code-intel-server.test.d.ts +2 -0
  185. package/dist/mcp/__tests__/code-intel-server.test.d.ts.map +1 -0
  186. package/dist/mcp/__tests__/code-intel-server.test.js +43 -0
  187. package/dist/mcp/__tests__/code-intel-server.test.js.map +1 -0
  188. package/dist/mcp/__tests__/memory-server.test.d.ts +2 -0
  189. package/dist/mcp/__tests__/memory-server.test.d.ts.map +1 -0
  190. package/dist/mcp/__tests__/memory-server.test.js +34 -0
  191. package/dist/mcp/__tests__/memory-server.test.js.map +1 -0
  192. package/dist/mcp/__tests__/memory-validation.test.d.ts +2 -0
  193. package/dist/mcp/__tests__/memory-validation.test.d.ts.map +1 -0
  194. package/dist/mcp/__tests__/memory-validation.test.js +29 -0
  195. package/dist/mcp/__tests__/memory-validation.test.js.map +1 -0
  196. package/dist/mcp/__tests__/path-traversal.test.js +55 -0
  197. package/dist/mcp/__tests__/path-traversal.test.js.map +1 -1
  198. package/dist/mcp/__tests__/state-paths.test.js +43 -6
  199. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  200. package/dist/mcp/__tests__/state-server-ralph-phase.test.js +50 -0
  201. package/dist/mcp/__tests__/state-server-ralph-phase.test.js.map +1 -1
  202. package/dist/mcp/__tests__/state-server-schema.test.js +3 -7
  203. package/dist/mcp/__tests__/state-server-schema.test.js.map +1 -1
  204. package/dist/mcp/__tests__/state-server.test.js +30 -1
  205. package/dist/mcp/__tests__/state-server.test.js.map +1 -1
  206. package/dist/mcp/__tests__/trace-server.test.js +58 -0
  207. package/dist/mcp/__tests__/trace-server.test.js.map +1 -1
  208. package/dist/mcp/bootstrap.d.ts +3 -0
  209. package/dist/mcp/bootstrap.d.ts.map +1 -0
  210. package/dist/mcp/bootstrap.js +13 -0
  211. package/dist/mcp/bootstrap.js.map +1 -0
  212. package/dist/mcp/code-intel-server.d.ts +8 -0
  213. package/dist/mcp/code-intel-server.d.ts.map +1 -1
  214. package/dist/mcp/code-intel-server.js +50 -24
  215. package/dist/mcp/code-intel-server.js.map +1 -1
  216. package/dist/mcp/memory-server.js +34 -13
  217. package/dist/mcp/memory-server.js.map +1 -1
  218. package/dist/mcp/memory-validation.d.ts +9 -0
  219. package/dist/mcp/memory-validation.d.ts.map +1 -0
  220. package/dist/mcp/memory-validation.js +11 -0
  221. package/dist/mcp/memory-validation.js.map +1 -0
  222. package/dist/mcp/state-paths.d.ts +2 -0
  223. package/dist/mcp/state-paths.d.ts.map +1 -1
  224. package/dist/mcp/state-paths.js +83 -12
  225. package/dist/mcp/state-paths.js.map +1 -1
  226. package/dist/mcp/state-server.d.ts.map +1 -1
  227. package/dist/mcp/state-server.js +85 -47
  228. package/dist/mcp/state-server.js.map +1 -1
  229. package/dist/mcp/trace-server.d.ts +16 -0
  230. package/dist/mcp/trace-server.d.ts.map +1 -1
  231. package/dist/mcp/trace-server.js +84 -24
  232. package/dist/mcp/trace-server.js.map +1 -1
  233. package/dist/modes/__tests__/base-ralph-contract.test.d.ts +2 -0
  234. package/dist/modes/__tests__/base-ralph-contract.test.d.ts.map +1 -0
  235. package/dist/modes/__tests__/base-ralph-contract.test.js +49 -0
  236. package/dist/modes/__tests__/base-ralph-contract.test.js.map +1 -0
  237. package/dist/modes/__tests__/base-tmux-pane.test.js +13 -1
  238. package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
  239. package/dist/modes/base.d.ts +0 -4
  240. package/dist/modes/base.d.ts.map +1 -1
  241. package/dist/modes/base.js +31 -11
  242. package/dist/modes/base.js.map +1 -1
  243. package/dist/notifications/__tests__/config.test.js +47 -1
  244. package/dist/notifications/__tests__/config.test.js.map +1 -1
  245. package/dist/notifications/__tests__/formatter.test.js +54 -2
  246. package/dist/notifications/__tests__/formatter.test.js.map +1 -1
  247. package/dist/notifications/__tests__/hook-config.test.d.ts +5 -0
  248. package/dist/notifications/__tests__/hook-config.test.d.ts.map +1 -0
  249. package/dist/notifications/__tests__/hook-config.test.js +139 -0
  250. package/dist/notifications/__tests__/hook-config.test.js.map +1 -0
  251. package/dist/notifications/__tests__/idle-cooldown.test.d.ts +5 -0
  252. package/dist/notifications/__tests__/idle-cooldown.test.d.ts.map +1 -0
  253. package/dist/notifications/__tests__/idle-cooldown.test.js +100 -0
  254. package/dist/notifications/__tests__/idle-cooldown.test.js.map +1 -0
  255. package/dist/notifications/__tests__/notifier.test.js +89 -1
  256. package/dist/notifications/__tests__/notifier.test.js.map +1 -1
  257. package/dist/notifications/__tests__/reply-config.test.d.ts +2 -0
  258. package/dist/notifications/__tests__/reply-config.test.d.ts.map +1 -0
  259. package/dist/notifications/__tests__/reply-config.test.js +79 -0
  260. package/dist/notifications/__tests__/reply-config.test.js.map +1 -0
  261. package/dist/notifications/__tests__/reply-listener.test.js +35 -1
  262. package/dist/notifications/__tests__/reply-listener.test.js.map +1 -1
  263. package/dist/notifications/__tests__/session-registry.test.js +40 -0
  264. package/dist/notifications/__tests__/session-registry.test.js.map +1 -1
  265. package/dist/notifications/__tests__/template-engine.test.d.ts +5 -0
  266. package/dist/notifications/__tests__/template-engine.test.d.ts.map +1 -0
  267. package/dist/notifications/__tests__/template-engine.test.js +147 -0
  268. package/dist/notifications/__tests__/template-engine.test.js.map +1 -0
  269. package/dist/notifications/config.d.ts +8 -0
  270. package/dist/notifications/config.d.ts.map +1 -1
  271. package/dist/notifications/config.js +110 -19
  272. package/dist/notifications/config.js.map +1 -1
  273. package/dist/notifications/formatter.d.ts +5 -0
  274. package/dist/notifications/formatter.d.ts.map +1 -1
  275. package/dist/notifications/formatter.js +45 -10
  276. package/dist/notifications/formatter.js.map +1 -1
  277. package/dist/notifications/hook-config-types.d.ts +43 -0
  278. package/dist/notifications/hook-config-types.d.ts.map +1 -0
  279. package/dist/notifications/hook-config-types.js +8 -0
  280. package/dist/notifications/hook-config-types.js.map +1 -0
  281. package/dist/notifications/hook-config.d.ts +40 -0
  282. package/dist/notifications/hook-config.d.ts.map +1 -0
  283. package/dist/notifications/hook-config.js +127 -0
  284. package/dist/notifications/hook-config.js.map +1 -0
  285. package/dist/notifications/idle-cooldown.d.ts +35 -0
  286. package/dist/notifications/idle-cooldown.d.ts.map +1 -0
  287. package/dist/notifications/idle-cooldown.js +108 -0
  288. package/dist/notifications/idle-cooldown.js.map +1 -0
  289. package/dist/notifications/index.d.ts +3 -0
  290. package/dist/notifications/index.d.ts.map +1 -1
  291. package/dist/notifications/index.js +43 -1
  292. package/dist/notifications/index.js.map +1 -1
  293. package/dist/notifications/notifier.d.ts +9 -0
  294. package/dist/notifications/notifier.d.ts.map +1 -1
  295. package/dist/notifications/notifier.js +36 -30
  296. package/dist/notifications/notifier.js.map +1 -1
  297. package/dist/notifications/reply-listener.d.ts +3 -0
  298. package/dist/notifications/reply-listener.d.ts.map +1 -1
  299. package/dist/notifications/reply-listener.js +61 -7
  300. package/dist/notifications/reply-listener.js.map +1 -1
  301. package/dist/notifications/session-registry.d.ts +1 -1
  302. package/dist/notifications/session-registry.d.ts.map +1 -1
  303. package/dist/notifications/session-registry.js +18 -6
  304. package/dist/notifications/session-registry.js.map +1 -1
  305. package/dist/notifications/template-engine.d.ts +34 -0
  306. package/dist/notifications/template-engine.d.ts.map +1 -0
  307. package/dist/notifications/template-engine.js +246 -0
  308. package/dist/notifications/template-engine.js.map +1 -0
  309. package/dist/notifications/types.d.ts +6 -0
  310. package/dist/notifications/types.d.ts.map +1 -1
  311. package/dist/openclaw/__tests__/config.test.d.ts +6 -0
  312. package/dist/openclaw/__tests__/config.test.d.ts.map +1 -0
  313. package/dist/openclaw/__tests__/config.test.js +174 -0
  314. package/dist/openclaw/__tests__/config.test.js.map +1 -0
  315. package/dist/openclaw/__tests__/dispatcher.test.d.ts +5 -0
  316. package/dist/openclaw/__tests__/dispatcher.test.d.ts.map +1 -0
  317. package/dist/openclaw/__tests__/dispatcher.test.js +104 -0
  318. package/dist/openclaw/__tests__/dispatcher.test.js.map +1 -0
  319. package/dist/openclaw/__tests__/index.test.d.ts +6 -0
  320. package/dist/openclaw/__tests__/index.test.d.ts.map +1 -0
  321. package/dist/openclaw/__tests__/index.test.js +131 -0
  322. package/dist/openclaw/__tests__/index.test.js.map +1 -0
  323. package/dist/openclaw/config.d.ts +37 -0
  324. package/dist/openclaw/config.d.ts.map +1 -0
  325. package/dist/openclaw/config.js +106 -0
  326. package/dist/openclaw/config.js.map +1 -0
  327. package/dist/openclaw/dispatcher.d.ts +63 -0
  328. package/dist/openclaw/dispatcher.d.ts.map +1 -0
  329. package/dist/openclaw/dispatcher.js +223 -0
  330. package/dist/openclaw/dispatcher.js.map +1 -0
  331. package/dist/openclaw/index.d.ts +27 -0
  332. package/dist/openclaw/index.d.ts.map +1 -0
  333. package/dist/openclaw/index.js +130 -0
  334. package/dist/openclaw/index.js.map +1 -0
  335. package/dist/openclaw/types.d.ts +105 -0
  336. package/dist/openclaw/types.d.ts.map +1 -0
  337. package/dist/openclaw/types.js +12 -0
  338. package/dist/openclaw/types.js.map +1 -0
  339. package/dist/ralph/contract.d.ts.map +1 -1
  340. package/dist/ralph/contract.js +13 -4
  341. package/dist/ralph/contract.js.map +1 -1
  342. package/dist/team/__tests__/phase-controller.test.js +14 -0
  343. package/dist/team/__tests__/phase-controller.test.js.map +1 -1
  344. package/dist/team/__tests__/runtime.test.js +328 -1
  345. package/dist/team/__tests__/runtime.test.js.map +1 -1
  346. package/dist/team/__tests__/scaling.test.d.ts +2 -0
  347. package/dist/team/__tests__/scaling.test.d.ts.map +1 -0
  348. package/dist/team/__tests__/scaling.test.js +295 -0
  349. package/dist/team/__tests__/scaling.test.js.map +1 -0
  350. package/dist/team/__tests__/state.test.js +62 -1
  351. package/dist/team/__tests__/state.test.js.map +1 -1
  352. package/dist/team/__tests__/tmux-session.test.js +219 -14
  353. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  354. package/dist/team/__tests__/worker-bootstrap.test.js +4 -0
  355. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  356. package/dist/team/contracts.d.ts +14 -0
  357. package/dist/team/contracts.d.ts.map +1 -0
  358. package/dist/team/contracts.js +30 -0
  359. package/dist/team/contracts.js.map +1 -0
  360. package/dist/team/model-contract.d.ts +1 -0
  361. package/dist/team/model-contract.d.ts.map +1 -1
  362. package/dist/team/model-contract.js +5 -1
  363. package/dist/team/model-contract.js.map +1 -1
  364. package/dist/team/phase-controller.d.ts +2 -0
  365. package/dist/team/phase-controller.d.ts.map +1 -1
  366. package/dist/team/phase-controller.js +16 -2
  367. package/dist/team/phase-controller.js.map +1 -1
  368. package/dist/team/runtime.d.ts.map +1 -1
  369. package/dist/team/runtime.js +356 -65
  370. package/dist/team/runtime.js.map +1 -1
  371. package/dist/team/scaling.d.ts +58 -0
  372. package/dist/team/scaling.d.ts.map +1 -0
  373. package/dist/team/scaling.js +319 -0
  374. package/dist/team/scaling.js.map +1 -0
  375. package/dist/team/state.d.ts +11 -2
  376. package/dist/team/state.d.ts.map +1 -1
  377. package/dist/team/state.js +97 -27
  378. package/dist/team/state.js.map +1 -1
  379. package/dist/team/team-ops.d.ts +2 -0
  380. package/dist/team/team-ops.d.ts.map +1 -1
  381. package/dist/team/team-ops.js +4 -0
  382. package/dist/team/team-ops.js.map +1 -1
  383. package/dist/team/tmux-session.d.ts +34 -5
  384. package/dist/team/tmux-session.d.ts.map +1 -1
  385. package/dist/team/tmux-session.js +177 -49
  386. package/dist/team/tmux-session.js.map +1 -1
  387. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  388. package/dist/team/worker-bootstrap.js +20 -0
  389. package/dist/team/worker-bootstrap.js.map +1 -1
  390. package/dist/utils/__tests__/paths.test.js +8 -1
  391. package/dist/utils/__tests__/paths.test.js.map +1 -1
  392. package/dist/utils/paths.d.ts.map +1 -1
  393. package/dist/utils/paths.js +14 -6
  394. package/dist/utils/paths.js.map +1 -1
  395. package/dist/verification/__tests__/verifier.test.js +20 -1
  396. package/dist/verification/__tests__/verifier.test.js.map +1 -1
  397. package/dist/verification/verifier.d.ts +5 -0
  398. package/dist/verification/verifier.d.ts.map +1 -1
  399. package/dist/verification/verifier.js +19 -0
  400. package/dist/verification/verifier.js.map +1 -1
  401. package/package.json +2 -1
  402. package/prompts/architect.md +11 -0
  403. package/prompts/critic.md +14 -1
  404. package/prompts/planner.md +21 -0
  405. package/scripts/notify-hook/auto-nudge.js +80 -1
  406. package/scripts/notify-hook/payload-parser.js +21 -0
  407. package/scripts/notify-hook/team-worker.js +142 -0
  408. package/scripts/notify-hook/tmux-injection.js +3 -3
  409. package/scripts/notify-hook.js +55 -4
  410. package/skills/configure-notifications/SKILL.md +278 -0
  411. package/skills/configure-openclaw/SKILL.md +267 -0
  412. package/skills/configure-slack/SKILL.md +226 -0
  413. package/skills/omx-setup/SKILL.md +14 -19
  414. package/skills/plan/SKILL.md +57 -33
  415. package/skills/ralplan/SKILL.md +107 -21
  416. package/skills/team/SKILL.md +10 -1
  417. package/templates/AGENTS.md +11 -3
@@ -68,6 +68,21 @@ export function parseTeamWorkerEnv(rawValue) {
68
68
  return { teamName: match[1], workerName: match[2] };
69
69
  }
70
70
 
71
+ export function resolveWorkerIdleNotifyEnabled() {
72
+ const raw = safeString(process.env.OMX_TEAM_WORKER_IDLE_NOTIFY || '').trim().toLowerCase();
73
+ // Default: enabled. Disable with "false", "0", or "off".
74
+ if (raw === 'false' || raw === '0' || raw === 'off') return false;
75
+ return true;
76
+ }
77
+
78
+ export function resolveWorkerIdleCooldownMs() {
79
+ const raw = safeString(process.env.OMX_TEAM_WORKER_IDLE_COOLDOWN_MS || '');
80
+ const parsed = asNumber(raw);
81
+ // Default: 30 seconds. Guard against unreasonable values.
82
+ if (parsed !== null && parsed >= 5_000 && parsed <= 10 * 60_000) return parsed;
83
+ return 30_000;
84
+ }
85
+
71
86
  export function resolveAllWorkersIdleCooldownMs() {
72
87
  const raw = safeString(process.env.OMX_TEAM_ALL_IDLE_COOLDOWN_MS || '');
73
88
  const parsed = asNumber(raw);
@@ -212,3 +227,130 @@ export async function maybeNotifyLeaderAllWorkersIdle({ cwd, stateDir, logsDir,
212
227
  }).catch(() => {});
213
228
  }
214
229
  }
230
+
231
+ export async function maybeNotifyLeaderWorkerIdle({ cwd, stateDir, logsDir, parsedTeamWorker }) {
232
+ if (!resolveWorkerIdleNotifyEnabled()) return;
233
+
234
+ const { teamName, workerName } = parsedTeamWorker;
235
+ const nowMs = Date.now();
236
+ const nowIso = new Date(nowMs).toISOString();
237
+
238
+ // Read current worker status (full object for task context)
239
+ const workerDir = join(stateDir, 'team', teamName, 'workers', workerName);
240
+ const statusPath = join(workerDir, 'status.json');
241
+ let currentState = 'unknown';
242
+ let currentTaskId = '';
243
+ let currentReason = '';
244
+ try {
245
+ if (existsSync(statusPath)) {
246
+ const parsed = JSON.parse(await readFile(statusPath, 'utf-8'));
247
+ if (parsed && typeof parsed.state === 'string') currentState = parsed.state;
248
+ if (parsed && typeof parsed.current_task_id === 'string') currentTaskId = parsed.current_task_id;
249
+ if (parsed && typeof parsed.reason === 'string') currentReason = parsed.reason;
250
+ }
251
+ } catch { /* ignore */ }
252
+
253
+ // Read and update previous state for transition detection
254
+ const prevStatePath = join(workerDir, 'prev-notify-state.json');
255
+ let prevState = 'unknown';
256
+ try {
257
+ if (existsSync(prevStatePath)) {
258
+ const parsed = JSON.parse(await readFile(prevStatePath, 'utf-8'));
259
+ if (parsed && typeof parsed.state === 'string') prevState = parsed.state;
260
+ }
261
+ } catch { /* ignore */ }
262
+
263
+ // Always update prev state (atomic write)
264
+ try {
265
+ await mkdir(workerDir, { recursive: true });
266
+ const tmpPath = prevStatePath + '.tmp.' + process.pid;
267
+ await writeFile(tmpPath, JSON.stringify({ state: currentState, updated_at: nowIso }, null, 2));
268
+ await rename(tmpPath, prevStatePath);
269
+ } catch { /* best effort */ }
270
+
271
+ // Only fire on working->idle transition (non-idle to idle)
272
+ if (currentState !== 'idle') return;
273
+ if (prevState === 'idle' || prevState === 'done') return;
274
+
275
+ // Check per-worker cooldown
276
+ const cooldownPath = join(workerDir, 'worker-idle-notify.json');
277
+ const cooldownMs = resolveWorkerIdleCooldownMs();
278
+ let lastNotifiedMs = 0;
279
+ try {
280
+ if (existsSync(cooldownPath)) {
281
+ const parsed = JSON.parse(await readFile(cooldownPath, 'utf-8'));
282
+ lastNotifiedMs = asNumber(parsed && parsed.last_notified_at_ms) ?? 0;
283
+ }
284
+ } catch { /* ignore */ }
285
+ if ((nowMs - lastNotifiedMs) < cooldownMs) return;
286
+
287
+ // Read team config for tmux target
288
+ const teamInfo = await readTeamWorkersForIdleCheck(stateDir, teamName);
289
+ if (!teamInfo) return;
290
+ const { tmuxSession, leaderPaneId } = teamInfo;
291
+ const tmuxTarget = leaderPaneId || tmuxSession;
292
+ if (!tmuxTarget) return;
293
+
294
+ // Build notification message with context
295
+ const parts = [`[OMX] ${workerName} idle`];
296
+ if (prevState && prevState !== 'unknown') parts.push(`(was: ${prevState})`);
297
+ if (currentTaskId) parts.push(`task: ${currentTaskId}`);
298
+ if (currentReason) parts.push(`reason: ${currentReason}`);
299
+ const message = `${parts.join('. ')}. ${DEFAULT_MARKER}`;
300
+
301
+ try {
302
+ await runProcess('tmux', ['send-keys', '-t', tmuxTarget, '-l', message], 3000);
303
+ await new Promise(r => setTimeout(r, 100));
304
+ await runProcess('tmux', ['send-keys', '-t', tmuxTarget, 'C-m'], 3000);
305
+ await new Promise(r => setTimeout(r, 100));
306
+ await runProcess('tmux', ['send-keys', '-t', tmuxTarget, 'C-m'], 3000);
307
+
308
+ // Update cooldown state
309
+ try {
310
+ const tmpPath = cooldownPath + '.tmp.' + process.pid;
311
+ await writeFile(tmpPath, JSON.stringify({
312
+ last_notified_at_ms: nowMs,
313
+ last_notified_at: nowIso,
314
+ prev_state: prevState,
315
+ }, null, 2));
316
+ await rename(tmpPath, cooldownPath);
317
+ } catch { /* best effort */ }
318
+
319
+ // Write event to events.ndjson
320
+ const eventsDir = join(stateDir, 'team', teamName, 'events');
321
+ const eventsPath = join(eventsDir, 'events.ndjson');
322
+ try {
323
+ await mkdir(eventsDir, { recursive: true });
324
+ const event = {
325
+ event_id: `worker-idle-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`,
326
+ team: teamName,
327
+ type: 'worker_idle',
328
+ worker: workerName,
329
+ prev_state: prevState,
330
+ task_id: currentTaskId || null,
331
+ reason: currentReason || null,
332
+ created_at: nowIso,
333
+ };
334
+ await appendFile(eventsPath, JSON.stringify(event) + '\n');
335
+ } catch { /* best effort */ }
336
+
337
+ await logTmuxHookEvent(logsDir, {
338
+ timestamp: nowIso,
339
+ type: 'worker_idle_notification',
340
+ team: teamName,
341
+ tmux_target: tmuxTarget,
342
+ worker: workerName,
343
+ prev_state: prevState,
344
+ task_id: currentTaskId || null,
345
+ });
346
+ } catch (err) {
347
+ await logTmuxHookEvent(logsDir, {
348
+ timestamp: nowIso,
349
+ type: 'worker_idle_notification',
350
+ team: teamName,
351
+ tmux_target: tmuxTarget,
352
+ worker: workerName,
353
+ error: err instanceof Error ? err.message : safeString(err),
354
+ }).catch(() => {});
355
+ }
356
+ }
@@ -245,13 +245,13 @@ export async function handleTmuxInjection({
245
245
  return;
246
246
  }
247
247
 
248
- const { renderPrompt } = await import('./payload-parser.js');
249
- const prompt = renderPrompt(config.prompt_template, {
248
+ const { renderPrompt, injectLanguageReminder } = await import('./payload-parser.js');
249
+ const prompt = injectLanguageReminder(renderPrompt(config.prompt_template, {
250
250
  mode: mode || 'unknown',
251
251
  threadId,
252
252
  turnId,
253
253
  timestamp: nowIso,
254
- });
254
+ }), sourceText);
255
255
  const fallbackPane = safeString(process.env.TMUX_PANE || '');
256
256
  const resolution = await resolvePaneTarget(config.target, fallbackPane, cwd, modePane);
257
257
  if (!resolution.paneTarget) {
@@ -44,6 +44,7 @@ import {
44
44
  resolveTeamStateDirForWorker,
45
45
  updateWorkerHeartbeat,
46
46
  maybeNotifyLeaderAllWorkersIdle,
47
+ maybeNotifyLeaderWorkerIdle,
47
48
  } from './notify-hook/team-worker.js';
48
49
  import { DEFAULT_MARKER } from './tmux-hook-engine.js';
49
50
 
@@ -129,8 +130,27 @@ async function main() {
129
130
  const statePath = join(scopedDir, f);
130
131
  const state = JSON.parse(await readFile(statePath, 'utf-8'));
131
132
  if (state.active) {
132
- state.iteration = (state.iteration || 0) + 1;
133
- state.last_turn_at = new Date().toISOString();
133
+ const nowIso = new Date().toISOString();
134
+ const nextIteration = (state.iteration || 0) + 1;
135
+ state.iteration = nextIteration;
136
+ state.last_turn_at = nowIso;
137
+
138
+ const maxIterations = asNumber(state.max_iterations);
139
+ if (maxIterations !== null && maxIterations > 0 && nextIteration >= maxIterations) {
140
+ state.active = false;
141
+ if (typeof state.current_phase !== 'string' || !state.current_phase.trim()) {
142
+ state.current_phase = 'complete';
143
+ } else if (!['cancelled', 'failed', 'complete'].includes(state.current_phase)) {
144
+ state.current_phase = 'complete';
145
+ }
146
+ if (typeof state.completed_at !== 'string' || !state.completed_at) {
147
+ state.completed_at = nowIso;
148
+ }
149
+ if (typeof state.stop_reason !== 'string' || !state.stop_reason) {
150
+ state.stop_reason = 'max_iterations_reached';
151
+ }
152
+ }
153
+
134
154
  await writeFile(statePath, JSON.stringify(state, null, 2));
135
155
  }
136
156
  }
@@ -248,6 +268,15 @@ async function main() {
248
268
  }
249
269
  }
250
270
 
271
+ // 4.55. Notify leader when individual worker transitions to idle (worker session only)
272
+ if (isTeamWorker && parsedTeamWorker) {
273
+ try {
274
+ await maybeNotifyLeaderWorkerIdle({ cwd, stateDir, logsDir, parsedTeamWorker });
275
+ } catch {
276
+ // Non-critical
277
+ }
278
+ }
279
+
251
280
  // 4.6. Notify leader when all workers are idle (worker session only)
252
281
  if (isTeamWorker && parsedTeamWorker) {
253
282
  try {
@@ -300,6 +329,7 @@ async function main() {
300
329
  if (!isTeamWorker) {
301
330
  try {
302
331
  const { notifyLifecycle } = await import('../dist/notifications/index.js');
332
+ const { shouldSendIdleNotification, recordIdleNotificationSent } = await import('../dist/notifications/idle-cooldown.js');
303
333
  const sessionJsonPath = join(stateDir, 'session.json');
304
334
  let notifySessionId = '';
305
335
  try {
@@ -307,11 +337,14 @@ async function main() {
307
337
  notifySessionId = safeString(sessionData && sessionData.session_id ? sessionData.session_id : '');
308
338
  } catch { /* no session file */ }
309
339
 
310
- if (notifySessionId) {
311
- await notifyLifecycle('session-idle', {
340
+ if (notifySessionId && shouldSendIdleNotification(stateDir, notifySessionId)) {
341
+ const idleResult = await notifyLifecycle('session-idle', {
312
342
  sessionId: notifySessionId,
313
343
  projectPath: cwd,
314
344
  });
345
+ if (idleResult && idleResult.anySuccess) {
346
+ recordIdleNotificationSent(stateDir, notifySessionId);
347
+ }
315
348
  try {
316
349
  const { buildNativeHookEvent } = await import('../dist/hooks/extensibility/events.js');
317
350
  const { dispatchHookEvent } = await import('../dist/hooks/extensibility/dispatcher.js');
@@ -334,6 +367,24 @@ async function main() {
334
367
  }
335
368
  }
336
369
 
370
+ // 8.5. Skill activation tracking: update skill-active-state.json when a keyword is detected.
371
+ try {
372
+ const { recordSkillActivation } = await import('../dist/hooks/keyword-detector.js');
373
+ const inputMessages = normalizeInputMessages(payload);
374
+ const latestUserInput = safeString(inputMessages.length > 0 ? inputMessages[inputMessages.length - 1] : '');
375
+ if (latestUserInput) {
376
+ await recordSkillActivation({
377
+ stateDir,
378
+ text: latestUserInput,
379
+ sessionId: payloadSessionId,
380
+ threadId: safeString(payload['thread-id'] || payload.thread_id || ''),
381
+ turnId: safeString(payload['turn-id'] || payload.turn_id || ''),
382
+ });
383
+ }
384
+ } catch {
385
+ // Non-fatal: keyword detector module may not be built yet
386
+ }
387
+
337
388
  // 9. Auto-nudge: detect Codex stall patterns and automatically send a continuation prompt.
338
389
  // Works for both leader and worker contexts.
339
390
  try {
@@ -0,0 +1,278 @@
1
+ ---
2
+ name: configure-notifications
3
+ description: Configure OMX notifications - unified entry point for all platforms
4
+ triggers:
5
+ - "configure notifications"
6
+ - "setup notifications"
7
+ - "notification settings"
8
+ - "configure discord"
9
+ - "configure telegram"
10
+ - "configure slack"
11
+ - "configure openclaw"
12
+ - "setup discord"
13
+ - "setup telegram"
14
+ - "setup slack"
15
+ - "setup openclaw"
16
+ - "discord notifications"
17
+ - "telegram notifications"
18
+ - "slack notifications"
19
+ - "openclaw notifications"
20
+ - "discord webhook"
21
+ - "telegram bot"
22
+ - "slack webhook"
23
+ ---
24
+
25
+ # Configure OMX Notifications
26
+
27
+ Unified entry point for setting up notifications across all supported platforms.
28
+ OMX can notify you on Discord, Telegram, Slack, or your own OpenClaw gateway.
29
+
30
+ ## How This Skill Works
31
+
32
+ This skill detects what's already configured, presents a menu, and delegates to the
33
+ appropriate platform skill. It also handles cross-cutting settings like verbosity,
34
+ notification profiles, reply listener, and idle cooldown.
35
+
36
+ ## Step 1: Detect Currently Configured Platforms
37
+
38
+ ```bash
39
+ CONFIG_FILE="$HOME/.codex/.omx-config.json"
40
+
41
+ if [ -f "$CONFIG_FILE" ]; then
42
+ DISCORD_ENABLED=$(jq -r '.notifications.discord.enabled // false' "$CONFIG_FILE" 2>/dev/null)
43
+ DISCORD_BOT_ENABLED=$(jq -r '.notifications["discord-bot"].enabled // false' "$CONFIG_FILE" 2>/dev/null)
44
+ TELEGRAM_ENABLED=$(jq -r '.notifications.telegram.enabled // false' "$CONFIG_FILE" 2>/dev/null)
45
+ SLACK_ENABLED=$(jq -r '.notifications.slack.enabled // false' "$CONFIG_FILE" 2>/dev/null)
46
+ OPENCLAW_ENABLED=$(jq -r '.notifications.openclaw.enabled // false' "$CONFIG_FILE" 2>/dev/null)
47
+ NOTIF_ENABLED=$(jq -r '.notifications.enabled // false' "$CONFIG_FILE" 2>/dev/null)
48
+ VERBOSITY=$(jq -r '.notifications.verbosity // "session"' "$CONFIG_FILE" 2>/dev/null)
49
+ COOLDOWN=$(jq -r '.notifications.idleCooldownSeconds // 60' "$CONFIG_FILE" 2>/dev/null)
50
+ REPLY_ENABLED=$(jq -r '.notifications.reply.enabled // false' "$CONFIG_FILE" 2>/dev/null)
51
+
52
+ echo "NOTIF_ENABLED=$NOTIF_ENABLED"
53
+ echo "DISCORD_ENABLED=$DISCORD_ENABLED"
54
+ echo "DISCORD_BOT_ENABLED=$DISCORD_BOT_ENABLED"
55
+ echo "TELEGRAM_ENABLED=$TELEGRAM_ENABLED"
56
+ echo "SLACK_ENABLED=$SLACK_ENABLED"
57
+ echo "OPENCLAW_ENABLED=$OPENCLAW_ENABLED"
58
+ echo "VERBOSITY=$VERBOSITY"
59
+ echo "COOLDOWN=$COOLDOWN"
60
+ echo "REPLY_ENABLED=$REPLY_ENABLED"
61
+ else
62
+ echo "NO_CONFIG_FILE"
63
+ fi
64
+ ```
65
+
66
+ ## Step 2: Show Current Status and Main Menu
67
+
68
+ Display a summary of what's configured:
69
+
70
+ ```
71
+ OMX Notification Status
72
+ ───────────────────────
73
+ Discord webhook: enabled / not configured
74
+ Discord bot: enabled / not configured
75
+ Telegram: enabled / not configured
76
+ Slack: enabled / not configured
77
+ OpenClaw: enabled / not configured
78
+
79
+ Verbosity: session (default)
80
+ Idle cooldown: 60s
81
+ Reply listener: disabled
82
+ ```
83
+
84
+ Then use AskUserQuestion:
85
+
86
+ **Question:** "What would you like to configure?"
87
+
88
+ **Options:**
89
+ 1. **Discord** - Webhook or bot notifications to Discord channels
90
+ 2. **Telegram** - Bot notifications to personal or group chats
91
+ 3. **Slack** - Incoming webhook notifications to Slack channels
92
+ 4. **OpenClaw** - Self-hosted HTTP or CLI command gateway
93
+ 5. **Cross-cutting settings** - Verbosity, idle cooldown, profiles, reply listener
94
+ 6. **Disable all notifications** - Turn off all notification dispatching
95
+
96
+ ## Step 3: Delegate to Platform Skill
97
+
98
+ Based on the user's choice, invoke the appropriate platform skill:
99
+
100
+ - **Discord** → invoke `/configure-discord`
101
+ - **Telegram** → invoke `/configure-telegram`
102
+ - **Slack** → invoke `/configure-slack`
103
+ - **OpenClaw** → invoke `/configure-openclaw`
104
+ - **Cross-cutting settings** → continue with Step 4 below
105
+ - **Disable all** → continue with Step 5 below
106
+
107
+ When delegating, say: "Starting the [Platform] configuration wizard..." and invoke the skill.
108
+
109
+ ## Step 4: Cross-Cutting Settings
110
+
111
+ If the user chose "Cross-cutting settings":
112
+
113
+ ### 4a. Verbosity
114
+
115
+ Use AskUserQuestion:
116
+
117
+ **Question:** "How verbose should notifications be?"
118
+
119
+ **Options:**
120
+ 1. **session (Recommended)** - Start, idle, stop, end events + tmux snippet
121
+ 2. **minimal** - Start, stop, end only (no idle events, no tmux tail)
122
+ 3. **agent** - All session events plus ask-user-question prompts
123
+ 4. **verbose** - Everything including tool call output
124
+
125
+ Write verbosity to config:
126
+
127
+ ```bash
128
+ echo "$(cat "$CONFIG_FILE")" | jq \
129
+ --arg verbosity "$VERBOSITY" \
130
+ '.notifications.verbosity = $verbosity' > "$CONFIG_FILE"
131
+ ```
132
+
133
+ Env var alternative: `OMX_NOTIFY_VERBOSITY=session`
134
+
135
+ ### 4b. Idle Notification Cooldown
136
+
137
+ Use AskUserQuestion:
138
+
139
+ **Question:** "How often should idle notifications fire at most? (in seconds)"
140
+
141
+ **Options:**
142
+ 1. **60 seconds (default)** - At most once per minute
143
+ 2. **300 seconds** - At most once per 5 minutes
144
+ 3. **0 (disabled)** - Send every turn with no throttling
145
+ 4. **Custom** - Enter a number of seconds
146
+
147
+ Write the cooldown to config:
148
+
149
+ ```bash
150
+ echo "$(cat "$CONFIG_FILE")" | jq \
151
+ --argjson cooldown "$COOLDOWN_SECONDS" \
152
+ '.notifications.idleCooldownSeconds = $cooldown' > "$CONFIG_FILE"
153
+ ```
154
+
155
+ Env var alternative: `OMX_IDLE_COOLDOWN_SECONDS=60`
156
+
157
+ ### 4c. Notification Profiles
158
+
159
+ Explain that profiles let the user have different notification configs per context:
160
+
161
+ ```
162
+ Notification Profiles
163
+ ─────────────────────
164
+ Profiles let you switch notification targets based on context.
165
+ For example: a "work" profile for your work Slack, a "personal"
166
+ profile for your personal Telegram.
167
+
168
+ Activate a profile with: OMX_NOTIFY_PROFILE=work
169
+ or set a default: .omx-config.json > notifications.defaultProfile
170
+ ```
171
+
172
+ Use AskUserQuestion:
173
+
174
+ **Question:** "Would you like to configure notification profiles?"
175
+
176
+ **Options:**
177
+ 1. **Yes** - Set up named profiles
178
+ 2. **No, use flat config** - Keep the current single-config setup
179
+
180
+ If yes, guide the user to manually add profiles under `notifications.profiles` in `.omx-config.json`, and set `defaultProfile`.
181
+
182
+ ### 4d. Reply Listener
183
+
184
+ Explain the reply listener:
185
+
186
+ ```
187
+ Reply Listener
188
+ ──────────────
189
+ The reply listener lets you send messages back to Codex from
190
+ Discord (bot) or Telegram. When OMX asks for input, you can
191
+ reply directly from your phone or messaging app.
192
+
193
+ Requires:
194
+ - Discord Bot or Telegram platform configured
195
+ - OMX_REPLY_ENABLED=true in your shell profile
196
+ - For Discord: OMX_REPLY_DISCORD_USER_IDS=<your user ID>
197
+ (only messages from these IDs are accepted for security)
198
+ ```
199
+
200
+ Use AskUserQuestion:
201
+
202
+ **Question:** "Would you like to enable the reply listener?"
203
+
204
+ **Options:**
205
+ 1. **Yes** - Enable two-way communication from Discord/Telegram
206
+ 2. **No** - Keep notifications one-way only
207
+
208
+ If yes, write to config:
209
+
210
+ ```bash
211
+ echo "$(cat "$CONFIG_FILE")" | jq \
212
+ '.notifications.reply = (.notifications.reply // {}) |
213
+ .notifications.reply.enabled = true' > "$CONFIG_FILE"
214
+ ```
215
+
216
+ And remind them to set `OMX_REPLY_ENABLED=true` and (for Discord) `OMX_REPLY_DISCORD_USER_IDS`.
217
+
218
+ ## Step 5: Disable All Notifications
219
+
220
+ If the user chose "Disable all notifications":
221
+
222
+ Use AskUserQuestion:
223
+
224
+ **Question:** "Are you sure you want to disable all notifications?"
225
+
226
+ **Options:**
227
+ 1. **Yes, disable all** - Set notifications.enabled = false
228
+ 2. **No, go back** - Return to the main menu
229
+
230
+ If confirmed:
231
+
232
+ ```bash
233
+ echo "$(cat "$CONFIG_FILE")" | jq \
234
+ '.notifications.enabled = false' > "$CONFIG_FILE"
235
+ ```
236
+
237
+ Confirm: "Notifications disabled. Re-enable anytime by running /configure-notifications."
238
+
239
+ ## Step 6: After Configuration
240
+
241
+ After completing any platform or setting configuration, offer to configure another:
242
+
243
+ Use AskUserQuestion:
244
+
245
+ **Question:** "Would you like to configure another platform or setting?"
246
+
247
+ **Options:**
248
+ 1. **Yes** - Return to the main menu (Step 2)
249
+ 2. **No, I'm done** - Show final summary and exit
250
+
251
+ ## Final Summary
252
+
253
+ Display a summary of all active notification platforms:
254
+
255
+ ```
256
+ OMX Notification Configuration Complete!
257
+ ─────────────────────────────────────────
258
+ Active platforms:
259
+ Discord webhook: enabled
260
+ Telegram: enabled
261
+
262
+ Verbosity: session
263
+ Idle cooldown: 60s
264
+ Reply listener: disabled
265
+
266
+ Config saved to: ~/.codex/.omx-config.json
267
+
268
+ Quick reference — env vars:
269
+ OMX_DISCORD_WEBHOOK_URL=...
270
+ OMX_TELEGRAM_BOT_TOKEN=...
271
+ OMX_TELEGRAM_CHAT_ID=...
272
+ OMX_SLACK_WEBHOOK_URL=...
273
+ OMX_NOTIFY_VERBOSITY=session
274
+ OMX_IDLE_COOLDOWN_SECONDS=60
275
+ OMX_OPENCLAW=1
276
+
277
+ Run /configure-notifications again to update any settings.
278
+ ```