@jstn-sdk/rcs 0.1.0 → 0.1.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 (1736) hide show
  1. package/README.md +142 -102
  2. package/dist/agents/definitions.d.ts.map +1 -1
  3. package/dist/agents/definitions.js +0 -101
  4. package/dist/agents/definitions.js.map +1 -1
  5. package/dist/blueprint/runtime.d.ts +52 -0
  6. package/dist/blueprint/runtime.d.ts.map +1 -0
  7. package/dist/{ralplan → blueprint}/runtime.js +19 -19
  8. package/dist/blueprint/runtime.js.map +1 -0
  9. package/dist/catalog/reader.d.ts.map +1 -1
  10. package/dist/catalog/reader.js +8 -2
  11. package/dist/catalog/reader.js.map +1 -1
  12. package/dist/catalog/schema.js +1 -1
  13. package/dist/catalog/schema.js.map +1 -1
  14. package/dist/cli/forge.d.ts +17 -0
  15. package/dist/cli/{ralph.d.ts.map → forge.d.ts.map} +1 -1
  16. package/dist/cli/{ralph.js → forge.js} +82 -82
  17. package/dist/cli/{ralph.js.map → forge.js.map} +1 -1
  18. package/dist/cli/index.d.ts +1 -1
  19. package/dist/cli/index.js +15 -15
  20. package/dist/cli/setup.d.ts.map +1 -1
  21. package/dist/cli/setup.js +2 -3
  22. package/dist/cli/setup.js.map +1 -1
  23. package/dist/cli/star-prompt.js +2 -2
  24. package/dist/cli/star-prompt.js.map +1 -1
  25. package/dist/cli/state.js +1 -1
  26. package/dist/cli/team.d.ts.map +1 -1
  27. package/dist/cli/team.js +3 -2
  28. package/dist/cli/team.js.map +1 -1
  29. package/dist/cli/tmux-hook.d.ts.map +1 -1
  30. package/dist/cli/tmux-hook.js +9 -1
  31. package/dist/cli/tmux-hook.js.map +1 -1
  32. package/dist/config/generator.d.ts +1 -1
  33. package/dist/config/generator.d.ts.map +1 -1
  34. package/dist/config/generator.js +1 -1
  35. package/dist/config/generator.js.map +1 -1
  36. package/dist/forge/contract.d.ts +17 -0
  37. package/dist/{ralph → forge}/contract.d.ts.map +1 -1
  38. package/dist/{ralph → forge}/contract.js +16 -16
  39. package/dist/{ralph → forge}/contract.js.map +1 -1
  40. package/dist/{ralph → forge}/persistence.d.ts +5 -5
  41. package/dist/{ralph → forge}/persistence.d.ts.map +1 -1
  42. package/dist/{ralph → forge}/persistence.js +7 -6
  43. package/dist/forge/persistence.js.map +1 -0
  44. package/dist/hooks/agents-overlay.d.ts +1 -1
  45. package/dist/hooks/agents-overlay.d.ts.map +1 -1
  46. package/dist/hooks/agents-overlay.js +37 -31
  47. package/dist/hooks/agents-overlay.js.map +1 -1
  48. package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
  49. package/dist/hooks/extensibility/dispatcher.js +82 -14
  50. package/dist/hooks/extensibility/dispatcher.js.map +1 -1
  51. package/dist/hooks/keyword-detector.d.ts +8 -8
  52. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  53. package/dist/hooks/keyword-detector.js +94 -64
  54. package/dist/hooks/keyword-detector.js.map +1 -1
  55. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  56. package/dist/hooks/keyword-registry.js +9 -11
  57. package/dist/hooks/keyword-registry.js.map +1 -1
  58. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  59. package/dist/hooks/prompt-guidance-contract.js +10 -21
  60. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  61. package/dist/hooks/task-size-detector.js +2 -2
  62. package/dist/hooks/task-size-detector.js.map +1 -1
  63. package/dist/hooks/triage-state.d.ts +1 -1
  64. package/dist/hooks/triage-state.js +1 -1
  65. package/dist/hud/colors.d.ts +2 -2
  66. package/dist/hud/colors.js +2 -2
  67. package/dist/hud/render.js +21 -21
  68. package/dist/hud/render.js.map +1 -1
  69. package/dist/hud/state.d.ts +3 -3
  70. package/dist/hud/state.d.ts.map +1 -1
  71. package/dist/hud/state.js +18 -15
  72. package/dist/hud/state.js.map +1 -1
  73. package/dist/hud/types.d.ts +6 -6
  74. package/dist/hud/types.d.ts.map +1 -1
  75. package/dist/mcp/bootstrap.d.ts.map +1 -1
  76. package/dist/mcp/bootstrap.js +36 -2
  77. package/dist/mcp/bootstrap.js.map +1 -1
  78. package/dist/mcp/state-paths.d.ts +1 -0
  79. package/dist/mcp/state-paths.d.ts.map +1 -1
  80. package/dist/mcp/state-paths.js +4 -1
  81. package/dist/mcp/state-paths.js.map +1 -1
  82. package/dist/mcp/state-server.d.ts +4 -4
  83. package/dist/mcp/state-server.js +2 -2
  84. package/dist/mcp/state-server.js.map +1 -1
  85. package/dist/modes/base.d.ts +2 -2
  86. package/dist/modes/base.d.ts.map +1 -1
  87. package/dist/modes/base.js +29 -26
  88. package/dist/modes/base.js.map +1 -1
  89. package/dist/notifications/reply-listener.d.ts.map +1 -1
  90. package/dist/notifications/reply-listener.js +7 -1
  91. package/dist/notifications/reply-listener.js.map +1 -1
  92. package/dist/notifications/tmux.d.ts.map +1 -1
  93. package/dist/notifications/tmux.js +39 -6
  94. package/dist/notifications/tmux.js.map +1 -1
  95. package/dist/pipeline/index.d.ts +7 -6
  96. package/dist/pipeline/index.d.ts.map +1 -1
  97. package/dist/pipeline/index.js +5 -4
  98. package/dist/pipeline/index.js.map +1 -1
  99. package/dist/pipeline/orchestrator.d.ts +5 -5
  100. package/dist/pipeline/orchestrator.js +25 -25
  101. package/dist/pipeline/orchestrator.js.map +1 -1
  102. package/dist/pipeline/stages/blueprint.d.ts +25 -0
  103. package/dist/pipeline/stages/blueprint.d.ts.map +1 -0
  104. package/dist/pipeline/stages/{ralplan.js → blueprint.js} +16 -16
  105. package/dist/pipeline/stages/blueprint.js.map +1 -0
  106. package/dist/pipeline/stages/code-review.d.ts +2 -2
  107. package/dist/pipeline/stages/code-review.js +6 -6
  108. package/dist/pipeline/stages/code-review.js.map +1 -1
  109. package/dist/pipeline/stages/forge-verify.d.ts +50 -0
  110. package/dist/pipeline/stages/forge-verify.d.ts.map +1 -0
  111. package/dist/pipeline/stages/{ralph-verify.js → forge-verify.js} +21 -24
  112. package/dist/pipeline/stages/forge-verify.js.map +1 -0
  113. package/dist/pipeline/stages/team-exec.d.ts +1 -1
  114. package/dist/pipeline/stages/team-exec.js +19 -19
  115. package/dist/pipeline/stages/team-exec.js.map +1 -1
  116. package/dist/pipeline/types.d.ts +12 -12
  117. package/dist/pipeline/types.d.ts.map +1 -1
  118. package/dist/pipeline/types.js +1 -1
  119. package/dist/planning/artifacts.d.ts +3 -4
  120. package/dist/planning/artifacts.d.ts.map +1 -1
  121. package/dist/planning/artifacts.js +2 -3
  122. package/dist/planning/artifacts.js.map +1 -1
  123. package/dist/question/policy.js +1 -1
  124. package/dist/runtime/bridge.d.ts.map +1 -1
  125. package/dist/runtime/bridge.js +70 -13
  126. package/dist/runtime/bridge.js.map +1 -1
  127. package/dist/scripts/codex-native-hook.js +30 -30
  128. package/dist/scripts/codex-native-hook.js.map +1 -1
  129. package/dist/scripts/eval/eval-cross-server-party-flow.d.ts +3 -0
  130. package/dist/scripts/eval/eval-cross-server-party-flow.d.ts.map +1 -0
  131. package/dist/scripts/eval/eval-cross-server-party-flow.js +12 -0
  132. package/dist/scripts/eval/eval-cross-server-party-flow.js.map +1 -0
  133. package/dist/scripts/eval/eval-gui-onboarding-clarity.d.ts +3 -0
  134. package/dist/scripts/eval/eval-gui-onboarding-clarity.d.ts.map +1 -0
  135. package/dist/scripts/eval/eval-gui-onboarding-clarity.js +17 -0
  136. package/dist/scripts/eval/eval-gui-onboarding-clarity.js.map +1 -0
  137. package/dist/scripts/eval/eval-liveops-reward-loop-balance.d.ts +3 -0
  138. package/dist/scripts/eval/eval-liveops-reward-loop-balance.d.ts.map +1 -0
  139. package/dist/scripts/eval/eval-liveops-reward-loop-balance.js +12 -0
  140. package/dist/scripts/eval/eval-liveops-reward-loop-balance.js.map +1 -0
  141. package/dist/scripts/eval/eval-profile-datastore-recovery.d.ts +3 -0
  142. package/dist/scripts/eval/eval-profile-datastore-recovery.d.ts.map +1 -0
  143. package/dist/scripts/eval/eval-profile-datastore-recovery.js +17 -0
  144. package/dist/scripts/eval/eval-profile-datastore-recovery.js.map +1 -0
  145. package/dist/scripts/eval/eval-remote-contract-hardening.d.ts +3 -0
  146. package/dist/scripts/eval/eval-remote-contract-hardening.d.ts.map +1 -0
  147. package/dist/scripts/eval/eval-remote-contract-hardening.js +17 -0
  148. package/dist/scripts/eval/eval-remote-contract-hardening.js.map +1 -0
  149. package/dist/scripts/notify-fallback-watcher.js +140 -139
  150. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  151. package/dist/scripts/notify-hook/forge-session-resume.d.ts +23 -0
  152. package/dist/scripts/notify-hook/{ralph-session-resume.d.ts.map → forge-session-resume.d.ts.map} +1 -1
  153. package/dist/scripts/notify-hook/{ralph-session-resume.js → forge-session-resume.js} +37 -36
  154. package/dist/scripts/notify-hook/{ralph-session-resume.js.map → forge-session-resume.js.map} +1 -1
  155. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
  156. package/dist/scripts/notify-hook/team-dispatch.js +34 -4
  157. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  158. package/dist/scripts/notify-hook/visual-verdict.js +3 -3
  159. package/dist/scripts/notify-hook.js +9 -9
  160. package/dist/scripts/run-test-files.js +1 -1
  161. package/dist/scripts/run-test-files.js.map +1 -1
  162. package/dist/scripts/surface-taxonomy.d.ts +23 -0
  163. package/dist/scripts/surface-taxonomy.d.ts.map +1 -0
  164. package/dist/scripts/surface-taxonomy.js +271 -0
  165. package/dist/scripts/surface-taxonomy.js.map +1 -0
  166. package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
  167. package/dist/scripts/sync-plugin-mirror.js +5 -4
  168. package/dist/scripts/sync-plugin-mirror.js.map +1 -1
  169. package/dist/scripts/tmux-hook-engine.d.ts +1 -1
  170. package/dist/scripts/tmux-hook-engine.d.ts.map +1 -1
  171. package/dist/scripts/tmux-hook-engine.js +29 -20
  172. package/dist/scripts/tmux-hook-engine.js.map +1 -1
  173. package/dist/state/operations.d.ts +1 -1
  174. package/dist/state/operations.d.ts.map +1 -1
  175. package/dist/state/operations.js +18 -18
  176. package/dist/state/operations.js.map +1 -1
  177. package/dist/state/skill-active.d.ts +13 -1
  178. package/dist/state/skill-active.d.ts.map +1 -1
  179. package/dist/state/skill-active.js +38 -17
  180. package/dist/state/skill-active.js.map +1 -1
  181. package/dist/state/workflow-transition.d.ts +6 -5
  182. package/dist/state/workflow-transition.d.ts.map +1 -1
  183. package/dist/state/workflow-transition.js +27 -15
  184. package/dist/state/workflow-transition.js.map +1 -1
  185. package/dist/team/contracts.d.ts +1 -1
  186. package/dist/team/contracts.js +2 -2
  187. package/dist/team/followup-planner.d.ts +2 -2
  188. package/dist/team/followup-planner.d.ts.map +1 -1
  189. package/dist/team/followup-planner.js +16 -14
  190. package/dist/team/followup-planner.js.map +1 -1
  191. package/dist/team/idle-nudge.d.ts.map +1 -1
  192. package/dist/team/idle-nudge.js +3 -2
  193. package/dist/team/idle-nudge.js.map +1 -1
  194. package/dist/team/leader-activity.js +1 -1
  195. package/dist/team/model-contract.d.ts.map +1 -1
  196. package/dist/team/model-contract.js +4 -1
  197. package/dist/team/model-contract.js.map +1 -1
  198. package/dist/team/orchestrator.js +4 -4
  199. package/dist/team/orchestrator.js.map +1 -1
  200. package/dist/team/role-router.js +3 -3
  201. package/dist/team/role-router.js.map +1 -1
  202. package/dist/team/state/dispatch.d.ts.map +1 -1
  203. package/dist/team/state/dispatch.js +4 -1
  204. package/dist/team/state/dispatch.js.map +1 -1
  205. package/dist/team/tmux-session.d.ts +4 -0
  206. package/dist/team/tmux-session.d.ts.map +1 -1
  207. package/dist/team/tmux-session.js +42 -9
  208. package/dist/team/tmux-session.js.map +1 -1
  209. package/dist/team/worktree.d.ts +1 -1
  210. package/dist/utils/platform-command.d.ts.map +1 -1
  211. package/dist/utils/platform-command.js +9 -0
  212. package/dist/utils/platform-command.js.map +1 -1
  213. package/dist/verification/verifier.d.ts +1 -1
  214. package/dist/verification/verifier.js +2 -2
  215. package/docs/STATE_MODEL.md +24 -24
  216. package/docs/agents.html +8 -16
  217. package/docs/archive/README.md +15 -0
  218. package/docs/{prompt-migration-changelog.md → archive/prompt-migration-changelog.md} +0 -11
  219. package/docs/{release-body-0.9.0.md → archive/release-body-0.9.0.md} +6 -24
  220. package/docs/{release-body-0.9.1.md → archive/release-body-0.9.1.md} +3 -3
  221. package/docs/codex-native-hooks.md +4 -4
  222. package/docs/contracts/forge-cancel-contract.md +20 -0
  223. package/docs/contracts/forge-state-contract.md +52 -0
  224. package/docs/contracts/multi-state-transition-contract.md +5 -5
  225. package/docs/contracts/multi-state-transition-review.md +3 -3
  226. package/docs/contracts/repo-aware-team-dag-decomposition.md +1 -1
  227. package/docs/contracts/rust-runtime-thin-adapter-contract.md +1 -1
  228. package/docs/contracts/team-startup-dispatch-latency.md +1 -1
  229. package/docs/getting-started.html +6 -1
  230. package/docs/guidance-schema.md +6 -3
  231. package/docs/index.html +55 -4
  232. package/docs/integrations.html +4 -3
  233. package/docs/issues/team-forge-followup-team.md +38 -0
  234. package/docs/openclaw-integration.md +2 -2
  235. package/docs/prompt-guidance-contract.md +11 -11
  236. package/docs/prs/{dev-deprecate-team-ralph.md → dev-deprecate-team-forge.md} +27 -27
  237. package/docs/prs/{dev-fix-ralph-live-pane-invariant.md → dev-fix-forge-live-pane-invariant.md} +7 -7
  238. package/docs/prs/{dev-team-ralph-workflow-positioning.md → dev-team-forge-workflow-positioning.md} +7 -7
  239. package/docs/qa/forge-persistence-gate.md +20 -0
  240. package/docs/qa/rust-runtime-thin-adapter-gate.md +31 -40
  241. package/docs/readme/README.de.md +13 -0
  242. package/docs/readme/README.el.md +13 -0
  243. package/docs/readme/README.es.md +13 -0
  244. package/docs/readme/README.fr.md +13 -0
  245. package/docs/readme/README.it.md +13 -0
  246. package/docs/readme/README.ja.md +13 -0
  247. package/docs/readme/README.ko.md +13 -0
  248. package/docs/readme/README.pl.md +13 -0
  249. package/docs/readme/README.pt.md +13 -0
  250. package/docs/readme/README.ru.md +13 -0
  251. package/docs/readme/README.tr.md +13 -0
  252. package/docs/readme/README.uk.md +13 -0
  253. package/docs/readme/README.vi.md +13 -0
  254. package/docs/readme/README.zh-TW.md +13 -0
  255. package/docs/readme/README.zh.md +13 -0
  256. package/docs/readme/rcs-cover.svg +75 -0
  257. package/docs/reference/canonical-vocabulary.md +106 -0
  258. package/docs/reference/forge-parity-matrix.md +26 -0
  259. package/docs/reference/forge-upstream-baseline.md +32 -0
  260. package/docs/reference/rcs-config-schema-routing.md +5 -5
  261. package/docs/reference/roblox-pre-action-protocol.md +4 -0
  262. package/docs/reference/roblox-taxonomy-migration-plan.md +46 -0
  263. package/docs/reference/roblox-workspace-standard.md +83 -0
  264. package/docs/reference/robloxstudio-mcp-compatibility.md +117 -0
  265. package/docs/reference/semantic-design-system.md +110 -0
  266. package/docs/reference/surface-map.md +131 -0
  267. package/docs/reference/team-allocation-rebalance-policy.md +1 -1
  268. package/docs/release-notes-v0.1.0.md +1 -1
  269. package/docs/release-notes-v0.1.1.md +49 -0
  270. package/docs/reports/open-prs-dev-readiness-2026-04-09.md +2 -2
  271. package/docs/shared/agent-tiers.md +3 -3
  272. package/docs/skills.html +10 -12
  273. package/docs/troubleshooting.md +1 -1
  274. package/package.json +20 -13
  275. package/plugins/roblox-ai-os-creator-skills/.codex-plugin/plugin.json +1 -1
  276. package/plugins/roblox-ai-os-creator-skills/docs/reference/roblox-pre-action-protocol.md +4 -0
  277. package/plugins/roblox-ai-os-creator-skills/skills/ai-slop-cleaner/SKILL.md +14 -7
  278. package/plugins/roblox-ai-os-creator-skills/skills/analyze/SKILL.md +9 -2
  279. package/plugins/roblox-ai-os-creator-skills/skills/ask-claude/SKILL.md +7 -0
  280. package/plugins/roblox-ai-os-creator-skills/skills/ask-gemini/SKILL.md +7 -0
  281. package/plugins/roblox-ai-os-creator-skills/skills/autoforge/SKILL.md +7 -0
  282. package/plugins/roblox-ai-os-creator-skills/skills/autopilot/SKILL.md +48 -41
  283. package/plugins/roblox-ai-os-creator-skills/skills/autoresearch/SKILL.md +8 -1
  284. package/plugins/roblox-ai-os-creator-skills/skills/blueprint/SKILL.md +227 -9
  285. package/plugins/roblox-ai-os-creator-skills/skills/blueprint-loop/SKILL.md +7 -0
  286. package/plugins/roblox-ai-os-creator-skills/skills/blueprint-psych/SKILL.md +7 -0
  287. package/plugins/roblox-ai-os-creator-skills/skills/blueprint-retention/SKILL.md +7 -0
  288. package/plugins/roblox-ai-os-creator-skills/skills/blueprint-social/SKILL.md +7 -0
  289. package/plugins/roblox-ai-os-creator-skills/skills/brief/SKILL.md +7 -0
  290. package/plugins/roblox-ai-os-creator-skills/skills/brief-audience/SKILL.md +7 -0
  291. package/plugins/roblox-ai-os-creator-skills/skills/brief-motivation/SKILL.md +7 -0
  292. package/plugins/roblox-ai-os-creator-skills/skills/cancel/SKILL.md +59 -52
  293. package/plugins/roblox-ai-os-creator-skills/skills/code-review/SKILL.md +30 -24
  294. package/plugins/roblox-ai-os-creator-skills/skills/configure-notifications/SKILL.md +7 -0
  295. package/plugins/roblox-ai-os-creator-skills/skills/crew/SKILL.md +7 -0
  296. package/plugins/roblox-ai-os-creator-skills/skills/deep-interview/SKILL.md +25 -18
  297. package/plugins/roblox-ai-os-creator-skills/skills/doctor/SKILL.md +7 -0
  298. package/plugins/roblox-ai-os-creator-skills/skills/forge/SKILL.md +174 -11
  299. package/plugins/roblox-ai-os-creator-skills/skills/forge-community/SKILL.md +7 -0
  300. package/plugins/roblox-ai-os-creator-skills/skills/forge-daily-loop/SKILL.md +7 -0
  301. package/plugins/roblox-ai-os-creator-skills/skills/forge-event-loop/SKILL.md +7 -0
  302. package/plugins/roblox-ai-os-creator-skills/skills/forge-fomo/SKILL.md +7 -0
  303. package/plugins/roblox-ai-os-creator-skills/skills/forge-mastery/SKILL.md +7 -0
  304. package/plugins/roblox-ai-os-creator-skills/skills/forge-progression/SKILL.md +7 -0
  305. package/plugins/roblox-ai-os-creator-skills/skills/forge-reward-loop/SKILL.md +7 -0
  306. package/plugins/roblox-ai-os-creator-skills/skills/forge-status/SKILL.md +7 -0
  307. package/plugins/roblox-ai-os-creator-skills/skills/help/SKILL.md +8 -1
  308. package/plugins/roblox-ai-os-creator-skills/skills/hud/SKILL.md +16 -9
  309. package/plugins/roblox-ai-os-creator-skills/skills/note/SKILL.md +8 -1
  310. package/plugins/roblox-ai-os-creator-skills/skills/pipeline/SKILL.md +18 -11
  311. package/plugins/roblox-ai-os-creator-skills/skills/plan/SKILL.md +36 -29
  312. package/plugins/roblox-ai-os-creator-skills/skills/rcs-setup/SKILL.md +8 -1
  313. package/plugins/roblox-ai-os-creator-skills/skills/security-review/SKILL.md +120 -236
  314. package/plugins/roblox-ai-os-creator-skills/skills/skill/SKILL.md +20 -13
  315. package/plugins/roblox-ai-os-creator-skills/skills/team/SKILL.md +17 -11
  316. package/plugins/roblox-ai-os-creator-skills/skills/trace/SKILL.md +7 -0
  317. package/plugins/roblox-ai-os-creator-skills/skills/ultraqa/SKILL.md +10 -3
  318. package/plugins/roblox-ai-os-creator-skills/skills/ultrawork/SKILL.md +19 -12
  319. package/plugins/roblox-ai-os-creator-skills/skills/{visual-ralph → visual-forge}/SKILL.md +36 -27
  320. package/plugins/roblox-ai-os-creator-skills/skills/visual-verdict/SKILL.md +9 -2
  321. package/plugins/roblox-ai-os-creator-skills/skills/wiki/SKILL.md +10 -3
  322. package/plugins/roblox-ai-os-creator-skills/skills/worker/SKILL.md +16 -7
  323. package/plugins/roblox-ai-os-creator-skills/templates/roblox/pre-action-plan.md +1 -0
  324. package/prompts/analyst.md +7 -0
  325. package/prompts/architect.md +11 -4
  326. package/prompts/build-fixer.md +7 -0
  327. package/prompts/code-reviewer.md +9 -2
  328. package/prompts/code-simplifier.md +4 -0
  329. package/prompts/critic.md +13 -6
  330. package/prompts/debugger.md +8 -1
  331. package/prompts/dependency-expert.md +8 -1
  332. package/prompts/designer.md +20 -10
  333. package/prompts/executor.md +7 -0
  334. package/prompts/explore-harness.md +7 -0
  335. package/prompts/explore.md +7 -0
  336. package/prompts/git-master.md +8 -1
  337. package/prompts/planner.md +10 -3
  338. package/prompts/researcher.md +7 -0
  339. package/prompts/security-reviewer.md +76 -92
  340. package/prompts/sisyphus-lite.md +7 -0
  341. package/prompts/team-executor.md +7 -0
  342. package/prompts/team-orchestrator.md +9 -2
  343. package/prompts/test-engineer.md +11 -3
  344. package/prompts/verifier.md +7 -0
  345. package/prompts/vision.md +9 -2
  346. package/prompts/writer.md +11 -4
  347. package/skills/.agents/skills/roblox-animations/SKILL.md +220 -0
  348. package/skills/.agents/skills/roblox-datastores/SKILL.md +219 -0
  349. package/skills/.agents/skills/roblox-gui/SKILL.md +192 -0
  350. package/skills/.agents/skills/roblox-monetization/SKILL.md +208 -0
  351. package/skills/.agents/skills/roblox-performance/SKILL.md +230 -0
  352. package/skills/.agents/skills/roblox-remote-events/SKILL.md +199 -0
  353. package/skills/.agents/skills/roblox-security/SKILL.md +236 -0
  354. package/skills/ai-slop-cleaner/SKILL.md +14 -7
  355. package/skills/analyze/SKILL.md +9 -2
  356. package/skills/ask-claude/SKILL.md +7 -0
  357. package/skills/ask-gemini/SKILL.md +7 -0
  358. package/skills/autoforge/SKILL.md +7 -0
  359. package/skills/autopilot/SKILL.md +48 -41
  360. package/skills/autoresearch/SKILL.md +8 -1
  361. package/skills/blueprint/SKILL.md +227 -9
  362. package/skills/blueprint-loop/SKILL.md +7 -0
  363. package/skills/blueprint-psych/SKILL.md +7 -0
  364. package/skills/blueprint-retention/SKILL.md +7 -0
  365. package/skills/blueprint-social/SKILL.md +7 -0
  366. package/skills/brief/SKILL.md +7 -0
  367. package/skills/brief-audience/SKILL.md +7 -0
  368. package/skills/brief-motivation/SKILL.md +7 -0
  369. package/skills/build-fix/SKILL.md +9 -2
  370. package/skills/cancel/SKILL.md +59 -52
  371. package/skills/code-review/SKILL.md +30 -24
  372. package/skills/configure-notifications/SKILL.md +7 -0
  373. package/skills/crew/SKILL.md +7 -0
  374. package/skills/deep-interview/SKILL.md +25 -18
  375. package/skills/deepsearch/SKILL.md +7 -0
  376. package/skills/doctor/SKILL.md +7 -0
  377. package/skills/ecomode/SKILL.md +9 -2
  378. package/skills/forge/SKILL.md +174 -11
  379. package/skills/forge-community/SKILL.md +7 -0
  380. package/skills/forge-daily-loop/SKILL.md +7 -0
  381. package/skills/forge-event-loop/SKILL.md +7 -0
  382. package/skills/forge-fomo/SKILL.md +7 -0
  383. package/skills/{ralph-init → forge-init}/SKILL.md +20 -13
  384. package/skills/forge-mastery/SKILL.md +7 -0
  385. package/skills/forge-progression/SKILL.md +7 -0
  386. package/skills/forge-reward-loop/SKILL.md +7 -0
  387. package/skills/forge-status/SKILL.md +7 -0
  388. package/skills/git-master/SKILL.md +7 -0
  389. package/skills/help/SKILL.md +8 -1
  390. package/skills/hud/SKILL.md +16 -9
  391. package/skills/note/SKILL.md +8 -1
  392. package/skills/pipeline/SKILL.md +18 -11
  393. package/skills/plan/SKILL.md +36 -29
  394. package/skills/rcs-setup/SKILL.md +8 -1
  395. package/skills/review/SKILL.md +7 -0
  396. package/skills/security-review/SKILL.md +120 -236
  397. package/skills/skill/SKILL.md +20 -13
  398. package/skills/skills-lock.json +47 -0
  399. package/skills/swarm/SKILL.md +8 -1
  400. package/skills/tdd/SKILL.md +7 -0
  401. package/skills/team/SKILL.md +17 -11
  402. package/skills/trace/SKILL.md +7 -0
  403. package/skills/ultraqa/SKILL.md +10 -3
  404. package/skills/ultrawork/SKILL.md +19 -12
  405. package/skills/{visual-ralph → visual-forge}/SKILL.md +36 -27
  406. package/skills/visual-verdict/SKILL.md +9 -2
  407. package/skills/web-clone/SKILL.md +14 -7
  408. package/skills/wiki/SKILL.md +10 -3
  409. package/skills/worker/SKILL.md +16 -7
  410. package/src/scripts/__tests__/codex-native-hook.test.ts +386 -319
  411. package/src/scripts/__tests__/run-test-files.test.ts +6 -4
  412. package/src/scripts/__tests__/verify-native-agents.test.ts +16 -16
  413. package/src/scripts/codex-native-hook.ts +34 -34
  414. package/src/scripts/eval/eval-cross-server-party-flow.ts +14 -0
  415. package/src/scripts/eval/eval-gui-onboarding-clarity.ts +20 -0
  416. package/src/scripts/eval/eval-liveops-reward-loop-balance.ts +14 -0
  417. package/src/scripts/eval/eval-profile-datastore-recovery.ts +20 -0
  418. package/src/scripts/eval/eval-remote-contract-hardening.ts +20 -0
  419. package/src/scripts/notify-fallback-watcher.ts +147 -146
  420. package/src/scripts/notify-hook/__tests__/team-worker-posttooluse.test.ts +24 -10
  421. package/src/scripts/notify-hook/{ralph-session-resume.ts → forge-session-resume.ts} +45 -43
  422. package/src/scripts/notify-hook/team-dispatch.ts +31 -4
  423. package/src/scripts/notify-hook/visual-verdict.ts +3 -3
  424. package/src/scripts/notify-hook.ts +10 -10
  425. package/src/scripts/run-test-files.ts +1 -1
  426. package/src/scripts/surface-taxonomy.ts +316 -0
  427. package/src/scripts/sync-plugin-mirror.ts +5 -4
  428. package/src/scripts/tmux-hook-engine.ts +31 -19
  429. package/templates/AGENTS.md +24 -15
  430. package/templates/catalog-manifest.json +5 -88
  431. package/templates/roblox/pre-action-plan.md +1 -0
  432. package/templates/roblox/robloxstudio-mcp.codex.json +18 -0
  433. package/templates/roblox/robloxstudio-mcp.windows.json +22 -0
  434. package/dist/adapt/__tests__/foundation.test.d.ts +0 -2
  435. package/dist/adapt/__tests__/foundation.test.d.ts.map +0 -1
  436. package/dist/adapt/__tests__/foundation.test.js +0 -171
  437. package/dist/adapt/__tests__/foundation.test.js.map +0 -1
  438. package/dist/adapt/__tests__/hermes.test.d.ts +0 -2
  439. package/dist/adapt/__tests__/hermes.test.d.ts.map +0 -1
  440. package/dist/adapt/__tests__/hermes.test.js +0 -137
  441. package/dist/adapt/__tests__/hermes.test.js.map +0 -1
  442. package/dist/agents/__tests__/definitions.test.d.ts +0 -2
  443. package/dist/agents/__tests__/definitions.test.d.ts.map +0 -1
  444. package/dist/agents/__tests__/definitions.test.js +0 -62
  445. package/dist/agents/__tests__/definitions.test.js.map +0 -1
  446. package/dist/agents/__tests__/native-config.test.d.ts +0 -2
  447. package/dist/agents/__tests__/native-config.test.d.ts.map +0 -1
  448. package/dist/agents/__tests__/native-config.test.js +0 -278
  449. package/dist/agents/__tests__/native-config.test.js.map +0 -1
  450. package/dist/autoresearch/__tests__/contracts.test.d.ts +0 -2
  451. package/dist/autoresearch/__tests__/contracts.test.d.ts.map +0 -1
  452. package/dist/autoresearch/__tests__/contracts.test.js +0 -127
  453. package/dist/autoresearch/__tests__/contracts.test.js.map +0 -1
  454. package/dist/autoresearch/__tests__/runtime-parity-extra.test.d.ts +0 -2
  455. package/dist/autoresearch/__tests__/runtime-parity-extra.test.d.ts.map +0 -1
  456. package/dist/autoresearch/__tests__/runtime-parity-extra.test.js +0 -356
  457. package/dist/autoresearch/__tests__/runtime-parity-extra.test.js.map +0 -1
  458. package/dist/autoresearch/__tests__/runtime.test.d.ts +0 -2
  459. package/dist/autoresearch/__tests__/runtime.test.d.ts.map +0 -1
  460. package/dist/autoresearch/__tests__/runtime.test.js +0 -218
  461. package/dist/autoresearch/__tests__/runtime.test.js.map +0 -1
  462. package/dist/autoresearch/__tests__/skill-validation.test.d.ts +0 -2
  463. package/dist/autoresearch/__tests__/skill-validation.test.d.ts.map +0 -1
  464. package/dist/autoresearch/__tests__/skill-validation.test.js +0 -91
  465. package/dist/autoresearch/__tests__/skill-validation.test.js.map +0 -1
  466. package/dist/catalog/__tests__/generator.test.d.ts +0 -2
  467. package/dist/catalog/__tests__/generator.test.d.ts.map +0 -1
  468. package/dist/catalog/__tests__/generator.test.js +0 -49
  469. package/dist/catalog/__tests__/generator.test.js.map +0 -1
  470. package/dist/catalog/__tests__/plugin-bundle-ssot.test.d.ts +0 -2
  471. package/dist/catalog/__tests__/plugin-bundle-ssot.test.d.ts.map +0 -1
  472. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +0 -83
  473. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +0 -1
  474. package/dist/catalog/__tests__/schema.test.d.ts +0 -2
  475. package/dist/catalog/__tests__/schema.test.d.ts.map +0 -1
  476. package/dist/catalog/__tests__/schema.test.js +0 -91
  477. package/dist/catalog/__tests__/schema.test.js.map +0 -1
  478. package/dist/cli/__tests__/adapt-help.test.d.ts +0 -2
  479. package/dist/cli/__tests__/adapt-help.test.d.ts.map +0 -1
  480. package/dist/cli/__tests__/adapt-help.test.js +0 -37
  481. package/dist/cli/__tests__/adapt-help.test.js.map +0 -1
  482. package/dist/cli/__tests__/adapt.test.d.ts +0 -2
  483. package/dist/cli/__tests__/adapt.test.d.ts.map +0 -1
  484. package/dist/cli/__tests__/adapt.test.js +0 -62
  485. package/dist/cli/__tests__/adapt.test.js.map +0 -1
  486. package/dist/cli/__tests__/agents-init.test.d.ts +0 -2
  487. package/dist/cli/__tests__/agents-init.test.d.ts.map +0 -1
  488. package/dist/cli/__tests__/agents-init.test.js +0 -184
  489. package/dist/cli/__tests__/agents-init.test.js.map +0 -1
  490. package/dist/cli/__tests__/agents.test.d.ts +0 -2
  491. package/dist/cli/__tests__/agents.test.d.ts.map +0 -1
  492. package/dist/cli/__tests__/agents.test.js +0 -137
  493. package/dist/cli/__tests__/agents.test.js.map +0 -1
  494. package/dist/cli/__tests__/ask.test.d.ts +0 -2
  495. package/dist/cli/__tests__/ask.test.d.ts.map +0 -1
  496. package/dist/cli/__tests__/ask.test.js +0 -265
  497. package/dist/cli/__tests__/ask.test.js.map +0 -1
  498. package/dist/cli/__tests__/autoresearch-guided.test.d.ts +0 -2
  499. package/dist/cli/__tests__/autoresearch-guided.test.d.ts.map +0 -1
  500. package/dist/cli/__tests__/autoresearch-guided.test.js +0 -365
  501. package/dist/cli/__tests__/autoresearch-guided.test.js.map +0 -1
  502. package/dist/cli/__tests__/autoresearch.test.d.ts +0 -2
  503. package/dist/cli/__tests__/autoresearch.test.d.ts.map +0 -1
  504. package/dist/cli/__tests__/autoresearch.test.js +0 -203
  505. package/dist/cli/__tests__/autoresearch.test.js.map +0 -1
  506. package/dist/cli/__tests__/catalog-contract.test.d.ts +0 -2
  507. package/dist/cli/__tests__/catalog-contract.test.d.ts.map +0 -1
  508. package/dist/cli/__tests__/catalog-contract.test.js +0 -18
  509. package/dist/cli/__tests__/catalog-contract.test.js.map +0 -1
  510. package/dist/cli/__tests__/cleanup.test.d.ts +0 -2
  511. package/dist/cli/__tests__/cleanup.test.d.ts.map +0 -1
  512. package/dist/cli/__tests__/cleanup.test.js +0 -419
  513. package/dist/cli/__tests__/cleanup.test.js.map +0 -1
  514. package/dist/cli/__tests__/codex-plugin-layout.test.d.ts +0 -2
  515. package/dist/cli/__tests__/codex-plugin-layout.test.d.ts.map +0 -1
  516. package/dist/cli/__tests__/codex-plugin-layout.test.js +0 -210
  517. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +0 -1
  518. package/dist/cli/__tests__/doctor-context-window-warning.test.d.ts +0 -2
  519. package/dist/cli/__tests__/doctor-context-window-warning.test.d.ts.map +0 -1
  520. package/dist/cli/__tests__/doctor-context-window-warning.test.js +0 -122
  521. package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +0 -1
  522. package/dist/cli/__tests__/doctor-invalid-config.test.d.ts +0 -2
  523. package/dist/cli/__tests__/doctor-invalid-config.test.d.ts.map +0 -1
  524. package/dist/cli/__tests__/doctor-invalid-config.test.js +0 -52
  525. package/dist/cli/__tests__/doctor-invalid-config.test.js.map +0 -1
  526. package/dist/cli/__tests__/doctor-team.test.d.ts +0 -2
  527. package/dist/cli/__tests__/doctor-team.test.d.ts.map +0 -1
  528. package/dist/cli/__tests__/doctor-team.test.js +0 -299
  529. package/dist/cli/__tests__/doctor-team.test.js.map +0 -1
  530. package/dist/cli/__tests__/doctor-warning-copy.test.d.ts +0 -2
  531. package/dist/cli/__tests__/doctor-warning-copy.test.d.ts.map +0 -1
  532. package/dist/cli/__tests__/doctor-warning-copy.test.js +0 -438
  533. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +0 -1
  534. package/dist/cli/__tests__/error-handling-warnings.test.d.ts +0 -2
  535. package/dist/cli/__tests__/error-handling-warnings.test.d.ts.map +0 -1
  536. package/dist/cli/__tests__/error-handling-warnings.test.js +0 -52
  537. package/dist/cli/__tests__/error-handling-warnings.test.js.map +0 -1
  538. package/dist/cli/__tests__/exec.test.d.ts +0 -2
  539. package/dist/cli/__tests__/exec.test.d.ts.map +0 -1
  540. package/dist/cli/__tests__/exec.test.js +0 -213
  541. package/dist/cli/__tests__/exec.test.js.map +0 -1
  542. package/dist/cli/__tests__/explore-windows-diagnostics.test.d.ts +0 -2
  543. package/dist/cli/__tests__/explore-windows-diagnostics.test.d.ts.map +0 -1
  544. package/dist/cli/__tests__/explore-windows-diagnostics.test.js +0 -17
  545. package/dist/cli/__tests__/explore-windows-diagnostics.test.js.map +0 -1
  546. package/dist/cli/__tests__/explore.test.d.ts +0 -2
  547. package/dist/cli/__tests__/explore.test.d.ts.map +0 -1
  548. package/dist/cli/__tests__/explore.test.js +0 -1090
  549. package/dist/cli/__tests__/explore.test.js.map +0 -1
  550. package/dist/cli/__tests__/hooks.test.d.ts +0 -2
  551. package/dist/cli/__tests__/hooks.test.d.ts.map +0 -1
  552. package/dist/cli/__tests__/hooks.test.js +0 -55
  553. package/dist/cli/__tests__/hooks.test.js.map +0 -1
  554. package/dist/cli/__tests__/index.test.d.ts +0 -2
  555. package/dist/cli/__tests__/index.test.d.ts.map +0 -1
  556. package/dist/cli/__tests__/index.test.js +0 -2259
  557. package/dist/cli/__tests__/index.test.js.map +0 -1
  558. package/dist/cli/__tests__/launch-fallback.test.d.ts +0 -2
  559. package/dist/cli/__tests__/launch-fallback.test.d.ts.map +0 -1
  560. package/dist/cli/__tests__/launch-fallback.test.js +0 -661
  561. package/dist/cli/__tests__/launch-fallback.test.js.map +0 -1
  562. package/dist/cli/__tests__/lifecycle-notifications.test.d.ts +0 -2
  563. package/dist/cli/__tests__/lifecycle-notifications.test.d.ts.map +0 -1
  564. package/dist/cli/__tests__/lifecycle-notifications.test.js +0 -48
  565. package/dist/cli/__tests__/lifecycle-notifications.test.js.map +0 -1
  566. package/dist/cli/__tests__/list.test.d.ts +0 -2
  567. package/dist/cli/__tests__/list.test.d.ts.map +0 -1
  568. package/dist/cli/__tests__/list.test.js +0 -38
  569. package/dist/cli/__tests__/list.test.js.map +0 -1
  570. package/dist/cli/__tests__/mcp-parity.test.d.ts +0 -2
  571. package/dist/cli/__tests__/mcp-parity.test.d.ts.map +0 -1
  572. package/dist/cli/__tests__/mcp-parity.test.js +0 -228
  573. package/dist/cli/__tests__/mcp-parity.test.js.map +0 -1
  574. package/dist/cli/__tests__/mcp-serve.test.d.ts +0 -2
  575. package/dist/cli/__tests__/mcp-serve.test.d.ts.map +0 -1
  576. package/dist/cli/__tests__/mcp-serve.test.js +0 -64
  577. package/dist/cli/__tests__/mcp-serve.test.js.map +0 -1
  578. package/dist/cli/__tests__/native-assets.test.d.ts +0 -2
  579. package/dist/cli/__tests__/native-assets.test.d.ts.map +0 -1
  580. package/dist/cli/__tests__/native-assets.test.js +0 -308
  581. package/dist/cli/__tests__/native-assets.test.js.map +0 -1
  582. package/dist/cli/__tests__/native-hook-dispatch-contract.test.d.ts +0 -2
  583. package/dist/cli/__tests__/native-hook-dispatch-contract.test.d.ts.map +0 -1
  584. package/dist/cli/__tests__/native-hook-dispatch-contract.test.js +0 -11
  585. package/dist/cli/__tests__/native-hook-dispatch-contract.test.js.map +0 -1
  586. package/dist/cli/__tests__/nested-help-routing.test.d.ts +0 -2
  587. package/dist/cli/__tests__/nested-help-routing.test.d.ts.map +0 -1
  588. package/dist/cli/__tests__/nested-help-routing.test.js +0 -96
  589. package/dist/cli/__tests__/nested-help-routing.test.js.map +0 -1
  590. package/dist/cli/__tests__/package-bin-contract.test.d.ts +0 -2
  591. package/dist/cli/__tests__/package-bin-contract.test.d.ts.map +0 -1
  592. package/dist/cli/__tests__/package-bin-contract.test.js +0 -177
  593. package/dist/cli/__tests__/package-bin-contract.test.js.map +0 -1
  594. package/dist/cli/__tests__/packaged-explore-harness-lock.d.ts +0 -3
  595. package/dist/cli/__tests__/packaged-explore-harness-lock.d.ts.map +0 -1
  596. package/dist/cli/__tests__/packaged-explore-harness-lock.js +0 -67
  597. package/dist/cli/__tests__/packaged-explore-harness-lock.js.map +0 -1
  598. package/dist/cli/__tests__/packaged-script-resolution.test.d.ts +0 -2
  599. package/dist/cli/__tests__/packaged-script-resolution.test.d.ts.map +0 -1
  600. package/dist/cli/__tests__/packaged-script-resolution.test.js +0 -19
  601. package/dist/cli/__tests__/packaged-script-resolution.test.js.map +0 -1
  602. package/dist/cli/__tests__/prompt-skill-sanitization.test.d.ts +0 -2
  603. package/dist/cli/__tests__/prompt-skill-sanitization.test.d.ts.map +0 -1
  604. package/dist/cli/__tests__/prompt-skill-sanitization.test.js +0 -48
  605. package/dist/cli/__tests__/prompt-skill-sanitization.test.js.map +0 -1
  606. package/dist/cli/__tests__/question.test.d.ts +0 -2
  607. package/dist/cli/__tests__/question.test.d.ts.map +0 -1
  608. package/dist/cli/__tests__/question.test.js +0 -633
  609. package/dist/cli/__tests__/question.test.js.map +0 -1
  610. package/dist/cli/__tests__/ralph-deslop-contract.test.d.ts +0 -2
  611. package/dist/cli/__tests__/ralph-deslop-contract.test.d.ts.map +0 -1
  612. package/dist/cli/__tests__/ralph-deslop-contract.test.js +0 -28
  613. package/dist/cli/__tests__/ralph-deslop-contract.test.js.map +0 -1
  614. package/dist/cli/__tests__/ralph-prd-deep-interview.test.d.ts +0 -2
  615. package/dist/cli/__tests__/ralph-prd-deep-interview.test.d.ts.map +0 -1
  616. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js +0 -24
  617. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +0 -1
  618. package/dist/cli/__tests__/ralph-prd-smoke.test.d.ts +0 -2
  619. package/dist/cli/__tests__/ralph-prd-smoke.test.d.ts.map +0 -1
  620. package/dist/cli/__tests__/ralph-prd-smoke.test.js +0 -167
  621. package/dist/cli/__tests__/ralph-prd-smoke.test.js.map +0 -1
  622. package/dist/cli/__tests__/ralph.test.d.ts +0 -2
  623. package/dist/cli/__tests__/ralph.test.d.ts.map +0 -1
  624. package/dist/cli/__tests__/ralph.test.js +0 -256
  625. package/dist/cli/__tests__/ralph.test.js.map +0 -1
  626. package/dist/cli/__tests__/resume.test.d.ts +0 -2
  627. package/dist/cli/__tests__/resume.test.d.ts.map +0 -1
  628. package/dist/cli/__tests__/resume.test.js +0 -84
  629. package/dist/cli/__tests__/resume.test.js.map +0 -1
  630. package/dist/cli/__tests__/session-scoped-runtime.test.d.ts +0 -2
  631. package/dist/cli/__tests__/session-scoped-runtime.test.d.ts.map +0 -1
  632. package/dist/cli/__tests__/session-scoped-runtime.test.js +0 -146
  633. package/dist/cli/__tests__/session-scoped-runtime.test.js.map +0 -1
  634. package/dist/cli/__tests__/session-search-help.test.d.ts +0 -2
  635. package/dist/cli/__tests__/session-search-help.test.d.ts.map +0 -1
  636. package/dist/cli/__tests__/session-search-help.test.js +0 -76
  637. package/dist/cli/__tests__/session-search-help.test.js.map +0 -1
  638. package/dist/cli/__tests__/session-search.test.d.ts +0 -2
  639. package/dist/cli/__tests__/session-search.test.d.ts.map +0 -1
  640. package/dist/cli/__tests__/session-search.test.js +0 -77
  641. package/dist/cli/__tests__/session-search.test.js.map +0 -1
  642. package/dist/cli/__tests__/setup-agents-overwrite.test.d.ts +0 -2
  643. package/dist/cli/__tests__/setup-agents-overwrite.test.d.ts.map +0 -1
  644. package/dist/cli/__tests__/setup-agents-overwrite.test.js +0 -457
  645. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +0 -1
  646. package/dist/cli/__tests__/setup-gh-star.test.d.ts +0 -2
  647. package/dist/cli/__tests__/setup-gh-star.test.d.ts.map +0 -1
  648. package/dist/cli/__tests__/setup-gh-star.test.js +0 -67
  649. package/dist/cli/__tests__/setup-gh-star.test.js.map +0 -1
  650. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.d.ts +0 -2
  651. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.d.ts.map +0 -1
  652. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +0 -189
  653. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +0 -1
  654. package/dist/cli/__tests__/setup-install-mode.test.d.ts +0 -2
  655. package/dist/cli/__tests__/setup-install-mode.test.d.ts.map +0 -1
  656. package/dist/cli/__tests__/setup-install-mode.test.js +0 -873
  657. package/dist/cli/__tests__/setup-install-mode.test.js.map +0 -1
  658. package/dist/cli/__tests__/setup-prompts-overwrite.test.d.ts +0 -2
  659. package/dist/cli/__tests__/setup-prompts-overwrite.test.d.ts.map +0 -1
  660. package/dist/cli/__tests__/setup-prompts-overwrite.test.js +0 -191
  661. package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +0 -1
  662. package/dist/cli/__tests__/setup-refresh.test.d.ts +0 -2
  663. package/dist/cli/__tests__/setup-refresh.test.d.ts.map +0 -1
  664. package/dist/cli/__tests__/setup-refresh.test.js +0 -591
  665. package/dist/cli/__tests__/setup-refresh.test.js.map +0 -1
  666. package/dist/cli/__tests__/setup-scope.test.d.ts +0 -2
  667. package/dist/cli/__tests__/setup-scope.test.d.ts.map +0 -1
  668. package/dist/cli/__tests__/setup-scope.test.js +0 -340
  669. package/dist/cli/__tests__/setup-scope.test.js.map +0 -1
  670. package/dist/cli/__tests__/setup-skill-validation.test.d.ts +0 -2
  671. package/dist/cli/__tests__/setup-skill-validation.test.d.ts.map +0 -1
  672. package/dist/cli/__tests__/setup-skill-validation.test.js +0 -44
  673. package/dist/cli/__tests__/setup-skill-validation.test.js.map +0 -1
  674. package/dist/cli/__tests__/setup-skills-overwrite.test.d.ts +0 -2
  675. package/dist/cli/__tests__/setup-skills-overwrite.test.d.ts.map +0 -1
  676. package/dist/cli/__tests__/setup-skills-overwrite.test.js +0 -295
  677. package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +0 -1
  678. package/dist/cli/__tests__/sidecar.test.d.ts +0 -2
  679. package/dist/cli/__tests__/sidecar.test.d.ts.map +0 -1
  680. package/dist/cli/__tests__/sidecar.test.js +0 -24
  681. package/dist/cli/__tests__/sidecar.test.js.map +0 -1
  682. package/dist/cli/__tests__/sparkshell-cli.test.d.ts +0 -2
  683. package/dist/cli/__tests__/sparkshell-cli.test.d.ts.map +0 -1
  684. package/dist/cli/__tests__/sparkshell-cli.test.js +0 -400
  685. package/dist/cli/__tests__/sparkshell-cli.test.js.map +0 -1
  686. package/dist/cli/__tests__/sparkshell-packaging.test.d.ts +0 -2
  687. package/dist/cli/__tests__/sparkshell-packaging.test.d.ts.map +0 -1
  688. package/dist/cli/__tests__/sparkshell-packaging.test.js +0 -74
  689. package/dist/cli/__tests__/sparkshell-packaging.test.js.map +0 -1
  690. package/dist/cli/__tests__/star-prompt.test.d.ts +0 -2
  691. package/dist/cli/__tests__/star-prompt.test.d.ts.map +0 -1
  692. package/dist/cli/__tests__/star-prompt.test.js +0 -172
  693. package/dist/cli/__tests__/star-prompt.test.js.map +0 -1
  694. package/dist/cli/__tests__/state.test.d.ts +0 -2
  695. package/dist/cli/__tests__/state.test.d.ts.map +0 -1
  696. package/dist/cli/__tests__/state.test.js +0 -46
  697. package/dist/cli/__tests__/state.test.js.map +0 -1
  698. package/dist/cli/__tests__/team-decompose.test.d.ts +0 -2
  699. package/dist/cli/__tests__/team-decompose.test.d.ts.map +0 -1
  700. package/dist/cli/__tests__/team-decompose.test.js +0 -133
  701. package/dist/cli/__tests__/team-decompose.test.js.map +0 -1
  702. package/dist/cli/__tests__/team.test.d.ts +0 -2
  703. package/dist/cli/__tests__/team.test.d.ts.map +0 -1
  704. package/dist/cli/__tests__/team.test.js +0 -1820
  705. package/dist/cli/__tests__/team.test.js.map +0 -1
  706. package/dist/cli/__tests__/uninstall.test.d.ts +0 -2
  707. package/dist/cli/__tests__/uninstall.test.d.ts.map +0 -1
  708. package/dist/cli/__tests__/uninstall.test.js +0 -766
  709. package/dist/cli/__tests__/uninstall.test.js.map +0 -1
  710. package/dist/cli/__tests__/update.test.d.ts +0 -2
  711. package/dist/cli/__tests__/update.test.d.ts.map +0 -1
  712. package/dist/cli/__tests__/update.test.js +0 -589
  713. package/dist/cli/__tests__/update.test.js.map +0 -1
  714. package/dist/cli/__tests__/version-sync-contract.test.d.ts +0 -2
  715. package/dist/cli/__tests__/version-sync-contract.test.d.ts.map +0 -1
  716. package/dist/cli/__tests__/version-sync-contract.test.js +0 -41
  717. package/dist/cli/__tests__/version-sync-contract.test.js.map +0 -1
  718. package/dist/cli/__tests__/version.test.d.ts +0 -2
  719. package/dist/cli/__tests__/version.test.d.ts.map +0 -1
  720. package/dist/cli/__tests__/version.test.js +0 -21
  721. package/dist/cli/__tests__/version.test.js.map +0 -1
  722. package/dist/cli/__tests__/windows-popup-loop-contract.test.d.ts +0 -2
  723. package/dist/cli/__tests__/windows-popup-loop-contract.test.d.ts.map +0 -1
  724. package/dist/cli/__tests__/windows-popup-loop-contract.test.js +0 -31
  725. package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +0 -1
  726. package/dist/cli/ralph.d.ts +0 -17
  727. package/dist/compat/__tests__/doctor-contract.test.d.ts +0 -2
  728. package/dist/compat/__tests__/doctor-contract.test.d.ts.map +0 -1
  729. package/dist/compat/__tests__/doctor-contract.test.js +0 -108
  730. package/dist/compat/__tests__/doctor-contract.test.js.map +0 -1
  731. package/dist/compat/__tests__/rust-runtime-compat.test.d.ts +0 -2
  732. package/dist/compat/__tests__/rust-runtime-compat.test.d.ts.map +0 -1
  733. package/dist/compat/__tests__/rust-runtime-compat.test.js +0 -218
  734. package/dist/compat/__tests__/rust-runtime-compat.test.js.map +0 -1
  735. package/dist/config/__tests__/codex-hooks.test.d.ts +0 -2
  736. package/dist/config/__tests__/codex-hooks.test.d.ts.map +0 -1
  737. package/dist/config/__tests__/codex-hooks.test.js +0 -77
  738. package/dist/config/__tests__/codex-hooks.test.js.map +0 -1
  739. package/dist/config/__tests__/generator-idempotent.test.d.ts +0 -2
  740. package/dist/config/__tests__/generator-idempotent.test.d.ts.map +0 -1
  741. package/dist/config/__tests__/generator-idempotent.test.js +0 -882
  742. package/dist/config/__tests__/generator-idempotent.test.js.map +0 -1
  743. package/dist/config/__tests__/generator-notify.test.d.ts +0 -2
  744. package/dist/config/__tests__/generator-notify.test.d.ts.map +0 -1
  745. package/dist/config/__tests__/generator-notify.test.js +0 -343
  746. package/dist/config/__tests__/generator-notify.test.js.map +0 -1
  747. package/dist/config/__tests__/generator-status-line-presets.test.d.ts +0 -2
  748. package/dist/config/__tests__/generator-status-line-presets.test.d.ts.map +0 -1
  749. package/dist/config/__tests__/generator-status-line-presets.test.js +0 -203
  750. package/dist/config/__tests__/generator-status-line-presets.test.js.map +0 -1
  751. package/dist/config/__tests__/mcp-registry.test.d.ts +0 -2
  752. package/dist/config/__tests__/mcp-registry.test.d.ts.map +0 -1
  753. package/dist/config/__tests__/mcp-registry.test.js +0 -190
  754. package/dist/config/__tests__/mcp-registry.test.js.map +0 -1
  755. package/dist/config/__tests__/models.test.d.ts +0 -2
  756. package/dist/config/__tests__/models.test.d.ts.map +0 -1
  757. package/dist/config/__tests__/models.test.js +0 -224
  758. package/dist/config/__tests__/models.test.js.map +0 -1
  759. package/dist/config/__tests__/wiki-config-contract.test.d.ts +0 -2
  760. package/dist/config/__tests__/wiki-config-contract.test.d.ts.map +0 -1
  761. package/dist/config/__tests__/wiki-config-contract.test.js +0 -19
  762. package/dist/config/__tests__/wiki-config-contract.test.js.map +0 -1
  763. package/dist/document-refresh/__tests__/enforcer.test.d.ts +0 -2
  764. package/dist/document-refresh/__tests__/enforcer.test.d.ts.map +0 -1
  765. package/dist/document-refresh/__tests__/enforcer.test.js +0 -128
  766. package/dist/document-refresh/__tests__/enforcer.test.js.map +0 -1
  767. package/dist/hooks/__tests__/agents-overlay.test.d.ts +0 -8
  768. package/dist/hooks/__tests__/agents-overlay.test.d.ts.map +0 -1
  769. package/dist/hooks/__tests__/agents-overlay.test.js +0 -644
  770. package/dist/hooks/__tests__/agents-overlay.test.js.map +0 -1
  771. package/dist/hooks/__tests__/analyze-routing-contract.test.d.ts +0 -2
  772. package/dist/hooks/__tests__/analyze-routing-contract.test.d.ts.map +0 -1
  773. package/dist/hooks/__tests__/analyze-routing-contract.test.js +0 -45
  774. package/dist/hooks/__tests__/analyze-routing-contract.test.js.map +0 -1
  775. package/dist/hooks/__tests__/analyze-skill-contract.test.d.ts +0 -2
  776. package/dist/hooks/__tests__/analyze-skill-contract.test.d.ts.map +0 -1
  777. package/dist/hooks/__tests__/analyze-skill-contract.test.js +0 -48
  778. package/dist/hooks/__tests__/analyze-skill-contract.test.js.map +0 -1
  779. package/dist/hooks/__tests__/anti-slop-workflow.test.d.ts +0 -2
  780. package/dist/hooks/__tests__/anti-slop-workflow.test.d.ts.map +0 -1
  781. package/dist/hooks/__tests__/anti-slop-workflow.test.js +0 -146
  782. package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +0 -1
  783. package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts +0 -2
  784. package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts.map +0 -1
  785. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +0 -37
  786. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +0 -1
  787. package/dist/hooks/__tests__/clawhip-event-contract.test.d.ts +0 -2
  788. package/dist/hooks/__tests__/clawhip-event-contract.test.d.ts.map +0 -1
  789. package/dist/hooks/__tests__/clawhip-event-contract.test.js +0 -37
  790. package/dist/hooks/__tests__/clawhip-event-contract.test.js.map +0 -1
  791. package/dist/hooks/__tests__/code-review-skill-contract.test.d.ts +0 -2
  792. package/dist/hooks/__tests__/code-review-skill-contract.test.d.ts.map +0 -1
  793. package/dist/hooks/__tests__/code-review-skill-contract.test.js +0 -56
  794. package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +0 -1
  795. package/dist/hooks/__tests__/codebase-map.test.d.ts +0 -8
  796. package/dist/hooks/__tests__/codebase-map.test.d.ts.map +0 -1
  797. package/dist/hooks/__tests__/codebase-map.test.js +0 -218
  798. package/dist/hooks/__tests__/codebase-map.test.js.map +0 -1
  799. package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts +0 -18
  800. package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts.map +0 -1
  801. package/dist/hooks/__tests__/consensus-execution-handoff.test.js +0 -234
  802. package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +0 -1
  803. package/dist/hooks/__tests__/debugger-log-recency-contract.test.d.ts +0 -2
  804. package/dist/hooks/__tests__/debugger-log-recency-contract.test.d.ts.map +0 -1
  805. package/dist/hooks/__tests__/debugger-log-recency-contract.test.js +0 -20
  806. package/dist/hooks/__tests__/debugger-log-recency-contract.test.js.map +0 -1
  807. package/dist/hooks/__tests__/deep-interview-contract.test.d.ts +0 -2
  808. package/dist/hooks/__tests__/deep-interview-contract.test.d.ts.map +0 -1
  809. package/dist/hooks/__tests__/deep-interview-contract.test.js +0 -213
  810. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +0 -1
  811. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.d.ts +0 -2
  812. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.d.ts.map +0 -1
  813. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.js +0 -43
  814. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.js.map +0 -1
  815. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.d.ts +0 -2
  816. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.d.ts.map +0 -1
  817. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.js +0 -38
  818. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.js.map +0 -1
  819. package/dist/hooks/__tests__/explore-routing.test.d.ts +0 -2
  820. package/dist/hooks/__tests__/explore-routing.test.d.ts.map +0 -1
  821. package/dist/hooks/__tests__/explore-routing.test.js +0 -43
  822. package/dist/hooks/__tests__/explore-routing.test.js.map +0 -1
  823. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.d.ts +0 -2
  824. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.d.ts.map +0 -1
  825. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js +0 -69
  826. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js.map +0 -1
  827. package/dist/hooks/__tests__/keyword-detector.test.d.ts +0 -2
  828. package/dist/hooks/__tests__/keyword-detector.test.d.ts.map +0 -1
  829. package/dist/hooks/__tests__/keyword-detector.test.js +0 -1716
  830. package/dist/hooks/__tests__/keyword-detector.test.js.map +0 -1
  831. package/dist/hooks/__tests__/notify-fallback-watcher.test.d.ts +0 -2
  832. package/dist/hooks/__tests__/notify-fallback-watcher.test.d.ts.map +0 -1
  833. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +0 -3898
  834. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +0 -1
  835. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.d.ts +0 -2
  836. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.d.ts.map +0 -1
  837. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +0 -786
  838. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +0 -1
  839. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.d.ts +0 -2
  840. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.d.ts.map +0 -1
  841. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +0 -2397
  842. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +0 -1
  843. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.d.ts +0 -2
  844. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.d.ts.map +0 -1
  845. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +0 -160
  846. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +0 -1
  847. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.d.ts +0 -2
  848. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.d.ts.map +0 -1
  849. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +0 -1178
  850. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +0 -1
  851. package/dist/hooks/__tests__/notify-hook-modules.test.d.ts +0 -9
  852. package/dist/hooks/__tests__/notify-hook-modules.test.d.ts.map +0 -1
  853. package/dist/hooks/__tests__/notify-hook-modules.test.js +0 -529
  854. package/dist/hooks/__tests__/notify-hook-modules.test.js.map +0 -1
  855. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.d.ts +0 -2
  856. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.d.ts.map +0 -1
  857. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.js +0 -14
  858. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.js.map +0 -1
  859. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.d.ts +0 -2
  860. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.d.ts.map +0 -1
  861. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +0 -682
  862. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +0 -1
  863. package/dist/hooks/__tests__/notify-hook-regression-205.test.d.ts +0 -9
  864. package/dist/hooks/__tests__/notify-hook-regression-205.test.d.ts.map +0 -1
  865. package/dist/hooks/__tests__/notify-hook-regression-205.test.js +0 -255
  866. package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +0 -1
  867. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.d.ts +0 -2
  868. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.d.ts.map +0 -1
  869. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js +0 -162
  870. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js.map +0 -1
  871. package/dist/hooks/__tests__/notify-hook-session-scope.test.d.ts +0 -2
  872. package/dist/hooks/__tests__/notify-hook-session-scope.test.d.ts.map +0 -1
  873. package/dist/hooks/__tests__/notify-hook-session-scope.test.js +0 -301
  874. package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +0 -1
  875. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.d.ts +0 -2
  876. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.d.ts.map +0 -1
  877. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +0 -1510
  878. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +0 -1
  879. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.d.ts +0 -2
  880. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.d.ts.map +0 -1
  881. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +0 -2879
  882. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +0 -1
  883. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.d.ts +0 -2
  884. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.d.ts.map +0 -1
  885. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +0 -228
  886. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +0 -1
  887. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts +0 -2
  888. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts.map +0 -1
  889. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js +0 -35
  890. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js.map +0 -1
  891. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.d.ts +0 -2
  892. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.d.ts.map +0 -1
  893. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +0 -1589
  894. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +0 -1
  895. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.d.ts +0 -10
  896. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.d.ts.map +0 -1
  897. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +0 -0
  898. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +0 -1
  899. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.d.ts +0 -11
  900. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.d.ts.map +0 -1
  901. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js +0 -266
  902. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js.map +0 -1
  903. package/dist/hooks/__tests__/notify-hook-worker-idle.test.d.ts +0 -2
  904. package/dist/hooks/__tests__/notify-hook-worker-idle.test.d.ts.map +0 -1
  905. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +0 -895
  906. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +0 -1
  907. package/dist/hooks/__tests__/openclaw-setup-contract.test.d.ts +0 -2
  908. package/dist/hooks/__tests__/openclaw-setup-contract.test.d.ts.map +0 -1
  909. package/dist/hooks/__tests__/openclaw-setup-contract.test.js +0 -61
  910. package/dist/hooks/__tests__/openclaw-setup-contract.test.js.map +0 -1
  911. package/dist/hooks/__tests__/pre-context-gate-skills.test.d.ts +0 -2
  912. package/dist/hooks/__tests__/pre-context-gate-skills.test.d.ts.map +0 -1
  913. package/dist/hooks/__tests__/pre-context-gate-skills.test.js +0 -40
  914. package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +0 -1
  915. package/dist/hooks/__tests__/prompt-guidance-catalog.test.d.ts +0 -2
  916. package/dist/hooks/__tests__/prompt-guidance-catalog.test.d.ts.map +0 -1
  917. package/dist/hooks/__tests__/prompt-guidance-catalog.test.js +0 -11
  918. package/dist/hooks/__tests__/prompt-guidance-catalog.test.js.map +0 -1
  919. package/dist/hooks/__tests__/prompt-guidance-contract.test.d.ts +0 -2
  920. package/dist/hooks/__tests__/prompt-guidance-contract.test.d.ts.map +0 -1
  921. package/dist/hooks/__tests__/prompt-guidance-contract.test.js +0 -38
  922. package/dist/hooks/__tests__/prompt-guidance-contract.test.js.map +0 -1
  923. package/dist/hooks/__tests__/prompt-guidance-fragments.test.d.ts +0 -2
  924. package/dist/hooks/__tests__/prompt-guidance-fragments.test.d.ts.map +0 -1
  925. package/dist/hooks/__tests__/prompt-guidance-fragments.test.js +0 -48
  926. package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +0 -1
  927. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.d.ts +0 -2
  928. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.d.ts.map +0 -1
  929. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.js +0 -11
  930. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.js.map +0 -1
  931. package/dist/hooks/__tests__/prompt-guidance-test-helpers.d.ts +0 -5
  932. package/dist/hooks/__tests__/prompt-guidance-test-helpers.d.ts.map +0 -1
  933. package/dist/hooks/__tests__/prompt-guidance-test-helpers.js +0 -34
  934. package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +0 -1
  935. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.d.ts +0 -2
  936. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.d.ts.map +0 -1
  937. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +0 -65
  938. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +0 -1
  939. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.d.ts +0 -2
  940. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.d.ts.map +0 -1
  941. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.js +0 -38
  942. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.js.map +0 -1
  943. package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts +0 -2
  944. package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts.map +0 -1
  945. package/dist/hooks/__tests__/prompt-refactor-contract.test.js +0 -22
  946. package/dist/hooks/__tests__/prompt-refactor-contract.test.js.map +0 -1
  947. package/dist/hooks/__tests__/prompt-team-routing.test.d.ts +0 -2
  948. package/dist/hooks/__tests__/prompt-team-routing.test.d.ts.map +0 -1
  949. package/dist/hooks/__tests__/prompt-team-routing.test.js +0 -49
  950. package/dist/hooks/__tests__/prompt-team-routing.test.js.map +0 -1
  951. package/dist/hooks/__tests__/session.test.d.ts +0 -2
  952. package/dist/hooks/__tests__/session.test.d.ts.map +0 -1
  953. package/dist/hooks/__tests__/session.test.js +0 -322
  954. package/dist/hooks/__tests__/session.test.js.map +0 -1
  955. package/dist/hooks/__tests__/skill-guidance-contract.test.d.ts +0 -2
  956. package/dist/hooks/__tests__/skill-guidance-contract.test.d.ts.map +0 -1
  957. package/dist/hooks/__tests__/skill-guidance-contract.test.js +0 -29
  958. package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +0 -1
  959. package/dist/hooks/__tests__/task-size-detector.test.d.ts +0 -2
  960. package/dist/hooks/__tests__/task-size-detector.test.d.ts.map +0 -1
  961. package/dist/hooks/__tests__/task-size-detector.test.js +0 -330
  962. package/dist/hooks/__tests__/task-size-detector.test.js.map +0 -1
  963. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.d.ts +0 -2
  964. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.d.ts.map +0 -1
  965. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js +0 -28
  966. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js.map +0 -1
  967. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.d.ts +0 -2
  968. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.d.ts.map +0 -1
  969. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.js +0 -24
  970. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.js.map +0 -1
  971. package/dist/hooks/__tests__/tmux-hook-engine.test.d.ts +0 -2
  972. package/dist/hooks/__tests__/tmux-hook-engine.test.d.ts.map +0 -1
  973. package/dist/hooks/__tests__/tmux-hook-engine.test.js +0 -403
  974. package/dist/hooks/__tests__/tmux-hook-engine.test.js.map +0 -1
  975. package/dist/hooks/__tests__/triage-config.test.d.ts +0 -2
  976. package/dist/hooks/__tests__/triage-config.test.d.ts.map +0 -1
  977. package/dist/hooks/__tests__/triage-config.test.js +0 -211
  978. package/dist/hooks/__tests__/triage-config.test.js.map +0 -1
  979. package/dist/hooks/__tests__/triage-heuristic.test.d.ts +0 -2
  980. package/dist/hooks/__tests__/triage-heuristic.test.d.ts.map +0 -1
  981. package/dist/hooks/__tests__/triage-heuristic.test.js +0 -285
  982. package/dist/hooks/__tests__/triage-heuristic.test.js.map +0 -1
  983. package/dist/hooks/__tests__/triage-state.test.d.ts +0 -2
  984. package/dist/hooks/__tests__/triage-state.test.d.ts.map +0 -1
  985. package/dist/hooks/__tests__/triage-state.test.js +0 -426
  986. package/dist/hooks/__tests__/triage-state.test.js.map +0 -1
  987. package/dist/hooks/__tests__/visual-ralph-skill.test.d.ts +0 -2
  988. package/dist/hooks/__tests__/visual-ralph-skill.test.d.ts.map +0 -1
  989. package/dist/hooks/__tests__/visual-ralph-skill.test.js +0 -44
  990. package/dist/hooks/__tests__/visual-ralph-skill.test.js.map +0 -1
  991. package/dist/hooks/__tests__/visual-verdict-loop.test.d.ts +0 -2
  992. package/dist/hooks/__tests__/visual-verdict-loop.test.d.ts.map +0 -1
  993. package/dist/hooks/__tests__/visual-verdict-loop.test.js +0 -35
  994. package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +0 -1
  995. package/dist/hooks/__tests__/wiki-docs-contract.test.d.ts +0 -2
  996. package/dist/hooks/__tests__/wiki-docs-contract.test.d.ts.map +0 -1
  997. package/dist/hooks/__tests__/wiki-docs-contract.test.js +0 -34
  998. package/dist/hooks/__tests__/wiki-docs-contract.test.js.map +0 -1
  999. package/dist/hooks/code-simplifier/__tests__/index.test.d.ts +0 -2
  1000. package/dist/hooks/code-simplifier/__tests__/index.test.d.ts.map +0 -1
  1001. package/dist/hooks/code-simplifier/__tests__/index.test.js +0 -187
  1002. package/dist/hooks/code-simplifier/__tests__/index.test.js.map +0 -1
  1003. package/dist/hooks/extensibility/__tests__/dispatcher.test.d.ts +0 -2
  1004. package/dist/hooks/extensibility/__tests__/dispatcher.test.d.ts.map +0 -1
  1005. package/dist/hooks/extensibility/__tests__/dispatcher.test.js +0 -242
  1006. package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +0 -1
  1007. package/dist/hooks/extensibility/__tests__/events.test.d.ts +0 -2
  1008. package/dist/hooks/extensibility/__tests__/events.test.d.ts.map +0 -1
  1009. package/dist/hooks/extensibility/__tests__/events.test.js +0 -125
  1010. package/dist/hooks/extensibility/__tests__/events.test.js.map +0 -1
  1011. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.d.ts +0 -2
  1012. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.d.ts.map +0 -1
  1013. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.js +0 -153
  1014. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.js.map +0 -1
  1015. package/dist/hooks/extensibility/__tests__/loader.test.d.ts +0 -2
  1016. package/dist/hooks/extensibility/__tests__/loader.test.d.ts.map +0 -1
  1017. package/dist/hooks/extensibility/__tests__/loader.test.js +0 -254
  1018. package/dist/hooks/extensibility/__tests__/loader.test.js.map +0 -1
  1019. package/dist/hooks/extensibility/__tests__/logging.test.d.ts +0 -2
  1020. package/dist/hooks/extensibility/__tests__/logging.test.d.ts.map +0 -1
  1021. package/dist/hooks/extensibility/__tests__/logging.test.js +0 -74
  1022. package/dist/hooks/extensibility/__tests__/logging.test.js.map +0 -1
  1023. package/dist/hooks/extensibility/__tests__/plugin-runner.test.d.ts +0 -2
  1024. package/dist/hooks/extensibility/__tests__/plugin-runner.test.d.ts.map +0 -1
  1025. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js +0 -202
  1026. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js.map +0 -1
  1027. package/dist/hooks/extensibility/__tests__/runtime.test.d.ts +0 -2
  1028. package/dist/hooks/extensibility/__tests__/runtime.test.d.ts.map +0 -1
  1029. package/dist/hooks/extensibility/__tests__/runtime.test.js +0 -198
  1030. package/dist/hooks/extensibility/__tests__/runtime.test.js.map +0 -1
  1031. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.d.ts +0 -2
  1032. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.d.ts.map +0 -1
  1033. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.js +0 -32
  1034. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.js.map +0 -1
  1035. package/dist/hooks/extensibility/__tests__/sdk.test.d.ts +0 -2
  1036. package/dist/hooks/extensibility/__tests__/sdk.test.d.ts.map +0 -1
  1037. package/dist/hooks/extensibility/__tests__/sdk.test.js +0 -479
  1038. package/dist/hooks/extensibility/__tests__/sdk.test.js.map +0 -1
  1039. package/dist/hud/__tests__/authority.test.d.ts +0 -2
  1040. package/dist/hud/__tests__/authority.test.d.ts.map +0 -1
  1041. package/dist/hud/__tests__/authority.test.js +0 -56
  1042. package/dist/hud/__tests__/authority.test.js.map +0 -1
  1043. package/dist/hud/__tests__/colors.test.d.ts +0 -2
  1044. package/dist/hud/__tests__/colors.test.d.ts.map +0 -1
  1045. package/dist/hud/__tests__/colors.test.js +0 -92
  1046. package/dist/hud/__tests__/colors.test.js.map +0 -1
  1047. package/dist/hud/__tests__/hud-tmux-injection.test.d.ts +0 -10
  1048. package/dist/hud/__tests__/hud-tmux-injection.test.d.ts.map +0 -1
  1049. package/dist/hud/__tests__/hud-tmux-injection.test.js +0 -150
  1050. package/dist/hud/__tests__/hud-tmux-injection.test.js.map +0 -1
  1051. package/dist/hud/__tests__/index.test.d.ts +0 -2
  1052. package/dist/hud/__tests__/index.test.d.ts.map +0 -1
  1053. package/dist/hud/__tests__/index.test.js +0 -180
  1054. package/dist/hud/__tests__/index.test.js.map +0 -1
  1055. package/dist/hud/__tests__/reconcile.test.d.ts +0 -2
  1056. package/dist/hud/__tests__/reconcile.test.d.ts.map +0 -1
  1057. package/dist/hud/__tests__/reconcile.test.js +0 -125
  1058. package/dist/hud/__tests__/reconcile.test.js.map +0 -1
  1059. package/dist/hud/__tests__/render.test.d.ts +0 -2
  1060. package/dist/hud/__tests__/render.test.d.ts.map +0 -1
  1061. package/dist/hud/__tests__/render.test.js +0 -573
  1062. package/dist/hud/__tests__/render.test.js.map +0 -1
  1063. package/dist/hud/__tests__/state.test.d.ts +0 -2
  1064. package/dist/hud/__tests__/state.test.d.ts.map +0 -1
  1065. package/dist/hud/__tests__/state.test.js +0 -618
  1066. package/dist/hud/__tests__/state.test.js.map +0 -1
  1067. package/dist/hud/__tests__/types.test.d.ts +0 -2
  1068. package/dist/hud/__tests__/types.test.d.ts.map +0 -1
  1069. package/dist/hud/__tests__/types.test.js +0 -79
  1070. package/dist/hud/__tests__/types.test.js.map +0 -1
  1071. package/dist/hud/__tests__/watch.test.d.ts +0 -2
  1072. package/dist/hud/__tests__/watch.test.d.ts.map +0 -1
  1073. package/dist/hud/__tests__/watch.test.js +0 -63
  1074. package/dist/hud/__tests__/watch.test.js.map +0 -1
  1075. package/dist/mcp/__tests__/bootstrap.test.d.ts +0 -2
  1076. package/dist/mcp/__tests__/bootstrap.test.d.ts.map +0 -1
  1077. package/dist/mcp/__tests__/bootstrap.test.js +0 -207
  1078. package/dist/mcp/__tests__/bootstrap.test.js.map +0 -1
  1079. package/dist/mcp/__tests__/code-intel-server.test.d.ts +0 -2
  1080. package/dist/mcp/__tests__/code-intel-server.test.d.ts.map +0 -1
  1081. package/dist/mcp/__tests__/code-intel-server.test.js +0 -70
  1082. package/dist/mcp/__tests__/code-intel-server.test.js.map +0 -1
  1083. package/dist/mcp/__tests__/memory-server.test.d.ts +0 -2
  1084. package/dist/mcp/__tests__/memory-server.test.d.ts.map +0 -1
  1085. package/dist/mcp/__tests__/memory-server.test.js +0 -36
  1086. package/dist/mcp/__tests__/memory-server.test.js.map +0 -1
  1087. package/dist/mcp/__tests__/memory-validation.test.d.ts +0 -2
  1088. package/dist/mcp/__tests__/memory-validation.test.d.ts.map +0 -1
  1089. package/dist/mcp/__tests__/memory-validation.test.js +0 -29
  1090. package/dist/mcp/__tests__/memory-validation.test.js.map +0 -1
  1091. package/dist/mcp/__tests__/path-traversal.test.d.ts +0 -2
  1092. package/dist/mcp/__tests__/path-traversal.test.d.ts.map +0 -1
  1093. package/dist/mcp/__tests__/path-traversal.test.js +0 -83
  1094. package/dist/mcp/__tests__/path-traversal.test.js.map +0 -1
  1095. package/dist/mcp/__tests__/server-lifecycle.test.d.ts +0 -2
  1096. package/dist/mcp/__tests__/server-lifecycle.test.d.ts.map +0 -1
  1097. package/dist/mcp/__tests__/server-lifecycle.test.js +0 -260
  1098. package/dist/mcp/__tests__/server-lifecycle.test.js.map +0 -1
  1099. package/dist/mcp/__tests__/state-paths.test.d.ts +0 -2
  1100. package/dist/mcp/__tests__/state-paths.test.d.ts.map +0 -1
  1101. package/dist/mcp/__tests__/state-paths.test.js +0 -209
  1102. package/dist/mcp/__tests__/state-paths.test.js.map +0 -1
  1103. package/dist/mcp/__tests__/state-server-ralph-phase.test.d.ts +0 -2
  1104. package/dist/mcp/__tests__/state-server-ralph-phase.test.d.ts.map +0 -1
  1105. package/dist/mcp/__tests__/state-server-ralph-phase.test.js +0 -109
  1106. package/dist/mcp/__tests__/state-server-ralph-phase.test.js.map +0 -1
  1107. package/dist/mcp/__tests__/state-server-schema.test.d.ts +0 -2
  1108. package/dist/mcp/__tests__/state-server-schema.test.d.ts.map +0 -1
  1109. package/dist/mcp/__tests__/state-server-schema.test.js +0 -29
  1110. package/dist/mcp/__tests__/state-server-schema.test.js.map +0 -1
  1111. package/dist/mcp/__tests__/state-server-team-tools.test.d.ts +0 -2
  1112. package/dist/mcp/__tests__/state-server-team-tools.test.d.ts.map +0 -1
  1113. package/dist/mcp/__tests__/state-server-team-tools.test.js +0 -35
  1114. package/dist/mcp/__tests__/state-server-team-tools.test.js.map +0 -1
  1115. package/dist/mcp/__tests__/state-server.test.d.ts +0 -2
  1116. package/dist/mcp/__tests__/state-server.test.d.ts.map +0 -1
  1117. package/dist/mcp/__tests__/state-server.test.js +0 -965
  1118. package/dist/mcp/__tests__/state-server.test.js.map +0 -1
  1119. package/dist/mcp/__tests__/trace-server.test.d.ts +0 -2
  1120. package/dist/mcp/__tests__/trace-server.test.d.ts.map +0 -1
  1121. package/dist/mcp/__tests__/trace-server.test.js +0 -119
  1122. package/dist/mcp/__tests__/trace-server.test.js.map +0 -1
  1123. package/dist/mcp/__tests__/wiki-server.test.d.ts +0 -2
  1124. package/dist/mcp/__tests__/wiki-server.test.d.ts.map +0 -1
  1125. package/dist/mcp/__tests__/wiki-server.test.js +0 -30
  1126. package/dist/mcp/__tests__/wiki-server.test.js.map +0 -1
  1127. package/dist/modes/__tests__/base-autoresearch-contract.test.d.ts +0 -2
  1128. package/dist/modes/__tests__/base-autoresearch-contract.test.d.ts.map +0 -1
  1129. package/dist/modes/__tests__/base-autoresearch-contract.test.js +0 -123
  1130. package/dist/modes/__tests__/base-autoresearch-contract.test.js.map +0 -1
  1131. package/dist/modes/__tests__/base-multi-state-compat.test.d.ts +0 -2
  1132. package/dist/modes/__tests__/base-multi-state-compat.test.d.ts.map +0 -1
  1133. package/dist/modes/__tests__/base-multi-state-compat.test.js +0 -38
  1134. package/dist/modes/__tests__/base-multi-state-compat.test.js.map +0 -1
  1135. package/dist/modes/__tests__/base-ralph-contract.test.d.ts +0 -2
  1136. package/dist/modes/__tests__/base-ralph-contract.test.d.ts.map +0 -1
  1137. package/dist/modes/__tests__/base-ralph-contract.test.js +0 -64
  1138. package/dist/modes/__tests__/base-ralph-contract.test.js.map +0 -1
  1139. package/dist/modes/__tests__/base-session-scope.test.d.ts +0 -2
  1140. package/dist/modes/__tests__/base-session-scope.test.d.ts.map +0 -1
  1141. package/dist/modes/__tests__/base-session-scope.test.js +0 -98
  1142. package/dist/modes/__tests__/base-session-scope.test.js.map +0 -1
  1143. package/dist/modes/__tests__/base-tmux-pane.test.d.ts +0 -2
  1144. package/dist/modes/__tests__/base-tmux-pane.test.d.ts.map +0 -1
  1145. package/dist/modes/__tests__/base-tmux-pane.test.js +0 -39
  1146. package/dist/modes/__tests__/base-tmux-pane.test.js.map +0 -1
  1147. package/dist/notifications/__tests__/config.test.d.ts +0 -2
  1148. package/dist/notifications/__tests__/config.test.d.ts.map +0 -1
  1149. package/dist/notifications/__tests__/config.test.js +0 -269
  1150. package/dist/notifications/__tests__/config.test.js.map +0 -1
  1151. package/dist/notifications/__tests__/custom-alias-enablement.test.d.ts +0 -2
  1152. package/dist/notifications/__tests__/custom-alias-enablement.test.d.ts.map +0 -1
  1153. package/dist/notifications/__tests__/custom-alias-enablement.test.js +0 -84
  1154. package/dist/notifications/__tests__/custom-alias-enablement.test.js.map +0 -1
  1155. package/dist/notifications/__tests__/dispatch-cooldown.test.d.ts +0 -5
  1156. package/dist/notifications/__tests__/dispatch-cooldown.test.d.ts.map +0 -1
  1157. package/dist/notifications/__tests__/dispatch-cooldown.test.js +0 -100
  1158. package/dist/notifications/__tests__/dispatch-cooldown.test.js.map +0 -1
  1159. package/dist/notifications/__tests__/dispatcher.test.d.ts +0 -2
  1160. package/dist/notifications/__tests__/dispatcher.test.d.ts.map +0 -1
  1161. package/dist/notifications/__tests__/dispatcher.test.js +0 -202
  1162. package/dist/notifications/__tests__/dispatcher.test.js.map +0 -1
  1163. package/dist/notifications/__tests__/formatter.test.d.ts +0 -2
  1164. package/dist/notifications/__tests__/formatter.test.d.ts.map +0 -1
  1165. package/dist/notifications/__tests__/formatter.test.js +0 -270
  1166. package/dist/notifications/__tests__/formatter.test.js.map +0 -1
  1167. package/dist/notifications/__tests__/hook-config.test.d.ts +0 -5
  1168. package/dist/notifications/__tests__/hook-config.test.d.ts.map +0 -1
  1169. package/dist/notifications/__tests__/hook-config.test.js +0 -139
  1170. package/dist/notifications/__tests__/hook-config.test.js.map +0 -1
  1171. package/dist/notifications/__tests__/idle-cooldown.test.d.ts +0 -5
  1172. package/dist/notifications/__tests__/idle-cooldown.test.d.ts.map +0 -1
  1173. package/dist/notifications/__tests__/idle-cooldown.test.js +0 -209
  1174. package/dist/notifications/__tests__/idle-cooldown.test.js.map +0 -1
  1175. package/dist/notifications/__tests__/index.test.d.ts +0 -2
  1176. package/dist/notifications/__tests__/index.test.d.ts.map +0 -1
  1177. package/dist/notifications/__tests__/index.test.js +0 -188
  1178. package/dist/notifications/__tests__/index.test.js.map +0 -1
  1179. package/dist/notifications/__tests__/lifecycle-dedupe.test.d.ts +0 -2
  1180. package/dist/notifications/__tests__/lifecycle-dedupe.test.d.ts.map +0 -1
  1181. package/dist/notifications/__tests__/lifecycle-dedupe.test.js +0 -86
  1182. package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +0 -1
  1183. package/dist/notifications/__tests__/notifier.test.d.ts +0 -2
  1184. package/dist/notifications/__tests__/notifier.test.d.ts.map +0 -1
  1185. package/dist/notifications/__tests__/notifier.test.js +0 -239
  1186. package/dist/notifications/__tests__/notifier.test.js.map +0 -1
  1187. package/dist/notifications/__tests__/profiles.test.d.ts +0 -2
  1188. package/dist/notifications/__tests__/profiles.test.d.ts.map +0 -1
  1189. package/dist/notifications/__tests__/profiles.test.js +0 -404
  1190. package/dist/notifications/__tests__/profiles.test.js.map +0 -1
  1191. package/dist/notifications/__tests__/reply-config.test.d.ts +0 -2
  1192. package/dist/notifications/__tests__/reply-config.test.d.ts.map +0 -1
  1193. package/dist/notifications/__tests__/reply-config.test.js +0 -79
  1194. package/dist/notifications/__tests__/reply-config.test.js.map +0 -1
  1195. package/dist/notifications/__tests__/reply-listener.test.d.ts +0 -2
  1196. package/dist/notifications/__tests__/reply-listener.test.d.ts.map +0 -1
  1197. package/dist/notifications/__tests__/reply-listener.test.js +0 -723
  1198. package/dist/notifications/__tests__/reply-listener.test.js.map +0 -1
  1199. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.d.ts +0 -2
  1200. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.d.ts.map +0 -1
  1201. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js +0 -93
  1202. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js.map +0 -1
  1203. package/dist/notifications/__tests__/session-registry.test.d.ts +0 -2
  1204. package/dist/notifications/__tests__/session-registry.test.d.ts.map +0 -1
  1205. package/dist/notifications/__tests__/session-registry.test.js +0 -234
  1206. package/dist/notifications/__tests__/session-registry.test.js.map +0 -1
  1207. package/dist/notifications/__tests__/session-status.test.d.ts +0 -2
  1208. package/dist/notifications/__tests__/session-status.test.d.ts.map +0 -1
  1209. package/dist/notifications/__tests__/session-status.test.js +0 -249
  1210. package/dist/notifications/__tests__/session-status.test.js.map +0 -1
  1211. package/dist/notifications/__tests__/temp-mode.test.d.ts +0 -2
  1212. package/dist/notifications/__tests__/temp-mode.test.d.ts.map +0 -1
  1213. package/dist/notifications/__tests__/temp-mode.test.js +0 -172
  1214. package/dist/notifications/__tests__/temp-mode.test.js.map +0 -1
  1215. package/dist/notifications/__tests__/template-engine.test.d.ts +0 -5
  1216. package/dist/notifications/__tests__/template-engine.test.d.ts.map +0 -1
  1217. package/dist/notifications/__tests__/template-engine.test.js +0 -158
  1218. package/dist/notifications/__tests__/template-engine.test.js.map +0 -1
  1219. package/dist/notifications/__tests__/tmux-detector.test.d.ts +0 -2
  1220. package/dist/notifications/__tests__/tmux-detector.test.d.ts.map +0 -1
  1221. package/dist/notifications/__tests__/tmux-detector.test.js +0 -208
  1222. package/dist/notifications/__tests__/tmux-detector.test.js.map +0 -1
  1223. package/dist/notifications/__tests__/tmux.test.d.ts +0 -2
  1224. package/dist/notifications/__tests__/tmux.test.d.ts.map +0 -1
  1225. package/dist/notifications/__tests__/tmux.test.js +0 -285
  1226. package/dist/notifications/__tests__/tmux.test.js.map +0 -1
  1227. package/dist/notifications/__tests__/verbosity.test.d.ts +0 -2
  1228. package/dist/notifications/__tests__/verbosity.test.d.ts.map +0 -1
  1229. package/dist/notifications/__tests__/verbosity.test.js +0 -237
  1230. package/dist/notifications/__tests__/verbosity.test.js.map +0 -1
  1231. package/dist/openclaw/__tests__/config.test.d.ts +0 -6
  1232. package/dist/openclaw/__tests__/config.test.d.ts.map +0 -1
  1233. package/dist/openclaw/__tests__/config.test.js +0 -344
  1234. package/dist/openclaw/__tests__/config.test.js.map +0 -1
  1235. package/dist/openclaw/__tests__/dispatcher.test.d.ts +0 -5
  1236. package/dist/openclaw/__tests__/dispatcher.test.d.ts.map +0 -1
  1237. package/dist/openclaw/__tests__/dispatcher.test.js +0 -169
  1238. package/dist/openclaw/__tests__/dispatcher.test.js.map +0 -1
  1239. package/dist/openclaw/__tests__/index.test.d.ts +0 -6
  1240. package/dist/openclaw/__tests__/index.test.d.ts.map +0 -1
  1241. package/dist/openclaw/__tests__/index.test.js +0 -382
  1242. package/dist/openclaw/__tests__/index.test.js.map +0 -1
  1243. package/dist/pipeline/__tests__/orchestrator.test.d.ts +0 -2
  1244. package/dist/pipeline/__tests__/orchestrator.test.d.ts.map +0 -1
  1245. package/dist/pipeline/__tests__/orchestrator.test.js +0 -505
  1246. package/dist/pipeline/__tests__/orchestrator.test.js.map +0 -1
  1247. package/dist/pipeline/__tests__/stages.test.d.ts +0 -2
  1248. package/dist/pipeline/__tests__/stages.test.d.ts.map +0 -1
  1249. package/dist/pipeline/__tests__/stages.test.js +0 -754
  1250. package/dist/pipeline/__tests__/stages.test.js.map +0 -1
  1251. package/dist/pipeline/stages/ralph-verify.d.ts +0 -53
  1252. package/dist/pipeline/stages/ralph-verify.d.ts.map +0 -1
  1253. package/dist/pipeline/stages/ralph-verify.js.map +0 -1
  1254. package/dist/pipeline/stages/ralplan.d.ts +0 -25
  1255. package/dist/pipeline/stages/ralplan.d.ts.map +0 -1
  1256. package/dist/pipeline/stages/ralplan.js.map +0 -1
  1257. package/dist/planning/__tests__/artifacts.test.d.ts +0 -2
  1258. package/dist/planning/__tests__/artifacts.test.d.ts.map +0 -1
  1259. package/dist/planning/__tests__/artifacts.test.js +0 -544
  1260. package/dist/planning/__tests__/artifacts.test.js.map +0 -1
  1261. package/dist/question/__tests__/client.test.d.ts +0 -2
  1262. package/dist/question/__tests__/client.test.d.ts.map +0 -1
  1263. package/dist/question/__tests__/client.test.js +0 -90
  1264. package/dist/question/__tests__/client.test.js.map +0 -1
  1265. package/dist/question/__tests__/deep-interview.test.d.ts +0 -2
  1266. package/dist/question/__tests__/deep-interview.test.d.ts.map +0 -1
  1267. package/dist/question/__tests__/deep-interview.test.js +0 -209
  1268. package/dist/question/__tests__/deep-interview.test.js.map +0 -1
  1269. package/dist/question/__tests__/policy.test.d.ts +0 -2
  1270. package/dist/question/__tests__/policy.test.d.ts.map +0 -1
  1271. package/dist/question/__tests__/policy.test.js +0 -107
  1272. package/dist/question/__tests__/policy.test.js.map +0 -1
  1273. package/dist/question/__tests__/renderer.test.d.ts +0 -2
  1274. package/dist/question/__tests__/renderer.test.d.ts.map +0 -1
  1275. package/dist/question/__tests__/renderer.test.js +0 -707
  1276. package/dist/question/__tests__/renderer.test.js.map +0 -1
  1277. package/dist/question/__tests__/state.test.d.ts +0 -2
  1278. package/dist/question/__tests__/state.test.d.ts.map +0 -1
  1279. package/dist/question/__tests__/state.test.js +0 -102
  1280. package/dist/question/__tests__/state.test.js.map +0 -1
  1281. package/dist/question/__tests__/types.test.d.ts +0 -2
  1282. package/dist/question/__tests__/types.test.d.ts.map +0 -1
  1283. package/dist/question/__tests__/types.test.js +0 -65
  1284. package/dist/question/__tests__/types.test.js.map +0 -1
  1285. package/dist/question/__tests__/ui.test.d.ts +0 -2
  1286. package/dist/question/__tests__/ui.test.d.ts.map +0 -1
  1287. package/dist/question/__tests__/ui.test.js +0 -446
  1288. package/dist/question/__tests__/ui.test.js.map +0 -1
  1289. package/dist/ralph/__tests__/persistence.test.d.ts +0 -2
  1290. package/dist/ralph/__tests__/persistence.test.d.ts.map +0 -1
  1291. package/dist/ralph/__tests__/persistence.test.js +0 -116
  1292. package/dist/ralph/__tests__/persistence.test.js.map +0 -1
  1293. package/dist/ralph/contract.d.ts +0 -17
  1294. package/dist/ralph/persistence.js.map +0 -1
  1295. package/dist/ralplan/__tests__/runtime.test.d.ts +0 -2
  1296. package/dist/ralplan/__tests__/runtime.test.d.ts.map +0 -1
  1297. package/dist/ralplan/__tests__/runtime.test.js +0 -165
  1298. package/dist/ralplan/__tests__/runtime.test.js.map +0 -1
  1299. package/dist/ralplan/runtime.d.ts +0 -52
  1300. package/dist/ralplan/runtime.d.ts.map +0 -1
  1301. package/dist/ralplan/runtime.js.map +0 -1
  1302. package/dist/runtime/__tests__/bridge.test.d.ts +0 -2
  1303. package/dist/runtime/__tests__/bridge.test.d.ts.map +0 -1
  1304. package/dist/runtime/__tests__/bridge.test.js +0 -194
  1305. package/dist/runtime/__tests__/bridge.test.js.map +0 -1
  1306. package/dist/runtime/__tests__/run-loop.test.d.ts +0 -2
  1307. package/dist/runtime/__tests__/run-loop.test.d.ts.map +0 -1
  1308. package/dist/runtime/__tests__/run-loop.test.js +0 -35
  1309. package/dist/runtime/__tests__/run-loop.test.js.map +0 -1
  1310. package/dist/runtime/__tests__/run-outcome.test.d.ts +0 -2
  1311. package/dist/runtime/__tests__/run-outcome.test.d.ts.map +0 -1
  1312. package/dist/runtime/__tests__/run-outcome.test.js +0 -102
  1313. package/dist/runtime/__tests__/run-outcome.test.js.map +0 -1
  1314. package/dist/runtime/__tests__/run-state.test.d.ts +0 -2
  1315. package/dist/runtime/__tests__/run-state.test.d.ts.map +0 -1
  1316. package/dist/runtime/__tests__/run-state.test.js +0 -37
  1317. package/dist/runtime/__tests__/run-state.test.js.map +0 -1
  1318. package/dist/scripts/__tests__/codex-native-hook.test.d.ts +0 -2
  1319. package/dist/scripts/__tests__/codex-native-hook.test.d.ts.map +0 -1
  1320. package/dist/scripts/__tests__/codex-native-hook.test.js +0 -6788
  1321. package/dist/scripts/__tests__/codex-native-hook.test.js.map +0 -1
  1322. package/dist/scripts/__tests__/generate-release-body.test.d.ts +0 -2
  1323. package/dist/scripts/__tests__/generate-release-body.test.d.ts.map +0 -1
  1324. package/dist/scripts/__tests__/generate-release-body.test.js +0 -233
  1325. package/dist/scripts/__tests__/generate-release-body.test.js.map +0 -1
  1326. package/dist/scripts/__tests__/hook-derived-watcher.test.d.ts +0 -2
  1327. package/dist/scripts/__tests__/hook-derived-watcher.test.d.ts.map +0 -1
  1328. package/dist/scripts/__tests__/hook-derived-watcher.test.js +0 -195
  1329. package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +0 -1
  1330. package/dist/scripts/__tests__/postinstall.test.d.ts +0 -2
  1331. package/dist/scripts/__tests__/postinstall.test.d.ts.map +0 -1
  1332. package/dist/scripts/__tests__/postinstall.test.js +0 -92
  1333. package/dist/scripts/__tests__/postinstall.test.js.map +0 -1
  1334. package/dist/scripts/__tests__/prompt-inventory.test.d.ts +0 -2
  1335. package/dist/scripts/__tests__/prompt-inventory.test.d.ts.map +0 -1
  1336. package/dist/scripts/__tests__/prompt-inventory.test.js +0 -56
  1337. package/dist/scripts/__tests__/prompt-inventory.test.js.map +0 -1
  1338. package/dist/scripts/__tests__/run-test-files.test.d.ts +0 -2
  1339. package/dist/scripts/__tests__/run-test-files.test.d.ts.map +0 -1
  1340. package/dist/scripts/__tests__/run-test-files.test.js +0 -62
  1341. package/dist/scripts/__tests__/run-test-files.test.js.map +0 -1
  1342. package/dist/scripts/__tests__/smoke-packed-install.test.d.ts +0 -2
  1343. package/dist/scripts/__tests__/smoke-packed-install.test.d.ts.map +0 -1
  1344. package/dist/scripts/__tests__/smoke-packed-install.test.js +0 -135
  1345. package/dist/scripts/__tests__/smoke-packed-install.test.js.map +0 -1
  1346. package/dist/scripts/__tests__/test-reply-listener-live.test.d.ts +0 -2
  1347. package/dist/scripts/__tests__/test-reply-listener-live.test.d.ts.map +0 -1
  1348. package/dist/scripts/__tests__/test-reply-listener-live.test.js +0 -82
  1349. package/dist/scripts/__tests__/test-reply-listener-live.test.js.map +0 -1
  1350. package/dist/scripts/__tests__/verify-native-agents.test.d.ts +0 -2
  1351. package/dist/scripts/__tests__/verify-native-agents.test.d.ts.map +0 -1
  1352. package/dist/scripts/__tests__/verify-native-agents.test.js +0 -166
  1353. package/dist/scripts/__tests__/verify-native-agents.test.js.map +0 -1
  1354. package/dist/scripts/eval/eval-candidate-handoff.d.ts +0 -2
  1355. package/dist/scripts/eval/eval-candidate-handoff.d.ts.map +0 -1
  1356. package/dist/scripts/eval/eval-candidate-handoff.js +0 -11
  1357. package/dist/scripts/eval/eval-candidate-handoff.js.map +0 -1
  1358. package/dist/scripts/eval/eval-cli-discoverability.d.ts +0 -3
  1359. package/dist/scripts/eval/eval-cli-discoverability.d.ts.map +0 -1
  1360. package/dist/scripts/eval/eval-cli-discoverability.js +0 -37
  1361. package/dist/scripts/eval/eval-cli-discoverability.js.map +0 -1
  1362. package/dist/scripts/eval/eval-fresh-run-tagging.d.ts +0 -2
  1363. package/dist/scripts/eval/eval-fresh-run-tagging.d.ts.map +0 -1
  1364. package/dist/scripts/eval/eval-fresh-run-tagging.js +0 -11
  1365. package/dist/scripts/eval/eval-fresh-run-tagging.js.map +0 -1
  1366. package/dist/scripts/eval/eval-help-consistency.d.ts +0 -2
  1367. package/dist/scripts/eval/eval-help-consistency.d.ts.map +0 -1
  1368. package/dist/scripts/eval/eval-help-consistency.js +0 -12
  1369. package/dist/scripts/eval/eval-help-consistency.js.map +0 -1
  1370. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.d.ts +0 -2
  1371. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.d.ts.map +0 -1
  1372. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.js +0 -31
  1373. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.js.map +0 -1
  1374. package/dist/scripts/eval/eval-parity-smoke.d.ts +0 -2
  1375. package/dist/scripts/eval/eval-parity-smoke.d.ts.map +0 -1
  1376. package/dist/scripts/eval/eval-parity-smoke.js +0 -23
  1377. package/dist/scripts/eval/eval-parity-smoke.js.map +0 -1
  1378. package/dist/scripts/eval/eval-parity-sweep.d.ts +0 -2
  1379. package/dist/scripts/eval/eval-parity-sweep.d.ts.map +0 -1
  1380. package/dist/scripts/eval/eval-parity-sweep.js +0 -29
  1381. package/dist/scripts/eval/eval-parity-sweep.js.map +0 -1
  1382. package/dist/scripts/eval/eval-resume-dirty-guard.d.ts +0 -2
  1383. package/dist/scripts/eval/eval-resume-dirty-guard.d.ts.map +0 -1
  1384. package/dist/scripts/eval/eval-resume-dirty-guard.js +0 -11
  1385. package/dist/scripts/eval/eval-resume-dirty-guard.js.map +0 -1
  1386. package/dist/scripts/eval/eval-security-path-traversal.d.ts +0 -3
  1387. package/dist/scripts/eval/eval-security-path-traversal.d.ts.map +0 -1
  1388. package/dist/scripts/eval/eval-security-path-traversal.js +0 -35
  1389. package/dist/scripts/eval/eval-security-path-traversal.js.map +0 -1
  1390. package/dist/scripts/notify-hook/__tests__/operational-events.test.d.ts +0 -2
  1391. package/dist/scripts/notify-hook/__tests__/operational-events.test.d.ts.map +0 -1
  1392. package/dist/scripts/notify-hook/__tests__/operational-events.test.js +0 -24
  1393. package/dist/scripts/notify-hook/__tests__/operational-events.test.js.map +0 -1
  1394. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts +0 -2
  1395. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts.map +0 -1
  1396. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js +0 -153
  1397. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js.map +0 -1
  1398. package/dist/scripts/notify-hook/ralph-session-resume.d.ts +0 -22
  1399. package/dist/session-history/__tests__/search.test.d.ts +0 -2
  1400. package/dist/session-history/__tests__/search.test.d.ts.map +0 -1
  1401. package/dist/session-history/__tests__/search.test.js +0 -150
  1402. package/dist/session-history/__tests__/search.test.js.map +0 -1
  1403. package/dist/sidecar/__tests__/boundary.test.d.ts +0 -2
  1404. package/dist/sidecar/__tests__/boundary.test.d.ts.map +0 -1
  1405. package/dist/sidecar/__tests__/boundary.test.js +0 -48
  1406. package/dist/sidecar/__tests__/boundary.test.js.map +0 -1
  1407. package/dist/sidecar/__tests__/collector.test.d.ts +0 -2
  1408. package/dist/sidecar/__tests__/collector.test.d.ts.map +0 -1
  1409. package/dist/sidecar/__tests__/collector.test.js +0 -162
  1410. package/dist/sidecar/__tests__/collector.test.js.map +0 -1
  1411. package/dist/sidecar/__tests__/render.test.d.ts +0 -2
  1412. package/dist/sidecar/__tests__/render.test.d.ts.map +0 -1
  1413. package/dist/sidecar/__tests__/render.test.js +0 -67
  1414. package/dist/sidecar/__tests__/render.test.js.map +0 -1
  1415. package/dist/sidecar/__tests__/tmux.test.d.ts +0 -2
  1416. package/dist/sidecar/__tests__/tmux.test.d.ts.map +0 -1
  1417. package/dist/sidecar/__tests__/tmux.test.js +0 -30
  1418. package/dist/sidecar/__tests__/tmux.test.js.map +0 -1
  1419. package/dist/sidecar/__tests__/watch.test.d.ts +0 -2
  1420. package/dist/sidecar/__tests__/watch.test.d.ts.map +0 -1
  1421. package/dist/sidecar/__tests__/watch.test.js +0 -42
  1422. package/dist/sidecar/__tests__/watch.test.js.map +0 -1
  1423. package/dist/state/__tests__/mode-state-context.test.d.ts +0 -2
  1424. package/dist/state/__tests__/mode-state-context.test.d.ts.map +0 -1
  1425. package/dist/state/__tests__/mode-state-context.test.js +0 -35
  1426. package/dist/state/__tests__/mode-state-context.test.js.map +0 -1
  1427. package/dist/state/__tests__/operations-ralph-phase.test.d.ts +0 -2
  1428. package/dist/state/__tests__/operations-ralph-phase.test.d.ts.map +0 -1
  1429. package/dist/state/__tests__/operations-ralph-phase.test.js +0 -103
  1430. package/dist/state/__tests__/operations-ralph-phase.test.js.map +0 -1
  1431. package/dist/state/__tests__/operations.test.d.ts +0 -2
  1432. package/dist/state/__tests__/operations.test.d.ts.map +0 -1
  1433. package/dist/state/__tests__/operations.test.js +0 -439
  1434. package/dist/state/__tests__/operations.test.js.map +0 -1
  1435. package/dist/state/__tests__/path-traversal.test.d.ts +0 -2
  1436. package/dist/state/__tests__/path-traversal.test.d.ts.map +0 -1
  1437. package/dist/state/__tests__/path-traversal.test.js +0 -49
  1438. package/dist/state/__tests__/path-traversal.test.js.map +0 -1
  1439. package/dist/state/__tests__/skill-active.test.d.ts +0 -2
  1440. package/dist/state/__tests__/skill-active.test.d.ts.map +0 -1
  1441. package/dist/state/__tests__/skill-active.test.js +0 -160
  1442. package/dist/state/__tests__/skill-active.test.js.map +0 -1
  1443. package/dist/state/__tests__/workflow-transition.test.d.ts +0 -2
  1444. package/dist/state/__tests__/workflow-transition.test.d.ts.map +0 -1
  1445. package/dist/state/__tests__/workflow-transition.test.js +0 -77
  1446. package/dist/state/__tests__/workflow-transition.test.js.map +0 -1
  1447. package/dist/subagents/__tests__/tracker.test.d.ts +0 -2
  1448. package/dist/subagents/__tests__/tracker.test.d.ts.map +0 -1
  1449. package/dist/subagents/__tests__/tracker.test.js +0 -47
  1450. package/dist/subagents/__tests__/tracker.test.js.map +0 -1
  1451. package/dist/team/__tests__/allocation-policy.test.d.ts +0 -2
  1452. package/dist/team/__tests__/allocation-policy.test.d.ts.map +0 -1
  1453. package/dist/team/__tests__/allocation-policy.test.js +0 -111
  1454. package/dist/team/__tests__/allocation-policy.test.js.map +0 -1
  1455. package/dist/team/__tests__/api-interop.test.d.ts +0 -2
  1456. package/dist/team/__tests__/api-interop.test.d.ts.map +0 -1
  1457. package/dist/team/__tests__/api-interop.test.js +0 -2262
  1458. package/dist/team/__tests__/api-interop.test.js.map +0 -1
  1459. package/dist/team/__tests__/commit-hygiene.test.d.ts +0 -2
  1460. package/dist/team/__tests__/commit-hygiene.test.d.ts.map +0 -1
  1461. package/dist/team/__tests__/commit-hygiene.test.js +0 -93
  1462. package/dist/team/__tests__/commit-hygiene.test.js.map +0 -1
  1463. package/dist/team/__tests__/cross-rebase-smoke.test.d.ts +0 -2
  1464. package/dist/team/__tests__/cross-rebase-smoke.test.d.ts.map +0 -1
  1465. package/dist/team/__tests__/cross-rebase-smoke.test.js +0 -161
  1466. package/dist/team/__tests__/cross-rebase-smoke.test.js.map +0 -1
  1467. package/dist/team/__tests__/current-task-baseline.test.d.ts +0 -2
  1468. package/dist/team/__tests__/current-task-baseline.test.d.ts.map +0 -1
  1469. package/dist/team/__tests__/current-task-baseline.test.js +0 -87
  1470. package/dist/team/__tests__/current-task-baseline.test.js.map +0 -1
  1471. package/dist/team/__tests__/delegation-policy.test.d.ts +0 -2
  1472. package/dist/team/__tests__/delegation-policy.test.d.ts.map +0 -1
  1473. package/dist/team/__tests__/delegation-policy.test.js +0 -69
  1474. package/dist/team/__tests__/delegation-policy.test.js.map +0 -1
  1475. package/dist/team/__tests__/delivery-e2e-smoke.test.d.ts +0 -2
  1476. package/dist/team/__tests__/delivery-e2e-smoke.test.d.ts.map +0 -1
  1477. package/dist/team/__tests__/delivery-e2e-smoke.test.js +0 -679
  1478. package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +0 -1
  1479. package/dist/team/__tests__/events.test.d.ts +0 -2
  1480. package/dist/team/__tests__/events.test.d.ts.map +0 -1
  1481. package/dist/team/__tests__/events.test.js +0 -313
  1482. package/dist/team/__tests__/events.test.js.map +0 -1
  1483. package/dist/team/__tests__/followup-planner.test.d.ts +0 -2
  1484. package/dist/team/__tests__/followup-planner.test.d.ts.map +0 -1
  1485. package/dist/team/__tests__/followup-planner.test.js +0 -84
  1486. package/dist/team/__tests__/followup-planner.test.js.map +0 -1
  1487. package/dist/team/__tests__/hardening-e2e.test.d.ts +0 -2
  1488. package/dist/team/__tests__/hardening-e2e.test.d.ts.map +0 -1
  1489. package/dist/team/__tests__/hardening-e2e.test.js +0 -98
  1490. package/dist/team/__tests__/hardening-e2e.test.js.map +0 -1
  1491. package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts +0 -2
  1492. package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts.map +0 -1
  1493. package/dist/team/__tests__/hook-primary-e2e-contract.test.js +0 -78
  1494. package/dist/team/__tests__/hook-primary-e2e-contract.test.js.map +0 -1
  1495. package/dist/team/__tests__/idle-nudge.test.d.ts +0 -2
  1496. package/dist/team/__tests__/idle-nudge.test.d.ts.map +0 -1
  1497. package/dist/team/__tests__/idle-nudge.test.js +0 -230
  1498. package/dist/team/__tests__/idle-nudge.test.js.map +0 -1
  1499. package/dist/team/__tests__/leader-activity.test.d.ts +0 -2
  1500. package/dist/team/__tests__/leader-activity.test.d.ts.map +0 -1
  1501. package/dist/team/__tests__/leader-activity.test.js +0 -261
  1502. package/dist/team/__tests__/leader-activity.test.js.map +0 -1
  1503. package/dist/team/__tests__/mcp-comm.test.d.ts +0 -2
  1504. package/dist/team/__tests__/mcp-comm.test.d.ts.map +0 -1
  1505. package/dist/team/__tests__/mcp-comm.test.js +0 -289
  1506. package/dist/team/__tests__/mcp-comm.test.js.map +0 -1
  1507. package/dist/team/__tests__/model-contract.test.d.ts +0 -2
  1508. package/dist/team/__tests__/model-contract.test.d.ts.map +0 -1
  1509. package/dist/team/__tests__/model-contract.test.js +0 -171
  1510. package/dist/team/__tests__/model-contract.test.js.map +0 -1
  1511. package/dist/team/__tests__/orchestrator.test.d.ts +0 -2
  1512. package/dist/team/__tests__/orchestrator.test.d.ts.map +0 -1
  1513. package/dist/team/__tests__/orchestrator.test.js +0 -111
  1514. package/dist/team/__tests__/orchestrator.test.js.map +0 -1
  1515. package/dist/team/__tests__/phase-controller.test.d.ts +0 -2
  1516. package/dist/team/__tests__/phase-controller.test.d.ts.map +0 -1
  1517. package/dist/team/__tests__/phase-controller.test.js +0 -50
  1518. package/dist/team/__tests__/phase-controller.test.js.map +0 -1
  1519. package/dist/team/__tests__/rebalance-policy.test.d.ts +0 -2
  1520. package/dist/team/__tests__/rebalance-policy.test.d.ts.map +0 -1
  1521. package/dist/team/__tests__/rebalance-policy.test.js +0 -168
  1522. package/dist/team/__tests__/rebalance-policy.test.js.map +0 -1
  1523. package/dist/team/__tests__/repo-aware-decomposition.test.d.ts +0 -2
  1524. package/dist/team/__tests__/repo-aware-decomposition.test.d.ts.map +0 -1
  1525. package/dist/team/__tests__/repo-aware-decomposition.test.js +0 -136
  1526. package/dist/team/__tests__/repo-aware-decomposition.test.js.map +0 -1
  1527. package/dist/team/__tests__/role-router.test.d.ts +0 -2
  1528. package/dist/team/__tests__/role-router.test.d.ts.map +0 -1
  1529. package/dist/team/__tests__/role-router.test.js +0 -263
  1530. package/dist/team/__tests__/role-router.test.js.map +0 -1
  1531. package/dist/team/__tests__/runtime-cli.test.d.ts +0 -2
  1532. package/dist/team/__tests__/runtime-cli.test.d.ts.map +0 -1
  1533. package/dist/team/__tests__/runtime-cli.test.js +0 -304
  1534. package/dist/team/__tests__/runtime-cli.test.js.map +0 -1
  1535. package/dist/team/__tests__/runtime.test.d.ts +0 -2
  1536. package/dist/team/__tests__/runtime.test.d.ts.map +0 -1
  1537. package/dist/team/__tests__/runtime.test.js +0 -5734
  1538. package/dist/team/__tests__/runtime.test.js.map +0 -1
  1539. package/dist/team/__tests__/scaling.test.d.ts +0 -2
  1540. package/dist/team/__tests__/scaling.test.d.ts.map +0 -1
  1541. package/dist/team/__tests__/scaling.test.js +0 -1005
  1542. package/dist/team/__tests__/scaling.test.js.map +0 -1
  1543. package/dist/team/__tests__/shutdown-fallback.test.d.ts +0 -2
  1544. package/dist/team/__tests__/shutdown-fallback.test.d.ts.map +0 -1
  1545. package/dist/team/__tests__/shutdown-fallback.test.js +0 -125
  1546. package/dist/team/__tests__/shutdown-fallback.test.js.map +0 -1
  1547. package/dist/team/__tests__/state-root.test.d.ts +0 -2
  1548. package/dist/team/__tests__/state-root.test.d.ts.map +0 -1
  1549. package/dist/team/__tests__/state-root.test.js +0 -195
  1550. package/dist/team/__tests__/state-root.test.js.map +0 -1
  1551. package/dist/team/__tests__/state.test.d.ts +0 -2
  1552. package/dist/team/__tests__/state.test.d.ts.map +0 -1
  1553. package/dist/team/__tests__/state.test.js +0 -1859
  1554. package/dist/team/__tests__/state.test.js.map +0 -1
  1555. package/dist/team/__tests__/team-identity.test.d.ts +0 -2
  1556. package/dist/team/__tests__/team-identity.test.d.ts.map +0 -1
  1557. package/dist/team/__tests__/team-identity.test.js +0 -166
  1558. package/dist/team/__tests__/team-identity.test.js.map +0 -1
  1559. package/dist/team/__tests__/team-ops-contract.test.d.ts +0 -2
  1560. package/dist/team/__tests__/team-ops-contract.test.d.ts.map +0 -1
  1561. package/dist/team/__tests__/team-ops-contract.test.js +0 -96
  1562. package/dist/team/__tests__/team-ops-contract.test.js.map +0 -1
  1563. package/dist/team/__tests__/tmux-claude-workers-demo.test.d.ts +0 -2
  1564. package/dist/team/__tests__/tmux-claude-workers-demo.test.d.ts.map +0 -1
  1565. package/dist/team/__tests__/tmux-claude-workers-demo.test.js +0 -191
  1566. package/dist/team/__tests__/tmux-claude-workers-demo.test.js.map +0 -1
  1567. package/dist/team/__tests__/tmux-session.test.d.ts +0 -2
  1568. package/dist/team/__tests__/tmux-session.test.d.ts.map +0 -1
  1569. package/dist/team/__tests__/tmux-session.test.js +0 -3785
  1570. package/dist/team/__tests__/tmux-session.test.js.map +0 -1
  1571. package/dist/team/__tests__/tmux-test-fixture.d.ts +0 -20
  1572. package/dist/team/__tests__/tmux-test-fixture.d.ts.map +0 -1
  1573. package/dist/team/__tests__/tmux-test-fixture.js +0 -152
  1574. package/dist/team/__tests__/tmux-test-fixture.js.map +0 -1
  1575. package/dist/team/__tests__/tmux-test-fixture.test.d.ts +0 -2
  1576. package/dist/team/__tests__/tmux-test-fixture.test.d.ts.map +0 -1
  1577. package/dist/team/__tests__/tmux-test-fixture.test.js +0 -113
  1578. package/dist/team/__tests__/tmux-test-fixture.test.js.map +0 -1
  1579. package/dist/team/__tests__/worker-bootstrap.test.d.ts +0 -2
  1580. package/dist/team/__tests__/worker-bootstrap.test.d.ts.map +0 -1
  1581. package/dist/team/__tests__/worker-bootstrap.test.js +0 -685
  1582. package/dist/team/__tests__/worker-bootstrap.test.js.map +0 -1
  1583. package/dist/team/__tests__/worker-runtime-identity.test.d.ts +0 -2
  1584. package/dist/team/__tests__/worker-runtime-identity.test.d.ts.map +0 -1
  1585. package/dist/team/__tests__/worker-runtime-identity.test.js +0 -250
  1586. package/dist/team/__tests__/worker-runtime-identity.test.js.map +0 -1
  1587. package/dist/team/__tests__/worktree.test.d.ts +0 -2
  1588. package/dist/team/__tests__/worktree.test.d.ts.map +0 -1
  1589. package/dist/team/__tests__/worktree.test.js +0 -317
  1590. package/dist/team/__tests__/worktree.test.js.map +0 -1
  1591. package/dist/utils/__tests__/agents-md.test.d.ts +0 -2
  1592. package/dist/utils/__tests__/agents-md.test.d.ts.map +0 -1
  1593. package/dist/utils/__tests__/agents-md.test.js +0 -52
  1594. package/dist/utils/__tests__/agents-md.test.js.map +0 -1
  1595. package/dist/utils/__tests__/agents-model-table.test.d.ts +0 -2
  1596. package/dist/utils/__tests__/agents-model-table.test.d.ts.map +0 -1
  1597. package/dist/utils/__tests__/agents-model-table.test.js +0 -104
  1598. package/dist/utils/__tests__/agents-model-table.test.js.map +0 -1
  1599. package/dist/utils/__tests__/dep-versions.test.d.ts +0 -2
  1600. package/dist/utils/__tests__/dep-versions.test.d.ts.map +0 -1
  1601. package/dist/utils/__tests__/dep-versions.test.js +0 -46
  1602. package/dist/utils/__tests__/dep-versions.test.js.map +0 -1
  1603. package/dist/utils/__tests__/package.test.d.ts +0 -2
  1604. package/dist/utils/__tests__/package.test.d.ts.map +0 -1
  1605. package/dist/utils/__tests__/package.test.js +0 -21
  1606. package/dist/utils/__tests__/package.test.js.map +0 -1
  1607. package/dist/utils/__tests__/paths.test.d.ts +0 -2
  1608. package/dist/utils/__tests__/paths.test.d.ts.map +0 -1
  1609. package/dist/utils/__tests__/paths.test.js +0 -541
  1610. package/dist/utils/__tests__/paths.test.js.map +0 -1
  1611. package/dist/utils/__tests__/platform-command.test.d.ts +0 -2
  1612. package/dist/utils/__tests__/platform-command.test.d.ts.map +0 -1
  1613. package/dist/utils/__tests__/platform-command.test.js +0 -410
  1614. package/dist/utils/__tests__/platform-command.test.js.map +0 -1
  1615. package/dist/utils/__tests__/repo-deps.test.d.ts +0 -2
  1616. package/dist/utils/__tests__/repo-deps.test.d.ts.map +0 -1
  1617. package/dist/utils/__tests__/repo-deps.test.js +0 -71
  1618. package/dist/utils/__tests__/repo-deps.test.js.map +0 -1
  1619. package/dist/verification/__tests__/ci-rust-gates.test.d.ts +0 -2
  1620. package/dist/verification/__tests__/ci-rust-gates.test.d.ts.map +0 -1
  1621. package/dist/verification/__tests__/ci-rust-gates.test.js +0 -89
  1622. package/dist/verification/__tests__/ci-rust-gates.test.js.map +0 -1
  1623. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.d.ts +0 -2
  1624. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.d.ts.map +0 -1
  1625. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +0 -54
  1626. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +0 -1
  1627. package/dist/verification/__tests__/explore-harness-release-workflow.test.d.ts +0 -2
  1628. package/dist/verification/__tests__/explore-harness-release-workflow.test.d.ts.map +0 -1
  1629. package/dist/verification/__tests__/explore-harness-release-workflow.test.js +0 -73
  1630. package/dist/verification/__tests__/explore-harness-release-workflow.test.js.map +0 -1
  1631. package/dist/verification/__tests__/native-release-manifest.test.d.ts +0 -2
  1632. package/dist/verification/__tests__/native-release-manifest.test.d.ts.map +0 -1
  1633. package/dist/verification/__tests__/native-release-manifest.test.js +0 -80
  1634. package/dist/verification/__tests__/native-release-manifest.test.js.map +0 -1
  1635. package/dist/verification/__tests__/pr-check-workflow.test.d.ts +0 -2
  1636. package/dist/verification/__tests__/pr-check-workflow.test.d.ts.map +0 -1
  1637. package/dist/verification/__tests__/pr-check-workflow.test.js +0 -27
  1638. package/dist/verification/__tests__/pr-check-workflow.test.js.map +0 -1
  1639. package/dist/verification/__tests__/ralph-persistence-gate.test.d.ts +0 -2
  1640. package/dist/verification/__tests__/ralph-persistence-gate.test.d.ts.map +0 -1
  1641. package/dist/verification/__tests__/ralph-persistence-gate.test.js +0 -55
  1642. package/dist/verification/__tests__/ralph-persistence-gate.test.js.map +0 -1
  1643. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.d.ts +0 -2
  1644. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.d.ts.map +0 -1
  1645. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.js +0 -32
  1646. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.js.map +0 -1
  1647. package/dist/verification/__tests__/verifier.test.d.ts +0 -2
  1648. package/dist/verification/__tests__/verifier.test.d.ts.map +0 -1
  1649. package/dist/verification/__tests__/verifier.test.js +0 -113
  1650. package/dist/verification/__tests__/verifier.test.js.map +0 -1
  1651. package/dist/visual/__tests__/verdict.test.d.ts +0 -2
  1652. package/dist/visual/__tests__/verdict.test.d.ts.map +0 -1
  1653. package/dist/visual/__tests__/verdict.test.js +0 -81
  1654. package/dist/visual/__tests__/verdict.test.js.map +0 -1
  1655. package/dist/wiki/__tests__/cjk-tokenize.test.d.ts +0 -12
  1656. package/dist/wiki/__tests__/cjk-tokenize.test.d.ts.map +0 -1
  1657. package/dist/wiki/__tests__/cjk-tokenize.test.js +0 -139
  1658. package/dist/wiki/__tests__/cjk-tokenize.test.js.map +0 -1
  1659. package/dist/wiki/__tests__/crlf-parse.test.d.ts +0 -2
  1660. package/dist/wiki/__tests__/crlf-parse.test.d.ts.map +0 -1
  1661. package/dist/wiki/__tests__/crlf-parse.test.js +0 -24
  1662. package/dist/wiki/__tests__/crlf-parse.test.js.map +0 -1
  1663. package/dist/wiki/__tests__/escape-newline.test.d.ts +0 -2
  1664. package/dist/wiki/__tests__/escape-newline.test.d.ts.map +0 -1
  1665. package/dist/wiki/__tests__/escape-newline.test.js +0 -45
  1666. package/dist/wiki/__tests__/escape-newline.test.js.map +0 -1
  1667. package/dist/wiki/__tests__/ingest.test.d.ts +0 -5
  1668. package/dist/wiki/__tests__/ingest.test.d.ts.map +0 -1
  1669. package/dist/wiki/__tests__/ingest.test.js +0 -181
  1670. package/dist/wiki/__tests__/ingest.test.js.map +0 -1
  1671. package/dist/wiki/__tests__/lint.test.d.ts +0 -5
  1672. package/dist/wiki/__tests__/lint.test.d.ts.map +0 -1
  1673. package/dist/wiki/__tests__/lint.test.js +0 -163
  1674. package/dist/wiki/__tests__/lint.test.js.map +0 -1
  1675. package/dist/wiki/__tests__/query.test.d.ts +0 -5
  1676. package/dist/wiki/__tests__/query.test.d.ts.map +0 -1
  1677. package/dist/wiki/__tests__/query.test.js +0 -141
  1678. package/dist/wiki/__tests__/query.test.js.map +0 -1
  1679. package/dist/wiki/__tests__/reserved-file-guard.test.d.ts +0 -2
  1680. package/dist/wiki/__tests__/reserved-file-guard.test.d.ts.map +0 -1
  1681. package/dist/wiki/__tests__/reserved-file-guard.test.js +0 -44
  1682. package/dist/wiki/__tests__/reserved-file-guard.test.js.map +0 -1
  1683. package/dist/wiki/__tests__/session-hooks.test.d.ts +0 -5
  1684. package/dist/wiki/__tests__/session-hooks.test.d.ts.map +0 -1
  1685. package/dist/wiki/__tests__/session-hooks.test.js +0 -36
  1686. package/dist/wiki/__tests__/session-hooks.test.js.map +0 -1
  1687. package/dist/wiki/__tests__/slug-nonascii.test.d.ts +0 -2
  1688. package/dist/wiki/__tests__/slug-nonascii.test.d.ts.map +0 -1
  1689. package/dist/wiki/__tests__/slug-nonascii.test.js +0 -30
  1690. package/dist/wiki/__tests__/slug-nonascii.test.js.map +0 -1
  1691. package/dist/wiki/__tests__/storage.test.d.ts +0 -5
  1692. package/dist/wiki/__tests__/storage.test.d.ts.map +0 -1
  1693. package/dist/wiki/__tests__/storage.test.js +0 -278
  1694. package/dist/wiki/__tests__/storage.test.js.map +0 -1
  1695. package/dist/wiki/__tests__/test-helpers.d.ts +0 -31
  1696. package/dist/wiki/__tests__/test-helpers.d.ts.map +0 -1
  1697. package/dist/wiki/__tests__/test-helpers.js +0 -108
  1698. package/dist/wiki/__tests__/test-helpers.js.map +0 -1
  1699. package/docs/contracts/ralph-cancel-contract.md +0 -23
  1700. package/docs/contracts/ralph-state-contract.md +0 -95
  1701. package/docs/issues/team-ralph-followup-team.md +0 -38
  1702. package/docs/qa/ralph-persistence-gate.md +0 -59
  1703. package/docs/reference/ralph-parity-matrix.md +0 -25
  1704. package/docs/reference/ralph-upstream-baseline.md +0 -34
  1705. package/plugins/roblox-ai-os-creator-skills/skills/ralph/SKILL.md +0 -269
  1706. package/plugins/roblox-ai-os-creator-skills/skills/ralplan/SKILL.md +0 -162
  1707. package/prompts/api-reviewer.md +0 -113
  1708. package/prompts/information-architect.md +0 -226
  1709. package/prompts/performance-reviewer.md +0 -109
  1710. package/prompts/product-analyst.md +0 -304
  1711. package/prompts/product-manager.md +0 -245
  1712. package/prompts/qa-tester.md +0 -124
  1713. package/prompts/quality-reviewer.md +0 -123
  1714. package/prompts/quality-strategist.md +0 -274
  1715. package/prompts/style-reviewer.md +0 -102
  1716. package/prompts/ux-researcher.md +0 -327
  1717. package/skills/frontend-ui-ux/SKILL.md +0 -34
  1718. package/skills/ralph/SKILL.md +0 -269
  1719. package/skills/ralplan/SKILL.md +0 -162
  1720. package/src/scripts/eval/eval-adaptive-sort-optimization.py +0 -24
  1721. package/src/scripts/eval/eval-candidate-handoff.ts +0 -8
  1722. package/src/scripts/eval/eval-cli-discoverability.ts +0 -40
  1723. package/src/scripts/eval/eval-fresh-run-tagging.ts +0 -8
  1724. package/src/scripts/eval/eval-help-consistency.ts +0 -11
  1725. package/src/scripts/eval/eval-in-action-cat-shellout-demo.ts +0 -31
  1726. package/src/scripts/eval/eval-ml-kaggle-model-optimization.py +0 -29
  1727. package/src/scripts/eval/eval-noisy-bayesopt-highdim.py +0 -44
  1728. package/src/scripts/eval/eval-noisy-latent-subspace-discovery.py +0 -44
  1729. package/src/scripts/eval/eval-parity-smoke.ts +0 -20
  1730. package/src/scripts/eval/eval-parity-sweep.ts +0 -26
  1731. package/src/scripts/eval/eval-resume-dirty-guard.ts +0 -8
  1732. package/src/scripts/eval/eval-security-path-traversal.ts +0 -38
  1733. package/src/scripts/run-autoresearch-showcase.sh +0 -75
  1734. /package/docs/{migration-mainline-post-v0.4.4.md → archive/migration-mainline-post-v0.4.4.md} +0 -0
  1735. /package/docs/{qa-plan-0.4.2.md → archive/qa-plan-0.4.2.md} +0 -0
  1736. /package/docs/{qa-report-0.4.2.md → archive/qa-report-0.4.2.md} +0 -0
@@ -1,2879 +0,0 @@
1
- import { describe, it } from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { spawnSync } from 'node:child_process';
4
- import { chmod, mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
5
- import { existsSync } from 'node:fs';
6
- import { tmpdir } from 'node:os';
7
- import { join } from 'node:path';
8
- import { initTeamState, enqueueDispatchRequest, readDispatchRequest } from '../../team/state.js';
9
- const NOTIFY_HOOK_SCRIPT = new URL('../../../dist/scripts/notify-hook.js', import.meta.url);
10
- async function withTempWorkingDir(run) {
11
- const cwd = await mkdtemp(join(tmpdir(), 'rcs-notify-team-nudge-'));
12
- try {
13
- await run(cwd);
14
- }
15
- finally {
16
- await rm(cwd, { recursive: true, force: true });
17
- }
18
- }
19
- async function writeJson(path, value) {
20
- await writeFile(path, JSON.stringify(value, null, 2));
21
- }
22
- async function writeCanonicalTeamFixture(cwd, { teamName, sessionId, ownerSessionId, coarseState = 'missing', }) {
23
- const stateDir = join(cwd, '.rcs', 'state');
24
- const teamDir = join(stateDir, 'team', teamName);
25
- const workersDir = join(teamDir, 'workers');
26
- const nowIso = new Date().toISOString();
27
- await mkdir(join(cwd, '.rcs', 'logs'), { recursive: true });
28
- await mkdir(workersDir, { recursive: true });
29
- await writeJson(join(stateDir, 'session.json'), { session_id: sessionId });
30
- if (coarseState !== 'missing') {
31
- await writeJson(join(stateDir, 'team-state.json'), {
32
- active: coarseState === 'active',
33
- team_name: teamName,
34
- current_phase: 'team-exec',
35
- });
36
- }
37
- await writeJson(join(stateDir, 'hud-state.json'), {
38
- last_turn_at: nowIso,
39
- turn_count: 1,
40
- });
41
- await writeJson(join(teamDir, 'manifest.v2.json'), {
42
- schema_version: 2,
43
- name: teamName,
44
- task: 'canonical notify fallback repro',
45
- leader: {
46
- session_id: ownerSessionId,
47
- worker_id: 'leader-fixed',
48
- role: 'coordinator',
49
- },
50
- policy: {
51
- worker_launch_mode: 'interactive',
52
- display_mode: 'split_pane',
53
- dispatch_mode: 'hook_preferred_with_fallback',
54
- dispatch_ack_timeout_ms: 2000,
55
- },
56
- governance: {
57
- delegation_only: false,
58
- plan_approval_required: false,
59
- nested_teams_allowed: false,
60
- one_team_per_leader_session: true,
61
- cleanup_requires_all_workers_inactive: true,
62
- },
63
- lifecycle_profile: 'default',
64
- permissions_snapshot: {
65
- approval_mode: 'never',
66
- sandbox_mode: 'danger-full-access',
67
- network_access: true,
68
- },
69
- tmux_session: `${teamName}:0`,
70
- leader_pane_id: '%97',
71
- hud_pane_id: null,
72
- resize_hook_name: null,
73
- resize_hook_target: null,
74
- worker_count: 2,
75
- next_task_id: 1,
76
- workers: [
77
- { name: 'worker-1', index: 1, pane_id: '%1', role: 'executor' },
78
- { name: 'worker-2', index: 2, pane_id: '%2', role: 'executor' },
79
- ],
80
- created_at: nowIso,
81
- });
82
- await writeJson(join(teamDir, 'phase.json'), {
83
- current_phase: 'team-exec',
84
- updated_at: nowIso,
85
- transitions: [],
86
- });
87
- for (const worker of ['worker-1', 'worker-2']) {
88
- await mkdir(join(workersDir, worker), { recursive: true });
89
- await writeJson(join(workersDir, worker, 'status.json'), {
90
- state: 'idle',
91
- updated_at: nowIso,
92
- });
93
- }
94
- }
95
- async function readTeamDeliveryLog(cwd) {
96
- const path = join(cwd, '.rcs', 'logs', `team-delivery-${new Date().toISOString().slice(0, 10)}.jsonl`);
97
- const raw = await readFile(path, 'utf-8').catch(() => '');
98
- return raw
99
- .split('\n')
100
- .map((line) => line.trim())
101
- .filter(Boolean)
102
- .map((line) => JSON.parse(line));
103
- }
104
- function buildFakeTmux(tmuxLogPath) {
105
- return `#!/usr/bin/env bash
106
- set -eu
107
- echo "$@" >> "${tmuxLogPath}"
108
- cmd="$1"
109
- shift || true
110
- if [[ "$cmd" == "display-message" ]]; then
111
- exit 0
112
- fi
113
- if [[ "$cmd" == "send-keys" ]]; then
114
- exit 0
115
- fi
116
- if [[ "$cmd" == "list-panes" ]]; then
117
- echo "%1 12345"
118
- echo "%2 12346"
119
- exit 0
120
- fi
121
- exit 0
122
- `;
123
- }
124
- function buildFakeTmuxWithListPanes(tmuxLogPath, listPaneLines) {
125
- const escapedLines = listPaneLines
126
- .map((line) => line.replaceAll('\\', '\\\\').replaceAll('"', '\\"'))
127
- .join('\\n');
128
- return `#!/usr/bin/env bash
129
- set -eu
130
- echo "$@" >> "${tmuxLogPath}"
131
- cmd="$1"
132
- shift || true
133
- if [[ "$cmd" == "display-message" ]]; then
134
- exit 0
135
- fi
136
- if [[ "$cmd" == "send-keys" ]]; then
137
- exit 0
138
- fi
139
- if [[ "$cmd" == "list-panes" ]]; then
140
- printf "%b\\n" "${escapedLines}"
141
- exit 0
142
- fi
143
- exit 0
144
- `;
145
- }
146
- function runNotifyHook(cwd, fakeBinDir, extraEnv = {}) {
147
- const payload = {
148
- cwd,
149
- type: 'agent-turn-complete',
150
- 'thread-id': 'thread-test',
151
- 'turn-id': `turn-${Date.now()}`,
152
- 'input-messages': ['test'],
153
- 'last-assistant-message': 'output',
154
- };
155
- return spawnSync(process.execPath, [NOTIFY_HOOK_SCRIPT.pathname, JSON.stringify(payload)], {
156
- encoding: 'utf8',
157
- env: {
158
- ...process.env,
159
- PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
160
- RCS_TEAM_LEADER_NUDGE_MS: '10000',
161
- RCS_TEAM_LEADER_STALE_MS: '10000',
162
- RCS_TEAM_WORKER: '',
163
- RCS_TEAM_STATE_ROOT: '',
164
- RCS_TEAM_LEADER_CWD: '',
165
- RCS_MODEL_INSTRUCTIONS_FILE: '',
166
- TMUX: '',
167
- TMUX_PANE: '',
168
- ...extraEnv,
169
- },
170
- });
171
- }
172
- describe('notify-hook leader-side authority handoff', () => {
173
- it('does not inject leader nudge from notify-hook when team is active and stale', async () => {
174
- await withTempWorkingDir(async (cwd) => {
175
- const rcsDir = join(cwd, '.rcs');
176
- const stateDir = join(rcsDir, 'state');
177
- const logsDir = join(rcsDir, 'logs');
178
- const teamName = 'handoff-alpha';
179
- const teamDir = join(stateDir, 'team', teamName);
180
- const mailboxDir = join(teamDir, 'mailbox');
181
- const fakeBinDir = join(cwd, 'fake-bin');
182
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
183
- const tmuxLogPath = join(cwd, 'tmux.log');
184
- await mkdir(logsDir, { recursive: true });
185
- await mkdir(mailboxDir, { recursive: true });
186
- await mkdir(fakeBinDir, { recursive: true });
187
- await writeJson(join(stateDir, 'team-state.json'), {
188
- active: true,
189
- team_name: teamName,
190
- current_phase: 'team-exec',
191
- });
192
- await writeJson(join(teamDir, 'config.json'), {
193
- name: teamName,
194
- tmux_session: 'handoff-sess:0',
195
- leader_pane_id: '%91',
196
- });
197
- await writeJson(join(stateDir, 'hud-state.json'), {
198
- last_turn_at: new Date(Date.now() - 300_000).toISOString(),
199
- turn_count: 1,
200
- });
201
- await writeJson(join(mailboxDir, 'leader-fixed.json'), {
202
- worker: 'leader-fixed',
203
- messages: [
204
- {
205
- message_id: 'm1',
206
- from_worker: 'worker-1',
207
- to_worker: 'leader-fixed',
208
- body: 'ACK',
209
- created_at: '2026-02-14T00:00:00.000Z',
210
- },
211
- ],
212
- });
213
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
214
- await chmod(fakeTmuxPath, 0o755);
215
- const result = runNotifyHook(cwd, fakeBinDir, {
216
- RCS_SESSION_ID: 'sess-canonical-missing',
217
- });
218
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
219
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8').catch(() => '');
220
- assert.match(tmuxLog, /send-keys/, 'current implementation nudges the leader directly in this stale-leader path');
221
- });
222
- });
223
- it('does not drain pending dispatch requests from notify-hook leader context', async () => {
224
- await withTempWorkingDir(async (cwd) => {
225
- const fakeBinDir = join(cwd, 'fake-bin');
226
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
227
- const tmuxLogPath = join(cwd, 'tmux.log');
228
- await mkdir(join(cwd, '.rcs', 'logs'), { recursive: true });
229
- await mkdir(fakeBinDir, { recursive: true });
230
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
231
- await chmod(fakeTmuxPath, 0o755);
232
- await initTeamState('handoff-dispatch', 'task', 'executor', 1, cwd);
233
- const queued = await enqueueDispatchRequest('handoff-dispatch', {
234
- kind: 'inbox',
235
- to_worker: 'worker-1',
236
- worker_index: 1,
237
- trigger_message: 'dispatch ping',
238
- }, cwd);
239
- const result = runNotifyHook(cwd, fakeBinDir, {
240
- RCS_SESSION_ID: 'sess-canonical-inactive',
241
- });
242
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
243
- const request = await readDispatchRequest('handoff-dispatch', queued.request.request_id, cwd);
244
- assert.equal(request?.status, 'failed');
245
- });
246
- });
247
- it('does not nudge stale leader when recent team status activity proves the leader is active', async () => {
248
- await withTempWorkingDir(async (cwd) => {
249
- const rcsDir = join(cwd, '.rcs');
250
- const stateDir = join(rcsDir, 'state');
251
- const logsDir = join(rcsDir, 'logs');
252
- const teamName = 'beta-active-status';
253
- const teamDir = join(stateDir, 'team', teamName);
254
- const workersDir = join(teamDir, 'workers');
255
- const fakeBinDir = join(cwd, 'fake-bin');
256
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
257
- const tmuxLogPath = join(cwd, 'tmux.log');
258
- await mkdir(logsDir, { recursive: true });
259
- await mkdir(join(workersDir, 'worker-1'), { recursive: true });
260
- await mkdir(fakeBinDir, { recursive: true });
261
- await writeJson(join(stateDir, 'team-state.json'), {
262
- active: true,
263
- team_name: teamName,
264
- current_phase: 'team-exec',
265
- });
266
- await writeJson(join(teamDir, 'config.json'), {
267
- name: teamName,
268
- tmux_session: 'rcs-team-beta-active-status',
269
- leader_pane_id: '%92',
270
- workers: [
271
- { name: 'worker-1', index: 1, pane_id: '%10' },
272
- ],
273
- });
274
- await writeJson(join(stateDir, 'hud-state.json'), {
275
- last_turn_at: new Date(Date.now() - 300_000).toISOString(),
276
- turn_count: 5,
277
- });
278
- await writeJson(join(stateDir, 'leader-runtime-activity.json'), {
279
- last_activity_at: new Date(Date.now() - 5_000).toISOString(),
280
- last_team_status_at: new Date(Date.now() - 5_000).toISOString(),
281
- last_source: 'team_status',
282
- last_team_name: teamName,
283
- });
284
- await writeJson(join(workersDir, 'worker-1', 'status.json'), {
285
- state: 'working',
286
- current_task_id: '1',
287
- updated_at: new Date().toISOString(),
288
- });
289
- await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%10 12345']));
290
- await chmod(fakeTmuxPath, 0o755);
291
- const result = runNotifyHook(cwd, fakeBinDir, {
292
- RCS_SESSION_ID: 'sess-current',
293
- });
294
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
295
- if (existsSync(tmuxLogPath)) {
296
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
297
- assert.doesNotMatch(tmuxLog, /Team beta-active-status:/);
298
- assert.doesNotMatch(tmuxLog, /leader stale/);
299
- }
300
- });
301
- });
302
- });
303
- describe('notify-hook team leader nudge', () => {
304
- it('disables leader nudges when deep-interview state is active', async () => {
305
- await withTempWorkingDir(async (cwd) => {
306
- const rcsDir = join(cwd, '.rcs');
307
- const stateDir = join(rcsDir, 'state');
308
- const logsDir = join(rcsDir, 'logs');
309
- const teamName = 'deep-interview-suppressed';
310
- const teamDir = join(stateDir, 'team', teamName);
311
- const mailboxDir = join(teamDir, 'mailbox');
312
- const fakeBinDir = join(cwd, 'fake-bin');
313
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
314
- const tmuxLogPath = join(cwd, 'tmux.log');
315
- await mkdir(logsDir, { recursive: true });
316
- await mkdir(mailboxDir, { recursive: true });
317
- await mkdir(fakeBinDir, { recursive: true });
318
- await writeJson(join(stateDir, 'deep-interview-state.json'), {
319
- active: true,
320
- mode: 'deep-interview',
321
- current_phase: 'deep-interview',
322
- });
323
- await writeJson(join(stateDir, 'team-state.json'), {
324
- active: true,
325
- team_name: teamName,
326
- current_phase: 'team-exec',
327
- });
328
- await writeJson(join(teamDir, 'config.json'), {
329
- name: teamName,
330
- tmux_session: 'deep-interview-suppressed:0',
331
- leader_pane_id: '%97',
332
- });
333
- await writeJson(join(stateDir, 'hud-state.json'), {
334
- last_turn_at: new Date(Date.now() - 300_000).toISOString(),
335
- turn_count: 1,
336
- });
337
- await writeJson(join(mailboxDir, 'leader-fixed.json'), {
338
- worker: 'leader-fixed',
339
- messages: [{ message_id: 'msg-1', from_worker: 'worker-1', to_worker: 'leader-fixed', body: 'review', created_at: new Date().toISOString() }],
340
- });
341
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
342
- await chmod(fakeTmuxPath, 0o755);
343
- const result = runNotifyHook(cwd, fakeBinDir, {
344
- RCS_SESSION_ID: 'sess-canonical-missing',
345
- });
346
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
347
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8').catch(() => '');
348
- assert.doesNotMatch(tmuxLog, /send-keys -t %97 -l Team deep-interview-suppressed:/);
349
- });
350
- });
351
- it('sends immediate all-workers-idle nudge for active team (leader context)', async () => {
352
- await withTempWorkingDir(async (cwd) => {
353
- const rcsDir = join(cwd, '.rcs');
354
- const stateDir = join(rcsDir, 'state');
355
- const logsDir = join(rcsDir, 'logs');
356
- const teamName = 'idle-alpha';
357
- const teamDir = join(stateDir, 'team', teamName);
358
- const workersDir = join(teamDir, 'workers');
359
- const fakeBinDir = join(cwd, 'fake-bin');
360
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
361
- const tmuxLogPath = join(cwd, 'tmux.log');
362
- await mkdir(logsDir, { recursive: true });
363
- await mkdir(workersDir, { recursive: true });
364
- await mkdir(fakeBinDir, { recursive: true });
365
- await writeJson(join(stateDir, 'team-state.json'), {
366
- active: true,
367
- team_name: teamName,
368
- current_phase: 'team-exec',
369
- });
370
- await writeJson(join(teamDir, 'config.json'), {
371
- name: teamName,
372
- tmux_session: 'idle-sess:0',
373
- leader_pane_id: '%99',
374
- workers: [
375
- { name: 'worker-1', index: 1, role: 'executor', assigned_tasks: [] },
376
- { name: 'worker-2', index: 2, role: 'executor', assigned_tasks: [] },
377
- ],
378
- });
379
- await writeJson(join(stateDir, 'hud-state.json'), {
380
- last_turn_at: new Date().toISOString(),
381
- turn_count: 1,
382
- });
383
- await mkdir(join(workersDir, 'worker-1'), { recursive: true });
384
- await writeJson(join(workersDir, 'worker-1', 'status.json'), {
385
- state: 'idle',
386
- updated_at: new Date().toISOString(),
387
- });
388
- await mkdir(join(workersDir, 'worker-2'), { recursive: true });
389
- await writeJson(join(workersDir, 'worker-2', 'status.json'), {
390
- state: 'idle',
391
- updated_at: new Date().toISOString(),
392
- });
393
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
394
- await chmod(fakeTmuxPath, 0o755);
395
- const result = runNotifyHook(cwd, fakeBinDir, {
396
- RCS_SESSION_ID: 'sess-canonical-inactive',
397
- });
398
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
399
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
400
- assert.match(tmuxLog, /send-keys/);
401
- assert.match(tmuxLog, /-t %99/, 'should target leader pane when present');
402
- assert.match(tmuxLog, /\[RCS\] All 2 workers idle/, 'should emit all-workers-idle nudge');
403
- assert.doesNotMatch(tmuxLog, /\[RCS_INTENT:/, 'should keep orchestration intent out of injected display text');
404
- assert.match(tmuxLog, /\[RCS_TMUX_INJECT\]/, 'should include injection marker');
405
- const submitMatches = tmuxLog.match(/send-keys -t %99 C-m/g) || [];
406
- assert.equal(submitMatches.length, 2, 'leader nudge should submit with isolated double C-m');
407
- assert.ok(!/send-keys[^\n]*-l[^\n]*C-m/.test(tmuxLog), 'must not mix literal payload with submit keypresses');
408
- const eventsPath = join(teamDir, 'events', 'events.ndjson');
409
- assert.ok(existsSync(eventsPath), 'events.ndjson should exist');
410
- const eventsContent = await readFile(eventsPath, 'utf-8');
411
- const events = eventsContent.trim().split('\n').map(line => JSON.parse(line));
412
- const nudgeEvent = events.find((e) => e.type === 'team_leader_nudge');
413
- assert.ok(nudgeEvent, 'should have team_leader_nudge event');
414
- assert.equal(nudgeEvent.reason, 'done_waiting_on_leader');
415
- assert.equal(nudgeEvent.orchestration_intent, 'done-review-or-shutdown');
416
- });
417
- });
418
- it('suggests shutdown when all workers are idle and the current task set is complete', async () => {
419
- await withTempWorkingDir(async (cwd) => {
420
- const rcsDir = join(cwd, '.rcs');
421
- const stateDir = join(rcsDir, 'state');
422
- const logsDir = join(rcsDir, 'logs');
423
- const teamName = 'idle-shutdown';
424
- const teamDir = join(stateDir, 'team', teamName);
425
- const workersDir = join(teamDir, 'workers');
426
- const tasksDir = join(teamDir, 'tasks');
427
- const fakeBinDir = join(cwd, 'fake-bin');
428
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
429
- const tmuxLogPath = join(cwd, 'tmux.log');
430
- const nowIso = new Date().toISOString();
431
- await mkdir(logsDir, { recursive: true });
432
- await mkdir(workersDir, { recursive: true });
433
- await mkdir(tasksDir, { recursive: true });
434
- await mkdir(fakeBinDir, { recursive: true });
435
- await writeJson(join(stateDir, 'team-state.json'), {
436
- active: true,
437
- team_name: teamName,
438
- current_phase: 'team-exec',
439
- });
440
- await writeJson(join(teamDir, 'config.json'), {
441
- name: teamName,
442
- tmux_session: 'idle-shutdown:0',
443
- leader_pane_id: '%96',
444
- workers: [
445
- { name: 'worker-1', index: 1, pane_id: '%10', role: 'executor' },
446
- { name: 'worker-2', index: 2, pane_id: '%11', role: 'executor' },
447
- ],
448
- });
449
- await writeJson(join(stateDir, 'hud-state.json'), {
450
- last_turn_at: nowIso,
451
- turn_count: 1,
452
- });
453
- await writeJson(join(tasksDir, 'task-1.json'), {
454
- id: '1',
455
- subject: 'Done',
456
- description: 'completed work item',
457
- status: 'completed',
458
- owner: 'worker-1',
459
- created_at: nowIso,
460
- });
461
- for (const worker of ['worker-1', 'worker-2']) {
462
- await mkdir(join(workersDir, worker), { recursive: true });
463
- await writeJson(join(workersDir, worker, 'status.json'), {
464
- state: 'idle',
465
- updated_at: nowIso,
466
- });
467
- }
468
- await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%10 12345', '%11 12346']));
469
- await chmod(fakeTmuxPath, 0o755);
470
- const result = runNotifyHook(cwd, fakeBinDir, {
471
- RCS_SESSION_ID: 'sess-canonical-missing',
472
- });
473
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
474
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
475
- assert.match(tmuxLog, /\[RCS\] All 2 workers idle\./);
476
- assert.match(tmuxLog, /Team idle-shutdown looks complete\./);
477
- assert.match(tmuxLog, /Next: decide whether to reconcile\/merge results or gracefully shut down: rcs team shutdown idle-shutdown\./);
478
- assert.doesNotMatch(tmuxLog, /keep polling/);
479
- });
480
- });
481
- it('suggests reusing the team when follow-up tasks are pending and worker panes are still reusable', async () => {
482
- await withTempWorkingDir(async (cwd) => {
483
- const rcsDir = join(cwd, '.rcs');
484
- const stateDir = join(rcsDir, 'state');
485
- const logsDir = join(rcsDir, 'logs');
486
- const teamName = 'idle-followup-reuse';
487
- const teamDir = join(stateDir, 'team', teamName);
488
- const workersDir = join(teamDir, 'workers');
489
- const tasksDir = join(teamDir, 'tasks');
490
- const fakeBinDir = join(cwd, 'fake-bin');
491
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
492
- const tmuxLogPath = join(cwd, 'tmux.log');
493
- const nowIso = new Date().toISOString();
494
- await mkdir(logsDir, { recursive: true });
495
- await mkdir(workersDir, { recursive: true });
496
- await mkdir(tasksDir, { recursive: true });
497
- await mkdir(fakeBinDir, { recursive: true });
498
- await writeJson(join(stateDir, 'team-state.json'), {
499
- active: true,
500
- team_name: teamName,
501
- current_phase: 'team-exec',
502
- });
503
- await writeJson(join(teamDir, 'config.json'), {
504
- name: teamName,
505
- tmux_session: 'idle-followup-reuse:0',
506
- leader_pane_id: '%97',
507
- workers: [
508
- { name: 'worker-1', index: 1, pane_id: '%10', role: 'executor' },
509
- { name: 'worker-2', index: 2, pane_id: '%11', role: 'executor' },
510
- ],
511
- });
512
- await writeJson(join(stateDir, 'hud-state.json'), {
513
- last_turn_at: nowIso,
514
- turn_count: 1,
515
- });
516
- await writeJson(join(tasksDir, 'task-2.json'), {
517
- id: '2',
518
- subject: 'Follow-up',
519
- description: 'queued follow-up task',
520
- status: 'pending',
521
- created_at: nowIso,
522
- });
523
- for (const worker of ['worker-1', 'worker-2']) {
524
- await mkdir(join(workersDir, worker), { recursive: true });
525
- await writeJson(join(workersDir, worker, 'status.json'), {
526
- state: 'idle',
527
- updated_at: nowIso,
528
- });
529
- }
530
- await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%10 12345', '%11 12346']));
531
- await chmod(fakeTmuxPath, 0o755);
532
- const result = runNotifyHook(cwd, fakeBinDir, {
533
- RCS_SESSION_ID: 'sess-canonical-inactive',
534
- });
535
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
536
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
537
- assert.match(tmuxLog, /\[RCS\] All 2 workers idle/);
538
- assert.match(tmuxLog, /Team idle-followup-reuse has idle workers ready\./);
539
- assert.match(tmuxLog, /Next: assign the next follow-up task to this idle team\./);
540
- assert.doesNotMatch(tmuxLog, /launch a new team/);
541
- });
542
- });
543
- it('suggests launching a new team when follow-up tasks are pending but worker panes are no longer reusable', async () => {
544
- await withTempWorkingDir(async (cwd) => {
545
- const rcsDir = join(cwd, '.rcs');
546
- const stateDir = join(rcsDir, 'state');
547
- const logsDir = join(rcsDir, 'logs');
548
- const teamName = 'idle-followup-relaunch';
549
- const teamDir = join(stateDir, 'team', teamName);
550
- const workersDir = join(teamDir, 'workers');
551
- const tasksDir = join(teamDir, 'tasks');
552
- const fakeBinDir = join(cwd, 'fake-bin');
553
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
554
- const tmuxLogPath = join(cwd, 'tmux.log');
555
- const nowIso = new Date().toISOString();
556
- await mkdir(logsDir, { recursive: true });
557
- await mkdir(workersDir, { recursive: true });
558
- await mkdir(tasksDir, { recursive: true });
559
- await mkdir(fakeBinDir, { recursive: true });
560
- await writeJson(join(stateDir, 'team-state.json'), {
561
- active: true,
562
- team_name: teamName,
563
- current_phase: 'team-exec',
564
- });
565
- await writeJson(join(teamDir, 'config.json'), {
566
- name: teamName,
567
- tmux_session: 'idle-followup-relaunch:0',
568
- leader_pane_id: '%98',
569
- workers: [
570
- { name: 'worker-1', index: 1, pane_id: '%10', role: 'executor' },
571
- { name: 'worker-2', index: 2, pane_id: '%11', role: 'executor' },
572
- ],
573
- });
574
- await writeJson(join(stateDir, 'hud-state.json'), {
575
- last_turn_at: nowIso,
576
- turn_count: 1,
577
- });
578
- await writeJson(join(tasksDir, 'task-2.json'), {
579
- id: '2',
580
- subject: 'Follow-up',
581
- description: 'queued follow-up task',
582
- status: 'pending',
583
- created_at: nowIso,
584
- });
585
- for (const worker of ['worker-1', 'worker-2']) {
586
- await mkdir(join(workersDir, worker), { recursive: true });
587
- await writeJson(join(workersDir, worker, 'status.json'), {
588
- state: 'idle',
589
- updated_at: nowIso,
590
- });
591
- }
592
- await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%98 12349']));
593
- await chmod(fakeTmuxPath, 0o755);
594
- const result = runNotifyHook(cwd, fakeBinDir);
595
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
596
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
597
- assert.match(tmuxLog, /\[RCS\] All 2 workers idle/);
598
- assert.match(tmuxLog, /Team idle-followup-relaunch has follow-up work ready\./);
599
- assert.match(tmuxLog, /Next: launch a new team for the next task set\./);
600
- assert.doesNotMatch(tmuxLog, /idle workers ready/);
601
- });
602
- });
603
- it('falls back to global team-state when session-scoped state is active but team-state.json remains global', async () => {
604
- await withTempWorkingDir(async (cwd) => {
605
- const rcsDir = join(cwd, '.rcs');
606
- const stateDir = join(rcsDir, 'state');
607
- const logsDir = join(rcsDir, 'logs');
608
- const sessionId = 'sess-idle-fallback';
609
- const sessionDir = join(stateDir, 'sessions', sessionId);
610
- const teamName = 'idle-global-fallback';
611
- const teamDir = join(stateDir, 'team', teamName);
612
- const workersDir = join(teamDir, 'workers');
613
- const fakeBinDir = join(cwd, 'fake-bin');
614
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
615
- const tmuxLogPath = join(cwd, 'tmux.log');
616
- await mkdir(logsDir, { recursive: true });
617
- await mkdir(sessionDir, { recursive: true });
618
- await mkdir(workersDir, { recursive: true });
619
- await mkdir(fakeBinDir, { recursive: true });
620
- await writeJson(join(stateDir, 'session.json'), { session_id: sessionId });
621
- await writeJson(join(stateDir, 'team-state.json'), {
622
- active: true,
623
- team_name: teamName,
624
- current_phase: 'team-exec',
625
- });
626
- await writeJson(join(teamDir, 'config.json'), {
627
- name: teamName,
628
- tmux_session: 'idle-global:0',
629
- leader_pane_id: '%97',
630
- workers: [
631
- { name: 'worker-1', index: 1, role: 'executor', assigned_tasks: [] },
632
- { name: 'worker-2', index: 2, role: 'executor', assigned_tasks: [] },
633
- ],
634
- });
635
- await writeJson(join(stateDir, 'hud-state.json'), {
636
- last_turn_at: new Date().toISOString(),
637
- turn_count: 1,
638
- });
639
- for (const worker of ['worker-1', 'worker-2']) {
640
- await mkdir(join(workersDir, worker), { recursive: true });
641
- await writeJson(join(workersDir, worker, 'status.json'), {
642
- state: 'idle',
643
- updated_at: new Date().toISOString(),
644
- });
645
- }
646
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
647
- await chmod(fakeTmuxPath, 0o755);
648
- const result = runNotifyHook(cwd, fakeBinDir);
649
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
650
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
651
- assert.match(tmuxLog, /send-keys/);
652
- assert.match(tmuxLog, /-t %97/, 'should still target the leader pane');
653
- assert.match(tmuxLog, /\[RCS\] All 2 workers idle/, 'global team-state fallback should still fire idle nudge');
654
- });
655
- });
656
- it('falls back to canonical team state when coarse team-state is missing', async () => {
657
- await withTempWorkingDir(async (cwd) => {
658
- const fakeBinDir = join(cwd, 'fake-bin');
659
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
660
- const tmuxLogPath = join(cwd, 'tmux.log');
661
- await mkdir(fakeBinDir, { recursive: true });
662
- await writeCanonicalTeamFixture(cwd, {
663
- teamName: 'canonical-missing',
664
- sessionId: 'sess-canonical-missing',
665
- ownerSessionId: 'sess-canonical-missing',
666
- });
667
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
668
- await chmod(fakeTmuxPath, 0o755);
669
- const result = runNotifyHook(cwd, fakeBinDir, {
670
- RCS_SESSION_ID: 'sess-canonical-missing',
671
- });
672
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
673
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
674
- assert.match(tmuxLog, /send-keys/);
675
- assert.match(tmuxLog, /-t %97/, 'should target canonical leader pane');
676
- assert.match(tmuxLog, /\[RCS\] All 2 workers idle/, 'canonical fallback should still fire idle nudge');
677
- });
678
- });
679
- it('falls back to canonical team state when coarse team-state is inactive', async () => {
680
- await withTempWorkingDir(async (cwd) => {
681
- const fakeBinDir = join(cwd, 'fake-bin');
682
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
683
- const tmuxLogPath = join(cwd, 'tmux.log');
684
- await mkdir(fakeBinDir, { recursive: true });
685
- await writeCanonicalTeamFixture(cwd, {
686
- teamName: 'canonical-inactive',
687
- sessionId: 'sess-canonical-inactive',
688
- ownerSessionId: 'sess-canonical-inactive',
689
- coarseState: 'inactive',
690
- });
691
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
692
- await chmod(fakeTmuxPath, 0o755);
693
- const result = runNotifyHook(cwd, fakeBinDir, {
694
- RCS_SESSION_ID: 'sess-canonical-inactive',
695
- });
696
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
697
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
698
- assert.match(tmuxLog, /send-keys/);
699
- assert.match(tmuxLog, /-t %97/, 'should still target canonical leader pane');
700
- assert.match(tmuxLog, /\[RCS\] All 2 workers idle/, 'inactive coarse state should still fall back canonically');
701
- });
702
- });
703
- it('ignores invalid team_name before canonical leader follow-up team path joins', async () => {
704
- await withTempWorkingDir(async (cwd) => {
705
- const fakeBinDir = join(cwd, 'fake-bin');
706
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
707
- const tmuxLogPath = join(cwd, 'tmux.log');
708
- await mkdir(fakeBinDir, { recursive: true });
709
- await writeCanonicalTeamFixture(cwd, {
710
- teamName: 'canonical-safe',
711
- sessionId: 'sess-canonical-safe',
712
- ownerSessionId: 'sess-canonical-safe',
713
- coarseState: 'inactive',
714
- });
715
- const teamRoot = join(cwd, '.rcs', 'state', 'team');
716
- await mkdir(join(teamRoot, '..-bad-team'), { recursive: true });
717
- await writeJson(join(teamRoot, '..-bad-team', 'manifest.v2.json'), {
718
- schema_version: 2,
719
- name: '..-bad-team',
720
- task: 'invalid canonical fallback fixture',
721
- leader: { session_id: 'sess-canonical-safe', worker_id: 'leader-fixed', role: 'coordinator' },
722
- tmux_session: 'bad:0',
723
- leader_pane_id: '%666',
724
- hud_pane_id: null,
725
- resize_hook_name: null,
726
- resize_hook_target: null,
727
- worker_count: 1,
728
- next_task_id: 1,
729
- workers: [{ name: 'worker-1', index: 1, pane_id: '%666', role: 'executor' }],
730
- created_at: new Date().toISOString(),
731
- policy: {
732
- worker_launch_mode: 'interactive',
733
- display_mode: 'split_pane',
734
- dispatch_mode: 'hook_preferred_with_fallback',
735
- dispatch_ack_timeout_ms: 2000,
736
- },
737
- governance: {
738
- delegation_only: false,
739
- plan_approval_required: false,
740
- nested_teams_allowed: false,
741
- one_team_per_leader_session: true,
742
- cleanup_requires_all_workers_inactive: true,
743
- },
744
- lifecycle_profile: 'default',
745
- permissions_snapshot: {
746
- approval_mode: 'never',
747
- sandbox_mode: 'danger-full-access',
748
- network_access: true,
749
- },
750
- });
751
- await writeJson(join(teamRoot, '..-bad-team', 'phase.json'), {
752
- current_phase: 'team-exec',
753
- updated_at: new Date().toISOString(),
754
- transitions: [],
755
- });
756
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
757
- await chmod(fakeTmuxPath, 0o755);
758
- const result = runNotifyHook(cwd, fakeBinDir, {
759
- RCS_SESSION_ID: 'sess-canonical-safe',
760
- });
761
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
762
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
763
- assert.match(tmuxLog, /-t %97/, 'should still target the valid canonical leader pane');
764
- assert.doesNotMatch(tmuxLog, /%666/, 'invalid canonical team names must be ignored before joins');
765
- assert.match(tmuxLog, /\[RCS\] All 2 workers idle/, 'valid canonical fallback should still fire idle nudge');
766
- });
767
- });
768
- it('nudges leader via tmux send-keys when team is active and mailbox has messages', async () => {
769
- await withTempWorkingDir(async (cwd) => {
770
- const rcsDir = join(cwd, '.rcs');
771
- const stateDir = join(rcsDir, 'state');
772
- const logsDir = join(rcsDir, 'logs');
773
- const teamName = 'alpha';
774
- const teamDir = join(stateDir, 'team', teamName);
775
- const mailboxDir = join(teamDir, 'mailbox');
776
- const fakeBinDir = join(cwd, 'fake-bin');
777
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
778
- const tmuxLogPath = join(cwd, 'tmux.log');
779
- await mkdir(logsDir, { recursive: true });
780
- await mkdir(mailboxDir, { recursive: true });
781
- await mkdir(fakeBinDir, { recursive: true });
782
- await writeJson(join(stateDir, 'team-state.json'), {
783
- active: true,
784
- team_name: teamName,
785
- current_phase: 'team-exec',
786
- });
787
- await writeJson(join(teamDir, 'config.json'), {
788
- name: teamName,
789
- tmux_session: 'devsess:0',
790
- leader_pane_id: '%91',
791
- });
792
- await writeJson(join(mailboxDir, 'leader-fixed.json'), {
793
- worker: 'leader-fixed',
794
- messages: [
795
- {
796
- message_id: 'm1',
797
- from_worker: 'worker-1',
798
- to_worker: 'leader-fixed',
799
- body: 'ACK',
800
- created_at: '2026-02-14T00:00:00.000Z',
801
- },
802
- ],
803
- });
804
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
805
- await chmod(fakeTmuxPath, 0o755);
806
- const result = runNotifyHook(cwd, fakeBinDir);
807
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
808
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
809
- assert.match(tmuxLog, /send-keys/);
810
- assert.match(tmuxLog, /-t %91/);
811
- assert.doesNotMatch(tmuxLog, /-t devsess:0/);
812
- assert.match(tmuxLog, /Team alpha:/);
813
- assert.match(tmuxLog, /\[RCS_TMUX_INJECT\]/, 'should include injection marker');
814
- const deliveryLog = await readTeamDeliveryLog(cwd);
815
- assert.ok(deliveryLog.some((entry) => entry.event === 'nudge_triggered'
816
- && entry.source === 'notify_hook'
817
- && entry.team === teamName
818
- && entry.to_worker === 'leader-fixed'
819
- && entry.transport === 'send-keys'
820
- && entry.result === 'sent'));
821
- });
822
- });
823
- it('injects leader nudge into a busy live Codex pane so the message can queue', async () => {
824
- await withTempWorkingDir(async (cwd) => {
825
- const rcsDir = join(cwd, '.rcs');
826
- const stateDir = join(rcsDir, 'state');
827
- const logsDir = join(rcsDir, 'logs');
828
- const teamName = 'busy-live-pane';
829
- const teamDir = join(stateDir, 'team', teamName);
830
- const mailboxDir = join(teamDir, 'mailbox');
831
- const fakeBinDir = join(cwd, 'fake-bin');
832
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
833
- const tmuxLogPath = join(cwd, 'tmux.log');
834
- await mkdir(logsDir, { recursive: true });
835
- await mkdir(mailboxDir, { recursive: true });
836
- await mkdir(fakeBinDir, { recursive: true });
837
- await writeJson(join(stateDir, 'team-state.json'), {
838
- active: true,
839
- team_name: teamName,
840
- current_phase: 'team-exec',
841
- });
842
- await writeJson(join(teamDir, 'config.json'), {
843
- name: teamName,
844
- tmux_session: 'busy-live-pane:0',
845
- leader_pane_id: '%93',
846
- });
847
- await writeJson(join(mailboxDir, 'leader-fixed.json'), {
848
- worker: 'leader-fixed',
849
- messages: [
850
- {
851
- message_id: 'busy-msg-1',
852
- from_worker: 'worker-1',
853
- to_worker: 'leader-fixed',
854
- body: 'Need leader review',
855
- created_at: '2026-03-12T00:00:00.000Z',
856
- },
857
- ],
858
- });
859
- const fakeTmux = `#!/usr/bin/env bash
860
- set -eu
861
- echo "$@" >> "${tmuxLogPath}"
862
- cmd="$1"
863
- shift || true
864
- if [[ "$cmd" == "display-message" ]]; then
865
- target=""
866
- format=""
867
- while (($#)); do
868
- case "$1" in
869
- -p) shift ;;
870
- -t) target="$2"; shift 2 ;;
871
- *) format="$1"; shift ;;
872
- esac
873
- done
874
- if [[ "$format" == "#{pane_in_mode}" && "$target" == "%93" ]]; then
875
- echo "0"
876
- exit 0
877
- fi
878
- if [[ "$format" == "#{pane_current_command}" && "$target" == "%93" ]]; then
879
- echo "codex"
880
- exit 0
881
- fi
882
- exit 0
883
- fi
884
- if [[ "$cmd" == "capture-pane" ]]; then
885
- cat <<'EOF'
886
- OpenAI Codex
887
- • Working… (esc to interrupt)
888
-
889
- EOF
890
- exit 0
891
- fi
892
- if [[ "$cmd" == "send-keys" ]]; then
893
- exit 0
894
- fi
895
- if [[ "$cmd" == "list-panes" ]]; then
896
- echo "%1 12345"
897
- exit 0
898
- fi
899
- exit 0
900
- `;
901
- await writeFile(fakeTmuxPath, fakeTmux);
902
- await chmod(fakeTmuxPath, 0o755);
903
- const result = runNotifyHook(cwd, fakeBinDir);
904
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
905
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
906
- assert.match(tmuxLog, /display-message -p -t %93 #\{pane_in_mode\}/);
907
- assert.match(tmuxLog, /capture-pane -t %93 -p -S -80/);
908
- assert.match(tmuxLog, /send-keys -t %93 -l .*Team busy-live-pane:/);
909
- assert.match(tmuxLog, /\[RCS_TMUX_INJECT\]/, 'should keep the injection marker on busy-pane sends');
910
- const eventsPath = join(teamDir, 'events', 'events.ndjson');
911
- assert.ok(existsSync(eventsPath), 'events.ndjson should exist');
912
- const events = (await readFile(eventsPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
913
- assert.ok(events.some((entry) => entry.type === 'team_leader_nudge' && entry.reason === 'new_mailbox_message'));
914
- assert.ok(!events.some((entry) => entry.type === 'leader_notification_deferred' && entry.reason === 'pane_has_active_task'));
915
- });
916
- });
917
- it('surfaces ack-like mailbox replies without work-start evidence as missing-start nudges', async () => {
918
- await withTempWorkingDir(async (cwd) => {
919
- const rcsDir = join(cwd, '.rcs');
920
- const stateDir = join(rcsDir, 'state');
921
- const logsDir = join(rcsDir, 'logs');
922
- const teamName = 'ack-missing-start';
923
- const teamDir = join(stateDir, 'team', teamName);
924
- const mailboxDir = join(teamDir, 'mailbox');
925
- const workersDir = join(teamDir, 'workers');
926
- const fakeBinDir = join(cwd, 'fake-bin');
927
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
928
- const tmuxLogPath = join(cwd, 'tmux.log');
929
- await mkdir(logsDir, { recursive: true });
930
- await mkdir(mailboxDir, { recursive: true });
931
- await mkdir(join(workersDir, 'worker-1'), { recursive: true });
932
- await mkdir(fakeBinDir, { recursive: true });
933
- await writeJson(join(stateDir, 'team-state.json'), {
934
- active: true,
935
- team_name: teamName,
936
- current_phase: 'team-exec',
937
- });
938
- await writeJson(join(teamDir, 'config.json'), {
939
- name: teamName,
940
- tmux_session: 'ack-sess:0',
941
- leader_pane_id: '%94',
942
- workers: [
943
- { name: 'worker-1', index: 1, role: 'executor', assigned_tasks: ['1'] },
944
- ],
945
- });
946
- await writeJson(join(mailboxDir, 'leader-fixed.json'), {
947
- worker: 'leader-fixed',
948
- messages: [
949
- {
950
- message_id: 'ack-1',
951
- from_worker: 'worker-1',
952
- to_worker: 'leader-fixed',
953
- body: 'on it',
954
- created_at: '2026-02-14T00:00:00.000Z',
955
- },
956
- ],
957
- });
958
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
959
- await chmod(fakeTmuxPath, 0o755);
960
- const result = runNotifyHook(cwd, fakeBinDir);
961
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
962
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
963
- assert.match(tmuxLog, /worker-1 said "on it"/);
964
- assert.match(tmuxLog, /no start evidence/);
965
- assert.match(tmuxLog, /status: unknown/);
966
- assert.match(tmuxLog, /Next: check worker-1 msg\/output, confirm task in rcs team status ack-missing-start/);
967
- assert.doesNotMatch(tmuxLog, /\[RCS_INTENT:/);
968
- const eventsPath = join(teamDir, 'events', 'events.ndjson');
969
- const events = (await readFile(eventsPath, 'utf-8')).trim().split('\n').map(line => JSON.parse(line));
970
- const nudgeEvent = events.find((e) => e.type === 'team_leader_nudge' && e.reason === 'ack_without_start_evidence');
971
- assert.ok(nudgeEvent, 'should emit an ack_without_start_evidence leader nudge');
972
- assert.equal(nudgeEvent.orchestration_intent, 'followup-relaunch');
973
- });
974
- });
975
- it('does not classify ack-like replies as missing-start after a worker has claimed work', async () => {
976
- await withTempWorkingDir(async (cwd) => {
977
- const rcsDir = join(cwd, '.rcs');
978
- const stateDir = join(rcsDir, 'state');
979
- const logsDir = join(rcsDir, 'logs');
980
- const teamName = 'ack-with-start';
981
- const teamDir = join(stateDir, 'team', teamName);
982
- const mailboxDir = join(teamDir, 'mailbox');
983
- const workersDir = join(teamDir, 'workers');
984
- const tasksDir = join(teamDir, 'tasks');
985
- const fakeBinDir = join(cwd, 'fake-bin');
986
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
987
- const tmuxLogPath = join(cwd, 'tmux.log');
988
- await mkdir(logsDir, { recursive: true });
989
- await mkdir(mailboxDir, { recursive: true });
990
- await mkdir(join(workersDir, 'worker-1'), { recursive: true });
991
- await mkdir(tasksDir, { recursive: true });
992
- await mkdir(fakeBinDir, { recursive: true });
993
- await writeJson(join(stateDir, 'team-state.json'), {
994
- active: true,
995
- team_name: teamName,
996
- current_phase: 'team-exec',
997
- });
998
- await writeJson(join(teamDir, 'config.json'), {
999
- name: teamName,
1000
- tmux_session: 'ack-started:0',
1001
- leader_pane_id: '%95',
1002
- workers: [
1003
- { name: 'worker-1', index: 1, role: 'executor', assigned_tasks: ['1'] },
1004
- ],
1005
- });
1006
- await writeJson(join(stateDir, 'hud-state.json'), {
1007
- last_turn_at: new Date().toISOString(),
1008
- turn_count: 1,
1009
- });
1010
- await writeJson(join(workersDir, 'worker-1', 'status.json'), {
1011
- state: 'working',
1012
- current_task_id: '1',
1013
- updated_at: new Date().toISOString(),
1014
- });
1015
- await writeJson(join(tasksDir, 'task-1.json'), {
1016
- id: '1',
1017
- subject: 'Investigate failure',
1018
- description: 'trace ack without start',
1019
- status: 'in_progress',
1020
- owner: 'worker-1',
1021
- created_at: new Date().toISOString(),
1022
- });
1023
- await writeJson(join(mailboxDir, 'leader-fixed.json'), {
1024
- worker: 'leader-fixed',
1025
- messages: [
1026
- {
1027
- message_id: 'ack-2',
1028
- from_worker: 'worker-1',
1029
- to_worker: 'leader-fixed',
1030
- body: 'on it',
1031
- created_at: '2026-02-14T00:00:00.000Z',
1032
- },
1033
- ],
1034
- });
1035
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
1036
- await chmod(fakeTmuxPath, 0o755);
1037
- const result = runNotifyHook(cwd, fakeBinDir);
1038
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
1039
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
1040
- assert.doesNotMatch(tmuxLog, /no start evidence/);
1041
- assert.match(tmuxLog, /Team ack-with-start: 1 msg\(s\) for leader\./);
1042
- assert.match(tmuxLog, /Next: read messages; keep orchestrating; if done, gracefully shut down: rcs team shutdown ack-with-start\./);
1043
- const eventsPath = join(teamDir, 'events', 'events.ndjson');
1044
- const events = (await readFile(eventsPath, 'utf-8')).trim().split('\n').map(line => JSON.parse(line));
1045
- const nudgeEvent = events.find((e) => e.type === 'team_leader_nudge');
1046
- assert.equal(nudgeEvent?.reason, 'new_mailbox_message');
1047
- });
1048
- });
1049
- it('does not re-nudge for the same fresh mailbox message on repeated notify-hook runs', async () => {
1050
- await withTempWorkingDir(async (cwd) => {
1051
- const rcsDir = join(cwd, '.rcs');
1052
- const stateDir = join(rcsDir, 'state');
1053
- const logsDir = join(rcsDir, 'logs');
1054
- const teamName = 'fresh-mailbox-bounded';
1055
- const teamDir = join(stateDir, 'team', teamName);
1056
- const mailboxDir = join(teamDir, 'mailbox');
1057
- const fakeBinDir = join(cwd, 'fake-bin');
1058
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
1059
- const tmuxLogPath = join(cwd, 'tmux.log');
1060
- await mkdir(logsDir, { recursive: true });
1061
- await mkdir(mailboxDir, { recursive: true });
1062
- await mkdir(fakeBinDir, { recursive: true });
1063
- await writeJson(join(stateDir, 'team-state.json'), {
1064
- active: true,
1065
- team_name: teamName,
1066
- current_phase: 'team-exec',
1067
- });
1068
- await writeJson(join(teamDir, 'config.json'), {
1069
- name: teamName,
1070
- tmux_session: 'fresh-mailbox-bounded:0',
1071
- leader_pane_id: '%97',
1072
- workers: [
1073
- { name: 'worker-1', index: 1, role: 'executor', assigned_tasks: ['1'] },
1074
- ],
1075
- });
1076
- await writeJson(join(stateDir, 'hud-state.json'), {
1077
- last_turn_at: new Date().toISOString(),
1078
- turn_count: 1,
1079
- });
1080
- await writeJson(join(mailboxDir, 'leader-fixed.json'), {
1081
- worker: 'leader-fixed',
1082
- messages: [
1083
- {
1084
- message_id: 'same-msg-1',
1085
- from_worker: 'worker-1',
1086
- to_worker: 'leader-fixed',
1087
- body: 'please review',
1088
- created_at: '2026-02-14T00:00:00.000Z',
1089
- },
1090
- ],
1091
- });
1092
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
1093
- await chmod(fakeTmuxPath, 0o755);
1094
- const first = runNotifyHook(cwd, fakeBinDir, { RCS_TEAM_LEADER_NUDGE_MS: '600000' });
1095
- assert.equal(first.status, 0, `notify-hook failed: ${first.stderr || first.stdout}`);
1096
- const second = runNotifyHook(cwd, fakeBinDir, { RCS_TEAM_LEADER_NUDGE_MS: '600000' });
1097
- assert.equal(second.status, 0, `notify-hook failed: ${second.stderr || second.stdout}`);
1098
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
1099
- const sends = tmuxLog.match(/send-keys -t %97 -l Team fresh-mailbox-bounded: 1 msg\(s\) for leader\./g) || [];
1100
- assert.equal(sends.length, 1, 'same mailbox message should not trigger repeated non-stale nudges');
1101
- });
1102
- });
1103
- it('does not inject leader nudge into a shell pane', async () => {
1104
- await withTempWorkingDir(async (cwd) => {
1105
- const rcsDir = join(cwd, '.rcs');
1106
- const stateDir = join(rcsDir, 'state');
1107
- const logsDir = join(rcsDir, 'logs');
1108
- const teamName = 'shell-guard';
1109
- const teamDir = join(stateDir, 'team', teamName);
1110
- const mailboxDir = join(teamDir, 'mailbox');
1111
- const fakeBinDir = join(cwd, 'fake-bin');
1112
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
1113
- const tmuxLogPath = join(cwd, 'tmux.log');
1114
- await mkdir(logsDir, { recursive: true });
1115
- await mkdir(mailboxDir, { recursive: true });
1116
- await mkdir(fakeBinDir, { recursive: true });
1117
- await writeJson(join(stateDir, 'team-state.json'), {
1118
- active: true,
1119
- team_name: teamName,
1120
- current_phase: 'team-exec',
1121
- });
1122
- await writeJson(join(teamDir, 'config.json'), {
1123
- name: teamName,
1124
- tmux_session: 'shell-guard:0',
1125
- leader_pane_id: '%71',
1126
- });
1127
- await writeJson(join(mailboxDir, 'leader-fixed.json'), {
1128
- worker: 'leader-fixed',
1129
- messages: [
1130
- {
1131
- message_id: 'm1',
1132
- from_worker: 'worker-1',
1133
- to_worker: 'leader-fixed',
1134
- body: 'ACK',
1135
- created_at: '2026-02-14T00:00:00.000Z',
1136
- },
1137
- ],
1138
- });
1139
- const fakeTmux = `#!/usr/bin/env bash
1140
- set -eu
1141
- echo "$@" >> "${tmuxLogPath}"
1142
- cmd="$1"
1143
- shift || true
1144
- if [[ "$cmd" == "display-message" ]]; then
1145
- target=""
1146
- format=""
1147
- while (($#)); do
1148
- case "$1" in
1149
- -p) shift ;;
1150
- -t) target="$2"; shift 2 ;;
1151
- *) format="$1"; shift ;;
1152
- esac
1153
- done
1154
- if [[ "$format" == "#{pane_current_command}" && "$target" == "%71" ]]; then
1155
- echo "zsh"
1156
- fi
1157
- exit 0
1158
- fi
1159
- if [[ "$cmd" == "send-keys" ]]; then
1160
- exit 0
1161
- fi
1162
- if [[ "$cmd" == "list-panes" ]]; then
1163
- echo "%1 12345"
1164
- exit 0
1165
- fi
1166
- exit 0
1167
- `;
1168
- await writeFile(fakeTmuxPath, fakeTmux);
1169
- await chmod(fakeTmuxPath, 0o755);
1170
- const result = runNotifyHook(cwd, fakeBinDir);
1171
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
1172
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
1173
- assert.match(tmuxLog, /display-message -p -t %71 #\{pane_current_command\}/);
1174
- assert.doesNotMatch(tmuxLog, /send-keys -t %71/, 'should not inject into a shell pane');
1175
- const eventsPath = join(teamDir, 'events', 'events.ndjson');
1176
- const events = (await readFile(eventsPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
1177
- const deferred = events.find((entry) => entry.type === 'leader_notification_deferred' && entry.reason === 'leader_pane_shell_no_injection');
1178
- assert.ok(deferred, 'should emit deferred event for shell-pane leader');
1179
- assert.equal(deferred.pane_current_command, 'zsh');
1180
- });
1181
- });
1182
- it('injects leader nudge even while the leader pane has an active task', async () => {
1183
- await withTempWorkingDir(async (cwd) => {
1184
- const rcsDir = join(cwd, '.rcs');
1185
- const stateDir = join(rcsDir, 'state');
1186
- const logsDir = join(rcsDir, 'logs');
1187
- const teamName = 'busy-leader-queue';
1188
- const teamDir = join(stateDir, 'team', teamName);
1189
- const mailboxDir = join(teamDir, 'mailbox');
1190
- const fakeBinDir = join(cwd, 'fake-bin');
1191
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
1192
- const tmuxLogPath = join(cwd, 'tmux.log');
1193
- await mkdir(logsDir, { recursive: true });
1194
- await mkdir(mailboxDir, { recursive: true });
1195
- await mkdir(fakeBinDir, { recursive: true });
1196
- await writeJson(join(stateDir, 'team-state.json'), {
1197
- active: true,
1198
- team_name: teamName,
1199
- current_phase: 'team-exec',
1200
- });
1201
- await writeJson(join(teamDir, 'config.json'), {
1202
- name: teamName,
1203
- tmux_session: 'busy-leader-queue:0',
1204
- leader_pane_id: '%73',
1205
- });
1206
- await writeJson(join(mailboxDir, 'leader-fixed.json'), {
1207
- worker: 'leader-fixed',
1208
- messages: [
1209
- {
1210
- message_id: 'm1',
1211
- from_worker: 'worker-1',
1212
- to_worker: 'leader-fixed',
1213
- body: 'please review queued message',
1214
- created_at: '2026-03-12T00:00:00.000Z',
1215
- },
1216
- ],
1217
- });
1218
- const fakeTmux = `#!/usr/bin/env bash
1219
- set -eu
1220
- echo "$@" >> "${tmuxLogPath}"
1221
- cmd="$1"
1222
- shift || true
1223
- if [[ "$cmd" == "display-message" ]]; then
1224
- target=""
1225
- format=""
1226
- while (($#)); do
1227
- case "$1" in
1228
- -p) shift ;;
1229
- -t) target="$2"; shift 2 ;;
1230
- *) format="$1"; shift ;;
1231
- esac
1232
- done
1233
- if [[ "$format" == "#{pane_in_mode}" && "$target" == "%73" ]]; then
1234
- echo "0"
1235
- exit 0
1236
- fi
1237
- if [[ "$format" == "#{pane_current_command}" && "$target" == "%73" ]]; then
1238
- echo "codex"
1239
- exit 0
1240
- fi
1241
- exit 0
1242
- fi
1243
- if [[ "$cmd" == "capture-pane" ]]; then
1244
- printf "• Running tests (3m 12s • esc to interrupt)\\n"
1245
- exit 0
1246
- fi
1247
- if [[ "$cmd" == "send-keys" ]]; then
1248
- exit 0
1249
- fi
1250
- if [[ "$cmd" == "list-panes" ]]; then
1251
- echo "%1 12345"
1252
- exit 0
1253
- fi
1254
- exit 0
1255
- `;
1256
- await writeFile(fakeTmuxPath, fakeTmux);
1257
- await chmod(fakeTmuxPath, 0o755);
1258
- const result = runNotifyHook(cwd, fakeBinDir);
1259
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
1260
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
1261
- assert.match(tmuxLog, /capture-pane/);
1262
- assert.match(tmuxLog, /send-keys -t %73/, 'should inject into a busy leader pane so Codex can queue the message');
1263
- const eventsPath = join(teamDir, 'events', 'events.ndjson');
1264
- if (existsSync(eventsPath)) {
1265
- const events = (await readFile(eventsPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
1266
- const deferred = events.find((entry) => entry.type === 'leader_notification_deferred' && entry.reason === 'pane_has_active_task');
1267
- assert.equal(deferred, undefined, 'busy leader pane should no longer defer notifications');
1268
- }
1269
- });
1270
- });
1271
- it('injects leader nudge when capture-pane fails but the leader pane is a live codex pane', async () => {
1272
- await withTempWorkingDir(async (cwd) => {
1273
- const rcsDir = join(cwd, '.rcs');
1274
- const stateDir = join(rcsDir, 'state');
1275
- const logsDir = join(rcsDir, 'logs');
1276
- const teamName = 'capture-failure-live-leader';
1277
- const teamDir = join(stateDir, 'team', teamName);
1278
- const mailboxDir = join(teamDir, 'mailbox');
1279
- const fakeBinDir = join(cwd, 'fake-bin');
1280
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
1281
- const tmuxLogPath = join(cwd, 'tmux.log');
1282
- await mkdir(logsDir, { recursive: true });
1283
- await mkdir(mailboxDir, { recursive: true });
1284
- await mkdir(fakeBinDir, { recursive: true });
1285
- await writeJson(join(stateDir, 'team-state.json'), {
1286
- active: true,
1287
- team_name: teamName,
1288
- current_phase: 'team-exec',
1289
- });
1290
- await writeJson(join(teamDir, 'config.json'), {
1291
- name: teamName,
1292
- tmux_session: 'capture-failure-live-leader:0',
1293
- leader_pane_id: '%74',
1294
- });
1295
- await writeJson(join(mailboxDir, 'leader-fixed.json'), {
1296
- worker: 'leader-fixed',
1297
- messages: [
1298
- {
1299
- message_id: 'm1',
1300
- from_worker: 'worker-1',
1301
- to_worker: 'leader-fixed',
1302
- body: 'please review capture failure path',
1303
- created_at: '2026-03-12T00:00:00.000Z',
1304
- },
1305
- ],
1306
- });
1307
- const fakeTmux = `#!/usr/bin/env bash
1308
- set -eu
1309
- echo "$@" >> "${tmuxLogPath}"
1310
- cmd="$1"
1311
- shift || true
1312
- if [[ "$cmd" == "display-message" ]]; then
1313
- target=""
1314
- format=""
1315
- while (($#)); do
1316
- case "$1" in
1317
- -p) shift ;;
1318
- -t) target="$2"; shift 2 ;;
1319
- *) format="$1"; shift ;;
1320
- esac
1321
- done
1322
- if [[ "$format" == "#{pane_in_mode}" && "$target" == "%74" ]]; then
1323
- echo "0"
1324
- exit 0
1325
- fi
1326
- if [[ "$format" == "#{pane_current_command}" && "$target" == "%74" ]]; then
1327
- echo "codex"
1328
- exit 0
1329
- fi
1330
- exit 0
1331
- fi
1332
- if [[ "$cmd" == "capture-pane" ]]; then
1333
- echo "capture failed" >&2
1334
- exit 1
1335
- fi
1336
- if [[ "$cmd" == "send-keys" ]]; then
1337
- exit 0
1338
- fi
1339
- if [[ "$cmd" == "list-panes" ]]; then
1340
- echo "%1 12345"
1341
- exit 0
1342
- fi
1343
- exit 0
1344
- `;
1345
- await writeFile(fakeTmuxPath, fakeTmux);
1346
- await chmod(fakeTmuxPath, 0o755);
1347
- const result = runNotifyHook(cwd, fakeBinDir);
1348
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
1349
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
1350
- assert.match(tmuxLog, /capture-pane -t %74 -p -S -80/);
1351
- assert.match(tmuxLog, /send-keys -t %74/, 'capture failures should not suppress leader injection into a live codex pane');
1352
- const eventsPath = join(teamDir, 'events', 'events.ndjson');
1353
- if (existsSync(eventsPath)) {
1354
- const events = (await readFile(eventsPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
1355
- const deferred = events.find((entry) => entry.type === 'leader_notification_deferred');
1356
- assert.equal(deferred, undefined, 'capture failure alone should not defer a live codex leader pane');
1357
- }
1358
- });
1359
- });
1360
- it('suppresses duplicate visible leader injection when the pane already shows the same classified state', async () => {
1361
- await withTempWorkingDir(async (cwd) => {
1362
- const rcsDir = join(cwd, '.rcs');
1363
- const stateDir = join(rcsDir, 'state');
1364
- const logsDir = join(rcsDir, 'logs');
1365
- const teamName = 'same-classified-state';
1366
- const teamDir = join(stateDir, 'team', teamName);
1367
- const mailboxDir = join(teamDir, 'mailbox');
1368
- const fakeBinDir = join(cwd, 'fake-bin');
1369
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
1370
- const tmuxLogPath = join(cwd, 'tmux.log');
1371
- await mkdir(logsDir, { recursive: true });
1372
- await mkdir(mailboxDir, { recursive: true });
1373
- await mkdir(fakeBinDir, { recursive: true });
1374
- await writeJson(join(stateDir, 'team-state.json'), {
1375
- active: true,
1376
- team_name: teamName,
1377
- current_phase: 'team-exec',
1378
- });
1379
- await writeJson(join(teamDir, 'config.json'), {
1380
- name: teamName,
1381
- tmux_session: 'same-classified-state:0',
1382
- leader_pane_id: '%75',
1383
- });
1384
- await writeJson(join(mailboxDir, 'leader-fixed.json'), {
1385
- worker: 'leader-fixed',
1386
- messages: [
1387
- {
1388
- message_id: 'same-classified-msg',
1389
- from_worker: 'worker-1',
1390
- to_worker: 'leader-fixed',
1391
- body: 'please review latest output',
1392
- created_at: '2026-03-12T00:00:00.000Z',
1393
- },
1394
- ],
1395
- });
1396
- const fakeTmux = `#!/usr/bin/env bash
1397
- set -eu
1398
- echo "$@" >> "${tmuxLogPath}"
1399
- cmd="$1"
1400
- shift || true
1401
- if [[ "$cmd" == "display-message" ]]; then
1402
- target=""
1403
- format=""
1404
- while (($#)); do
1405
- case "$1" in
1406
- -p) shift ;;
1407
- -t) target="$2"; shift 2 ;;
1408
- *) format="$1"; shift ;;
1409
- esac
1410
- done
1411
- if [[ "$format" == "#{pane_in_mode}" && "$target" == "%75" ]]; then
1412
- echo "0"
1413
- exit 0
1414
- fi
1415
- if [[ "$format" == "#{pane_current_command}" && "$target" == "%75" ]]; then
1416
- echo "codex"
1417
- exit 0
1418
- fi
1419
- exit 0
1420
- fi
1421
- if [[ "$cmd" == "capture-pane" ]]; then
1422
- cat <<'EOF'
1423
- Team same-classified-state: 1 msg(s) for leader. Next: read messages; keep orchestrating; if done, gracefully shut down: rcs team shutdown same-classified-state.
1424
- EOF
1425
- exit 0
1426
- fi
1427
- if [[ "$cmd" == "send-keys" ]]; then
1428
- exit 0
1429
- fi
1430
- if [[ "$cmd" == "list-panes" ]]; then
1431
- echo "%1 12345"
1432
- exit 0
1433
- fi
1434
- exit 0
1435
- `;
1436
- await writeFile(fakeTmuxPath, fakeTmux);
1437
- await chmod(fakeTmuxPath, 0o755);
1438
- const result = runNotifyHook(cwd, fakeBinDir);
1439
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
1440
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
1441
- assert.match(tmuxLog, /capture-pane -t %75 -p -S -80/);
1442
- assert.doesNotMatch(tmuxLog, /send-keys -t %75 -l Team same-classified-state: 1 msg\(s\) for leader\./, 'same visible classified state should not be reinjected');
1443
- const eventsPath = join(teamDir, 'events', 'events.ndjson');
1444
- const events = (await readFile(eventsPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
1445
- const nudgeEvent = events.find((entry) => entry.type === 'team_leader_nudge' && entry.reason === 'new_mailbox_message');
1446
- assert.ok(nudgeEvent, 'suppressed visible sends should still emit leader nudge events');
1447
- assert.equal(nudgeEvent.orchestration_intent, 'pending-mailbox-review');
1448
- const deliveryLog = await readTeamDeliveryLog(cwd);
1449
- assert.ok(deliveryLog.some((entry) => entry.event === 'nudge_triggered'
1450
- && entry.team === teamName
1451
- && entry.to_worker === 'leader-fixed'
1452
- && entry.result === 'suppressed'
1453
- && entry.reason === 'new_mailbox_message'
1454
- && entry.suppression_reason === 'pane_already_shows_same_classified_state'));
1455
- });
1456
- });
1457
- it('does not inject leader nudge while leader pane is in copy-mode', async () => {
1458
- await withTempWorkingDir(async (cwd) => {
1459
- const rcsDir = join(cwd, '.rcs');
1460
- const stateDir = join(rcsDir, 'state');
1461
- const logsDir = join(rcsDir, 'logs');
1462
- const teamName = 'scroll-guard';
1463
- const teamDir = join(stateDir, 'team', teamName);
1464
- const mailboxDir = join(teamDir, 'mailbox');
1465
- const fakeBinDir = join(cwd, 'fake-bin');
1466
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
1467
- const tmuxLogPath = join(cwd, 'tmux.log');
1468
- await mkdir(logsDir, { recursive: true });
1469
- await mkdir(mailboxDir, { recursive: true });
1470
- await mkdir(fakeBinDir, { recursive: true });
1471
- await writeJson(join(stateDir, 'team-state.json'), {
1472
- active: true,
1473
- team_name: teamName,
1474
- current_phase: 'team-exec',
1475
- });
1476
- await writeJson(join(teamDir, 'config.json'), {
1477
- name: teamName,
1478
- tmux_session: 'scroll-guard:0',
1479
- leader_pane_id: '%72',
1480
- });
1481
- await writeJson(join(mailboxDir, 'leader-fixed.json'), {
1482
- worker: 'leader-fixed',
1483
- messages: [
1484
- {
1485
- message_id: 'm1',
1486
- from_worker: 'worker-1',
1487
- to_worker: 'leader-fixed',
1488
- body: 'follow up',
1489
- created_at: '2026-03-12T00:00:00.000Z',
1490
- },
1491
- ],
1492
- });
1493
- const fakeTmux = `#!/usr/bin/env bash
1494
- set -eu
1495
- echo "$@" >> "${tmuxLogPath}"
1496
- cmd="$1"
1497
- shift || true
1498
- if [[ "$cmd" == "display-message" ]]; then
1499
- target=""
1500
- format=""
1501
- while (($#)); do
1502
- case "$1" in
1503
- -p) shift ;;
1504
- -t) target="$2"; shift 2 ;;
1505
- *) format="$1"; shift ;;
1506
- esac
1507
- done
1508
- if [[ "$format" == "#{pane_in_mode}" && "$target" == "%72" ]]; then
1509
- echo "1"
1510
- exit 0
1511
- fi
1512
- if [[ "$format" == "#{pane_current_command}" && "$target" == "%72" ]]; then
1513
- echo "codex"
1514
- exit 0
1515
- fi
1516
- exit 0
1517
- fi
1518
- if [[ "$cmd" == "send-keys" ]]; then
1519
- exit 0
1520
- fi
1521
- if [[ "$cmd" == "list-panes" ]]; then
1522
- echo "%1 12345"
1523
- exit 0
1524
- fi
1525
- exit 0
1526
- `;
1527
- await writeFile(fakeTmuxPath, fakeTmux);
1528
- await chmod(fakeTmuxPath, 0o755);
1529
- const result = runNotifyHook(cwd, fakeBinDir);
1530
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
1531
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
1532
- assert.match(tmuxLog, /display-message -p -t %72 #\{pane_in_mode\}/);
1533
- assert.doesNotMatch(tmuxLog, /send-keys -t %72/, 'should not inject into a scrolling leader pane');
1534
- const eventsPath = join(teamDir, 'events', 'events.ndjson');
1535
- const events = (await readFile(eventsPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
1536
- const deferred = events.find((entry) => entry.type === 'leader_notification_deferred' && entry.reason === 'scroll_active');
1537
- assert.ok(deferred, 'should emit deferred event for scrolling leader pane');
1538
- });
1539
- });
1540
- it('syncs stale root team-state to inactive when team-local phase is already terminal', async () => {
1541
- await withTempWorkingDir(async (cwd) => {
1542
- const rcsDir = join(cwd, '.rcs');
1543
- const stateDir = join(rcsDir, 'state');
1544
- const logsDir = join(rcsDir, 'logs');
1545
- const teamName = 'terminal-sync';
1546
- const teamDir = join(stateDir, 'team', teamName);
1547
- const fakeBinDir = join(cwd, 'fake-bin');
1548
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
1549
- const tmuxLogPath = join(cwd, 'tmux.log');
1550
- await mkdir(logsDir, { recursive: true });
1551
- await mkdir(teamDir, { recursive: true });
1552
- await mkdir(fakeBinDir, { recursive: true });
1553
- await writeJson(join(stateDir, 'team-state.json'), {
1554
- active: true,
1555
- team_name: teamName,
1556
- current_phase: 'team-exec',
1557
- });
1558
- await writeJson(join(teamDir, 'phase.json'), {
1559
- current_phase: 'complete',
1560
- transitions: [
1561
- { from: 'team-verify', to: 'complete', at: '2026-03-09T19:20:19.088Z' },
1562
- ],
1563
- updated_at: '2026-03-09T19:20:19.088Z',
1564
- });
1565
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
1566
- await chmod(fakeTmuxPath, 0o755);
1567
- const result = runNotifyHook(cwd, fakeBinDir);
1568
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
1569
- const syncedState = JSON.parse(await readFile(join(stateDir, 'team-state.json'), 'utf-8'));
1570
- assert.equal(syncedState.active, false);
1571
- assert.equal(syncedState.current_phase, 'complete');
1572
- assert.equal(syncedState.completed_at, '2026-03-09T19:20:19.088Z');
1573
- if (existsSync(tmuxLogPath)) {
1574
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
1575
- assert.doesNotMatch(tmuxLog, /send-keys/, 'must not nudge a terminal team');
1576
- }
1577
- });
1578
- });
1579
- it('does not nudge completed teams on reopen even when config and idle worker state still exist', async () => {
1580
- await withTempWorkingDir(async (cwd) => {
1581
- const rcsDir = join(cwd, '.rcs');
1582
- const stateDir = join(rcsDir, 'state');
1583
- const logsDir = join(rcsDir, 'logs');
1584
- const teamName = 'completed-reopen';
1585
- const teamDir = join(stateDir, 'team', teamName);
1586
- const workersDir = join(teamDir, 'workers');
1587
- const fakeBinDir = join(cwd, 'fake-bin');
1588
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
1589
- const tmuxLogPath = join(cwd, 'tmux.log');
1590
- const completedAt = '2026-03-21T08:40:35.471Z';
1591
- await mkdir(logsDir, { recursive: true });
1592
- await mkdir(workersDir, { recursive: true });
1593
- await mkdir(fakeBinDir, { recursive: true });
1594
- await writeJson(join(stateDir, 'team-state.json'), {
1595
- active: false,
1596
- team_name: teamName,
1597
- current_phase: 'complete',
1598
- completed_at: completedAt,
1599
- });
1600
- await writeJson(join(teamDir, 'config.json'), {
1601
- name: teamName,
1602
- tmux_session: 'completed-reopen:0',
1603
- leader_pane_id: '%91',
1604
- workers: [
1605
- { name: 'worker-1', index: 1, pane_id: '%10', role: 'executor' },
1606
- { name: 'worker-2', index: 2, pane_id: '%11', role: 'executor' },
1607
- ],
1608
- });
1609
- await writeJson(join(teamDir, 'phase.json'), {
1610
- current_phase: 'complete',
1611
- transitions: [{ from: 'team-verify', to: 'complete', at: completedAt }],
1612
- updated_at: completedAt,
1613
- });
1614
- for (const worker of ['worker-1', 'worker-2']) {
1615
- await mkdir(join(workersDir, worker), { recursive: true });
1616
- await writeJson(join(workersDir, worker, 'status.json'), {
1617
- state: 'idle',
1618
- updated_at: new Date().toISOString(),
1619
- });
1620
- }
1621
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
1622
- await chmod(fakeTmuxPath, 0o755);
1623
- const result = runNotifyHook(cwd, fakeBinDir);
1624
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
1625
- if (existsSync(tmuxLogPath)) {
1626
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
1627
- assert.doesNotMatch(tmuxLog, /send-keys/, 'completed teams must not re-nudge on reopen');
1628
- }
1629
- });
1630
- });
1631
- it('does not nudge a team owned by another session', async () => {
1632
- await withTempWorkingDir(async (cwd) => {
1633
- const rcsDir = join(cwd, '.rcs');
1634
- const stateDir = join(rcsDir, 'state');
1635
- const logsDir = join(rcsDir, 'logs');
1636
- const teamName = 'other-session-team';
1637
- const teamDir = join(stateDir, 'team', teamName);
1638
- const workersDir = join(teamDir, 'workers');
1639
- const fakeBinDir = join(cwd, 'fake-bin');
1640
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
1641
- const tmuxLogPath = join(cwd, 'tmux.log');
1642
- const nowIso = new Date().toISOString();
1643
- await mkdir(logsDir, { recursive: true });
1644
- await mkdir(workersDir, { recursive: true });
1645
- await mkdir(fakeBinDir, { recursive: true });
1646
- await writeJson(join(stateDir, 'session.json'), { session_id: 'sess-current' });
1647
- await writeJson(join(stateDir, 'team-state.json'), {
1648
- active: true,
1649
- team_name: teamName,
1650
- current_phase: 'team-exec',
1651
- });
1652
- await writeJson(join(teamDir, 'manifest.v2.json'), {
1653
- schema_version: 2,
1654
- name: teamName,
1655
- task: 'session ownership repro',
1656
- leader: {
1657
- session_id: 'sess-other',
1658
- worker_id: 'leader-fixed',
1659
- role: 'coordinator',
1660
- },
1661
- policy: {
1662
- worker_launch_mode: 'interactive',
1663
- display_mode: 'split_pane',
1664
- dispatch_mode: 'hook_preferred_with_fallback',
1665
- dispatch_ack_timeout_ms: 2000,
1666
- },
1667
- tmux_session: 'other-session-team:0',
1668
- leader_pane_id: '%94',
1669
- worker_count: 2,
1670
- workers: [
1671
- { name: 'worker-1', index: 1, pane_id: '%10', role: 'executor' },
1672
- { name: 'worker-2', index: 2, pane_id: '%11', role: 'executor' },
1673
- ],
1674
- created_at: nowIso,
1675
- });
1676
- for (const worker of ['worker-1', 'worker-2']) {
1677
- await mkdir(join(workersDir, worker), { recursive: true });
1678
- await writeJson(join(workersDir, worker, 'status.json'), {
1679
- state: 'idle',
1680
- updated_at: nowIso,
1681
- });
1682
- }
1683
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
1684
- await chmod(fakeTmuxPath, 0o755);
1685
- const result = runNotifyHook(cwd, fakeBinDir);
1686
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
1687
- if (existsSync(tmuxLogPath)) {
1688
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
1689
- assert.doesNotMatch(tmuxLog, /send-keys/, 'must not nudge teams owned by another session');
1690
- }
1691
- });
1692
- });
1693
- it('does not nudge a canonical-only team when owner session is blank', async () => {
1694
- await withTempWorkingDir(async (cwd) => {
1695
- const fakeBinDir = join(cwd, 'fake-bin');
1696
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
1697
- const tmuxLogPath = join(cwd, 'tmux.log');
1698
- await mkdir(fakeBinDir, { recursive: true });
1699
- await writeCanonicalTeamFixture(cwd, {
1700
- teamName: 'ownerless-team',
1701
- sessionId: 'sess-current',
1702
- ownerSessionId: '',
1703
- });
1704
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
1705
- await chmod(fakeTmuxPath, 0o755);
1706
- const result = runNotifyHook(cwd, fakeBinDir);
1707
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
1708
- if (existsSync(tmuxLogPath)) {
1709
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
1710
- assert.doesNotMatch(tmuxLog, /send-keys/, 'ownerless canonical teams must not nudge');
1711
- }
1712
- });
1713
- });
1714
- it('nudges when worker panes are alive and leader is stale (no recent HUD turn)', async () => {
1715
- await withTempWorkingDir(async (cwd) => {
1716
- const rcsDir = join(cwd, '.rcs');
1717
- const stateDir = join(rcsDir, 'state');
1718
- const logsDir = join(rcsDir, 'logs');
1719
- const teamName = 'beta';
1720
- const teamDir = join(stateDir, 'team', teamName);
1721
- const fakeBinDir = join(cwd, 'fake-bin');
1722
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
1723
- const tmuxLogPath = join(cwd, 'tmux.log');
1724
- await mkdir(logsDir, { recursive: true });
1725
- await mkdir(join(teamDir, 'mailbox'), { recursive: true });
1726
- await mkdir(fakeBinDir, { recursive: true });
1727
- await writeJson(join(stateDir, 'team-state.json'), {
1728
- active: true,
1729
- team_name: teamName,
1730
- current_phase: 'team-exec',
1731
- });
1732
- await writeJson(join(teamDir, 'config.json'), {
1733
- name: teamName,
1734
- tmux_session: 'rcs-team-beta',
1735
- leader_pane_id: '%92',
1736
- });
1737
- // Leader HUD state is stale (last turn 5 minutes ago)
1738
- await writeJson(join(stateDir, 'hud-state.json'), {
1739
- last_turn_at: new Date(Date.now() - 300_000).toISOString(),
1740
- turn_count: 5,
1741
- });
1742
- // No mailbox messages — but worker panes alive should trigger nudge
1743
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
1744
- await chmod(fakeTmuxPath, 0o755);
1745
- const result = runNotifyHook(cwd, fakeBinDir);
1746
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
1747
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
1748
- assert.match(tmuxLog, /send-keys/);
1749
- assert.match(tmuxLog, /Team beta:/);
1750
- assert.match(tmuxLog, /leader stale, \d+ worker pane\(s\) still active\./);
1751
- assert.match(tmuxLog, /Next: check messages; keep orchestrating; if done, gracefully shut down: rcs team shutdown beta\./);
1752
- assert.doesNotMatch(tmuxLog, /keep polling/);
1753
- assert.match(tmuxLog, /\[RCS_TMUX_INJECT\]/, 'should include injection marker');
1754
- });
1755
- });
1756
- it('nudges when team progress is stalled even if timing signals are fresh or missing (fallback threshold)', async () => {
1757
- await withTempWorkingDir(async (cwd) => {
1758
- const rcsDir = join(cwd, '.rcs');
1759
- const stateDir = join(rcsDir, 'state');
1760
- const logsDir = join(rcsDir, 'logs');
1761
- const teamName = 'stalled-progress';
1762
- const teamDir = join(stateDir, 'team', teamName);
1763
- const workersDir = join(teamDir, 'workers');
1764
- const tasksDir = join(teamDir, 'tasks');
1765
- const fakeBinDir = join(cwd, 'fake-bin');
1766
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
1767
- const tmuxLogPath = join(cwd, 'tmux.log');
1768
- const nowIso = new Date().toISOString();
1769
- await mkdir(logsDir, { recursive: true });
1770
- await mkdir(tasksDir, { recursive: true });
1771
- await mkdir(join(workersDir, 'worker-1'), { recursive: true });
1772
- await mkdir(fakeBinDir, { recursive: true });
1773
- await writeJson(join(stateDir, 'team-state.json'), {
1774
- active: true,
1775
- team_name: teamName,
1776
- current_phase: 'team-exec',
1777
- });
1778
- await writeJson(join(teamDir, 'config.json'), {
1779
- name: teamName,
1780
- tmux_session: 'rcs-team-stalled-progress',
1781
- leader_pane_id: '%90',
1782
- workers: [
1783
- { name: 'worker-1', index: 1, pane_id: '%10' },
1784
- { name: 'worker-2', index: 2, pane_id: '%11' },
1785
- ],
1786
- });
1787
- await writeJson(join(stateDir, 'hud-state.json'), {
1788
- last_turn_at: new Date(Date.now() - 300_000).toISOString(),
1789
- turn_count: 4,
1790
- });
1791
- await writeJson(join(tasksDir, 'task-1.json'), {
1792
- id: '1',
1793
- subject: 'Investigate stall',
1794
- description: 'worker-1 owns the active task',
1795
- status: 'in_progress',
1796
- owner: 'worker-1',
1797
- created_at: nowIso,
1798
- });
1799
- await writeJson(join(tasksDir, 'task-2.json'), {
1800
- id: '2',
1801
- subject: 'Follow-up',
1802
- description: 'still pending',
1803
- status: 'pending',
1804
- created_at: nowIso,
1805
- });
1806
- await writeJson(join(workersDir, 'worker-1', 'status.json'), {
1807
- state: 'working',
1808
- current_task_id: '1',
1809
- updated_at: nowIso,
1810
- });
1811
- await writeJson(join(workersDir, 'worker-1', 'heartbeat.json'), {
1812
- last_turn_at: nowIso,
1813
- turn_count: 2,
1814
- alive: true,
1815
- });
1816
- const stalledSignature = JSON.stringify({
1817
- tasks: [
1818
- { id: '1', owner: 'worker-1', status: 'in_progress' },
1819
- { id: '2', owner: '', status: 'pending' },
1820
- ],
1821
- workers: [
1822
- {
1823
- worker: 'worker-1',
1824
- state: 'working',
1825
- current_task_id: '1',
1826
- status_missing: false,
1827
- turn_count: 2,
1828
- heartbeat_missing: false,
1829
- },
1830
- {
1831
- worker: 'worker-2',
1832
- state: 'unknown',
1833
- current_task_id: '',
1834
- status_missing: true,
1835
- turn_count: null,
1836
- heartbeat_missing: true,
1837
- },
1838
- ],
1839
- });
1840
- await writeJson(join(stateDir, 'team-leader-nudge.json'), {
1841
- last_nudged_by_team: {
1842
- [teamName]: {
1843
- at: new Date(Date.now() - 5_000).toISOString(),
1844
- last_message_id: '',
1845
- reason: 'new_mailbox_message',
1846
- },
1847
- },
1848
- progress_by_team: {
1849
- [teamName]: {
1850
- signature: stalledSignature,
1851
- last_progress_at: new Date(Date.now() - 180_000).toISOString(),
1852
- },
1853
- },
1854
- });
1855
- await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%10 12345', '%11 12346']));
1856
- await chmod(fakeTmuxPath, 0o755);
1857
- const result = runNotifyHook(cwd, fakeBinDir, {
1858
- RCS_TEAM_PROGRESS_STALL_MS: '60000',
1859
- RCS_TEAM_LEADER_NUDGE_MS: '30000',
1860
- });
1861
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
1862
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
1863
- assert.match(tmuxLog, /Team stalled-progress: leader stale, no progress 3m(?:\d+s)?\./);
1864
- assert.match(tmuxLog, /Next: rcs team status stalled-progress; read worker messages; unblock\/reassign or shutdown\./);
1865
- assert.doesNotMatch(tmuxLog, /keep polling/);
1866
- assert.doesNotMatch(tmuxLog, /\[RCS_INTENT:/);
1867
- assert.match(tmuxLog, /\[RCS_TMUX_INJECT\]/);
1868
- const eventsPath = join(teamDir, 'events', 'events.ndjson');
1869
- const events = (await readFile(eventsPath, 'utf-8')).trim().split('\n').map(line => JSON.parse(line));
1870
- const nudgeEvent = events.find((e) => e.type === 'team_leader_nudge');
1871
- assert.equal(nudgeEvent?.reason, 'stuck_waiting_on_leader');
1872
- assert.equal(nudgeEvent?.orchestration_intent, 'stalled-unblock');
1873
- });
1874
- });
1875
- it('nudges when team progress is stalled before the leader becomes stale (fallback threshold)', async () => {
1876
- await withTempWorkingDir(async (cwd) => {
1877
- const rcsDir = join(cwd, '.rcs');
1878
- const stateDir = join(rcsDir, 'state');
1879
- const logsDir = join(rcsDir, 'logs');
1880
- const teamName = 'stalled-before-stale';
1881
- const teamDir = join(stateDir, 'team', teamName);
1882
- const workersDir = join(teamDir, 'workers');
1883
- const tasksDir = join(teamDir, 'tasks');
1884
- const fakeBinDir = join(cwd, 'fake-bin');
1885
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
1886
- const tmuxLogPath = join(cwd, 'tmux.log');
1887
- const nowIso = new Date().toISOString();
1888
- await mkdir(logsDir, { recursive: true });
1889
- await mkdir(tasksDir, { recursive: true });
1890
- await mkdir(join(workersDir, 'worker-1'), { recursive: true });
1891
- await mkdir(fakeBinDir, { recursive: true });
1892
- await writeJson(join(stateDir, 'team-state.json'), {
1893
- active: true,
1894
- team_name: teamName,
1895
- current_phase: 'team-exec',
1896
- });
1897
- await writeJson(join(teamDir, 'config.json'), {
1898
- name: teamName,
1899
- tmux_session: 'rcs-team-stalled-before-stale',
1900
- leader_pane_id: '%89',
1901
- workers: [
1902
- { name: 'worker-1', index: 1, pane_id: '%10' },
1903
- { name: 'worker-2', index: 2, pane_id: '%11' },
1904
- ],
1905
- });
1906
- await writeJson(join(stateDir, 'hud-state.json'), {
1907
- last_turn_at: nowIso,
1908
- turn_count: 4,
1909
- });
1910
- await writeJson(join(tasksDir, 'task-1.json'), {
1911
- id: '1',
1912
- subject: 'Investigate stall',
1913
- description: 'worker-1 owns the active task',
1914
- status: 'in_progress',
1915
- owner: 'worker-1',
1916
- created_at: nowIso,
1917
- });
1918
- await writeJson(join(tasksDir, 'task-2.json'), {
1919
- id: '2',
1920
- subject: 'Follow-up',
1921
- description: 'still pending',
1922
- status: 'pending',
1923
- created_at: nowIso,
1924
- });
1925
- await writeJson(join(workersDir, 'worker-1', 'status.json'), {
1926
- state: 'working',
1927
- current_task_id: '1',
1928
- updated_at: nowIso,
1929
- });
1930
- await writeJson(join(workersDir, 'worker-1', 'heartbeat.json'), {
1931
- last_turn_at: nowIso,
1932
- turn_count: 2,
1933
- alive: true,
1934
- });
1935
- const stalledSignature = JSON.stringify({
1936
- tasks: [
1937
- { id: '1', owner: 'worker-1', status: 'in_progress' },
1938
- { id: '2', owner: '', status: 'pending' },
1939
- ],
1940
- workers: [
1941
- {
1942
- worker: 'worker-1',
1943
- state: 'working',
1944
- current_task_id: '1',
1945
- status_missing: false,
1946
- turn_count: 2,
1947
- heartbeat_missing: false,
1948
- },
1949
- {
1950
- worker: 'worker-2',
1951
- state: 'unknown',
1952
- current_task_id: '',
1953
- status_missing: true,
1954
- turn_count: null,
1955
- heartbeat_missing: true,
1956
- },
1957
- ],
1958
- });
1959
- await writeJson(join(stateDir, 'team-leader-nudge.json'), {
1960
- last_nudged_by_team: {
1961
- [teamName]: {
1962
- at: new Date(Date.now() - 5_000).toISOString(),
1963
- last_message_id: '',
1964
- reason: 'new_mailbox_message',
1965
- },
1966
- },
1967
- progress_by_team: {
1968
- [teamName]: {
1969
- signature: stalledSignature,
1970
- last_progress_at: new Date(Date.now() - 180_000).toISOString(),
1971
- },
1972
- },
1973
- });
1974
- await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%10 12345', '%11 12346']));
1975
- await chmod(fakeTmuxPath, 0o755);
1976
- const result = runNotifyHook(cwd, fakeBinDir, {
1977
- RCS_TEAM_PROGRESS_STALL_MS: '60000',
1978
- RCS_TEAM_LEADER_NUDGE_MS: '30000',
1979
- RCS_TEAM_LEADER_STALE_MS: '60000',
1980
- });
1981
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
1982
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
1983
- assert.match(tmuxLog, /Team stalled-before-stale: worker panes stalled, no progress 3m(?:\d+s)?\./);
1984
- assert.match(tmuxLog, /Next: rcs team status stalled-before-stale; read worker messages; unblock\/reassign or shutdown\./);
1985
- assert.doesNotMatch(tmuxLog, /keep polling/);
1986
- assert.doesNotMatch(tmuxLog, /leader stale/);
1987
- const eventsPath = join(teamDir, 'events', 'events.ndjson');
1988
- const events = (await readFile(eventsPath, 'utf-8')).trim().split('\n').map(line => JSON.parse(line));
1989
- const nudgeEvent = events.find((e) => e.type === 'team_leader_nudge');
1990
- assert.equal(nudgeEvent?.reason, 'stuck_waiting_on_leader');
1991
- });
1992
- });
1993
- it('nudges stalled team after configurable worker turn stall window elapses (primary threshold)', async () => {
1994
- await withTempWorkingDir(async (cwd) => {
1995
- const rcsDir = join(cwd, '.rcs');
1996
- const stateDir = join(rcsDir, 'state');
1997
- const logsDir = join(rcsDir, 'logs');
1998
- const teamName = 'worker-turn-stall-threshold';
1999
- const teamDir = join(stateDir, 'team', teamName);
2000
- const workersDir = join(teamDir, 'workers');
2001
- const tasksDir = join(teamDir, 'tasks');
2002
- const fakeBinDir = join(cwd, 'fake-bin');
2003
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
2004
- const tmuxLogPath = join(cwd, 'tmux.log');
2005
- const nowIso = new Date().toISOString();
2006
- await mkdir(logsDir, { recursive: true });
2007
- await mkdir(tasksDir, { recursive: true });
2008
- await mkdir(join(workersDir, 'worker-1'), { recursive: true });
2009
- await mkdir(fakeBinDir, { recursive: true });
2010
- await writeJson(join(stateDir, 'team-state.json'), {
2011
- active: true,
2012
- team_name: teamName,
2013
- current_phase: 'team-exec',
2014
- });
2015
- await writeJson(join(teamDir, 'config.json'), {
2016
- name: teamName,
2017
- tmux_session: 'rcs-team-worker-turn-stall-threshold',
2018
- leader_pane_id: '%86',
2019
- workers: [
2020
- { name: 'worker-1', index: 1, pane_id: '%10' },
2021
- ],
2022
- });
2023
- await writeJson(join(stateDir, 'hud-state.json'), {
2024
- last_turn_at: nowIso,
2025
- turn_count: 4,
2026
- });
2027
- await writeJson(join(tasksDir, 'task-1.json'), {
2028
- id: '1',
2029
- subject: 'Investigate stall',
2030
- description: 'worker-1 owns the active task',
2031
- status: 'in_progress',
2032
- owner: 'worker-1',
2033
- created_at: nowIso,
2034
- });
2035
- await writeJson(join(workersDir, 'worker-1', 'status.json'), {
2036
- state: 'working',
2037
- current_task_id: '1',
2038
- updated_at: nowIso,
2039
- });
2040
- await writeJson(join(workersDir, 'worker-1', 'heartbeat.json'), {
2041
- last_turn_at: nowIso,
2042
- turn_count: 5,
2043
- alive: true,
2044
- });
2045
- const previousSignature = JSON.stringify({
2046
- tasks: [
2047
- { id: '1', owner: 'worker-1', status: 'in_progress' },
2048
- ],
2049
- workers: [
2050
- {
2051
- worker: 'worker-1',
2052
- state: 'working',
2053
- current_task_id: '1',
2054
- status_missing: false,
2055
- turn_count: 5,
2056
- heartbeat_missing: false,
2057
- },
2058
- ],
2059
- });
2060
- await writeJson(join(stateDir, 'team-leader-nudge.json'), {
2061
- last_nudged_by_team: {
2062
- [teamName]: {
2063
- at: new Date(Date.now() - 60_000).toISOString(),
2064
- last_message_id: '',
2065
- reason: 'new_mailbox_message',
2066
- },
2067
- },
2068
- progress_by_team: {
2069
- [teamName]: {
2070
- signature: previousSignature,
2071
- last_progress_at: new Date(Date.now() - 45_000).toISOString(),
2072
- },
2073
- },
2074
- });
2075
- await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%10 12345']));
2076
- await chmod(fakeTmuxPath, 0o755);
2077
- const result = runNotifyHook(cwd, fakeBinDir, {
2078
- RCS_TEAM_PROGRESS_STALL_MS: '120000',
2079
- RCS_TEAM_WORKER_TURN_STALL_MS: '30000',
2080
- RCS_TEAM_LEADER_NUDGE_MS: '30000',
2081
- RCS_TEAM_LEADER_STALE_MS: '60000',
2082
- });
2083
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
2084
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
2085
- assert.match(tmuxLog, /Team worker-turn-stall-threshold: worker panes stalled, no progress 45s\./);
2086
- });
2087
- });
2088
- it('does not nudge stalled team when an in-progress worker is still advancing heartbeat turns', async () => {
2089
- await withTempWorkingDir(async (cwd) => {
2090
- const rcsDir = join(cwd, '.rcs');
2091
- const stateDir = join(rcsDir, 'state');
2092
- const logsDir = join(rcsDir, 'logs');
2093
- const teamName = 'active-turns-no-stall';
2094
- const teamDir = join(stateDir, 'team', teamName);
2095
- const workersDir = join(teamDir, 'workers');
2096
- const tasksDir = join(teamDir, 'tasks');
2097
- const fakeBinDir = join(cwd, 'fake-bin');
2098
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
2099
- const tmuxLogPath = join(cwd, 'tmux.log');
2100
- const nowIso = new Date().toISOString();
2101
- await mkdir(logsDir, { recursive: true });
2102
- await mkdir(tasksDir, { recursive: true });
2103
- await mkdir(join(workersDir, 'worker-1'), { recursive: true });
2104
- await mkdir(fakeBinDir, { recursive: true });
2105
- await writeJson(join(stateDir, 'team-state.json'), {
2106
- active: true,
2107
- team_name: teamName,
2108
- current_phase: 'team-exec',
2109
- });
2110
- await writeJson(join(teamDir, 'config.json'), {
2111
- name: teamName,
2112
- tmux_session: 'rcs-team-active-turns-no-stall',
2113
- leader_pane_id: '%87',
2114
- workers: [
2115
- { name: 'worker-1', index: 1, pane_id: '%10' },
2116
- { name: 'worker-2', index: 2, pane_id: '%11' },
2117
- ],
2118
- });
2119
- await writeJson(join(stateDir, 'hud-state.json'), {
2120
- last_turn_at: nowIso,
2121
- turn_count: 4,
2122
- });
2123
- await writeJson(join(tasksDir, 'task-1.json'), {
2124
- id: '1',
2125
- subject: 'Investigate stall',
2126
- description: 'worker-1 owns the active task',
2127
- status: 'in_progress',
2128
- owner: 'worker-1',
2129
- created_at: nowIso,
2130
- });
2131
- await writeJson(join(tasksDir, 'task-2.json'), {
2132
- id: '2',
2133
- subject: 'Follow-up',
2134
- description: 'still pending',
2135
- status: 'pending',
2136
- created_at: nowIso,
2137
- });
2138
- await writeJson(join(workersDir, 'worker-1', 'status.json'), {
2139
- state: 'working',
2140
- current_task_id: '1',
2141
- updated_at: nowIso,
2142
- });
2143
- await writeJson(join(workersDir, 'worker-1', 'heartbeat.json'), {
2144
- last_turn_at: nowIso,
2145
- turn_count: 8,
2146
- alive: true,
2147
- });
2148
- const previousSignature = JSON.stringify({
2149
- tasks: [
2150
- { id: '1', owner: 'worker-1', status: 'in_progress' },
2151
- { id: '2', owner: '', status: 'pending' },
2152
- ],
2153
- workers: [
2154
- {
2155
- worker: 'worker-1',
2156
- state: 'working',
2157
- current_task_id: '1',
2158
- status_missing: false,
2159
- turn_count: 2,
2160
- heartbeat_missing: false,
2161
- },
2162
- {
2163
- worker: 'worker-2',
2164
- state: 'unknown',
2165
- current_task_id: '',
2166
- status_missing: true,
2167
- turn_count: null,
2168
- heartbeat_missing: true,
2169
- },
2170
- ]
2171
- });
2172
- await writeJson(join(stateDir, 'team-leader-nudge.json'), {
2173
- last_nudged_by_team: {
2174
- [teamName]: {
2175
- at: new Date(Date.now() - 5_000).toISOString(),
2176
- last_message_id: '',
2177
- reason: 'new_mailbox_message',
2178
- },
2179
- },
2180
- progress_by_team: {
2181
- [teamName]: {
2182
- signature: previousSignature,
2183
- last_progress_at: new Date(Date.now() - 180_000).toISOString(),
2184
- },
2185
- },
2186
- });
2187
- await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%10 12345', '%11 12346']));
2188
- await chmod(fakeTmuxPath, 0o755);
2189
- const result = runNotifyHook(cwd, fakeBinDir, {
2190
- RCS_TEAM_PROGRESS_STALL_MS: '60000',
2191
- RCS_TEAM_LEADER_NUDGE_MS: '30000',
2192
- RCS_TEAM_LEADER_STALE_MS: '60000',
2193
- });
2194
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
2195
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
2196
- assert.doesNotMatch(tmuxLog, /active-turns-no-stall: worker panes stalled, no progress/);
2197
- assert.doesNotMatch(tmuxLog, /active-turns-no-stall: leader stale, no progress/);
2198
- });
2199
- });
2200
- it('bounds repeated stalled-team nudges before leader stale by cooldown', async () => {
2201
- await withTempWorkingDir(async (cwd) => {
2202
- const rcsDir = join(cwd, '.rcs');
2203
- const stateDir = join(rcsDir, 'state');
2204
- const logsDir = join(rcsDir, 'logs');
2205
- const teamName = 'stalled-before-stale-bounded';
2206
- const teamDir = join(stateDir, 'team', teamName);
2207
- const workersDir = join(teamDir, 'workers');
2208
- const tasksDir = join(teamDir, 'tasks');
2209
- const fakeBinDir = join(cwd, 'fake-bin');
2210
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
2211
- const tmuxLogPath = join(cwd, 'tmux.log');
2212
- const nowIso = new Date().toISOString();
2213
- await mkdir(logsDir, { recursive: true });
2214
- await mkdir(tasksDir, { recursive: true });
2215
- await mkdir(join(workersDir, 'worker-1'), { recursive: true });
2216
- await mkdir(fakeBinDir, { recursive: true });
2217
- await writeJson(join(stateDir, 'team-state.json'), {
2218
- active: true,
2219
- team_name: teamName,
2220
- current_phase: 'team-exec',
2221
- });
2222
- await writeJson(join(teamDir, 'config.json'), {
2223
- name: teamName,
2224
- tmux_session: 'rcs-team-stalled-before-stale-bounded',
2225
- leader_pane_id: '%88',
2226
- workers: [
2227
- { name: 'worker-1', index: 1, pane_id: '%10' },
2228
- { name: 'worker-2', index: 2, pane_id: '%11' },
2229
- ],
2230
- });
2231
- await writeJson(join(stateDir, 'hud-state.json'), {
2232
- last_turn_at: nowIso,
2233
- turn_count: 4,
2234
- });
2235
- await writeJson(join(tasksDir, 'task-1.json'), {
2236
- id: '1',
2237
- subject: 'Investigate stall',
2238
- description: 'worker-1 owns the active task',
2239
- status: 'in_progress',
2240
- owner: 'worker-1',
2241
- created_at: nowIso,
2242
- });
2243
- await writeJson(join(tasksDir, 'task-2.json'), {
2244
- id: '2',
2245
- subject: 'Follow-up',
2246
- description: 'still pending',
2247
- status: 'pending',
2248
- created_at: nowIso,
2249
- });
2250
- await writeJson(join(workersDir, 'worker-1', 'status.json'), {
2251
- state: 'working',
2252
- current_task_id: '1',
2253
- updated_at: nowIso,
2254
- });
2255
- await writeJson(join(workersDir, 'worker-1', 'heartbeat.json'), {
2256
- last_turn_at: nowIso,
2257
- turn_count: 2,
2258
- alive: true,
2259
- });
2260
- const stalledSignature = JSON.stringify({
2261
- tasks: [
2262
- { id: '1', owner: 'worker-1', status: 'in_progress' },
2263
- { id: '2', owner: '', status: 'pending' },
2264
- ],
2265
- workers: [
2266
- {
2267
- worker: 'worker-1',
2268
- state: 'working',
2269
- current_task_id: '1',
2270
- status_missing: false,
2271
- turn_count: 2,
2272
- heartbeat_missing: false,
2273
- },
2274
- {
2275
- worker: 'worker-2',
2276
- state: 'unknown',
2277
- current_task_id: '',
2278
- status_missing: true,
2279
- turn_count: null,
2280
- heartbeat_missing: true,
2281
- },
2282
- ],
2283
- });
2284
- await writeJson(join(stateDir, 'team-leader-nudge.json'), {
2285
- progress_by_team: {
2286
- [teamName]: {
2287
- signature: stalledSignature,
2288
- last_progress_at: new Date(Date.now() - 180_000).toISOString(),
2289
- },
2290
- },
2291
- });
2292
- await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%10 12345', '%11 12346']));
2293
- await chmod(fakeTmuxPath, 0o755);
2294
- const first = runNotifyHook(cwd, fakeBinDir, {
2295
- RCS_TEAM_PROGRESS_STALL_MS: '60000',
2296
- RCS_TEAM_LEADER_NUDGE_MS: '30000',
2297
- RCS_TEAM_LEADER_STALE_MS: '60000',
2298
- });
2299
- assert.equal(first.status, 0, `notify-hook failed: ${first.stderr || first.stdout}`);
2300
- const second = runNotifyHook(cwd, fakeBinDir, {
2301
- RCS_TEAM_PROGRESS_STALL_MS: '60000',
2302
- RCS_TEAM_LEADER_NUDGE_MS: '30000',
2303
- RCS_TEAM_LEADER_STALE_MS: '60000',
2304
- });
2305
- assert.equal(second.status, 0, `notify-hook failed: ${second.stderr || second.stdout}`);
2306
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
2307
- const sends = tmuxLog.match(/send-keys -t %88 -l Team stalled-before-stale-bounded: worker panes stalled, no progress/g) || [];
2308
- assert.equal(sends.length, 1, 'cooldown should keep repeated stalled-team nudges bounded');
2309
- assert.match(tmuxLog, /Next: rcs team status stalled-before-stale-bounded; read worker messages; unblock\/reassign or shutdown\./);
2310
- });
2311
- });
2312
- it('does not treat leader and HUD panes as active worker panes when worker pane ids are known', async () => {
2313
- await withTempWorkingDir(async (cwd) => {
2314
- const rcsDir = join(cwd, '.rcs');
2315
- const stateDir = join(rcsDir, 'state');
2316
- const logsDir = join(rcsDir, 'logs');
2317
- const teamName = 'stale-no-workers';
2318
- const teamDir = join(stateDir, 'team', teamName);
2319
- const fakeBinDir = join(cwd, 'fake-bin');
2320
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
2321
- const tmuxLogPath = join(cwd, 'tmux.log');
2322
- await mkdir(logsDir, { recursive: true });
2323
- await mkdir(join(teamDir, 'mailbox'), { recursive: true });
2324
- await mkdir(fakeBinDir, { recursive: true });
2325
- await writeJson(join(stateDir, 'team-state.json'), {
2326
- active: true,
2327
- team_name: teamName,
2328
- current_phase: 'team-exec',
2329
- });
2330
- await writeJson(join(teamDir, 'config.json'), {
2331
- name: teamName,
2332
- tmux_session: 'rcs-team-stale-no-workers',
2333
- leader_pane_id: '%92',
2334
- hud_pane_id: '%93',
2335
- workers: [
2336
- { name: 'worker-1', index: 1, pane_id: '%10' },
2337
- { name: 'worker-2', index: 2, pane_id: '%11' },
2338
- ],
2339
- });
2340
- await writeJson(join(stateDir, 'hud-state.json'), {
2341
- last_turn_at: new Date(Date.now() - 300_000).toISOString(),
2342
- turn_count: 5,
2343
- });
2344
- await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%92 12345', '%93 12346']));
2345
- await chmod(fakeTmuxPath, 0o755);
2346
- const result = runNotifyHook(cwd, fakeBinDir);
2347
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
2348
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
2349
- assert.doesNotMatch(tmuxLog, /send-keys -t %92 -l Team stale-no-workers: leader stale,/);
2350
- });
2351
- });
2352
- it('does not send a generic periodic leader nudge when the leader is not stale', async () => {
2353
- await withTempWorkingDir(async (cwd) => {
2354
- const rcsDir = join(cwd, '.rcs');
2355
- const stateDir = join(rcsDir, 'state');
2356
- const logsDir = join(rcsDir, 'logs');
2357
- const teamName = 'fresh-leader';
2358
- const teamDir = join(stateDir, 'team', teamName);
2359
- const fakeBinDir = join(cwd, 'fake-bin');
2360
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
2361
- const tmuxLogPath = join(cwd, 'tmux.log');
2362
- await mkdir(logsDir, { recursive: true });
2363
- await mkdir(join(teamDir, 'mailbox'), { recursive: true });
2364
- await mkdir(fakeBinDir, { recursive: true });
2365
- await writeJson(join(stateDir, 'team-state.json'), {
2366
- active: true,
2367
- team_name: teamName,
2368
- current_phase: 'team-exec',
2369
- });
2370
- await writeJson(join(teamDir, 'config.json'), {
2371
- name: teamName,
2372
- tmux_session: 'rcs-team-fresh',
2373
- leader_pane_id: '%95',
2374
- });
2375
- await writeJson(join(stateDir, 'hud-state.json'), {
2376
- last_turn_at: new Date().toISOString(),
2377
- turn_count: 2,
2378
- });
2379
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
2380
- await chmod(fakeTmuxPath, 0o755);
2381
- const result = runNotifyHook(cwd, fakeBinDir, { RCS_TEAM_LEADER_NUDGE_MS: '30000' });
2382
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
2383
- if (existsSync(tmuxLogPath)) {
2384
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
2385
- assert.doesNotMatch(tmuxLog, /Team fresh-leader/, 'non-stale leader should not receive generic periodic follow-up');
2386
- }
2387
- });
2388
- });
2389
- it('uses a 30s cadence for stale leader follow-up nudges', async () => {
2390
- await withTempWorkingDir(async (cwd) => {
2391
- const rcsDir = join(cwd, '.rcs');
2392
- const stateDir = join(rcsDir, 'state');
2393
- const logsDir = join(rcsDir, 'logs');
2394
- const teamName = 'stale-cadence';
2395
- const teamDir = join(stateDir, 'team', teamName);
2396
- const fakeBinDir = join(cwd, 'fake-bin');
2397
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
2398
- const tmuxLogPath = join(cwd, 'tmux.log');
2399
- const now = Date.now();
2400
- await mkdir(logsDir, { recursive: true });
2401
- await mkdir(join(teamDir, 'mailbox'), { recursive: true });
2402
- await mkdir(fakeBinDir, { recursive: true });
2403
- await writeJson(join(stateDir, 'team-state.json'), {
2404
- active: true,
2405
- team_name: teamName,
2406
- current_phase: 'team-exec',
2407
- });
2408
- await writeJson(join(teamDir, 'config.json'), {
2409
- name: teamName,
2410
- tmux_session: 'rcs-team-stale-cadence',
2411
- leader_pane_id: '%96',
2412
- });
2413
- const staleHud = {
2414
- last_turn_at: new Date(now - 300_000).toISOString(),
2415
- turn_count: 5,
2416
- };
2417
- await writeJson(join(stateDir, 'hud-state.json'), staleHud);
2418
- await writeJson(join(stateDir, 'team-leader-nudge.json'), {
2419
- last_nudged_by_team: {
2420
- [teamName]: {
2421
- at: new Date(now - 20_000).toISOString(),
2422
- last_message_id: '',
2423
- },
2424
- },
2425
- });
2426
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
2427
- await chmod(fakeTmuxPath, 0o755);
2428
- const blocked = runNotifyHook(cwd, fakeBinDir, { RCS_TEAM_LEADER_NUDGE_MS: '30000' });
2429
- assert.equal(blocked.status, 0, `notify-hook failed: ${blocked.stderr || blocked.stdout}`);
2430
- if (existsSync(tmuxLogPath)) {
2431
- const firstLog = await readFile(tmuxLogPath, 'utf-8');
2432
- assert.doesNotMatch(firstLog, /Team stale-cadence:/, 'stale follow-up should be blocked inside the 30s window');
2433
- }
2434
- await writeJson(join(stateDir, 'hud-state.json'), staleHud);
2435
- await writeJson(join(stateDir, 'team-leader-nudge.json'), {
2436
- last_nudged_by_team: {
2437
- [teamName]: {
2438
- at: new Date(now - 31_000).toISOString(),
2439
- last_message_id: '',
2440
- },
2441
- },
2442
- });
2443
- const allowed = runNotifyHook(cwd, fakeBinDir, { RCS_TEAM_LEADER_NUDGE_MS: '30000' });
2444
- assert.equal(allowed.status, 0, `notify-hook failed: ${allowed.stderr || allowed.stdout}`);
2445
- const finalLog = await readFile(tmuxLogPath, 'utf-8');
2446
- assert.match(finalLog, /Team stale-cadence:/);
2447
- assert.match(finalLog, /Team stale-cadence: leader stale, \d+ worker pane\(s\) still active\./);
2448
- });
2449
- });
2450
- it('suppresses stale leader follow-up when detached worktree progress is still fresh', async () => {
2451
- await withTempWorkingDir(async (cwd) => {
2452
- const rcsDir = join(cwd, '.rcs');
2453
- const stateDir = join(rcsDir, 'state');
2454
- const logsDir = join(rcsDir, 'logs');
2455
- const teamName = 'fresh-detached-progress';
2456
- const teamDir = join(stateDir, 'team', teamName);
2457
- const workersDir = join(teamDir, 'workers');
2458
- const tasksDir = join(teamDir, 'tasks');
2459
- const workerWorktree = join(cwd, 'worktrees', 'worker-1');
2460
- const fakeBinDir = join(cwd, 'fake-bin');
2461
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
2462
- const tmuxLogPath = join(cwd, 'tmux.log');
2463
- await mkdir(logsDir, { recursive: true });
2464
- await mkdir(tasksDir, { recursive: true });
2465
- await mkdir(join(workersDir, 'worker-1'), { recursive: true });
2466
- await mkdir(join(workerWorktree, '.rcs', 'state'), { recursive: true });
2467
- await mkdir(fakeBinDir, { recursive: true });
2468
- await writeJson(join(stateDir, 'team-state.json'), {
2469
- active: true,
2470
- team_name: teamName,
2471
- current_phase: 'team-exec',
2472
- });
2473
- await writeJson(join(teamDir, 'config.json'), {
2474
- name: teamName,
2475
- tmux_session: 'rcs-team-fresh-detached-progress',
2476
- leader_pane_id: '%99',
2477
- workers: [
2478
- { name: 'worker-1', index: 1, pane_id: '%10', worktree_path: workerWorktree },
2479
- ],
2480
- });
2481
- await writeJson(join(stateDir, 'hud-state.json'), {
2482
- last_turn_at: new Date(Date.now() - 300_000).toISOString(),
2483
- turn_count: 5,
2484
- });
2485
- await writeJson(join(tasksDir, 'task-1.json'), {
2486
- id: '1',
2487
- subject: 'Apply detached fix',
2488
- description: 'keep going',
2489
- status: 'in_progress',
2490
- owner: 'worker-1',
2491
- created_at: new Date(Date.now() - 300_000).toISOString(),
2492
- });
2493
- await writeJson(join(workersDir, 'worker-1', 'status.json'), {
2494
- state: 'working',
2495
- current_task_id: '1',
2496
- updated_at: new Date(Date.now() - 300_000).toISOString(),
2497
- });
2498
- await writeJson(join(workersDir, 'worker-1', 'heartbeat.json'), {
2499
- last_turn_at: new Date(Date.now() - 300_000).toISOString(),
2500
- turn_count: 2,
2501
- alive: true,
2502
- });
2503
- await writeJson(join(stateDir, 'team-leader-nudge.json'), {
2504
- last_nudged_by_team: {
2505
- [teamName]: {
2506
- at: new Date(Date.now() - 60_000).toISOString(),
2507
- last_message_id: '',
2508
- reason: 'stale_leader_panes_alive',
2509
- },
2510
- },
2511
- progress_by_team: {
2512
- [teamName]: {
2513
- signature: JSON.stringify({
2514
- tasks: [{ id: '1', owner: 'worker-1', status: 'in_progress' }],
2515
- workers: [{
2516
- worker: 'worker-1',
2517
- state: 'working',
2518
- current_task_id: '1',
2519
- status_missing: false,
2520
- turn_count: 2,
2521
- heartbeat_missing: false,
2522
- }],
2523
- }),
2524
- last_progress_at: new Date(Date.now() - 300_000).toISOString(),
2525
- },
2526
- },
2527
- });
2528
- await writeJson(join(workerWorktree, '.rcs', 'state', 'current-task-baseline.json'), {
2529
- version: 1,
2530
- tasks: [],
2531
- });
2532
- await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%10 12345']));
2533
- await chmod(fakeTmuxPath, 0o755);
2534
- const result = runNotifyHook(cwd, fakeBinDir, {
2535
- RCS_TEAM_PROGRESS_STALL_MS: '60000',
2536
- RCS_TEAM_LEADER_NUDGE_MS: '30000',
2537
- RCS_TEAM_LEADER_STALE_MS: '60000',
2538
- });
2539
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
2540
- if (existsSync(tmuxLogPath)) {
2541
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
2542
- assert.doesNotMatch(tmuxLog, /Team fresh-detached-progress: leader stale,/);
2543
- }
2544
- });
2545
- });
2546
- it('emits team_leader_nudge event to events.ndjson when nudge fires', async () => {
2547
- await withTempWorkingDir(async (cwd) => {
2548
- const rcsDir = join(cwd, '.rcs');
2549
- const stateDir = join(rcsDir, 'state');
2550
- const logsDir = join(rcsDir, 'logs');
2551
- const teamName = 'gamma';
2552
- const teamDir = join(stateDir, 'team', teamName);
2553
- const eventsDir = join(teamDir, 'events');
2554
- const mailboxDir = join(teamDir, 'mailbox');
2555
- const fakeBinDir = join(cwd, 'fake-bin');
2556
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
2557
- const tmuxLogPath = join(cwd, 'tmux.log');
2558
- await mkdir(logsDir, { recursive: true });
2559
- await mkdir(eventsDir, { recursive: true });
2560
- await mkdir(mailboxDir, { recursive: true });
2561
- await mkdir(fakeBinDir, { recursive: true });
2562
- await writeJson(join(stateDir, 'team-state.json'), {
2563
- active: true,
2564
- team_name: teamName,
2565
- current_phase: 'team-exec',
2566
- });
2567
- await writeJson(join(teamDir, 'config.json'), {
2568
- name: teamName,
2569
- tmux_session: 'rcs-team-gamma',
2570
- leader_pane_id: '%93',
2571
- });
2572
- await writeJson(join(mailboxDir, 'leader-fixed.json'), {
2573
- worker: 'leader-fixed',
2574
- messages: [
2575
- {
2576
- message_id: 'msg-99',
2577
- from_worker: 'worker-1',
2578
- to_worker: 'leader-fixed',
2579
- body: 'Task complete',
2580
- created_at: '2026-02-14T00:00:00.000Z',
2581
- },
2582
- ],
2583
- });
2584
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
2585
- await chmod(fakeTmuxPath, 0o755);
2586
- const result = runNotifyHook(cwd, fakeBinDir);
2587
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
2588
- // Verify event was written
2589
- const eventsPath = join(eventsDir, 'events.ndjson');
2590
- assert.ok(existsSync(eventsPath), 'events.ndjson should exist after nudge');
2591
- const eventsContent = await readFile(eventsPath, 'utf-8');
2592
- const events = eventsContent.trim().split('\n').map(line => JSON.parse(line));
2593
- const nudgeEvent = events.find((e) => e.type === 'team_leader_nudge');
2594
- assert.ok(nudgeEvent, 'should have a team_leader_nudge event');
2595
- assert.equal(nudgeEvent.team, teamName);
2596
- assert.equal(nudgeEvent.worker, 'leader-fixed');
2597
- assert.ok(nudgeEvent.reason, 'event should have a reason');
2598
- assert.notEqual(nudgeEvent.reason, 'leader_pane_missing_no_injection');
2599
- assert.ok(nudgeEvent.orchestration_intent, 'event should record an orchestration intent');
2600
- });
2601
- });
2602
- it('defers leader nudge when leader_pane_id is missing', async () => {
2603
- await withTempWorkingDir(async (cwd) => {
2604
- const rcsDir = join(cwd, '.rcs');
2605
- const stateDir = join(rcsDir, 'state');
2606
- const logsDir = join(rcsDir, 'logs');
2607
- const teamName = 'gamma-missing-pane';
2608
- const teamDir = join(stateDir, 'team', teamName);
2609
- const eventsDir = join(teamDir, 'events');
2610
- const mailboxDir = join(teamDir, 'mailbox');
2611
- const fakeBinDir = join(cwd, 'fake-bin');
2612
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
2613
- const tmuxLogPath = join(cwd, 'tmux.log');
2614
- await mkdir(logsDir, { recursive: true });
2615
- await mkdir(eventsDir, { recursive: true });
2616
- await mkdir(mailboxDir, { recursive: true });
2617
- await mkdir(fakeBinDir, { recursive: true });
2618
- await writeJson(join(stateDir, 'team-state.json'), {
2619
- active: true,
2620
- team_name: teamName,
2621
- current_phase: 'team-exec',
2622
- });
2623
- await writeJson(join(teamDir, 'config.json'), {
2624
- name: teamName,
2625
- tmux_session: 'devsess:0',
2626
- });
2627
- await writeJson(join(mailboxDir, 'leader-fixed.json'), {
2628
- worker: 'leader-fixed',
2629
- messages: [
2630
- {
2631
- message_id: 'msg-missing-pane',
2632
- from_worker: 'worker-1',
2633
- to_worker: 'leader-fixed',
2634
- body: 'Task complete',
2635
- created_at: '2026-02-14T00:00:00.000Z',
2636
- },
2637
- ],
2638
- });
2639
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
2640
- await chmod(fakeTmuxPath, 0o755);
2641
- const result = runNotifyHook(cwd, fakeBinDir);
2642
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
2643
- if (existsSync(tmuxLogPath)) {
2644
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
2645
- assert.doesNotMatch(tmuxLog, /send-keys -t .*devsess/, 'must not fall back to session target');
2646
- }
2647
- const eventsPath = join(eventsDir, 'events.ndjson');
2648
- assert.ok(existsSync(eventsPath), 'events.ndjson should exist');
2649
- const eventsContent = await readFile(eventsPath, 'utf-8');
2650
- const events = eventsContent.trim().split('\n').map(line => JSON.parse(line));
2651
- const deferred = events.find((e) => e.type === 'leader_notification_deferred' && e.reason === 'leader_pane_missing_no_injection');
2652
- assert.ok(deferred);
2653
- assert.equal(deferred.type, 'leader_notification_deferred');
2654
- assert.equal(deferred.worker, 'leader-fixed');
2655
- assert.equal(deferred.to_worker, 'leader-fixed');
2656
- assert.equal(deferred.source_type, 'leader_nudge');
2657
- assert.equal(deferred.tmux_session, 'devsess:0');
2658
- assert.equal(deferred.leader_pane_id, null);
2659
- assert.equal(deferred.orchestration_intent, 'pending-mailbox-review');
2660
- assert.equal(deferred.tmux_injection_attempted, false);
2661
- const nudgeStatePath = join(stateDir, 'team-leader-nudge.json');
2662
- assert.ok(existsSync(nudgeStatePath), 'nudge state should still advance on deferred leader visibility');
2663
- const nudgeState = JSON.parse(await readFile(nudgeStatePath, 'utf-8'));
2664
- assert.ok(nudgeState.last_nudged_by_team?.[teamName]?.at);
2665
- assert.equal(nudgeState.last_nudged_by_team?.[teamName]?.orchestration_intent, 'pending-mailbox-review');
2666
- const leaderAttentionPath = join(stateDir, 'team', teamName, 'leader-attention.json');
2667
- assert.ok(existsSync(leaderAttentionPath), 'leader attention state should be written from notify-hook');
2668
- const leaderAttention = JSON.parse(await readFile(leaderAttentionPath, 'utf-8'));
2669
- assert.equal(leaderAttention.source, 'notify_hook');
2670
- assert.equal(leaderAttention.team_name, teamName);
2671
- assert.equal(leaderAttention.leader_decision_state, 'still_actionable');
2672
- assert.equal(leaderAttention.leader_attention_pending, true);
2673
- assert.equal(leaderAttention.leader_attention_reason, 'new_mailbox_message');
2674
- assert.deepEqual(leaderAttention.attention_reasons, ['new_mailbox_message']);
2675
- assert.equal(leaderAttention.leader_session_active, true);
2676
- assert.equal(leaderAttention.leader_session_stopped_at, null);
2677
- });
2678
- });
2679
- it('bounds repeated all-workers-idle nudges by cooldown', async () => {
2680
- await withTempWorkingDir(async (cwd) => {
2681
- const rcsDir = join(cwd, '.rcs');
2682
- const stateDir = join(rcsDir, 'state');
2683
- const logsDir = join(rcsDir, 'logs');
2684
- const teamName = 'idle-bounded';
2685
- const teamDir = join(stateDir, 'team', teamName);
2686
- const workersDir = join(teamDir, 'workers');
2687
- const fakeBinDir = join(cwd, 'fake-bin');
2688
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
2689
- const tmuxLogPath = join(cwd, 'tmux.log');
2690
- await mkdir(logsDir, { recursive: true });
2691
- await mkdir(workersDir, { recursive: true });
2692
- await mkdir(fakeBinDir, { recursive: true });
2693
- await writeJson(join(stateDir, 'team-state.json'), {
2694
- active: true,
2695
- team_name: teamName,
2696
- current_phase: 'team-exec',
2697
- });
2698
- await writeJson(join(teamDir, 'config.json'), {
2699
- name: teamName,
2700
- tmux_session: 'idle-bounded:0',
2701
- leader_pane_id: '%98',
2702
- workers: [
2703
- { name: 'worker-1', index: 1, role: 'executor', assigned_tasks: [] },
2704
- { name: 'worker-2', index: 2, role: 'executor', assigned_tasks: [] },
2705
- ],
2706
- });
2707
- await writeJson(join(stateDir, 'hud-state.json'), {
2708
- last_turn_at: new Date().toISOString(),
2709
- turn_count: 1,
2710
- });
2711
- for (const worker of ['worker-1', 'worker-2']) {
2712
- await mkdir(join(workersDir, worker), { recursive: true });
2713
- await writeJson(join(workersDir, worker, 'status.json'), {
2714
- state: 'idle',
2715
- updated_at: new Date().toISOString(),
2716
- });
2717
- }
2718
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
2719
- await chmod(fakeTmuxPath, 0o755);
2720
- const first = runNotifyHook(cwd, fakeBinDir, { RCS_TEAM_LEADER_ALL_IDLE_COOLDOWN_MS: '600000' });
2721
- assert.equal(first.status, 0, `notify-hook failed: ${first.stderr || first.stdout}`);
2722
- const second = runNotifyHook(cwd, fakeBinDir, { RCS_TEAM_LEADER_ALL_IDLE_COOLDOWN_MS: '600000' });
2723
- assert.equal(second.status, 0, `notify-hook failed: ${second.stderr || second.stdout}`);
2724
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
2725
- const sends = tmuxLog.match(/send-keys -t %98 -l \[RCS\] All 2 workers idle/g) || [];
2726
- assert.equal(sends.length, 1, 'cooldown should keep repeated all-workers-idle leader nudges bounded');
2727
- assert.doesNotMatch(tmuxLog, /\[RCS_INTENT:/);
2728
- });
2729
- });
2730
- it('does not nudge when no active team state exists', async () => {
2731
- await withTempWorkingDir(async (cwd) => {
2732
- const rcsDir = join(cwd, '.rcs');
2733
- const stateDir = join(rcsDir, 'state');
2734
- const logsDir = join(rcsDir, 'logs');
2735
- const fakeBinDir = join(cwd, 'fake-bin');
2736
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
2737
- const tmuxLogPath = join(cwd, 'tmux.log');
2738
- await mkdir(logsDir, { recursive: true });
2739
- await mkdir(stateDir, { recursive: true });
2740
- await mkdir(fakeBinDir, { recursive: true });
2741
- // No team-state.json — no active team
2742
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
2743
- await chmod(fakeTmuxPath, 0o755);
2744
- const result = runNotifyHook(cwd, fakeBinDir);
2745
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
2746
- // tmux log should not contain display-message for any team nudge
2747
- const hasLog = existsSync(tmuxLogPath);
2748
- if (hasLog) {
2749
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
2750
- assert.doesNotMatch(tmuxLog, /Team .+: leader stale/);
2751
- }
2752
- });
2753
- });
2754
- it('includes stale_leader_with_messages reason when both conditions met', async () => {
2755
- await withTempWorkingDir(async (cwd) => {
2756
- const rcsDir = join(cwd, '.rcs');
2757
- const stateDir = join(rcsDir, 'state');
2758
- const logsDir = join(rcsDir, 'logs');
2759
- const teamName = 'delta';
2760
- const teamDir = join(stateDir, 'team', teamName);
2761
- const eventsDir = join(teamDir, 'events');
2762
- const mailboxDir = join(teamDir, 'mailbox');
2763
- const fakeBinDir = join(cwd, 'fake-bin');
2764
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
2765
- const tmuxLogPath = join(cwd, 'tmux.log');
2766
- await mkdir(logsDir, { recursive: true });
2767
- await mkdir(eventsDir, { recursive: true });
2768
- await mkdir(mailboxDir, { recursive: true });
2769
- await mkdir(fakeBinDir, { recursive: true });
2770
- await writeJson(join(stateDir, 'team-state.json'), {
2771
- active: true,
2772
- team_name: teamName,
2773
- current_phase: 'team-exec',
2774
- });
2775
- await writeJson(join(teamDir, 'config.json'), {
2776
- name: teamName,
2777
- tmux_session: 'rcs-team-delta',
2778
- leader_pane_id: '%94',
2779
- });
2780
- // Leader stale
2781
- await writeJson(join(stateDir, 'hud-state.json'), {
2782
- last_turn_at: new Date(Date.now() - 300_000).toISOString(),
2783
- turn_count: 3,
2784
- });
2785
- // Mailbox has messages
2786
- await writeJson(join(mailboxDir, 'leader-fixed.json'), {
2787
- worker: 'leader-fixed',
2788
- messages: [
2789
- {
2790
- message_id: 'combo-msg',
2791
- from_worker: 'worker-2',
2792
- to_worker: 'leader-fixed',
2793
- body: 'done',
2794
- created_at: '2026-02-14T00:00:00.000Z',
2795
- },
2796
- ],
2797
- });
2798
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
2799
- await chmod(fakeTmuxPath, 0o755);
2800
- const result = runNotifyHook(cwd, fakeBinDir);
2801
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
2802
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
2803
- assert.match(tmuxLog, /Team delta: leader stale, \d+ pane\(s\) active, 1 msg\(s\) pending\./);
2804
- assert.match(tmuxLog, /Next: read messages; keep orchestrating; if done, gracefully shut down: rcs team shutdown delta\./);
2805
- assert.doesNotMatch(tmuxLog, /keep polling/);
2806
- assert.match(tmuxLog, /\[RCS_TMUX_INJECT\]/, 'should include injection marker');
2807
- // Verify event reason
2808
- const eventsPath = join(eventsDir, 'events.ndjson');
2809
- assert.ok(existsSync(eventsPath), 'events.ndjson should exist');
2810
- const eventsContent = await readFile(eventsPath, 'utf-8');
2811
- const events = eventsContent.trim().split('\n').map(line => JSON.parse(line));
2812
- const nudgeEvent = events.find((e) => e.type === 'team_leader_nudge');
2813
- assert.ok(nudgeEvent);
2814
- assert.equal(nudgeEvent.reason, 'stale_leader_with_messages');
2815
- });
2816
- });
2817
- it('rejects invalid team_name before leader follow-up team path joins', async () => {
2818
- await withTempWorkingDir(async (cwd) => {
2819
- const rcsDir = join(cwd, '.rcs');
2820
- const stateDir = join(rcsDir, 'state');
2821
- const logsDir = join(rcsDir, 'logs');
2822
- const fakeBinDir = join(cwd, 'fake-bin');
2823
- const fakeTmuxPath = join(fakeBinDir, 'tmux');
2824
- const tmuxLogPath = join(cwd, 'tmux.log');
2825
- const validTeamName = 'valid-team';
2826
- const validTeamDir = join(stateDir, 'team', validTeamName);
2827
- const workersDir = join(validTeamDir, 'workers');
2828
- const nowIso = new Date().toISOString();
2829
- await mkdir(logsDir, { recursive: true });
2830
- await mkdir(workersDir, { recursive: true });
2831
- await mkdir(fakeBinDir, { recursive: true });
2832
- await writeJson(join(stateDir, 'session.json'), { session_id: 'sess-current' });
2833
- await writeJson(join(stateDir, 'team-state.json'), {
2834
- active: true,
2835
- team_name: '../team/valid-team',
2836
- current_phase: 'team-exec',
2837
- });
2838
- await writeJson(join(validTeamDir, 'manifest.v2.json'), {
2839
- schema_version: 2,
2840
- name: validTeamName,
2841
- task: 'invalid team path repro',
2842
- leader: {
2843
- session_id: 'sess-current',
2844
- worker_id: 'leader-fixed',
2845
- role: 'coordinator',
2846
- },
2847
- policy: {
2848
- worker_launch_mode: 'interactive',
2849
- display_mode: 'split_pane',
2850
- dispatch_mode: 'hook_preferred_with_fallback',
2851
- dispatch_ack_timeout_ms: 2000,
2852
- },
2853
- tmux_session: 'valid-team:0',
2854
- leader_pane_id: '%94',
2855
- worker_count: 1,
2856
- workers: [
2857
- { name: 'worker-1', index: 1, pane_id: '%10', role: 'executor' },
2858
- ],
2859
- created_at: nowIso,
2860
- });
2861
- await mkdir(join(workersDir, 'worker-1'), { recursive: true });
2862
- await writeJson(join(workersDir, 'worker-1', 'status.json'), {
2863
- state: 'idle',
2864
- updated_at: nowIso,
2865
- });
2866
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
2867
- await chmod(fakeTmuxPath, 0o755);
2868
- const result = runNotifyHook(cwd, fakeBinDir, {
2869
- RCS_SESSION_ID: 'sess-current',
2870
- });
2871
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
2872
- if (existsSync(tmuxLogPath)) {
2873
- const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
2874
- assert.doesNotMatch(tmuxLog, /send-keys/, 'invalid team_name must not be used for leader follow-up path resolution');
2875
- }
2876
- });
2877
- });
2878
- });
2879
- //# sourceMappingURL=notify-hook-team-leader-nudge.test.js.map