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
|
@@ -1,16 +1,47 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { closeSync, existsSync, ftruncateSync, linkSync, mkdirSync, openSync, readdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, writeSync } from 'node:fs';
|
|
3
|
+
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { hostname } from 'node:os';
|
|
5
|
+
import { basename, dirname, join } from 'node:path';
|
|
6
|
+
import { AGENT_DEFINITIONS } from '../agents/definitions.js';
|
|
7
|
+
import { getBaseStateDir, getBaseStateDirWithSource } from '../state/paths.js';
|
|
8
|
+
import { canonicalizeOriginCwd } from '../leader/contract.js';
|
|
9
|
+
import { codexAgentsDir, projectCodexAgentsDir } from '../utils/paths.js';
|
|
5
10
|
export const SUBAGENT_TRACKING_SCHEMA_VERSION = 1;
|
|
6
11
|
export const DEFAULT_SUBAGENT_ACTIVE_WINDOW_MS = 120_000;
|
|
12
|
+
export const OMX_ADAPTED_PROVENANCE = 'omx_adapted';
|
|
13
|
+
export const NATIVE_SUBAGENT_PROVENANCE = 'native_subagent';
|
|
14
|
+
const KNOWN_TYPED_AGENT_ROLES = new Set(Object.keys(AGENT_DEFINITIONS).map((role) => role.toLowerCase()));
|
|
7
15
|
export function subagentTrackingPath(cwd) {
|
|
8
16
|
return join(getBaseStateDir(cwd), 'subagent-tracking.json');
|
|
9
17
|
}
|
|
18
|
+
export function resolveInstalledRoleName(role, codexHomeOverride, projectRootOverride) {
|
|
19
|
+
const normalizedRole = role.trim().toLowerCase();
|
|
20
|
+
if (!normalizedRole)
|
|
21
|
+
return null;
|
|
22
|
+
if (KNOWN_TYPED_AGENT_ROLES.has(normalizedRole))
|
|
23
|
+
return normalizedRole;
|
|
24
|
+
for (const agentsDir of [codexAgentsDir(codexHomeOverride), projectCodexAgentsDir(projectRootOverride)]) {
|
|
25
|
+
try {
|
|
26
|
+
for (const entry of readdirSync(agentsDir, { withFileTypes: true })) {
|
|
27
|
+
if (!entry.isFile() || !entry.name.endsWith('.toml'))
|
|
28
|
+
continue;
|
|
29
|
+
const installedRole = entry.name.slice(0, -'.toml'.length).trim().toLowerCase();
|
|
30
|
+
if (installedRole === normalizedRole)
|
|
31
|
+
return installedRole;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Missing or unreadable agent directories do not invalidate built-in roles.
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
10
40
|
export function createSubagentTrackingState() {
|
|
11
41
|
return {
|
|
12
42
|
schemaVersion: SUBAGENT_TRACKING_SCHEMA_VERSION,
|
|
13
43
|
sessions: {},
|
|
44
|
+
pending_role_intents: [],
|
|
14
45
|
};
|
|
15
46
|
}
|
|
16
47
|
function normalizeSubagentStatus(value) {
|
|
@@ -88,6 +119,40 @@ export function isTrustedSubagentThread(session, threadId) {
|
|
|
88
119
|
return false;
|
|
89
120
|
return session.threads[normalizedThreadId]?.kind === 'subagent';
|
|
90
121
|
}
|
|
122
|
+
function normalizePendingRoleIntent(value) {
|
|
123
|
+
if (!value || typeof value !== 'object')
|
|
124
|
+
return null;
|
|
125
|
+
const candidate = value;
|
|
126
|
+
const role = readOptionalTrimmedString(candidate.role);
|
|
127
|
+
const sessionId = readOptionalTrimmedString(candidate.session_id);
|
|
128
|
+
const parentThreadId = readOptionalTrimmedString(candidate.parent_thread_id);
|
|
129
|
+
const createdAt = readOptionalTrimmedString(candidate.created_at);
|
|
130
|
+
const expiresAt = readOptionalTrimmedString(candidate.expires_at);
|
|
131
|
+
if (!role || !sessionId || !parentThreadId || !Object.hasOwn(candidate, 'correlation_token') || !createdAt || !expiresAt)
|
|
132
|
+
return null;
|
|
133
|
+
if (!Number.isFinite(Date.parse(createdAt)) || !Number.isFinite(Date.parse(expiresAt)))
|
|
134
|
+
return null;
|
|
135
|
+
const bindingState = candidate.binding_state === 'bound' ? 'bound' : undefined;
|
|
136
|
+
const boundAt = readOptionalTrimmedString(candidate.bound_at);
|
|
137
|
+
const hasValidBoundAt = Boolean(boundAt && Number.isFinite(Date.parse(boundAt)));
|
|
138
|
+
const originCwd = readOptionalTrimmedString(candidate.origin_cwd);
|
|
139
|
+
return {
|
|
140
|
+
role,
|
|
141
|
+
session_id: sessionId,
|
|
142
|
+
parent_thread_id: parentThreadId,
|
|
143
|
+
// Bound journals are durable security records. Retain malformed credentials verbatim so
|
|
144
|
+
// completion can reject them rather than silently converting them into claimant-less data.
|
|
145
|
+
correlation_token: candidate.correlation_token,
|
|
146
|
+
created_at: createdAt,
|
|
147
|
+
expires_at: expiresAt,
|
|
148
|
+
...(bindingState ? { binding_state: bindingState } : {}),
|
|
149
|
+
...(bindingState && Object.hasOwn(candidate, 'binding_claimant_token')
|
|
150
|
+
? { binding_claimant_token: candidate.binding_claimant_token }
|
|
151
|
+
: {}),
|
|
152
|
+
...(bindingState && hasValidBoundAt ? { bound_at: boundAt } : {}),
|
|
153
|
+
...(originCwd ? { origin_cwd: originCwd } : {}),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
91
156
|
export function normalizeSubagentTrackingState(input) {
|
|
92
157
|
const base = createSubagentTrackingState();
|
|
93
158
|
if (!input || typeof input !== 'object')
|
|
@@ -102,9 +167,7 @@ export function normalizeSubagentTrackingState(input) {
|
|
|
102
167
|
if (!rawThread || typeof rawThread !== 'object')
|
|
103
168
|
continue;
|
|
104
169
|
const candidate = rawThread;
|
|
105
|
-
const normalizedThreadId = typeof candidate.thread_id === 'string' && candidate.thread_id.trim().length > 0
|
|
106
|
-
? candidate.thread_id.trim()
|
|
107
|
-
: threadId.trim();
|
|
170
|
+
const normalizedThreadId = typeof candidate.thread_id === 'string' && candidate.thread_id.trim().length > 0 ? candidate.thread_id.trim() : threadId.trim();
|
|
108
171
|
if (!normalizedThreadId)
|
|
109
172
|
continue;
|
|
110
173
|
const kind = candidate.kind === 'leader' ? 'leader' : 'subagent';
|
|
@@ -113,32 +176,31 @@ export function normalizeSubagentTrackingState(input) {
|
|
|
113
176
|
: typeof candidate.last_seen_at === 'string' && candidate.last_seen_at.trim().length > 0
|
|
114
177
|
? candidate.last_seen_at
|
|
115
178
|
: new Date(0).toISOString();
|
|
116
|
-
const lastSeenAt = typeof candidate.last_seen_at === 'string' && candidate.last_seen_at.trim().length > 0
|
|
117
|
-
? candidate.last_seen_at
|
|
118
|
-
: firstSeenAt;
|
|
179
|
+
const lastSeenAt = typeof candidate.last_seen_at === 'string' && candidate.last_seen_at.trim().length > 0 ? candidate.last_seen_at : firstSeenAt;
|
|
119
180
|
threads[normalizedThreadId] = {
|
|
120
181
|
thread_id: normalizedThreadId,
|
|
121
182
|
kind,
|
|
122
183
|
first_seen_at: firstSeenAt,
|
|
123
184
|
last_seen_at: lastSeenAt,
|
|
124
|
-
...(typeof candidate.last_turn_id === 'string' && candidate.last_turn_id.trim().length > 0
|
|
125
|
-
|
|
126
|
-
: {}),
|
|
127
|
-
...(typeof candidate.completed_at === 'string' && candidate.completed_at.trim().length > 0
|
|
128
|
-
? { completed_at: candidate.completed_at }
|
|
129
|
-
: {}),
|
|
185
|
+
...(typeof candidate.last_turn_id === 'string' && candidate.last_turn_id.trim().length > 0 ? { last_turn_id: candidate.last_turn_id } : {}),
|
|
186
|
+
...(typeof candidate.completed_at === 'string' && candidate.completed_at.trim().length > 0 ? { completed_at: candidate.completed_at } : {}),
|
|
130
187
|
...(typeof candidate.last_completed_turn_id === 'string' && candidate.last_completed_turn_id.trim().length > 0
|
|
131
188
|
? { last_completed_turn_id: candidate.last_completed_turn_id }
|
|
132
189
|
: {}),
|
|
133
|
-
turn_count: typeof candidate.turn_count === 'number' && Number.isFinite(candidate.turn_count) && candidate.turn_count > 0
|
|
134
|
-
? candidate.turn_count
|
|
135
|
-
: 1,
|
|
190
|
+
turn_count: typeof candidate.turn_count === 'number' && Number.isFinite(candidate.turn_count) && candidate.turn_count > 0 ? candidate.turn_count : 1,
|
|
136
191
|
...(typeof candidate.mode === 'string' && candidate.mode.trim().length > 0 ? { mode: candidate.mode } : {}),
|
|
137
192
|
...(typeof candidate.role === 'string' && candidate.role.trim().length > 0 ? { role: candidate.role.trim() } : {}),
|
|
193
|
+
...(typeof candidate.provenance_kind === 'string' && candidate.provenance_kind.trim().length > 0
|
|
194
|
+
? { provenance_kind: candidate.provenance_kind.trim() }
|
|
195
|
+
: {}),
|
|
138
196
|
...(typeof candidate.lane_id === 'string' && candidate.lane_id.trim().length > 0 ? { lane_id: candidate.lane_id.trim() } : {}),
|
|
139
197
|
...(typeof candidate.scope === 'string' && candidate.scope.trim().length > 0 ? { scope: candidate.scope.trim() } : {}),
|
|
140
|
-
...(typeof candidate.agent_nickname === 'string' && candidate.agent_nickname.trim().length > 0
|
|
141
|
-
|
|
198
|
+
...(typeof candidate.agent_nickname === 'string' && candidate.agent_nickname.trim().length > 0
|
|
199
|
+
? { agent_nickname: candidate.agent_nickname.trim() }
|
|
200
|
+
: {}),
|
|
201
|
+
...(typeof candidate.completion_source === 'string' && candidate.completion_source.trim().length > 0
|
|
202
|
+
? { completion_source: candidate.completion_source }
|
|
203
|
+
: {}),
|
|
142
204
|
...(normalizeSubagentStatus(candidate.status) ? { status: normalizeSubagentStatus(candidate.status) } : {}),
|
|
143
205
|
...(typeof candidate.last_handoff_summary === 'string' && candidate.last_handoff_summary.trim().length > 0
|
|
144
206
|
? { last_handoff_summary: candidate.last_handoff_summary.trim() }
|
|
@@ -158,9 +220,7 @@ export function normalizeSubagentTrackingState(input) {
|
|
|
158
220
|
};
|
|
159
221
|
}
|
|
160
222
|
const sessionCandidate = rawSession;
|
|
161
|
-
const leaderThreadId = typeof sessionCandidate.leader_thread_id === 'string'
|
|
162
|
-
? sessionCandidate.leader_thread_id.trim() || undefined
|
|
163
|
-
: undefined;
|
|
223
|
+
const leaderThreadId = typeof sessionCandidate.leader_thread_id === 'string' ? sessionCandidate.leader_thread_id.trim() || undefined : undefined;
|
|
164
224
|
const updatedAt = typeof sessionCandidate.updated_at === 'string' && sessionCandidate.updated_at.trim().length > 0
|
|
165
225
|
? sessionCandidate.updated_at
|
|
166
226
|
: new Date(0).toISOString();
|
|
@@ -171,11 +231,398 @@ export function normalizeSubagentTrackingState(input) {
|
|
|
171
231
|
threads,
|
|
172
232
|
};
|
|
173
233
|
}
|
|
234
|
+
const pendingRoleIntents = Array.isArray(parsed.pending_role_intents)
|
|
235
|
+
? parsed.pending_role_intents.map((intent) => normalizePendingRoleIntent(intent)).filter((intent) => intent !== null)
|
|
236
|
+
: [];
|
|
174
237
|
return {
|
|
175
238
|
schemaVersion: SUBAGENT_TRACKING_SCHEMA_VERSION,
|
|
176
239
|
sessions,
|
|
240
|
+
pending_role_intents: pendingRoleIntents,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function atomicTrackingTempPath(path) {
|
|
244
|
+
return `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
245
|
+
}
|
|
246
|
+
export const DEFAULT_CROSS_PROCESS_LOCK_MAX_ATTEMPTS = 80;
|
|
247
|
+
export const DEFAULT_CROSS_PROCESS_LOCK_RETRY_MS = 2;
|
|
248
|
+
export const CROSS_PROCESS_LOCK_LEASE_MS = 60_000;
|
|
249
|
+
const crossProcessLockWaitArray = new Int32Array(new SharedArrayBuffer(4));
|
|
250
|
+
export class CrossProcessLockLostError extends Error {
|
|
251
|
+
constructor(lockPath) {
|
|
252
|
+
super(`Lost cross-process lock ownership at ${lockPath}`);
|
|
253
|
+
this.name = 'CrossProcessLockLostError';
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
export function crossProcessLockPath(resourcePath) {
|
|
257
|
+
return `${resourcePath}.lock`;
|
|
258
|
+
}
|
|
259
|
+
function sleepForCrossProcessLockSync(durationMs) {
|
|
260
|
+
Atomics.wait(crossProcessLockWaitArray, 0, 0, durationMs);
|
|
261
|
+
}
|
|
262
|
+
export function readProcessStartIdentity(pid) {
|
|
263
|
+
if (process.platform !== 'linux')
|
|
264
|
+
return undefined;
|
|
265
|
+
try {
|
|
266
|
+
const stat = readFileSync(`/proc/${pid}/stat`, 'utf-8');
|
|
267
|
+
const closingParenthesis = stat.lastIndexOf(')');
|
|
268
|
+
const fields = stat.slice(closingParenthesis + 1).trim().split(/\s+/);
|
|
269
|
+
const starttime = fields[19];
|
|
270
|
+
const bootId = readFileSync('/proc/sys/kernel/random/boot_id', 'utf-8').trim();
|
|
271
|
+
if (closingParenthesis < 0 || !starttime || !/^\d+$/.test(starttime) || !bootId)
|
|
272
|
+
return undefined;
|
|
273
|
+
return `${bootId}:${starttime}`;
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function createCrossProcessLockClaim(token) {
|
|
280
|
+
const pidStartId = readProcessStartIdentity(process.pid);
|
|
281
|
+
return {
|
|
282
|
+
token,
|
|
283
|
+
pid: process.pid,
|
|
284
|
+
host: hostname(),
|
|
285
|
+
acquiredAtMs: Date.now(),
|
|
286
|
+
...(pidStartId ? { pidStartId } : {}),
|
|
177
287
|
};
|
|
178
288
|
}
|
|
289
|
+
function serializeCrossProcessLockClaim(claim) {
|
|
290
|
+
return `${JSON.stringify({
|
|
291
|
+
token: claim.token,
|
|
292
|
+
pid: claim.pid,
|
|
293
|
+
host: claim.host,
|
|
294
|
+
acquired_at: new Date(claim.acquiredAtMs).toISOString(),
|
|
295
|
+
...(claim.pidStartId ? { pid_start_id: claim.pidStartId } : {}),
|
|
296
|
+
})}\n`;
|
|
297
|
+
}
|
|
298
|
+
function readCrossProcessLockState(lockPath) {
|
|
299
|
+
try {
|
|
300
|
+
const parsed = JSON.parse(readFileSync(lockPath, 'utf-8'));
|
|
301
|
+
const token = typeof parsed.token === 'string' && parsed.token === parsed.token.trim() && parsed.token ? parsed.token : undefined;
|
|
302
|
+
const pid = typeof parsed.pid === 'number' && Number.isSafeInteger(parsed.pid) && parsed.pid > 0 ? parsed.pid : undefined;
|
|
303
|
+
const host = typeof parsed.host === 'string' && parsed.host.trim() ? parsed.host : undefined;
|
|
304
|
+
const acquiredAtMs = typeof parsed.acquired_at === 'string' ? Date.parse(parsed.acquired_at) : Number.NaN;
|
|
305
|
+
const pidStartId = parsed.pid_start_id === undefined
|
|
306
|
+
? undefined
|
|
307
|
+
: typeof parsed.pid_start_id === 'string' && parsed.pid_start_id.trim()
|
|
308
|
+
? parsed.pid_start_id
|
|
309
|
+
: null;
|
|
310
|
+
if (!token || !pid || !host || !Number.isFinite(acquiredAtMs) || pidStartId === null)
|
|
311
|
+
return { kind: 'malformed' };
|
|
312
|
+
return {
|
|
313
|
+
kind: 'claim',
|
|
314
|
+
claim: { token, pid, host, acquiredAtMs, ...(pidStartId ? { pidStartId } : {}) },
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
if (error.code === 'ENOENT')
|
|
319
|
+
return { kind: 'missing' };
|
|
320
|
+
return { kind: 'malformed' };
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function isCrossProcessLockOwnerDead(pid) {
|
|
324
|
+
try {
|
|
325
|
+
process.kill(pid, 0);
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
return error.code === 'ESRCH';
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
function isCrossProcessLockOlderThanLease(acquiredAtMs, nowMs) {
|
|
333
|
+
return acquiredAtMs < nowMs - CROSS_PROCESS_LOCK_LEASE_MS;
|
|
334
|
+
}
|
|
335
|
+
function isCrossProcessLockReclaimable(claim) {
|
|
336
|
+
if (claim.host !== hostname())
|
|
337
|
+
return isCrossProcessLockOlderThanLease(claim.acquiredAtMs, Date.now());
|
|
338
|
+
if (isCrossProcessLockOwnerDead(claim.pid))
|
|
339
|
+
return true;
|
|
340
|
+
const currentPidStartId = readProcessStartIdentity(claim.pid);
|
|
341
|
+
if (claim.pidStartId && currentPidStartId)
|
|
342
|
+
return currentPidStartId !== claim.pidStartId;
|
|
343
|
+
return isCrossProcessLockOlderThanLease(claim.acquiredAtMs, Date.now());
|
|
344
|
+
}
|
|
345
|
+
function removeCrossProcessLockFile(path) {
|
|
346
|
+
try {
|
|
347
|
+
unlinkSync(path);
|
|
348
|
+
}
|
|
349
|
+
catch (error) {
|
|
350
|
+
if (error.code !== 'ENOENT')
|
|
351
|
+
throw error;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function tryAcquireCrossProcessFileLock(lockPath, token) {
|
|
355
|
+
const temporaryPath = `${lockPath}.${process.pid}.${randomUUID()}.tmp`;
|
|
356
|
+
let acquired = false;
|
|
357
|
+
try {
|
|
358
|
+
writeFileSync(temporaryPath, serializeCrossProcessLockClaim(createCrossProcessLockClaim(token)));
|
|
359
|
+
try {
|
|
360
|
+
linkSync(temporaryPath, lockPath);
|
|
361
|
+
acquired = true;
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
if (error.code === 'EEXIST')
|
|
366
|
+
return false;
|
|
367
|
+
throw error;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
finally {
|
|
371
|
+
try {
|
|
372
|
+
removeCrossProcessLockFile(temporaryPath);
|
|
373
|
+
}
|
|
374
|
+
catch (error) {
|
|
375
|
+
if (!acquired)
|
|
376
|
+
throw error;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
function restoreQuarantinedCrossProcessLock(lockPath, quarantinedPath) {
|
|
381
|
+
try {
|
|
382
|
+
linkSync(quarantinedPath, lockPath);
|
|
383
|
+
}
|
|
384
|
+
catch (error) {
|
|
385
|
+
const code = error.code;
|
|
386
|
+
// EEXIST: a replacement claim already holds the lock; the displaced copy is redundant.
|
|
387
|
+
// ENOENT: the displaced artifact was already removed (e.g. by a concurrent bounded
|
|
388
|
+
// sweep) — a fenced clean terminal outcome, never a cleanup failure to throw on.
|
|
389
|
+
if (code === 'EEXIST') {
|
|
390
|
+
removeCrossProcessLockFile(quarantinedPath);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
if (code === 'ENOENT')
|
|
394
|
+
return;
|
|
395
|
+
throw error;
|
|
396
|
+
}
|
|
397
|
+
removeCrossProcessLockFile(quarantinedPath);
|
|
398
|
+
}
|
|
399
|
+
function recoverCrossProcessFileLock(lockPath, observed) {
|
|
400
|
+
if (observed.kind === 'missing')
|
|
401
|
+
return true;
|
|
402
|
+
if (observed.kind === 'claim' && !isCrossProcessLockReclaimable(observed.claim))
|
|
403
|
+
return false;
|
|
404
|
+
const quarantinedPath = `${lockPath}.${Date.now()}.${randomUUID()}.quarantine`;
|
|
405
|
+
try {
|
|
406
|
+
renameSync(lockPath, quarantinedPath);
|
|
407
|
+
}
|
|
408
|
+
catch (error) {
|
|
409
|
+
if (error.code === 'ENOENT')
|
|
410
|
+
return true;
|
|
411
|
+
throw error;
|
|
412
|
+
}
|
|
413
|
+
const barrier = crossProcessQuarantineBarrier;
|
|
414
|
+
crossProcessQuarantineBarrier = null;
|
|
415
|
+
barrier?.(lockPath, quarantinedPath);
|
|
416
|
+
const captured = readCrossProcessLockState(quarantinedPath);
|
|
417
|
+
const capturedExpectedClaim = observed.kind === 'claim'
|
|
418
|
+
&& captured.kind === 'claim'
|
|
419
|
+
&& captured.claim.token === observed.claim.token;
|
|
420
|
+
const capturedRecoverable = captured.kind === 'malformed'
|
|
421
|
+
|| (capturedExpectedClaim && captured.kind === 'claim' && isCrossProcessLockReclaimable(captured.claim));
|
|
422
|
+
if (!capturedRecoverable) {
|
|
423
|
+
restoreQuarantinedCrossProcessLock(lockPath, quarantinedPath);
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
426
|
+
removeCrossProcessLockFile(quarantinedPath);
|
|
427
|
+
return true;
|
|
428
|
+
}
|
|
429
|
+
function assertCrossProcessFileLockOwnership(lockPath, token) {
|
|
430
|
+
const state = readCrossProcessLockState(lockPath);
|
|
431
|
+
if (state.kind === 'claim' && state.claim.token === token)
|
|
432
|
+
return;
|
|
433
|
+
throw new CrossProcessLockLostError(lockPath);
|
|
434
|
+
}
|
|
435
|
+
function releaseCrossProcessFileLock(lockPath, token) {
|
|
436
|
+
const observed = readCrossProcessLockState(lockPath);
|
|
437
|
+
if (observed.kind !== 'claim' || observed.claim.token !== token)
|
|
438
|
+
return;
|
|
439
|
+
const quarantinedPath = `${lockPath}.${Date.now()}.${randomUUID()}.release`;
|
|
440
|
+
try {
|
|
441
|
+
renameSync(lockPath, quarantinedPath);
|
|
442
|
+
}
|
|
443
|
+
catch (error) {
|
|
444
|
+
if (error.code === 'ENOENT')
|
|
445
|
+
return;
|
|
446
|
+
throw error;
|
|
447
|
+
}
|
|
448
|
+
const barrier = crossProcessQuarantineBarrier;
|
|
449
|
+
crossProcessQuarantineBarrier = null;
|
|
450
|
+
barrier?.(lockPath, quarantinedPath);
|
|
451
|
+
const captured = readCrossProcessLockState(quarantinedPath);
|
|
452
|
+
if (captured.kind === 'claim' && captured.claim.token === token) {
|
|
453
|
+
removeCrossProcessLockFile(quarantinedPath);
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
restoreQuarantinedCrossProcessLock(lockPath, quarantinedPath);
|
|
457
|
+
}
|
|
458
|
+
function crossProcessLockStagePath(resourcePath, token) {
|
|
459
|
+
return `${resourcePath}.stage.${token}`;
|
|
460
|
+
}
|
|
461
|
+
function createCrossProcessLockStage(stagePath) {
|
|
462
|
+
const descriptor = openSync(stagePath, 'wx');
|
|
463
|
+
closeSync(descriptor);
|
|
464
|
+
}
|
|
465
|
+
function sweepForeignCrossProcessLockStages(resourcePath, token) {
|
|
466
|
+
const directory = dirname(resourcePath);
|
|
467
|
+
const stagePrefix = `${basename(resourcePath)}.stage.`;
|
|
468
|
+
for (const entry of readdirSync(directory)) {
|
|
469
|
+
if (!entry.startsWith(stagePrefix) || entry.slice(stagePrefix.length) === token)
|
|
470
|
+
continue;
|
|
471
|
+
removeCrossProcessLockFile(join(directory, entry));
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
export const CROSS_PROCESS_LOCK_ARTIFACT_SWEEP_CAP = 64;
|
|
475
|
+
function sweepAbandonedCrossProcessLockArtifacts(resourcePath) {
|
|
476
|
+
const directory = dirname(resourcePath);
|
|
477
|
+
const lockName = basename(crossProcessLockPath(resourcePath));
|
|
478
|
+
const escapedLockName = lockName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
479
|
+
const artifactPattern = new RegExp(`^${escapedLockName}\\.([^.]+)\\.[^.]+\\.(?:quarantine|release)$`);
|
|
480
|
+
const nowMs = Date.now();
|
|
481
|
+
const aged = [];
|
|
482
|
+
for (const entry of readdirSync(directory)) {
|
|
483
|
+
const match = artifactPattern.exec(entry);
|
|
484
|
+
if (!match)
|
|
485
|
+
continue;
|
|
486
|
+
const displacedAtMs = Number(match[1]);
|
|
487
|
+
// Only lease-aged, parseable-timestamp artifacts are eligible; fresh/live/malformed-ts
|
|
488
|
+
// artifacts are always preserved (never delete a live successor's in-flight evidence).
|
|
489
|
+
if (!Number.isFinite(displacedAtMs) || nowMs - displacedAtMs <= CROSS_PROCESS_LOCK_LEASE_MS)
|
|
490
|
+
continue;
|
|
491
|
+
aged.push({ displacedAtMs, entry });
|
|
492
|
+
}
|
|
493
|
+
// Bounded, deterministic cleanup: process oldest-first (tie-break by name) and remove at
|
|
494
|
+
// most CROSS_PROCESS_LOCK_ARTIFACT_SWEEP_CAP per acquisition, so a large backlog drains
|
|
495
|
+
// predictably across acquisitions instead of doing unbounded work in a single lock take.
|
|
496
|
+
aged.sort((a, b) => a.displacedAtMs - b.displacedAtMs || (a.entry < b.entry ? -1 : a.entry > b.entry ? 1 : 0));
|
|
497
|
+
for (const { entry } of aged.slice(0, CROSS_PROCESS_LOCK_ARTIFACT_SWEEP_CAP)) {
|
|
498
|
+
removeCrossProcessLockFile(join(directory, entry));
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
let crossProcessPublishBarrier = null;
|
|
502
|
+
let crossProcessQuarantineBarrier = null;
|
|
503
|
+
export function __setCrossProcessPublishBarrierForTest(barrier) {
|
|
504
|
+
crossProcessPublishBarrier = barrier;
|
|
505
|
+
}
|
|
506
|
+
export function __setCrossProcessQuarantineBarrierForTest(barrier) {
|
|
507
|
+
crossProcessQuarantineBarrier = barrier;
|
|
508
|
+
}
|
|
509
|
+
export function withCrossProcessFileLockSync(resourcePath, operation, options = {}) {
|
|
510
|
+
const lockPath = crossProcessLockPath(resourcePath);
|
|
511
|
+
const maxAttempts = typeof options.maxAttempts === 'number' && Number.isFinite(options.maxAttempts)
|
|
512
|
+
? Math.max(1, Math.floor(options.maxAttempts))
|
|
513
|
+
: DEFAULT_CROSS_PROCESS_LOCK_MAX_ATTEMPTS;
|
|
514
|
+
const retryMs = typeof options.retryMs === 'number' && Number.isFinite(options.retryMs)
|
|
515
|
+
? Math.max(1, Math.floor(options.retryMs))
|
|
516
|
+
: DEFAULT_CROSS_PROCESS_LOCK_RETRY_MS;
|
|
517
|
+
mkdirSync(dirname(lockPath), { recursive: true });
|
|
518
|
+
const token = randomUUID();
|
|
519
|
+
const stagePath = crossProcessLockStagePath(resourcePath, token);
|
|
520
|
+
let acquired = false;
|
|
521
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
522
|
+
if (tryAcquireCrossProcessFileLock(lockPath, token)) {
|
|
523
|
+
acquired = true;
|
|
524
|
+
break;
|
|
525
|
+
}
|
|
526
|
+
const recovered = recoverCrossProcessFileLock(lockPath, readCrossProcessLockState(lockPath));
|
|
527
|
+
if (recovered && tryAcquireCrossProcessFileLock(lockPath, token)) {
|
|
528
|
+
acquired = true;
|
|
529
|
+
break;
|
|
530
|
+
}
|
|
531
|
+
if (attempt === maxAttempts - 1) {
|
|
532
|
+
throw new Error(`Timed out waiting for cross-process lock at ${lockPath}`);
|
|
533
|
+
}
|
|
534
|
+
sleepForCrossProcessLockSync(Math.min(25, retryMs * 2 ** Math.min(attempt, 4)));
|
|
535
|
+
}
|
|
536
|
+
if (!acquired) {
|
|
537
|
+
throw new Error(`Timed out waiting for cross-process lock at ${lockPath}`);
|
|
538
|
+
}
|
|
539
|
+
try {
|
|
540
|
+
sweepForeignCrossProcessLockStages(resourcePath, token);
|
|
541
|
+
sweepAbandonedCrossProcessLockArtifacts(resourcePath);
|
|
542
|
+
createCrossProcessLockStage(stagePath);
|
|
543
|
+
return operation({
|
|
544
|
+
assertOwnership: () => assertCrossProcessFileLockOwnership(lockPath, token),
|
|
545
|
+
publish: (contents) => {
|
|
546
|
+
let descriptor;
|
|
547
|
+
try {
|
|
548
|
+
descriptor = openSync(stagePath, 'r+');
|
|
549
|
+
}
|
|
550
|
+
catch (error) {
|
|
551
|
+
if (error.code === 'ENOENT')
|
|
552
|
+
throw new CrossProcessLockLostError(lockPath);
|
|
553
|
+
throw error;
|
|
554
|
+
}
|
|
555
|
+
try {
|
|
556
|
+
ftruncateSync(descriptor, 0);
|
|
557
|
+
writeSync(descriptor, contents);
|
|
558
|
+
}
|
|
559
|
+
finally {
|
|
560
|
+
closeSync(descriptor);
|
|
561
|
+
}
|
|
562
|
+
const barrier = crossProcessPublishBarrier;
|
|
563
|
+
crossProcessPublishBarrier = null;
|
|
564
|
+
barrier?.();
|
|
565
|
+
try {
|
|
566
|
+
renameSync(stagePath, resourcePath);
|
|
567
|
+
}
|
|
568
|
+
catch (error) {
|
|
569
|
+
if (error.code === 'ENOENT')
|
|
570
|
+
throw new CrossProcessLockLostError(lockPath);
|
|
571
|
+
throw error;
|
|
572
|
+
}
|
|
573
|
+
createCrossProcessLockStage(stagePath);
|
|
574
|
+
},
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
finally {
|
|
578
|
+
removeCrossProcessLockFile(stagePath);
|
|
579
|
+
releaseCrossProcessFileLock(lockPath, token);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
function readSubagentTrackingStateSync(cwd) {
|
|
583
|
+
const path = subagentTrackingPath(cwd);
|
|
584
|
+
if (!existsSync(path))
|
|
585
|
+
return createSubagentTrackingState();
|
|
586
|
+
try {
|
|
587
|
+
return normalizeSubagentTrackingState(JSON.parse(readFileSync(path, 'utf-8')));
|
|
588
|
+
}
|
|
589
|
+
catch {
|
|
590
|
+
return createSubagentTrackingState();
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
// Strict reads preserve fail-closed behavior for security-sensitive tracker decisions.
|
|
594
|
+
export async function readSubagentTrackingStateStrict(cwd) {
|
|
595
|
+
const path = subagentTrackingPath(cwd);
|
|
596
|
+
let raw;
|
|
597
|
+
try {
|
|
598
|
+
raw = await readFile(path, 'utf-8');
|
|
599
|
+
}
|
|
600
|
+
catch (error) {
|
|
601
|
+
if (error?.code === 'ENOENT')
|
|
602
|
+
return { ok: true, state: createSubagentTrackingState() };
|
|
603
|
+
return { ok: false };
|
|
604
|
+
}
|
|
605
|
+
try {
|
|
606
|
+
return { ok: true, state: normalizeSubagentTrackingState(JSON.parse(raw)) };
|
|
607
|
+
}
|
|
608
|
+
catch {
|
|
609
|
+
return { ok: false };
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
function writeSubagentTrackingStateSync(cwd, state, publish) {
|
|
613
|
+
const normalized = normalizeSubagentTrackingState(state);
|
|
614
|
+
const path = subagentTrackingPath(cwd);
|
|
615
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
616
|
+
const contents = `${JSON.stringify(normalized, null, 2)}\n`;
|
|
617
|
+
if (publish) {
|
|
618
|
+
publish(contents);
|
|
619
|
+
return path;
|
|
620
|
+
}
|
|
621
|
+
const temporaryPath = atomicTrackingTempPath(path);
|
|
622
|
+
writeFileSync(temporaryPath, contents);
|
|
623
|
+
renameSync(temporaryPath, path);
|
|
624
|
+
return path;
|
|
625
|
+
}
|
|
179
626
|
export async function readSubagentTrackingState(cwd) {
|
|
180
627
|
const path = subagentTrackingPath(cwd);
|
|
181
628
|
if (!existsSync(path))
|
|
@@ -191,9 +638,299 @@ export async function writeSubagentTrackingState(cwd, state) {
|
|
|
191
638
|
const normalized = normalizeSubagentTrackingState(state);
|
|
192
639
|
const path = subagentTrackingPath(cwd);
|
|
193
640
|
await mkdir(dirname(path), { recursive: true });
|
|
194
|
-
|
|
641
|
+
const temporaryPath = atomicTrackingTempPath(path);
|
|
642
|
+
await writeFile(temporaryPath, `${JSON.stringify(normalized, null, 2)}\n`);
|
|
643
|
+
await rename(temporaryPath, path);
|
|
195
644
|
return path;
|
|
196
645
|
}
|
|
646
|
+
function normalizeNowMs(nowMs) {
|
|
647
|
+
return typeof nowMs === 'number' && Number.isFinite(nowMs) ? nowMs : Date.now();
|
|
648
|
+
}
|
|
649
|
+
function isExpiredPendingRoleIntent(intent, nowMs) {
|
|
650
|
+
if (intent.binding_state === 'bound')
|
|
651
|
+
return false;
|
|
652
|
+
const expiresAtMs = Date.parse(intent.expires_at);
|
|
653
|
+
return !Number.isFinite(expiresAtMs) || expiresAtMs <= nowMs;
|
|
654
|
+
}
|
|
655
|
+
function pendingRoleIntentPredicates(cwd, canonicalOrigin, nowMs) {
|
|
656
|
+
const isCwdPartitionedStateRoot = getBaseStateDirWithSource(cwd).rootSource === 'cwd-default';
|
|
657
|
+
const isOwn = (intent) => (intent.origin_cwd
|
|
658
|
+
? canonicalizeOriginCwd(intent.origin_cwd) === canonicalOrigin
|
|
659
|
+
: isCwdPartitionedStateRoot);
|
|
660
|
+
const shouldPruneExpired = (intent) => (isOwn(intent)
|
|
661
|
+
&& intent.binding_state !== 'bound'
|
|
662
|
+
&& isExpiredPendingRoleIntent(intent, nowMs));
|
|
663
|
+
return { isOwn, shouldPruneExpired };
|
|
664
|
+
}
|
|
665
|
+
export function isRoleIntentOwnedByCwd(cwd, intent) {
|
|
666
|
+
return pendingRoleIntentPredicates(cwd, canonicalizeOriginCwd(cwd), Date.now()).isOwn(intent);
|
|
667
|
+
}
|
|
668
|
+
function sameLogicalRoleIntent(intent, sessionId, parentThreadId, correlationToken) {
|
|
669
|
+
return (intent.session_id === sessionId
|
|
670
|
+
&& intent.parent_thread_id === parentThreadId
|
|
671
|
+
&& (correlationToken === undefined || intent.correlation_token === correlationToken));
|
|
672
|
+
}
|
|
673
|
+
export function isCanonicalCorrelationToken(value) {
|
|
674
|
+
return typeof value === 'string' && /^[0-9a-f]{32}$/.test(value);
|
|
675
|
+
}
|
|
676
|
+
export function isCanonicalClaimantToken(value) {
|
|
677
|
+
return typeof value === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(value);
|
|
678
|
+
}
|
|
679
|
+
function hasOwnBoundLogicalIntent(all, isOwn, sessionId, parentThreadId, correlationToken) {
|
|
680
|
+
return all.some((intent) => (isOwn(intent)
|
|
681
|
+
&& intent.binding_state === 'bound'
|
|
682
|
+
&& sameLogicalRoleIntent(intent, sessionId, parentThreadId, correlationToken)));
|
|
683
|
+
}
|
|
684
|
+
function selectDominantRoleIntent(candidates, canonicalOrigin) {
|
|
685
|
+
return [...candidates].sort((left, right) => {
|
|
686
|
+
const leftIsBound = left.binding_state === 'bound';
|
|
687
|
+
const rightIsBound = right.binding_state === 'bound';
|
|
688
|
+
if (leftIsBound !== rightIsBound)
|
|
689
|
+
return leftIsBound ? -1 : 1;
|
|
690
|
+
const leftIsExactOrigin = left.origin_cwd !== undefined
|
|
691
|
+
&& canonicalizeOriginCwd(left.origin_cwd) === canonicalOrigin;
|
|
692
|
+
const rightIsExactOrigin = right.origin_cwd !== undefined
|
|
693
|
+
&& canonicalizeOriginCwd(right.origin_cwd) === canonicalOrigin;
|
|
694
|
+
if (leftIsExactOrigin !== rightIsExactOrigin)
|
|
695
|
+
return leftIsExactOrigin ? -1 : 1;
|
|
696
|
+
const leftStableKey = [
|
|
697
|
+
left.role,
|
|
698
|
+
left.correlation_token,
|
|
699
|
+
left.created_at,
|
|
700
|
+
left.expires_at,
|
|
701
|
+
left.binding_state ?? '',
|
|
702
|
+
left.binding_claimant_token ?? '',
|
|
703
|
+
left.bound_at ?? '',
|
|
704
|
+
left.origin_cwd ?? '',
|
|
705
|
+
].join('\u0000');
|
|
706
|
+
const rightStableKey = [
|
|
707
|
+
right.role,
|
|
708
|
+
right.correlation_token,
|
|
709
|
+
right.created_at,
|
|
710
|
+
right.expires_at,
|
|
711
|
+
right.binding_state ?? '',
|
|
712
|
+
right.binding_claimant_token ?? '',
|
|
713
|
+
right.bound_at ?? '',
|
|
714
|
+
right.origin_cwd ?? '',
|
|
715
|
+
].join('\u0000');
|
|
716
|
+
return leftStableKey.localeCompare(rightStableKey);
|
|
717
|
+
})[0] ?? null;
|
|
718
|
+
}
|
|
719
|
+
export function recordPendingRoleIntent(cwd, input) {
|
|
720
|
+
const role = resolveInstalledRoleName(input.role);
|
|
721
|
+
if (!role)
|
|
722
|
+
return { ok: false, reason: 'unknown_role' };
|
|
723
|
+
const correlationToken = input.correlationToken;
|
|
724
|
+
if (!isCanonicalCorrelationToken(correlationToken)) {
|
|
725
|
+
return { ok: false, reason: 'invalid_correlation_token' };
|
|
726
|
+
}
|
|
727
|
+
const nowMs = normalizeNowMs(input.nowMs);
|
|
728
|
+
const sessionId = input.sessionId.trim();
|
|
729
|
+
const parentThreadId = input.parentThreadId.trim();
|
|
730
|
+
const canonicalOrigin = canonicalizeOriginCwd(cwd);
|
|
731
|
+
if (canonicalOrigin === null)
|
|
732
|
+
return { ok: false, reason: 'invalid_origin' };
|
|
733
|
+
const { isOwn, shouldPruneExpired } = pendingRoleIntentPredicates(cwd, canonicalOrigin, nowMs);
|
|
734
|
+
return withCrossProcessFileLockSync(subagentTrackingPath(cwd), (context) => {
|
|
735
|
+
const state = readSubagentTrackingStateSync(cwd);
|
|
736
|
+
const all = state.pending_role_intents;
|
|
737
|
+
if (all.some((intent) => (isOwn(intent)
|
|
738
|
+
&& intent.session_id === sessionId
|
|
739
|
+
&& intent.parent_thread_id === parentThreadId
|
|
740
|
+
&& (intent.binding_state === 'bound' || !isExpiredPendingRoleIntent(intent, nowMs))))) {
|
|
741
|
+
return { ok: false, reason: 'single_flight_conflict' };
|
|
742
|
+
}
|
|
743
|
+
const ttlMs = typeof input.ttlMs === 'number' && Number.isFinite(input.ttlMs) ? input.ttlMs : 10 * 60_000;
|
|
744
|
+
const intent = {
|
|
745
|
+
role,
|
|
746
|
+
session_id: sessionId,
|
|
747
|
+
parent_thread_id: parentThreadId,
|
|
748
|
+
correlation_token: correlationToken,
|
|
749
|
+
created_at: new Date(nowMs).toISOString(),
|
|
750
|
+
expires_at: new Date(nowMs + ttlMs).toISOString(),
|
|
751
|
+
// Store the canonical origin workspace so it authenticates future bind/complete/recover.
|
|
752
|
+
...(canonicalOrigin ? { origin_cwd: canonicalOrigin } : {}),
|
|
753
|
+
};
|
|
754
|
+
state.pending_role_intents = [...all.filter((candidate) => !shouldPruneExpired(candidate)), intent];
|
|
755
|
+
context.assertOwnership();
|
|
756
|
+
writeSubagentTrackingStateSync(cwd, state, context.publish);
|
|
757
|
+
return { ok: true, intent };
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
export function bindPendingRoleIntentUnderLock(cwd, input, bind) {
|
|
761
|
+
const nowMs = normalizeNowMs(input.nowMs);
|
|
762
|
+
const sessionId = input.sessionId.trim();
|
|
763
|
+
const parentThreadId = input.parentThreadId.trim();
|
|
764
|
+
const correlationToken = input.correlationToken;
|
|
765
|
+
if (!isCanonicalCorrelationToken(correlationToken))
|
|
766
|
+
return null;
|
|
767
|
+
// Fail-closed origin authentication: establish the caller's canonical origin workspace up
|
|
768
|
+
// front. A malformed/unavailable origin can never disclose role/claimant, run the bind
|
|
769
|
+
// callback, mutate pending->bound, or acquire the lock.
|
|
770
|
+
const canonicalOrigin = canonicalizeOriginCwd(cwd);
|
|
771
|
+
if (canonicalOrigin === null)
|
|
772
|
+
return null;
|
|
773
|
+
return withCrossProcessFileLockSync(subagentTrackingPath(cwd), (context) => {
|
|
774
|
+
const state = readSubagentTrackingStateSync(cwd);
|
|
775
|
+
const all = state.pending_role_intents;
|
|
776
|
+
const { isOwn, shouldPruneExpired } = pendingRoleIntentPredicates(cwd, canonicalOrigin, nowMs);
|
|
777
|
+
const matchedIntent = selectDominantRoleIntent(all.filter((intent) => (isOwn(intent)
|
|
778
|
+
&& correlationToken !== undefined
|
|
779
|
+
&& sameLogicalRoleIntent(intent, sessionId, parentThreadId, correlationToken)
|
|
780
|
+
&& (intent.binding_state === 'bound' || !isExpiredPendingRoleIntent(intent, nowMs)))), canonicalOrigin);
|
|
781
|
+
if (!matchedIntent) {
|
|
782
|
+
const retained = all.filter((intent) => !shouldPruneExpired(intent));
|
|
783
|
+
if (retained.length !== all.length) {
|
|
784
|
+
state.pending_role_intents = retained;
|
|
785
|
+
context.assertOwnership();
|
|
786
|
+
writeSubagentTrackingStateSync(cwd, state, context.publish);
|
|
787
|
+
}
|
|
788
|
+
return null;
|
|
789
|
+
}
|
|
790
|
+
const adaptedIntent = {
|
|
791
|
+
role: matchedIntent.role,
|
|
792
|
+
provenanceKind: OMX_ADAPTED_PROVENANCE,
|
|
793
|
+
};
|
|
794
|
+
if (matchedIntent.binding_state === 'bound') {
|
|
795
|
+
const next = all
|
|
796
|
+
.filter((intent) => (intent.binding_state === 'bound'
|
|
797
|
+
|| !(isOwn(intent) && sameLogicalRoleIntent(intent, sessionId, parentThreadId, correlationToken))))
|
|
798
|
+
.map((intent) => (intent === matchedIntent && !intent.origin_cwd
|
|
799
|
+
? { ...intent, origin_cwd: canonicalOrigin }
|
|
800
|
+
: intent));
|
|
801
|
+
if (next.length !== all.length || !matchedIntent.origin_cwd) {
|
|
802
|
+
state.pending_role_intents = next;
|
|
803
|
+
context.assertOwnership();
|
|
804
|
+
writeSubagentTrackingStateSync(cwd, state, context.publish);
|
|
805
|
+
}
|
|
806
|
+
return {
|
|
807
|
+
...adaptedIntent,
|
|
808
|
+
claimantToken: undefined,
|
|
809
|
+
alreadyBound: true,
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
const claimantToken = randomUUID();
|
|
813
|
+
const boundState = bind(state, adaptedIntent);
|
|
814
|
+
boundState.pending_role_intents = all
|
|
815
|
+
.filter((intent) => !shouldPruneExpired(intent))
|
|
816
|
+
.filter((intent) => (intent === matchedIntent
|
|
817
|
+
|| !(isOwn(intent) && sameLogicalRoleIntent(intent, sessionId, parentThreadId, correlationToken))))
|
|
818
|
+
.map((intent) => (intent === matchedIntent
|
|
819
|
+
? {
|
|
820
|
+
...matchedIntent,
|
|
821
|
+
binding_state: 'bound',
|
|
822
|
+
binding_claimant_token: claimantToken,
|
|
823
|
+
bound_at: new Date(nowMs).toISOString(),
|
|
824
|
+
origin_cwd: matchedIntent.origin_cwd ?? canonicalOrigin,
|
|
825
|
+
}
|
|
826
|
+
: intent));
|
|
827
|
+
context.assertOwnership();
|
|
828
|
+
writeSubagentTrackingStateSync(cwd, boundState, context.publish);
|
|
829
|
+
return { ...adaptedIntent, claimantToken, alreadyBound: false };
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
export function consumePendingRoleIntent(cwd, input) {
|
|
833
|
+
const nowMs = normalizeNowMs(input.nowMs);
|
|
834
|
+
const sessionId = input.sessionId.trim();
|
|
835
|
+
const parentThreadId = input.parentThreadId.trim();
|
|
836
|
+
const correlationToken = input.correlationToken;
|
|
837
|
+
if (!isCanonicalCorrelationToken(correlationToken))
|
|
838
|
+
return null;
|
|
839
|
+
const canonicalOrigin = canonicalizeOriginCwd(cwd);
|
|
840
|
+
if (canonicalOrigin === null)
|
|
841
|
+
return null;
|
|
842
|
+
return withCrossProcessFileLockSync(subagentTrackingPath(cwd), (context) => {
|
|
843
|
+
const state = readSubagentTrackingStateSync(cwd);
|
|
844
|
+
const all = state.pending_role_intents;
|
|
845
|
+
const { isOwn, shouldPruneExpired } = pendingRoleIntentPredicates(cwd, canonicalOrigin, nowMs);
|
|
846
|
+
if (hasOwnBoundLogicalIntent(all, isOwn, sessionId, parentThreadId, correlationToken))
|
|
847
|
+
return null;
|
|
848
|
+
const consumed = selectDominantRoleIntent(all.filter((intent) => (isOwn(intent)
|
|
849
|
+
&& intent.binding_state !== 'bound'
|
|
850
|
+
&& !isExpiredPendingRoleIntent(intent, nowMs)
|
|
851
|
+
&& correlationToken !== undefined
|
|
852
|
+
&& sameLogicalRoleIntent(intent, sessionId, parentThreadId, correlationToken))), canonicalOrigin);
|
|
853
|
+
if (!consumed) {
|
|
854
|
+
const retained = all.filter((intent) => !shouldPruneExpired(intent));
|
|
855
|
+
if (retained.length !== all.length) {
|
|
856
|
+
state.pending_role_intents = retained;
|
|
857
|
+
context.assertOwnership();
|
|
858
|
+
writeSubagentTrackingStateSync(cwd, state, context.publish);
|
|
859
|
+
}
|
|
860
|
+
return null;
|
|
861
|
+
}
|
|
862
|
+
state.pending_role_intents = all
|
|
863
|
+
.filter((intent) => !shouldPruneExpired(intent))
|
|
864
|
+
.filter((intent) => (intent.binding_state === 'bound'
|
|
865
|
+
|| !(isOwn(intent) && sameLogicalRoleIntent(intent, sessionId, parentThreadId, correlationToken))));
|
|
866
|
+
context.assertOwnership();
|
|
867
|
+
writeSubagentTrackingStateSync(cwd, state, context.publish);
|
|
868
|
+
return { role: consumed.role, provenanceKind: OMX_ADAPTED_PROVENANCE };
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
export function completeAdaptedRoleBinding(cwd, input) {
|
|
872
|
+
const nowMs = normalizeNowMs(input.nowMs);
|
|
873
|
+
const sessionId = input.sessionId.trim();
|
|
874
|
+
const parentThreadId = input.parentThreadId.trim();
|
|
875
|
+
const correlationToken = input.correlationToken;
|
|
876
|
+
const claimantToken = input.claimantToken;
|
|
877
|
+
const canonicalOrigin = canonicalizeOriginCwd(cwd);
|
|
878
|
+
if (canonicalOrigin === null)
|
|
879
|
+
return 'not_found';
|
|
880
|
+
return withCrossProcessFileLockSync(subagentTrackingPath(cwd), (context) => {
|
|
881
|
+
const state = readSubagentTrackingStateSync(cwd);
|
|
882
|
+
const all = state.pending_role_intents;
|
|
883
|
+
const { isOwn, shouldPruneExpired } = pendingRoleIntentPredicates(cwd, canonicalOrigin, nowMs);
|
|
884
|
+
// Select the owned bound scope before authenticating it. Credentials are not a lookup key:
|
|
885
|
+
// otherwise an invalid dominant duplicate could be bypassed by a lower valid duplicate.
|
|
886
|
+
const boundIntent = selectDominantRoleIntent(all.filter((intent) => (isOwn(intent)
|
|
887
|
+
&& intent.binding_state === 'bound'
|
|
888
|
+
&& sameLogicalRoleIntent(intent, sessionId, parentThreadId))), canonicalOrigin);
|
|
889
|
+
if (!boundIntent) {
|
|
890
|
+
const retained = all.filter((intent) => !shouldPruneExpired(intent));
|
|
891
|
+
if (retained.length !== all.length) {
|
|
892
|
+
state.pending_role_intents = retained;
|
|
893
|
+
context.assertOwnership();
|
|
894
|
+
writeSubagentTrackingStateSync(cwd, state, context.publish);
|
|
895
|
+
}
|
|
896
|
+
return 'not_found';
|
|
897
|
+
}
|
|
898
|
+
const hasClaimant = Object.hasOwn(boundIntent, 'binding_claimant_token');
|
|
899
|
+
if (!isCanonicalCorrelationToken(boundIntent.correlation_token)
|
|
900
|
+
|| !isCanonicalCorrelationToken(correlationToken)
|
|
901
|
+
|| boundIntent.correlation_token !== correlationToken
|
|
902
|
+
|| (hasClaimant && (!isCanonicalClaimantToken(boundIntent.binding_claimant_token)
|
|
903
|
+
|| !isCanonicalClaimantToken(claimantToken)
|
|
904
|
+
|| boundIntent.binding_claimant_token !== claimantToken)))
|
|
905
|
+
return 'claimant_mismatch';
|
|
906
|
+
state.pending_role_intents = all
|
|
907
|
+
.filter((intent) => !shouldPruneExpired(intent))
|
|
908
|
+
.filter((intent) => !(isOwn(intent) && sameLogicalRoleIntent(intent, sessionId, parentThreadId, boundIntent.correlation_token)));
|
|
909
|
+
context.assertOwnership();
|
|
910
|
+
writeSubagentTrackingStateSync(cwd, state, context.publish);
|
|
911
|
+
return 'completed';
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
export function listBoundAdaptedRoleIntents(cwd, _nowMs, ownedDominant = false) {
|
|
915
|
+
const allBound = readSubagentTrackingStateSync(cwd).pending_role_intents.filter((intent) => intent.binding_state === 'bound');
|
|
916
|
+
if (!ownedDominant)
|
|
917
|
+
return allBound;
|
|
918
|
+
const canonicalOrigin = canonicalizeOriginCwd(cwd);
|
|
919
|
+
if (canonicalOrigin === null)
|
|
920
|
+
return [];
|
|
921
|
+
const { isOwn } = pendingRoleIntentPredicates(cwd, canonicalOrigin, Date.now());
|
|
922
|
+
const scopes = new Map();
|
|
923
|
+
for (const intent of allBound) {
|
|
924
|
+
if (!isOwn(intent))
|
|
925
|
+
continue;
|
|
926
|
+
const key = `${intent.session_id}\u0000${intent.parent_thread_id}`;
|
|
927
|
+
scopes.set(key, [...(scopes.get(key) ?? []), intent]);
|
|
928
|
+
}
|
|
929
|
+
return [...scopes.values()].flatMap((candidates) => {
|
|
930
|
+
const dominant = selectDominantRoleIntent(candidates, canonicalOrigin);
|
|
931
|
+
return dominant ? [dominant] : [];
|
|
932
|
+
});
|
|
933
|
+
}
|
|
197
934
|
export function recordSubagentTurn(state, input) {
|
|
198
935
|
const sessionId = input.sessionId.trim();
|
|
199
936
|
const threadId = input.threadId.trim();
|
|
@@ -209,42 +946,29 @@ export function recordSubagentTurn(state, input) {
|
|
|
209
946
|
const requestedKind = input.kind === 'leader' || input.kind === 'subagent' ? input.kind : undefined;
|
|
210
947
|
const requestedLeaderThreadId = input.leaderThreadId?.trim();
|
|
211
948
|
const existingThread = existingSession.threads[threadId];
|
|
212
|
-
const existingKind = existingThread?.kind === 'leader' || existingThread?.kind === 'subagent'
|
|
213
|
-
? existingThread.kind
|
|
214
|
-
: undefined;
|
|
949
|
+
const existingKind = existingThread?.kind === 'leader' || existingThread?.kind === 'subagent' ? existingThread.kind : undefined;
|
|
215
950
|
const existingLeaderThreadId = existingSession.leader_thread_id?.trim();
|
|
216
951
|
// `leader_thread_id` is the session's top-level leader boundary. A native
|
|
217
952
|
// subagent can itself be the immediate parent of a nested native role, but
|
|
218
953
|
// that must not reclassify known subagent evidence as the session leader.
|
|
219
|
-
const requestedLeaderThread = requestedLeaderThreadId
|
|
220
|
-
? existingSession.threads[requestedLeaderThreadId]
|
|
221
|
-
: undefined;
|
|
954
|
+
const requestedLeaderThread = requestedLeaderThreadId ? existingSession.threads[requestedLeaderThreadId] : undefined;
|
|
222
955
|
const requestedLeaderWouldReclassifySubagent = requestedLeaderThread?.kind === 'subagent';
|
|
223
|
-
const requestedSessionLeaderThreadId = requestedLeaderWouldReclassifySubagent
|
|
224
|
-
? undefined
|
|
225
|
-
: requestedLeaderThreadId;
|
|
956
|
+
const requestedSessionLeaderThreadId = requestedLeaderWouldReclassifySubagent ? undefined : requestedLeaderThreadId;
|
|
226
957
|
const preserveExistingSubagent = existingKind === 'subagent' && requestedKind !== 'subagent';
|
|
227
|
-
const preserveKnownLeader = requestedKind === 'subagent'
|
|
228
|
-
&& (existingKind === 'leader' || existingLeaderThreadId === threadId);
|
|
958
|
+
const preserveKnownLeader = requestedKind === 'subagent' && (existingKind === 'leader' || existingLeaderThreadId === threadId);
|
|
229
959
|
const leaderThreadId = preserveKnownLeader
|
|
230
960
|
? existingLeaderThreadId || threadId
|
|
231
|
-
: existingLeaderThreadId
|
|
232
|
-
|| requestedSessionLeaderThreadId
|
|
233
|
-
|| (requestedKind === 'subagent' || preserveExistingSubagent ? undefined : threadId);
|
|
961
|
+
: existingLeaderThreadId || requestedSessionLeaderThreadId || (requestedKind === 'subagent' || preserveExistingSubagent ? undefined : threadId);
|
|
234
962
|
const kind = preserveKnownLeader
|
|
235
963
|
? 'leader'
|
|
236
964
|
: requestedKind === 'leader' && existingKind === 'subagent'
|
|
237
965
|
? 'subagent'
|
|
238
|
-
: requestedKind ?? (threadId === leaderThreadId ? 'leader' : existingKind ?? 'subagent');
|
|
966
|
+
: (requestedKind ?? (threadId === leaderThreadId ? 'leader' : (existingKind ?? 'subagent')));
|
|
239
967
|
const requestedStatus = normalizeSubagentStatus(input.status);
|
|
240
968
|
const preservedStatus = normalizeSubagentStatus(existingThread?.status);
|
|
241
969
|
const preserveCompletionEvidence = input.preserveCompletionEvidence === true;
|
|
242
|
-
const clearsPriorCompletion = input.completed !== true
|
|
243
|
-
|
|
244
|
-
&& Boolean(existingThread?.completed_at);
|
|
245
|
-
const status = requestedStatus
|
|
246
|
-
?? (input.completed ? 'closed' : undefined)
|
|
247
|
-
?? (clearsPriorCompletion ? undefined : preservedStatus);
|
|
970
|
+
const clearsPriorCompletion = input.completed !== true && preserveCompletionEvidence !== true && Boolean(existingThread?.completed_at);
|
|
971
|
+
const status = requestedStatus ?? (input.completed ? 'closed' : undefined) ?? (clearsPriorCompletion ? undefined : preservedStatus);
|
|
248
972
|
const preservedCompletion = preserveCompletionEvidence && existingThread?.completed_at
|
|
249
973
|
? {
|
|
250
974
|
completed_at: existingThread.completed_at,
|
|
@@ -258,7 +982,11 @@ export function recordSubagentTurn(state, input) {
|
|
|
258
982
|
first_seen_at: existingThread?.first_seen_at ?? timestamp,
|
|
259
983
|
last_seen_at: timestamp,
|
|
260
984
|
turn_count: (existingThread?.turn_count ?? 0) + 1,
|
|
261
|
-
...(input.turnId?.trim()
|
|
985
|
+
...(input.turnId?.trim()
|
|
986
|
+
? { last_turn_id: input.turnId.trim() }
|
|
987
|
+
: existingThread?.last_turn_id
|
|
988
|
+
? { last_turn_id: existingThread.last_turn_id }
|
|
989
|
+
: {}),
|
|
262
990
|
...(input.completed
|
|
263
991
|
? {
|
|
264
992
|
completed_at: timestamp,
|
|
@@ -268,27 +996,44 @@ export function recordSubagentTurn(state, input) {
|
|
|
268
996
|
: preservedCompletion),
|
|
269
997
|
...(input.mode?.trim() ? { mode: input.mode.trim() } : existingThread?.mode ? { mode: existingThread.mode } : {}),
|
|
270
998
|
...(input.role?.trim() ? { role: input.role.trim() } : existingThread?.role ? { role: existingThread.role } : {}),
|
|
999
|
+
...(input.provenanceKind?.trim()
|
|
1000
|
+
? { provenance_kind: input.provenanceKind.trim() }
|
|
1001
|
+
: existingThread?.provenance_kind
|
|
1002
|
+
? { provenance_kind: existingThread.provenance_kind }
|
|
1003
|
+
: {}),
|
|
271
1004
|
...(input.laneId?.trim() ? { lane_id: input.laneId.trim() } : existingThread?.lane_id ? { lane_id: existingThread.lane_id } : {}),
|
|
272
1005
|
...(input.scope?.trim() ? { scope: input.scope.trim() } : existingThread?.scope ? { scope: existingThread.scope } : {}),
|
|
273
1006
|
...(input.agentNickname?.trim()
|
|
274
1007
|
? { agent_nickname: input.agentNickname.trim() }
|
|
275
|
-
: existingThread?.agent_nickname
|
|
1008
|
+
: existingThread?.agent_nickname
|
|
1009
|
+
? { agent_nickname: existingThread.agent_nickname }
|
|
1010
|
+
: {}),
|
|
276
1011
|
...(status ? { status } : {}),
|
|
277
1012
|
...(input.lastHandoffSummary?.trim()
|
|
278
1013
|
? { last_handoff_summary: input.lastHandoffSummary.trim() }
|
|
279
|
-
: existingThread?.last_handoff_summary
|
|
1014
|
+
: existingThread?.last_handoff_summary
|
|
1015
|
+
? { last_handoff_summary: existingThread.last_handoff_summary }
|
|
1016
|
+
: {}),
|
|
280
1017
|
...(input.resumeRequestedAt?.trim()
|
|
281
1018
|
? { resume_requested_at: input.resumeRequestedAt.trim() }
|
|
282
|
-
: existingThread?.resume_requested_at
|
|
1019
|
+
: existingThread?.resume_requested_at
|
|
1020
|
+
? { resume_requested_at: existingThread.resume_requested_at }
|
|
1021
|
+
: {}),
|
|
283
1022
|
...(input.resumeCompletedAt?.trim()
|
|
284
1023
|
? { resume_completed_at: input.resumeCompletedAt.trim() }
|
|
285
|
-
: existingThread?.resume_completed_at
|
|
1024
|
+
: existingThread?.resume_completed_at
|
|
1025
|
+
? { resume_completed_at: existingThread.resume_completed_at }
|
|
1026
|
+
: {}),
|
|
286
1027
|
...(input.resumeFailedAt?.trim()
|
|
287
1028
|
? { resume_failed_at: input.resumeFailedAt.trim() }
|
|
288
|
-
: existingThread?.resume_failed_at
|
|
1029
|
+
: existingThread?.resume_failed_at
|
|
1030
|
+
? { resume_failed_at: existingThread.resume_failed_at }
|
|
1031
|
+
: {}),
|
|
289
1032
|
...(input.resumeFailureReason?.trim()
|
|
290
1033
|
? { resume_failure_reason: input.resumeFailureReason.trim() }
|
|
291
|
-
: existingThread?.resume_failure_reason
|
|
1034
|
+
: existingThread?.resume_failure_reason
|
|
1035
|
+
? { resume_failure_reason: existingThread.resume_failure_reason }
|
|
1036
|
+
: {}),
|
|
292
1037
|
};
|
|
293
1038
|
const threads = {
|
|
294
1039
|
...existingSession.threads,
|
|
@@ -309,10 +1054,13 @@ export function recordSubagentTurn(state, input) {
|
|
|
309
1054
|
return normalized;
|
|
310
1055
|
}
|
|
311
1056
|
export async function recordSubagentTurnForSession(cwd, input) {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
1057
|
+
return withCrossProcessFileLockSync(subagentTrackingPath(cwd), (context) => {
|
|
1058
|
+
const current = readSubagentTrackingStateSync(cwd);
|
|
1059
|
+
const next = recordSubagentTurn(current, input);
|
|
1060
|
+
context.assertOwnership();
|
|
1061
|
+
writeSubagentTrackingStateSync(cwd, next, context.publish);
|
|
1062
|
+
return next;
|
|
1063
|
+
});
|
|
316
1064
|
}
|
|
317
1065
|
export function summarizeSubagentSession(state, sessionId, options = {}) {
|
|
318
1066
|
const normalized = normalizeSubagentTrackingState(state);
|
|
@@ -320,11 +1068,7 @@ export function summarizeSubagentSession(state, sessionId, options = {}) {
|
|
|
320
1068
|
if (!session)
|
|
321
1069
|
return null;
|
|
322
1070
|
const activeWindowMs = options.activeWindowMs ?? DEFAULT_SUBAGENT_ACTIVE_WINDOW_MS;
|
|
323
|
-
const nowMs = typeof options.now === 'string'
|
|
324
|
-
? Date.parse(options.now)
|
|
325
|
-
: options.now instanceof Date
|
|
326
|
-
? options.now.getTime()
|
|
327
|
-
: Date.now();
|
|
1071
|
+
const nowMs = typeof options.now === 'string' ? Date.parse(options.now) : options.now instanceof Date ? options.now.getTime() : Date.now();
|
|
328
1072
|
const allThreadIds = Object.keys(session.threads).sort();
|
|
329
1073
|
const allSubagentThreadIds = allThreadIds.filter((threadId) => isTrustedSubagentThread(session, threadId));
|
|
330
1074
|
const activeSubagentThreadIds = allSubagentThreadIds.filter((threadId) => {
|