@jstn-sdk/rcs 0.1.0 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1739) hide show
  1. package/README.md +154 -101
  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.d.ts.map +1 -1
  20. package/dist/cli/index.js +20 -15
  21. package/dist/cli/index.js.map +1 -1
  22. package/dist/cli/setup.d.ts.map +1 -1
  23. package/dist/cli/setup.js +2 -3
  24. package/dist/cli/setup.js.map +1 -1
  25. package/dist/cli/star-prompt.js +2 -2
  26. package/dist/cli/star-prompt.js.map +1 -1
  27. package/dist/cli/state.js +1 -1
  28. package/dist/cli/team.d.ts.map +1 -1
  29. package/dist/cli/team.js +3 -2
  30. package/dist/cli/team.js.map +1 -1
  31. package/dist/cli/tmux-hook.d.ts.map +1 -1
  32. package/dist/cli/tmux-hook.js +9 -1
  33. package/dist/cli/tmux-hook.js.map +1 -1
  34. package/dist/config/generator.d.ts +1 -1
  35. package/dist/config/generator.d.ts.map +1 -1
  36. package/dist/config/generator.js +1 -1
  37. package/dist/config/generator.js.map +1 -1
  38. package/dist/forge/contract.d.ts +17 -0
  39. package/dist/{ralph → forge}/contract.d.ts.map +1 -1
  40. package/dist/{ralph → forge}/contract.js +16 -16
  41. package/dist/{ralph → forge}/contract.js.map +1 -1
  42. package/dist/{ralph → forge}/persistence.d.ts +5 -5
  43. package/dist/{ralph → forge}/persistence.d.ts.map +1 -1
  44. package/dist/{ralph → forge}/persistence.js +7 -6
  45. package/dist/forge/persistence.js.map +1 -0
  46. package/dist/hooks/agents-overlay.d.ts +1 -1
  47. package/dist/hooks/agents-overlay.d.ts.map +1 -1
  48. package/dist/hooks/agents-overlay.js +37 -31
  49. package/dist/hooks/agents-overlay.js.map +1 -1
  50. package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
  51. package/dist/hooks/extensibility/dispatcher.js +82 -14
  52. package/dist/hooks/extensibility/dispatcher.js.map +1 -1
  53. package/dist/hooks/keyword-detector.d.ts +8 -8
  54. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  55. package/dist/hooks/keyword-detector.js +94 -64
  56. package/dist/hooks/keyword-detector.js.map +1 -1
  57. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  58. package/dist/hooks/keyword-registry.js +9 -11
  59. package/dist/hooks/keyword-registry.js.map +1 -1
  60. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  61. package/dist/hooks/prompt-guidance-contract.js +10 -21
  62. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  63. package/dist/hooks/task-size-detector.js +2 -2
  64. package/dist/hooks/task-size-detector.js.map +1 -1
  65. package/dist/hooks/triage-state.d.ts +1 -1
  66. package/dist/hooks/triage-state.js +1 -1
  67. package/dist/hud/colors.d.ts +2 -2
  68. package/dist/hud/colors.js +2 -2
  69. package/dist/hud/render.js +21 -21
  70. package/dist/hud/render.js.map +1 -1
  71. package/dist/hud/state.d.ts +3 -3
  72. package/dist/hud/state.d.ts.map +1 -1
  73. package/dist/hud/state.js +18 -15
  74. package/dist/hud/state.js.map +1 -1
  75. package/dist/hud/types.d.ts +6 -6
  76. package/dist/hud/types.d.ts.map +1 -1
  77. package/dist/mcp/bootstrap.d.ts.map +1 -1
  78. package/dist/mcp/bootstrap.js +36 -2
  79. package/dist/mcp/bootstrap.js.map +1 -1
  80. package/dist/mcp/state-paths.d.ts +1 -0
  81. package/dist/mcp/state-paths.d.ts.map +1 -1
  82. package/dist/mcp/state-paths.js +4 -1
  83. package/dist/mcp/state-paths.js.map +1 -1
  84. package/dist/mcp/state-server.d.ts +4 -4
  85. package/dist/mcp/state-server.js +2 -2
  86. package/dist/mcp/state-server.js.map +1 -1
  87. package/dist/modes/base.d.ts +2 -2
  88. package/dist/modes/base.d.ts.map +1 -1
  89. package/dist/modes/base.js +29 -26
  90. package/dist/modes/base.js.map +1 -1
  91. package/dist/notifications/reply-listener.d.ts.map +1 -1
  92. package/dist/notifications/reply-listener.js +7 -1
  93. package/dist/notifications/reply-listener.js.map +1 -1
  94. package/dist/notifications/tmux.d.ts.map +1 -1
  95. package/dist/notifications/tmux.js +39 -6
  96. package/dist/notifications/tmux.js.map +1 -1
  97. package/dist/pipeline/index.d.ts +7 -6
  98. package/dist/pipeline/index.d.ts.map +1 -1
  99. package/dist/pipeline/index.js +5 -4
  100. package/dist/pipeline/index.js.map +1 -1
  101. package/dist/pipeline/orchestrator.d.ts +5 -5
  102. package/dist/pipeline/orchestrator.js +25 -25
  103. package/dist/pipeline/orchestrator.js.map +1 -1
  104. package/dist/pipeline/stages/blueprint.d.ts +25 -0
  105. package/dist/pipeline/stages/blueprint.d.ts.map +1 -0
  106. package/dist/pipeline/stages/{ralplan.js → blueprint.js} +16 -16
  107. package/dist/pipeline/stages/blueprint.js.map +1 -0
  108. package/dist/pipeline/stages/code-review.d.ts +2 -2
  109. package/dist/pipeline/stages/code-review.js +6 -6
  110. package/dist/pipeline/stages/code-review.js.map +1 -1
  111. package/dist/pipeline/stages/forge-verify.d.ts +50 -0
  112. package/dist/pipeline/stages/forge-verify.d.ts.map +1 -0
  113. package/dist/pipeline/stages/{ralph-verify.js → forge-verify.js} +21 -24
  114. package/dist/pipeline/stages/forge-verify.js.map +1 -0
  115. package/dist/pipeline/stages/team-exec.d.ts +1 -1
  116. package/dist/pipeline/stages/team-exec.js +19 -19
  117. package/dist/pipeline/stages/team-exec.js.map +1 -1
  118. package/dist/pipeline/types.d.ts +12 -12
  119. package/dist/pipeline/types.d.ts.map +1 -1
  120. package/dist/pipeline/types.js +1 -1
  121. package/dist/planning/artifacts.d.ts +3 -4
  122. package/dist/planning/artifacts.d.ts.map +1 -1
  123. package/dist/planning/artifacts.js +2 -3
  124. package/dist/planning/artifacts.js.map +1 -1
  125. package/dist/question/policy.js +1 -1
  126. package/dist/runtime/bridge.d.ts.map +1 -1
  127. package/dist/runtime/bridge.js +70 -13
  128. package/dist/runtime/bridge.js.map +1 -1
  129. package/dist/scripts/codex-native-hook.js +30 -30
  130. package/dist/scripts/codex-native-hook.js.map +1 -1
  131. package/dist/scripts/eval/eval-cross-server-party-flow.d.ts +3 -0
  132. package/dist/scripts/eval/eval-cross-server-party-flow.d.ts.map +1 -0
  133. package/dist/scripts/eval/eval-cross-server-party-flow.js +12 -0
  134. package/dist/scripts/eval/eval-cross-server-party-flow.js.map +1 -0
  135. package/dist/scripts/eval/eval-gui-onboarding-clarity.d.ts +3 -0
  136. package/dist/scripts/eval/eval-gui-onboarding-clarity.d.ts.map +1 -0
  137. package/dist/scripts/eval/eval-gui-onboarding-clarity.js +17 -0
  138. package/dist/scripts/eval/eval-gui-onboarding-clarity.js.map +1 -0
  139. package/dist/scripts/eval/eval-liveops-reward-loop-balance.d.ts +3 -0
  140. package/dist/scripts/eval/eval-liveops-reward-loop-balance.d.ts.map +1 -0
  141. package/dist/scripts/eval/eval-liveops-reward-loop-balance.js +12 -0
  142. package/dist/scripts/eval/eval-liveops-reward-loop-balance.js.map +1 -0
  143. package/dist/scripts/eval/eval-profile-datastore-recovery.d.ts +3 -0
  144. package/dist/scripts/eval/eval-profile-datastore-recovery.d.ts.map +1 -0
  145. package/dist/scripts/eval/eval-profile-datastore-recovery.js +17 -0
  146. package/dist/scripts/eval/eval-profile-datastore-recovery.js.map +1 -0
  147. package/dist/scripts/eval/eval-remote-contract-hardening.d.ts +3 -0
  148. package/dist/scripts/eval/eval-remote-contract-hardening.d.ts.map +1 -0
  149. package/dist/scripts/eval/eval-remote-contract-hardening.js +17 -0
  150. package/dist/scripts/eval/eval-remote-contract-hardening.js.map +1 -0
  151. package/dist/scripts/notify-fallback-watcher.js +140 -139
  152. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  153. package/dist/scripts/notify-hook/forge-session-resume.d.ts +23 -0
  154. package/dist/scripts/notify-hook/{ralph-session-resume.d.ts.map → forge-session-resume.d.ts.map} +1 -1
  155. package/dist/scripts/notify-hook/{ralph-session-resume.js → forge-session-resume.js} +37 -36
  156. package/dist/scripts/notify-hook/{ralph-session-resume.js.map → forge-session-resume.js.map} +1 -1
  157. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
  158. package/dist/scripts/notify-hook/team-dispatch.js +34 -4
  159. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  160. package/dist/scripts/notify-hook/visual-verdict.js +3 -3
  161. package/dist/scripts/notify-hook.js +9 -9
  162. package/dist/scripts/run-test-files.js +1 -1
  163. package/dist/scripts/run-test-files.js.map +1 -1
  164. package/dist/scripts/surface-taxonomy.d.ts +23 -0
  165. package/dist/scripts/surface-taxonomy.d.ts.map +1 -0
  166. package/dist/scripts/surface-taxonomy.js +271 -0
  167. package/dist/scripts/surface-taxonomy.js.map +1 -0
  168. package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
  169. package/dist/scripts/sync-plugin-mirror.js +5 -4
  170. package/dist/scripts/sync-plugin-mirror.js.map +1 -1
  171. package/dist/scripts/tmux-hook-engine.d.ts +1 -1
  172. package/dist/scripts/tmux-hook-engine.d.ts.map +1 -1
  173. package/dist/scripts/tmux-hook-engine.js +29 -20
  174. package/dist/scripts/tmux-hook-engine.js.map +1 -1
  175. package/dist/state/operations.d.ts +1 -1
  176. package/dist/state/operations.d.ts.map +1 -1
  177. package/dist/state/operations.js +18 -18
  178. package/dist/state/operations.js.map +1 -1
  179. package/dist/state/skill-active.d.ts +13 -1
  180. package/dist/state/skill-active.d.ts.map +1 -1
  181. package/dist/state/skill-active.js +38 -17
  182. package/dist/state/skill-active.js.map +1 -1
  183. package/dist/state/workflow-transition.d.ts +6 -5
  184. package/dist/state/workflow-transition.d.ts.map +1 -1
  185. package/dist/state/workflow-transition.js +27 -15
  186. package/dist/state/workflow-transition.js.map +1 -1
  187. package/dist/team/contracts.d.ts +1 -1
  188. package/dist/team/contracts.js +2 -2
  189. package/dist/team/followup-planner.d.ts +2 -2
  190. package/dist/team/followup-planner.d.ts.map +1 -1
  191. package/dist/team/followup-planner.js +16 -14
  192. package/dist/team/followup-planner.js.map +1 -1
  193. package/dist/team/idle-nudge.d.ts.map +1 -1
  194. package/dist/team/idle-nudge.js +3 -2
  195. package/dist/team/idle-nudge.js.map +1 -1
  196. package/dist/team/leader-activity.js +1 -1
  197. package/dist/team/model-contract.d.ts.map +1 -1
  198. package/dist/team/model-contract.js +4 -1
  199. package/dist/team/model-contract.js.map +1 -1
  200. package/dist/team/orchestrator.js +4 -4
  201. package/dist/team/orchestrator.js.map +1 -1
  202. package/dist/team/role-router.js +3 -3
  203. package/dist/team/role-router.js.map +1 -1
  204. package/dist/team/state/dispatch.d.ts.map +1 -1
  205. package/dist/team/state/dispatch.js +4 -1
  206. package/dist/team/state/dispatch.js.map +1 -1
  207. package/dist/team/tmux-session.d.ts +4 -0
  208. package/dist/team/tmux-session.d.ts.map +1 -1
  209. package/dist/team/tmux-session.js +42 -9
  210. package/dist/team/tmux-session.js.map +1 -1
  211. package/dist/team/worktree.d.ts +1 -1
  212. package/dist/utils/platform-command.d.ts.map +1 -1
  213. package/dist/utils/platform-command.js +9 -0
  214. package/dist/utils/platform-command.js.map +1 -1
  215. package/dist/verification/verifier.d.ts +1 -1
  216. package/dist/verification/verifier.js +2 -2
  217. package/docs/STATE_MODEL.md +24 -24
  218. package/docs/agents.html +8 -16
  219. package/docs/archive/README.md +15 -0
  220. package/docs/{prompt-migration-changelog.md → archive/prompt-migration-changelog.md} +0 -11
  221. package/docs/{release-body-0.9.0.md → archive/release-body-0.9.0.md} +6 -24
  222. package/docs/{release-body-0.9.1.md → archive/release-body-0.9.1.md} +3 -3
  223. package/docs/codex-native-hooks.md +4 -4
  224. package/docs/contracts/forge-cancel-contract.md +20 -0
  225. package/docs/contracts/forge-state-contract.md +52 -0
  226. package/docs/contracts/multi-state-transition-contract.md +5 -5
  227. package/docs/contracts/multi-state-transition-review.md +3 -3
  228. package/docs/contracts/repo-aware-team-dag-decomposition.md +1 -1
  229. package/docs/contracts/rust-runtime-thin-adapter-contract.md +1 -1
  230. package/docs/contracts/team-startup-dispatch-latency.md +1 -1
  231. package/docs/getting-started.html +11 -1
  232. package/docs/guidance-schema.md +6 -3
  233. package/docs/index.html +55 -4
  234. package/docs/integrations.html +4 -3
  235. package/docs/issues/team-forge-followup-team.md +38 -0
  236. package/docs/openclaw-integration.md +2 -2
  237. package/docs/prompt-guidance-contract.md +11 -11
  238. package/docs/prs/{dev-deprecate-team-ralph.md → dev-deprecate-team-forge.md} +27 -27
  239. package/docs/prs/{dev-fix-ralph-live-pane-invariant.md → dev-fix-forge-live-pane-invariant.md} +7 -7
  240. package/docs/prs/{dev-team-ralph-workflow-positioning.md → dev-team-forge-workflow-positioning.md} +7 -7
  241. package/docs/qa/forge-persistence-gate.md +20 -0
  242. package/docs/qa/rust-runtime-thin-adapter-gate.md +31 -40
  243. package/docs/readme/README.de.md +14 -0
  244. package/docs/readme/README.el.md +14 -0
  245. package/docs/readme/README.es.md +14 -0
  246. package/docs/readme/README.fr.md +14 -0
  247. package/docs/readme/README.it.md +14 -0
  248. package/docs/readme/README.ja.md +14 -0
  249. package/docs/readme/README.ko.md +14 -0
  250. package/docs/readme/README.pl.md +14 -0
  251. package/docs/readme/README.pt.md +14 -0
  252. package/docs/readme/README.ru.md +14 -0
  253. package/docs/readme/README.tr.md +14 -0
  254. package/docs/readme/README.uk.md +14 -0
  255. package/docs/readme/README.vi.md +14 -0
  256. package/docs/readme/README.zh-TW.md +14 -0
  257. package/docs/readme/README.zh.md +14 -0
  258. package/docs/readme/rcs-cover.svg +75 -0
  259. package/docs/reference/canonical-vocabulary.md +106 -0
  260. package/docs/reference/forge-parity-matrix.md +26 -0
  261. package/docs/reference/forge-upstream-baseline.md +32 -0
  262. package/docs/reference/rcs-config-schema-routing.md +5 -5
  263. package/docs/reference/roblox-pre-action-protocol.md +4 -0
  264. package/docs/reference/roblox-taxonomy-migration-plan.md +46 -0
  265. package/docs/reference/roblox-workspace-standard.md +83 -0
  266. package/docs/reference/robloxstudio-mcp-compatibility.md +117 -0
  267. package/docs/reference/semantic-design-system.md +110 -0
  268. package/docs/reference/surface-map.md +131 -0
  269. package/docs/reference/team-allocation-rebalance-policy.md +1 -1
  270. package/docs/release-notes-v0.1.0.md +1 -1
  271. package/docs/release-notes-v0.1.1.md +49 -0
  272. package/docs/release-notes-v0.1.6.md +27 -0
  273. package/docs/reports/open-prs-dev-readiness-2026-04-09.md +2 -2
  274. package/docs/shared/agent-tiers.md +3 -3
  275. package/docs/skills.html +10 -12
  276. package/docs/troubleshooting.md +1 -1
  277. package/package.json +20 -13
  278. package/plugins/roblox-ai-os-creator-skills/.codex-plugin/plugin.json +1 -1
  279. package/plugins/roblox-ai-os-creator-skills/docs/reference/roblox-pre-action-protocol.md +4 -0
  280. package/plugins/roblox-ai-os-creator-skills/skills/ai-slop-cleaner/SKILL.md +14 -7
  281. package/plugins/roblox-ai-os-creator-skills/skills/analyze/SKILL.md +9 -2
  282. package/plugins/roblox-ai-os-creator-skills/skills/ask-claude/SKILL.md +7 -0
  283. package/plugins/roblox-ai-os-creator-skills/skills/ask-gemini/SKILL.md +7 -0
  284. package/plugins/roblox-ai-os-creator-skills/skills/autoforge/SKILL.md +7 -0
  285. package/plugins/roblox-ai-os-creator-skills/skills/autopilot/SKILL.md +48 -41
  286. package/plugins/roblox-ai-os-creator-skills/skills/autoresearch/SKILL.md +8 -1
  287. package/plugins/roblox-ai-os-creator-skills/skills/blueprint/SKILL.md +227 -9
  288. package/plugins/roblox-ai-os-creator-skills/skills/blueprint-loop/SKILL.md +7 -0
  289. package/plugins/roblox-ai-os-creator-skills/skills/blueprint-psych/SKILL.md +7 -0
  290. package/plugins/roblox-ai-os-creator-skills/skills/blueprint-retention/SKILL.md +7 -0
  291. package/plugins/roblox-ai-os-creator-skills/skills/blueprint-social/SKILL.md +7 -0
  292. package/plugins/roblox-ai-os-creator-skills/skills/brief/SKILL.md +7 -0
  293. package/plugins/roblox-ai-os-creator-skills/skills/brief-audience/SKILL.md +7 -0
  294. package/plugins/roblox-ai-os-creator-skills/skills/brief-motivation/SKILL.md +7 -0
  295. package/plugins/roblox-ai-os-creator-skills/skills/cancel/SKILL.md +59 -52
  296. package/plugins/roblox-ai-os-creator-skills/skills/code-review/SKILL.md +30 -24
  297. package/plugins/roblox-ai-os-creator-skills/skills/configure-notifications/SKILL.md +7 -0
  298. package/plugins/roblox-ai-os-creator-skills/skills/crew/SKILL.md +7 -0
  299. package/plugins/roblox-ai-os-creator-skills/skills/deep-interview/SKILL.md +25 -18
  300. package/plugins/roblox-ai-os-creator-skills/skills/doctor/SKILL.md +7 -0
  301. package/plugins/roblox-ai-os-creator-skills/skills/forge/SKILL.md +174 -11
  302. package/plugins/roblox-ai-os-creator-skills/skills/forge-community/SKILL.md +7 -0
  303. package/plugins/roblox-ai-os-creator-skills/skills/forge-daily-loop/SKILL.md +7 -0
  304. package/plugins/roblox-ai-os-creator-skills/skills/forge-event-loop/SKILL.md +7 -0
  305. package/plugins/roblox-ai-os-creator-skills/skills/forge-fomo/SKILL.md +7 -0
  306. package/plugins/roblox-ai-os-creator-skills/skills/forge-mastery/SKILL.md +7 -0
  307. package/plugins/roblox-ai-os-creator-skills/skills/forge-progression/SKILL.md +7 -0
  308. package/plugins/roblox-ai-os-creator-skills/skills/forge-reward-loop/SKILL.md +7 -0
  309. package/plugins/roblox-ai-os-creator-skills/skills/forge-status/SKILL.md +7 -0
  310. package/plugins/roblox-ai-os-creator-skills/skills/help/SKILL.md +8 -1
  311. package/plugins/roblox-ai-os-creator-skills/skills/hud/SKILL.md +16 -9
  312. package/plugins/roblox-ai-os-creator-skills/skills/note/SKILL.md +8 -1
  313. package/plugins/roblox-ai-os-creator-skills/skills/pipeline/SKILL.md +18 -11
  314. package/plugins/roblox-ai-os-creator-skills/skills/plan/SKILL.md +36 -29
  315. package/plugins/roblox-ai-os-creator-skills/skills/rcs-setup/SKILL.md +8 -1
  316. package/plugins/roblox-ai-os-creator-skills/skills/security-review/SKILL.md +120 -236
  317. package/plugins/roblox-ai-os-creator-skills/skills/skill/SKILL.md +20 -13
  318. package/plugins/roblox-ai-os-creator-skills/skills/team/SKILL.md +17 -11
  319. package/plugins/roblox-ai-os-creator-skills/skills/trace/SKILL.md +7 -0
  320. package/plugins/roblox-ai-os-creator-skills/skills/ultraqa/SKILL.md +10 -3
  321. package/plugins/roblox-ai-os-creator-skills/skills/ultrawork/SKILL.md +19 -12
  322. package/plugins/roblox-ai-os-creator-skills/skills/{visual-ralph → visual-forge}/SKILL.md +36 -27
  323. package/plugins/roblox-ai-os-creator-skills/skills/visual-verdict/SKILL.md +9 -2
  324. package/plugins/roblox-ai-os-creator-skills/skills/wiki/SKILL.md +10 -3
  325. package/plugins/roblox-ai-os-creator-skills/skills/worker/SKILL.md +16 -7
  326. package/plugins/roblox-ai-os-creator-skills/templates/roblox/pre-action-plan.md +1 -0
  327. package/prompts/analyst.md +7 -0
  328. package/prompts/architect.md +11 -4
  329. package/prompts/build-fixer.md +7 -0
  330. package/prompts/code-reviewer.md +9 -2
  331. package/prompts/code-simplifier.md +4 -0
  332. package/prompts/critic.md +13 -6
  333. package/prompts/debugger.md +8 -1
  334. package/prompts/dependency-expert.md +8 -1
  335. package/prompts/designer.md +20 -10
  336. package/prompts/executor.md +7 -0
  337. package/prompts/explore-harness.md +7 -0
  338. package/prompts/explore.md +7 -0
  339. package/prompts/git-master.md +8 -1
  340. package/prompts/planner.md +10 -3
  341. package/prompts/researcher.md +7 -0
  342. package/prompts/security-reviewer.md +76 -92
  343. package/prompts/sisyphus-lite.md +7 -0
  344. package/prompts/team-executor.md +7 -0
  345. package/prompts/team-orchestrator.md +9 -2
  346. package/prompts/test-engineer.md +11 -3
  347. package/prompts/verifier.md +7 -0
  348. package/prompts/vision.md +9 -2
  349. package/prompts/writer.md +11 -4
  350. package/skills/.agents/skills/roblox-animations/SKILL.md +220 -0
  351. package/skills/.agents/skills/roblox-datastores/SKILL.md +219 -0
  352. package/skills/.agents/skills/roblox-gui/SKILL.md +192 -0
  353. package/skills/.agents/skills/roblox-monetization/SKILL.md +208 -0
  354. package/skills/.agents/skills/roblox-performance/SKILL.md +230 -0
  355. package/skills/.agents/skills/roblox-remote-events/SKILL.md +199 -0
  356. package/skills/.agents/skills/roblox-security/SKILL.md +236 -0
  357. package/skills/ai-slop-cleaner/SKILL.md +14 -7
  358. package/skills/analyze/SKILL.md +9 -2
  359. package/skills/ask-claude/SKILL.md +7 -0
  360. package/skills/ask-gemini/SKILL.md +7 -0
  361. package/skills/autoforge/SKILL.md +7 -0
  362. package/skills/autopilot/SKILL.md +48 -41
  363. package/skills/autoresearch/SKILL.md +8 -1
  364. package/skills/blueprint/SKILL.md +227 -9
  365. package/skills/blueprint-loop/SKILL.md +7 -0
  366. package/skills/blueprint-psych/SKILL.md +7 -0
  367. package/skills/blueprint-retention/SKILL.md +7 -0
  368. package/skills/blueprint-social/SKILL.md +7 -0
  369. package/skills/brief/SKILL.md +7 -0
  370. package/skills/brief-audience/SKILL.md +7 -0
  371. package/skills/brief-motivation/SKILL.md +7 -0
  372. package/skills/build-fix/SKILL.md +9 -2
  373. package/skills/cancel/SKILL.md +59 -52
  374. package/skills/code-review/SKILL.md +30 -24
  375. package/skills/configure-notifications/SKILL.md +7 -0
  376. package/skills/crew/SKILL.md +7 -0
  377. package/skills/deep-interview/SKILL.md +25 -18
  378. package/skills/deepsearch/SKILL.md +7 -0
  379. package/skills/doctor/SKILL.md +7 -0
  380. package/skills/ecomode/SKILL.md +9 -2
  381. package/skills/forge/SKILL.md +174 -11
  382. package/skills/forge-community/SKILL.md +7 -0
  383. package/skills/forge-daily-loop/SKILL.md +7 -0
  384. package/skills/forge-event-loop/SKILL.md +7 -0
  385. package/skills/forge-fomo/SKILL.md +7 -0
  386. package/skills/{ralph-init → forge-init}/SKILL.md +20 -13
  387. package/skills/forge-mastery/SKILL.md +7 -0
  388. package/skills/forge-progression/SKILL.md +7 -0
  389. package/skills/forge-reward-loop/SKILL.md +7 -0
  390. package/skills/forge-status/SKILL.md +7 -0
  391. package/skills/git-master/SKILL.md +7 -0
  392. package/skills/help/SKILL.md +8 -1
  393. package/skills/hud/SKILL.md +16 -9
  394. package/skills/note/SKILL.md +8 -1
  395. package/skills/pipeline/SKILL.md +18 -11
  396. package/skills/plan/SKILL.md +36 -29
  397. package/skills/rcs-setup/SKILL.md +8 -1
  398. package/skills/review/SKILL.md +7 -0
  399. package/skills/security-review/SKILL.md +120 -236
  400. package/skills/skill/SKILL.md +20 -13
  401. package/skills/skills-lock.json +47 -0
  402. package/skills/swarm/SKILL.md +8 -1
  403. package/skills/tdd/SKILL.md +7 -0
  404. package/skills/team/SKILL.md +17 -11
  405. package/skills/trace/SKILL.md +7 -0
  406. package/skills/ultraqa/SKILL.md +10 -3
  407. package/skills/ultrawork/SKILL.md +19 -12
  408. package/skills/{visual-ralph → visual-forge}/SKILL.md +36 -27
  409. package/skills/visual-verdict/SKILL.md +9 -2
  410. package/skills/web-clone/SKILL.md +14 -7
  411. package/skills/wiki/SKILL.md +10 -3
  412. package/skills/worker/SKILL.md +16 -7
  413. package/src/scripts/__tests__/codex-native-hook.test.ts +386 -319
  414. package/src/scripts/__tests__/run-test-files.test.ts +6 -4
  415. package/src/scripts/__tests__/verify-native-agents.test.ts +16 -16
  416. package/src/scripts/codex-native-hook.ts +34 -34
  417. package/src/scripts/eval/eval-cross-server-party-flow.ts +14 -0
  418. package/src/scripts/eval/eval-gui-onboarding-clarity.ts +20 -0
  419. package/src/scripts/eval/eval-liveops-reward-loop-balance.ts +14 -0
  420. package/src/scripts/eval/eval-profile-datastore-recovery.ts +20 -0
  421. package/src/scripts/eval/eval-remote-contract-hardening.ts +20 -0
  422. package/src/scripts/notify-fallback-watcher.ts +147 -146
  423. package/src/scripts/notify-hook/__tests__/team-worker-posttooluse.test.ts +24 -10
  424. package/src/scripts/notify-hook/{ralph-session-resume.ts → forge-session-resume.ts} +45 -43
  425. package/src/scripts/notify-hook/team-dispatch.ts +31 -4
  426. package/src/scripts/notify-hook/visual-verdict.ts +3 -3
  427. package/src/scripts/notify-hook.ts +10 -10
  428. package/src/scripts/run-test-files.ts +1 -1
  429. package/src/scripts/surface-taxonomy.ts +316 -0
  430. package/src/scripts/sync-plugin-mirror.ts +5 -4
  431. package/src/scripts/tmux-hook-engine.ts +31 -19
  432. package/templates/AGENTS.md +24 -15
  433. package/templates/catalog-manifest.json +5 -88
  434. package/templates/roblox/pre-action-plan.md +1 -0
  435. package/templates/roblox/robloxstudio-mcp.codex.json +18 -0
  436. package/templates/roblox/robloxstudio-mcp.windows.json +22 -0
  437. package/dist/adapt/__tests__/foundation.test.d.ts +0 -2
  438. package/dist/adapt/__tests__/foundation.test.d.ts.map +0 -1
  439. package/dist/adapt/__tests__/foundation.test.js +0 -171
  440. package/dist/adapt/__tests__/foundation.test.js.map +0 -1
  441. package/dist/adapt/__tests__/hermes.test.d.ts +0 -2
  442. package/dist/adapt/__tests__/hermes.test.d.ts.map +0 -1
  443. package/dist/adapt/__tests__/hermes.test.js +0 -137
  444. package/dist/adapt/__tests__/hermes.test.js.map +0 -1
  445. package/dist/agents/__tests__/definitions.test.d.ts +0 -2
  446. package/dist/agents/__tests__/definitions.test.d.ts.map +0 -1
  447. package/dist/agents/__tests__/definitions.test.js +0 -62
  448. package/dist/agents/__tests__/definitions.test.js.map +0 -1
  449. package/dist/agents/__tests__/native-config.test.d.ts +0 -2
  450. package/dist/agents/__tests__/native-config.test.d.ts.map +0 -1
  451. package/dist/agents/__tests__/native-config.test.js +0 -278
  452. package/dist/agents/__tests__/native-config.test.js.map +0 -1
  453. package/dist/autoresearch/__tests__/contracts.test.d.ts +0 -2
  454. package/dist/autoresearch/__tests__/contracts.test.d.ts.map +0 -1
  455. package/dist/autoresearch/__tests__/contracts.test.js +0 -127
  456. package/dist/autoresearch/__tests__/contracts.test.js.map +0 -1
  457. package/dist/autoresearch/__tests__/runtime-parity-extra.test.d.ts +0 -2
  458. package/dist/autoresearch/__tests__/runtime-parity-extra.test.d.ts.map +0 -1
  459. package/dist/autoresearch/__tests__/runtime-parity-extra.test.js +0 -356
  460. package/dist/autoresearch/__tests__/runtime-parity-extra.test.js.map +0 -1
  461. package/dist/autoresearch/__tests__/runtime.test.d.ts +0 -2
  462. package/dist/autoresearch/__tests__/runtime.test.d.ts.map +0 -1
  463. package/dist/autoresearch/__tests__/runtime.test.js +0 -218
  464. package/dist/autoresearch/__tests__/runtime.test.js.map +0 -1
  465. package/dist/autoresearch/__tests__/skill-validation.test.d.ts +0 -2
  466. package/dist/autoresearch/__tests__/skill-validation.test.d.ts.map +0 -1
  467. package/dist/autoresearch/__tests__/skill-validation.test.js +0 -91
  468. package/dist/autoresearch/__tests__/skill-validation.test.js.map +0 -1
  469. package/dist/catalog/__tests__/generator.test.d.ts +0 -2
  470. package/dist/catalog/__tests__/generator.test.d.ts.map +0 -1
  471. package/dist/catalog/__tests__/generator.test.js +0 -49
  472. package/dist/catalog/__tests__/generator.test.js.map +0 -1
  473. package/dist/catalog/__tests__/plugin-bundle-ssot.test.d.ts +0 -2
  474. package/dist/catalog/__tests__/plugin-bundle-ssot.test.d.ts.map +0 -1
  475. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +0 -83
  476. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +0 -1
  477. package/dist/catalog/__tests__/schema.test.d.ts +0 -2
  478. package/dist/catalog/__tests__/schema.test.d.ts.map +0 -1
  479. package/dist/catalog/__tests__/schema.test.js +0 -91
  480. package/dist/catalog/__tests__/schema.test.js.map +0 -1
  481. package/dist/cli/__tests__/adapt-help.test.d.ts +0 -2
  482. package/dist/cli/__tests__/adapt-help.test.d.ts.map +0 -1
  483. package/dist/cli/__tests__/adapt-help.test.js +0 -37
  484. package/dist/cli/__tests__/adapt-help.test.js.map +0 -1
  485. package/dist/cli/__tests__/adapt.test.d.ts +0 -2
  486. package/dist/cli/__tests__/adapt.test.d.ts.map +0 -1
  487. package/dist/cli/__tests__/adapt.test.js +0 -62
  488. package/dist/cli/__tests__/adapt.test.js.map +0 -1
  489. package/dist/cli/__tests__/agents-init.test.d.ts +0 -2
  490. package/dist/cli/__tests__/agents-init.test.d.ts.map +0 -1
  491. package/dist/cli/__tests__/agents-init.test.js +0 -184
  492. package/dist/cli/__tests__/agents-init.test.js.map +0 -1
  493. package/dist/cli/__tests__/agents.test.d.ts +0 -2
  494. package/dist/cli/__tests__/agents.test.d.ts.map +0 -1
  495. package/dist/cli/__tests__/agents.test.js +0 -137
  496. package/dist/cli/__tests__/agents.test.js.map +0 -1
  497. package/dist/cli/__tests__/ask.test.d.ts +0 -2
  498. package/dist/cli/__tests__/ask.test.d.ts.map +0 -1
  499. package/dist/cli/__tests__/ask.test.js +0 -265
  500. package/dist/cli/__tests__/ask.test.js.map +0 -1
  501. package/dist/cli/__tests__/autoresearch-guided.test.d.ts +0 -2
  502. package/dist/cli/__tests__/autoresearch-guided.test.d.ts.map +0 -1
  503. package/dist/cli/__tests__/autoresearch-guided.test.js +0 -365
  504. package/dist/cli/__tests__/autoresearch-guided.test.js.map +0 -1
  505. package/dist/cli/__tests__/autoresearch.test.d.ts +0 -2
  506. package/dist/cli/__tests__/autoresearch.test.d.ts.map +0 -1
  507. package/dist/cli/__tests__/autoresearch.test.js +0 -203
  508. package/dist/cli/__tests__/autoresearch.test.js.map +0 -1
  509. package/dist/cli/__tests__/catalog-contract.test.d.ts +0 -2
  510. package/dist/cli/__tests__/catalog-contract.test.d.ts.map +0 -1
  511. package/dist/cli/__tests__/catalog-contract.test.js +0 -18
  512. package/dist/cli/__tests__/catalog-contract.test.js.map +0 -1
  513. package/dist/cli/__tests__/cleanup.test.d.ts +0 -2
  514. package/dist/cli/__tests__/cleanup.test.d.ts.map +0 -1
  515. package/dist/cli/__tests__/cleanup.test.js +0 -419
  516. package/dist/cli/__tests__/cleanup.test.js.map +0 -1
  517. package/dist/cli/__tests__/codex-plugin-layout.test.d.ts +0 -2
  518. package/dist/cli/__tests__/codex-plugin-layout.test.d.ts.map +0 -1
  519. package/dist/cli/__tests__/codex-plugin-layout.test.js +0 -210
  520. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +0 -1
  521. package/dist/cli/__tests__/doctor-context-window-warning.test.d.ts +0 -2
  522. package/dist/cli/__tests__/doctor-context-window-warning.test.d.ts.map +0 -1
  523. package/dist/cli/__tests__/doctor-context-window-warning.test.js +0 -122
  524. package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +0 -1
  525. package/dist/cli/__tests__/doctor-invalid-config.test.d.ts +0 -2
  526. package/dist/cli/__tests__/doctor-invalid-config.test.d.ts.map +0 -1
  527. package/dist/cli/__tests__/doctor-invalid-config.test.js +0 -52
  528. package/dist/cli/__tests__/doctor-invalid-config.test.js.map +0 -1
  529. package/dist/cli/__tests__/doctor-team.test.d.ts +0 -2
  530. package/dist/cli/__tests__/doctor-team.test.d.ts.map +0 -1
  531. package/dist/cli/__tests__/doctor-team.test.js +0 -299
  532. package/dist/cli/__tests__/doctor-team.test.js.map +0 -1
  533. package/dist/cli/__tests__/doctor-warning-copy.test.d.ts +0 -2
  534. package/dist/cli/__tests__/doctor-warning-copy.test.d.ts.map +0 -1
  535. package/dist/cli/__tests__/doctor-warning-copy.test.js +0 -438
  536. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +0 -1
  537. package/dist/cli/__tests__/error-handling-warnings.test.d.ts +0 -2
  538. package/dist/cli/__tests__/error-handling-warnings.test.d.ts.map +0 -1
  539. package/dist/cli/__tests__/error-handling-warnings.test.js +0 -52
  540. package/dist/cli/__tests__/error-handling-warnings.test.js.map +0 -1
  541. package/dist/cli/__tests__/exec.test.d.ts +0 -2
  542. package/dist/cli/__tests__/exec.test.d.ts.map +0 -1
  543. package/dist/cli/__tests__/exec.test.js +0 -213
  544. package/dist/cli/__tests__/exec.test.js.map +0 -1
  545. package/dist/cli/__tests__/explore-windows-diagnostics.test.d.ts +0 -2
  546. package/dist/cli/__tests__/explore-windows-diagnostics.test.d.ts.map +0 -1
  547. package/dist/cli/__tests__/explore-windows-diagnostics.test.js +0 -17
  548. package/dist/cli/__tests__/explore-windows-diagnostics.test.js.map +0 -1
  549. package/dist/cli/__tests__/explore.test.d.ts +0 -2
  550. package/dist/cli/__tests__/explore.test.d.ts.map +0 -1
  551. package/dist/cli/__tests__/explore.test.js +0 -1090
  552. package/dist/cli/__tests__/explore.test.js.map +0 -1
  553. package/dist/cli/__tests__/hooks.test.d.ts +0 -2
  554. package/dist/cli/__tests__/hooks.test.d.ts.map +0 -1
  555. package/dist/cli/__tests__/hooks.test.js +0 -55
  556. package/dist/cli/__tests__/hooks.test.js.map +0 -1
  557. package/dist/cli/__tests__/index.test.d.ts +0 -2
  558. package/dist/cli/__tests__/index.test.d.ts.map +0 -1
  559. package/dist/cli/__tests__/index.test.js +0 -2259
  560. package/dist/cli/__tests__/index.test.js.map +0 -1
  561. package/dist/cli/__tests__/launch-fallback.test.d.ts +0 -2
  562. package/dist/cli/__tests__/launch-fallback.test.d.ts.map +0 -1
  563. package/dist/cli/__tests__/launch-fallback.test.js +0 -661
  564. package/dist/cli/__tests__/launch-fallback.test.js.map +0 -1
  565. package/dist/cli/__tests__/lifecycle-notifications.test.d.ts +0 -2
  566. package/dist/cli/__tests__/lifecycle-notifications.test.d.ts.map +0 -1
  567. package/dist/cli/__tests__/lifecycle-notifications.test.js +0 -48
  568. package/dist/cli/__tests__/lifecycle-notifications.test.js.map +0 -1
  569. package/dist/cli/__tests__/list.test.d.ts +0 -2
  570. package/dist/cli/__tests__/list.test.d.ts.map +0 -1
  571. package/dist/cli/__tests__/list.test.js +0 -38
  572. package/dist/cli/__tests__/list.test.js.map +0 -1
  573. package/dist/cli/__tests__/mcp-parity.test.d.ts +0 -2
  574. package/dist/cli/__tests__/mcp-parity.test.d.ts.map +0 -1
  575. package/dist/cli/__tests__/mcp-parity.test.js +0 -228
  576. package/dist/cli/__tests__/mcp-parity.test.js.map +0 -1
  577. package/dist/cli/__tests__/mcp-serve.test.d.ts +0 -2
  578. package/dist/cli/__tests__/mcp-serve.test.d.ts.map +0 -1
  579. package/dist/cli/__tests__/mcp-serve.test.js +0 -64
  580. package/dist/cli/__tests__/mcp-serve.test.js.map +0 -1
  581. package/dist/cli/__tests__/native-assets.test.d.ts +0 -2
  582. package/dist/cli/__tests__/native-assets.test.d.ts.map +0 -1
  583. package/dist/cli/__tests__/native-assets.test.js +0 -308
  584. package/dist/cli/__tests__/native-assets.test.js.map +0 -1
  585. package/dist/cli/__tests__/native-hook-dispatch-contract.test.d.ts +0 -2
  586. package/dist/cli/__tests__/native-hook-dispatch-contract.test.d.ts.map +0 -1
  587. package/dist/cli/__tests__/native-hook-dispatch-contract.test.js +0 -11
  588. package/dist/cli/__tests__/native-hook-dispatch-contract.test.js.map +0 -1
  589. package/dist/cli/__tests__/nested-help-routing.test.d.ts +0 -2
  590. package/dist/cli/__tests__/nested-help-routing.test.d.ts.map +0 -1
  591. package/dist/cli/__tests__/nested-help-routing.test.js +0 -96
  592. package/dist/cli/__tests__/nested-help-routing.test.js.map +0 -1
  593. package/dist/cli/__tests__/package-bin-contract.test.d.ts +0 -2
  594. package/dist/cli/__tests__/package-bin-contract.test.d.ts.map +0 -1
  595. package/dist/cli/__tests__/package-bin-contract.test.js +0 -177
  596. package/dist/cli/__tests__/package-bin-contract.test.js.map +0 -1
  597. package/dist/cli/__tests__/packaged-explore-harness-lock.d.ts +0 -3
  598. package/dist/cli/__tests__/packaged-explore-harness-lock.d.ts.map +0 -1
  599. package/dist/cli/__tests__/packaged-explore-harness-lock.js +0 -67
  600. package/dist/cli/__tests__/packaged-explore-harness-lock.js.map +0 -1
  601. package/dist/cli/__tests__/packaged-script-resolution.test.d.ts +0 -2
  602. package/dist/cli/__tests__/packaged-script-resolution.test.d.ts.map +0 -1
  603. package/dist/cli/__tests__/packaged-script-resolution.test.js +0 -19
  604. package/dist/cli/__tests__/packaged-script-resolution.test.js.map +0 -1
  605. package/dist/cli/__tests__/prompt-skill-sanitization.test.d.ts +0 -2
  606. package/dist/cli/__tests__/prompt-skill-sanitization.test.d.ts.map +0 -1
  607. package/dist/cli/__tests__/prompt-skill-sanitization.test.js +0 -48
  608. package/dist/cli/__tests__/prompt-skill-sanitization.test.js.map +0 -1
  609. package/dist/cli/__tests__/question.test.d.ts +0 -2
  610. package/dist/cli/__tests__/question.test.d.ts.map +0 -1
  611. package/dist/cli/__tests__/question.test.js +0 -633
  612. package/dist/cli/__tests__/question.test.js.map +0 -1
  613. package/dist/cli/__tests__/ralph-deslop-contract.test.d.ts +0 -2
  614. package/dist/cli/__tests__/ralph-deslop-contract.test.d.ts.map +0 -1
  615. package/dist/cli/__tests__/ralph-deslop-contract.test.js +0 -28
  616. package/dist/cli/__tests__/ralph-deslop-contract.test.js.map +0 -1
  617. package/dist/cli/__tests__/ralph-prd-deep-interview.test.d.ts +0 -2
  618. package/dist/cli/__tests__/ralph-prd-deep-interview.test.d.ts.map +0 -1
  619. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js +0 -24
  620. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +0 -1
  621. package/dist/cli/__tests__/ralph-prd-smoke.test.d.ts +0 -2
  622. package/dist/cli/__tests__/ralph-prd-smoke.test.d.ts.map +0 -1
  623. package/dist/cli/__tests__/ralph-prd-smoke.test.js +0 -167
  624. package/dist/cli/__tests__/ralph-prd-smoke.test.js.map +0 -1
  625. package/dist/cli/__tests__/ralph.test.d.ts +0 -2
  626. package/dist/cli/__tests__/ralph.test.d.ts.map +0 -1
  627. package/dist/cli/__tests__/ralph.test.js +0 -256
  628. package/dist/cli/__tests__/ralph.test.js.map +0 -1
  629. package/dist/cli/__tests__/resume.test.d.ts +0 -2
  630. package/dist/cli/__tests__/resume.test.d.ts.map +0 -1
  631. package/dist/cli/__tests__/resume.test.js +0 -84
  632. package/dist/cli/__tests__/resume.test.js.map +0 -1
  633. package/dist/cli/__tests__/session-scoped-runtime.test.d.ts +0 -2
  634. package/dist/cli/__tests__/session-scoped-runtime.test.d.ts.map +0 -1
  635. package/dist/cli/__tests__/session-scoped-runtime.test.js +0 -146
  636. package/dist/cli/__tests__/session-scoped-runtime.test.js.map +0 -1
  637. package/dist/cli/__tests__/session-search-help.test.d.ts +0 -2
  638. package/dist/cli/__tests__/session-search-help.test.d.ts.map +0 -1
  639. package/dist/cli/__tests__/session-search-help.test.js +0 -76
  640. package/dist/cli/__tests__/session-search-help.test.js.map +0 -1
  641. package/dist/cli/__tests__/session-search.test.d.ts +0 -2
  642. package/dist/cli/__tests__/session-search.test.d.ts.map +0 -1
  643. package/dist/cli/__tests__/session-search.test.js +0 -77
  644. package/dist/cli/__tests__/session-search.test.js.map +0 -1
  645. package/dist/cli/__tests__/setup-agents-overwrite.test.d.ts +0 -2
  646. package/dist/cli/__tests__/setup-agents-overwrite.test.d.ts.map +0 -1
  647. package/dist/cli/__tests__/setup-agents-overwrite.test.js +0 -457
  648. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +0 -1
  649. package/dist/cli/__tests__/setup-gh-star.test.d.ts +0 -2
  650. package/dist/cli/__tests__/setup-gh-star.test.d.ts.map +0 -1
  651. package/dist/cli/__tests__/setup-gh-star.test.js +0 -67
  652. package/dist/cli/__tests__/setup-gh-star.test.js.map +0 -1
  653. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.d.ts +0 -2
  654. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.d.ts.map +0 -1
  655. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +0 -189
  656. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +0 -1
  657. package/dist/cli/__tests__/setup-install-mode.test.d.ts +0 -2
  658. package/dist/cli/__tests__/setup-install-mode.test.d.ts.map +0 -1
  659. package/dist/cli/__tests__/setup-install-mode.test.js +0 -873
  660. package/dist/cli/__tests__/setup-install-mode.test.js.map +0 -1
  661. package/dist/cli/__tests__/setup-prompts-overwrite.test.d.ts +0 -2
  662. package/dist/cli/__tests__/setup-prompts-overwrite.test.d.ts.map +0 -1
  663. package/dist/cli/__tests__/setup-prompts-overwrite.test.js +0 -191
  664. package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +0 -1
  665. package/dist/cli/__tests__/setup-refresh.test.d.ts +0 -2
  666. package/dist/cli/__tests__/setup-refresh.test.d.ts.map +0 -1
  667. package/dist/cli/__tests__/setup-refresh.test.js +0 -591
  668. package/dist/cli/__tests__/setup-refresh.test.js.map +0 -1
  669. package/dist/cli/__tests__/setup-scope.test.d.ts +0 -2
  670. package/dist/cli/__tests__/setup-scope.test.d.ts.map +0 -1
  671. package/dist/cli/__tests__/setup-scope.test.js +0 -340
  672. package/dist/cli/__tests__/setup-scope.test.js.map +0 -1
  673. package/dist/cli/__tests__/setup-skill-validation.test.d.ts +0 -2
  674. package/dist/cli/__tests__/setup-skill-validation.test.d.ts.map +0 -1
  675. package/dist/cli/__tests__/setup-skill-validation.test.js +0 -44
  676. package/dist/cli/__tests__/setup-skill-validation.test.js.map +0 -1
  677. package/dist/cli/__tests__/setup-skills-overwrite.test.d.ts +0 -2
  678. package/dist/cli/__tests__/setup-skills-overwrite.test.d.ts.map +0 -1
  679. package/dist/cli/__tests__/setup-skills-overwrite.test.js +0 -295
  680. package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +0 -1
  681. package/dist/cli/__tests__/sidecar.test.d.ts +0 -2
  682. package/dist/cli/__tests__/sidecar.test.d.ts.map +0 -1
  683. package/dist/cli/__tests__/sidecar.test.js +0 -24
  684. package/dist/cli/__tests__/sidecar.test.js.map +0 -1
  685. package/dist/cli/__tests__/sparkshell-cli.test.d.ts +0 -2
  686. package/dist/cli/__tests__/sparkshell-cli.test.d.ts.map +0 -1
  687. package/dist/cli/__tests__/sparkshell-cli.test.js +0 -400
  688. package/dist/cli/__tests__/sparkshell-cli.test.js.map +0 -1
  689. package/dist/cli/__tests__/sparkshell-packaging.test.d.ts +0 -2
  690. package/dist/cli/__tests__/sparkshell-packaging.test.d.ts.map +0 -1
  691. package/dist/cli/__tests__/sparkshell-packaging.test.js +0 -74
  692. package/dist/cli/__tests__/sparkshell-packaging.test.js.map +0 -1
  693. package/dist/cli/__tests__/star-prompt.test.d.ts +0 -2
  694. package/dist/cli/__tests__/star-prompt.test.d.ts.map +0 -1
  695. package/dist/cli/__tests__/star-prompt.test.js +0 -172
  696. package/dist/cli/__tests__/star-prompt.test.js.map +0 -1
  697. package/dist/cli/__tests__/state.test.d.ts +0 -2
  698. package/dist/cli/__tests__/state.test.d.ts.map +0 -1
  699. package/dist/cli/__tests__/state.test.js +0 -46
  700. package/dist/cli/__tests__/state.test.js.map +0 -1
  701. package/dist/cli/__tests__/team-decompose.test.d.ts +0 -2
  702. package/dist/cli/__tests__/team-decompose.test.d.ts.map +0 -1
  703. package/dist/cli/__tests__/team-decompose.test.js +0 -133
  704. package/dist/cli/__tests__/team-decompose.test.js.map +0 -1
  705. package/dist/cli/__tests__/team.test.d.ts +0 -2
  706. package/dist/cli/__tests__/team.test.d.ts.map +0 -1
  707. package/dist/cli/__tests__/team.test.js +0 -1820
  708. package/dist/cli/__tests__/team.test.js.map +0 -1
  709. package/dist/cli/__tests__/uninstall.test.d.ts +0 -2
  710. package/dist/cli/__tests__/uninstall.test.d.ts.map +0 -1
  711. package/dist/cli/__tests__/uninstall.test.js +0 -766
  712. package/dist/cli/__tests__/uninstall.test.js.map +0 -1
  713. package/dist/cli/__tests__/update.test.d.ts +0 -2
  714. package/dist/cli/__tests__/update.test.d.ts.map +0 -1
  715. package/dist/cli/__tests__/update.test.js +0 -589
  716. package/dist/cli/__tests__/update.test.js.map +0 -1
  717. package/dist/cli/__tests__/version-sync-contract.test.d.ts +0 -2
  718. package/dist/cli/__tests__/version-sync-contract.test.d.ts.map +0 -1
  719. package/dist/cli/__tests__/version-sync-contract.test.js +0 -41
  720. package/dist/cli/__tests__/version-sync-contract.test.js.map +0 -1
  721. package/dist/cli/__tests__/version.test.d.ts +0 -2
  722. package/dist/cli/__tests__/version.test.d.ts.map +0 -1
  723. package/dist/cli/__tests__/version.test.js +0 -21
  724. package/dist/cli/__tests__/version.test.js.map +0 -1
  725. package/dist/cli/__tests__/windows-popup-loop-contract.test.d.ts +0 -2
  726. package/dist/cli/__tests__/windows-popup-loop-contract.test.d.ts.map +0 -1
  727. package/dist/cli/__tests__/windows-popup-loop-contract.test.js +0 -31
  728. package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +0 -1
  729. package/dist/cli/ralph.d.ts +0 -17
  730. package/dist/compat/__tests__/doctor-contract.test.d.ts +0 -2
  731. package/dist/compat/__tests__/doctor-contract.test.d.ts.map +0 -1
  732. package/dist/compat/__tests__/doctor-contract.test.js +0 -108
  733. package/dist/compat/__tests__/doctor-contract.test.js.map +0 -1
  734. package/dist/compat/__tests__/rust-runtime-compat.test.d.ts +0 -2
  735. package/dist/compat/__tests__/rust-runtime-compat.test.d.ts.map +0 -1
  736. package/dist/compat/__tests__/rust-runtime-compat.test.js +0 -218
  737. package/dist/compat/__tests__/rust-runtime-compat.test.js.map +0 -1
  738. package/dist/config/__tests__/codex-hooks.test.d.ts +0 -2
  739. package/dist/config/__tests__/codex-hooks.test.d.ts.map +0 -1
  740. package/dist/config/__tests__/codex-hooks.test.js +0 -77
  741. package/dist/config/__tests__/codex-hooks.test.js.map +0 -1
  742. package/dist/config/__tests__/generator-idempotent.test.d.ts +0 -2
  743. package/dist/config/__tests__/generator-idempotent.test.d.ts.map +0 -1
  744. package/dist/config/__tests__/generator-idempotent.test.js +0 -882
  745. package/dist/config/__tests__/generator-idempotent.test.js.map +0 -1
  746. package/dist/config/__tests__/generator-notify.test.d.ts +0 -2
  747. package/dist/config/__tests__/generator-notify.test.d.ts.map +0 -1
  748. package/dist/config/__tests__/generator-notify.test.js +0 -343
  749. package/dist/config/__tests__/generator-notify.test.js.map +0 -1
  750. package/dist/config/__tests__/generator-status-line-presets.test.d.ts +0 -2
  751. package/dist/config/__tests__/generator-status-line-presets.test.d.ts.map +0 -1
  752. package/dist/config/__tests__/generator-status-line-presets.test.js +0 -203
  753. package/dist/config/__tests__/generator-status-line-presets.test.js.map +0 -1
  754. package/dist/config/__tests__/mcp-registry.test.d.ts +0 -2
  755. package/dist/config/__tests__/mcp-registry.test.d.ts.map +0 -1
  756. package/dist/config/__tests__/mcp-registry.test.js +0 -190
  757. package/dist/config/__tests__/mcp-registry.test.js.map +0 -1
  758. package/dist/config/__tests__/models.test.d.ts +0 -2
  759. package/dist/config/__tests__/models.test.d.ts.map +0 -1
  760. package/dist/config/__tests__/models.test.js +0 -224
  761. package/dist/config/__tests__/models.test.js.map +0 -1
  762. package/dist/config/__tests__/wiki-config-contract.test.d.ts +0 -2
  763. package/dist/config/__tests__/wiki-config-contract.test.d.ts.map +0 -1
  764. package/dist/config/__tests__/wiki-config-contract.test.js +0 -19
  765. package/dist/config/__tests__/wiki-config-contract.test.js.map +0 -1
  766. package/dist/document-refresh/__tests__/enforcer.test.d.ts +0 -2
  767. package/dist/document-refresh/__tests__/enforcer.test.d.ts.map +0 -1
  768. package/dist/document-refresh/__tests__/enforcer.test.js +0 -128
  769. package/dist/document-refresh/__tests__/enforcer.test.js.map +0 -1
  770. package/dist/hooks/__tests__/agents-overlay.test.d.ts +0 -8
  771. package/dist/hooks/__tests__/agents-overlay.test.d.ts.map +0 -1
  772. package/dist/hooks/__tests__/agents-overlay.test.js +0 -644
  773. package/dist/hooks/__tests__/agents-overlay.test.js.map +0 -1
  774. package/dist/hooks/__tests__/analyze-routing-contract.test.d.ts +0 -2
  775. package/dist/hooks/__tests__/analyze-routing-contract.test.d.ts.map +0 -1
  776. package/dist/hooks/__tests__/analyze-routing-contract.test.js +0 -45
  777. package/dist/hooks/__tests__/analyze-routing-contract.test.js.map +0 -1
  778. package/dist/hooks/__tests__/analyze-skill-contract.test.d.ts +0 -2
  779. package/dist/hooks/__tests__/analyze-skill-contract.test.d.ts.map +0 -1
  780. package/dist/hooks/__tests__/analyze-skill-contract.test.js +0 -48
  781. package/dist/hooks/__tests__/analyze-skill-contract.test.js.map +0 -1
  782. package/dist/hooks/__tests__/anti-slop-workflow.test.d.ts +0 -2
  783. package/dist/hooks/__tests__/anti-slop-workflow.test.d.ts.map +0 -1
  784. package/dist/hooks/__tests__/anti-slop-workflow.test.js +0 -146
  785. package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +0 -1
  786. package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts +0 -2
  787. package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts.map +0 -1
  788. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +0 -37
  789. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +0 -1
  790. package/dist/hooks/__tests__/clawhip-event-contract.test.d.ts +0 -2
  791. package/dist/hooks/__tests__/clawhip-event-contract.test.d.ts.map +0 -1
  792. package/dist/hooks/__tests__/clawhip-event-contract.test.js +0 -37
  793. package/dist/hooks/__tests__/clawhip-event-contract.test.js.map +0 -1
  794. package/dist/hooks/__tests__/code-review-skill-contract.test.d.ts +0 -2
  795. package/dist/hooks/__tests__/code-review-skill-contract.test.d.ts.map +0 -1
  796. package/dist/hooks/__tests__/code-review-skill-contract.test.js +0 -56
  797. package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +0 -1
  798. package/dist/hooks/__tests__/codebase-map.test.d.ts +0 -8
  799. package/dist/hooks/__tests__/codebase-map.test.d.ts.map +0 -1
  800. package/dist/hooks/__tests__/codebase-map.test.js +0 -218
  801. package/dist/hooks/__tests__/codebase-map.test.js.map +0 -1
  802. package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts +0 -18
  803. package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts.map +0 -1
  804. package/dist/hooks/__tests__/consensus-execution-handoff.test.js +0 -234
  805. package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +0 -1
  806. package/dist/hooks/__tests__/debugger-log-recency-contract.test.d.ts +0 -2
  807. package/dist/hooks/__tests__/debugger-log-recency-contract.test.d.ts.map +0 -1
  808. package/dist/hooks/__tests__/debugger-log-recency-contract.test.js +0 -20
  809. package/dist/hooks/__tests__/debugger-log-recency-contract.test.js.map +0 -1
  810. package/dist/hooks/__tests__/deep-interview-contract.test.d.ts +0 -2
  811. package/dist/hooks/__tests__/deep-interview-contract.test.d.ts.map +0 -1
  812. package/dist/hooks/__tests__/deep-interview-contract.test.js +0 -213
  813. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +0 -1
  814. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.d.ts +0 -2
  815. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.d.ts.map +0 -1
  816. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.js +0 -43
  817. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.js.map +0 -1
  818. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.d.ts +0 -2
  819. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.d.ts.map +0 -1
  820. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.js +0 -38
  821. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.js.map +0 -1
  822. package/dist/hooks/__tests__/explore-routing.test.d.ts +0 -2
  823. package/dist/hooks/__tests__/explore-routing.test.d.ts.map +0 -1
  824. package/dist/hooks/__tests__/explore-routing.test.js +0 -43
  825. package/dist/hooks/__tests__/explore-routing.test.js.map +0 -1
  826. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.d.ts +0 -2
  827. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.d.ts.map +0 -1
  828. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js +0 -69
  829. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js.map +0 -1
  830. package/dist/hooks/__tests__/keyword-detector.test.d.ts +0 -2
  831. package/dist/hooks/__tests__/keyword-detector.test.d.ts.map +0 -1
  832. package/dist/hooks/__tests__/keyword-detector.test.js +0 -1716
  833. package/dist/hooks/__tests__/keyword-detector.test.js.map +0 -1
  834. package/dist/hooks/__tests__/notify-fallback-watcher.test.d.ts +0 -2
  835. package/dist/hooks/__tests__/notify-fallback-watcher.test.d.ts.map +0 -1
  836. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +0 -3898
  837. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +0 -1
  838. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.d.ts +0 -2
  839. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.d.ts.map +0 -1
  840. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +0 -786
  841. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +0 -1
  842. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.d.ts +0 -2
  843. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.d.ts.map +0 -1
  844. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +0 -2397
  845. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +0 -1
  846. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.d.ts +0 -2
  847. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.d.ts.map +0 -1
  848. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +0 -160
  849. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +0 -1
  850. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.d.ts +0 -2
  851. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.d.ts.map +0 -1
  852. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +0 -1178
  853. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +0 -1
  854. package/dist/hooks/__tests__/notify-hook-modules.test.d.ts +0 -9
  855. package/dist/hooks/__tests__/notify-hook-modules.test.d.ts.map +0 -1
  856. package/dist/hooks/__tests__/notify-hook-modules.test.js +0 -529
  857. package/dist/hooks/__tests__/notify-hook-modules.test.js.map +0 -1
  858. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.d.ts +0 -2
  859. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.d.ts.map +0 -1
  860. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.js +0 -14
  861. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.js.map +0 -1
  862. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.d.ts +0 -2
  863. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.d.ts.map +0 -1
  864. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +0 -682
  865. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +0 -1
  866. package/dist/hooks/__tests__/notify-hook-regression-205.test.d.ts +0 -9
  867. package/dist/hooks/__tests__/notify-hook-regression-205.test.d.ts.map +0 -1
  868. package/dist/hooks/__tests__/notify-hook-regression-205.test.js +0 -255
  869. package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +0 -1
  870. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.d.ts +0 -2
  871. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.d.ts.map +0 -1
  872. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js +0 -162
  873. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js.map +0 -1
  874. package/dist/hooks/__tests__/notify-hook-session-scope.test.d.ts +0 -2
  875. package/dist/hooks/__tests__/notify-hook-session-scope.test.d.ts.map +0 -1
  876. package/dist/hooks/__tests__/notify-hook-session-scope.test.js +0 -301
  877. package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +0 -1
  878. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.d.ts +0 -2
  879. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.d.ts.map +0 -1
  880. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +0 -1510
  881. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +0 -1
  882. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.d.ts +0 -2
  883. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.d.ts.map +0 -1
  884. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +0 -2879
  885. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +0 -1
  886. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.d.ts +0 -2
  887. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.d.ts.map +0 -1
  888. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +0 -228
  889. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +0 -1
  890. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts +0 -2
  891. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts.map +0 -1
  892. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js +0 -35
  893. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js.map +0 -1
  894. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.d.ts +0 -2
  895. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.d.ts.map +0 -1
  896. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +0 -1589
  897. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +0 -1
  898. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.d.ts +0 -10
  899. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.d.ts.map +0 -1
  900. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +0 -0
  901. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +0 -1
  902. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.d.ts +0 -11
  903. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.d.ts.map +0 -1
  904. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js +0 -266
  905. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js.map +0 -1
  906. package/dist/hooks/__tests__/notify-hook-worker-idle.test.d.ts +0 -2
  907. package/dist/hooks/__tests__/notify-hook-worker-idle.test.d.ts.map +0 -1
  908. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +0 -895
  909. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +0 -1
  910. package/dist/hooks/__tests__/openclaw-setup-contract.test.d.ts +0 -2
  911. package/dist/hooks/__tests__/openclaw-setup-contract.test.d.ts.map +0 -1
  912. package/dist/hooks/__tests__/openclaw-setup-contract.test.js +0 -61
  913. package/dist/hooks/__tests__/openclaw-setup-contract.test.js.map +0 -1
  914. package/dist/hooks/__tests__/pre-context-gate-skills.test.d.ts +0 -2
  915. package/dist/hooks/__tests__/pre-context-gate-skills.test.d.ts.map +0 -1
  916. package/dist/hooks/__tests__/pre-context-gate-skills.test.js +0 -40
  917. package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +0 -1
  918. package/dist/hooks/__tests__/prompt-guidance-catalog.test.d.ts +0 -2
  919. package/dist/hooks/__tests__/prompt-guidance-catalog.test.d.ts.map +0 -1
  920. package/dist/hooks/__tests__/prompt-guidance-catalog.test.js +0 -11
  921. package/dist/hooks/__tests__/prompt-guidance-catalog.test.js.map +0 -1
  922. package/dist/hooks/__tests__/prompt-guidance-contract.test.d.ts +0 -2
  923. package/dist/hooks/__tests__/prompt-guidance-contract.test.d.ts.map +0 -1
  924. package/dist/hooks/__tests__/prompt-guidance-contract.test.js +0 -38
  925. package/dist/hooks/__tests__/prompt-guidance-contract.test.js.map +0 -1
  926. package/dist/hooks/__tests__/prompt-guidance-fragments.test.d.ts +0 -2
  927. package/dist/hooks/__tests__/prompt-guidance-fragments.test.d.ts.map +0 -1
  928. package/dist/hooks/__tests__/prompt-guidance-fragments.test.js +0 -48
  929. package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +0 -1
  930. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.d.ts +0 -2
  931. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.d.ts.map +0 -1
  932. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.js +0 -11
  933. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.js.map +0 -1
  934. package/dist/hooks/__tests__/prompt-guidance-test-helpers.d.ts +0 -5
  935. package/dist/hooks/__tests__/prompt-guidance-test-helpers.d.ts.map +0 -1
  936. package/dist/hooks/__tests__/prompt-guidance-test-helpers.js +0 -34
  937. package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +0 -1
  938. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.d.ts +0 -2
  939. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.d.ts.map +0 -1
  940. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +0 -65
  941. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +0 -1
  942. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.d.ts +0 -2
  943. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.d.ts.map +0 -1
  944. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.js +0 -38
  945. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.js.map +0 -1
  946. package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts +0 -2
  947. package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts.map +0 -1
  948. package/dist/hooks/__tests__/prompt-refactor-contract.test.js +0 -22
  949. package/dist/hooks/__tests__/prompt-refactor-contract.test.js.map +0 -1
  950. package/dist/hooks/__tests__/prompt-team-routing.test.d.ts +0 -2
  951. package/dist/hooks/__tests__/prompt-team-routing.test.d.ts.map +0 -1
  952. package/dist/hooks/__tests__/prompt-team-routing.test.js +0 -49
  953. package/dist/hooks/__tests__/prompt-team-routing.test.js.map +0 -1
  954. package/dist/hooks/__tests__/session.test.d.ts +0 -2
  955. package/dist/hooks/__tests__/session.test.d.ts.map +0 -1
  956. package/dist/hooks/__tests__/session.test.js +0 -322
  957. package/dist/hooks/__tests__/session.test.js.map +0 -1
  958. package/dist/hooks/__tests__/skill-guidance-contract.test.d.ts +0 -2
  959. package/dist/hooks/__tests__/skill-guidance-contract.test.d.ts.map +0 -1
  960. package/dist/hooks/__tests__/skill-guidance-contract.test.js +0 -29
  961. package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +0 -1
  962. package/dist/hooks/__tests__/task-size-detector.test.d.ts +0 -2
  963. package/dist/hooks/__tests__/task-size-detector.test.d.ts.map +0 -1
  964. package/dist/hooks/__tests__/task-size-detector.test.js +0 -330
  965. package/dist/hooks/__tests__/task-size-detector.test.js.map +0 -1
  966. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.d.ts +0 -2
  967. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.d.ts.map +0 -1
  968. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js +0 -28
  969. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js.map +0 -1
  970. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.d.ts +0 -2
  971. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.d.ts.map +0 -1
  972. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.js +0 -24
  973. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.js.map +0 -1
  974. package/dist/hooks/__tests__/tmux-hook-engine.test.d.ts +0 -2
  975. package/dist/hooks/__tests__/tmux-hook-engine.test.d.ts.map +0 -1
  976. package/dist/hooks/__tests__/tmux-hook-engine.test.js +0 -403
  977. package/dist/hooks/__tests__/tmux-hook-engine.test.js.map +0 -1
  978. package/dist/hooks/__tests__/triage-config.test.d.ts +0 -2
  979. package/dist/hooks/__tests__/triage-config.test.d.ts.map +0 -1
  980. package/dist/hooks/__tests__/triage-config.test.js +0 -211
  981. package/dist/hooks/__tests__/triage-config.test.js.map +0 -1
  982. package/dist/hooks/__tests__/triage-heuristic.test.d.ts +0 -2
  983. package/dist/hooks/__tests__/triage-heuristic.test.d.ts.map +0 -1
  984. package/dist/hooks/__tests__/triage-heuristic.test.js +0 -285
  985. package/dist/hooks/__tests__/triage-heuristic.test.js.map +0 -1
  986. package/dist/hooks/__tests__/triage-state.test.d.ts +0 -2
  987. package/dist/hooks/__tests__/triage-state.test.d.ts.map +0 -1
  988. package/dist/hooks/__tests__/triage-state.test.js +0 -426
  989. package/dist/hooks/__tests__/triage-state.test.js.map +0 -1
  990. package/dist/hooks/__tests__/visual-ralph-skill.test.d.ts +0 -2
  991. package/dist/hooks/__tests__/visual-ralph-skill.test.d.ts.map +0 -1
  992. package/dist/hooks/__tests__/visual-ralph-skill.test.js +0 -44
  993. package/dist/hooks/__tests__/visual-ralph-skill.test.js.map +0 -1
  994. package/dist/hooks/__tests__/visual-verdict-loop.test.d.ts +0 -2
  995. package/dist/hooks/__tests__/visual-verdict-loop.test.d.ts.map +0 -1
  996. package/dist/hooks/__tests__/visual-verdict-loop.test.js +0 -35
  997. package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +0 -1
  998. package/dist/hooks/__tests__/wiki-docs-contract.test.d.ts +0 -2
  999. package/dist/hooks/__tests__/wiki-docs-contract.test.d.ts.map +0 -1
  1000. package/dist/hooks/__tests__/wiki-docs-contract.test.js +0 -34
  1001. package/dist/hooks/__tests__/wiki-docs-contract.test.js.map +0 -1
  1002. package/dist/hooks/code-simplifier/__tests__/index.test.d.ts +0 -2
  1003. package/dist/hooks/code-simplifier/__tests__/index.test.d.ts.map +0 -1
  1004. package/dist/hooks/code-simplifier/__tests__/index.test.js +0 -187
  1005. package/dist/hooks/code-simplifier/__tests__/index.test.js.map +0 -1
  1006. package/dist/hooks/extensibility/__tests__/dispatcher.test.d.ts +0 -2
  1007. package/dist/hooks/extensibility/__tests__/dispatcher.test.d.ts.map +0 -1
  1008. package/dist/hooks/extensibility/__tests__/dispatcher.test.js +0 -242
  1009. package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +0 -1
  1010. package/dist/hooks/extensibility/__tests__/events.test.d.ts +0 -2
  1011. package/dist/hooks/extensibility/__tests__/events.test.d.ts.map +0 -1
  1012. package/dist/hooks/extensibility/__tests__/events.test.js +0 -125
  1013. package/dist/hooks/extensibility/__tests__/events.test.js.map +0 -1
  1014. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.d.ts +0 -2
  1015. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.d.ts.map +0 -1
  1016. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.js +0 -153
  1017. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.js.map +0 -1
  1018. package/dist/hooks/extensibility/__tests__/loader.test.d.ts +0 -2
  1019. package/dist/hooks/extensibility/__tests__/loader.test.d.ts.map +0 -1
  1020. package/dist/hooks/extensibility/__tests__/loader.test.js +0 -254
  1021. package/dist/hooks/extensibility/__tests__/loader.test.js.map +0 -1
  1022. package/dist/hooks/extensibility/__tests__/logging.test.d.ts +0 -2
  1023. package/dist/hooks/extensibility/__tests__/logging.test.d.ts.map +0 -1
  1024. package/dist/hooks/extensibility/__tests__/logging.test.js +0 -74
  1025. package/dist/hooks/extensibility/__tests__/logging.test.js.map +0 -1
  1026. package/dist/hooks/extensibility/__tests__/plugin-runner.test.d.ts +0 -2
  1027. package/dist/hooks/extensibility/__tests__/plugin-runner.test.d.ts.map +0 -1
  1028. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js +0 -202
  1029. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js.map +0 -1
  1030. package/dist/hooks/extensibility/__tests__/runtime.test.d.ts +0 -2
  1031. package/dist/hooks/extensibility/__tests__/runtime.test.d.ts.map +0 -1
  1032. package/dist/hooks/extensibility/__tests__/runtime.test.js +0 -198
  1033. package/dist/hooks/extensibility/__tests__/runtime.test.js.map +0 -1
  1034. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.d.ts +0 -2
  1035. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.d.ts.map +0 -1
  1036. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.js +0 -32
  1037. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.js.map +0 -1
  1038. package/dist/hooks/extensibility/__tests__/sdk.test.d.ts +0 -2
  1039. package/dist/hooks/extensibility/__tests__/sdk.test.d.ts.map +0 -1
  1040. package/dist/hooks/extensibility/__tests__/sdk.test.js +0 -479
  1041. package/dist/hooks/extensibility/__tests__/sdk.test.js.map +0 -1
  1042. package/dist/hud/__tests__/authority.test.d.ts +0 -2
  1043. package/dist/hud/__tests__/authority.test.d.ts.map +0 -1
  1044. package/dist/hud/__tests__/authority.test.js +0 -56
  1045. package/dist/hud/__tests__/authority.test.js.map +0 -1
  1046. package/dist/hud/__tests__/colors.test.d.ts +0 -2
  1047. package/dist/hud/__tests__/colors.test.d.ts.map +0 -1
  1048. package/dist/hud/__tests__/colors.test.js +0 -92
  1049. package/dist/hud/__tests__/colors.test.js.map +0 -1
  1050. package/dist/hud/__tests__/hud-tmux-injection.test.d.ts +0 -10
  1051. package/dist/hud/__tests__/hud-tmux-injection.test.d.ts.map +0 -1
  1052. package/dist/hud/__tests__/hud-tmux-injection.test.js +0 -150
  1053. package/dist/hud/__tests__/hud-tmux-injection.test.js.map +0 -1
  1054. package/dist/hud/__tests__/index.test.d.ts +0 -2
  1055. package/dist/hud/__tests__/index.test.d.ts.map +0 -1
  1056. package/dist/hud/__tests__/index.test.js +0 -180
  1057. package/dist/hud/__tests__/index.test.js.map +0 -1
  1058. package/dist/hud/__tests__/reconcile.test.d.ts +0 -2
  1059. package/dist/hud/__tests__/reconcile.test.d.ts.map +0 -1
  1060. package/dist/hud/__tests__/reconcile.test.js +0 -125
  1061. package/dist/hud/__tests__/reconcile.test.js.map +0 -1
  1062. package/dist/hud/__tests__/render.test.d.ts +0 -2
  1063. package/dist/hud/__tests__/render.test.d.ts.map +0 -1
  1064. package/dist/hud/__tests__/render.test.js +0 -573
  1065. package/dist/hud/__tests__/render.test.js.map +0 -1
  1066. package/dist/hud/__tests__/state.test.d.ts +0 -2
  1067. package/dist/hud/__tests__/state.test.d.ts.map +0 -1
  1068. package/dist/hud/__tests__/state.test.js +0 -618
  1069. package/dist/hud/__tests__/state.test.js.map +0 -1
  1070. package/dist/hud/__tests__/types.test.d.ts +0 -2
  1071. package/dist/hud/__tests__/types.test.d.ts.map +0 -1
  1072. package/dist/hud/__tests__/types.test.js +0 -79
  1073. package/dist/hud/__tests__/types.test.js.map +0 -1
  1074. package/dist/hud/__tests__/watch.test.d.ts +0 -2
  1075. package/dist/hud/__tests__/watch.test.d.ts.map +0 -1
  1076. package/dist/hud/__tests__/watch.test.js +0 -63
  1077. package/dist/hud/__tests__/watch.test.js.map +0 -1
  1078. package/dist/mcp/__tests__/bootstrap.test.d.ts +0 -2
  1079. package/dist/mcp/__tests__/bootstrap.test.d.ts.map +0 -1
  1080. package/dist/mcp/__tests__/bootstrap.test.js +0 -207
  1081. package/dist/mcp/__tests__/bootstrap.test.js.map +0 -1
  1082. package/dist/mcp/__tests__/code-intel-server.test.d.ts +0 -2
  1083. package/dist/mcp/__tests__/code-intel-server.test.d.ts.map +0 -1
  1084. package/dist/mcp/__tests__/code-intel-server.test.js +0 -70
  1085. package/dist/mcp/__tests__/code-intel-server.test.js.map +0 -1
  1086. package/dist/mcp/__tests__/memory-server.test.d.ts +0 -2
  1087. package/dist/mcp/__tests__/memory-server.test.d.ts.map +0 -1
  1088. package/dist/mcp/__tests__/memory-server.test.js +0 -36
  1089. package/dist/mcp/__tests__/memory-server.test.js.map +0 -1
  1090. package/dist/mcp/__tests__/memory-validation.test.d.ts +0 -2
  1091. package/dist/mcp/__tests__/memory-validation.test.d.ts.map +0 -1
  1092. package/dist/mcp/__tests__/memory-validation.test.js +0 -29
  1093. package/dist/mcp/__tests__/memory-validation.test.js.map +0 -1
  1094. package/dist/mcp/__tests__/path-traversal.test.d.ts +0 -2
  1095. package/dist/mcp/__tests__/path-traversal.test.d.ts.map +0 -1
  1096. package/dist/mcp/__tests__/path-traversal.test.js +0 -83
  1097. package/dist/mcp/__tests__/path-traversal.test.js.map +0 -1
  1098. package/dist/mcp/__tests__/server-lifecycle.test.d.ts +0 -2
  1099. package/dist/mcp/__tests__/server-lifecycle.test.d.ts.map +0 -1
  1100. package/dist/mcp/__tests__/server-lifecycle.test.js +0 -260
  1101. package/dist/mcp/__tests__/server-lifecycle.test.js.map +0 -1
  1102. package/dist/mcp/__tests__/state-paths.test.d.ts +0 -2
  1103. package/dist/mcp/__tests__/state-paths.test.d.ts.map +0 -1
  1104. package/dist/mcp/__tests__/state-paths.test.js +0 -209
  1105. package/dist/mcp/__tests__/state-paths.test.js.map +0 -1
  1106. package/dist/mcp/__tests__/state-server-ralph-phase.test.d.ts +0 -2
  1107. package/dist/mcp/__tests__/state-server-ralph-phase.test.d.ts.map +0 -1
  1108. package/dist/mcp/__tests__/state-server-ralph-phase.test.js +0 -109
  1109. package/dist/mcp/__tests__/state-server-ralph-phase.test.js.map +0 -1
  1110. package/dist/mcp/__tests__/state-server-schema.test.d.ts +0 -2
  1111. package/dist/mcp/__tests__/state-server-schema.test.d.ts.map +0 -1
  1112. package/dist/mcp/__tests__/state-server-schema.test.js +0 -29
  1113. package/dist/mcp/__tests__/state-server-schema.test.js.map +0 -1
  1114. package/dist/mcp/__tests__/state-server-team-tools.test.d.ts +0 -2
  1115. package/dist/mcp/__tests__/state-server-team-tools.test.d.ts.map +0 -1
  1116. package/dist/mcp/__tests__/state-server-team-tools.test.js +0 -35
  1117. package/dist/mcp/__tests__/state-server-team-tools.test.js.map +0 -1
  1118. package/dist/mcp/__tests__/state-server.test.d.ts +0 -2
  1119. package/dist/mcp/__tests__/state-server.test.d.ts.map +0 -1
  1120. package/dist/mcp/__tests__/state-server.test.js +0 -965
  1121. package/dist/mcp/__tests__/state-server.test.js.map +0 -1
  1122. package/dist/mcp/__tests__/trace-server.test.d.ts +0 -2
  1123. package/dist/mcp/__tests__/trace-server.test.d.ts.map +0 -1
  1124. package/dist/mcp/__tests__/trace-server.test.js +0 -119
  1125. package/dist/mcp/__tests__/trace-server.test.js.map +0 -1
  1126. package/dist/mcp/__tests__/wiki-server.test.d.ts +0 -2
  1127. package/dist/mcp/__tests__/wiki-server.test.d.ts.map +0 -1
  1128. package/dist/mcp/__tests__/wiki-server.test.js +0 -30
  1129. package/dist/mcp/__tests__/wiki-server.test.js.map +0 -1
  1130. package/dist/modes/__tests__/base-autoresearch-contract.test.d.ts +0 -2
  1131. package/dist/modes/__tests__/base-autoresearch-contract.test.d.ts.map +0 -1
  1132. package/dist/modes/__tests__/base-autoresearch-contract.test.js +0 -123
  1133. package/dist/modes/__tests__/base-autoresearch-contract.test.js.map +0 -1
  1134. package/dist/modes/__tests__/base-multi-state-compat.test.d.ts +0 -2
  1135. package/dist/modes/__tests__/base-multi-state-compat.test.d.ts.map +0 -1
  1136. package/dist/modes/__tests__/base-multi-state-compat.test.js +0 -38
  1137. package/dist/modes/__tests__/base-multi-state-compat.test.js.map +0 -1
  1138. package/dist/modes/__tests__/base-ralph-contract.test.d.ts +0 -2
  1139. package/dist/modes/__tests__/base-ralph-contract.test.d.ts.map +0 -1
  1140. package/dist/modes/__tests__/base-ralph-contract.test.js +0 -64
  1141. package/dist/modes/__tests__/base-ralph-contract.test.js.map +0 -1
  1142. package/dist/modes/__tests__/base-session-scope.test.d.ts +0 -2
  1143. package/dist/modes/__tests__/base-session-scope.test.d.ts.map +0 -1
  1144. package/dist/modes/__tests__/base-session-scope.test.js +0 -98
  1145. package/dist/modes/__tests__/base-session-scope.test.js.map +0 -1
  1146. package/dist/modes/__tests__/base-tmux-pane.test.d.ts +0 -2
  1147. package/dist/modes/__tests__/base-tmux-pane.test.d.ts.map +0 -1
  1148. package/dist/modes/__tests__/base-tmux-pane.test.js +0 -39
  1149. package/dist/modes/__tests__/base-tmux-pane.test.js.map +0 -1
  1150. package/dist/notifications/__tests__/config.test.d.ts +0 -2
  1151. package/dist/notifications/__tests__/config.test.d.ts.map +0 -1
  1152. package/dist/notifications/__tests__/config.test.js +0 -269
  1153. package/dist/notifications/__tests__/config.test.js.map +0 -1
  1154. package/dist/notifications/__tests__/custom-alias-enablement.test.d.ts +0 -2
  1155. package/dist/notifications/__tests__/custom-alias-enablement.test.d.ts.map +0 -1
  1156. package/dist/notifications/__tests__/custom-alias-enablement.test.js +0 -84
  1157. package/dist/notifications/__tests__/custom-alias-enablement.test.js.map +0 -1
  1158. package/dist/notifications/__tests__/dispatch-cooldown.test.d.ts +0 -5
  1159. package/dist/notifications/__tests__/dispatch-cooldown.test.d.ts.map +0 -1
  1160. package/dist/notifications/__tests__/dispatch-cooldown.test.js +0 -100
  1161. package/dist/notifications/__tests__/dispatch-cooldown.test.js.map +0 -1
  1162. package/dist/notifications/__tests__/dispatcher.test.d.ts +0 -2
  1163. package/dist/notifications/__tests__/dispatcher.test.d.ts.map +0 -1
  1164. package/dist/notifications/__tests__/dispatcher.test.js +0 -202
  1165. package/dist/notifications/__tests__/dispatcher.test.js.map +0 -1
  1166. package/dist/notifications/__tests__/formatter.test.d.ts +0 -2
  1167. package/dist/notifications/__tests__/formatter.test.d.ts.map +0 -1
  1168. package/dist/notifications/__tests__/formatter.test.js +0 -270
  1169. package/dist/notifications/__tests__/formatter.test.js.map +0 -1
  1170. package/dist/notifications/__tests__/hook-config.test.d.ts +0 -5
  1171. package/dist/notifications/__tests__/hook-config.test.d.ts.map +0 -1
  1172. package/dist/notifications/__tests__/hook-config.test.js +0 -139
  1173. package/dist/notifications/__tests__/hook-config.test.js.map +0 -1
  1174. package/dist/notifications/__tests__/idle-cooldown.test.d.ts +0 -5
  1175. package/dist/notifications/__tests__/idle-cooldown.test.d.ts.map +0 -1
  1176. package/dist/notifications/__tests__/idle-cooldown.test.js +0 -209
  1177. package/dist/notifications/__tests__/idle-cooldown.test.js.map +0 -1
  1178. package/dist/notifications/__tests__/index.test.d.ts +0 -2
  1179. package/dist/notifications/__tests__/index.test.d.ts.map +0 -1
  1180. package/dist/notifications/__tests__/index.test.js +0 -188
  1181. package/dist/notifications/__tests__/index.test.js.map +0 -1
  1182. package/dist/notifications/__tests__/lifecycle-dedupe.test.d.ts +0 -2
  1183. package/dist/notifications/__tests__/lifecycle-dedupe.test.d.ts.map +0 -1
  1184. package/dist/notifications/__tests__/lifecycle-dedupe.test.js +0 -86
  1185. package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +0 -1
  1186. package/dist/notifications/__tests__/notifier.test.d.ts +0 -2
  1187. package/dist/notifications/__tests__/notifier.test.d.ts.map +0 -1
  1188. package/dist/notifications/__tests__/notifier.test.js +0 -239
  1189. package/dist/notifications/__tests__/notifier.test.js.map +0 -1
  1190. package/dist/notifications/__tests__/profiles.test.d.ts +0 -2
  1191. package/dist/notifications/__tests__/profiles.test.d.ts.map +0 -1
  1192. package/dist/notifications/__tests__/profiles.test.js +0 -404
  1193. package/dist/notifications/__tests__/profiles.test.js.map +0 -1
  1194. package/dist/notifications/__tests__/reply-config.test.d.ts +0 -2
  1195. package/dist/notifications/__tests__/reply-config.test.d.ts.map +0 -1
  1196. package/dist/notifications/__tests__/reply-config.test.js +0 -79
  1197. package/dist/notifications/__tests__/reply-config.test.js.map +0 -1
  1198. package/dist/notifications/__tests__/reply-listener.test.d.ts +0 -2
  1199. package/dist/notifications/__tests__/reply-listener.test.d.ts.map +0 -1
  1200. package/dist/notifications/__tests__/reply-listener.test.js +0 -723
  1201. package/dist/notifications/__tests__/reply-listener.test.js.map +0 -1
  1202. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.d.ts +0 -2
  1203. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.d.ts.map +0 -1
  1204. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js +0 -93
  1205. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js.map +0 -1
  1206. package/dist/notifications/__tests__/session-registry.test.d.ts +0 -2
  1207. package/dist/notifications/__tests__/session-registry.test.d.ts.map +0 -1
  1208. package/dist/notifications/__tests__/session-registry.test.js +0 -234
  1209. package/dist/notifications/__tests__/session-registry.test.js.map +0 -1
  1210. package/dist/notifications/__tests__/session-status.test.d.ts +0 -2
  1211. package/dist/notifications/__tests__/session-status.test.d.ts.map +0 -1
  1212. package/dist/notifications/__tests__/session-status.test.js +0 -249
  1213. package/dist/notifications/__tests__/session-status.test.js.map +0 -1
  1214. package/dist/notifications/__tests__/temp-mode.test.d.ts +0 -2
  1215. package/dist/notifications/__tests__/temp-mode.test.d.ts.map +0 -1
  1216. package/dist/notifications/__tests__/temp-mode.test.js +0 -172
  1217. package/dist/notifications/__tests__/temp-mode.test.js.map +0 -1
  1218. package/dist/notifications/__tests__/template-engine.test.d.ts +0 -5
  1219. package/dist/notifications/__tests__/template-engine.test.d.ts.map +0 -1
  1220. package/dist/notifications/__tests__/template-engine.test.js +0 -158
  1221. package/dist/notifications/__tests__/template-engine.test.js.map +0 -1
  1222. package/dist/notifications/__tests__/tmux-detector.test.d.ts +0 -2
  1223. package/dist/notifications/__tests__/tmux-detector.test.d.ts.map +0 -1
  1224. package/dist/notifications/__tests__/tmux-detector.test.js +0 -208
  1225. package/dist/notifications/__tests__/tmux-detector.test.js.map +0 -1
  1226. package/dist/notifications/__tests__/tmux.test.d.ts +0 -2
  1227. package/dist/notifications/__tests__/tmux.test.d.ts.map +0 -1
  1228. package/dist/notifications/__tests__/tmux.test.js +0 -285
  1229. package/dist/notifications/__tests__/tmux.test.js.map +0 -1
  1230. package/dist/notifications/__tests__/verbosity.test.d.ts +0 -2
  1231. package/dist/notifications/__tests__/verbosity.test.d.ts.map +0 -1
  1232. package/dist/notifications/__tests__/verbosity.test.js +0 -237
  1233. package/dist/notifications/__tests__/verbosity.test.js.map +0 -1
  1234. package/dist/openclaw/__tests__/config.test.d.ts +0 -6
  1235. package/dist/openclaw/__tests__/config.test.d.ts.map +0 -1
  1236. package/dist/openclaw/__tests__/config.test.js +0 -344
  1237. package/dist/openclaw/__tests__/config.test.js.map +0 -1
  1238. package/dist/openclaw/__tests__/dispatcher.test.d.ts +0 -5
  1239. package/dist/openclaw/__tests__/dispatcher.test.d.ts.map +0 -1
  1240. package/dist/openclaw/__tests__/dispatcher.test.js +0 -169
  1241. package/dist/openclaw/__tests__/dispatcher.test.js.map +0 -1
  1242. package/dist/openclaw/__tests__/index.test.d.ts +0 -6
  1243. package/dist/openclaw/__tests__/index.test.d.ts.map +0 -1
  1244. package/dist/openclaw/__tests__/index.test.js +0 -382
  1245. package/dist/openclaw/__tests__/index.test.js.map +0 -1
  1246. package/dist/pipeline/__tests__/orchestrator.test.d.ts +0 -2
  1247. package/dist/pipeline/__tests__/orchestrator.test.d.ts.map +0 -1
  1248. package/dist/pipeline/__tests__/orchestrator.test.js +0 -505
  1249. package/dist/pipeline/__tests__/orchestrator.test.js.map +0 -1
  1250. package/dist/pipeline/__tests__/stages.test.d.ts +0 -2
  1251. package/dist/pipeline/__tests__/stages.test.d.ts.map +0 -1
  1252. package/dist/pipeline/__tests__/stages.test.js +0 -754
  1253. package/dist/pipeline/__tests__/stages.test.js.map +0 -1
  1254. package/dist/pipeline/stages/ralph-verify.d.ts +0 -53
  1255. package/dist/pipeline/stages/ralph-verify.d.ts.map +0 -1
  1256. package/dist/pipeline/stages/ralph-verify.js.map +0 -1
  1257. package/dist/pipeline/stages/ralplan.d.ts +0 -25
  1258. package/dist/pipeline/stages/ralplan.d.ts.map +0 -1
  1259. package/dist/pipeline/stages/ralplan.js.map +0 -1
  1260. package/dist/planning/__tests__/artifacts.test.d.ts +0 -2
  1261. package/dist/planning/__tests__/artifacts.test.d.ts.map +0 -1
  1262. package/dist/planning/__tests__/artifacts.test.js +0 -544
  1263. package/dist/planning/__tests__/artifacts.test.js.map +0 -1
  1264. package/dist/question/__tests__/client.test.d.ts +0 -2
  1265. package/dist/question/__tests__/client.test.d.ts.map +0 -1
  1266. package/dist/question/__tests__/client.test.js +0 -90
  1267. package/dist/question/__tests__/client.test.js.map +0 -1
  1268. package/dist/question/__tests__/deep-interview.test.d.ts +0 -2
  1269. package/dist/question/__tests__/deep-interview.test.d.ts.map +0 -1
  1270. package/dist/question/__tests__/deep-interview.test.js +0 -209
  1271. package/dist/question/__tests__/deep-interview.test.js.map +0 -1
  1272. package/dist/question/__tests__/policy.test.d.ts +0 -2
  1273. package/dist/question/__tests__/policy.test.d.ts.map +0 -1
  1274. package/dist/question/__tests__/policy.test.js +0 -107
  1275. package/dist/question/__tests__/policy.test.js.map +0 -1
  1276. package/dist/question/__tests__/renderer.test.d.ts +0 -2
  1277. package/dist/question/__tests__/renderer.test.d.ts.map +0 -1
  1278. package/dist/question/__tests__/renderer.test.js +0 -707
  1279. package/dist/question/__tests__/renderer.test.js.map +0 -1
  1280. package/dist/question/__tests__/state.test.d.ts +0 -2
  1281. package/dist/question/__tests__/state.test.d.ts.map +0 -1
  1282. package/dist/question/__tests__/state.test.js +0 -102
  1283. package/dist/question/__tests__/state.test.js.map +0 -1
  1284. package/dist/question/__tests__/types.test.d.ts +0 -2
  1285. package/dist/question/__tests__/types.test.d.ts.map +0 -1
  1286. package/dist/question/__tests__/types.test.js +0 -65
  1287. package/dist/question/__tests__/types.test.js.map +0 -1
  1288. package/dist/question/__tests__/ui.test.d.ts +0 -2
  1289. package/dist/question/__tests__/ui.test.d.ts.map +0 -1
  1290. package/dist/question/__tests__/ui.test.js +0 -446
  1291. package/dist/question/__tests__/ui.test.js.map +0 -1
  1292. package/dist/ralph/__tests__/persistence.test.d.ts +0 -2
  1293. package/dist/ralph/__tests__/persistence.test.d.ts.map +0 -1
  1294. package/dist/ralph/__tests__/persistence.test.js +0 -116
  1295. package/dist/ralph/__tests__/persistence.test.js.map +0 -1
  1296. package/dist/ralph/contract.d.ts +0 -17
  1297. package/dist/ralph/persistence.js.map +0 -1
  1298. package/dist/ralplan/__tests__/runtime.test.d.ts +0 -2
  1299. package/dist/ralplan/__tests__/runtime.test.d.ts.map +0 -1
  1300. package/dist/ralplan/__tests__/runtime.test.js +0 -165
  1301. package/dist/ralplan/__tests__/runtime.test.js.map +0 -1
  1302. package/dist/ralplan/runtime.d.ts +0 -52
  1303. package/dist/ralplan/runtime.d.ts.map +0 -1
  1304. package/dist/ralplan/runtime.js.map +0 -1
  1305. package/dist/runtime/__tests__/bridge.test.d.ts +0 -2
  1306. package/dist/runtime/__tests__/bridge.test.d.ts.map +0 -1
  1307. package/dist/runtime/__tests__/bridge.test.js +0 -194
  1308. package/dist/runtime/__tests__/bridge.test.js.map +0 -1
  1309. package/dist/runtime/__tests__/run-loop.test.d.ts +0 -2
  1310. package/dist/runtime/__tests__/run-loop.test.d.ts.map +0 -1
  1311. package/dist/runtime/__tests__/run-loop.test.js +0 -35
  1312. package/dist/runtime/__tests__/run-loop.test.js.map +0 -1
  1313. package/dist/runtime/__tests__/run-outcome.test.d.ts +0 -2
  1314. package/dist/runtime/__tests__/run-outcome.test.d.ts.map +0 -1
  1315. package/dist/runtime/__tests__/run-outcome.test.js +0 -102
  1316. package/dist/runtime/__tests__/run-outcome.test.js.map +0 -1
  1317. package/dist/runtime/__tests__/run-state.test.d.ts +0 -2
  1318. package/dist/runtime/__tests__/run-state.test.d.ts.map +0 -1
  1319. package/dist/runtime/__tests__/run-state.test.js +0 -37
  1320. package/dist/runtime/__tests__/run-state.test.js.map +0 -1
  1321. package/dist/scripts/__tests__/codex-native-hook.test.d.ts +0 -2
  1322. package/dist/scripts/__tests__/codex-native-hook.test.d.ts.map +0 -1
  1323. package/dist/scripts/__tests__/codex-native-hook.test.js +0 -6788
  1324. package/dist/scripts/__tests__/codex-native-hook.test.js.map +0 -1
  1325. package/dist/scripts/__tests__/generate-release-body.test.d.ts +0 -2
  1326. package/dist/scripts/__tests__/generate-release-body.test.d.ts.map +0 -1
  1327. package/dist/scripts/__tests__/generate-release-body.test.js +0 -233
  1328. package/dist/scripts/__tests__/generate-release-body.test.js.map +0 -1
  1329. package/dist/scripts/__tests__/hook-derived-watcher.test.d.ts +0 -2
  1330. package/dist/scripts/__tests__/hook-derived-watcher.test.d.ts.map +0 -1
  1331. package/dist/scripts/__tests__/hook-derived-watcher.test.js +0 -195
  1332. package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +0 -1
  1333. package/dist/scripts/__tests__/postinstall.test.d.ts +0 -2
  1334. package/dist/scripts/__tests__/postinstall.test.d.ts.map +0 -1
  1335. package/dist/scripts/__tests__/postinstall.test.js +0 -92
  1336. package/dist/scripts/__tests__/postinstall.test.js.map +0 -1
  1337. package/dist/scripts/__tests__/prompt-inventory.test.d.ts +0 -2
  1338. package/dist/scripts/__tests__/prompt-inventory.test.d.ts.map +0 -1
  1339. package/dist/scripts/__tests__/prompt-inventory.test.js +0 -56
  1340. package/dist/scripts/__tests__/prompt-inventory.test.js.map +0 -1
  1341. package/dist/scripts/__tests__/run-test-files.test.d.ts +0 -2
  1342. package/dist/scripts/__tests__/run-test-files.test.d.ts.map +0 -1
  1343. package/dist/scripts/__tests__/run-test-files.test.js +0 -62
  1344. package/dist/scripts/__tests__/run-test-files.test.js.map +0 -1
  1345. package/dist/scripts/__tests__/smoke-packed-install.test.d.ts +0 -2
  1346. package/dist/scripts/__tests__/smoke-packed-install.test.d.ts.map +0 -1
  1347. package/dist/scripts/__tests__/smoke-packed-install.test.js +0 -135
  1348. package/dist/scripts/__tests__/smoke-packed-install.test.js.map +0 -1
  1349. package/dist/scripts/__tests__/test-reply-listener-live.test.d.ts +0 -2
  1350. package/dist/scripts/__tests__/test-reply-listener-live.test.d.ts.map +0 -1
  1351. package/dist/scripts/__tests__/test-reply-listener-live.test.js +0 -82
  1352. package/dist/scripts/__tests__/test-reply-listener-live.test.js.map +0 -1
  1353. package/dist/scripts/__tests__/verify-native-agents.test.d.ts +0 -2
  1354. package/dist/scripts/__tests__/verify-native-agents.test.d.ts.map +0 -1
  1355. package/dist/scripts/__tests__/verify-native-agents.test.js +0 -166
  1356. package/dist/scripts/__tests__/verify-native-agents.test.js.map +0 -1
  1357. package/dist/scripts/eval/eval-candidate-handoff.d.ts +0 -2
  1358. package/dist/scripts/eval/eval-candidate-handoff.d.ts.map +0 -1
  1359. package/dist/scripts/eval/eval-candidate-handoff.js +0 -11
  1360. package/dist/scripts/eval/eval-candidate-handoff.js.map +0 -1
  1361. package/dist/scripts/eval/eval-cli-discoverability.d.ts +0 -3
  1362. package/dist/scripts/eval/eval-cli-discoverability.d.ts.map +0 -1
  1363. package/dist/scripts/eval/eval-cli-discoverability.js +0 -37
  1364. package/dist/scripts/eval/eval-cli-discoverability.js.map +0 -1
  1365. package/dist/scripts/eval/eval-fresh-run-tagging.d.ts +0 -2
  1366. package/dist/scripts/eval/eval-fresh-run-tagging.d.ts.map +0 -1
  1367. package/dist/scripts/eval/eval-fresh-run-tagging.js +0 -11
  1368. package/dist/scripts/eval/eval-fresh-run-tagging.js.map +0 -1
  1369. package/dist/scripts/eval/eval-help-consistency.d.ts +0 -2
  1370. package/dist/scripts/eval/eval-help-consistency.d.ts.map +0 -1
  1371. package/dist/scripts/eval/eval-help-consistency.js +0 -12
  1372. package/dist/scripts/eval/eval-help-consistency.js.map +0 -1
  1373. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.d.ts +0 -2
  1374. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.d.ts.map +0 -1
  1375. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.js +0 -31
  1376. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.js.map +0 -1
  1377. package/dist/scripts/eval/eval-parity-smoke.d.ts +0 -2
  1378. package/dist/scripts/eval/eval-parity-smoke.d.ts.map +0 -1
  1379. package/dist/scripts/eval/eval-parity-smoke.js +0 -23
  1380. package/dist/scripts/eval/eval-parity-smoke.js.map +0 -1
  1381. package/dist/scripts/eval/eval-parity-sweep.d.ts +0 -2
  1382. package/dist/scripts/eval/eval-parity-sweep.d.ts.map +0 -1
  1383. package/dist/scripts/eval/eval-parity-sweep.js +0 -29
  1384. package/dist/scripts/eval/eval-parity-sweep.js.map +0 -1
  1385. package/dist/scripts/eval/eval-resume-dirty-guard.d.ts +0 -2
  1386. package/dist/scripts/eval/eval-resume-dirty-guard.d.ts.map +0 -1
  1387. package/dist/scripts/eval/eval-resume-dirty-guard.js +0 -11
  1388. package/dist/scripts/eval/eval-resume-dirty-guard.js.map +0 -1
  1389. package/dist/scripts/eval/eval-security-path-traversal.d.ts +0 -3
  1390. package/dist/scripts/eval/eval-security-path-traversal.d.ts.map +0 -1
  1391. package/dist/scripts/eval/eval-security-path-traversal.js +0 -35
  1392. package/dist/scripts/eval/eval-security-path-traversal.js.map +0 -1
  1393. package/dist/scripts/notify-hook/__tests__/operational-events.test.d.ts +0 -2
  1394. package/dist/scripts/notify-hook/__tests__/operational-events.test.d.ts.map +0 -1
  1395. package/dist/scripts/notify-hook/__tests__/operational-events.test.js +0 -24
  1396. package/dist/scripts/notify-hook/__tests__/operational-events.test.js.map +0 -1
  1397. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts +0 -2
  1398. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts.map +0 -1
  1399. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js +0 -153
  1400. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js.map +0 -1
  1401. package/dist/scripts/notify-hook/ralph-session-resume.d.ts +0 -22
  1402. package/dist/session-history/__tests__/search.test.d.ts +0 -2
  1403. package/dist/session-history/__tests__/search.test.d.ts.map +0 -1
  1404. package/dist/session-history/__tests__/search.test.js +0 -150
  1405. package/dist/session-history/__tests__/search.test.js.map +0 -1
  1406. package/dist/sidecar/__tests__/boundary.test.d.ts +0 -2
  1407. package/dist/sidecar/__tests__/boundary.test.d.ts.map +0 -1
  1408. package/dist/sidecar/__tests__/boundary.test.js +0 -48
  1409. package/dist/sidecar/__tests__/boundary.test.js.map +0 -1
  1410. package/dist/sidecar/__tests__/collector.test.d.ts +0 -2
  1411. package/dist/sidecar/__tests__/collector.test.d.ts.map +0 -1
  1412. package/dist/sidecar/__tests__/collector.test.js +0 -162
  1413. package/dist/sidecar/__tests__/collector.test.js.map +0 -1
  1414. package/dist/sidecar/__tests__/render.test.d.ts +0 -2
  1415. package/dist/sidecar/__tests__/render.test.d.ts.map +0 -1
  1416. package/dist/sidecar/__tests__/render.test.js +0 -67
  1417. package/dist/sidecar/__tests__/render.test.js.map +0 -1
  1418. package/dist/sidecar/__tests__/tmux.test.d.ts +0 -2
  1419. package/dist/sidecar/__tests__/tmux.test.d.ts.map +0 -1
  1420. package/dist/sidecar/__tests__/tmux.test.js +0 -30
  1421. package/dist/sidecar/__tests__/tmux.test.js.map +0 -1
  1422. package/dist/sidecar/__tests__/watch.test.d.ts +0 -2
  1423. package/dist/sidecar/__tests__/watch.test.d.ts.map +0 -1
  1424. package/dist/sidecar/__tests__/watch.test.js +0 -42
  1425. package/dist/sidecar/__tests__/watch.test.js.map +0 -1
  1426. package/dist/state/__tests__/mode-state-context.test.d.ts +0 -2
  1427. package/dist/state/__tests__/mode-state-context.test.d.ts.map +0 -1
  1428. package/dist/state/__tests__/mode-state-context.test.js +0 -35
  1429. package/dist/state/__tests__/mode-state-context.test.js.map +0 -1
  1430. package/dist/state/__tests__/operations-ralph-phase.test.d.ts +0 -2
  1431. package/dist/state/__tests__/operations-ralph-phase.test.d.ts.map +0 -1
  1432. package/dist/state/__tests__/operations-ralph-phase.test.js +0 -103
  1433. package/dist/state/__tests__/operations-ralph-phase.test.js.map +0 -1
  1434. package/dist/state/__tests__/operations.test.d.ts +0 -2
  1435. package/dist/state/__tests__/operations.test.d.ts.map +0 -1
  1436. package/dist/state/__tests__/operations.test.js +0 -439
  1437. package/dist/state/__tests__/operations.test.js.map +0 -1
  1438. package/dist/state/__tests__/path-traversal.test.d.ts +0 -2
  1439. package/dist/state/__tests__/path-traversal.test.d.ts.map +0 -1
  1440. package/dist/state/__tests__/path-traversal.test.js +0 -49
  1441. package/dist/state/__tests__/path-traversal.test.js.map +0 -1
  1442. package/dist/state/__tests__/skill-active.test.d.ts +0 -2
  1443. package/dist/state/__tests__/skill-active.test.d.ts.map +0 -1
  1444. package/dist/state/__tests__/skill-active.test.js +0 -160
  1445. package/dist/state/__tests__/skill-active.test.js.map +0 -1
  1446. package/dist/state/__tests__/workflow-transition.test.d.ts +0 -2
  1447. package/dist/state/__tests__/workflow-transition.test.d.ts.map +0 -1
  1448. package/dist/state/__tests__/workflow-transition.test.js +0 -77
  1449. package/dist/state/__tests__/workflow-transition.test.js.map +0 -1
  1450. package/dist/subagents/__tests__/tracker.test.d.ts +0 -2
  1451. package/dist/subagents/__tests__/tracker.test.d.ts.map +0 -1
  1452. package/dist/subagents/__tests__/tracker.test.js +0 -47
  1453. package/dist/subagents/__tests__/tracker.test.js.map +0 -1
  1454. package/dist/team/__tests__/allocation-policy.test.d.ts +0 -2
  1455. package/dist/team/__tests__/allocation-policy.test.d.ts.map +0 -1
  1456. package/dist/team/__tests__/allocation-policy.test.js +0 -111
  1457. package/dist/team/__tests__/allocation-policy.test.js.map +0 -1
  1458. package/dist/team/__tests__/api-interop.test.d.ts +0 -2
  1459. package/dist/team/__tests__/api-interop.test.d.ts.map +0 -1
  1460. package/dist/team/__tests__/api-interop.test.js +0 -2262
  1461. package/dist/team/__tests__/api-interop.test.js.map +0 -1
  1462. package/dist/team/__tests__/commit-hygiene.test.d.ts +0 -2
  1463. package/dist/team/__tests__/commit-hygiene.test.d.ts.map +0 -1
  1464. package/dist/team/__tests__/commit-hygiene.test.js +0 -93
  1465. package/dist/team/__tests__/commit-hygiene.test.js.map +0 -1
  1466. package/dist/team/__tests__/cross-rebase-smoke.test.d.ts +0 -2
  1467. package/dist/team/__tests__/cross-rebase-smoke.test.d.ts.map +0 -1
  1468. package/dist/team/__tests__/cross-rebase-smoke.test.js +0 -161
  1469. package/dist/team/__tests__/cross-rebase-smoke.test.js.map +0 -1
  1470. package/dist/team/__tests__/current-task-baseline.test.d.ts +0 -2
  1471. package/dist/team/__tests__/current-task-baseline.test.d.ts.map +0 -1
  1472. package/dist/team/__tests__/current-task-baseline.test.js +0 -87
  1473. package/dist/team/__tests__/current-task-baseline.test.js.map +0 -1
  1474. package/dist/team/__tests__/delegation-policy.test.d.ts +0 -2
  1475. package/dist/team/__tests__/delegation-policy.test.d.ts.map +0 -1
  1476. package/dist/team/__tests__/delegation-policy.test.js +0 -69
  1477. package/dist/team/__tests__/delegation-policy.test.js.map +0 -1
  1478. package/dist/team/__tests__/delivery-e2e-smoke.test.d.ts +0 -2
  1479. package/dist/team/__tests__/delivery-e2e-smoke.test.d.ts.map +0 -1
  1480. package/dist/team/__tests__/delivery-e2e-smoke.test.js +0 -679
  1481. package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +0 -1
  1482. package/dist/team/__tests__/events.test.d.ts +0 -2
  1483. package/dist/team/__tests__/events.test.d.ts.map +0 -1
  1484. package/dist/team/__tests__/events.test.js +0 -313
  1485. package/dist/team/__tests__/events.test.js.map +0 -1
  1486. package/dist/team/__tests__/followup-planner.test.d.ts +0 -2
  1487. package/dist/team/__tests__/followup-planner.test.d.ts.map +0 -1
  1488. package/dist/team/__tests__/followup-planner.test.js +0 -84
  1489. package/dist/team/__tests__/followup-planner.test.js.map +0 -1
  1490. package/dist/team/__tests__/hardening-e2e.test.d.ts +0 -2
  1491. package/dist/team/__tests__/hardening-e2e.test.d.ts.map +0 -1
  1492. package/dist/team/__tests__/hardening-e2e.test.js +0 -98
  1493. package/dist/team/__tests__/hardening-e2e.test.js.map +0 -1
  1494. package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts +0 -2
  1495. package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts.map +0 -1
  1496. package/dist/team/__tests__/hook-primary-e2e-contract.test.js +0 -78
  1497. package/dist/team/__tests__/hook-primary-e2e-contract.test.js.map +0 -1
  1498. package/dist/team/__tests__/idle-nudge.test.d.ts +0 -2
  1499. package/dist/team/__tests__/idle-nudge.test.d.ts.map +0 -1
  1500. package/dist/team/__tests__/idle-nudge.test.js +0 -230
  1501. package/dist/team/__tests__/idle-nudge.test.js.map +0 -1
  1502. package/dist/team/__tests__/leader-activity.test.d.ts +0 -2
  1503. package/dist/team/__tests__/leader-activity.test.d.ts.map +0 -1
  1504. package/dist/team/__tests__/leader-activity.test.js +0 -261
  1505. package/dist/team/__tests__/leader-activity.test.js.map +0 -1
  1506. package/dist/team/__tests__/mcp-comm.test.d.ts +0 -2
  1507. package/dist/team/__tests__/mcp-comm.test.d.ts.map +0 -1
  1508. package/dist/team/__tests__/mcp-comm.test.js +0 -289
  1509. package/dist/team/__tests__/mcp-comm.test.js.map +0 -1
  1510. package/dist/team/__tests__/model-contract.test.d.ts +0 -2
  1511. package/dist/team/__tests__/model-contract.test.d.ts.map +0 -1
  1512. package/dist/team/__tests__/model-contract.test.js +0 -171
  1513. package/dist/team/__tests__/model-contract.test.js.map +0 -1
  1514. package/dist/team/__tests__/orchestrator.test.d.ts +0 -2
  1515. package/dist/team/__tests__/orchestrator.test.d.ts.map +0 -1
  1516. package/dist/team/__tests__/orchestrator.test.js +0 -111
  1517. package/dist/team/__tests__/orchestrator.test.js.map +0 -1
  1518. package/dist/team/__tests__/phase-controller.test.d.ts +0 -2
  1519. package/dist/team/__tests__/phase-controller.test.d.ts.map +0 -1
  1520. package/dist/team/__tests__/phase-controller.test.js +0 -50
  1521. package/dist/team/__tests__/phase-controller.test.js.map +0 -1
  1522. package/dist/team/__tests__/rebalance-policy.test.d.ts +0 -2
  1523. package/dist/team/__tests__/rebalance-policy.test.d.ts.map +0 -1
  1524. package/dist/team/__tests__/rebalance-policy.test.js +0 -168
  1525. package/dist/team/__tests__/rebalance-policy.test.js.map +0 -1
  1526. package/dist/team/__tests__/repo-aware-decomposition.test.d.ts +0 -2
  1527. package/dist/team/__tests__/repo-aware-decomposition.test.d.ts.map +0 -1
  1528. package/dist/team/__tests__/repo-aware-decomposition.test.js +0 -136
  1529. package/dist/team/__tests__/repo-aware-decomposition.test.js.map +0 -1
  1530. package/dist/team/__tests__/role-router.test.d.ts +0 -2
  1531. package/dist/team/__tests__/role-router.test.d.ts.map +0 -1
  1532. package/dist/team/__tests__/role-router.test.js +0 -263
  1533. package/dist/team/__tests__/role-router.test.js.map +0 -1
  1534. package/dist/team/__tests__/runtime-cli.test.d.ts +0 -2
  1535. package/dist/team/__tests__/runtime-cli.test.d.ts.map +0 -1
  1536. package/dist/team/__tests__/runtime-cli.test.js +0 -304
  1537. package/dist/team/__tests__/runtime-cli.test.js.map +0 -1
  1538. package/dist/team/__tests__/runtime.test.d.ts +0 -2
  1539. package/dist/team/__tests__/runtime.test.d.ts.map +0 -1
  1540. package/dist/team/__tests__/runtime.test.js +0 -5734
  1541. package/dist/team/__tests__/runtime.test.js.map +0 -1
  1542. package/dist/team/__tests__/scaling.test.d.ts +0 -2
  1543. package/dist/team/__tests__/scaling.test.d.ts.map +0 -1
  1544. package/dist/team/__tests__/scaling.test.js +0 -1005
  1545. package/dist/team/__tests__/scaling.test.js.map +0 -1
  1546. package/dist/team/__tests__/shutdown-fallback.test.d.ts +0 -2
  1547. package/dist/team/__tests__/shutdown-fallback.test.d.ts.map +0 -1
  1548. package/dist/team/__tests__/shutdown-fallback.test.js +0 -125
  1549. package/dist/team/__tests__/shutdown-fallback.test.js.map +0 -1
  1550. package/dist/team/__tests__/state-root.test.d.ts +0 -2
  1551. package/dist/team/__tests__/state-root.test.d.ts.map +0 -1
  1552. package/dist/team/__tests__/state-root.test.js +0 -195
  1553. package/dist/team/__tests__/state-root.test.js.map +0 -1
  1554. package/dist/team/__tests__/state.test.d.ts +0 -2
  1555. package/dist/team/__tests__/state.test.d.ts.map +0 -1
  1556. package/dist/team/__tests__/state.test.js +0 -1859
  1557. package/dist/team/__tests__/state.test.js.map +0 -1
  1558. package/dist/team/__tests__/team-identity.test.d.ts +0 -2
  1559. package/dist/team/__tests__/team-identity.test.d.ts.map +0 -1
  1560. package/dist/team/__tests__/team-identity.test.js +0 -166
  1561. package/dist/team/__tests__/team-identity.test.js.map +0 -1
  1562. package/dist/team/__tests__/team-ops-contract.test.d.ts +0 -2
  1563. package/dist/team/__tests__/team-ops-contract.test.d.ts.map +0 -1
  1564. package/dist/team/__tests__/team-ops-contract.test.js +0 -96
  1565. package/dist/team/__tests__/team-ops-contract.test.js.map +0 -1
  1566. package/dist/team/__tests__/tmux-claude-workers-demo.test.d.ts +0 -2
  1567. package/dist/team/__tests__/tmux-claude-workers-demo.test.d.ts.map +0 -1
  1568. package/dist/team/__tests__/tmux-claude-workers-demo.test.js +0 -191
  1569. package/dist/team/__tests__/tmux-claude-workers-demo.test.js.map +0 -1
  1570. package/dist/team/__tests__/tmux-session.test.d.ts +0 -2
  1571. package/dist/team/__tests__/tmux-session.test.d.ts.map +0 -1
  1572. package/dist/team/__tests__/tmux-session.test.js +0 -3785
  1573. package/dist/team/__tests__/tmux-session.test.js.map +0 -1
  1574. package/dist/team/__tests__/tmux-test-fixture.d.ts +0 -20
  1575. package/dist/team/__tests__/tmux-test-fixture.d.ts.map +0 -1
  1576. package/dist/team/__tests__/tmux-test-fixture.js +0 -152
  1577. package/dist/team/__tests__/tmux-test-fixture.js.map +0 -1
  1578. package/dist/team/__tests__/tmux-test-fixture.test.d.ts +0 -2
  1579. package/dist/team/__tests__/tmux-test-fixture.test.d.ts.map +0 -1
  1580. package/dist/team/__tests__/tmux-test-fixture.test.js +0 -113
  1581. package/dist/team/__tests__/tmux-test-fixture.test.js.map +0 -1
  1582. package/dist/team/__tests__/worker-bootstrap.test.d.ts +0 -2
  1583. package/dist/team/__tests__/worker-bootstrap.test.d.ts.map +0 -1
  1584. package/dist/team/__tests__/worker-bootstrap.test.js +0 -685
  1585. package/dist/team/__tests__/worker-bootstrap.test.js.map +0 -1
  1586. package/dist/team/__tests__/worker-runtime-identity.test.d.ts +0 -2
  1587. package/dist/team/__tests__/worker-runtime-identity.test.d.ts.map +0 -1
  1588. package/dist/team/__tests__/worker-runtime-identity.test.js +0 -250
  1589. package/dist/team/__tests__/worker-runtime-identity.test.js.map +0 -1
  1590. package/dist/team/__tests__/worktree.test.d.ts +0 -2
  1591. package/dist/team/__tests__/worktree.test.d.ts.map +0 -1
  1592. package/dist/team/__tests__/worktree.test.js +0 -317
  1593. package/dist/team/__tests__/worktree.test.js.map +0 -1
  1594. package/dist/utils/__tests__/agents-md.test.d.ts +0 -2
  1595. package/dist/utils/__tests__/agents-md.test.d.ts.map +0 -1
  1596. package/dist/utils/__tests__/agents-md.test.js +0 -52
  1597. package/dist/utils/__tests__/agents-md.test.js.map +0 -1
  1598. package/dist/utils/__tests__/agents-model-table.test.d.ts +0 -2
  1599. package/dist/utils/__tests__/agents-model-table.test.d.ts.map +0 -1
  1600. package/dist/utils/__tests__/agents-model-table.test.js +0 -104
  1601. package/dist/utils/__tests__/agents-model-table.test.js.map +0 -1
  1602. package/dist/utils/__tests__/dep-versions.test.d.ts +0 -2
  1603. package/dist/utils/__tests__/dep-versions.test.d.ts.map +0 -1
  1604. package/dist/utils/__tests__/dep-versions.test.js +0 -46
  1605. package/dist/utils/__tests__/dep-versions.test.js.map +0 -1
  1606. package/dist/utils/__tests__/package.test.d.ts +0 -2
  1607. package/dist/utils/__tests__/package.test.d.ts.map +0 -1
  1608. package/dist/utils/__tests__/package.test.js +0 -21
  1609. package/dist/utils/__tests__/package.test.js.map +0 -1
  1610. package/dist/utils/__tests__/paths.test.d.ts +0 -2
  1611. package/dist/utils/__tests__/paths.test.d.ts.map +0 -1
  1612. package/dist/utils/__tests__/paths.test.js +0 -541
  1613. package/dist/utils/__tests__/paths.test.js.map +0 -1
  1614. package/dist/utils/__tests__/platform-command.test.d.ts +0 -2
  1615. package/dist/utils/__tests__/platform-command.test.d.ts.map +0 -1
  1616. package/dist/utils/__tests__/platform-command.test.js +0 -410
  1617. package/dist/utils/__tests__/platform-command.test.js.map +0 -1
  1618. package/dist/utils/__tests__/repo-deps.test.d.ts +0 -2
  1619. package/dist/utils/__tests__/repo-deps.test.d.ts.map +0 -1
  1620. package/dist/utils/__tests__/repo-deps.test.js +0 -71
  1621. package/dist/utils/__tests__/repo-deps.test.js.map +0 -1
  1622. package/dist/verification/__tests__/ci-rust-gates.test.d.ts +0 -2
  1623. package/dist/verification/__tests__/ci-rust-gates.test.d.ts.map +0 -1
  1624. package/dist/verification/__tests__/ci-rust-gates.test.js +0 -89
  1625. package/dist/verification/__tests__/ci-rust-gates.test.js.map +0 -1
  1626. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.d.ts +0 -2
  1627. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.d.ts.map +0 -1
  1628. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +0 -54
  1629. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +0 -1
  1630. package/dist/verification/__tests__/explore-harness-release-workflow.test.d.ts +0 -2
  1631. package/dist/verification/__tests__/explore-harness-release-workflow.test.d.ts.map +0 -1
  1632. package/dist/verification/__tests__/explore-harness-release-workflow.test.js +0 -73
  1633. package/dist/verification/__tests__/explore-harness-release-workflow.test.js.map +0 -1
  1634. package/dist/verification/__tests__/native-release-manifest.test.d.ts +0 -2
  1635. package/dist/verification/__tests__/native-release-manifest.test.d.ts.map +0 -1
  1636. package/dist/verification/__tests__/native-release-manifest.test.js +0 -80
  1637. package/dist/verification/__tests__/native-release-manifest.test.js.map +0 -1
  1638. package/dist/verification/__tests__/pr-check-workflow.test.d.ts +0 -2
  1639. package/dist/verification/__tests__/pr-check-workflow.test.d.ts.map +0 -1
  1640. package/dist/verification/__tests__/pr-check-workflow.test.js +0 -27
  1641. package/dist/verification/__tests__/pr-check-workflow.test.js.map +0 -1
  1642. package/dist/verification/__tests__/ralph-persistence-gate.test.d.ts +0 -2
  1643. package/dist/verification/__tests__/ralph-persistence-gate.test.d.ts.map +0 -1
  1644. package/dist/verification/__tests__/ralph-persistence-gate.test.js +0 -55
  1645. package/dist/verification/__tests__/ralph-persistence-gate.test.js.map +0 -1
  1646. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.d.ts +0 -2
  1647. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.d.ts.map +0 -1
  1648. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.js +0 -32
  1649. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.js.map +0 -1
  1650. package/dist/verification/__tests__/verifier.test.d.ts +0 -2
  1651. package/dist/verification/__tests__/verifier.test.d.ts.map +0 -1
  1652. package/dist/verification/__tests__/verifier.test.js +0 -113
  1653. package/dist/verification/__tests__/verifier.test.js.map +0 -1
  1654. package/dist/visual/__tests__/verdict.test.d.ts +0 -2
  1655. package/dist/visual/__tests__/verdict.test.d.ts.map +0 -1
  1656. package/dist/visual/__tests__/verdict.test.js +0 -81
  1657. package/dist/visual/__tests__/verdict.test.js.map +0 -1
  1658. package/dist/wiki/__tests__/cjk-tokenize.test.d.ts +0 -12
  1659. package/dist/wiki/__tests__/cjk-tokenize.test.d.ts.map +0 -1
  1660. package/dist/wiki/__tests__/cjk-tokenize.test.js +0 -139
  1661. package/dist/wiki/__tests__/cjk-tokenize.test.js.map +0 -1
  1662. package/dist/wiki/__tests__/crlf-parse.test.d.ts +0 -2
  1663. package/dist/wiki/__tests__/crlf-parse.test.d.ts.map +0 -1
  1664. package/dist/wiki/__tests__/crlf-parse.test.js +0 -24
  1665. package/dist/wiki/__tests__/crlf-parse.test.js.map +0 -1
  1666. package/dist/wiki/__tests__/escape-newline.test.d.ts +0 -2
  1667. package/dist/wiki/__tests__/escape-newline.test.d.ts.map +0 -1
  1668. package/dist/wiki/__tests__/escape-newline.test.js +0 -45
  1669. package/dist/wiki/__tests__/escape-newline.test.js.map +0 -1
  1670. package/dist/wiki/__tests__/ingest.test.d.ts +0 -5
  1671. package/dist/wiki/__tests__/ingest.test.d.ts.map +0 -1
  1672. package/dist/wiki/__tests__/ingest.test.js +0 -181
  1673. package/dist/wiki/__tests__/ingest.test.js.map +0 -1
  1674. package/dist/wiki/__tests__/lint.test.d.ts +0 -5
  1675. package/dist/wiki/__tests__/lint.test.d.ts.map +0 -1
  1676. package/dist/wiki/__tests__/lint.test.js +0 -163
  1677. package/dist/wiki/__tests__/lint.test.js.map +0 -1
  1678. package/dist/wiki/__tests__/query.test.d.ts +0 -5
  1679. package/dist/wiki/__tests__/query.test.d.ts.map +0 -1
  1680. package/dist/wiki/__tests__/query.test.js +0 -141
  1681. package/dist/wiki/__tests__/query.test.js.map +0 -1
  1682. package/dist/wiki/__tests__/reserved-file-guard.test.d.ts +0 -2
  1683. package/dist/wiki/__tests__/reserved-file-guard.test.d.ts.map +0 -1
  1684. package/dist/wiki/__tests__/reserved-file-guard.test.js +0 -44
  1685. package/dist/wiki/__tests__/reserved-file-guard.test.js.map +0 -1
  1686. package/dist/wiki/__tests__/session-hooks.test.d.ts +0 -5
  1687. package/dist/wiki/__tests__/session-hooks.test.d.ts.map +0 -1
  1688. package/dist/wiki/__tests__/session-hooks.test.js +0 -36
  1689. package/dist/wiki/__tests__/session-hooks.test.js.map +0 -1
  1690. package/dist/wiki/__tests__/slug-nonascii.test.d.ts +0 -2
  1691. package/dist/wiki/__tests__/slug-nonascii.test.d.ts.map +0 -1
  1692. package/dist/wiki/__tests__/slug-nonascii.test.js +0 -30
  1693. package/dist/wiki/__tests__/slug-nonascii.test.js.map +0 -1
  1694. package/dist/wiki/__tests__/storage.test.d.ts +0 -5
  1695. package/dist/wiki/__tests__/storage.test.d.ts.map +0 -1
  1696. package/dist/wiki/__tests__/storage.test.js +0 -278
  1697. package/dist/wiki/__tests__/storage.test.js.map +0 -1
  1698. package/dist/wiki/__tests__/test-helpers.d.ts +0 -31
  1699. package/dist/wiki/__tests__/test-helpers.d.ts.map +0 -1
  1700. package/dist/wiki/__tests__/test-helpers.js +0 -108
  1701. package/dist/wiki/__tests__/test-helpers.js.map +0 -1
  1702. package/docs/contracts/ralph-cancel-contract.md +0 -23
  1703. package/docs/contracts/ralph-state-contract.md +0 -95
  1704. package/docs/issues/team-ralph-followup-team.md +0 -38
  1705. package/docs/qa/ralph-persistence-gate.md +0 -59
  1706. package/docs/reference/ralph-parity-matrix.md +0 -25
  1707. package/docs/reference/ralph-upstream-baseline.md +0 -34
  1708. package/plugins/roblox-ai-os-creator-skills/skills/ralph/SKILL.md +0 -269
  1709. package/plugins/roblox-ai-os-creator-skills/skills/ralplan/SKILL.md +0 -162
  1710. package/prompts/api-reviewer.md +0 -113
  1711. package/prompts/information-architect.md +0 -226
  1712. package/prompts/performance-reviewer.md +0 -109
  1713. package/prompts/product-analyst.md +0 -304
  1714. package/prompts/product-manager.md +0 -245
  1715. package/prompts/qa-tester.md +0 -124
  1716. package/prompts/quality-reviewer.md +0 -123
  1717. package/prompts/quality-strategist.md +0 -274
  1718. package/prompts/style-reviewer.md +0 -102
  1719. package/prompts/ux-researcher.md +0 -327
  1720. package/skills/frontend-ui-ux/SKILL.md +0 -34
  1721. package/skills/ralph/SKILL.md +0 -269
  1722. package/skills/ralplan/SKILL.md +0 -162
  1723. package/src/scripts/eval/eval-adaptive-sort-optimization.py +0 -24
  1724. package/src/scripts/eval/eval-candidate-handoff.ts +0 -8
  1725. package/src/scripts/eval/eval-cli-discoverability.ts +0 -40
  1726. package/src/scripts/eval/eval-fresh-run-tagging.ts +0 -8
  1727. package/src/scripts/eval/eval-help-consistency.ts +0 -11
  1728. package/src/scripts/eval/eval-in-action-cat-shellout-demo.ts +0 -31
  1729. package/src/scripts/eval/eval-ml-kaggle-model-optimization.py +0 -29
  1730. package/src/scripts/eval/eval-noisy-bayesopt-highdim.py +0 -44
  1731. package/src/scripts/eval/eval-noisy-latent-subspace-discovery.py +0 -44
  1732. package/src/scripts/eval/eval-parity-smoke.ts +0 -20
  1733. package/src/scripts/eval/eval-parity-sweep.ts +0 -26
  1734. package/src/scripts/eval/eval-resume-dirty-guard.ts +0 -8
  1735. package/src/scripts/eval/eval-security-path-traversal.ts +0 -38
  1736. package/src/scripts/run-autoresearch-showcase.sh +0 -75
  1737. /package/docs/{migration-mainline-post-v0.4.4.md → archive/migration-mainline-post-v0.4.4.md} +0 -0
  1738. /package/docs/{qa-plan-0.4.2.md → archive/qa-plan-0.4.2.md} +0 -0
  1739. /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