oh-my-codex 0.11.13 → 0.12.1

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 (377) hide show
  1. package/Cargo.lock +5 -5
  2. package/Cargo.toml +1 -1
  3. package/README.md +34 -17
  4. package/crates/omx-runtime/src/main.rs +6 -2
  5. package/dist/agents/native-config.js +1 -1
  6. package/dist/agents/native-config.js.map +1 -1
  7. package/dist/cli/__tests__/autoresearch-guided.test.js +74 -2
  8. package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
  9. package/dist/cli/__tests__/cleanup.test.js +37 -30
  10. package/dist/cli/__tests__/cleanup.test.js.map +1 -1
  11. package/dist/cli/__tests__/error-handling-warnings.test.js +3 -1
  12. package/dist/cli/__tests__/error-handling-warnings.test.js.map +1 -1
  13. package/dist/cli/__tests__/index.test.js +276 -5
  14. package/dist/cli/__tests__/index.test.js.map +1 -1
  15. package/dist/cli/__tests__/launch-fallback.test.js +95 -1
  16. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  17. package/dist/cli/__tests__/setup-refresh.test.js +49 -9
  18. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  19. package/dist/cli/__tests__/setup-scope.test.js +9 -0
  20. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  21. package/dist/cli/__tests__/team.test.js +136 -11
  22. package/dist/cli/__tests__/team.test.js.map +1 -1
  23. package/dist/cli/__tests__/uninstall.test.js +10 -0
  24. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  25. package/dist/cli/__tests__/windows-popup-loop-contract.test.js +1 -0
  26. package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
  27. package/dist/cli/autoresearch-guided.d.ts.map +1 -1
  28. package/dist/cli/autoresearch-guided.js +2 -1
  29. package/dist/cli/autoresearch-guided.js.map +1 -1
  30. package/dist/cli/autoresearch.d.ts.map +1 -1
  31. package/dist/cli/autoresearch.js +2 -1
  32. package/dist/cli/autoresearch.js.map +1 -1
  33. package/dist/cli/cleanup.d.ts.map +1 -1
  34. package/dist/cli/cleanup.js +10 -5
  35. package/dist/cli/cleanup.js.map +1 -1
  36. package/dist/cli/index.d.ts +21 -1
  37. package/dist/cli/index.d.ts.map +1 -1
  38. package/dist/cli/index.js +298 -36
  39. package/dist/cli/index.js.map +1 -1
  40. package/dist/cli/omx.js +2 -0
  41. package/dist/cli/omx.js.map +1 -1
  42. package/dist/cli/setup.d.ts +1 -0
  43. package/dist/cli/setup.d.ts.map +1 -1
  44. package/dist/cli/setup.js +41 -7
  45. package/dist/cli/setup.js.map +1 -1
  46. package/dist/cli/team.d.ts.map +1 -1
  47. package/dist/cli/team.js +16 -557
  48. package/dist/cli/team.js.map +1 -1
  49. package/dist/cli/uninstall.d.ts.map +1 -1
  50. package/dist/cli/uninstall.js +34 -9
  51. package/dist/cli/uninstall.js.map +1 -1
  52. package/dist/config/__tests__/generator-idempotent.test.js +79 -2
  53. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  54. package/dist/config/__tests__/generator-notify.test.js +2 -0
  55. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  56. package/dist/config/codex-hooks.d.ts +11 -0
  57. package/dist/config/codex-hooks.d.ts.map +1 -0
  58. package/dist/config/codex-hooks.js +50 -0
  59. package/dist/config/codex-hooks.js.map +1 -0
  60. package/dist/config/generator.d.ts +5 -3
  61. package/dist/config/generator.d.ts.map +1 -1
  62. package/dist/config/generator.js +24 -14
  63. package/dist/config/generator.js.map +1 -1
  64. package/dist/hooks/__tests__/debugger-log-recency-contract.test.d.ts +2 -0
  65. package/dist/hooks/__tests__/debugger-log-recency-contract.test.d.ts.map +1 -0
  66. package/dist/hooks/__tests__/debugger-log-recency-contract.test.js +20 -0
  67. package/dist/hooks/__tests__/debugger-log-recency-contract.test.js.map +1 -0
  68. package/dist/hooks/__tests__/keyword-detector.test.js +132 -0
  69. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  70. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +292 -4
  71. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  72. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +86 -0
  73. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
  74. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +40 -0
  75. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  76. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.d.ts +2 -0
  77. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.d.ts.map +1 -0
  78. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +54 -0
  79. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -0
  80. package/dist/hooks/__tests__/notify-hook-modules.test.js +31 -0
  81. package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -1
  82. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +51 -0
  83. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
  84. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.d.ts +2 -0
  85. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.d.ts.map +1 -0
  86. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js +136 -0
  87. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js.map +1 -0
  88. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +120 -0
  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 +145 -20
  91. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  92. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +116 -0
  93. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
  94. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +86 -0
  95. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
  96. package/dist/hooks/__tests__/pre-context-gate-skills.test.js +1 -0
  97. package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -1
  98. package/dist/hooks/extensibility/__tests__/runtime.test.js +49 -0
  99. package/dist/hooks/extensibility/__tests__/runtime.test.js.map +1 -1
  100. package/dist/hooks/extensibility/runtime.d.ts.map +1 -1
  101. package/dist/hooks/extensibility/runtime.js +10 -0
  102. package/dist/hooks/extensibility/runtime.js.map +1 -1
  103. package/dist/hooks/extensibility/types.d.ts +1 -1
  104. package/dist/hooks/extensibility/types.d.ts.map +1 -1
  105. package/dist/hooks/keyword-detector.d.ts +2 -0
  106. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  107. package/dist/hooks/keyword-detector.js +76 -4
  108. package/dist/hooks/keyword-detector.js.map +1 -1
  109. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  110. package/dist/hooks/prompt-guidance-contract.js +12 -8
  111. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  112. package/dist/hooks/session.d.ts +5 -1
  113. package/dist/hooks/session.d.ts.map +1 -1
  114. package/dist/hooks/session.js +10 -6
  115. package/dist/hooks/session.js.map +1 -1
  116. package/dist/hud/index.d.ts.map +1 -1
  117. package/dist/hud/index.js +6 -1
  118. package/dist/hud/index.js.map +1 -1
  119. package/dist/mcp/__tests__/bootstrap.test.js +0 -3
  120. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
  121. package/dist/mcp/__tests__/code-intel-server.test.js +27 -1
  122. package/dist/mcp/__tests__/code-intel-server.test.js.map +1 -1
  123. package/dist/mcp/__tests__/server-lifecycle.test.js +0 -5
  124. package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
  125. package/dist/mcp/bootstrap.d.ts +1 -1
  126. package/dist/mcp/bootstrap.d.ts.map +1 -1
  127. package/dist/mcp/bootstrap.js +0 -1
  128. package/dist/mcp/bootstrap.js.map +1 -1
  129. package/dist/mcp/code-intel-server.d.ts +20 -0
  130. package/dist/mcp/code-intel-server.d.ts.map +1 -1
  131. package/dist/mcp/code-intel-server.js +6 -5
  132. package/dist/mcp/code-intel-server.js.map +1 -1
  133. package/dist/notifications/__tests__/idle-cooldown.test.js +24 -1
  134. package/dist/notifications/__tests__/idle-cooldown.test.js.map +1 -1
  135. package/dist/notifications/__tests__/reply-listener.test.js +20 -1
  136. package/dist/notifications/__tests__/reply-listener.test.js.map +1 -1
  137. package/dist/notifications/__tests__/tmux.test.js +41 -0
  138. package/dist/notifications/__tests__/tmux.test.js.map +1 -1
  139. package/dist/notifications/idle-cooldown.d.ts +13 -0
  140. package/dist/notifications/idle-cooldown.d.ts.map +1 -1
  141. package/dist/notifications/idle-cooldown.js +50 -16
  142. package/dist/notifications/idle-cooldown.js.map +1 -1
  143. package/dist/notifications/reply-listener.d.ts.map +1 -1
  144. package/dist/notifications/reply-listener.js +2 -0
  145. package/dist/notifications/reply-listener.js.map +1 -1
  146. package/dist/notifications/tmux.d.ts.map +1 -1
  147. package/dist/notifications/tmux.js +4 -0
  148. package/dist/notifications/tmux.js.map +1 -1
  149. package/dist/scripts/__tests__/codex-native-hook.test.d.ts +2 -0
  150. package/dist/scripts/__tests__/codex-native-hook.test.d.ts.map +1 -0
  151. package/dist/scripts/__tests__/codex-native-hook.test.js +1050 -0
  152. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -0
  153. package/dist/scripts/codex-native-hook.d.ts +22 -0
  154. package/dist/scripts/codex-native-hook.d.ts.map +1 -0
  155. package/dist/scripts/codex-native-hook.js +792 -0
  156. package/dist/scripts/codex-native-hook.js.map +1 -0
  157. package/dist/scripts/codex-native-pre-post.d.ts +26 -0
  158. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -0
  159. package/dist/scripts/codex-native-pre-post.js +118 -0
  160. package/dist/scripts/codex-native-pre-post.js.map +1 -0
  161. package/dist/scripts/notify-fallback-watcher.js +322 -21
  162. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  163. package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
  164. package/dist/scripts/notify-hook/auto-nudge.js +5 -6
  165. package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
  166. package/dist/scripts/notify-hook/log.d.ts +2 -2
  167. package/dist/scripts/notify-hook/log.d.ts.map +1 -1
  168. package/dist/scripts/notify-hook/log.js +10 -2
  169. package/dist/scripts/notify-hook/log.js.map +1 -1
  170. package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
  171. package/dist/scripts/notify-hook/managed-tmux.js +2 -0
  172. package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
  173. package/dist/scripts/notify-hook/orchestration-intent.d.ts +18 -0
  174. package/dist/scripts/notify-hook/orchestration-intent.d.ts.map +1 -0
  175. package/dist/scripts/notify-hook/orchestration-intent.js +72 -0
  176. package/dist/scripts/notify-hook/orchestration-intent.js.map +1 -0
  177. package/dist/scripts/notify-hook/process-runner.js.map +1 -1
  178. package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
  179. package/dist/scripts/notify-hook/ralph-session-resume.js +7 -0
  180. package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
  181. package/dist/scripts/notify-hook/team-dispatch.d.ts +15 -6
  182. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
  183. package/dist/scripts/notify-hook/team-dispatch.js +125 -6
  184. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  185. package/dist/scripts/notify-hook/team-leader-nudge.d.ts +3 -2
  186. package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
  187. package/dist/scripts/notify-hook/team-leader-nudge.js +165 -37
  188. package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
  189. package/dist/scripts/notify-hook/team-tmux-guard.d.ts +4 -1
  190. package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
  191. package/dist/scripts/notify-hook/team-tmux-guard.js +33 -44
  192. package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
  193. package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
  194. package/dist/scripts/notify-hook/team-worker.js +68 -5
  195. package/dist/scripts/notify-hook/team-worker.js.map +1 -1
  196. package/dist/scripts/notify-hook/utils.d.ts +1 -1
  197. package/dist/scripts/notify-hook/utils.d.ts.map +1 -1
  198. package/dist/scripts/notify-hook/utils.js.map +1 -1
  199. package/dist/scripts/notify-hook.js +55 -32
  200. package/dist/scripts/notify-hook.js.map +1 -1
  201. package/dist/team/__tests__/api-interop.test.js +344 -18
  202. package/dist/team/__tests__/api-interop.test.js.map +1 -1
  203. package/dist/team/__tests__/delivery-e2e-smoke.test.d.ts +2 -0
  204. package/dist/team/__tests__/delivery-e2e-smoke.test.d.ts.map +1 -0
  205. package/dist/team/__tests__/delivery-e2e-smoke.test.js +671 -0
  206. package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -0
  207. package/dist/team/__tests__/mcp-comm.test.js +5 -0
  208. package/dist/team/__tests__/mcp-comm.test.js.map +1 -1
  209. package/dist/team/__tests__/runtime.test.js +543 -15
  210. package/dist/team/__tests__/runtime.test.js.map +1 -1
  211. package/dist/team/__tests__/state.test.js +133 -8
  212. package/dist/team/__tests__/state.test.js.map +1 -1
  213. package/dist/team/__tests__/team-ops-contract.test.js +4 -0
  214. package/dist/team/__tests__/team-ops-contract.test.js.map +1 -1
  215. package/dist/team/__tests__/tmux-session.test.js +160 -0
  216. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  217. package/dist/team/__tests__/worker-bootstrap.test.js +19 -1
  218. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  219. package/dist/team/api-interop.d.ts.map +1 -1
  220. package/dist/team/api-interop.js +95 -23
  221. package/dist/team/api-interop.js.map +1 -1
  222. package/dist/team/contracts.d.ts +11 -1
  223. package/dist/team/contracts.d.ts.map +1 -1
  224. package/dist/team/contracts.js +29 -0
  225. package/dist/team/contracts.js.map +1 -1
  226. package/dist/team/delivery-log.d.ts +14 -0
  227. package/dist/team/delivery-log.d.ts.map +1 -0
  228. package/dist/team/delivery-log.js +35 -0
  229. package/dist/team/delivery-log.js.map +1 -0
  230. package/dist/team/idle-nudge.d.ts +2 -2
  231. package/dist/team/idle-nudge.js +2 -2
  232. package/dist/team/mcp-comm.d.ts +4 -0
  233. package/dist/team/mcp-comm.d.ts.map +1 -1
  234. package/dist/team/mcp-comm.js +84 -1
  235. package/dist/team/mcp-comm.js.map +1 -1
  236. package/dist/team/pane-status.d.ts +149 -0
  237. package/dist/team/pane-status.d.ts.map +1 -0
  238. package/dist/team/pane-status.js +558 -0
  239. package/dist/team/pane-status.js.map +1 -0
  240. package/dist/team/reminder-intents.d.ts +11 -0
  241. package/dist/team/reminder-intents.d.ts.map +1 -0
  242. package/dist/team/reminder-intents.js +40 -0
  243. package/dist/team/reminder-intents.js.map +1 -0
  244. package/dist/team/runtime-cli.d.ts +1 -1
  245. package/dist/team/runtime-cli.js +2 -2
  246. package/dist/team/runtime-cli.js.map +1 -1
  247. package/dist/team/runtime.d.ts +2 -1
  248. package/dist/team/runtime.d.ts.map +1 -1
  249. package/dist/team/runtime.js +409 -191
  250. package/dist/team/runtime.js.map +1 -1
  251. package/dist/team/scaling.d.ts.map +1 -1
  252. package/dist/team/scaling.js +6 -5
  253. package/dist/team/scaling.js.map +1 -1
  254. package/dist/team/state/dispatch.d.ts +4 -1
  255. package/dist/team/state/dispatch.d.ts.map +1 -1
  256. package/dist/team/state/dispatch.js +59 -18
  257. package/dist/team/state/dispatch.js.map +1 -1
  258. package/dist/team/state/mailbox.d.ts.map +1 -1
  259. package/dist/team/state/mailbox.js +45 -2
  260. package/dist/team/state/mailbox.js.map +1 -1
  261. package/dist/team/state/monitor.d.ts +2 -1
  262. package/dist/team/state/monitor.d.ts.map +1 -1
  263. package/dist/team/state/monitor.js +30 -1
  264. package/dist/team/state/monitor.js.map +1 -1
  265. package/dist/team/state/types.d.ts +5 -2
  266. package/dist/team/state/types.d.ts.map +1 -1
  267. package/dist/team/state/types.js.map +1 -1
  268. package/dist/team/state.d.ts +30 -3
  269. package/dist/team/state.d.ts.map +1 -1
  270. package/dist/team/state.js +170 -2
  271. package/dist/team/state.js.map +1 -1
  272. package/dist/team/team-ops.d.ts +5 -1
  273. package/dist/team/team-ops.d.ts.map +1 -1
  274. package/dist/team/team-ops.js +4 -0
  275. package/dist/team/team-ops.js.map +1 -1
  276. package/dist/team/tmux-session.d.ts +2 -0
  277. package/dist/team/tmux-session.d.ts.map +1 -1
  278. package/dist/team/tmux-session.js +19 -3
  279. package/dist/team/tmux-session.js.map +1 -1
  280. package/dist/team/worker-bootstrap.d.ts +4 -0
  281. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  282. package/dist/team/worker-bootstrap.js +33 -6
  283. package/dist/team/worker-bootstrap.js.map +1 -1
  284. package/dist/utils/__tests__/paths.test.js +63 -1
  285. package/dist/utils/__tests__/paths.test.js.map +1 -1
  286. package/dist/utils/__tests__/platform-command.test.js +50 -4
  287. package/dist/utils/__tests__/platform-command.test.js.map +1 -1
  288. package/dist/utils/paths.d.ts +12 -0
  289. package/dist/utils/paths.d.ts.map +1 -1
  290. package/dist/utils/paths.js +44 -2
  291. package/dist/utils/paths.js.map +1 -1
  292. package/dist/utils/platform-command.d.ts.map +1 -1
  293. package/dist/utils/platform-command.js +13 -5
  294. package/dist/utils/platform-command.js.map +1 -1
  295. package/dist/utils/sleep.d.ts.map +1 -1
  296. package/dist/utils/sleep.js +10 -1
  297. package/dist/utils/sleep.js.map +1 -1
  298. package/package.json +1 -1
  299. package/prompts/analyst.md +2 -2
  300. package/prompts/api-reviewer.md +2 -2
  301. package/prompts/architect.md +2 -2
  302. package/prompts/build-fixer.md +2 -2
  303. package/prompts/code-reviewer.md +2 -2
  304. package/prompts/code-simplifier.md +1 -1
  305. package/prompts/critic.md +2 -2
  306. package/prompts/debugger.md +3 -2
  307. package/prompts/dependency-expert.md +2 -2
  308. package/prompts/designer.md +2 -2
  309. package/prompts/executor.md +3 -2
  310. package/prompts/explore.md +2 -2
  311. package/prompts/git-master.md +2 -2
  312. package/prompts/information-architect.md +15 -102
  313. package/prompts/performance-reviewer.md +2 -2
  314. package/prompts/planner.md +3 -2
  315. package/prompts/product-analyst.md +2 -2
  316. package/prompts/product-manager.md +2 -2
  317. package/prompts/qa-tester.md +2 -2
  318. package/prompts/quality-reviewer.md +2 -2
  319. package/prompts/quality-strategist.md +2 -2
  320. package/prompts/researcher.md +2 -2
  321. package/prompts/security-reviewer.md +2 -2
  322. package/prompts/sisyphus-lite.md +2 -2
  323. package/prompts/style-reviewer.md +2 -2
  324. package/prompts/team-executor.md +2 -2
  325. package/prompts/test-engineer.md +2 -2
  326. package/prompts/ux-researcher.md +2 -2
  327. package/prompts/verifier.md +3 -2
  328. package/prompts/vision.md +2 -2
  329. package/prompts/writer.md +2 -2
  330. package/skills/team/SKILL.md +18 -33
  331. package/src/scripts/__tests__/codex-native-hook.test.ts +1346 -0
  332. package/src/scripts/codex-native-hook.ts +983 -0
  333. package/src/scripts/codex-native-pre-post.ts +161 -0
  334. package/src/scripts/notify-fallback-watcher.ts +378 -29
  335. package/src/scripts/notify-hook/auto-nudge.ts +5 -10
  336. package/src/scripts/notify-hook/log.ts +18 -4
  337. package/src/scripts/notify-hook/managed-tmux.ts +1 -0
  338. package/src/scripts/notify-hook/orchestration-intent.ts +82 -0
  339. package/src/scripts/notify-hook/process-runner.ts +4 -4
  340. package/src/scripts/notify-hook/ralph-session-resume.ts +9 -0
  341. package/src/scripts/notify-hook/team-dispatch.ts +134 -6
  342. package/src/scripts/notify-hook/team-leader-nudge.ts +183 -37
  343. package/src/scripts/notify-hook/team-tmux-guard.ts +35 -43
  344. package/src/scripts/notify-hook/team-worker.ts +73 -4
  345. package/src/scripts/notify-hook/utils.ts +1 -1
  346. package/src/scripts/notify-hook.ts +64 -32
  347. package/templates/AGENTS.md +21 -11
  348. package/README.de.md +0 -263
  349. package/README.el.md +0 -223
  350. package/README.es.md +0 -263
  351. package/README.fr.md +0 -263
  352. package/README.it.md +0 -263
  353. package/README.ja.md +0 -264
  354. package/README.ko.md +0 -264
  355. package/README.pl.md +0 -216
  356. package/README.pt.md +0 -263
  357. package/README.ru.md +0 -263
  358. package/README.tr.md +0 -263
  359. package/README.vi.md +0 -223
  360. package/README.zh-TW.md +0 -293
  361. package/README.zh.md +0 -264
  362. package/dist/mcp/__tests__/team-server-cleanup.test.d.ts +0 -2
  363. package/dist/mcp/__tests__/team-server-cleanup.test.d.ts.map +0 -1
  364. package/dist/mcp/__tests__/team-server-cleanup.test.js +0 -219
  365. package/dist/mcp/__tests__/team-server-cleanup.test.js.map +0 -1
  366. package/dist/mcp/__tests__/team-server-runtime-deps.test.d.ts +0 -2
  367. package/dist/mcp/__tests__/team-server-runtime-deps.test.d.ts.map +0 -1
  368. package/dist/mcp/__tests__/team-server-runtime-deps.test.js +0 -13
  369. package/dist/mcp/__tests__/team-server-runtime-deps.test.js.map +0 -1
  370. package/dist/mcp/__tests__/team-server-wait.test.d.ts +0 -2
  371. package/dist/mcp/__tests__/team-server-wait.test.d.ts.map +0 -1
  372. package/dist/mcp/__tests__/team-server-wait.test.js +0 -155
  373. package/dist/mcp/__tests__/team-server-wait.test.js.map +0 -1
  374. package/dist/mcp/team-server.d.ts +0 -24
  375. package/dist/mcp/team-server.d.ts.map +0 -1
  376. package/dist/mcp/team-server.js +0 -482
  377. package/dist/mcp/team-server.js.map +0 -1
@@ -1,10 +1,10 @@
1
1
  import { describe, it } from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
- import { mkdtemp, rm, mkdir, readFile, writeFile } from 'node:fs/promises';
3
+ import { chmod, mkdtemp, rm, mkdir, readFile, writeFile } from 'node:fs/promises';
4
4
  import { join } from 'node:path';
5
5
  import { tmpdir } from 'node:os';
6
6
  import { resolveTeamApiOperation, buildLegacyTeamDeprecationHint, executeTeamApiOperation, LEGACY_TEAM_MCP_TOOLS, TEAM_API_OPERATIONS, } from '../api-interop.js';
7
- import { initTeamState, createTask, readTask, sendDirectMessage, enqueueDispatchRequest, readDispatchRequest, listDispatchRequests, appendTeamEvent, updateWorkerHeartbeat, writeMonitorSnapshot, writeWorkerStatus, } from '../state.js';
7
+ import { initTeamState, createTask, readTeamLeaderAttention, readTeamManifestV2, readTask, writeTeamLeaderAttention, writeTeamManifestV2, writeTeamPhase, sendDirectMessage, enqueueDispatchRequest, readDispatchRequest, listDispatchRequests, appendTeamEvent, markOwnedTeamsLeaderStopObserved, markOwnedTeamsLeaderSessionStopped, updateWorkerHeartbeat, writeMonitorSnapshot, writeWorkerStatus, } from '../state.js';
8
8
  async function setupTeam(name) {
9
9
  const cwd = await mkdtemp(join(tmpdir(), `omx-interop-${name}-`));
10
10
  const previousTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
@@ -21,6 +21,76 @@ async function setupTeam(name) {
21
21
  },
22
22
  };
23
23
  }
24
+ async function withMailboxCompatHoleRuntime(cwd, fn) {
25
+ const fakeBin = join(cwd, 'runtime-bin');
26
+ const runtimePath = join(fakeBin, 'omx-runtime');
27
+ const previousPath = process.env.PATH;
28
+ const previousBinary = process.env.OMX_RUNTIME_BINARY;
29
+ const previousBridge = process.env.OMX_RUNTIME_BRIDGE;
30
+ await mkdir(fakeBin, { recursive: true });
31
+ await writeFile(runtimePath, `#!/usr/bin/env node
32
+ const fs = require('fs');
33
+ const path = require('path');
34
+ const argv = process.argv.slice(2);
35
+ function argValue(prefix) {
36
+ const entry = argv.find((value) => value.startsWith(prefix));
37
+ return entry ? entry.slice(prefix.length) : null;
38
+ }
39
+ function stateDir() {
40
+ return argValue('--state-dir=') || process.cwd();
41
+ }
42
+ function readJson(file, fallback) {
43
+ try { return JSON.parse(fs.readFileSync(file, 'utf8')); } catch { return fallback; }
44
+ }
45
+ function writeJson(file, value) {
46
+ fs.mkdirSync(path.dirname(file), { recursive: true });
47
+ fs.writeFileSync(file, JSON.stringify(value, null, 2) + '\\n');
48
+ }
49
+ if (argv[0] === 'schema') {
50
+ process.stdout.write(JSON.stringify({ schema_version: 1, commands: [], events: [], transport: 'tmux' }) + '\\n');
51
+ process.exit(0);
52
+ }
53
+ if (argv[0] !== 'exec') process.exit(1);
54
+ const command = JSON.parse(argv[1] || '{}');
55
+ const dir = stateDir();
56
+ if (command.command === 'CreateMailboxMessage') {
57
+ writeJson(path.join(dir, 'mailbox.json'), readJson(path.join(dir, 'mailbox.json'), { records: [] }));
58
+ process.stdout.write(JSON.stringify({ event: 'MailboxMessageCreated', message_id: command.message_id, from_worker: command.from_worker, to_worker: command.to_worker }) + '\\n');
59
+ process.exit(0);
60
+ }
61
+ process.stdout.write(JSON.stringify({ event: 'ok' }) + '\\n');
62
+ `, 'utf8');
63
+ await chmod(runtimePath, 0o755);
64
+ process.env.PATH = `${fakeBin}:${previousPath || ''}`;
65
+ process.env.OMX_RUNTIME_BINARY = runtimePath;
66
+ process.env.OMX_RUNTIME_BRIDGE = '1';
67
+ try {
68
+ return await fn();
69
+ }
70
+ finally {
71
+ if (typeof previousPath === 'string')
72
+ process.env.PATH = previousPath;
73
+ else
74
+ delete process.env.PATH;
75
+ if (typeof previousBinary === 'string')
76
+ process.env.OMX_RUNTIME_BINARY = previousBinary;
77
+ else
78
+ delete process.env.OMX_RUNTIME_BINARY;
79
+ if (typeof previousBridge === 'string')
80
+ process.env.OMX_RUNTIME_BRIDGE = previousBridge;
81
+ else
82
+ delete process.env.OMX_RUNTIME_BRIDGE;
83
+ }
84
+ }
85
+ async function readTeamDeliveryLog(cwd) {
86
+ const path = join(cwd, '.omx', 'logs', `team-delivery-${new Date().toISOString().slice(0, 10)}.jsonl`);
87
+ const raw = await readFile(path, 'utf-8').catch(() => '');
88
+ return raw
89
+ .split('\n')
90
+ .map((line) => line.trim())
91
+ .filter(Boolean)
92
+ .map((line) => JSON.parse(line));
93
+ }
24
94
  // ─── resolveTeamApiOperation ──────────────────────────────────────────────
25
95
  describe('resolveTeamApiOperation', () => {
26
96
  it('resolves a valid kebab-case operation', () => {
@@ -149,6 +219,15 @@ describe('executeTeamApiOperation: send-message', () => {
149
219
  const mailboxRequest = parsedRequests.find((request) => request.message_id === messageId);
150
220
  assert.ok(mailboxRequest, 'send-message should enqueue a mailbox dispatch request');
151
221
  assert.equal(mailboxRequest?.to_worker, 'worker-2');
222
+ const deliveryLog = await readTeamDeliveryLog(cwd);
223
+ assert.ok(deliveryLog.some((entry) => entry.event === 'mailbox_created'
224
+ && entry.message_id === messageId
225
+ && entry.from_worker === 'worker-1'
226
+ && entry.to_worker === 'worker-2'));
227
+ assert.ok(deliveryLog.some((entry) => entry.event === 'dispatch_attempted'
228
+ && entry.request_id === mailboxRequest?.request_id
229
+ && entry.message_id === messageId
230
+ && entry.to_worker === 'worker-2'));
152
231
  }
153
232
  finally {
154
233
  await cleanup();
@@ -197,6 +276,15 @@ describe('executeTeamApiOperation: send-message', () => {
197
276
  const mailbox = JSON.parse(await readFile(join(repoCwd, '.omx', 'state', 'team', teamName, 'mailbox', 'leader-fixed.json'), 'utf-8'));
198
277
  const workerMessages = (mailbox.messages ?? []).filter((message) => message.from_worker === 'worker-1' && message.to_worker === 'leader-fixed');
199
278
  assert.equal(workerMessages.length, 1, 'deduped leader sends should not append duplicate worker mailbox rows');
279
+ const deliveryLog = [
280
+ ...(await readTeamDeliveryLog(repoCwd)),
281
+ ...(await readTeamDeliveryLog(workerCwd)),
282
+ ];
283
+ const createdEvents = deliveryLog.filter((entry) => entry.event === 'mailbox_created'
284
+ && entry.from_worker === 'worker-1'
285
+ && entry.to_worker === 'leader-fixed'
286
+ && entry.message_id === firstMessage.message_id);
287
+ assert.equal(createdEvents.length, 1, 'deduped leader sends should only emit one mailbox_created event');
200
288
  }
201
289
  finally {
202
290
  if (typeof prevTeamStateRoot === 'string')
@@ -207,6 +295,43 @@ describe('executeTeamApiOperation: send-message', () => {
207
295
  await rm(workerCwd, { recursive: true, force: true });
208
296
  }
209
297
  });
298
+ it('returns the persisted mailbox message when bridge compat omits the mailbox row under an explicit shared state root', async () => {
299
+ const teamName = 'msg-team-shared-root';
300
+ const root = await mkdtemp(join(tmpdir(), 'omx-interop-shared-root-'));
301
+ const leaderCwd = join(root, 'leader');
302
+ const workerCwd = join(root, 'worker-worktree');
303
+ const sharedStateRoot = join(root, 'shared-state');
304
+ const prevTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
305
+ try {
306
+ await mkdir(leaderCwd, { recursive: true });
307
+ await mkdir(workerCwd, { recursive: true });
308
+ process.env.OMX_TEAM_STATE_ROOT = sharedStateRoot;
309
+ await initTeamState(teamName, 'shared state root mailbox fallback', 'executor', 2, leaderCwd);
310
+ await withMailboxCompatHoleRuntime(root, async () => {
311
+ const result = await executeTeamApiOperation('send-message', {
312
+ team_name: teamName,
313
+ from_worker: 'worker-1',
314
+ to_worker: 'leader-fixed',
315
+ body: 'shared-root hello',
316
+ }, workerCwd);
317
+ assert.equal(result.ok, true);
318
+ if (!result.ok)
319
+ throw new Error('expected send-message call to succeed');
320
+ const message = result.data.message;
321
+ assert.equal(message.body, 'shared-root hello');
322
+ assert.equal(message.to_worker, 'leader-fixed');
323
+ const mailbox = JSON.parse(await readFile(join(sharedStateRoot, 'team', teamName, 'mailbox', 'leader-fixed.json'), 'utf8'));
324
+ assert.equal(mailbox.messages?.length, 1);
325
+ });
326
+ }
327
+ finally {
328
+ if (typeof prevTeamStateRoot === 'string')
329
+ process.env.OMX_TEAM_STATE_ROOT = prevTeamStateRoot;
330
+ else
331
+ delete process.env.OMX_TEAM_STATE_ROOT;
332
+ await rm(root, { recursive: true, force: true });
333
+ }
334
+ });
210
335
  it('returns error when from_worker missing', async () => {
211
336
  const result = await executeTeamApiOperation('send-message', {
212
337
  team_name: 'any', to_worker: 'w2', body: 'hi',
@@ -318,11 +443,70 @@ describe('executeTeamApiOperation: mailbox-mark-delivered', () => {
318
443
  assert.equal(result.data.dispatch_updated, true);
319
444
  const updatedDispatch = await readDispatchRequest('mark-dlv', dispatch.request.request_id, cwd);
320
445
  assert.equal(updatedDispatch?.status, 'delivered');
446
+ const deliveryLog = await readTeamDeliveryLog(cwd);
447
+ assert.ok(deliveryLog.some((entry) => entry.event === 'delivered'
448
+ && entry.message_id === msgId
449
+ && entry.to_worker === 'worker-2'));
450
+ assert.ok(deliveryLog.some((entry) => entry.event === 'mark_delivered'
451
+ && entry.message_id === msgId
452
+ && entry.request_id === dispatch.request.request_id
453
+ && entry.dispatch_updated === true));
321
454
  }
322
455
  finally {
323
456
  await cleanup();
324
457
  }
325
458
  });
459
+ it('marks leader-fixed mailbox delivery from a worker worktree and resolves the matching dispatch receipt', async () => {
460
+ const teamName = 'mark-dlv-leader-worktree';
461
+ const repoCwd = await mkdtemp(join(tmpdir(), 'omx-interop-mark-dlv-root-'));
462
+ const workerCwd = await mkdtemp(join(tmpdir(), 'omx-interop-mark-dlv-worktree-'));
463
+ const prevTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
464
+ delete process.env.OMX_TEAM_STATE_ROOT;
465
+ try {
466
+ await initTeamState(teamName, 'leader mailbox delivery receipt', 'executor', 2, repoCwd);
467
+ process.env.OMX_TEAM_STATE_ROOT = join(repoCwd, '.omx', 'state');
468
+ const sendResult = await executeTeamApiOperation('send-message', {
469
+ team_name: teamName,
470
+ from_worker: 'worker-1',
471
+ to_worker: 'leader-fixed',
472
+ body: 'DONE: worker-1 finished a mailbox integrity probe',
473
+ }, workerCwd);
474
+ assert.equal(sendResult.ok, true);
475
+ if (!sendResult.ok)
476
+ throw new Error('expected successful leader send-message result');
477
+ const message = sendResult.data.message;
478
+ const messageId = String(message.message_id ?? '');
479
+ assert.ok(messageId, 'leader mailbox message should include a message_id');
480
+ const pendingRequests = await listDispatchRequests(teamName, repoCwd, { kind: 'mailbox', to_worker: 'leader-fixed' });
481
+ const pendingDispatch = pendingRequests.find((request) => request.message_id === messageId);
482
+ assert.ok(pendingDispatch, 'leader mailbox send should enqueue a matching dispatch request');
483
+ const result = await executeTeamApiOperation('mailbox-mark-delivered', {
484
+ team_name: teamName,
485
+ worker: 'leader-fixed',
486
+ message_id: messageId,
487
+ }, workerCwd);
488
+ assert.equal(result.ok, true);
489
+ if (!result.ok)
490
+ throw new Error('expected successful leader mailbox-mark-delivered result');
491
+ assert.equal(result.data.updated, true);
492
+ assert.equal(result.data.dispatch_request_id, pendingDispatch?.request_id);
493
+ assert.equal(result.data.dispatch_updated, true);
494
+ const updatedDispatch = await readDispatchRequest(teamName, pendingDispatch.request_id, repoCwd);
495
+ assert.equal(updatedDispatch?.status, 'delivered');
496
+ assert.ok(updatedDispatch?.delivered_at, 'leader dispatch receipt should record delivered_at');
497
+ const leaderMailbox = JSON.parse(await readFile(join(repoCwd, '.omx', 'state', 'team', teamName, 'mailbox', 'leader-fixed.json'), 'utf-8'));
498
+ const deliveredMessage = (leaderMailbox.messages ?? []).find((entry) => entry.message_id === messageId);
499
+ assert.equal(typeof deliveredMessage?.delivered_at, 'string');
500
+ }
501
+ finally {
502
+ if (typeof prevTeamStateRoot === 'string')
503
+ process.env.OMX_TEAM_STATE_ROOT = prevTeamStateRoot;
504
+ else
505
+ delete process.env.OMX_TEAM_STATE_ROOT;
506
+ await rm(repoCwd, { recursive: true, force: true });
507
+ await rm(workerCwd, { recursive: true, force: true });
508
+ }
509
+ });
326
510
  it('reports when no matching mailbox dispatch request exists', async () => {
327
511
  const { cwd, cleanup } = await setupTeam('mark-dlv-no-dispatch');
328
512
  try {
@@ -1208,7 +1392,7 @@ describe('executeTeamApiOperation: read-idle-state', () => {
1208
1392
  });
1209
1393
  // ─── read-stall-state ───────────────────────────────────────────────────────
1210
1394
  describe('executeTeamApiOperation: read-stall-state', () => {
1211
- it('returns structured stall state from summary, snapshot, and recent events', async () => {
1395
+ it('returns structured stall state from authoritative leader attention state', async () => {
1212
1396
  const { cwd, cleanup } = await setupTeam('stall-state-team');
1213
1397
  try {
1214
1398
  const task = await createTask('stall-state-team', {
@@ -1256,15 +1440,21 @@ describe('executeTeamApiOperation: read-stall-state', () => {
1256
1440
  mailboxNotifiedByMessageId: {},
1257
1441
  completedEventTaskIds: {},
1258
1442
  }, cwd);
1259
- const idleEvent = await appendTeamEvent('stall-state-team', {
1260
- type: 'all_workers_idle',
1261
- worker: 'worker-2',
1262
- worker_count: 2,
1263
- }, cwd);
1264
- const nudgeEvent = await appendTeamEvent('stall-state-team', {
1265
- type: 'team_leader_nudge',
1266
- worker: 'leader-fixed',
1267
- reason: 'all_workers_idle',
1443
+ await writeTeamLeaderAttention('stall-state-team', {
1444
+ team_name: 'stall-state-team',
1445
+ updated_at: '2026-03-10T10:05:00.000Z',
1446
+ source: 'native_stop',
1447
+ leader_decision_state: 'still_actionable',
1448
+ leader_attention_pending: true,
1449
+ leader_attention_reason: 'leader_session_stopped',
1450
+ attention_reasons: ['leader_session_stopped'],
1451
+ leader_stale: false,
1452
+ leader_session_active: false,
1453
+ leader_session_id: 'leader-session-1',
1454
+ leader_session_stopped_at: '2026-03-10T10:05:00.000Z',
1455
+ unread_leader_message_count: 1,
1456
+ work_remaining: true,
1457
+ stalled_for_ms: null,
1268
1458
  }, cwd);
1269
1459
  const result = await executeTeamApiOperation('read-stall-state', {
1270
1460
  team_name: 'stall-state-team',
@@ -1279,18 +1469,154 @@ describe('executeTeamApiOperation: read-stall-state', () => {
1279
1469
  assert.equal(result.data.pending_task_count, 1);
1280
1470
  assert.equal(result.data.all_workers_idle, true);
1281
1471
  assert.match(result.data.reasons.join(' '), /workers_non_reporting:worker-1/);
1282
- assert.match(result.data.reasons.join(' '), /leader_attention_pending:team_leader_nudge/);
1283
- const lastAllIdle = result.data.last_all_workers_idle_event;
1284
- const lastNudge = result.data.last_team_leader_nudge_event;
1285
- assert.equal(lastAllIdle?.event_id, idleEvent.event_id);
1286
- assert.equal(lastNudge?.event_id, nudgeEvent.event_id);
1287
- assert.equal(lastNudge?.reason, 'all_workers_idle');
1472
+ assert.match(result.data.reasons.join(' '), /leader_attention_pending:leader_session_stopped/);
1473
+ const attention = result.data.leader_attention_state;
1474
+ assert.equal(attention?.leader_session_active, false);
1475
+ assert.equal(attention?.source, 'native_stop');
1476
+ }
1477
+ }
1478
+ finally {
1479
+ await cleanup();
1480
+ }
1481
+ });
1482
+ it('uses unread leader mailbox state even without recent nudge events', async () => {
1483
+ const { cwd, cleanup } = await setupTeam('stall-state-mailbox');
1484
+ try {
1485
+ await sendDirectMessage('stall-state-mailbox', 'worker-1', 'leader-fixed', 'please review', cwd);
1486
+ const result = await executeTeamApiOperation('read-stall-state', {
1487
+ team_name: 'stall-state-mailbox',
1488
+ }, cwd);
1489
+ assert.equal(result.ok, true);
1490
+ if (result.ok) {
1491
+ assert.equal(result.data.leader_attention_pending, true);
1492
+ assert.equal(result.data.leader_stale, false);
1493
+ assert.equal(result.data.unread_leader_message_count, 1);
1494
+ assert.match(result.data.reasons.join(' '), /leader_attention_pending:unread_leader_mailbox/);
1288
1495
  }
1289
1496
  }
1290
1497
  finally {
1291
1498
  await cleanup();
1292
1499
  }
1293
1500
  });
1501
+ it('suppresses stale native-stop attention after newer leader activity', async () => {
1502
+ const { cwd, cleanup } = await setupTeam('stall-state-resume');
1503
+ try {
1504
+ await writeTeamLeaderAttention('stall-state-resume', {
1505
+ team_name: 'stall-state-resume',
1506
+ updated_at: '2026-03-10T10:05:00.000Z',
1507
+ source: 'native_stop',
1508
+ leader_decision_state: 'still_actionable',
1509
+ leader_attention_pending: true,
1510
+ leader_attention_reason: 'leader_session_stopped',
1511
+ attention_reasons: ['leader_session_stopped'],
1512
+ leader_stale: false,
1513
+ leader_session_active: false,
1514
+ leader_session_id: 'leader-session-1',
1515
+ leader_session_stopped_at: '2026-03-10T10:05:00.000Z',
1516
+ unread_leader_message_count: 0,
1517
+ work_remaining: false,
1518
+ stalled_for_ms: null,
1519
+ }, cwd);
1520
+ await writeFile(join(cwd, '.omx', 'state', 'leader-runtime-activity.json'), JSON.stringify({
1521
+ last_activity_at: '2026-03-10T10:06:00.000Z',
1522
+ last_source: 'team_status',
1523
+ last_team_name: 'stall-state-resume',
1524
+ }, null, 2));
1525
+ const result = await executeTeamApiOperation('read-stall-state', {
1526
+ team_name: 'stall-state-resume',
1527
+ }, cwd);
1528
+ assert.equal(result.ok, true);
1529
+ if (result.ok) {
1530
+ assert.equal(result.data.leader_attention_pending, false);
1531
+ assert.equal(result.data.leader_stale, false);
1532
+ assert.doesNotMatch(result.data.reasons.join(' '), /leader_attention_pending:leader_session_stopped/);
1533
+ }
1534
+ }
1535
+ finally {
1536
+ await cleanup();
1537
+ }
1538
+ });
1539
+ it('marks only active leader-owned teams as stopped on session end', async () => {
1540
+ const { cwd, cleanup } = await setupTeam('owned-team');
1541
+ try {
1542
+ await initTeamState('other-team', 'Other', 'executor', 1, cwd);
1543
+ const ownedManifest = await readTeamManifestV2('owned-team', cwd);
1544
+ const otherManifest = await readTeamManifestV2('other-team', cwd);
1545
+ assert.ok(ownedManifest);
1546
+ assert.ok(otherManifest);
1547
+ await writeTeamManifestV2({
1548
+ ...ownedManifest,
1549
+ leader: {
1550
+ ...ownedManifest.leader,
1551
+ session_id: 'leader-session-1',
1552
+ },
1553
+ }, cwd);
1554
+ await writeTeamManifestV2({
1555
+ ...otherManifest,
1556
+ leader: {
1557
+ ...otherManifest.leader,
1558
+ session_id: 'leader-session-2',
1559
+ },
1560
+ }, cwd);
1561
+ await writeTeamLeaderAttention('owned-team', {
1562
+ team_name: 'owned-team',
1563
+ updated_at: '2026-03-10T10:12:00.000Z',
1564
+ source: 'notify_hook',
1565
+ leader_decision_state: 'still_actionable',
1566
+ leader_attention_pending: true,
1567
+ leader_attention_reason: 'stale_leader_with_messages',
1568
+ attention_reasons: ['stale_leader_with_messages'],
1569
+ leader_stale: true,
1570
+ leader_session_active: true,
1571
+ leader_session_id: 'leader-session-1',
1572
+ leader_session_stopped_at: null,
1573
+ unread_leader_message_count: 1,
1574
+ work_remaining: true,
1575
+ stalled_for_ms: null,
1576
+ }, cwd);
1577
+ await writeTeamPhase('other-team', {
1578
+ current_phase: 'complete',
1579
+ max_fix_attempts: 3,
1580
+ current_fix_attempt: 0,
1581
+ transitions: [],
1582
+ updated_at: '2026-03-10T10:10:00.000Z',
1583
+ }, cwd);
1584
+ const updatedTeams = await markOwnedTeamsLeaderSessionStopped(cwd, 'leader-session-1', '2026-03-10T10:15:00.000Z');
1585
+ assert.deepEqual(updatedTeams, ['owned-team']);
1586
+ const ownedAttention = await readTeamLeaderAttention('owned-team', cwd);
1587
+ const otherAttention = await readTeamLeaderAttention('other-team', cwd);
1588
+ assert.equal(ownedAttention?.leader_session_active, false);
1589
+ assert.equal(ownedAttention?.leader_attention_pending, true);
1590
+ assert.equal(ownedAttention?.leader_attention_reason, 'stale_leader_with_messages');
1591
+ assert.deepEqual(ownedAttention?.attention_reasons, ['stale_leader_with_messages', 'leader_session_stopped']);
1592
+ assert.equal(otherAttention, null);
1593
+ }
1594
+ finally {
1595
+ await cleanup();
1596
+ }
1597
+ });
1598
+ it('marks only active leader-owned teams from the native stop hook', async () => {
1599
+ const { cwd, cleanup } = await setupTeam('owned-stop-team');
1600
+ try {
1601
+ const ownedManifest = await readTeamManifestV2('owned-stop-team', cwd);
1602
+ assert.ok(ownedManifest);
1603
+ await writeTeamManifestV2({
1604
+ ...ownedManifest,
1605
+ leader: {
1606
+ ...ownedManifest.leader,
1607
+ session_id: 'leader-session-stop',
1608
+ },
1609
+ }, cwd);
1610
+ const updatedTeams = await markOwnedTeamsLeaderStopObserved(cwd, 'leader-session-stop', '2026-03-10T10:15:00.000Z');
1611
+ assert.deepEqual(updatedTeams, ['owned-stop-team']);
1612
+ const ownedAttention = await readTeamLeaderAttention('owned-stop-team', cwd);
1613
+ assert.equal(ownedAttention?.source, 'native_stop');
1614
+ assert.equal(ownedAttention?.leader_session_active, false);
1615
+ }
1616
+ finally {
1617
+ await cleanup();
1618
+ }
1619
+ });
1294
1620
  });
1295
1621
  // ─── get-summary ──────────────────────────────────────────────────────────
1296
1622
  describe('executeTeamApiOperation: get-summary', () => {