@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.
- package/README.md +142 -102
- package/dist/agents/definitions.d.ts.map +1 -1
- package/dist/agents/definitions.js +0 -101
- package/dist/agents/definitions.js.map +1 -1
- package/dist/blueprint/runtime.d.ts +52 -0
- package/dist/blueprint/runtime.d.ts.map +1 -0
- package/dist/{ralplan → blueprint}/runtime.js +19 -19
- package/dist/blueprint/runtime.js.map +1 -0
- package/dist/catalog/reader.d.ts.map +1 -1
- package/dist/catalog/reader.js +8 -2
- package/dist/catalog/reader.js.map +1 -1
- package/dist/catalog/schema.js +1 -1
- package/dist/catalog/schema.js.map +1 -1
- package/dist/cli/forge.d.ts +17 -0
- package/dist/cli/{ralph.d.ts.map → forge.d.ts.map} +1 -1
- package/dist/cli/{ralph.js → forge.js} +82 -82
- package/dist/cli/{ralph.js.map → forge.js.map} +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +15 -15
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +2 -3
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/star-prompt.js +2 -2
- package/dist/cli/star-prompt.js.map +1 -1
- package/dist/cli/state.js +1 -1
- package/dist/cli/team.d.ts.map +1 -1
- package/dist/cli/team.js +3 -2
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/tmux-hook.d.ts.map +1 -1
- package/dist/cli/tmux-hook.js +9 -1
- package/dist/cli/tmux-hook.js.map +1 -1
- package/dist/config/generator.d.ts +1 -1
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +1 -1
- package/dist/config/generator.js.map +1 -1
- package/dist/forge/contract.d.ts +17 -0
- package/dist/{ralph → forge}/contract.d.ts.map +1 -1
- package/dist/{ralph → forge}/contract.js +16 -16
- package/dist/{ralph → forge}/contract.js.map +1 -1
- package/dist/{ralph → forge}/persistence.d.ts +5 -5
- package/dist/{ralph → forge}/persistence.d.ts.map +1 -1
- package/dist/{ralph → forge}/persistence.js +7 -6
- package/dist/forge/persistence.js.map +1 -0
- package/dist/hooks/agents-overlay.d.ts +1 -1
- package/dist/hooks/agents-overlay.d.ts.map +1 -1
- package/dist/hooks/agents-overlay.js +37 -31
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
- package/dist/hooks/extensibility/dispatcher.js +82 -14
- package/dist/hooks/extensibility/dispatcher.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +8 -8
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +94 -64
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/keyword-registry.d.ts.map +1 -1
- package/dist/hooks/keyword-registry.js +9 -11
- package/dist/hooks/keyword-registry.js.map +1 -1
- package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
- package/dist/hooks/prompt-guidance-contract.js +10 -21
- package/dist/hooks/prompt-guidance-contract.js.map +1 -1
- package/dist/hooks/task-size-detector.js +2 -2
- package/dist/hooks/task-size-detector.js.map +1 -1
- package/dist/hooks/triage-state.d.ts +1 -1
- package/dist/hooks/triage-state.js +1 -1
- package/dist/hud/colors.d.ts +2 -2
- package/dist/hud/colors.js +2 -2
- package/dist/hud/render.js +21 -21
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.d.ts +3 -3
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +18 -15
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/types.d.ts +6 -6
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/mcp/bootstrap.d.ts.map +1 -1
- package/dist/mcp/bootstrap.js +36 -2
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/state-paths.d.ts +1 -0
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +4 -1
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/mcp/state-server.d.ts +4 -4
- package/dist/mcp/state-server.js +2 -2
- package/dist/mcp/state-server.js.map +1 -1
- package/dist/modes/base.d.ts +2 -2
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +29 -26
- package/dist/modes/base.js.map +1 -1
- package/dist/notifications/reply-listener.d.ts.map +1 -1
- package/dist/notifications/reply-listener.js +7 -1
- package/dist/notifications/reply-listener.js.map +1 -1
- package/dist/notifications/tmux.d.ts.map +1 -1
- package/dist/notifications/tmux.js +39 -6
- package/dist/notifications/tmux.js.map +1 -1
- package/dist/pipeline/index.d.ts +7 -6
- package/dist/pipeline/index.d.ts.map +1 -1
- package/dist/pipeline/index.js +5 -4
- package/dist/pipeline/index.js.map +1 -1
- package/dist/pipeline/orchestrator.d.ts +5 -5
- package/dist/pipeline/orchestrator.js +25 -25
- package/dist/pipeline/orchestrator.js.map +1 -1
- package/dist/pipeline/stages/blueprint.d.ts +25 -0
- package/dist/pipeline/stages/blueprint.d.ts.map +1 -0
- package/dist/pipeline/stages/{ralplan.js → blueprint.js} +16 -16
- package/dist/pipeline/stages/blueprint.js.map +1 -0
- package/dist/pipeline/stages/code-review.d.ts +2 -2
- package/dist/pipeline/stages/code-review.js +6 -6
- package/dist/pipeline/stages/code-review.js.map +1 -1
- package/dist/pipeline/stages/forge-verify.d.ts +50 -0
- package/dist/pipeline/stages/forge-verify.d.ts.map +1 -0
- package/dist/pipeline/stages/{ralph-verify.js → forge-verify.js} +21 -24
- package/dist/pipeline/stages/forge-verify.js.map +1 -0
- package/dist/pipeline/stages/team-exec.d.ts +1 -1
- package/dist/pipeline/stages/team-exec.js +19 -19
- package/dist/pipeline/stages/team-exec.js.map +1 -1
- package/dist/pipeline/types.d.ts +12 -12
- package/dist/pipeline/types.d.ts.map +1 -1
- package/dist/pipeline/types.js +1 -1
- package/dist/planning/artifacts.d.ts +3 -4
- package/dist/planning/artifacts.d.ts.map +1 -1
- package/dist/planning/artifacts.js +2 -3
- package/dist/planning/artifacts.js.map +1 -1
- package/dist/question/policy.js +1 -1
- package/dist/runtime/bridge.d.ts.map +1 -1
- package/dist/runtime/bridge.js +70 -13
- package/dist/runtime/bridge.js.map +1 -1
- package/dist/scripts/codex-native-hook.js +30 -30
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/eval/eval-cross-server-party-flow.d.ts +3 -0
- package/dist/scripts/eval/eval-cross-server-party-flow.d.ts.map +1 -0
- package/dist/scripts/eval/eval-cross-server-party-flow.js +12 -0
- package/dist/scripts/eval/eval-cross-server-party-flow.js.map +1 -0
- package/dist/scripts/eval/eval-gui-onboarding-clarity.d.ts +3 -0
- package/dist/scripts/eval/eval-gui-onboarding-clarity.d.ts.map +1 -0
- package/dist/scripts/eval/eval-gui-onboarding-clarity.js +17 -0
- package/dist/scripts/eval/eval-gui-onboarding-clarity.js.map +1 -0
- package/dist/scripts/eval/eval-liveops-reward-loop-balance.d.ts +3 -0
- package/dist/scripts/eval/eval-liveops-reward-loop-balance.d.ts.map +1 -0
- package/dist/scripts/eval/eval-liveops-reward-loop-balance.js +12 -0
- package/dist/scripts/eval/eval-liveops-reward-loop-balance.js.map +1 -0
- package/dist/scripts/eval/eval-profile-datastore-recovery.d.ts +3 -0
- package/dist/scripts/eval/eval-profile-datastore-recovery.d.ts.map +1 -0
- package/dist/scripts/eval/eval-profile-datastore-recovery.js +17 -0
- package/dist/scripts/eval/eval-profile-datastore-recovery.js.map +1 -0
- package/dist/scripts/eval/eval-remote-contract-hardening.d.ts +3 -0
- package/dist/scripts/eval/eval-remote-contract-hardening.d.ts.map +1 -0
- package/dist/scripts/eval/eval-remote-contract-hardening.js +17 -0
- package/dist/scripts/eval/eval-remote-contract-hardening.js.map +1 -0
- package/dist/scripts/notify-fallback-watcher.js +140 -139
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/forge-session-resume.d.ts +23 -0
- package/dist/scripts/notify-hook/{ralph-session-resume.d.ts.map → forge-session-resume.d.ts.map} +1 -1
- package/dist/scripts/notify-hook/{ralph-session-resume.js → forge-session-resume.js} +37 -36
- package/dist/scripts/notify-hook/{ralph-session-resume.js.map → forge-session-resume.js.map} +1 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.js +34 -4
- package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
- package/dist/scripts/notify-hook/visual-verdict.js +3 -3
- package/dist/scripts/notify-hook.js +9 -9
- package/dist/scripts/run-test-files.js +1 -1
- package/dist/scripts/run-test-files.js.map +1 -1
- package/dist/scripts/surface-taxonomy.d.ts +23 -0
- package/dist/scripts/surface-taxonomy.d.ts.map +1 -0
- package/dist/scripts/surface-taxonomy.js +271 -0
- package/dist/scripts/surface-taxonomy.js.map +1 -0
- package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
- package/dist/scripts/sync-plugin-mirror.js +5 -4
- package/dist/scripts/sync-plugin-mirror.js.map +1 -1
- package/dist/scripts/tmux-hook-engine.d.ts +1 -1
- package/dist/scripts/tmux-hook-engine.d.ts.map +1 -1
- package/dist/scripts/tmux-hook-engine.js +29 -20
- package/dist/scripts/tmux-hook-engine.js.map +1 -1
- package/dist/state/operations.d.ts +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +18 -18
- package/dist/state/operations.js.map +1 -1
- package/dist/state/skill-active.d.ts +13 -1
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +38 -17
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/workflow-transition.d.ts +6 -5
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js +27 -15
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/team/contracts.d.ts +1 -1
- package/dist/team/contracts.js +2 -2
- package/dist/team/followup-planner.d.ts +2 -2
- package/dist/team/followup-planner.d.ts.map +1 -1
- package/dist/team/followup-planner.js +16 -14
- package/dist/team/followup-planner.js.map +1 -1
- package/dist/team/idle-nudge.d.ts.map +1 -1
- package/dist/team/idle-nudge.js +3 -2
- package/dist/team/idle-nudge.js.map +1 -1
- package/dist/team/leader-activity.js +1 -1
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +4 -1
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/orchestrator.js +4 -4
- package/dist/team/orchestrator.js.map +1 -1
- package/dist/team/role-router.js +3 -3
- package/dist/team/role-router.js.map +1 -1
- package/dist/team/state/dispatch.d.ts.map +1 -1
- package/dist/team/state/dispatch.js +4 -1
- package/dist/team/state/dispatch.js.map +1 -1
- package/dist/team/tmux-session.d.ts +4 -0
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +42 -9
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worktree.d.ts +1 -1
- package/dist/utils/platform-command.d.ts.map +1 -1
- package/dist/utils/platform-command.js +9 -0
- package/dist/utils/platform-command.js.map +1 -1
- package/dist/verification/verifier.d.ts +1 -1
- package/dist/verification/verifier.js +2 -2
- package/docs/STATE_MODEL.md +24 -24
- package/docs/agents.html +8 -16
- package/docs/archive/README.md +15 -0
- package/docs/{prompt-migration-changelog.md → archive/prompt-migration-changelog.md} +0 -11
- package/docs/{release-body-0.9.0.md → archive/release-body-0.9.0.md} +6 -24
- package/docs/{release-body-0.9.1.md → archive/release-body-0.9.1.md} +3 -3
- package/docs/codex-native-hooks.md +4 -4
- package/docs/contracts/forge-cancel-contract.md +20 -0
- package/docs/contracts/forge-state-contract.md +52 -0
- package/docs/contracts/multi-state-transition-contract.md +5 -5
- package/docs/contracts/multi-state-transition-review.md +3 -3
- package/docs/contracts/repo-aware-team-dag-decomposition.md +1 -1
- package/docs/contracts/rust-runtime-thin-adapter-contract.md +1 -1
- package/docs/contracts/team-startup-dispatch-latency.md +1 -1
- package/docs/getting-started.html +6 -1
- package/docs/guidance-schema.md +6 -3
- package/docs/index.html +55 -4
- package/docs/integrations.html +4 -3
- package/docs/issues/team-forge-followup-team.md +38 -0
- package/docs/openclaw-integration.md +2 -2
- package/docs/prompt-guidance-contract.md +11 -11
- package/docs/prs/{dev-deprecate-team-ralph.md → dev-deprecate-team-forge.md} +27 -27
- package/docs/prs/{dev-fix-ralph-live-pane-invariant.md → dev-fix-forge-live-pane-invariant.md} +7 -7
- package/docs/prs/{dev-team-ralph-workflow-positioning.md → dev-team-forge-workflow-positioning.md} +7 -7
- package/docs/qa/forge-persistence-gate.md +20 -0
- package/docs/qa/rust-runtime-thin-adapter-gate.md +31 -40
- package/docs/readme/README.de.md +13 -0
- package/docs/readme/README.el.md +13 -0
- package/docs/readme/README.es.md +13 -0
- package/docs/readme/README.fr.md +13 -0
- package/docs/readme/README.it.md +13 -0
- package/docs/readme/README.ja.md +13 -0
- package/docs/readme/README.ko.md +13 -0
- package/docs/readme/README.pl.md +13 -0
- package/docs/readme/README.pt.md +13 -0
- package/docs/readme/README.ru.md +13 -0
- package/docs/readme/README.tr.md +13 -0
- package/docs/readme/README.uk.md +13 -0
- package/docs/readme/README.vi.md +13 -0
- package/docs/readme/README.zh-TW.md +13 -0
- package/docs/readme/README.zh.md +13 -0
- package/docs/readme/rcs-cover.svg +75 -0
- package/docs/reference/canonical-vocabulary.md +106 -0
- package/docs/reference/forge-parity-matrix.md +26 -0
- package/docs/reference/forge-upstream-baseline.md +32 -0
- package/docs/reference/rcs-config-schema-routing.md +5 -5
- package/docs/reference/roblox-pre-action-protocol.md +4 -0
- package/docs/reference/roblox-taxonomy-migration-plan.md +46 -0
- package/docs/reference/roblox-workspace-standard.md +83 -0
- package/docs/reference/robloxstudio-mcp-compatibility.md +117 -0
- package/docs/reference/semantic-design-system.md +110 -0
- package/docs/reference/surface-map.md +131 -0
- package/docs/reference/team-allocation-rebalance-policy.md +1 -1
- package/docs/release-notes-v0.1.0.md +1 -1
- package/docs/release-notes-v0.1.1.md +49 -0
- package/docs/reports/open-prs-dev-readiness-2026-04-09.md +2 -2
- package/docs/shared/agent-tiers.md +3 -3
- package/docs/skills.html +10 -12
- package/docs/troubleshooting.md +1 -1
- package/package.json +20 -13
- package/plugins/roblox-ai-os-creator-skills/.codex-plugin/plugin.json +1 -1
- package/plugins/roblox-ai-os-creator-skills/docs/reference/roblox-pre-action-protocol.md +4 -0
- package/plugins/roblox-ai-os-creator-skills/skills/ai-slop-cleaner/SKILL.md +14 -7
- package/plugins/roblox-ai-os-creator-skills/skills/analyze/SKILL.md +9 -2
- package/plugins/roblox-ai-os-creator-skills/skills/ask-claude/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/ask-gemini/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/autoforge/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/autopilot/SKILL.md +48 -41
- package/plugins/roblox-ai-os-creator-skills/skills/autoresearch/SKILL.md +8 -1
- package/plugins/roblox-ai-os-creator-skills/skills/blueprint/SKILL.md +227 -9
- package/plugins/roblox-ai-os-creator-skills/skills/blueprint-loop/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/blueprint-psych/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/blueprint-retention/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/blueprint-social/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/brief/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/brief-audience/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/brief-motivation/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/cancel/SKILL.md +59 -52
- package/plugins/roblox-ai-os-creator-skills/skills/code-review/SKILL.md +30 -24
- package/plugins/roblox-ai-os-creator-skills/skills/configure-notifications/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/crew/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/deep-interview/SKILL.md +25 -18
- package/plugins/roblox-ai-os-creator-skills/skills/doctor/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/forge/SKILL.md +174 -11
- package/plugins/roblox-ai-os-creator-skills/skills/forge-community/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/forge-daily-loop/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/forge-event-loop/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/forge-fomo/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/forge-mastery/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/forge-progression/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/forge-reward-loop/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/forge-status/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/help/SKILL.md +8 -1
- package/plugins/roblox-ai-os-creator-skills/skills/hud/SKILL.md +16 -9
- package/plugins/roblox-ai-os-creator-skills/skills/note/SKILL.md +8 -1
- package/plugins/roblox-ai-os-creator-skills/skills/pipeline/SKILL.md +18 -11
- package/plugins/roblox-ai-os-creator-skills/skills/plan/SKILL.md +36 -29
- package/plugins/roblox-ai-os-creator-skills/skills/rcs-setup/SKILL.md +8 -1
- package/plugins/roblox-ai-os-creator-skills/skills/security-review/SKILL.md +120 -236
- package/plugins/roblox-ai-os-creator-skills/skills/skill/SKILL.md +20 -13
- package/plugins/roblox-ai-os-creator-skills/skills/team/SKILL.md +17 -11
- package/plugins/roblox-ai-os-creator-skills/skills/trace/SKILL.md +7 -0
- package/plugins/roblox-ai-os-creator-skills/skills/ultraqa/SKILL.md +10 -3
- package/plugins/roblox-ai-os-creator-skills/skills/ultrawork/SKILL.md +19 -12
- package/plugins/roblox-ai-os-creator-skills/skills/{visual-ralph → visual-forge}/SKILL.md +36 -27
- package/plugins/roblox-ai-os-creator-skills/skills/visual-verdict/SKILL.md +9 -2
- package/plugins/roblox-ai-os-creator-skills/skills/wiki/SKILL.md +10 -3
- package/plugins/roblox-ai-os-creator-skills/skills/worker/SKILL.md +16 -7
- package/plugins/roblox-ai-os-creator-skills/templates/roblox/pre-action-plan.md +1 -0
- package/prompts/analyst.md +7 -0
- package/prompts/architect.md +11 -4
- package/prompts/build-fixer.md +7 -0
- package/prompts/code-reviewer.md +9 -2
- package/prompts/code-simplifier.md +4 -0
- package/prompts/critic.md +13 -6
- package/prompts/debugger.md +8 -1
- package/prompts/dependency-expert.md +8 -1
- package/prompts/designer.md +20 -10
- package/prompts/executor.md +7 -0
- package/prompts/explore-harness.md +7 -0
- package/prompts/explore.md +7 -0
- package/prompts/git-master.md +8 -1
- package/prompts/planner.md +10 -3
- package/prompts/researcher.md +7 -0
- package/prompts/security-reviewer.md +76 -92
- package/prompts/sisyphus-lite.md +7 -0
- package/prompts/team-executor.md +7 -0
- package/prompts/team-orchestrator.md +9 -2
- package/prompts/test-engineer.md +11 -3
- package/prompts/verifier.md +7 -0
- package/prompts/vision.md +9 -2
- package/prompts/writer.md +11 -4
- package/skills/.agents/skills/roblox-animations/SKILL.md +220 -0
- package/skills/.agents/skills/roblox-datastores/SKILL.md +219 -0
- package/skills/.agents/skills/roblox-gui/SKILL.md +192 -0
- package/skills/.agents/skills/roblox-monetization/SKILL.md +208 -0
- package/skills/.agents/skills/roblox-performance/SKILL.md +230 -0
- package/skills/.agents/skills/roblox-remote-events/SKILL.md +199 -0
- package/skills/.agents/skills/roblox-security/SKILL.md +236 -0
- package/skills/ai-slop-cleaner/SKILL.md +14 -7
- package/skills/analyze/SKILL.md +9 -2
- package/skills/ask-claude/SKILL.md +7 -0
- package/skills/ask-gemini/SKILL.md +7 -0
- package/skills/autoforge/SKILL.md +7 -0
- package/skills/autopilot/SKILL.md +48 -41
- package/skills/autoresearch/SKILL.md +8 -1
- package/skills/blueprint/SKILL.md +227 -9
- package/skills/blueprint-loop/SKILL.md +7 -0
- package/skills/blueprint-psych/SKILL.md +7 -0
- package/skills/blueprint-retention/SKILL.md +7 -0
- package/skills/blueprint-social/SKILL.md +7 -0
- package/skills/brief/SKILL.md +7 -0
- package/skills/brief-audience/SKILL.md +7 -0
- package/skills/brief-motivation/SKILL.md +7 -0
- package/skills/build-fix/SKILL.md +9 -2
- package/skills/cancel/SKILL.md +59 -52
- package/skills/code-review/SKILL.md +30 -24
- package/skills/configure-notifications/SKILL.md +7 -0
- package/skills/crew/SKILL.md +7 -0
- package/skills/deep-interview/SKILL.md +25 -18
- package/skills/deepsearch/SKILL.md +7 -0
- package/skills/doctor/SKILL.md +7 -0
- package/skills/ecomode/SKILL.md +9 -2
- package/skills/forge/SKILL.md +174 -11
- package/skills/forge-community/SKILL.md +7 -0
- package/skills/forge-daily-loop/SKILL.md +7 -0
- package/skills/forge-event-loop/SKILL.md +7 -0
- package/skills/forge-fomo/SKILL.md +7 -0
- package/skills/{ralph-init → forge-init}/SKILL.md +20 -13
- package/skills/forge-mastery/SKILL.md +7 -0
- package/skills/forge-progression/SKILL.md +7 -0
- package/skills/forge-reward-loop/SKILL.md +7 -0
- package/skills/forge-status/SKILL.md +7 -0
- package/skills/git-master/SKILL.md +7 -0
- package/skills/help/SKILL.md +8 -1
- package/skills/hud/SKILL.md +16 -9
- package/skills/note/SKILL.md +8 -1
- package/skills/pipeline/SKILL.md +18 -11
- package/skills/plan/SKILL.md +36 -29
- package/skills/rcs-setup/SKILL.md +8 -1
- package/skills/review/SKILL.md +7 -0
- package/skills/security-review/SKILL.md +120 -236
- package/skills/skill/SKILL.md +20 -13
- package/skills/skills-lock.json +47 -0
- package/skills/swarm/SKILL.md +8 -1
- package/skills/tdd/SKILL.md +7 -0
- package/skills/team/SKILL.md +17 -11
- package/skills/trace/SKILL.md +7 -0
- package/skills/ultraqa/SKILL.md +10 -3
- package/skills/ultrawork/SKILL.md +19 -12
- package/skills/{visual-ralph → visual-forge}/SKILL.md +36 -27
- package/skills/visual-verdict/SKILL.md +9 -2
- package/skills/web-clone/SKILL.md +14 -7
- package/skills/wiki/SKILL.md +10 -3
- package/skills/worker/SKILL.md +16 -7
- package/src/scripts/__tests__/codex-native-hook.test.ts +386 -319
- package/src/scripts/__tests__/run-test-files.test.ts +6 -4
- package/src/scripts/__tests__/verify-native-agents.test.ts +16 -16
- package/src/scripts/codex-native-hook.ts +34 -34
- package/src/scripts/eval/eval-cross-server-party-flow.ts +14 -0
- package/src/scripts/eval/eval-gui-onboarding-clarity.ts +20 -0
- package/src/scripts/eval/eval-liveops-reward-loop-balance.ts +14 -0
- package/src/scripts/eval/eval-profile-datastore-recovery.ts +20 -0
- package/src/scripts/eval/eval-remote-contract-hardening.ts +20 -0
- package/src/scripts/notify-fallback-watcher.ts +147 -146
- package/src/scripts/notify-hook/__tests__/team-worker-posttooluse.test.ts +24 -10
- package/src/scripts/notify-hook/{ralph-session-resume.ts → forge-session-resume.ts} +45 -43
- package/src/scripts/notify-hook/team-dispatch.ts +31 -4
- package/src/scripts/notify-hook/visual-verdict.ts +3 -3
- package/src/scripts/notify-hook.ts +10 -10
- package/src/scripts/run-test-files.ts +1 -1
- package/src/scripts/surface-taxonomy.ts +316 -0
- package/src/scripts/sync-plugin-mirror.ts +5 -4
- package/src/scripts/tmux-hook-engine.ts +31 -19
- package/templates/AGENTS.md +24 -15
- package/templates/catalog-manifest.json +5 -88
- package/templates/roblox/pre-action-plan.md +1 -0
- package/templates/roblox/robloxstudio-mcp.codex.json +18 -0
- package/templates/roblox/robloxstudio-mcp.windows.json +22 -0
- package/dist/adapt/__tests__/foundation.test.d.ts +0 -2
- package/dist/adapt/__tests__/foundation.test.d.ts.map +0 -1
- package/dist/adapt/__tests__/foundation.test.js +0 -171
- package/dist/adapt/__tests__/foundation.test.js.map +0 -1
- package/dist/adapt/__tests__/hermes.test.d.ts +0 -2
- package/dist/adapt/__tests__/hermes.test.d.ts.map +0 -1
- package/dist/adapt/__tests__/hermes.test.js +0 -137
- package/dist/adapt/__tests__/hermes.test.js.map +0 -1
- package/dist/agents/__tests__/definitions.test.d.ts +0 -2
- package/dist/agents/__tests__/definitions.test.d.ts.map +0 -1
- package/dist/agents/__tests__/definitions.test.js +0 -62
- package/dist/agents/__tests__/definitions.test.js.map +0 -1
- package/dist/agents/__tests__/native-config.test.d.ts +0 -2
- package/dist/agents/__tests__/native-config.test.d.ts.map +0 -1
- package/dist/agents/__tests__/native-config.test.js +0 -278
- package/dist/agents/__tests__/native-config.test.js.map +0 -1
- package/dist/autoresearch/__tests__/contracts.test.d.ts +0 -2
- package/dist/autoresearch/__tests__/contracts.test.d.ts.map +0 -1
- package/dist/autoresearch/__tests__/contracts.test.js +0 -127
- package/dist/autoresearch/__tests__/contracts.test.js.map +0 -1
- package/dist/autoresearch/__tests__/runtime-parity-extra.test.d.ts +0 -2
- package/dist/autoresearch/__tests__/runtime-parity-extra.test.d.ts.map +0 -1
- package/dist/autoresearch/__tests__/runtime-parity-extra.test.js +0 -356
- package/dist/autoresearch/__tests__/runtime-parity-extra.test.js.map +0 -1
- package/dist/autoresearch/__tests__/runtime.test.d.ts +0 -2
- package/dist/autoresearch/__tests__/runtime.test.d.ts.map +0 -1
- package/dist/autoresearch/__tests__/runtime.test.js +0 -218
- package/dist/autoresearch/__tests__/runtime.test.js.map +0 -1
- package/dist/autoresearch/__tests__/skill-validation.test.d.ts +0 -2
- package/dist/autoresearch/__tests__/skill-validation.test.d.ts.map +0 -1
- package/dist/autoresearch/__tests__/skill-validation.test.js +0 -91
- package/dist/autoresearch/__tests__/skill-validation.test.js.map +0 -1
- package/dist/catalog/__tests__/generator.test.d.ts +0 -2
- package/dist/catalog/__tests__/generator.test.d.ts.map +0 -1
- package/dist/catalog/__tests__/generator.test.js +0 -49
- package/dist/catalog/__tests__/generator.test.js.map +0 -1
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.d.ts +0 -2
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.d.ts.map +0 -1
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +0 -83
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +0 -1
- package/dist/catalog/__tests__/schema.test.d.ts +0 -2
- package/dist/catalog/__tests__/schema.test.d.ts.map +0 -1
- package/dist/catalog/__tests__/schema.test.js +0 -91
- package/dist/catalog/__tests__/schema.test.js.map +0 -1
- package/dist/cli/__tests__/adapt-help.test.d.ts +0 -2
- package/dist/cli/__tests__/adapt-help.test.d.ts.map +0 -1
- package/dist/cli/__tests__/adapt-help.test.js +0 -37
- package/dist/cli/__tests__/adapt-help.test.js.map +0 -1
- package/dist/cli/__tests__/adapt.test.d.ts +0 -2
- package/dist/cli/__tests__/adapt.test.d.ts.map +0 -1
- package/dist/cli/__tests__/adapt.test.js +0 -62
- package/dist/cli/__tests__/adapt.test.js.map +0 -1
- package/dist/cli/__tests__/agents-init.test.d.ts +0 -2
- package/dist/cli/__tests__/agents-init.test.d.ts.map +0 -1
- package/dist/cli/__tests__/agents-init.test.js +0 -184
- package/dist/cli/__tests__/agents-init.test.js.map +0 -1
- package/dist/cli/__tests__/agents.test.d.ts +0 -2
- package/dist/cli/__tests__/agents.test.d.ts.map +0 -1
- package/dist/cli/__tests__/agents.test.js +0 -137
- package/dist/cli/__tests__/agents.test.js.map +0 -1
- package/dist/cli/__tests__/ask.test.d.ts +0 -2
- package/dist/cli/__tests__/ask.test.d.ts.map +0 -1
- package/dist/cli/__tests__/ask.test.js +0 -265
- package/dist/cli/__tests__/ask.test.js.map +0 -1
- package/dist/cli/__tests__/autoresearch-guided.test.d.ts +0 -2
- package/dist/cli/__tests__/autoresearch-guided.test.d.ts.map +0 -1
- package/dist/cli/__tests__/autoresearch-guided.test.js +0 -365
- package/dist/cli/__tests__/autoresearch-guided.test.js.map +0 -1
- package/dist/cli/__tests__/autoresearch.test.d.ts +0 -2
- package/dist/cli/__tests__/autoresearch.test.d.ts.map +0 -1
- package/dist/cli/__tests__/autoresearch.test.js +0 -203
- package/dist/cli/__tests__/autoresearch.test.js.map +0 -1
- package/dist/cli/__tests__/catalog-contract.test.d.ts +0 -2
- package/dist/cli/__tests__/catalog-contract.test.d.ts.map +0 -1
- package/dist/cli/__tests__/catalog-contract.test.js +0 -18
- package/dist/cli/__tests__/catalog-contract.test.js.map +0 -1
- package/dist/cli/__tests__/cleanup.test.d.ts +0 -2
- package/dist/cli/__tests__/cleanup.test.d.ts.map +0 -1
- package/dist/cli/__tests__/cleanup.test.js +0 -419
- package/dist/cli/__tests__/cleanup.test.js.map +0 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.d.ts +0 -2
- package/dist/cli/__tests__/codex-plugin-layout.test.d.ts.map +0 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +0 -210
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +0 -1
- package/dist/cli/__tests__/doctor-context-window-warning.test.d.ts +0 -2
- package/dist/cli/__tests__/doctor-context-window-warning.test.d.ts.map +0 -1
- package/dist/cli/__tests__/doctor-context-window-warning.test.js +0 -122
- package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +0 -1
- package/dist/cli/__tests__/doctor-invalid-config.test.d.ts +0 -2
- package/dist/cli/__tests__/doctor-invalid-config.test.d.ts.map +0 -1
- package/dist/cli/__tests__/doctor-invalid-config.test.js +0 -52
- package/dist/cli/__tests__/doctor-invalid-config.test.js.map +0 -1
- package/dist/cli/__tests__/doctor-team.test.d.ts +0 -2
- package/dist/cli/__tests__/doctor-team.test.d.ts.map +0 -1
- package/dist/cli/__tests__/doctor-team.test.js +0 -299
- package/dist/cli/__tests__/doctor-team.test.js.map +0 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.d.ts +0 -2
- package/dist/cli/__tests__/doctor-warning-copy.test.d.ts.map +0 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +0 -438
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +0 -1
- package/dist/cli/__tests__/error-handling-warnings.test.d.ts +0 -2
- package/dist/cli/__tests__/error-handling-warnings.test.d.ts.map +0 -1
- package/dist/cli/__tests__/error-handling-warnings.test.js +0 -52
- package/dist/cli/__tests__/error-handling-warnings.test.js.map +0 -1
- package/dist/cli/__tests__/exec.test.d.ts +0 -2
- package/dist/cli/__tests__/exec.test.d.ts.map +0 -1
- package/dist/cli/__tests__/exec.test.js +0 -213
- package/dist/cli/__tests__/exec.test.js.map +0 -1
- package/dist/cli/__tests__/explore-windows-diagnostics.test.d.ts +0 -2
- package/dist/cli/__tests__/explore-windows-diagnostics.test.d.ts.map +0 -1
- package/dist/cli/__tests__/explore-windows-diagnostics.test.js +0 -17
- package/dist/cli/__tests__/explore-windows-diagnostics.test.js.map +0 -1
- package/dist/cli/__tests__/explore.test.d.ts +0 -2
- package/dist/cli/__tests__/explore.test.d.ts.map +0 -1
- package/dist/cli/__tests__/explore.test.js +0 -1090
- package/dist/cli/__tests__/explore.test.js.map +0 -1
- package/dist/cli/__tests__/hooks.test.d.ts +0 -2
- package/dist/cli/__tests__/hooks.test.d.ts.map +0 -1
- package/dist/cli/__tests__/hooks.test.js +0 -55
- package/dist/cli/__tests__/hooks.test.js.map +0 -1
- package/dist/cli/__tests__/index.test.d.ts +0 -2
- package/dist/cli/__tests__/index.test.d.ts.map +0 -1
- package/dist/cli/__tests__/index.test.js +0 -2259
- package/dist/cli/__tests__/index.test.js.map +0 -1
- package/dist/cli/__tests__/launch-fallback.test.d.ts +0 -2
- package/dist/cli/__tests__/launch-fallback.test.d.ts.map +0 -1
- package/dist/cli/__tests__/launch-fallback.test.js +0 -661
- package/dist/cli/__tests__/launch-fallback.test.js.map +0 -1
- package/dist/cli/__tests__/lifecycle-notifications.test.d.ts +0 -2
- package/dist/cli/__tests__/lifecycle-notifications.test.d.ts.map +0 -1
- package/dist/cli/__tests__/lifecycle-notifications.test.js +0 -48
- package/dist/cli/__tests__/lifecycle-notifications.test.js.map +0 -1
- package/dist/cli/__tests__/list.test.d.ts +0 -2
- package/dist/cli/__tests__/list.test.d.ts.map +0 -1
- package/dist/cli/__tests__/list.test.js +0 -38
- package/dist/cli/__tests__/list.test.js.map +0 -1
- package/dist/cli/__tests__/mcp-parity.test.d.ts +0 -2
- package/dist/cli/__tests__/mcp-parity.test.d.ts.map +0 -1
- package/dist/cli/__tests__/mcp-parity.test.js +0 -228
- package/dist/cli/__tests__/mcp-parity.test.js.map +0 -1
- package/dist/cli/__tests__/mcp-serve.test.d.ts +0 -2
- package/dist/cli/__tests__/mcp-serve.test.d.ts.map +0 -1
- package/dist/cli/__tests__/mcp-serve.test.js +0 -64
- package/dist/cli/__tests__/mcp-serve.test.js.map +0 -1
- package/dist/cli/__tests__/native-assets.test.d.ts +0 -2
- package/dist/cli/__tests__/native-assets.test.d.ts.map +0 -1
- package/dist/cli/__tests__/native-assets.test.js +0 -308
- package/dist/cli/__tests__/native-assets.test.js.map +0 -1
- package/dist/cli/__tests__/native-hook-dispatch-contract.test.d.ts +0 -2
- package/dist/cli/__tests__/native-hook-dispatch-contract.test.d.ts.map +0 -1
- package/dist/cli/__tests__/native-hook-dispatch-contract.test.js +0 -11
- package/dist/cli/__tests__/native-hook-dispatch-contract.test.js.map +0 -1
- package/dist/cli/__tests__/nested-help-routing.test.d.ts +0 -2
- package/dist/cli/__tests__/nested-help-routing.test.d.ts.map +0 -1
- package/dist/cli/__tests__/nested-help-routing.test.js +0 -96
- package/dist/cli/__tests__/nested-help-routing.test.js.map +0 -1
- package/dist/cli/__tests__/package-bin-contract.test.d.ts +0 -2
- package/dist/cli/__tests__/package-bin-contract.test.d.ts.map +0 -1
- package/dist/cli/__tests__/package-bin-contract.test.js +0 -177
- package/dist/cli/__tests__/package-bin-contract.test.js.map +0 -1
- package/dist/cli/__tests__/packaged-explore-harness-lock.d.ts +0 -3
- package/dist/cli/__tests__/packaged-explore-harness-lock.d.ts.map +0 -1
- package/dist/cli/__tests__/packaged-explore-harness-lock.js +0 -67
- package/dist/cli/__tests__/packaged-explore-harness-lock.js.map +0 -1
- package/dist/cli/__tests__/packaged-script-resolution.test.d.ts +0 -2
- package/dist/cli/__tests__/packaged-script-resolution.test.d.ts.map +0 -1
- package/dist/cli/__tests__/packaged-script-resolution.test.js +0 -19
- package/dist/cli/__tests__/packaged-script-resolution.test.js.map +0 -1
- package/dist/cli/__tests__/prompt-skill-sanitization.test.d.ts +0 -2
- package/dist/cli/__tests__/prompt-skill-sanitization.test.d.ts.map +0 -1
- package/dist/cli/__tests__/prompt-skill-sanitization.test.js +0 -48
- package/dist/cli/__tests__/prompt-skill-sanitization.test.js.map +0 -1
- package/dist/cli/__tests__/question.test.d.ts +0 -2
- package/dist/cli/__tests__/question.test.d.ts.map +0 -1
- package/dist/cli/__tests__/question.test.js +0 -633
- package/dist/cli/__tests__/question.test.js.map +0 -1
- package/dist/cli/__tests__/ralph-deslop-contract.test.d.ts +0 -2
- package/dist/cli/__tests__/ralph-deslop-contract.test.d.ts.map +0 -1
- package/dist/cli/__tests__/ralph-deslop-contract.test.js +0 -28
- package/dist/cli/__tests__/ralph-deslop-contract.test.js.map +0 -1
- package/dist/cli/__tests__/ralph-prd-deep-interview.test.d.ts +0 -2
- package/dist/cli/__tests__/ralph-prd-deep-interview.test.d.ts.map +0 -1
- package/dist/cli/__tests__/ralph-prd-deep-interview.test.js +0 -24
- package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +0 -1
- package/dist/cli/__tests__/ralph-prd-smoke.test.d.ts +0 -2
- package/dist/cli/__tests__/ralph-prd-smoke.test.d.ts.map +0 -1
- package/dist/cli/__tests__/ralph-prd-smoke.test.js +0 -167
- package/dist/cli/__tests__/ralph-prd-smoke.test.js.map +0 -1
- package/dist/cli/__tests__/ralph.test.d.ts +0 -2
- package/dist/cli/__tests__/ralph.test.d.ts.map +0 -1
- package/dist/cli/__tests__/ralph.test.js +0 -256
- package/dist/cli/__tests__/ralph.test.js.map +0 -1
- package/dist/cli/__tests__/resume.test.d.ts +0 -2
- package/dist/cli/__tests__/resume.test.d.ts.map +0 -1
- package/dist/cli/__tests__/resume.test.js +0 -84
- package/dist/cli/__tests__/resume.test.js.map +0 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.d.ts +0 -2
- package/dist/cli/__tests__/session-scoped-runtime.test.d.ts.map +0 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.js +0 -146
- package/dist/cli/__tests__/session-scoped-runtime.test.js.map +0 -1
- package/dist/cli/__tests__/session-search-help.test.d.ts +0 -2
- package/dist/cli/__tests__/session-search-help.test.d.ts.map +0 -1
- package/dist/cli/__tests__/session-search-help.test.js +0 -76
- package/dist/cli/__tests__/session-search-help.test.js.map +0 -1
- package/dist/cli/__tests__/session-search.test.d.ts +0 -2
- package/dist/cli/__tests__/session-search.test.d.ts.map +0 -1
- package/dist/cli/__tests__/session-search.test.js +0 -77
- package/dist/cli/__tests__/session-search.test.js.map +0 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.d.ts +0 -2
- package/dist/cli/__tests__/setup-agents-overwrite.test.d.ts.map +0 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +0 -457
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +0 -1
- package/dist/cli/__tests__/setup-gh-star.test.d.ts +0 -2
- package/dist/cli/__tests__/setup-gh-star.test.d.ts.map +0 -1
- package/dist/cli/__tests__/setup-gh-star.test.js +0 -67
- package/dist/cli/__tests__/setup-gh-star.test.js.map +0 -1
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.d.ts +0 -2
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.d.ts.map +0 -1
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +0 -189
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +0 -1
- package/dist/cli/__tests__/setup-install-mode.test.d.ts +0 -2
- package/dist/cli/__tests__/setup-install-mode.test.d.ts.map +0 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +0 -873
- package/dist/cli/__tests__/setup-install-mode.test.js.map +0 -1
- package/dist/cli/__tests__/setup-prompts-overwrite.test.d.ts +0 -2
- package/dist/cli/__tests__/setup-prompts-overwrite.test.d.ts.map +0 -1
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js +0 -191
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +0 -1
- package/dist/cli/__tests__/setup-refresh.test.d.ts +0 -2
- package/dist/cli/__tests__/setup-refresh.test.d.ts.map +0 -1
- package/dist/cli/__tests__/setup-refresh.test.js +0 -591
- package/dist/cli/__tests__/setup-refresh.test.js.map +0 -1
- package/dist/cli/__tests__/setup-scope.test.d.ts +0 -2
- package/dist/cli/__tests__/setup-scope.test.d.ts.map +0 -1
- package/dist/cli/__tests__/setup-scope.test.js +0 -340
- package/dist/cli/__tests__/setup-scope.test.js.map +0 -1
- package/dist/cli/__tests__/setup-skill-validation.test.d.ts +0 -2
- package/dist/cli/__tests__/setup-skill-validation.test.d.ts.map +0 -1
- package/dist/cli/__tests__/setup-skill-validation.test.js +0 -44
- package/dist/cli/__tests__/setup-skill-validation.test.js.map +0 -1
- package/dist/cli/__tests__/setup-skills-overwrite.test.d.ts +0 -2
- package/dist/cli/__tests__/setup-skills-overwrite.test.d.ts.map +0 -1
- package/dist/cli/__tests__/setup-skills-overwrite.test.js +0 -295
- package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +0 -1
- package/dist/cli/__tests__/sidecar.test.d.ts +0 -2
- package/dist/cli/__tests__/sidecar.test.d.ts.map +0 -1
- package/dist/cli/__tests__/sidecar.test.js +0 -24
- package/dist/cli/__tests__/sidecar.test.js.map +0 -1
- package/dist/cli/__tests__/sparkshell-cli.test.d.ts +0 -2
- package/dist/cli/__tests__/sparkshell-cli.test.d.ts.map +0 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js +0 -400
- package/dist/cli/__tests__/sparkshell-cli.test.js.map +0 -1
- package/dist/cli/__tests__/sparkshell-packaging.test.d.ts +0 -2
- package/dist/cli/__tests__/sparkshell-packaging.test.d.ts.map +0 -1
- package/dist/cli/__tests__/sparkshell-packaging.test.js +0 -74
- package/dist/cli/__tests__/sparkshell-packaging.test.js.map +0 -1
- package/dist/cli/__tests__/star-prompt.test.d.ts +0 -2
- package/dist/cli/__tests__/star-prompt.test.d.ts.map +0 -1
- package/dist/cli/__tests__/star-prompt.test.js +0 -172
- package/dist/cli/__tests__/star-prompt.test.js.map +0 -1
- package/dist/cli/__tests__/state.test.d.ts +0 -2
- package/dist/cli/__tests__/state.test.d.ts.map +0 -1
- package/dist/cli/__tests__/state.test.js +0 -46
- package/dist/cli/__tests__/state.test.js.map +0 -1
- package/dist/cli/__tests__/team-decompose.test.d.ts +0 -2
- package/dist/cli/__tests__/team-decompose.test.d.ts.map +0 -1
- package/dist/cli/__tests__/team-decompose.test.js +0 -133
- package/dist/cli/__tests__/team-decompose.test.js.map +0 -1
- package/dist/cli/__tests__/team.test.d.ts +0 -2
- package/dist/cli/__tests__/team.test.d.ts.map +0 -1
- package/dist/cli/__tests__/team.test.js +0 -1820
- package/dist/cli/__tests__/team.test.js.map +0 -1
- package/dist/cli/__tests__/uninstall.test.d.ts +0 -2
- package/dist/cli/__tests__/uninstall.test.d.ts.map +0 -1
- package/dist/cli/__tests__/uninstall.test.js +0 -766
- package/dist/cli/__tests__/uninstall.test.js.map +0 -1
- package/dist/cli/__tests__/update.test.d.ts +0 -2
- package/dist/cli/__tests__/update.test.d.ts.map +0 -1
- package/dist/cli/__tests__/update.test.js +0 -589
- package/dist/cli/__tests__/update.test.js.map +0 -1
- package/dist/cli/__tests__/version-sync-contract.test.d.ts +0 -2
- package/dist/cli/__tests__/version-sync-contract.test.d.ts.map +0 -1
- package/dist/cli/__tests__/version-sync-contract.test.js +0 -41
- package/dist/cli/__tests__/version-sync-contract.test.js.map +0 -1
- package/dist/cli/__tests__/version.test.d.ts +0 -2
- package/dist/cli/__tests__/version.test.d.ts.map +0 -1
- package/dist/cli/__tests__/version.test.js +0 -21
- package/dist/cli/__tests__/version.test.js.map +0 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.d.ts +0 -2
- package/dist/cli/__tests__/windows-popup-loop-contract.test.d.ts.map +0 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js +0 -31
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +0 -1
- package/dist/cli/ralph.d.ts +0 -17
- package/dist/compat/__tests__/doctor-contract.test.d.ts +0 -2
- package/dist/compat/__tests__/doctor-contract.test.d.ts.map +0 -1
- package/dist/compat/__tests__/doctor-contract.test.js +0 -108
- package/dist/compat/__tests__/doctor-contract.test.js.map +0 -1
- package/dist/compat/__tests__/rust-runtime-compat.test.d.ts +0 -2
- package/dist/compat/__tests__/rust-runtime-compat.test.d.ts.map +0 -1
- package/dist/compat/__tests__/rust-runtime-compat.test.js +0 -218
- package/dist/compat/__tests__/rust-runtime-compat.test.js.map +0 -1
- package/dist/config/__tests__/codex-hooks.test.d.ts +0 -2
- package/dist/config/__tests__/codex-hooks.test.d.ts.map +0 -1
- package/dist/config/__tests__/codex-hooks.test.js +0 -77
- package/dist/config/__tests__/codex-hooks.test.js.map +0 -1
- package/dist/config/__tests__/generator-idempotent.test.d.ts +0 -2
- package/dist/config/__tests__/generator-idempotent.test.d.ts.map +0 -1
- package/dist/config/__tests__/generator-idempotent.test.js +0 -882
- package/dist/config/__tests__/generator-idempotent.test.js.map +0 -1
- package/dist/config/__tests__/generator-notify.test.d.ts +0 -2
- package/dist/config/__tests__/generator-notify.test.d.ts.map +0 -1
- package/dist/config/__tests__/generator-notify.test.js +0 -343
- package/dist/config/__tests__/generator-notify.test.js.map +0 -1
- package/dist/config/__tests__/generator-status-line-presets.test.d.ts +0 -2
- package/dist/config/__tests__/generator-status-line-presets.test.d.ts.map +0 -1
- package/dist/config/__tests__/generator-status-line-presets.test.js +0 -203
- package/dist/config/__tests__/generator-status-line-presets.test.js.map +0 -1
- package/dist/config/__tests__/mcp-registry.test.d.ts +0 -2
- package/dist/config/__tests__/mcp-registry.test.d.ts.map +0 -1
- package/dist/config/__tests__/mcp-registry.test.js +0 -190
- package/dist/config/__tests__/mcp-registry.test.js.map +0 -1
- package/dist/config/__tests__/models.test.d.ts +0 -2
- package/dist/config/__tests__/models.test.d.ts.map +0 -1
- package/dist/config/__tests__/models.test.js +0 -224
- package/dist/config/__tests__/models.test.js.map +0 -1
- package/dist/config/__tests__/wiki-config-contract.test.d.ts +0 -2
- package/dist/config/__tests__/wiki-config-contract.test.d.ts.map +0 -1
- package/dist/config/__tests__/wiki-config-contract.test.js +0 -19
- package/dist/config/__tests__/wiki-config-contract.test.js.map +0 -1
- package/dist/document-refresh/__tests__/enforcer.test.d.ts +0 -2
- package/dist/document-refresh/__tests__/enforcer.test.d.ts.map +0 -1
- package/dist/document-refresh/__tests__/enforcer.test.js +0 -128
- package/dist/document-refresh/__tests__/enforcer.test.js.map +0 -1
- package/dist/hooks/__tests__/agents-overlay.test.d.ts +0 -8
- package/dist/hooks/__tests__/agents-overlay.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +0 -644
- package/dist/hooks/__tests__/agents-overlay.test.js.map +0 -1
- package/dist/hooks/__tests__/analyze-routing-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/analyze-routing-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/analyze-routing-contract.test.js +0 -45
- package/dist/hooks/__tests__/analyze-routing-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/analyze-skill-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/analyze-skill-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/analyze-skill-contract.test.js +0 -48
- package/dist/hooks/__tests__/analyze-skill-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/anti-slop-workflow.test.d.ts +0 -2
- package/dist/hooks/__tests__/anti-slop-workflow.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/anti-slop-workflow.test.js +0 -146
- package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +0 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +0 -37
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/clawhip-event-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/clawhip-event-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/clawhip-event-contract.test.js +0 -37
- package/dist/hooks/__tests__/clawhip-event-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/code-review-skill-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/code-review-skill-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/code-review-skill-contract.test.js +0 -56
- package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/codebase-map.test.d.ts +0 -8
- package/dist/hooks/__tests__/codebase-map.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/codebase-map.test.js +0 -218
- package/dist/hooks/__tests__/codebase-map.test.js.map +0 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts +0 -18
- package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js +0 -234
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +0 -1
- package/dist/hooks/__tests__/debugger-log-recency-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/debugger-log-recency-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/debugger-log-recency-contract.test.js +0 -20
- package/dist/hooks/__tests__/debugger-log-recency-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/deep-interview-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js +0 -213
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.js +0 -43
- package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.js +0 -38
- package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/explore-routing.test.d.ts +0 -2
- package/dist/hooks/__tests__/explore-routing.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/explore-routing.test.js +0 -43
- package/dist/hooks/__tests__/explore-routing.test.js.map +0 -1
- package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js +0 -69
- package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/keyword-detector.test.d.ts +0 -2
- package/dist/hooks/__tests__/keyword-detector.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +0 -1716
- package/dist/hooks/__tests__/keyword-detector.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.d.ts +0 -2
- package/dist/hooks/__tests__/notify-fallback-watcher.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +0 -3898
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.d.ts +0 -2
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +0 -786
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.d.ts +0 -2
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +0 -2397
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.d.ts +0 -2
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +0 -160
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.d.ts +0 -2
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +0 -1178
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-modules.test.d.ts +0 -9
- package/dist/hooks/__tests__/notify-hook-modules.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-modules.test.js +0 -529
- package/dist/hooks/__tests__/notify-hook-modules.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.js +0 -14
- package/dist/hooks/__tests__/notify-hook-native-dispatch-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.d.ts +0 -2
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +0 -682
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-regression-205.test.d.ts +0 -9
- package/dist/hooks/__tests__/notify-hook-regression-205.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js +0 -255
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.d.ts +0 -2
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js +0 -162
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-session-scope.test.d.ts +0 -2
- package/dist/hooks/__tests__/notify-hook-session-scope.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js +0 -301
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.d.ts +0 -2
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +0 -1510
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.d.ts +0 -2
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +0 -2879
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.d.ts +0 -2
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +0 -228
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts +0 -2
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js +0 -35
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.d.ts +0 -2
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +0 -1589
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.d.ts +0 -10
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +0 -0
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-visual-verdict.test.d.ts +0 -11
- package/dist/hooks/__tests__/notify-hook-visual-verdict.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js +0 -266
- package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js.map +0 -1
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.d.ts +0 -2
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +0 -895
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +0 -1
- package/dist/hooks/__tests__/openclaw-setup-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/openclaw-setup-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/openclaw-setup-contract.test.js +0 -61
- package/dist/hooks/__tests__/openclaw-setup-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/pre-context-gate-skills.test.d.ts +0 -2
- package/dist/hooks/__tests__/pre-context-gate-skills.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/pre-context-gate-skills.test.js +0 -40
- package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +0 -1
- package/dist/hooks/__tests__/prompt-guidance-catalog.test.d.ts +0 -2
- package/dist/hooks/__tests__/prompt-guidance-catalog.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/prompt-guidance-catalog.test.js +0 -11
- package/dist/hooks/__tests__/prompt-guidance-catalog.test.js.map +0 -1
- package/dist/hooks/__tests__/prompt-guidance-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/prompt-guidance-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/prompt-guidance-contract.test.js +0 -38
- package/dist/hooks/__tests__/prompt-guidance-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.d.ts +0 -2
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.js +0 -48
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +0 -1
- package/dist/hooks/__tests__/prompt-guidance-scenarios.test.d.ts +0 -2
- package/dist/hooks/__tests__/prompt-guidance-scenarios.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/prompt-guidance-scenarios.test.js +0 -11
- package/dist/hooks/__tests__/prompt-guidance-scenarios.test.js.map +0 -1
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.d.ts +0 -5
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.d.ts.map +0 -1
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.js +0 -34
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +0 -1
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.d.ts +0 -2
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +0 -65
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +0 -1
- package/dist/hooks/__tests__/prompt-orchestration-boundary.test.d.ts +0 -2
- package/dist/hooks/__tests__/prompt-orchestration-boundary.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/prompt-orchestration-boundary.test.js +0 -38
- package/dist/hooks/__tests__/prompt-orchestration-boundary.test.js.map +0 -1
- package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/prompt-refactor-contract.test.js +0 -22
- package/dist/hooks/__tests__/prompt-refactor-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/prompt-team-routing.test.d.ts +0 -2
- package/dist/hooks/__tests__/prompt-team-routing.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/prompt-team-routing.test.js +0 -49
- package/dist/hooks/__tests__/prompt-team-routing.test.js.map +0 -1
- package/dist/hooks/__tests__/session.test.d.ts +0 -2
- package/dist/hooks/__tests__/session.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/session.test.js +0 -322
- package/dist/hooks/__tests__/session.test.js.map +0 -1
- package/dist/hooks/__tests__/skill-guidance-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/skill-guidance-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/skill-guidance-contract.test.js +0 -29
- package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/task-size-detector.test.d.ts +0 -2
- package/dist/hooks/__tests__/task-size-detector.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/task-size-detector.test.js +0 -330
- package/dist/hooks/__tests__/task-size-detector.test.js.map +0 -1
- package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js +0 -28
- package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js.map +0 -1
- package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.d.ts +0 -2
- package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.js +0 -24
- package/dist/hooks/__tests__/tmux-hook-engine-types-sync.test.js.map +0 -1
- package/dist/hooks/__tests__/tmux-hook-engine.test.d.ts +0 -2
- package/dist/hooks/__tests__/tmux-hook-engine.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/tmux-hook-engine.test.js +0 -403
- package/dist/hooks/__tests__/tmux-hook-engine.test.js.map +0 -1
- package/dist/hooks/__tests__/triage-config.test.d.ts +0 -2
- package/dist/hooks/__tests__/triage-config.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/triage-config.test.js +0 -211
- package/dist/hooks/__tests__/triage-config.test.js.map +0 -1
- package/dist/hooks/__tests__/triage-heuristic.test.d.ts +0 -2
- package/dist/hooks/__tests__/triage-heuristic.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/triage-heuristic.test.js +0 -285
- package/dist/hooks/__tests__/triage-heuristic.test.js.map +0 -1
- package/dist/hooks/__tests__/triage-state.test.d.ts +0 -2
- package/dist/hooks/__tests__/triage-state.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/triage-state.test.js +0 -426
- package/dist/hooks/__tests__/triage-state.test.js.map +0 -1
- package/dist/hooks/__tests__/visual-ralph-skill.test.d.ts +0 -2
- package/dist/hooks/__tests__/visual-ralph-skill.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/visual-ralph-skill.test.js +0 -44
- package/dist/hooks/__tests__/visual-ralph-skill.test.js.map +0 -1
- package/dist/hooks/__tests__/visual-verdict-loop.test.d.ts +0 -2
- package/dist/hooks/__tests__/visual-verdict-loop.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/visual-verdict-loop.test.js +0 -35
- package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +0 -1
- package/dist/hooks/__tests__/wiki-docs-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/wiki-docs-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/wiki-docs-contract.test.js +0 -34
- package/dist/hooks/__tests__/wiki-docs-contract.test.js.map +0 -1
- package/dist/hooks/code-simplifier/__tests__/index.test.d.ts +0 -2
- package/dist/hooks/code-simplifier/__tests__/index.test.d.ts.map +0 -1
- package/dist/hooks/code-simplifier/__tests__/index.test.js +0 -187
- package/dist/hooks/code-simplifier/__tests__/index.test.js.map +0 -1
- package/dist/hooks/extensibility/__tests__/dispatcher.test.d.ts +0 -2
- package/dist/hooks/extensibility/__tests__/dispatcher.test.d.ts.map +0 -1
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js +0 -242
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +0 -1
- package/dist/hooks/extensibility/__tests__/events.test.d.ts +0 -2
- package/dist/hooks/extensibility/__tests__/events.test.d.ts.map +0 -1
- package/dist/hooks/extensibility/__tests__/events.test.js +0 -125
- package/dist/hooks/extensibility/__tests__/events.test.js.map +0 -1
- package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.d.ts +0 -2
- package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.d.ts.map +0 -1
- package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.js +0 -153
- package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.js.map +0 -1
- package/dist/hooks/extensibility/__tests__/loader.test.d.ts +0 -2
- package/dist/hooks/extensibility/__tests__/loader.test.d.ts.map +0 -1
- package/dist/hooks/extensibility/__tests__/loader.test.js +0 -254
- package/dist/hooks/extensibility/__tests__/loader.test.js.map +0 -1
- package/dist/hooks/extensibility/__tests__/logging.test.d.ts +0 -2
- package/dist/hooks/extensibility/__tests__/logging.test.d.ts.map +0 -1
- package/dist/hooks/extensibility/__tests__/logging.test.js +0 -74
- package/dist/hooks/extensibility/__tests__/logging.test.js.map +0 -1
- package/dist/hooks/extensibility/__tests__/plugin-runner.test.d.ts +0 -2
- package/dist/hooks/extensibility/__tests__/plugin-runner.test.d.ts.map +0 -1
- package/dist/hooks/extensibility/__tests__/plugin-runner.test.js +0 -202
- package/dist/hooks/extensibility/__tests__/plugin-runner.test.js.map +0 -1
- package/dist/hooks/extensibility/__tests__/runtime.test.d.ts +0 -2
- package/dist/hooks/extensibility/__tests__/runtime.test.d.ts.map +0 -1
- package/dist/hooks/extensibility/__tests__/runtime.test.js +0 -198
- package/dist/hooks/extensibility/__tests__/runtime.test.js.map +0 -1
- package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.d.ts +0 -2
- package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.d.ts.map +0 -1
- package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.js +0 -32
- package/dist/hooks/extensibility/__tests__/sdk-public-surface.test.js.map +0 -1
- package/dist/hooks/extensibility/__tests__/sdk.test.d.ts +0 -2
- package/dist/hooks/extensibility/__tests__/sdk.test.d.ts.map +0 -1
- package/dist/hooks/extensibility/__tests__/sdk.test.js +0 -479
- package/dist/hooks/extensibility/__tests__/sdk.test.js.map +0 -1
- package/dist/hud/__tests__/authority.test.d.ts +0 -2
- package/dist/hud/__tests__/authority.test.d.ts.map +0 -1
- package/dist/hud/__tests__/authority.test.js +0 -56
- package/dist/hud/__tests__/authority.test.js.map +0 -1
- package/dist/hud/__tests__/colors.test.d.ts +0 -2
- package/dist/hud/__tests__/colors.test.d.ts.map +0 -1
- package/dist/hud/__tests__/colors.test.js +0 -92
- package/dist/hud/__tests__/colors.test.js.map +0 -1
- package/dist/hud/__tests__/hud-tmux-injection.test.d.ts +0 -10
- package/dist/hud/__tests__/hud-tmux-injection.test.d.ts.map +0 -1
- package/dist/hud/__tests__/hud-tmux-injection.test.js +0 -150
- package/dist/hud/__tests__/hud-tmux-injection.test.js.map +0 -1
- package/dist/hud/__tests__/index.test.d.ts +0 -2
- package/dist/hud/__tests__/index.test.d.ts.map +0 -1
- package/dist/hud/__tests__/index.test.js +0 -180
- package/dist/hud/__tests__/index.test.js.map +0 -1
- package/dist/hud/__tests__/reconcile.test.d.ts +0 -2
- package/dist/hud/__tests__/reconcile.test.d.ts.map +0 -1
- package/dist/hud/__tests__/reconcile.test.js +0 -125
- package/dist/hud/__tests__/reconcile.test.js.map +0 -1
- package/dist/hud/__tests__/render.test.d.ts +0 -2
- package/dist/hud/__tests__/render.test.d.ts.map +0 -1
- package/dist/hud/__tests__/render.test.js +0 -573
- package/dist/hud/__tests__/render.test.js.map +0 -1
- package/dist/hud/__tests__/state.test.d.ts +0 -2
- package/dist/hud/__tests__/state.test.d.ts.map +0 -1
- package/dist/hud/__tests__/state.test.js +0 -618
- package/dist/hud/__tests__/state.test.js.map +0 -1
- package/dist/hud/__tests__/types.test.d.ts +0 -2
- package/dist/hud/__tests__/types.test.d.ts.map +0 -1
- package/dist/hud/__tests__/types.test.js +0 -79
- package/dist/hud/__tests__/types.test.js.map +0 -1
- package/dist/hud/__tests__/watch.test.d.ts +0 -2
- package/dist/hud/__tests__/watch.test.d.ts.map +0 -1
- package/dist/hud/__tests__/watch.test.js +0 -63
- package/dist/hud/__tests__/watch.test.js.map +0 -1
- package/dist/mcp/__tests__/bootstrap.test.d.ts +0 -2
- package/dist/mcp/__tests__/bootstrap.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/bootstrap.test.js +0 -207
- package/dist/mcp/__tests__/bootstrap.test.js.map +0 -1
- package/dist/mcp/__tests__/code-intel-server.test.d.ts +0 -2
- package/dist/mcp/__tests__/code-intel-server.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/code-intel-server.test.js +0 -70
- package/dist/mcp/__tests__/code-intel-server.test.js.map +0 -1
- package/dist/mcp/__tests__/memory-server.test.d.ts +0 -2
- package/dist/mcp/__tests__/memory-server.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/memory-server.test.js +0 -36
- package/dist/mcp/__tests__/memory-server.test.js.map +0 -1
- package/dist/mcp/__tests__/memory-validation.test.d.ts +0 -2
- package/dist/mcp/__tests__/memory-validation.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/memory-validation.test.js +0 -29
- package/dist/mcp/__tests__/memory-validation.test.js.map +0 -1
- package/dist/mcp/__tests__/path-traversal.test.d.ts +0 -2
- package/dist/mcp/__tests__/path-traversal.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/path-traversal.test.js +0 -83
- package/dist/mcp/__tests__/path-traversal.test.js.map +0 -1
- package/dist/mcp/__tests__/server-lifecycle.test.d.ts +0 -2
- package/dist/mcp/__tests__/server-lifecycle.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js +0 -260
- package/dist/mcp/__tests__/server-lifecycle.test.js.map +0 -1
- package/dist/mcp/__tests__/state-paths.test.d.ts +0 -2
- package/dist/mcp/__tests__/state-paths.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/state-paths.test.js +0 -209
- package/dist/mcp/__tests__/state-paths.test.js.map +0 -1
- package/dist/mcp/__tests__/state-server-ralph-phase.test.d.ts +0 -2
- package/dist/mcp/__tests__/state-server-ralph-phase.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/state-server-ralph-phase.test.js +0 -109
- package/dist/mcp/__tests__/state-server-ralph-phase.test.js.map +0 -1
- package/dist/mcp/__tests__/state-server-schema.test.d.ts +0 -2
- package/dist/mcp/__tests__/state-server-schema.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/state-server-schema.test.js +0 -29
- package/dist/mcp/__tests__/state-server-schema.test.js.map +0 -1
- package/dist/mcp/__tests__/state-server-team-tools.test.d.ts +0 -2
- package/dist/mcp/__tests__/state-server-team-tools.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/state-server-team-tools.test.js +0 -35
- package/dist/mcp/__tests__/state-server-team-tools.test.js.map +0 -1
- package/dist/mcp/__tests__/state-server.test.d.ts +0 -2
- package/dist/mcp/__tests__/state-server.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/state-server.test.js +0 -965
- package/dist/mcp/__tests__/state-server.test.js.map +0 -1
- package/dist/mcp/__tests__/trace-server.test.d.ts +0 -2
- package/dist/mcp/__tests__/trace-server.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/trace-server.test.js +0 -119
- package/dist/mcp/__tests__/trace-server.test.js.map +0 -1
- package/dist/mcp/__tests__/wiki-server.test.d.ts +0 -2
- package/dist/mcp/__tests__/wiki-server.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/wiki-server.test.js +0 -30
- package/dist/mcp/__tests__/wiki-server.test.js.map +0 -1
- package/dist/modes/__tests__/base-autoresearch-contract.test.d.ts +0 -2
- package/dist/modes/__tests__/base-autoresearch-contract.test.d.ts.map +0 -1
- package/dist/modes/__tests__/base-autoresearch-contract.test.js +0 -123
- package/dist/modes/__tests__/base-autoresearch-contract.test.js.map +0 -1
- package/dist/modes/__tests__/base-multi-state-compat.test.d.ts +0 -2
- package/dist/modes/__tests__/base-multi-state-compat.test.d.ts.map +0 -1
- package/dist/modes/__tests__/base-multi-state-compat.test.js +0 -38
- package/dist/modes/__tests__/base-multi-state-compat.test.js.map +0 -1
- package/dist/modes/__tests__/base-ralph-contract.test.d.ts +0 -2
- package/dist/modes/__tests__/base-ralph-contract.test.d.ts.map +0 -1
- package/dist/modes/__tests__/base-ralph-contract.test.js +0 -64
- package/dist/modes/__tests__/base-ralph-contract.test.js.map +0 -1
- package/dist/modes/__tests__/base-session-scope.test.d.ts +0 -2
- package/dist/modes/__tests__/base-session-scope.test.d.ts.map +0 -1
- package/dist/modes/__tests__/base-session-scope.test.js +0 -98
- package/dist/modes/__tests__/base-session-scope.test.js.map +0 -1
- package/dist/modes/__tests__/base-tmux-pane.test.d.ts +0 -2
- package/dist/modes/__tests__/base-tmux-pane.test.d.ts.map +0 -1
- package/dist/modes/__tests__/base-tmux-pane.test.js +0 -39
- package/dist/modes/__tests__/base-tmux-pane.test.js.map +0 -1
- package/dist/notifications/__tests__/config.test.d.ts +0 -2
- package/dist/notifications/__tests__/config.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/config.test.js +0 -269
- package/dist/notifications/__tests__/config.test.js.map +0 -1
- package/dist/notifications/__tests__/custom-alias-enablement.test.d.ts +0 -2
- package/dist/notifications/__tests__/custom-alias-enablement.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/custom-alias-enablement.test.js +0 -84
- package/dist/notifications/__tests__/custom-alias-enablement.test.js.map +0 -1
- package/dist/notifications/__tests__/dispatch-cooldown.test.d.ts +0 -5
- package/dist/notifications/__tests__/dispatch-cooldown.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/dispatch-cooldown.test.js +0 -100
- package/dist/notifications/__tests__/dispatch-cooldown.test.js.map +0 -1
- package/dist/notifications/__tests__/dispatcher.test.d.ts +0 -2
- package/dist/notifications/__tests__/dispatcher.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/dispatcher.test.js +0 -202
- package/dist/notifications/__tests__/dispatcher.test.js.map +0 -1
- package/dist/notifications/__tests__/formatter.test.d.ts +0 -2
- package/dist/notifications/__tests__/formatter.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/formatter.test.js +0 -270
- package/dist/notifications/__tests__/formatter.test.js.map +0 -1
- package/dist/notifications/__tests__/hook-config.test.d.ts +0 -5
- package/dist/notifications/__tests__/hook-config.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/hook-config.test.js +0 -139
- package/dist/notifications/__tests__/hook-config.test.js.map +0 -1
- package/dist/notifications/__tests__/idle-cooldown.test.d.ts +0 -5
- package/dist/notifications/__tests__/idle-cooldown.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/idle-cooldown.test.js +0 -209
- package/dist/notifications/__tests__/idle-cooldown.test.js.map +0 -1
- package/dist/notifications/__tests__/index.test.d.ts +0 -2
- package/dist/notifications/__tests__/index.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/index.test.js +0 -188
- package/dist/notifications/__tests__/index.test.js.map +0 -1
- package/dist/notifications/__tests__/lifecycle-dedupe.test.d.ts +0 -2
- package/dist/notifications/__tests__/lifecycle-dedupe.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/lifecycle-dedupe.test.js +0 -86
- package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +0 -1
- package/dist/notifications/__tests__/notifier.test.d.ts +0 -2
- package/dist/notifications/__tests__/notifier.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/notifier.test.js +0 -239
- package/dist/notifications/__tests__/notifier.test.js.map +0 -1
- package/dist/notifications/__tests__/profiles.test.d.ts +0 -2
- package/dist/notifications/__tests__/profiles.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/profiles.test.js +0 -404
- package/dist/notifications/__tests__/profiles.test.js.map +0 -1
- package/dist/notifications/__tests__/reply-config.test.d.ts +0 -2
- package/dist/notifications/__tests__/reply-config.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/reply-config.test.js +0 -79
- package/dist/notifications/__tests__/reply-config.test.js.map +0 -1
- package/dist/notifications/__tests__/reply-listener.test.d.ts +0 -2
- package/dist/notifications/__tests__/reply-listener.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/reply-listener.test.js +0 -723
- package/dist/notifications/__tests__/reply-listener.test.js.map +0 -1
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.d.ts +0 -2
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js +0 -93
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js.map +0 -1
- package/dist/notifications/__tests__/session-registry.test.d.ts +0 -2
- package/dist/notifications/__tests__/session-registry.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/session-registry.test.js +0 -234
- package/dist/notifications/__tests__/session-registry.test.js.map +0 -1
- package/dist/notifications/__tests__/session-status.test.d.ts +0 -2
- package/dist/notifications/__tests__/session-status.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/session-status.test.js +0 -249
- package/dist/notifications/__tests__/session-status.test.js.map +0 -1
- package/dist/notifications/__tests__/temp-mode.test.d.ts +0 -2
- package/dist/notifications/__tests__/temp-mode.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/temp-mode.test.js +0 -172
- package/dist/notifications/__tests__/temp-mode.test.js.map +0 -1
- package/dist/notifications/__tests__/template-engine.test.d.ts +0 -5
- package/dist/notifications/__tests__/template-engine.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/template-engine.test.js +0 -158
- package/dist/notifications/__tests__/template-engine.test.js.map +0 -1
- package/dist/notifications/__tests__/tmux-detector.test.d.ts +0 -2
- package/dist/notifications/__tests__/tmux-detector.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/tmux-detector.test.js +0 -208
- package/dist/notifications/__tests__/tmux-detector.test.js.map +0 -1
- package/dist/notifications/__tests__/tmux.test.d.ts +0 -2
- package/dist/notifications/__tests__/tmux.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/tmux.test.js +0 -285
- package/dist/notifications/__tests__/tmux.test.js.map +0 -1
- package/dist/notifications/__tests__/verbosity.test.d.ts +0 -2
- package/dist/notifications/__tests__/verbosity.test.d.ts.map +0 -1
- package/dist/notifications/__tests__/verbosity.test.js +0 -237
- package/dist/notifications/__tests__/verbosity.test.js.map +0 -1
- package/dist/openclaw/__tests__/config.test.d.ts +0 -6
- package/dist/openclaw/__tests__/config.test.d.ts.map +0 -1
- package/dist/openclaw/__tests__/config.test.js +0 -344
- package/dist/openclaw/__tests__/config.test.js.map +0 -1
- package/dist/openclaw/__tests__/dispatcher.test.d.ts +0 -5
- package/dist/openclaw/__tests__/dispatcher.test.d.ts.map +0 -1
- package/dist/openclaw/__tests__/dispatcher.test.js +0 -169
- package/dist/openclaw/__tests__/dispatcher.test.js.map +0 -1
- package/dist/openclaw/__tests__/index.test.d.ts +0 -6
- package/dist/openclaw/__tests__/index.test.d.ts.map +0 -1
- package/dist/openclaw/__tests__/index.test.js +0 -382
- package/dist/openclaw/__tests__/index.test.js.map +0 -1
- package/dist/pipeline/__tests__/orchestrator.test.d.ts +0 -2
- package/dist/pipeline/__tests__/orchestrator.test.d.ts.map +0 -1
- package/dist/pipeline/__tests__/orchestrator.test.js +0 -505
- package/dist/pipeline/__tests__/orchestrator.test.js.map +0 -1
- package/dist/pipeline/__tests__/stages.test.d.ts +0 -2
- package/dist/pipeline/__tests__/stages.test.d.ts.map +0 -1
- package/dist/pipeline/__tests__/stages.test.js +0 -754
- package/dist/pipeline/__tests__/stages.test.js.map +0 -1
- package/dist/pipeline/stages/ralph-verify.d.ts +0 -53
- package/dist/pipeline/stages/ralph-verify.d.ts.map +0 -1
- package/dist/pipeline/stages/ralph-verify.js.map +0 -1
- package/dist/pipeline/stages/ralplan.d.ts +0 -25
- package/dist/pipeline/stages/ralplan.d.ts.map +0 -1
- package/dist/pipeline/stages/ralplan.js.map +0 -1
- package/dist/planning/__tests__/artifacts.test.d.ts +0 -2
- package/dist/planning/__tests__/artifacts.test.d.ts.map +0 -1
- package/dist/planning/__tests__/artifacts.test.js +0 -544
- package/dist/planning/__tests__/artifacts.test.js.map +0 -1
- package/dist/question/__tests__/client.test.d.ts +0 -2
- package/dist/question/__tests__/client.test.d.ts.map +0 -1
- package/dist/question/__tests__/client.test.js +0 -90
- package/dist/question/__tests__/client.test.js.map +0 -1
- package/dist/question/__tests__/deep-interview.test.d.ts +0 -2
- package/dist/question/__tests__/deep-interview.test.d.ts.map +0 -1
- package/dist/question/__tests__/deep-interview.test.js +0 -209
- package/dist/question/__tests__/deep-interview.test.js.map +0 -1
- package/dist/question/__tests__/policy.test.d.ts +0 -2
- package/dist/question/__tests__/policy.test.d.ts.map +0 -1
- package/dist/question/__tests__/policy.test.js +0 -107
- package/dist/question/__tests__/policy.test.js.map +0 -1
- package/dist/question/__tests__/renderer.test.d.ts +0 -2
- package/dist/question/__tests__/renderer.test.d.ts.map +0 -1
- package/dist/question/__tests__/renderer.test.js +0 -707
- package/dist/question/__tests__/renderer.test.js.map +0 -1
- package/dist/question/__tests__/state.test.d.ts +0 -2
- package/dist/question/__tests__/state.test.d.ts.map +0 -1
- package/dist/question/__tests__/state.test.js +0 -102
- package/dist/question/__tests__/state.test.js.map +0 -1
- package/dist/question/__tests__/types.test.d.ts +0 -2
- package/dist/question/__tests__/types.test.d.ts.map +0 -1
- package/dist/question/__tests__/types.test.js +0 -65
- package/dist/question/__tests__/types.test.js.map +0 -1
- package/dist/question/__tests__/ui.test.d.ts +0 -2
- package/dist/question/__tests__/ui.test.d.ts.map +0 -1
- package/dist/question/__tests__/ui.test.js +0 -446
- package/dist/question/__tests__/ui.test.js.map +0 -1
- package/dist/ralph/__tests__/persistence.test.d.ts +0 -2
- package/dist/ralph/__tests__/persistence.test.d.ts.map +0 -1
- package/dist/ralph/__tests__/persistence.test.js +0 -116
- package/dist/ralph/__tests__/persistence.test.js.map +0 -1
- package/dist/ralph/contract.d.ts +0 -17
- package/dist/ralph/persistence.js.map +0 -1
- package/dist/ralplan/__tests__/runtime.test.d.ts +0 -2
- package/dist/ralplan/__tests__/runtime.test.d.ts.map +0 -1
- package/dist/ralplan/__tests__/runtime.test.js +0 -165
- package/dist/ralplan/__tests__/runtime.test.js.map +0 -1
- package/dist/ralplan/runtime.d.ts +0 -52
- package/dist/ralplan/runtime.d.ts.map +0 -1
- package/dist/ralplan/runtime.js.map +0 -1
- package/dist/runtime/__tests__/bridge.test.d.ts +0 -2
- package/dist/runtime/__tests__/bridge.test.d.ts.map +0 -1
- package/dist/runtime/__tests__/bridge.test.js +0 -194
- package/dist/runtime/__tests__/bridge.test.js.map +0 -1
- package/dist/runtime/__tests__/run-loop.test.d.ts +0 -2
- package/dist/runtime/__tests__/run-loop.test.d.ts.map +0 -1
- package/dist/runtime/__tests__/run-loop.test.js +0 -35
- package/dist/runtime/__tests__/run-loop.test.js.map +0 -1
- package/dist/runtime/__tests__/run-outcome.test.d.ts +0 -2
- package/dist/runtime/__tests__/run-outcome.test.d.ts.map +0 -1
- package/dist/runtime/__tests__/run-outcome.test.js +0 -102
- package/dist/runtime/__tests__/run-outcome.test.js.map +0 -1
- package/dist/runtime/__tests__/run-state.test.d.ts +0 -2
- package/dist/runtime/__tests__/run-state.test.d.ts.map +0 -1
- package/dist/runtime/__tests__/run-state.test.js +0 -37
- package/dist/runtime/__tests__/run-state.test.js.map +0 -1
- package/dist/scripts/__tests__/codex-native-hook.test.d.ts +0 -2
- package/dist/scripts/__tests__/codex-native-hook.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +0 -6788
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +0 -1
- package/dist/scripts/__tests__/generate-release-body.test.d.ts +0 -2
- package/dist/scripts/__tests__/generate-release-body.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/generate-release-body.test.js +0 -233
- package/dist/scripts/__tests__/generate-release-body.test.js.map +0 -1
- package/dist/scripts/__tests__/hook-derived-watcher.test.d.ts +0 -2
- package/dist/scripts/__tests__/hook-derived-watcher.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/hook-derived-watcher.test.js +0 -195
- package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +0 -1
- package/dist/scripts/__tests__/postinstall.test.d.ts +0 -2
- package/dist/scripts/__tests__/postinstall.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/postinstall.test.js +0 -92
- package/dist/scripts/__tests__/postinstall.test.js.map +0 -1
- package/dist/scripts/__tests__/prompt-inventory.test.d.ts +0 -2
- package/dist/scripts/__tests__/prompt-inventory.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/prompt-inventory.test.js +0 -56
- package/dist/scripts/__tests__/prompt-inventory.test.js.map +0 -1
- package/dist/scripts/__tests__/run-test-files.test.d.ts +0 -2
- package/dist/scripts/__tests__/run-test-files.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/run-test-files.test.js +0 -62
- package/dist/scripts/__tests__/run-test-files.test.js.map +0 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.d.ts +0 -2
- package/dist/scripts/__tests__/smoke-packed-install.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js +0 -135
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +0 -1
- package/dist/scripts/__tests__/test-reply-listener-live.test.d.ts +0 -2
- package/dist/scripts/__tests__/test-reply-listener-live.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/test-reply-listener-live.test.js +0 -82
- package/dist/scripts/__tests__/test-reply-listener-live.test.js.map +0 -1
- package/dist/scripts/__tests__/verify-native-agents.test.d.ts +0 -2
- package/dist/scripts/__tests__/verify-native-agents.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/verify-native-agents.test.js +0 -166
- package/dist/scripts/__tests__/verify-native-agents.test.js.map +0 -1
- package/dist/scripts/eval/eval-candidate-handoff.d.ts +0 -2
- package/dist/scripts/eval/eval-candidate-handoff.d.ts.map +0 -1
- package/dist/scripts/eval/eval-candidate-handoff.js +0 -11
- package/dist/scripts/eval/eval-candidate-handoff.js.map +0 -1
- package/dist/scripts/eval/eval-cli-discoverability.d.ts +0 -3
- package/dist/scripts/eval/eval-cli-discoverability.d.ts.map +0 -1
- package/dist/scripts/eval/eval-cli-discoverability.js +0 -37
- package/dist/scripts/eval/eval-cli-discoverability.js.map +0 -1
- package/dist/scripts/eval/eval-fresh-run-tagging.d.ts +0 -2
- package/dist/scripts/eval/eval-fresh-run-tagging.d.ts.map +0 -1
- package/dist/scripts/eval/eval-fresh-run-tagging.js +0 -11
- package/dist/scripts/eval/eval-fresh-run-tagging.js.map +0 -1
- package/dist/scripts/eval/eval-help-consistency.d.ts +0 -2
- package/dist/scripts/eval/eval-help-consistency.d.ts.map +0 -1
- package/dist/scripts/eval/eval-help-consistency.js +0 -12
- package/dist/scripts/eval/eval-help-consistency.js.map +0 -1
- package/dist/scripts/eval/eval-in-action-cat-shellout-demo.d.ts +0 -2
- package/dist/scripts/eval/eval-in-action-cat-shellout-demo.d.ts.map +0 -1
- package/dist/scripts/eval/eval-in-action-cat-shellout-demo.js +0 -31
- package/dist/scripts/eval/eval-in-action-cat-shellout-demo.js.map +0 -1
- package/dist/scripts/eval/eval-parity-smoke.d.ts +0 -2
- package/dist/scripts/eval/eval-parity-smoke.d.ts.map +0 -1
- package/dist/scripts/eval/eval-parity-smoke.js +0 -23
- package/dist/scripts/eval/eval-parity-smoke.js.map +0 -1
- package/dist/scripts/eval/eval-parity-sweep.d.ts +0 -2
- package/dist/scripts/eval/eval-parity-sweep.d.ts.map +0 -1
- package/dist/scripts/eval/eval-parity-sweep.js +0 -29
- package/dist/scripts/eval/eval-parity-sweep.js.map +0 -1
- package/dist/scripts/eval/eval-resume-dirty-guard.d.ts +0 -2
- package/dist/scripts/eval/eval-resume-dirty-guard.d.ts.map +0 -1
- package/dist/scripts/eval/eval-resume-dirty-guard.js +0 -11
- package/dist/scripts/eval/eval-resume-dirty-guard.js.map +0 -1
- package/dist/scripts/eval/eval-security-path-traversal.d.ts +0 -3
- package/dist/scripts/eval/eval-security-path-traversal.d.ts.map +0 -1
- package/dist/scripts/eval/eval-security-path-traversal.js +0 -35
- package/dist/scripts/eval/eval-security-path-traversal.js.map +0 -1
- package/dist/scripts/notify-hook/__tests__/operational-events.test.d.ts +0 -2
- package/dist/scripts/notify-hook/__tests__/operational-events.test.d.ts.map +0 -1
- package/dist/scripts/notify-hook/__tests__/operational-events.test.js +0 -24
- package/dist/scripts/notify-hook/__tests__/operational-events.test.js.map +0 -1
- package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts +0 -2
- package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts.map +0 -1
- package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js +0 -153
- package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js.map +0 -1
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts +0 -22
- package/dist/session-history/__tests__/search.test.d.ts +0 -2
- package/dist/session-history/__tests__/search.test.d.ts.map +0 -1
- package/dist/session-history/__tests__/search.test.js +0 -150
- package/dist/session-history/__tests__/search.test.js.map +0 -1
- package/dist/sidecar/__tests__/boundary.test.d.ts +0 -2
- package/dist/sidecar/__tests__/boundary.test.d.ts.map +0 -1
- package/dist/sidecar/__tests__/boundary.test.js +0 -48
- package/dist/sidecar/__tests__/boundary.test.js.map +0 -1
- package/dist/sidecar/__tests__/collector.test.d.ts +0 -2
- package/dist/sidecar/__tests__/collector.test.d.ts.map +0 -1
- package/dist/sidecar/__tests__/collector.test.js +0 -162
- package/dist/sidecar/__tests__/collector.test.js.map +0 -1
- package/dist/sidecar/__tests__/render.test.d.ts +0 -2
- package/dist/sidecar/__tests__/render.test.d.ts.map +0 -1
- package/dist/sidecar/__tests__/render.test.js +0 -67
- package/dist/sidecar/__tests__/render.test.js.map +0 -1
- package/dist/sidecar/__tests__/tmux.test.d.ts +0 -2
- package/dist/sidecar/__tests__/tmux.test.d.ts.map +0 -1
- package/dist/sidecar/__tests__/tmux.test.js +0 -30
- package/dist/sidecar/__tests__/tmux.test.js.map +0 -1
- package/dist/sidecar/__tests__/watch.test.d.ts +0 -2
- package/dist/sidecar/__tests__/watch.test.d.ts.map +0 -1
- package/dist/sidecar/__tests__/watch.test.js +0 -42
- package/dist/sidecar/__tests__/watch.test.js.map +0 -1
- package/dist/state/__tests__/mode-state-context.test.d.ts +0 -2
- package/dist/state/__tests__/mode-state-context.test.d.ts.map +0 -1
- package/dist/state/__tests__/mode-state-context.test.js +0 -35
- package/dist/state/__tests__/mode-state-context.test.js.map +0 -1
- package/dist/state/__tests__/operations-ralph-phase.test.d.ts +0 -2
- package/dist/state/__tests__/operations-ralph-phase.test.d.ts.map +0 -1
- package/dist/state/__tests__/operations-ralph-phase.test.js +0 -103
- package/dist/state/__tests__/operations-ralph-phase.test.js.map +0 -1
- package/dist/state/__tests__/operations.test.d.ts +0 -2
- package/dist/state/__tests__/operations.test.d.ts.map +0 -1
- package/dist/state/__tests__/operations.test.js +0 -439
- package/dist/state/__tests__/operations.test.js.map +0 -1
- package/dist/state/__tests__/path-traversal.test.d.ts +0 -2
- package/dist/state/__tests__/path-traversal.test.d.ts.map +0 -1
- package/dist/state/__tests__/path-traversal.test.js +0 -49
- package/dist/state/__tests__/path-traversal.test.js.map +0 -1
- package/dist/state/__tests__/skill-active.test.d.ts +0 -2
- package/dist/state/__tests__/skill-active.test.d.ts.map +0 -1
- package/dist/state/__tests__/skill-active.test.js +0 -160
- package/dist/state/__tests__/skill-active.test.js.map +0 -1
- package/dist/state/__tests__/workflow-transition.test.d.ts +0 -2
- package/dist/state/__tests__/workflow-transition.test.d.ts.map +0 -1
- package/dist/state/__tests__/workflow-transition.test.js +0 -77
- package/dist/state/__tests__/workflow-transition.test.js.map +0 -1
- package/dist/subagents/__tests__/tracker.test.d.ts +0 -2
- package/dist/subagents/__tests__/tracker.test.d.ts.map +0 -1
- package/dist/subagents/__tests__/tracker.test.js +0 -47
- package/dist/subagents/__tests__/tracker.test.js.map +0 -1
- package/dist/team/__tests__/allocation-policy.test.d.ts +0 -2
- package/dist/team/__tests__/allocation-policy.test.d.ts.map +0 -1
- package/dist/team/__tests__/allocation-policy.test.js +0 -111
- package/dist/team/__tests__/allocation-policy.test.js.map +0 -1
- package/dist/team/__tests__/api-interop.test.d.ts +0 -2
- package/dist/team/__tests__/api-interop.test.d.ts.map +0 -1
- package/dist/team/__tests__/api-interop.test.js +0 -2262
- package/dist/team/__tests__/api-interop.test.js.map +0 -1
- package/dist/team/__tests__/commit-hygiene.test.d.ts +0 -2
- package/dist/team/__tests__/commit-hygiene.test.d.ts.map +0 -1
- package/dist/team/__tests__/commit-hygiene.test.js +0 -93
- package/dist/team/__tests__/commit-hygiene.test.js.map +0 -1
- package/dist/team/__tests__/cross-rebase-smoke.test.d.ts +0 -2
- package/dist/team/__tests__/cross-rebase-smoke.test.d.ts.map +0 -1
- package/dist/team/__tests__/cross-rebase-smoke.test.js +0 -161
- package/dist/team/__tests__/cross-rebase-smoke.test.js.map +0 -1
- package/dist/team/__tests__/current-task-baseline.test.d.ts +0 -2
- package/dist/team/__tests__/current-task-baseline.test.d.ts.map +0 -1
- package/dist/team/__tests__/current-task-baseline.test.js +0 -87
- package/dist/team/__tests__/current-task-baseline.test.js.map +0 -1
- package/dist/team/__tests__/delegation-policy.test.d.ts +0 -2
- package/dist/team/__tests__/delegation-policy.test.d.ts.map +0 -1
- package/dist/team/__tests__/delegation-policy.test.js +0 -69
- package/dist/team/__tests__/delegation-policy.test.js.map +0 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.d.ts +0 -2
- package/dist/team/__tests__/delivery-e2e-smoke.test.d.ts.map +0 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.js +0 -679
- package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +0 -1
- package/dist/team/__tests__/events.test.d.ts +0 -2
- package/dist/team/__tests__/events.test.d.ts.map +0 -1
- package/dist/team/__tests__/events.test.js +0 -313
- package/dist/team/__tests__/events.test.js.map +0 -1
- package/dist/team/__tests__/followup-planner.test.d.ts +0 -2
- package/dist/team/__tests__/followup-planner.test.d.ts.map +0 -1
- package/dist/team/__tests__/followup-planner.test.js +0 -84
- package/dist/team/__tests__/followup-planner.test.js.map +0 -1
- package/dist/team/__tests__/hardening-e2e.test.d.ts +0 -2
- package/dist/team/__tests__/hardening-e2e.test.d.ts.map +0 -1
- package/dist/team/__tests__/hardening-e2e.test.js +0 -98
- package/dist/team/__tests__/hardening-e2e.test.js.map +0 -1
- package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts +0 -2
- package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts.map +0 -1
- package/dist/team/__tests__/hook-primary-e2e-contract.test.js +0 -78
- package/dist/team/__tests__/hook-primary-e2e-contract.test.js.map +0 -1
- package/dist/team/__tests__/idle-nudge.test.d.ts +0 -2
- package/dist/team/__tests__/idle-nudge.test.d.ts.map +0 -1
- package/dist/team/__tests__/idle-nudge.test.js +0 -230
- package/dist/team/__tests__/idle-nudge.test.js.map +0 -1
- package/dist/team/__tests__/leader-activity.test.d.ts +0 -2
- package/dist/team/__tests__/leader-activity.test.d.ts.map +0 -1
- package/dist/team/__tests__/leader-activity.test.js +0 -261
- package/dist/team/__tests__/leader-activity.test.js.map +0 -1
- package/dist/team/__tests__/mcp-comm.test.d.ts +0 -2
- package/dist/team/__tests__/mcp-comm.test.d.ts.map +0 -1
- package/dist/team/__tests__/mcp-comm.test.js +0 -289
- package/dist/team/__tests__/mcp-comm.test.js.map +0 -1
- package/dist/team/__tests__/model-contract.test.d.ts +0 -2
- package/dist/team/__tests__/model-contract.test.d.ts.map +0 -1
- package/dist/team/__tests__/model-contract.test.js +0 -171
- package/dist/team/__tests__/model-contract.test.js.map +0 -1
- package/dist/team/__tests__/orchestrator.test.d.ts +0 -2
- package/dist/team/__tests__/orchestrator.test.d.ts.map +0 -1
- package/dist/team/__tests__/orchestrator.test.js +0 -111
- package/dist/team/__tests__/orchestrator.test.js.map +0 -1
- package/dist/team/__tests__/phase-controller.test.d.ts +0 -2
- package/dist/team/__tests__/phase-controller.test.d.ts.map +0 -1
- package/dist/team/__tests__/phase-controller.test.js +0 -50
- package/dist/team/__tests__/phase-controller.test.js.map +0 -1
- package/dist/team/__tests__/rebalance-policy.test.d.ts +0 -2
- package/dist/team/__tests__/rebalance-policy.test.d.ts.map +0 -1
- package/dist/team/__tests__/rebalance-policy.test.js +0 -168
- package/dist/team/__tests__/rebalance-policy.test.js.map +0 -1
- package/dist/team/__tests__/repo-aware-decomposition.test.d.ts +0 -2
- package/dist/team/__tests__/repo-aware-decomposition.test.d.ts.map +0 -1
- package/dist/team/__tests__/repo-aware-decomposition.test.js +0 -136
- package/dist/team/__tests__/repo-aware-decomposition.test.js.map +0 -1
- package/dist/team/__tests__/role-router.test.d.ts +0 -2
- package/dist/team/__tests__/role-router.test.d.ts.map +0 -1
- package/dist/team/__tests__/role-router.test.js +0 -263
- package/dist/team/__tests__/role-router.test.js.map +0 -1
- package/dist/team/__tests__/runtime-cli.test.d.ts +0 -2
- package/dist/team/__tests__/runtime-cli.test.d.ts.map +0 -1
- package/dist/team/__tests__/runtime-cli.test.js +0 -304
- package/dist/team/__tests__/runtime-cli.test.js.map +0 -1
- package/dist/team/__tests__/runtime.test.d.ts +0 -2
- package/dist/team/__tests__/runtime.test.d.ts.map +0 -1
- package/dist/team/__tests__/runtime.test.js +0 -5734
- package/dist/team/__tests__/runtime.test.js.map +0 -1
- package/dist/team/__tests__/scaling.test.d.ts +0 -2
- package/dist/team/__tests__/scaling.test.d.ts.map +0 -1
- package/dist/team/__tests__/scaling.test.js +0 -1005
- package/dist/team/__tests__/scaling.test.js.map +0 -1
- package/dist/team/__tests__/shutdown-fallback.test.d.ts +0 -2
- package/dist/team/__tests__/shutdown-fallback.test.d.ts.map +0 -1
- package/dist/team/__tests__/shutdown-fallback.test.js +0 -125
- package/dist/team/__tests__/shutdown-fallback.test.js.map +0 -1
- package/dist/team/__tests__/state-root.test.d.ts +0 -2
- package/dist/team/__tests__/state-root.test.d.ts.map +0 -1
- package/dist/team/__tests__/state-root.test.js +0 -195
- package/dist/team/__tests__/state-root.test.js.map +0 -1
- package/dist/team/__tests__/state.test.d.ts +0 -2
- package/dist/team/__tests__/state.test.d.ts.map +0 -1
- package/dist/team/__tests__/state.test.js +0 -1859
- package/dist/team/__tests__/state.test.js.map +0 -1
- package/dist/team/__tests__/team-identity.test.d.ts +0 -2
- package/dist/team/__tests__/team-identity.test.d.ts.map +0 -1
- package/dist/team/__tests__/team-identity.test.js +0 -166
- package/dist/team/__tests__/team-identity.test.js.map +0 -1
- package/dist/team/__tests__/team-ops-contract.test.d.ts +0 -2
- package/dist/team/__tests__/team-ops-contract.test.d.ts.map +0 -1
- package/dist/team/__tests__/team-ops-contract.test.js +0 -96
- package/dist/team/__tests__/team-ops-contract.test.js.map +0 -1
- package/dist/team/__tests__/tmux-claude-workers-demo.test.d.ts +0 -2
- package/dist/team/__tests__/tmux-claude-workers-demo.test.d.ts.map +0 -1
- package/dist/team/__tests__/tmux-claude-workers-demo.test.js +0 -191
- package/dist/team/__tests__/tmux-claude-workers-demo.test.js.map +0 -1
- package/dist/team/__tests__/tmux-session.test.d.ts +0 -2
- package/dist/team/__tests__/tmux-session.test.d.ts.map +0 -1
- package/dist/team/__tests__/tmux-session.test.js +0 -3785
- package/dist/team/__tests__/tmux-session.test.js.map +0 -1
- package/dist/team/__tests__/tmux-test-fixture.d.ts +0 -20
- package/dist/team/__tests__/tmux-test-fixture.d.ts.map +0 -1
- package/dist/team/__tests__/tmux-test-fixture.js +0 -152
- package/dist/team/__tests__/tmux-test-fixture.js.map +0 -1
- package/dist/team/__tests__/tmux-test-fixture.test.d.ts +0 -2
- package/dist/team/__tests__/tmux-test-fixture.test.d.ts.map +0 -1
- package/dist/team/__tests__/tmux-test-fixture.test.js +0 -113
- package/dist/team/__tests__/tmux-test-fixture.test.js.map +0 -1
- package/dist/team/__tests__/worker-bootstrap.test.d.ts +0 -2
- package/dist/team/__tests__/worker-bootstrap.test.d.ts.map +0 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +0 -685
- package/dist/team/__tests__/worker-bootstrap.test.js.map +0 -1
- package/dist/team/__tests__/worker-runtime-identity.test.d.ts +0 -2
- package/dist/team/__tests__/worker-runtime-identity.test.d.ts.map +0 -1
- package/dist/team/__tests__/worker-runtime-identity.test.js +0 -250
- package/dist/team/__tests__/worker-runtime-identity.test.js.map +0 -1
- package/dist/team/__tests__/worktree.test.d.ts +0 -2
- package/dist/team/__tests__/worktree.test.d.ts.map +0 -1
- package/dist/team/__tests__/worktree.test.js +0 -317
- package/dist/team/__tests__/worktree.test.js.map +0 -1
- package/dist/utils/__tests__/agents-md.test.d.ts +0 -2
- package/dist/utils/__tests__/agents-md.test.d.ts.map +0 -1
- package/dist/utils/__tests__/agents-md.test.js +0 -52
- package/dist/utils/__tests__/agents-md.test.js.map +0 -1
- package/dist/utils/__tests__/agents-model-table.test.d.ts +0 -2
- package/dist/utils/__tests__/agents-model-table.test.d.ts.map +0 -1
- package/dist/utils/__tests__/agents-model-table.test.js +0 -104
- package/dist/utils/__tests__/agents-model-table.test.js.map +0 -1
- package/dist/utils/__tests__/dep-versions.test.d.ts +0 -2
- package/dist/utils/__tests__/dep-versions.test.d.ts.map +0 -1
- package/dist/utils/__tests__/dep-versions.test.js +0 -46
- package/dist/utils/__tests__/dep-versions.test.js.map +0 -1
- package/dist/utils/__tests__/package.test.d.ts +0 -2
- package/dist/utils/__tests__/package.test.d.ts.map +0 -1
- package/dist/utils/__tests__/package.test.js +0 -21
- package/dist/utils/__tests__/package.test.js.map +0 -1
- package/dist/utils/__tests__/paths.test.d.ts +0 -2
- package/dist/utils/__tests__/paths.test.d.ts.map +0 -1
- package/dist/utils/__tests__/paths.test.js +0 -541
- package/dist/utils/__tests__/paths.test.js.map +0 -1
- package/dist/utils/__tests__/platform-command.test.d.ts +0 -2
- package/dist/utils/__tests__/platform-command.test.d.ts.map +0 -1
- package/dist/utils/__tests__/platform-command.test.js +0 -410
- package/dist/utils/__tests__/platform-command.test.js.map +0 -1
- package/dist/utils/__tests__/repo-deps.test.d.ts +0 -2
- package/dist/utils/__tests__/repo-deps.test.d.ts.map +0 -1
- package/dist/utils/__tests__/repo-deps.test.js +0 -71
- package/dist/utils/__tests__/repo-deps.test.js.map +0 -1
- package/dist/verification/__tests__/ci-rust-gates.test.d.ts +0 -2
- package/dist/verification/__tests__/ci-rust-gates.test.d.ts.map +0 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +0 -89
- package/dist/verification/__tests__/ci-rust-gates.test.js.map +0 -1
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.d.ts +0 -2
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.d.ts.map +0 -1
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +0 -54
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +0 -1
- package/dist/verification/__tests__/explore-harness-release-workflow.test.d.ts +0 -2
- package/dist/verification/__tests__/explore-harness-release-workflow.test.d.ts.map +0 -1
- package/dist/verification/__tests__/explore-harness-release-workflow.test.js +0 -73
- package/dist/verification/__tests__/explore-harness-release-workflow.test.js.map +0 -1
- package/dist/verification/__tests__/native-release-manifest.test.d.ts +0 -2
- package/dist/verification/__tests__/native-release-manifest.test.d.ts.map +0 -1
- package/dist/verification/__tests__/native-release-manifest.test.js +0 -80
- package/dist/verification/__tests__/native-release-manifest.test.js.map +0 -1
- package/dist/verification/__tests__/pr-check-workflow.test.d.ts +0 -2
- package/dist/verification/__tests__/pr-check-workflow.test.d.ts.map +0 -1
- package/dist/verification/__tests__/pr-check-workflow.test.js +0 -27
- package/dist/verification/__tests__/pr-check-workflow.test.js.map +0 -1
- package/dist/verification/__tests__/ralph-persistence-gate.test.d.ts +0 -2
- package/dist/verification/__tests__/ralph-persistence-gate.test.d.ts.map +0 -1
- package/dist/verification/__tests__/ralph-persistence-gate.test.js +0 -55
- package/dist/verification/__tests__/ralph-persistence-gate.test.js.map +0 -1
- package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.d.ts +0 -2
- package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.d.ts.map +0 -1
- package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.js +0 -32
- package/dist/verification/__tests__/rust-runtime-thin-adapter-gate.test.js.map +0 -1
- package/dist/verification/__tests__/verifier.test.d.ts +0 -2
- package/dist/verification/__tests__/verifier.test.d.ts.map +0 -1
- package/dist/verification/__tests__/verifier.test.js +0 -113
- package/dist/verification/__tests__/verifier.test.js.map +0 -1
- package/dist/visual/__tests__/verdict.test.d.ts +0 -2
- package/dist/visual/__tests__/verdict.test.d.ts.map +0 -1
- package/dist/visual/__tests__/verdict.test.js +0 -81
- package/dist/visual/__tests__/verdict.test.js.map +0 -1
- package/dist/wiki/__tests__/cjk-tokenize.test.d.ts +0 -12
- package/dist/wiki/__tests__/cjk-tokenize.test.d.ts.map +0 -1
- package/dist/wiki/__tests__/cjk-tokenize.test.js +0 -139
- package/dist/wiki/__tests__/cjk-tokenize.test.js.map +0 -1
- package/dist/wiki/__tests__/crlf-parse.test.d.ts +0 -2
- package/dist/wiki/__tests__/crlf-parse.test.d.ts.map +0 -1
- package/dist/wiki/__tests__/crlf-parse.test.js +0 -24
- package/dist/wiki/__tests__/crlf-parse.test.js.map +0 -1
- package/dist/wiki/__tests__/escape-newline.test.d.ts +0 -2
- package/dist/wiki/__tests__/escape-newline.test.d.ts.map +0 -1
- package/dist/wiki/__tests__/escape-newline.test.js +0 -45
- package/dist/wiki/__tests__/escape-newline.test.js.map +0 -1
- package/dist/wiki/__tests__/ingest.test.d.ts +0 -5
- package/dist/wiki/__tests__/ingest.test.d.ts.map +0 -1
- package/dist/wiki/__tests__/ingest.test.js +0 -181
- package/dist/wiki/__tests__/ingest.test.js.map +0 -1
- package/dist/wiki/__tests__/lint.test.d.ts +0 -5
- package/dist/wiki/__tests__/lint.test.d.ts.map +0 -1
- package/dist/wiki/__tests__/lint.test.js +0 -163
- package/dist/wiki/__tests__/lint.test.js.map +0 -1
- package/dist/wiki/__tests__/query.test.d.ts +0 -5
- package/dist/wiki/__tests__/query.test.d.ts.map +0 -1
- package/dist/wiki/__tests__/query.test.js +0 -141
- package/dist/wiki/__tests__/query.test.js.map +0 -1
- package/dist/wiki/__tests__/reserved-file-guard.test.d.ts +0 -2
- package/dist/wiki/__tests__/reserved-file-guard.test.d.ts.map +0 -1
- package/dist/wiki/__tests__/reserved-file-guard.test.js +0 -44
- package/dist/wiki/__tests__/reserved-file-guard.test.js.map +0 -1
- package/dist/wiki/__tests__/session-hooks.test.d.ts +0 -5
- package/dist/wiki/__tests__/session-hooks.test.d.ts.map +0 -1
- package/dist/wiki/__tests__/session-hooks.test.js +0 -36
- package/dist/wiki/__tests__/session-hooks.test.js.map +0 -1
- package/dist/wiki/__tests__/slug-nonascii.test.d.ts +0 -2
- package/dist/wiki/__tests__/slug-nonascii.test.d.ts.map +0 -1
- package/dist/wiki/__tests__/slug-nonascii.test.js +0 -30
- package/dist/wiki/__tests__/slug-nonascii.test.js.map +0 -1
- package/dist/wiki/__tests__/storage.test.d.ts +0 -5
- package/dist/wiki/__tests__/storage.test.d.ts.map +0 -1
- package/dist/wiki/__tests__/storage.test.js +0 -278
- package/dist/wiki/__tests__/storage.test.js.map +0 -1
- package/dist/wiki/__tests__/test-helpers.d.ts +0 -31
- package/dist/wiki/__tests__/test-helpers.d.ts.map +0 -1
- package/dist/wiki/__tests__/test-helpers.js +0 -108
- package/dist/wiki/__tests__/test-helpers.js.map +0 -1
- package/docs/contracts/ralph-cancel-contract.md +0 -23
- package/docs/contracts/ralph-state-contract.md +0 -95
- package/docs/issues/team-ralph-followup-team.md +0 -38
- package/docs/qa/ralph-persistence-gate.md +0 -59
- package/docs/reference/ralph-parity-matrix.md +0 -25
- package/docs/reference/ralph-upstream-baseline.md +0 -34
- package/plugins/roblox-ai-os-creator-skills/skills/ralph/SKILL.md +0 -269
- package/plugins/roblox-ai-os-creator-skills/skills/ralplan/SKILL.md +0 -162
- package/prompts/api-reviewer.md +0 -113
- package/prompts/information-architect.md +0 -226
- package/prompts/performance-reviewer.md +0 -109
- package/prompts/product-analyst.md +0 -304
- package/prompts/product-manager.md +0 -245
- package/prompts/qa-tester.md +0 -124
- package/prompts/quality-reviewer.md +0 -123
- package/prompts/quality-strategist.md +0 -274
- package/prompts/style-reviewer.md +0 -102
- package/prompts/ux-researcher.md +0 -327
- package/skills/frontend-ui-ux/SKILL.md +0 -34
- package/skills/ralph/SKILL.md +0 -269
- package/skills/ralplan/SKILL.md +0 -162
- package/src/scripts/eval/eval-adaptive-sort-optimization.py +0 -24
- package/src/scripts/eval/eval-candidate-handoff.ts +0 -8
- package/src/scripts/eval/eval-cli-discoverability.ts +0 -40
- package/src/scripts/eval/eval-fresh-run-tagging.ts +0 -8
- package/src/scripts/eval/eval-help-consistency.ts +0 -11
- package/src/scripts/eval/eval-in-action-cat-shellout-demo.ts +0 -31
- package/src/scripts/eval/eval-ml-kaggle-model-optimization.py +0 -29
- package/src/scripts/eval/eval-noisy-bayesopt-highdim.py +0 -44
- package/src/scripts/eval/eval-noisy-latent-subspace-discovery.py +0 -44
- package/src/scripts/eval/eval-parity-smoke.ts +0 -20
- package/src/scripts/eval/eval-parity-sweep.ts +0 -26
- package/src/scripts/eval/eval-resume-dirty-guard.ts +0 -8
- package/src/scripts/eval/eval-security-path-traversal.ts +0 -38
- package/src/scripts/run-autoresearch-showcase.sh +0 -75
- /package/docs/{migration-mainline-post-v0.4.4.md → archive/migration-mainline-post-v0.4.4.md} +0 -0
- /package/docs/{qa-plan-0.4.2.md → archive/qa-plan-0.4.2.md} +0 -0
- /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
|