oh-my-codex 0.12.4 → 0.12.6
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 +5 -5
- package/Cargo.toml +1 -1
- package/README.md +27 -3
- package/dist/cli/__tests__/ask.test.js +26 -0
- package/dist/cli/__tests__/ask.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +28 -0
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/explore.test.js +95 -8
- package/dist/cli/__tests__/explore.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +102 -4
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +169 -0
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +31 -0
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +66 -2
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +51 -1
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +148 -3
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +14 -1
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/cleanup.js +1 -1
- package/dist/cli/cleanup.js.map +1 -1
- package/dist/cli/constants.d.ts +1 -0
- package/dist/cli/constants.d.ts.map +1 -1
- package/dist/cli/constants.js +1 -0
- package/dist/cli/constants.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +15 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/explore.d.ts +1 -0
- package/dist/cli/explore.d.ts.map +1 -1
- package/dist/cli/explore.js +49 -1
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +2 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +127 -14
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-parity.d.ts +1 -1
- package/dist/cli/mcp-parity.d.ts.map +1 -1
- package/dist/cli/mcp-parity.js +24 -0
- package/dist/cli/mcp-parity.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +17 -5
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/team.d.ts.map +1 -1
- package/dist/cli/team.js +80 -6
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +1 -0
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +60 -0
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/mcp-registry.test.js +61 -0
- package/dist/config/__tests__/mcp-registry.test.js.map +1 -1
- package/dist/config/__tests__/wiki-config-contract.test.d.ts +2 -0
- package/dist/config/__tests__/wiki-config-contract.test.d.ts.map +1 -0
- package/dist/config/__tests__/wiki-config-contract.test.js +19 -0
- package/dist/config/__tests__/wiki-config-contract.test.js.map +1 -0
- package/dist/config/generator.d.ts +1 -0
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +88 -3
- package/dist/config/generator.js.map +1 -1
- package/dist/config/mcp-registry.d.ts +2 -0
- package/dist/config/mcp-registry.d.ts.map +1 -1
- package/dist/config/mcp-registry.js +12 -0
- package/dist/config/mcp-registry.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +39 -0
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +297 -4
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +392 -22
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +166 -67
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +112 -2
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-modules.test.js +52 -12
- package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-regression-205.test.d.ts +2 -3
- package/dist/hooks/__tests__/notify-hook-regression-205.test.d.ts.map +1 -1
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js +18 -23
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js +33 -0
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +176 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +355 -7
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +90 -2
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/session.test.js +142 -2
- package/dist/hooks/__tests__/session.test.js.map +1 -1
- package/dist/hooks/__tests__/wiki-docs-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/wiki-docs-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/wiki-docs-contract.test.js +34 -0
- package/dist/hooks/__tests__/wiki-docs-contract.test.js.map +1 -0
- package/dist/hooks/agents-overlay.d.ts.map +1 -1
- package/dist/hooks/agents-overlay.js +0 -1
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js +32 -0
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/runtime.test.js +31 -0
- package/dist/hooks/extensibility/__tests__/runtime.test.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/sdk.test.js +33 -3
- package/dist/hooks/extensibility/__tests__/sdk.test.js.map +1 -1
- package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
- package/dist/hooks/extensibility/dispatcher.js +41 -0
- package/dist/hooks/extensibility/dispatcher.js.map +1 -1
- package/dist/hooks/extensibility/sdk/runtime-state.d.ts.map +1 -1
- package/dist/hooks/extensibility/sdk/runtime-state.js +7 -1
- package/dist/hooks/extensibility/sdk/runtime-state.js.map +1 -1
- package/dist/hooks/extensibility/types.d.ts +1 -0
- package/dist/hooks/extensibility/types.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +6 -1
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +207 -10
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/keyword-registry.d.ts.map +1 -1
- package/dist/hooks/keyword-registry.js +3 -0
- package/dist/hooks/keyword-registry.js.map +1 -1
- package/dist/hooks/session.d.ts +14 -2
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +120 -16
- package/dist/hooks/session.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +111 -2
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +18 -21
- package/dist/hud/state.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js +88 -1
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js +3 -0
- package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
- package/dist/mcp/__tests__/state-paths.test.js +30 -2
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server.test.js +415 -0
- package/dist/mcp/__tests__/state-server.test.js.map +1 -1
- package/dist/mcp/__tests__/wiki-server.test.d.ts +2 -0
- package/dist/mcp/__tests__/wiki-server.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/wiki-server.test.js +30 -0
- package/dist/mcp/__tests__/wiki-server.test.js.map +1 -0
- package/dist/mcp/bootstrap.d.ts +19 -1
- package/dist/mcp/bootstrap.d.ts.map +1 -1
- package/dist/mcp/bootstrap.js +185 -0
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/state-paths.d.ts +5 -0
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +41 -11
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/mcp/state-server.d.ts +4 -4
- package/dist/mcp/state-server.d.ts.map +1 -1
- package/dist/mcp/state-server.js +49 -2
- package/dist/mcp/state-server.js.map +1 -1
- package/dist/mcp/wiki-server.d.ts +181 -0
- package/dist/mcp/wiki-server.d.ts.map +1 -0
- package/dist/mcp/wiki-server.js +235 -0
- package/dist/mcp/wiki-server.js.map +1 -0
- package/dist/modes/__tests__/base-autoresearch-contract.test.js +74 -2
- package/dist/modes/__tests__/base-autoresearch-contract.test.js.map +1 -1
- package/dist/modes/__tests__/base-multi-state-compat.test.d.ts +2 -0
- package/dist/modes/__tests__/base-multi-state-compat.test.d.ts.map +1 -0
- package/dist/modes/__tests__/base-multi-state-compat.test.js +38 -0
- package/dist/modes/__tests__/base-multi-state-compat.test.js.map +1 -0
- package/dist/modes/__tests__/base-tmux-pane.test.js +1 -1
- package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
- package/dist/modes/base.d.ts +2 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +55 -31
- package/dist/modes/base.js.map +1 -1
- package/dist/notifications/__tests__/formatter.test.js +11 -0
- package/dist/notifications/__tests__/formatter.test.js.map +1 -1
- package/dist/notifications/__tests__/idle-cooldown.test.js +32 -1
- package/dist/notifications/__tests__/idle-cooldown.test.js.map +1 -1
- package/dist/notifications/__tests__/index.test.d.ts +2 -0
- package/dist/notifications/__tests__/index.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/index.test.js +113 -0
- package/dist/notifications/__tests__/index.test.js.map +1 -0
- package/dist/notifications/__tests__/lifecycle-dedupe.test.d.ts +2 -0
- package/dist/notifications/__tests__/lifecycle-dedupe.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/lifecycle-dedupe.test.js +86 -0
- package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +1 -0
- package/dist/notifications/__tests__/reply-listener.test.js +174 -0
- package/dist/notifications/__tests__/reply-listener.test.js.map +1 -1
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.d.ts +2 -0
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js +93 -0
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js.map +1 -0
- package/dist/notifications/__tests__/session-registry.test.js +48 -1
- package/dist/notifications/__tests__/session-registry.test.js.map +1 -1
- package/dist/notifications/__tests__/session-status.test.d.ts +2 -0
- package/dist/notifications/__tests__/session-status.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/session-status.test.js +159 -0
- package/dist/notifications/__tests__/session-status.test.js.map +1 -0
- package/dist/notifications/__tests__/tmux.test.js +58 -1
- package/dist/notifications/__tests__/tmux.test.js.map +1 -1
- package/dist/notifications/idle-cooldown.d.ts +11 -0
- package/dist/notifications/idle-cooldown.d.ts.map +1 -1
- package/dist/notifications/idle-cooldown.js +42 -8
- package/dist/notifications/idle-cooldown.js.map +1 -1
- package/dist/notifications/index.d.ts +1 -1
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +41 -8
- package/dist/notifications/index.js.map +1 -1
- package/dist/notifications/lifecycle-dedupe.d.ts +8 -0
- package/dist/notifications/lifecycle-dedupe.d.ts.map +1 -0
- package/dist/notifications/lifecycle-dedupe.js +112 -0
- package/dist/notifications/lifecycle-dedupe.js.map +1 -0
- package/dist/notifications/reply-listener.d.ts +10 -1
- package/dist/notifications/reply-listener.d.ts.map +1 -1
- package/dist/notifications/reply-listener.js +49 -11
- package/dist/notifications/reply-listener.js.map +1 -1
- package/dist/notifications/session-registry.d.ts.map +1 -1
- package/dist/notifications/session-registry.js +7 -1
- package/dist/notifications/session-registry.js.map +1 -1
- package/dist/notifications/session-status.d.ts +23 -0
- package/dist/notifications/session-status.d.ts.map +1 -0
- package/dist/notifications/session-status.js +187 -0
- package/dist/notifications/session-status.js.map +1 -0
- package/dist/notifications/tmux.d.ts +10 -0
- package/dist/notifications/tmux.d.ts.map +1 -1
- package/dist/notifications/tmux.js +59 -5
- package/dist/notifications/tmux.js.map +1 -1
- package/dist/notifications/types.d.ts +2 -0
- package/dist/notifications/types.d.ts.map +1 -1
- package/dist/openclaw/__tests__/index.test.js +84 -0
- package/dist/openclaw/__tests__/index.test.js.map +1 -1
- package/dist/openclaw/index.d.ts.map +1 -1
- package/dist/openclaw/index.js +7 -14
- package/dist/openclaw/index.js.map +1 -1
- package/dist/openclaw/types.d.ts +2 -2
- package/dist/openclaw/types.d.ts.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +692 -40
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/hook-derived-watcher.test.d.ts +2 -0
- package/dist/scripts/__tests__/hook-derived-watcher.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/hook-derived-watcher.test.js +87 -0
- package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +1 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +309 -77
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/hook-derived-watcher.js +43 -1
- package/dist/scripts/hook-derived-watcher.js.map +1 -1
- package/dist/scripts/notify-fallback-watcher.js +95 -21
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/active-team.d.ts +9 -0
- package/dist/scripts/notify-hook/active-team.d.ts.map +1 -0
- package/dist/scripts/notify-hook/active-team.js +44 -0
- package/dist/scripts/notify-hook/active-team.js.map +1 -0
- package/dist/scripts/notify-hook/auto-nudge.d.ts +5 -3
- package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.js +121 -78
- package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.js +18 -4
- package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
- package/dist/scripts/notify-hook/operational-events.d.ts.map +1 -1
- package/dist/scripts/notify-hook/operational-events.js +21 -0
- package/dist/scripts/notify-hook/operational-events.js.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.js +3 -2
- package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
- package/dist/scripts/notify-hook/state-io.d.ts +10 -1
- package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
- package/dist/scripts/notify-hook/state-io.js +56 -12
- package/dist/scripts/notify-hook/state-io.js.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.js +305 -167
- package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.js +87 -15
- package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +11 -2
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook.js +26 -16
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/run-provider-advisor.js +20 -2
- package/dist/scripts/run-provider-advisor.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +1 -8
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +12 -68
- package/dist/scripts/smoke-packed-install.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +113 -0
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/skill-active.test.js +35 -0
- package/dist/state/__tests__/skill-active.test.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.d.ts +2 -0
- package/dist/state/__tests__/workflow-transition.test.d.ts.map +1 -0
- package/dist/state/__tests__/workflow-transition.test.js +56 -0
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -0
- package/dist/state/operations.d.ts +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +88 -2
- package/dist/state/operations.js.map +1 -1
- package/dist/state/skill-active.d.ts +2 -2
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +119 -33
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts +15 -0
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -0
- package/dist/state/workflow-transition-reconcile.js +100 -0
- package/dist/state/workflow-transition-reconcile.js.map +1 -0
- package/dist/state/workflow-transition.d.ts +22 -0
- package/dist/state/workflow-transition.d.ts.map +1 -0
- package/dist/state/workflow-transition.js +188 -0
- package/dist/state/workflow-transition.js.map +1 -0
- package/dist/team/__tests__/api-interop.test.js +90 -0
- package/dist/team/__tests__/api-interop.test.js.map +1 -1
- package/dist/team/__tests__/current-task-baseline.test.d.ts +2 -0
- package/dist/team/__tests__/current-task-baseline.test.d.ts.map +1 -0
- package/dist/team/__tests__/current-task-baseline.test.js +87 -0
- package/dist/team/__tests__/current-task-baseline.test.js.map +1 -0
- package/dist/team/__tests__/hardening-e2e.test.js +17 -0
- package/dist/team/__tests__/hardening-e2e.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +673 -65
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/shutdown-fallback.test.js +11 -1
- package/dist/team/__tests__/shutdown-fallback.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +447 -4
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/api-interop.d.ts.map +1 -1
- package/dist/team/api-interop.js +10 -1
- package/dist/team/api-interop.js.map +1 -1
- package/dist/team/current-task-baseline.d.ts +32 -0
- package/dist/team/current-task-baseline.d.ts.map +1 -0
- package/dist/team/current-task-baseline.js +85 -0
- package/dist/team/current-task-baseline.js.map +1 -0
- package/dist/team/delivery-log.d.ts +1 -1
- package/dist/team/delivery-log.d.ts.map +1 -1
- package/dist/team/delivery-log.js.map +1 -1
- package/dist/team/leader-activity.d.ts +1 -0
- package/dist/team/leader-activity.d.ts.map +1 -1
- package/dist/team/leader-activity.js +4 -2
- package/dist/team/leader-activity.js.map +1 -1
- package/dist/team/progress-evidence.d.ts +2 -0
- package/dist/team/progress-evidence.d.ts.map +1 -0
- package/dist/team/progress-evidence.js +77 -0
- package/dist/team/progress-evidence.js.map +1 -0
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +269 -64
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +1 -1
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +2 -13
- package/dist/team/state.js.map +1 -1
- package/dist/team/tmux-session.d.ts +12 -3
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +174 -20
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worktree.d.ts +6 -1
- package/dist/team/worktree.d.ts.map +1 -1
- package/dist/team/worktree.js +28 -4
- package/dist/team/worktree.js.map +1 -1
- package/dist/utils/__tests__/agents-md.test.js +21 -1
- package/dist/utils/__tests__/agents-md.test.js.map +1 -1
- package/dist/utils/__tests__/repo-deps.test.d.ts +2 -0
- package/dist/utils/__tests__/repo-deps.test.d.ts.map +1 -0
- package/dist/utils/__tests__/repo-deps.test.js +71 -0
- package/dist/utils/__tests__/repo-deps.test.js.map +1 -0
- package/dist/utils/agents-md.d.ts +1 -0
- package/dist/utils/agents-md.d.ts.map +1 -1
- package/dist/utils/agents-md.js +7 -3
- package/dist/utils/agents-md.js.map +1 -1
- package/dist/utils/paths.d.ts +4 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +20 -0
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/repo-deps.d.ts +20 -0
- package/dist/utils/repo-deps.d.ts.map +1 -0
- package/dist/utils/repo-deps.js +78 -0
- package/dist/utils/repo-deps.js.map +1 -0
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.d.ts +2 -0
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.d.ts.map +1 -0
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +54 -0
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -0
- package/dist/wiki/__tests__/cjk-tokenize.test.d.ts +12 -0
- package/dist/wiki/__tests__/cjk-tokenize.test.d.ts.map +1 -0
- package/dist/wiki/__tests__/cjk-tokenize.test.js +139 -0
- package/dist/wiki/__tests__/cjk-tokenize.test.js.map +1 -0
- package/dist/wiki/__tests__/crlf-parse.test.d.ts +2 -0
- package/dist/wiki/__tests__/crlf-parse.test.d.ts.map +1 -0
- package/dist/wiki/__tests__/crlf-parse.test.js +24 -0
- package/dist/wiki/__tests__/crlf-parse.test.js.map +1 -0
- package/dist/wiki/__tests__/escape-newline.test.d.ts +2 -0
- package/dist/wiki/__tests__/escape-newline.test.d.ts.map +1 -0
- package/dist/wiki/__tests__/escape-newline.test.js +45 -0
- package/dist/wiki/__tests__/escape-newline.test.js.map +1 -0
- package/dist/wiki/__tests__/ingest.test.d.ts +5 -0
- package/dist/wiki/__tests__/ingest.test.d.ts.map +1 -0
- package/dist/wiki/__tests__/ingest.test.js +181 -0
- package/dist/wiki/__tests__/ingest.test.js.map +1 -0
- package/dist/wiki/__tests__/lint.test.d.ts +5 -0
- package/dist/wiki/__tests__/lint.test.d.ts.map +1 -0
- package/dist/wiki/__tests__/lint.test.js +163 -0
- package/dist/wiki/__tests__/lint.test.js.map +1 -0
- package/dist/wiki/__tests__/query.test.d.ts +5 -0
- package/dist/wiki/__tests__/query.test.d.ts.map +1 -0
- package/dist/wiki/__tests__/query.test.js +141 -0
- package/dist/wiki/__tests__/query.test.js.map +1 -0
- package/dist/wiki/__tests__/reserved-file-guard.test.d.ts +2 -0
- package/dist/wiki/__tests__/reserved-file-guard.test.d.ts.map +1 -0
- package/dist/wiki/__tests__/reserved-file-guard.test.js +44 -0
- package/dist/wiki/__tests__/reserved-file-guard.test.js.map +1 -0
- package/dist/wiki/__tests__/session-hooks.test.d.ts +5 -0
- package/dist/wiki/__tests__/session-hooks.test.d.ts.map +1 -0
- package/dist/wiki/__tests__/session-hooks.test.js +36 -0
- package/dist/wiki/__tests__/session-hooks.test.js.map +1 -0
- package/dist/wiki/__tests__/slug-nonascii.test.d.ts +2 -0
- package/dist/wiki/__tests__/slug-nonascii.test.d.ts.map +1 -0
- package/dist/wiki/__tests__/slug-nonascii.test.js +24 -0
- package/dist/wiki/__tests__/slug-nonascii.test.js.map +1 -0
- package/dist/wiki/__tests__/storage.test.d.ts +5 -0
- package/dist/wiki/__tests__/storage.test.d.ts.map +1 -0
- package/dist/wiki/__tests__/storage.test.js +278 -0
- package/dist/wiki/__tests__/storage.test.js.map +1 -0
- package/dist/wiki/__tests__/test-helpers.d.ts +31 -0
- package/dist/wiki/__tests__/test-helpers.d.ts.map +1 -0
- package/dist/wiki/__tests__/test-helpers.js +108 -0
- package/dist/wiki/__tests__/test-helpers.js.map +1 -0
- package/dist/wiki/index.d.ts +14 -0
- package/dist/wiki/index.d.ts.map +1 -0
- package/dist/wiki/index.js +17 -0
- package/dist/wiki/index.js.map +1 -0
- package/dist/wiki/ingest.d.ts +20 -0
- package/dist/wiki/ingest.d.ts.map +1 -0
- package/dist/wiki/ingest.js +115 -0
- package/dist/wiki/ingest.js.map +1 -0
- package/dist/wiki/lifecycle.d.ts +20 -0
- package/dist/wiki/lifecycle.d.ts.map +1 -0
- package/dist/wiki/lifecycle.js +212 -0
- package/dist/wiki/lifecycle.js.map +1 -0
- package/dist/wiki/lint.d.ts +25 -0
- package/dist/wiki/lint.d.ts.map +1 -0
- package/dist/wiki/lint.js +166 -0
- package/dist/wiki/lint.js.map +1 -0
- package/dist/wiki/query.d.ts +36 -0
- package/dist/wiki/query.d.ts.map +1 -0
- package/dist/wiki/query.js +138 -0
- package/dist/wiki/query.js.map +1 -0
- package/dist/wiki/storage.d.ts +33 -0
- package/dist/wiki/storage.d.ts.map +1 -0
- package/dist/wiki/storage.js +321 -0
- package/dist/wiki/storage.js.map +1 -0
- package/dist/wiki/types.d.ts +83 -0
- package/dist/wiki/types.d.ts.map +1 -0
- package/dist/wiki/types.js +15 -0
- package/dist/wiki/types.js.map +1 -0
- package/package.json +3 -1
- package/skills/configure-notifications/SKILL.md +1 -0
- package/skills/doctor/SKILL.md +11 -0
- package/skills/omx-setup/SKILL.md +1 -1
- package/skills/wiki/SKILL.md +57 -0
- package/src/scripts/__tests__/codex-native-hook.test.ts +920 -56
- package/src/scripts/__tests__/hook-derived-watcher.test.ts +111 -0
- package/src/scripts/codex-native-hook.ts +377 -83
- package/src/scripts/hook-derived-watcher.ts +43 -1
- package/src/scripts/notify-fallback-watcher.ts +99 -20
- package/src/scripts/notify-hook/active-team.ts +54 -0
- package/src/scripts/notify-hook/auto-nudge.ts +132 -79
- package/src/scripts/notify-hook/managed-tmux.ts +22 -4
- package/src/scripts/notify-hook/operational-events.ts +21 -0
- package/src/scripts/notify-hook/ralph-session-resume.ts +3 -2
- package/src/scripts/notify-hook/state-io.ts +89 -12
- package/src/scripts/notify-hook/team-dispatch.ts +326 -168
- package/src/scripts/notify-hook/team-leader-nudge.ts +91 -14
- package/src/scripts/notify-hook/tmux-injection.ts +11 -2
- package/src/scripts/notify-hook.ts +36 -22
- package/src/scripts/run-provider-advisor.ts +20 -2
- package/src/scripts/smoke-packed-install.ts +16 -83
- package/templates/AGENTS.md +3 -4
|
@@ -19,6 +19,79 @@ async function withTempWorkingDir(run) {
|
|
|
19
19
|
async function writeJson(path, value) {
|
|
20
20
|
await writeFile(path, JSON.stringify(value, null, 2));
|
|
21
21
|
}
|
|
22
|
+
async function writeCanonicalTeamFixture(cwd, { teamName, sessionId, ownerSessionId, coarseState = 'missing', }) {
|
|
23
|
+
const stateDir = join(cwd, '.omx', 'state');
|
|
24
|
+
const teamDir = join(stateDir, 'team', teamName);
|
|
25
|
+
const workersDir = join(teamDir, 'workers');
|
|
26
|
+
const nowIso = new Date().toISOString();
|
|
27
|
+
await mkdir(join(cwd, '.omx', 'logs'), { recursive: true });
|
|
28
|
+
await mkdir(workersDir, { recursive: true });
|
|
29
|
+
await writeJson(join(stateDir, 'session.json'), { session_id: sessionId });
|
|
30
|
+
if (coarseState !== 'missing') {
|
|
31
|
+
await writeJson(join(stateDir, 'team-state.json'), {
|
|
32
|
+
active: coarseState === 'active',
|
|
33
|
+
team_name: teamName,
|
|
34
|
+
current_phase: 'team-exec',
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
await writeJson(join(stateDir, 'hud-state.json'), {
|
|
38
|
+
last_turn_at: nowIso,
|
|
39
|
+
turn_count: 1,
|
|
40
|
+
});
|
|
41
|
+
await writeJson(join(teamDir, 'manifest.v2.json'), {
|
|
42
|
+
schema_version: 2,
|
|
43
|
+
name: teamName,
|
|
44
|
+
task: 'canonical notify fallback repro',
|
|
45
|
+
leader: {
|
|
46
|
+
session_id: ownerSessionId,
|
|
47
|
+
worker_id: 'leader-fixed',
|
|
48
|
+
role: 'coordinator',
|
|
49
|
+
},
|
|
50
|
+
policy: {
|
|
51
|
+
worker_launch_mode: 'interactive',
|
|
52
|
+
display_mode: 'split_pane',
|
|
53
|
+
dispatch_mode: 'hook_preferred_with_fallback',
|
|
54
|
+
dispatch_ack_timeout_ms: 2000,
|
|
55
|
+
},
|
|
56
|
+
governance: {
|
|
57
|
+
delegation_only: false,
|
|
58
|
+
plan_approval_required: false,
|
|
59
|
+
nested_teams_allowed: false,
|
|
60
|
+
one_team_per_leader_session: true,
|
|
61
|
+
cleanup_requires_all_workers_inactive: true,
|
|
62
|
+
},
|
|
63
|
+
lifecycle_profile: 'default',
|
|
64
|
+
permissions_snapshot: {
|
|
65
|
+
approval_mode: 'never',
|
|
66
|
+
sandbox_mode: 'danger-full-access',
|
|
67
|
+
network_access: true,
|
|
68
|
+
},
|
|
69
|
+
tmux_session: `${teamName}:0`,
|
|
70
|
+
leader_pane_id: '%97',
|
|
71
|
+
hud_pane_id: null,
|
|
72
|
+
resize_hook_name: null,
|
|
73
|
+
resize_hook_target: null,
|
|
74
|
+
worker_count: 2,
|
|
75
|
+
next_task_id: 1,
|
|
76
|
+
workers: [
|
|
77
|
+
{ name: 'worker-1', index: 1, pane_id: '%1', role: 'executor' },
|
|
78
|
+
{ name: 'worker-2', index: 2, pane_id: '%2', role: 'executor' },
|
|
79
|
+
],
|
|
80
|
+
created_at: nowIso,
|
|
81
|
+
});
|
|
82
|
+
await writeJson(join(teamDir, 'phase.json'), {
|
|
83
|
+
current_phase: 'team-exec',
|
|
84
|
+
updated_at: nowIso,
|
|
85
|
+
transitions: [],
|
|
86
|
+
});
|
|
87
|
+
for (const worker of ['worker-1', 'worker-2']) {
|
|
88
|
+
await mkdir(join(workersDir, worker), { recursive: true });
|
|
89
|
+
await writeJson(join(workersDir, worker, 'status.json'), {
|
|
90
|
+
state: 'idle',
|
|
91
|
+
updated_at: nowIso,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
22
95
|
async function readTeamDeliveryLog(cwd) {
|
|
23
96
|
const path = join(cwd, '.omx', 'logs', `team-delivery-${new Date().toISOString().slice(0, 10)}.jsonl`);
|
|
24
97
|
const raw = await readFile(path, 'utf-8').catch(() => '');
|
|
@@ -139,7 +212,9 @@ describe('notify-hook leader-side authority handoff', () => {
|
|
|
139
212
|
});
|
|
140
213
|
await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
|
|
141
214
|
await chmod(fakeTmuxPath, 0o755);
|
|
142
|
-
const result = runNotifyHook(cwd, fakeBinDir
|
|
215
|
+
const result = runNotifyHook(cwd, fakeBinDir, {
|
|
216
|
+
OMX_SESSION_ID: 'sess-canonical-missing',
|
|
217
|
+
});
|
|
143
218
|
assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
|
|
144
219
|
const tmuxLog = await readFile(tmuxLogPath, 'utf-8').catch(() => '');
|
|
145
220
|
assert.match(tmuxLog, /send-keys/, 'current implementation nudges the leader directly in this stale-leader path');
|
|
@@ -161,7 +236,9 @@ describe('notify-hook leader-side authority handoff', () => {
|
|
|
161
236
|
worker_index: 1,
|
|
162
237
|
trigger_message: 'dispatch ping',
|
|
163
238
|
}, cwd);
|
|
164
|
-
const result = runNotifyHook(cwd, fakeBinDir
|
|
239
|
+
const result = runNotifyHook(cwd, fakeBinDir, {
|
|
240
|
+
OMX_SESSION_ID: 'sess-canonical-inactive',
|
|
241
|
+
});
|
|
165
242
|
assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
|
|
166
243
|
const request = await readDispatchRequest('handoff-dispatch', queued.request.request_id, cwd);
|
|
167
244
|
assert.equal(request?.status, 'failed');
|
|
@@ -211,7 +288,9 @@ describe('notify-hook leader-side authority handoff', () => {
|
|
|
211
288
|
});
|
|
212
289
|
await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%10 12345']));
|
|
213
290
|
await chmod(fakeTmuxPath, 0o755);
|
|
214
|
-
const result = runNotifyHook(cwd, fakeBinDir
|
|
291
|
+
const result = runNotifyHook(cwd, fakeBinDir, {
|
|
292
|
+
OMX_SESSION_ID: 'sess-current',
|
|
293
|
+
});
|
|
215
294
|
assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
|
|
216
295
|
if (existsSync(tmuxLogPath)) {
|
|
217
296
|
const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
|
|
@@ -261,7 +340,9 @@ describe('notify-hook team leader nudge', () => {
|
|
|
261
340
|
});
|
|
262
341
|
await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
|
|
263
342
|
await chmod(fakeTmuxPath, 0o755);
|
|
264
|
-
const result = runNotifyHook(cwd, fakeBinDir
|
|
343
|
+
const result = runNotifyHook(cwd, fakeBinDir, {
|
|
344
|
+
OMX_SESSION_ID: 'sess-canonical-missing',
|
|
345
|
+
});
|
|
265
346
|
assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
|
|
266
347
|
const tmuxLog = await readFile(tmuxLogPath, 'utf-8').catch(() => '');
|
|
267
348
|
assert.doesNotMatch(tmuxLog, /send-keys -t %97 -l Team deep-interview-suppressed:/);
|
|
@@ -311,7 +392,9 @@ describe('notify-hook team leader nudge', () => {
|
|
|
311
392
|
});
|
|
312
393
|
await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
|
|
313
394
|
await chmod(fakeTmuxPath, 0o755);
|
|
314
|
-
const result = runNotifyHook(cwd, fakeBinDir
|
|
395
|
+
const result = runNotifyHook(cwd, fakeBinDir, {
|
|
396
|
+
OMX_SESSION_ID: 'sess-canonical-inactive',
|
|
397
|
+
});
|
|
315
398
|
assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
|
|
316
399
|
const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
|
|
317
400
|
assert.match(tmuxLog, /send-keys/);
|
|
@@ -384,7 +467,9 @@ describe('notify-hook team leader nudge', () => {
|
|
|
384
467
|
}
|
|
385
468
|
await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%10 12345', '%11 12346']));
|
|
386
469
|
await chmod(fakeTmuxPath, 0o755);
|
|
387
|
-
const result = runNotifyHook(cwd, fakeBinDir
|
|
470
|
+
const result = runNotifyHook(cwd, fakeBinDir, {
|
|
471
|
+
OMX_SESSION_ID: 'sess-canonical-missing',
|
|
472
|
+
});
|
|
388
473
|
assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
|
|
389
474
|
const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
|
|
390
475
|
assert.match(tmuxLog, /\[OMX\] All 2 workers idle\./);
|
|
@@ -444,7 +529,9 @@ describe('notify-hook team leader nudge', () => {
|
|
|
444
529
|
}
|
|
445
530
|
await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%10 12345', '%11 12346']));
|
|
446
531
|
await chmod(fakeTmuxPath, 0o755);
|
|
447
|
-
const result = runNotifyHook(cwd, fakeBinDir
|
|
532
|
+
const result = runNotifyHook(cwd, fakeBinDir, {
|
|
533
|
+
OMX_SESSION_ID: 'sess-canonical-inactive',
|
|
534
|
+
});
|
|
448
535
|
assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
|
|
449
536
|
const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
|
|
450
537
|
assert.match(tmuxLog, /\[OMX\] All 2 workers idle/);
|
|
@@ -566,6 +653,53 @@ describe('notify-hook team leader nudge', () => {
|
|
|
566
653
|
assert.match(tmuxLog, /\[OMX\] All 2 workers idle/, 'global team-state fallback should still fire idle nudge');
|
|
567
654
|
});
|
|
568
655
|
});
|
|
656
|
+
it('falls back to canonical team state when coarse team-state is missing', async () => {
|
|
657
|
+
await withTempWorkingDir(async (cwd) => {
|
|
658
|
+
const fakeBinDir = join(cwd, 'fake-bin');
|
|
659
|
+
const fakeTmuxPath = join(fakeBinDir, 'tmux');
|
|
660
|
+
const tmuxLogPath = join(cwd, 'tmux.log');
|
|
661
|
+
await mkdir(fakeBinDir, { recursive: true });
|
|
662
|
+
await writeCanonicalTeamFixture(cwd, {
|
|
663
|
+
teamName: 'canonical-missing',
|
|
664
|
+
sessionId: 'sess-canonical-missing',
|
|
665
|
+
ownerSessionId: 'sess-canonical-missing',
|
|
666
|
+
});
|
|
667
|
+
await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
|
|
668
|
+
await chmod(fakeTmuxPath, 0o755);
|
|
669
|
+
const result = runNotifyHook(cwd, fakeBinDir, {
|
|
670
|
+
OMX_SESSION_ID: 'sess-canonical-missing',
|
|
671
|
+
});
|
|
672
|
+
assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
|
|
673
|
+
const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
|
|
674
|
+
assert.match(tmuxLog, /send-keys/);
|
|
675
|
+
assert.match(tmuxLog, /-t %97/, 'should target canonical leader pane');
|
|
676
|
+
assert.match(tmuxLog, /\[OMX\] All 2 workers idle/, 'canonical fallback should still fire idle nudge');
|
|
677
|
+
});
|
|
678
|
+
});
|
|
679
|
+
it('falls back to canonical team state when coarse team-state is inactive', async () => {
|
|
680
|
+
await withTempWorkingDir(async (cwd) => {
|
|
681
|
+
const fakeBinDir = join(cwd, 'fake-bin');
|
|
682
|
+
const fakeTmuxPath = join(fakeBinDir, 'tmux');
|
|
683
|
+
const tmuxLogPath = join(cwd, 'tmux.log');
|
|
684
|
+
await mkdir(fakeBinDir, { recursive: true });
|
|
685
|
+
await writeCanonicalTeamFixture(cwd, {
|
|
686
|
+
teamName: 'canonical-inactive',
|
|
687
|
+
sessionId: 'sess-canonical-inactive',
|
|
688
|
+
ownerSessionId: 'sess-canonical-inactive',
|
|
689
|
+
coarseState: 'inactive',
|
|
690
|
+
});
|
|
691
|
+
await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
|
|
692
|
+
await chmod(fakeTmuxPath, 0o755);
|
|
693
|
+
const result = runNotifyHook(cwd, fakeBinDir, {
|
|
694
|
+
OMX_SESSION_ID: 'sess-canonical-inactive',
|
|
695
|
+
});
|
|
696
|
+
assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
|
|
697
|
+
const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
|
|
698
|
+
assert.match(tmuxLog, /send-keys/);
|
|
699
|
+
assert.match(tmuxLog, /-t %97/, 'should still target canonical leader pane');
|
|
700
|
+
assert.match(tmuxLog, /\[OMX\] All 2 workers idle/, 'inactive coarse state should still fall back canonically');
|
|
701
|
+
});
|
|
702
|
+
});
|
|
569
703
|
it('nudges leader via tmux send-keys when team is active and mailbox has messages', async () => {
|
|
570
704
|
await withTempWorkingDir(async (cwd) => {
|
|
571
705
|
const omxDir = join(cwd, '.omx');
|
|
@@ -1158,6 +1292,103 @@ exit 0
|
|
|
1158
1292
|
}
|
|
1159
1293
|
});
|
|
1160
1294
|
});
|
|
1295
|
+
it('suppresses duplicate visible leader injection when the pane already shows the same classified state', async () => {
|
|
1296
|
+
await withTempWorkingDir(async (cwd) => {
|
|
1297
|
+
const omxDir = join(cwd, '.omx');
|
|
1298
|
+
const stateDir = join(omxDir, 'state');
|
|
1299
|
+
const logsDir = join(omxDir, 'logs');
|
|
1300
|
+
const teamName = 'same-classified-state';
|
|
1301
|
+
const teamDir = join(stateDir, 'team', teamName);
|
|
1302
|
+
const mailboxDir = join(teamDir, 'mailbox');
|
|
1303
|
+
const fakeBinDir = join(cwd, 'fake-bin');
|
|
1304
|
+
const fakeTmuxPath = join(fakeBinDir, 'tmux');
|
|
1305
|
+
const tmuxLogPath = join(cwd, 'tmux.log');
|
|
1306
|
+
await mkdir(logsDir, { recursive: true });
|
|
1307
|
+
await mkdir(mailboxDir, { recursive: true });
|
|
1308
|
+
await mkdir(fakeBinDir, { recursive: true });
|
|
1309
|
+
await writeJson(join(stateDir, 'team-state.json'), {
|
|
1310
|
+
active: true,
|
|
1311
|
+
team_name: teamName,
|
|
1312
|
+
current_phase: 'team-exec',
|
|
1313
|
+
});
|
|
1314
|
+
await writeJson(join(teamDir, 'config.json'), {
|
|
1315
|
+
name: teamName,
|
|
1316
|
+
tmux_session: 'same-classified-state:0',
|
|
1317
|
+
leader_pane_id: '%75',
|
|
1318
|
+
});
|
|
1319
|
+
await writeJson(join(mailboxDir, 'leader-fixed.json'), {
|
|
1320
|
+
worker: 'leader-fixed',
|
|
1321
|
+
messages: [
|
|
1322
|
+
{
|
|
1323
|
+
message_id: 'same-classified-msg',
|
|
1324
|
+
from_worker: 'worker-1',
|
|
1325
|
+
to_worker: 'leader-fixed',
|
|
1326
|
+
body: 'please review latest output',
|
|
1327
|
+
created_at: '2026-03-12T00:00:00.000Z',
|
|
1328
|
+
},
|
|
1329
|
+
],
|
|
1330
|
+
});
|
|
1331
|
+
const fakeTmux = `#!/usr/bin/env bash
|
|
1332
|
+
set -eu
|
|
1333
|
+
echo "$@" >> "${tmuxLogPath}"
|
|
1334
|
+
cmd="$1"
|
|
1335
|
+
shift || true
|
|
1336
|
+
if [[ "$cmd" == "display-message" ]]; then
|
|
1337
|
+
target=""
|
|
1338
|
+
format=""
|
|
1339
|
+
while (($#)); do
|
|
1340
|
+
case "$1" in
|
|
1341
|
+
-p) shift ;;
|
|
1342
|
+
-t) target="$2"; shift 2 ;;
|
|
1343
|
+
*) format="$1"; shift ;;
|
|
1344
|
+
esac
|
|
1345
|
+
done
|
|
1346
|
+
if [[ "$format" == "#{pane_in_mode}" && "$target" == "%75" ]]; then
|
|
1347
|
+
echo "0"
|
|
1348
|
+
exit 0
|
|
1349
|
+
fi
|
|
1350
|
+
if [[ "$format" == "#{pane_current_command}" && "$target" == "%75" ]]; then
|
|
1351
|
+
echo "codex"
|
|
1352
|
+
exit 0
|
|
1353
|
+
fi
|
|
1354
|
+
exit 0
|
|
1355
|
+
fi
|
|
1356
|
+
if [[ "$cmd" == "capture-pane" ]]; then
|
|
1357
|
+
cat <<'EOF'
|
|
1358
|
+
Team same-classified-state: 1 msg(s) for leader. Next: read messages; keep orchestrating; if done, gracefully shut down: omx team shutdown same-classified-state.
|
|
1359
|
+
EOF
|
|
1360
|
+
exit 0
|
|
1361
|
+
fi
|
|
1362
|
+
if [[ "$cmd" == "send-keys" ]]; then
|
|
1363
|
+
exit 0
|
|
1364
|
+
fi
|
|
1365
|
+
if [[ "$cmd" == "list-panes" ]]; then
|
|
1366
|
+
echo "%1 12345"
|
|
1367
|
+
exit 0
|
|
1368
|
+
fi
|
|
1369
|
+
exit 0
|
|
1370
|
+
`;
|
|
1371
|
+
await writeFile(fakeTmuxPath, fakeTmux);
|
|
1372
|
+
await chmod(fakeTmuxPath, 0o755);
|
|
1373
|
+
const result = runNotifyHook(cwd, fakeBinDir);
|
|
1374
|
+
assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
|
|
1375
|
+
const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
|
|
1376
|
+
assert.match(tmuxLog, /capture-pane -t %75 -p -S -80/);
|
|
1377
|
+
assert.doesNotMatch(tmuxLog, /send-keys -t %75 -l Team same-classified-state: 1 msg\(s\) for leader\./, 'same visible classified state should not be reinjected');
|
|
1378
|
+
const eventsPath = join(teamDir, 'events', 'events.ndjson');
|
|
1379
|
+
const events = (await readFile(eventsPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
|
|
1380
|
+
const nudgeEvent = events.find((entry) => entry.type === 'team_leader_nudge' && entry.reason === 'new_mailbox_message');
|
|
1381
|
+
assert.ok(nudgeEvent, 'suppressed visible sends should still emit leader nudge events');
|
|
1382
|
+
assert.equal(nudgeEvent.orchestration_intent, 'pending-mailbox-review');
|
|
1383
|
+
const deliveryLog = await readTeamDeliveryLog(cwd);
|
|
1384
|
+
assert.ok(deliveryLog.some((entry) => entry.event === 'nudge_triggered'
|
|
1385
|
+
&& entry.team === teamName
|
|
1386
|
+
&& entry.to_worker === 'leader-fixed'
|
|
1387
|
+
&& entry.result === 'suppressed'
|
|
1388
|
+
&& entry.reason === 'new_mailbox_message'
|
|
1389
|
+
&& entry.suppression_reason === 'pane_already_shows_same_classified_state'));
|
|
1390
|
+
});
|
|
1391
|
+
});
|
|
1161
1392
|
it('does not inject leader nudge while leader pane is in copy-mode', async () => {
|
|
1162
1393
|
await withTempWorkingDir(async (cwd) => {
|
|
1163
1394
|
const omxDir = join(cwd, '.omx');
|
|
@@ -1394,6 +1625,27 @@ exit 0
|
|
|
1394
1625
|
}
|
|
1395
1626
|
});
|
|
1396
1627
|
});
|
|
1628
|
+
it('does not nudge a canonical-only team when owner session is blank', async () => {
|
|
1629
|
+
await withTempWorkingDir(async (cwd) => {
|
|
1630
|
+
const fakeBinDir = join(cwd, 'fake-bin');
|
|
1631
|
+
const fakeTmuxPath = join(fakeBinDir, 'tmux');
|
|
1632
|
+
const tmuxLogPath = join(cwd, 'tmux.log');
|
|
1633
|
+
await mkdir(fakeBinDir, { recursive: true });
|
|
1634
|
+
await writeCanonicalTeamFixture(cwd, {
|
|
1635
|
+
teamName: 'ownerless-team',
|
|
1636
|
+
sessionId: 'sess-current',
|
|
1637
|
+
ownerSessionId: '',
|
|
1638
|
+
});
|
|
1639
|
+
await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
|
|
1640
|
+
await chmod(fakeTmuxPath, 0o755);
|
|
1641
|
+
const result = runNotifyHook(cwd, fakeBinDir);
|
|
1642
|
+
assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
|
|
1643
|
+
if (existsSync(tmuxLogPath)) {
|
|
1644
|
+
const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
|
|
1645
|
+
assert.doesNotMatch(tmuxLog, /send-keys/, 'ownerless canonical teams must not nudge');
|
|
1646
|
+
}
|
|
1647
|
+
});
|
|
1648
|
+
});
|
|
1397
1649
|
it('nudges when worker panes are alive and leader is stale (no recent HUD turn)', async () => {
|
|
1398
1650
|
await withTempWorkingDir(async (cwd) => {
|
|
1399
1651
|
const omxDir = join(cwd, '.omx');
|
|
@@ -2130,6 +2382,102 @@ exit 0
|
|
|
2130
2382
|
assert.match(finalLog, /Team stale-cadence: leader stale, \d+ worker pane\(s\) still active\./);
|
|
2131
2383
|
});
|
|
2132
2384
|
});
|
|
2385
|
+
it('suppresses stale leader follow-up when detached worktree progress is still fresh', async () => {
|
|
2386
|
+
await withTempWorkingDir(async (cwd) => {
|
|
2387
|
+
const omxDir = join(cwd, '.omx');
|
|
2388
|
+
const stateDir = join(omxDir, 'state');
|
|
2389
|
+
const logsDir = join(omxDir, 'logs');
|
|
2390
|
+
const teamName = 'fresh-detached-progress';
|
|
2391
|
+
const teamDir = join(stateDir, 'team', teamName);
|
|
2392
|
+
const workersDir = join(teamDir, 'workers');
|
|
2393
|
+
const tasksDir = join(teamDir, 'tasks');
|
|
2394
|
+
const workerWorktree = join(cwd, 'worktrees', 'worker-1');
|
|
2395
|
+
const fakeBinDir = join(cwd, 'fake-bin');
|
|
2396
|
+
const fakeTmuxPath = join(fakeBinDir, 'tmux');
|
|
2397
|
+
const tmuxLogPath = join(cwd, 'tmux.log');
|
|
2398
|
+
await mkdir(logsDir, { recursive: true });
|
|
2399
|
+
await mkdir(tasksDir, { recursive: true });
|
|
2400
|
+
await mkdir(join(workersDir, 'worker-1'), { recursive: true });
|
|
2401
|
+
await mkdir(join(workerWorktree, '.omx', 'state'), { recursive: true });
|
|
2402
|
+
await mkdir(fakeBinDir, { recursive: true });
|
|
2403
|
+
await writeJson(join(stateDir, 'team-state.json'), {
|
|
2404
|
+
active: true,
|
|
2405
|
+
team_name: teamName,
|
|
2406
|
+
current_phase: 'team-exec',
|
|
2407
|
+
});
|
|
2408
|
+
await writeJson(join(teamDir, 'config.json'), {
|
|
2409
|
+
name: teamName,
|
|
2410
|
+
tmux_session: 'omx-team-fresh-detached-progress',
|
|
2411
|
+
leader_pane_id: '%99',
|
|
2412
|
+
workers: [
|
|
2413
|
+
{ name: 'worker-1', index: 1, pane_id: '%10', worktree_path: workerWorktree },
|
|
2414
|
+
],
|
|
2415
|
+
});
|
|
2416
|
+
await writeJson(join(stateDir, 'hud-state.json'), {
|
|
2417
|
+
last_turn_at: new Date(Date.now() - 300_000).toISOString(),
|
|
2418
|
+
turn_count: 5,
|
|
2419
|
+
});
|
|
2420
|
+
await writeJson(join(tasksDir, 'task-1.json'), {
|
|
2421
|
+
id: '1',
|
|
2422
|
+
subject: 'Apply detached fix',
|
|
2423
|
+
description: 'keep going',
|
|
2424
|
+
status: 'in_progress',
|
|
2425
|
+
owner: 'worker-1',
|
|
2426
|
+
created_at: new Date(Date.now() - 300_000).toISOString(),
|
|
2427
|
+
});
|
|
2428
|
+
await writeJson(join(workersDir, 'worker-1', 'status.json'), {
|
|
2429
|
+
state: 'working',
|
|
2430
|
+
current_task_id: '1',
|
|
2431
|
+
updated_at: new Date(Date.now() - 300_000).toISOString(),
|
|
2432
|
+
});
|
|
2433
|
+
await writeJson(join(workersDir, 'worker-1', 'heartbeat.json'), {
|
|
2434
|
+
last_turn_at: new Date(Date.now() - 300_000).toISOString(),
|
|
2435
|
+
turn_count: 2,
|
|
2436
|
+
alive: true,
|
|
2437
|
+
});
|
|
2438
|
+
await writeJson(join(stateDir, 'team-leader-nudge.json'), {
|
|
2439
|
+
last_nudged_by_team: {
|
|
2440
|
+
[teamName]: {
|
|
2441
|
+
at: new Date(Date.now() - 60_000).toISOString(),
|
|
2442
|
+
last_message_id: '',
|
|
2443
|
+
reason: 'stale_leader_panes_alive',
|
|
2444
|
+
},
|
|
2445
|
+
},
|
|
2446
|
+
progress_by_team: {
|
|
2447
|
+
[teamName]: {
|
|
2448
|
+
signature: JSON.stringify({
|
|
2449
|
+
tasks: [{ id: '1', owner: 'worker-1', status: 'in_progress' }],
|
|
2450
|
+
workers: [{
|
|
2451
|
+
worker: 'worker-1',
|
|
2452
|
+
state: 'working',
|
|
2453
|
+
current_task_id: '1',
|
|
2454
|
+
status_missing: false,
|
|
2455
|
+
turn_count: 2,
|
|
2456
|
+
heartbeat_missing: false,
|
|
2457
|
+
}],
|
|
2458
|
+
}),
|
|
2459
|
+
last_progress_at: new Date(Date.now() - 300_000).toISOString(),
|
|
2460
|
+
},
|
|
2461
|
+
},
|
|
2462
|
+
});
|
|
2463
|
+
await writeJson(join(workerWorktree, '.omx', 'state', 'current-task-baseline.json'), {
|
|
2464
|
+
version: 1,
|
|
2465
|
+
tasks: [],
|
|
2466
|
+
});
|
|
2467
|
+
await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%10 12345']));
|
|
2468
|
+
await chmod(fakeTmuxPath, 0o755);
|
|
2469
|
+
const result = runNotifyHook(cwd, fakeBinDir, {
|
|
2470
|
+
OMX_TEAM_PROGRESS_STALL_MS: '60000',
|
|
2471
|
+
OMX_TEAM_LEADER_NUDGE_MS: '30000',
|
|
2472
|
+
OMX_TEAM_LEADER_STALE_MS: '60000',
|
|
2473
|
+
});
|
|
2474
|
+
assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
|
|
2475
|
+
if (existsSync(tmuxLogPath)) {
|
|
2476
|
+
const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
|
|
2477
|
+
assert.doesNotMatch(tmuxLog, /Team fresh-detached-progress: leader stale,/);
|
|
2478
|
+
}
|
|
2479
|
+
});
|
|
2480
|
+
});
|
|
2133
2481
|
it('emits team_leader_nudge event to events.ndjson when nudge fires', async () => {
|
|
2134
2482
|
await withTempWorkingDir(async (cwd) => {
|
|
2135
2483
|
const omxDir = join(cwd, '.omx');
|