oh-my-codex 0.20.2 → 0.20.5
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/Cargo.lock +36 -18
- package/Cargo.toml +1 -1
- package/README.md +28 -2
- package/crates/omx-runtime/Cargo.toml +4 -0
- package/crates/omx-runtime/src/main.rs +415 -2
- package/crates/omx-runtime/tests/execution.rs +483 -0
- package/crates/omx-runtime-core/src/dispatch.rs +96 -10
- package/crates/omx-runtime-core/src/engine.rs +839 -29
- package/crates/omx-runtime-core/src/lib.rs +8 -0
- package/dist/adapt/__tests__/herdr-target.test.d.ts +2 -0
- package/dist/adapt/__tests__/herdr-target.test.d.ts.map +1 -0
- package/dist/adapt/__tests__/herdr-target.test.js +72 -0
- package/dist/adapt/__tests__/herdr-target.test.js.map +1 -0
- package/dist/adapt/contracts.d.ts +1 -1
- package/dist/adapt/contracts.d.ts.map +1 -1
- package/dist/adapt/contracts.js +1 -1
- package/dist/adapt/contracts.js.map +1 -1
- package/dist/adapt/herdr/__tests__/authority.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/authority.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/authority.test.js +49 -0
- package/dist/adapt/herdr/__tests__/authority.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/bridge.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/bridge.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/bridge.test.js +176 -0
- package/dist/adapt/herdr/__tests__/bridge.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/sanitize.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/sanitize.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/sanitize.test.js +45 -0
- package/dist/adapt/herdr/__tests__/sanitize.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/semantic.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/semantic.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/semantic.test.js +130 -0
- package/dist/adapt/herdr/__tests__/semantic.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/seq-store.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/seq-store.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/seq-store.test.js +54 -0
- package/dist/adapt/herdr/__tests__/seq-store.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/socket-live.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/socket-live.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/socket-live.test.js +104 -0
- package/dist/adapt/herdr/__tests__/socket-live.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/team-map.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/team-map.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/team-map.test.js +46 -0
- package/dist/adapt/herdr/__tests__/team-map.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/transport.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/transport.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/transport.test.js +160 -0
- package/dist/adapt/herdr/__tests__/transport.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/wiring.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/wiring.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/wiring.test.js +118 -0
- package/dist/adapt/herdr/__tests__/wiring.test.js.map +1 -0
- package/dist/adapt/herdr/authority.d.ts +34 -0
- package/dist/adapt/herdr/authority.d.ts.map +1 -0
- package/dist/adapt/herdr/authority.js +71 -0
- package/dist/adapt/herdr/authority.js.map +1 -0
- package/dist/adapt/herdr/bridge.d.ts +84 -0
- package/dist/adapt/herdr/bridge.d.ts.map +1 -0
- package/dist/adapt/herdr/bridge.js +222 -0
- package/dist/adapt/herdr/bridge.js.map +1 -0
- package/dist/adapt/herdr/sanitize.d.ts +20 -0
- package/dist/adapt/herdr/sanitize.d.ts.map +1 -0
- package/dist/adapt/herdr/sanitize.js +70 -0
- package/dist/adapt/herdr/sanitize.js.map +1 -0
- package/dist/adapt/herdr/semantic.d.ts +67 -0
- package/dist/adapt/herdr/semantic.d.ts.map +1 -0
- package/dist/adapt/herdr/semantic.js +170 -0
- package/dist/adapt/herdr/semantic.js.map +1 -0
- package/dist/adapt/herdr/seq-store.d.ts +32 -0
- package/dist/adapt/herdr/seq-store.d.ts.map +1 -0
- package/dist/adapt/herdr/seq-store.js +126 -0
- package/dist/adapt/herdr/seq-store.js.map +1 -0
- package/dist/adapt/herdr/team-map.d.ts +30 -0
- package/dist/adapt/herdr/team-map.d.ts.map +1 -0
- package/dist/adapt/herdr/team-map.js +37 -0
- package/dist/adapt/herdr/team-map.js.map +1 -0
- package/dist/adapt/herdr/transport.d.ts +115 -0
- package/dist/adapt/herdr/transport.d.ts.map +1 -0
- package/dist/adapt/herdr/transport.js +260 -0
- package/dist/adapt/herdr/transport.js.map +1 -0
- package/dist/adapt/herdr/wiring.d.ts +24 -0
- package/dist/adapt/herdr/wiring.d.ts.map +1 -0
- package/dist/adapt/herdr/wiring.js +62 -0
- package/dist/adapt/herdr/wiring.js.map +1 -0
- package/dist/adapt/herdr.d.ts +19 -0
- package/dist/adapt/herdr.d.ts.map +1 -0
- package/dist/adapt/herdr.js +115 -0
- package/dist/adapt/herdr.js.map +1 -0
- package/dist/adapt/index.d.ts +4 -0
- package/dist/adapt/index.d.ts.map +1 -1
- package/dist/adapt/index.js +48 -0
- package/dist/adapt/index.js.map +1 -1
- package/dist/adapt/registry.d.ts.map +1 -1
- package/dist/adapt/registry.js +11 -0
- package/dist/adapt/registry.js.map +1 -1
- package/dist/agents/__tests__/definitions.test.js +81 -0
- package/dist/agents/__tests__/definitions.test.js.map +1 -1
- package/dist/agents/__tests__/native-config.test.js +25 -0
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/native-config.d.ts +2 -1
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js.map +1 -1
- package/dist/auth/__tests__/hotswap.test.js +60 -1
- package/dist/auth/__tests__/hotswap.test.js.map +1 -1
- package/dist/auth/__tests__/storage.test.js +33 -1
- package/dist/auth/__tests__/storage.test.js.map +1 -1
- package/dist/auth/hotswap.d.ts +22 -2
- package/dist/auth/hotswap.d.ts.map +1 -1
- package/dist/auth/hotswap.js +107 -22
- package/dist/auth/hotswap.js.map +1 -1
- package/dist/auth/storage.js +1 -1
- package/dist/auth/storage.js.map +1 -1
- package/dist/autopilot/__tests__/ralplan-gate.test.js +86 -1333
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
- package/dist/autopilot/ralplan-gate.d.ts.map +1 -1
- package/dist/autopilot/ralplan-gate.js +7 -6
- package/dist/autopilot/ralplan-gate.js.map +1 -1
- package/dist/cli/__tests__/agents-init.test.js +4 -23
- package/dist/cli/__tests__/agents-init.test.js.map +1 -1
- package/dist/cli/__tests__/api.test.js +61 -24
- package/dist/cli/__tests__/api.test.js.map +1 -1
- package/dist/cli/__tests__/auth.test.js +63 -7
- package/dist/cli/__tests__/auth.test.js.map +1 -1
- package/dist/cli/__tests__/codex-feature-probe.test.js +66 -1
- package/dist/cli/__tests__/codex-feature-probe.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +150 -2
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/detached-leader-teardown.test.d.ts +2 -0
- package/dist/cli/__tests__/detached-leader-teardown.test.d.ts.map +1 -0
- package/dist/cli/__tests__/detached-leader-teardown.test.js +473 -0
- package/dist/cli/__tests__/detached-leader-teardown.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-process-identity-readiness.test.d.ts +2 -0
- package/dist/cli/__tests__/doctor-process-identity-readiness.test.d.ts.map +1 -0
- package/dist/cli/__tests__/doctor-process-identity-readiness.test.js +103 -0
- package/dist/cli/__tests__/doctor-process-identity-readiness.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-state-root-binding.test.d.ts +2 -0
- package/dist/cli/__tests__/doctor-state-root-binding.test.d.ts.map +1 -0
- package/dist/cli/__tests__/doctor-state-root-binding.test.js +139 -0
- package/dist/cli/__tests__/doctor-state-root-binding.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-warning-copy.test.js +135 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/exec.test.js +211 -0
- package/dist/cli/__tests__/exec.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +878 -463
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +1290 -127
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +8 -4
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/native-assets.test.js +398 -16
- package/dist/cli/__tests__/native-assets.test.js.map +1 -1
- package/dist/cli/__tests__/native-hook-claim-journal.test.js +132 -6
- package/dist/cli/__tests__/native-hook-claim-journal.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +3 -3
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +3 -3
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js +49 -164
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js.map +1 -1
- package/dist/cli/__tests__/ralplan-child-binding-3212.test.d.ts +2 -0
- package/dist/cli/__tests__/ralplan-child-binding-3212.test.d.ts.map +1 -0
- package/dist/cli/__tests__/ralplan-child-binding-3212.test.js +56 -0
- package/dist/cli/__tests__/ralplan-child-binding-3212.test.js.map +1 -0
- package/dist/cli/__tests__/ralplan.test.js +107 -109
- package/dist/cli/__tests__/ralplan.test.js.map +1 -1
- package/dist/cli/__tests__/resume.test.js +11 -10
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.js +1118 -43
- package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
- package/dist/cli/__tests__/session-search-help.test.js +25 -1
- package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +8 -55
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +224 -7
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js +93 -41
- package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +150 -8
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +117 -2
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +95 -4
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/__tests__/update.test.js +669 -177
- package/dist/cli/__tests__/update.test.js.map +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js +33 -2
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
- package/dist/cli/api.d.ts.map +1 -1
- package/dist/cli/api.js +9 -10
- package/dist/cli/api.js.map +1 -1
- package/dist/cli/codex-feature-probe.d.ts +16 -0
- package/dist/cli/codex-feature-probe.d.ts.map +1 -1
- package/dist/cli/codex-feature-probe.js +44 -0
- package/dist/cli/codex-feature-probe.js.map +1 -1
- package/dist/cli/codex-home.d.ts.map +1 -1
- package/dist/cli/codex-home.js +7 -4
- package/dist/cli/codex-home.js.map +1 -1
- package/dist/cli/doctor.d.ts +20 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +290 -3
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +234 -12
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2409 -746
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-parity.js +2 -2
- package/dist/cli/mcp-parity.js.map +1 -1
- package/dist/cli/native-assets.d.ts +25 -0
- package/dist/cli/native-assets.d.ts.map +1 -1
- package/dist/cli/native-assets.js +448 -51
- package/dist/cli/native-assets.js.map +1 -1
- package/dist/cli/native-hook-claim-journal.d.ts +20 -5
- package/dist/cli/native-hook-claim-journal.d.ts.map +1 -1
- package/dist/cli/native-hook-claim-journal.js +67 -32
- package/dist/cli/native-hook-claim-journal.js.map +1 -1
- package/dist/cli/package-manager-ownership.d.ts +63 -0
- package/dist/cli/package-manager-ownership.d.ts.map +1 -0
- package/dist/cli/package-manager-ownership.js +323 -0
- package/dist/cli/package-manager-ownership.js.map +1 -0
- package/dist/cli/ralph.js +2 -2
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/ralplan.d.ts +5 -7
- package/dist/cli/ralplan.d.ts.map +1 -1
- package/dist/cli/ralplan.js +83 -134
- package/dist/cli/ralplan.js.map +1 -1
- package/dist/cli/session-search.d.ts +5 -0
- package/dist/cli/session-search.d.ts.map +1 -1
- package/dist/cli/session-search.js +87 -0
- package/dist/cli/session-search.js.map +1 -1
- package/dist/cli/setup-preferences.d.ts +15 -0
- package/dist/cli/setup-preferences.d.ts.map +1 -1
- package/dist/cli/setup-preferences.js +27 -1
- package/dist/cli/setup-preferences.js.map +1 -1
- package/dist/cli/setup.d.ts +8 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +119 -47
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/sparkshell.d.ts.map +1 -1
- package/dist/cli/sparkshell.js +52 -9
- package/dist/cli/sparkshell.js.map +1 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +2 -2
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/uninstall.d.ts +9 -0
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +71 -30
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/cli/update-worker.d.ts +2 -0
- package/dist/cli/update-worker.d.ts.map +1 -0
- package/dist/cli/update-worker.js +142 -0
- package/dist/cli/update-worker.js.map +1 -0
- package/dist/cli/update.d.ts +14 -22
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +192 -241
- package/dist/cli/update.js.map +1 -1
- package/dist/compat/__tests__/rust-runtime-compat.test.js +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +503 -30
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +5 -3
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/__tests__/models.test.js +67 -3
- package/dist/config/__tests__/models.test.js.map +1 -1
- package/dist/config/generator.d.ts +27 -21
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +610 -152
- package/dist/config/generator.js.map +1 -1
- package/dist/config/models.d.ts +12 -2
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +15 -1
- package/dist/config/models.js.map +1 -1
- package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js +25 -0
- package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.d.ts +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.js +2 -0
- package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +5 -3
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +27 -4
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/issue-3293-autopilot-handoff.test.d.ts +2 -0
- package/dist/hooks/__tests__/issue-3293-autopilot-handoff.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/issue-3293-autopilot-handoff.test.js +172 -0
- package/dist/hooks/__tests__/issue-3293-autopilot-handoff.test.js.map +1 -0
- package/dist/hooks/__tests__/keyword-detector.test.js +176 -37
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +402 -545
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +39 -4
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +161 -26
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +27 -0
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +10 -118
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js +7 -0
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +533 -14
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +159 -24
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +482 -32
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js +2 -1
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +68 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +7 -1
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +44 -4
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-contract.test.js +9 -0
- package/dist/hooks/__tests__/prompt-guidance-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/session.test.js +3130 -365
- package/dist/hooks/__tests__/session.test.js.map +1 -1
- package/dist/hooks/agents-overlay.js +1 -1
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js +108 -2
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/sdk.test.js +151 -1
- package/dist/hooks/extensibility/__tests__/sdk.test.js.map +1 -1
- package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
- package/dist/hooks/extensibility/dispatcher.js +20 -3
- package/dist/hooks/extensibility/dispatcher.js.map +1 -1
- package/dist/hooks/extensibility/plugin-runner.js +1 -0
- package/dist/hooks/extensibility/plugin-runner.js.map +1 -1
- package/dist/hooks/extensibility/runtime.d.ts.map +1 -1
- package/dist/hooks/extensibility/runtime.js.map +1 -1
- package/dist/hooks/extensibility/sdk/paths.d.ts +1 -1
- package/dist/hooks/extensibility/sdk/paths.d.ts.map +1 -1
- package/dist/hooks/extensibility/sdk/paths.js +2 -2
- package/dist/hooks/extensibility/sdk/paths.js.map +1 -1
- package/dist/hooks/extensibility/sdk/runtime-state.d.ts +1 -1
- package/dist/hooks/extensibility/sdk/runtime-state.d.ts.map +1 -1
- package/dist/hooks/extensibility/sdk/runtime-state.js +55 -15
- package/dist/hooks/extensibility/sdk/runtime-state.js.map +1 -1
- package/dist/hooks/extensibility/sdk.d.ts +1 -0
- package/dist/hooks/extensibility/sdk.d.ts.map +1 -1
- package/dist/hooks/extensibility/sdk.js +1 -1
- package/dist/hooks/extensibility/sdk.js.map +1 -1
- package/dist/hooks/extensibility/types.d.ts +7 -0
- package/dist/hooks/extensibility/types.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +10 -3
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +116 -20
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/session.d.ts +204 -14
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +1500 -223
- package/dist/hooks/session.js.map +1 -1
- package/dist/hud/__tests__/hud-tmux-injection.test.js +6 -6
- package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
- package/dist/hud/__tests__/index.test.js +26 -16
- package/dist/hud/__tests__/index.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +83 -78
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +36 -31
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +155 -198
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/tmux.d.ts +42 -4
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +1017 -139
- package/dist/hud/tmux.js.map +1 -1
- package/dist/leader/__tests__/contract.test.js +124 -37
- package/dist/leader/__tests__/contract.test.js.map +1 -1
- package/dist/leader/contract.d.ts +17 -6
- package/dist/leader/contract.d.ts.map +1 -1
- package/dist/leader/contract.js +102 -26
- package/dist/leader/contract.js.map +1 -1
- package/dist/mcp/__tests__/code-intel-server.test.js +31 -3
- package/dist/mcp/__tests__/code-intel-server.test.js.map +1 -1
- package/dist/mcp/__tests__/hermes-bridge.test.js +17 -0
- package/dist/mcp/__tests__/hermes-bridge.test.js.map +1 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js +4 -4
- package/dist/mcp/__tests__/state-paths.test.js +735 -4
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server.test.js +1 -1
- package/dist/mcp/__tests__/state-server.test.js.map +1 -1
- package/dist/mcp/__tests__/trace-server.test.js +2 -2
- package/dist/mcp/__tests__/trace-server.test.js.map +1 -1
- package/dist/mcp/__tests__/wiki-server.test.js +18 -0
- package/dist/mcp/__tests__/wiki-server.test.js.map +1 -1
- package/dist/mcp/code-intel-server.d.ts.map +1 -1
- package/dist/mcp/code-intel-server.js +13 -3
- package/dist/mcp/code-intel-server.js.map +1 -1
- package/dist/mcp/hermes-bridge.d.ts.map +1 -1
- package/dist/mcp/hermes-bridge.js +2 -2
- package/dist/mcp/hermes-bridge.js.map +1 -1
- package/dist/mcp/state-paths.d.ts +78 -4
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +543 -40
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/mcp/state-server.d.ts +4 -4
- package/dist/mcp/state-server.d.ts.map +1 -1
- package/dist/mcp/wiki-server.d.ts +11 -0
- package/dist/mcp/wiki-server.d.ts.map +1 -1
- package/dist/mcp/wiki-server.js +9 -2
- package/dist/mcp/wiki-server.js.map +1 -1
- package/dist/modes/__tests__/base-autopilot-gates.test.js +36 -7
- package/dist/modes/__tests__/base-autopilot-gates.test.js.map +1 -1
- package/dist/modes/__tests__/base-multi-state-compat.test.js +1 -1
- package/dist/modes/__tests__/base-multi-state-compat.test.js.map +1 -1
- package/dist/modes/__tests__/base-session-scope.test.js +17 -8
- package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
- package/dist/modes/__tests__/base-tmux-pane.test.js +4 -4
- package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
- package/dist/modes/base.d.ts +5 -5
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +76 -21
- package/dist/modes/base.js.map +1 -1
- package/dist/native-assets/archive.d.ts +17 -0
- package/dist/native-assets/archive.d.ts.map +1 -0
- package/dist/native-assets/archive.js +238 -0
- package/dist/native-assets/archive.js.map +1 -0
- package/dist/native-assets/policy.d.ts +42 -0
- package/dist/native-assets/policy.d.ts.map +1 -0
- package/dist/native-assets/policy.js +155 -0
- package/dist/native-assets/policy.js.map +1 -0
- package/dist/notifications/temp-contract.d.ts.map +1 -1
- package/dist/notifications/temp-contract.js +4 -0
- package/dist/notifications/temp-contract.js.map +1 -1
- package/dist/pipeline/__tests__/orchestrator.test.js +164 -42
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +72 -155
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/orchestrator.d.ts.map +1 -1
- package/dist/pipeline/orchestrator.js +124 -18
- package/dist/pipeline/orchestrator.js.map +1 -1
- package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
- package/dist/pipeline/stages/ralplan.js +36 -8
- package/dist/pipeline/stages/ralplan.js.map +1 -1
- package/dist/ralplan/__tests__/consensus-gate.test.js +73 -1316
- package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
- package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts +2 -0
- package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts.map +1 -0
- package/dist/ralplan/__tests__/documented-leader-preflight.test.js +335 -0
- package/dist/ralplan/__tests__/documented-leader-preflight.test.js.map +1 -0
- package/dist/ralplan/__tests__/runtime.test.js +85 -101
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.d.ts +9 -1
- package/dist/ralplan/consensus-gate.d.ts.map +1 -1
- package/dist/ralplan/consensus-gate.js +82 -338
- package/dist/ralplan/consensus-gate.js.map +1 -1
- package/dist/ralplan/documented-leader-preflight.d.ts +41 -0
- package/dist/ralplan/documented-leader-preflight.d.ts.map +1 -0
- package/dist/ralplan/documented-leader-preflight.js +360 -0
- package/dist/ralplan/documented-leader-preflight.js.map +1 -0
- package/dist/ralplan/runtime.d.ts +2 -1
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +67 -168
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/runtime/__tests__/bridge.test.js +42 -1
- package/dist/runtime/__tests__/bridge.test.js.map +1 -1
- package/dist/runtime/bridge.d.ts +12 -0
- package/dist/runtime/bridge.d.ts.map +1 -1
- package/dist/runtime/bridge.js +52 -1
- package/dist/runtime/bridge.js.map +1 -1
- package/dist/runtime/run-state.d.ts +5 -1
- package/dist/runtime/run-state.d.ts.map +1 -1
- package/dist/runtime/run-state.js +15 -8
- package/dist/runtime/run-state.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +16323 -8978
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/issue-3293-callsite-parity.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3293-callsite-parity.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3293-callsite-parity.test.js +225 -0
- package/dist/scripts/__tests__/issue-3293-callsite-parity.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3293-cancel-transaction.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3293-cancel-transaction.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3293-cancel-transaction.test.js +188 -0
- package/dist/scripts/__tests__/issue-3293-cancel-transaction.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3293-hook-owned-cancel.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3293-hook-owned-cancel.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3293-hook-owned-cancel.test.js +259 -0
- package/dist/scripts/__tests__/issue-3293-hook-owned-cancel.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.js +491 -0
- package/dist/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3358-ultragoal-cancel-lifecycle.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3358-ultragoal-cancel-lifecycle.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3358-ultragoal-cancel-lifecycle.test.js +708 -0
- package/dist/scripts/__tests__/issue-3358-ultragoal-cancel-lifecycle.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3369-autopilot-ralplan-state-machine.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3369-autopilot-ralplan-state-machine.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3369-autopilot-ralplan-state-machine.test.js +208 -0
- package/dist/scripts/__tests__/issue-3369-autopilot-ralplan-state-machine.test.js.map +1 -0
- package/dist/scripts/__tests__/notify-state-io.test.js +26 -0
- package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-tmux-injection.test.js +23 -1
- package/dist/scripts/__tests__/notify-tmux-injection.test.js.map +1 -1
- package/dist/scripts/__tests__/postinstall.test.js +19 -1
- package/dist/scripts/__tests__/postinstall.test.js.map +1 -1
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.d.ts +2 -0
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.js +108 -0
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.js.map +1 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js +63 -173
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js.map +1 -1
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js +74 -159
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js +404 -13
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
- package/dist/scripts/__tests__/verify-native-release-assets.test.d.ts +2 -0
- package/dist/scripts/__tests__/verify-native-release-assets.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/verify-native-release-assets.test.js +235 -0
- package/dist/scripts/__tests__/verify-native-release-assets.test.js.map +1 -0
- package/dist/scripts/codex-native-hook.d.ts +53 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +14448 -1480
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/codex-native-pre-post.d.ts +9 -0
- package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
- package/dist/scripts/codex-native-pre-post.js +35 -12
- package/dist/scripts/codex-native-pre-post.js.map +1 -1
- package/dist/scripts/generate-native-release-manifest.js +80 -51
- package/dist/scripts/generate-native-release-manifest.js.map +1 -1
- package/dist/scripts/notify-fallback-watcher.js +78 -115
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.js +74 -3
- package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
- package/dist/scripts/notify-hook/state-io.js +5 -0
- package/dist/scripts/notify-hook/state-io.js.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts +9 -0
- package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.js +234 -79
- package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.js +71 -16
- package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts +12 -4
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.js +365 -44
- package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.js +42 -21
- package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker.d.ts +3 -0
- package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker.js +82 -33
- package/dist/scripts/notify-hook/team-worker.js.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts +1 -0
- package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +32 -3
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook.js +79 -82
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/postinstall-advisory.d.ts +14 -0
- package/dist/scripts/postinstall-advisory.d.ts.map +1 -0
- package/dist/scripts/postinstall-advisory.js +49 -0
- package/dist/scripts/postinstall-advisory.js.map +1 -0
- package/dist/scripts/postinstall.d.ts +1 -1
- package/dist/scripts/postinstall.d.ts.map +1 -1
- package/dist/scripts/postinstall.js +1 -1
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +80 -4
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +3162 -26
- package/dist/scripts/smoke-packed-install.js.map +1 -1
- package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
- package/dist/scripts/sync-plugin-mirror.js +16 -1
- package/dist/scripts/sync-plugin-mirror.js.map +1 -1
- package/dist/scripts/verify-native-release-assets.js +37 -23
- package/dist/scripts/verify-native-release-assets.js.map +1 -1
- package/dist/state/__tests__/mode-state-context.test.js +61 -0
- package/dist/state/__tests__/mode-state-context.test.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +462 -850
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/skill-active.test.js +400 -2
- package/dist/state/__tests__/skill-active.test.js.map +1 -1
- package/dist/state/mode-state-context.d.ts +8 -0
- package/dist/state/mode-state-context.d.ts.map +1 -1
- package/dist/state/mode-state-context.js +73 -0
- package/dist/state/mode-state-context.js.map +1 -1
- package/dist/state/operations.d.ts +3 -0
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +144 -40
- package/dist/state/operations.js.map +1 -1
- package/dist/state/skill-active.d.ts +18 -1
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +420 -23
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts +3 -0
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +10 -4
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js +3 -1
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js +53 -247
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js.map +1 -1
- package/dist/subagents/__tests__/tracker.test.js +837 -1048
- package/dist/subagents/__tests__/tracker.test.js.map +1 -1
- package/dist/subagents/tracker.d.ts +58 -135
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +811 -632
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/team/__tests__/api-interop.test.js +91 -1
- package/dist/team/__tests__/api-interop.test.js.map +1 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.js +58 -17
- package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
- package/dist/team/__tests__/idle-nudge.test.js +45 -15
- package/dist/team/__tests__/idle-nudge.test.js.map +1 -1
- package/dist/team/__tests__/mcp-comm.test.js +197 -30
- package/dist/team/__tests__/mcp-comm.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +110 -3
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/notice-ledger.test.d.ts +2 -0
- package/dist/team/__tests__/notice-ledger.test.d.ts.map +1 -0
- package/dist/team/__tests__/notice-ledger.test.js +131 -0
- package/dist/team/__tests__/notice-ledger.test.js.map +1 -0
- package/dist/team/__tests__/pane-teardown-residue-e2e.test.d.ts +2 -0
- package/dist/team/__tests__/pane-teardown-residue-e2e.test.d.ts.map +1 -0
- package/dist/team/__tests__/pane-teardown-residue-e2e.test.js +410 -0
- package/dist/team/__tests__/pane-teardown-residue-e2e.test.js.map +1 -0
- package/dist/team/__tests__/phase-controller.test.js +20 -0
- package/dist/team/__tests__/phase-controller.test.js.map +1 -1
- package/dist/team/__tests__/runtime-cli.test.js +9 -0
- package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +3963 -428
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +2405 -203
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/state-root.test.js +117 -2
- package/dist/team/__tests__/state-root.test.js.map +1 -1
- package/dist/team/__tests__/state.test.js +804 -36
- package/dist/team/__tests__/state.test.js.map +1 -1
- package/dist/team/__tests__/team-ops-contract.test.js +6 -0
- package/dist/team/__tests__/team-ops-contract.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +4099 -1039
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/tmux-source-authority-realtmux.test.d.ts +2 -0
- package/dist/team/__tests__/tmux-source-authority-realtmux.test.d.ts.map +1 -0
- package/dist/team/__tests__/tmux-source-authority-realtmux.test.js +149 -0
- package/dist/team/__tests__/tmux-source-authority-realtmux.test.js.map +1 -0
- package/dist/team/__tests__/tmux-test-fixture.d.ts +69 -0
- package/dist/team/__tests__/tmux-test-fixture.d.ts.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.js +242 -15
- package/dist/team/__tests__/tmux-test-fixture.js.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.test.js +177 -1
- package/dist/team/__tests__/tmux-test-fixture.test.js.map +1 -1
- package/dist/team/__tests__/worker-runtime-identity.test.js +53 -44
- package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
- package/dist/team/__tests__/worktree.test.js +6 -0
- package/dist/team/__tests__/worktree.test.js.map +1 -1
- package/dist/team/api-interop.d.ts.map +1 -1
- package/dist/team/api-interop.js +15 -9
- package/dist/team/api-interop.js.map +1 -1
- package/dist/team/exact-pane.d.ts +23 -0
- package/dist/team/exact-pane.d.ts.map +1 -0
- package/dist/team/exact-pane.js +133 -0
- package/dist/team/exact-pane.js.map +1 -0
- package/dist/team/idle-nudge.d.ts +12 -1
- package/dist/team/idle-nudge.d.ts.map +1 -1
- package/dist/team/idle-nudge.js +41 -14
- package/dist/team/idle-nudge.js.map +1 -1
- package/dist/team/model-contract.d.ts +2 -5
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +59 -17
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/notice-ledger.d.ts +54 -0
- package/dist/team/notice-ledger.d.ts.map +1 -0
- package/dist/team/notice-ledger.js +259 -0
- package/dist/team/notice-ledger.js.map +1 -0
- package/dist/team/phase-controller.d.ts.map +1 -1
- package/dist/team/phase-controller.js +2 -0
- package/dist/team/phase-controller.js.map +1 -1
- package/dist/team/runtime.d.ts +4 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +1527 -291
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts +13 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +1503 -387
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state/dispatch.d.ts.map +1 -1
- package/dist/team/state/dispatch.js +26 -8
- package/dist/team/state/dispatch.js.map +1 -1
- package/dist/team/state/locks.d.ts.map +1 -1
- package/dist/team/state/locks.js +61 -13
- package/dist/team/state/locks.js.map +1 -1
- package/dist/team/state/monitor.d.ts +10 -0
- package/dist/team/state/monitor.d.ts.map +1 -1
- package/dist/team/state/monitor.js +13 -0
- package/dist/team/state/monitor.js.map +1 -1
- package/dist/team/state/tasks.d.ts.map +1 -1
- package/dist/team/state/tasks.js +4 -3
- package/dist/team/state/tasks.js.map +1 -1
- package/dist/team/state/types.d.ts +15 -0
- package/dist/team/state/types.d.ts.map +1 -1
- package/dist/team/state/types.js.map +1 -1
- package/dist/team/state-root.d.ts +12 -0
- package/dist/team/state-root.d.ts.map +1 -1
- package/dist/team/state-root.js +177 -0
- package/dist/team/state-root.js.map +1 -1
- package/dist/team/state.d.ts +85 -1
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +672 -129
- package/dist/team/state.js.map +1 -1
- package/dist/team/team-ops.d.ts +5 -0
- package/dist/team/team-ops.d.ts.map +1 -1
- package/dist/team/team-ops.js +4 -0
- package/dist/team/team-ops.js.map +1 -1
- package/dist/team/tmux-session.d.ts +163 -27
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +1682 -376
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worktree.d.ts.map +1 -1
- package/dist/team/worktree.js +4 -0
- package/dist/team/worktree.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +950 -2
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js +1 -0
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts +35 -1
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +232 -46
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/utils/__tests__/file-durability.test.d.ts +2 -0
- package/dist/utils/__tests__/file-durability.test.d.ts.map +1 -0
- package/dist/utils/__tests__/file-durability.test.js +114 -0
- package/dist/utils/__tests__/file-durability.test.js.map +1 -0
- package/dist/utils/__tests__/paths.test.js +21 -1
- package/dist/utils/__tests__/paths.test.js.map +1 -1
- package/dist/utils/file-durability.d.ts +25 -0
- package/dist/utils/file-durability.d.ts.map +1 -0
- package/dist/utils/file-durability.js +67 -0
- package/dist/utils/file-durability.js.map +1 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +14 -6
- package/dist/utils/paths.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +49 -4
- package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +3 -0
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
- package/dist/verification/__tests__/explore-harness-release-workflow.test.js +60 -0
- package/dist/verification/__tests__/explore-harness-release-workflow.test.js.map +1 -1
- package/dist/verification/__tests__/native-release-manifest.test.js +157 -4
- package/dist/verification/__tests__/native-release-manifest.test.js.map +1 -1
- package/dist/wiki/lint.d.ts +4 -1
- package/dist/wiki/lint.d.ts.map +1 -1
- package/dist/wiki/lint.js +3 -2
- package/dist/wiki/lint.js.map +1 -1
- package/package.json +13 -5
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +105 -17
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +13 -5
- package/plugins/oh-my-codex/skills/cancel/SKILL.md +30 -85
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +6 -4
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +16 -17
- package/plugins/oh-my-codex/skills/team/SKILL.md +13 -9
- package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +3 -2
- package/skills/autopilot/SKILL.md +13 -5
- package/skills/cancel/SKILL.md +30 -85
- package/skills/ralph/SKILL.md +6 -4
- package/skills/ralplan/SKILL.md +16 -17
- package/skills/team/SKILL.md +13 -9
- package/skills/ultragoal/SKILL.md +3 -2
- package/src/scripts/__tests__/codex-native-hook.test.ts +8831 -951
- package/src/scripts/__tests__/issue-3293-callsite-parity.test.ts +187 -0
- package/src/scripts/__tests__/issue-3293-cancel-transaction.test.ts +189 -0
- package/src/scripts/__tests__/issue-3293-hook-owned-cancel.test.ts +187 -0
- package/src/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.ts +591 -0
- package/src/scripts/__tests__/issue-3358-ultragoal-cancel-lifecycle.test.ts +701 -0
- package/src/scripts/__tests__/issue-3369-autopilot-ralplan-state-machine.test.ts +211 -0
- package/src/scripts/__tests__/notify-state-io.test.ts +29 -0
- package/src/scripts/__tests__/notify-tmux-injection.test.ts +26 -1
- package/src/scripts/__tests__/postinstall.test.ts +23 -1
- package/src/scripts/__tests__/reasoning-artifact-contract.test.ts +129 -0
- package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +67 -185
- package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +79 -178
- package/src/scripts/__tests__/smoke-packed-install.test.ts +525 -16
- package/src/scripts/__tests__/verify-native-release-assets.test.ts +240 -0
- package/src/scripts/codex-native-hook.ts +14238 -1429
- package/src/scripts/codex-native-pre-post.ts +43 -12
- package/src/scripts/generate-native-release-manifest.ts +83 -79
- package/src/scripts/notify-fallback-watcher.ts +91 -122
- package/src/scripts/notify-hook/auto-nudge.ts +71 -3
- package/src/scripts/notify-hook/state-io.ts +11 -0
- package/src/scripts/notify-hook/team-dispatch.ts +242 -75
- package/src/scripts/notify-hook/team-leader-nudge.ts +72 -22
- package/src/scripts/notify-hook/team-tmux-guard.ts +366 -39
- package/src/scripts/notify-hook/team-worker-stop.ts +43 -20
- package/src/scripts/notify-hook/team-worker.ts +82 -31
- package/src/scripts/notify-hook/tmux-injection.ts +33 -3
- package/src/scripts/notify-hook.ts +84 -82
- package/src/scripts/postinstall-advisory.ts +67 -0
- package/src/scripts/postinstall.ts +1 -1
- package/src/scripts/smoke-packed-install.ts +3608 -39
- package/src/scripts/sync-plugin-mirror.ts +17 -1
- package/src/scripts/verify-native-release-assets.ts +39 -31
- package/templates/AGENTS.md +1 -0
- package/dist/subagents/__tests__/adapted-role-binding.test.d.ts +0 -2
- package/dist/subagents/__tests__/adapted-role-binding.test.d.ts.map +0 -1
- package/dist/subagents/__tests__/adapted-role-binding.test.js +0 -988
- package/dist/subagents/__tests__/adapted-role-binding.test.js.map +0 -1
- package/dist/subagents/adapted-role-binding.d.ts +0 -17
- package/dist/subagents/adapted-role-binding.d.ts.map +0 -1
- package/dist/subagents/adapted-role-binding.js +0 -75
- package/dist/subagents/adapted-role-binding.js.map +0 -1
package/dist/team/state.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { appendFile, readFile, writeFile, mkdir, rm, rename, readdir } from 'fs/promises';
|
|
2
|
-
import { join, dirname, resolve, sep } from 'path';
|
|
1
|
+
import { appendFile, readFile, writeFile, mkdir, rm, rename, readdir, open, realpath } from 'fs/promises';
|
|
2
|
+
import { basename, join, dirname, resolve, sep } from 'path';
|
|
3
3
|
import { existsSync } from 'fs';
|
|
4
4
|
import { randomUUID } from 'crypto';
|
|
5
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
5
6
|
import { readUsableSessionState } from '../hooks/session.js';
|
|
6
7
|
import { isTerminalPhase } from './orchestrator.js';
|
|
7
8
|
import { computeTaskReadiness as computeTaskReadinessImpl, claimTask as claimTaskImpl, transitionTaskStatus as transitionTaskStatusImpl, releaseTaskClaim as releaseTaskClaimImpl, reclaimExpiredTaskClaim as reclaimExpiredTaskClaimImpl, listTasks as listTasksImpl, } from './state/tasks.js';
|
|
@@ -16,6 +17,20 @@ import { TEAM_NAME_SAFE_PATTERN, WORKER_NAME_SAFE_PATTERN, TASK_ID_SAFE_PATTERN,
|
|
|
16
17
|
import { resolveCanonicalTeamStateRoot } from './state-root.js';
|
|
17
18
|
import { normalizeTeamTaskCoordinationPlanForStorage } from './coordination-protocol.js';
|
|
18
19
|
let renameForAtomicWrite = rename;
|
|
20
|
+
let openForAtomicWrite = open;
|
|
21
|
+
let platformForAtomicWrite = process.platform;
|
|
22
|
+
export function setWriteAtomicOpenForTests(fn) {
|
|
23
|
+
openForAtomicWrite = fn;
|
|
24
|
+
}
|
|
25
|
+
export function resetWriteAtomicOpenForTests() {
|
|
26
|
+
openForAtomicWrite = open;
|
|
27
|
+
}
|
|
28
|
+
export function setWriteAtomicPlatformForTests(platform) {
|
|
29
|
+
platformForAtomicWrite = platform;
|
|
30
|
+
}
|
|
31
|
+
export function resetWriteAtomicPlatformForTests() {
|
|
32
|
+
platformForAtomicWrite = process.platform;
|
|
33
|
+
}
|
|
19
34
|
export function setWriteAtomicRenameForTests(fn) {
|
|
20
35
|
renameForAtomicWrite = fn;
|
|
21
36
|
}
|
|
@@ -314,6 +329,12 @@ function isTeamManifestV2(value) {
|
|
|
314
329
|
return false;
|
|
315
330
|
if (!(typeof v.hud_pane_id === 'string' || v.hud_pane_id === null))
|
|
316
331
|
return false;
|
|
332
|
+
if (!(typeof v.leader_pane_pid === 'number' || v.leader_pane_pid === null || v.leader_pane_pid === undefined))
|
|
333
|
+
return false;
|
|
334
|
+
if (!(typeof v.hud_pane_pid === 'number' || v.hud_pane_pid === null || v.hud_pane_pid === undefined))
|
|
335
|
+
return false;
|
|
336
|
+
if (v.startup_cleanup_panes !== undefined && !normalizeStartupCleanupPanes(v.startup_cleanup_panes))
|
|
337
|
+
return false;
|
|
317
338
|
if (!(typeof v.resize_hook_name === 'string' || v.resize_hook_name === null))
|
|
318
339
|
return false;
|
|
319
340
|
if (!(typeof v.resize_hook_target === 'string' || v.resize_hook_target === null))
|
|
@@ -326,14 +347,54 @@ function isTeamManifestV2(value) {
|
|
|
326
347
|
return false;
|
|
327
348
|
return true;
|
|
328
349
|
}
|
|
329
|
-
// Atomic write: write to {path}.tmp.{pid}, then
|
|
350
|
+
// Atomic write: write to {path}.tmp.{pid}, fsync it, rename, then fsync parent.
|
|
351
|
+
function isUnsupportedParentDirectorySyncError(error) {
|
|
352
|
+
const code = error.code;
|
|
353
|
+
return (code === 'EINVAL'
|
|
354
|
+
|| code === 'ENOTSUP'
|
|
355
|
+
|| code === 'EISDIR'
|
|
356
|
+
|| (code === 'EPERM' && platformForAtomicWrite === 'win32'));
|
|
357
|
+
}
|
|
358
|
+
async function syncParentDirectory(path) {
|
|
359
|
+
let handle;
|
|
360
|
+
try {
|
|
361
|
+
handle = await openForAtomicWrite(dirname(path), 'r');
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
if (isUnsupportedParentDirectorySyncError(error))
|
|
365
|
+
return;
|
|
366
|
+
throw error;
|
|
367
|
+
}
|
|
368
|
+
try {
|
|
369
|
+
await handle.sync();
|
|
370
|
+
}
|
|
371
|
+
catch (error) {
|
|
372
|
+
if (!isUnsupportedParentDirectorySyncError(error))
|
|
373
|
+
throw error;
|
|
374
|
+
}
|
|
375
|
+
finally {
|
|
376
|
+
await handle.close();
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
export async function removeDurableFile(path) {
|
|
380
|
+
await rm(path, { force: true });
|
|
381
|
+
await syncParentDirectory(path);
|
|
382
|
+
}
|
|
330
383
|
export async function writeAtomic(filePath, data) {
|
|
331
384
|
const parent = dirname(filePath);
|
|
332
385
|
await mkdir(parent, { recursive: true });
|
|
333
386
|
const tmpPath = `${filePath}.tmp.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}`;
|
|
334
387
|
await writeFile(tmpPath, data, 'utf8');
|
|
388
|
+
const handle = await openForAtomicWrite(tmpPath, 'r');
|
|
389
|
+
try {
|
|
390
|
+
await handle.sync();
|
|
391
|
+
}
|
|
392
|
+
finally {
|
|
393
|
+
await handle.close();
|
|
394
|
+
}
|
|
335
395
|
try {
|
|
336
396
|
await renameForAtomicWrite(tmpPath, filePath);
|
|
397
|
+
await syncParentDirectory(filePath);
|
|
337
398
|
}
|
|
338
399
|
catch (error) {
|
|
339
400
|
const err = error;
|
|
@@ -350,6 +411,205 @@ export async function writeAtomic(filePath, data) {
|
|
|
350
411
|
throw error;
|
|
351
412
|
}
|
|
352
413
|
}
|
|
414
|
+
function membershipTransactionPath(teamName, cwd) {
|
|
415
|
+
return join(teamDir(teamName, cwd), '.membership-task-transaction.json');
|
|
416
|
+
}
|
|
417
|
+
async function applyMembershipTransactionFiles(files, useNewBytes) {
|
|
418
|
+
for (const file of files) {
|
|
419
|
+
const bytes = useNewBytes ? file.newBytes : file.oldBytes;
|
|
420
|
+
if (bytes === null)
|
|
421
|
+
await removeDurableFile(file.path);
|
|
422
|
+
else
|
|
423
|
+
await writeAtomic(file.path, bytes);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
async function validateMembershipTransactionFiles(teamName, cwd, files) {
|
|
427
|
+
const expectedConfigPath = resolve(teamConfigPath(teamName, cwd));
|
|
428
|
+
const expectedManifestPath = resolve(teamManifestV2Path(teamName, cwd));
|
|
429
|
+
const expectedTasksDir = resolve(teamDir(teamName, cwd), 'tasks');
|
|
430
|
+
const seenPaths = new Set();
|
|
431
|
+
let configCount = 0;
|
|
432
|
+
const canonicalStateRoot = await realpath(resolveTeamStateRoot(cwd));
|
|
433
|
+
const canonicalTeamRoot = await realpath(teamDir(teamName, cwd));
|
|
434
|
+
if (canonicalTeamRoot !== canonicalStateRoot && !canonicalTeamRoot.startsWith(`${canonicalStateRoot}${sep}`)) {
|
|
435
|
+
throw new Error(`Membership transaction team root escapes canonical state root for ${teamName}`);
|
|
436
|
+
}
|
|
437
|
+
const canonicalTasksDir = await realpath(resolve(teamDir(teamName, cwd), 'tasks'));
|
|
438
|
+
if (!canonicalTasksDir.startsWith(`${canonicalTeamRoot}${sep}`)) {
|
|
439
|
+
throw new Error(`Membership transaction tasks root escapes canonical team root for ${teamName}`);
|
|
440
|
+
}
|
|
441
|
+
for (const file of files) {
|
|
442
|
+
if (!file || typeof file.path !== 'string'
|
|
443
|
+
|| (file.oldBytes !== null && typeof file.oldBytes !== 'string')
|
|
444
|
+
|| (file.newBytes !== null && typeof file.newBytes !== 'string')) {
|
|
445
|
+
throw new Error(`Invalid membership transaction file entry for ${teamName}`);
|
|
446
|
+
}
|
|
447
|
+
const resolvedPath = resolve(file.path);
|
|
448
|
+
if (resolvedPath !== file.path || seenPaths.has(resolvedPath)) {
|
|
449
|
+
throw new Error(`Invalid membership transaction path for ${teamName}`);
|
|
450
|
+
}
|
|
451
|
+
seenPaths.add(resolvedPath);
|
|
452
|
+
let expectedParent;
|
|
453
|
+
if (resolvedPath === expectedConfigPath) {
|
|
454
|
+
configCount += 1;
|
|
455
|
+
expectedParent = canonicalTeamRoot;
|
|
456
|
+
}
|
|
457
|
+
else if (resolvedPath === expectedManifestPath) {
|
|
458
|
+
expectedParent = canonicalTeamRoot;
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
if (dirname(resolvedPath) !== expectedTasksDir) {
|
|
462
|
+
throw new Error(`Membership transaction path escapes expected team files for ${teamName}`);
|
|
463
|
+
}
|
|
464
|
+
const match = basename(resolvedPath).match(/^task-([A-Za-z0-9_-]+)\.json$/);
|
|
465
|
+
if (!match || resolve(taskFilePath(teamName, match[1], cwd)) !== resolvedPath) {
|
|
466
|
+
throw new Error(`Invalid membership transaction task path for ${teamName}`);
|
|
467
|
+
}
|
|
468
|
+
expectedParent = canonicalTasksDir;
|
|
469
|
+
}
|
|
470
|
+
const canonicalParent = await realpath(dirname(resolvedPath));
|
|
471
|
+
if (canonicalParent !== expectedParent) {
|
|
472
|
+
throw new Error(`Membership transaction path traverses a symlink for ${teamName}`);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
if (configCount !== 1) {
|
|
476
|
+
throw new Error(`Membership transaction must contain exactly one config path for ${teamName}`);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Resolve an interrupted membership/task commit before a reader or writer observes
|
|
481
|
+
* its files. Prepared transactions roll back; committed transactions roll forward.
|
|
482
|
+
*/
|
|
483
|
+
export async function recoverTeamMembershipTaskTransaction(teamName, cwd, options = {}) {
|
|
484
|
+
const journalPath = membershipTransactionPath(teamName, cwd);
|
|
485
|
+
let journal;
|
|
486
|
+
try {
|
|
487
|
+
journal = JSON.parse(await readFile(journalPath, 'utf8'));
|
|
488
|
+
}
|
|
489
|
+
catch (error) {
|
|
490
|
+
if (error.code === 'ENOENT')
|
|
491
|
+
return;
|
|
492
|
+
throw error;
|
|
493
|
+
}
|
|
494
|
+
if (journal.schemaVersion !== 1 || (journal.phase !== 'prepared' && journal.phase !== 'committed') || !Array.isArray(journal.files)) {
|
|
495
|
+
throw new Error(`Invalid membership transaction journal for ${teamName}`);
|
|
496
|
+
}
|
|
497
|
+
await validateMembershipTransactionFiles(teamName, cwd, journal.files);
|
|
498
|
+
await applyMembershipTransactionFiles(journal.files, journal.phase === 'committed');
|
|
499
|
+
if (!options.retainJournal)
|
|
500
|
+
await removeDurableFile(journalPath);
|
|
501
|
+
}
|
|
502
|
+
/** Finalize a previously committed membership transaction after caller verification. */
|
|
503
|
+
export async function finalizeTeamMembershipTaskTransaction(teamName, cwd) {
|
|
504
|
+
const journalPath = membershipTransactionPath(teamName, cwd);
|
|
505
|
+
const journal = JSON.parse(await readFile(journalPath, 'utf8'));
|
|
506
|
+
if (journal.schemaVersion !== 1 || journal.phase !== 'committed' || !Array.isArray(journal.files)) {
|
|
507
|
+
throw new Error(`Cannot finalize non-committed membership transaction for ${teamName}`);
|
|
508
|
+
}
|
|
509
|
+
await validateMembershipTransactionFiles(teamName, cwd, journal.files);
|
|
510
|
+
await removeDurableFile(journalPath);
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Persist config/manifest and task membership changes as an old-or-new journaled
|
|
514
|
+
* generation. Callers must hold the team membership barrier for the whole call.
|
|
515
|
+
*/
|
|
516
|
+
export async function commitTeamMembershipTaskTransaction(teamName, cwd, transaction) {
|
|
517
|
+
if (!taskMembershipBarrierContext.getStore()?.has(taskMembershipBarrierKey(teamName, cwd))) {
|
|
518
|
+
throw new Error(`membership_transaction_barrier_required:${teamName}`);
|
|
519
|
+
}
|
|
520
|
+
const currentGeneration = await readConfigGenerationRaw(teamName, cwd);
|
|
521
|
+
if (currentGeneration === null)
|
|
522
|
+
throw new Error(`team_config_missing:${teamName}`);
|
|
523
|
+
if (transaction.baseGeneration !== currentGeneration) {
|
|
524
|
+
throw new Error(`team_membership_stale_generation:${teamName}:${transaction.baseGeneration}:${currentGeneration}`);
|
|
525
|
+
}
|
|
526
|
+
const acceptedGeneration = currentGeneration + 1;
|
|
527
|
+
const nextConfig = JSON.parse(transaction.config.newBytes);
|
|
528
|
+
nextConfig.config_generation = acceptedGeneration;
|
|
529
|
+
const nextManifest = transaction.manifest?.newBytes === null
|
|
530
|
+
? null
|
|
531
|
+
: transaction.manifest
|
|
532
|
+
? { ...JSON.parse(transaction.manifest.newBytes), config_generation: acceptedGeneration }
|
|
533
|
+
: undefined;
|
|
534
|
+
const files = [
|
|
535
|
+
...transaction.tasks.map((task) => ({
|
|
536
|
+
path: taskFilePath(teamName, task.taskId, cwd),
|
|
537
|
+
oldBytes: task.oldBytes,
|
|
538
|
+
newBytes: task.newBytes,
|
|
539
|
+
})),
|
|
540
|
+
{
|
|
541
|
+
path: teamConfigPath(teamName, cwd),
|
|
542
|
+
oldBytes: transaction.config.oldBytes,
|
|
543
|
+
newBytes: JSON.stringify(nextConfig, null, 2),
|
|
544
|
+
},
|
|
545
|
+
];
|
|
546
|
+
if (transaction.manifest) {
|
|
547
|
+
files.push({
|
|
548
|
+
path: teamManifestV2Path(teamName, cwd),
|
|
549
|
+
oldBytes: transaction.manifest.oldBytes,
|
|
550
|
+
newBytes: nextManifest === null ? null : JSON.stringify(nextManifest, null, 2),
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
const journalPath = membershipTransactionPath(teamName, cwd);
|
|
554
|
+
const journal = {
|
|
555
|
+
schemaVersion: 1,
|
|
556
|
+
// Membership rollback is itself a durable desired-state transition: an
|
|
557
|
+
// interruption must finish restoring the original membership, not revive
|
|
558
|
+
// the transient scaled-up generation.
|
|
559
|
+
phase: transaction.recoverToNewOnFailure ? 'committed' : 'prepared',
|
|
560
|
+
files,
|
|
561
|
+
};
|
|
562
|
+
await writeAtomic(journalPath, JSON.stringify(journal, null, 2));
|
|
563
|
+
try {
|
|
564
|
+
if (transaction.interruptAfterFirstTaskWrite && transaction.tasks.length > 0) {
|
|
565
|
+
await applyMembershipTransactionFiles(files.slice(0, 1), true);
|
|
566
|
+
throw new Error('injected_scale_down_interruption:after-first-task-write');
|
|
567
|
+
}
|
|
568
|
+
await applyMembershipTransactionFiles(files, true);
|
|
569
|
+
if (transaction.failRollbackPersistence || transaction.failRollbackPersistenceAfter) {
|
|
570
|
+
// Exercise the restore path after a complete new generation is visible.
|
|
571
|
+
// The catch below intentionally writes OLD bytes then leaves the durable
|
|
572
|
+
// journal in place so public entry recovery owns convergence.
|
|
573
|
+
throw new Error('injected_scale_down_failure:rollback-persistence-failure');
|
|
574
|
+
}
|
|
575
|
+
journal.phase = 'committed';
|
|
576
|
+
await writeAtomic(journalPath, JSON.stringify(journal, null, 2));
|
|
577
|
+
if (!transaction.retainJournalOnSuccess)
|
|
578
|
+
await removeDurableFile(journalPath);
|
|
579
|
+
}
|
|
580
|
+
catch (error) {
|
|
581
|
+
if (error instanceof Error && error.message === 'injected_scale_down_interruption:after-first-task-write')
|
|
582
|
+
throw error;
|
|
583
|
+
if (transaction.failRollbackPersistence || transaction.failRollbackPersistenceAfter) {
|
|
584
|
+
const target = transaction.failRollbackPersistenceAfter;
|
|
585
|
+
const targetIndex = target ? files.findIndex((file) => file.path === (target === 'config'
|
|
586
|
+
? teamConfigPath(teamName, cwd)
|
|
587
|
+
: teamManifestV2Path(teamName, cwd))) : 0;
|
|
588
|
+
const partial = files.slice(0, Math.max(1, targetIndex + 1));
|
|
589
|
+
await applyMembershipTransactionFiles(partial, false);
|
|
590
|
+
throw error;
|
|
591
|
+
}
|
|
592
|
+
if (transaction.recoverToNewOnFailure) {
|
|
593
|
+
try {
|
|
594
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
595
|
+
}
|
|
596
|
+
catch {
|
|
597
|
+
// Keep the committed-direction journal as durable recovery authority.
|
|
598
|
+
}
|
|
599
|
+
throw error;
|
|
600
|
+
}
|
|
601
|
+
// Leave the prepared marker durable if restoring old bytes also fails. Entry
|
|
602
|
+
// recovery will retry until the state has converged to the old generation.
|
|
603
|
+
try {
|
|
604
|
+
await applyMembershipTransactionFiles(files, false);
|
|
605
|
+
await removeDurableFile(journalPath);
|
|
606
|
+
}
|
|
607
|
+
catch {
|
|
608
|
+
// The prepared journal is the durable recovery authority.
|
|
609
|
+
}
|
|
610
|
+
throw error;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
353
613
|
// Initialize team state directory + config.json
|
|
354
614
|
// Creates: .omx/state/team/{name}/, workers/{worker-1}..{worker-N}/, tasks/
|
|
355
615
|
// Throws if workerCount > maxWorkers (default 20)
|
|
@@ -401,12 +661,16 @@ export async function initTeamState(teamName, task, agentType, workerCount, cwd,
|
|
|
401
661
|
workers,
|
|
402
662
|
created_at: new Date().toISOString(),
|
|
403
663
|
tmux_session: `omx-team-${teamName}`,
|
|
664
|
+
tmux_session_id: undefined,
|
|
665
|
+
tmux_session_created: undefined,
|
|
404
666
|
next_task_id: 1,
|
|
405
667
|
leader_cwd: workspace.leader_cwd,
|
|
406
668
|
team_state_root: workspace.team_state_root,
|
|
407
669
|
workspace_mode: workspace.workspace_mode,
|
|
408
670
|
worktree_mode: workspace.worktree_mode,
|
|
409
671
|
leader_pane_id: null,
|
|
672
|
+
leader_pane_pid: null,
|
|
673
|
+
hud_pane_pid: null,
|
|
410
674
|
hud_pane_id: null,
|
|
411
675
|
tmux_pane_owner_id: tmuxPaneOwnerId,
|
|
412
676
|
resize_hook_name: null,
|
|
@@ -415,8 +679,11 @@ export async function initTeamState(teamName, task, agentType, workerCount, cwd,
|
|
|
415
679
|
display_name: workspace.display_name,
|
|
416
680
|
requested_name: workspace.requested_name,
|
|
417
681
|
identity_source: workspace.identity_source,
|
|
682
|
+
config_generation: 0,
|
|
418
683
|
};
|
|
419
|
-
await
|
|
684
|
+
await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
685
|
+
await writeAtomic(join(root, 'config.json'), JSON.stringify(config, null, 2));
|
|
686
|
+
});
|
|
420
687
|
await writeTeamPhase(teamName, {
|
|
421
688
|
current_phase: 'team-exec',
|
|
422
689
|
max_fix_attempts: 3,
|
|
@@ -438,6 +705,8 @@ export async function initTeamState(teamName, task, agentType, workerCount, cwd,
|
|
|
438
705
|
lifecycle_profile: lifecycleProfile,
|
|
439
706
|
permissions_snapshot: permissionsSnapshot,
|
|
440
707
|
tmux_session: config.tmux_session,
|
|
708
|
+
tmux_session_id: config.tmux_session_id,
|
|
709
|
+
tmux_session_created: config.tmux_session_created,
|
|
441
710
|
worker_count: workerCount,
|
|
442
711
|
workers,
|
|
443
712
|
next_task_id: 1,
|
|
@@ -447,11 +716,14 @@ export async function initTeamState(teamName, task, agentType, workerCount, cwd,
|
|
|
447
716
|
workspace_mode: workspace.workspace_mode,
|
|
448
717
|
worktree_mode: workspace.worktree_mode,
|
|
449
718
|
leader_pane_id: null,
|
|
719
|
+
leader_pane_pid: null,
|
|
720
|
+
hud_pane_pid: null,
|
|
450
721
|
hud_pane_id: null,
|
|
451
722
|
tmux_pane_owner_id: tmuxPaneOwnerId,
|
|
452
723
|
resize_hook_name: null,
|
|
453
724
|
resize_hook_target: null,
|
|
454
725
|
next_worker_index: workerCount + 1,
|
|
726
|
+
startup_cleanup_panes: undefined,
|
|
455
727
|
display_name: workspace.display_name,
|
|
456
728
|
requested_name: workspace.requested_name,
|
|
457
729
|
identity_source: workspace.identity_source,
|
|
@@ -460,34 +732,64 @@ export async function initTeamState(teamName, task, agentType, workerCount, cwd,
|
|
|
460
732
|
}
|
|
461
733
|
async function writeConfig(cfg, cwd) {
|
|
462
734
|
const normalized = normalizeTeamConfig(cfg);
|
|
463
|
-
const
|
|
464
|
-
await
|
|
735
|
+
const configPath = teamConfigPath(normalized.name, cwd);
|
|
736
|
+
const oldConfigBytes = await readFile(configPath, 'utf8');
|
|
465
737
|
// Keep v2 manifest in sync when present. Don't create it implicitly here to preserve migration behavior.
|
|
466
|
-
const existing = await
|
|
467
|
-
if (existing) {
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
738
|
+
const existing = await readTeamManifestV2Raw(normalized.name, cwd);
|
|
739
|
+
if (!existing) {
|
|
740
|
+
await writeAtomic(configPath, JSON.stringify(normalized, null, 2));
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
const merged = {
|
|
744
|
+
...existing,
|
|
745
|
+
task: normalized.task,
|
|
746
|
+
tmux_session: normalized.tmux_session,
|
|
747
|
+
tmux_session_id: normalized.tmux_session_id,
|
|
748
|
+
tmux_session_created: normalized.tmux_session_created,
|
|
749
|
+
worker_count: normalized.worker_count,
|
|
750
|
+
workers: normalized.workers,
|
|
751
|
+
lifecycle_profile: normalized.lifecycle_profile,
|
|
752
|
+
next_task_id: normalizeNextTaskId(normalized.next_task_id),
|
|
753
|
+
leader_cwd: normalized.leader_cwd,
|
|
754
|
+
team_state_root: normalized.team_state_root,
|
|
755
|
+
workspace_mode: normalized.workspace_mode,
|
|
756
|
+
worktree_mode: normalized.worktree_mode,
|
|
757
|
+
leader_pane_id: normalized.leader_pane_id,
|
|
758
|
+
leader_pane_pid: normalized.leader_pane_pid,
|
|
759
|
+
hud_pane_pid: normalized.hud_pane_pid,
|
|
760
|
+
hud_pane_id: normalized.hud_pane_id,
|
|
761
|
+
tmux_pane_owner_id: normalized.tmux_pane_owner_id,
|
|
762
|
+
resize_hook_name: normalized.resize_hook_name,
|
|
763
|
+
resize_hook_target: normalized.resize_hook_target,
|
|
764
|
+
next_worker_index: normalized.next_worker_index ?? existing.next_worker_index,
|
|
765
|
+
startup_cleanup_panes: normalized.startup_cleanup_panes,
|
|
766
|
+
display_name: normalized.display_name ?? existing.display_name,
|
|
767
|
+
requested_name: normalized.requested_name ?? existing.requested_name,
|
|
768
|
+
identity_source: normalized.identity_source ?? existing.identity_source,
|
|
769
|
+
config_generation: normalized.config_generation,
|
|
770
|
+
};
|
|
771
|
+
const manifestPath = teamManifestV2Path(normalized.name, cwd);
|
|
772
|
+
const files = [
|
|
773
|
+
{ path: configPath, oldBytes: oldConfigBytes, newBytes: JSON.stringify(normalized, null, 2) },
|
|
774
|
+
{ path: manifestPath, oldBytes: await readFile(manifestPath, 'utf8'), newBytes: JSON.stringify(merged, null, 2) },
|
|
775
|
+
];
|
|
776
|
+
const journalPath = membershipTransactionPath(normalized.name, cwd);
|
|
777
|
+
const journal = { schemaVersion: 1, phase: 'prepared', files };
|
|
778
|
+
await writeAtomic(journalPath, JSON.stringify(journal, null, 2));
|
|
779
|
+
try {
|
|
780
|
+
await applyMembershipTransactionFiles(files, true);
|
|
781
|
+
journal.phase = 'committed';
|
|
782
|
+
await writeAtomic(journalPath, JSON.stringify(journal, null, 2));
|
|
783
|
+
await removeDurableFile(journalPath);
|
|
784
|
+
}
|
|
785
|
+
catch (error) {
|
|
786
|
+
try {
|
|
787
|
+
await recoverTeamMembershipTaskTransaction(normalized.name, cwd);
|
|
788
|
+
}
|
|
789
|
+
catch {
|
|
790
|
+
// The prepared journal is the durable recovery authority.
|
|
791
|
+
}
|
|
792
|
+
throw error;
|
|
491
793
|
}
|
|
492
794
|
}
|
|
493
795
|
function teamConfigFromManifest(manifest) {
|
|
@@ -507,34 +809,73 @@ function teamConfigFromManifest(manifest) {
|
|
|
507
809
|
workers: manifest.workers,
|
|
508
810
|
created_at: manifest.created_at,
|
|
509
811
|
tmux_session: manifest.tmux_session,
|
|
812
|
+
tmux_session_id: manifest.tmux_session_id,
|
|
813
|
+
tmux_session_created: manifest.tmux_session_created,
|
|
510
814
|
next_task_id: manifest.next_task_id,
|
|
511
815
|
leader_cwd: manifest.leader_cwd,
|
|
512
816
|
team_state_root: manifest.team_state_root,
|
|
513
817
|
workspace_mode: manifest.workspace_mode,
|
|
514
818
|
worktree_mode: manifest.worktree_mode,
|
|
515
819
|
leader_pane_id: manifest.leader_pane_id,
|
|
820
|
+
leader_pane_pid: manifest.leader_pane_pid ?? null,
|
|
821
|
+
hud_pane_pid: manifest.hud_pane_pid ?? null,
|
|
516
822
|
hud_pane_id: manifest.hud_pane_id,
|
|
517
|
-
tmux_pane_owner_id: manifest.tmux_pane_owner_id
|
|
823
|
+
tmux_pane_owner_id: typeof manifest.tmux_pane_owner_id === 'string' && manifest.tmux_pane_owner_id.trim() !== ''
|
|
824
|
+
? manifest.tmux_pane_owner_id.trim()
|
|
825
|
+
: undefined,
|
|
518
826
|
resize_hook_name: manifest.resize_hook_name,
|
|
519
827
|
resize_hook_target: manifest.resize_hook_target,
|
|
520
828
|
next_worker_index: manifest.next_worker_index,
|
|
829
|
+
startup_cleanup_panes: manifest.startup_cleanup_panes,
|
|
521
830
|
display_name: manifest.display_name,
|
|
522
831
|
requested_name: manifest.requested_name,
|
|
523
832
|
identity_source: manifest.identity_source,
|
|
524
833
|
};
|
|
525
834
|
}
|
|
835
|
+
function normalizeStartupCleanupPanes(value) {
|
|
836
|
+
if (!Array.isArray(value))
|
|
837
|
+
return null;
|
|
838
|
+
const panes = new Map();
|
|
839
|
+
for (const raw of value) {
|
|
840
|
+
if (!raw || typeof raw !== 'object')
|
|
841
|
+
return null;
|
|
842
|
+
const paneId = raw.pane_id;
|
|
843
|
+
const pid = raw.pid;
|
|
844
|
+
if (typeof paneId !== 'string' || !/^%[0-9]+$/.test(paneId))
|
|
845
|
+
return null;
|
|
846
|
+
if (!(pid === null || (typeof pid === 'number' && Number.isSafeInteger(pid) && pid > 0)))
|
|
847
|
+
return null;
|
|
848
|
+
panes.set(paneId, { pane_id: paneId, pid });
|
|
849
|
+
}
|
|
850
|
+
return [...panes.values()];
|
|
851
|
+
}
|
|
526
852
|
function normalizeTeamConfig(config) {
|
|
527
853
|
const workerLaunchMode = config.worker_launch_mode === 'prompt' ? 'prompt' : 'interactive';
|
|
854
|
+
const configGeneration = typeof config.config_generation === 'number'
|
|
855
|
+
&& Number.isSafeInteger(config.config_generation) && config.config_generation >= 0
|
|
856
|
+
? config.config_generation
|
|
857
|
+
: 0;
|
|
858
|
+
const startupCleanupPanes = normalizeStartupCleanupPanes(config.startup_cleanup_panes ?? []);
|
|
528
859
|
return {
|
|
529
860
|
...config,
|
|
861
|
+
config_generation: configGeneration,
|
|
530
862
|
lifecycle_profile: 'default',
|
|
531
863
|
leader_pane_id: config.leader_pane_id ?? null,
|
|
864
|
+
leader_pane_pid: typeof config.leader_pane_pid === 'number' && Number.isSafeInteger(config.leader_pane_pid) && config.leader_pane_pid > 0
|
|
865
|
+
? config.leader_pane_pid
|
|
866
|
+
: null,
|
|
867
|
+
hud_pane_pid: typeof config.hud_pane_pid === 'number' && Number.isSafeInteger(config.hud_pane_pid) && config.hud_pane_pid > 0
|
|
868
|
+
? config.hud_pane_pid
|
|
869
|
+
: null,
|
|
532
870
|
hud_pane_id: config.hud_pane_id ?? null,
|
|
533
871
|
tmux_pane_owner_id: typeof config.tmux_pane_owner_id === 'string' && config.tmux_pane_owner_id.trim() !== ''
|
|
534
872
|
? config.tmux_pane_owner_id.trim()
|
|
535
|
-
:
|
|
873
|
+
: undefined,
|
|
536
874
|
resize_hook_name: config.resize_hook_name ?? null,
|
|
537
875
|
resize_hook_target: config.resize_hook_target ?? null,
|
|
876
|
+
startup_cleanup_panes: startupCleanupPanes && startupCleanupPanes.length > 0
|
|
877
|
+
? startupCleanupPanes
|
|
878
|
+
: undefined,
|
|
538
879
|
worker_launch_mode: workerLaunchMode,
|
|
539
880
|
};
|
|
540
881
|
}
|
|
@@ -556,6 +897,8 @@ function teamManifestFromConfig(config) {
|
|
|
556
897
|
lifecycle_profile: normalized.lifecycle_profile,
|
|
557
898
|
permissions_snapshot: defaultPermissionsSnapshot(),
|
|
558
899
|
tmux_session: normalized.tmux_session,
|
|
900
|
+
tmux_session_id: normalized.tmux_session_id,
|
|
901
|
+
tmux_session_created: normalized.tmux_session_created,
|
|
559
902
|
worker_count: normalized.worker_count,
|
|
560
903
|
workers: normalized.workers,
|
|
561
904
|
next_task_id: normalizeNextTaskId(normalized.next_task_id),
|
|
@@ -565,35 +908,41 @@ function teamManifestFromConfig(config) {
|
|
|
565
908
|
workspace_mode: normalized.workspace_mode,
|
|
566
909
|
worktree_mode: normalized.worktree_mode,
|
|
567
910
|
leader_pane_id: normalized.leader_pane_id,
|
|
911
|
+
leader_pane_pid: normalized.leader_pane_pid,
|
|
912
|
+
hud_pane_pid: normalized.hud_pane_pid,
|
|
568
913
|
hud_pane_id: normalized.hud_pane_id,
|
|
569
914
|
tmux_pane_owner_id: normalized.tmux_pane_owner_id,
|
|
570
915
|
resize_hook_name: normalized.resize_hook_name,
|
|
571
916
|
resize_hook_target: normalized.resize_hook_target,
|
|
572
917
|
next_worker_index: normalized.next_worker_index,
|
|
918
|
+
startup_cleanup_panes: normalized.startup_cleanup_panes,
|
|
573
919
|
display_name: normalized.display_name,
|
|
574
920
|
requested_name: normalized.requested_name,
|
|
575
921
|
identity_source: normalized.identity_source,
|
|
922
|
+
config_generation: normalized.config_generation,
|
|
576
923
|
};
|
|
577
924
|
}
|
|
578
925
|
export async function writeTeamManifestV2(manifest, cwd) {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
926
|
+
await withTeamTaskBarrier(manifest.name, cwd, async () => {
|
|
927
|
+
const normalizedPolicy = normalizeTeamPolicy(manifest.policy, {
|
|
928
|
+
display_mode: manifest.policy?.display_mode === 'split_pane' ? 'split_pane' : 'auto',
|
|
929
|
+
worker_launch_mode: manifest.policy?.worker_launch_mode === 'prompt' ? 'prompt' : 'interactive',
|
|
930
|
+
});
|
|
931
|
+
const normalizedGovernance = normalizeTeamGovernance(manifest.governance, manifest.policy);
|
|
932
|
+
const tmuxPaneOwnerId = typeof manifest.tmux_pane_owner_id === 'string' && manifest.tmux_pane_owner_id.trim() !== ''
|
|
933
|
+
? manifest.tmux_pane_owner_id.trim()
|
|
934
|
+
: undefined;
|
|
935
|
+
const p = teamManifestV2Path(manifest.name, cwd);
|
|
936
|
+
await writeAtomic(p, JSON.stringify({
|
|
937
|
+
...manifest,
|
|
938
|
+
tmux_pane_owner_id: tmuxPaneOwnerId,
|
|
939
|
+
policy: normalizedPolicy,
|
|
940
|
+
governance: normalizedGovernance,
|
|
941
|
+
lifecycle_profile: 'default',
|
|
942
|
+
}, null, 2));
|
|
582
943
|
});
|
|
583
|
-
const normalizedGovernance = normalizeTeamGovernance(manifest.governance, manifest.policy);
|
|
584
|
-
const tmuxPaneOwnerId = typeof manifest.tmux_pane_owner_id === 'string' && manifest.tmux_pane_owner_id.trim() !== ''
|
|
585
|
-
? manifest.tmux_pane_owner_id.trim()
|
|
586
|
-
: defaultTmuxPaneOwnerId(manifest.name);
|
|
587
|
-
const p = teamManifestV2Path(manifest.name, cwd);
|
|
588
|
-
await writeAtomic(p, JSON.stringify({
|
|
589
|
-
...manifest,
|
|
590
|
-
tmux_pane_owner_id: tmuxPaneOwnerId,
|
|
591
|
-
policy: normalizedPolicy,
|
|
592
|
-
governance: normalizedGovernance,
|
|
593
|
-
lifecycle_profile: 'default',
|
|
594
|
-
}, null, 2));
|
|
595
944
|
}
|
|
596
|
-
|
|
945
|
+
async function readTeamManifestV2Raw(teamName, cwd) {
|
|
597
946
|
try {
|
|
598
947
|
const p = teamManifestV2Path(teamName, cwd);
|
|
599
948
|
if (!existsSync(p))
|
|
@@ -607,7 +956,7 @@ export async function readTeamManifestV2(teamName, cwd) {
|
|
|
607
956
|
const legacyTeamDecomposition = legacyPolicy?.team_decomposition;
|
|
608
957
|
const tmuxPaneOwnerId = typeof parsedManifest.tmux_pane_owner_id === 'string' && parsedManifest.tmux_pane_owner_id.trim() !== ''
|
|
609
958
|
? parsedManifest.tmux_pane_owner_id.trim()
|
|
610
|
-
:
|
|
959
|
+
: undefined;
|
|
611
960
|
return {
|
|
612
961
|
...parsedManifest,
|
|
613
962
|
tmux_pane_owner_id: tmuxPaneOwnerId,
|
|
@@ -627,6 +976,12 @@ export async function readTeamManifestV2(teamName, cwd) {
|
|
|
627
976
|
return null;
|
|
628
977
|
}
|
|
629
978
|
}
|
|
979
|
+
export async function readTeamManifestV2(teamName, cwd) {
|
|
980
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
981
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
982
|
+
return await readTeamManifestV2Raw(teamName, cwd);
|
|
983
|
+
});
|
|
984
|
+
}
|
|
630
985
|
// Idempotent migration; keeps config.json untouched.
|
|
631
986
|
export async function migrateV1ToV2(teamName, cwd) {
|
|
632
987
|
const existing = await readTeamManifestV2(teamName, cwd);
|
|
@@ -683,11 +1038,23 @@ async function computeNextTaskIdFromDisk(teamName, cwd) {
|
|
|
683
1038
|
}
|
|
684
1039
|
return maxId + 1;
|
|
685
1040
|
}
|
|
1041
|
+
async function readConfigGenerationRaw(teamName, cwd) {
|
|
1042
|
+
try {
|
|
1043
|
+
const raw = JSON.parse(await readFile(teamConfigPath(teamName, cwd), 'utf8'));
|
|
1044
|
+
return typeof raw.config_generation === 'number'
|
|
1045
|
+
&& Number.isSafeInteger(raw.config_generation) && raw.config_generation >= 0
|
|
1046
|
+
? raw.config_generation
|
|
1047
|
+
: 0;
|
|
1048
|
+
}
|
|
1049
|
+
catch {
|
|
1050
|
+
return null;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
686
1053
|
// Read team config
|
|
687
|
-
|
|
688
|
-
const v2 = await
|
|
1054
|
+
async function readTeamConfigRaw(teamName, cwd) {
|
|
1055
|
+
const v2 = await readTeamManifestV2Raw(teamName, cwd);
|
|
689
1056
|
if (v2)
|
|
690
|
-
return teamConfigFromManifest(v2);
|
|
1057
|
+
return { ...teamConfigFromManifest(v2), config_generation: (await readConfigGenerationRaw(teamName, cwd)) ?? 0 };
|
|
691
1058
|
// Attempt idempotent migration on first read.
|
|
692
1059
|
const migrated = await migrateV1ToV2(teamName, cwd);
|
|
693
1060
|
if (migrated)
|
|
@@ -706,6 +1073,12 @@ export async function readTeamConfig(teamName, cwd) {
|
|
|
706
1073
|
return null;
|
|
707
1074
|
}
|
|
708
1075
|
}
|
|
1076
|
+
export async function readTeamConfig(teamName, cwd) {
|
|
1077
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1078
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1079
|
+
return await readTeamConfigRaw(teamName, cwd);
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
709
1082
|
// Write worker identity file
|
|
710
1083
|
export async function writeWorkerIdentity(teamName, workerName, identity, cwd) {
|
|
711
1084
|
const p = join(workerDir(teamName, workerName, cwd), 'identity.json');
|
|
@@ -753,7 +1126,8 @@ export async function writeWorkerStatus(teamName, workerName, status, cwd) {
|
|
|
753
1126
|
const p = join(workerDir(teamName, workerName, cwd), 'status.json');
|
|
754
1127
|
await writeAtomic(p, JSON.stringify(status, null, 2));
|
|
755
1128
|
}
|
|
756
|
-
// File-based scaling lock
|
|
1129
|
+
// File-based scaling lock kept outside the deletable team root. Operations that
|
|
1130
|
+
// also mutate membership acquire this lock before the membership barrier.
|
|
757
1131
|
export async function withScalingLock(teamName, cwd, fn) {
|
|
758
1132
|
return await withScalingLockImpl(teamName, cwd, LOCK_STALE_MS, { teamDir, taskClaimLockDir, mailboxLockDir }, fn);
|
|
759
1133
|
}
|
|
@@ -768,21 +1142,50 @@ function taskFilePath(teamName, taskId, cwd) {
|
|
|
768
1142
|
assertPathWithinDir(p, resolveTeamStateRoot(cwd));
|
|
769
1143
|
return p;
|
|
770
1144
|
}
|
|
1145
|
+
const taskMembershipBarrierContext = new AsyncLocalStorage();
|
|
1146
|
+
function taskMembershipBarrierKey(teamName, cwd) {
|
|
1147
|
+
return `${resolve(cwd)}\0${teamName}`;
|
|
1148
|
+
}
|
|
771
1149
|
async function withTeamLock(teamName, cwd, fn) {
|
|
772
1150
|
return await withTeamLockImpl(teamName, cwd, LOCK_STALE_MS, { teamDir, taskClaimLockDir, mailboxLockDir }, fn);
|
|
773
1151
|
}
|
|
1152
|
+
/**
|
|
1153
|
+
* Serializes membership snapshots with task creation and claims. The global
|
|
1154
|
+
* lock order is scaling, membership, then task claim locks. Operations that do
|
|
1155
|
+
* not scale acquire only this barrier (and then any task claim lock).
|
|
1156
|
+
*/
|
|
1157
|
+
export async function withTeamTaskBarrier(teamName, cwd, fn) {
|
|
1158
|
+
const key = taskMembershipBarrierKey(teamName, cwd);
|
|
1159
|
+
if (taskMembershipBarrierContext.getStore()?.has(key))
|
|
1160
|
+
return await fn();
|
|
1161
|
+
return await withTeamLock(teamName, cwd, async () => {
|
|
1162
|
+
const held = new Set(taskMembershipBarrierContext.getStore() ?? []);
|
|
1163
|
+
held.add(key);
|
|
1164
|
+
return await taskMembershipBarrierContext.run(held, fn);
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
774
1167
|
async function withTaskClaimLock(teamName, taskId, cwd, fn) {
|
|
775
1168
|
return await withTaskClaimLockImpl(teamName, taskId, cwd, LOCK_STALE_MS, { teamDir, taskClaimLockDir, mailboxLockDir }, fn);
|
|
776
1169
|
}
|
|
777
1170
|
async function withMailboxLock(teamName, workerName, cwd, fn) {
|
|
778
1171
|
return await withMailboxLockImpl(teamName, workerName, cwd, LOCK_STALE_MS, { teamDir, taskClaimLockDir, mailboxLockDir }, fn);
|
|
779
1172
|
}
|
|
1173
|
+
export function teamContinuationRequiredDiagnostic(phase) {
|
|
1174
|
+
const epoch = phase.terminal_epoch ?? phase.updated_at;
|
|
1175
|
+
const reason = phase.terminal_reason ?? `terminal_phase_${phase.current_phase}`;
|
|
1176
|
+
return `team_continuation_required:terminal_epoch=${epoch}:reason=${reason}:action=reopen_or_start_continuation`;
|
|
1177
|
+
}
|
|
780
1178
|
// Create a task (auto-increment ID)
|
|
781
1179
|
export async function createTask(teamName, task, cwd) {
|
|
782
|
-
return
|
|
1180
|
+
return withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1181
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
783
1182
|
const cfg = await readTeamConfig(teamName, cwd);
|
|
784
1183
|
if (!cfg)
|
|
785
1184
|
throw new Error(`Team ${teamName} not found`);
|
|
1185
|
+
const phase = await readTeamPhase(teamName, cwd);
|
|
1186
|
+
if (phase?.terminal_epoch || (phase && isTerminalPhase(phase.current_phase))) {
|
|
1187
|
+
throw new Error(teamContinuationRequiredDiagnostic(phase));
|
|
1188
|
+
}
|
|
786
1189
|
let nextNumeric = normalizeNextTaskId(cfg.next_task_id);
|
|
787
1190
|
const nextNumericFromDisk = await computeNextTaskIdFromDisk(teamName, cwd);
|
|
788
1191
|
if (!hasValidNextTaskId(cfg.next_task_id) || nextNumericFromDisk > nextNumeric) {
|
|
@@ -808,7 +1211,7 @@ export async function createTask(teamName, task, cwd) {
|
|
|
808
1211
|
});
|
|
809
1212
|
}
|
|
810
1213
|
// Read a task (returns null on missing/malformed)
|
|
811
|
-
|
|
1214
|
+
async function readTaskRaw(teamName, taskId, cwd) {
|
|
812
1215
|
try {
|
|
813
1216
|
const p = taskFilePath(teamName, taskId, cwd);
|
|
814
1217
|
if (!existsSync(p))
|
|
@@ -821,98 +1224,121 @@ export async function readTask(teamName, taskId, cwd) {
|
|
|
821
1224
|
return null;
|
|
822
1225
|
}
|
|
823
1226
|
}
|
|
1227
|
+
export async function readTask(teamName, taskId, cwd) {
|
|
1228
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1229
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1230
|
+
return await readTaskRaw(teamName, taskId, cwd);
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
824
1233
|
// Update a task (merge updates, atomic write)
|
|
825
1234
|
export async function updateTask(teamName, taskId, updates, cwd) {
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
1235
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1236
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1237
|
+
const lock = await withTaskClaimLock(teamName, taskId, cwd, async () => {
|
|
1238
|
+
const existing = await readTaskRaw(teamName, taskId, cwd);
|
|
1239
|
+
if (!existing)
|
|
1240
|
+
return null;
|
|
1241
|
+
if (updates.status !== undefined && !['pending', 'blocked', 'in_progress', 'completed', 'failed'].includes(updates.status)) {
|
|
1242
|
+
throw new Error(`Invalid task status: ${updates.status}`);
|
|
1243
|
+
}
|
|
1244
|
+
const rawDeps = updates.depends_on ?? updates.blocked_by ?? existing.depends_on ?? existing.blocked_by ?? [];
|
|
1245
|
+
const normalizedDeps = Array.isArray(rawDeps) ? rawDeps : [];
|
|
1246
|
+
const merged = normalizeTask({
|
|
1247
|
+
...normalizeTask(existing),
|
|
1248
|
+
...updates,
|
|
1249
|
+
id: existing.id,
|
|
1250
|
+
created_at: existing.created_at,
|
|
1251
|
+
depends_on: normalizedDeps,
|
|
1252
|
+
version: Math.max(1, existing.version ?? 1) + 1,
|
|
1253
|
+
});
|
|
1254
|
+
await writeAtomic(taskFilePath(teamName, taskId, cwd), JSON.stringify(merged, null, 2));
|
|
1255
|
+
return merged;
|
|
842
1256
|
});
|
|
843
|
-
|
|
844
|
-
|
|
1257
|
+
if (!lock.ok)
|
|
1258
|
+
throw new Error(`Timed out acquiring task claim lock for ${teamName}/${taskId}`);
|
|
1259
|
+
return lock.value;
|
|
845
1260
|
});
|
|
846
|
-
if (!lock.ok) {
|
|
847
|
-
throw new Error(`Timed out acquiring task claim lock for ${teamName}/${taskId}`);
|
|
848
|
-
}
|
|
849
|
-
return lock.value;
|
|
850
1261
|
}
|
|
851
1262
|
// List all tasks sorted by numeric ID
|
|
852
1263
|
export async function listTasks(teamName, cwd) {
|
|
853
|
-
return await
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
1264
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1265
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1266
|
+
return await listTasksImpl(teamName, cwd, {
|
|
1267
|
+
teamDir,
|
|
1268
|
+
isTeamTask,
|
|
1269
|
+
normalizeTask,
|
|
1270
|
+
});
|
|
857
1271
|
});
|
|
858
1272
|
}
|
|
859
1273
|
export async function computeTaskReadiness(teamName, taskId, cwd) {
|
|
860
1274
|
return await computeTaskReadinessImpl(teamName, taskId, cwd, { readTask });
|
|
861
1275
|
}
|
|
862
1276
|
export async function claimTask(teamName, taskId, workerName, expectedVersion, cwd) {
|
|
863
|
-
return await
|
|
864
|
-
teamName,
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
1277
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1278
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1279
|
+
return await claimTaskImpl(taskId, workerName, expectedVersion, {
|
|
1280
|
+
teamName,
|
|
1281
|
+
cwd,
|
|
1282
|
+
readTask,
|
|
1283
|
+
readTeamConfig,
|
|
1284
|
+
withTaskClaimLock,
|
|
1285
|
+
normalizeTask,
|
|
1286
|
+
isTerminalTaskStatus,
|
|
1287
|
+
taskFilePath,
|
|
1288
|
+
writeAtomic,
|
|
1289
|
+
});
|
|
873
1290
|
});
|
|
874
1291
|
}
|
|
875
1292
|
export async function transitionTaskStatus(teamName, taskId, from, to, claimToken, cwd, terminalData) {
|
|
876
|
-
return await
|
|
877
|
-
teamName,
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
1293
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1294
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1295
|
+
return await transitionTaskStatusImpl(taskId, from, to, claimToken, terminalData, {
|
|
1296
|
+
teamName,
|
|
1297
|
+
cwd,
|
|
1298
|
+
readTask,
|
|
1299
|
+
readTeamConfig,
|
|
1300
|
+
withTaskClaimLock,
|
|
1301
|
+
normalizeTask,
|
|
1302
|
+
isTerminalTaskStatus,
|
|
1303
|
+
canTransitionTaskStatus,
|
|
1304
|
+
taskFilePath,
|
|
1305
|
+
writeAtomic,
|
|
1306
|
+
appendTeamEvent,
|
|
1307
|
+
readMonitorSnapshot,
|
|
1308
|
+
writeMonitorSnapshot,
|
|
1309
|
+
});
|
|
890
1310
|
});
|
|
891
1311
|
}
|
|
892
1312
|
export async function releaseTaskClaim(teamName, taskId, claimToken, workerName, cwd) {
|
|
893
|
-
return await
|
|
894
|
-
teamName,
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1313
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1314
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1315
|
+
return await releaseTaskClaimImpl(taskId, claimToken, workerName, {
|
|
1316
|
+
teamName,
|
|
1317
|
+
cwd,
|
|
1318
|
+
readTask,
|
|
1319
|
+
readTeamConfig,
|
|
1320
|
+
withTaskClaimLock,
|
|
1321
|
+
normalizeTask,
|
|
1322
|
+
isTerminalTaskStatus,
|
|
1323
|
+
taskFilePath,
|
|
1324
|
+
writeAtomic,
|
|
1325
|
+
});
|
|
903
1326
|
});
|
|
904
1327
|
}
|
|
905
1328
|
export async function reclaimExpiredTaskClaim(teamName, taskId, cwd) {
|
|
906
|
-
return await
|
|
907
|
-
teamName,
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
1329
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1330
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1331
|
+
return await reclaimExpiredTaskClaimImpl(taskId, {
|
|
1332
|
+
teamName,
|
|
1333
|
+
cwd,
|
|
1334
|
+
readTask,
|
|
1335
|
+
readTeamConfig,
|
|
1336
|
+
withTaskClaimLock,
|
|
1337
|
+
normalizeTask,
|
|
1338
|
+
isTerminalTaskStatus,
|
|
1339
|
+
taskFilePath,
|
|
1340
|
+
writeAtomic,
|
|
1341
|
+
});
|
|
916
1342
|
});
|
|
917
1343
|
}
|
|
918
1344
|
export async function appendTeamEvent(teamName, event, cwd) {
|
|
@@ -1012,6 +1438,48 @@ async function readDispatchRequests(teamName, cwd) {
|
|
|
1012
1438
|
return [];
|
|
1013
1439
|
}
|
|
1014
1440
|
}
|
|
1441
|
+
/** Read only strictly recognized target-team legacy request records for rollback scoping. */
|
|
1442
|
+
function isStrictLegacyDispatchRequestForRollback(value, teamName) {
|
|
1443
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
1444
|
+
return false;
|
|
1445
|
+
const request = value;
|
|
1446
|
+
const requiredFields = [
|
|
1447
|
+
'request_id', 'kind', 'team_name', 'to_worker', 'trigger_message',
|
|
1448
|
+
'transport_preference', 'fallback_allowed', 'status', 'attempt_count',
|
|
1449
|
+
'created_at', 'updated_at',
|
|
1450
|
+
];
|
|
1451
|
+
if (requiredFields.some((field) => !Object.prototype.hasOwnProperty.call(request, field)))
|
|
1452
|
+
return false;
|
|
1453
|
+
return typeof request.request_id === 'string'
|
|
1454
|
+
&& request.request_id.length > 0
|
|
1455
|
+
&& ['inbox', 'mailbox', 'nudge'].includes(String(request.kind))
|
|
1456
|
+
&& request.team_name === teamName
|
|
1457
|
+
&& typeof request.to_worker === 'string'
|
|
1458
|
+
&& request.to_worker.length > 0
|
|
1459
|
+
&& typeof request.trigger_message === 'string'
|
|
1460
|
+
&& ['hook_preferred_with_fallback', 'transport_direct', 'prompt_stdin'].includes(String(request.transport_preference))
|
|
1461
|
+
&& typeof request.fallback_allowed === 'boolean'
|
|
1462
|
+
&& ['pending', 'notified', 'delivered', 'failed'].includes(String(request.status))
|
|
1463
|
+
&& typeof request.attempt_count === 'number'
|
|
1464
|
+
&& Number.isFinite(request.attempt_count)
|
|
1465
|
+
&& typeof request.created_at === 'string'
|
|
1466
|
+
&& typeof request.updated_at === 'string';
|
|
1467
|
+
}
|
|
1468
|
+
async function readLegacyDispatchRequestsForRollback(teamName, cwd) {
|
|
1469
|
+
const path = dispatchRequestsPath(teamName, cwd);
|
|
1470
|
+
try {
|
|
1471
|
+
const raw = JSON.parse(await readFile(path, 'utf8'));
|
|
1472
|
+
if (!Array.isArray(raw) || raw.some((entry) => !isStrictLegacyDispatchRequestForRollback(entry, teamName))) {
|
|
1473
|
+
throw new Error('legacy dispatch rollback evidence is malformed or unrecognized');
|
|
1474
|
+
}
|
|
1475
|
+
return raw;
|
|
1476
|
+
}
|
|
1477
|
+
catch (error) {
|
|
1478
|
+
if (error.code === 'ENOENT')
|
|
1479
|
+
return [];
|
|
1480
|
+
throw error;
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1015
1483
|
async function writeDispatchRequests(teamName, requests, cwd) {
|
|
1016
1484
|
await writeAtomic(dispatchRequestsPath(teamName, cwd), JSON.stringify(requests, null, 2));
|
|
1017
1485
|
await writeBridgeDispatchCompat(teamName, requests, cwd);
|
|
@@ -1065,6 +1533,61 @@ export function resolveDispatchLockTimeoutMs(env = process.env) {
|
|
|
1065
1533
|
async function withDispatchLock(teamName, cwd, fn) {
|
|
1066
1534
|
return await withDispatchLockImpl(teamName, cwd, teamDir, dispatchLockDir, fn);
|
|
1067
1535
|
}
|
|
1536
|
+
/** Remove worker-targeted dispatch requests under the authoritative dispatch lock. */
|
|
1537
|
+
export async function removeDispatchRequestsForWorkers(teamName, workerNames, cwd) {
|
|
1538
|
+
const names = new Set(workerNames);
|
|
1539
|
+
await withDispatchLock(teamName, cwd, async () => {
|
|
1540
|
+
// Do not derive rollback IDs from bridge-normalized root records: unscoped
|
|
1541
|
+
// and other-team records can share a target worker name. This team's legacy
|
|
1542
|
+
// file is the canonical rollback scope.
|
|
1543
|
+
const requests = await readLegacyDispatchRequestsForRollback(teamName, cwd);
|
|
1544
|
+
const legacyRequestIds = requests
|
|
1545
|
+
.filter((request) => names.has(request.to_worker))
|
|
1546
|
+
.map((request) => request.request_id);
|
|
1547
|
+
let removedRequestIds = legacyRequestIds;
|
|
1548
|
+
if (isBridgeEnabled()) {
|
|
1549
|
+
const stateDir = resolveBridgeStateDir(cwd);
|
|
1550
|
+
const bridge = getDefaultBridge(stateDir);
|
|
1551
|
+
const snapshot = bridge.execCommand({ command: 'CaptureSnapshot' });
|
|
1552
|
+
if (snapshot.event !== 'SnapshotCaptured') {
|
|
1553
|
+
throw new Error(`authoritative_dispatch_rollback_discovery_failed:${[...names].join(',')}`);
|
|
1554
|
+
}
|
|
1555
|
+
const scopedAuthoritativeIds = bridge.readDispatchRecordsStrict()
|
|
1556
|
+
.filter((record) => {
|
|
1557
|
+
const metadataTeam = typeof record.metadata?.team_name === 'string' ? record.metadata.team_name : '';
|
|
1558
|
+
return metadataTeam === teamName && names.has(record.target);
|
|
1559
|
+
})
|
|
1560
|
+
.map((record) => record.request_id);
|
|
1561
|
+
removedRequestIds = [...new Set([...legacyRequestIds, ...scopedAuthoritativeIds])];
|
|
1562
|
+
if (removedRequestIds.length === 0) {
|
|
1563
|
+
await writeAtomic(dispatchRequestsPath(teamName, cwd), JSON.stringify(requests, null, 2));
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
const removal = bridge.removeDispatchRecords(removedRequestIds);
|
|
1567
|
+
if (removal.event !== 'DispatchRecordsRemoved'
|
|
1568
|
+
|| removedRequestIds.some((requestId) => !removal.request_ids.includes(requestId))) {
|
|
1569
|
+
throw new Error(`authoritative_dispatch_rollback_command_failed:${[...names].join(',')}`);
|
|
1570
|
+
}
|
|
1571
|
+
// Force a separate runtime command after mutation. The removal event is
|
|
1572
|
+
// the authoritative acknowledgement; TS must not inspect or rewrite the
|
|
1573
|
+
// shared root dispatch.json as a substitute for runtime verification.
|
|
1574
|
+
const verificationSnapshot = bridge.execCommand({ command: 'CaptureSnapshot' });
|
|
1575
|
+
if (verificationSnapshot.event !== 'SnapshotCaptured') {
|
|
1576
|
+
throw new Error(`authoritative_dispatch_rollback_verification_failed:${[...names].join(',')}`);
|
|
1577
|
+
}
|
|
1578
|
+
const remainingRemovedRecord = bridge.readDispatchRecordsStrict()
|
|
1579
|
+
.some((record) => removedRequestIds.includes(record.request_id));
|
|
1580
|
+
if (remainingRemovedRecord) {
|
|
1581
|
+
throw new Error(`authoritative_dispatch_rollback_verification_failed:${[...names].join(',')}`);
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
// The legacy per-team request file is compatibility output only. Update it
|
|
1585
|
+
// only after the authoritative runtime confirms removal; never regenerate
|
|
1586
|
+
// the shared bridge dispatch.json from a local snapshot during rollback.
|
|
1587
|
+
const retained = requests.filter((request) => !names.has(request.to_worker));
|
|
1588
|
+
await writeAtomic(dispatchRequestsPath(teamName, cwd), JSON.stringify(retained, null, 2));
|
|
1589
|
+
});
|
|
1590
|
+
}
|
|
1068
1591
|
export async function enqueueDispatchRequest(teamName, requestInput, cwd) {
|
|
1069
1592
|
return await enqueueDispatchRequestImpl(requestInput, {
|
|
1070
1593
|
teamName,
|
|
@@ -1429,10 +1952,30 @@ export async function markOwnedTeamsLeaderStopObserved(cwd, leaderSessionId, now
|
|
|
1429
1952
|
}
|
|
1430
1953
|
// === Config persistence (public wrapper) ===
|
|
1431
1954
|
export async function saveTeamConfig(config, cwd) {
|
|
1432
|
-
await
|
|
1955
|
+
await withTeamTaskBarrier(config.name, cwd, async () => {
|
|
1956
|
+
// The caller's config is a full canonical replacement; recover any
|
|
1957
|
+
// interrupted membership generation while holding the same barrier before
|
|
1958
|
+
// deriving and writing its manifest companion.
|
|
1959
|
+
await recoverTeamMembershipTaskTransaction(config.name, cwd);
|
|
1960
|
+
const currentGeneration = await readConfigGenerationRaw(config.name, cwd);
|
|
1961
|
+
if (currentGeneration === null)
|
|
1962
|
+
throw new Error(`team_config_missing:${config.name}`);
|
|
1963
|
+
const expectedGeneration = normalizeTeamConfig(config).config_generation;
|
|
1964
|
+
if (expectedGeneration !== currentGeneration) {
|
|
1965
|
+
throw new Error(`team_config_stale_generation:${config.name}:${expectedGeneration}:${currentGeneration}`);
|
|
1966
|
+
}
|
|
1967
|
+
config.config_generation = currentGeneration + 1;
|
|
1968
|
+
await writeConfig(config, cwd);
|
|
1969
|
+
});
|
|
1433
1970
|
}
|
|
1434
|
-
// Delete team state
|
|
1971
|
+
// Delete team state only after excluding both scaling and membership mutations.
|
|
1972
|
+
// The scaling lock lives outside the deletable team root, so waiters cannot
|
|
1973
|
+
// recreate a deleted team merely by acquiring their lock.
|
|
1435
1974
|
export async function cleanupTeamState(teamName, cwd) {
|
|
1436
|
-
await
|
|
1975
|
+
await withScalingLock(teamName, cwd, async () => {
|
|
1976
|
+
await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1977
|
+
await rm(teamDir(teamName, cwd), { recursive: true, force: true });
|
|
1978
|
+
});
|
|
1979
|
+
});
|
|
1437
1980
|
}
|
|
1438
1981
|
//# sourceMappingURL=state.js.map
|