@jstn-sdk/rcs 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1736) hide show
  1. package/README.md +142 -102
  2. package/dist/agents/definitions.d.ts.map +1 -1
  3. package/dist/agents/definitions.js +0 -101
  4. package/dist/agents/definitions.js.map +1 -1
  5. package/dist/blueprint/runtime.d.ts +52 -0
  6. package/dist/blueprint/runtime.d.ts.map +1 -0
  7. package/dist/{ralplan → blueprint}/runtime.js +19 -19
  8. package/dist/blueprint/runtime.js.map +1 -0
  9. package/dist/catalog/reader.d.ts.map +1 -1
  10. package/dist/catalog/reader.js +8 -2
  11. package/dist/catalog/reader.js.map +1 -1
  12. package/dist/catalog/schema.js +1 -1
  13. package/dist/catalog/schema.js.map +1 -1
  14. package/dist/cli/forge.d.ts +17 -0
  15. package/dist/cli/{ralph.d.ts.map → forge.d.ts.map} +1 -1
  16. package/dist/cli/{ralph.js → forge.js} +82 -82
  17. package/dist/cli/{ralph.js.map → forge.js.map} +1 -1
  18. package/dist/cli/index.d.ts +1 -1
  19. package/dist/cli/index.js +15 -15
  20. package/dist/cli/setup.d.ts.map +1 -1
  21. package/dist/cli/setup.js +2 -3
  22. package/dist/cli/setup.js.map +1 -1
  23. package/dist/cli/star-prompt.js +2 -2
  24. package/dist/cli/star-prompt.js.map +1 -1
  25. package/dist/cli/state.js +1 -1
  26. package/dist/cli/team.d.ts.map +1 -1
  27. package/dist/cli/team.js +3 -2
  28. package/dist/cli/team.js.map +1 -1
  29. package/dist/cli/tmux-hook.d.ts.map +1 -1
  30. package/dist/cli/tmux-hook.js +9 -1
  31. package/dist/cli/tmux-hook.js.map +1 -1
  32. package/dist/config/generator.d.ts +1 -1
  33. package/dist/config/generator.d.ts.map +1 -1
  34. package/dist/config/generator.js +1 -1
  35. package/dist/config/generator.js.map +1 -1
  36. package/dist/forge/contract.d.ts +17 -0
  37. package/dist/{ralph → forge}/contract.d.ts.map +1 -1
  38. package/dist/{ralph → forge}/contract.js +16 -16
  39. package/dist/{ralph → forge}/contract.js.map +1 -1
  40. package/dist/{ralph → forge}/persistence.d.ts +5 -5
  41. package/dist/{ralph → forge}/persistence.d.ts.map +1 -1
  42. package/dist/{ralph → forge}/persistence.js +7 -6
  43. package/dist/forge/persistence.js.map +1 -0
  44. package/dist/hooks/agents-overlay.d.ts +1 -1
  45. package/dist/hooks/agents-overlay.d.ts.map +1 -1
  46. package/dist/hooks/agents-overlay.js +37 -31
  47. package/dist/hooks/agents-overlay.js.map +1 -1
  48. package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
  49. package/dist/hooks/extensibility/dispatcher.js +82 -14
  50. package/dist/hooks/extensibility/dispatcher.js.map +1 -1
  51. package/dist/hooks/keyword-detector.d.ts +8 -8
  52. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  53. package/dist/hooks/keyword-detector.js +94 -64
  54. package/dist/hooks/keyword-detector.js.map +1 -1
  55. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  56. package/dist/hooks/keyword-registry.js +9 -11
  57. package/dist/hooks/keyword-registry.js.map +1 -1
  58. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  59. package/dist/hooks/prompt-guidance-contract.js +10 -21
  60. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  61. package/dist/hooks/task-size-detector.js +2 -2
  62. package/dist/hooks/task-size-detector.js.map +1 -1
  63. package/dist/hooks/triage-state.d.ts +1 -1
  64. package/dist/hooks/triage-state.js +1 -1
  65. package/dist/hud/colors.d.ts +2 -2
  66. package/dist/hud/colors.js +2 -2
  67. package/dist/hud/render.js +21 -21
  68. package/dist/hud/render.js.map +1 -1
  69. package/dist/hud/state.d.ts +3 -3
  70. package/dist/hud/state.d.ts.map +1 -1
  71. package/dist/hud/state.js +18 -15
  72. package/dist/hud/state.js.map +1 -1
  73. package/dist/hud/types.d.ts +6 -6
  74. package/dist/hud/types.d.ts.map +1 -1
  75. package/dist/mcp/bootstrap.d.ts.map +1 -1
  76. package/dist/mcp/bootstrap.js +36 -2
  77. package/dist/mcp/bootstrap.js.map +1 -1
  78. package/dist/mcp/state-paths.d.ts +1 -0
  79. package/dist/mcp/state-paths.d.ts.map +1 -1
  80. package/dist/mcp/state-paths.js +4 -1
  81. package/dist/mcp/state-paths.js.map +1 -1
  82. package/dist/mcp/state-server.d.ts +4 -4
  83. package/dist/mcp/state-server.js +2 -2
  84. package/dist/mcp/state-server.js.map +1 -1
  85. package/dist/modes/base.d.ts +2 -2
  86. package/dist/modes/base.d.ts.map +1 -1
  87. package/dist/modes/base.js +29 -26
  88. package/dist/modes/base.js.map +1 -1
  89. package/dist/notifications/reply-listener.d.ts.map +1 -1
  90. package/dist/notifications/reply-listener.js +7 -1
  91. package/dist/notifications/reply-listener.js.map +1 -1
  92. package/dist/notifications/tmux.d.ts.map +1 -1
  93. package/dist/notifications/tmux.js +39 -6
  94. package/dist/notifications/tmux.js.map +1 -1
  95. package/dist/pipeline/index.d.ts +7 -6
  96. package/dist/pipeline/index.d.ts.map +1 -1
  97. package/dist/pipeline/index.js +5 -4
  98. package/dist/pipeline/index.js.map +1 -1
  99. package/dist/pipeline/orchestrator.d.ts +5 -5
  100. package/dist/pipeline/orchestrator.js +25 -25
  101. package/dist/pipeline/orchestrator.js.map +1 -1
  102. package/dist/pipeline/stages/blueprint.d.ts +25 -0
  103. package/dist/pipeline/stages/blueprint.d.ts.map +1 -0
  104. package/dist/pipeline/stages/{ralplan.js → blueprint.js} +16 -16
  105. package/dist/pipeline/stages/blueprint.js.map +1 -0
  106. package/dist/pipeline/stages/code-review.d.ts +2 -2
  107. package/dist/pipeline/stages/code-review.js +6 -6
  108. package/dist/pipeline/stages/code-review.js.map +1 -1
  109. package/dist/pipeline/stages/forge-verify.d.ts +50 -0
  110. package/dist/pipeline/stages/forge-verify.d.ts.map +1 -0
  111. package/dist/pipeline/stages/{ralph-verify.js → forge-verify.js} +21 -24
  112. package/dist/pipeline/stages/forge-verify.js.map +1 -0
  113. package/dist/pipeline/stages/team-exec.d.ts +1 -1
  114. package/dist/pipeline/stages/team-exec.js +19 -19
  115. package/dist/pipeline/stages/team-exec.js.map +1 -1
  116. package/dist/pipeline/types.d.ts +12 -12
  117. package/dist/pipeline/types.d.ts.map +1 -1
  118. package/dist/pipeline/types.js +1 -1
  119. package/dist/planning/artifacts.d.ts +3 -4
  120. package/dist/planning/artifacts.d.ts.map +1 -1
  121. package/dist/planning/artifacts.js +2 -3
  122. package/dist/planning/artifacts.js.map +1 -1
  123. package/dist/question/policy.js +1 -1
  124. package/dist/runtime/bridge.d.ts.map +1 -1
  125. package/dist/runtime/bridge.js +70 -13
  126. package/dist/runtime/bridge.js.map +1 -1
  127. package/dist/scripts/codex-native-hook.js +30 -30
  128. package/dist/scripts/codex-native-hook.js.map +1 -1
  129. package/dist/scripts/eval/eval-cross-server-party-flow.d.ts +3 -0
  130. package/dist/scripts/eval/eval-cross-server-party-flow.d.ts.map +1 -0
  131. package/dist/scripts/eval/eval-cross-server-party-flow.js +12 -0
  132. package/dist/scripts/eval/eval-cross-server-party-flow.js.map +1 -0
  133. package/dist/scripts/eval/eval-gui-onboarding-clarity.d.ts +3 -0
  134. package/dist/scripts/eval/eval-gui-onboarding-clarity.d.ts.map +1 -0
  135. package/dist/scripts/eval/eval-gui-onboarding-clarity.js +17 -0
  136. package/dist/scripts/eval/eval-gui-onboarding-clarity.js.map +1 -0
  137. package/dist/scripts/eval/eval-liveops-reward-loop-balance.d.ts +3 -0
  138. package/dist/scripts/eval/eval-liveops-reward-loop-balance.d.ts.map +1 -0
  139. package/dist/scripts/eval/eval-liveops-reward-loop-balance.js +12 -0
  140. package/dist/scripts/eval/eval-liveops-reward-loop-balance.js.map +1 -0
  141. package/dist/scripts/eval/eval-profile-datastore-recovery.d.ts +3 -0
  142. package/dist/scripts/eval/eval-profile-datastore-recovery.d.ts.map +1 -0
  143. package/dist/scripts/eval/eval-profile-datastore-recovery.js +17 -0
  144. package/dist/scripts/eval/eval-profile-datastore-recovery.js.map +1 -0
  145. package/dist/scripts/eval/eval-remote-contract-hardening.d.ts +3 -0
  146. package/dist/scripts/eval/eval-remote-contract-hardening.d.ts.map +1 -0
  147. package/dist/scripts/eval/eval-remote-contract-hardening.js +17 -0
  148. package/dist/scripts/eval/eval-remote-contract-hardening.js.map +1 -0
  149. package/dist/scripts/notify-fallback-watcher.js +140 -139
  150. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  151. package/dist/scripts/notify-hook/forge-session-resume.d.ts +23 -0
  152. package/dist/scripts/notify-hook/{ralph-session-resume.d.ts.map → forge-session-resume.d.ts.map} +1 -1
  153. package/dist/scripts/notify-hook/{ralph-session-resume.js → forge-session-resume.js} +37 -36
  154. package/dist/scripts/notify-hook/{ralph-session-resume.js.map → forge-session-resume.js.map} +1 -1
  155. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
  156. package/dist/scripts/notify-hook/team-dispatch.js +34 -4
  157. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  158. package/dist/scripts/notify-hook/visual-verdict.js +3 -3
  159. package/dist/scripts/notify-hook.js +9 -9
  160. package/dist/scripts/run-test-files.js +1 -1
  161. package/dist/scripts/run-test-files.js.map +1 -1
  162. package/dist/scripts/surface-taxonomy.d.ts +23 -0
  163. package/dist/scripts/surface-taxonomy.d.ts.map +1 -0
  164. package/dist/scripts/surface-taxonomy.js +271 -0
  165. package/dist/scripts/surface-taxonomy.js.map +1 -0
  166. package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
  167. package/dist/scripts/sync-plugin-mirror.js +5 -4
  168. package/dist/scripts/sync-plugin-mirror.js.map +1 -1
  169. package/dist/scripts/tmux-hook-engine.d.ts +1 -1
  170. package/dist/scripts/tmux-hook-engine.d.ts.map +1 -1
  171. package/dist/scripts/tmux-hook-engine.js +29 -20
  172. package/dist/scripts/tmux-hook-engine.js.map +1 -1
  173. package/dist/state/operations.d.ts +1 -1
  174. package/dist/state/operations.d.ts.map +1 -1
  175. package/dist/state/operations.js +18 -18
  176. package/dist/state/operations.js.map +1 -1
  177. package/dist/state/skill-active.d.ts +13 -1
  178. package/dist/state/skill-active.d.ts.map +1 -1
  179. package/dist/state/skill-active.js +38 -17
  180. package/dist/state/skill-active.js.map +1 -1
  181. package/dist/state/workflow-transition.d.ts +6 -5
  182. package/dist/state/workflow-transition.d.ts.map +1 -1
  183. package/dist/state/workflow-transition.js +27 -15
  184. package/dist/state/workflow-transition.js.map +1 -1
  185. package/dist/team/contracts.d.ts +1 -1
  186. package/dist/team/contracts.js +2 -2
  187. package/dist/team/followup-planner.d.ts +2 -2
  188. package/dist/team/followup-planner.d.ts.map +1 -1
  189. package/dist/team/followup-planner.js +16 -14
  190. package/dist/team/followup-planner.js.map +1 -1
  191. package/dist/team/idle-nudge.d.ts.map +1 -1
  192. package/dist/team/idle-nudge.js +3 -2
  193. package/dist/team/idle-nudge.js.map +1 -1
  194. package/dist/team/leader-activity.js +1 -1
  195. package/dist/team/model-contract.d.ts.map +1 -1
  196. package/dist/team/model-contract.js +4 -1
  197. package/dist/team/model-contract.js.map +1 -1
  198. package/dist/team/orchestrator.js +4 -4
  199. package/dist/team/orchestrator.js.map +1 -1
  200. package/dist/team/role-router.js +3 -3
  201. package/dist/team/role-router.js.map +1 -1
  202. package/dist/team/state/dispatch.d.ts.map +1 -1
  203. package/dist/team/state/dispatch.js +4 -1
  204. package/dist/team/state/dispatch.js.map +1 -1
  205. package/dist/team/tmux-session.d.ts +4 -0
  206. package/dist/team/tmux-session.d.ts.map +1 -1
  207. package/dist/team/tmux-session.js +42 -9
  208. package/dist/team/tmux-session.js.map +1 -1
  209. package/dist/team/worktree.d.ts +1 -1
  210. package/dist/utils/platform-command.d.ts.map +1 -1
  211. package/dist/utils/platform-command.js +9 -0
  212. package/dist/utils/platform-command.js.map +1 -1
  213. package/dist/verification/verifier.d.ts +1 -1
  214. package/dist/verification/verifier.js +2 -2
  215. package/docs/STATE_MODEL.md +24 -24
  216. package/docs/agents.html +8 -16
  217. package/docs/archive/README.md +15 -0
  218. package/docs/{prompt-migration-changelog.md → archive/prompt-migration-changelog.md} +0 -11
  219. package/docs/{release-body-0.9.0.md → archive/release-body-0.9.0.md} +6 -24
  220. package/docs/{release-body-0.9.1.md → archive/release-body-0.9.1.md} +3 -3
  221. package/docs/codex-native-hooks.md +4 -4
  222. package/docs/contracts/forge-cancel-contract.md +20 -0
  223. package/docs/contracts/forge-state-contract.md +52 -0
  224. package/docs/contracts/multi-state-transition-contract.md +5 -5
  225. package/docs/contracts/multi-state-transition-review.md +3 -3
  226. package/docs/contracts/repo-aware-team-dag-decomposition.md +1 -1
  227. package/docs/contracts/rust-runtime-thin-adapter-contract.md +1 -1
  228. package/docs/contracts/team-startup-dispatch-latency.md +1 -1
  229. package/docs/getting-started.html +6 -1
  230. package/docs/guidance-schema.md +6 -3
  231. package/docs/index.html +55 -4
  232. package/docs/integrations.html +4 -3
  233. package/docs/issues/team-forge-followup-team.md +38 -0
  234. package/docs/openclaw-integration.md +2 -2
  235. package/docs/prompt-guidance-contract.md +11 -11
  236. package/docs/prs/{dev-deprecate-team-ralph.md → dev-deprecate-team-forge.md} +27 -27
  237. package/docs/prs/{dev-fix-ralph-live-pane-invariant.md → dev-fix-forge-live-pane-invariant.md} +7 -7
  238. package/docs/prs/{dev-team-ralph-workflow-positioning.md → dev-team-forge-workflow-positioning.md} +7 -7
  239. package/docs/qa/forge-persistence-gate.md +20 -0
  240. package/docs/qa/rust-runtime-thin-adapter-gate.md +31 -40
  241. package/docs/readme/README.de.md +13 -0
  242. package/docs/readme/README.el.md +13 -0
  243. package/docs/readme/README.es.md +13 -0
  244. package/docs/readme/README.fr.md +13 -0
  245. package/docs/readme/README.it.md +13 -0
  246. package/docs/readme/README.ja.md +13 -0
  247. package/docs/readme/README.ko.md +13 -0
  248. package/docs/readme/README.pl.md +13 -0
  249. package/docs/readme/README.pt.md +13 -0
  250. package/docs/readme/README.ru.md +13 -0
  251. package/docs/readme/README.tr.md +13 -0
  252. package/docs/readme/README.uk.md +13 -0
  253. package/docs/readme/README.vi.md +13 -0
  254. package/docs/readme/README.zh-TW.md +13 -0
  255. package/docs/readme/README.zh.md +13 -0
  256. package/docs/readme/rcs-cover.svg +75 -0
  257. package/docs/reference/canonical-vocabulary.md +106 -0
  258. package/docs/reference/forge-parity-matrix.md +26 -0
  259. package/docs/reference/forge-upstream-baseline.md +32 -0
  260. package/docs/reference/rcs-config-schema-routing.md +5 -5
  261. package/docs/reference/roblox-pre-action-protocol.md +4 -0
  262. package/docs/reference/roblox-taxonomy-migration-plan.md +46 -0
  263. package/docs/reference/roblox-workspace-standard.md +83 -0
  264. package/docs/reference/robloxstudio-mcp-compatibility.md +117 -0
  265. package/docs/reference/semantic-design-system.md +110 -0
  266. package/docs/reference/surface-map.md +131 -0
  267. package/docs/reference/team-allocation-rebalance-policy.md +1 -1
  268. package/docs/release-notes-v0.1.0.md +1 -1
  269. package/docs/release-notes-v0.1.1.md +49 -0
  270. package/docs/reports/open-prs-dev-readiness-2026-04-09.md +2 -2
  271. package/docs/shared/agent-tiers.md +3 -3
  272. package/docs/skills.html +10 -12
  273. package/docs/troubleshooting.md +1 -1
  274. package/package.json +20 -13
  275. package/plugins/roblox-ai-os-creator-skills/.codex-plugin/plugin.json +1 -1
  276. package/plugins/roblox-ai-os-creator-skills/docs/reference/roblox-pre-action-protocol.md +4 -0
  277. package/plugins/roblox-ai-os-creator-skills/skills/ai-slop-cleaner/SKILL.md +14 -7
  278. package/plugins/roblox-ai-os-creator-skills/skills/analyze/SKILL.md +9 -2
  279. package/plugins/roblox-ai-os-creator-skills/skills/ask-claude/SKILL.md +7 -0
  280. package/plugins/roblox-ai-os-creator-skills/skills/ask-gemini/SKILL.md +7 -0
  281. package/plugins/roblox-ai-os-creator-skills/skills/autoforge/SKILL.md +7 -0
  282. package/plugins/roblox-ai-os-creator-skills/skills/autopilot/SKILL.md +48 -41
  283. package/plugins/roblox-ai-os-creator-skills/skills/autoresearch/SKILL.md +8 -1
  284. package/plugins/roblox-ai-os-creator-skills/skills/blueprint/SKILL.md +227 -9
  285. package/plugins/roblox-ai-os-creator-skills/skills/blueprint-loop/SKILL.md +7 -0
  286. package/plugins/roblox-ai-os-creator-skills/skills/blueprint-psych/SKILL.md +7 -0
  287. package/plugins/roblox-ai-os-creator-skills/skills/blueprint-retention/SKILL.md +7 -0
  288. package/plugins/roblox-ai-os-creator-skills/skills/blueprint-social/SKILL.md +7 -0
  289. package/plugins/roblox-ai-os-creator-skills/skills/brief/SKILL.md +7 -0
  290. package/plugins/roblox-ai-os-creator-skills/skills/brief-audience/SKILL.md +7 -0
  291. package/plugins/roblox-ai-os-creator-skills/skills/brief-motivation/SKILL.md +7 -0
  292. package/plugins/roblox-ai-os-creator-skills/skills/cancel/SKILL.md +59 -52
  293. package/plugins/roblox-ai-os-creator-skills/skills/code-review/SKILL.md +30 -24
  294. package/plugins/roblox-ai-os-creator-skills/skills/configure-notifications/SKILL.md +7 -0
  295. package/plugins/roblox-ai-os-creator-skills/skills/crew/SKILL.md +7 -0
  296. package/plugins/roblox-ai-os-creator-skills/skills/deep-interview/SKILL.md +25 -18
  297. package/plugins/roblox-ai-os-creator-skills/skills/doctor/SKILL.md +7 -0
  298. package/plugins/roblox-ai-os-creator-skills/skills/forge/SKILL.md +174 -11
  299. package/plugins/roblox-ai-os-creator-skills/skills/forge-community/SKILL.md +7 -0
  300. package/plugins/roblox-ai-os-creator-skills/skills/forge-daily-loop/SKILL.md +7 -0
  301. package/plugins/roblox-ai-os-creator-skills/skills/forge-event-loop/SKILL.md +7 -0
  302. package/plugins/roblox-ai-os-creator-skills/skills/forge-fomo/SKILL.md +7 -0
  303. package/plugins/roblox-ai-os-creator-skills/skills/forge-mastery/SKILL.md +7 -0
  304. package/plugins/roblox-ai-os-creator-skills/skills/forge-progression/SKILL.md +7 -0
  305. package/plugins/roblox-ai-os-creator-skills/skills/forge-reward-loop/SKILL.md +7 -0
  306. package/plugins/roblox-ai-os-creator-skills/skills/forge-status/SKILL.md +7 -0
  307. package/plugins/roblox-ai-os-creator-skills/skills/help/SKILL.md +8 -1
  308. package/plugins/roblox-ai-os-creator-skills/skills/hud/SKILL.md +16 -9
  309. package/plugins/roblox-ai-os-creator-skills/skills/note/SKILL.md +8 -1
  310. package/plugins/roblox-ai-os-creator-skills/skills/pipeline/SKILL.md +18 -11
  311. package/plugins/roblox-ai-os-creator-skills/skills/plan/SKILL.md +36 -29
  312. package/plugins/roblox-ai-os-creator-skills/skills/rcs-setup/SKILL.md +8 -1
  313. package/plugins/roblox-ai-os-creator-skills/skills/security-review/SKILL.md +120 -236
  314. package/plugins/roblox-ai-os-creator-skills/skills/skill/SKILL.md +20 -13
  315. package/plugins/roblox-ai-os-creator-skills/skills/team/SKILL.md +17 -11
  316. package/plugins/roblox-ai-os-creator-skills/skills/trace/SKILL.md +7 -0
  317. package/plugins/roblox-ai-os-creator-skills/skills/ultraqa/SKILL.md +10 -3
  318. package/plugins/roblox-ai-os-creator-skills/skills/ultrawork/SKILL.md +19 -12
  319. package/plugins/roblox-ai-os-creator-skills/skills/{visual-ralph → visual-forge}/SKILL.md +36 -27
  320. package/plugins/roblox-ai-os-creator-skills/skills/visual-verdict/SKILL.md +9 -2
  321. package/plugins/roblox-ai-os-creator-skills/skills/wiki/SKILL.md +10 -3
  322. package/plugins/roblox-ai-os-creator-skills/skills/worker/SKILL.md +16 -7
  323. package/plugins/roblox-ai-os-creator-skills/templates/roblox/pre-action-plan.md +1 -0
  324. package/prompts/analyst.md +7 -0
  325. package/prompts/architect.md +11 -4
  326. package/prompts/build-fixer.md +7 -0
  327. package/prompts/code-reviewer.md +9 -2
  328. package/prompts/code-simplifier.md +4 -0
  329. package/prompts/critic.md +13 -6
  330. package/prompts/debugger.md +8 -1
  331. package/prompts/dependency-expert.md +8 -1
  332. package/prompts/designer.md +20 -10
  333. package/prompts/executor.md +7 -0
  334. package/prompts/explore-harness.md +7 -0
  335. package/prompts/explore.md +7 -0
  336. package/prompts/git-master.md +8 -1
  337. package/prompts/planner.md +10 -3
  338. package/prompts/researcher.md +7 -0
  339. package/prompts/security-reviewer.md +76 -92
  340. package/prompts/sisyphus-lite.md +7 -0
  341. package/prompts/team-executor.md +7 -0
  342. package/prompts/team-orchestrator.md +9 -2
  343. package/prompts/test-engineer.md +11 -3
  344. package/prompts/verifier.md +7 -0
  345. package/prompts/vision.md +9 -2
  346. package/prompts/writer.md +11 -4
  347. package/skills/.agents/skills/roblox-animations/SKILL.md +220 -0
  348. package/skills/.agents/skills/roblox-datastores/SKILL.md +219 -0
  349. package/skills/.agents/skills/roblox-gui/SKILL.md +192 -0
  350. package/skills/.agents/skills/roblox-monetization/SKILL.md +208 -0
  351. package/skills/.agents/skills/roblox-performance/SKILL.md +230 -0
  352. package/skills/.agents/skills/roblox-remote-events/SKILL.md +199 -0
  353. package/skills/.agents/skills/roblox-security/SKILL.md +236 -0
  354. package/skills/ai-slop-cleaner/SKILL.md +14 -7
  355. package/skills/analyze/SKILL.md +9 -2
  356. package/skills/ask-claude/SKILL.md +7 -0
  357. package/skills/ask-gemini/SKILL.md +7 -0
  358. package/skills/autoforge/SKILL.md +7 -0
  359. package/skills/autopilot/SKILL.md +48 -41
  360. package/skills/autoresearch/SKILL.md +8 -1
  361. package/skills/blueprint/SKILL.md +227 -9
  362. package/skills/blueprint-loop/SKILL.md +7 -0
  363. package/skills/blueprint-psych/SKILL.md +7 -0
  364. package/skills/blueprint-retention/SKILL.md +7 -0
  365. package/skills/blueprint-social/SKILL.md +7 -0
  366. package/skills/brief/SKILL.md +7 -0
  367. package/skills/brief-audience/SKILL.md +7 -0
  368. package/skills/brief-motivation/SKILL.md +7 -0
  369. package/skills/build-fix/SKILL.md +9 -2
  370. package/skills/cancel/SKILL.md +59 -52
  371. package/skills/code-review/SKILL.md +30 -24
  372. package/skills/configure-notifications/SKILL.md +7 -0
  373. package/skills/crew/SKILL.md +7 -0
  374. package/skills/deep-interview/SKILL.md +25 -18
  375. package/skills/deepsearch/SKILL.md +7 -0
  376. package/skills/doctor/SKILL.md +7 -0
  377. package/skills/ecomode/SKILL.md +9 -2
  378. package/skills/forge/SKILL.md +174 -11
  379. package/skills/forge-community/SKILL.md +7 -0
  380. package/skills/forge-daily-loop/SKILL.md +7 -0
  381. package/skills/forge-event-loop/SKILL.md +7 -0
  382. package/skills/forge-fomo/SKILL.md +7 -0
  383. package/skills/{ralph-init → forge-init}/SKILL.md +20 -13
  384. package/skills/forge-mastery/SKILL.md +7 -0
  385. package/skills/forge-progression/SKILL.md +7 -0
  386. package/skills/forge-reward-loop/SKILL.md +7 -0
  387. package/skills/forge-status/SKILL.md +7 -0
  388. package/skills/git-master/SKILL.md +7 -0
  389. package/skills/help/SKILL.md +8 -1
  390. package/skills/hud/SKILL.md +16 -9
  391. package/skills/note/SKILL.md +8 -1
  392. package/skills/pipeline/SKILL.md +18 -11
  393. package/skills/plan/SKILL.md +36 -29
  394. package/skills/rcs-setup/SKILL.md +8 -1
  395. package/skills/review/SKILL.md +7 -0
  396. package/skills/security-review/SKILL.md +120 -236
  397. package/skills/skill/SKILL.md +20 -13
  398. package/skills/skills-lock.json +47 -0
  399. package/skills/swarm/SKILL.md +8 -1
  400. package/skills/tdd/SKILL.md +7 -0
  401. package/skills/team/SKILL.md +17 -11
  402. package/skills/trace/SKILL.md +7 -0
  403. package/skills/ultraqa/SKILL.md +10 -3
  404. package/skills/ultrawork/SKILL.md +19 -12
  405. package/skills/{visual-ralph → visual-forge}/SKILL.md +36 -27
  406. package/skills/visual-verdict/SKILL.md +9 -2
  407. package/skills/web-clone/SKILL.md +14 -7
  408. package/skills/wiki/SKILL.md +10 -3
  409. package/skills/worker/SKILL.md +16 -7
  410. package/src/scripts/__tests__/codex-native-hook.test.ts +386 -319
  411. package/src/scripts/__tests__/run-test-files.test.ts +6 -4
  412. package/src/scripts/__tests__/verify-native-agents.test.ts +16 -16
  413. package/src/scripts/codex-native-hook.ts +34 -34
  414. package/src/scripts/eval/eval-cross-server-party-flow.ts +14 -0
  415. package/src/scripts/eval/eval-gui-onboarding-clarity.ts +20 -0
  416. package/src/scripts/eval/eval-liveops-reward-loop-balance.ts +14 -0
  417. package/src/scripts/eval/eval-profile-datastore-recovery.ts +20 -0
  418. package/src/scripts/eval/eval-remote-contract-hardening.ts +20 -0
  419. package/src/scripts/notify-fallback-watcher.ts +147 -146
  420. package/src/scripts/notify-hook/__tests__/team-worker-posttooluse.test.ts +24 -10
  421. package/src/scripts/notify-hook/{ralph-session-resume.ts → forge-session-resume.ts} +45 -43
  422. package/src/scripts/notify-hook/team-dispatch.ts +31 -4
  423. package/src/scripts/notify-hook/visual-verdict.ts +3 -3
  424. package/src/scripts/notify-hook.ts +10 -10
  425. package/src/scripts/run-test-files.ts +1 -1
  426. package/src/scripts/surface-taxonomy.ts +316 -0
  427. package/src/scripts/sync-plugin-mirror.ts +5 -4
  428. package/src/scripts/tmux-hook-engine.ts +31 -19
  429. package/templates/AGENTS.md +24 -15
  430. package/templates/catalog-manifest.json +5 -88
  431. package/templates/roblox/pre-action-plan.md +1 -0
  432. package/templates/roblox/robloxstudio-mcp.codex.json +18 -0
  433. package/templates/roblox/robloxstudio-mcp.windows.json +22 -0
  434. package/dist/adapt/__tests__/foundation.test.d.ts +0 -2
  435. package/dist/adapt/__tests__/foundation.test.d.ts.map +0 -1
  436. package/dist/adapt/__tests__/foundation.test.js +0 -171
  437. package/dist/adapt/__tests__/foundation.test.js.map +0 -1
  438. package/dist/adapt/__tests__/hermes.test.d.ts +0 -2
  439. package/dist/adapt/__tests__/hermes.test.d.ts.map +0 -1
  440. package/dist/adapt/__tests__/hermes.test.js +0 -137
  441. package/dist/adapt/__tests__/hermes.test.js.map +0 -1
  442. package/dist/agents/__tests__/definitions.test.d.ts +0 -2
  443. package/dist/agents/__tests__/definitions.test.d.ts.map +0 -1
  444. package/dist/agents/__tests__/definitions.test.js +0 -62
  445. package/dist/agents/__tests__/definitions.test.js.map +0 -1
  446. package/dist/agents/__tests__/native-config.test.d.ts +0 -2
  447. package/dist/agents/__tests__/native-config.test.d.ts.map +0 -1
  448. package/dist/agents/__tests__/native-config.test.js +0 -278
  449. package/dist/agents/__tests__/native-config.test.js.map +0 -1
  450. package/dist/autoresearch/__tests__/contracts.test.d.ts +0 -2
  451. package/dist/autoresearch/__tests__/contracts.test.d.ts.map +0 -1
  452. package/dist/autoresearch/__tests__/contracts.test.js +0 -127
  453. package/dist/autoresearch/__tests__/contracts.test.js.map +0 -1
  454. package/dist/autoresearch/__tests__/runtime-parity-extra.test.d.ts +0 -2
  455. package/dist/autoresearch/__tests__/runtime-parity-extra.test.d.ts.map +0 -1
  456. package/dist/autoresearch/__tests__/runtime-parity-extra.test.js +0 -356
  457. package/dist/autoresearch/__tests__/runtime-parity-extra.test.js.map +0 -1
  458. package/dist/autoresearch/__tests__/runtime.test.d.ts +0 -2
  459. package/dist/autoresearch/__tests__/runtime.test.d.ts.map +0 -1
  460. package/dist/autoresearch/__tests__/runtime.test.js +0 -218
  461. package/dist/autoresearch/__tests__/runtime.test.js.map +0 -1
  462. package/dist/autoresearch/__tests__/skill-validation.test.d.ts +0 -2
  463. package/dist/autoresearch/__tests__/skill-validation.test.d.ts.map +0 -1
  464. package/dist/autoresearch/__tests__/skill-validation.test.js +0 -91
  465. package/dist/autoresearch/__tests__/skill-validation.test.js.map +0 -1
  466. package/dist/catalog/__tests__/generator.test.d.ts +0 -2
  467. package/dist/catalog/__tests__/generator.test.d.ts.map +0 -1
  468. package/dist/catalog/__tests__/generator.test.js +0 -49
  469. package/dist/catalog/__tests__/generator.test.js.map +0 -1
  470. package/dist/catalog/__tests__/plugin-bundle-ssot.test.d.ts +0 -2
  471. package/dist/catalog/__tests__/plugin-bundle-ssot.test.d.ts.map +0 -1
  472. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +0 -83
  473. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +0 -1
  474. package/dist/catalog/__tests__/schema.test.d.ts +0 -2
  475. package/dist/catalog/__tests__/schema.test.d.ts.map +0 -1
  476. package/dist/catalog/__tests__/schema.test.js +0 -91
  477. package/dist/catalog/__tests__/schema.test.js.map +0 -1
  478. package/dist/cli/__tests__/adapt-help.test.d.ts +0 -2
  479. package/dist/cli/__tests__/adapt-help.test.d.ts.map +0 -1
  480. package/dist/cli/__tests__/adapt-help.test.js +0 -37
  481. package/dist/cli/__tests__/adapt-help.test.js.map +0 -1
  482. package/dist/cli/__tests__/adapt.test.d.ts +0 -2
  483. package/dist/cli/__tests__/adapt.test.d.ts.map +0 -1
  484. package/dist/cli/__tests__/adapt.test.js +0 -62
  485. package/dist/cli/__tests__/adapt.test.js.map +0 -1
  486. package/dist/cli/__tests__/agents-init.test.d.ts +0 -2
  487. package/dist/cli/__tests__/agents-init.test.d.ts.map +0 -1
  488. package/dist/cli/__tests__/agents-init.test.js +0 -184
  489. package/dist/cli/__tests__/agents-init.test.js.map +0 -1
  490. package/dist/cli/__tests__/agents.test.d.ts +0 -2
  491. package/dist/cli/__tests__/agents.test.d.ts.map +0 -1
  492. package/dist/cli/__tests__/agents.test.js +0 -137
  493. package/dist/cli/__tests__/agents.test.js.map +0 -1
  494. package/dist/cli/__tests__/ask.test.d.ts +0 -2
  495. package/dist/cli/__tests__/ask.test.d.ts.map +0 -1
  496. package/dist/cli/__tests__/ask.test.js +0 -265
  497. package/dist/cli/__tests__/ask.test.js.map +0 -1
  498. package/dist/cli/__tests__/autoresearch-guided.test.d.ts +0 -2
  499. package/dist/cli/__tests__/autoresearch-guided.test.d.ts.map +0 -1
  500. package/dist/cli/__tests__/autoresearch-guided.test.js +0 -365
  501. package/dist/cli/__tests__/autoresearch-guided.test.js.map +0 -1
  502. package/dist/cli/__tests__/autoresearch.test.d.ts +0 -2
  503. package/dist/cli/__tests__/autoresearch.test.d.ts.map +0 -1
  504. package/dist/cli/__tests__/autoresearch.test.js +0 -203
  505. package/dist/cli/__tests__/autoresearch.test.js.map +0 -1
  506. package/dist/cli/__tests__/catalog-contract.test.d.ts +0 -2
  507. package/dist/cli/__tests__/catalog-contract.test.d.ts.map +0 -1
  508. package/dist/cli/__tests__/catalog-contract.test.js +0 -18
  509. package/dist/cli/__tests__/catalog-contract.test.js.map +0 -1
  510. package/dist/cli/__tests__/cleanup.test.d.ts +0 -2
  511. package/dist/cli/__tests__/cleanup.test.d.ts.map +0 -1
  512. package/dist/cli/__tests__/cleanup.test.js +0 -419
  513. package/dist/cli/__tests__/cleanup.test.js.map +0 -1
  514. package/dist/cli/__tests__/codex-plugin-layout.test.d.ts +0 -2
  515. package/dist/cli/__tests__/codex-plugin-layout.test.d.ts.map +0 -1
  516. package/dist/cli/__tests__/codex-plugin-layout.test.js +0 -210
  517. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +0 -1
  518. package/dist/cli/__tests__/doctor-context-window-warning.test.d.ts +0 -2
  519. package/dist/cli/__tests__/doctor-context-window-warning.test.d.ts.map +0 -1
  520. package/dist/cli/__tests__/doctor-context-window-warning.test.js +0 -122
  521. package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +0 -1
  522. package/dist/cli/__tests__/doctor-invalid-config.test.d.ts +0 -2
  523. package/dist/cli/__tests__/doctor-invalid-config.test.d.ts.map +0 -1
  524. package/dist/cli/__tests__/doctor-invalid-config.test.js +0 -52
  525. package/dist/cli/__tests__/doctor-invalid-config.test.js.map +0 -1
  526. package/dist/cli/__tests__/doctor-team.test.d.ts +0 -2
  527. package/dist/cli/__tests__/doctor-team.test.d.ts.map +0 -1
  528. package/dist/cli/__tests__/doctor-team.test.js +0 -299
  529. package/dist/cli/__tests__/doctor-team.test.js.map +0 -1
  530. package/dist/cli/__tests__/doctor-warning-copy.test.d.ts +0 -2
  531. package/dist/cli/__tests__/doctor-warning-copy.test.d.ts.map +0 -1
  532. package/dist/cli/__tests__/doctor-warning-copy.test.js +0 -438
  533. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +0 -1
  534. package/dist/cli/__tests__/error-handling-warnings.test.d.ts +0 -2
  535. package/dist/cli/__tests__/error-handling-warnings.test.d.ts.map +0 -1
  536. package/dist/cli/__tests__/error-handling-warnings.test.js +0 -52
  537. package/dist/cli/__tests__/error-handling-warnings.test.js.map +0 -1
  538. package/dist/cli/__tests__/exec.test.d.ts +0 -2
  539. package/dist/cli/__tests__/exec.test.d.ts.map +0 -1
  540. package/dist/cli/__tests__/exec.test.js +0 -213
  541. package/dist/cli/__tests__/exec.test.js.map +0 -1
  542. package/dist/cli/__tests__/explore-windows-diagnostics.test.d.ts +0 -2
  543. package/dist/cli/__tests__/explore-windows-diagnostics.test.d.ts.map +0 -1
  544. package/dist/cli/__tests__/explore-windows-diagnostics.test.js +0 -17
  545. package/dist/cli/__tests__/explore-windows-diagnostics.test.js.map +0 -1
  546. package/dist/cli/__tests__/explore.test.d.ts +0 -2
  547. package/dist/cli/__tests__/explore.test.d.ts.map +0 -1
  548. package/dist/cli/__tests__/explore.test.js +0 -1090
  549. package/dist/cli/__tests__/explore.test.js.map +0 -1
  550. package/dist/cli/__tests__/hooks.test.d.ts +0 -2
  551. package/dist/cli/__tests__/hooks.test.d.ts.map +0 -1
  552. package/dist/cli/__tests__/hooks.test.js +0 -55
  553. package/dist/cli/__tests__/hooks.test.js.map +0 -1
  554. package/dist/cli/__tests__/index.test.d.ts +0 -2
  555. package/dist/cli/__tests__/index.test.d.ts.map +0 -1
  556. package/dist/cli/__tests__/index.test.js +0 -2259
  557. package/dist/cli/__tests__/index.test.js.map +0 -1
  558. package/dist/cli/__tests__/launch-fallback.test.d.ts +0 -2
  559. package/dist/cli/__tests__/launch-fallback.test.d.ts.map +0 -1
  560. package/dist/cli/__tests__/launch-fallback.test.js +0 -661
  561. package/dist/cli/__tests__/launch-fallback.test.js.map +0 -1
  562. package/dist/cli/__tests__/lifecycle-notifications.test.d.ts +0 -2
  563. package/dist/cli/__tests__/lifecycle-notifications.test.d.ts.map +0 -1
  564. package/dist/cli/__tests__/lifecycle-notifications.test.js +0 -48
  565. package/dist/cli/__tests__/lifecycle-notifications.test.js.map +0 -1
  566. package/dist/cli/__tests__/list.test.d.ts +0 -2
  567. package/dist/cli/__tests__/list.test.d.ts.map +0 -1
  568. package/dist/cli/__tests__/list.test.js +0 -38
  569. package/dist/cli/__tests__/list.test.js.map +0 -1
  570. package/dist/cli/__tests__/mcp-parity.test.d.ts +0 -2
  571. package/dist/cli/__tests__/mcp-parity.test.d.ts.map +0 -1
  572. package/dist/cli/__tests__/mcp-parity.test.js +0 -228
  573. package/dist/cli/__tests__/mcp-parity.test.js.map +0 -1
  574. package/dist/cli/__tests__/mcp-serve.test.d.ts +0 -2
  575. package/dist/cli/__tests__/mcp-serve.test.d.ts.map +0 -1
  576. package/dist/cli/__tests__/mcp-serve.test.js +0 -64
  577. package/dist/cli/__tests__/mcp-serve.test.js.map +0 -1
  578. package/dist/cli/__tests__/native-assets.test.d.ts +0 -2
  579. package/dist/cli/__tests__/native-assets.test.d.ts.map +0 -1
  580. package/dist/cli/__tests__/native-assets.test.js +0 -308
  581. package/dist/cli/__tests__/native-assets.test.js.map +0 -1
  582. package/dist/cli/__tests__/native-hook-dispatch-contract.test.d.ts +0 -2
  583. package/dist/cli/__tests__/native-hook-dispatch-contract.test.d.ts.map +0 -1
  584. package/dist/cli/__tests__/native-hook-dispatch-contract.test.js +0 -11
  585. package/dist/cli/__tests__/native-hook-dispatch-contract.test.js.map +0 -1
  586. package/dist/cli/__tests__/nested-help-routing.test.d.ts +0 -2
  587. package/dist/cli/__tests__/nested-help-routing.test.d.ts.map +0 -1
  588. package/dist/cli/__tests__/nested-help-routing.test.js +0 -96
  589. package/dist/cli/__tests__/nested-help-routing.test.js.map +0 -1
  590. package/dist/cli/__tests__/package-bin-contract.test.d.ts +0 -2
  591. package/dist/cli/__tests__/package-bin-contract.test.d.ts.map +0 -1
  592. package/dist/cli/__tests__/package-bin-contract.test.js +0 -177
  593. package/dist/cli/__tests__/package-bin-contract.test.js.map +0 -1
  594. package/dist/cli/__tests__/packaged-explore-harness-lock.d.ts +0 -3
  595. package/dist/cli/__tests__/packaged-explore-harness-lock.d.ts.map +0 -1
  596. package/dist/cli/__tests__/packaged-explore-harness-lock.js +0 -67
  597. package/dist/cli/__tests__/packaged-explore-harness-lock.js.map +0 -1
  598. package/dist/cli/__tests__/packaged-script-resolution.test.d.ts +0 -2
  599. package/dist/cli/__tests__/packaged-script-resolution.test.d.ts.map +0 -1
  600. package/dist/cli/__tests__/packaged-script-resolution.test.js +0 -19
  601. package/dist/cli/__tests__/packaged-script-resolution.test.js.map +0 -1
  602. package/dist/cli/__tests__/prompt-skill-sanitization.test.d.ts +0 -2
  603. package/dist/cli/__tests__/prompt-skill-sanitization.test.d.ts.map +0 -1
  604. package/dist/cli/__tests__/prompt-skill-sanitization.test.js +0 -48
  605. package/dist/cli/__tests__/prompt-skill-sanitization.test.js.map +0 -1
  606. package/dist/cli/__tests__/question.test.d.ts +0 -2
  607. package/dist/cli/__tests__/question.test.d.ts.map +0 -1
  608. package/dist/cli/__tests__/question.test.js +0 -633
  609. package/dist/cli/__tests__/question.test.js.map +0 -1
  610. package/dist/cli/__tests__/ralph-deslop-contract.test.d.ts +0 -2
  611. package/dist/cli/__tests__/ralph-deslop-contract.test.d.ts.map +0 -1
  612. package/dist/cli/__tests__/ralph-deslop-contract.test.js +0 -28
  613. package/dist/cli/__tests__/ralph-deslop-contract.test.js.map +0 -1
  614. package/dist/cli/__tests__/ralph-prd-deep-interview.test.d.ts +0 -2
  615. package/dist/cli/__tests__/ralph-prd-deep-interview.test.d.ts.map +0 -1
  616. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js +0 -24
  617. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +0 -1
  618. package/dist/cli/__tests__/ralph-prd-smoke.test.d.ts +0 -2
  619. package/dist/cli/__tests__/ralph-prd-smoke.test.d.ts.map +0 -1
  620. package/dist/cli/__tests__/ralph-prd-smoke.test.js +0 -167
  621. package/dist/cli/__tests__/ralph-prd-smoke.test.js.map +0 -1
  622. package/dist/cli/__tests__/ralph.test.d.ts +0 -2
  623. package/dist/cli/__tests__/ralph.test.d.ts.map +0 -1
  624. package/dist/cli/__tests__/ralph.test.js +0 -256
  625. package/dist/cli/__tests__/ralph.test.js.map +0 -1
  626. package/dist/cli/__tests__/resume.test.d.ts +0 -2
  627. package/dist/cli/__tests__/resume.test.d.ts.map +0 -1
  628. package/dist/cli/__tests__/resume.test.js +0 -84
  629. package/dist/cli/__tests__/resume.test.js.map +0 -1
  630. package/dist/cli/__tests__/session-scoped-runtime.test.d.ts +0 -2
  631. package/dist/cli/__tests__/session-scoped-runtime.test.d.ts.map +0 -1
  632. package/dist/cli/__tests__/session-scoped-runtime.test.js +0 -146
  633. package/dist/cli/__tests__/session-scoped-runtime.test.js.map +0 -1
  634. package/dist/cli/__tests__/session-search-help.test.d.ts +0 -2
  635. package/dist/cli/__tests__/session-search-help.test.d.ts.map +0 -1
  636. package/dist/cli/__tests__/session-search-help.test.js +0 -76
  637. package/dist/cli/__tests__/session-search-help.test.js.map +0 -1
  638. package/dist/cli/__tests__/session-search.test.d.ts +0 -2
  639. package/dist/cli/__tests__/session-search.test.d.ts.map +0 -1
  640. package/dist/cli/__tests__/session-search.test.js +0 -77
  641. package/dist/cli/__tests__/session-search.test.js.map +0 -1
  642. package/dist/cli/__tests__/setup-agents-overwrite.test.d.ts +0 -2
  643. package/dist/cli/__tests__/setup-agents-overwrite.test.d.ts.map +0 -1
  644. package/dist/cli/__tests__/setup-agents-overwrite.test.js +0 -457
  645. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +0 -1
  646. package/dist/cli/__tests__/setup-gh-star.test.d.ts +0 -2
  647. package/dist/cli/__tests__/setup-gh-star.test.d.ts.map +0 -1
  648. package/dist/cli/__tests__/setup-gh-star.test.js +0 -67
  649. package/dist/cli/__tests__/setup-gh-star.test.js.map +0 -1
  650. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.d.ts +0 -2
  651. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.d.ts.map +0 -1
  652. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +0 -189
  653. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +0 -1
  654. package/dist/cli/__tests__/setup-install-mode.test.d.ts +0 -2
  655. package/dist/cli/__tests__/setup-install-mode.test.d.ts.map +0 -1
  656. package/dist/cli/__tests__/setup-install-mode.test.js +0 -873
  657. package/dist/cli/__tests__/setup-install-mode.test.js.map +0 -1
  658. package/dist/cli/__tests__/setup-prompts-overwrite.test.d.ts +0 -2
  659. package/dist/cli/__tests__/setup-prompts-overwrite.test.d.ts.map +0 -1
  660. package/dist/cli/__tests__/setup-prompts-overwrite.test.js +0 -191
  661. package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +0 -1
  662. package/dist/cli/__tests__/setup-refresh.test.d.ts +0 -2
  663. package/dist/cli/__tests__/setup-refresh.test.d.ts.map +0 -1
  664. package/dist/cli/__tests__/setup-refresh.test.js +0 -591
  665. package/dist/cli/__tests__/setup-refresh.test.js.map +0 -1
  666. package/dist/cli/__tests__/setup-scope.test.d.ts +0 -2
  667. package/dist/cli/__tests__/setup-scope.test.d.ts.map +0 -1
  668. package/dist/cli/__tests__/setup-scope.test.js +0 -340
  669. package/dist/cli/__tests__/setup-scope.test.js.map +0 -1
  670. package/dist/cli/__tests__/setup-skill-validation.test.d.ts +0 -2
  671. package/dist/cli/__tests__/setup-skill-validation.test.d.ts.map +0 -1
  672. package/dist/cli/__tests__/setup-skill-validation.test.js +0 -44
  673. package/dist/cli/__tests__/setup-skill-validation.test.js.map +0 -1
  674. package/dist/cli/__tests__/setup-skills-overwrite.test.d.ts +0 -2
  675. package/dist/cli/__tests__/setup-skills-overwrite.test.d.ts.map +0 -1
  676. package/dist/cli/__tests__/setup-skills-overwrite.test.js +0 -295
  677. package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +0 -1
  678. package/dist/cli/__tests__/sidecar.test.d.ts +0 -2
  679. package/dist/cli/__tests__/sidecar.test.d.ts.map +0 -1
  680. package/dist/cli/__tests__/sidecar.test.js +0 -24
  681. package/dist/cli/__tests__/sidecar.test.js.map +0 -1
  682. package/dist/cli/__tests__/sparkshell-cli.test.d.ts +0 -2
  683. package/dist/cli/__tests__/sparkshell-cli.test.d.ts.map +0 -1
  684. package/dist/cli/__tests__/sparkshell-cli.test.js +0 -400
  685. package/dist/cli/__tests__/sparkshell-cli.test.js.map +0 -1
  686. package/dist/cli/__tests__/sparkshell-packaging.test.d.ts +0 -2
  687. package/dist/cli/__tests__/sparkshell-packaging.test.d.ts.map +0 -1
  688. package/dist/cli/__tests__/sparkshell-packaging.test.js +0 -74
  689. package/dist/cli/__tests__/sparkshell-packaging.test.js.map +0 -1
  690. package/dist/cli/__tests__/star-prompt.test.d.ts +0 -2
  691. package/dist/cli/__tests__/star-prompt.test.d.ts.map +0 -1
  692. package/dist/cli/__tests__/star-prompt.test.js +0 -172
  693. package/dist/cli/__tests__/star-prompt.test.js.map +0 -1
  694. package/dist/cli/__tests__/state.test.d.ts +0 -2
  695. package/dist/cli/__tests__/state.test.d.ts.map +0 -1
  696. package/dist/cli/__tests__/state.test.js +0 -46
  697. package/dist/cli/__tests__/state.test.js.map +0 -1
  698. package/dist/cli/__tests__/team-decompose.test.d.ts +0 -2
  699. package/dist/cli/__tests__/team-decompose.test.d.ts.map +0 -1
  700. package/dist/cli/__tests__/team-decompose.test.js +0 -133
  701. package/dist/cli/__tests__/team-decompose.test.js.map +0 -1
  702. package/dist/cli/__tests__/team.test.d.ts +0 -2
  703. package/dist/cli/__tests__/team.test.d.ts.map +0 -1
  704. package/dist/cli/__tests__/team.test.js +0 -1820
  705. package/dist/cli/__tests__/team.test.js.map +0 -1
  706. package/dist/cli/__tests__/uninstall.test.d.ts +0 -2
  707. package/dist/cli/__tests__/uninstall.test.d.ts.map +0 -1
  708. package/dist/cli/__tests__/uninstall.test.js +0 -766
  709. package/dist/cli/__tests__/uninstall.test.js.map +0 -1
  710. package/dist/cli/__tests__/update.test.d.ts +0 -2
  711. package/dist/cli/__tests__/update.test.d.ts.map +0 -1
  712. package/dist/cli/__tests__/update.test.js +0 -589
  713. package/dist/cli/__tests__/update.test.js.map +0 -1
  714. package/dist/cli/__tests__/version-sync-contract.test.d.ts +0 -2
  715. package/dist/cli/__tests__/version-sync-contract.test.d.ts.map +0 -1
  716. package/dist/cli/__tests__/version-sync-contract.test.js +0 -41
  717. package/dist/cli/__tests__/version-sync-contract.test.js.map +0 -1
  718. package/dist/cli/__tests__/version.test.d.ts +0 -2
  719. package/dist/cli/__tests__/version.test.d.ts.map +0 -1
  720. package/dist/cli/__tests__/version.test.js +0 -21
  721. package/dist/cli/__tests__/version.test.js.map +0 -1
  722. package/dist/cli/__tests__/windows-popup-loop-contract.test.d.ts +0 -2
  723. package/dist/cli/__tests__/windows-popup-loop-contract.test.d.ts.map +0 -1
  724. package/dist/cli/__tests__/windows-popup-loop-contract.test.js +0 -31
  725. package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +0 -1
  726. package/dist/cli/ralph.d.ts +0 -17
  727. package/dist/compat/__tests__/doctor-contract.test.d.ts +0 -2
  728. package/dist/compat/__tests__/doctor-contract.test.d.ts.map +0 -1
  729. package/dist/compat/__tests__/doctor-contract.test.js +0 -108
  730. package/dist/compat/__tests__/doctor-contract.test.js.map +0 -1
  731. package/dist/compat/__tests__/rust-runtime-compat.test.d.ts +0 -2
  732. package/dist/compat/__tests__/rust-runtime-compat.test.d.ts.map +0 -1
  733. package/dist/compat/__tests__/rust-runtime-compat.test.js +0 -218
  734. package/dist/compat/__tests__/rust-runtime-compat.test.js.map +0 -1
  735. package/dist/config/__tests__/codex-hooks.test.d.ts +0 -2
  736. package/dist/config/__tests__/codex-hooks.test.d.ts.map +0 -1
  737. package/dist/config/__tests__/codex-hooks.test.js +0 -77
  738. package/dist/config/__tests__/codex-hooks.test.js.map +0 -1
  739. package/dist/config/__tests__/generator-idempotent.test.d.ts +0 -2
  740. package/dist/config/__tests__/generator-idempotent.test.d.ts.map +0 -1
  741. package/dist/config/__tests__/generator-idempotent.test.js +0 -882
  742. package/dist/config/__tests__/generator-idempotent.test.js.map +0 -1
  743. package/dist/config/__tests__/generator-notify.test.d.ts +0 -2
  744. package/dist/config/__tests__/generator-notify.test.d.ts.map +0 -1
  745. package/dist/config/__tests__/generator-notify.test.js +0 -343
  746. package/dist/config/__tests__/generator-notify.test.js.map +0 -1
  747. package/dist/config/__tests__/generator-status-line-presets.test.d.ts +0 -2
  748. package/dist/config/__tests__/generator-status-line-presets.test.d.ts.map +0 -1
  749. package/dist/config/__tests__/generator-status-line-presets.test.js +0 -203
  750. package/dist/config/__tests__/generator-status-line-presets.test.js.map +0 -1
  751. package/dist/config/__tests__/mcp-registry.test.d.ts +0 -2
  752. package/dist/config/__tests__/mcp-registry.test.d.ts.map +0 -1
  753. package/dist/config/__tests__/mcp-registry.test.js +0 -190
  754. package/dist/config/__tests__/mcp-registry.test.js.map +0 -1
  755. package/dist/config/__tests__/models.test.d.ts +0 -2
  756. package/dist/config/__tests__/models.test.d.ts.map +0 -1
  757. package/dist/config/__tests__/models.test.js +0 -224
  758. package/dist/config/__tests__/models.test.js.map +0 -1
  759. package/dist/config/__tests__/wiki-config-contract.test.d.ts +0 -2
  760. package/dist/config/__tests__/wiki-config-contract.test.d.ts.map +0 -1
  761. package/dist/config/__tests__/wiki-config-contract.test.js +0 -19
  762. package/dist/config/__tests__/wiki-config-contract.test.js.map +0 -1
  763. package/dist/document-refresh/__tests__/enforcer.test.d.ts +0 -2
  764. package/dist/document-refresh/__tests__/enforcer.test.d.ts.map +0 -1
  765. package/dist/document-refresh/__tests__/enforcer.test.js +0 -128
  766. package/dist/document-refresh/__tests__/enforcer.test.js.map +0 -1
  767. package/dist/hooks/__tests__/agents-overlay.test.d.ts +0 -8
  768. package/dist/hooks/__tests__/agents-overlay.test.d.ts.map +0 -1
  769. package/dist/hooks/__tests__/agents-overlay.test.js +0 -644
  770. package/dist/hooks/__tests__/agents-overlay.test.js.map +0 -1
  771. package/dist/hooks/__tests__/analyze-routing-contract.test.d.ts +0 -2
  772. package/dist/hooks/__tests__/analyze-routing-contract.test.d.ts.map +0 -1
  773. package/dist/hooks/__tests__/analyze-routing-contract.test.js +0 -45
  774. package/dist/hooks/__tests__/analyze-routing-contract.test.js.map +0 -1
  775. package/dist/hooks/__tests__/analyze-skill-contract.test.d.ts +0 -2
  776. package/dist/hooks/__tests__/analyze-skill-contract.test.d.ts.map +0 -1
  777. package/dist/hooks/__tests__/analyze-skill-contract.test.js +0 -48
  778. package/dist/hooks/__tests__/analyze-skill-contract.test.js.map +0 -1
  779. package/dist/hooks/__tests__/anti-slop-workflow.test.d.ts +0 -2
  780. package/dist/hooks/__tests__/anti-slop-workflow.test.d.ts.map +0 -1
  781. package/dist/hooks/__tests__/anti-slop-workflow.test.js +0 -146
  782. package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +0 -1
  783. package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts +0 -2
  784. package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts.map +0 -1
  785. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +0 -37
  786. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +0 -1
  787. package/dist/hooks/__tests__/clawhip-event-contract.test.d.ts +0 -2
  788. package/dist/hooks/__tests__/clawhip-event-contract.test.d.ts.map +0 -1
  789. package/dist/hooks/__tests__/clawhip-event-contract.test.js +0 -37
  790. package/dist/hooks/__tests__/clawhip-event-contract.test.js.map +0 -1
  791. package/dist/hooks/__tests__/code-review-skill-contract.test.d.ts +0 -2
  792. package/dist/hooks/__tests__/code-review-skill-contract.test.d.ts.map +0 -1
  793. package/dist/hooks/__tests__/code-review-skill-contract.test.js +0 -56
  794. package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +0 -1
  795. package/dist/hooks/__tests__/codebase-map.test.d.ts +0 -8
  796. package/dist/hooks/__tests__/codebase-map.test.d.ts.map +0 -1
  797. package/dist/hooks/__tests__/codebase-map.test.js +0 -218
  798. package/dist/hooks/__tests__/codebase-map.test.js.map +0 -1
  799. package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts +0 -18
  800. package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts.map +0 -1
  801. package/dist/hooks/__tests__/consensus-execution-handoff.test.js +0 -234
  802. package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +0 -1
  803. package/dist/hooks/__tests__/debugger-log-recency-contract.test.d.ts +0 -2
  804. package/dist/hooks/__tests__/debugger-log-recency-contract.test.d.ts.map +0 -1
  805. package/dist/hooks/__tests__/debugger-log-recency-contract.test.js +0 -20
  806. package/dist/hooks/__tests__/debugger-log-recency-contract.test.js.map +0 -1
  807. package/dist/hooks/__tests__/deep-interview-contract.test.d.ts +0 -2
  808. package/dist/hooks/__tests__/deep-interview-contract.test.d.ts.map +0 -1
  809. package/dist/hooks/__tests__/deep-interview-contract.test.js +0 -213
  810. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +0 -1
  811. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.d.ts +0 -2
  812. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.d.ts.map +0 -1
  813. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.js +0 -43
  814. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.js.map +0 -1
  815. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.d.ts +0 -2
  816. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.d.ts.map +0 -1
  817. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.js +0 -38
  818. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.js.map +0 -1
  819. package/dist/hooks/__tests__/explore-routing.test.d.ts +0 -2
  820. package/dist/hooks/__tests__/explore-routing.test.d.ts.map +0 -1
  821. package/dist/hooks/__tests__/explore-routing.test.js +0 -43
  822. package/dist/hooks/__tests__/explore-routing.test.js.map +0 -1
  823. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.d.ts +0 -2
  824. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.d.ts.map +0 -1
  825. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js +0 -69
  826. package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js.map +0 -1
  827. package/dist/hooks/__tests__/keyword-detector.test.d.ts +0 -2
  828. package/dist/hooks/__tests__/keyword-detector.test.d.ts.map +0 -1
  829. package/dist/hooks/__tests__/keyword-detector.test.js +0 -1716
  830. package/dist/hooks/__tests__/keyword-detector.test.js.map +0 -1
  831. package/dist/hooks/__tests__/notify-fallback-watcher.test.d.ts +0 -2
  832. package/dist/hooks/__tests__/notify-fallback-watcher.test.d.ts.map +0 -1
  833. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +0 -3898
  834. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +0 -1
  835. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.d.ts +0 -2
  836. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.d.ts.map +0 -1
  837. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +0 -786
  838. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +0 -1
  839. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.d.ts +0 -2
  840. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.d.ts.map +0 -1
  841. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +0 -2397
  842. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +0 -1
  843. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.d.ts +0 -2
  844. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.d.ts.map +0 -1
  845. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +0 -160
  846. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +0 -1
  847. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.d.ts +0 -2
  848. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.d.ts.map +0 -1
  849. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +0 -1178
  850. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +0 -1
  851. package/dist/hooks/__tests__/notify-hook-modules.test.d.ts +0 -9
  852. package/dist/hooks/__tests__/notify-hook-modules.test.d.ts.map +0 -1
  853. package/dist/hooks/__tests__/notify-hook-modules.test.js +0 -529
  854. package/dist/hooks/__tests__/notify-hook-modules.test.js.map +0 -1
  855. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.d.ts +0 -2
  856. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.d.ts.map +0 -1
  857. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.js +0 -14
  858. package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.js.map +0 -1
  859. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.d.ts +0 -2
  860. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.d.ts.map +0 -1
  861. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +0 -682
  862. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +0 -1
  863. package/dist/hooks/__tests__/notify-hook-regression-205.test.d.ts +0 -9
  864. package/dist/hooks/__tests__/notify-hook-regression-205.test.d.ts.map +0 -1
  865. package/dist/hooks/__tests__/notify-hook-regression-205.test.js +0 -255
  866. package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +0 -1
  867. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.d.ts +0 -2
  868. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.d.ts.map +0 -1
  869. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js +0 -162
  870. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js.map +0 -1
  871. package/dist/hooks/__tests__/notify-hook-session-scope.test.d.ts +0 -2
  872. package/dist/hooks/__tests__/notify-hook-session-scope.test.d.ts.map +0 -1
  873. package/dist/hooks/__tests__/notify-hook-session-scope.test.js +0 -301
  874. package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +0 -1
  875. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.d.ts +0 -2
  876. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.d.ts.map +0 -1
  877. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +0 -1510
  878. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +0 -1
  879. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.d.ts +0 -2
  880. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.d.ts.map +0 -1
  881. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +0 -2879
  882. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +0 -1
  883. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.d.ts +0 -2
  884. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.d.ts.map +0 -1
  885. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +0 -228
  886. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +0 -1
  887. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts +0 -2
  888. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts.map +0 -1
  889. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js +0 -35
  890. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js.map +0 -1
  891. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.d.ts +0 -2
  892. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.d.ts.map +0 -1
  893. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +0 -1589
  894. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +0 -1
  895. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.d.ts +0 -10
  896. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.d.ts.map +0 -1
  897. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +0 -0
  898. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +0 -1
  899. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.d.ts +0 -11
  900. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.d.ts.map +0 -1
  901. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js +0 -266
  902. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js.map +0 -1
  903. package/dist/hooks/__tests__/notify-hook-worker-idle.test.d.ts +0 -2
  904. package/dist/hooks/__tests__/notify-hook-worker-idle.test.d.ts.map +0 -1
  905. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +0 -895
  906. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +0 -1
  907. package/dist/hooks/__tests__/openclaw-setup-contract.test.d.ts +0 -2
  908. package/dist/hooks/__tests__/openclaw-setup-contract.test.d.ts.map +0 -1
  909. package/dist/hooks/__tests__/openclaw-setup-contract.test.js +0 -61
  910. package/dist/hooks/__tests__/openclaw-setup-contract.test.js.map +0 -1
  911. package/dist/hooks/__tests__/pre-context-gate-skills.test.d.ts +0 -2
  912. package/dist/hooks/__tests__/pre-context-gate-skills.test.d.ts.map +0 -1
  913. package/dist/hooks/__tests__/pre-context-gate-skills.test.js +0 -40
  914. package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +0 -1
  915. package/dist/hooks/__tests__/prompt-guidance-catalog.test.d.ts +0 -2
  916. package/dist/hooks/__tests__/prompt-guidance-catalog.test.d.ts.map +0 -1
  917. package/dist/hooks/__tests__/prompt-guidance-catalog.test.js +0 -11
  918. package/dist/hooks/__tests__/prompt-guidance-catalog.test.js.map +0 -1
  919. package/dist/hooks/__tests__/prompt-guidance-contract.test.d.ts +0 -2
  920. package/dist/hooks/__tests__/prompt-guidance-contract.test.d.ts.map +0 -1
  921. package/dist/hooks/__tests__/prompt-guidance-contract.test.js +0 -38
  922. package/dist/hooks/__tests__/prompt-guidance-contract.test.js.map +0 -1
  923. package/dist/hooks/__tests__/prompt-guidance-fragments.test.d.ts +0 -2
  924. package/dist/hooks/__tests__/prompt-guidance-fragments.test.d.ts.map +0 -1
  925. package/dist/hooks/__tests__/prompt-guidance-fragments.test.js +0 -48
  926. package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +0 -1
  927. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.d.ts +0 -2
  928. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.d.ts.map +0 -1
  929. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.js +0 -11
  930. package/dist/hooks/__tests__/prompt-guidance-scenarios.test.js.map +0 -1
  931. package/dist/hooks/__tests__/prompt-guidance-test-helpers.d.ts +0 -5
  932. package/dist/hooks/__tests__/prompt-guidance-test-helpers.d.ts.map +0 -1
  933. package/dist/hooks/__tests__/prompt-guidance-test-helpers.js +0 -34
  934. package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +0 -1
  935. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.d.ts +0 -2
  936. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.d.ts.map +0 -1
  937. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +0 -65
  938. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +0 -1
  939. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.d.ts +0 -2
  940. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.d.ts.map +0 -1
  941. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.js +0 -38
  942. package/dist/hooks/__tests__/prompt-orchestration-boundary.test.js.map +0 -1
  943. package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts +0 -2
  944. package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts.map +0 -1
  945. package/dist/hooks/__tests__/prompt-refactor-contract.test.js +0 -22
  946. package/dist/hooks/__tests__/prompt-refactor-contract.test.js.map +0 -1
  947. package/dist/hooks/__tests__/prompt-team-routing.test.d.ts +0 -2
  948. package/dist/hooks/__tests__/prompt-team-routing.test.d.ts.map +0 -1
  949. package/dist/hooks/__tests__/prompt-team-routing.test.js +0 -49
  950. package/dist/hooks/__tests__/prompt-team-routing.test.js.map +0 -1
  951. package/dist/hooks/__tests__/session.test.d.ts +0 -2
  952. package/dist/hooks/__tests__/session.test.d.ts.map +0 -1
  953. package/dist/hooks/__tests__/session.test.js +0 -322
  954. package/dist/hooks/__tests__/session.test.js.map +0 -1
  955. package/dist/hooks/__tests__/skill-guidance-contract.test.d.ts +0 -2
  956. package/dist/hooks/__tests__/skill-guidance-contract.test.d.ts.map +0 -1
  957. package/dist/hooks/__tests__/skill-guidance-contract.test.js +0 -29
  958. package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +0 -1
  959. package/dist/hooks/__tests__/task-size-detector.test.d.ts +0 -2
  960. package/dist/hooks/__tests__/task-size-detector.test.d.ts.map +0 -1
  961. package/dist/hooks/__tests__/task-size-detector.test.js +0 -330
  962. package/dist/hooks/__tests__/task-size-detector.test.js.map +0 -1
  963. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.d.ts +0 -2
  964. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.d.ts.map +0 -1
  965. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js +0 -28
  966. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js.map +0 -1
  967. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.d.ts +0 -2
  968. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.d.ts.map +0 -1
  969. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.js +0 -24
  970. package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.js.map +0 -1
  971. package/dist/hooks/__tests__/tmux-hook-engine.test.d.ts +0 -2
  972. package/dist/hooks/__tests__/tmux-hook-engine.test.d.ts.map +0 -1
  973. package/dist/hooks/__tests__/tmux-hook-engine.test.js +0 -403
  974. package/dist/hooks/__tests__/tmux-hook-engine.test.js.map +0 -1
  975. package/dist/hooks/__tests__/triage-config.test.d.ts +0 -2
  976. package/dist/hooks/__tests__/triage-config.test.d.ts.map +0 -1
  977. package/dist/hooks/__tests__/triage-config.test.js +0 -211
  978. package/dist/hooks/__tests__/triage-config.test.js.map +0 -1
  979. package/dist/hooks/__tests__/triage-heuristic.test.d.ts +0 -2
  980. package/dist/hooks/__tests__/triage-heuristic.test.d.ts.map +0 -1
  981. package/dist/hooks/__tests__/triage-heuristic.test.js +0 -285
  982. package/dist/hooks/__tests__/triage-heuristic.test.js.map +0 -1
  983. package/dist/hooks/__tests__/triage-state.test.d.ts +0 -2
  984. package/dist/hooks/__tests__/triage-state.test.d.ts.map +0 -1
  985. package/dist/hooks/__tests__/triage-state.test.js +0 -426
  986. package/dist/hooks/__tests__/triage-state.test.js.map +0 -1
  987. package/dist/hooks/__tests__/visual-ralph-skill.test.d.ts +0 -2
  988. package/dist/hooks/__tests__/visual-ralph-skill.test.d.ts.map +0 -1
  989. package/dist/hooks/__tests__/visual-ralph-skill.test.js +0 -44
  990. package/dist/hooks/__tests__/visual-ralph-skill.test.js.map +0 -1
  991. package/dist/hooks/__tests__/visual-verdict-loop.test.d.ts +0 -2
  992. package/dist/hooks/__tests__/visual-verdict-loop.test.d.ts.map +0 -1
  993. package/dist/hooks/__tests__/visual-verdict-loop.test.js +0 -35
  994. package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +0 -1
  995. package/dist/hooks/__tests__/wiki-docs-contract.test.d.ts +0 -2
  996. package/dist/hooks/__tests__/wiki-docs-contract.test.d.ts.map +0 -1
  997. package/dist/hooks/__tests__/wiki-docs-contract.test.js +0 -34
  998. package/dist/hooks/__tests__/wiki-docs-contract.test.js.map +0 -1
  999. package/dist/hooks/code-simplifier/__tests__/index.test.d.ts +0 -2
  1000. package/dist/hooks/code-simplifier/__tests__/index.test.d.ts.map +0 -1
  1001. package/dist/hooks/code-simplifier/__tests__/index.test.js +0 -187
  1002. package/dist/hooks/code-simplifier/__tests__/index.test.js.map +0 -1
  1003. package/dist/hooks/extensibility/__tests__/dispatcher.test.d.ts +0 -2
  1004. package/dist/hooks/extensibility/__tests__/dispatcher.test.d.ts.map +0 -1
  1005. package/dist/hooks/extensibility/__tests__/dispatcher.test.js +0 -242
  1006. package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +0 -1
  1007. package/dist/hooks/extensibility/__tests__/events.test.d.ts +0 -2
  1008. package/dist/hooks/extensibility/__tests__/events.test.d.ts.map +0 -1
  1009. package/dist/hooks/extensibility/__tests__/events.test.js +0 -125
  1010. package/dist/hooks/extensibility/__tests__/events.test.js.map +0 -1
  1011. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.d.ts +0 -2
  1012. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.d.ts.map +0 -1
  1013. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.js +0 -153
  1014. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.js.map +0 -1
  1015. package/dist/hooks/extensibility/__tests__/loader.test.d.ts +0 -2
  1016. package/dist/hooks/extensibility/__tests__/loader.test.d.ts.map +0 -1
  1017. package/dist/hooks/extensibility/__tests__/loader.test.js +0 -254
  1018. package/dist/hooks/extensibility/__tests__/loader.test.js.map +0 -1
  1019. package/dist/hooks/extensibility/__tests__/logging.test.d.ts +0 -2
  1020. package/dist/hooks/extensibility/__tests__/logging.test.d.ts.map +0 -1
  1021. package/dist/hooks/extensibility/__tests__/logging.test.js +0 -74
  1022. package/dist/hooks/extensibility/__tests__/logging.test.js.map +0 -1
  1023. package/dist/hooks/extensibility/__tests__/plugin-runner.test.d.ts +0 -2
  1024. package/dist/hooks/extensibility/__tests__/plugin-runner.test.d.ts.map +0 -1
  1025. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js +0 -202
  1026. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js.map +0 -1
  1027. package/dist/hooks/extensibility/__tests__/runtime.test.d.ts +0 -2
  1028. package/dist/hooks/extensibility/__tests__/runtime.test.d.ts.map +0 -1
  1029. package/dist/hooks/extensibility/__tests__/runtime.test.js +0 -198
  1030. package/dist/hooks/extensibility/__tests__/runtime.test.js.map +0 -1
  1031. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.d.ts +0 -2
  1032. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.d.ts.map +0 -1
  1033. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.js +0 -32
  1034. package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.js.map +0 -1
  1035. package/dist/hooks/extensibility/__tests__/sdk.test.d.ts +0 -2
  1036. package/dist/hooks/extensibility/__tests__/sdk.test.d.ts.map +0 -1
  1037. package/dist/hooks/extensibility/__tests__/sdk.test.js +0 -479
  1038. package/dist/hooks/extensibility/__tests__/sdk.test.js.map +0 -1
  1039. package/dist/hud/__tests__/authority.test.d.ts +0 -2
  1040. package/dist/hud/__tests__/authority.test.d.ts.map +0 -1
  1041. package/dist/hud/__tests__/authority.test.js +0 -56
  1042. package/dist/hud/__tests__/authority.test.js.map +0 -1
  1043. package/dist/hud/__tests__/colors.test.d.ts +0 -2
  1044. package/dist/hud/__tests__/colors.test.d.ts.map +0 -1
  1045. package/dist/hud/__tests__/colors.test.js +0 -92
  1046. package/dist/hud/__tests__/colors.test.js.map +0 -1
  1047. package/dist/hud/__tests__/hud-tmux-injection.test.d.ts +0 -10
  1048. package/dist/hud/__tests__/hud-tmux-injection.test.d.ts.map +0 -1
  1049. package/dist/hud/__tests__/hud-tmux-injection.test.js +0 -150
  1050. package/dist/hud/__tests__/hud-tmux-injection.test.js.map +0 -1
  1051. package/dist/hud/__tests__/index.test.d.ts +0 -2
  1052. package/dist/hud/__tests__/index.test.d.ts.map +0 -1
  1053. package/dist/hud/__tests__/index.test.js +0 -180
  1054. package/dist/hud/__tests__/index.test.js.map +0 -1
  1055. package/dist/hud/__tests__/reconcile.test.d.ts +0 -2
  1056. package/dist/hud/__tests__/reconcile.test.d.ts.map +0 -1
  1057. package/dist/hud/__tests__/reconcile.test.js +0 -125
  1058. package/dist/hud/__tests__/reconcile.test.js.map +0 -1
  1059. package/dist/hud/__tests__/render.test.d.ts +0 -2
  1060. package/dist/hud/__tests__/render.test.d.ts.map +0 -1
  1061. package/dist/hud/__tests__/render.test.js +0 -573
  1062. package/dist/hud/__tests__/render.test.js.map +0 -1
  1063. package/dist/hud/__tests__/state.test.d.ts +0 -2
  1064. package/dist/hud/__tests__/state.test.d.ts.map +0 -1
  1065. package/dist/hud/__tests__/state.test.js +0 -618
  1066. package/dist/hud/__tests__/state.test.js.map +0 -1
  1067. package/dist/hud/__tests__/types.test.d.ts +0 -2
  1068. package/dist/hud/__tests__/types.test.d.ts.map +0 -1
  1069. package/dist/hud/__tests__/types.test.js +0 -79
  1070. package/dist/hud/__tests__/types.test.js.map +0 -1
  1071. package/dist/hud/__tests__/watch.test.d.ts +0 -2
  1072. package/dist/hud/__tests__/watch.test.d.ts.map +0 -1
  1073. package/dist/hud/__tests__/watch.test.js +0 -63
  1074. package/dist/hud/__tests__/watch.test.js.map +0 -1
  1075. package/dist/mcp/__tests__/bootstrap.test.d.ts +0 -2
  1076. package/dist/mcp/__tests__/bootstrap.test.d.ts.map +0 -1
  1077. package/dist/mcp/__tests__/bootstrap.test.js +0 -207
  1078. package/dist/mcp/__tests__/bootstrap.test.js.map +0 -1
  1079. package/dist/mcp/__tests__/code-intel-server.test.d.ts +0 -2
  1080. package/dist/mcp/__tests__/code-intel-server.test.d.ts.map +0 -1
  1081. package/dist/mcp/__tests__/code-intel-server.test.js +0 -70
  1082. package/dist/mcp/__tests__/code-intel-server.test.js.map +0 -1
  1083. package/dist/mcp/__tests__/memory-server.test.d.ts +0 -2
  1084. package/dist/mcp/__tests__/memory-server.test.d.ts.map +0 -1
  1085. package/dist/mcp/__tests__/memory-server.test.js +0 -36
  1086. package/dist/mcp/__tests__/memory-server.test.js.map +0 -1
  1087. package/dist/mcp/__tests__/memory-validation.test.d.ts +0 -2
  1088. package/dist/mcp/__tests__/memory-validation.test.d.ts.map +0 -1
  1089. package/dist/mcp/__tests__/memory-validation.test.js +0 -29
  1090. package/dist/mcp/__tests__/memory-validation.test.js.map +0 -1
  1091. package/dist/mcp/__tests__/path-traversal.test.d.ts +0 -2
  1092. package/dist/mcp/__tests__/path-traversal.test.d.ts.map +0 -1
  1093. package/dist/mcp/__tests__/path-traversal.test.js +0 -83
  1094. package/dist/mcp/__tests__/path-traversal.test.js.map +0 -1
  1095. package/dist/mcp/__tests__/server-lifecycle.test.d.ts +0 -2
  1096. package/dist/mcp/__tests__/server-lifecycle.test.d.ts.map +0 -1
  1097. package/dist/mcp/__tests__/server-lifecycle.test.js +0 -260
  1098. package/dist/mcp/__tests__/server-lifecycle.test.js.map +0 -1
  1099. package/dist/mcp/__tests__/state-paths.test.d.ts +0 -2
  1100. package/dist/mcp/__tests__/state-paths.test.d.ts.map +0 -1
  1101. package/dist/mcp/__tests__/state-paths.test.js +0 -209
  1102. package/dist/mcp/__tests__/state-paths.test.js.map +0 -1
  1103. package/dist/mcp/__tests__/state-server-ralph-phase.test.d.ts +0 -2
  1104. package/dist/mcp/__tests__/state-server-ralph-phase.test.d.ts.map +0 -1
  1105. package/dist/mcp/__tests__/state-server-ralph-phase.test.js +0 -109
  1106. package/dist/mcp/__tests__/state-server-ralph-phase.test.js.map +0 -1
  1107. package/dist/mcp/__tests__/state-server-schema.test.d.ts +0 -2
  1108. package/dist/mcp/__tests__/state-server-schema.test.d.ts.map +0 -1
  1109. package/dist/mcp/__tests__/state-server-schema.test.js +0 -29
  1110. package/dist/mcp/__tests__/state-server-schema.test.js.map +0 -1
  1111. package/dist/mcp/__tests__/state-server-team-tools.test.d.ts +0 -2
  1112. package/dist/mcp/__tests__/state-server-team-tools.test.d.ts.map +0 -1
  1113. package/dist/mcp/__tests__/state-server-team-tools.test.js +0 -35
  1114. package/dist/mcp/__tests__/state-server-team-tools.test.js.map +0 -1
  1115. package/dist/mcp/__tests__/state-server.test.d.ts +0 -2
  1116. package/dist/mcp/__tests__/state-server.test.d.ts.map +0 -1
  1117. package/dist/mcp/__tests__/state-server.test.js +0 -965
  1118. package/dist/mcp/__tests__/state-server.test.js.map +0 -1
  1119. package/dist/mcp/__tests__/trace-server.test.d.ts +0 -2
  1120. package/dist/mcp/__tests__/trace-server.test.d.ts.map +0 -1
  1121. package/dist/mcp/__tests__/trace-server.test.js +0 -119
  1122. package/dist/mcp/__tests__/trace-server.test.js.map +0 -1
  1123. package/dist/mcp/__tests__/wiki-server.test.d.ts +0 -2
  1124. package/dist/mcp/__tests__/wiki-server.test.d.ts.map +0 -1
  1125. package/dist/mcp/__tests__/wiki-server.test.js +0 -30
  1126. package/dist/mcp/__tests__/wiki-server.test.js.map +0 -1
  1127. package/dist/modes/__tests__/base-autoresearch-contract.test.d.ts +0 -2
  1128. package/dist/modes/__tests__/base-autoresearch-contract.test.d.ts.map +0 -1
  1129. package/dist/modes/__tests__/base-autoresearch-contract.test.js +0 -123
  1130. package/dist/modes/__tests__/base-autoresearch-contract.test.js.map +0 -1
  1131. package/dist/modes/__tests__/base-multi-state-compat.test.d.ts +0 -2
  1132. package/dist/modes/__tests__/base-multi-state-compat.test.d.ts.map +0 -1
  1133. package/dist/modes/__tests__/base-multi-state-compat.test.js +0 -38
  1134. package/dist/modes/__tests__/base-multi-state-compat.test.js.map +0 -1
  1135. package/dist/modes/__tests__/base-ralph-contract.test.d.ts +0 -2
  1136. package/dist/modes/__tests__/base-ralph-contract.test.d.ts.map +0 -1
  1137. package/dist/modes/__tests__/base-ralph-contract.test.js +0 -64
  1138. package/dist/modes/__tests__/base-ralph-contract.test.js.map +0 -1
  1139. package/dist/modes/__tests__/base-session-scope.test.d.ts +0 -2
  1140. package/dist/modes/__tests__/base-session-scope.test.d.ts.map +0 -1
  1141. package/dist/modes/__tests__/base-session-scope.test.js +0 -98
  1142. package/dist/modes/__tests__/base-session-scope.test.js.map +0 -1
  1143. package/dist/modes/__tests__/base-tmux-pane.test.d.ts +0 -2
  1144. package/dist/modes/__tests__/base-tmux-pane.test.d.ts.map +0 -1
  1145. package/dist/modes/__tests__/base-tmux-pane.test.js +0 -39
  1146. package/dist/modes/__tests__/base-tmux-pane.test.js.map +0 -1
  1147. package/dist/notifications/__tests__/config.test.d.ts +0 -2
  1148. package/dist/notifications/__tests__/config.test.d.ts.map +0 -1
  1149. package/dist/notifications/__tests__/config.test.js +0 -269
  1150. package/dist/notifications/__tests__/config.test.js.map +0 -1
  1151. package/dist/notifications/__tests__/custom-alias-enablement.test.d.ts +0 -2
  1152. package/dist/notifications/__tests__/custom-alias-enablement.test.d.ts.map +0 -1
  1153. package/dist/notifications/__tests__/custom-alias-enablement.test.js +0 -84
  1154. package/dist/notifications/__tests__/custom-alias-enablement.test.js.map +0 -1
  1155. package/dist/notifications/__tests__/dispatch-cooldown.test.d.ts +0 -5
  1156. package/dist/notifications/__tests__/dispatch-cooldown.test.d.ts.map +0 -1
  1157. package/dist/notifications/__tests__/dispatch-cooldown.test.js +0 -100
  1158. package/dist/notifications/__tests__/dispatch-cooldown.test.js.map +0 -1
  1159. package/dist/notifications/__tests__/dispatcher.test.d.ts +0 -2
  1160. package/dist/notifications/__tests__/dispatcher.test.d.ts.map +0 -1
  1161. package/dist/notifications/__tests__/dispatcher.test.js +0 -202
  1162. package/dist/notifications/__tests__/dispatcher.test.js.map +0 -1
  1163. package/dist/notifications/__tests__/formatter.test.d.ts +0 -2
  1164. package/dist/notifications/__tests__/formatter.test.d.ts.map +0 -1
  1165. package/dist/notifications/__tests__/formatter.test.js +0 -270
  1166. package/dist/notifications/__tests__/formatter.test.js.map +0 -1
  1167. package/dist/notifications/__tests__/hook-config.test.d.ts +0 -5
  1168. package/dist/notifications/__tests__/hook-config.test.d.ts.map +0 -1
  1169. package/dist/notifications/__tests__/hook-config.test.js +0 -139
  1170. package/dist/notifications/__tests__/hook-config.test.js.map +0 -1
  1171. package/dist/notifications/__tests__/idle-cooldown.test.d.ts +0 -5
  1172. package/dist/notifications/__tests__/idle-cooldown.test.d.ts.map +0 -1
  1173. package/dist/notifications/__tests__/idle-cooldown.test.js +0 -209
  1174. package/dist/notifications/__tests__/idle-cooldown.test.js.map +0 -1
  1175. package/dist/notifications/__tests__/index.test.d.ts +0 -2
  1176. package/dist/notifications/__tests__/index.test.d.ts.map +0 -1
  1177. package/dist/notifications/__tests__/index.test.js +0 -188
  1178. package/dist/notifications/__tests__/index.test.js.map +0 -1
  1179. package/dist/notifications/__tests__/lifecycle-dedupe.test.d.ts +0 -2
  1180. package/dist/notifications/__tests__/lifecycle-dedupe.test.d.ts.map +0 -1
  1181. package/dist/notifications/__tests__/lifecycle-dedupe.test.js +0 -86
  1182. package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +0 -1
  1183. package/dist/notifications/__tests__/notifier.test.d.ts +0 -2
  1184. package/dist/notifications/__tests__/notifier.test.d.ts.map +0 -1
  1185. package/dist/notifications/__tests__/notifier.test.js +0 -239
  1186. package/dist/notifications/__tests__/notifier.test.js.map +0 -1
  1187. package/dist/notifications/__tests__/profiles.test.d.ts +0 -2
  1188. package/dist/notifications/__tests__/profiles.test.d.ts.map +0 -1
  1189. package/dist/notifications/__tests__/profiles.test.js +0 -404
  1190. package/dist/notifications/__tests__/profiles.test.js.map +0 -1
  1191. package/dist/notifications/__tests__/reply-config.test.d.ts +0 -2
  1192. package/dist/notifications/__tests__/reply-config.test.d.ts.map +0 -1
  1193. package/dist/notifications/__tests__/reply-config.test.js +0 -79
  1194. package/dist/notifications/__tests__/reply-config.test.js.map +0 -1
  1195. package/dist/notifications/__tests__/reply-listener.test.d.ts +0 -2
  1196. package/dist/notifications/__tests__/reply-listener.test.d.ts.map +0 -1
  1197. package/dist/notifications/__tests__/reply-listener.test.js +0 -723
  1198. package/dist/notifications/__tests__/reply-listener.test.js.map +0 -1
  1199. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.d.ts +0 -2
  1200. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.d.ts.map +0 -1
  1201. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js +0 -93
  1202. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js.map +0 -1
  1203. package/dist/notifications/__tests__/session-registry.test.d.ts +0 -2
  1204. package/dist/notifications/__tests__/session-registry.test.d.ts.map +0 -1
  1205. package/dist/notifications/__tests__/session-registry.test.js +0 -234
  1206. package/dist/notifications/__tests__/session-registry.test.js.map +0 -1
  1207. package/dist/notifications/__tests__/session-status.test.d.ts +0 -2
  1208. package/dist/notifications/__tests__/session-status.test.d.ts.map +0 -1
  1209. package/dist/notifications/__tests__/session-status.test.js +0 -249
  1210. package/dist/notifications/__tests__/session-status.test.js.map +0 -1
  1211. package/dist/notifications/__tests__/temp-mode.test.d.ts +0 -2
  1212. package/dist/notifications/__tests__/temp-mode.test.d.ts.map +0 -1
  1213. package/dist/notifications/__tests__/temp-mode.test.js +0 -172
  1214. package/dist/notifications/__tests__/temp-mode.test.js.map +0 -1
  1215. package/dist/notifications/__tests__/template-engine.test.d.ts +0 -5
  1216. package/dist/notifications/__tests__/template-engine.test.d.ts.map +0 -1
  1217. package/dist/notifications/__tests__/template-engine.test.js +0 -158
  1218. package/dist/notifications/__tests__/template-engine.test.js.map +0 -1
  1219. package/dist/notifications/__tests__/tmux-detector.test.d.ts +0 -2
  1220. package/dist/notifications/__tests__/tmux-detector.test.d.ts.map +0 -1
  1221. package/dist/notifications/__tests__/tmux-detector.test.js +0 -208
  1222. package/dist/notifications/__tests__/tmux-detector.test.js.map +0 -1
  1223. package/dist/notifications/__tests__/tmux.test.d.ts +0 -2
  1224. package/dist/notifications/__tests__/tmux.test.d.ts.map +0 -1
  1225. package/dist/notifications/__tests__/tmux.test.js +0 -285
  1226. package/dist/notifications/__tests__/tmux.test.js.map +0 -1
  1227. package/dist/notifications/__tests__/verbosity.test.d.ts +0 -2
  1228. package/dist/notifications/__tests__/verbosity.test.d.ts.map +0 -1
  1229. package/dist/notifications/__tests__/verbosity.test.js +0 -237
  1230. package/dist/notifications/__tests__/verbosity.test.js.map +0 -1
  1231. package/dist/openclaw/__tests__/config.test.d.ts +0 -6
  1232. package/dist/openclaw/__tests__/config.test.d.ts.map +0 -1
  1233. package/dist/openclaw/__tests__/config.test.js +0 -344
  1234. package/dist/openclaw/__tests__/config.test.js.map +0 -1
  1235. package/dist/openclaw/__tests__/dispatcher.test.d.ts +0 -5
  1236. package/dist/openclaw/__tests__/dispatcher.test.d.ts.map +0 -1
  1237. package/dist/openclaw/__tests__/dispatcher.test.js +0 -169
  1238. package/dist/openclaw/__tests__/dispatcher.test.js.map +0 -1
  1239. package/dist/openclaw/__tests__/index.test.d.ts +0 -6
  1240. package/dist/openclaw/__tests__/index.test.d.ts.map +0 -1
  1241. package/dist/openclaw/__tests__/index.test.js +0 -382
  1242. package/dist/openclaw/__tests__/index.test.js.map +0 -1
  1243. package/dist/pipeline/__tests__/orchestrator.test.d.ts +0 -2
  1244. package/dist/pipeline/__tests__/orchestrator.test.d.ts.map +0 -1
  1245. package/dist/pipeline/__tests__/orchestrator.test.js +0 -505
  1246. package/dist/pipeline/__tests__/orchestrator.test.js.map +0 -1
  1247. package/dist/pipeline/__tests__/stages.test.d.ts +0 -2
  1248. package/dist/pipeline/__tests__/stages.test.d.ts.map +0 -1
  1249. package/dist/pipeline/__tests__/stages.test.js +0 -754
  1250. package/dist/pipeline/__tests__/stages.test.js.map +0 -1
  1251. package/dist/pipeline/stages/ralph-verify.d.ts +0 -53
  1252. package/dist/pipeline/stages/ralph-verify.d.ts.map +0 -1
  1253. package/dist/pipeline/stages/ralph-verify.js.map +0 -1
  1254. package/dist/pipeline/stages/ralplan.d.ts +0 -25
  1255. package/dist/pipeline/stages/ralplan.d.ts.map +0 -1
  1256. package/dist/pipeline/stages/ralplan.js.map +0 -1
  1257. package/dist/planning/__tests__/artifacts.test.d.ts +0 -2
  1258. package/dist/planning/__tests__/artifacts.test.d.ts.map +0 -1
  1259. package/dist/planning/__tests__/artifacts.test.js +0 -544
  1260. package/dist/planning/__tests__/artifacts.test.js.map +0 -1
  1261. package/dist/question/__tests__/client.test.d.ts +0 -2
  1262. package/dist/question/__tests__/client.test.d.ts.map +0 -1
  1263. package/dist/question/__tests__/client.test.js +0 -90
  1264. package/dist/question/__tests__/client.test.js.map +0 -1
  1265. package/dist/question/__tests__/deep-interview.test.d.ts +0 -2
  1266. package/dist/question/__tests__/deep-interview.test.d.ts.map +0 -1
  1267. package/dist/question/__tests__/deep-interview.test.js +0 -209
  1268. package/dist/question/__tests__/deep-interview.test.js.map +0 -1
  1269. package/dist/question/__tests__/policy.test.d.ts +0 -2
  1270. package/dist/question/__tests__/policy.test.d.ts.map +0 -1
  1271. package/dist/question/__tests__/policy.test.js +0 -107
  1272. package/dist/question/__tests__/policy.test.js.map +0 -1
  1273. package/dist/question/__tests__/renderer.test.d.ts +0 -2
  1274. package/dist/question/__tests__/renderer.test.d.ts.map +0 -1
  1275. package/dist/question/__tests__/renderer.test.js +0 -707
  1276. package/dist/question/__tests__/renderer.test.js.map +0 -1
  1277. package/dist/question/__tests__/state.test.d.ts +0 -2
  1278. package/dist/question/__tests__/state.test.d.ts.map +0 -1
  1279. package/dist/question/__tests__/state.test.js +0 -102
  1280. package/dist/question/__tests__/state.test.js.map +0 -1
  1281. package/dist/question/__tests__/types.test.d.ts +0 -2
  1282. package/dist/question/__tests__/types.test.d.ts.map +0 -1
  1283. package/dist/question/__tests__/types.test.js +0 -65
  1284. package/dist/question/__tests__/types.test.js.map +0 -1
  1285. package/dist/question/__tests__/ui.test.d.ts +0 -2
  1286. package/dist/question/__tests__/ui.test.d.ts.map +0 -1
  1287. package/dist/question/__tests__/ui.test.js +0 -446
  1288. package/dist/question/__tests__/ui.test.js.map +0 -1
  1289. package/dist/ralph/__tests__/persistence.test.d.ts +0 -2
  1290. package/dist/ralph/__tests__/persistence.test.d.ts.map +0 -1
  1291. package/dist/ralph/__tests__/persistence.test.js +0 -116
  1292. package/dist/ralph/__tests__/persistence.test.js.map +0 -1
  1293. package/dist/ralph/contract.d.ts +0 -17
  1294. package/dist/ralph/persistence.js.map +0 -1
  1295. package/dist/ralplan/__tests__/runtime.test.d.ts +0 -2
  1296. package/dist/ralplan/__tests__/runtime.test.d.ts.map +0 -1
  1297. package/dist/ralplan/__tests__/runtime.test.js +0 -165
  1298. package/dist/ralplan/__tests__/runtime.test.js.map +0 -1
  1299. package/dist/ralplan/runtime.d.ts +0 -52
  1300. package/dist/ralplan/runtime.d.ts.map +0 -1
  1301. package/dist/ralplan/runtime.js.map +0 -1
  1302. package/dist/runtime/__tests__/bridge.test.d.ts +0 -2
  1303. package/dist/runtime/__tests__/bridge.test.d.ts.map +0 -1
  1304. package/dist/runtime/__tests__/bridge.test.js +0 -194
  1305. package/dist/runtime/__tests__/bridge.test.js.map +0 -1
  1306. package/dist/runtime/__tests__/run-loop.test.d.ts +0 -2
  1307. package/dist/runtime/__tests__/run-loop.test.d.ts.map +0 -1
  1308. package/dist/runtime/__tests__/run-loop.test.js +0 -35
  1309. package/dist/runtime/__tests__/run-loop.test.js.map +0 -1
  1310. package/dist/runtime/__tests__/run-outcome.test.d.ts +0 -2
  1311. package/dist/runtime/__tests__/run-outcome.test.d.ts.map +0 -1
  1312. package/dist/runtime/__tests__/run-outcome.test.js +0 -102
  1313. package/dist/runtime/__tests__/run-outcome.test.js.map +0 -1
  1314. package/dist/runtime/__tests__/run-state.test.d.ts +0 -2
  1315. package/dist/runtime/__tests__/run-state.test.d.ts.map +0 -1
  1316. package/dist/runtime/__tests__/run-state.test.js +0 -37
  1317. package/dist/runtime/__tests__/run-state.test.js.map +0 -1
  1318. package/dist/scripts/__tests__/codex-native-hook.test.d.ts +0 -2
  1319. package/dist/scripts/__tests__/codex-native-hook.test.d.ts.map +0 -1
  1320. package/dist/scripts/__tests__/codex-native-hook.test.js +0 -6788
  1321. package/dist/scripts/__tests__/codex-native-hook.test.js.map +0 -1
  1322. package/dist/scripts/__tests__/generate-release-body.test.d.ts +0 -2
  1323. package/dist/scripts/__tests__/generate-release-body.test.d.ts.map +0 -1
  1324. package/dist/scripts/__tests__/generate-release-body.test.js +0 -233
  1325. package/dist/scripts/__tests__/generate-release-body.test.js.map +0 -1
  1326. package/dist/scripts/__tests__/hook-derived-watcher.test.d.ts +0 -2
  1327. package/dist/scripts/__tests__/hook-derived-watcher.test.d.ts.map +0 -1
  1328. package/dist/scripts/__tests__/hook-derived-watcher.test.js +0 -195
  1329. package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +0 -1
  1330. package/dist/scripts/__tests__/postinstall.test.d.ts +0 -2
  1331. package/dist/scripts/__tests__/postinstall.test.d.ts.map +0 -1
  1332. package/dist/scripts/__tests__/postinstall.test.js +0 -92
  1333. package/dist/scripts/__tests__/postinstall.test.js.map +0 -1
  1334. package/dist/scripts/__tests__/prompt-inventory.test.d.ts +0 -2
  1335. package/dist/scripts/__tests__/prompt-inventory.test.d.ts.map +0 -1
  1336. package/dist/scripts/__tests__/prompt-inventory.test.js +0 -56
  1337. package/dist/scripts/__tests__/prompt-inventory.test.js.map +0 -1
  1338. package/dist/scripts/__tests__/run-test-files.test.d.ts +0 -2
  1339. package/dist/scripts/__tests__/run-test-files.test.d.ts.map +0 -1
  1340. package/dist/scripts/__tests__/run-test-files.test.js +0 -62
  1341. package/dist/scripts/__tests__/run-test-files.test.js.map +0 -1
  1342. package/dist/scripts/__tests__/smoke-packed-install.test.d.ts +0 -2
  1343. package/dist/scripts/__tests__/smoke-packed-install.test.d.ts.map +0 -1
  1344. package/dist/scripts/__tests__/smoke-packed-install.test.js +0 -135
  1345. package/dist/scripts/__tests__/smoke-packed-install.test.js.map +0 -1
  1346. package/dist/scripts/__tests__/test-reply-listener-live.test.d.ts +0 -2
  1347. package/dist/scripts/__tests__/test-reply-listener-live.test.d.ts.map +0 -1
  1348. package/dist/scripts/__tests__/test-reply-listener-live.test.js +0 -82
  1349. package/dist/scripts/__tests__/test-reply-listener-live.test.js.map +0 -1
  1350. package/dist/scripts/__tests__/verify-native-agents.test.d.ts +0 -2
  1351. package/dist/scripts/__tests__/verify-native-agents.test.d.ts.map +0 -1
  1352. package/dist/scripts/__tests__/verify-native-agents.test.js +0 -166
  1353. package/dist/scripts/__tests__/verify-native-agents.test.js.map +0 -1
  1354. package/dist/scripts/eval/eval-candidate-handoff.d.ts +0 -2
  1355. package/dist/scripts/eval/eval-candidate-handoff.d.ts.map +0 -1
  1356. package/dist/scripts/eval/eval-candidate-handoff.js +0 -11
  1357. package/dist/scripts/eval/eval-candidate-handoff.js.map +0 -1
  1358. package/dist/scripts/eval/eval-cli-discoverability.d.ts +0 -3
  1359. package/dist/scripts/eval/eval-cli-discoverability.d.ts.map +0 -1
  1360. package/dist/scripts/eval/eval-cli-discoverability.js +0 -37
  1361. package/dist/scripts/eval/eval-cli-discoverability.js.map +0 -1
  1362. package/dist/scripts/eval/eval-fresh-run-tagging.d.ts +0 -2
  1363. package/dist/scripts/eval/eval-fresh-run-tagging.d.ts.map +0 -1
  1364. package/dist/scripts/eval/eval-fresh-run-tagging.js +0 -11
  1365. package/dist/scripts/eval/eval-fresh-run-tagging.js.map +0 -1
  1366. package/dist/scripts/eval/eval-help-consistency.d.ts +0 -2
  1367. package/dist/scripts/eval/eval-help-consistency.d.ts.map +0 -1
  1368. package/dist/scripts/eval/eval-help-consistency.js +0 -12
  1369. package/dist/scripts/eval/eval-help-consistency.js.map +0 -1
  1370. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.d.ts +0 -2
  1371. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.d.ts.map +0 -1
  1372. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.js +0 -31
  1373. package/dist/scripts/eval/eval-in-action-cat-shellout-demo.js.map +0 -1
  1374. package/dist/scripts/eval/eval-parity-smoke.d.ts +0 -2
  1375. package/dist/scripts/eval/eval-parity-smoke.d.ts.map +0 -1
  1376. package/dist/scripts/eval/eval-parity-smoke.js +0 -23
  1377. package/dist/scripts/eval/eval-parity-smoke.js.map +0 -1
  1378. package/dist/scripts/eval/eval-parity-sweep.d.ts +0 -2
  1379. package/dist/scripts/eval/eval-parity-sweep.d.ts.map +0 -1
  1380. package/dist/scripts/eval/eval-parity-sweep.js +0 -29
  1381. package/dist/scripts/eval/eval-parity-sweep.js.map +0 -1
  1382. package/dist/scripts/eval/eval-resume-dirty-guard.d.ts +0 -2
  1383. package/dist/scripts/eval/eval-resume-dirty-guard.d.ts.map +0 -1
  1384. package/dist/scripts/eval/eval-resume-dirty-guard.js +0 -11
  1385. package/dist/scripts/eval/eval-resume-dirty-guard.js.map +0 -1
  1386. package/dist/scripts/eval/eval-security-path-traversal.d.ts +0 -3
  1387. package/dist/scripts/eval/eval-security-path-traversal.d.ts.map +0 -1
  1388. package/dist/scripts/eval/eval-security-path-traversal.js +0 -35
  1389. package/dist/scripts/eval/eval-security-path-traversal.js.map +0 -1
  1390. package/dist/scripts/notify-hook/__tests__/operational-events.test.d.ts +0 -2
  1391. package/dist/scripts/notify-hook/__tests__/operational-events.test.d.ts.map +0 -1
  1392. package/dist/scripts/notify-hook/__tests__/operational-events.test.js +0 -24
  1393. package/dist/scripts/notify-hook/__tests__/operational-events.test.js.map +0 -1
  1394. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts +0 -2
  1395. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts.map +0 -1
  1396. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js +0 -153
  1397. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js.map +0 -1
  1398. package/dist/scripts/notify-hook/ralph-session-resume.d.ts +0 -22
  1399. package/dist/session-history/__tests__/search.test.d.ts +0 -2
  1400. package/dist/session-history/__tests__/search.test.d.ts.map +0 -1
  1401. package/dist/session-history/__tests__/search.test.js +0 -150
  1402. package/dist/session-history/__tests__/search.test.js.map +0 -1
  1403. package/dist/sidecar/__tests__/boundary.test.d.ts +0 -2
  1404. package/dist/sidecar/__tests__/boundary.test.d.ts.map +0 -1
  1405. package/dist/sidecar/__tests__/boundary.test.js +0 -48
  1406. package/dist/sidecar/__tests__/boundary.test.js.map +0 -1
  1407. package/dist/sidecar/__tests__/collector.test.d.ts +0 -2
  1408. package/dist/sidecar/__tests__/collector.test.d.ts.map +0 -1
  1409. package/dist/sidecar/__tests__/collector.test.js +0 -162
  1410. package/dist/sidecar/__tests__/collector.test.js.map +0 -1
  1411. package/dist/sidecar/__tests__/render.test.d.ts +0 -2
  1412. package/dist/sidecar/__tests__/render.test.d.ts.map +0 -1
  1413. package/dist/sidecar/__tests__/render.test.js +0 -67
  1414. package/dist/sidecar/__tests__/render.test.js.map +0 -1
  1415. package/dist/sidecar/__tests__/tmux.test.d.ts +0 -2
  1416. package/dist/sidecar/__tests__/tmux.test.d.ts.map +0 -1
  1417. package/dist/sidecar/__tests__/tmux.test.js +0 -30
  1418. package/dist/sidecar/__tests__/tmux.test.js.map +0 -1
  1419. package/dist/sidecar/__tests__/watch.test.d.ts +0 -2
  1420. package/dist/sidecar/__tests__/watch.test.d.ts.map +0 -1
  1421. package/dist/sidecar/__tests__/watch.test.js +0 -42
  1422. package/dist/sidecar/__tests__/watch.test.js.map +0 -1
  1423. package/dist/state/__tests__/mode-state-context.test.d.ts +0 -2
  1424. package/dist/state/__tests__/mode-state-context.test.d.ts.map +0 -1
  1425. package/dist/state/__tests__/mode-state-context.test.js +0 -35
  1426. package/dist/state/__tests__/mode-state-context.test.js.map +0 -1
  1427. package/dist/state/__tests__/operations-ralph-phase.test.d.ts +0 -2
  1428. package/dist/state/__tests__/operations-ralph-phase.test.d.ts.map +0 -1
  1429. package/dist/state/__tests__/operations-ralph-phase.test.js +0 -103
  1430. package/dist/state/__tests__/operations-ralph-phase.test.js.map +0 -1
  1431. package/dist/state/__tests__/operations.test.d.ts +0 -2
  1432. package/dist/state/__tests__/operations.test.d.ts.map +0 -1
  1433. package/dist/state/__tests__/operations.test.js +0 -439
  1434. package/dist/state/__tests__/operations.test.js.map +0 -1
  1435. package/dist/state/__tests__/path-traversal.test.d.ts +0 -2
  1436. package/dist/state/__tests__/path-traversal.test.d.ts.map +0 -1
  1437. package/dist/state/__tests__/path-traversal.test.js +0 -49
  1438. package/dist/state/__tests__/path-traversal.test.js.map +0 -1
  1439. package/dist/state/__tests__/skill-active.test.d.ts +0 -2
  1440. package/dist/state/__tests__/skill-active.test.d.ts.map +0 -1
  1441. package/dist/state/__tests__/skill-active.test.js +0 -160
  1442. package/dist/state/__tests__/skill-active.test.js.map +0 -1
  1443. package/dist/state/__tests__/workflow-transition.test.d.ts +0 -2
  1444. package/dist/state/__tests__/workflow-transition.test.d.ts.map +0 -1
  1445. package/dist/state/__tests__/workflow-transition.test.js +0 -77
  1446. package/dist/state/__tests__/workflow-transition.test.js.map +0 -1
  1447. package/dist/subagents/__tests__/tracker.test.d.ts +0 -2
  1448. package/dist/subagents/__tests__/tracker.test.d.ts.map +0 -1
  1449. package/dist/subagents/__tests__/tracker.test.js +0 -47
  1450. package/dist/subagents/__tests__/tracker.test.js.map +0 -1
  1451. package/dist/team/__tests__/allocation-policy.test.d.ts +0 -2
  1452. package/dist/team/__tests__/allocation-policy.test.d.ts.map +0 -1
  1453. package/dist/team/__tests__/allocation-policy.test.js +0 -111
  1454. package/dist/team/__tests__/allocation-policy.test.js.map +0 -1
  1455. package/dist/team/__tests__/api-interop.test.d.ts +0 -2
  1456. package/dist/team/__tests__/api-interop.test.d.ts.map +0 -1
  1457. package/dist/team/__tests__/api-interop.test.js +0 -2262
  1458. package/dist/team/__tests__/api-interop.test.js.map +0 -1
  1459. package/dist/team/__tests__/commit-hygiene.test.d.ts +0 -2
  1460. package/dist/team/__tests__/commit-hygiene.test.d.ts.map +0 -1
  1461. package/dist/team/__tests__/commit-hygiene.test.js +0 -93
  1462. package/dist/team/__tests__/commit-hygiene.test.js.map +0 -1
  1463. package/dist/team/__tests__/cross-rebase-smoke.test.d.ts +0 -2
  1464. package/dist/team/__tests__/cross-rebase-smoke.test.d.ts.map +0 -1
  1465. package/dist/team/__tests__/cross-rebase-smoke.test.js +0 -161
  1466. package/dist/team/__tests__/cross-rebase-smoke.test.js.map +0 -1
  1467. package/dist/team/__tests__/current-task-baseline.test.d.ts +0 -2
  1468. package/dist/team/__tests__/current-task-baseline.test.d.ts.map +0 -1
  1469. package/dist/team/__tests__/current-task-baseline.test.js +0 -87
  1470. package/dist/team/__tests__/current-task-baseline.test.js.map +0 -1
  1471. package/dist/team/__tests__/delegation-policy.test.d.ts +0 -2
  1472. package/dist/team/__tests__/delegation-policy.test.d.ts.map +0 -1
  1473. package/dist/team/__tests__/delegation-policy.test.js +0 -69
  1474. package/dist/team/__tests__/delegation-policy.test.js.map +0 -1
  1475. package/dist/team/__tests__/delivery-e2e-smoke.test.d.ts +0 -2
  1476. package/dist/team/__tests__/delivery-e2e-smoke.test.d.ts.map +0 -1
  1477. package/dist/team/__tests__/delivery-e2e-smoke.test.js +0 -679
  1478. package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +0 -1
  1479. package/dist/team/__tests__/events.test.d.ts +0 -2
  1480. package/dist/team/__tests__/events.test.d.ts.map +0 -1
  1481. package/dist/team/__tests__/events.test.js +0 -313
  1482. package/dist/team/__tests__/events.test.js.map +0 -1
  1483. package/dist/team/__tests__/followup-planner.test.d.ts +0 -2
  1484. package/dist/team/__tests__/followup-planner.test.d.ts.map +0 -1
  1485. package/dist/team/__tests__/followup-planner.test.js +0 -84
  1486. package/dist/team/__tests__/followup-planner.test.js.map +0 -1
  1487. package/dist/team/__tests__/hardening-e2e.test.d.ts +0 -2
  1488. package/dist/team/__tests__/hardening-e2e.test.d.ts.map +0 -1
  1489. package/dist/team/__tests__/hardening-e2e.test.js +0 -98
  1490. package/dist/team/__tests__/hardening-e2e.test.js.map +0 -1
  1491. package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts +0 -2
  1492. package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts.map +0 -1
  1493. package/dist/team/__tests__/hook-primary-e2e-contract.test.js +0 -78
  1494. package/dist/team/__tests__/hook-primary-e2e-contract.test.js.map +0 -1
  1495. package/dist/team/__tests__/idle-nudge.test.d.ts +0 -2
  1496. package/dist/team/__tests__/idle-nudge.test.d.ts.map +0 -1
  1497. package/dist/team/__tests__/idle-nudge.test.js +0 -230
  1498. package/dist/team/__tests__/idle-nudge.test.js.map +0 -1
  1499. package/dist/team/__tests__/leader-activity.test.d.ts +0 -2
  1500. package/dist/team/__tests__/leader-activity.test.d.ts.map +0 -1
  1501. package/dist/team/__tests__/leader-activity.test.js +0 -261
  1502. package/dist/team/__tests__/leader-activity.test.js.map +0 -1
  1503. package/dist/team/__tests__/mcp-comm.test.d.ts +0 -2
  1504. package/dist/team/__tests__/mcp-comm.test.d.ts.map +0 -1
  1505. package/dist/team/__tests__/mcp-comm.test.js +0 -289
  1506. package/dist/team/__tests__/mcp-comm.test.js.map +0 -1
  1507. package/dist/team/__tests__/model-contract.test.d.ts +0 -2
  1508. package/dist/team/__tests__/model-contract.test.d.ts.map +0 -1
  1509. package/dist/team/__tests__/model-contract.test.js +0 -171
  1510. package/dist/team/__tests__/model-contract.test.js.map +0 -1
  1511. package/dist/team/__tests__/orchestrator.test.d.ts +0 -2
  1512. package/dist/team/__tests__/orchestrator.test.d.ts.map +0 -1
  1513. package/dist/team/__tests__/orchestrator.test.js +0 -111
  1514. package/dist/team/__tests__/orchestrator.test.js.map +0 -1
  1515. package/dist/team/__tests__/phase-controller.test.d.ts +0 -2
  1516. package/dist/team/__tests__/phase-controller.test.d.ts.map +0 -1
  1517. package/dist/team/__tests__/phase-controller.test.js +0 -50
  1518. package/dist/team/__tests__/phase-controller.test.js.map +0 -1
  1519. package/dist/team/__tests__/rebalance-policy.test.d.ts +0 -2
  1520. package/dist/team/__tests__/rebalance-policy.test.d.ts.map +0 -1
  1521. package/dist/team/__tests__/rebalance-policy.test.js +0 -168
  1522. package/dist/team/__tests__/rebalance-policy.test.js.map +0 -1
  1523. package/dist/team/__tests__/repo-aware-decomposition.test.d.ts +0 -2
  1524. package/dist/team/__tests__/repo-aware-decomposition.test.d.ts.map +0 -1
  1525. package/dist/team/__tests__/repo-aware-decomposition.test.js +0 -136
  1526. package/dist/team/__tests__/repo-aware-decomposition.test.js.map +0 -1
  1527. package/dist/team/__tests__/role-router.test.d.ts +0 -2
  1528. package/dist/team/__tests__/role-router.test.d.ts.map +0 -1
  1529. package/dist/team/__tests__/role-router.test.js +0 -263
  1530. package/dist/team/__tests__/role-router.test.js.map +0 -1
  1531. package/dist/team/__tests__/runtime-cli.test.d.ts +0 -2
  1532. package/dist/team/__tests__/runtime-cli.test.d.ts.map +0 -1
  1533. package/dist/team/__tests__/runtime-cli.test.js +0 -304
  1534. package/dist/team/__tests__/runtime-cli.test.js.map +0 -1
  1535. package/dist/team/__tests__/runtime.test.d.ts +0 -2
  1536. package/dist/team/__tests__/runtime.test.d.ts.map +0 -1
  1537. package/dist/team/__tests__/runtime.test.js +0 -5734
  1538. package/dist/team/__tests__/runtime.test.js.map +0 -1
  1539. package/dist/team/__tests__/scaling.test.d.ts +0 -2
  1540. package/dist/team/__tests__/scaling.test.d.ts.map +0 -1
  1541. package/dist/team/__tests__/scaling.test.js +0 -1005
  1542. package/dist/team/__tests__/scaling.test.js.map +0 -1
  1543. package/dist/team/__tests__/shutdown-fallback.test.d.ts +0 -2
  1544. package/dist/team/__tests__/shutdown-fallback.test.d.ts.map +0 -1
  1545. package/dist/team/__tests__/shutdown-fallback.test.js +0 -125
  1546. package/dist/team/__tests__/shutdown-fallback.test.js.map +0 -1
  1547. package/dist/team/__tests__/state-root.test.d.ts +0 -2
  1548. package/dist/team/__tests__/state-root.test.d.ts.map +0 -1
  1549. package/dist/team/__tests__/state-root.test.js +0 -195
  1550. package/dist/team/__tests__/state-root.test.js.map +0 -1
  1551. package/dist/team/__tests__/state.test.d.ts +0 -2
  1552. package/dist/team/__tests__/state.test.d.ts.map +0 -1
  1553. package/dist/team/__tests__/state.test.js +0 -1859
  1554. package/dist/team/__tests__/state.test.js.map +0 -1
  1555. package/dist/team/__tests__/team-identity.test.d.ts +0 -2
  1556. package/dist/team/__tests__/team-identity.test.d.ts.map +0 -1
  1557. package/dist/team/__tests__/team-identity.test.js +0 -166
  1558. package/dist/team/__tests__/team-identity.test.js.map +0 -1
  1559. package/dist/team/__tests__/team-ops-contract.test.d.ts +0 -2
  1560. package/dist/team/__tests__/team-ops-contract.test.d.ts.map +0 -1
  1561. package/dist/team/__tests__/team-ops-contract.test.js +0 -96
  1562. package/dist/team/__tests__/team-ops-contract.test.js.map +0 -1
  1563. package/dist/team/__tests__/tmux-claude-workers-demo.test.d.ts +0 -2
  1564. package/dist/team/__tests__/tmux-claude-workers-demo.test.d.ts.map +0 -1
  1565. package/dist/team/__tests__/tmux-claude-workers-demo.test.js +0 -191
  1566. package/dist/team/__tests__/tmux-claude-workers-demo.test.js.map +0 -1
  1567. package/dist/team/__tests__/tmux-session.test.d.ts +0 -2
  1568. package/dist/team/__tests__/tmux-session.test.d.ts.map +0 -1
  1569. package/dist/team/__tests__/tmux-session.test.js +0 -3785
  1570. package/dist/team/__tests__/tmux-session.test.js.map +0 -1
  1571. package/dist/team/__tests__/tmux-test-fixture.d.ts +0 -20
  1572. package/dist/team/__tests__/tmux-test-fixture.d.ts.map +0 -1
  1573. package/dist/team/__tests__/tmux-test-fixture.js +0 -152
  1574. package/dist/team/__tests__/tmux-test-fixture.js.map +0 -1
  1575. package/dist/team/__tests__/tmux-test-fixture.test.d.ts +0 -2
  1576. package/dist/team/__tests__/tmux-test-fixture.test.d.ts.map +0 -1
  1577. package/dist/team/__tests__/tmux-test-fixture.test.js +0 -113
  1578. package/dist/team/__tests__/tmux-test-fixture.test.js.map +0 -1
  1579. package/dist/team/__tests__/worker-bootstrap.test.d.ts +0 -2
  1580. package/dist/team/__tests__/worker-bootstrap.test.d.ts.map +0 -1
  1581. package/dist/team/__tests__/worker-bootstrap.test.js +0 -685
  1582. package/dist/team/__tests__/worker-bootstrap.test.js.map +0 -1
  1583. package/dist/team/__tests__/worker-runtime-identity.test.d.ts +0 -2
  1584. package/dist/team/__tests__/worker-runtime-identity.test.d.ts.map +0 -1
  1585. package/dist/team/__tests__/worker-runtime-identity.test.js +0 -250
  1586. package/dist/team/__tests__/worker-runtime-identity.test.js.map +0 -1
  1587. package/dist/team/__tests__/worktree.test.d.ts +0 -2
  1588. package/dist/team/__tests__/worktree.test.d.ts.map +0 -1
  1589. package/dist/team/__tests__/worktree.test.js +0 -317
  1590. package/dist/team/__tests__/worktree.test.js.map +0 -1
  1591. package/dist/utils/__tests__/agents-md.test.d.ts +0 -2
  1592. package/dist/utils/__tests__/agents-md.test.d.ts.map +0 -1
  1593. package/dist/utils/__tests__/agents-md.test.js +0 -52
  1594. package/dist/utils/__tests__/agents-md.test.js.map +0 -1
  1595. package/dist/utils/__tests__/agents-model-table.test.d.ts +0 -2
  1596. package/dist/utils/__tests__/agents-model-table.test.d.ts.map +0 -1
  1597. package/dist/utils/__tests__/agents-model-table.test.js +0 -104
  1598. package/dist/utils/__tests__/agents-model-table.test.js.map +0 -1
  1599. package/dist/utils/__tests__/dep-versions.test.d.ts +0 -2
  1600. package/dist/utils/__tests__/dep-versions.test.d.ts.map +0 -1
  1601. package/dist/utils/__tests__/dep-versions.test.js +0 -46
  1602. package/dist/utils/__tests__/dep-versions.test.js.map +0 -1
  1603. package/dist/utils/__tests__/package.test.d.ts +0 -2
  1604. package/dist/utils/__tests__/package.test.d.ts.map +0 -1
  1605. package/dist/utils/__tests__/package.test.js +0 -21
  1606. package/dist/utils/__tests__/package.test.js.map +0 -1
  1607. package/dist/utils/__tests__/paths.test.d.ts +0 -2
  1608. package/dist/utils/__tests__/paths.test.d.ts.map +0 -1
  1609. package/dist/utils/__tests__/paths.test.js +0 -541
  1610. package/dist/utils/__tests__/paths.test.js.map +0 -1
  1611. package/dist/utils/__tests__/platform-command.test.d.ts +0 -2
  1612. package/dist/utils/__tests__/platform-command.test.d.ts.map +0 -1
  1613. package/dist/utils/__tests__/platform-command.test.js +0 -410
  1614. package/dist/utils/__tests__/platform-command.test.js.map +0 -1
  1615. package/dist/utils/__tests__/repo-deps.test.d.ts +0 -2
  1616. package/dist/utils/__tests__/repo-deps.test.d.ts.map +0 -1
  1617. package/dist/utils/__tests__/repo-deps.test.js +0 -71
  1618. package/dist/utils/__tests__/repo-deps.test.js.map +0 -1
  1619. package/dist/verification/__tests__/ci-rust-gates.test.d.ts +0 -2
  1620. package/dist/verification/__tests__/ci-rust-gates.test.d.ts.map +0 -1
  1621. package/dist/verification/__tests__/ci-rust-gates.test.js +0 -89
  1622. package/dist/verification/__tests__/ci-rust-gates.test.js.map +0 -1
  1623. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.d.ts +0 -2
  1624. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.d.ts.map +0 -1
  1625. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +0 -54
  1626. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +0 -1
  1627. package/dist/verification/__tests__/explore-harness-release-workflow.test.d.ts +0 -2
  1628. package/dist/verification/__tests__/explore-harness-release-workflow.test.d.ts.map +0 -1
  1629. package/dist/verification/__tests__/explore-harness-release-workflow.test.js +0 -73
  1630. package/dist/verification/__tests__/explore-harness-release-workflow.test.js.map +0 -1
  1631. package/dist/verification/__tests__/native-release-manifest.test.d.ts +0 -2
  1632. package/dist/verification/__tests__/native-release-manifest.test.d.ts.map +0 -1
  1633. package/dist/verification/__tests__/native-release-manifest.test.js +0 -80
  1634. package/dist/verification/__tests__/native-release-manifest.test.js.map +0 -1
  1635. package/dist/verification/__tests__/pr-check-workflow.test.d.ts +0 -2
  1636. package/dist/verification/__tests__/pr-check-workflow.test.d.ts.map +0 -1
  1637. package/dist/verification/__tests__/pr-check-workflow.test.js +0 -27
  1638. package/dist/verification/__tests__/pr-check-workflow.test.js.map +0 -1
  1639. package/dist/verification/__tests__/ralph-persistence-gate.test.d.ts +0 -2
  1640. package/dist/verification/__tests__/ralph-persistence-gate.test.d.ts.map +0 -1
  1641. package/dist/verification/__tests__/ralph-persistence-gate.test.js +0 -55
  1642. package/dist/verification/__tests__/ralph-persistence-gate.test.js.map +0 -1
  1643. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.d.ts +0 -2
  1644. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.d.ts.map +0 -1
  1645. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.js +0 -32
  1646. package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.js.map +0 -1
  1647. package/dist/verification/__tests__/verifier.test.d.ts +0 -2
  1648. package/dist/verification/__tests__/verifier.test.d.ts.map +0 -1
  1649. package/dist/verification/__tests__/verifier.test.js +0 -113
  1650. package/dist/verification/__tests__/verifier.test.js.map +0 -1
  1651. package/dist/visual/__tests__/verdict.test.d.ts +0 -2
  1652. package/dist/visual/__tests__/verdict.test.d.ts.map +0 -1
  1653. package/dist/visual/__tests__/verdict.test.js +0 -81
  1654. package/dist/visual/__tests__/verdict.test.js.map +0 -1
  1655. package/dist/wiki/__tests__/cjk-tokenize.test.d.ts +0 -12
  1656. package/dist/wiki/__tests__/cjk-tokenize.test.d.ts.map +0 -1
  1657. package/dist/wiki/__tests__/cjk-tokenize.test.js +0 -139
  1658. package/dist/wiki/__tests__/cjk-tokenize.test.js.map +0 -1
  1659. package/dist/wiki/__tests__/crlf-parse.test.d.ts +0 -2
  1660. package/dist/wiki/__tests__/crlf-parse.test.d.ts.map +0 -1
  1661. package/dist/wiki/__tests__/crlf-parse.test.js +0 -24
  1662. package/dist/wiki/__tests__/crlf-parse.test.js.map +0 -1
  1663. package/dist/wiki/__tests__/escape-newline.test.d.ts +0 -2
  1664. package/dist/wiki/__tests__/escape-newline.test.d.ts.map +0 -1
  1665. package/dist/wiki/__tests__/escape-newline.test.js +0 -45
  1666. package/dist/wiki/__tests__/escape-newline.test.js.map +0 -1
  1667. package/dist/wiki/__tests__/ingest.test.d.ts +0 -5
  1668. package/dist/wiki/__tests__/ingest.test.d.ts.map +0 -1
  1669. package/dist/wiki/__tests__/ingest.test.js +0 -181
  1670. package/dist/wiki/__tests__/ingest.test.js.map +0 -1
  1671. package/dist/wiki/__tests__/lint.test.d.ts +0 -5
  1672. package/dist/wiki/__tests__/lint.test.d.ts.map +0 -1
  1673. package/dist/wiki/__tests__/lint.test.js +0 -163
  1674. package/dist/wiki/__tests__/lint.test.js.map +0 -1
  1675. package/dist/wiki/__tests__/query.test.d.ts +0 -5
  1676. package/dist/wiki/__tests__/query.test.d.ts.map +0 -1
  1677. package/dist/wiki/__tests__/query.test.js +0 -141
  1678. package/dist/wiki/__tests__/query.test.js.map +0 -1
  1679. package/dist/wiki/__tests__/reserved-file-guard.test.d.ts +0 -2
  1680. package/dist/wiki/__tests__/reserved-file-guard.test.d.ts.map +0 -1
  1681. package/dist/wiki/__tests__/reserved-file-guard.test.js +0 -44
  1682. package/dist/wiki/__tests__/reserved-file-guard.test.js.map +0 -1
  1683. package/dist/wiki/__tests__/session-hooks.test.d.ts +0 -5
  1684. package/dist/wiki/__tests__/session-hooks.test.d.ts.map +0 -1
  1685. package/dist/wiki/__tests__/session-hooks.test.js +0 -36
  1686. package/dist/wiki/__tests__/session-hooks.test.js.map +0 -1
  1687. package/dist/wiki/__tests__/slug-nonascii.test.d.ts +0 -2
  1688. package/dist/wiki/__tests__/slug-nonascii.test.d.ts.map +0 -1
  1689. package/dist/wiki/__tests__/slug-nonascii.test.js +0 -30
  1690. package/dist/wiki/__tests__/slug-nonascii.test.js.map +0 -1
  1691. package/dist/wiki/__tests__/storage.test.d.ts +0 -5
  1692. package/dist/wiki/__tests__/storage.test.d.ts.map +0 -1
  1693. package/dist/wiki/__tests__/storage.test.js +0 -278
  1694. package/dist/wiki/__tests__/storage.test.js.map +0 -1
  1695. package/dist/wiki/__tests__/test-helpers.d.ts +0 -31
  1696. package/dist/wiki/__tests__/test-helpers.d.ts.map +0 -1
  1697. package/dist/wiki/__tests__/test-helpers.js +0 -108
  1698. package/dist/wiki/__tests__/test-helpers.js.map +0 -1
  1699. package/docs/contracts/ralph-cancel-contract.md +0 -23
  1700. package/docs/contracts/ralph-state-contract.md +0 -95
  1701. package/docs/issues/team-ralph-followup-team.md +0 -38
  1702. package/docs/qa/ralph-persistence-gate.md +0 -59
  1703. package/docs/reference/ralph-parity-matrix.md +0 -25
  1704. package/docs/reference/ralph-upstream-baseline.md +0 -34
  1705. package/plugins/roblox-ai-os-creator-skills/skills/ralph/SKILL.md +0 -269
  1706. package/plugins/roblox-ai-os-creator-skills/skills/ralplan/SKILL.md +0 -162
  1707. package/prompts/api-reviewer.md +0 -113
  1708. package/prompts/information-architect.md +0 -226
  1709. package/prompts/performance-reviewer.md +0 -109
  1710. package/prompts/product-analyst.md +0 -304
  1711. package/prompts/product-manager.md +0 -245
  1712. package/prompts/qa-tester.md +0 -124
  1713. package/prompts/quality-reviewer.md +0 -123
  1714. package/prompts/quality-strategist.md +0 -274
  1715. package/prompts/style-reviewer.md +0 -102
  1716. package/prompts/ux-researcher.md +0 -327
  1717. package/skills/frontend-ui-ux/SKILL.md +0 -34
  1718. package/skills/ralph/SKILL.md +0 -269
  1719. package/skills/ralplan/SKILL.md +0 -162
  1720. package/src/scripts/eval/eval-adaptive-sort-optimization.py +0 -24
  1721. package/src/scripts/eval/eval-candidate-handoff.ts +0 -8
  1722. package/src/scripts/eval/eval-cli-discoverability.ts +0 -40
  1723. package/src/scripts/eval/eval-fresh-run-tagging.ts +0 -8
  1724. package/src/scripts/eval/eval-help-consistency.ts +0 -11
  1725. package/src/scripts/eval/eval-in-action-cat-shellout-demo.ts +0 -31
  1726. package/src/scripts/eval/eval-ml-kaggle-model-optimization.py +0 -29
  1727. package/src/scripts/eval/eval-noisy-bayesopt-highdim.py +0 -44
  1728. package/src/scripts/eval/eval-noisy-latent-subspace-discovery.py +0 -44
  1729. package/src/scripts/eval/eval-parity-smoke.ts +0 -20
  1730. package/src/scripts/eval/eval-parity-sweep.ts +0 -26
  1731. package/src/scripts/eval/eval-resume-dirty-guard.ts +0 -8
  1732. package/src/scripts/eval/eval-security-path-traversal.ts +0 -38
  1733. package/src/scripts/run-autoresearch-showcase.sh +0 -75
  1734. /package/docs/{migration-mainline-post-v0.4.4.md → archive/migration-mainline-post-v0.4.4.md} +0 -0
  1735. /package/docs/{qa-plan-0.4.2.md → archive/qa-plan-0.4.2.md} +0 -0
  1736. /package/docs/{qa-report-0.4.2.md → archive/qa-report-0.4.2.md} +0 -0
@@ -1,3785 +0,0 @@
1
- import { describe, it } from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import fs from 'node:fs';
4
- import { syncBuiltinESMExports } from 'node:module';
5
- import { PassThrough } from 'node:stream';
6
- import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from 'fs/promises';
7
- import { join } from 'path';
8
- import { tmpdir } from 'os';
9
- import { buildClientAttachedReconcileHookName, assertTeamWorkerCliBinaryAvailable, buildWorkerProcessLaunchSpec, buildReconcileHudResizeArgs, buildRegisterClientAttachedReconcileArgs, buildRegisterResizeHookArgs, buildResizeHookName, buildResizeHookTarget, buildScheduleDelayedHudResizeArgs, buildUnregisterClientAttachedReconcileArgs, buildUnregisterResizeHookArgs, buildWorkerStartupCommand, buildHudPaneTarget, chooseTeamLeaderPaneId, createTeamSession, enableMouseScrolling, isMsysOrGitBash, isNativeWindows, isTmuxAvailable, restoreStandaloneHudPane, translatePathForMsys, isWsl2, isWorkerAlive, killWorker, killWorkerByPaneId, teardownWorkerPanes, listTeamSessions, resolveTeamWorkerCli, resolveTeamWorkerLaunchMode, resolveWorkerCliForSend, resolveTeamWorkerCliPlan, buildWorkerSubmitPlan, sanitizeTeamName, shouldAttemptAdaptiveRetry, sendToWorker, sendToWorkerStdin, sleepFractionalSeconds, translateWorkerLaunchArgsForCli, waitForWorkerReady, waitForWorkerReadyAsync, paneIsBootstrapping, classifyWorkerStartupInjectSafety, checkWorkerStartupInjectSafety, dismissTrustPromptIfPresent, evaluateStartupDirectTriggerSafetyCapture, mitigateCopyModeUnderlineArtifacts, } from '../tmux-session.js';
10
- import { HUD_RESIZE_RECONCILE_DELAY_SECONDS, HUD_TMUX_TEAM_HEIGHT_LINES } from '../../hud/constants.js';
11
- import * as tmuxSessionModule from '../tmux-session.js';
12
- import { RCS_ENTRY_PATH_ENV, RCS_STARTUP_CWD_ENV } from '../../utils/paths.js';
13
- function withEmptyPath(fn) {
14
- const prev = process.env.PATH;
15
- process.env.PATH = '';
16
- try {
17
- return fn();
18
- }
19
- finally {
20
- if (typeof prev === 'string')
21
- process.env.PATH = prev;
22
- else
23
- delete process.env.PATH;
24
- }
25
- }
26
- function withMockedExistsSync(mock, fn) {
27
- const original = fs.existsSync;
28
- fs.existsSync = mock;
29
- syncBuiltinESMExports();
30
- try {
31
- return fn();
32
- }
33
- finally {
34
- fs.existsSync = original;
35
- syncBuiltinESMExports();
36
- }
37
- }
38
- function escapeRegExp(value) {
39
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
40
- }
41
- const CLAUDE_BYPASS_PROMPT_CAPTURE = `Bypass Permissions mode
42
-
43
- 1. No, exit
44
- 2. Yes, I accept
45
-
46
- Press Enter to confirm`;
47
- const READY_HELPER_CAPTURE = `╭────────────────────────────────────────────╮
48
- │ >_ OpenAI Codex (v0.114.0) │
49
- │ │
50
- │ model: gpt-5.5 high /model to change │
51
- │ directory: ~/Workspace/demo │
52
- ╰────────────────────────────────────────────╯
53
-
54
- How can I help you today?`;
55
- const VIEWPORT_WITHOUT_VISIBLE_PROMPT_CAPTURE = `╭────────────────────────────────────────────╮
56
- │ >_ OpenAI Codex (v0.118.0) │
57
- │ │
58
- │ model: gpt-5.5 high /model to change │
59
- │ directory: ~/Workspace/demo │
60
- ╰────────────────────────────────────────────╯
61
-
62
- ⚠ MCP startup incomplete (failed: hf request)`;
63
- const VIEWPORT_SCROLLBACK_READY_CAPTURE = `${VIEWPORT_WITHOUT_VISIBLE_PROMPT_CAPTURE}
64
-
65
- › support lane on multi-image attach`;
66
- const QUEUED_AFTER_TOOL_CALL_CAPTURE = `• Messages to be submitted after next tool call (press esc to interrupt and send immediately)
67
- ↳ Read $RCS_TEAM_STATE_ROOT/team/demo/workers/worker-1/inbox.md, work now, report progress
68
-
69
- › Write tests for @filename`;
70
- async function withMockTmuxFixture(dirPrefix, tmuxScript, run) {
71
- const fakeBinDir = await mkdtemp(join(tmpdir(), dirPrefix));
72
- const logPath = join(fakeBinDir, 'tmux.log');
73
- const tmuxStubPath = join(fakeBinDir, 'tmux');
74
- const previousPath = process.env.PATH;
75
- try {
76
- await writeFile(tmuxStubPath, tmuxScript(logPath));
77
- await chmod(tmuxStubPath, 0o755);
78
- process.env.PATH = `${fakeBinDir}:${previousPath ?? ''}`;
79
- return await run({ logPath });
80
- }
81
- finally {
82
- if (typeof previousPath === 'string')
83
- process.env.PATH = previousPath;
84
- else
85
- delete process.env.PATH;
86
- await rm(fakeBinDir, { recursive: true, force: true });
87
- }
88
- }
89
- describe('sanitizeTeamName', () => {
90
- it('lowercases and strips invalid chars', () => {
91
- assert.equal(sanitizeTeamName('My Team!'), 'my-team');
92
- });
93
- it('truncates to 30 chars', () => {
94
- const long = 'a'.repeat(50);
95
- assert.equal(sanitizeTeamName(long).length, 30);
96
- });
97
- it('rejects empty after sanitization', () => {
98
- assert.throws(() => sanitizeTeamName('!!!'), /empty/i);
99
- });
100
- });
101
- describe('chooseTeamLeaderPaneId', () => {
102
- it('keeps preferred pane when it is not HUD', () => {
103
- const panes = [
104
- { paneId: '%1', currentCommand: 'node', startCommand: "'codex'" },
105
- { paneId: '%2', currentCommand: 'node', startCommand: "node rcs hud --watch" },
106
- ];
107
- assert.equal(chooseTeamLeaderPaneId(panes, '%1'), '%1');
108
- });
109
- it('switches away from HUD preferred pane to first non-HUD pane', () => {
110
- const panes = [
111
- { paneId: '%2', currentCommand: 'node', startCommand: "node rcs hud --watch" },
112
- { paneId: '%1', currentCommand: 'node', startCommand: "'codex'" },
113
- ];
114
- assert.equal(chooseTeamLeaderPaneId(panes, '%2'), '%1');
115
- });
116
- it('falls back to preferred pane when all panes are HUD panes', () => {
117
- const panes = [
118
- { paneId: '%2', currentCommand: 'node', startCommand: "node rcs hud --watch" },
119
- { paneId: '%3', currentCommand: 'node', startCommand: "node rcs hud --watch" },
120
- ];
121
- assert.equal(chooseTeamLeaderPaneId(panes, '%2'), '%2');
122
- });
123
- });
124
- describe('HUD resize hook command builders', () => {
125
- it('buildResizeHookName normalizes all segments into collision-safe tokens', () => {
126
- const name = buildResizeHookName('Team A', 'Session:Main', '0', '%12');
127
- assert.equal(name, 'rcs_resize_Team_A_Session_Main_0_12');
128
- });
129
- it('buildResizeHookTarget uses session:window format', () => {
130
- assert.equal(buildResizeHookTarget('my-session', '3'), 'my-session:3');
131
- });
132
- it('buildHudPaneTarget always returns %<pane_id>', () => {
133
- assert.equal(buildHudPaneTarget('%41'), '%41');
134
- assert.equal(buildHudPaneTarget('41'), '%41');
135
- });
136
- it('buildRegisterResizeHookArgs uses window target and numeric client-resized hook slot', () => {
137
- const args = buildRegisterResizeHookArgs('my-session:0', 'rcs_resize_team_session_0_1', '%1');
138
- assert.equal(args[0], 'set-hook');
139
- assert.equal(args[1], '-t');
140
- assert.equal(args[2], 'my-session:0');
141
- assert.match(args[3] ?? '', /^client-resized\[\d+\]$/);
142
- assert.equal(args[4], `run-shell -b 'tmux resize-pane -t %1 -y ${HUD_TMUX_TEAM_HEIGHT_LINES} >/dev/null 2>&1 || true'`);
143
- });
144
- it('buildUnregisterResizeHookArgs removes the exact numeric hook slot', () => {
145
- const registered = buildRegisterResizeHookArgs('my-session:0', 'rcs_resize_team_session_0_1', '%1');
146
- const unregistered = buildUnregisterResizeHookArgs('my-session:0', 'rcs_resize_team_session_0_1');
147
- assert.deepEqual(unregistered, ['set-hook', '-u', '-t', 'my-session:0', registered[3]]);
148
- });
149
- it('buildClientAttachedReconcileHookName normalizes all segments into collision-safe tokens', () => {
150
- const name = buildClientAttachedReconcileHookName('Team A', 'Session:Main', '0', '%12');
151
- assert.equal(name, 'rcs_attached_Team_A_Session_Main_0_12');
152
- });
153
- it('buildRegisterClientAttachedReconcileArgs installs one-shot client-attached reconcile hook', () => {
154
- const args = buildRegisterClientAttachedReconcileArgs('my-session:0', 'rcs_attached_team_session_0_1', '%1');
155
- assert.equal(args[0], 'set-hook');
156
- assert.equal(args[1], '-t');
157
- assert.equal(args[2], 'my-session:0');
158
- assert.match(args[3] ?? '', /^client-attached\[\d+\]$/);
159
- assert.match(args[4] ?? '', /^run-shell -b 'tmux resize-pane -t %1 -y \d+ >\/dev\/null 2>&1 \|\| true; tmux set-hook -u -t my-session:0 client-attached\[\d+\]'$/);
160
- });
161
- it('buildUnregisterClientAttachedReconcileArgs removes the exact numeric client-attached slot', () => {
162
- const registered = buildRegisterClientAttachedReconcileArgs('my-session:0', 'rcs_attached_team_session_0_1', '%1');
163
- const unregistered = buildUnregisterClientAttachedReconcileArgs('my-session:0', 'rcs_attached_team_session_0_1');
164
- assert.deepEqual(unregistered, ['set-hook', '-u', '-t', 'my-session:0', registered[3]]);
165
- });
166
- it('hook indices stay within signed 32-bit range (issue #240)', () => {
167
- // buildResizeHookSlot and buildClientAttachedHookSlot must produce indices
168
- // in [0, 2147483647) so tmux (signed 32-bit) does not overflow.
169
- const longName = 'rcs_resize_' + 'a'.repeat(200);
170
- const resizeArgs = buildRegisterResizeHookArgs('sess:0', longName, '%1');
171
- const attachedArgs = buildRegisterClientAttachedReconcileArgs('sess:0', longName, '%1');
172
- const resizeSlot = resizeArgs[3] ?? '';
173
- const attachedSlot = attachedArgs[3] ?? '';
174
- const resizeIndex = Number((resizeSlot.match(/\[(\d+)\]/) ?? [])[1]);
175
- const attachedIndex = Number((attachedSlot.match(/\[(\d+)\]/) ?? [])[1]);
176
- assert.ok(resizeIndex >= 0, `resize index must be non-negative, got ${resizeIndex}`);
177
- assert.ok(resizeIndex < 2147483647, `resize index must be < 2^31-1, got ${resizeIndex}`);
178
- assert.ok(attachedIndex >= 0, `attached index must be non-negative, got ${attachedIndex}`);
179
- assert.ok(attachedIndex < 2147483647, `attached index must be < 2^31-1, got ${attachedIndex}`);
180
- });
181
- it('hook indices are deterministic across calls', () => {
182
- const name = 'rcs_resize_team_session_0_1';
183
- const a = buildRegisterResizeHookArgs('s:0', name, '%1');
184
- const b = buildRegisterResizeHookArgs('s:0', name, '%1');
185
- assert.equal(a[3], b[3]);
186
- const c = buildRegisterClientAttachedReconcileArgs('s:0', name, '%1');
187
- const d = buildRegisterClientAttachedReconcileArgs('s:0', name, '%1');
188
- assert.equal(c[3], d[3]);
189
- });
190
- it('buildScheduleDelayedHudResizeArgs schedules tmux-side delayed reconcile', () => {
191
- assert.deepEqual(buildScheduleDelayedHudResizeArgs('%1'), ['run-shell', '-b', `sleep ${HUD_RESIZE_RECONCILE_DELAY_SECONDS}; tmux resize-pane -t %1 -y ${HUD_TMUX_TEAM_HEIGHT_LINES} >/dev/null 2>&1 || true`]);
192
- });
193
- it('buildReconcileHudResizeArgs executes a best-effort quiet resize command', () => {
194
- const args = buildReconcileHudResizeArgs('%7');
195
- assert.equal(args.join(' ').includes('split-window'), false);
196
- assert.deepEqual(args, ['run-shell', `tmux resize-pane -t %7 -y ${HUD_TMUX_TEAM_HEIGHT_LINES} >/dev/null 2>&1 || true`]);
197
- });
198
- it('resolves the tmux executable for win32 hook shell snippets', async () => {
199
- const fakeBin = await mkdtemp(join(tmpdir(), 'rcs-win32-hook-tmux-'));
200
- const prevPath = process.env.PATH;
201
- const prevPathext = process.env.PATHEXT;
202
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
203
- try {
204
- const tmuxPath = join(fakeBin, 'tmux.exe');
205
- await writeFile(tmuxPath, '');
206
- process.env.PATH = fakeBin;
207
- process.env.PATHEXT = '.EXE';
208
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
209
- const resizeArgs = buildRegisterResizeHookArgs('my-session:0', 'rcs_resize_team_session_0_1', '%1');
210
- const delayedArgs = buildScheduleDelayedHudResizeArgs('%1');
211
- const reconcileArgs = buildReconcileHudResizeArgs('%1');
212
- assert.match(resizeArgs[4] ?? '', new RegExp(escapeRegExp(tmuxPath)));
213
- assert.doesNotMatch(resizeArgs[4] ?? '', /^run-shell -b 'tmux resize-pane/);
214
- assert.match(delayedArgs[2] ?? '', new RegExp(escapeRegExp(tmuxPath)));
215
- assert.doesNotMatch(delayedArgs[2] ?? '', /sleep \d+; tmux resize-pane/);
216
- assert.match(reconcileArgs[1] ?? '', new RegExp(escapeRegExp(tmuxPath)));
217
- assert.doesNotMatch(reconcileArgs[1] ?? '', /^tmux resize-pane/);
218
- }
219
- finally {
220
- if (origPlatform)
221
- Object.defineProperty(process, 'platform', origPlatform);
222
- if (typeof prevPath === 'string')
223
- process.env.PATH = prevPath;
224
- else
225
- delete process.env.PATH;
226
- if (typeof prevPathext === 'string')
227
- process.env.PATHEXT = prevPathext;
228
- else
229
- delete process.env.PATHEXT;
230
- await rm(fakeBin, { recursive: true, force: true });
231
- }
232
- });
233
- it('resolves the tmux executable twice for win32 client-attached one-shot hooks', async () => {
234
- const fakeBin = await mkdtemp(join(tmpdir(), 'rcs-win32-attached-hook-'));
235
- const prevPath = process.env.PATH;
236
- const prevPathext = process.env.PATHEXT;
237
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
238
- try {
239
- const tmuxPath = join(fakeBin, 'tmux.exe');
240
- await writeFile(tmuxPath, '');
241
- process.env.PATH = fakeBin;
242
- process.env.PATHEXT = '.EXE';
243
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
244
- const args = buildRegisterClientAttachedReconcileArgs('my-session:0', 'rcs_attached_team_session_0_1', '%1');
245
- const matches = (args[4] ?? '').match(new RegExp(escapeRegExp(tmuxPath), 'g')) || [];
246
- assert.equal(matches.length, 2, 'client-attached hook should resolve tmux for both resize and unregister commands');
247
- assert.doesNotMatch(args[4] ?? '', /; tmux set-hook -u -t my-session:0 client-attached/);
248
- }
249
- finally {
250
- if (origPlatform)
251
- Object.defineProperty(process, 'platform', origPlatform);
252
- if (typeof prevPath === 'string')
253
- process.env.PATH = prevPath;
254
- else
255
- delete process.env.PATH;
256
- if (typeof prevPathext === 'string')
257
- process.env.PATHEXT = prevPathext;
258
- else
259
- delete process.env.PATHEXT;
260
- await rm(fakeBin, { recursive: true, force: true });
261
- }
262
- });
263
- });
264
- describe('evaluateStartupDirectTriggerSafetyCapture', () => {
265
- it('allows startup direct triggers on a ready prompt or Codex viewport', () => {
266
- assert.deepEqual(evaluateStartupDirectTriggerSafetyCapture(READY_HELPER_CAPTURE, 'codex'), {
267
- safe: true,
268
- reason: 'ready_prompt',
269
- });
270
- assert.deepEqual(evaluateStartupDirectTriggerSafetyCapture(VIEWPORT_WITHOUT_VISIBLE_PROMPT_CAPTURE, 'codex'), {
271
- safe: true,
272
- reason: 'codex_viewport',
273
- });
274
- });
275
- it('blocks startup direct triggers through trust and Claude bypass prompts', () => {
276
- assert.deepEqual(evaluateStartupDirectTriggerSafetyCapture(`Do you trust the contents of this directory?
277
- Press enter to continue`, 'codex'), {
278
- safe: false,
279
- reason: 'trust_prompt',
280
- });
281
- assert.deepEqual(evaluateStartupDirectTriggerSafetyCapture(CLAUDE_BYPASS_PROMPT_CAPTURE, 'claude'), {
282
- safe: false,
283
- reason: 'claude_bypass_prompt',
284
- });
285
- });
286
- });
287
- describe('sendToWorker validation', () => {
288
- it('rejects text over 200 chars', async () => {
289
- await assert.rejects(sendToWorker('rcs-team-x', 1, 'a'.repeat(200)), /< 200/i);
290
- });
291
- it('rejects empty/whitespace text', async () => {
292
- await assert.rejects(sendToWorker('rcs-team-x', 1, ' '), /non-empty/i);
293
- });
294
- it('rejects injection marker', async () => {
295
- await assert.rejects(sendToWorker('rcs-team-x', 1, `hello [RCS_TMUX_INJECT]`), /marker/i);
296
- });
297
- it('auto-accepts the Claude bypass prompt before sending worker text', async () => {
298
- await withMockTmuxFixture('rcs-tmux-claude-bypass-send-', (logPath) => `#!/bin/sh
299
- set -eu
300
- state_dir="$(dirname "${logPath}")"
301
- accepted_file="$state_dir/accepted"
302
- printf '%s\n' "$*" >> "${logPath}"
303
- case "$1" in
304
- capture-pane)
305
- if [ -f "$accepted_file" ]; then
306
- cat <<'EOF'
307
- How can I help you today?
308
- EOF
309
- else
310
- cat <<'EOF'
311
- ${CLAUDE_BYPASS_PROMPT_CAPTURE}
312
- EOF
313
- fi
314
- exit 0
315
- ;;
316
- send-keys)
317
- if [ "\${4:-}" = "-l" ] && [ "\${6:-}" = "2" ]; then
318
- : > "$accepted_file"
319
- fi
320
- exit 0
321
- ;;
322
- *)
323
- exit 0
324
- ;;
325
- esac
326
- `, async ({ logPath }) => {
327
- await sendToWorker('rcs-team-x', 1, 'check inbox');
328
- const log = await readFile(logPath, 'utf-8');
329
- const acceptIndex = log.indexOf('send-keys -t rcs-team-x:1 -l -- 2');
330
- const submitIndex = log.indexOf('send-keys -t rcs-team-x:1 -l -- check inbox');
331
- assert.notEqual(acceptIndex, -1, `expected bypass acceptance in log:\n${log}`);
332
- assert.notEqual(submitIndex, -1, `expected worker text submission in log:\n${log}`);
333
- assert.ok(acceptIndex < submitIndex, `expected bypass acceptance before worker text:\n${log}`);
334
- });
335
- });
336
- it('ignores stale queued-next-tool-call banner text that only survives in scrollback history', async () => {
337
- await withMockTmuxFixture('rcs-tmux-codex-stale-queued-scrollback-', (logPath) => `#!/bin/sh
338
- set -eu
339
- state_dir="$(dirname "${logPath}")"
340
- text_sent_file="$state_dir/text-sent"
341
- printf '%s\n' "$*" >> "${logPath}"
342
- case "$1" in
343
- capture-pane)
344
- if printf '%s\n' "$*" | grep -q -- ' -S -80'; then
345
- if [ -f "$text_sent_file" ]; then
346
- cat <<'EOF'
347
- ${QUEUED_AFTER_TOOL_CALL_CAPTURE}
348
- EOF
349
- else
350
- cat <<'EOF'
351
- ${READY_HELPER_CAPTURE}
352
- EOF
353
- fi
354
- else
355
- cat <<'EOF'
356
- ${READY_HELPER_CAPTURE}
357
- EOF
358
- fi
359
- exit 0
360
- ;;
361
- send-keys)
362
- if [ "\${4:-}" = "-l" ] && [ "\${6:-}" = "check inbox" ]; then
363
- : > "$text_sent_file"
364
- fi
365
- exit 0
366
- ;;
367
- *)
368
- exit 0
369
- ;;
370
- esac
371
- `, async ({ logPath }) => {
372
- await sendToWorker('rcs-team-x', 1, 'check inbox');
373
- const log = await readFile(logPath, 'utf-8');
374
- const enterCount = (log.match(/send-keys -t rcs-team-x:1 C-m/g) || []).length;
375
- assert.equal(enterCount, 2, `expected only the baseline submit presses when the queued banner is stale scrollback:\n${log}`);
376
- assert.match(log, /capture-pane -t rcs-team-x:1 -p/);
377
- assert.match(log, /capture-pane -t rcs-team-x:1 -p -S -80/);
378
- });
379
- });
380
- it('keeps nudging Codex when the visible pane still shows a live queued-next-tool-call banner', async () => {
381
- await withMockTmuxFixture('rcs-tmux-codex-visible-queued-submit-', (logPath) => `#!/bin/sh
382
- set -eu
383
- state_dir="$(dirname "${logPath}")"
384
- text_sent_file="$state_dir/text-sent"
385
- enter_count_file="$state_dir/enter-count"
386
- printf '%s\n' "$*" >> "${logPath}"
387
- case "$1" in
388
- capture-pane)
389
- enter_count=0
390
- if [ -f "$enter_count_file" ]; then
391
- enter_count=$(cat "$enter_count_file")
392
- fi
393
- if printf '%s\n' "$*" | grep -q -- ' -S -80'; then
394
- cat <<'EOF'
395
- ${READY_HELPER_CAPTURE}
396
- EOF
397
- else
398
- if [ "$enter_count" -ge 4 ]; then
399
- cat <<'EOF'
400
- initialized in .
401
-
402
- ◦ Waiting for background terminal (59s…)
403
- EOF
404
- elif [ -f "$text_sent_file" ]; then
405
- cat <<'EOF'
406
- ${QUEUED_AFTER_TOOL_CALL_CAPTURE}
407
- EOF
408
- else
409
- cat <<'EOF'
410
- ${READY_HELPER_CAPTURE}
411
- EOF
412
- fi
413
- fi
414
- exit 0
415
- ;;
416
- send-keys)
417
- if [ "\${4:-}" = "-l" ] && [ "\${6:-}" = "check inbox" ]; then
418
- : > "$text_sent_file"
419
- fi
420
- if [ "\${4:-}" = "C-m" ]; then
421
- enter_count=0
422
- if [ -f "$enter_count_file" ]; then
423
- enter_count=$(cat "$enter_count_file")
424
- fi
425
- enter_count=$((enter_count + 1))
426
- printf '%s' "$enter_count" > "$enter_count_file"
427
- fi
428
- exit 0
429
- ;;
430
- *)
431
- exit 0
432
- ;;
433
- esac
434
- `, async ({ logPath }) => {
435
- await sendToWorker('rcs-team-x', 1, 'check inbox');
436
- const log = await readFile(logPath, 'utf-8');
437
- const enterCount = (log.match(/send-keys -t rcs-team-x:1 C-m/g) || []).length;
438
- assert.ok(enterCount >= 4, `expected extra submit nudges when Codex queues the trigger:\n${log}`);
439
- });
440
- });
441
- it('fails closed when the visible queued-next-tool-call banner never clears after the final submit round', async () => {
442
- await withMockTmuxFixture('rcs-tmux-codex-stuck-queued-submit-', (logPath) => `#!/bin/sh
443
- set -eu
444
- state_dir="$(dirname "${logPath}")"
445
- text_sent_file="$state_dir/text-sent"
446
- printf '%s\n' "$*" >> "${logPath}"
447
- case "$1" in
448
- capture-pane)
449
- if printf '%s\n' "$*" | grep -q -- ' -S -80'; then
450
- cat <<'EOF'
451
- ${READY_HELPER_CAPTURE}
452
- EOF
453
- else
454
- if [ -f "$text_sent_file" ]; then
455
- cat <<'EOF'
456
- ${QUEUED_AFTER_TOOL_CALL_CAPTURE}
457
- EOF
458
- else
459
- cat <<'EOF'
460
- ${READY_HELPER_CAPTURE}
461
- EOF
462
- fi
463
- fi
464
- exit 0
465
- ;;
466
- send-keys)
467
- if [ "\${4:-}" = "-l" ] && [ "\${6:-}" = "check inbox" ]; then
468
- : > "$text_sent_file"
469
- fi
470
- exit 0
471
- ;;
472
- *)
473
- exit 0
474
- ;;
475
- esac
476
- `, async ({ logPath }) => {
477
- await assert.rejects(() => sendToWorker('rcs-team-x', 1, 'check inbox'), /submit_queued_after_tool_call/);
478
- const log = await readFile(logPath, 'utf-8');
479
- const enterCount = (log.match(/send-keys -t rcs-team-x:1 C-m/g) || []).length;
480
- assert.ok(enterCount >= 4, `expected repeated submit nudges before failing closed on stuck queued banner:\n${log}`);
481
- });
482
- });
483
- });
484
- describe('startup direct trigger safety', () => {
485
- it('classifies ready panes as safe and blocks trust, bypass, bootstrapping, and active-task captures', () => {
486
- assert.equal(classifyWorkerStartupInjectSafety(READY_HELPER_CAPTURE), 'safe');
487
- assert.equal(classifyWorkerStartupInjectSafety('Do you trust the contents of this directory?\nPress enter to continue'), 'trust_prompt');
488
- assert.equal(classifyWorkerStartupInjectSafety(CLAUDE_BYPASS_PROMPT_CAPTURE), 'claude_bypass_prompt');
489
- assert.equal(classifyWorkerStartupInjectSafety('OpenAI Codex\nmodel: loading'), 'bootstrapping');
490
- assert.equal(classifyWorkerStartupInjectSafety('OpenAI Codex\nmodel: test\n• Running tests (esc to interrupt)'), 'active_task');
491
- });
492
- it('checks visible pane first and refuses direct injection through a trust prompt', async () => {
493
- await withMockTmuxFixture('rcs-tmux-startup-direct-trust-', (logPath) => `#!/bin/sh
494
- set -eu
495
- printf '%s\n' "$*" >> "${logPath}"
496
- case "$1" in
497
- capture-pane)
498
- cat <<'EOF'
499
- Do you trust the contents of this directory?
500
- Press enter to continue
501
- EOF
502
- exit 0
503
- ;;
504
- *)
505
- exit 0
506
- ;;
507
- esac
508
- `, async ({ logPath }) => {
509
- assert.deepEqual(await checkWorkerStartupInjectSafety('rcs-team-x', 1), { safe: false, reason: 'trust_prompt' });
510
- const log = await readFile(logPath, 'utf-8');
511
- assert.doesNotMatch(log, /send-keys/);
512
- });
513
- });
514
- });
515
- describe('shouldAttemptAdaptiveRetry', () => {
516
- it('returns false when adaptive retry is disabled', () => {
517
- assert.equal(shouldAttemptAdaptiveRetry('auto', true, false, '❯ hello', 'hello'), false);
518
- });
519
- it('returns false when strategy is not auto', () => {
520
- assert.equal(shouldAttemptAdaptiveRetry('queue', true, true, '❯ hello', 'hello'), false);
521
- });
522
- it('returns false when pane was not initially busy', () => {
523
- assert.equal(shouldAttemptAdaptiveRetry('auto', false, true, '❯ hello', 'hello'), false);
524
- });
525
- it('returns false when trigger text is missing from latest capture', () => {
526
- assert.equal(shouldAttemptAdaptiveRetry('auto', true, true, '❯ ready prompt', 'hello'), false);
527
- });
528
- it('returns false when latest capture still shows active task markers', () => {
529
- const activeCapture = '• Doing work (2m 10s • esc to interrupt)\n❯ hello';
530
- assert.equal(shouldAttemptAdaptiveRetry('auto', true, true, activeCapture, 'hello'), false);
531
- });
532
- it('returns false when latest capture shows Claude active generation line', () => {
533
- const activeCapture = '· Caramelizing…\n❯ hello';
534
- assert.equal(shouldAttemptAdaptiveRetry('auto', true, true, activeCapture, 'hello'), false);
535
- });
536
- it('returns false when latest capture shows Claude apostrophe generation line', () => {
537
- const activeCapture = "· Beboppin'...\n❯ hello";
538
- assert.equal(shouldAttemptAdaptiveRetry('auto', true, true, activeCapture, 'hello'), false);
539
- });
540
- it('returns false when latest capture shows Claude sparkle generation line', () => {
541
- const activeCapture = '✻ Pollinating…\n❯ hello';
542
- assert.equal(shouldAttemptAdaptiveRetry('auto', true, true, activeCapture, 'hello'), false);
543
- });
544
- it('returns false when latest capture shows background terminal running status', () => {
545
- const activeCapture = '2 background terminal running\n❯ hello';
546
- assert.equal(shouldAttemptAdaptiveRetry('auto', true, true, activeCapture, 'hello'), false);
547
- });
548
- it('does not treat non-ellipsis Claude bullet text as active generation', () => {
549
- const readyCapture = '· Caramelizing\n❯ hello';
550
- assert.equal(shouldAttemptAdaptiveRetry('auto', true, true, readyCapture, 'hello'), true);
551
- });
552
- it('returns true only when auto+busy and latest capture is ready with visible text', () => {
553
- const readyCapture = '❯ hello';
554
- assert.equal(shouldAttemptAdaptiveRetry('auto', true, true, readyCapture, 'hello'), true);
555
- });
556
- });
557
- describe('paneIsBootstrapping (#391)', () => {
558
- it('detects "loading" keyword', () => {
559
- assert.equal(paneIsBootstrapping(['loading model weights…']), true);
560
- });
561
- it('detects "model: loading" pattern', () => {
562
- assert.equal(paneIsBootstrapping(['gpt-4o', 'model: loading']), true);
563
- });
564
- it('detects "initializing" keyword', () => {
565
- assert.equal(paneIsBootstrapping(['Initializing workspace']), true);
566
- });
567
- it('detects "connecting to" keyword', () => {
568
- assert.equal(paneIsBootstrapping(['connecting to server']), true);
569
- });
570
- it('returns false for normal ready prompt', () => {
571
- assert.equal(paneIsBootstrapping(['› ']), false);
572
- });
573
- it('returns false for status bar without loading', () => {
574
- assert.equal(paneIsBootstrapping(['gpt-4o', '50% left', '› ']), false);
575
- });
576
- });
577
- describe('paneLooksReady gate: status-only is not ready (#391)', () => {
578
- // These verify the fix for #391: status bar markers alone (gpt-*, % left,
579
- // Claude Code v*) must NOT count as ready without a prompt character.
580
- // We test indirectly via shouldAttemptAdaptiveRetry since paneLooksReady is
581
- // not exported, but the adaptive retry guard calls paneLooksReady internally.
582
- it('shouldAttemptAdaptiveRetry returns false for status-only capture (no prompt)', () => {
583
- // Capture has Codex status bar but no prompt character — paneLooksReady
584
- // should return false, so adaptive retry should also return false.
585
- const statusOnlyCapture = 'gpt-4o 50% left';
586
- assert.equal(shouldAttemptAdaptiveRetry('auto', true, true, statusOnlyCapture, 'gpt-4o'), false);
587
- });
588
- it('shouldAttemptAdaptiveRetry returns false for Claude status-only capture', () => {
589
- const statusOnlyCapture = 'Claude Code v1.2.3 claude-sonnet-4-20250514';
590
- assert.equal(shouldAttemptAdaptiveRetry('auto', true, true, statusOnlyCapture, 'Claude Code'), false);
591
- });
592
- it('shouldAttemptAdaptiveRetry returns false when pane is bootstrapping', () => {
593
- const loadingCapture = 'gpt-4o\nmodel: loading\n› hello';
594
- assert.equal(shouldAttemptAdaptiveRetry('auto', true, true, loadingCapture, 'hello'), false);
595
- });
596
- it('shouldAttemptAdaptiveRetry treats issue-only prompt as ready even without glyph', () => {
597
- const issuePromptCapture = 'IND-123 only...';
598
- assert.equal(shouldAttemptAdaptiveRetry('auto', true, true, issuePromptCapture, 'IND-123 only...'), true);
599
- });
600
- });
601
- describe('buildWorkerStartupCommand', () => {
602
- it('auto-selects gemini worker CLI from gemini model', () => {
603
- const prevShell = process.env.SHELL;
604
- const prevCli = process.env.RCS_TEAM_WORKER_CLI;
605
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
606
- process.env.SHELL = '/bin/bash';
607
- delete process.env.RCS_TEAM_WORKER_CLI; // auto
608
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
609
- try {
610
- const cmd = buildWorkerStartupCommand('alpha', 1, ['--model', 'gemini-2.0-pro'], process.cwd(), {}, undefined, 'Read worker inbox');
611
- assert.match(cmd, /exec .*gemini/);
612
- assert.match(cmd, /--approval-mode/);
613
- assert.match(cmd, /yolo/);
614
- assert.match(cmd, /--model/);
615
- assert.match(cmd, /gemini-2.0-pro/);
616
- assert.match(cmd, /(?:^|\s|')-i(?:'|\s|$)/);
617
- assert.match(cmd, /Read worker inbox/);
618
- assert.match(cmd, /Read worker inbox/);
619
- }
620
- finally {
621
- if (typeof prevShell === 'string')
622
- process.env.SHELL = prevShell;
623
- else
624
- delete process.env.SHELL;
625
- if (typeof prevCli === 'string')
626
- process.env.RCS_TEAM_WORKER_CLI = prevCli;
627
- else
628
- delete process.env.RCS_TEAM_WORKER_CLI;
629
- if (typeof prevBypass === 'string')
630
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
631
- else
632
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
633
- }
634
- });
635
- it('auto-selects claude worker CLI from claude model', () => {
636
- const prevShell = process.env.SHELL;
637
- const prevCli = process.env.RCS_TEAM_WORKER_CLI;
638
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
639
- process.env.SHELL = '/bin/bash';
640
- delete process.env.RCS_TEAM_WORKER_CLI; // auto
641
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
642
- try {
643
- const cmd = buildWorkerStartupCommand('alpha', 1, ['--model', 'claude-3-7-sonnet']);
644
- assert.match(cmd, /exec .*claude/);
645
- assert.equal((cmd.match(/--dangerously-skip-permissions/g) || []).length, 1);
646
- assert.doesNotMatch(cmd, /--model/);
647
- assert.doesNotMatch(cmd, /model_instructions_file=/);
648
- }
649
- finally {
650
- if (typeof prevShell === 'string')
651
- process.env.SHELL = prevShell;
652
- else
653
- delete process.env.SHELL;
654
- if (typeof prevCli === 'string')
655
- process.env.RCS_TEAM_WORKER_CLI = prevCli;
656
- else
657
- delete process.env.RCS_TEAM_WORKER_CLI;
658
- if (typeof prevBypass === 'string')
659
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
660
- else
661
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
662
- }
663
- });
664
- it('respects explicit RCS_TEAM_WORKER_CLI override', () => {
665
- const prevShell = process.env.SHELL;
666
- const prevCli = process.env.RCS_TEAM_WORKER_CLI;
667
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
668
- process.env.SHELL = '/bin/bash';
669
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
670
- try {
671
- process.env.RCS_TEAM_WORKER_CLI = 'codex';
672
- const codexCmd = buildWorkerStartupCommand('alpha', 1, ['--model', 'claude-3-7-sonnet']);
673
- assert.match(codexCmd, /exec .*codex/);
674
- process.env.RCS_TEAM_WORKER_CLI = 'claude';
675
- const claudeCmd = buildWorkerStartupCommand('alpha', 1, ['--model', 'gpt-5']);
676
- assert.match(claudeCmd, /exec .*claude/);
677
- assert.equal((claudeCmd.match(/--dangerously-skip-permissions/g) || []).length, 1);
678
- assert.doesNotMatch(claudeCmd, /--model/);
679
- }
680
- finally {
681
- if (typeof prevShell === 'string')
682
- process.env.SHELL = prevShell;
683
- else
684
- delete process.env.SHELL;
685
- if (typeof prevCli === 'string')
686
- process.env.RCS_TEAM_WORKER_CLI = prevCli;
687
- else
688
- delete process.env.RCS_TEAM_WORKER_CLI;
689
- if (typeof prevBypass === 'string')
690
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
691
- else
692
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
693
- }
694
- });
695
- it('applies claude skip-permissions when worker CLI is provided by plan override', () => {
696
- const prevShell = process.env.SHELL;
697
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
698
- process.env.SHELL = '/bin/bash';
699
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
700
- try {
701
- const cmd = buildWorkerStartupCommand('alpha', 1, ['--model', 'gpt-5', '--dangerously-bypass-approvals-and-sandbox'], process.cwd(), {}, 'claude');
702
- assert.match(cmd, /exec .*claude/);
703
- assert.equal((cmd.match(/--dangerously-skip-permissions/g) || []).length, 1);
704
- assert.doesNotMatch(cmd, /dangerously-bypass-approvals-and-sandbox/);
705
- assert.doesNotMatch(cmd, /--model/);
706
- }
707
- finally {
708
- if (typeof prevShell === 'string')
709
- process.env.SHELL = prevShell;
710
- else
711
- delete process.env.SHELL;
712
- if (typeof prevBypass === 'string')
713
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
714
- else
715
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
716
- }
717
- });
718
- it('drops all explicit launch args for claude workers', () => {
719
- const prevShell = process.env.SHELL;
720
- const prevCli = process.env.RCS_TEAM_WORKER_CLI;
721
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
722
- process.env.SHELL = '/bin/bash';
723
- process.env.RCS_TEAM_WORKER_CLI = 'claude';
724
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
725
- try {
726
- const cmd = buildWorkerStartupCommand('alpha', 1, [
727
- '--dangerously-bypass-approvals-and-sandbox',
728
- '-c', 'model_instructions_file="/tmp/custom.md"',
729
- '--model', 'claude-3-7-sonnet',
730
- ]);
731
- assert.match(cmd, /exec .*claude/);
732
- assert.equal((cmd.match(/--dangerously-skip-permissions/g) || []).length, 1);
733
- assert.doesNotMatch(cmd, /dangerously-bypass-approvals-and-sandbox/);
734
- assert.doesNotMatch(cmd, /model_instructions_file=/);
735
- assert.doesNotMatch(cmd, /--model/);
736
- assert.doesNotMatch(cmd, /claude-3-7-sonnet/);
737
- }
738
- finally {
739
- if (typeof prevShell === 'string')
740
- process.env.SHELL = prevShell;
741
- else
742
- delete process.env.SHELL;
743
- if (typeof prevCli === 'string')
744
- process.env.RCS_TEAM_WORKER_CLI = prevCli;
745
- else
746
- delete process.env.RCS_TEAM_WORKER_CLI;
747
- if (typeof prevBypass === 'string')
748
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
749
- else
750
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
751
- }
752
- });
753
- it('does not pass bypass flags in claude mode', () => {
754
- const prevArgv = process.argv;
755
- const prevShell = process.env.SHELL;
756
- const prevCli = process.env.RCS_TEAM_WORKER_CLI;
757
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
758
- process.env.SHELL = '/bin/bash';
759
- process.env.RCS_TEAM_WORKER_CLI = 'claude';
760
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
761
- process.argv = [...prevArgv, '--madmax'];
762
- try {
763
- const cmd = buildWorkerStartupCommand('alpha', 1);
764
- assert.match(cmd, /exec .*claude/);
765
- assert.equal((cmd.match(/--dangerously-skip-permissions/g) || []).length, 1);
766
- assert.doesNotMatch(cmd, /dangerously-bypass-approvals-and-sandbox/);
767
- }
768
- finally {
769
- process.argv = prevArgv;
770
- if (typeof prevShell === 'string')
771
- process.env.SHELL = prevShell;
772
- else
773
- delete process.env.SHELL;
774
- if (typeof prevCli === 'string')
775
- process.env.RCS_TEAM_WORKER_CLI = prevCli;
776
- else
777
- delete process.env.RCS_TEAM_WORKER_CLI;
778
- if (typeof prevBypass === 'string')
779
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
780
- else
781
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
782
- }
783
- });
784
- it('uses zsh with ~/.zshrc and non-login shell exec semantics', () => {
785
- const prevShell = process.env.SHELL;
786
- process.env.SHELL = '/bin/zsh';
787
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
788
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
789
- try {
790
- const cmd = withMockedExistsSync((candidate) => candidate === '/bin/zsh', () => buildWorkerStartupCommand('alpha', 2));
791
- assert.match(cmd, /RCS_TEAM_WORKER=alpha\/worker-2/);
792
- assert.match(cmd, /'\/bin\/zsh' -c/);
793
- assert.doesNotMatch(cmd, /'\/bin\/zsh' -lc\b/);
794
- assert.match(cmd, /source ~\/\.zshrc/);
795
- assert.match(cmd, /exec .*codex/);
796
- }
797
- finally {
798
- if (typeof prevShell === 'string')
799
- process.env.SHELL = prevShell;
800
- else
801
- delete process.env.SHELL;
802
- if (typeof prevBypass === 'string')
803
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
804
- else
805
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
806
- }
807
- });
808
- it('accepts Homebrew zsh as a supported worker shell without falling back', () => {
809
- const prevShell = process.env.SHELL;
810
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
811
- process.env.SHELL = '/opt/homebrew/bin/zsh';
812
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
813
- try {
814
- const cmd = withMockedExistsSync((candidate) => candidate === '/opt/homebrew/bin/zsh', () => buildWorkerStartupCommand('alpha', 2));
815
- assert.match(cmd, /'\/opt\/homebrew\/bin\/zsh' -c/);
816
- assert.doesNotMatch(cmd, /'\/bin\/sh' -c/);
817
- assert.match(cmd, /source ~\/\.zshrc/);
818
- }
819
- finally {
820
- if (typeof prevShell === 'string')
821
- process.env.SHELL = prevShell;
822
- else
823
- delete process.env.SHELL;
824
- if (typeof prevBypass === 'string')
825
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
826
- else
827
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
828
- }
829
- });
830
- it('accepts MacPorts zsh as a supported worker shell without falling back', () => {
831
- const prevShell = process.env.SHELL;
832
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
833
- process.env.SHELL = '/opt/local/bin/zsh';
834
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
835
- try {
836
- const cmd = withMockedExistsSync((candidate) => candidate === '/opt/local/bin/zsh', () => buildWorkerStartupCommand('alpha', 2));
837
- assert.match(cmd, /'\/opt\/local\/bin\/zsh' -c/);
838
- assert.doesNotMatch(cmd, /'\/bin\/sh' -c/);
839
- assert.match(cmd, /source ~\/\.zshrc/);
840
- }
841
- finally {
842
- if (typeof prevShell === 'string')
843
- process.env.SHELL = prevShell;
844
- else
845
- delete process.env.SHELL;
846
- if (typeof prevBypass === 'string')
847
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
848
- else
849
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
850
- }
851
- });
852
- it('uses bash with ~/.bashrc and preserves launch args', () => {
853
- const prevShell = process.env.SHELL;
854
- process.env.SHELL = '/bin/bash';
855
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
856
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
857
- try {
858
- const cmd = buildWorkerStartupCommand('alpha', 1, ['--model', 'gpt-5']);
859
- assert.match(cmd, /source ~\/\.bashrc/);
860
- assert.match(cmd, /exec .*codex/);
861
- assert.match(cmd, /--model/);
862
- assert.match(cmd, /gpt-5/);
863
- }
864
- finally {
865
- if (typeof prevShell === 'string')
866
- process.env.SHELL = prevShell;
867
- else
868
- delete process.env.SHELL;
869
- if (typeof prevBypass === 'string')
870
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
871
- else
872
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
873
- }
874
- });
875
- it('injects canonical team state env vars when provided', () => {
876
- const prevShell = process.env.SHELL;
877
- process.env.SHELL = '/bin/bash';
878
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
879
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
880
- try {
881
- const cmd = buildWorkerStartupCommand('alpha', 1, [], '/tmp/worker-cwd', {
882
- RCS_TEAM_STATE_ROOT: '/tmp/leader/.rcs/state',
883
- RCS_TEAM_LEADER_CWD: '/tmp/leader',
884
- });
885
- assert.match(cmd, /RCS_TEAM_STATE_ROOT=\/tmp\/leader\/\.rcs\/state/);
886
- assert.match(cmd, /RCS_TEAM_LEADER_CWD=\/tmp\/leader/);
887
- }
888
- finally {
889
- if (typeof prevShell === 'string')
890
- process.env.SHELL = prevShell;
891
- else
892
- delete process.env.SHELL;
893
- if (typeof prevBypass === 'string')
894
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
895
- else
896
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
897
- }
898
- });
899
- it('inherits only allowlisted ambient proxy env vars for tmux startup commands', () => {
900
- const prevShell = process.env.SHELL;
901
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
902
- const prevHttpsProxy = process.env.HTTPS_PROXY;
903
- const prevHttpProxy = process.env.HTTP_PROXY;
904
- const prevNoProxy = process.env.NO_PROXY;
905
- const prevLowerHttpsProxy = process.env.https_proxy;
906
- const prevCustom = process.env.AWS_SECRET_ACCESS_KEY;
907
- process.env.SHELL = '/bin/bash';
908
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
909
- process.env.HTTPS_PROXY = 'https://upper-proxy.example:443';
910
- process.env.HTTP_PROXY = 'http://upper-proxy.example:80';
911
- process.env.NO_PROXY = 'localhost,127.0.0.1';
912
- process.env.https_proxy = 'https://lower-proxy.example:443';
913
- process.env.AWS_SECRET_ACCESS_KEY = 'should-not-inherit';
914
- try {
915
- const cmd = buildWorkerStartupCommand('alpha', 1, [], '/tmp/project');
916
- assert.match(cmd, /HTTPS_PROXY=https:\/\/upper-proxy\.example:443/);
917
- assert.match(cmd, /HTTP_PROXY=http:\/\/upper-proxy\.example:80/);
918
- assert.match(cmd, /NO_PROXY=localhost,127\.0\.0\.1/);
919
- assert.match(cmd, /https_proxy=https:\/\/lower-proxy\.example:443/);
920
- assert.doesNotMatch(cmd, /AWS_SECRET_ACCESS_KEY=should-not-inherit/);
921
- }
922
- finally {
923
- if (typeof prevShell === 'string')
924
- process.env.SHELL = prevShell;
925
- else
926
- delete process.env.SHELL;
927
- if (typeof prevBypass === 'string')
928
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
929
- else
930
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
931
- if (typeof prevHttpsProxy === 'string')
932
- process.env.HTTPS_PROXY = prevHttpsProxy;
933
- else
934
- delete process.env.HTTPS_PROXY;
935
- if (typeof prevHttpProxy === 'string')
936
- process.env.HTTP_PROXY = prevHttpProxy;
937
- else
938
- delete process.env.HTTP_PROXY;
939
- if (typeof prevNoProxy === 'string')
940
- process.env.NO_PROXY = prevNoProxy;
941
- else
942
- delete process.env.NO_PROXY;
943
- if (typeof prevLowerHttpsProxy === 'string')
944
- process.env.https_proxy = prevLowerHttpsProxy;
945
- else
946
- delete process.env.https_proxy;
947
- if (typeof prevCustom === 'string')
948
- process.env.AWS_SECRET_ACCESS_KEY = prevCustom;
949
- else
950
- delete process.env.AWS_SECRET_ACCESS_KEY;
951
- }
952
- });
953
- it('preserves explicit worker env precedence over inherited ambient proxy vars', () => {
954
- const prevShell = process.env.SHELL;
955
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
956
- const prevHttpsProxy = process.env.HTTPS_PROXY;
957
- process.env.SHELL = '/bin/bash';
958
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
959
- process.env.HTTPS_PROXY = 'https://ambient-proxy.example:443';
960
- try {
961
- const cmd = buildWorkerStartupCommand('alpha', 1, [], '/tmp/project', { HTTPS_PROXY: 'https://explicit-proxy.example:8443' });
962
- assert.match(cmd, /HTTPS_PROXY=https:\/\/explicit-proxy\.example:8443/);
963
- assert.doesNotMatch(cmd, /HTTPS_PROXY=https:\/\/ambient-proxy\.example:443/);
964
- }
965
- finally {
966
- if (typeof prevShell === 'string')
967
- process.env.SHELL = prevShell;
968
- else
969
- delete process.env.SHELL;
970
- if (typeof prevBypass === 'string')
971
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
972
- else
973
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
974
- if (typeof prevHttpsProxy === 'string')
975
- process.env.HTTPS_PROXY = prevHttpsProxy;
976
- else
977
- delete process.env.HTTPS_PROXY;
978
- }
979
- });
980
- it('resolves POSIX leader paths before building fish worker startup commands', async () => {
981
- const fakeBin = await mkdtemp(join(tmpdir(), 'rcs-worker-startup-posix-'));
982
- const prevPath = process.env.PATH;
983
- const prevShell = process.env.SHELL;
984
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
985
- process.env.PATH = fakeBin;
986
- process.env.SHELL = '/bin/fish';
987
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
988
- try {
989
- const nodePath = join(fakeBin, 'node');
990
- const codexPath = join(fakeBin, 'codex');
991
- await writeFile(nodePath, '#!/bin/sh\n');
992
- await writeFile(codexPath, '#!/bin/sh\n');
993
- await chmod(nodePath, 0o755);
994
- await chmod(codexPath, 0o755);
995
- const { buildWorkerStartupCommand: buildFreshWorkerStartupCommand } = await import(`../tmux-session.js?posix-path=${Date.now()}`);
996
- const cmd = buildFreshWorkerStartupCommand('alpha', 1, ['-c', 'model_reasoning_effort="low"'], process.cwd(), {}, 'codex');
997
- assert.match(cmd, new RegExp(escapeRegExp(`RCS_LEADER_NODE_PATH=${nodePath}`)));
998
- assert.match(cmd, new RegExp(escapeRegExp(`RCS_LEADER_CLI_PATH=${codexPath}`)));
999
- assert.match(cmd, new RegExp(escapeRegExp(`export PATH='\\''${fakeBin}'\\'':$PATH; exec '\\''${codexPath}'\\''`)));
1000
- assert.doesNotMatch(cmd, /export PATH='\\''node'\\'':\$PATH/);
1001
- assert.doesNotMatch(cmd, / exec codex(?:\s|')/);
1002
- }
1003
- finally {
1004
- if (typeof prevPath === 'string')
1005
- process.env.PATH = prevPath;
1006
- else
1007
- delete process.env.PATH;
1008
- if (typeof prevShell === 'string')
1009
- process.env.SHELL = prevShell;
1010
- else
1011
- delete process.env.SHELL;
1012
- if (typeof prevBypass === 'string')
1013
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1014
- else
1015
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1016
- await rm(fakeBin, { recursive: true, force: true });
1017
- }
1018
- });
1019
- it('inherits bypass flag from process argv once', () => {
1020
- const prevArgv = process.argv;
1021
- const prevShell = process.env.SHELL;
1022
- process.env.SHELL = '/bin/bash';
1023
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1024
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1025
- process.argv = [...prevArgv, '--dangerously-bypass-approvals-and-sandbox'];
1026
- try {
1027
- const cmd = buildWorkerStartupCommand('alpha', 1, ['--dangerously-bypass-approvals-and-sandbox']);
1028
- const matches = cmd.match(/--dangerously-bypass-approvals-and-sandbox/g) || [];
1029
- assert.equal(matches.length, 1);
1030
- }
1031
- finally {
1032
- process.argv = prevArgv;
1033
- if (typeof prevShell === 'string')
1034
- process.env.SHELL = prevShell;
1035
- else
1036
- delete process.env.SHELL;
1037
- if (typeof prevBypass === 'string')
1038
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1039
- else
1040
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1041
- }
1042
- });
1043
- it('maps --madmax to bypass flag in worker command', () => {
1044
- const prevArgv = process.argv;
1045
- const prevShell = process.env.SHELL;
1046
- process.env.SHELL = '/bin/bash';
1047
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1048
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1049
- process.argv = [...prevArgv, '--madmax'];
1050
- try {
1051
- const cmd = buildWorkerStartupCommand('alpha', 1);
1052
- const matches = cmd.match(/--dangerously-bypass-approvals-and-sandbox/g) || [];
1053
- assert.equal(matches.length, 1);
1054
- }
1055
- finally {
1056
- process.argv = prevArgv;
1057
- if (typeof prevShell === 'string')
1058
- process.env.SHELL = prevShell;
1059
- else
1060
- delete process.env.SHELL;
1061
- if (typeof prevBypass === 'string')
1062
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1063
- else
1064
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1065
- }
1066
- });
1067
- it('preserves reasoning override args in worker command', () => {
1068
- const prevShell = process.env.SHELL;
1069
- process.env.SHELL = '/bin/bash';
1070
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1071
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1072
- try {
1073
- const cmd = buildWorkerStartupCommand('alpha', 1, ['-c', 'model_reasoning_effort="xhigh"']);
1074
- assert.match(cmd, /exec .*codex/);
1075
- assert.match(cmd, /'-c'/);
1076
- assert.match(cmd, /'model_reasoning_effort=\"xhigh\"'/);
1077
- }
1078
- finally {
1079
- if (typeof prevShell === 'string')
1080
- process.env.SHELL = prevShell;
1081
- else
1082
- delete process.env.SHELL;
1083
- if (typeof prevBypass === 'string')
1084
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1085
- else
1086
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1087
- }
1088
- });
1089
- it('forces codex bypass under explicit launch-arg profiles', () => {
1090
- const prevShell = process.env.SHELL;
1091
- process.env.SHELL = '/bin/bash';
1092
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1093
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1094
- try {
1095
- const profiles = [
1096
- ['--model', 'gpt-5', '-c', 'model_reasoning_effort="high"'],
1097
- ['--model', 'gpt-5.3-codex-spark', '-c', 'model_reasoning_effort="low"'],
1098
- ];
1099
- for (const launchArgs of profiles) {
1100
- const cmd = buildWorkerStartupCommand('alpha', 1, launchArgs, process.cwd(), {}, 'codex');
1101
- assert.match(cmd, /exec .*codex/);
1102
- assert.equal((cmd.match(/--dangerously-bypass-approvals-and-sandbox/g) || []).length, 1);
1103
- assert.match(cmd, /--model/);
1104
- assert.match(cmd, new RegExp(launchArgs[1].replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
1105
- assert.match(cmd, new RegExp(launchArgs[3].replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
1106
- }
1107
- }
1108
- finally {
1109
- if (typeof prevShell === 'string')
1110
- process.env.SHELL = prevShell;
1111
- else
1112
- delete process.env.SHELL;
1113
- if (typeof prevBypass === 'string')
1114
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1115
- else
1116
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1117
- }
1118
- });
1119
- it('supports worker-specific reasoning overrides for codex and strips them for claude workers', () => {
1120
- const prevShell = process.env.SHELL;
1121
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1122
- process.env.SHELL = '/bin/bash';
1123
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1124
- try {
1125
- const codexCmd = buildWorkerStartupCommand('alpha', 1, ['-c', 'model_reasoning_effort="low"'], process.cwd(), {}, 'codex');
1126
- const claudeCmd = buildWorkerStartupCommand('alpha', 2, ['-c', 'model_reasoning_effort="high"'], process.cwd(), {}, 'claude');
1127
- assert.match(codexCmd, /exec .*codex/);
1128
- assert.match(codexCmd, /'model_reasoning_effort="low"'/);
1129
- assert.match(claudeCmd, /exec .*claude/);
1130
- assert.equal((claudeCmd.match(/--dangerously-skip-permissions/g) || []).length, 1);
1131
- assert.doesNotMatch(claudeCmd, /model_reasoning_effort/);
1132
- }
1133
- finally {
1134
- if (typeof prevShell === 'string')
1135
- process.env.SHELL = prevShell;
1136
- else
1137
- delete process.env.SHELL;
1138
- if (typeof prevBypass === 'string')
1139
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1140
- else
1141
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1142
- }
1143
- });
1144
- it('injects model_instructions_file override by default', () => {
1145
- const prevShell = process.env.SHELL;
1146
- process.env.SHELL = '/bin/bash';
1147
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1148
- const prevInstr = process.env.RCS_MODEL_INSTRUCTIONS_FILE;
1149
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT; // default enabled
1150
- delete process.env.RCS_MODEL_INSTRUCTIONS_FILE;
1151
- try {
1152
- const cmd = buildWorkerStartupCommand('alpha', 1, [], '/tmp/project');
1153
- assert.match(cmd, /'-c'/);
1154
- assert.match(cmd, /model_instructions_file=/);
1155
- assert.match(cmd, /AGENTS\.md/);
1156
- }
1157
- finally {
1158
- if (typeof prevShell === 'string')
1159
- process.env.SHELL = prevShell;
1160
- else
1161
- delete process.env.SHELL;
1162
- if (typeof prevBypass === 'string')
1163
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1164
- else
1165
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1166
- if (typeof prevInstr === 'string')
1167
- process.env.RCS_MODEL_INSTRUCTIONS_FILE = prevInstr;
1168
- else
1169
- delete process.env.RCS_MODEL_INSTRUCTIONS_FILE;
1170
- }
1171
- });
1172
- it('uses per-worker RCS_MODEL_INSTRUCTIONS_FILE from extraEnv when building process launch spec', () => {
1173
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1174
- const prevInstr = process.env.RCS_MODEL_INSTRUCTIONS_FILE;
1175
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1176
- delete process.env.RCS_MODEL_INSTRUCTIONS_FILE;
1177
- try {
1178
- const spec = buildWorkerProcessLaunchSpec('alpha', 1, ['-c', 'model_reasoning_effort="low"'], '/tmp/project', { RCS_MODEL_INSTRUCTIONS_FILE: '/tmp/project/.rcs/state/team/alpha/workers/worker-1/AGENTS.md' }, 'codex');
1179
- const joined = spec.args.join(' ');
1180
- assert.match(joined, /model_reasoning_effort="low"/);
1181
- assert.match(joined, /model_instructions_file="\/tmp\/project\/.rcs\/state\/team\/alpha\/workers\/worker-1\/AGENTS\.md"/);
1182
- }
1183
- finally {
1184
- if (typeof prevBypass === 'string')
1185
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1186
- else
1187
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1188
- if (typeof prevInstr === 'string')
1189
- process.env.RCS_MODEL_INSTRUCTIONS_FILE = prevInstr;
1190
- else
1191
- delete process.env.RCS_MODEL_INSTRUCTIONS_FILE;
1192
- }
1193
- });
1194
- it('does not inject model_instructions_file override when disabled', () => {
1195
- const prevShell = process.env.SHELL;
1196
- process.env.SHELL = '/bin/bash';
1197
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1198
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1199
- try {
1200
- const cmd = buildWorkerStartupCommand('alpha', 1, [], '/tmp/project');
1201
- assert.doesNotMatch(cmd, /model_instructions_file=/);
1202
- }
1203
- finally {
1204
- if (typeof prevShell === 'string')
1205
- process.env.SHELL = prevShell;
1206
- else
1207
- delete process.env.SHELL;
1208
- if (typeof prevBypass === 'string')
1209
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1210
- else
1211
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1212
- }
1213
- });
1214
- it('does not inject model_instructions_file when already provided in launch args', () => {
1215
- const prevShell = process.env.SHELL;
1216
- process.env.SHELL = '/bin/bash';
1217
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1218
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT; // default enabled
1219
- try {
1220
- const cmd = buildWorkerStartupCommand('alpha', 1, ['-c', 'model_instructions_file="/tmp/custom.md"'], '/tmp/project');
1221
- const matches = cmd.match(/model_instructions_file=/g) || [];
1222
- assert.equal(matches.length, 1);
1223
- assert.match(cmd, /custom\.md/);
1224
- }
1225
- finally {
1226
- if (typeof prevShell === 'string')
1227
- process.env.SHELL = prevShell;
1228
- else
1229
- delete process.env.SHELL;
1230
- if (typeof prevBypass === 'string')
1231
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1232
- else
1233
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1234
- }
1235
- });
1236
- it('translates model_instructions_file path for MSYS2/Git Bash environments', () => {
1237
- const prevShell = process.env.SHELL;
1238
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1239
- const prevInstructions = process.env.RCS_MODEL_INSTRUCTIONS_FILE;
1240
- const prevMsystem = process.env.MSYSTEM;
1241
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
1242
- process.env.SHELL = '/bin/bash';
1243
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT; // default enabled
1244
- process.env.RCS_MODEL_INSTRUCTIONS_FILE = 'C:\\repo\\AGENTS.md';
1245
- process.env.MSYSTEM = 'MINGW64';
1246
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
1247
- try {
1248
- const cmd = buildWorkerStartupCommand('alpha', 1, [], 'C:\\repo');
1249
- assert.match(cmd, /model_instructions_file=\"\/c\/repo\/AGENTS\.md\"/);
1250
- }
1251
- finally {
1252
- if (origPlatform)
1253
- Object.defineProperty(process, 'platform', origPlatform);
1254
- if (typeof prevShell === 'string')
1255
- process.env.SHELL = prevShell;
1256
- else
1257
- delete process.env.SHELL;
1258
- if (typeof prevBypass === 'string')
1259
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1260
- else
1261
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1262
- if (typeof prevInstructions === 'string')
1263
- process.env.RCS_MODEL_INSTRUCTIONS_FILE = prevInstructions;
1264
- else
1265
- delete process.env.RCS_MODEL_INSTRUCTIONS_FILE;
1266
- if (typeof prevMsystem === 'string')
1267
- process.env.MSYSTEM = prevMsystem;
1268
- else
1269
- delete process.env.MSYSTEM;
1270
- }
1271
- });
1272
- it('ignores unsupported SHELL values and resolves a supported worker shell', () => {
1273
- const prevShell = process.env.SHELL;
1274
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1275
- process.env.SHELL = '/usr/bin/fish';
1276
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1277
- try {
1278
- const cmd = buildWorkerStartupCommand('alpha', 1, [], process.cwd());
1279
- assert.doesNotMatch(cmd, /fish/, 'worker shell must not inherit unsupported fish SHELL');
1280
- assert.match(cmd, /\/(?:bin|usr\/bin|usr\/local\/bin|opt\/homebrew\/bin)\/(?:zsh|bash)\b|\/bin\/sh\b/);
1281
- }
1282
- finally {
1283
- if (typeof prevShell === 'string')
1284
- process.env.SHELL = prevShell;
1285
- else
1286
- delete process.env.SHELL;
1287
- if (typeof prevBypass === 'string')
1288
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1289
- else
1290
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1291
- }
1292
- });
1293
- it('never emits fish-style PATH manipulation for unsupported SHELL values', () => {
1294
- const prevShell = process.env.SHELL;
1295
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1296
- process.env.SHELL = '/usr/bin/fish';
1297
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1298
- try {
1299
- const cmd = buildWorkerStartupCommand('alpha', 1, [], process.cwd());
1300
- assert.doesNotMatch(cmd, /set -x PATH/, 'must not emit fish PATH syntax');
1301
- }
1302
- finally {
1303
- if (typeof prevShell === 'string')
1304
- process.env.SHELL = prevShell;
1305
- else
1306
- delete process.env.SHELL;
1307
- if (typeof prevBypass === 'string')
1308
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1309
- else
1310
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1311
- }
1312
- });
1313
- it('uses /bin/sh on MSYS2/Windows regardless of zsh availability', () => {
1314
- const prevShell = process.env.SHELL;
1315
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1316
- const prevMsystem = process.env.MSYSTEM;
1317
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
1318
- process.env.SHELL = '/bin/zsh';
1319
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1320
- process.env.MSYSTEM = 'MINGW64';
1321
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
1322
- try {
1323
- const cmd = buildWorkerStartupCommand('alpha', 1, [], 'C:\\repo');
1324
- assert.match(cmd, /\/bin\/sh/, 'must use /bin/sh on MSYS2/Windows');
1325
- assert.doesNotMatch(cmd, /\/zsh/, 'must not attempt zsh on Windows');
1326
- assert.doesNotMatch(cmd, /\.zshrc/, 'must not source zshrc on Windows');
1327
- }
1328
- finally {
1329
- if (origPlatform)
1330
- Object.defineProperty(process, 'platform', origPlatform);
1331
- if (typeof prevShell === 'string')
1332
- process.env.SHELL = prevShell;
1333
- else
1334
- delete process.env.SHELL;
1335
- if (typeof prevBypass === 'string')
1336
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1337
- else
1338
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1339
- if (typeof prevMsystem === 'string')
1340
- process.env.MSYSTEM = prevMsystem;
1341
- else
1342
- delete process.env.MSYSTEM;
1343
- }
1344
- });
1345
- it('uses a native PowerShell startup command on native Windows instead of /bin/sh -lc', async () => {
1346
- const fakeBin = await mkdtemp(join(tmpdir(), 'rcs-worker-startup-win32-'));
1347
- const prevPath = process.env.PATH;
1348
- const prevPathext = process.env.PATHEXT;
1349
- const prevShell = process.env.SHELL;
1350
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1351
- const prevLeaderNodePath = process.env.RCS_LEADER_NODE_PATH;
1352
- const prevMsystem = process.env.MSYSTEM;
1353
- const prevOstype = process.env.OSTYPE;
1354
- const prevWsl = process.env.WSL_DISTRO_NAME;
1355
- const prevWslInterop = process.env.WSL_INTEROP;
1356
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
1357
- process.env.PATH = fakeBin;
1358
- process.env.PATHEXT = '.PS1';
1359
- process.env.SHELL = '/bin/zsh';
1360
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1361
- process.env.RCS_LEADER_NODE_PATH = 'C:\\Program Files\\nodejs\\node.exe';
1362
- delete process.env.MSYSTEM;
1363
- delete process.env.OSTYPE;
1364
- delete process.env.WSL_DISTRO_NAME;
1365
- delete process.env.WSL_INTEROP;
1366
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
1367
- try {
1368
- const codexPs1Path = join(fakeBin, 'codex.ps1');
1369
- await writeFile(codexPs1Path, '');
1370
- const cmd = buildWorkerStartupCommand('alpha', 1, ['--model', 'gpt-5'], 'C:\\repo');
1371
- assert.doesNotMatch(cmd, /\/bin\/sh -lc/, 'native Windows workers must not launch through POSIX sh');
1372
- assert.match(cmd, /^powershell\.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -EncodedCommand /);
1373
- const encoded = cmd.replace(/^powershell\.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -EncodedCommand /, '');
1374
- const decoded = Buffer.from(encoded, 'base64').toString('utf16le');
1375
- assert.match(decoded, /\$env:PATH = 'C:\\Program Files\\nodejs;' \+ \$env:PATH/);
1376
- assert.match(decoded, /\$env:RCS_TEAM_WORKER = 'alpha\/worker-1'/);
1377
- assert.match(decoded, new RegExp(escapeRegExp(`'-File' '${codexPs1Path}'`)));
1378
- assert.match(decoded, /'--model' 'gpt-5'/);
1379
- assert.match(decoded, /'--dangerously-bypass-approvals-and-sandbox'/);
1380
- }
1381
- finally {
1382
- if (origPlatform)
1383
- Object.defineProperty(process, 'platform', origPlatform);
1384
- if (typeof prevPath === 'string')
1385
- process.env.PATH = prevPath;
1386
- else
1387
- delete process.env.PATH;
1388
- if (typeof prevPathext === 'string')
1389
- process.env.PATHEXT = prevPathext;
1390
- else
1391
- delete process.env.PATHEXT;
1392
- if (typeof prevShell === 'string')
1393
- process.env.SHELL = prevShell;
1394
- else
1395
- delete process.env.SHELL;
1396
- if (typeof prevBypass === 'string')
1397
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1398
- else
1399
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1400
- if (typeof prevLeaderNodePath === 'string')
1401
- process.env.RCS_LEADER_NODE_PATH = prevLeaderNodePath;
1402
- else
1403
- delete process.env.RCS_LEADER_NODE_PATH;
1404
- if (typeof prevMsystem === 'string')
1405
- process.env.MSYSTEM = prevMsystem;
1406
- else
1407
- delete process.env.MSYSTEM;
1408
- if (typeof prevOstype === 'string')
1409
- process.env.OSTYPE = prevOstype;
1410
- else
1411
- delete process.env.OSTYPE;
1412
- if (typeof prevWsl === 'string')
1413
- process.env.WSL_DISTRO_NAME = prevWsl;
1414
- else
1415
- delete process.env.WSL_DISTRO_NAME;
1416
- if (typeof prevWslInterop === 'string')
1417
- process.env.WSL_INTEROP = prevWslInterop;
1418
- else
1419
- delete process.env.WSL_INTEROP;
1420
- await rm(fakeBin, { recursive: true, force: true });
1421
- }
1422
- });
1423
- it('uses the resolved PowerShell executable path in native Windows startup commands', async () => {
1424
- const fakeBin = await mkdtemp(join(tmpdir(), 'rcs-worker-startup-win32-powershell-'));
1425
- const prevPath = process.env.PATH;
1426
- const prevPathext = process.env.PATHEXT;
1427
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1428
- const prevLeaderNodePath = process.env.RCS_LEADER_NODE_PATH;
1429
- const prevMsystem = process.env.MSYSTEM;
1430
- const prevOstype = process.env.OSTYPE;
1431
- const prevWsl = process.env.WSL_DISTRO_NAME;
1432
- const prevWslInterop = process.env.WSL_INTEROP;
1433
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
1434
- process.env.PATH = fakeBin;
1435
- process.env.PATHEXT = '.EXE;.PS1';
1436
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1437
- process.env.RCS_LEADER_NODE_PATH = 'C:\\Program Files\\nodejs\\node.exe';
1438
- delete process.env.MSYSTEM;
1439
- delete process.env.OSTYPE;
1440
- delete process.env.WSL_DISTRO_NAME;
1441
- delete process.env.WSL_INTEROP;
1442
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
1443
- try {
1444
- const codexPs1Path = join(fakeBin, 'codex.ps1');
1445
- const powershellExePath = join(fakeBin, 'powershell.exe');
1446
- await writeFile(codexPs1Path, '');
1447
- await writeFile(powershellExePath, '');
1448
- const cmd = buildWorkerStartupCommand('alpha', 1, ['--model', 'gpt-5'], 'C:\\repo');
1449
- const prefix = `${powershellExePath} -NoLogo -NoProfile -ExecutionPolicy Bypass -EncodedCommand `;
1450
- assert.ok(cmd.startsWith(prefix), cmd);
1451
- }
1452
- finally {
1453
- if (origPlatform)
1454
- Object.defineProperty(process, 'platform', origPlatform);
1455
- if (typeof prevPath === 'string')
1456
- process.env.PATH = prevPath;
1457
- else
1458
- delete process.env.PATH;
1459
- if (typeof prevPathext === 'string')
1460
- process.env.PATHEXT = prevPathext;
1461
- else
1462
- delete process.env.PATHEXT;
1463
- if (typeof prevBypass === 'string')
1464
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1465
- else
1466
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1467
- if (typeof prevLeaderNodePath === 'string')
1468
- process.env.RCS_LEADER_NODE_PATH = prevLeaderNodePath;
1469
- else
1470
- delete process.env.RCS_LEADER_NODE_PATH;
1471
- if (typeof prevMsystem === 'string')
1472
- process.env.MSYSTEM = prevMsystem;
1473
- else
1474
- delete process.env.MSYSTEM;
1475
- if (typeof prevOstype === 'string')
1476
- process.env.OSTYPE = prevOstype;
1477
- else
1478
- delete process.env.OSTYPE;
1479
- if (typeof prevWsl === 'string')
1480
- process.env.WSL_DISTRO_NAME = prevWsl;
1481
- else
1482
- delete process.env.WSL_DISTRO_NAME;
1483
- if (typeof prevWslInterop === 'string')
1484
- process.env.WSL_INTEROP = prevWslInterop;
1485
- else
1486
- delete process.env.WSL_INTEROP;
1487
- await rm(fakeBin, { recursive: true, force: true });
1488
- }
1489
- });
1490
- it('prefers a no-space native Windows PowerShell path when one is available', async () => {
1491
- const fakeBin = await mkdtemp(join(tmpdir(), 'rcs-worker-startup-win32-nospace-powershell-'));
1492
- const prevPath = process.env.PATH;
1493
- const prevPathext = process.env.PATHEXT;
1494
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1495
- const prevLeaderNodePath = process.env.RCS_LEADER_NODE_PATH;
1496
- const prevSystemRoot = process.env.SystemRoot;
1497
- const prevSYSTEMROOT = process.env.SYSTEMROOT;
1498
- const prevWindir = process.env.windir;
1499
- const prevWINDIR = process.env.WINDIR;
1500
- const prevMsystem = process.env.MSYSTEM;
1501
- const prevOstype = process.env.OSTYPE;
1502
- const prevWsl = process.env.WSL_DISTRO_NAME;
1503
- const prevWslInterop = process.env.WSL_INTEROP;
1504
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
1505
- process.env.PATH = fakeBin;
1506
- process.env.PATHEXT = '.EXE;.PS1';
1507
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1508
- process.env.RCS_LEADER_NODE_PATH = 'C:\\Program Files\\nodejs\\node.exe';
1509
- process.env.SystemRoot = 'C:\\Windows';
1510
- delete process.env.SYSTEMROOT;
1511
- delete process.env.windir;
1512
- delete process.env.WINDIR;
1513
- delete process.env.MSYSTEM;
1514
- delete process.env.OSTYPE;
1515
- delete process.env.WSL_DISTRO_NAME;
1516
- delete process.env.WSL_INTEROP;
1517
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
1518
- try {
1519
- const codexPs1Path = join(fakeBin, 'codex.ps1');
1520
- const pathPowerShellExe = join(fakeBin, 'powershell.exe');
1521
- const windowsPowerShellExe = 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe';
1522
- await writeFile(codexPs1Path, '');
1523
- await writeFile(pathPowerShellExe, '');
1524
- const cmd = withMockedExistsSync((candidate) => candidate === windowsPowerShellExe
1525
- || candidate === pathPowerShellExe
1526
- || candidate === codexPs1Path, () => buildWorkerStartupCommand('alpha', 1, ['--model', 'gpt-5'], 'C:\\repo'));
1527
- const prefix = `${windowsPowerShellExe} -NoLogo -NoProfile -ExecutionPolicy Bypass -EncodedCommand `;
1528
- assert.ok(cmd.startsWith(prefix), cmd);
1529
- assert.ok(!cmd.startsWith(`${pathPowerShellExe} `), cmd);
1530
- }
1531
- finally {
1532
- if (origPlatform)
1533
- Object.defineProperty(process, 'platform', origPlatform);
1534
- if (typeof prevPath === 'string')
1535
- process.env.PATH = prevPath;
1536
- else
1537
- delete process.env.PATH;
1538
- if (typeof prevPathext === 'string')
1539
- process.env.PATHEXT = prevPathext;
1540
- else
1541
- delete process.env.PATHEXT;
1542
- if (typeof prevBypass === 'string')
1543
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1544
- else
1545
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1546
- if (typeof prevLeaderNodePath === 'string')
1547
- process.env.RCS_LEADER_NODE_PATH = prevLeaderNodePath;
1548
- else
1549
- delete process.env.RCS_LEADER_NODE_PATH;
1550
- if (typeof prevSystemRoot === 'string')
1551
- process.env.SystemRoot = prevSystemRoot;
1552
- else
1553
- delete process.env.SystemRoot;
1554
- if (typeof prevSYSTEMROOT === 'string')
1555
- process.env.SYSTEMROOT = prevSYSTEMROOT;
1556
- else
1557
- delete process.env.SYSTEMROOT;
1558
- if (typeof prevWindir === 'string')
1559
- process.env.windir = prevWindir;
1560
- else
1561
- delete process.env.windir;
1562
- if (typeof prevWINDIR === 'string')
1563
- process.env.WINDIR = prevWINDIR;
1564
- else
1565
- delete process.env.WINDIR;
1566
- if (typeof prevMsystem === 'string')
1567
- process.env.MSYSTEM = prevMsystem;
1568
- else
1569
- delete process.env.MSYSTEM;
1570
- if (typeof prevOstype === 'string')
1571
- process.env.OSTYPE = prevOstype;
1572
- else
1573
- delete process.env.OSTYPE;
1574
- if (typeof prevWsl === 'string')
1575
- process.env.WSL_DISTRO_NAME = prevWsl;
1576
- else
1577
- delete process.env.WSL_DISTRO_NAME;
1578
- if (typeof prevWslInterop === 'string')
1579
- process.env.WSL_INTEROP = prevWslInterop;
1580
- else
1581
- delete process.env.WSL_INTEROP;
1582
- await rm(fakeBin, { recursive: true, force: true });
1583
- }
1584
- });
1585
- it('uses the resolved node-hosted Codex launcher in native Windows startup commands', async () => {
1586
- const fakeRoot = await mkdtemp(join(tmpdir(), 'rcs-worker-startup-win32-node-hosted-'));
1587
- const fakeBin = join(fakeRoot, 'node_modules', '.bin');
1588
- const prevPath = process.env.PATH;
1589
- const prevPathext = process.env.PATHEXT;
1590
- const prevShell = process.env.SHELL;
1591
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1592
- const prevLeaderNodePath = process.env.RCS_LEADER_NODE_PATH;
1593
- const prevMsystem = process.env.MSYSTEM;
1594
- const prevOstype = process.env.OSTYPE;
1595
- const prevWsl = process.env.WSL_DISTRO_NAME;
1596
- const prevWslInterop = process.env.WSL_INTEROP;
1597
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
1598
- process.env.PATH = fakeBin;
1599
- process.env.PATHEXT = '.CMD;.PS1';
1600
- process.env.SHELL = '/bin/zsh';
1601
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1602
- process.env.RCS_LEADER_NODE_PATH = 'C:\\Program Files\\nodejs\\node.exe';
1603
- delete process.env.MSYSTEM;
1604
- delete process.env.OSTYPE;
1605
- delete process.env.WSL_DISTRO_NAME;
1606
- delete process.env.WSL_INTEROP;
1607
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
1608
- try {
1609
- const codexCmdPath = join(fakeBin, 'codex.cmd');
1610
- const codexJsPath = join(fakeRoot, 'node_modules', '@openai', 'codex', 'bin', 'codex.js');
1611
- await mkdir(fakeBin, { recursive: true });
1612
- await mkdir(join(fakeRoot, 'node_modules', '@openai', 'codex', 'bin'), { recursive: true });
1613
- await writeFile(codexCmdPath, '@echo off\r\n');
1614
- await writeFile(codexJsPath, '');
1615
- const cmd = buildWorkerStartupCommand('alpha', 1, ['--model', 'gpt-5'], 'C:\\repo');
1616
- const prefix = 'powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -EncodedCommand ';
1617
- assert.ok(cmd.startsWith(prefix));
1618
- const decoded = Buffer.from(cmd.slice(prefix.length), 'base64').toString('utf16le');
1619
- assert.match(decoded, new RegExp(escapeRegExp(`$env:RCS_LEADER_CLI_PATH = '${codexJsPath}'`)));
1620
- assert.match(decoded, new RegExp(escapeRegExp(`& '${process.execPath}' '${codexJsPath}' '--model' 'gpt-5' '--dangerously-bypass-approvals-and-sandbox'`)));
1621
- assert.doesNotMatch(decoded, new RegExp(escapeRegExp(codexCmdPath)));
1622
- }
1623
- finally {
1624
- if (origPlatform)
1625
- Object.defineProperty(process, 'platform', origPlatform);
1626
- if (typeof prevPath === 'string')
1627
- process.env.PATH = prevPath;
1628
- else
1629
- delete process.env.PATH;
1630
- if (typeof prevPathext === 'string')
1631
- process.env.PATHEXT = prevPathext;
1632
- else
1633
- delete process.env.PATHEXT;
1634
- if (typeof prevShell === 'string')
1635
- process.env.SHELL = prevShell;
1636
- else
1637
- delete process.env.SHELL;
1638
- if (typeof prevBypass === 'string')
1639
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1640
- else
1641
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1642
- if (typeof prevLeaderNodePath === 'string')
1643
- process.env.RCS_LEADER_NODE_PATH = prevLeaderNodePath;
1644
- else
1645
- delete process.env.RCS_LEADER_NODE_PATH;
1646
- if (typeof prevMsystem === 'string')
1647
- process.env.MSYSTEM = prevMsystem;
1648
- else
1649
- delete process.env.MSYSTEM;
1650
- if (typeof prevOstype === 'string')
1651
- process.env.OSTYPE = prevOstype;
1652
- else
1653
- delete process.env.OSTYPE;
1654
- if (typeof prevWsl === 'string')
1655
- process.env.WSL_DISTRO_NAME = prevWsl;
1656
- else
1657
- delete process.env.WSL_DISTRO_NAME;
1658
- if (typeof prevWslInterop === 'string')
1659
- process.env.WSL_INTEROP = prevWslInterop;
1660
- else
1661
- delete process.env.WSL_INTEROP;
1662
- await rm(fakeRoot, { recursive: true, force: true });
1663
- }
1664
- });
1665
- it('falls back to bash when SHELL is unsupported and zsh candidates are unavailable', () => {
1666
- const prevShell = process.env.SHELL;
1667
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1668
- process.env.SHELL = '/opt/custom/fish';
1669
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1670
- try {
1671
- const cmd = withMockedExistsSync((candidate) => candidate === '/opt/custom/fish' || candidate === '/bin/bash', () => buildWorkerStartupCommand('alpha', 1, [], process.cwd()));
1672
- assert.match(cmd, /\/bin\/bash\b/, 'must fall back to bash when zsh is unavailable');
1673
- assert.match(cmd, /\.bashrc/, 'must source bash rc file for bash fallback');
1674
- assert.doesNotMatch(cmd, /fish/, 'must not launch unsupported fish shell');
1675
- }
1676
- finally {
1677
- if (typeof prevShell === 'string')
1678
- process.env.SHELL = prevShell;
1679
- else
1680
- delete process.env.SHELL;
1681
- if (typeof prevBypass === 'string')
1682
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1683
- else
1684
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1685
- }
1686
- });
1687
- it('falls back to /bin/sh when no supported shell candidates exist', () => {
1688
- const prevShell = process.env.SHELL;
1689
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1690
- process.env.SHELL = '/opt/custom/fish';
1691
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1692
- try {
1693
- const cmd = withMockedExistsSync((candidate) => candidate === '/opt/custom/fish', () => buildWorkerStartupCommand('alpha', 1, [], process.cwd()));
1694
- assert.match(cmd, /'\/bin\/sh' -c\b/, 'must launch workers through /bin/sh when no supported shells exist');
1695
- assert.doesNotMatch(cmd, /'\/bin\/sh' -lc\b/);
1696
- assert.doesNotMatch(cmd, /\.zshrc|\.bashrc/, 'must not source zsh/bash rc files for /bin/sh fallback');
1697
- }
1698
- finally {
1699
- if (typeof prevShell === 'string')
1700
- process.env.SHELL = prevShell;
1701
- else
1702
- delete process.env.SHELL;
1703
- if (typeof prevBypass === 'string')
1704
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1705
- else
1706
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1707
- }
1708
- });
1709
- });
1710
- describe('team worker CLI helpers', () => {
1711
- it('resolveTeamWorkerCli auto-detects claude models', () => {
1712
- assert.equal(resolveTeamWorkerCli(['--model', 'claude-3-7-sonnet'], {}), 'claude');
1713
- assert.equal(resolveTeamWorkerCli(['--model=claude-sonnet-4-6'], {}), 'claude');
1714
- assert.equal(resolveTeamWorkerCli(['--model', 'gemini-2.0-pro'], {}), 'gemini');
1715
- assert.equal(resolveTeamWorkerCli(['--model', 'gpt-5'], {}), 'codex');
1716
- assert.equal(resolveTeamWorkerCli([], {}), 'codex');
1717
- });
1718
- it('resolveTeamWorkerCli accepts explicit gemini override', () => {
1719
- assert.equal(resolveTeamWorkerCli([], { RCS_TEAM_WORKER_CLI: 'gemini' }), 'gemini');
1720
- });
1721
- it('resolveTeamWorkerCliPlan accepts gemini in CLI map', () => {
1722
- const plan = resolveTeamWorkerCliPlan(3, [], { RCS_TEAM_WORKER_CLI_MAP: 'codex,gemini,claude' });
1723
- assert.deepEqual(plan, ['codex', 'gemini', 'claude']);
1724
- });
1725
- it('translateWorkerLaunchArgsForCli preserves args for codex', () => {
1726
- const args = ['--model', 'gpt-5', '-c', 'model_reasoning_effort="xhigh"'];
1727
- assert.deepEqual(translateWorkerLaunchArgsForCli('codex', args), args);
1728
- });
1729
- it('translateWorkerLaunchArgsForCli returns only skip-permissions for claude', () => {
1730
- assert.deepEqual(translateWorkerLaunchArgsForCli('claude', ['-c', 'model_reasoning_effort="xhigh"', '--model', 'claude-3-7-sonnet']), ['--dangerously-skip-permissions']);
1731
- });
1732
- it('translateWorkerLaunchArgsForCli keeps read-only claude roles out of skip-permissions mode', () => {
1733
- assert.deepEqual(translateWorkerLaunchArgsForCli('claude', ['--model', 'claude-3-7-sonnet'], undefined, 'architect'), []);
1734
- });
1735
- it('translateWorkerLaunchArgsForCli emits gemini approval-mode by default and adds -i when initial prompt is provided', () => {
1736
- assert.deepEqual(translateWorkerLaunchArgsForCli('gemini', ['--model', 'gemini-2.0-pro', '--json']), ['--approval-mode', 'yolo', '--model', 'gemini-2.0-pro']);
1737
- assert.deepEqual(translateWorkerLaunchArgsForCli('gemini', ['--model', 'gemini-2.0-pro', '--json'], 'Read worker inbox'), ['--approval-mode', 'yolo', '-i', 'Read worker inbox', '--model', 'gemini-2.0-pro']);
1738
- assert.deepEqual(translateWorkerLaunchArgsForCli('gemini', ['--json']), ['--approval-mode', 'yolo']);
1739
- assert.deepEqual(translateWorkerLaunchArgsForCli('gemini', ['--json'], 'Read worker inbox'), ['--approval-mode', 'yolo', '-i', 'Read worker inbox']);
1740
- });
1741
- it('translateWorkerLaunchArgsForCli omits non-gemini default models for gemini workers', () => {
1742
- assert.deepEqual(translateWorkerLaunchArgsForCli('gemini', ['--model', 'gpt-5.3-codex-spark'], 'Read worker inbox'), ['--approval-mode', 'yolo', '-i', 'Read worker inbox']);
1743
- });
1744
- it('translateWorkerLaunchArgsForCli keeps planning/read-only gemini roles out of yolo mode', () => {
1745
- assert.deepEqual(translateWorkerLaunchArgsForCli('gemini', ['--model', 'gemini-2.0-pro'], 'Read worker inbox', 'planner'), ['-i', 'Read worker inbox', '--model', 'gemini-2.0-pro']);
1746
- });
1747
- it('assertTeamWorkerCliBinaryAvailable throws clear error when binary missing', () => {
1748
- assert.throws(() => assertTeamWorkerCliBinaryAvailable('claude', () => false), /not available on PATH/i);
1749
- });
1750
- it('resolveTeamWorkerCliPlan supports mixed per-worker CLI map', () => {
1751
- const plan = resolveTeamWorkerCliPlan(4, [], { RCS_TEAM_WORKER_CLI_MAP: 'codex,codex,gemini,claude' });
1752
- assert.deepEqual(plan, ['codex', 'codex', 'gemini', 'claude']);
1753
- });
1754
- it('resolveTeamWorkerCliPlan accepts single-value map and expands to all workers', () => {
1755
- const plan = resolveTeamWorkerCliPlan(3, [], { RCS_TEAM_WORKER_CLI_MAP: 'claude' });
1756
- assert.deepEqual(plan, ['claude', 'claude', 'claude']);
1757
- });
1758
- it('resolveTeamWorkerCliPlan supports auto entries in CLI map', () => {
1759
- const plan = resolveTeamWorkerCliPlan(2, ['--model', 'claude-3-7-sonnet'], { RCS_TEAM_WORKER_CLI_MAP: 'auto,codex' });
1760
- assert.deepEqual(plan, ['claude', 'codex']);
1761
- });
1762
- it('resolveTeamWorkerCliPlan auto entries ignore RCS_TEAM_WORKER_CLI override', () => {
1763
- const plan = resolveTeamWorkerCliPlan(1, ['--model', 'claude-3-7-sonnet'], {
1764
- RCS_TEAM_WORKER_CLI: 'codex',
1765
- RCS_TEAM_WORKER_CLI_MAP: 'auto',
1766
- });
1767
- assert.deepEqual(plan, ['claude']);
1768
- });
1769
- it('resolveTeamWorkerCliPlan rejects map lengths that do not match workerCount', () => {
1770
- assert.throws(() => resolveTeamWorkerCliPlan(4, [], { RCS_TEAM_WORKER_CLI_MAP: 'codex,claude' }), /expected 1 or 4/i);
1771
- });
1772
- it('resolveTeamWorkerCliPlan rejects empty entries in CLI map', () => {
1773
- assert.throws(() => resolveTeamWorkerCliPlan(2, [], { RCS_TEAM_WORKER_CLI_MAP: 'codex,' }), /empty entries are not allowed/i);
1774
- });
1775
- it('resolveTeamWorkerCliPlan reports invalid entry errors with RCS_TEAM_WORKER_CLI_MAP', () => {
1776
- assert.throws(() => resolveTeamWorkerCliPlan(1, [], { RCS_TEAM_WORKER_CLI_MAP: 'claudee' }), /RCS_TEAM_WORKER_CLI_MAP/i);
1777
- });
1778
- it('resolveWorkerCliForSend prioritizes explicit worker CLI over map/global', () => {
1779
- assert.equal(resolveWorkerCliForSend(2, 'claude', [], { RCS_TEAM_WORKER_CLI_MAP: 'codex,codex' }), 'claude');
1780
- });
1781
- it('resolveWorkerCliForSend resolves per-worker map entry by index', () => {
1782
- assert.equal(resolveWorkerCliForSend(2, undefined, [], { RCS_TEAM_WORKER_CLI_MAP: 'codex,claude' }), 'claude');
1783
- });
1784
- it('buildWorkerSubmitPlan disables queue-first for claude workers', () => {
1785
- const plan = buildWorkerSubmitPlan('auto', 'claude', true, true);
1786
- assert.equal(plan.queueFirstRound, false);
1787
- assert.equal(plan.submitKeyPressesPerRound, 1);
1788
- assert.equal(plan.allowAdaptiveRetry, false);
1789
- });
1790
- it('buildWorkerSubmitPlan preserves queue-first behavior for busy codex workers', () => {
1791
- const plan = buildWorkerSubmitPlan('auto', 'codex', true, true);
1792
- assert.equal(plan.queueFirstRound, true);
1793
- assert.equal(plan.submitKeyPressesPerRound, 2);
1794
- assert.equal(plan.allowAdaptiveRetry, true);
1795
- });
1796
- });
1797
- describe('team worker launch mode helpers', () => {
1798
- it('resolveTeamWorkerLaunchMode defaults to interactive and accepts prompt', () => {
1799
- assert.equal(resolveTeamWorkerLaunchMode({}), 'interactive');
1800
- assert.equal(resolveTeamWorkerLaunchMode({ RCS_TEAM_WORKER_LAUNCH_MODE: 'interactive' }), 'interactive');
1801
- assert.equal(resolveTeamWorkerLaunchMode({ RCS_TEAM_WORKER_LAUNCH_MODE: 'prompt' }), 'prompt');
1802
- assert.equal(resolveTeamWorkerLaunchMode({ RCS_TEAM_WORKER_LAUNCH_MODE: ' PROMPT ' }), 'prompt');
1803
- });
1804
- it('resolveTeamWorkerLaunchMode rejects unsupported values', () => {
1805
- assert.throws(() => resolveTeamWorkerLaunchMode({ RCS_TEAM_WORKER_LAUNCH_MODE: 'tmux' }), /Invalid RCS_TEAM_WORKER_LAUNCH_MODE value/i);
1806
- });
1807
- it('buildWorkerProcessLaunchSpec returns command/args/env for prompt process spawn', () => {
1808
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1809
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1810
- try {
1811
- const spec = buildWorkerProcessLaunchSpec('alpha-team', 2, ['--model', 'gpt-5.3-codex'], '/tmp/workspace', { RCS_TEAM_STATE_ROOT: '/tmp/workspace/.rcs/state' }, 'codex');
1812
- // command is now the resolved absolute path (or bare binary if which fails)
1813
- assert.equal(spec.workerCli, 'codex');
1814
- assert.ok(typeof spec.command === 'string' && spec.command.length > 0, 'command must be a non-empty string');
1815
- assert.deepEqual(spec.args, ['--model', 'gpt-5.3-codex', '--dangerously-bypass-approvals-and-sandbox']);
1816
- assert.equal(spec.env.RCS_TEAM_WORKER, 'alpha-team/worker-2');
1817
- assert.equal(spec.env.RCS_TEAM_STATE_ROOT, '/tmp/workspace/.rcs/state');
1818
- }
1819
- finally {
1820
- if (typeof prevBypass === 'string')
1821
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1822
- else
1823
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1824
- }
1825
- });
1826
- it('buildWorkerProcessLaunchSpec does not force codex bypass for read-only roles', () => {
1827
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1828
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1829
- try {
1830
- const spec = buildWorkerProcessLaunchSpec('alpha-team', 2, ['--model', 'gpt-5.3-codex-spark'], '/tmp/workspace', { RCS_TEAM_STATE_ROOT: '/tmp/workspace/.rcs/state' }, 'codex', undefined, 'explore');
1831
- assert.deepEqual(spec.args, ['--model', 'gpt-5.3-codex-spark']);
1832
- }
1833
- finally {
1834
- if (typeof prevBypass === 'string')
1835
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1836
- else
1837
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1838
- }
1839
- });
1840
- it('buildWorkerProcessLaunchSpec includes leader node and CLI path env vars', () => {
1841
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1842
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1843
- try {
1844
- const spec = buildWorkerProcessLaunchSpec('beta-team', 1, [], '/tmp/workspace', {}, 'codex');
1845
- assert.ok(typeof spec.env.RCS_LEADER_NODE_PATH === 'string' && spec.env.RCS_LEADER_NODE_PATH.length > 0, 'RCS_LEADER_NODE_PATH must be set');
1846
- assert.ok(typeof spec.env.RCS_LEADER_CLI_PATH === 'string' && spec.env.RCS_LEADER_CLI_PATH.length > 0, 'RCS_LEADER_CLI_PATH must be set');
1847
- // command matches the resolved CLI path stored in env
1848
- assert.equal(spec.command, spec.env.RCS_LEADER_CLI_PATH);
1849
- }
1850
- finally {
1851
- if (typeof prevBypass === 'string')
1852
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1853
- else
1854
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1855
- }
1856
- });
1857
- it('buildWorkerProcessLaunchSpec wraps Windows PowerShell shims for prompt workers', async () => {
1858
- const fakeBin = await mkdtemp(join(tmpdir(), 'rcs-worker-spec-win32-'));
1859
- const prevPath = process.env.PATH;
1860
- const prevPathext = process.env.PATHEXT;
1861
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1862
- const prevMsystem = process.env.MSYSTEM;
1863
- const prevOstype = process.env.OSTYPE;
1864
- const prevWsl = process.env.WSL_DISTRO_NAME;
1865
- const prevWslInterop = process.env.WSL_INTEROP;
1866
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
1867
- process.env.PATH = fakeBin;
1868
- process.env.PATHEXT = '.PS1';
1869
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1870
- delete process.env.MSYSTEM;
1871
- delete process.env.OSTYPE;
1872
- delete process.env.WSL_DISTRO_NAME;
1873
- delete process.env.WSL_INTEROP;
1874
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
1875
- try {
1876
- const codexPs1Path = join(fakeBin, 'codex.ps1');
1877
- await writeFile(codexPs1Path, '');
1878
- const spec = buildWorkerProcessLaunchSpec('beta-team', 1, ['--model', 'gpt-5'], 'C:\\workspace', {}, 'codex');
1879
- assert.match(spec.command, /powershell(?:\.exe)?$/i);
1880
- assert.deepEqual(spec.args.slice(0, 5), ['-NoLogo', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File']);
1881
- assert.equal(spec.args[5], codexPs1Path);
1882
- assert.deepEqual(spec.args.slice(6), ['--model', 'gpt-5', '--dangerously-bypass-approvals-and-sandbox']);
1883
- assert.equal(spec.env.RCS_LEADER_CLI_PATH, codexPs1Path);
1884
- assert.notEqual(spec.command, codexPs1Path);
1885
- }
1886
- finally {
1887
- if (origPlatform)
1888
- Object.defineProperty(process, 'platform', origPlatform);
1889
- if (typeof prevPath === 'string')
1890
- process.env.PATH = prevPath;
1891
- else
1892
- delete process.env.PATH;
1893
- if (typeof prevPathext === 'string')
1894
- process.env.PATHEXT = prevPathext;
1895
- else
1896
- delete process.env.PATHEXT;
1897
- if (typeof prevBypass === 'string')
1898
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1899
- else
1900
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1901
- if (typeof prevMsystem === 'string')
1902
- process.env.MSYSTEM = prevMsystem;
1903
- else
1904
- delete process.env.MSYSTEM;
1905
- if (typeof prevOstype === 'string')
1906
- process.env.OSTYPE = prevOstype;
1907
- else
1908
- delete process.env.OSTYPE;
1909
- if (typeof prevWsl === 'string')
1910
- process.env.WSL_DISTRO_NAME = prevWsl;
1911
- else
1912
- delete process.env.WSL_DISTRO_NAME;
1913
- if (typeof prevWslInterop === 'string')
1914
- process.env.WSL_INTEROP = prevWslInterop;
1915
- else
1916
- delete process.env.WSL_INTEROP;
1917
- await rm(fakeBin, { recursive: true, force: true });
1918
- }
1919
- });
1920
- it('buildWorkerProcessLaunchSpec records the resolved node-hosted Codex launcher on native Windows', async () => {
1921
- const fakeRoot = await mkdtemp(join(tmpdir(), 'rcs-worker-spec-win32-node-hosted-'));
1922
- const fakeBin = join(fakeRoot, 'node_modules', '.bin');
1923
- const prevPath = process.env.PATH;
1924
- const prevPathext = process.env.PATHEXT;
1925
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1926
- const prevMsystem = process.env.MSYSTEM;
1927
- const prevOstype = process.env.OSTYPE;
1928
- const prevWsl = process.env.WSL_DISTRO_NAME;
1929
- const prevWslInterop = process.env.WSL_INTEROP;
1930
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
1931
- process.env.PATH = fakeBin;
1932
- process.env.PATHEXT = '.CMD;.PS1';
1933
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1934
- delete process.env.MSYSTEM;
1935
- delete process.env.OSTYPE;
1936
- delete process.env.WSL_DISTRO_NAME;
1937
- delete process.env.WSL_INTEROP;
1938
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
1939
- try {
1940
- const codexCmdPath = join(fakeBin, 'codex.cmd');
1941
- const codexJsPath = join(fakeRoot, 'node_modules', '@openai', 'codex', 'bin', 'codex.js');
1942
- await mkdir(fakeBin, { recursive: true });
1943
- await mkdir(join(fakeRoot, 'node_modules', '@openai', 'codex', 'bin'), { recursive: true });
1944
- await writeFile(codexCmdPath, '@echo off\r\n');
1945
- await writeFile(codexJsPath, '');
1946
- const spec = buildWorkerProcessLaunchSpec('beta-team', 1, ['--model', 'gpt-5'], 'C:\\workspace', {}, 'codex');
1947
- assert.equal(spec.command, process.execPath);
1948
- assert.deepEqual(spec.args, [codexJsPath, '--model', 'gpt-5', '--dangerously-bypass-approvals-and-sandbox']);
1949
- assert.equal(spec.env.RCS_LEADER_CLI_PATH, codexJsPath);
1950
- assert.notEqual(spec.env.RCS_LEADER_CLI_PATH, codexCmdPath);
1951
- }
1952
- finally {
1953
- if (origPlatform)
1954
- Object.defineProperty(process, 'platform', origPlatform);
1955
- if (typeof prevPath === 'string')
1956
- process.env.PATH = prevPath;
1957
- else
1958
- delete process.env.PATH;
1959
- if (typeof prevPathext === 'string')
1960
- process.env.PATHEXT = prevPathext;
1961
- else
1962
- delete process.env.PATHEXT;
1963
- if (typeof prevBypass === 'string')
1964
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1965
- else
1966
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1967
- if (typeof prevMsystem === 'string')
1968
- process.env.MSYSTEM = prevMsystem;
1969
- else
1970
- delete process.env.MSYSTEM;
1971
- if (typeof prevOstype === 'string')
1972
- process.env.OSTYPE = prevOstype;
1973
- else
1974
- delete process.env.OSTYPE;
1975
- if (typeof prevWsl === 'string')
1976
- process.env.WSL_DISTRO_NAME = prevWsl;
1977
- else
1978
- delete process.env.WSL_DISTRO_NAME;
1979
- if (typeof prevWslInterop === 'string')
1980
- process.env.WSL_INTEROP = prevWslInterop;
1981
- else
1982
- delete process.env.WSL_INTEROP;
1983
- await rm(fakeRoot, { recursive: true, force: true });
1984
- }
1985
- });
1986
- it('buildWorkerProcessLaunchSpec preserves ambient CODEX_HOME so Codex workers keep provider websocket metadata', async () => {
1987
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
1988
- const prevCodexHome = process.env.CODEX_HOME;
1989
- const prevProviderEnv = process.env.CUSTOM_PROVIDER_API_KEY;
1990
- const codexHome = await mkdtemp(join(tmpdir(), 'rcs-team-provider-websocket-'));
1991
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1992
- process.env.CODEX_HOME = codexHome;
1993
- process.env.CUSTOM_PROVIDER_API_KEY = 'test-secret';
1994
- try {
1995
- await writeFile(join(codexHome, 'config.toml'), [
1996
- 'model = "gpt-5.5"',
1997
- 'model_provider = "custom_provider"',
1998
- '',
1999
- '[model_providers.custom_provider]',
2000
- 'name = "custom_provider"',
2001
- 'base_url = "http://localhost:3000/v1"',
2002
- 'wire_api = "responses"',
2003
- 'supports_websockets = true',
2004
- 'requires_openai_auth = true',
2005
- 'env_key = "CUSTOM_PROVIDER_API_KEY"',
2006
- '',
2007
- ].join('\n'));
2008
- const spec = buildWorkerProcessLaunchSpec('websocket-team', 1, [], '/tmp/workspace', {}, 'codex');
2009
- assert.equal(spec.env.CODEX_HOME, codexHome);
2010
- assert.equal(spec.env.CUSTOM_PROVIDER_API_KEY, 'test-secret');
2011
- }
2012
- finally {
2013
- if (typeof prevBypass === 'string')
2014
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
2015
- else
2016
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
2017
- if (typeof prevCodexHome === 'string')
2018
- process.env.CODEX_HOME = prevCodexHome;
2019
- else
2020
- delete process.env.CODEX_HOME;
2021
- if (typeof prevProviderEnv === 'string')
2022
- process.env.CUSTOM_PROVIDER_API_KEY = prevProviderEnv;
2023
- else
2024
- delete process.env.CUSTOM_PROVIDER_API_KEY;
2025
- await rm(codexHome, { recursive: true, force: true });
2026
- }
2027
- });
2028
- it('buildWorkerProcessLaunchSpec injects the active provider env_key from CODEX_HOME config.toml', async () => {
2029
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
2030
- const prevCodexHome = process.env.CODEX_HOME;
2031
- const prevProviderEnv = process.env.CUSTOM_PROVIDER_API_KEY;
2032
- const codexHome = await mkdtemp(join(tmpdir(), 'rcs-team-provider-env-'));
2033
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
2034
- process.env.CODEX_HOME = codexHome;
2035
- process.env.CUSTOM_PROVIDER_API_KEY = 'test-secret';
2036
- try {
2037
- await writeFile(join(codexHome, 'config.toml'), [
2038
- 'model_provider = "custom_provider"',
2039
- '',
2040
- '[model_providers.custom_provider]',
2041
- 'name = "custom_provider"',
2042
- 'base_url = "http://localhost:3000/v1"',
2043
- 'wire_api = "responses"',
2044
- 'requires_openai_auth = true',
2045
- 'env_key = "CUSTOM_PROVIDER_API_KEY"',
2046
- '',
2047
- ].join('\n'));
2048
- const spec = buildWorkerProcessLaunchSpec('gamma-team', 1, [], '/tmp/workspace', {}, 'codex');
2049
- assert.equal(spec.env.CUSTOM_PROVIDER_API_KEY, 'test-secret');
2050
- }
2051
- finally {
2052
- if (typeof prevBypass === 'string')
2053
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
2054
- else
2055
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
2056
- if (typeof prevCodexHome === 'string')
2057
- process.env.CODEX_HOME = prevCodexHome;
2058
- else
2059
- delete process.env.CODEX_HOME;
2060
- if (typeof prevProviderEnv === 'string')
2061
- process.env.CUSTOM_PROVIDER_API_KEY = prevProviderEnv;
2062
- else
2063
- delete process.env.CUSTOM_PROVIDER_API_KEY;
2064
- await rm(codexHome, { recursive: true, force: true });
2065
- }
2066
- });
2067
- it('buildWorkerProcessLaunchSpec uses CLI model_provider override for Codex provider env injection', async () => {
2068
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
2069
- const prevCodexHome = process.env.CODEX_HOME;
2070
- const prevDefaultProviderEnv = process.env.DEFAULT_PROVIDER_API_KEY;
2071
- const prevCheapProviderEnv = process.env.CHEAP_PROVIDER_API_KEY;
2072
- const codexHome = await mkdtemp(join(tmpdir(), 'rcs-team-provider-cli-override-'));
2073
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
2074
- process.env.CODEX_HOME = codexHome;
2075
- process.env.DEFAULT_PROVIDER_API_KEY = 'default-secret';
2076
- process.env.CHEAP_PROVIDER_API_KEY = 'cheap-secret';
2077
- try {
2078
- await writeFile(join(codexHome, 'config.toml'), [
2079
- 'model_provider = "default_provider"',
2080
- '',
2081
- '[model_providers.default_provider]',
2082
- 'name = "default_provider"',
2083
- 'base_url = "http://localhost:3000/v1"',
2084
- 'wire_api = "responses"',
2085
- 'requires_openai_auth = true',
2086
- 'env_key = "DEFAULT_PROVIDER_API_KEY"',
2087
- '',
2088
- '[model_providers.cheapRouter]',
2089
- 'name = "cheapRouter"',
2090
- 'base_url = "http://localhost:4000/v1"',
2091
- 'wire_api = "responses"',
2092
- 'requires_openai_auth = true',
2093
- 'env_key = "CHEAP_PROVIDER_API_KEY"',
2094
- '',
2095
- ].join('\n'));
2096
- const spec = buildWorkerProcessLaunchSpec('provider-override-team', 1, ['-c', 'model_provider="cheapRouter"', '--model', 'gpt-5.5'], '/tmp/workspace', {}, 'codex');
2097
- assert.equal(spec.env.CHEAP_PROVIDER_API_KEY, 'cheap-secret');
2098
- assert.equal(spec.env.DEFAULT_PROVIDER_API_KEY, undefined);
2099
- assert.deepEqual(spec.args.slice(0, 4), ['-c', 'model_provider="cheapRouter"', '--model', 'gpt-5.5']);
2100
- }
2101
- finally {
2102
- if (typeof prevBypass === 'string')
2103
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
2104
- else
2105
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
2106
- if (typeof prevCodexHome === 'string')
2107
- process.env.CODEX_HOME = prevCodexHome;
2108
- else
2109
- delete process.env.CODEX_HOME;
2110
- if (typeof prevDefaultProviderEnv === 'string')
2111
- process.env.DEFAULT_PROVIDER_API_KEY = prevDefaultProviderEnv;
2112
- else
2113
- delete process.env.DEFAULT_PROVIDER_API_KEY;
2114
- if (typeof prevCheapProviderEnv === 'string')
2115
- process.env.CHEAP_PROVIDER_API_KEY = prevCheapProviderEnv;
2116
- else
2117
- delete process.env.CHEAP_PROVIDER_API_KEY;
2118
- await rm(codexHome, { recursive: true, force: true });
2119
- }
2120
- });
2121
- it('buildWorkerProcessLaunchSpec does not inject the active provider env_key for non-codex workers', async () => {
2122
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
2123
- const prevCodexHome = process.env.CODEX_HOME;
2124
- const prevProviderEnv = process.env.CUSTOM_PROVIDER_API_KEY;
2125
- const codexHome = await mkdtemp(join(tmpdir(), 'rcs-team-provider-env-'));
2126
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
2127
- process.env.CODEX_HOME = codexHome;
2128
- process.env.CUSTOM_PROVIDER_API_KEY = 'test-secret';
2129
- try {
2130
- await writeFile(join(codexHome, 'config.toml'), [
2131
- 'model_provider = "custom_provider"',
2132
- '',
2133
- '[model_providers.custom_provider]',
2134
- 'name = "custom_provider"',
2135
- 'base_url = "http://localhost:3000/v1"',
2136
- 'wire_api = "responses"',
2137
- 'requires_openai_auth = true',
2138
- 'env_key = "CUSTOM_PROVIDER_API_KEY"',
2139
- '',
2140
- ].join('\n'));
2141
- const spec = buildWorkerProcessLaunchSpec('delta-team', 1, [], '/tmp/workspace', {}, 'claude');
2142
- assert.equal(spec.workerCli, 'claude');
2143
- assert.equal(spec.env.CODEX_HOME, undefined);
2144
- assert.equal(spec.env.CUSTOM_PROVIDER_API_KEY, undefined);
2145
- }
2146
- finally {
2147
- if (typeof prevBypass === 'string')
2148
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
2149
- else
2150
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
2151
- if (typeof prevCodexHome === 'string')
2152
- process.env.CODEX_HOME = prevCodexHome;
2153
- else
2154
- delete process.env.CODEX_HOME;
2155
- if (typeof prevProviderEnv === 'string')
2156
- process.env.CUSTOM_PROVIDER_API_KEY = prevProviderEnv;
2157
- else
2158
- delete process.env.CUSTOM_PROVIDER_API_KEY;
2159
- await rm(codexHome, { recursive: true, force: true });
2160
- }
2161
- });
2162
- it('buildWorkerProcessLaunchSpec reads provider env from worker CODEX_HOME override', async () => {
2163
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
2164
- const prevCodexHome = process.env.CODEX_HOME;
2165
- const prevPrimaryProviderEnv = process.env.PRIMARY_PROVIDER_API_KEY;
2166
- const prevWorkerProviderEnv = process.env.WORKER_PROVIDER_API_KEY;
2167
- const leaderCodexHome = await mkdtemp(join(tmpdir(), 'rcs-team-provider-env-leader-'));
2168
- const workerCodexHome = await mkdtemp(join(tmpdir(), 'rcs-team-provider-env-worker-'));
2169
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
2170
- process.env.CODEX_HOME = leaderCodexHome;
2171
- process.env.PRIMARY_PROVIDER_API_KEY = 'leader-secret';
2172
- process.env.WORKER_PROVIDER_API_KEY = 'worker-secret';
2173
- try {
2174
- await writeFile(join(leaderCodexHome, 'config.toml'), [
2175
- 'model_provider = "primary_provider"',
2176
- '',
2177
- '[model_providers.primary_provider]',
2178
- 'name = "primary_provider"',
2179
- 'base_url = "http://localhost:3000/v1"',
2180
- 'wire_api = "responses"',
2181
- 'requires_openai_auth = true',
2182
- 'env_key = "PRIMARY_PROVIDER_API_KEY"',
2183
- '',
2184
- ].join('\n'));
2185
- await writeFile(join(workerCodexHome, 'config.toml'), [
2186
- 'model_provider = "worker_provider"',
2187
- '',
2188
- '[model_providers.worker_provider]',
2189
- 'name = "worker_provider"',
2190
- 'base_url = "http://localhost:4000/v1"',
2191
- 'wire_api = "responses"',
2192
- 'requires_openai_auth = true',
2193
- 'env_key = "WORKER_PROVIDER_API_KEY"',
2194
- '',
2195
- ].join('\n'));
2196
- const spec = buildWorkerProcessLaunchSpec('epsilon-team', 1, [], '/tmp/workspace', { CODEX_HOME: workerCodexHome }, 'codex');
2197
- assert.equal(spec.env.CODEX_HOME, workerCodexHome);
2198
- assert.equal(spec.env.WORKER_PROVIDER_API_KEY, 'worker-secret');
2199
- assert.equal(spec.env.PRIMARY_PROVIDER_API_KEY, undefined);
2200
- }
2201
- finally {
2202
- if (typeof prevBypass === 'string')
2203
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
2204
- else
2205
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
2206
- if (typeof prevCodexHome === 'string')
2207
- process.env.CODEX_HOME = prevCodexHome;
2208
- else
2209
- delete process.env.CODEX_HOME;
2210
- if (typeof prevPrimaryProviderEnv === 'string')
2211
- process.env.PRIMARY_PROVIDER_API_KEY = prevPrimaryProviderEnv;
2212
- else
2213
- delete process.env.PRIMARY_PROVIDER_API_KEY;
2214
- if (typeof prevWorkerProviderEnv === 'string')
2215
- process.env.WORKER_PROVIDER_API_KEY = prevWorkerProviderEnv;
2216
- else
2217
- delete process.env.WORKER_PROVIDER_API_KEY;
2218
- await rm(leaderCodexHome, { recursive: true, force: true });
2219
- await rm(workerCodexHome, { recursive: true, force: true });
2220
- }
2221
- });
2222
- it('buildWorkerProcessLaunchSpec keeps the worker env contract unchanged for ambient proxy vars', () => {
2223
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
2224
- const prevHttpsProxy = process.env.HTTPS_PROXY;
2225
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
2226
- process.env.HTTPS_PROXY = 'https://ambient-proxy.example:443';
2227
- try {
2228
- const spec = buildWorkerProcessLaunchSpec('eta-team', 1, [], '/tmp/workspace', {}, 'codex');
2229
- assert.equal(spec.env.HTTPS_PROXY, undefined);
2230
- }
2231
- finally {
2232
- if (typeof prevBypass === 'string')
2233
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
2234
- else
2235
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
2236
- if (typeof prevHttpsProxy === 'string')
2237
- process.env.HTTPS_PROXY = prevHttpsProxy;
2238
- else
2239
- delete process.env.HTTPS_PROXY;
2240
- }
2241
- });
2242
- it('buildWorkerProcessLaunchSpec resolves relative worker CODEX_HOME against the worker cwd', async () => {
2243
- const prevBypass = process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
2244
- const prevCodexHome = process.env.CODEX_HOME;
2245
- const prevLeaderProviderEnv = process.env.LEADER_PROVIDER_API_KEY;
2246
- const prevWorkerProviderEnv = process.env.WORKER_PROVIDER_API_KEY;
2247
- const originalCwd = process.cwd();
2248
- const leaderCwd = await mkdtemp(join(tmpdir(), 'rcs-team-provider-relative-leader-'));
2249
- const workerCwd = await mkdtemp(join(tmpdir(), 'rcs-team-provider-relative-worker-'));
2250
- const leaderCodexHome = join(leaderCwd, '.codex');
2251
- const workerCodexHome = join(workerCwd, '.codex');
2252
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
2253
- process.env.CODEX_HOME = leaderCodexHome;
2254
- process.env.LEADER_PROVIDER_API_KEY = 'leader-secret';
2255
- process.env.WORKER_PROVIDER_API_KEY = 'worker-secret';
2256
- try {
2257
- await mkdir(leaderCodexHome, { recursive: true });
2258
- await mkdir(workerCodexHome, { recursive: true });
2259
- await writeFile(join(leaderCodexHome, 'config.toml'), [
2260
- 'model_provider = "leader_provider"',
2261
- '',
2262
- '[model_providers.leader_provider]',
2263
- 'name = "leader_provider"',
2264
- 'base_url = "http://localhost:3000/v1"',
2265
- 'wire_api = "responses"',
2266
- 'requires_openai_auth = true',
2267
- 'env_key = "LEADER_PROVIDER_API_KEY"',
2268
- '',
2269
- ].join('\n'));
2270
- await writeFile(join(workerCodexHome, 'config.toml'), [
2271
- 'model_provider = "worker_provider"',
2272
- '',
2273
- '[model_providers.worker_provider]',
2274
- 'name = "worker_provider"',
2275
- 'base_url = "http://localhost:4000/v1"',
2276
- 'wire_api = "responses"',
2277
- 'requires_openai_auth = true',
2278
- 'env_key = "WORKER_PROVIDER_API_KEY"',
2279
- '',
2280
- ].join('\n'));
2281
- process.chdir(leaderCwd);
2282
- const spec = buildWorkerProcessLaunchSpec('zeta-team', 1, [], workerCwd, { CODEX_HOME: '.codex' }, 'codex');
2283
- assert.equal(spec.env.CODEX_HOME, '.codex');
2284
- assert.equal(spec.env.WORKER_PROVIDER_API_KEY, 'worker-secret');
2285
- assert.equal(spec.env.LEADER_PROVIDER_API_KEY, undefined);
2286
- }
2287
- finally {
2288
- process.chdir(originalCwd);
2289
- if (typeof prevBypass === 'string')
2290
- process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
2291
- else
2292
- delete process.env.RCS_BYPASS_DEFAULT_SYSTEM_PROMPT;
2293
- if (typeof prevCodexHome === 'string')
2294
- process.env.CODEX_HOME = prevCodexHome;
2295
- else
2296
- delete process.env.CODEX_HOME;
2297
- if (typeof prevLeaderProviderEnv === 'string')
2298
- process.env.LEADER_PROVIDER_API_KEY = prevLeaderProviderEnv;
2299
- else
2300
- delete process.env.LEADER_PROVIDER_API_KEY;
2301
- if (typeof prevWorkerProviderEnv === 'string')
2302
- process.env.WORKER_PROVIDER_API_KEY = prevWorkerProviderEnv;
2303
- else
2304
- delete process.env.WORKER_PROVIDER_API_KEY;
2305
- await rm(leaderCwd, { recursive: true, force: true });
2306
- await rm(workerCwd, { recursive: true, force: true });
2307
- }
2308
- });
2309
- });
2310
- describe('sendToWorkerStdin', () => {
2311
- it('writes a newline-terminated trigger message to worker stdin', () => {
2312
- const stdin = new PassThrough();
2313
- let captured = '';
2314
- stdin.on('data', (chunk) => {
2315
- captured += chunk.toString();
2316
- });
2317
- sendToWorkerStdin(stdin, 'check inbox now');
2318
- assert.equal(captured, 'check inbox now\n');
2319
- });
2320
- it('validates trigger text before writing to stdin', () => {
2321
- const stdin = new PassThrough();
2322
- assert.throws(() => sendToWorkerStdin(stdin, ''), /non-empty/i);
2323
- assert.throws(() => sendToWorkerStdin(stdin, 'a'.repeat(200)), /< 200 characters/i);
2324
- });
2325
- });
2326
- describe('tmux-dependent functions when tmux is unavailable', () => {
2327
- it('isTmuxAvailable returns false', () => {
2328
- withEmptyPath(() => {
2329
- assert.equal(isTmuxAvailable(), false);
2330
- });
2331
- });
2332
- it('createTeamSession throws', () => {
2333
- withEmptyPath(() => {
2334
- assert.throws(() => createTeamSession('My Team', 1, process.cwd()), /tmux is not available/i);
2335
- });
2336
- });
2337
- it('listTeamSessions returns empty', () => {
2338
- withEmptyPath(() => {
2339
- assert.deepEqual(listTeamSessions(), []);
2340
- });
2341
- });
2342
- it('waitForWorkerReady uses visible capture-pane argv without tail flags', async () => {
2343
- await withMockTmuxFixture('rcs-tmux-worker-ready-visible-capture-', (logPath) => `#!/bin/sh
2344
- set -eu
2345
- printf '%s\n' "$*" >> "${logPath}"
2346
- case "$1" in
2347
- capture-pane)
2348
- cat <<'EOF'
2349
- ${READY_HELPER_CAPTURE}
2350
- EOF
2351
- exit 0
2352
- ;;
2353
- *)
2354
- exit 0
2355
- ;;
2356
- esac
2357
- `, async ({ logPath }) => {
2358
- assert.equal(waitForWorkerReady('rcs-team-x', 1, 1_000), true);
2359
- const log = await readFile(logPath, 'utf-8');
2360
- assert.match(log, /capture-pane -t rcs-team-x:1 -p/);
2361
- assert.doesNotMatch(log, /capture-pane -t rcs-team-x:1 -p -S/);
2362
- });
2363
- });
2364
- it('waitForWorkerReady accepts Codex 0.114.0-style welcome helper text', async () => {
2365
- await withMockTmuxFixture('rcs-tmux-worker-ready-hello-', (logPath) => `#!/bin/sh
2366
- set -eu
2367
- printf '%s\n' "$*" >> "${logPath}"
2368
- case "$1" in
2369
- capture-pane)
2370
- cat <<'EOF'
2371
- ╭────────────────────────────────────────────╮
2372
- │ >_ OpenAI Codex (v0.114.0) │
2373
- │ │
2374
- │ model: gpt-5.5 high /model to change │
2375
- │ directory: ~/Workspace/demo │
2376
- ╰────────────────────────────────────────────╯
2377
-
2378
- How can I help you today?
2379
- EOF
2380
- exit 0
2381
- ;;
2382
- *)
2383
- exit 0
2384
- ;;
2385
- esac
2386
- `, async () => {
2387
- assert.equal(waitForWorkerReady('rcs-team-x', 1, 1_000), true);
2388
- });
2389
- });
2390
- it('waitForWorkerReady falls back to recent scrollback when a live Codex viewport pushes the prompt below the visible slice', async () => {
2391
- await withMockTmuxFixture('rcs-tmux-worker-ready-scrollback-fallback-', (logPath) => `#!/bin/sh
2392
- set -eu
2393
- printf '%s\n' "$*" >> "${logPath}"
2394
- case "$1" in
2395
- capture-pane)
2396
- if printf '%s\n' "$*" | grep -q -- ' -S -80'; then
2397
- cat <<'EOF'
2398
- ${VIEWPORT_SCROLLBACK_READY_CAPTURE}
2399
- EOF
2400
- else
2401
- cat <<'EOF'
2402
- ${VIEWPORT_WITHOUT_VISIBLE_PROMPT_CAPTURE}
2403
- EOF
2404
- fi
2405
- exit 0
2406
- ;;
2407
- *)
2408
- exit 0
2409
- ;;
2410
- esac
2411
- `, async ({ logPath }) => {
2412
- assert.equal(waitForWorkerReady('rcs-team-x', 1, 1_000), true);
2413
- const log = await readFile(logPath, 'utf-8');
2414
- assert.match(log, /capture-pane -t rcs-team-x:1 -p/);
2415
- assert.match(log, /capture-pane -t rcs-team-x:1 -p -S -80/);
2416
- });
2417
- });
2418
- it('waitForWorkerReady does not consult scrollback when the visible slice is only status text', async () => {
2419
- await withMockTmuxFixture('rcs-tmux-worker-ready-no-scrollback-status-', (logPath) => `#!/bin/sh
2420
- set -eu
2421
- printf '%s\n' "$*" >> "${logPath}"
2422
- case "$1" in
2423
- capture-pane)
2424
- cat <<'EOF'
2425
- gpt-5 50% left
2426
- EOF
2427
- exit 0
2428
- ;;
2429
- *)
2430
- exit 0
2431
- ;;
2432
- esac
2433
- `, async ({ logPath }) => {
2434
- assert.equal(waitForWorkerReady('rcs-team-x', 1, 250), false);
2435
- const log = await readFile(logPath, 'utf-8');
2436
- assert.match(log, /capture-pane -t rcs-team-x:1 -p/);
2437
- assert.doesNotMatch(log, /capture-pane -t rcs-team-x:1 -p -S -80/);
2438
- });
2439
- });
2440
- it('waitForWorkerReady auto-accepts the Claude bypass prompt', async () => {
2441
- await withMockTmuxFixture('rcs-tmux-claude-bypass-ready-', (logPath) => `#!/bin/sh
2442
- set -eu
2443
- state_dir="$(dirname "${logPath}")"
2444
- accepted_file="$state_dir/accepted"
2445
- printf '%s\n' "$*" >> "${logPath}"
2446
- case "$1" in
2447
- capture-pane)
2448
- if [ -f "$accepted_file" ]; then
2449
- cat <<'EOF'
2450
- ${READY_HELPER_CAPTURE}
2451
- EOF
2452
- else
2453
- cat <<'EOF'
2454
- ${CLAUDE_BYPASS_PROMPT_CAPTURE}
2455
- EOF
2456
- fi
2457
- exit 0
2458
- ;;
2459
- send-keys)
2460
- if [ "\${4:-}" = "-l" ] && [ "\${6:-}" = "2" ]; then
2461
- : > "$accepted_file"
2462
- fi
2463
- exit 0
2464
- ;;
2465
- *)
2466
- exit 0
2467
- ;;
2468
- esac
2469
- `, async ({ logPath }) => {
2470
- assert.equal(waitForWorkerReady('rcs-team-x', 1, 5_000), true);
2471
- const log = await readFile(logPath, 'utf-8');
2472
- assert.match(log, /send-keys -t rcs-team-x:1 -l -- 2/);
2473
- assert.match(log, /send-keys -t rcs-team-x:1 C-m/);
2474
- });
2475
- });
2476
- it('waitForWorkerReady leaves the Claude bypass prompt untouched when auto-accept is disabled', async () => {
2477
- const previousAutoAccept = process.env.RCS_TEAM_AUTO_ACCEPT_BYPASS;
2478
- process.env.RCS_TEAM_AUTO_ACCEPT_BYPASS = '0';
2479
- try {
2480
- await withMockTmuxFixture('rcs-tmux-claude-bypass-blocked-', (logPath) => `#!/bin/sh
2481
- set -eu
2482
- printf '%s\n' "$*" >> "${logPath}"
2483
- case "$1" in
2484
- capture-pane)
2485
- cat <<'EOF'
2486
- ${CLAUDE_BYPASS_PROMPT_CAPTURE}
2487
- EOF
2488
- exit 0
2489
- ;;
2490
- *)
2491
- exit 0
2492
- ;;
2493
- esac
2494
- `, async ({ logPath }) => {
2495
- assert.equal(waitForWorkerReady('rcs-team-x', 1, 250), false);
2496
- const log = await readFile(logPath, 'utf-8');
2497
- assert.doesNotMatch(log, /send-keys/);
2498
- });
2499
- }
2500
- finally {
2501
- if (typeof previousAutoAccept === 'string')
2502
- process.env.RCS_TEAM_AUTO_ACCEPT_BYPASS = previousAutoAccept;
2503
- else
2504
- delete process.env.RCS_TEAM_AUTO_ACCEPT_BYPASS;
2505
- }
2506
- });
2507
- it('waitForWorkerReady returns false on timeout', () => {
2508
- withEmptyPath(() => {
2509
- assert.equal(waitForWorkerReady('rcs-team-x', 1, 1), false);
2510
- });
2511
- });
2512
- });
2513
- describe('waitForWorkerReadyAsync parity', () => {
2514
- it('uses visible capture-pane argv without tail flags', async () => {
2515
- await withMockTmuxFixture('rcs-tmux-worker-ready-async-visible-capture-', (logPath) => `#!/bin/sh
2516
- set -eu
2517
- printf '%s\n' "$*" >> "${logPath}"
2518
- case "$1" in
2519
- capture-pane)
2520
- cat <<'EOF'
2521
- ${READY_HELPER_CAPTURE}
2522
- EOF
2523
- exit 0
2524
- ;;
2525
- *)
2526
- exit 0
2527
- ;;
2528
- esac
2529
- `, async ({ logPath }) => {
2530
- assert.equal(await waitForWorkerReadyAsync('rcs-team-x', 1, 1_000), true);
2531
- const log = await readFile(logPath, 'utf-8');
2532
- assert.match(log, /capture-pane -t rcs-team-x:1 -p/);
2533
- assert.doesNotMatch(log, /capture-pane -t rcs-team-x:1 -p -S/);
2534
- });
2535
- });
2536
- it('falls back to recent scrollback only when visible slice shows a live Codex viewport', async () => {
2537
- await withMockTmuxFixture('rcs-tmux-worker-ready-async-scrollback-fallback-', (logPath) => `#!/bin/sh
2538
- set -eu
2539
- printf '%s\n' "$*" >> "${logPath}"
2540
- case "$1" in
2541
- capture-pane)
2542
- if printf '%s\n' "$*" | grep -q -- ' -S -80'; then
2543
- cat <<'EOF'
2544
- ${VIEWPORT_SCROLLBACK_READY_CAPTURE}
2545
- EOF
2546
- else
2547
- cat <<'EOF'
2548
- ${VIEWPORT_WITHOUT_VISIBLE_PROMPT_CAPTURE}
2549
- EOF
2550
- fi
2551
- exit 0
2552
- ;;
2553
- *)
2554
- exit 0
2555
- ;;
2556
- esac
2557
- `, async ({ logPath }) => {
2558
- assert.equal(await waitForWorkerReadyAsync('rcs-team-x', 1, 1_000), true);
2559
- const log = await readFile(logPath, 'utf-8');
2560
- assert.match(log, /capture-pane -t rcs-team-x:1 -p/);
2561
- assert.match(log, /capture-pane -t rcs-team-x:1 -p -S -80/);
2562
- });
2563
- await withMockTmuxFixture('rcs-tmux-worker-ready-async-no-scrollback-status-', (logPath) => `#!/bin/sh
2564
- set -eu
2565
- printf '%s\n' "$*" >> "${logPath}"
2566
- case "$1" in
2567
- capture-pane)
2568
- printf 'gpt-5 50%% left\n'
2569
- exit 0
2570
- ;;
2571
- *)
2572
- exit 0
2573
- ;;
2574
- esac
2575
- `, async ({ logPath }) => {
2576
- assert.equal(await waitForWorkerReadyAsync('rcs-team-x', 1, 250), false);
2577
- const log = await readFile(logPath, 'utf-8');
2578
- assert.match(log, /capture-pane -t rcs-team-x:1 -p/);
2579
- assert.doesNotMatch(log, /capture-pane -t rcs-team-x:1 -p -S -80/);
2580
- });
2581
- });
2582
- it('auto-accepts trust prompts and then observes readiness', async () => {
2583
- const previousAutoTrust = process.env.RCS_TEAM_AUTO_TRUST;
2584
- delete process.env.RCS_TEAM_AUTO_TRUST;
2585
- try {
2586
- await withMockTmuxFixture('rcs-tmux-worker-ready-async-trust-', (logPath) => `#!/bin/sh
2587
- set -eu
2588
- state_dir="$(dirname "${logPath}")"
2589
- accepted_file="$state_dir/accepted"
2590
- printf '%s\n' "$*" >> "${logPath}"
2591
- case "$1" in
2592
- capture-pane)
2593
- if [ -f "$accepted_file" ]; then
2594
- cat <<'EOF'
2595
- ${READY_HELPER_CAPTURE}
2596
- EOF
2597
- else
2598
- cat <<'EOF'
2599
- Do you trust the contents of this directory?
2600
- Press enter to continue
2601
- EOF
2602
- fi
2603
- exit 0
2604
- ;;
2605
- send-keys)
2606
- if [ "\${4:-}" = "C-m" ]; then
2607
- : > "$accepted_file"
2608
- fi
2609
- exit 0
2610
- ;;
2611
- *)
2612
- exit 0
2613
- ;;
2614
- esac
2615
- `, async ({ logPath }) => {
2616
- assert.equal(await waitForWorkerReadyAsync('rcs-team-x', 1, 5_000), true);
2617
- const log = await readFile(logPath, 'utf-8');
2618
- assert.match(log, /send-keys -t rcs-team-x:1 C-m/);
2619
- });
2620
- }
2621
- finally {
2622
- if (typeof previousAutoTrust === 'string')
2623
- process.env.RCS_TEAM_AUTO_TRUST = previousAutoTrust;
2624
- else
2625
- delete process.env.RCS_TEAM_AUTO_TRUST;
2626
- }
2627
- });
2628
- it('auto-accepts the Claude bypass prompt and then observes readiness', async () => {
2629
- const previousAutoAccept = process.env.RCS_TEAM_AUTO_ACCEPT_BYPASS;
2630
- delete process.env.RCS_TEAM_AUTO_ACCEPT_BYPASS;
2631
- try {
2632
- await withMockTmuxFixture('rcs-tmux-worker-ready-async-claude-bypass-', (logPath) => `#!/bin/sh
2633
- set -eu
2634
- state_dir="$(dirname "${logPath}")"
2635
- accepted_file="$state_dir/accepted"
2636
- printf '%s\n' "$*" >> "${logPath}"
2637
- case "$1" in
2638
- capture-pane)
2639
- if [ -f "$accepted_file" ]; then
2640
- cat <<'EOF'
2641
- ${READY_HELPER_CAPTURE}
2642
- EOF
2643
- else
2644
- cat <<'EOF'
2645
- ${CLAUDE_BYPASS_PROMPT_CAPTURE}
2646
- EOF
2647
- fi
2648
- exit 0
2649
- ;;
2650
- send-keys)
2651
- if [ "\${4:-}" = "-l" ] && [ "\${6:-}" = "2" ]; then
2652
- : > "$accepted_file"
2653
- fi
2654
- exit 0
2655
- ;;
2656
- *)
2657
- exit 0
2658
- ;;
2659
- esac
2660
- `, async ({ logPath }) => {
2661
- assert.equal(await waitForWorkerReadyAsync('rcs-team-x', 1, 5_000), true);
2662
- const log = await readFile(logPath, 'utf-8');
2663
- assert.match(log, /send-keys -t rcs-team-x:1 -l -- 2/);
2664
- });
2665
- }
2666
- finally {
2667
- if (typeof previousAutoAccept === 'string')
2668
- process.env.RCS_TEAM_AUTO_ACCEPT_BYPASS = previousAutoAccept;
2669
- else
2670
- delete process.env.RCS_TEAM_AUTO_ACCEPT_BYPASS;
2671
- }
2672
- });
2673
- it('returns false on timeout or tmux command failure', async () => {
2674
- await withMockTmuxFixture('rcs-tmux-worker-ready-async-capture-failure-', (logPath) => `#!/bin/sh
2675
- set -eu
2676
- printf '%s\n' "$*" >> "${logPath}"
2677
- case "$1" in
2678
- capture-pane)
2679
- exit 1
2680
- ;;
2681
- *)
2682
- exit 0
2683
- ;;
2684
- esac
2685
- `, async () => {
2686
- assert.equal(await waitForWorkerReadyAsync('rcs-team-x', 1, 1), false);
2687
- });
2688
- await withEmptyPath(async () => {
2689
- assert.equal(await waitForWorkerReadyAsync('rcs-team-x', 1, 1), false);
2690
- });
2691
- });
2692
- });
2693
- describe('createTeamSession tmux instance tagging', () => {
2694
- it('tags leader, worker, and HUD panes with pane-scoped instance ownership', async () => {
2695
- const cwd = await mkdtemp(join(tmpdir(), 'rcs-team-pane-tags-'));
2696
- const prevTmux = process.env.TMUX;
2697
- const prevTmuxPane = process.env.TMUX_PANE;
2698
- const prevSessionId = process.env.RCS_SESSION_ID;
2699
- const prevWorkerCli = process.env.RCS_TEAM_WORKER_CLI;
2700
- try {
2701
- await withMockTmuxFixture('rcs-tmux-pane-tags-', (logPath) => `#!/bin/sh
2702
- set -eu
2703
- printf '%s\n' "$*" >> "${logPath}"
2704
- case "\${1:-}" in
2705
- -V)
2706
- echo "tmux 3.4"
2707
- exit 0
2708
- ;;
2709
- display-message)
2710
- case "$*" in
2711
- *"#{window_width}"*)
2712
- echo "120"
2713
- ;;
2714
- *)
2715
- echo "shared:0 %1"
2716
- ;;
2717
- esac
2718
- exit 0
2719
- ;;
2720
- list-panes)
2721
- case "$*" in
2722
- *"pane_current_command"*)
2723
- printf "%%1\\tnode\\t'codex'\\n"
2724
- ;;
2725
- *)
2726
- printf "%%1\\n"
2727
- ;;
2728
- esac
2729
- exit 0
2730
- ;;
2731
- split-window)
2732
- case "$*" in
2733
- *" -h "*)
2734
- echo "%2"
2735
- ;;
2736
- *)
2737
- echo "%3"
2738
- ;;
2739
- esac
2740
- exit 0
2741
- ;;
2742
- set-option|resize-pane|select-layout|set-window-option|select-pane|set-hook|run-shell)
2743
- exit 0
2744
- ;;
2745
- *)
2746
- exit 0
2747
- ;;
2748
- esac
2749
- `, async ({ logPath }) => {
2750
- const fakeBinDir = join(logPath, '..');
2751
- const geminiPath = join(fakeBinDir, 'gemini');
2752
- await writeFile(geminiPath, '#!/bin/sh\nexit 0\n');
2753
- await chmod(geminiPath, 0o755);
2754
- process.env.TMUX = '1';
2755
- process.env.TMUX_PANE = '%1';
2756
- process.env.RCS_SESSION_ID = 'rcs-pane-scope';
2757
- process.env.RCS_TEAM_WORKER_CLI = 'gemini';
2758
- const session = createTeamSession('Pane Tags', 1, cwd);
2759
- assert.equal(session.name, 'shared:0');
2760
- assert.equal(session.leaderPaneId, '%1');
2761
- assert.deepEqual(session.workerPaneIds, ['%2']);
2762
- assert.equal(session.hudPaneId, '%3');
2763
- const tmuxLog = await readFile(logPath, 'utf-8');
2764
- assert.match(tmuxLog, /set-option -t shared @rcs_instance_id rcs-pane-scope/);
2765
- assert.match(tmuxLog, /set-option -p -t %1 @rcs_pane_instance_id rcs-pane-scope/);
2766
- assert.match(tmuxLog, /set-option -p -t %2 @rcs_pane_instance_id rcs-pane-scope/);
2767
- assert.match(tmuxLog, /set-option -p -t %3 @rcs_pane_instance_id rcs-pane-scope/);
2768
- });
2769
- }
2770
- finally {
2771
- if (typeof prevTmux === 'string')
2772
- process.env.TMUX = prevTmux;
2773
- else
2774
- delete process.env.TMUX;
2775
- if (typeof prevTmuxPane === 'string')
2776
- process.env.TMUX_PANE = prevTmuxPane;
2777
- else
2778
- delete process.env.TMUX_PANE;
2779
- if (typeof prevSessionId === 'string')
2780
- process.env.RCS_SESSION_ID = prevSessionId;
2781
- else
2782
- delete process.env.RCS_SESSION_ID;
2783
- if (typeof prevWorkerCli === 'string')
2784
- process.env.RCS_TEAM_WORKER_CLI = prevWorkerCli;
2785
- else
2786
- delete process.env.RCS_TEAM_WORKER_CLI;
2787
- await rm(cwd, { recursive: true, force: true });
2788
- }
2789
- });
2790
- });
2791
- describe('native Windows HUD reconciliation', () => {
2792
- it('allows team startup on native Windows when current tmux client is reachable without TMUX env vars', async () => {
2793
- const cwd = await mkdtemp(join(tmpdir(), 'rcs-team-win32-no-env-'));
2794
- const prevTmux = process.env.TMUX;
2795
- const prevTmuxPane = process.env.TMUX_PANE;
2796
- const prevWorkerCli = process.env.RCS_TEAM_WORKER_CLI;
2797
- const prevMsystem = process.env.MSYSTEM;
2798
- const prevOstype = process.env.OSTYPE;
2799
- const prevWsl = process.env.WSL_DISTRO_NAME;
2800
- const prevWslInterop = process.env.WSL_INTEROP;
2801
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
2802
- try {
2803
- await withMockTmuxFixture('rcs-tmux-win32-no-env-', (logPath) => `#!/bin/sh
2804
- set -eu
2805
- printf '%s\\n' "$*" >> "${logPath}"
2806
- case "\${1:-}" in
2807
- -V)
2808
- echo "tmux 3.4"
2809
- exit 0
2810
- ;;
2811
- display-message)
2812
- case "$*" in
2813
- *"#{window_width}"*)
2814
- echo "120"
2815
- ;;
2816
- *)
2817
- echo "leader:0 %1"
2818
- ;;
2819
- esac
2820
- exit 0
2821
- ;;
2822
- list-panes)
2823
- case "$*" in
2824
- *"pane_current_command"*)
2825
- printf "%%1\\tnode\\t'codex'\\n%%2\\tgemini\\t'gemini'\\n%%3\\tnode\\t'node rcs hud --watch'\\n"
2826
- ;;
2827
- *)
2828
- printf "%%1\\n%%2\\n%%3\\n"
2829
- ;;
2830
- esac
2831
- exit 0
2832
- ;;
2833
- split-window)
2834
- case "$*" in
2835
- *" -h "*)
2836
- echo "%2"
2837
- ;;
2838
- *)
2839
- echo "%3"
2840
- ;;
2841
- esac
2842
- exit 0
2843
- ;;
2844
- resize-pane|select-layout|set-window-option|select-pane|kill-pane|set-hook|run-shell)
2845
- exit 0
2846
- ;;
2847
- *)
2848
- exit 0
2849
- ;;
2850
- esac
2851
- `, async ({ logPath }) => {
2852
- const fakeBinDir = join(logPath, '..');
2853
- const geminiPath = join(fakeBinDir, 'gemini');
2854
- await writeFile(geminiPath, '#!/bin/sh\nexit 0\n');
2855
- await chmod(geminiPath, 0o755);
2856
- delete process.env.TMUX;
2857
- delete process.env.TMUX_PANE;
2858
- process.env.RCS_TEAM_WORKER_CLI = 'gemini';
2859
- delete process.env.MSYSTEM;
2860
- delete process.env.OSTYPE;
2861
- delete process.env.WSL_DISTRO_NAME;
2862
- delete process.env.WSL_INTEROP;
2863
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
2864
- const session = createTeamSession('Windows Team', 1, cwd);
2865
- assert.equal(session.name, 'leader:0');
2866
- assert.equal(session.leaderPaneId, '%1');
2867
- assert.equal(session.hudPaneId, '%3');
2868
- const tmuxLog = await readFile(logPath, 'utf-8');
2869
- assert.match(tmuxLog, /display-message -p #S:#I #{pane_id}/);
2870
- assert.match(tmuxLog, /powershell\.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -EncodedCommand/);
2871
- assert.doesNotMatch(tmuxLog, /\/bin\/sh -lc/);
2872
- assert.match(tmuxLog, new RegExp(`resize-pane -t %3 -y ${HUD_TMUX_TEAM_HEIGHT_LINES}`));
2873
- });
2874
- }
2875
- finally {
2876
- if (origPlatform)
2877
- Object.defineProperty(process, 'platform', origPlatform);
2878
- if (typeof prevTmux === 'string')
2879
- process.env.TMUX = prevTmux;
2880
- else
2881
- delete process.env.TMUX;
2882
- if (typeof prevTmuxPane === 'string')
2883
- process.env.TMUX_PANE = prevTmuxPane;
2884
- else
2885
- delete process.env.TMUX_PANE;
2886
- if (typeof prevWorkerCli === 'string')
2887
- process.env.RCS_TEAM_WORKER_CLI = prevWorkerCli;
2888
- else
2889
- delete process.env.RCS_TEAM_WORKER_CLI;
2890
- if (typeof prevMsystem === 'string')
2891
- process.env.MSYSTEM = prevMsystem;
2892
- else
2893
- delete process.env.MSYSTEM;
2894
- if (typeof prevOstype === 'string')
2895
- process.env.OSTYPE = prevOstype;
2896
- else
2897
- delete process.env.OSTYPE;
2898
- if (typeof prevWsl === 'string')
2899
- process.env.WSL_DISTRO_NAME = prevWsl;
2900
- else
2901
- delete process.env.WSL_DISTRO_NAME;
2902
- if (typeof prevWslInterop === 'string')
2903
- process.env.WSL_INTEROP = prevWslInterop;
2904
- else
2905
- delete process.env.WSL_INTEROP;
2906
- await rm(cwd, { recursive: true, force: true });
2907
- }
2908
- });
2909
- it('avoids nested tmux run-shell hooks during team HUD startup on native Windows', async () => {
2910
- const cwd = await mkdtemp(join(tmpdir(), 'rcs-team-win32-hud-'));
2911
- const prevTmux = process.env.TMUX;
2912
- const prevTmuxPane = process.env.TMUX_PANE;
2913
- const prevWorkerCli = process.env.RCS_TEAM_WORKER_CLI;
2914
- const prevMsystem = process.env.MSYSTEM;
2915
- const prevOstype = process.env.OSTYPE;
2916
- const prevWsl = process.env.WSL_DISTRO_NAME;
2917
- const prevWslInterop = process.env.WSL_INTEROP;
2918
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
2919
- try {
2920
- await withMockTmuxFixture('rcs-tmux-win32-hud-reconcile-', (logPath) => `#!/bin/sh
2921
- set -eu
2922
- printf '%s\\n' "$*" >> "${logPath}"
2923
- case "\${1:-}" in
2924
- -V)
2925
- echo "tmux 3.4"
2926
- exit 0
2927
- ;;
2928
- display-message)
2929
- case "$*" in
2930
- *"#{window_width}"*)
2931
- echo "120"
2932
- ;;
2933
- *)
2934
- echo "leader:0 %1"
2935
- ;;
2936
- esac
2937
- exit 0
2938
- ;;
2939
- list-panes)
2940
- case "$*" in
2941
- *"pane_current_command"*)
2942
- printf "%%1\\tnode\\t'codex'\\n%%2\\tgemini\\t'gemini'\\n%%3\\tnode\\t'node rcs hud --watch'\\n"
2943
- ;;
2944
- *)
2945
- printf "%%1\\n%%2\\n%%3\\n"
2946
- ;;
2947
- esac
2948
- exit 0
2949
- ;;
2950
- split-window)
2951
- case "$*" in
2952
- *" -h "*)
2953
- echo "%2"
2954
- ;;
2955
- *)
2956
- echo "%3"
2957
- ;;
2958
- esac
2959
- exit 0
2960
- ;;
2961
- resize-pane|select-layout|set-window-option|select-pane|kill-pane)
2962
- exit 0
2963
- ;;
2964
- set-hook|run-shell)
2965
- exit 0
2966
- ;;
2967
- *)
2968
- exit 0
2969
- ;;
2970
- esac
2971
- `, async ({ logPath }) => {
2972
- const fakeBinDir = join(logPath, '..');
2973
- const geminiPath = join(fakeBinDir, 'gemini');
2974
- await writeFile(geminiPath, '#!/bin/sh\nexit 0\n');
2975
- await chmod(geminiPath, 0o755);
2976
- process.env.TMUX = 'leader-session,stub,0';
2977
- process.env.TMUX_PANE = '%1';
2978
- process.env.RCS_TEAM_WORKER_CLI = 'gemini';
2979
- delete process.env.MSYSTEM;
2980
- delete process.env.OSTYPE;
2981
- delete process.env.WSL_DISTRO_NAME;
2982
- delete process.env.WSL_INTEROP;
2983
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
2984
- const session = createTeamSession('Windows Team', 1, cwd);
2985
- assert.equal(session.hudPaneId, '%3');
2986
- assert.equal(session.resizeHookName, null);
2987
- assert.equal(session.resizeHookTarget, null);
2988
- const tmuxLog = await readFile(logPath, 'utf-8');
2989
- assert.match(tmuxLog, new RegExp(`resize-pane -t %3 -y ${HUD_TMUX_TEAM_HEIGHT_LINES}`));
2990
- assert.doesNotMatch(tmuxLog, /set-hook -t leader:0 client-resized\[\d+\]/);
2991
- assert.doesNotMatch(tmuxLog, /set-hook -t leader:0 client-attached\[\d+\]/);
2992
- assert.doesNotMatch(tmuxLog, /run-shell -b sleep \d+; tmux resize-pane -t %3 -y \d+ >/);
2993
- assert.doesNotMatch(tmuxLog, /run-shell tmux resize-pane -t %3 -y \d+ >/);
2994
- });
2995
- }
2996
- finally {
2997
- if (origPlatform)
2998
- Object.defineProperty(process, 'platform', origPlatform);
2999
- if (typeof prevTmux === 'string')
3000
- process.env.TMUX = prevTmux;
3001
- else
3002
- delete process.env.TMUX;
3003
- if (typeof prevTmuxPane === 'string')
3004
- process.env.TMUX_PANE = prevTmuxPane;
3005
- else
3006
- delete process.env.TMUX_PANE;
3007
- if (typeof prevWorkerCli === 'string')
3008
- process.env.RCS_TEAM_WORKER_CLI = prevWorkerCli;
3009
- else
3010
- delete process.env.RCS_TEAM_WORKER_CLI;
3011
- if (typeof prevMsystem === 'string')
3012
- process.env.MSYSTEM = prevMsystem;
3013
- else
3014
- delete process.env.MSYSTEM;
3015
- if (typeof prevOstype === 'string')
3016
- process.env.OSTYPE = prevOstype;
3017
- else
3018
- delete process.env.OSTYPE;
3019
- if (typeof prevWsl === 'string')
3020
- process.env.WSL_DISTRO_NAME = prevWsl;
3021
- else
3022
- delete process.env.WSL_DISTRO_NAME;
3023
- if (typeof prevWslInterop === 'string')
3024
- process.env.WSL_INTEROP = prevWslInterop;
3025
- else
3026
- delete process.env.WSL_INTEROP;
3027
- await rm(cwd, { recursive: true, force: true });
3028
- }
3029
- });
3030
- it('rejects synthetic worker and HUD pane ids that never materialize on native Windows', async () => {
3031
- const cwd = await mkdtemp(join(tmpdir(), 'rcs-team-win32-synthetic-pane-'));
3032
- const prevTmux = process.env.TMUX;
3033
- const prevTmuxPane = process.env.TMUX_PANE;
3034
- const prevWorkerCli = process.env.RCS_TEAM_WORKER_CLI;
3035
- const prevMsystem = process.env.MSYSTEM;
3036
- const prevOstype = process.env.OSTYPE;
3037
- const prevWsl = process.env.WSL_DISTRO_NAME;
3038
- const prevWslInterop = process.env.WSL_INTEROP;
3039
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
3040
- try {
3041
- await withMockTmuxFixture('rcs-tmux-win32-synthetic-pane-', (logPath) => `#!/bin/sh
3042
- set -eu
3043
- printf '%s\\n' "$*" >> "${logPath}"
3044
- case "\${1:-}" in
3045
- -V)
3046
- echo "tmux 3.3.2"
3047
- exit 0
3048
- ;;
3049
- display-message)
3050
- case "$*" in
3051
- *"#{window_width}"*)
3052
- echo "120"
3053
- ;;
3054
- *)
3055
- echo "leader:0 %1"
3056
- ;;
3057
- esac
3058
- exit 0
3059
- ;;
3060
- list-panes)
3061
- case "$*" in
3062
- *"pane_current_command"*)
3063
- printf "%%1\\tnode\\t'codex'\\n"
3064
- ;;
3065
- *)
3066
- printf "%%1\\n"
3067
- ;;
3068
- esac
3069
- exit 0
3070
- ;;
3071
- split-window)
3072
- case "$*" in
3073
- *" -h "*)
3074
- echo "%2"
3075
- ;;
3076
- *)
3077
- echo "%3"
3078
- ;;
3079
- esac
3080
- exit 0
3081
- ;;
3082
- kill-pane|select-layout|set-window-option|select-pane|resize-pane|set-hook|run-shell)
3083
- exit 0
3084
- ;;
3085
- *)
3086
- exit 0
3087
- ;;
3088
- esac
3089
- `, async ({ logPath }) => {
3090
- const fakeBinDir = join(logPath, '..');
3091
- const geminiPath = join(fakeBinDir, 'gemini');
3092
- const powershellExePath = join(fakeBinDir, 'powershell.exe');
3093
- await writeFile(geminiPath, '#!/bin/sh\nexit 0\n');
3094
- await chmod(geminiPath, 0o755);
3095
- await writeFile(powershellExePath, '');
3096
- process.env.TMUX = 'leader-session,stub,0';
3097
- process.env.TMUX_PANE = '%1';
3098
- process.env.RCS_TEAM_WORKER_CLI = 'gemini';
3099
- delete process.env.MSYSTEM;
3100
- delete process.env.OSTYPE;
3101
- delete process.env.WSL_DISTRO_NAME;
3102
- delete process.env.WSL_INTEROP;
3103
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
3104
- assert.throws(() => createTeamSession('Windows Team', 1, cwd), /worker pane 1 did not remain present/);
3105
- const tmuxLog = await readFile(logPath, 'utf-8');
3106
- const listPaneCalls = tmuxLog.match(/list-panes -t leader:0 -F #\{pane_id\}\t#\{pane_current_command\}\t#\{pane_start_command\}/g) || [];
3107
- assert.ok(listPaneCalls.length >= 2, tmuxLog);
3108
- assert.match(tmuxLog, /kill-pane -t %2/);
3109
- });
3110
- }
3111
- finally {
3112
- if (origPlatform)
3113
- Object.defineProperty(process, 'platform', origPlatform);
3114
- if (typeof prevTmux === 'string')
3115
- process.env.TMUX = prevTmux;
3116
- else
3117
- delete process.env.TMUX;
3118
- if (typeof prevTmuxPane === 'string')
3119
- process.env.TMUX_PANE = prevTmuxPane;
3120
- else
3121
- delete process.env.TMUX_PANE;
3122
- if (typeof prevWorkerCli === 'string')
3123
- process.env.RCS_TEAM_WORKER_CLI = prevWorkerCli;
3124
- else
3125
- delete process.env.RCS_TEAM_WORKER_CLI;
3126
- if (typeof prevMsystem === 'string')
3127
- process.env.MSYSTEM = prevMsystem;
3128
- else
3129
- delete process.env.MSYSTEM;
3130
- if (typeof prevOstype === 'string')
3131
- process.env.OSTYPE = prevOstype;
3132
- else
3133
- delete process.env.OSTYPE;
3134
- if (typeof prevWsl === 'string')
3135
- process.env.WSL_DISTRO_NAME = prevWsl;
3136
- else
3137
- delete process.env.WSL_DISTRO_NAME;
3138
- if (typeof prevWslInterop === 'string')
3139
- process.env.WSL_INTEROP = prevWslInterop;
3140
- else
3141
- delete process.env.WSL_INTEROP;
3142
- await rm(cwd, { recursive: true, force: true });
3143
- }
3144
- });
3145
- it('restores standalone HUD panes with direct resize on native Windows', async () => {
3146
- const cwd = await mkdtemp(join(tmpdir(), 'rcs-standalone-win32-hud-'));
3147
- const prevLeaderNodePath = process.env.RCS_LEADER_NODE_PATH;
3148
- const prevMsystem = process.env.MSYSTEM;
3149
- const prevOstype = process.env.OSTYPE;
3150
- const prevWsl = process.env.WSL_DISTRO_NAME;
3151
- const prevWslInterop = process.env.WSL_INTEROP;
3152
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
3153
- try {
3154
- await withMockTmuxFixture('rcs-tmux-win32-standalone-hud-', (logPath) => `#!/bin/sh
3155
- set -eu
3156
- printf '%s\\n' "$*" >> "${logPath}"
3157
- case "\${1:-}" in
3158
- split-window)
3159
- echo "%44"
3160
- exit 0
3161
- ;;
3162
- resize-pane|select-pane)
3163
- exit 0
3164
- ;;
3165
- set-hook|run-shell)
3166
- exit 0
3167
- ;;
3168
- *)
3169
- exit 0
3170
- ;;
3171
- esac
3172
- `, async ({ logPath }) => {
3173
- delete process.env.MSYSTEM;
3174
- delete process.env.OSTYPE;
3175
- delete process.env.WSL_DISTRO_NAME;
3176
- delete process.env.WSL_INTEROP;
3177
- process.env.RCS_LEADER_NODE_PATH = 'C:\\Program Files\\nodejs\\node.exe';
3178
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
3179
- const paneId = restoreStandaloneHudPane('%11', cwd);
3180
- assert.equal(paneId, '%44');
3181
- const tmuxLog = await readFile(logPath, 'utf-8');
3182
- assert.match(tmuxLog, /'C:\\Program Files\\nodejs\\node\.exe'/);
3183
- assert.match(tmuxLog, new RegExp(`resize-pane -t %44 -y ${HUD_TMUX_TEAM_HEIGHT_LINES}`));
3184
- assert.match(tmuxLog, /select-pane -t %11/);
3185
- assert.doesNotMatch(tmuxLog, /run-shell -b sleep \d+; tmux resize-pane -t %44 -y \d+ >/);
3186
- assert.doesNotMatch(tmuxLog, /run-shell tmux resize-pane -t %44 -y \d+ >/);
3187
- assert.doesNotMatch(tmuxLog, /set-hook -t /);
3188
- });
3189
- }
3190
- finally {
3191
- if (origPlatform)
3192
- Object.defineProperty(process, 'platform', origPlatform);
3193
- if (typeof prevLeaderNodePath === 'string')
3194
- process.env.RCS_LEADER_NODE_PATH = prevLeaderNodePath;
3195
- else
3196
- delete process.env.RCS_LEADER_NODE_PATH;
3197
- if (typeof prevMsystem === 'string')
3198
- process.env.MSYSTEM = prevMsystem;
3199
- else
3200
- delete process.env.MSYSTEM;
3201
- if (typeof prevOstype === 'string')
3202
- process.env.OSTYPE = prevOstype;
3203
- else
3204
- delete process.env.OSTYPE;
3205
- if (typeof prevWsl === 'string')
3206
- process.env.WSL_DISTRO_NAME = prevWsl;
3207
- else
3208
- delete process.env.WSL_DISTRO_NAME;
3209
- if (typeof prevWslInterop === 'string')
3210
- process.env.WSL_INTEROP = prevWslInterop;
3211
- else
3212
- delete process.env.WSL_INTEROP;
3213
- await rm(cwd, { recursive: true, force: true });
3214
- }
3215
- });
3216
- it('restores standalone HUD panes with an absolute RCS entry path after cwd drift', async () => {
3217
- const cwd = await mkdtemp(join(tmpdir(), 'rcs-standalone-relative-hud-'));
3218
- const startupCwd = await mkdtemp(join(tmpdir(), 'rcs-standalone-relative-start-'));
3219
- const previousEntryPath = process.env[RCS_ENTRY_PATH_ENV];
3220
- const previousStartupCwd = process.env[RCS_STARTUP_CWD_ENV];
3221
- const previousArgv = process.argv;
3222
- try {
3223
- const launcherDir = join(startupCwd, 'dist', 'cli');
3224
- const launcherPath = join(launcherDir, 'rcs.js');
3225
- await mkdir(launcherDir, { recursive: true });
3226
- await writeFile(launcherPath, '#!/usr/bin/env node\n');
3227
- await withMockTmuxFixture('rcs-tmux-relative-standalone-hud-', (logPath) => `#!/bin/sh
3228
- set -eu
3229
- printf '%s\\n' "$*" >> "${logPath}"
3230
- case "\${1:-}" in
3231
- split-window)
3232
- echo "%44"
3233
- exit 0
3234
- ;;
3235
- run-shell|select-pane|resize-pane|set-hook)
3236
- exit 0
3237
- ;;
3238
- *)
3239
- exit 0
3240
- ;;
3241
- esac
3242
- `, async ({ logPath }) => {
3243
- delete process.env[RCS_ENTRY_PATH_ENV];
3244
- process.env[RCS_STARTUP_CWD_ENV] = startupCwd;
3245
- process.argv = [previousArgv[0] || 'node', 'dist/cli/rcs.js'];
3246
- const paneId = restoreStandaloneHudPane('%11', cwd);
3247
- assert.equal(paneId, '%44');
3248
- const tmuxLog = await readFile(logPath, 'utf-8');
3249
- assert.match(tmuxLog, new RegExp(escapeRegExp(launcherPath)));
3250
- assert.doesNotMatch(tmuxLog, /'dist\/cli\/rcs\.js' hud --watch/);
3251
- });
3252
- }
3253
- finally {
3254
- process.argv = previousArgv;
3255
- if (typeof previousEntryPath === 'string')
3256
- process.env[RCS_ENTRY_PATH_ENV] = previousEntryPath;
3257
- else
3258
- delete process.env[RCS_ENTRY_PATH_ENV];
3259
- if (typeof previousStartupCwd === 'string')
3260
- process.env[RCS_STARTUP_CWD_ENV] = previousStartupCwd;
3261
- else
3262
- delete process.env[RCS_STARTUP_CWD_ENV];
3263
- await rm(cwd, { recursive: true, force: true });
3264
- await rm(startupCwd, { recursive: true, force: true });
3265
- }
3266
- });
3267
- it('restores standalone HUD panes with the packaged CLI entry when argv1 is not the RCS CLI', async () => {
3268
- const cwd = await mkdtemp(join(tmpdir(), 'rcs-standalone-noncli-hud-'));
3269
- const previousArgv = process.argv;
3270
- try {
3271
- await withMockTmuxFixture('rcs-tmux-noncli-standalone-hud-', (logPath) => `#!/bin/sh
3272
- set -eu
3273
- printf '%s\\n' "$*" >> "${logPath}"
3274
- case "\${1:-}" in
3275
- split-window)
3276
- echo "%44"
3277
- exit 0
3278
- ;;
3279
- run-shell|select-pane|resize-pane|set-hook)
3280
- exit 0
3281
- ;;
3282
- *)
3283
- exit 0
3284
- ;;
3285
- esac
3286
- `, async ({ logPath }) => {
3287
- process.argv = [previousArgv[0] || 'node', '/tmp/codex-host-binary'];
3288
- const paneId = restoreStandaloneHudPane('%11', cwd);
3289
- assert.equal(paneId, '%44');
3290
- const tmuxLog = await readFile(logPath, 'utf-8');
3291
- assert.match(tmuxLog, /dist\/cli\/rcs\.js' hud --watch/);
3292
- assert.doesNotMatch(tmuxLog, /\/tmp\/codex-host-binary' hud --watch/);
3293
- });
3294
- }
3295
- finally {
3296
- process.argv = previousArgv;
3297
- await rm(cwd, { recursive: true, force: true });
3298
- }
3299
- });
3300
- });
3301
- describe('dismissTrustPromptIfPresent capture shape', () => {
3302
- it('uses visible capture-pane argv without tail flags', async () => {
3303
- const previousAutoTrust = process.env.RCS_TEAM_AUTO_TRUST;
3304
- delete process.env.RCS_TEAM_AUTO_TRUST;
3305
- try {
3306
- await withMockTmuxFixture('rcs-tmux-dismiss-trust-visible-capture-', (logPath) => `#!/bin/sh
3307
- set -eu
3308
- printf '%s\n' "$*" >> "${logPath}"
3309
- case "$1" in
3310
- capture-pane)
3311
- cat <<'EOF'
3312
- Do you trust the contents of this directory?
3313
- Press enter to continue
3314
- EOF
3315
- exit 0
3316
- ;;
3317
- send-keys)
3318
- exit 0
3319
- ;;
3320
- *)
3321
- exit 0
3322
- ;;
3323
- esac
3324
- `, async ({ logPath }) => {
3325
- assert.equal(dismissTrustPromptIfPresent('rcs-team-x', 1), true);
3326
- const log = await readFile(logPath, 'utf-8');
3327
- assert.match(log, /capture-pane -t rcs-team-x:1 -p/);
3328
- assert.doesNotMatch(log, /capture-pane -t rcs-team-x:1 -p -S/);
3329
- });
3330
- }
3331
- finally {
3332
- if (typeof previousAutoTrust === 'string')
3333
- process.env.RCS_TEAM_AUTO_TRUST = previousAutoTrust;
3334
- else
3335
- delete process.env.RCS_TEAM_AUTO_TRUST;
3336
- }
3337
- });
3338
- });
3339
- describe('dismissTrustPromptIfPresent', () => {
3340
- it('returns false when tmux is unavailable', () => {
3341
- withEmptyPath(() => {
3342
- assert.equal(dismissTrustPromptIfPresent('rcs-team-x', 1), false);
3343
- });
3344
- });
3345
- it('returns false when RCS_TEAM_AUTO_TRUST is disabled', () => {
3346
- const prev = process.env.RCS_TEAM_AUTO_TRUST;
3347
- process.env.RCS_TEAM_AUTO_TRUST = '0';
3348
- try {
3349
- assert.equal(dismissTrustPromptIfPresent('rcs-team-x', 1), false);
3350
- }
3351
- finally {
3352
- if (typeof prev === 'string')
3353
- process.env.RCS_TEAM_AUTO_TRUST = prev;
3354
- else
3355
- delete process.env.RCS_TEAM_AUTO_TRUST;
3356
- }
3357
- });
3358
- it('returns false when RCS_TEAM_AUTO_TRUST is unset (auto-trust enabled) but tmux unavailable', () => {
3359
- const prev = process.env.RCS_TEAM_AUTO_TRUST;
3360
- delete process.env.RCS_TEAM_AUTO_TRUST;
3361
- try {
3362
- withEmptyPath(() => {
3363
- assert.equal(dismissTrustPromptIfPresent('rcs-team-x', 1), false);
3364
- });
3365
- }
3366
- finally {
3367
- if (typeof prev === 'string')
3368
- process.env.RCS_TEAM_AUTO_TRUST = prev;
3369
- }
3370
- });
3371
- });
3372
- describe('isWorkerAlive', () => {
3373
- it('does not require pane_current_command to match "codex"', () => {
3374
- // This was a real failure mode: tmux reports pane_current_command=node for the Codex TUI,
3375
- // which caused workers to be treated as dead and the leader to clean up state too early.
3376
- withEmptyPath(() => {
3377
- assert.equal(isWorkerAlive('rcs-team-x', 1), false);
3378
- });
3379
- });
3380
- });
3381
- describe('isWsl2', () => {
3382
- it('returns true when WSL_DISTRO_NAME is set', () => {
3383
- const prev = process.env.WSL_DISTRO_NAME;
3384
- process.env.WSL_DISTRO_NAME = 'Ubuntu-22.04';
3385
- try {
3386
- assert.equal(isWsl2(), true);
3387
- }
3388
- finally {
3389
- if (typeof prev === 'string')
3390
- process.env.WSL_DISTRO_NAME = prev;
3391
- else
3392
- delete process.env.WSL_DISTRO_NAME;
3393
- }
3394
- });
3395
- it('returns true when WSL_INTEROP is set and WSL_DISTRO_NAME is absent', () => {
3396
- const prevDistro = process.env.WSL_DISTRO_NAME;
3397
- const prevInterop = process.env.WSL_INTEROP;
3398
- delete process.env.WSL_DISTRO_NAME;
3399
- process.env.WSL_INTEROP = '/run/WSL/8_interop';
3400
- try {
3401
- assert.equal(isWsl2(), true);
3402
- }
3403
- finally {
3404
- if (typeof prevDistro === 'string')
3405
- process.env.WSL_DISTRO_NAME = prevDistro;
3406
- else
3407
- delete process.env.WSL_DISTRO_NAME;
3408
- if (typeof prevInterop === 'string')
3409
- process.env.WSL_INTEROP = prevInterop;
3410
- else
3411
- delete process.env.WSL_INTEROP;
3412
- }
3413
- });
3414
- it('returns a boolean without throwing when no WSL env vars are present', () => {
3415
- const prevDistro = process.env.WSL_DISTRO_NAME;
3416
- const prevInterop = process.env.WSL_INTEROP;
3417
- delete process.env.WSL_DISTRO_NAME;
3418
- delete process.env.WSL_INTEROP;
3419
- try {
3420
- assert.equal(typeof isWsl2(), 'boolean');
3421
- }
3422
- finally {
3423
- if (typeof prevDistro === 'string')
3424
- process.env.WSL_DISTRO_NAME = prevDistro;
3425
- else
3426
- delete process.env.WSL_DISTRO_NAME;
3427
- if (typeof prevInterop === 'string')
3428
- process.env.WSL_INTEROP = prevInterop;
3429
- else
3430
- delete process.env.WSL_INTEROP;
3431
- }
3432
- });
3433
- });
3434
- describe('isMsysOrGitBash', () => {
3435
- it('returns true on win32 when MSYSTEM is set', () => {
3436
- assert.equal(isMsysOrGitBash({ MSYSTEM: 'MINGW64' }, 'win32'), true);
3437
- });
3438
- it('returns true on win32 when OSTYPE indicates msys/mingw', () => {
3439
- assert.equal(isMsysOrGitBash({ OSTYPE: 'msys' }, 'win32'), true);
3440
- assert.equal(isMsysOrGitBash({ OSTYPE: 'mingw64' }, 'win32'), true);
3441
- });
3442
- it('returns false outside win32', () => {
3443
- assert.equal(isMsysOrGitBash({ MSYSTEM: 'MINGW64' }, 'linux'), false);
3444
- });
3445
- });
3446
- describe('translatePathForMsys', () => {
3447
- it('returns original path outside MSYS2/Git Bash', () => {
3448
- assert.equal(translatePathForMsys('C:\\repo\\AGENTS.md', {}, 'linux'), 'C:\\repo\\AGENTS.md');
3449
- });
3450
- it('uses cygpath translation when available', () => {
3451
- const translated = translatePathForMsys('C:\\repo\\AGENTS.md', { MSYSTEM: 'MINGW64' }, 'win32', () => ({ status: 0, stdout: '/c/repo/AGENTS.md\n', stderr: '', error: undefined, output: [] }));
3452
- assert.equal(translated, '/c/repo/AGENTS.md');
3453
- });
3454
- it('falls back gracefully when cygpath is unavailable', () => {
3455
- const translated = translatePathForMsys('C:\\repo\\AGENTS.md', { MSYSTEM: 'MINGW64' }, 'win32', () => ({ status: 1, stdout: '', stderr: 'not found', error: Object.assign(new Error('ENOENT'), { code: 'ENOENT' }), output: [] }));
3456
- assert.equal(translated, '/c/repo/AGENTS.md');
3457
- });
3458
- });
3459
- describe('isNativeWindows', () => {
3460
- it('returns true when process.platform is win32 and not WSL2', () => {
3461
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
3462
- const prevDistro = process.env.WSL_DISTRO_NAME;
3463
- const prevInterop = process.env.WSL_INTEROP;
3464
- delete process.env.WSL_DISTRO_NAME;
3465
- delete process.env.WSL_INTEROP;
3466
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
3467
- try {
3468
- assert.equal(isNativeWindows(), true);
3469
- }
3470
- finally {
3471
- if (origPlatform)
3472
- Object.defineProperty(process, 'platform', origPlatform);
3473
- if (typeof prevDistro === 'string')
3474
- process.env.WSL_DISTRO_NAME = prevDistro;
3475
- else
3476
- delete process.env.WSL_DISTRO_NAME;
3477
- if (typeof prevInterop === 'string')
3478
- process.env.WSL_INTEROP = prevInterop;
3479
- else
3480
- delete process.env.WSL_INTEROP;
3481
- }
3482
- });
3483
- it('returns false when process.platform is win32 but WSL2 is detected', () => {
3484
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
3485
- const prevDistro = process.env.WSL_DISTRO_NAME;
3486
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
3487
- process.env.WSL_DISTRO_NAME = 'Ubuntu-22.04';
3488
- try {
3489
- assert.equal(isNativeWindows(), false);
3490
- }
3491
- finally {
3492
- if (origPlatform)
3493
- Object.defineProperty(process, 'platform', origPlatform);
3494
- if (typeof prevDistro === 'string')
3495
- process.env.WSL_DISTRO_NAME = prevDistro;
3496
- else
3497
- delete process.env.WSL_DISTRO_NAME;
3498
- }
3499
- });
3500
- it('returns false on win32 when MSYS2/Git Bash is detected', () => {
3501
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
3502
- const prevMsystem = process.env.MSYSTEM;
3503
- Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
3504
- process.env.MSYSTEM = 'MINGW64';
3505
- try {
3506
- assert.equal(isNativeWindows(), false);
3507
- }
3508
- finally {
3509
- if (origPlatform)
3510
- Object.defineProperty(process, 'platform', origPlatform);
3511
- if (typeof prevMsystem === 'string')
3512
- process.env.MSYSTEM = prevMsystem;
3513
- else
3514
- delete process.env.MSYSTEM;
3515
- }
3516
- });
3517
- it('returns false on Linux', () => {
3518
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
3519
- Object.defineProperty(process, 'platform', { value: 'linux', configurable: true });
3520
- try {
3521
- assert.equal(isNativeWindows(), false);
3522
- }
3523
- finally {
3524
- if (origPlatform)
3525
- Object.defineProperty(process, 'platform', origPlatform);
3526
- }
3527
- });
3528
- it('returns false on macOS', () => {
3529
- const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
3530
- Object.defineProperty(process, 'platform', { value: 'darwin', configurable: true });
3531
- try {
3532
- assert.equal(isNativeWindows(), false);
3533
- }
3534
- finally {
3535
- if (origPlatform)
3536
- Object.defineProperty(process, 'platform', origPlatform);
3537
- }
3538
- });
3539
- });
3540
- describe('enableMouseScrolling', () => {
3541
- it('returns false when tmux is unavailable', () => {
3542
- // When tmux is not on PATH, enableMouseScrolling should gracefully return false
3543
- // rather than throwing, so callers do not need to guard against errors.
3544
- withEmptyPath(() => {
3545
- assert.equal(enableMouseScrolling('rcs-team-x'), false);
3546
- });
3547
- });
3548
- it('returns false for empty session target when tmux unavailable', () => {
3549
- withEmptyPath(() => {
3550
- assert.equal(enableMouseScrolling(''), false);
3551
- });
3552
- });
3553
- it('returns false in WSL2 environment when tmux is unavailable', () => {
3554
- // WSL2 path: even with the XT override branch active, the function must
3555
- // return false (not throw) when tmux is not on PATH.
3556
- const prev = process.env.WSL_DISTRO_NAME;
3557
- process.env.WSL_DISTRO_NAME = 'Ubuntu-22.04';
3558
- try {
3559
- withEmptyPath(() => {
3560
- assert.equal(enableMouseScrolling('rcs-team-x'), false);
3561
- });
3562
- }
3563
- finally {
3564
- if (typeof prev === 'string')
3565
- process.env.WSL_DISTRO_NAME = prev;
3566
- else
3567
- delete process.env.WSL_DISTRO_NAME;
3568
- }
3569
- });
3570
- });
3571
- describe('killWorkerByPaneId leader pane guard', () => {
3572
- it('skips kill when workerPaneId matches leaderPaneId (guard fires before tmux is called)', () => {
3573
- // With empty PATH tmux is unavailable, so any actual kill-pane call would fail.
3574
- // When the guard fires (paneId === leaderPaneId) the function returns early
3575
- // without invoking tmux, so no error is thrown regardless of PATH.
3576
- withEmptyPath(() => {
3577
- assert.doesNotThrow(() => killWorkerByPaneId('%5', '%5'));
3578
- });
3579
- });
3580
- it('does not skip kill when pane ids differ (falls through to tmux attempt)', () => {
3581
- // Different IDs: guard does not fire. tmux is unavailable but kill errors are swallowed internally.
3582
- withEmptyPath(() => {
3583
- assert.doesNotThrow(() => killWorkerByPaneId('%5', '%6'));
3584
- });
3585
- });
3586
- it('skips kill for non-percent pane id without reaching tmux', () => {
3587
- withEmptyPath(() => {
3588
- assert.doesNotThrow(() => killWorkerByPaneId('invalid', '%5'));
3589
- });
3590
- });
3591
- it('skips kill when no leaderPaneId provided and pane id is valid percent id', () => {
3592
- // Without leaderPaneId the guard is not active; tmux call fails gracefully.
3593
- withEmptyPath(() => {
3594
- assert.doesNotThrow(() => killWorkerByPaneId('%5'));
3595
- });
3596
- });
3597
- });
3598
- describe('sleepFractionalSeconds', () => {
3599
- it('uses ceil(ms) so sub-millisecond positive values still sleep', () => {
3600
- const calls = [];
3601
- const captureSleep = (ms) => {
3602
- calls.push(ms);
3603
- };
3604
- sleepFractionalSeconds(0.1, captureSleep);
3605
- sleepFractionalSeconds(0.0001, captureSleep);
3606
- assert.deepEqual(calls, [100, 1]);
3607
- });
3608
- it('ignores invalid values and clamps extreme sleeps to 60s max', () => {
3609
- const calls = [];
3610
- const captureSleep = (ms) => {
3611
- calls.push(ms);
3612
- };
3613
- sleepFractionalSeconds(0, captureSleep);
3614
- sleepFractionalSeconds(-1, captureSleep);
3615
- sleepFractionalSeconds(NaN, captureSleep);
3616
- sleepFractionalSeconds(Number.POSITIVE_INFINITY, captureSleep);
3617
- sleepFractionalSeconds(999_999, captureSleep);
3618
- assert.deepEqual(calls, [60_000]);
3619
- });
3620
- });
3621
- describe('enableMouseScrolling scroll and copy setup (issue #206)', () => {
3622
- it('returns false gracefully when scroll-copy setup fails because tmux is unavailable', () => {
3623
- // With empty PATH the initial "mouse on" call fails, so the function returns
3624
- // false before any binding calls are made. No throw must occur.
3625
- withEmptyPath(() => {
3626
- assert.equal(enableMouseScrolling('rcs-team-x'), false);
3627
- });
3628
- });
3629
- it('does not throw when WSL2 env is set and tmux is unavailable (regression + #206)', () => {
3630
- const prev = process.env.WSL_DISTRO_NAME;
3631
- process.env.WSL_DISTRO_NAME = 'Ubuntu-22.04';
3632
- try {
3633
- withEmptyPath(() => {
3634
- assert.doesNotThrow(() => enableMouseScrolling('rcs-team-x'));
3635
- });
3636
- }
3637
- finally {
3638
- if (typeof prev === 'string')
3639
- process.env.WSL_DISTRO_NAME = prev;
3640
- else
3641
- delete process.env.WSL_DISTRO_NAME;
3642
- }
3643
- });
3644
- });
3645
- describe('enableMouseScrolling session scoping (issue #817)', () => {
3646
- it('only applies session-scoped tmux options and does not mutate global bindings or terminal-overrides', async () => {
3647
- await withMockTmuxFixture('rcs-tmux-enable-mouse-scope-', (tmuxLogPath) => `#!/bin/sh
3648
- printf '%s\n' "$*" >> "${tmuxLogPath}"
3649
- case "$1" in
3650
- show-options)
3651
- if [ "$2" = "-gv" ] && [ "$3" = "-t" ] && [ "$4" = "rcs-team-x" ] && [ "$5" = "mode-style" ]; then
3652
- printf '%s\n' 'bg=yellow,fg=black,underscore'
3653
- exit 0
3654
- fi
3655
- exit 1
3656
- ;;
3657
- set-option)
3658
- if [ "$2" = "-t" ]; then
3659
- exit 0
3660
- fi
3661
- exit 1
3662
- ;;
3663
- *)
3664
- exit 0
3665
- ;;
3666
- esac
3667
- `, async ({ logPath }) => {
3668
- assert.equal(enableMouseScrolling('rcs-team-x'), true);
3669
- const tmuxLog = await readFile(logPath, 'utf-8');
3670
- assert.match(tmuxLog, /set-option -t rcs-team-x mouse on/);
3671
- assert.match(tmuxLog, /set-option -t rcs-team-x set-clipboard on/);
3672
- assert.match(tmuxLog, /set-option -t rcs-team-x mode-style bg=yellow,fg=black,underscore,nounderscore,nodouble-underscore,nocurly-underscore,nodotted-underscore,nodashed-underscore/);
3673
- assert.doesNotMatch(tmuxLog, /bind-key/);
3674
- assert.doesNotMatch(tmuxLog, /terminal-overrides/);
3675
- });
3676
- });
3677
- });
3678
- describe('mitigateCopyModeUnderlineArtifacts', () => {
3679
- it('best-effort sanitizes copy-mode style options without requiring global tmux changes', async () => {
3680
- await withMockTmuxFixture('rcs-tmux-sanitize-copy-style-', (tmuxLogPath) => `#!/bin/sh
3681
- printf '%s\n' "$*" >> "${tmuxLogPath}"
3682
- case "$1" in
3683
- show-options)
3684
- if [ "$2" = "-gv" ] && [ "$3" = "-t" ] && [ "$4" = "rcs-team-x" ] && [ "$5" = "mode-style" ]; then
3685
- printf '%s\n' 'bg=yellow,fg=black,underscore'
3686
- exit 0
3687
- fi
3688
- if [ "$2" = "-gv" ] && [ "$3" = "-t" ] && [ "$4" = "rcs-team-x" ] && [ "$5" = "copy-mode-selection-style" ]; then
3689
- printf '%s\n' 'fg=white,bg=blue,curly-underscore'
3690
- exit 0
3691
- fi
3692
- exit 1
3693
- ;;
3694
- set-option)
3695
- if [ "$2" = "-t" ]; then
3696
- exit 0
3697
- fi
3698
- exit 1
3699
- ;;
3700
- *)
3701
- exit 0
3702
- ;;
3703
- esac
3704
- `, async ({ logPath }) => {
3705
- assert.equal(mitigateCopyModeUnderlineArtifacts('rcs-team-x'), true);
3706
- const tmuxLog = await readFile(logPath, 'utf-8');
3707
- assert.match(tmuxLog, /set-option -t rcs-team-x mode-style bg=yellow,fg=black,underscore,nounderscore,nodouble-underscore,nocurly-underscore,nodotted-underscore,nodashed-underscore/);
3708
- assert.match(tmuxLog, /set-option -t rcs-team-x copy-mode-selection-style fg=white,bg=blue,curly-underscore,nounderscore,nodouble-underscore,nocurly-underscore,nodotted-underscore,nodashed-underscore/);
3709
- assert.doesNotMatch(tmuxLog, /set-option -g/);
3710
- });
3711
- });
3712
- });
3713
- describe('killWorker leader pane guard', () => {
3714
- it('returns immediately when workerPaneId matches leaderPaneId', () => {
3715
- // Guard fires before any tmux send-keys call, so no error even with empty PATH.
3716
- withEmptyPath(() => {
3717
- assert.doesNotThrow(() => killWorker('rcs-team-x:0', 1, '%5', '%5'));
3718
- });
3719
- });
3720
- it('proceeds (gracefully) when pane ids differ', () => {
3721
- // Guard does not fire; tmux calls fail gracefully with empty PATH.
3722
- withEmptyPath(() => {
3723
- assert.doesNotThrow(() => killWorker('rcs-team-x:0', 1, '%5', '%6'));
3724
- });
3725
- });
3726
- it('proceeds when leaderPaneId is not provided', () => {
3727
- withEmptyPath(() => {
3728
- assert.doesNotThrow(() => killWorker('rcs-team-x:0', 1, '%5'));
3729
- });
3730
- });
3731
- });
3732
- describe('teardownWorkerPanes shared primitive', () => {
3733
- it('excludes leader and hud panes in shared pane-kill primitive', async () => {
3734
- await withMockTmuxFixture('rcs-tmux-teardown-', (logPath) => `#!/bin/sh
3735
- set -eu
3736
- printf '%s\\n' "$*" >> "${logPath}"
3737
- exit 0
3738
- `, async ({ logPath }) => {
3739
- const summary = await teardownWorkerPanes(['%1', '%2', '%3'], {
3740
- leaderPaneId: '%1',
3741
- hudPaneId: '%2',
3742
- graceMs: 1,
3743
- });
3744
- assert.equal(summary.excluded.leader, 1);
3745
- assert.equal(summary.excluded.hud, 1);
3746
- assert.equal(summary.kill.attempted, 1);
3747
- assert.equal(summary.kill.succeeded, 1);
3748
- const log = await readFile(logPath, 'utf-8');
3749
- assert.match(log, /kill-pane -t %3/);
3750
- assert.doesNotMatch(log, /kill-pane -t %1/);
3751
- assert.doesNotMatch(log, /kill-pane -t %2/);
3752
- });
3753
- });
3754
- it('uses pane-id-direct kill semantics without liveness-gated helper calls', async () => {
3755
- const source = await readFile(new URL('../tmux-session.js', import.meta.url), 'utf-8');
3756
- const primitiveBlock = source.split('export async function teardownWorkerPanes')[1] ?? '';
3757
- assert.equal(primitiveBlock.includes('isWorkerAlive'), false);
3758
- assert.equal(primitiveBlock.includes('killWorker('), false);
3759
- });
3760
- it('continues best-effort when a pane target is missing', async () => {
3761
- await withMockTmuxFixture('rcs-tmux-teardown-missing-', (logPath) => `#!/bin/sh
3762
- set -eu
3763
- printf '%s\\n' "$*" >> "${logPath}"
3764
- if [ "$1" = "kill-pane" ] && [ "\${3:-}" = "%404" ]; then
3765
- echo "missing pane" >&2
3766
- exit 1
3767
- fi
3768
- exit 0
3769
- `, async ({ logPath }) => {
3770
- const summary = await teardownWorkerPanes(['%404', '%405'], { graceMs: 1 });
3771
- assert.equal(summary.kill.attempted, 2);
3772
- assert.equal(summary.kill.succeeded, 1);
3773
- assert.equal(summary.kill.failed, 1);
3774
- const log = await readFile(logPath, 'utf-8');
3775
- assert.match(log, /kill-pane -t %404/);
3776
- assert.match(log, /kill-pane -t %405/);
3777
- });
3778
- });
3779
- });
3780
- describe('leader mailbox-only boundary', () => {
3781
- it('does not export direct leader pane injection helper', () => {
3782
- assert.equal('sendToLeaderPane' in tmuxSessionModule, false);
3783
- });
3784
- });
3785
- //# sourceMappingURL=tmux-session.test.js.map