oh-my-codex 0.12.5 → 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 +17 -0
- package/dist/cli/__tests__/ask.test.js +26 -0
- package/dist/cli/__tests__/ask.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 +58 -0
- 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 +11 -1
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +92 -0
- 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/explore.d.ts +1 -0
- package/dist/cli/explore.d.ts.map +1 -1
- package/dist/cli/explore.js +45 -1
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +103 -10
- 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 +2 -2
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/team.d.ts.map +1 -1
- package/dist/cli/team.js +54 -14
- 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 +1 -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.map +1 -1
- package/dist/config/generator.js +8 -0
- 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 +18 -0
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +75 -0
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +140 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +35 -0
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +86 -2
- package/dist/hooks/__tests__/notify-hook-managed-tmux.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 +193 -0
- 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 +41 -1
- 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__/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/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +42 -5
- 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.map +1 -1
- package/dist/hooks/session.js +26 -4
- package/dist/hooks/session.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +27 -0
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +3 -1
- package/dist/hud/state.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js +65 -1
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server.test.js +31 -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 +18 -1
- package/dist/mcp/bootstrap.d.ts.map +1 -1
- package/dist/mcp/bootstrap.js +158 -0
- package/dist/mcp/bootstrap.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 +27 -22
- 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 +22 -1
- package/dist/modes/__tests__/base-autoresearch-contract.test.js.map +1 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +10 -0
- 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 +155 -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 +2 -0
- package/dist/notifications/reply-listener.d.ts.map +1 -1
- package/dist/notifications/reply-listener.js +42 -6
- 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 +270 -1
- 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 +134 -6
- 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 +27 -2
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.js +17 -1
- 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 +5 -3
- package/dist/scripts/notify-hook/managed-tmux.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 +79 -3
- 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 +2 -1
- package/dist/scripts/notify-hook/tmux-injection.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/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 +1 -1
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +1 -0
- package/dist/state/skill-active.js.map +1 -1
- 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__/hardening-e2e.test.js +17 -0
- package/dist/team/__tests__/hardening-e2e.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +23 -0
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +210 -0
- 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/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 +44 -0
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +57 -8
- 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 +4 -2
- 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 +378 -0
- package/src/scripts/__tests__/hook-derived-watcher.test.ts +111 -0
- package/src/scripts/codex-native-hook.ts +187 -7
- package/src/scripts/hook-derived-watcher.ts +43 -1
- package/src/scripts/notify-fallback-watcher.ts +26 -2
- package/src/scripts/notify-hook/auto-nudge.ts +19 -1
- package/src/scripts/notify-hook/managed-tmux.ts +8 -3
- package/src/scripts/notify-hook/team-dispatch.ts +326 -168
- package/src/scripts/notify-hook/team-leader-nudge.ts +82 -3
- package/src/scripts/notify-hook/tmux-injection.ts +2 -1
- package/src/scripts/run-provider-advisor.ts +20 -2
- package/src/scripts/smoke-packed-install.ts +16 -83
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
import type { HookEventEnvelope } from "../hooks/extensibility/types.js";
|
|
44
44
|
import { dispatchHookEvent } from "../hooks/extensibility/dispatcher.js";
|
|
45
45
|
import { reconcileHudForPromptSubmit } from "../hud/reconcile.js";
|
|
46
|
+
import { onSessionStart as buildWikiSessionStartContext } from "../wiki/lifecycle.js";
|
|
46
47
|
|
|
47
48
|
type CodexHookEventName =
|
|
48
49
|
| "SessionStart"
|
|
@@ -70,6 +71,14 @@ const TERMINAL_MODE_PHASES = new Set(["complete", "failed", "cancelled"]);
|
|
|
70
71
|
const SKILL_STOP_BLOCKERS = new Set(["ralplan"]);
|
|
71
72
|
const TEAM_TERMINAL_TASK_STATUSES = new Set(["completed", "failed"]);
|
|
72
73
|
const NATIVE_STOP_STATE_FILE = "native-stop-state.json";
|
|
74
|
+
const STABLE_FINAL_RECOMMENDATION_PATTERNS = [
|
|
75
|
+
/^\s*(?:launch|release|ship)-?ready\s*:\s*(?:yes|no)\b[^\n\r]*/im,
|
|
76
|
+
/^\s*ready to release\s*:\s*(?:yes|no)\b[^\n\r]*/im,
|
|
77
|
+
/^\s*(?:final\s+)?recommendation\s*:\s*(?:yes|no|ship|hold|release|do not release|proceed|do not proceed)\b[^\n\r]*/im,
|
|
78
|
+
/^\s*decision\s*:\s*(?:yes|no|ship|hold|release|do not release|proceed|do not proceed)\b[^\n\r]*/im,
|
|
79
|
+
] as const;
|
|
80
|
+
const RELEASE_READINESS_FINALIZE_SYSTEM_MESSAGE =
|
|
81
|
+
"OMX release-readiness detected a stable final recommendation with no active worker tasks; emit one concise final decision summary and finalize.";
|
|
73
82
|
|
|
74
83
|
function safeString(value: unknown): string {
|
|
75
84
|
return typeof value === "string" ? value : "";
|
|
@@ -141,6 +150,21 @@ function readPromptText(payload: CodexHookPayload): string {
|
|
|
141
150
|
return "";
|
|
142
151
|
}
|
|
143
152
|
|
|
153
|
+
function sanitizePayloadForHookContext(
|
|
154
|
+
payload: CodexHookPayload,
|
|
155
|
+
hookEventName: CodexHookEventName,
|
|
156
|
+
): CodexHookPayload {
|
|
157
|
+
if (hookEventName !== "UserPromptSubmit") return payload;
|
|
158
|
+
|
|
159
|
+
const sanitized = { ...payload };
|
|
160
|
+
delete sanitized.prompt;
|
|
161
|
+
delete sanitized.input;
|
|
162
|
+
delete sanitized.user_prompt;
|
|
163
|
+
delete sanitized.userPrompt;
|
|
164
|
+
delete sanitized.text;
|
|
165
|
+
return sanitized;
|
|
166
|
+
}
|
|
167
|
+
|
|
144
168
|
function buildBaseContext(
|
|
145
169
|
cwd: string,
|
|
146
170
|
payload: CodexHookPayload,
|
|
@@ -151,10 +175,7 @@ function buildBaseContext(
|
|
|
151
175
|
project_path: cwd,
|
|
152
176
|
transcript_path: safeString(payload.transcript_path ?? payload.transcriptPath) || null,
|
|
153
177
|
source: safeString(payload.source),
|
|
154
|
-
payload,
|
|
155
|
-
...(hookEventName === "UserPromptSubmit"
|
|
156
|
-
? { prompt: readPromptText(payload) }
|
|
157
|
-
: {}),
|
|
178
|
+
payload: sanitizePayloadForHookContext(payload, hookEventName),
|
|
158
179
|
};
|
|
159
180
|
}
|
|
160
181
|
|
|
@@ -426,6 +447,11 @@ async function buildSessionStartContext(
|
|
|
426
447
|
}
|
|
427
448
|
}
|
|
428
449
|
|
|
450
|
+
const wikiContext = buildWikiSessionStartContext({ cwd });
|
|
451
|
+
if (wikiContext.additionalContext) {
|
|
452
|
+
sections.push(wikiContext.additionalContext);
|
|
453
|
+
}
|
|
454
|
+
|
|
429
455
|
const subagentSummary = await readSubagentSessionSummary(cwd, sessionId).catch(() => null);
|
|
430
456
|
if (subagentSummary && subagentSummary.activeSubagentThreadIds.length > 0) {
|
|
431
457
|
sections.push(`[Subagents]\n- active subagent threads: ${subagentSummary.activeSubagentThreadIds.length}`);
|
|
@@ -676,6 +702,12 @@ async function buildTeamStopOutput(cwd: string, sessionId?: string): Promise<Rec
|
|
|
676
702
|
const teamState = await readTeamModeStateForStop(cwd, sessionId);
|
|
677
703
|
if (teamState?.active !== true) return null;
|
|
678
704
|
const teamName = safeString(teamState.team_name).trim();
|
|
705
|
+
if (teamName) {
|
|
706
|
+
const canonicalTeamDir = join(resolveCanonicalTeamStateRoot(cwd), "team", teamName);
|
|
707
|
+
if (!existsSync(canonicalTeamDir)) {
|
|
708
|
+
return null;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
679
711
|
const coarsePhase = teamState.current_phase;
|
|
680
712
|
const canonicalPhase = teamName ? (await readTeamPhase(teamName, cwd))?.current_phase ?? coarsePhase : coarsePhase;
|
|
681
713
|
if (!isNonTerminalPhase(canonicalPhase)) return null;
|
|
@@ -696,6 +728,54 @@ function buildTeamStopOutputForPhase(teamName: string, phase: string): Record<st
|
|
|
696
728
|
};
|
|
697
729
|
}
|
|
698
730
|
|
|
731
|
+
function extractStableFinalRecommendationSummary(message: string): string {
|
|
732
|
+
for (const pattern of STABLE_FINAL_RECOMMENDATION_PATTERNS) {
|
|
733
|
+
const match = pattern.exec(message);
|
|
734
|
+
if (!match) continue;
|
|
735
|
+
const summary = match[0]?.trim().replace(/\s+/g, " ");
|
|
736
|
+
if (!summary) continue;
|
|
737
|
+
return /[.!?]$/.test(summary) ? summary : `${summary}.`;
|
|
738
|
+
}
|
|
739
|
+
return "";
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
function buildStableFinalRecommendationStopSignature(
|
|
743
|
+
payload: CodexHookPayload,
|
|
744
|
+
teamName: string,
|
|
745
|
+
summary: string,
|
|
746
|
+
): string {
|
|
747
|
+
const sessionId = readPayloadSessionId(payload) || "no-session";
|
|
748
|
+
const threadId = readPayloadThreadId(payload) || "no-thread";
|
|
749
|
+
const normalizedSummary = normalizeAutoNudgeSignatureText(summary) || summary.toLowerCase();
|
|
750
|
+
return ["release-readiness-finalize", sessionId, threadId, teamName, normalizedSummary].join("|");
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
function hasReleaseReadinessMode(payload: CodexHookPayload): boolean {
|
|
754
|
+
const mode = safeString(payload.mode).trim().toLowerCase();
|
|
755
|
+
return mode === "release-readiness";
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
async function hasReleaseReadinessStopMarker(
|
|
759
|
+
cwd: string,
|
|
760
|
+
sessionId: string,
|
|
761
|
+
teamName: string,
|
|
762
|
+
): Promise<boolean> {
|
|
763
|
+
if (!sessionId) return false;
|
|
764
|
+
|
|
765
|
+
const markerState = await readStopSessionPinnedState("release-readiness-state.json", cwd, sessionId);
|
|
766
|
+
if (markerState?.active !== true || markerState.stable_final_recommendation_emitted !== true) {
|
|
767
|
+
return false;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
const markerTeamName = safeString(markerState.team_name).trim();
|
|
771
|
+
if (markerTeamName && markerTeamName !== teamName) return false;
|
|
772
|
+
|
|
773
|
+
const markerSessionId = safeString(markerState.session_id).trim();
|
|
774
|
+
if (markerSessionId && markerSessionId !== sessionId) return false;
|
|
775
|
+
|
|
776
|
+
return true;
|
|
777
|
+
}
|
|
778
|
+
|
|
699
779
|
function readPayloadSessionId(payload: CodexHookPayload): string {
|
|
700
780
|
return safeString(payload.session_id ?? payload.sessionId).trim();
|
|
701
781
|
}
|
|
@@ -935,6 +1015,66 @@ async function findCanonicalActiveTeamForSession(
|
|
|
935
1015
|
return null;
|
|
936
1016
|
}
|
|
937
1017
|
|
|
1018
|
+
async function resolveActiveTeamNameForStop(
|
|
1019
|
+
cwd: string,
|
|
1020
|
+
sessionId: string,
|
|
1021
|
+
): Promise<string> {
|
|
1022
|
+
const directState = await readTeamModeStateForStop(cwd, sessionId);
|
|
1023
|
+
const directTeamName = safeString(directState?.team_name).trim();
|
|
1024
|
+
if (directState?.active === true && directTeamName) return directTeamName;
|
|
1025
|
+
|
|
1026
|
+
const canonicalTeam = await findCanonicalActiveTeamForSession(cwd, sessionId);
|
|
1027
|
+
return canonicalTeam?.teamName ?? "";
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
async function maybeBuildReleaseReadinessFinalizeStopOutput(
|
|
1031
|
+
payload: CodexHookPayload,
|
|
1032
|
+
cwd: string,
|
|
1033
|
+
stateDir: string,
|
|
1034
|
+
sessionId: string,
|
|
1035
|
+
): Promise<{ matched: boolean; output: Record<string, unknown> | null }> {
|
|
1036
|
+
if (!sessionId) return { matched: false, output: null };
|
|
1037
|
+
|
|
1038
|
+
const teamName = await resolveActiveTeamNameForStop(cwd, sessionId);
|
|
1039
|
+
if (!teamName) return { matched: false, output: null };
|
|
1040
|
+
|
|
1041
|
+
const explicitReleaseReadinessContext =
|
|
1042
|
+
hasReleaseReadinessMode(payload)
|
|
1043
|
+
|| await hasReleaseReadinessStopMarker(cwd, sessionId, teamName);
|
|
1044
|
+
if (!explicitReleaseReadinessContext) {
|
|
1045
|
+
return { matched: false, output: null };
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
const summary = extractStableFinalRecommendationSummary(
|
|
1049
|
+
safeString(payload.last_assistant_message ?? payload.lastAssistantMessage),
|
|
1050
|
+
);
|
|
1051
|
+
if (!summary) return { matched: false, output: null };
|
|
1052
|
+
|
|
1053
|
+
const leaderAttention = await readTeamLeaderAttention(teamName, cwd);
|
|
1054
|
+
if (
|
|
1055
|
+
!leaderAttention
|
|
1056
|
+
|| leaderAttention.leader_decision_state !== "done_waiting_on_leader"
|
|
1057
|
+
|| leaderAttention.work_remaining !== false
|
|
1058
|
+
) {
|
|
1059
|
+
return { matched: false, output: null };
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
const signature = buildStableFinalRecommendationStopSignature(payload, teamName, summary);
|
|
1063
|
+
const output = await maybeReturnRepeatableStopOutput(
|
|
1064
|
+
payload,
|
|
1065
|
+
stateDir,
|
|
1066
|
+
signature,
|
|
1067
|
+
{
|
|
1068
|
+
decision: "block",
|
|
1069
|
+
reason:
|
|
1070
|
+
`Stable final recommendation already reached with no active worker tasks. Emit exactly one concise final decision summary aligned to "${summary}" with no filler or residual acknowledgements (for example "yes"), then stop.`,
|
|
1071
|
+
stopReason: "release_readiness_auto_finalize",
|
|
1072
|
+
systemMessage: RELEASE_READINESS_FINALIZE_SYSTEM_MESSAGE,
|
|
1073
|
+
},
|
|
1074
|
+
);
|
|
1075
|
+
return { matched: true, output };
|
|
1076
|
+
}
|
|
1077
|
+
|
|
938
1078
|
async function buildSkillStopOutput(
|
|
939
1079
|
cwd: string,
|
|
940
1080
|
sessionId: string,
|
|
@@ -1088,6 +1228,14 @@ async function buildStopHookOutput(
|
|
|
1088
1228
|
const ultraqaOutput = await buildModeBasedStopOutput("ultraqa", cwd, canonicalSessionId);
|
|
1089
1229
|
if (!stopHookActive && ultraqaOutput) return ultraqaOutput;
|
|
1090
1230
|
|
|
1231
|
+
const releaseReadinessFinalizeResult = await maybeBuildReleaseReadinessFinalizeStopOutput(
|
|
1232
|
+
payload,
|
|
1233
|
+
cwd,
|
|
1234
|
+
stateDir,
|
|
1235
|
+
canonicalSessionId,
|
|
1236
|
+
);
|
|
1237
|
+
if (releaseReadinessFinalizeResult.matched) return releaseReadinessFinalizeResult.output;
|
|
1238
|
+
|
|
1091
1239
|
const teamOutput = await buildTeamStopOutput(cwd, canonicalSessionId);
|
|
1092
1240
|
if (teamOutput) {
|
|
1093
1241
|
const teamSignature = buildRepeatableStopSignature(payload, "team-stop", safeString(teamOutput.stopReason));
|
|
@@ -1257,17 +1405,49 @@ export async function dispatchCodexNativeHook(
|
|
|
1257
1405
|
};
|
|
1258
1406
|
}
|
|
1259
1407
|
|
|
1260
|
-
|
|
1408
|
+
interface NativeHookCliReadResult {
|
|
1409
|
+
payload: CodexHookPayload;
|
|
1410
|
+
parseError: Error | null;
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
async function readStdinJson(): Promise<NativeHookCliReadResult> {
|
|
1261
1414
|
const chunks: Buffer[] = [];
|
|
1262
1415
|
for await (const chunk of process.stdin) {
|
|
1263
1416
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
|
|
1264
1417
|
}
|
|
1265
1418
|
const raw = Buffer.concat(chunks).toString("utf-8").trim();
|
|
1266
|
-
|
|
1419
|
+
if (!raw) {
|
|
1420
|
+
return { payload: {}, parseError: null };
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
try {
|
|
1424
|
+
return {
|
|
1425
|
+
payload: safeObject(JSON.parse(raw)),
|
|
1426
|
+
parseError: null,
|
|
1427
|
+
};
|
|
1428
|
+
} catch (error) {
|
|
1429
|
+
return {
|
|
1430
|
+
payload: {},
|
|
1431
|
+
parseError: error instanceof Error ? error : new Error(String(error)),
|
|
1432
|
+
};
|
|
1433
|
+
}
|
|
1267
1434
|
}
|
|
1268
1435
|
|
|
1269
1436
|
export async function runCodexNativeHookCli(): Promise<void> {
|
|
1270
|
-
const payload = await readStdinJson();
|
|
1437
|
+
const { payload, parseError } = await readStdinJson();
|
|
1438
|
+
if (parseError) {
|
|
1439
|
+
process.stdout.write(`${JSON.stringify({
|
|
1440
|
+
decision: "block",
|
|
1441
|
+
reason: "OMX native hook received malformed JSON input. Preserve runtime state and inspect the emitting hook payload before retrying.",
|
|
1442
|
+
hookSpecificOutput: {
|
|
1443
|
+
hookEventName: "Unknown",
|
|
1444
|
+
additionalContext:
|
|
1445
|
+
`stdin JSON parsing failed inside codex-native-hook: ${parseError.message}. Emit valid JSON from the native hook caller before retrying.`,
|
|
1446
|
+
},
|
|
1447
|
+
})}\n`);
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1271
1451
|
const result = await dispatchCodexNativeHook(payload);
|
|
1272
1452
|
if (result.outputJson) {
|
|
1273
1453
|
process.stdout.write(`${JSON.stringify(result.outputJson)}\n`);
|
|
@@ -62,6 +62,48 @@ function safeString(value: unknown): string {
|
|
|
62
62
|
return typeof value === 'string' ? value : '';
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
function collectMessageTextFragments(value: unknown, fragments: string[]): void {
|
|
66
|
+
if (typeof value === 'string') {
|
|
67
|
+
if (value.trim() !== '') fragments.push(value);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (Array.isArray(value)) {
|
|
72
|
+
for (const item of value) collectMessageTextFragments(item, fragments);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!value || typeof value !== 'object') return;
|
|
77
|
+
|
|
78
|
+
const record = value as Record<string, unknown>;
|
|
79
|
+
let usedPreferredField = false;
|
|
80
|
+
for (const key of ['text', 'message', 'content']) {
|
|
81
|
+
if (!(key in record)) continue;
|
|
82
|
+
usedPreferredField = true;
|
|
83
|
+
collectMessageTextFragments(record[key], fragments);
|
|
84
|
+
}
|
|
85
|
+
if (usedPreferredField) return;
|
|
86
|
+
|
|
87
|
+
for (const child of Object.values(record)) {
|
|
88
|
+
collectMessageTextFragments(child, fragments);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function extractMessageText(payload: Record<string, unknown>): string {
|
|
93
|
+
for (const candidate of [payload.text, payload.message, payload.content]) {
|
|
94
|
+
if (typeof candidate === 'string') {
|
|
95
|
+
if (candidate.trim() !== '') return candidate;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const fragments: string[] = [];
|
|
100
|
+
collectMessageTextFragments(candidate, fragments);
|
|
101
|
+
const text = fragments.join('\n').trim();
|
|
102
|
+
if (text) return text;
|
|
103
|
+
}
|
|
104
|
+
return '';
|
|
105
|
+
}
|
|
106
|
+
|
|
65
107
|
function derivedLog(entry: Record<string, unknown>): Promise<void> {
|
|
66
108
|
return appendFile(logPath, `${JSON.stringify({ timestamp: new Date().toISOString(), ...entry })}\n`).catch(() => {});
|
|
67
109
|
}
|
|
@@ -185,7 +227,7 @@ function inferDerivedEvent(parsed: Record<string, unknown> | null, meta: FileMet
|
|
|
185
227
|
}
|
|
186
228
|
|
|
187
229
|
if (payloadType === 'assistant_message') {
|
|
188
|
-
const message =
|
|
230
|
+
const message = extractMessageText(payload);
|
|
189
231
|
const looksLikeQuestion = /\?|\b(can you|could you|please provide|need input|what should)/i.test(message);
|
|
190
232
|
if (looksLikeQuestion) {
|
|
191
233
|
return {
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
readSubagentSessionSummary,
|
|
34
34
|
} from '../subagents/tracker.js';
|
|
35
35
|
import { listNotifyCanonicalActiveTeams } from './notify-hook/active-team.js';
|
|
36
|
+
import { sameFilePath } from '../utils/paths.js';
|
|
36
37
|
|
|
37
38
|
function argValue(name: string, fallback = ''): string {
|
|
38
39
|
const idx = process.argv.indexOf(name);
|
|
@@ -128,6 +129,7 @@ const RALPH_CONTINUE_TEXT = 'Ralph loop active continue';
|
|
|
128
129
|
const RALPH_CONTINUE_CADENCE_MS = 60_000;
|
|
129
130
|
const RALPH_STEER_LOCK_STALE_MS = 30_000;
|
|
130
131
|
const RALPH_TERMINAL_PHASES = new Set(['complete', 'failed', 'cancelled']);
|
|
132
|
+
const RALPH_STARTING_PHASE_TIMEOUT_MS = RALPH_CONTINUE_CADENCE_MS * 2;
|
|
131
133
|
const QUIET_ONCE_EVENT_TYPES = new Set(['watcher_start', 'watcher_once_complete']);
|
|
132
134
|
|
|
133
135
|
interface WatcherFileMeta {
|
|
@@ -457,10 +459,19 @@ function hasRalphTerminalState(raw: Record<string, unknown> | null | undefined):
|
|
|
457
459
|
if (raw.active !== true) return true;
|
|
458
460
|
const phase = safeString(raw.current_phase).trim().toLowerCase();
|
|
459
461
|
if (phase && RALPH_TERMINAL_PHASES.has(phase)) return true;
|
|
462
|
+
if (isStaleRalphStartingPhase(raw)) return true;
|
|
460
463
|
if (safeString(raw.completed_at).trim()) return true;
|
|
461
464
|
return false;
|
|
462
465
|
}
|
|
463
466
|
|
|
467
|
+
function isStaleRalphStartingPhase(raw: Record<string, unknown>): boolean {
|
|
468
|
+
const phase = safeString(raw.current_phase).trim().toLowerCase();
|
|
469
|
+
if (phase !== 'starting') return false;
|
|
470
|
+
const reference = parseIsoMillis(safeString(raw.last_turn_at)) ?? parseIsoMillis(safeString(raw.started_at));
|
|
471
|
+
if (reference === null) return false;
|
|
472
|
+
return Date.now() - reference > RALPH_STARTING_PHASE_TIMEOUT_MS;
|
|
473
|
+
}
|
|
474
|
+
|
|
464
475
|
async function loadPersistedWatcherState(): Promise<void> {
|
|
465
476
|
const persisted = await readFile(statePath, 'utf-8')
|
|
466
477
|
.then((content) => JSON.parse(content) as Record<string, unknown>)
|
|
@@ -537,6 +548,14 @@ async function resolveActiveModeState(mode: string): Promise<ActiveModeResult> {
|
|
|
537
548
|
.then((content) => JSON.parse(content) as Record<string, unknown>)
|
|
538
549
|
.catch(() => null);
|
|
539
550
|
if (!parsed || typeof parsed !== 'object') continue;
|
|
551
|
+
if (mode === 'ralph' && dir !== stateDir && isStaleRalphStartingPhase(parsed)) {
|
|
552
|
+
return {
|
|
553
|
+
active: false,
|
|
554
|
+
reason: 'starting_stale',
|
|
555
|
+
path,
|
|
556
|
+
state: parsed,
|
|
557
|
+
};
|
|
558
|
+
}
|
|
540
559
|
if (hasRalphTerminalState(parsed)) {
|
|
541
560
|
return {
|
|
542
561
|
active: false,
|
|
@@ -909,7 +928,7 @@ async function resolveAuthorityPrimaryWatcherHealth(now = Date.now()): Promise<A
|
|
|
909
928
|
|
|
910
929
|
const existingRecord = await readPidFileRecord(pidFilePath).catch(() => null);
|
|
911
930
|
if (!existingRecord) return createAuthorityBackoffState('pid_missing');
|
|
912
|
-
if (existingRecord.cwd &&
|
|
931
|
+
if (existingRecord.cwd && !sameFilePath(existingRecord.cwd, cwd)) return createAuthorityBackoffState('cwd_mismatch');
|
|
913
932
|
if (!isPidAlive(existingRecord.pid)) {
|
|
914
933
|
return createAuthorityBackoffState('pid_stale', {
|
|
915
934
|
primary_pid: existingRecord.pid,
|
|
@@ -1004,7 +1023,12 @@ async function runRalphContinueSteerTick(): Promise<void> {
|
|
|
1004
1023
|
singleton_lock_path: ralphSteerLockPath,
|
|
1005
1024
|
};
|
|
1006
1025
|
|
|
1007
|
-
if (!activeRalph.active)
|
|
1026
|
+
if (!activeRalph.active) {
|
|
1027
|
+
if (activeRalph.reason === 'starting_stale') {
|
|
1028
|
+
lastRalphContinueSteer.last_reason = 'starting_stale';
|
|
1029
|
+
}
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
1008
1032
|
|
|
1009
1033
|
if (parseIsoMillis(lastRalphContinueSteer.last_sent_at) === null && parseIsoMillis(lastRalphContinueSteer.cooldown_anchor_at) === null) {
|
|
1010
1034
|
lastRalphContinueSteer.cooldown_anchor_at = startupIso;
|
|
@@ -347,6 +347,24 @@ function looksLikePermissionSeekingContinuation(normalizedText) {
|
|
|
347
347
|
return matchesNormalizedPatterns(normalizedText, normalizePatternList(PERMISSION_SEEKING_STALL_PATTERNS));
|
|
348
348
|
}
|
|
349
349
|
|
|
350
|
+
/**
|
|
351
|
+
* Pattern to identify test-runner output lines (status symbols, PASS/FAIL prefixes).
|
|
352
|
+
* These lines may incidentally contain stall-pattern words inside test names and
|
|
353
|
+
* should be excluded before running stall detection on pane captures.
|
|
354
|
+
*/
|
|
355
|
+
const CAPTURE_TEST_LINE_RE = /^\s*(?:[✓✗✕×●✔✘▶◆○]|(?:PASS|FAIL|SKIP|ERROR)\s)/u;
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Strip lines that look like test-runner output so stall patterns inside test
|
|
359
|
+
* names (e.g. "✓ should continue with the next step") do not trigger a nudge.
|
|
360
|
+
*/
|
|
361
|
+
function filterCapturedTestLines(text) {
|
|
362
|
+
return safeString(text)
|
|
363
|
+
.split('\n')
|
|
364
|
+
.filter((line) => !CAPTURE_TEST_LINE_RE.test(line))
|
|
365
|
+
.join('\n');
|
|
366
|
+
}
|
|
367
|
+
|
|
350
368
|
function summarizePaneCaptureForLog(captured, maxLines = 6) {
|
|
351
369
|
const lines = safeString(captured)
|
|
352
370
|
.replace(/\r\n?/g, '\n')
|
|
@@ -516,7 +534,7 @@ export async function maybeAutoNudge({ cwd, stateDir, logsDir, payload }) {
|
|
|
516
534
|
|
|
517
535
|
if (!detected && paneId) {
|
|
518
536
|
captured = await capturePane(paneId);
|
|
519
|
-
detected = detectStallPattern(captured, config.patterns, skillState?.phase);
|
|
537
|
+
detected = detectStallPattern(filterCapturedTestLines(captured), config.patterns, skillState?.phase);
|
|
520
538
|
source = 'capture-pane';
|
|
521
539
|
}
|
|
522
540
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { execFileSync } from 'child_process';
|
|
2
2
|
import { readFileSync } from 'fs';
|
|
3
|
-
import { basename, dirname
|
|
3
|
+
import { basename, dirname } from 'path';
|
|
4
4
|
import { readSessionState, isSessionStale } from '../../hooks/session.js';
|
|
5
5
|
import { runProcess } from './process-runner.js';
|
|
6
6
|
import { safeString } from './utils.js';
|
|
7
|
+
import { sameFilePath } from '../../utils/paths.js';
|
|
7
8
|
|
|
8
9
|
function sanitizeTmuxToken(value: string): string {
|
|
9
10
|
const cleaned = safeString(value)
|
|
@@ -139,7 +140,7 @@ export async function resolveManagedSessionContext(cwd: string, payload: any, {
|
|
|
139
140
|
if (!sessionState) {
|
|
140
141
|
return { managed: false, reason: 'missing_session_state', invocationSessionId, sessionState: null, expectedTmuxSessionName: '', currentTmuxSessionName: '' };
|
|
141
142
|
}
|
|
142
|
-
if (
|
|
143
|
+
if (!sameFilePath(safeString(sessionState.cwd || cwd), cwd)) {
|
|
143
144
|
return { managed: false, reason: 'cwd_mismatch', invocationSessionId, sessionState, expectedTmuxSessionName: '', currentTmuxSessionName: '' };
|
|
144
145
|
}
|
|
145
146
|
const canonicalSessionId = safeString(sessionState.session_id).trim();
|
|
@@ -152,7 +153,11 @@ export async function resolveManagedSessionContext(cwd: string, payload: any, {
|
|
|
152
153
|
return { managed: false, reason: 'stale_session', invocationSessionId, sessionState, expectedTmuxSessionName: '', currentTmuxSessionName: '' };
|
|
153
154
|
}
|
|
154
155
|
|
|
155
|
-
const
|
|
156
|
+
const authoritativeSessionCwd = safeString(sessionState.cwd || cwd).trim() || cwd;
|
|
157
|
+
const expectedTmuxSessionName = buildExpectedManagedTmuxSessionName(
|
|
158
|
+
authoritativeSessionCwd,
|
|
159
|
+
canonicalSessionId || invocationSessionId,
|
|
160
|
+
);
|
|
156
161
|
const currentTmuxSessionName = readCurrentTmuxSessionName();
|
|
157
162
|
if (currentTmuxSessionName && currentTmuxSessionName === expectedTmuxSessionName) {
|
|
158
163
|
return {
|