oh-my-codex 0.20.1 → 0.20.3
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 +7 -6
- package/Cargo.toml +1 -1
- package/README.md +36 -1
- package/crates/omx-runtime/Cargo.toml +1 -0
- package/crates/omx-runtime/src/main.rs +25 -2
- package/crates/omx-runtime/tests/execution.rs +219 -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__/hermes.test.js.map +1 -1
- package/dist/adapt/contracts.d.ts.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.d.ts +2 -0
- package/dist/auth/__tests__/hotswap.test.d.ts.map +1 -0
- package/dist/auth/__tests__/hotswap.test.js +183 -0
- package/dist/auth/__tests__/hotswap.test.js.map +1 -0
- package/dist/auth/hotswap.d.ts +6 -0
- package/dist/auth/hotswap.d.ts.map +1 -1
- package/dist/auth/hotswap.js +102 -19
- package/dist/auth/hotswap.js.map +1 -1
- package/dist/auth/paths.js.map +1 -1
- package/dist/auth/storage.js.map +1 -1
- package/dist/autopilot/__tests__/ralplan-gate.test.js +5 -5
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
- package/dist/autopilot/completion-gate.js.map +1 -1
- package/dist/autopilot/fsm.d.ts +1 -1
- package/dist/autopilot/fsm.d.ts.map +1 -1
- package/dist/autoresearch/goal.js.map +1 -1
- package/dist/autoresearch/runtime.js.map +1 -1
- package/dist/capabilities/lockfile.js.map +1 -1
- package/dist/catalog/reader.js.map +1 -1
- package/dist/catalog/skill-mirror.js.map +1 -1
- package/dist/cli/__tests__/adapt-help.test.js.map +1 -1
- package/dist/cli/__tests__/agents-init.test.js.map +1 -1
- package/dist/cli/__tests__/agents.test.js.map +1 -1
- package/dist/cli/__tests__/api.test.js.map +1 -1
- package/dist/cli/__tests__/ask.test.js.map +1 -1
- package/dist/cli/__tests__/auth.test.js +60 -6
- package/dist/cli/__tests__/auth.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch.test.js.map +1 -1
- package/dist/cli/__tests__/capabilities.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +80 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-invalid-config.test.js +47 -4
- package/dist/cli/__tests__/doctor-invalid-config.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +752 -15
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/exec.test.js +136 -0
- package/dist/cli/__tests__/exec.test.js.map +1 -1
- package/dist/cli/__tests__/imagegen-continuation.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +473 -14
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +336 -4
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +87 -12
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts +2 -0
- package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts.map +1 -0
- package/dist/cli/__tests__/native-hook-claim-journal.test.js +206 -0
- package/dist/cli/__tests__/native-hook-claim-journal.test.js.map +1 -0
- package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-deslop-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +6 -0
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-prd-smoke.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +8 -3
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts +2 -0
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts.map +1 -0
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js +72 -0
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js.map +1 -0
- package/dist/cli/__tests__/ralplan.test.d.ts +2 -0
- package/dist/cli/__tests__/ralplan.test.d.ts.map +1 -0
- package/dist/cli/__tests__/ralplan.test.js +55 -0
- package/dist/cli/__tests__/ralplan.test.js.map +1 -0
- package/dist/cli/__tests__/resume.test.js +17 -11
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.js +25 -0
- 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__/session-search.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +79 -0
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-gh-star.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +77 -3
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts +2 -0
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts.map +1 -0
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js +285 -0
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js.map +1 -0
- package/dist/cli/__tests__/setup-install-mode.test.js +2579 -294
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-preferences.test.d.ts +2 -0
- package/dist/cli/__tests__/setup-preferences.test.d.ts.map +1 -0
- package/dist/cli/__tests__/setup-preferences.test.js +79 -0
- package/dist/cli/__tests__/setup-preferences.test.js.map +1 -0
- package/dist/cli/__tests__/setup-refresh.test.js +33 -2
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +46 -3
- package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
- package/dist/cli/__tests__/state.test.js +37 -0
- package/dist/cli/__tests__/state.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +105 -7
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +61 -1
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +1817 -24
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/__tests__/update.test.js +58 -0
- package/dist/cli/__tests__/update.test.js.map +1 -1
- package/dist/cli/__tests__/url.test.js.map +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js +2 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
- package/dist/cli/adapt.js.map +1 -1
- package/dist/cli/agents-init.js.map +1 -1
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/api.js.map +1 -1
- package/dist/cli/ask.d.ts +1 -1
- package/dist/cli/ask.d.ts.map +1 -1
- package/dist/cli/ask.js.map +1 -1
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/autoresearch-guided.js.map +1 -1
- package/dist/cli/autoresearch-intake.js.map +1 -1
- package/dist/cli/capabilities.js.map +1 -1
- package/dist/cli/cleanup.js.map +1 -1
- package/dist/cli/codex-feature-probe.js.map +1 -1
- package/dist/cli/codex-home.js.map +1 -1
- package/dist/cli/doctor.d.ts +21 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +607 -130
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +14 -3
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +245 -57
- 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/mcp-serve.js.map +1 -1
- package/dist/cli/mission.js.map +1 -1
- package/dist/cli/native-assets.js.map +1 -1
- package/dist/cli/native-hook-claim-journal.d.ts +29 -0
- package/dist/cli/native-hook-claim-journal.d.ts.map +1 -0
- package/dist/cli/native-hook-claim-journal.js +252 -0
- package/dist/cli/native-hook-claim-journal.js.map +1 -0
- package/dist/cli/omx.js.map +1 -1
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/project-runtime-codex-homes.js.map +1 -1
- package/dist/cli/question.js.map +1 -1
- package/dist/cli/ralph.d.ts.map +1 -1
- package/dist/cli/ralph.js +3 -2
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/ralplan.d.ts +10 -0
- package/dist/cli/ralplan.d.ts.map +1 -0
- package/dist/cli/ralplan.js +110 -0
- package/dist/cli/ralplan.js.map +1 -0
- 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 +11 -0
- package/dist/cli/setup-preferences.d.ts.map +1 -1
- package/dist/cli/setup-preferences.js +32 -0
- package/dist/cli/setup-preferences.js.map +1 -1
- package/dist/cli/setup.d.ts +58 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +1450 -398
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/sparkshell.js.map +1 -1
- package/dist/cli/star-prompt.js.map +1 -1
- package/dist/cli/state.d.ts.map +1 -1
- package/dist/cli/state.js +2 -1
- package/dist/cli/state.js.map +1 -1
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/ultragoal.d.ts +5 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +34 -2
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/uninstall.d.ts +17 -0
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +986 -95
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +8 -1
- package/dist/cli/update.js.map +1 -1
- package/dist/cli/url.js.map +1 -1
- package/dist/compat/__tests__/doctor-contract.test.js +5 -1
- package/dist/compat/__tests__/doctor-contract.test.js.map +1 -1
- package/dist/compat/__tests__/rust-runtime-compat.test.js +1 -1
- package/dist/compat/__tests__/rust-runtime-compat.test.js.map +1 -1
- package/dist/config/__tests__/codex-hooks.test.js +1287 -11
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +1179 -32
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +6 -1
- 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/codex-feature-flags.d.ts.map +1 -1
- package/dist/config/codex-feature-flags.js.map +1 -1
- package/dist/config/codex-hooks.d.ts +124 -1
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +2142 -265
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/commit-lore-guard.js.map +1 -1
- package/dist/config/generator.d.ts +23 -34
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +1480 -246
- package/dist/config/generator.js.map +1 -1
- package/dist/config/mcp-registry.js.map +1 -1
- package/dist/config/models.d.ts +14 -4
- 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/config/omx-first-party-mcp.js.map +1 -1
- package/dist/config/team-mode.d.ts.map +1 -1
- package/dist/document-refresh/__tests__/enforcer.test.js.map +1 -1
- package/dist/document-refresh/enforcer.js.map +1 -1
- package/dist/exec/followup.js.map +1 -1
- package/dist/goal-workflows/artifacts.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +7 -4
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/analyze-routing-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/analyze-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +9 -3
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/design-skill.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +1376 -6
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +252 -543
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +38 -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 +765 -10
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +2 -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 +142 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +48 -2
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +61 -44
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js +3 -2
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js +243 -4
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +531 -12
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +163 -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-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-visual-verdict.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +43 -4
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/openclaw-setup-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -1
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +1 -1
- package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts +2 -0
- package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/prompt-session-provenance.test.js +82 -0
- package/dist/hooks/__tests__/prompt-session-provenance.test.js.map +1 -0
- package/dist/hooks/__tests__/session.test.js +878 -11
- package/dist/hooks/__tests__/session.test.js.map +1 -1
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -1
- package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/visual-ralph-skill.test.js.map +1 -1
- package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +1 -1
- package/dist/hooks/agents-overlay.js +5 -5
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/code-simplifier/index.js.map +1 -1
- package/dist/hooks/explore-routing.js.map +1 -1
- package/dist/hooks/extensibility/dispatcher.js.map +1 -1
- package/dist/hooks/extensibility/events.js.map +1 -1
- package/dist/hooks/extensibility/loader.js.map +1 -1
- package/dist/hooks/extensibility/plugin-runner-stdin.js.map +1 -1
- package/dist/hooks/extensibility/sdk/logging.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +33 -7
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +2228 -119
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/keyword-registry.d.ts +12 -0
- package/dist/hooks/keyword-registry.d.ts.map +1 -1
- package/dist/hooks/keyword-registry.js +41 -0
- package/dist/hooks/keyword-registry.js.map +1 -1
- package/dist/hooks/prompt-session-provenance.d.ts +87 -0
- package/dist/hooks/prompt-session-provenance.d.ts.map +1 -0
- package/dist/hooks/prompt-session-provenance.js +180 -0
- package/dist/hooks/prompt-session-provenance.js.map +1 -0
- package/dist/hooks/session.d.ts +163 -34
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +1395 -317
- package/dist/hooks/session.js.map +1 -1
- package/dist/hooks/task-size-detector.js.map +1 -1
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/authority.js.map +1 -1
- package/dist/hud/constants.js.map +1 -1
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/tmux.js.map +1 -1
- package/dist/leader/__tests__/contract.test.js +153 -1
- package/dist/leader/__tests__/contract.test.js.map +1 -1
- package/dist/leader/contract.d.ts +42 -5
- package/dist/leader/contract.d.ts.map +1 -1
- package/dist/leader/contract.js +184 -3
- package/dist/leader/contract.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.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__/server-lifecycle.test.js +15 -2
- package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
- package/dist/mcp/__tests__/state-paths.test.js +98 -1
- package/dist/mcp/__tests__/state-paths.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/bootstrap.js.map +1 -1
- package/dist/mcp/code-intel-server.d.ts +58 -58
- 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.js.map +1 -1
- package/dist/mcp/hermes-server.d.ts +70 -70
- package/dist/mcp/hermes-server.d.ts.map +1 -1
- package/dist/mcp/lifecycle-telemetry.js.map +1 -1
- package/dist/mcp/memory-server.d.ts +34 -34
- package/dist/mcp/memory-server.d.ts.map +1 -1
- package/dist/mcp/memory-server.js.map +1 -1
- package/dist/mcp/state-paths.d.ts +14 -0
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +96 -20
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/mcp/state-server.d.ts +47 -47
- package/dist/mcp/state-server.d.ts.map +1 -1
- package/dist/mcp/trace-server.d.ts +4 -4
- package/dist/mcp/trace-server.d.ts.map +1 -1
- package/dist/mcp/trace-server.js.map +1 -1
- package/dist/mcp/wiki-server.d.ts +34 -23
- 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-session-scope.test.js +53 -1
- 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.map +1 -1
- package/dist/modes/base.js +5 -5
- package/dist/modes/base.js.map +1 -1
- package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +1 -1
- package/dist/notifications/__tests__/reply-listener.test.js.map +1 -1
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js +177 -85
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js.map +1 -1
- package/dist/notifications/__tests__/session-registry.test.js.map +1 -1
- package/dist/notifications/__tests__/template-engine.test.js.map +1 -1
- package/dist/notifications/__tests__/verbosity.test.js.map +1 -1
- package/dist/notifications/http-client.js.map +1 -1
- package/dist/notifications/index.d.ts +4 -1
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +3 -9
- package/dist/notifications/index.js.map +1 -1
- package/dist/notifications/lifecycle-dedupe.js.map +1 -1
- package/dist/notifications/reply-listener.d.ts.map +1 -1
- package/dist/notifications/reply-listener.js.map +1 -1
- package/dist/notifications/session-registry.js.map +1 -1
- package/dist/notifications/session-status.js.map +1 -1
- 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/notifications/tmux-detector.js.map +1 -1
- package/dist/notifications/tmux.js.map +1 -1
- package/dist/openclaw/config.js.map +1 -1
- package/dist/openclaw/dispatcher.js.map +1 -1
- package/dist/pipeline/__tests__/orchestrator.test.js +4 -4
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +16 -13
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/stages/code-review.js.map +1 -1
- package/dist/pipeline/stages/ralph-verify.js.map +1 -1
- package/dist/pipeline/stages/ralplan.js.map +1 -1
- package/dist/pipeline/stages/team-exec.js.map +1 -1
- package/dist/pipeline/stages/ultragoal.js.map +1 -1
- package/dist/pipeline/stages/ultraqa.js.map +1 -1
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -1
- package/dist/planning/artifact-names.js.map +1 -1
- package/dist/planning/artifacts.js.map +1 -1
- package/dist/question/__tests__/state.test.js.map +1 -1
- package/dist/question/__tests__/ui.test.js.map +1 -1
- package/dist/question/autopilot-wait.js.map +1 -1
- package/dist/question/client.d.ts.map +1 -1
- package/dist/question/client.js.map +1 -1
- package/dist/question/deep-interview.js.map +1 -1
- package/dist/question/events.js.map +1 -1
- package/dist/question/renderer.js.map +1 -1
- package/dist/question/state.d.ts.map +1 -1
- package/dist/question/state.js.map +1 -1
- package/dist/question/ui.js.map +1 -1
- package/dist/ralph/contract.d.ts +1 -1
- package/dist/ralph/contract.d.ts.map +1 -1
- package/dist/ralplan/__tests__/consensus-gate.test.js +527 -8
- 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 +46 -0
- package/dist/ralplan/__tests__/documented-leader-preflight.test.js.map +1 -0
- package/dist/ralplan/__tests__/runtime.test.js +116 -14
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.d.ts +3 -3
- package/dist/ralplan/consensus-gate.d.ts.map +1 -1
- package/dist/ralplan/consensus-gate.js +173 -70
- package/dist/ralplan/consensus-gate.js.map +1 -1
- package/dist/ralplan/documented-leader-preflight.d.ts +34 -0
- package/dist/ralplan/documented-leader-preflight.d.ts.map +1 -0
- package/dist/ralplan/documented-leader-preflight.js +58 -0
- package/dist/ralplan/documented-leader-preflight.js.map +1 -0
- package/dist/ralplan/runtime.d.ts +3 -2
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +12 -9
- 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/process-tree.js.map +1 -1
- package/dist/runtime/run-loop.js.map +1 -1
- package/dist/runtime/run-outcome.d.ts +3 -3
- package/dist/runtime/run-outcome.d.ts.map +1 -1
- package/dist/runtime/run-outcome.js.map +1 -1
- package/dist/runtime/run-state.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +6657 -995
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts +2 -0
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts.map +1 -0
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js +634 -0
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js.map +1 -0
- package/dist/scripts/__tests__/generate-release-body.test.js.map +1 -1
- package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts +2 -0
- package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/notify-fallback-delivery.test.js +174 -0
- package/dist/scripts/__tests__/notify-fallback-delivery.test.js.map +1 -0
- package/dist/scripts/__tests__/notify-state-io.test.js +57 -1
- package/dist/scripts/__tests__/notify-state-io.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.d.ts +2 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js +78 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js.map +1 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts +2 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js +55 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -0
- package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js +1100 -4
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
- package/dist/scripts/__tests__/test-reply-listener-live.test.js.map +1 -1
- package/dist/scripts/build-api.js.map +1 -1
- package/dist/scripts/build-explore-harness.js.map +1 -1
- package/dist/scripts/build-sparkshell.js.map +1 -1
- package/dist/scripts/cleanup-explore-harness.js.map +1 -1
- package/dist/scripts/codex-execution-surface.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts +4 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +11577 -1184
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/generate-native-release-manifest.js.map +1 -1
- package/dist/scripts/generate-release-body.js.map +1 -1
- package/dist/scripts/hook-payload-guard.d.ts.map +1 -1
- package/dist/scripts/hook-payload-guard.js.map +1 -1
- package/dist/scripts/notify-fallback-delivery.d.ts +48 -0
- package/dist/scripts/notify-fallback-delivery.d.ts.map +1 -0
- package/dist/scripts/notify-fallback-delivery.js +419 -0
- package/dist/scripts/notify-fallback-delivery.js.map +1 -0
- package/dist/scripts/notify-fallback-watcher.js +218 -138
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.d.ts +18 -9
- package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.js +112 -15
- package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.d.ts +23 -0
- package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.js +122 -12
- package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
- package/dist/scripts/notify-hook/orchestration-intent.d.ts +7 -7
- package/dist/scripts/notify-hook/orchestration-intent.d.ts.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts +5 -2
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.js +33 -37
- package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
- package/dist/scripts/notify-hook/state-io.d.ts +17 -0
- package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
- package/dist/scripts/notify-hook/state-io.js +73 -11
- package/dist/scripts/notify-hook/state-io.js.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts +10 -1
- 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 +2 -2
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.js +39 -13
- package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts +16 -8
- 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-posttooluse.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.d.ts +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.js +19 -18
- package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker.d.ts +5 -2
- package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker.js +37 -28
- package/dist/scripts/notify-hook/team-worker.js.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts +8 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +53 -18
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook/visual-verdict.d.ts +1 -1
- package/dist/scripts/notify-hook/visual-verdict.d.ts.map +1 -1
- package/dist/scripts/notify-hook/visual-verdict.js +15 -13
- package/dist/scripts/notify-hook/visual-verdict.js.map +1 -1
- package/dist/scripts/notify-hook.d.ts +24 -1
- package/dist/scripts/notify-hook.d.ts.map +1 -1
- package/dist/scripts/notify-hook.js +267 -90
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/scripts/prompt-inventory.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +927 -5
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +4317 -13
- package/dist/scripts/smoke-packed-install.js.map +1 -1
- package/dist/scripts/sync-plugin-mirror.js.map +1 -1
- package/dist/scripts/test-reply-listener-live.js.map +1 -1
- package/dist/scripts/test-sparkshell.js.map +1 -1
- package/dist/scripts/verify-native-agents.js.map +1 -1
- package/dist/session-history/friction.js.map +1 -1
- package/dist/session-history/search.js.map +1 -1
- package/dist/sidecar/__tests__/boundary.test.js.map +1 -1
- package/dist/sidecar/collector.js.map +1 -1
- package/dist/sidecar/index.js.map +1 -1
- package/dist/sidecar/render.js.map +1 -1
- package/dist/sidecar/tmux.js.map +1 -1
- package/dist/state/__tests__/mode-state-context.test.js +54 -0
- package/dist/state/__tests__/mode-state-context.test.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +66 -15
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/skill-active.test.js +19 -1
- package/dist/state/__tests__/skill-active.test.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +61 -0
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/mode-state-context.d.ts +5 -0
- package/dist/state/mode-state-context.d.ts.map +1 -1
- package/dist/state/mode-state-context.js +59 -0
- package/dist/state/mode-state-context.js.map +1 -1
- package/dist/state/operations.d.ts +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +49 -55
- package/dist/state/operations.js.map +1 -1
- package/dist/state/paths.d.ts +1 -1
- package/dist/state/paths.d.ts.map +1 -1
- package/dist/state/paths.js +1 -1
- package/dist/state/paths.js.map +1 -1
- package/dist/state/skill-active.d.ts +13 -1
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +43 -4
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/terminal-normalization.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +20 -4
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.d.ts +1 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts +2 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts.map +1 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js +52 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js.map +1 -0
- package/dist/subagents/__tests__/tracker.test.js +1550 -10
- package/dist/subagents/__tests__/tracker.test.js.map +1 -1
- package/dist/subagents/role-routing-marker.d.ts +10 -0
- package/dist/subagents/role-routing-marker.d.ts.map +1 -0
- package/dist/subagents/role-routing-marker.js +136 -0
- package/dist/subagents/role-routing-marker.js.map +1 -0
- package/dist/subagents/tracker.d.ts +91 -0
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +806 -62
- 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__/approved-execution.test.js.map +1 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.js +52 -10
- 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 +93 -27
- package/dist/team/__tests__/mcp-comm.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +341 -4
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/role-router.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 +3624 -355
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +2516 -118
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- 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 +3664 -969
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.js.map +1 -1
- package/dist/team/__tests__/worker-runtime-identity.test.js +38 -2
- 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 +2 -2
- 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/commit-hygiene.js.map +1 -1
- package/dist/team/contracts.d.ts +5 -5
- package/dist/team/contracts.d.ts.map +1 -1
- package/dist/team/delivery-log.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/followup-planner.js.map +1 -1
- package/dist/team/goal-workflow.js.map +1 -1
- 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 +18 -2
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +314 -35
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/orchestrator.js.map +1 -1
- package/dist/team/pane-status.js.map +1 -1
- package/dist/team/phase-controller.js.map +1 -1
- package/dist/team/reminder-intents.d.ts +1 -1
- package/dist/team/reminder-intents.d.ts.map +1 -1
- package/dist/team/reminder-intents.js.map +1 -1
- package/dist/team/runtime-cli.js.map +1 -1
- package/dist/team/runtime.d.ts +1 -0
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +1326 -231
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts +22 -8
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +1463 -376
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state/dispatch-lock.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/events.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/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-root.js.map +1 -1
- package/dist/team/state.d.ts +67 -1
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +636 -129
- package/dist/team/state.js.map +1 -1
- package/dist/team/team-identity.d.ts.map +1 -1
- package/dist/team/team-identity.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 +125 -23
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +1340 -333
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worker-bootstrap.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.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +4 -1
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/url-reader/index.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 +57 -0
- package/dist/utils/__tests__/file-durability.test.js.map +1 -0
- package/dist/utils/agents-model-table.js.map +1 -1
- package/dist/utils/file-durability.d.ts +15 -0
- package/dist/utils/file-durability.d.ts.map +1 -0
- package/dist/utils/file-durability.js +37 -0
- package/dist/utils/file-durability.js.map +1 -0
- package/dist/utils/package.js.map +1 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/platform-command.js.map +1 -1
- package/dist/utils/repo-deps.js.map +1 -1
- package/dist/utils/version.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +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/verifier.js.map +1 -1
- package/dist/visual/constants.d.ts +1 -1
- package/dist/visual/constants.d.ts.map +1 -1
- package/dist/vscode/__tests__/index.test.js.map +1 -1
- package/dist/vscode/index.js.map +1 -1
- package/dist/wiki/__tests__/cjk-tokenize.test.js.map +1 -1
- package/dist/wiki/__tests__/lint.test.js.map +1 -1
- package/dist/wiki/__tests__/query.test.js.map +1 -1
- package/dist/wiki/__tests__/storage.test.js.map +1 -1
- package/dist/wiki/__tests__/test-helpers.d.ts.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/dist/wiki/query.js.map +1 -1
- package/dist/wiki/storage.js.map +1 -1
- package/package.json +2 -2
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +24 -0
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +10 -5
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +6 -2
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +6 -2
- package/plugins/oh-my-codex/skills/team/SKILL.md +13 -9
- package/skills/omx-setup/SKILL.md +10 -5
- package/skills/ralph/SKILL.md +6 -2
- package/skills/ralplan/SKILL.md +6 -2
- package/skills/team/SKILL.md +13 -9
- package/src/scripts/__tests__/codex-native-hook.test.ts +20048 -10827
- package/src/scripts/__tests__/fixtures/issue-3138-installed-smoke.ts +734 -0
- package/src/scripts/__tests__/notify-fallback-delivery.test.ts +177 -0
- package/src/scripts/__tests__/notify-state-io.test.ts +73 -0
- package/src/scripts/__tests__/reasoning-artifact-contract.test.ts +129 -0
- package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +78 -0
- package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +60 -0
- package/src/scripts/__tests__/smoke-packed-install.test.ts +1309 -4
- package/src/scripts/codex-native-hook.ts +11429 -1163
- package/src/scripts/notify-fallback-delivery.ts +416 -0
- package/src/scripts/notify-fallback-watcher.ts +216 -155
- package/src/scripts/notify-hook/auto-nudge.ts +113 -14
- package/src/scripts/notify-hook/managed-tmux.ts +149 -12
- package/src/scripts/notify-hook/ralph-session-resume.ts +37 -36
- package/src/scripts/notify-hook/state-io.ts +100 -13
- package/src/scripts/notify-hook/team-dispatch.ts +242 -75
- package/src/scripts/notify-hook/team-leader-nudge.ts +40 -18
- package/src/scripts/notify-hook/team-tmux-guard.ts +366 -39
- package/src/scripts/notify-hook/team-worker-stop.ts +20 -16
- package/src/scripts/notify-hook/team-worker.ts +39 -26
- package/src/scripts/notify-hook/tmux-injection.ts +66 -23
- package/src/scripts/notify-hook/visual-verdict.ts +22 -12
- package/src/scripts/notify-hook.ts +336 -90
- package/src/scripts/smoke-packed-install.ts +5154 -149
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,10 @@ 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;
|
|
317
336
|
if (!(typeof v.resize_hook_name === 'string' || v.resize_hook_name === null))
|
|
318
337
|
return false;
|
|
319
338
|
if (!(typeof v.resize_hook_target === 'string' || v.resize_hook_target === null))
|
|
@@ -326,14 +345,54 @@ function isTeamManifestV2(value) {
|
|
|
326
345
|
return false;
|
|
327
346
|
return true;
|
|
328
347
|
}
|
|
329
|
-
// Atomic write: write to {path}.tmp.{pid}, then
|
|
348
|
+
// Atomic write: write to {path}.tmp.{pid}, fsync it, rename, then fsync parent.
|
|
349
|
+
function isUnsupportedParentDirectorySyncError(error) {
|
|
350
|
+
const code = error.code;
|
|
351
|
+
return (code === 'EINVAL'
|
|
352
|
+
|| code === 'ENOTSUP'
|
|
353
|
+
|| code === 'EISDIR'
|
|
354
|
+
|| (code === 'EPERM' && platformForAtomicWrite === 'win32'));
|
|
355
|
+
}
|
|
356
|
+
async function syncParentDirectory(path) {
|
|
357
|
+
let handle;
|
|
358
|
+
try {
|
|
359
|
+
handle = await openForAtomicWrite(dirname(path), 'r');
|
|
360
|
+
}
|
|
361
|
+
catch (error) {
|
|
362
|
+
if (isUnsupportedParentDirectorySyncError(error))
|
|
363
|
+
return;
|
|
364
|
+
throw error;
|
|
365
|
+
}
|
|
366
|
+
try {
|
|
367
|
+
await handle.sync();
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
if (!isUnsupportedParentDirectorySyncError(error))
|
|
371
|
+
throw error;
|
|
372
|
+
}
|
|
373
|
+
finally {
|
|
374
|
+
await handle.close();
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
export async function removeDurableFile(path) {
|
|
378
|
+
await rm(path, { force: true });
|
|
379
|
+
await syncParentDirectory(path);
|
|
380
|
+
}
|
|
330
381
|
export async function writeAtomic(filePath, data) {
|
|
331
382
|
const parent = dirname(filePath);
|
|
332
383
|
await mkdir(parent, { recursive: true });
|
|
333
384
|
const tmpPath = `${filePath}.tmp.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}`;
|
|
334
385
|
await writeFile(tmpPath, data, 'utf8');
|
|
386
|
+
const handle = await openForAtomicWrite(tmpPath, 'r');
|
|
387
|
+
try {
|
|
388
|
+
await handle.sync();
|
|
389
|
+
}
|
|
390
|
+
finally {
|
|
391
|
+
await handle.close();
|
|
392
|
+
}
|
|
335
393
|
try {
|
|
336
394
|
await renameForAtomicWrite(tmpPath, filePath);
|
|
395
|
+
await syncParentDirectory(filePath);
|
|
337
396
|
}
|
|
338
397
|
catch (error) {
|
|
339
398
|
const err = error;
|
|
@@ -350,6 +409,205 @@ export async function writeAtomic(filePath, data) {
|
|
|
350
409
|
throw error;
|
|
351
410
|
}
|
|
352
411
|
}
|
|
412
|
+
function membershipTransactionPath(teamName, cwd) {
|
|
413
|
+
return join(teamDir(teamName, cwd), '.membership-task-transaction.json');
|
|
414
|
+
}
|
|
415
|
+
async function applyMembershipTransactionFiles(files, useNewBytes) {
|
|
416
|
+
for (const file of files) {
|
|
417
|
+
const bytes = useNewBytes ? file.newBytes : file.oldBytes;
|
|
418
|
+
if (bytes === null)
|
|
419
|
+
await removeDurableFile(file.path);
|
|
420
|
+
else
|
|
421
|
+
await writeAtomic(file.path, bytes);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
async function validateMembershipTransactionFiles(teamName, cwd, files) {
|
|
425
|
+
const expectedConfigPath = resolve(teamConfigPath(teamName, cwd));
|
|
426
|
+
const expectedManifestPath = resolve(teamManifestV2Path(teamName, cwd));
|
|
427
|
+
const expectedTasksDir = resolve(teamDir(teamName, cwd), 'tasks');
|
|
428
|
+
const seenPaths = new Set();
|
|
429
|
+
let configCount = 0;
|
|
430
|
+
const canonicalStateRoot = await realpath(resolveTeamStateRoot(cwd));
|
|
431
|
+
const canonicalTeamRoot = await realpath(teamDir(teamName, cwd));
|
|
432
|
+
if (canonicalTeamRoot !== canonicalStateRoot && !canonicalTeamRoot.startsWith(`${canonicalStateRoot}${sep}`)) {
|
|
433
|
+
throw new Error(`Membership transaction team root escapes canonical state root for ${teamName}`);
|
|
434
|
+
}
|
|
435
|
+
const canonicalTasksDir = await realpath(resolve(teamDir(teamName, cwd), 'tasks'));
|
|
436
|
+
if (!canonicalTasksDir.startsWith(`${canonicalTeamRoot}${sep}`)) {
|
|
437
|
+
throw new Error(`Membership transaction tasks root escapes canonical team root for ${teamName}`);
|
|
438
|
+
}
|
|
439
|
+
for (const file of files) {
|
|
440
|
+
if (!file || typeof file.path !== 'string'
|
|
441
|
+
|| (file.oldBytes !== null && typeof file.oldBytes !== 'string')
|
|
442
|
+
|| (file.newBytes !== null && typeof file.newBytes !== 'string')) {
|
|
443
|
+
throw new Error(`Invalid membership transaction file entry for ${teamName}`);
|
|
444
|
+
}
|
|
445
|
+
const resolvedPath = resolve(file.path);
|
|
446
|
+
if (resolvedPath !== file.path || seenPaths.has(resolvedPath)) {
|
|
447
|
+
throw new Error(`Invalid membership transaction path for ${teamName}`);
|
|
448
|
+
}
|
|
449
|
+
seenPaths.add(resolvedPath);
|
|
450
|
+
let expectedParent;
|
|
451
|
+
if (resolvedPath === expectedConfigPath) {
|
|
452
|
+
configCount += 1;
|
|
453
|
+
expectedParent = canonicalTeamRoot;
|
|
454
|
+
}
|
|
455
|
+
else if (resolvedPath === expectedManifestPath) {
|
|
456
|
+
expectedParent = canonicalTeamRoot;
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
if (dirname(resolvedPath) !== expectedTasksDir) {
|
|
460
|
+
throw new Error(`Membership transaction path escapes expected team files for ${teamName}`);
|
|
461
|
+
}
|
|
462
|
+
const match = basename(resolvedPath).match(/^task-([A-Za-z0-9_-]+)\.json$/);
|
|
463
|
+
if (!match || resolve(taskFilePath(teamName, match[1], cwd)) !== resolvedPath) {
|
|
464
|
+
throw new Error(`Invalid membership transaction task path for ${teamName}`);
|
|
465
|
+
}
|
|
466
|
+
expectedParent = canonicalTasksDir;
|
|
467
|
+
}
|
|
468
|
+
const canonicalParent = await realpath(dirname(resolvedPath));
|
|
469
|
+
if (canonicalParent !== expectedParent) {
|
|
470
|
+
throw new Error(`Membership transaction path traverses a symlink for ${teamName}`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
if (configCount !== 1) {
|
|
474
|
+
throw new Error(`Membership transaction must contain exactly one config path for ${teamName}`);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Resolve an interrupted membership/task commit before a reader or writer observes
|
|
479
|
+
* its files. Prepared transactions roll back; committed transactions roll forward.
|
|
480
|
+
*/
|
|
481
|
+
export async function recoverTeamMembershipTaskTransaction(teamName, cwd, options = {}) {
|
|
482
|
+
const journalPath = membershipTransactionPath(teamName, cwd);
|
|
483
|
+
let journal;
|
|
484
|
+
try {
|
|
485
|
+
journal = JSON.parse(await readFile(journalPath, 'utf8'));
|
|
486
|
+
}
|
|
487
|
+
catch (error) {
|
|
488
|
+
if (error.code === 'ENOENT')
|
|
489
|
+
return;
|
|
490
|
+
throw error;
|
|
491
|
+
}
|
|
492
|
+
if (journal.schemaVersion !== 1 || (journal.phase !== 'prepared' && journal.phase !== 'committed') || !Array.isArray(journal.files)) {
|
|
493
|
+
throw new Error(`Invalid membership transaction journal for ${teamName}`);
|
|
494
|
+
}
|
|
495
|
+
await validateMembershipTransactionFiles(teamName, cwd, journal.files);
|
|
496
|
+
await applyMembershipTransactionFiles(journal.files, journal.phase === 'committed');
|
|
497
|
+
if (!options.retainJournal)
|
|
498
|
+
await removeDurableFile(journalPath);
|
|
499
|
+
}
|
|
500
|
+
/** Finalize a previously committed membership transaction after caller verification. */
|
|
501
|
+
export async function finalizeTeamMembershipTaskTransaction(teamName, cwd) {
|
|
502
|
+
const journalPath = membershipTransactionPath(teamName, cwd);
|
|
503
|
+
const journal = JSON.parse(await readFile(journalPath, 'utf8'));
|
|
504
|
+
if (journal.schemaVersion !== 1 || journal.phase !== 'committed' || !Array.isArray(journal.files)) {
|
|
505
|
+
throw new Error(`Cannot finalize non-committed membership transaction for ${teamName}`);
|
|
506
|
+
}
|
|
507
|
+
await validateMembershipTransactionFiles(teamName, cwd, journal.files);
|
|
508
|
+
await removeDurableFile(journalPath);
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Persist config/manifest and task membership changes as an old-or-new journaled
|
|
512
|
+
* generation. Callers must hold the team membership barrier for the whole call.
|
|
513
|
+
*/
|
|
514
|
+
export async function commitTeamMembershipTaskTransaction(teamName, cwd, transaction) {
|
|
515
|
+
if (!taskMembershipBarrierContext.getStore()?.has(taskMembershipBarrierKey(teamName, cwd))) {
|
|
516
|
+
throw new Error(`membership_transaction_barrier_required:${teamName}`);
|
|
517
|
+
}
|
|
518
|
+
const currentGeneration = await readConfigGenerationRaw(teamName, cwd);
|
|
519
|
+
if (currentGeneration === null)
|
|
520
|
+
throw new Error(`team_config_missing:${teamName}`);
|
|
521
|
+
if (transaction.baseGeneration !== currentGeneration) {
|
|
522
|
+
throw new Error(`team_membership_stale_generation:${teamName}:${transaction.baseGeneration}:${currentGeneration}`);
|
|
523
|
+
}
|
|
524
|
+
const acceptedGeneration = currentGeneration + 1;
|
|
525
|
+
const nextConfig = JSON.parse(transaction.config.newBytes);
|
|
526
|
+
nextConfig.config_generation = acceptedGeneration;
|
|
527
|
+
const nextManifest = transaction.manifest?.newBytes === null
|
|
528
|
+
? null
|
|
529
|
+
: transaction.manifest
|
|
530
|
+
? { ...JSON.parse(transaction.manifest.newBytes), config_generation: acceptedGeneration }
|
|
531
|
+
: undefined;
|
|
532
|
+
const files = [
|
|
533
|
+
...transaction.tasks.map((task) => ({
|
|
534
|
+
path: taskFilePath(teamName, task.taskId, cwd),
|
|
535
|
+
oldBytes: task.oldBytes,
|
|
536
|
+
newBytes: task.newBytes,
|
|
537
|
+
})),
|
|
538
|
+
{
|
|
539
|
+
path: teamConfigPath(teamName, cwd),
|
|
540
|
+
oldBytes: transaction.config.oldBytes,
|
|
541
|
+
newBytes: JSON.stringify(nextConfig, null, 2),
|
|
542
|
+
},
|
|
543
|
+
];
|
|
544
|
+
if (transaction.manifest) {
|
|
545
|
+
files.push({
|
|
546
|
+
path: teamManifestV2Path(teamName, cwd),
|
|
547
|
+
oldBytes: transaction.manifest.oldBytes,
|
|
548
|
+
newBytes: nextManifest === null ? null : JSON.stringify(nextManifest, null, 2),
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
const journalPath = membershipTransactionPath(teamName, cwd);
|
|
552
|
+
const journal = {
|
|
553
|
+
schemaVersion: 1,
|
|
554
|
+
// Membership rollback is itself a durable desired-state transition: an
|
|
555
|
+
// interruption must finish restoring the original membership, not revive
|
|
556
|
+
// the transient scaled-up generation.
|
|
557
|
+
phase: transaction.recoverToNewOnFailure ? 'committed' : 'prepared',
|
|
558
|
+
files,
|
|
559
|
+
};
|
|
560
|
+
await writeAtomic(journalPath, JSON.stringify(journal, null, 2));
|
|
561
|
+
try {
|
|
562
|
+
if (transaction.interruptAfterFirstTaskWrite && transaction.tasks.length > 0) {
|
|
563
|
+
await applyMembershipTransactionFiles(files.slice(0, 1), true);
|
|
564
|
+
throw new Error('injected_scale_down_interruption:after-first-task-write');
|
|
565
|
+
}
|
|
566
|
+
await applyMembershipTransactionFiles(files, true);
|
|
567
|
+
if (transaction.failRollbackPersistence || transaction.failRollbackPersistenceAfter) {
|
|
568
|
+
// Exercise the restore path after a complete new generation is visible.
|
|
569
|
+
// The catch below intentionally writes OLD bytes then leaves the durable
|
|
570
|
+
// journal in place so public entry recovery owns convergence.
|
|
571
|
+
throw new Error('injected_scale_down_failure:rollback-persistence-failure');
|
|
572
|
+
}
|
|
573
|
+
journal.phase = 'committed';
|
|
574
|
+
await writeAtomic(journalPath, JSON.stringify(journal, null, 2));
|
|
575
|
+
if (!transaction.retainJournalOnSuccess)
|
|
576
|
+
await removeDurableFile(journalPath);
|
|
577
|
+
}
|
|
578
|
+
catch (error) {
|
|
579
|
+
if (error instanceof Error && error.message === 'injected_scale_down_interruption:after-first-task-write')
|
|
580
|
+
throw error;
|
|
581
|
+
if (transaction.failRollbackPersistence || transaction.failRollbackPersistenceAfter) {
|
|
582
|
+
const target = transaction.failRollbackPersistenceAfter;
|
|
583
|
+
const targetIndex = target ? files.findIndex((file) => file.path === (target === 'config'
|
|
584
|
+
? teamConfigPath(teamName, cwd)
|
|
585
|
+
: teamManifestV2Path(teamName, cwd))) : 0;
|
|
586
|
+
const partial = files.slice(0, Math.max(1, targetIndex + 1));
|
|
587
|
+
await applyMembershipTransactionFiles(partial, false);
|
|
588
|
+
throw error;
|
|
589
|
+
}
|
|
590
|
+
if (transaction.recoverToNewOnFailure) {
|
|
591
|
+
try {
|
|
592
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
593
|
+
}
|
|
594
|
+
catch {
|
|
595
|
+
// Keep the committed-direction journal as durable recovery authority.
|
|
596
|
+
}
|
|
597
|
+
throw error;
|
|
598
|
+
}
|
|
599
|
+
// Leave the prepared marker durable if restoring old bytes also fails. Entry
|
|
600
|
+
// recovery will retry until the state has converged to the old generation.
|
|
601
|
+
try {
|
|
602
|
+
await applyMembershipTransactionFiles(files, false);
|
|
603
|
+
await removeDurableFile(journalPath);
|
|
604
|
+
}
|
|
605
|
+
catch {
|
|
606
|
+
// The prepared journal is the durable recovery authority.
|
|
607
|
+
}
|
|
608
|
+
throw error;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
353
611
|
// Initialize team state directory + config.json
|
|
354
612
|
// Creates: .omx/state/team/{name}/, workers/{worker-1}..{worker-N}/, tasks/
|
|
355
613
|
// Throws if workerCount > maxWorkers (default 20)
|
|
@@ -401,12 +659,16 @@ export async function initTeamState(teamName, task, agentType, workerCount, cwd,
|
|
|
401
659
|
workers,
|
|
402
660
|
created_at: new Date().toISOString(),
|
|
403
661
|
tmux_session: `omx-team-${teamName}`,
|
|
662
|
+
tmux_session_id: undefined,
|
|
663
|
+
tmux_session_created: undefined,
|
|
404
664
|
next_task_id: 1,
|
|
405
665
|
leader_cwd: workspace.leader_cwd,
|
|
406
666
|
team_state_root: workspace.team_state_root,
|
|
407
667
|
workspace_mode: workspace.workspace_mode,
|
|
408
668
|
worktree_mode: workspace.worktree_mode,
|
|
409
669
|
leader_pane_id: null,
|
|
670
|
+
leader_pane_pid: null,
|
|
671
|
+
hud_pane_pid: null,
|
|
410
672
|
hud_pane_id: null,
|
|
411
673
|
tmux_pane_owner_id: tmuxPaneOwnerId,
|
|
412
674
|
resize_hook_name: null,
|
|
@@ -415,8 +677,11 @@ export async function initTeamState(teamName, task, agentType, workerCount, cwd,
|
|
|
415
677
|
display_name: workspace.display_name,
|
|
416
678
|
requested_name: workspace.requested_name,
|
|
417
679
|
identity_source: workspace.identity_source,
|
|
680
|
+
config_generation: 0,
|
|
418
681
|
};
|
|
419
|
-
await
|
|
682
|
+
await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
683
|
+
await writeAtomic(join(root, 'config.json'), JSON.stringify(config, null, 2));
|
|
684
|
+
});
|
|
420
685
|
await writeTeamPhase(teamName, {
|
|
421
686
|
current_phase: 'team-exec',
|
|
422
687
|
max_fix_attempts: 3,
|
|
@@ -438,6 +703,8 @@ export async function initTeamState(teamName, task, agentType, workerCount, cwd,
|
|
|
438
703
|
lifecycle_profile: lifecycleProfile,
|
|
439
704
|
permissions_snapshot: permissionsSnapshot,
|
|
440
705
|
tmux_session: config.tmux_session,
|
|
706
|
+
tmux_session_id: config.tmux_session_id,
|
|
707
|
+
tmux_session_created: config.tmux_session_created,
|
|
441
708
|
worker_count: workerCount,
|
|
442
709
|
workers,
|
|
443
710
|
next_task_id: 1,
|
|
@@ -447,6 +714,8 @@ export async function initTeamState(teamName, task, agentType, workerCount, cwd,
|
|
|
447
714
|
workspace_mode: workspace.workspace_mode,
|
|
448
715
|
worktree_mode: workspace.worktree_mode,
|
|
449
716
|
leader_pane_id: null,
|
|
717
|
+
leader_pane_pid: null,
|
|
718
|
+
hud_pane_pid: null,
|
|
450
719
|
hud_pane_id: null,
|
|
451
720
|
tmux_pane_owner_id: tmuxPaneOwnerId,
|
|
452
721
|
resize_hook_name: null,
|
|
@@ -460,34 +729,63 @@ export async function initTeamState(teamName, task, agentType, workerCount, cwd,
|
|
|
460
729
|
}
|
|
461
730
|
async function writeConfig(cfg, cwd) {
|
|
462
731
|
const normalized = normalizeTeamConfig(cfg);
|
|
463
|
-
const
|
|
464
|
-
await
|
|
732
|
+
const configPath = teamConfigPath(normalized.name, cwd);
|
|
733
|
+
const oldConfigBytes = await readFile(configPath, 'utf8');
|
|
465
734
|
// 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
|
-
|
|
735
|
+
const existing = await readTeamManifestV2Raw(normalized.name, cwd);
|
|
736
|
+
if (!existing) {
|
|
737
|
+
await writeAtomic(configPath, JSON.stringify(normalized, null, 2));
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
const merged = {
|
|
741
|
+
...existing,
|
|
742
|
+
task: normalized.task,
|
|
743
|
+
tmux_session: normalized.tmux_session,
|
|
744
|
+
tmux_session_id: normalized.tmux_session_id,
|
|
745
|
+
tmux_session_created: normalized.tmux_session_created,
|
|
746
|
+
worker_count: normalized.worker_count,
|
|
747
|
+
workers: normalized.workers,
|
|
748
|
+
lifecycle_profile: normalized.lifecycle_profile,
|
|
749
|
+
next_task_id: normalizeNextTaskId(normalized.next_task_id),
|
|
750
|
+
leader_cwd: normalized.leader_cwd,
|
|
751
|
+
team_state_root: normalized.team_state_root,
|
|
752
|
+
workspace_mode: normalized.workspace_mode,
|
|
753
|
+
worktree_mode: normalized.worktree_mode,
|
|
754
|
+
leader_pane_id: normalized.leader_pane_id,
|
|
755
|
+
leader_pane_pid: normalized.leader_pane_pid,
|
|
756
|
+
hud_pane_pid: normalized.hud_pane_pid,
|
|
757
|
+
hud_pane_id: normalized.hud_pane_id,
|
|
758
|
+
tmux_pane_owner_id: normalized.tmux_pane_owner_id,
|
|
759
|
+
resize_hook_name: normalized.resize_hook_name,
|
|
760
|
+
resize_hook_target: normalized.resize_hook_target,
|
|
761
|
+
next_worker_index: normalized.next_worker_index ?? existing.next_worker_index,
|
|
762
|
+
display_name: normalized.display_name ?? existing.display_name,
|
|
763
|
+
requested_name: normalized.requested_name ?? existing.requested_name,
|
|
764
|
+
identity_source: normalized.identity_source ?? existing.identity_source,
|
|
765
|
+
config_generation: normalized.config_generation,
|
|
766
|
+
};
|
|
767
|
+
const manifestPath = teamManifestV2Path(normalized.name, cwd);
|
|
768
|
+
const files = [
|
|
769
|
+
{ path: configPath, oldBytes: oldConfigBytes, newBytes: JSON.stringify(normalized, null, 2) },
|
|
770
|
+
{ path: manifestPath, oldBytes: await readFile(manifestPath, 'utf8'), newBytes: JSON.stringify(merged, null, 2) },
|
|
771
|
+
];
|
|
772
|
+
const journalPath = membershipTransactionPath(normalized.name, cwd);
|
|
773
|
+
const journal = { schemaVersion: 1, phase: 'prepared', files };
|
|
774
|
+
await writeAtomic(journalPath, JSON.stringify(journal, null, 2));
|
|
775
|
+
try {
|
|
776
|
+
await applyMembershipTransactionFiles(files, true);
|
|
777
|
+
journal.phase = 'committed';
|
|
778
|
+
await writeAtomic(journalPath, JSON.stringify(journal, null, 2));
|
|
779
|
+
await removeDurableFile(journalPath);
|
|
780
|
+
}
|
|
781
|
+
catch (error) {
|
|
782
|
+
try {
|
|
783
|
+
await recoverTeamMembershipTaskTransaction(normalized.name, cwd);
|
|
784
|
+
}
|
|
785
|
+
catch {
|
|
786
|
+
// The prepared journal is the durable recovery authority.
|
|
787
|
+
}
|
|
788
|
+
throw error;
|
|
491
789
|
}
|
|
492
790
|
}
|
|
493
791
|
function teamConfigFromManifest(manifest) {
|
|
@@ -507,14 +805,20 @@ function teamConfigFromManifest(manifest) {
|
|
|
507
805
|
workers: manifest.workers,
|
|
508
806
|
created_at: manifest.created_at,
|
|
509
807
|
tmux_session: manifest.tmux_session,
|
|
808
|
+
tmux_session_id: manifest.tmux_session_id,
|
|
809
|
+
tmux_session_created: manifest.tmux_session_created,
|
|
510
810
|
next_task_id: manifest.next_task_id,
|
|
511
811
|
leader_cwd: manifest.leader_cwd,
|
|
512
812
|
team_state_root: manifest.team_state_root,
|
|
513
813
|
workspace_mode: manifest.workspace_mode,
|
|
514
814
|
worktree_mode: manifest.worktree_mode,
|
|
515
815
|
leader_pane_id: manifest.leader_pane_id,
|
|
816
|
+
leader_pane_pid: manifest.leader_pane_pid ?? null,
|
|
817
|
+
hud_pane_pid: manifest.hud_pane_pid ?? null,
|
|
516
818
|
hud_pane_id: manifest.hud_pane_id,
|
|
517
|
-
tmux_pane_owner_id: manifest.tmux_pane_owner_id
|
|
819
|
+
tmux_pane_owner_id: typeof manifest.tmux_pane_owner_id === 'string' && manifest.tmux_pane_owner_id.trim() !== ''
|
|
820
|
+
? manifest.tmux_pane_owner_id.trim()
|
|
821
|
+
: undefined,
|
|
518
822
|
resize_hook_name: manifest.resize_hook_name,
|
|
519
823
|
resize_hook_target: manifest.resize_hook_target,
|
|
520
824
|
next_worker_index: manifest.next_worker_index,
|
|
@@ -525,14 +829,25 @@ function teamConfigFromManifest(manifest) {
|
|
|
525
829
|
}
|
|
526
830
|
function normalizeTeamConfig(config) {
|
|
527
831
|
const workerLaunchMode = config.worker_launch_mode === 'prompt' ? 'prompt' : 'interactive';
|
|
832
|
+
const configGeneration = typeof config.config_generation === 'number'
|
|
833
|
+
&& Number.isSafeInteger(config.config_generation) && config.config_generation >= 0
|
|
834
|
+
? config.config_generation
|
|
835
|
+
: 0;
|
|
528
836
|
return {
|
|
529
837
|
...config,
|
|
838
|
+
config_generation: configGeneration,
|
|
530
839
|
lifecycle_profile: 'default',
|
|
531
840
|
leader_pane_id: config.leader_pane_id ?? null,
|
|
841
|
+
leader_pane_pid: typeof config.leader_pane_pid === 'number' && Number.isSafeInteger(config.leader_pane_pid) && config.leader_pane_pid > 0
|
|
842
|
+
? config.leader_pane_pid
|
|
843
|
+
: null,
|
|
844
|
+
hud_pane_pid: typeof config.hud_pane_pid === 'number' && Number.isSafeInteger(config.hud_pane_pid) && config.hud_pane_pid > 0
|
|
845
|
+
? config.hud_pane_pid
|
|
846
|
+
: null,
|
|
532
847
|
hud_pane_id: config.hud_pane_id ?? null,
|
|
533
848
|
tmux_pane_owner_id: typeof config.tmux_pane_owner_id === 'string' && config.tmux_pane_owner_id.trim() !== ''
|
|
534
849
|
? config.tmux_pane_owner_id.trim()
|
|
535
|
-
:
|
|
850
|
+
: undefined,
|
|
536
851
|
resize_hook_name: config.resize_hook_name ?? null,
|
|
537
852
|
resize_hook_target: config.resize_hook_target ?? null,
|
|
538
853
|
worker_launch_mode: workerLaunchMode,
|
|
@@ -556,6 +871,8 @@ function teamManifestFromConfig(config) {
|
|
|
556
871
|
lifecycle_profile: normalized.lifecycle_profile,
|
|
557
872
|
permissions_snapshot: defaultPermissionsSnapshot(),
|
|
558
873
|
tmux_session: normalized.tmux_session,
|
|
874
|
+
tmux_session_id: normalized.tmux_session_id,
|
|
875
|
+
tmux_session_created: normalized.tmux_session_created,
|
|
559
876
|
worker_count: normalized.worker_count,
|
|
560
877
|
workers: normalized.workers,
|
|
561
878
|
next_task_id: normalizeNextTaskId(normalized.next_task_id),
|
|
@@ -565,6 +882,8 @@ function teamManifestFromConfig(config) {
|
|
|
565
882
|
workspace_mode: normalized.workspace_mode,
|
|
566
883
|
worktree_mode: normalized.worktree_mode,
|
|
567
884
|
leader_pane_id: normalized.leader_pane_id,
|
|
885
|
+
leader_pane_pid: normalized.leader_pane_pid,
|
|
886
|
+
hud_pane_pid: normalized.hud_pane_pid,
|
|
568
887
|
hud_pane_id: normalized.hud_pane_id,
|
|
569
888
|
tmux_pane_owner_id: normalized.tmux_pane_owner_id,
|
|
570
889
|
resize_hook_name: normalized.resize_hook_name,
|
|
@@ -573,27 +892,30 @@ function teamManifestFromConfig(config) {
|
|
|
573
892
|
display_name: normalized.display_name,
|
|
574
893
|
requested_name: normalized.requested_name,
|
|
575
894
|
identity_source: normalized.identity_source,
|
|
895
|
+
config_generation: normalized.config_generation,
|
|
576
896
|
};
|
|
577
897
|
}
|
|
578
898
|
export async function writeTeamManifestV2(manifest, cwd) {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
899
|
+
await withTeamTaskBarrier(manifest.name, cwd, async () => {
|
|
900
|
+
const normalizedPolicy = normalizeTeamPolicy(manifest.policy, {
|
|
901
|
+
display_mode: manifest.policy?.display_mode === 'split_pane' ? 'split_pane' : 'auto',
|
|
902
|
+
worker_launch_mode: manifest.policy?.worker_launch_mode === 'prompt' ? 'prompt' : 'interactive',
|
|
903
|
+
});
|
|
904
|
+
const normalizedGovernance = normalizeTeamGovernance(manifest.governance, manifest.policy);
|
|
905
|
+
const tmuxPaneOwnerId = typeof manifest.tmux_pane_owner_id === 'string' && manifest.tmux_pane_owner_id.trim() !== ''
|
|
906
|
+
? manifest.tmux_pane_owner_id.trim()
|
|
907
|
+
: undefined;
|
|
908
|
+
const p = teamManifestV2Path(manifest.name, cwd);
|
|
909
|
+
await writeAtomic(p, JSON.stringify({
|
|
910
|
+
...manifest,
|
|
911
|
+
tmux_pane_owner_id: tmuxPaneOwnerId,
|
|
912
|
+
policy: normalizedPolicy,
|
|
913
|
+
governance: normalizedGovernance,
|
|
914
|
+
lifecycle_profile: 'default',
|
|
915
|
+
}, null, 2));
|
|
582
916
|
});
|
|
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
917
|
}
|
|
596
|
-
|
|
918
|
+
async function readTeamManifestV2Raw(teamName, cwd) {
|
|
597
919
|
try {
|
|
598
920
|
const p = teamManifestV2Path(teamName, cwd);
|
|
599
921
|
if (!existsSync(p))
|
|
@@ -607,7 +929,7 @@ export async function readTeamManifestV2(teamName, cwd) {
|
|
|
607
929
|
const legacyTeamDecomposition = legacyPolicy?.team_decomposition;
|
|
608
930
|
const tmuxPaneOwnerId = typeof parsedManifest.tmux_pane_owner_id === 'string' && parsedManifest.tmux_pane_owner_id.trim() !== ''
|
|
609
931
|
? parsedManifest.tmux_pane_owner_id.trim()
|
|
610
|
-
:
|
|
932
|
+
: undefined;
|
|
611
933
|
return {
|
|
612
934
|
...parsedManifest,
|
|
613
935
|
tmux_pane_owner_id: tmuxPaneOwnerId,
|
|
@@ -627,6 +949,12 @@ export async function readTeamManifestV2(teamName, cwd) {
|
|
|
627
949
|
return null;
|
|
628
950
|
}
|
|
629
951
|
}
|
|
952
|
+
export async function readTeamManifestV2(teamName, cwd) {
|
|
953
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
954
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
955
|
+
return await readTeamManifestV2Raw(teamName, cwd);
|
|
956
|
+
});
|
|
957
|
+
}
|
|
630
958
|
// Idempotent migration; keeps config.json untouched.
|
|
631
959
|
export async function migrateV1ToV2(teamName, cwd) {
|
|
632
960
|
const existing = await readTeamManifestV2(teamName, cwd);
|
|
@@ -683,11 +1011,23 @@ async function computeNextTaskIdFromDisk(teamName, cwd) {
|
|
|
683
1011
|
}
|
|
684
1012
|
return maxId + 1;
|
|
685
1013
|
}
|
|
1014
|
+
async function readConfigGenerationRaw(teamName, cwd) {
|
|
1015
|
+
try {
|
|
1016
|
+
const raw = JSON.parse(await readFile(teamConfigPath(teamName, cwd), 'utf8'));
|
|
1017
|
+
return typeof raw.config_generation === 'number'
|
|
1018
|
+
&& Number.isSafeInteger(raw.config_generation) && raw.config_generation >= 0
|
|
1019
|
+
? raw.config_generation
|
|
1020
|
+
: 0;
|
|
1021
|
+
}
|
|
1022
|
+
catch {
|
|
1023
|
+
return null;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
686
1026
|
// Read team config
|
|
687
|
-
|
|
688
|
-
const v2 = await
|
|
1027
|
+
async function readTeamConfigRaw(teamName, cwd) {
|
|
1028
|
+
const v2 = await readTeamManifestV2Raw(teamName, cwd);
|
|
689
1029
|
if (v2)
|
|
690
|
-
return teamConfigFromManifest(v2);
|
|
1030
|
+
return { ...teamConfigFromManifest(v2), config_generation: (await readConfigGenerationRaw(teamName, cwd)) ?? 0 };
|
|
691
1031
|
// Attempt idempotent migration on first read.
|
|
692
1032
|
const migrated = await migrateV1ToV2(teamName, cwd);
|
|
693
1033
|
if (migrated)
|
|
@@ -706,6 +1046,12 @@ export async function readTeamConfig(teamName, cwd) {
|
|
|
706
1046
|
return null;
|
|
707
1047
|
}
|
|
708
1048
|
}
|
|
1049
|
+
export async function readTeamConfig(teamName, cwd) {
|
|
1050
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1051
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1052
|
+
return await readTeamConfigRaw(teamName, cwd);
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
709
1055
|
// Write worker identity file
|
|
710
1056
|
export async function writeWorkerIdentity(teamName, workerName, identity, cwd) {
|
|
711
1057
|
const p = join(workerDir(teamName, workerName, cwd), 'identity.json');
|
|
@@ -753,7 +1099,8 @@ export async function writeWorkerStatus(teamName, workerName, status, cwd) {
|
|
|
753
1099
|
const p = join(workerDir(teamName, workerName, cwd), 'status.json');
|
|
754
1100
|
await writeAtomic(p, JSON.stringify(status, null, 2));
|
|
755
1101
|
}
|
|
756
|
-
// File-based scaling lock
|
|
1102
|
+
// File-based scaling lock kept outside the deletable team root. Operations that
|
|
1103
|
+
// also mutate membership acquire this lock before the membership barrier.
|
|
757
1104
|
export async function withScalingLock(teamName, cwd, fn) {
|
|
758
1105
|
return await withScalingLockImpl(teamName, cwd, LOCK_STALE_MS, { teamDir, taskClaimLockDir, mailboxLockDir }, fn);
|
|
759
1106
|
}
|
|
@@ -768,9 +1115,28 @@ function taskFilePath(teamName, taskId, cwd) {
|
|
|
768
1115
|
assertPathWithinDir(p, resolveTeamStateRoot(cwd));
|
|
769
1116
|
return p;
|
|
770
1117
|
}
|
|
1118
|
+
const taskMembershipBarrierContext = new AsyncLocalStorage();
|
|
1119
|
+
function taskMembershipBarrierKey(teamName, cwd) {
|
|
1120
|
+
return `${resolve(cwd)}\0${teamName}`;
|
|
1121
|
+
}
|
|
771
1122
|
async function withTeamLock(teamName, cwd, fn) {
|
|
772
1123
|
return await withTeamLockImpl(teamName, cwd, LOCK_STALE_MS, { teamDir, taskClaimLockDir, mailboxLockDir }, fn);
|
|
773
1124
|
}
|
|
1125
|
+
/**
|
|
1126
|
+
* Serializes membership snapshots with task creation and claims. The global
|
|
1127
|
+
* lock order is scaling, membership, then task claim locks. Operations that do
|
|
1128
|
+
* not scale acquire only this barrier (and then any task claim lock).
|
|
1129
|
+
*/
|
|
1130
|
+
export async function withTeamTaskBarrier(teamName, cwd, fn) {
|
|
1131
|
+
const key = taskMembershipBarrierKey(teamName, cwd);
|
|
1132
|
+
if (taskMembershipBarrierContext.getStore()?.has(key))
|
|
1133
|
+
return await fn();
|
|
1134
|
+
return await withTeamLock(teamName, cwd, async () => {
|
|
1135
|
+
const held = new Set(taskMembershipBarrierContext.getStore() ?? []);
|
|
1136
|
+
held.add(key);
|
|
1137
|
+
return await taskMembershipBarrierContext.run(held, fn);
|
|
1138
|
+
});
|
|
1139
|
+
}
|
|
774
1140
|
async function withTaskClaimLock(teamName, taskId, cwd, fn) {
|
|
775
1141
|
return await withTaskClaimLockImpl(teamName, taskId, cwd, LOCK_STALE_MS, { teamDir, taskClaimLockDir, mailboxLockDir }, fn);
|
|
776
1142
|
}
|
|
@@ -779,7 +1145,8 @@ async function withMailboxLock(teamName, workerName, cwd, fn) {
|
|
|
779
1145
|
}
|
|
780
1146
|
// Create a task (auto-increment ID)
|
|
781
1147
|
export async function createTask(teamName, task, cwd) {
|
|
782
|
-
return
|
|
1148
|
+
return withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1149
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
783
1150
|
const cfg = await readTeamConfig(teamName, cwd);
|
|
784
1151
|
if (!cfg)
|
|
785
1152
|
throw new Error(`Team ${teamName} not found`);
|
|
@@ -808,7 +1175,7 @@ export async function createTask(teamName, task, cwd) {
|
|
|
808
1175
|
});
|
|
809
1176
|
}
|
|
810
1177
|
// Read a task (returns null on missing/malformed)
|
|
811
|
-
|
|
1178
|
+
async function readTaskRaw(teamName, taskId, cwd) {
|
|
812
1179
|
try {
|
|
813
1180
|
const p = taskFilePath(teamName, taskId, cwd);
|
|
814
1181
|
if (!existsSync(p))
|
|
@@ -821,98 +1188,121 @@ export async function readTask(teamName, taskId, cwd) {
|
|
|
821
1188
|
return null;
|
|
822
1189
|
}
|
|
823
1190
|
}
|
|
1191
|
+
export async function readTask(teamName, taskId, cwd) {
|
|
1192
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1193
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1194
|
+
return await readTaskRaw(teamName, taskId, cwd);
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
824
1197
|
// Update a task (merge updates, atomic write)
|
|
825
1198
|
export async function updateTask(teamName, taskId, updates, cwd) {
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
1199
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1200
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1201
|
+
const lock = await withTaskClaimLock(teamName, taskId, cwd, async () => {
|
|
1202
|
+
const existing = await readTaskRaw(teamName, taskId, cwd);
|
|
1203
|
+
if (!existing)
|
|
1204
|
+
return null;
|
|
1205
|
+
if (updates.status !== undefined && !['pending', 'blocked', 'in_progress', 'completed', 'failed'].includes(updates.status)) {
|
|
1206
|
+
throw new Error(`Invalid task status: ${updates.status}`);
|
|
1207
|
+
}
|
|
1208
|
+
const rawDeps = updates.depends_on ?? updates.blocked_by ?? existing.depends_on ?? existing.blocked_by ?? [];
|
|
1209
|
+
const normalizedDeps = Array.isArray(rawDeps) ? rawDeps : [];
|
|
1210
|
+
const merged = normalizeTask({
|
|
1211
|
+
...normalizeTask(existing),
|
|
1212
|
+
...updates,
|
|
1213
|
+
id: existing.id,
|
|
1214
|
+
created_at: existing.created_at,
|
|
1215
|
+
depends_on: normalizedDeps,
|
|
1216
|
+
version: Math.max(1, existing.version ?? 1) + 1,
|
|
1217
|
+
});
|
|
1218
|
+
await writeAtomic(taskFilePath(teamName, taskId, cwd), JSON.stringify(merged, null, 2));
|
|
1219
|
+
return merged;
|
|
842
1220
|
});
|
|
843
|
-
|
|
844
|
-
|
|
1221
|
+
if (!lock.ok)
|
|
1222
|
+
throw new Error(`Timed out acquiring task claim lock for ${teamName}/${taskId}`);
|
|
1223
|
+
return lock.value;
|
|
845
1224
|
});
|
|
846
|
-
if (!lock.ok) {
|
|
847
|
-
throw new Error(`Timed out acquiring task claim lock for ${teamName}/${taskId}`);
|
|
848
|
-
}
|
|
849
|
-
return lock.value;
|
|
850
1225
|
}
|
|
851
1226
|
// List all tasks sorted by numeric ID
|
|
852
1227
|
export async function listTasks(teamName, cwd) {
|
|
853
|
-
return await
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
1228
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1229
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1230
|
+
return await listTasksImpl(teamName, cwd, {
|
|
1231
|
+
teamDir,
|
|
1232
|
+
isTeamTask,
|
|
1233
|
+
normalizeTask,
|
|
1234
|
+
});
|
|
857
1235
|
});
|
|
858
1236
|
}
|
|
859
1237
|
export async function computeTaskReadiness(teamName, taskId, cwd) {
|
|
860
1238
|
return await computeTaskReadinessImpl(teamName, taskId, cwd, { readTask });
|
|
861
1239
|
}
|
|
862
1240
|
export async function claimTask(teamName, taskId, workerName, expectedVersion, cwd) {
|
|
863
|
-
return await
|
|
864
|
-
teamName,
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
1241
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1242
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1243
|
+
return await claimTaskImpl(taskId, workerName, expectedVersion, {
|
|
1244
|
+
teamName,
|
|
1245
|
+
cwd,
|
|
1246
|
+
readTask,
|
|
1247
|
+
readTeamConfig,
|
|
1248
|
+
withTaskClaimLock,
|
|
1249
|
+
normalizeTask,
|
|
1250
|
+
isTerminalTaskStatus,
|
|
1251
|
+
taskFilePath,
|
|
1252
|
+
writeAtomic,
|
|
1253
|
+
});
|
|
873
1254
|
});
|
|
874
1255
|
}
|
|
875
1256
|
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
|
-
|
|
1257
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1258
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1259
|
+
return await transitionTaskStatusImpl(taskId, from, to, claimToken, terminalData, {
|
|
1260
|
+
teamName,
|
|
1261
|
+
cwd,
|
|
1262
|
+
readTask,
|
|
1263
|
+
readTeamConfig,
|
|
1264
|
+
withTaskClaimLock,
|
|
1265
|
+
normalizeTask,
|
|
1266
|
+
isTerminalTaskStatus,
|
|
1267
|
+
canTransitionTaskStatus,
|
|
1268
|
+
taskFilePath,
|
|
1269
|
+
writeAtomic,
|
|
1270
|
+
appendTeamEvent,
|
|
1271
|
+
readMonitorSnapshot,
|
|
1272
|
+
writeMonitorSnapshot,
|
|
1273
|
+
});
|
|
890
1274
|
});
|
|
891
1275
|
}
|
|
892
1276
|
export async function releaseTaskClaim(teamName, taskId, claimToken, workerName, cwd) {
|
|
893
|
-
return await
|
|
894
|
-
teamName,
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1277
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1278
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1279
|
+
return await releaseTaskClaimImpl(taskId, claimToken, workerName, {
|
|
1280
|
+
teamName,
|
|
1281
|
+
cwd,
|
|
1282
|
+
readTask,
|
|
1283
|
+
readTeamConfig,
|
|
1284
|
+
withTaskClaimLock,
|
|
1285
|
+
normalizeTask,
|
|
1286
|
+
isTerminalTaskStatus,
|
|
1287
|
+
taskFilePath,
|
|
1288
|
+
writeAtomic,
|
|
1289
|
+
});
|
|
903
1290
|
});
|
|
904
1291
|
}
|
|
905
1292
|
export async function reclaimExpiredTaskClaim(teamName, taskId, cwd) {
|
|
906
|
-
return await
|
|
907
|
-
teamName,
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
1293
|
+
return await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1294
|
+
await recoverTeamMembershipTaskTransaction(teamName, cwd);
|
|
1295
|
+
return await reclaimExpiredTaskClaimImpl(taskId, {
|
|
1296
|
+
teamName,
|
|
1297
|
+
cwd,
|
|
1298
|
+
readTask,
|
|
1299
|
+
readTeamConfig,
|
|
1300
|
+
withTaskClaimLock,
|
|
1301
|
+
normalizeTask,
|
|
1302
|
+
isTerminalTaskStatus,
|
|
1303
|
+
taskFilePath,
|
|
1304
|
+
writeAtomic,
|
|
1305
|
+
});
|
|
916
1306
|
});
|
|
917
1307
|
}
|
|
918
1308
|
export async function appendTeamEvent(teamName, event, cwd) {
|
|
@@ -1012,6 +1402,48 @@ async function readDispatchRequests(teamName, cwd) {
|
|
|
1012
1402
|
return [];
|
|
1013
1403
|
}
|
|
1014
1404
|
}
|
|
1405
|
+
/** Read only strictly recognized target-team legacy request records for rollback scoping. */
|
|
1406
|
+
function isStrictLegacyDispatchRequestForRollback(value, teamName) {
|
|
1407
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
1408
|
+
return false;
|
|
1409
|
+
const request = value;
|
|
1410
|
+
const requiredFields = [
|
|
1411
|
+
'request_id', 'kind', 'team_name', 'to_worker', 'trigger_message',
|
|
1412
|
+
'transport_preference', 'fallback_allowed', 'status', 'attempt_count',
|
|
1413
|
+
'created_at', 'updated_at',
|
|
1414
|
+
];
|
|
1415
|
+
if (requiredFields.some((field) => !Object.prototype.hasOwnProperty.call(request, field)))
|
|
1416
|
+
return false;
|
|
1417
|
+
return typeof request.request_id === 'string'
|
|
1418
|
+
&& request.request_id.length > 0
|
|
1419
|
+
&& ['inbox', 'mailbox', 'nudge'].includes(String(request.kind))
|
|
1420
|
+
&& request.team_name === teamName
|
|
1421
|
+
&& typeof request.to_worker === 'string'
|
|
1422
|
+
&& request.to_worker.length > 0
|
|
1423
|
+
&& typeof request.trigger_message === 'string'
|
|
1424
|
+
&& ['hook_preferred_with_fallback', 'transport_direct', 'prompt_stdin'].includes(String(request.transport_preference))
|
|
1425
|
+
&& typeof request.fallback_allowed === 'boolean'
|
|
1426
|
+
&& ['pending', 'notified', 'delivered', 'failed'].includes(String(request.status))
|
|
1427
|
+
&& typeof request.attempt_count === 'number'
|
|
1428
|
+
&& Number.isFinite(request.attempt_count)
|
|
1429
|
+
&& typeof request.created_at === 'string'
|
|
1430
|
+
&& typeof request.updated_at === 'string';
|
|
1431
|
+
}
|
|
1432
|
+
async function readLegacyDispatchRequestsForRollback(teamName, cwd) {
|
|
1433
|
+
const path = dispatchRequestsPath(teamName, cwd);
|
|
1434
|
+
try {
|
|
1435
|
+
const raw = JSON.parse(await readFile(path, 'utf8'));
|
|
1436
|
+
if (!Array.isArray(raw) || raw.some((entry) => !isStrictLegacyDispatchRequestForRollback(entry, teamName))) {
|
|
1437
|
+
throw new Error('legacy dispatch rollback evidence is malformed or unrecognized');
|
|
1438
|
+
}
|
|
1439
|
+
return raw;
|
|
1440
|
+
}
|
|
1441
|
+
catch (error) {
|
|
1442
|
+
if (error.code === 'ENOENT')
|
|
1443
|
+
return [];
|
|
1444
|
+
throw error;
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1015
1447
|
async function writeDispatchRequests(teamName, requests, cwd) {
|
|
1016
1448
|
await writeAtomic(dispatchRequestsPath(teamName, cwd), JSON.stringify(requests, null, 2));
|
|
1017
1449
|
await writeBridgeDispatchCompat(teamName, requests, cwd);
|
|
@@ -1065,6 +1497,61 @@ export function resolveDispatchLockTimeoutMs(env = process.env) {
|
|
|
1065
1497
|
async function withDispatchLock(teamName, cwd, fn) {
|
|
1066
1498
|
return await withDispatchLockImpl(teamName, cwd, teamDir, dispatchLockDir, fn);
|
|
1067
1499
|
}
|
|
1500
|
+
/** Remove worker-targeted dispatch requests under the authoritative dispatch lock. */
|
|
1501
|
+
export async function removeDispatchRequestsForWorkers(teamName, workerNames, cwd) {
|
|
1502
|
+
const names = new Set(workerNames);
|
|
1503
|
+
await withDispatchLock(teamName, cwd, async () => {
|
|
1504
|
+
// Do not derive rollback IDs from bridge-normalized root records: unscoped
|
|
1505
|
+
// and other-team records can share a target worker name. This team's legacy
|
|
1506
|
+
// file is the canonical rollback scope.
|
|
1507
|
+
const requests = await readLegacyDispatchRequestsForRollback(teamName, cwd);
|
|
1508
|
+
const legacyRequestIds = requests
|
|
1509
|
+
.filter((request) => names.has(request.to_worker))
|
|
1510
|
+
.map((request) => request.request_id);
|
|
1511
|
+
let removedRequestIds = legacyRequestIds;
|
|
1512
|
+
if (isBridgeEnabled()) {
|
|
1513
|
+
const stateDir = resolveBridgeStateDir(cwd);
|
|
1514
|
+
const bridge = getDefaultBridge(stateDir);
|
|
1515
|
+
const snapshot = bridge.execCommand({ command: 'CaptureSnapshot' });
|
|
1516
|
+
if (snapshot.event !== 'SnapshotCaptured') {
|
|
1517
|
+
throw new Error(`authoritative_dispatch_rollback_discovery_failed:${[...names].join(',')}`);
|
|
1518
|
+
}
|
|
1519
|
+
const scopedAuthoritativeIds = bridge.readDispatchRecordsStrict()
|
|
1520
|
+
.filter((record) => {
|
|
1521
|
+
const metadataTeam = typeof record.metadata?.team_name === 'string' ? record.metadata.team_name : '';
|
|
1522
|
+
return metadataTeam === teamName && names.has(record.target);
|
|
1523
|
+
})
|
|
1524
|
+
.map((record) => record.request_id);
|
|
1525
|
+
removedRequestIds = [...new Set([...legacyRequestIds, ...scopedAuthoritativeIds])];
|
|
1526
|
+
if (removedRequestIds.length === 0) {
|
|
1527
|
+
await writeAtomic(dispatchRequestsPath(teamName, cwd), JSON.stringify(requests, null, 2));
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1530
|
+
const removal = bridge.removeDispatchRecords(removedRequestIds);
|
|
1531
|
+
if (removal.event !== 'DispatchRecordsRemoved'
|
|
1532
|
+
|| removedRequestIds.some((requestId) => !removal.request_ids.includes(requestId))) {
|
|
1533
|
+
throw new Error(`authoritative_dispatch_rollback_command_failed:${[...names].join(',')}`);
|
|
1534
|
+
}
|
|
1535
|
+
// Force a separate runtime command after mutation. The removal event is
|
|
1536
|
+
// the authoritative acknowledgement; TS must not inspect or rewrite the
|
|
1537
|
+
// shared root dispatch.json as a substitute for runtime verification.
|
|
1538
|
+
const verificationSnapshot = bridge.execCommand({ command: 'CaptureSnapshot' });
|
|
1539
|
+
if (verificationSnapshot.event !== 'SnapshotCaptured') {
|
|
1540
|
+
throw new Error(`authoritative_dispatch_rollback_verification_failed:${[...names].join(',')}`);
|
|
1541
|
+
}
|
|
1542
|
+
const remainingRemovedRecord = bridge.readDispatchRecordsStrict()
|
|
1543
|
+
.some((record) => removedRequestIds.includes(record.request_id));
|
|
1544
|
+
if (remainingRemovedRecord) {
|
|
1545
|
+
throw new Error(`authoritative_dispatch_rollback_verification_failed:${[...names].join(',')}`);
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
// The legacy per-team request file is compatibility output only. Update it
|
|
1549
|
+
// only after the authoritative runtime confirms removal; never regenerate
|
|
1550
|
+
// the shared bridge dispatch.json from a local snapshot during rollback.
|
|
1551
|
+
const retained = requests.filter((request) => !names.has(request.to_worker));
|
|
1552
|
+
await writeAtomic(dispatchRequestsPath(teamName, cwd), JSON.stringify(retained, null, 2));
|
|
1553
|
+
});
|
|
1554
|
+
}
|
|
1068
1555
|
export async function enqueueDispatchRequest(teamName, requestInput, cwd) {
|
|
1069
1556
|
return await enqueueDispatchRequestImpl(requestInput, {
|
|
1070
1557
|
teamName,
|
|
@@ -1429,10 +1916,30 @@ export async function markOwnedTeamsLeaderStopObserved(cwd, leaderSessionId, now
|
|
|
1429
1916
|
}
|
|
1430
1917
|
// === Config persistence (public wrapper) ===
|
|
1431
1918
|
export async function saveTeamConfig(config, cwd) {
|
|
1432
|
-
await
|
|
1919
|
+
await withTeamTaskBarrier(config.name, cwd, async () => {
|
|
1920
|
+
// The caller's config is a full canonical replacement; recover any
|
|
1921
|
+
// interrupted membership generation while holding the same barrier before
|
|
1922
|
+
// deriving and writing its manifest companion.
|
|
1923
|
+
await recoverTeamMembershipTaskTransaction(config.name, cwd);
|
|
1924
|
+
const currentGeneration = await readConfigGenerationRaw(config.name, cwd);
|
|
1925
|
+
if (currentGeneration === null)
|
|
1926
|
+
throw new Error(`team_config_missing:${config.name}`);
|
|
1927
|
+
const expectedGeneration = normalizeTeamConfig(config).config_generation;
|
|
1928
|
+
if (expectedGeneration !== currentGeneration) {
|
|
1929
|
+
throw new Error(`team_config_stale_generation:${config.name}:${expectedGeneration}:${currentGeneration}`);
|
|
1930
|
+
}
|
|
1931
|
+
config.config_generation = currentGeneration + 1;
|
|
1932
|
+
await writeConfig(config, cwd);
|
|
1933
|
+
});
|
|
1433
1934
|
}
|
|
1434
|
-
// Delete team state
|
|
1935
|
+
// Delete team state only after excluding both scaling and membership mutations.
|
|
1936
|
+
// The scaling lock lives outside the deletable team root, so waiters cannot
|
|
1937
|
+
// recreate a deleted team merely by acquiring their lock.
|
|
1435
1938
|
export async function cleanupTeamState(teamName, cwd) {
|
|
1436
|
-
await
|
|
1939
|
+
await withScalingLock(teamName, cwd, async () => {
|
|
1940
|
+
await withTeamTaskBarrier(teamName, cwd, async () => {
|
|
1941
|
+
await rm(teamDir(teamName, cwd), { recursive: true, force: true });
|
|
1942
|
+
});
|
|
1943
|
+
});
|
|
1437
1944
|
}
|
|
1438
1945
|
//# sourceMappingURL=state.js.map
|