oh-my-codex 0.20.1 → 0.20.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +7 -6
- package/Cargo.toml +1 -1
- package/README.md +36 -1
- package/crates/omx-runtime/Cargo.toml +1 -0
- package/crates/omx-runtime/src/main.rs +25 -2
- package/crates/omx-runtime/tests/execution.rs +219 -0
- package/crates/omx-runtime-core/src/dispatch.rs +96 -10
- package/crates/omx-runtime-core/src/engine.rs +839 -29
- package/crates/omx-runtime-core/src/lib.rs +8 -0
- package/dist/adapt/__tests__/hermes.test.js.map +1 -1
- package/dist/adapt/contracts.d.ts.map +1 -1
- package/dist/agents/__tests__/definitions.test.js +81 -0
- package/dist/agents/__tests__/definitions.test.js.map +1 -1
- package/dist/agents/__tests__/native-config.test.js +25 -0
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/native-config.d.ts +2 -1
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js.map +1 -1
- package/dist/auth/__tests__/hotswap.test.d.ts +2 -0
- package/dist/auth/__tests__/hotswap.test.d.ts.map +1 -0
- package/dist/auth/__tests__/hotswap.test.js +183 -0
- package/dist/auth/__tests__/hotswap.test.js.map +1 -0
- package/dist/auth/hotswap.d.ts +6 -0
- package/dist/auth/hotswap.d.ts.map +1 -1
- package/dist/auth/hotswap.js +102 -19
- package/dist/auth/hotswap.js.map +1 -1
- package/dist/auth/paths.js.map +1 -1
- package/dist/auth/storage.js.map +1 -1
- package/dist/autopilot/__tests__/ralplan-gate.test.js +5 -5
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
- package/dist/autopilot/completion-gate.js.map +1 -1
- package/dist/autopilot/fsm.d.ts +1 -1
- package/dist/autopilot/fsm.d.ts.map +1 -1
- package/dist/autoresearch/goal.js.map +1 -1
- package/dist/autoresearch/runtime.js.map +1 -1
- package/dist/capabilities/lockfile.js.map +1 -1
- package/dist/catalog/reader.js.map +1 -1
- package/dist/catalog/skill-mirror.js.map +1 -1
- package/dist/cli/__tests__/adapt-help.test.js.map +1 -1
- package/dist/cli/__tests__/agents-init.test.js.map +1 -1
- package/dist/cli/__tests__/agents.test.js.map +1 -1
- package/dist/cli/__tests__/api.test.js.map +1 -1
- package/dist/cli/__tests__/ask.test.js.map +1 -1
- package/dist/cli/__tests__/auth.test.js +60 -6
- package/dist/cli/__tests__/auth.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch.test.js.map +1 -1
- package/dist/cli/__tests__/capabilities.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +80 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-invalid-config.test.js +47 -4
- package/dist/cli/__tests__/doctor-invalid-config.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +752 -15
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/exec.test.js +136 -0
- package/dist/cli/__tests__/exec.test.js.map +1 -1
- package/dist/cli/__tests__/imagegen-continuation.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +473 -14
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +336 -4
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +87 -12
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts +2 -0
- package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts.map +1 -0
- package/dist/cli/__tests__/native-hook-claim-journal.test.js +206 -0
- package/dist/cli/__tests__/native-hook-claim-journal.test.js.map +1 -0
- package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-deslop-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +6 -0
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-prd-smoke.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +8 -3
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts +2 -0
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts.map +1 -0
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js +72 -0
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js.map +1 -0
- package/dist/cli/__tests__/ralplan.test.d.ts +2 -0
- package/dist/cli/__tests__/ralplan.test.d.ts.map +1 -0
- package/dist/cli/__tests__/ralplan.test.js +55 -0
- package/dist/cli/__tests__/ralplan.test.js.map +1 -0
- package/dist/cli/__tests__/resume.test.js +17 -11
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.js +25 -0
- package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
- package/dist/cli/__tests__/session-search-help.test.js +25 -1
- package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
- package/dist/cli/__tests__/session-search.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +79 -0
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-gh-star.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +77 -3
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts +2 -0
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts.map +1 -0
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js +285 -0
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js.map +1 -0
- package/dist/cli/__tests__/setup-install-mode.test.js +2579 -294
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-preferences.test.d.ts +2 -0
- package/dist/cli/__tests__/setup-preferences.test.d.ts.map +1 -0
- package/dist/cli/__tests__/setup-preferences.test.js +79 -0
- package/dist/cli/__tests__/setup-preferences.test.js.map +1 -0
- package/dist/cli/__tests__/setup-refresh.test.js +33 -2
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +46 -3
- package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
- package/dist/cli/__tests__/state.test.js +37 -0
- package/dist/cli/__tests__/state.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +105 -7
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +61 -1
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +1817 -24
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/__tests__/update.test.js +58 -0
- package/dist/cli/__tests__/update.test.js.map +1 -1
- package/dist/cli/__tests__/url.test.js.map +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js +2 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
- package/dist/cli/adapt.js.map +1 -1
- package/dist/cli/agents-init.js.map +1 -1
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/api.js.map +1 -1
- package/dist/cli/ask.d.ts +1 -1
- package/dist/cli/ask.d.ts.map +1 -1
- package/dist/cli/ask.js.map +1 -1
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/autoresearch-guided.js.map +1 -1
- package/dist/cli/autoresearch-intake.js.map +1 -1
- package/dist/cli/capabilities.js.map +1 -1
- package/dist/cli/cleanup.js.map +1 -1
- package/dist/cli/codex-feature-probe.js.map +1 -1
- package/dist/cli/codex-home.js.map +1 -1
- package/dist/cli/doctor.d.ts +21 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +607 -130
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +14 -3
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +245 -57
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-parity.js +2 -2
- package/dist/cli/mcp-parity.js.map +1 -1
- package/dist/cli/mcp-serve.js.map +1 -1
- package/dist/cli/mission.js.map +1 -1
- package/dist/cli/native-assets.js.map +1 -1
- package/dist/cli/native-hook-claim-journal.d.ts +29 -0
- package/dist/cli/native-hook-claim-journal.d.ts.map +1 -0
- package/dist/cli/native-hook-claim-journal.js +252 -0
- package/dist/cli/native-hook-claim-journal.js.map +1 -0
- package/dist/cli/omx.js.map +1 -1
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/project-runtime-codex-homes.js.map +1 -1
- package/dist/cli/question.js.map +1 -1
- package/dist/cli/ralph.d.ts.map +1 -1
- package/dist/cli/ralph.js +3 -2
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/ralplan.d.ts +10 -0
- package/dist/cli/ralplan.d.ts.map +1 -0
- package/dist/cli/ralplan.js +110 -0
- package/dist/cli/ralplan.js.map +1 -0
- package/dist/cli/session-search.d.ts +5 -0
- package/dist/cli/session-search.d.ts.map +1 -1
- package/dist/cli/session-search.js +87 -0
- package/dist/cli/session-search.js.map +1 -1
- package/dist/cli/setup-preferences.d.ts +11 -0
- package/dist/cli/setup-preferences.d.ts.map +1 -1
- package/dist/cli/setup-preferences.js +32 -0
- package/dist/cli/setup-preferences.js.map +1 -1
- package/dist/cli/setup.d.ts +58 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +1450 -398
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/sparkshell.js.map +1 -1
- package/dist/cli/star-prompt.js.map +1 -1
- package/dist/cli/state.d.ts.map +1 -1
- package/dist/cli/state.js +2 -1
- package/dist/cli/state.js.map +1 -1
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/ultragoal.d.ts +5 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +34 -2
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/uninstall.d.ts +17 -0
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +986 -95
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +8 -1
- package/dist/cli/update.js.map +1 -1
- package/dist/cli/url.js.map +1 -1
- package/dist/compat/__tests__/doctor-contract.test.js +5 -1
- package/dist/compat/__tests__/doctor-contract.test.js.map +1 -1
- package/dist/compat/__tests__/rust-runtime-compat.test.js +1 -1
- package/dist/compat/__tests__/rust-runtime-compat.test.js.map +1 -1
- package/dist/config/__tests__/codex-hooks.test.js +1287 -11
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +1179 -32
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +6 -1
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/__tests__/models.test.js +67 -3
- package/dist/config/__tests__/models.test.js.map +1 -1
- package/dist/config/codex-feature-flags.d.ts.map +1 -1
- package/dist/config/codex-feature-flags.js.map +1 -1
- package/dist/config/codex-hooks.d.ts +124 -1
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +2142 -265
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/commit-lore-guard.js.map +1 -1
- package/dist/config/generator.d.ts +23 -34
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +1480 -246
- package/dist/config/generator.js.map +1 -1
- package/dist/config/mcp-registry.js.map +1 -1
- package/dist/config/models.d.ts +14 -4
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +15 -1
- package/dist/config/models.js.map +1 -1
- package/dist/config/omx-first-party-mcp.js.map +1 -1
- package/dist/config/team-mode.d.ts.map +1 -1
- package/dist/document-refresh/__tests__/enforcer.test.js.map +1 -1
- package/dist/document-refresh/enforcer.js.map +1 -1
- package/dist/exec/followup.js.map +1 -1
- package/dist/goal-workflows/artifacts.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +7 -4
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/analyze-routing-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/analyze-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +9 -3
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/design-skill.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +1376 -6
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +252 -543
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +38 -4
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +765 -10
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +2 -0
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +142 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +48 -2
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +61 -44
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js +3 -2
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js +243 -4
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +531 -12
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +163 -24
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +482 -32
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +68 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +7 -1
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +43 -4
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/openclaw-setup-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -1
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +1 -1
- package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts +2 -0
- package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/prompt-session-provenance.test.js +82 -0
- package/dist/hooks/__tests__/prompt-session-provenance.test.js.map +1 -0
- package/dist/hooks/__tests__/session.test.js +878 -11
- package/dist/hooks/__tests__/session.test.js.map +1 -1
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -1
- package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/visual-ralph-skill.test.js.map +1 -1
- package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +1 -1
- package/dist/hooks/agents-overlay.js +5 -5
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/code-simplifier/index.js.map +1 -1
- package/dist/hooks/explore-routing.js.map +1 -1
- package/dist/hooks/extensibility/dispatcher.js.map +1 -1
- package/dist/hooks/extensibility/events.js.map +1 -1
- package/dist/hooks/extensibility/loader.js.map +1 -1
- package/dist/hooks/extensibility/plugin-runner-stdin.js.map +1 -1
- package/dist/hooks/extensibility/sdk/logging.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +33 -7
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +2228 -119
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/keyword-registry.d.ts +12 -0
- package/dist/hooks/keyword-registry.d.ts.map +1 -1
- package/dist/hooks/keyword-registry.js +41 -0
- package/dist/hooks/keyword-registry.js.map +1 -1
- package/dist/hooks/prompt-session-provenance.d.ts +87 -0
- package/dist/hooks/prompt-session-provenance.d.ts.map +1 -0
- package/dist/hooks/prompt-session-provenance.js +180 -0
- package/dist/hooks/prompt-session-provenance.js.map +1 -0
- package/dist/hooks/session.d.ts +163 -34
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +1395 -317
- package/dist/hooks/session.js.map +1 -1
- package/dist/hooks/task-size-detector.js.map +1 -1
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/authority.js.map +1 -1
- package/dist/hud/constants.js.map +1 -1
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/tmux.js.map +1 -1
- package/dist/leader/__tests__/contract.test.js +153 -1
- package/dist/leader/__tests__/contract.test.js.map +1 -1
- package/dist/leader/contract.d.ts +42 -5
- package/dist/leader/contract.d.ts.map +1 -1
- package/dist/leader/contract.js +184 -3
- package/dist/leader/contract.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/code-intel-server.test.js +31 -3
- package/dist/mcp/__tests__/code-intel-server.test.js.map +1 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js +15 -2
- package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
- package/dist/mcp/__tests__/state-paths.test.js +98 -1
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/__tests__/wiki-server.test.js +18 -0
- package/dist/mcp/__tests__/wiki-server.test.js.map +1 -1
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/code-intel-server.d.ts +58 -58
- package/dist/mcp/code-intel-server.d.ts.map +1 -1
- package/dist/mcp/code-intel-server.js +13 -3
- package/dist/mcp/code-intel-server.js.map +1 -1
- package/dist/mcp/hermes-bridge.js.map +1 -1
- package/dist/mcp/hermes-server.d.ts +70 -70
- package/dist/mcp/hermes-server.d.ts.map +1 -1
- package/dist/mcp/lifecycle-telemetry.js.map +1 -1
- package/dist/mcp/memory-server.d.ts +34 -34
- package/dist/mcp/memory-server.d.ts.map +1 -1
- package/dist/mcp/memory-server.js.map +1 -1
- package/dist/mcp/state-paths.d.ts +14 -0
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +96 -20
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/mcp/state-server.d.ts +47 -47
- package/dist/mcp/state-server.d.ts.map +1 -1
- package/dist/mcp/trace-server.d.ts +4 -4
- package/dist/mcp/trace-server.d.ts.map +1 -1
- package/dist/mcp/trace-server.js.map +1 -1
- package/dist/mcp/wiki-server.d.ts +34 -23
- package/dist/mcp/wiki-server.d.ts.map +1 -1
- package/dist/mcp/wiki-server.js +9 -2
- package/dist/mcp/wiki-server.js.map +1 -1
- package/dist/modes/__tests__/base-session-scope.test.js +53 -1
- package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
- package/dist/modes/__tests__/base-tmux-pane.test.js +4 -4
- package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +5 -5
- package/dist/modes/base.js.map +1 -1
- package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +1 -1
- package/dist/notifications/__tests__/reply-listener.test.js.map +1 -1
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js +177 -85
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js.map +1 -1
- package/dist/notifications/__tests__/session-registry.test.js.map +1 -1
- package/dist/notifications/__tests__/template-engine.test.js.map +1 -1
- package/dist/notifications/__tests__/verbosity.test.js.map +1 -1
- package/dist/notifications/http-client.js.map +1 -1
- package/dist/notifications/index.d.ts +4 -1
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +3 -9
- package/dist/notifications/index.js.map +1 -1
- package/dist/notifications/lifecycle-dedupe.js.map +1 -1
- package/dist/notifications/reply-listener.d.ts.map +1 -1
- package/dist/notifications/reply-listener.js.map +1 -1
- package/dist/notifications/session-registry.js.map +1 -1
- package/dist/notifications/session-status.js.map +1 -1
- package/dist/notifications/temp-contract.d.ts.map +1 -1
- package/dist/notifications/temp-contract.js +4 -0
- package/dist/notifications/temp-contract.js.map +1 -1
- package/dist/notifications/tmux-detector.js.map +1 -1
- package/dist/notifications/tmux.js.map +1 -1
- package/dist/openclaw/config.js.map +1 -1
- package/dist/openclaw/dispatcher.js.map +1 -1
- package/dist/pipeline/__tests__/orchestrator.test.js +4 -4
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +16 -13
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/stages/code-review.js.map +1 -1
- package/dist/pipeline/stages/ralph-verify.js.map +1 -1
- package/dist/pipeline/stages/ralplan.js.map +1 -1
- package/dist/pipeline/stages/team-exec.js.map +1 -1
- package/dist/pipeline/stages/ultragoal.js.map +1 -1
- package/dist/pipeline/stages/ultraqa.js.map +1 -1
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -1
- package/dist/planning/artifact-names.js.map +1 -1
- package/dist/planning/artifacts.js.map +1 -1
- package/dist/question/__tests__/state.test.js.map +1 -1
- package/dist/question/__tests__/ui.test.js.map +1 -1
- package/dist/question/autopilot-wait.js.map +1 -1
- package/dist/question/client.d.ts.map +1 -1
- package/dist/question/client.js.map +1 -1
- package/dist/question/deep-interview.js.map +1 -1
- package/dist/question/events.js.map +1 -1
- package/dist/question/renderer.js.map +1 -1
- package/dist/question/state.d.ts.map +1 -1
- package/dist/question/state.js.map +1 -1
- package/dist/question/ui.js.map +1 -1
- package/dist/ralph/contract.d.ts +1 -1
- package/dist/ralph/contract.d.ts.map +1 -1
- package/dist/ralplan/__tests__/consensus-gate.test.js +527 -8
- package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
- package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts +2 -0
- package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts.map +1 -0
- package/dist/ralplan/__tests__/documented-leader-preflight.test.js +46 -0
- package/dist/ralplan/__tests__/documented-leader-preflight.test.js.map +1 -0
- package/dist/ralplan/__tests__/runtime.test.js +116 -14
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.d.ts +3 -3
- package/dist/ralplan/consensus-gate.d.ts.map +1 -1
- package/dist/ralplan/consensus-gate.js +173 -70
- package/dist/ralplan/consensus-gate.js.map +1 -1
- package/dist/ralplan/documented-leader-preflight.d.ts +34 -0
- package/dist/ralplan/documented-leader-preflight.d.ts.map +1 -0
- package/dist/ralplan/documented-leader-preflight.js +58 -0
- package/dist/ralplan/documented-leader-preflight.js.map +1 -0
- package/dist/ralplan/runtime.d.ts +3 -2
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +12 -9
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/runtime/__tests__/bridge.test.js +42 -1
- package/dist/runtime/__tests__/bridge.test.js.map +1 -1
- package/dist/runtime/bridge.d.ts +12 -0
- package/dist/runtime/bridge.d.ts.map +1 -1
- package/dist/runtime/bridge.js +52 -1
- package/dist/runtime/bridge.js.map +1 -1
- package/dist/runtime/process-tree.js.map +1 -1
- package/dist/runtime/run-loop.js.map +1 -1
- package/dist/runtime/run-outcome.d.ts +3 -3
- package/dist/runtime/run-outcome.d.ts.map +1 -1
- package/dist/runtime/run-outcome.js.map +1 -1
- package/dist/runtime/run-state.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +6657 -995
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts +2 -0
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts.map +1 -0
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js +634 -0
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js.map +1 -0
- package/dist/scripts/__tests__/generate-release-body.test.js.map +1 -1
- package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts +2 -0
- package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/notify-fallback-delivery.test.js +174 -0
- package/dist/scripts/__tests__/notify-fallback-delivery.test.js.map +1 -0
- package/dist/scripts/__tests__/notify-state-io.test.js +57 -1
- package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -1
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.d.ts +2 -0
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.js +108 -0
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.js.map +1 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.d.ts +2 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js +78 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js.map +1 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts +2 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js +55 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -0
- package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js +1100 -4
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
- package/dist/scripts/__tests__/test-reply-listener-live.test.js.map +1 -1
- package/dist/scripts/build-api.js.map +1 -1
- package/dist/scripts/build-explore-harness.js.map +1 -1
- package/dist/scripts/build-sparkshell.js.map +1 -1
- package/dist/scripts/cleanup-explore-harness.js.map +1 -1
- package/dist/scripts/codex-execution-surface.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts +4 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +11577 -1184
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/generate-native-release-manifest.js.map +1 -1
- package/dist/scripts/generate-release-body.js.map +1 -1
- package/dist/scripts/hook-payload-guard.d.ts.map +1 -1
- package/dist/scripts/hook-payload-guard.js.map +1 -1
- package/dist/scripts/notify-fallback-delivery.d.ts +48 -0
- package/dist/scripts/notify-fallback-delivery.d.ts.map +1 -0
- package/dist/scripts/notify-fallback-delivery.js +419 -0
- package/dist/scripts/notify-fallback-delivery.js.map +1 -0
- package/dist/scripts/notify-fallback-watcher.js +218 -138
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.d.ts +18 -9
- package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.js +112 -15
- package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.d.ts +23 -0
- package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.js +122 -12
- package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
- package/dist/scripts/notify-hook/orchestration-intent.d.ts +7 -7
- package/dist/scripts/notify-hook/orchestration-intent.d.ts.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts +5 -2
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.js +33 -37
- package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
- package/dist/scripts/notify-hook/state-io.d.ts +17 -0
- package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
- package/dist/scripts/notify-hook/state-io.js +73 -11
- package/dist/scripts/notify-hook/state-io.js.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts +10 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.js +234 -79
- package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts +2 -2
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.js +39 -13
- package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts +16 -8
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.js +365 -44
- package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker-posttooluse.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.d.ts +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.js +19 -18
- package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker.d.ts +5 -2
- package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker.js +37 -28
- package/dist/scripts/notify-hook/team-worker.js.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts +8 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +53 -18
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook/visual-verdict.d.ts +1 -1
- package/dist/scripts/notify-hook/visual-verdict.d.ts.map +1 -1
- package/dist/scripts/notify-hook/visual-verdict.js +15 -13
- package/dist/scripts/notify-hook/visual-verdict.js.map +1 -1
- package/dist/scripts/notify-hook.d.ts +24 -1
- package/dist/scripts/notify-hook.d.ts.map +1 -1
- package/dist/scripts/notify-hook.js +267 -90
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/scripts/prompt-inventory.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +927 -5
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +4317 -13
- package/dist/scripts/smoke-packed-install.js.map +1 -1
- package/dist/scripts/sync-plugin-mirror.js.map +1 -1
- package/dist/scripts/test-reply-listener-live.js.map +1 -1
- package/dist/scripts/test-sparkshell.js.map +1 -1
- package/dist/scripts/verify-native-agents.js.map +1 -1
- package/dist/session-history/friction.js.map +1 -1
- package/dist/session-history/search.js.map +1 -1
- package/dist/sidecar/__tests__/boundary.test.js.map +1 -1
- package/dist/sidecar/collector.js.map +1 -1
- package/dist/sidecar/index.js.map +1 -1
- package/dist/sidecar/render.js.map +1 -1
- package/dist/sidecar/tmux.js.map +1 -1
- package/dist/state/__tests__/mode-state-context.test.js +54 -0
- package/dist/state/__tests__/mode-state-context.test.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +66 -15
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/skill-active.test.js +19 -1
- package/dist/state/__tests__/skill-active.test.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +61 -0
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/mode-state-context.d.ts +5 -0
- package/dist/state/mode-state-context.d.ts.map +1 -1
- package/dist/state/mode-state-context.js +59 -0
- package/dist/state/mode-state-context.js.map +1 -1
- package/dist/state/operations.d.ts +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +49 -55
- package/dist/state/operations.js.map +1 -1
- package/dist/state/paths.d.ts +1 -1
- package/dist/state/paths.d.ts.map +1 -1
- package/dist/state/paths.js +1 -1
- package/dist/state/paths.js.map +1 -1
- package/dist/state/skill-active.d.ts +13 -1
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +43 -4
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/terminal-normalization.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +20 -4
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.d.ts +1 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts +2 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts.map +1 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js +52 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js.map +1 -0
- package/dist/subagents/__tests__/tracker.test.js +1550 -10
- package/dist/subagents/__tests__/tracker.test.js.map +1 -1
- package/dist/subagents/role-routing-marker.d.ts +10 -0
- package/dist/subagents/role-routing-marker.d.ts.map +1 -0
- package/dist/subagents/role-routing-marker.js +136 -0
- package/dist/subagents/role-routing-marker.js.map +1 -0
- package/dist/subagents/tracker.d.ts +91 -0
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +806 -62
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/team/__tests__/api-interop.test.js +91 -1
- package/dist/team/__tests__/api-interop.test.js.map +1 -1
- package/dist/team/__tests__/approved-execution.test.js.map +1 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.js +52 -10
- package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
- package/dist/team/__tests__/idle-nudge.test.js +45 -15
- package/dist/team/__tests__/idle-nudge.test.js.map +1 -1
- package/dist/team/__tests__/mcp-comm.test.js +93 -27
- package/dist/team/__tests__/mcp-comm.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +341 -4
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/role-router.test.js.map +1 -1
- package/dist/team/__tests__/runtime-cli.test.js +9 -0
- package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +3624 -355
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +2516 -118
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/state-root.test.js.map +1 -1
- package/dist/team/__tests__/state.test.js +804 -36
- package/dist/team/__tests__/state.test.js.map +1 -1
- package/dist/team/__tests__/team-ops-contract.test.js +6 -0
- package/dist/team/__tests__/team-ops-contract.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +3664 -969
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.js.map +1 -1
- package/dist/team/__tests__/worker-runtime-identity.test.js +38 -2
- package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
- package/dist/team/__tests__/worktree.test.js +6 -0
- package/dist/team/__tests__/worktree.test.js.map +1 -1
- package/dist/team/api-interop.d.ts +2 -2
- package/dist/team/api-interop.d.ts.map +1 -1
- package/dist/team/api-interop.js +15 -9
- package/dist/team/api-interop.js.map +1 -1
- package/dist/team/commit-hygiene.js.map +1 -1
- package/dist/team/contracts.d.ts +5 -5
- package/dist/team/contracts.d.ts.map +1 -1
- package/dist/team/delivery-log.js.map +1 -1
- package/dist/team/exact-pane.d.ts +23 -0
- package/dist/team/exact-pane.d.ts.map +1 -0
- package/dist/team/exact-pane.js +133 -0
- package/dist/team/exact-pane.js.map +1 -0
- package/dist/team/followup-planner.js.map +1 -1
- package/dist/team/goal-workflow.js.map +1 -1
- package/dist/team/idle-nudge.d.ts +12 -1
- package/dist/team/idle-nudge.d.ts.map +1 -1
- package/dist/team/idle-nudge.js +41 -14
- package/dist/team/idle-nudge.js.map +1 -1
- package/dist/team/model-contract.d.ts +18 -2
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +314 -35
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/orchestrator.js.map +1 -1
- package/dist/team/pane-status.js.map +1 -1
- package/dist/team/phase-controller.js.map +1 -1
- package/dist/team/reminder-intents.d.ts +1 -1
- package/dist/team/reminder-intents.d.ts.map +1 -1
- package/dist/team/reminder-intents.js.map +1 -1
- package/dist/team/runtime-cli.js.map +1 -1
- package/dist/team/runtime.d.ts +1 -0
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +1326 -231
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts +22 -8
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +1463 -376
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state/dispatch-lock.js.map +1 -1
- package/dist/team/state/dispatch.d.ts.map +1 -1
- package/dist/team/state/dispatch.js +26 -8
- package/dist/team/state/dispatch.js.map +1 -1
- package/dist/team/state/events.js.map +1 -1
- package/dist/team/state/locks.d.ts.map +1 -1
- package/dist/team/state/locks.js +61 -13
- package/dist/team/state/locks.js.map +1 -1
- package/dist/team/state/tasks.d.ts.map +1 -1
- package/dist/team/state/tasks.js +4 -3
- package/dist/team/state/tasks.js.map +1 -1
- package/dist/team/state-root.js.map +1 -1
- package/dist/team/state.d.ts +67 -1
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +636 -129
- package/dist/team/state.js.map +1 -1
- package/dist/team/team-identity.d.ts.map +1 -1
- package/dist/team/team-identity.js.map +1 -1
- package/dist/team/team-ops.d.ts +5 -0
- package/dist/team/team-ops.d.ts.map +1 -1
- package/dist/team/team-ops.js +4 -0
- package/dist/team/team-ops.js.map +1 -1
- package/dist/team/tmux-session.d.ts +125 -23
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +1340 -333
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worker-bootstrap.js.map +1 -1
- package/dist/team/worktree.d.ts.map +1 -1
- package/dist/team/worktree.js +4 -0
- package/dist/team/worktree.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +4 -1
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/url-reader/index.js.map +1 -1
- package/dist/utils/__tests__/file-durability.test.d.ts +2 -0
- package/dist/utils/__tests__/file-durability.test.d.ts.map +1 -0
- package/dist/utils/__tests__/file-durability.test.js +57 -0
- package/dist/utils/__tests__/file-durability.test.js.map +1 -0
- package/dist/utils/agents-model-table.js.map +1 -1
- package/dist/utils/file-durability.d.ts +15 -0
- package/dist/utils/file-durability.d.ts.map +1 -0
- package/dist/utils/file-durability.js +37 -0
- package/dist/utils/file-durability.js.map +1 -0
- package/dist/utils/package.js.map +1 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/platform-command.js.map +1 -1
- package/dist/utils/repo-deps.js.map +1 -1
- package/dist/utils/version.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +1 -1
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +3 -0
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
- package/dist/verification/verifier.js.map +1 -1
- package/dist/visual/constants.d.ts +1 -1
- package/dist/visual/constants.d.ts.map +1 -1
- package/dist/vscode/__tests__/index.test.js.map +1 -1
- package/dist/vscode/index.js.map +1 -1
- package/dist/wiki/__tests__/cjk-tokenize.test.js.map +1 -1
- package/dist/wiki/__tests__/lint.test.js.map +1 -1
- package/dist/wiki/__tests__/query.test.js.map +1 -1
- package/dist/wiki/__tests__/storage.test.js.map +1 -1
- package/dist/wiki/__tests__/test-helpers.d.ts.map +1 -1
- package/dist/wiki/lint.d.ts +4 -1
- package/dist/wiki/lint.d.ts.map +1 -1
- package/dist/wiki/lint.js +3 -2
- package/dist/wiki/lint.js.map +1 -1
- package/dist/wiki/query.js.map +1 -1
- package/dist/wiki/storage.js.map +1 -1
- package/package.json +2 -2
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +24 -0
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +10 -5
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +6 -2
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +6 -2
- package/plugins/oh-my-codex/skills/team/SKILL.md +13 -9
- package/skills/omx-setup/SKILL.md +10 -5
- package/skills/ralph/SKILL.md +6 -2
- package/skills/ralplan/SKILL.md +6 -2
- package/skills/team/SKILL.md +13 -9
- package/src/scripts/__tests__/codex-native-hook.test.ts +20048 -10827
- package/src/scripts/__tests__/fixtures/issue-3138-installed-smoke.ts +734 -0
- package/src/scripts/__tests__/notify-fallback-delivery.test.ts +177 -0
- package/src/scripts/__tests__/notify-state-io.test.ts +73 -0
- package/src/scripts/__tests__/reasoning-artifact-contract.test.ts +129 -0
- package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +78 -0
- package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +60 -0
- package/src/scripts/__tests__/smoke-packed-install.test.ts +1309 -4
- package/src/scripts/codex-native-hook.ts +11429 -1163
- package/src/scripts/notify-fallback-delivery.ts +416 -0
- package/src/scripts/notify-fallback-watcher.ts +216 -155
- package/src/scripts/notify-hook/auto-nudge.ts +113 -14
- package/src/scripts/notify-hook/managed-tmux.ts +149 -12
- package/src/scripts/notify-hook/ralph-session-resume.ts +37 -36
- package/src/scripts/notify-hook/state-io.ts +100 -13
- package/src/scripts/notify-hook/team-dispatch.ts +242 -75
- package/src/scripts/notify-hook/team-leader-nudge.ts +40 -18
- package/src/scripts/notify-hook/team-tmux-guard.ts +366 -39
- package/src/scripts/notify-hook/team-worker-stop.ts +20 -16
- package/src/scripts/notify-hook/team-worker.ts +39 -26
- package/src/scripts/notify-hook/tmux-injection.ts +66 -23
- package/src/scripts/notify-hook/visual-verdict.ts +22 -12
- package/src/scripts/notify-hook.ts +336 -90
- package/src/scripts/smoke-packed-install.ts +5154 -149
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
* rather than the full keyword/state table.
|
|
11
11
|
*/
|
|
12
12
|
import { constants as fsConstants } from 'node:fs';
|
|
13
|
-
import { access, lstat, mkdir, readFile, realpath, writeFile } from 'node:fs/promises';
|
|
13
|
+
import { access, lstat, mkdir, readFile, readdir, realpath, writeFile } from 'node:fs/promises';
|
|
14
14
|
import { withModeRuntimeContext } from '../state/mode-state-context.js';
|
|
15
15
|
import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
16
16
|
import { classifyTaskSize, isHeavyMode } from './task-size-detector.js';
|
|
17
17
|
import { isApprovedExecutionFollowupShortcut } from '../team/followup-planner.js';
|
|
18
18
|
import { isPlanningComplete, readPlanningArtifacts } from '../planning/artifacts.js';
|
|
19
19
|
import { hasDurableRalplanConsensusEvidenceForCwd } from '../ralplan/consensus-gate.js';
|
|
20
|
-
import { KEYWORD_TRIGGER_DEFINITIONS, compareKeywordMatches } from './keyword-registry.js';
|
|
20
|
+
import { getExplicitSkillDefinition, KEYWORD_TRIGGER_DEFINITIONS, compareKeywordMatches } from './keyword-registry.js';
|
|
21
21
|
import { readTeamModeConfig } from '../config/team-mode.js';
|
|
22
22
|
import { SKILL_ACTIVE_STATE_FILE, listActiveSkills, writeSkillActiveStateCopiesForStateDir, } from '../state/skill-active.js';
|
|
23
23
|
import { buildWorkflowTransitionError, evaluateWorkflowTransition, isTrackedWorkflowMode, } from '../state/workflow-transition.js';
|
|
@@ -30,6 +30,17 @@ import { deriveAutopilotChildPhase, AUTOPILOT_CHILD_PHASES } from '../autopilot/
|
|
|
30
30
|
import { canAdvanceAutopilotDeepInterviewToRalplan } from '../autopilot/deep-interview-gate.js';
|
|
31
31
|
import { canAdvanceAutopilotRalplanToUltragoal } from '../autopilot/ralplan-gate.js';
|
|
32
32
|
import { validateAutopilotCompletionTransition } from '../autopilot/completion-gate.js';
|
|
33
|
+
import { preflightSelectedTargetOwner, extractSelectedTargetOwnerEvidence, } from './prompt-session-provenance.js';
|
|
34
|
+
/** Stable diagnostic precedence for explicit candidates. */
|
|
35
|
+
export const KEYWORD_INERT_DIAGNOSTIC_ORDER = Object.freeze([
|
|
36
|
+
'fenced-code',
|
|
37
|
+
'indented-code',
|
|
38
|
+
'blockquote',
|
|
39
|
+
'inline-code',
|
|
40
|
+
'quote',
|
|
41
|
+
'escaped',
|
|
42
|
+
'not-leading-region',
|
|
43
|
+
]);
|
|
33
44
|
const ACTIVE_SKILL_CONTINUATION_PATTERNS = [
|
|
34
45
|
/^[\\/]?\s*keep going(?:\s+now)?[.!]?\s*$/i,
|
|
35
46
|
/^[\\/]?\s*continue(?:\s+now)?[.!]?\s*$/i,
|
|
@@ -350,6 +361,7 @@ export async function persistDeepInterviewModeState(stateDir, nextSkill, nowIso,
|
|
|
350
361
|
started_at: previousModeState?.active ? previousModeState.started_at || nowIso : nowIso,
|
|
351
362
|
updated_at: nowIso,
|
|
352
363
|
session_id: input.sessionId ?? previousModeState?.session_id,
|
|
364
|
+
owner_codex_session_id: nextSkill.owner_codex_session_id ?? previousModeState?.owner_codex_session_id,
|
|
353
365
|
thread_id: input.threadId ?? previousModeState?.thread_id,
|
|
354
366
|
turn_id: input.turnId ?? previousModeState?.turn_id,
|
|
355
367
|
...configStateFields,
|
|
@@ -376,6 +388,7 @@ export async function persistDeepInterviewModeState(stateDir, nextSkill, nowIso,
|
|
|
376
388
|
updated_at: nowIso,
|
|
377
389
|
completed_at: nowIso,
|
|
378
390
|
session_id: input.sessionId ?? previousModeState?.session_id ?? previousSkill?.session_id,
|
|
391
|
+
owner_codex_session_id: nextSkill?.owner_codex_session_id ?? previousModeState?.owner_codex_session_id ?? previousSkill?.owner_codex_session_id,
|
|
379
392
|
thread_id: input.threadId ?? previousModeState?.thread_id ?? previousSkill?.thread_id,
|
|
380
393
|
turn_id: input.turnId ?? previousModeState?.turn_id ?? previousSkill?.turn_id,
|
|
381
394
|
...(releasedInputLock ? { input_lock: releasedInputLock } : {}),
|
|
@@ -420,7 +433,7 @@ async function persistStatefulSkillSeedState(stateDir, nextSkill, nowIso, previo
|
|
|
420
433
|
const config = STATEFUL_SKILL_SEED_CONFIG[nextSkill.skill];
|
|
421
434
|
if (!config)
|
|
422
435
|
return nextSkill;
|
|
423
|
-
const { absolutePath, relativePath } = resolveSeedStateFilePath(stateDir, config.mode, nextSkill.session_id, config.scope);
|
|
436
|
+
const { absolutePath, relativePath } = resolveSeedStateFilePath(stateDir, config.mode, nextSkill.session_id, options.forceSessionScope ? 'session' : config.scope);
|
|
424
437
|
const existingModeStateResult = await readJsonStateWithStatus(absolutePath);
|
|
425
438
|
const existingModeState = existingModeStateResult.state;
|
|
426
439
|
const sameActiveSkill = previousSkill?.skill === nextSkill.skill && previousSkill.active;
|
|
@@ -450,6 +463,7 @@ async function persistStatefulSkillSeedState(stateDir, nextSkill, nowIso, previo
|
|
|
450
463
|
started_at: startedAt,
|
|
451
464
|
updated_at: nowIso,
|
|
452
465
|
session_id: nextSkill.session_id || safeString(existingModeState?.session_id).trim() || undefined,
|
|
466
|
+
owner_codex_session_id: nextSkill.owner_codex_session_id || safeString(existingModeState?.owner_codex_session_id).trim() || undefined,
|
|
453
467
|
thread_id: nextSkill.thread_id || safeString(existingModeState?.thread_id).trim() || undefined,
|
|
454
468
|
turn_id: nextSkill.turn_id || safeString(existingModeState?.turn_id).trim() || undefined,
|
|
455
469
|
}, { nowIso });
|
|
@@ -569,6 +583,7 @@ function keywordToPattern(keyword) {
|
|
|
569
583
|
return new RegExp(`${prefix}${escaped}${suffix}`, 'i');
|
|
570
584
|
}
|
|
571
585
|
const KEYWORD_MAP = KEYWORD_TRIGGER_DEFINITIONS.map((entry) => ({
|
|
586
|
+
keyword: entry.keyword,
|
|
572
587
|
pattern: keywordToPattern(entry.keyword),
|
|
573
588
|
skill: entry.skill,
|
|
574
589
|
priority: entry.priority,
|
|
@@ -653,8 +668,215 @@ const KEYWORD_INTENT_PATTERNS = {
|
|
|
653
668
|
/\bautopilot\s+(?:mode|workflow|skill|loop)\b/i,
|
|
654
669
|
],
|
|
655
670
|
};
|
|
656
|
-
|
|
657
|
-
|
|
671
|
+
const EXPLICIT_TOKEN_START = /\$(?:(?:[Oo][Hh]-[Mm][Yy]-[Cc][Oo][Dd][Ee][Xx]):)?([A-Za-z][A-Za-z0-9_-]*)/gyu;
|
|
672
|
+
const TOKEN_CONTINUATION = /[\p{L}\p{N}\p{M}\p{Pc}\p{Pd}]/u;
|
|
673
|
+
const SAFE_TOKEN_WHITESPACE = /[\p{Zs}\t\n\r\f\v\u2028\u2029]/u;
|
|
674
|
+
const EXPLICIT_TOKEN_BOUNDARY_PUNCTUATION = /[,;؛!?:؟)\]}"'”’»›」』—–…。、،]/u;
|
|
675
|
+
const DIRECTIVE_PUNCTUATION = /[,;؛:!?؟?、،]/u;
|
|
676
|
+
const CLAUSE_BOUNDARY_PUNCTUATION = /[,;؛.!?؟?。!?:،、\r\n\u2013\u2014\u2028\u2029]/u;
|
|
677
|
+
const LOGICAL_SENTENCE_BOUNDARY_PUNCTUATION = /[;؛.!?؟?。!?]/u;
|
|
678
|
+
function asciiCaseWordPattern(word) {
|
|
679
|
+
return [...word].map((character) => `[${character.toUpperCase()}${character.toLowerCase()}]`).join('');
|
|
680
|
+
}
|
|
681
|
+
const ASCII_DIRECTIVE_VERB = `(?:${['use', 'run', 'start', 'enable', 'launch', 'invoke', 'activate', 'resume', 'continue'].map(asciiCaseWordPattern).join('|')})`;
|
|
682
|
+
const ASCII_PLEASE = asciiCaseWordPattern('please');
|
|
683
|
+
const ASCII_INSTEAD = asciiCaseWordPattern('instead');
|
|
684
|
+
const ASCII_AND = asciiCaseWordPattern('and');
|
|
685
|
+
const ASCII_BUT = asciiCaseWordPattern('but');
|
|
686
|
+
const ASCII_THEN = asciiCaseWordPattern('then');
|
|
687
|
+
const ASCII_NOW = asciiCaseWordPattern('now');
|
|
688
|
+
const ASCII_THE = asciiCaseWordPattern('the');
|
|
689
|
+
const ASCII_WITH = asciiCaseWordPattern('with');
|
|
690
|
+
const ASCII_JUMP = asciiCaseWordPattern('jump');
|
|
691
|
+
const ASCII_STRAIGHT = asciiCaseWordPattern('straight');
|
|
692
|
+
const ASCII_TO = asciiCaseWordPattern('to');
|
|
693
|
+
const ASCII_ADVANCE = asciiCaseWordPattern('advance');
|
|
694
|
+
const ASCII_DIRECTIVE_COMMAND = `(?:${asciiCaseWordPattern('continue')}\\s+${ASCII_WITH}|${ASCII_JUMP}\\s+${ASCII_STRAIGHT}\\s+${ASCII_TO}|${ASCII_ADVANCE}\\s+${ASCII_TO}|${ASCII_DIRECTIVE_VERB})`;
|
|
695
|
+
const DIRECTIVE_COMMAND_PREFIX_SOURCE = `(?:(?:${ASCII_PLEASE}\\s+)?(?:(?:${ASCII_INSTEAD}|${ASCII_THEN}|${ASCII_NOW})\\s+)?${ASCII_DIRECTIVE_COMMAND}\\s+|(?:${ASCII_PLEASE}\\s+)?(?:${ASCII_INSTEAD}|${ASCII_THEN}|${ASCII_NOW}|${ASCII_PLEASE})\\s+|(?:${ASCII_AND}|${ASCII_BUT})\\s+(?:${ASCII_PLEASE}\\s+)?(?:${ASCII_INSTEAD}\\s+)?${ASCII_DIRECTIVE_COMMAND}\\s+)(?:${ASCII_THE}\\s+)?`;
|
|
696
|
+
const DIRECTIVE_COMMAND_PREFIX_AT = new RegExp(DIRECTIVE_COMMAND_PREFIX_SOURCE, 'yu');
|
|
697
|
+
const EXCLUSION_PREFIX = `(?:${['ignore', 'discard', 'skip', 'omit', 'forget', 'disregard', 'except'].map(asciiCaseWordPattern).join('|')}|${asciiCaseWordPattern('exclude')}(?:${asciiCaseWordPattern('ing')})?)`;
|
|
698
|
+
const ASCII_NEGATIVE_PREFIX = `(?:${asciiCaseWordPattern('do')}\\s+${asciiCaseWordPattern('not')}|${asciiCaseWordPattern('don')}'${asciiCaseWordPattern('t')}|${asciiCaseWordPattern('without')}|${asciiCaseWordPattern('never')}|${asciiCaseWordPattern('not')}|${asciiCaseWordPattern('no')}|${asciiCaseWordPattern('neither')}|${asciiCaseWordPattern('nor')}|${asciiCaseWordPattern('avoid')}(?:${asciiCaseWordPattern('ing')})?|${asciiCaseWordPattern('cannot')}|${asciiCaseWordPattern('can')}'${asciiCaseWordPattern('t')}|${EXCLUSION_PREFIX})`;
|
|
699
|
+
const NEGATIVE_PREFIX_PATTERN = new RegExp(`(?:${ASCII_NEGATIVE_PREFIX}|[Нн][Ее]\\s+(?:[Зз]апускай|[Ии]спользуй)|実行しないで|使わないで)`, 'u');
|
|
700
|
+
const LIST_DOCUMENTATION_SUFFIX = /^(?:\s*(?::|:|[—–])\s*\S|\s+(?:is|are|means|refer(?:s)?\s+to|denote(?:s)?)\b.*\b(?:commands?|workflows?|skills?|modes?|files?|documentation)\b)/i;
|
|
701
|
+
const EXPLICIT_DOCUMENTATION_SUFFIX_SOURCE = String.raw `\s+(?:(?:is|are|means|refer(?:s)?\s+to|denote(?:s)?)\b.*\b(?:commands?|workflows?|skills?|modes?|files?|documentation)\b|(?:is|are)\s+(?:(?:also|still)\s+)?(?:(?:its|an?|the)\s+)?alias(?:es)?\b|(?:is|are)\s+(?:(?:also|still)\s+)?(?:documented|described)\b|(?:appears?|occurs?|is\s+(?:also\s+)?mentioned)\b.*\b(?:docs?|documentation|examples?|references?|guide|manual)\b)`;
|
|
702
|
+
const EXPLICIT_DOCUMENTATION_SUFFIX_AT = new RegExp(EXPLICIT_DOCUMENTATION_SUFFIX_SOURCE, 'iyu');
|
|
703
|
+
const IMPLICIT_WORKFLOW_NOUN = '(?:modes?|workflows?|skills?|loops?)';
|
|
704
|
+
const POSTPOSED_NEGATIVE_PREDICATE = /\s+(?:(?:is|are|was|were|should|must|can|could|may|will|would)\s+(?:(?:also|still)\s+)?(?:not|never)\b|(?:isn't|aren't|wasn't|weren't|cannot|can't|shouldn't|mustn't|won't|wouldn't|couldn't)\b|(?:is|are|was|were)\s+(?:(?:also|still)\s+)?(?:inert|prohibited|forbidden|disabled|disallowed|unsupported)\b|(?:should|must|can|could|may|will|would)\s+(?:(?:also|still)\s+)?(?:not\s+)?be\s+(?:inert|avoided|prohibited|forbidden|disabled|disallowed|unsupported)\b|(?:is|are|was|were)\s+(?:(?:also|still)\s+)?to\s+be\s+(?:inert|avoided|prohibited|forbidden|disabled|disallowed|unsupported)\b)/iu;
|
|
705
|
+
const PROMPTS_TOKEN_PATTERN = /\/[Pp][Rr][Oo][Mm][Pp][Tt][Ss]:[\w.-]+/gu;
|
|
706
|
+
const COORDINATED_WORKFLOW_SUBJECT = '(?:(?:the|a|an)\\s+)?(?:autopilot|deep(?:[- ]+)interview|ralph|ralplan|ultrawork|ulw|ultragoal|ultraqa|autoresearch|coordinated\\s+team|team|consensus\\s+plan|code\\s+review|wiki|prometheus(?:-strict)?)';
|
|
707
|
+
const COORDINATED_SUBJECT_JOINER = '(?:and|or|nor|as\\s+well\\s+as|along\\s+with|together\\s+with|&)';
|
|
708
|
+
const EXPLICIT_POSTPOSED_SUBJECT = '\\$(?:oh-my-codex:)?[A-Za-z][A-Za-z0-9_-]*';
|
|
709
|
+
const COORDINATED_POSTPOSED_SEPARATOR_SOURCE = `\\s*(?:(?:[,,،、]|/)\\s*(?:${COORDINATED_SUBJECT_JOINER}\\s+)?|${COORDINATED_SUBJECT_JOINER}\\s+)`;
|
|
710
|
+
const COORDINATED_EXPLICIT_POSTPOSED_SEPARATOR = new RegExp(COORDINATED_POSTPOSED_SEPARATOR_SOURCE, 'iyu');
|
|
711
|
+
const COORDINATED_EXPLICIT_POSTPOSED_SUBJECT = new RegExp(`(?:(?:the|a|an)\\s+)?(?:${EXPLICIT_POSTPOSED_SUBJECT}|${COORDINATED_WORKFLOW_SUBJECT})`, 'iyu');
|
|
712
|
+
const COORDINATED_IMPLICIT_DOCUMENTATION_SUBJECT = new RegExp(`${COORDINATED_WORKFLOW_SUBJECT}(?:\\s+${IMPLICIT_WORKFLOW_NOUN})?`, 'iyu');
|
|
713
|
+
const COORDINATED_SUBJECT_QUANTIFIER = new RegExp(asciiCaseWordPattern('both'), 'yu');
|
|
714
|
+
const POSTPOSED_SUBJECT_NOUN = new RegExp(`\\s+${IMPLICIT_WORKFLOW_NOUN}`, 'iyu');
|
|
715
|
+
const IMPLICIT_POSTPOSED_SUBJECT_CHAIN = new RegExp(`^\\s*(?:${asciiCaseWordPattern('both')}\\s+)?${COORDINATED_WORKFLOW_SUBJECT}(?:\\s+${IMPLICIT_WORKFLOW_NOUN})?(?:${COORDINATED_POSTPOSED_SEPARATOR_SOURCE}${COORDINATED_WORKFLOW_SUBJECT}(?:\\s+${IMPLICIT_WORKFLOW_NOUN})?)*\\s*[,,،、]?\\s*$`, 'iu');
|
|
716
|
+
const IMPLICIT_DOCUMENTATION_SUBJECT_PATTERN = new RegExp(`^\\s*${COORDINATED_WORKFLOW_SUBJECT}(?:\\s+${IMPLICIT_WORKFLOW_NOUN})?(?:\\s+(?:(?:is|are|means|refer(?:s)?\\s+to|denote(?:s)?)\\b.*\\b(?:commands?|workflows?|skills?|modes?|files?|documentation)\\b|(?:is|are)\\s+(?:(?:documented|described)\\b|(?:(?:also|still)\\s+)?(?:(?:its|an?|the)\\s+)?alias(?:es)?\\b)|(?:appears?|occurs?|is\\s+(?:also\\s+)?mentioned)\\b.*\\b(?:docs?|documentation|examples?|references?|guide|manual)\\b)|\\s*(?::|:|[—–-]|\\/)\\s*\\S.*\\b(?:commands?|workflows?|skills?|modes?|files?|documentation)\\b)[.!?]?`, 'iu');
|
|
717
|
+
const DOCUMENTATION_LEADING_PATTERN = new RegExp(`^\\s*(?:(?:the|a|an)\\s+)?(?:docs?|documentation|examples?|references?|guide|manual)\\b.*\\b(?:mention(?:s|ed|ing)?|document(?:s|ed|ing)?|describ(?:e|es|ed|ing)|explain(?:s|ed|ing)|refer(?:s|red|ring)?\\s+to)\\b.*\\b${COORDINATED_WORKFLOW_SUBJECT}(?:\\s+${IMPLICIT_WORKFLOW_NOUN})?\\b`, 'iu');
|
|
718
|
+
function hasImplicitDocumentationSubjectPrefix(text) {
|
|
719
|
+
return IMPLICIT_DOCUMENTATION_SUBJECT_PATTERN.test(text);
|
|
720
|
+
}
|
|
721
|
+
function normalizeGrammarApostrophes(text) {
|
|
722
|
+
return text.replace(/[’']/gu, "'");
|
|
723
|
+
}
|
|
724
|
+
function latestPositiveContrastStart(text) {
|
|
725
|
+
const pattern = new RegExp(`${ASCII_BUT}\\s+(?:${ASCII_PLEASE}\\s+)?(?:${ASCII_INSTEAD}\\s+)?(?=${ASCII_DIRECTIVE_COMMAND})`, 'gu');
|
|
726
|
+
let start = -1;
|
|
727
|
+
let match;
|
|
728
|
+
while ((match = pattern.exec(text)) !== null) {
|
|
729
|
+
if (hasUnicodeGrammarTokenStart(text, match.index))
|
|
730
|
+
start = match.index;
|
|
731
|
+
}
|
|
732
|
+
return start;
|
|
733
|
+
}
|
|
734
|
+
function hasAsciiDirectiveCommand(text) {
|
|
735
|
+
const scanner = new RegExp(ASCII_DIRECTIVE_COMMAND, 'gu');
|
|
736
|
+
let match;
|
|
737
|
+
while ((match = scanner.exec(text)) !== null) {
|
|
738
|
+
if (hasUnicodeGrammarTokenBoundaries(text, match.index, scanner.lastIndex))
|
|
739
|
+
return true;
|
|
740
|
+
}
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
743
|
+
function isDiscourseNegation(text, start, end) {
|
|
744
|
+
const suffix = text.slice(end);
|
|
745
|
+
if (/^\s+worries\s*[,,،、]/iu.test(suffix))
|
|
746
|
+
return true;
|
|
747
|
+
return /(?:^|\s)i'm\s+$/iu.test(text.slice(0, start))
|
|
748
|
+
&& /^\s+sure\s*[,,،、]/iu.test(suffix);
|
|
749
|
+
}
|
|
750
|
+
function hasUnicodeBoundedNegativePrefix(text) {
|
|
751
|
+
const scanner = new RegExp(NEGATIVE_PREFIX_PATTERN.source, 'gu');
|
|
752
|
+
let match;
|
|
753
|
+
while ((match = scanner.exec(text)) !== null) {
|
|
754
|
+
if (hasUnicodeGrammarTokenBoundaries(text, match.index, scanner.lastIndex)
|
|
755
|
+
&& !isDiscourseNegation(text, match.index, scanner.lastIndex))
|
|
756
|
+
return true;
|
|
757
|
+
}
|
|
758
|
+
return false;
|
|
759
|
+
}
|
|
760
|
+
function isNegativePrefixExemptImplicitKeyword(keyword) {
|
|
761
|
+
const normalized = keyword.toLowerCase();
|
|
762
|
+
return normalized === "don't stop" || normalized === "don't assume";
|
|
763
|
+
}
|
|
764
|
+
function normalizedPunctuation(character) {
|
|
765
|
+
return character.normalize('NFKC');
|
|
766
|
+
}
|
|
767
|
+
function isDirectivePunctuation(character) {
|
|
768
|
+
return DIRECTIVE_PUNCTUATION.test(normalizedPunctuation(character));
|
|
769
|
+
}
|
|
770
|
+
function isClauseBoundaryAt(text, index) {
|
|
771
|
+
const character = codePointAt(text, index);
|
|
772
|
+
const normalized = normalizedPunctuation(character);
|
|
773
|
+
if (!CLAUSE_BOUNDARY_PUNCTUATION.test(normalized))
|
|
774
|
+
return false;
|
|
775
|
+
if (normalized !== '.')
|
|
776
|
+
return true;
|
|
777
|
+
const next = codePointAt(text, index + character.length);
|
|
778
|
+
return !next || SAFE_TOKEN_WHITESPACE.test(next) || /["'”’»›」』))\]}]/u.test(next);
|
|
779
|
+
}
|
|
780
|
+
function isLogicalSentenceBoundaryAt(text, index) {
|
|
781
|
+
const character = codePointAt(text, index);
|
|
782
|
+
const normalized = normalizedPunctuation(character);
|
|
783
|
+
return LOGICAL_SENTENCE_BOUNDARY_PUNCTUATION.test(normalized) && isClauseBoundaryAt(text, index);
|
|
784
|
+
}
|
|
785
|
+
function documentationSuffixLimit(text, start, limit) {
|
|
786
|
+
for (let cursor = start; cursor < limit;) {
|
|
787
|
+
if (isStrongDocumentationClauseSeparatorAt(text, cursor))
|
|
788
|
+
return cursor;
|
|
789
|
+
cursor += codePointAt(text, cursor).length;
|
|
790
|
+
}
|
|
791
|
+
return limit;
|
|
792
|
+
}
|
|
793
|
+
function hasExplicitDocumentationSuffixAt(text, start, limit) {
|
|
794
|
+
const clauseLimit = documentationSuffixLimit(text, start, limit);
|
|
795
|
+
EXPLICIT_DOCUMENTATION_SUFFIX_AT.lastIndex = 0;
|
|
796
|
+
return EXPLICIT_DOCUMENTATION_SUFFIX_AT.exec(text.slice(start, clauseLimit)) !== null;
|
|
797
|
+
}
|
|
798
|
+
function isAbbreviationDotAt(text, index) {
|
|
799
|
+
const context = text.slice(Math.max(0, index - 8), index + 1);
|
|
800
|
+
return /(?:^|[^A-Za-z0-9_])(?:e\.g|i\.e|etc|vs|mr|mrs|ms|dr|prof|sr|jr|st|no|fig|ver|v)\.$/i.test(context);
|
|
801
|
+
}
|
|
802
|
+
function hasLogicalSentenceBoundary(text) {
|
|
803
|
+
for (let cursor = 0; cursor < text.length;) {
|
|
804
|
+
const character = codePointAt(text, cursor);
|
|
805
|
+
if (character === '\r' || character === '\n' || character === '\u2028' || character === '\u2029')
|
|
806
|
+
return true;
|
|
807
|
+
if (isLogicalSentenceBoundaryAt(text, cursor)) {
|
|
808
|
+
if (normalizedPunctuation(character) !== '.' || !isAbbreviationDotAt(text, cursor))
|
|
809
|
+
return true;
|
|
810
|
+
}
|
|
811
|
+
cursor += character.length;
|
|
812
|
+
}
|
|
813
|
+
return false;
|
|
814
|
+
}
|
|
815
|
+
function codePointAt(text, index) {
|
|
816
|
+
const value = text.codePointAt(index);
|
|
817
|
+
return value === undefined ? '' : String.fromCodePoint(value);
|
|
818
|
+
}
|
|
819
|
+
function codePointBefore(text, index) {
|
|
820
|
+
if (index <= 0)
|
|
821
|
+
return '';
|
|
822
|
+
const trailing = text.charCodeAt(index - 1);
|
|
823
|
+
if (trailing >= 0xDC00 && trailing <= 0xDFFF && index >= 2) {
|
|
824
|
+
const leading = text.charCodeAt(index - 2);
|
|
825
|
+
if (leading >= 0xD800 && leading <= 0xDBFF)
|
|
826
|
+
return text.slice(index - 2, index);
|
|
827
|
+
}
|
|
828
|
+
return text[index - 1] ?? '';
|
|
829
|
+
}
|
|
830
|
+
function hasUnicodeGrammarTokenStart(text, start) {
|
|
831
|
+
const previous = codePointBefore(text, start);
|
|
832
|
+
return !previous || !TOKEN_CONTINUATION.test(previous);
|
|
833
|
+
}
|
|
834
|
+
/** ASCII grammar words cannot begin or end inside a Unicode identifier-like token. */
|
|
835
|
+
function hasUnicodeGrammarTokenBoundaries(text, start, end) {
|
|
836
|
+
const next = codePointAt(text, end);
|
|
837
|
+
return hasUnicodeGrammarTokenStart(text, start)
|
|
838
|
+
&& (!next || !TOKEN_CONTINUATION.test(next));
|
|
839
|
+
}
|
|
840
|
+
function firstGrammarTokenStart(text, start, end) {
|
|
841
|
+
let cursor = start;
|
|
842
|
+
while (cursor < end && SAFE_TOKEN_WHITESPACE.test(codePointAt(text, cursor)))
|
|
843
|
+
cursor += codePointAt(text, cursor).length;
|
|
844
|
+
return cursor;
|
|
845
|
+
}
|
|
846
|
+
function hasAsciiGrammarTokenCharacters(text, start, end) {
|
|
847
|
+
for (let cursor = start; cursor < end;) {
|
|
848
|
+
const character = codePointAt(text, cursor);
|
|
849
|
+
if (TOKEN_CONTINUATION.test(character) && !/^[A-Za-z0-9_-]$/u.test(character))
|
|
850
|
+
return false;
|
|
851
|
+
cursor += character.length;
|
|
852
|
+
}
|
|
853
|
+
return true;
|
|
854
|
+
}
|
|
855
|
+
function isExplicitTokenBoundary(text, index) {
|
|
856
|
+
if (index >= text.length)
|
|
857
|
+
return true;
|
|
858
|
+
const character = codePointAt(text, index);
|
|
859
|
+
if (SAFE_TOKEN_WHITESPACE.test(character))
|
|
860
|
+
return true;
|
|
861
|
+
const compatibility = character.normalize('NFKC');
|
|
862
|
+
if (compatibility === '.') {
|
|
863
|
+
const next = codePointAt(text, index + character.length);
|
|
864
|
+
return !next || SAFE_TOKEN_WHITESPACE.test(next) || next === '$';
|
|
865
|
+
}
|
|
866
|
+
if (character === "'" || character === '’' || compatibility === "'") {
|
|
867
|
+
const next = codePointAt(text, index + character.length);
|
|
868
|
+
return !next || !TOKEN_CONTINUATION.test(next);
|
|
869
|
+
}
|
|
870
|
+
if ([...compatibility].length === 1 && EXPLICIT_TOKEN_BOUNDARY_PUNCTUATION.test(compatibility))
|
|
871
|
+
return true;
|
|
872
|
+
return EXPLICIT_TOKEN_BOUNDARY_PUNCTUATION.test(character);
|
|
873
|
+
}
|
|
874
|
+
function maximalExplicitTokenEnd(text, initialEnd) {
|
|
875
|
+
let cursor = initialEnd;
|
|
876
|
+
while (cursor < text.length && !isExplicitTokenBoundary(text, cursor)) {
|
|
877
|
+
cursor += codePointAt(text, cursor).length;
|
|
878
|
+
}
|
|
879
|
+
return cursor;
|
|
658
880
|
}
|
|
659
881
|
/**
|
|
660
882
|
* Korean 2-set keyboard typo aliases for workflow keywords.
|
|
@@ -664,51 +886,1852 @@ function hasExplicitPromptsInvocation(text) {
|
|
|
664
886
|
* as the canonical keyword without introducing broad transliteration surprises.
|
|
665
887
|
*/
|
|
666
888
|
function normalizeWorkflowKeyboardTypos(text) {
|
|
667
|
-
return text.replace(/ㅕㅣㅈ/g, 'ulw');
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
889
|
+
return text.replace(/\$ㅕㅣㅈ(?=로)/g, '$ulw ').replace(/ㅕㅣㅈ/g, 'ulw');
|
|
890
|
+
}
|
|
891
|
+
const STRUCTURAL_INERT_DIAGNOSTICS = [
|
|
892
|
+
'fenced-code',
|
|
893
|
+
'indented-code',
|
|
894
|
+
'blockquote',
|
|
895
|
+
'inline-code',
|
|
896
|
+
'quote',
|
|
897
|
+
];
|
|
898
|
+
const QUOTE_CLOSERS = Object.freeze({
|
|
899
|
+
'“': '”',
|
|
900
|
+
'‘': '’',
|
|
901
|
+
'„': '“',
|
|
902
|
+
'‚': '‘',
|
|
903
|
+
'«': '»',
|
|
904
|
+
'‹': '›',
|
|
905
|
+
'「': '」',
|
|
906
|
+
'『': '』',
|
|
907
|
+
});
|
|
908
|
+
const LETTER_OR_NUMBER = /[\p{L}\p{N}]/u;
|
|
909
|
+
function lineEnd(text, start) {
|
|
910
|
+
for (let cursor = start; cursor < text.length; cursor += 1) {
|
|
911
|
+
const character = text[cursor];
|
|
912
|
+
if (character === '\r' || character === '\n' || character === '\u2028' || character === '\u2029')
|
|
913
|
+
return cursor;
|
|
914
|
+
}
|
|
915
|
+
return text.length;
|
|
916
|
+
}
|
|
917
|
+
function nextLineStart(text, end) {
|
|
918
|
+
return text[end] === '\r' && text[end + 1] === '\n' ? end + 2 : end + 1;
|
|
919
|
+
}
|
|
920
|
+
function advanceSpaces(text, start, maximum) {
|
|
921
|
+
let cursor = start;
|
|
922
|
+
while (cursor - start < maximum && text[cursor] === ' ')
|
|
923
|
+
cursor += 1;
|
|
924
|
+
return cursor;
|
|
925
|
+
}
|
|
926
|
+
function markdownContainerPrefix(line, maximumLeadingSpaces = 3) {
|
|
927
|
+
let cursor = advanceSpaces(line, 0, maximumLeadingSpaces);
|
|
928
|
+
let blockquoteDepth = 0;
|
|
929
|
+
let listDepth = 0;
|
|
930
|
+
while (cursor < line.length) {
|
|
931
|
+
if (line[cursor] === '>') {
|
|
932
|
+
blockquoteDepth += 1;
|
|
933
|
+
cursor += 1;
|
|
934
|
+
if (line[cursor] === ' ' || line[cursor] === '\t')
|
|
935
|
+
cursor += 1;
|
|
936
|
+
cursor = advanceSpaces(line, cursor, 3);
|
|
937
|
+
continue;
|
|
938
|
+
}
|
|
939
|
+
const listMarker = /^(?:(?:[-*+])|(?:\d{1,9}[.)]))[\t ]+/u.exec(line.slice(cursor));
|
|
940
|
+
if (!listMarker)
|
|
941
|
+
break;
|
|
942
|
+
listDepth += 1;
|
|
943
|
+
cursor += listMarker[0].length;
|
|
944
|
+
cursor = advanceSpaces(line, cursor, 3);
|
|
945
|
+
}
|
|
946
|
+
return { cursor, blockquoteDepth, listDepth };
|
|
947
|
+
}
|
|
948
|
+
function markdownFenceAtStart(line, maximumLeadingSpaces = 3) {
|
|
949
|
+
const container = markdownContainerPrefix(line, maximumLeadingSpaces);
|
|
950
|
+
let cursor = container.cursor;
|
|
951
|
+
const marker = line[cursor];
|
|
952
|
+
if (marker !== '`' && marker !== '~')
|
|
953
|
+
return null;
|
|
954
|
+
const start = cursor;
|
|
955
|
+
while (line[cursor] === marker)
|
|
956
|
+
cursor += 1;
|
|
957
|
+
const length = cursor - start;
|
|
958
|
+
return length >= 3
|
|
959
|
+
? { marker, length, blockquoteDepth: container.blockquoteDepth, listItem: container.listDepth > 0, indent: start, closingEligible: /^[\t ]*$/.test(line.slice(cursor)) }
|
|
960
|
+
: null;
|
|
961
|
+
}
|
|
962
|
+
function isBlockquoteLine(line) {
|
|
963
|
+
return markdownContainerPrefix(line).blockquoteDepth > 0;
|
|
964
|
+
}
|
|
965
|
+
function hasMarkdownCodeIndent(line) {
|
|
966
|
+
let columns = 0;
|
|
967
|
+
for (const character of line) {
|
|
968
|
+
if (character === ' ')
|
|
969
|
+
columns += 1;
|
|
970
|
+
else if (character === '\t')
|
|
971
|
+
columns += 4 - (columns % 4);
|
|
972
|
+
else
|
|
973
|
+
break;
|
|
974
|
+
if (columns >= 4)
|
|
975
|
+
return true;
|
|
976
|
+
}
|
|
977
|
+
return false;
|
|
978
|
+
}
|
|
979
|
+
function hasListContainedCodeIndent(line) {
|
|
980
|
+
const leading = /^[ \t]{0,3}/u.exec(line)?.[0] ?? '';
|
|
981
|
+
let cursor = leading.length;
|
|
982
|
+
let column = 0;
|
|
983
|
+
for (const character of leading)
|
|
984
|
+
column += character === '\t' ? 4 - (column % 4) : 1;
|
|
985
|
+
while (cursor < line.length) {
|
|
986
|
+
const marker = /^(?:[-+*]|\d{1,9}[.)])/u.exec(line.slice(cursor));
|
|
987
|
+
if (!marker)
|
|
988
|
+
return false;
|
|
989
|
+
for (const character of marker[0])
|
|
990
|
+
column += character === '\t' ? 4 - (column % 4) : 1;
|
|
991
|
+
cursor += marker[0].length;
|
|
992
|
+
const gap = /^[ \t]+/u.exec(line.slice(cursor))?.[0];
|
|
993
|
+
if (!gap)
|
|
994
|
+
return false;
|
|
995
|
+
const markerEndColumn = column;
|
|
996
|
+
for (const character of gap)
|
|
997
|
+
column += character === '\t' ? 4 - (column % 4) : 1;
|
|
998
|
+
cursor += gap.length;
|
|
999
|
+
if (column - markerEndColumn > 4)
|
|
1000
|
+
return true;
|
|
1001
|
+
}
|
|
1002
|
+
return false;
|
|
1003
|
+
}
|
|
1004
|
+
function collectIndentedCodeRanges(text) {
|
|
1005
|
+
const ranges = [];
|
|
1006
|
+
let lineStart = 0;
|
|
1007
|
+
while (lineStart <= text.length) {
|
|
1008
|
+
const end = lineEnd(text, lineStart);
|
|
1009
|
+
const line = text.slice(lineStart, end);
|
|
1010
|
+
if (hasMarkdownCodeIndent(line) || hasListContainedCodeIndent(line)) {
|
|
1011
|
+
ranges.push({ start: lineStart, end, reason: 'indented-code', bounded: true });
|
|
1012
|
+
}
|
|
1013
|
+
if (end === text.length)
|
|
1014
|
+
break;
|
|
1015
|
+
lineStart = nextLineStart(text, end);
|
|
1016
|
+
}
|
|
1017
|
+
return ranges;
|
|
1018
|
+
}
|
|
1019
|
+
function collectFencedCodeRanges(text) {
|
|
1020
|
+
const ranges = [];
|
|
1021
|
+
let lineStart = 0;
|
|
1022
|
+
let fence = null;
|
|
1023
|
+
while (lineStart <= text.length) {
|
|
1024
|
+
const end = lineEnd(text, lineStart);
|
|
1025
|
+
const line = text.slice(lineStart, end);
|
|
1026
|
+
if (fence) {
|
|
1027
|
+
const closer = markdownFenceAtStart(line, fence.definition.listItem ? fence.definition.indent + 3 : 3);
|
|
1028
|
+
if (closer?.marker === fence.definition.marker
|
|
1029
|
+
&& closer.length >= fence.definition.length
|
|
1030
|
+
&& closer.blockquoteDepth === fence.definition.blockquoteDepth
|
|
1031
|
+
&& !closer.listItem
|
|
1032
|
+
&& (!fence.definition.listItem || closer.indent >= fence.definition.indent)
|
|
1033
|
+
&& closer.closingEligible) {
|
|
1034
|
+
ranges.push({ start: fence.start, end, reason: 'fenced-code', bounded: true });
|
|
1035
|
+
fence = null;
|
|
1036
|
+
}
|
|
1037
|
+
else if (fence.definition.listItem) {
|
|
1038
|
+
const rootFence = markdownFenceAtStart(line);
|
|
1039
|
+
if (rootFence && rootFence.indent < fence.definition.indent) {
|
|
1040
|
+
ranges.push({ start: fence.start, end: lineStart, reason: 'fenced-code', bounded: true });
|
|
1041
|
+
fence = { definition: rootFence, start: lineStart };
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
else {
|
|
1046
|
+
const opener = markdownFenceAtStart(line);
|
|
1047
|
+
if (opener)
|
|
1048
|
+
fence = { definition: opener, start: lineStart };
|
|
1049
|
+
}
|
|
1050
|
+
if (end === text.length)
|
|
1051
|
+
break;
|
|
1052
|
+
lineStart = nextLineStart(text, end);
|
|
1053
|
+
}
|
|
1054
|
+
if (fence)
|
|
1055
|
+
ranges.push({ start: fence.start, end: text.length, reason: 'fenced-code', bounded: false });
|
|
1056
|
+
return ranges;
|
|
1057
|
+
}
|
|
1058
|
+
function collectInlineCodeRanges(text) {
|
|
1059
|
+
const ranges = [];
|
|
1060
|
+
let lineStart = 0;
|
|
1061
|
+
while (lineStart <= text.length) {
|
|
1062
|
+
const end = lineEnd(text, lineStart);
|
|
1063
|
+
let cursor = lineStart;
|
|
1064
|
+
let opener = null;
|
|
1065
|
+
while (cursor < end) {
|
|
1066
|
+
if (text[cursor] !== '`') {
|
|
1067
|
+
cursor += 1;
|
|
1068
|
+
continue;
|
|
1069
|
+
}
|
|
1070
|
+
let runEnd = cursor + 1;
|
|
1071
|
+
while (runEnd < end && text[runEnd] === '`')
|
|
1072
|
+
runEnd += 1;
|
|
1073
|
+
const length = runEnd - cursor;
|
|
1074
|
+
if (!opener)
|
|
1075
|
+
opener = { start: cursor, length };
|
|
1076
|
+
else if (opener.length === length) {
|
|
1077
|
+
ranges.push({ start: opener.start, end: runEnd, reason: 'inline-code', bounded: true });
|
|
1078
|
+
opener = null;
|
|
1079
|
+
}
|
|
1080
|
+
cursor = runEnd;
|
|
1081
|
+
}
|
|
1082
|
+
if (opener)
|
|
1083
|
+
ranges.push({ start: opener.start, end, reason: 'inline-code', bounded: false });
|
|
1084
|
+
if (end === text.length)
|
|
1085
|
+
break;
|
|
1086
|
+
lineStart = nextLineStart(text, end);
|
|
1087
|
+
}
|
|
1088
|
+
return ranges;
|
|
1089
|
+
}
|
|
1090
|
+
function collectQuoteRanges(text) {
|
|
1091
|
+
const ranges = [];
|
|
1092
|
+
let lineStart = 0;
|
|
1093
|
+
while (lineStart <= text.length) {
|
|
1094
|
+
const end = lineEnd(text, lineStart);
|
|
1095
|
+
let opener = null;
|
|
1096
|
+
for (let cursor = lineStart; cursor < end; cursor += 1) {
|
|
1097
|
+
const character = text[cursor];
|
|
1098
|
+
const previous = text[cursor - 1] ?? '';
|
|
1099
|
+
const next = text[cursor + 1] ?? '';
|
|
1100
|
+
if ((character === "'" || character === '’' || character === ''') && LETTER_OR_NUMBER.test(previous) && LETTER_OR_NUMBER.test(next))
|
|
1101
|
+
continue;
|
|
1102
|
+
if (!opener && (character === "'" || character === '’' || character === ''') && /[sS]/u.test(previous) && (!next || SAFE_TOKEN_WHITESPACE.test(next) || /[.,;:!?)}\]”’»›」』]/u.test(next)))
|
|
1103
|
+
continue;
|
|
1104
|
+
if (hasOddImmediateBackslashes(text, cursor))
|
|
1105
|
+
continue;
|
|
1106
|
+
if (opener && character === opener.closing) {
|
|
1107
|
+
ranges.push({ start: opener.start, end: cursor + 1, reason: 'quote', bounded: true });
|
|
1108
|
+
opener = null;
|
|
1109
|
+
continue;
|
|
1110
|
+
}
|
|
1111
|
+
if (!opener && (character === '"' || character === "'" || character === '"' || character === ''')) {
|
|
1112
|
+
opener = { start: cursor, closing: character };
|
|
1113
|
+
continue;
|
|
1114
|
+
}
|
|
1115
|
+
if (!opener && QUOTE_CLOSERS[character])
|
|
1116
|
+
opener = { start: cursor, closing: QUOTE_CLOSERS[character] };
|
|
1117
|
+
}
|
|
1118
|
+
if (opener)
|
|
1119
|
+
ranges.push({ start: opener.start, end, reason: 'quote', bounded: false });
|
|
1120
|
+
if (end === text.length)
|
|
1121
|
+
break;
|
|
1122
|
+
lineStart = nextLineStart(text, end);
|
|
1123
|
+
}
|
|
1124
|
+
return ranges;
|
|
1125
|
+
}
|
|
1126
|
+
function collectBlockquoteRanges(text) {
|
|
1127
|
+
const ranges = [];
|
|
1128
|
+
let lineStart = 0;
|
|
1129
|
+
while (lineStart <= text.length) {
|
|
1130
|
+
const end = lineEnd(text, lineStart);
|
|
1131
|
+
if (isBlockquoteLine(text.slice(lineStart, end))) {
|
|
1132
|
+
ranges.push({ start: lineStart, end, reason: 'blockquote', bounded: true });
|
|
1133
|
+
}
|
|
1134
|
+
if (end === text.length)
|
|
1135
|
+
break;
|
|
1136
|
+
lineStart = nextLineStart(text, end);
|
|
1137
|
+
}
|
|
1138
|
+
return ranges;
|
|
1139
|
+
}
|
|
1140
|
+
function createInertRangeIndex(ranges) {
|
|
1141
|
+
ranges.sort((a, b) => a.start - b.start || a.end - b.end);
|
|
1142
|
+
const starts = new Array(ranges.length);
|
|
1143
|
+
const maximumEnds = new Array(ranges.length);
|
|
1144
|
+
let maximumEnd = -1;
|
|
1145
|
+
for (const [index, range] of ranges.entries()) {
|
|
1146
|
+
starts[index] = range.start;
|
|
1147
|
+
maximumEnd = Math.max(maximumEnd, range.end);
|
|
1148
|
+
maximumEnds[index] = maximumEnd;
|
|
1149
|
+
}
|
|
1150
|
+
return { starts, maximumEnds };
|
|
1151
|
+
}
|
|
1152
|
+
function collectInertRangeIndexes(text) {
|
|
1153
|
+
return {
|
|
1154
|
+
'indented-code': createInertRangeIndex(collectIndentedCodeRanges(text)),
|
|
1155
|
+
'fenced-code': createInertRangeIndex(collectFencedCodeRanges(text)),
|
|
1156
|
+
blockquote: createInertRangeIndex(collectBlockquoteRanges(text)),
|
|
1157
|
+
'inline-code': createInertRangeIndex(collectInlineCodeRanges(text)),
|
|
1158
|
+
quote: createInertRangeIndex(collectQuoteRanges(text)),
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
function inertRangeEndAt(index, position) {
|
|
1162
|
+
let lower = 0;
|
|
1163
|
+
let upper = index.starts.length;
|
|
1164
|
+
while (lower < upper) {
|
|
1165
|
+
const middle = lower + Math.floor((upper - lower) / 2);
|
|
1166
|
+
if (index.starts[middle] <= position)
|
|
1167
|
+
lower = middle + 1;
|
|
1168
|
+
else
|
|
1169
|
+
upper = middle;
|
|
1170
|
+
}
|
|
1171
|
+
if (lower === 0)
|
|
1172
|
+
return null;
|
|
1173
|
+
const end = index.maximumEnds[lower - 1];
|
|
1174
|
+
return end > position ? end : null;
|
|
1175
|
+
}
|
|
1176
|
+
function isInInertRange(index, position) {
|
|
1177
|
+
return inertRangeEndAt(index, position) !== null;
|
|
1178
|
+
}
|
|
1179
|
+
function isStructurallyInert(indexes, position) {
|
|
1180
|
+
return STRUCTURAL_INERT_DIAGNOSTICS.some((reason) => isInInertRange(indexes[reason], position));
|
|
1181
|
+
}
|
|
1182
|
+
function structuralInertRangeEnd(indexes, position) {
|
|
1183
|
+
let end = -1;
|
|
1184
|
+
for (const reason of STRUCTURAL_INERT_DIAGNOSTICS)
|
|
1185
|
+
end = Math.max(end, inertRangeEndAt(indexes[reason], position) ?? -1);
|
|
1186
|
+
return end >= 0 ? end : null;
|
|
1187
|
+
}
|
|
1188
|
+
function lineStartForPosition(text, position) {
|
|
1189
|
+
for (let cursor = position - 1; cursor >= 0; cursor -= 1) {
|
|
1190
|
+
const character = text[cursor];
|
|
1191
|
+
if (character === '\n' || character === '\r' || character === '\u2028' || character === '\u2029')
|
|
1192
|
+
return cursor + 1;
|
|
1193
|
+
}
|
|
1194
|
+
return 0;
|
|
1195
|
+
}
|
|
1196
|
+
function leadingDirectiveCursor(text, regionStart, allowLineBreaks) {
|
|
1197
|
+
const whitespacePattern = allowLineBreaks ? /^\s*/u : /^[^\S\r\n\u2028\u2029]*/u;
|
|
1198
|
+
const cursor = regionStart + (whitespacePattern.exec(text.slice(regionStart))?.[0].length ?? 0);
|
|
1199
|
+
const container = markdownContainerPrefix(text.slice(cursor, lineEnd(text, cursor)));
|
|
1200
|
+
if (container.blockquoteDepth > 0)
|
|
1201
|
+
return { cursor, listItem: false };
|
|
1202
|
+
return { cursor: cursor + container.cursor, listItem: container.listDepth > 0 };
|
|
1203
|
+
}
|
|
1204
|
+
function directiveCommandTargetStart(text, cursor, limit = text.length) {
|
|
1205
|
+
DIRECTIVE_COMMAND_PREFIX_AT.lastIndex = cursor;
|
|
1206
|
+
const prefix = DIRECTIVE_COMMAND_PREFIX_AT.exec(text);
|
|
1207
|
+
const targetStart = prefix?.index === cursor ? cursor + prefix[0].length : null;
|
|
1208
|
+
return targetStart !== null && targetStart <= limit ? targetStart : null;
|
|
1209
|
+
}
|
|
1210
|
+
function promptLeadingExplicitCandidateStart(text) {
|
|
1211
|
+
const leading = leadingDirectiveCursor(text, 0, true);
|
|
1212
|
+
if (text[leading.cursor] === '$')
|
|
1213
|
+
return leading.cursor;
|
|
1214
|
+
const commandTarget = directiveCommandTargetStart(text, leading.cursor);
|
|
1215
|
+
return commandTarget !== null && text[commandTarget] === '$' ? commandTarget : leading.cursor;
|
|
1216
|
+
}
|
|
1217
|
+
function punctuationSeparatedCandidateStart(text, cursor) {
|
|
1218
|
+
let next = boundedHorizontalCursor(text, cursor, text.length);
|
|
1219
|
+
if (text[next] === '$')
|
|
1220
|
+
return next;
|
|
1221
|
+
const punctuationStart = next;
|
|
1222
|
+
while (next < text.length) {
|
|
1223
|
+
const character = codePointAt(text, next);
|
|
1224
|
+
if (!isDirectivePunctuation(character))
|
|
1225
|
+
break;
|
|
1226
|
+
next += character.length;
|
|
1227
|
+
}
|
|
1228
|
+
if (next === punctuationStart)
|
|
1229
|
+
return null;
|
|
1230
|
+
next = boundedHorizontalCursor(text, next, text.length);
|
|
1231
|
+
return text[next] === '$' ? next : null;
|
|
1232
|
+
}
|
|
1233
|
+
function coordinatedDocumentationCandidateStart(text, cursor) {
|
|
1234
|
+
const scanner = /(?:[^\S\r\n\u2028\u2029]+(?:[Aa][Nn][Dd]|[Oo][Rr])\s+|[^\S\r\n\u2028\u2029]*[,,،、]\s*(?:[Aa][Nn][Dd]|[Oo][Rr])\s+|[^\S\r\n\u2028\u2029]*\/[^\S\r\n\u2028\u2029]*)/uy;
|
|
1235
|
+
scanner.lastIndex = cursor;
|
|
1236
|
+
const separator = scanner.exec(text);
|
|
1237
|
+
if (!separator)
|
|
1238
|
+
return null;
|
|
1239
|
+
const next = cursor + separator[0].length;
|
|
1240
|
+
return text[next] === '$' ? next : null;
|
|
1241
|
+
}
|
|
1242
|
+
function clauseDirectiveStart(text, predecessorEnd, candidateStart) {
|
|
1243
|
+
if (predecessorEnd > candidateStart)
|
|
1244
|
+
return false;
|
|
1245
|
+
let clauseStart = predecessorEnd;
|
|
1246
|
+
for (let cursor = predecessorEnd; cursor < candidateStart;) {
|
|
1247
|
+
const character = codePointAt(text, cursor);
|
|
1248
|
+
if (isClauseBoundaryAt(text, cursor) || normalizedPunctuation(character) === ':')
|
|
1249
|
+
clauseStart = cursor + character.length;
|
|
1250
|
+
cursor += character.length;
|
|
1251
|
+
}
|
|
1252
|
+
const directiveStart = boundedHorizontalCursor(text, clauseStart, candidateStart);
|
|
1253
|
+
return hasAdjacentPredecessorSeparator(text, predecessorEnd, directiveStart)
|
|
1254
|
+
&& directiveCommandTargetStart(text, directiveStart, candidateStart) === candidateStart;
|
|
1255
|
+
}
|
|
1256
|
+
function hasAdjacentPredecessorSeparator(text, predecessorEnd, candidateStart) {
|
|
1257
|
+
if (predecessorEnd > candidateStart)
|
|
1258
|
+
return false;
|
|
1259
|
+
for (let cursor = predecessorEnd; cursor < candidateStart;) {
|
|
1260
|
+
const character = codePointAt(text, cursor);
|
|
1261
|
+
if (!SAFE_TOKEN_WHITESPACE.test(character)
|
|
1262
|
+
&& !isClauseBoundaryAt(text, cursor)
|
|
1263
|
+
&& normalizedPunctuation(character) !== ':'
|
|
1264
|
+
&& !/[—–-]/u.test(character))
|
|
1265
|
+
return false;
|
|
1266
|
+
cursor += character.length;
|
|
1267
|
+
}
|
|
1268
|
+
return true;
|
|
1269
|
+
}
|
|
1270
|
+
function isPostposedSubjectBoundaryAt(text, index) {
|
|
1271
|
+
if (!isClauseBoundaryAt(text, index))
|
|
1272
|
+
return false;
|
|
1273
|
+
return !/[,،、]/u.test(normalizedPunctuation(codePointAt(text, index)));
|
|
1274
|
+
}
|
|
1275
|
+
function collectLineMatchPositions(pattern, text, start, end, requireEndBoundary = true) {
|
|
1276
|
+
const matches = [];
|
|
1277
|
+
pattern.lastIndex = start;
|
|
679
1278
|
let match;
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
1279
|
+
while ((match = pattern.exec(text)) !== null && match.index < end) {
|
|
1280
|
+
if (pattern.lastIndex <= end
|
|
1281
|
+
&& hasUnicodeGrammarTokenStart(text, match.index)
|
|
1282
|
+
&& (!requireEndBoundary || hasUnicodeGrammarTokenBoundaries(text, match.index, pattern.lastIndex))) {
|
|
1283
|
+
matches.push({ start: match.index, end: pattern.lastIndex });
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
return matches;
|
|
1287
|
+
}
|
|
1288
|
+
function hasExclusionPrefixAt(text, start) {
|
|
1289
|
+
const pattern = new RegExp(`\\s*(?:${ASCII_PLEASE}\\s+)?${EXCLUSION_PREFIX}`, 'yu');
|
|
1290
|
+
pattern.lastIndex = start;
|
|
1291
|
+
const match = pattern.exec(text);
|
|
1292
|
+
return match?.index === start && hasUnicodeGrammarTokenBoundaries(text, start, pattern.lastIndex);
|
|
1293
|
+
}
|
|
1294
|
+
function collectExplicitPrefixNegationIndex(text, candidates) {
|
|
1295
|
+
const negatedStarts = new Set();
|
|
1296
|
+
const postposedSubjectStarts = new Map();
|
|
1297
|
+
const firstPostposedSubjectCandidates = new Set();
|
|
1298
|
+
const normalizedText = normalizeGrammarApostrophes(text);
|
|
1299
|
+
const negativeScanner = new RegExp(NEGATIVE_PREFIX_PATTERN.source, 'gu');
|
|
1300
|
+
const contrastScanner = new RegExp(`${ASCII_BUT}\\s+(?:${ASCII_PLEASE}\\s+)?(?:${ASCII_INSTEAD}\\s+)?(?=${ASCII_DIRECTIVE_COMMAND})`, 'gu');
|
|
1301
|
+
const directiveScanner = new RegExp(`(?:${ASCII_AND}|${ASCII_THEN})\\s+(?:${ASCII_PLEASE}\\s+)?(?:${ASCII_INSTEAD}\\s+)?(?=${ASCII_DIRECTIVE_COMMAND})`, 'gu');
|
|
1302
|
+
let firstCandidateIndex = 0;
|
|
1303
|
+
while (firstCandidateIndex < candidates.length) {
|
|
1304
|
+
const lineStart = lineStartForPosition(text, candidates[firstCandidateIndex].start);
|
|
1305
|
+
const lineLimit = lineEnd(text, candidates[firstCandidateIndex].end);
|
|
1306
|
+
let afterLineCandidateIndex = firstCandidateIndex;
|
|
1307
|
+
while (afterLineCandidateIndex < candidates.length && candidates[afterLineCandidateIndex].start < lineLimit)
|
|
1308
|
+
afterLineCandidateIndex += 1;
|
|
1309
|
+
const negativeMatches = collectLineMatchPositions(negativeScanner, normalizedText, lineStart, lineLimit);
|
|
1310
|
+
const contrastMatches = collectLineMatchPositions(contrastScanner, text, lineStart, lineLimit, false);
|
|
1311
|
+
const directiveMatches = collectLineMatchPositions(directiveScanner, text, lineStart, lineLimit, false);
|
|
1312
|
+
let negativeMatchIndex = 0;
|
|
1313
|
+
let contrastMatchIndex = 0;
|
|
1314
|
+
let directiveMatchIndex = 0;
|
|
1315
|
+
let latestNegativeStart = -1;
|
|
1316
|
+
let latestContrastStart = -1;
|
|
1317
|
+
let latestCoordinatedDirectiveStart = -1;
|
|
1318
|
+
let latestPunctuationDirectiveStart = -1;
|
|
1319
|
+
let cursor = lineStart;
|
|
1320
|
+
let clauseStart = lineStart;
|
|
1321
|
+
let punctuationStart = lineStart;
|
|
1322
|
+
let postposedSubjectStart = lineStart;
|
|
1323
|
+
let hasPostposedSubjectCandidate = false;
|
|
1324
|
+
for (let candidateIndex = firstCandidateIndex; candidateIndex < afterLineCandidateIndex; candidateIndex += 1) {
|
|
1325
|
+
const candidate = candidates[candidateIndex];
|
|
1326
|
+
while (cursor < candidate.start) {
|
|
1327
|
+
const character = codePointAt(text, cursor);
|
|
1328
|
+
if (isLogicalSentenceBoundaryAt(text, cursor))
|
|
1329
|
+
clauseStart = cursor + character.length;
|
|
1330
|
+
if (isClauseBoundaryAt(text, cursor))
|
|
1331
|
+
punctuationStart = cursor + character.length;
|
|
1332
|
+
if (isPostposedSubjectBoundaryAt(text, cursor)) {
|
|
1333
|
+
postposedSubjectStart = cursor + character.length;
|
|
1334
|
+
hasPostposedSubjectCandidate = false;
|
|
1335
|
+
}
|
|
1336
|
+
cursor += character.length;
|
|
1337
|
+
}
|
|
1338
|
+
while (negativeMatchIndex < negativeMatches.length && negativeMatches[negativeMatchIndex].end <= candidate.start) {
|
|
1339
|
+
latestNegativeStart = negativeMatches[negativeMatchIndex].start;
|
|
1340
|
+
negativeMatchIndex += 1;
|
|
1341
|
+
}
|
|
1342
|
+
while (contrastMatchIndex < contrastMatches.length && contrastMatches[contrastMatchIndex].end <= candidate.start) {
|
|
1343
|
+
latestContrastStart = contrastMatches[contrastMatchIndex].start;
|
|
1344
|
+
contrastMatchIndex += 1;
|
|
1345
|
+
}
|
|
1346
|
+
while (directiveMatchIndex < directiveMatches.length && directiveMatches[directiveMatchIndex].end <= candidate.start) {
|
|
1347
|
+
latestCoordinatedDirectiveStart = directiveMatches[directiveMatchIndex].start;
|
|
1348
|
+
directiveMatchIndex += 1;
|
|
1349
|
+
}
|
|
1350
|
+
const punctuationDirectiveStart = boundedHorizontalCursor(text, punctuationStart, candidate.start);
|
|
1351
|
+
if (directiveCommandTargetStart(text, punctuationDirectiveStart, candidate.start) === candidate.start) {
|
|
1352
|
+
latestPunctuationDirectiveStart = Math.max(latestPunctuationDirectiveStart, punctuationDirectiveStart);
|
|
1353
|
+
}
|
|
1354
|
+
let effectiveClauseStart = clauseStart;
|
|
1355
|
+
if (latestContrastStart >= effectiveClauseStart)
|
|
1356
|
+
effectiveClauseStart = latestContrastStart;
|
|
1357
|
+
if (latestPunctuationDirectiveStart >= effectiveClauseStart && latestPunctuationDirectiveStart > latestNegativeStart) {
|
|
1358
|
+
effectiveClauseStart = latestPunctuationDirectiveStart;
|
|
1359
|
+
}
|
|
1360
|
+
if (latestCoordinatedDirectiveStart >= effectiveClauseStart && hasExclusionPrefixAt(text, effectiveClauseStart)) {
|
|
1361
|
+
effectiveClauseStart = latestCoordinatedDirectiveStart;
|
|
1362
|
+
}
|
|
1363
|
+
if (latestNegativeStart >= effectiveClauseStart)
|
|
1364
|
+
negatedStarts.add(candidate.start);
|
|
1365
|
+
postposedSubjectStarts.set(candidate.start, postposedSubjectStart);
|
|
1366
|
+
if (!hasPostposedSubjectCandidate)
|
|
1367
|
+
firstPostposedSubjectCandidates.add(candidate.start);
|
|
1368
|
+
hasPostposedSubjectCandidate = true;
|
|
1369
|
+
}
|
|
1370
|
+
firstCandidateIndex = afterLineCandidateIndex;
|
|
1371
|
+
}
|
|
1372
|
+
return { negatedStarts, postposedSubjectStarts, firstPostposedSubjectCandidates };
|
|
1373
|
+
}
|
|
1374
|
+
function directivePrefixAfter(text, start, limit) {
|
|
1375
|
+
let cursor = boundedHorizontalCursor(text, start, limit);
|
|
1376
|
+
const transitionStart = cursor;
|
|
1377
|
+
if (cursor >= limit)
|
|
1378
|
+
return null;
|
|
1379
|
+
if (isClauseBoundaryAt(text, cursor)) {
|
|
1380
|
+
cursor += codePointAt(text, cursor).length;
|
|
1381
|
+
cursor = boundedHorizontalCursor(text, cursor, limit);
|
|
1382
|
+
}
|
|
1383
|
+
else {
|
|
1384
|
+
const coordinator = new RegExp(`(?:${ASCII_AND}|${ASCII_BUT}|${ASCII_INSTEAD}|${ASCII_THEN}|${ASCII_NOW})`, 'yu');
|
|
1385
|
+
coordinator.lastIndex = cursor;
|
|
1386
|
+
const match = coordinator.exec(text);
|
|
1387
|
+
if (match?.index !== cursor || !hasUnicodeGrammarTokenBoundaries(text, cursor, coordinator.lastIndex))
|
|
1388
|
+
return null;
|
|
1389
|
+
}
|
|
1390
|
+
const targetStart = directiveCommandTargetStart(text, cursor, limit);
|
|
1391
|
+
return targetStart === null ? null : { start: transitionStart, targetStart };
|
|
1392
|
+
}
|
|
1393
|
+
function isExclusionPrefixDirectiveTransitionAt(text, prefixStart, transitionStart, limit) {
|
|
1394
|
+
if (!hasExclusionPrefixAt(text, prefixStart))
|
|
1395
|
+
return false;
|
|
1396
|
+
const punctuationTransition = isClauseBoundaryAt(text, transitionStart);
|
|
1397
|
+
let coordinatedTransition = false;
|
|
1398
|
+
if (!punctuationTransition) {
|
|
1399
|
+
const coordinator = new RegExp(`(?:${ASCII_AND}|${ASCII_THEN})`, 'yu');
|
|
1400
|
+
coordinator.lastIndex = transitionStart;
|
|
1401
|
+
const match = coordinator.exec(text);
|
|
1402
|
+
coordinatedTransition = match?.index === transitionStart
|
|
1403
|
+
&& hasUnicodeGrammarTokenBoundaries(text, transitionStart, coordinator.lastIndex);
|
|
1404
|
+
}
|
|
1405
|
+
if (!punctuationTransition && !coordinatedTransition)
|
|
1406
|
+
return false;
|
|
1407
|
+
const directive = directivePrefixAfter(text, transitionStart, limit);
|
|
1408
|
+
if (directive?.start !== transitionStart)
|
|
1409
|
+
return false;
|
|
1410
|
+
return !punctuationTransition || clauseDirectiveStart(text, transitionStart, directive.targetStart);
|
|
1411
|
+
}
|
|
1412
|
+
function exclusionPrefixDirectiveTransitionStart(text, prefixStart, start, limit) {
|
|
1413
|
+
if (!hasExclusionPrefixAt(text, prefixStart))
|
|
1414
|
+
return null;
|
|
1415
|
+
for (let cursor = start; cursor < limit;) {
|
|
1416
|
+
if (isExclusionPrefixDirectiveTransitionAt(text, prefixStart, cursor, limit))
|
|
1417
|
+
return cursor;
|
|
1418
|
+
cursor += codePointAt(text, cursor).length;
|
|
1419
|
+
}
|
|
1420
|
+
return null;
|
|
1421
|
+
}
|
|
1422
|
+
function documentationDirectiveTransitionStart(text, start, limit) {
|
|
1423
|
+
const scanner = new RegExp(`(?:${ASCII_AND}|${ASCII_BUT}|${ASCII_THEN}|${ASCII_INSTEAD}|${ASCII_NOW})`, 'gu');
|
|
1424
|
+
scanner.lastIndex = start;
|
|
1425
|
+
let match;
|
|
1426
|
+
while ((match = scanner.exec(text)) !== null && match.index < limit) {
|
|
1427
|
+
if (scanner.lastIndex <= limit
|
|
1428
|
+
&& hasUnicodeGrammarTokenBoundaries(text, match.index, scanner.lastIndex)
|
|
1429
|
+
&& directiveCommandTargetStart(text, match.index, limit) !== null)
|
|
1430
|
+
return match.index;
|
|
1431
|
+
}
|
|
1432
|
+
return null;
|
|
1433
|
+
}
|
|
1434
|
+
function postposedNegationClauseEnd(text, start, limit) {
|
|
1435
|
+
for (let cursor = start; cursor < limit;) {
|
|
1436
|
+
if (isClauseBoundaryAt(text, cursor))
|
|
1437
|
+
return cursor;
|
|
1438
|
+
cursor += codePointAt(text, cursor).length;
|
|
1439
|
+
}
|
|
1440
|
+
return limit;
|
|
1441
|
+
}
|
|
1442
|
+
function stickyMatchEnd(pattern, text, start, limit) {
|
|
1443
|
+
pattern.lastIndex = start;
|
|
1444
|
+
const match = pattern.exec(text);
|
|
1445
|
+
return match && match.index === start && pattern.lastIndex <= limit ? pattern.lastIndex : null;
|
|
1446
|
+
}
|
|
1447
|
+
function coordinatedSubjectAt(text, start, limit, candidates, candidateIndexByStart) {
|
|
1448
|
+
const articlePrefix = /(?:the|a|an)/iyu;
|
|
1449
|
+
articlePrefix.lastIndex = start;
|
|
1450
|
+
const article = articlePrefix.exec(text);
|
|
1451
|
+
const articleSubjectStart = article?.index === start
|
|
1452
|
+
? boundedHorizontalCursor(text, articlePrefix.lastIndex, limit)
|
|
1453
|
+
: start;
|
|
1454
|
+
const candidateStart = article?.index === start
|
|
1455
|
+
&& articlePrefix.lastIndex <= limit
|
|
1456
|
+
&& articleSubjectStart > articlePrefix.lastIndex
|
|
1457
|
+
&& hasUnicodeGrammarTokenBoundaries(text, start, articlePrefix.lastIndex)
|
|
1458
|
+
? articleSubjectStart
|
|
1459
|
+
: start;
|
|
1460
|
+
const explicitIndex = candidateIndexByStart.get(candidateStart);
|
|
1461
|
+
if (explicitIndex !== undefined && candidates[explicitIndex].reasons.size === 0) {
|
|
1462
|
+
return { end: candidates[explicitIndex].end, explicitIndex };
|
|
1463
|
+
}
|
|
1464
|
+
const implicitEnd = stickyMatchEnd(COORDINATED_IMPLICIT_DOCUMENTATION_SUBJECT, text, start, limit);
|
|
1465
|
+
return implicitEnd === null ? null : { end: implicitEnd };
|
|
1466
|
+
}
|
|
1467
|
+
function collectMixedSubjectChain(text, start, limit, candidates, candidateIndexByStart) {
|
|
1468
|
+
const chainStart = boundedHorizontalCursor(text, start, limit);
|
|
1469
|
+
let cursor = chainStart;
|
|
1470
|
+
const quantifierEnd = stickyMatchEnd(COORDINATED_SUBJECT_QUANTIFIER, text, cursor, limit);
|
|
1471
|
+
const quantifiedSubjectStart = quantifierEnd === null ? cursor : boundedHorizontalCursor(text, quantifierEnd, limit);
|
|
1472
|
+
if (quantifierEnd !== null
|
|
1473
|
+
&& quantifiedSubjectStart > quantifierEnd
|
|
1474
|
+
&& hasUnicodeGrammarTokenBoundaries(text, cursor, quantifierEnd))
|
|
1475
|
+
cursor = quantifiedSubjectStart;
|
|
1476
|
+
const firstSubject = coordinatedSubjectAt(text, cursor, limit, candidates, candidateIndexByStart);
|
|
1477
|
+
if (!firstSubject)
|
|
1478
|
+
return null;
|
|
1479
|
+
const explicitIndexes = firstSubject.explicitIndex === undefined ? [] : [firstSubject.explicitIndex];
|
|
1480
|
+
cursor = firstSubject.end;
|
|
1481
|
+
while (cursor < limit) {
|
|
1482
|
+
const separatorEnd = stickyMatchEnd(COORDINATED_EXPLICIT_POSTPOSED_SEPARATOR, text, cursor, limit);
|
|
1483
|
+
if (separatorEnd === null)
|
|
1484
|
+
break;
|
|
1485
|
+
const subject = coordinatedSubjectAt(text, separatorEnd, limit, candidates, candidateIndexByStart);
|
|
1486
|
+
if (!subject)
|
|
1487
|
+
break;
|
|
1488
|
+
if (subject.explicitIndex !== undefined)
|
|
1489
|
+
explicitIndexes.push(subject.explicitIndex);
|
|
1490
|
+
cursor = subject.end;
|
|
1491
|
+
}
|
|
1492
|
+
return { start: chainStart, explicitIndexes, end: cursor };
|
|
1493
|
+
}
|
|
1494
|
+
function hasCoordinatedExplicitPostposedTail(text, start, end) {
|
|
1495
|
+
let cursor = stickyMatchEnd(POSTPOSED_SUBJECT_NOUN, text, start, end) ?? start;
|
|
1496
|
+
while (cursor < end) {
|
|
1497
|
+
const trailingStart = boundedHorizontalCursor(text, cursor, end);
|
|
1498
|
+
if (trailingStart === end)
|
|
1499
|
+
return true;
|
|
1500
|
+
if (/[,,،、]/u.test(text[trailingStart] ?? '')
|
|
1501
|
+
&& boundedHorizontalCursor(text, trailingStart + 1, end) === end)
|
|
1502
|
+
return true;
|
|
1503
|
+
const separatorEnd = stickyMatchEnd(COORDINATED_EXPLICIT_POSTPOSED_SEPARATOR, text, cursor, end);
|
|
1504
|
+
if (separatorEnd === null)
|
|
1505
|
+
return false;
|
|
1506
|
+
const subjectEnd = stickyMatchEnd(COORDINATED_EXPLICIT_POSTPOSED_SUBJECT, text, separatorEnd, end);
|
|
1507
|
+
if (subjectEnd === null)
|
|
1508
|
+
return false;
|
|
1509
|
+
cursor = stickyMatchEnd(POSTPOSED_SUBJECT_NOUN, text, subjectEnd, end) ?? subjectEnd;
|
|
1510
|
+
}
|
|
1511
|
+
return true;
|
|
1512
|
+
}
|
|
1513
|
+
function coordinatedPostposedSubjectGroupStartIndex(text, candidates, firstIndex, lastIndex) {
|
|
1514
|
+
let groupStartIndex = lastIndex;
|
|
1515
|
+
while (groupStartIndex > firstIndex
|
|
1516
|
+
&& hasCoordinatedExplicitPostposedTail(text, candidates[groupStartIndex - 1].end, candidates[groupStartIndex].end)) {
|
|
1517
|
+
groupStartIndex -= 1;
|
|
1518
|
+
}
|
|
1519
|
+
return groupStartIndex;
|
|
1520
|
+
}
|
|
1521
|
+
function mixedImplicitPostposedSubjectStart(text, candidate, prefixNegations, candidates, candidateIndexByStart, predicateStart) {
|
|
1522
|
+
if (!prefixNegations.firstPostposedSubjectCandidates.has(candidate.start))
|
|
1523
|
+
return candidate.start;
|
|
1524
|
+
const candidateIndex = candidateIndexByStart.get(candidate.start);
|
|
1525
|
+
const start = prefixNegations.postposedSubjectStarts.get(candidate.start) ?? candidate.start;
|
|
1526
|
+
const chain = collectMixedSubjectChain(text, start, predicateStart, candidates, candidateIndexByStart);
|
|
1527
|
+
return chain
|
|
1528
|
+
&& candidateIndex !== undefined
|
|
1529
|
+
&& chain.explicitIndexes.includes(candidateIndex)
|
|
1530
|
+
&& boundedHorizontalCursor(text, chain.end, predicateStart) === predicateStart
|
|
1531
|
+
? chain.start
|
|
1532
|
+
: candidate.start;
|
|
1533
|
+
}
|
|
1534
|
+
function collectPostposedExplicitNegationIndex(text, candidates) {
|
|
1535
|
+
const ends = new Map();
|
|
1536
|
+
const implicitBlocks = [];
|
|
1537
|
+
const prefixNegations = collectExplicitPrefixNegationIndex(text, candidates);
|
|
1538
|
+
const candidateIndexByStart = new Map();
|
|
1539
|
+
for (const [index, candidate] of candidates.entries())
|
|
1540
|
+
candidateIndexByStart.set(candidate.start, index);
|
|
1541
|
+
let firstCandidateIndex = 0;
|
|
1542
|
+
while (firstCandidateIndex < candidates.length) {
|
|
1543
|
+
const start = lineStartForPosition(text, candidates[firstCandidateIndex].start);
|
|
1544
|
+
const end = lineEnd(text, candidates[firstCandidateIndex].end);
|
|
1545
|
+
let afterLineCandidateIndex = firstCandidateIndex;
|
|
1546
|
+
while (afterLineCandidateIndex < candidates.length && candidates[afterLineCandidateIndex].start < end)
|
|
1547
|
+
afterLineCandidateIndex += 1;
|
|
1548
|
+
const predicateScanner = new RegExp(POSTPOSED_NEGATIVE_PREDICATE.source, 'giu');
|
|
1549
|
+
const normalizedLine = normalizeGrammarApostrophes(text.slice(start, end));
|
|
1550
|
+
let predicate;
|
|
1551
|
+
let lastCandidateIndex = firstCandidateIndex - 1;
|
|
1552
|
+
const groupStartIndexesByEndpoint = new Map();
|
|
1553
|
+
let lastEvaluatedCandidateIndex = -1;
|
|
1554
|
+
while ((predicate = predicateScanner.exec(normalizedLine)) !== null) {
|
|
1555
|
+
const predicateTokenStart = firstGrammarTokenStart(normalizedLine, predicate.index, predicateScanner.lastIndex);
|
|
1556
|
+
if (!hasUnicodeGrammarTokenBoundaries(normalizedLine, predicateTokenStart, predicateScanner.lastIndex)
|
|
1557
|
+
|| !hasAsciiGrammarTokenCharacters(normalizedLine, predicateTokenStart, predicateScanner.lastIndex))
|
|
1558
|
+
continue;
|
|
1559
|
+
const predicateStart = start + predicate.index;
|
|
1560
|
+
while (lastCandidateIndex + 1 < afterLineCandidateIndex && candidates[lastCandidateIndex + 1].end <= predicateStart) {
|
|
1561
|
+
lastCandidateIndex += 1;
|
|
1562
|
+
}
|
|
1563
|
+
if (lastCandidateIndex < firstCandidateIndex)
|
|
1564
|
+
continue;
|
|
1565
|
+
if (lastCandidateIndex === lastEvaluatedCandidateIndex)
|
|
1566
|
+
continue;
|
|
1567
|
+
lastEvaluatedCandidateIndex = lastCandidateIndex;
|
|
1568
|
+
const groupEndpoint = candidates[lastCandidateIndex].end;
|
|
1569
|
+
let groupStartIndex = groupStartIndexesByEndpoint.get(groupEndpoint);
|
|
1570
|
+
if (groupStartIndex === undefined) {
|
|
1571
|
+
groupStartIndex = coordinatedPostposedSubjectGroupStartIndex(text, candidates, firstCandidateIndex, lastCandidateIndex);
|
|
1572
|
+
groupStartIndexesByEndpoint.set(groupEndpoint, groupStartIndex);
|
|
1573
|
+
}
|
|
1574
|
+
if (!hasCoordinatedExplicitPostposedTail(text, candidates[groupStartIndex].end, predicateStart))
|
|
1575
|
+
continue;
|
|
1576
|
+
const predicateEnd = start + predicateScanner.lastIndex;
|
|
1577
|
+
const positiveTransition = directivePrefixAfter(text, predicateEnd, end);
|
|
1578
|
+
const negationEnd = positiveTransition?.start ?? postposedNegationClauseEnd(text, predicateEnd, end);
|
|
1579
|
+
for (let index = groupStartIndex; index <= lastCandidateIndex; index += 1)
|
|
1580
|
+
ends.set(candidates[index].start, negationEnd);
|
|
1581
|
+
const subjectStart = mixedImplicitPostposedSubjectStart(text, candidates[groupStartIndex], prefixNegations, candidates, candidateIndexByStart, predicateStart);
|
|
1582
|
+
implicitBlocks.push({
|
|
1583
|
+
start: subjectStart,
|
|
1584
|
+
end: positiveTransition?.start ?? postposedNegationClauseEnd(text, predicateEnd, end),
|
|
1585
|
+
});
|
|
1586
|
+
}
|
|
1587
|
+
firstCandidateIndex = afterLineCandidateIndex;
|
|
1588
|
+
}
|
|
1589
|
+
return {
|
|
1590
|
+
ends,
|
|
1591
|
+
prefixNegatedStarts: prefixNegations.negatedStarts,
|
|
1592
|
+
implicitBlocks: createInertRangeIndex(implicitBlocks),
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1595
|
+
function postposedExplicitNegationEnd(index, candidate) {
|
|
1596
|
+
return index.ends.get(candidate.start) ?? null;
|
|
1597
|
+
}
|
|
1598
|
+
function hasPostposedExplicitNegation(index, candidate) {
|
|
1599
|
+
return postposedExplicitNegationEnd(index, candidate) !== null;
|
|
1600
|
+
}
|
|
1601
|
+
function isNegativeExplicitMention(candidate, postposedNegations) {
|
|
1602
|
+
return hasPostposedExplicitNegation(postposedNegations, candidate)
|
|
1603
|
+
|| postposedNegations.prefixNegatedStarts.has(candidate.start);
|
|
1604
|
+
}
|
|
1605
|
+
function isInertOrNegativeMention(candidate, postposedNegations) {
|
|
1606
|
+
return [...candidate.reasons].some((reason) => reason !== 'not-leading-region') || isNegativeExplicitMention(candidate, postposedNegations);
|
|
1607
|
+
}
|
|
1608
|
+
function listItemDocumentationTokenRange(text, candidateStart, blockEnd) {
|
|
1609
|
+
const lineStart = lineStartForPosition(text, candidateStart);
|
|
1610
|
+
const leading = leadingDirectiveCursor(text, lineStart, false);
|
|
1611
|
+
if (!leading.listItem)
|
|
1612
|
+
return null;
|
|
1613
|
+
const end = lineEnd(text, blockEnd);
|
|
1614
|
+
const directiveTarget = directiveCommandTargetStart(text, leading.cursor);
|
|
1615
|
+
const tokenStart = directiveTarget !== null && directiveTarget < end && text[directiveTarget] === '$'
|
|
1616
|
+
? directiveTarget
|
|
1617
|
+
: leading.cursor;
|
|
1618
|
+
const tokenSequence = /^(?:(?:\$(?:oh-my-codex:)?[A-Za-z][A-Za-z0-9_-]*)|(?:\/prompts:[\w.-]+))(?:(?:\s*,\s*(?:(?:and|or)\s+)?|\s+(?:and|or)\s+|\s*\/\s*)(?:(?:\$(?:oh-my-codex:)?[A-Za-z][A-Za-z0-9_-]*)|(?:\/prompts:[\w.-]+)))*/iu.exec(text.slice(tokenStart, end));
|
|
1619
|
+
if (!tokenSequence || !LIST_DOCUMENTATION_SUFFIX.test(text.slice(tokenStart + tokenSequence[0].length, end)))
|
|
1620
|
+
return null;
|
|
1621
|
+
return { start: tokenStart, end: tokenStart + tokenSequence[0].length };
|
|
1622
|
+
}
|
|
1623
|
+
function isListItemDocumentation(text, candidateStart, blockEnd) {
|
|
1624
|
+
return listItemDocumentationTokenRange(text, candidateStart, blockEnd) !== null;
|
|
1625
|
+
}
|
|
1626
|
+
function hasActivePromptsTokenBoundary(text, start, end) {
|
|
1627
|
+
if (hasOddImmediateBackslashes(text, start))
|
|
1628
|
+
return false;
|
|
1629
|
+
const previous = codePointBefore(text, start);
|
|
1630
|
+
const validPrevious = !previous || SAFE_TOKEN_WHITESPACE.test(previous) || /[(\[{]/u.test(previous);
|
|
1631
|
+
return validPrevious && isExplicitTokenBoundary(text, end);
|
|
1632
|
+
}
|
|
1633
|
+
function isMarkdownTableDelimiter(line) {
|
|
1634
|
+
const trimmed = line.trim();
|
|
1635
|
+
if (!trimmed.includes('|'))
|
|
1636
|
+
return false;
|
|
1637
|
+
const cells = trimmed.replace(/^\|/u, '').replace(/\|$/u, '').split('|');
|
|
1638
|
+
return cells.length >= 2 && cells.every((cell) => /^\s*:?-{3,}:?\s*$/u.test(cell));
|
|
1639
|
+
}
|
|
1640
|
+
function collectMarkdownTableRanges(text) {
|
|
1641
|
+
const ranges = [];
|
|
1642
|
+
let start = 0;
|
|
1643
|
+
while (start < text.length) {
|
|
1644
|
+
const headerEnd = lineEnd(text, start);
|
|
1645
|
+
const delimiterStart = headerEnd < text.length ? nextLineStart(text, headerEnd) : text.length;
|
|
1646
|
+
const delimiterEnd = delimiterStart < text.length ? lineEnd(text, delimiterStart) : text.length;
|
|
1647
|
+
if (text.slice(start, headerEnd).includes('|') && isMarkdownTableDelimiter(text.slice(delimiterStart, delimiterEnd))) {
|
|
1648
|
+
let tableEnd = delimiterEnd;
|
|
1649
|
+
let rowStart = delimiterEnd < text.length ? nextLineStart(text, delimiterEnd) : text.length;
|
|
1650
|
+
while (rowStart < text.length) {
|
|
1651
|
+
const rowEnd = lineEnd(text, rowStart);
|
|
1652
|
+
if (!text.slice(rowStart, rowEnd).includes('|'))
|
|
1653
|
+
break;
|
|
1654
|
+
tableEnd = rowEnd;
|
|
1655
|
+
rowStart = rowEnd < text.length ? nextLineStart(text, rowEnd) : text.length;
|
|
1656
|
+
}
|
|
1657
|
+
ranges.push({ start, end: tableEnd });
|
|
1658
|
+
if (tableEnd === text.length)
|
|
1659
|
+
break;
|
|
1660
|
+
start = nextLineStart(text, tableEnd);
|
|
685
1661
|
continue;
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
1662
|
+
}
|
|
1663
|
+
if (headerEnd === text.length)
|
|
1664
|
+
break;
|
|
1665
|
+
start = nextLineStart(text, headerEnd);
|
|
1666
|
+
}
|
|
1667
|
+
return ranges;
|
|
1668
|
+
}
|
|
1669
|
+
function normalizeMarkdownReferenceLabel(label) {
|
|
1670
|
+
return label
|
|
1671
|
+
.trim()
|
|
1672
|
+
.replace(/\s+/gu, ' ')
|
|
1673
|
+
.normalize('NFKC')
|
|
1674
|
+
.toLowerCase()
|
|
1675
|
+
.toUpperCase()
|
|
1676
|
+
.toLowerCase();
|
|
1677
|
+
}
|
|
1678
|
+
function markdownLabelClosingIndex(text, start, limit) {
|
|
1679
|
+
for (let cursor = start; cursor < limit; cursor += 1) {
|
|
1680
|
+
if (text[cursor] === ']' && !hasOddImmediateBackslashes(text, cursor))
|
|
1681
|
+
return cursor;
|
|
1682
|
+
}
|
|
1683
|
+
return -1;
|
|
1684
|
+
}
|
|
1685
|
+
function referenceDestinationEnd(text, start, end) {
|
|
1686
|
+
if (/["'(`]/u.test(text[start] ?? ''))
|
|
1687
|
+
return null;
|
|
1688
|
+
const destination = /^(?:<[^>\r\n]*>|\S+)/u.exec(text.slice(start, end));
|
|
1689
|
+
return destination ? start + destination[0].length : null;
|
|
1690
|
+
}
|
|
1691
|
+
function referenceTitleStartAfterDestination(text, start, end) {
|
|
1692
|
+
const destinationEnd = referenceDestinationEnd(text, start, end);
|
|
1693
|
+
if (destinationEnd === null)
|
|
1694
|
+
return null;
|
|
1695
|
+
const titlePrefix = /^[ \t]+(["'(])/u.exec(text.slice(destinationEnd, end));
|
|
1696
|
+
return titlePrefix ? destinationEnd + titlePrefix[0].length - 1 : null;
|
|
1697
|
+
}
|
|
1698
|
+
function referenceTitleRange(text, start) {
|
|
1699
|
+
const opening = text[start];
|
|
1700
|
+
const closing = opening === '(' ? ')' : opening;
|
|
1701
|
+
for (let cursor = start + 1; cursor < text.length; cursor += 1) {
|
|
1702
|
+
if (text[cursor] === closing && !hasOddImmediateBackslashes(text, cursor)) {
|
|
1703
|
+
return { start, end: cursor + 1 };
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
return { start, end: text.length };
|
|
1707
|
+
}
|
|
1708
|
+
function collectMarkdownReferenceIndex(text) {
|
|
1709
|
+
const labels = new Set();
|
|
1710
|
+
const destinationRanges = [];
|
|
1711
|
+
const predecessorRanges = [];
|
|
1712
|
+
const codeIndex = createInertRangeIndex([...collectFencedCodeRanges(text), ...collectIndentedCodeRanges(text)]);
|
|
1713
|
+
const tablePredecessorRanges = collectMarkdownTableRanges(text);
|
|
1714
|
+
const tableRanges = createInertRangeIndex([...tablePredecessorRanges]);
|
|
1715
|
+
let titleMaskEnd = -1;
|
|
1716
|
+
let start = 0;
|
|
1717
|
+
while (start <= text.length) {
|
|
1718
|
+
if (start < titleMaskEnd) {
|
|
1719
|
+
const maskedLineEnd = lineEnd(text, start);
|
|
1720
|
+
if (maskedLineEnd === text.length)
|
|
693
1721
|
break;
|
|
1722
|
+
start = nextLineStart(text, maskedLineEnd);
|
|
1723
|
+
continue;
|
|
1724
|
+
}
|
|
1725
|
+
const end = lineEnd(text, start);
|
|
1726
|
+
const line = text.slice(start, end);
|
|
1727
|
+
const containerPrefix = /^[ \t]{0,3}(?:(?:>[ \t]{0,4})|(?:(?:[-+*]|\d{1,9}[.)])[ \t]+))*/u.exec(line)?.[0] ?? '';
|
|
1728
|
+
const labelStart = start + containerPrefix.length;
|
|
1729
|
+
if (!isInInertRange(codeIndex, labelStart) && text[labelStart] === '[') {
|
|
1730
|
+
const closing = markdownLabelClosingIndex(text, labelStart + 1, end);
|
|
1731
|
+
if (closing > labelStart) {
|
|
1732
|
+
const colon = /^\s*:\s*/u.exec(text.slice(closing + 1, end));
|
|
1733
|
+
if (colon) {
|
|
1734
|
+
const inlineDestinationStart = closing + 1 + colon[0].length;
|
|
1735
|
+
let destinationStart = inlineDestinationStart;
|
|
1736
|
+
let destinationLineEnd = end;
|
|
1737
|
+
let destinationEnd = destinationStart < end && !isInInertRange(codeIndex, destinationStart)
|
|
1738
|
+
? referenceDestinationEnd(text, destinationStart, destinationLineEnd)
|
|
1739
|
+
: null;
|
|
1740
|
+
if (destinationEnd === null && inlineDestinationStart === end && end < text.length) {
|
|
1741
|
+
const continuationStart = nextLineStart(text, end);
|
|
1742
|
+
destinationLineEnd = lineEnd(text, continuationStart);
|
|
1743
|
+
const indentation = /^[ \t]{0,3}/u.exec(text.slice(continuationStart, destinationLineEnd))?.[0].length ?? 0;
|
|
1744
|
+
destinationStart = continuationStart + indentation;
|
|
1745
|
+
destinationEnd = destinationStart < destinationLineEnd && !isInInertRange(codeIndex, destinationStart)
|
|
1746
|
+
? referenceDestinationEnd(text, destinationStart, destinationLineEnd)
|
|
1747
|
+
: null;
|
|
1748
|
+
}
|
|
1749
|
+
if (destinationEnd !== null) {
|
|
1750
|
+
const destinationRange = { start: destinationStart, end: destinationEnd };
|
|
1751
|
+
destinationRanges.push(destinationRange);
|
|
1752
|
+
predecessorRanges.push(destinationRange);
|
|
1753
|
+
let titleStart = referenceTitleStartAfterDestination(text, destinationStart, destinationLineEnd);
|
|
1754
|
+
if (titleStart === null && destinationLineEnd < text.length) {
|
|
1755
|
+
const titleLineStart = nextLineStart(text, destinationLineEnd);
|
|
1756
|
+
const titleLineEnd = lineEnd(text, titleLineStart);
|
|
1757
|
+
const titleIndent = /^[ \t]{0,3}/u.exec(text.slice(titleLineStart, titleLineEnd));
|
|
1758
|
+
const candidateStart = titleLineStart + (titleIndent?.[0].length ?? 0);
|
|
1759
|
+
if (titleIndent && /["'(]/u.test(text[candidateStart] ?? ''))
|
|
1760
|
+
titleStart = candidateStart;
|
|
1761
|
+
}
|
|
1762
|
+
if (titleStart !== null) {
|
|
1763
|
+
const titleRange = referenceTitleRange(text, titleStart);
|
|
1764
|
+
destinationRanges.push(titleRange);
|
|
1765
|
+
if (text[titleRange.end - 1] === (text[titleStart] === '(' ? ')' : text[titleStart]))
|
|
1766
|
+
predecessorRanges.push(titleRange);
|
|
1767
|
+
titleMaskEnd = Math.max(titleMaskEnd, titleRange.end);
|
|
1768
|
+
}
|
|
1769
|
+
labels.add(normalizeMarkdownReferenceLabel(text.slice(labelStart + 1, closing)));
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
if (end === text.length)
|
|
1775
|
+
break;
|
|
1776
|
+
start = nextLineStart(text, end);
|
|
1777
|
+
}
|
|
1778
|
+
return {
|
|
1779
|
+
labels,
|
|
1780
|
+
destinationRanges: createInertRangeIndex(destinationRanges),
|
|
1781
|
+
tableRanges,
|
|
1782
|
+
tablePredecessorRanges,
|
|
1783
|
+
predecessorRanges,
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
function hasMarkdownReferenceDefinition(index, label) {
|
|
1787
|
+
return index.labels.has(normalizeMarkdownReferenceLabel(label));
|
|
1788
|
+
}
|
|
1789
|
+
function balancedMarkdownLinkRange(text, labelStart, destinationStart, lineLimit) {
|
|
1790
|
+
let depth = 1;
|
|
1791
|
+
let quote = null;
|
|
1792
|
+
for (let cursor = destinationStart + 2; cursor < lineLimit; cursor += 1) {
|
|
1793
|
+
if (hasOddImmediateBackslashes(text, cursor))
|
|
1794
|
+
continue;
|
|
1795
|
+
const character = text[cursor];
|
|
1796
|
+
if (quote) {
|
|
1797
|
+
if (character === quote)
|
|
1798
|
+
quote = null;
|
|
1799
|
+
continue;
|
|
694
1800
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
if (!registryEntry)
|
|
1801
|
+
if ((character === '"' || character === "'") && /\s/u.test(text[cursor - 1] ?? '')) {
|
|
1802
|
+
quote = character;
|
|
698
1803
|
continue;
|
|
699
|
-
|
|
1804
|
+
}
|
|
1805
|
+
if (character === '(')
|
|
1806
|
+
depth += 1;
|
|
1807
|
+
else if (character === ')') {
|
|
1808
|
+
depth -= 1;
|
|
1809
|
+
if (depth === 0)
|
|
1810
|
+
return { start: labelStart, end: cursor + 1 };
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
return null;
|
|
1814
|
+
}
|
|
1815
|
+
function enclosingMarkdownLinkRange(text, start, end) {
|
|
1816
|
+
const lineStart = lineStartForPosition(text, start);
|
|
1817
|
+
const lineLimit = lineEnd(text, end);
|
|
1818
|
+
const destinationStart = text.lastIndexOf('](', start);
|
|
1819
|
+
if (destinationStart < lineStart)
|
|
1820
|
+
return null;
|
|
1821
|
+
const labelStart = text.lastIndexOf('[', destinationStart);
|
|
1822
|
+
if (labelStart < lineStart)
|
|
1823
|
+
return null;
|
|
1824
|
+
const range = balancedMarkdownLinkRange(text, labelStart, destinationStart, lineLimit);
|
|
1825
|
+
return range && start >= destinationStart + 2 && end <= range.end ? range : null;
|
|
1826
|
+
}
|
|
1827
|
+
function markdownDocumentationRange(text, start, end, referenceIndex) {
|
|
1828
|
+
const lineStart = lineStartForPosition(text, start);
|
|
1829
|
+
const lineLimit = lineEnd(text, end);
|
|
1830
|
+
const line = text.slice(lineStart, lineLimit);
|
|
1831
|
+
const tableEnd = inertRangeEndAt(referenceIndex.tableRanges, start);
|
|
1832
|
+
if (tableEnd !== null)
|
|
1833
|
+
return { start: lineStart, end: tableEnd };
|
|
1834
|
+
if (/^(?:#{1,6}\s|\|)/u.test(line.trimStart()))
|
|
1835
|
+
return { start: lineStart, end: lineLimit };
|
|
1836
|
+
const enclosingLink = enclosingMarkdownLinkRange(text, start, end);
|
|
1837
|
+
if (enclosingLink)
|
|
1838
|
+
return enclosingLink;
|
|
1839
|
+
const labelStart = text.lastIndexOf('[', start);
|
|
1840
|
+
if (labelStart >= lineStart) {
|
|
1841
|
+
const inlineLabelEnd = text.indexOf('](', end);
|
|
1842
|
+
if (inlineLabelEnd >= end && inlineLabelEnd < lineLimit) {
|
|
1843
|
+
return balancedMarkdownLinkRange(text, labelStart, inlineLabelEnd, lineLimit)
|
|
1844
|
+
?? { start: labelStart, end: inlineLabelEnd + 2 };
|
|
1845
|
+
}
|
|
1846
|
+
const referenceLabelEnd = text.indexOf('][', end);
|
|
1847
|
+
if (referenceLabelEnd >= end && referenceLabelEnd < lineLimit) {
|
|
1848
|
+
const closingBracket = text.indexOf(']', referenceLabelEnd + 2);
|
|
1849
|
+
return closingBracket >= 0 && closingBracket < lineLimit
|
|
1850
|
+
? { start: labelStart, end: closingBracket + 1 }
|
|
1851
|
+
: { start: labelStart, end: referenceLabelEnd + 2 };
|
|
1852
|
+
}
|
|
1853
|
+
const closingLabel = markdownLabelClosingIndex(text, end, lineLimit);
|
|
1854
|
+
if (closingLabel >= end && closingLabel < lineLimit) {
|
|
1855
|
+
const beforeLabel = text.slice(lineStart, labelStart);
|
|
1856
|
+
const afterLabel = text.slice(closingLabel + 1, lineLimit);
|
|
1857
|
+
if (!beforeLabel.trim() && (/^\s*:\s*\S/u.test(afterLabel) || !afterLabel.trim())) {
|
|
1858
|
+
return { start: lineStart, end: lineLimit };
|
|
1859
|
+
}
|
|
1860
|
+
const label = text.slice(labelStart + 1, closingLabel);
|
|
1861
|
+
if (hasMarkdownReferenceDefinition(referenceIndex, label))
|
|
1862
|
+
return { start: labelStart, end: closingLabel + 1 };
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
if (lineLimit < text.length) {
|
|
1866
|
+
const followingStart = nextLineStart(text, lineLimit);
|
|
1867
|
+
const followingEnd = lineEnd(text, followingStart);
|
|
1868
|
+
const followingLine = text.slice(followingStart, followingEnd);
|
|
1869
|
+
if (/^\s*(?:={3,}|-{3,})\s*$/u.test(followingLine) || (line.includes('|') && isMarkdownTableDelimiter(followingLine))) {
|
|
1870
|
+
return { start: lineStart, end: followingEnd };
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
return null;
|
|
1874
|
+
}
|
|
1875
|
+
function isMarkdownDocumentationMention(text, start, end, referenceIndex) {
|
|
1876
|
+
return markdownDocumentationRange(text, start, end, referenceIndex) !== null;
|
|
1877
|
+
}
|
|
1878
|
+
function isInactivePromptsMention(text, start, end, inertRangeIndexes, referenceIndex) {
|
|
1879
|
+
return !hasActivePromptsTokenBoundary(text, start, end)
|
|
1880
|
+
|| isMarkdownDocumentationMention(text, start, end, referenceIndex)
|
|
1881
|
+
|| isStructurallyInert(inertRangeIndexes, start)
|
|
1882
|
+
|| isInInertRange(referenceIndex.destinationRanges, start)
|
|
1883
|
+
|| isListItemDocumentation(text, start, end);
|
|
1884
|
+
}
|
|
1885
|
+
function hasDirectPromptsInvocation(text, inertRangeIndexes, referenceIndex) {
|
|
1886
|
+
const leading = leadingDirectiveCursor(text, 0, true);
|
|
1887
|
+
if (isStructurallyInert(inertRangeIndexes, leading.cursor))
|
|
1888
|
+
return false;
|
|
1889
|
+
const pattern = new RegExp(PROMPTS_TOKEN_PATTERN.source, PROMPTS_TOKEN_PATTERN.flags);
|
|
1890
|
+
pattern.lastIndex = leading.cursor;
|
|
1891
|
+
const match = pattern.exec(text);
|
|
1892
|
+
if (!match || match.index !== leading.cursor)
|
|
1893
|
+
return false;
|
|
1894
|
+
const matchEnd = match.index + match[0].length;
|
|
1895
|
+
if (!hasActivePromptsTokenBoundary(text, match.index, matchEnd))
|
|
1896
|
+
return false;
|
|
1897
|
+
return (!leading.listItem || !isListItemDocumentation(text, leading.cursor, matchEnd))
|
|
1898
|
+
&& !isMarkdownDocumentationMention(text, match.index, matchEnd, referenceIndex);
|
|
1899
|
+
}
|
|
1900
|
+
function boundedPredecessorRanges(text, referenceIndex) {
|
|
1901
|
+
const inertRangeIndexes = collectInertRangeIndexes(text);
|
|
1902
|
+
const structuralRanges = [
|
|
1903
|
+
...collectIndentedCodeRanges(text),
|
|
1904
|
+
...collectFencedCodeRanges(text),
|
|
1905
|
+
...collectBlockquoteRanges(text),
|
|
1906
|
+
...collectInlineCodeRanges(text),
|
|
1907
|
+
...collectQuoteRanges(text),
|
|
1908
|
+
];
|
|
1909
|
+
const unboundedStructuralRanges = structuralRanges.filter((range) => !range.bounded);
|
|
1910
|
+
const unboundedStructuralIndex = createInertRangeIndex(unboundedStructuralRanges);
|
|
1911
|
+
const isOutsideUnboundedStructuralParent = (range) => {
|
|
1912
|
+
const parentEnd = inertRangeEndAt(unboundedStructuralIndex, range.start);
|
|
1913
|
+
return parentEnd === null || range.end > parentEnd;
|
|
1914
|
+
};
|
|
1915
|
+
const ranges = [
|
|
1916
|
+
...referenceIndex.predecessorRanges.filter(isOutsideUnboundedStructuralParent),
|
|
1917
|
+
...referenceIndex.tablePredecessorRanges.filter(isOutsideUnboundedStructuralParent),
|
|
1918
|
+
...structuralRanges
|
|
1919
|
+
.filter((range) => range.bounded && isOutsideUnboundedStructuralParent(range))
|
|
1920
|
+
.map(({ start, end }) => ({ start, end })),
|
|
1921
|
+
];
|
|
1922
|
+
const pattern = new RegExp(PROMPTS_TOKEN_PATTERN.source, PROMPTS_TOKEN_PATTERN.flags);
|
|
1923
|
+
let match;
|
|
1924
|
+
while ((match = pattern.exec(text)) !== null) {
|
|
1925
|
+
const start = match.index;
|
|
1926
|
+
const end = start + match[0].length;
|
|
1927
|
+
if (!isExplicitTokenBoundary(text, end))
|
|
1928
|
+
continue;
|
|
1929
|
+
if (isInInertRange(unboundedStructuralIndex, start))
|
|
1930
|
+
continue;
|
|
1931
|
+
const inactive = isInactivePromptsMention(text, start, end, inertRangeIndexes, referenceIndex);
|
|
1932
|
+
const lineStart = lineStartForPosition(text, start);
|
|
1933
|
+
const leading = leadingDirectiveCursor(text, lineStart, false);
|
|
1934
|
+
if (!inactive && directiveCommandTargetStart(text, leading.cursor) !== start)
|
|
700
1935
|
continue;
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
1936
|
+
const markdownRange = inactive ? markdownDocumentationRange(text, start, end, referenceIndex) : null;
|
|
1937
|
+
const referenceEnd = inactive ? inertRangeEndAt(referenceIndex.destinationRanges, start) : null;
|
|
1938
|
+
ranges.push({
|
|
1939
|
+
start: markdownRange?.start ?? start,
|
|
1940
|
+
end: inactive && isListItemDocumentation(text, start, end) ? lineEnd(text, end) : Math.max(markdownRange?.end ?? end, referenceEnd ?? end),
|
|
705
1941
|
});
|
|
706
1942
|
}
|
|
1943
|
+
return ranges.sort((left, right) => left.start - right.start || left.end - right.end);
|
|
1944
|
+
}
|
|
1945
|
+
function hasOddImmediateBackslashes(text, index) {
|
|
1946
|
+
let count = 0;
|
|
1947
|
+
for (let cursor = index - 1; cursor >= 0 && text[cursor] === '\\'; cursor -= 1)
|
|
1948
|
+
count += 1;
|
|
1949
|
+
return count % 2 === 1;
|
|
1950
|
+
}
|
|
1951
|
+
function scanExplicitCandidates(text) {
|
|
1952
|
+
const inertRangeIndexes = collectInertRangeIndexes(text);
|
|
1953
|
+
const candidates = [];
|
|
1954
|
+
const dollarScanner = /\$/gu;
|
|
1955
|
+
let dollar;
|
|
1956
|
+
while ((dollar = dollarScanner.exec(text)) !== null) {
|
|
1957
|
+
const start = dollar.index;
|
|
1958
|
+
EXPLICIT_TOKEN_START.lastIndex = start;
|
|
1959
|
+
const canonicalMatch = EXPLICIT_TOKEN_START.exec(text);
|
|
1960
|
+
const canonicalEnd = canonicalMatch?.index === start ? start + canonicalMatch[0].length : null;
|
|
1961
|
+
const firstCharacter = codePointAt(text, start + 1);
|
|
1962
|
+
if (canonicalEnd === null && (!firstCharacter || SAFE_TOKEN_WHITESPACE.test(firstCharacter) || isExplicitTokenBoundary(text, start + 1)))
|
|
1963
|
+
continue;
|
|
1964
|
+
const initialEnd = canonicalEnd ?? start + 1;
|
|
1965
|
+
const end = maximalExplicitTokenEnd(text, initialEnd);
|
|
1966
|
+
const rawKeyword = text.slice(start, end);
|
|
1967
|
+
dollarScanner.lastIndex = Math.max(end, start + 1);
|
|
1968
|
+
const reasons = new Set();
|
|
1969
|
+
for (const reason of STRUCTURAL_INERT_DIAGNOSTICS) {
|
|
1970
|
+
if (isInInertRange(inertRangeIndexes[reason], start))
|
|
1971
|
+
reasons.add(reason);
|
|
1972
|
+
}
|
|
1973
|
+
if (hasOddImmediateBackslashes(text, start))
|
|
1974
|
+
reasons.add('escaped');
|
|
1975
|
+
const canonicalToken = canonicalEnd === end ? (canonicalMatch?.[1] ?? '').toLowerCase() : '';
|
|
1976
|
+
const normalizedToken = canonicalToken || rawKeyword.replace(/^\$(?:(?:[Oo][Hh]-[Mm][Yy]-[Cc][Oo][Dd][Ee][Xx]):)?/u, '').toLowerCase();
|
|
1977
|
+
const definition = canonicalToken ? getExplicitSkillDefinition(canonicalToken) : undefined;
|
|
1978
|
+
candidates.push({
|
|
1979
|
+
rawKeyword,
|
|
1980
|
+
normalizedToken,
|
|
1981
|
+
skill: definition?.skill ?? null,
|
|
1982
|
+
priority: definition?.priority ?? null,
|
|
1983
|
+
start,
|
|
1984
|
+
end,
|
|
1985
|
+
reasons,
|
|
1986
|
+
});
|
|
1987
|
+
}
|
|
1988
|
+
return candidates;
|
|
1989
|
+
}
|
|
1990
|
+
function boundedHorizontalCursor(text, start, limit) {
|
|
1991
|
+
let cursor = start;
|
|
1992
|
+
while (cursor < limit && /[^\S\r\n\u2028\u2029]/u.test(text[cursor] ?? ''))
|
|
1993
|
+
cursor += 1;
|
|
1994
|
+
return cursor;
|
|
1995
|
+
}
|
|
1996
|
+
function documentationFollowupAt(text, start, lineLimit, candidates, candidateIndexByStart, cache) {
|
|
1997
|
+
const cached = cache.get(start);
|
|
1998
|
+
if (cached !== undefined)
|
|
1999
|
+
return cached;
|
|
2000
|
+
let cursor = boundedHorizontalCursor(text, start, lineLimit);
|
|
2001
|
+
const commandTarget = directiveCommandTargetStart(text, cursor, lineLimit);
|
|
2002
|
+
if (commandTarget !== null)
|
|
2003
|
+
cursor = commandTarget;
|
|
2004
|
+
const chain = collectMixedSubjectChain(text, cursor, lineLimit, candidates, candidateIndexByStart);
|
|
2005
|
+
const followup = chain
|
|
2006
|
+
? {
|
|
2007
|
+
end: chain.end,
|
|
2008
|
+
reopenable: chain.explicitIndexes.length > 0
|
|
2009
|
+
? !hasExplicitDocumentationSuffixAt(text, chain.end, lineLimit)
|
|
2010
|
+
: !hasImplicitDocumentationSubjectPrefix(text.slice(chain.start, lineLimit)),
|
|
2011
|
+
}
|
|
2012
|
+
: null;
|
|
2013
|
+
cache.set(start, followup);
|
|
2014
|
+
return followup;
|
|
2015
|
+
}
|
|
2016
|
+
function isDocumentationClauseSeparatorAt(text, index) {
|
|
2017
|
+
const character = codePointAt(text, index);
|
|
2018
|
+
const normalized = normalizedPunctuation(character);
|
|
2019
|
+
return /[,;؛.!??؟。!?::،、]/u.test(normalized)
|
|
2020
|
+
&& (normalized !== '.' || !isAbbreviationDotAt(text, index));
|
|
2021
|
+
}
|
|
2022
|
+
function isStrongDocumentationClauseSeparatorAt(text, index) {
|
|
2023
|
+
const normalized = normalizedPunctuation(codePointAt(text, index));
|
|
2024
|
+
return /[;؛.!??؟。!?::]/u.test(normalized)
|
|
2025
|
+
&& (normalized !== '.' || !isAbbreviationDotAt(text, index));
|
|
2026
|
+
}
|
|
2027
|
+
function explicitDocumentationClauseEnd(text, start, lineLimit, candidates, candidateIndexByStart, followups) {
|
|
2028
|
+
for (let cursor = start; cursor < lineLimit;) {
|
|
2029
|
+
if (isDocumentationClauseSeparatorAt(text, cursor)) {
|
|
2030
|
+
const followup = documentationFollowupAt(text, cursor + codePointAt(text, cursor).length, lineLimit, candidates, candidateIndexByStart, followups);
|
|
2031
|
+
if (followup?.reopenable)
|
|
2032
|
+
return cursor;
|
|
2033
|
+
if (followup) {
|
|
2034
|
+
cursor = followup.end;
|
|
2035
|
+
continue;
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
cursor += codePointAt(text, cursor).length;
|
|
2039
|
+
}
|
|
2040
|
+
return documentationDirectiveTransitionStart(text, start, lineLimit) ?? lineLimit;
|
|
2041
|
+
}
|
|
2042
|
+
function explicitDocumentationSuffixClauseEnd(text, start, lineLimit, candidates, candidateIndexByStart, followups) {
|
|
2043
|
+
for (let cursor = start; cursor < lineLimit;) {
|
|
2044
|
+
if (isDocumentationClauseSeparatorAt(text, cursor)) {
|
|
2045
|
+
if (isStrongDocumentationClauseSeparatorAt(text, cursor))
|
|
2046
|
+
return cursor;
|
|
2047
|
+
const followup = documentationFollowupAt(text, cursor + codePointAt(text, cursor).length, lineLimit, candidates, candidateIndexByStart, followups);
|
|
2048
|
+
if (followup?.reopenable)
|
|
2049
|
+
return cursor;
|
|
2050
|
+
if (followup) {
|
|
2051
|
+
cursor = followup.end;
|
|
2052
|
+
continue;
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
cursor += codePointAt(text, cursor).length;
|
|
2056
|
+
}
|
|
2057
|
+
return documentationDirectiveTransitionStart(text, start, lineLimit) ?? lineLimit;
|
|
2058
|
+
}
|
|
2059
|
+
function hasStrongDocumentationClauseBoundary(text, start, end) {
|
|
2060
|
+
for (let cursor = start; cursor < end;) {
|
|
2061
|
+
if (isStrongDocumentationClauseSeparatorAt(text, cursor))
|
|
2062
|
+
return true;
|
|
2063
|
+
cursor += codePointAt(text, cursor).length;
|
|
2064
|
+
}
|
|
2065
|
+
return false;
|
|
2066
|
+
}
|
|
2067
|
+
function isCompactSlashDocumentationCandidate(candidate) {
|
|
2068
|
+
const parts = candidate.rawKeyword.split('/');
|
|
2069
|
+
if (parts.length < 2)
|
|
2070
|
+
return false;
|
|
2071
|
+
return parts.every((part) => {
|
|
2072
|
+
const match = /^\$(?:(?:[Oo][Hh]-[Mm][Yy]-[Cc][Oo][Dd][Ee][Xx]):)?([A-Za-z][A-Za-z0-9_-]*)$/u.exec(part);
|
|
2073
|
+
return match !== null && getExplicitSkillDefinition((match[1] ?? '').toLowerCase()) !== undefined;
|
|
2074
|
+
});
|
|
2075
|
+
}
|
|
2076
|
+
function documentationSubjectChainAtClauseStart(text, start, lineLimit, candidates, candidateIndexByStart) {
|
|
2077
|
+
const contentStart = boundedHorizontalCursor(text, start, lineLimit);
|
|
2078
|
+
const commandTarget = directiveCommandTargetStart(text, contentStart, lineLimit);
|
|
2079
|
+
return collectMixedSubjectChain(text, commandTarget ?? contentStart, lineLimit, candidates, candidateIndexByStart);
|
|
2080
|
+
}
|
|
2081
|
+
function independentDocumentaryClauseStart(text, clauseStart, chain, lineLimit, candidateIndexByStart) {
|
|
2082
|
+
const contentStart = boundedHorizontalCursor(text, clauseStart, lineLimit);
|
|
2083
|
+
const directiveTarget = directiveCommandTargetStart(text, contentStart, lineLimit);
|
|
2084
|
+
if (directiveTarget === null || directiveTarget !== chain.start || candidateIndexByStart.has(directiveTarget))
|
|
2085
|
+
return null;
|
|
2086
|
+
const coordinator = new RegExp(`[,,،、]\\s*(?:${ASCII_AND}|${asciiCaseWordPattern('or')}|${asciiCaseWordPattern('nor')})\\s+`, 'u').exec(text.slice(chain.start, chain.end));
|
|
2087
|
+
return coordinator
|
|
2088
|
+
? boundedHorizontalCursor(text, chain.start + coordinator.index + coordinator[0].length, lineLimit)
|
|
2089
|
+
: null;
|
|
2090
|
+
}
|
|
2091
|
+
function findMixedSubjectChainInDocumentationClause(text, start, limit, candidates, candidateIndexByStart) {
|
|
2092
|
+
for (let cursor = boundedHorizontalCursor(text, start, limit); cursor < limit;) {
|
|
2093
|
+
const chain = collectMixedSubjectChain(text, cursor, limit, candidates, candidateIndexByStart);
|
|
2094
|
+
if (chain) {
|
|
2095
|
+
if (chain.explicitIndexes.length > 0)
|
|
2096
|
+
return chain;
|
|
2097
|
+
cursor = chain.end;
|
|
2098
|
+
continue;
|
|
2099
|
+
}
|
|
2100
|
+
cursor += codePointAt(text, cursor).length;
|
|
2101
|
+
}
|
|
2102
|
+
return null;
|
|
2103
|
+
}
|
|
2104
|
+
function collectImplicitDocumentationLineRanges(text, candidates, candidateIndexByStart) {
|
|
2105
|
+
const ranges = [];
|
|
2106
|
+
const followups = new Map();
|
|
2107
|
+
let lineStart = 0;
|
|
2108
|
+
while (lineStart < text.length) {
|
|
2109
|
+
const lineLimit = lineEnd(text, lineStart);
|
|
2110
|
+
let clauseStart = lineStart;
|
|
2111
|
+
while (clauseStart < lineLimit) {
|
|
2112
|
+
const clauseLimit = documentationSuffixLimit(text, clauseStart, lineLimit);
|
|
2113
|
+
const clauseText = text.slice(clauseStart, clauseLimit);
|
|
2114
|
+
let subjectChain = documentationSubjectChainAtClauseStart(text, clauseStart, clauseLimit, candidates, candidateIndexByStart);
|
|
2115
|
+
const directDocumentation = Boolean(subjectChain
|
|
2116
|
+
&& (subjectChain.explicitIndexes.length > 0
|
|
2117
|
+
? hasExplicitDocumentationSuffixAt(text, subjectChain.end, clauseLimit)
|
|
2118
|
+
: hasImplicitDocumentationSubjectPrefix(text.slice(subjectChain.start, clauseLimit))));
|
|
2119
|
+
const leadingDocumentation = DOCUMENTATION_LEADING_PATTERN.test(clauseText);
|
|
2120
|
+
if (directDocumentation || leadingDocumentation) {
|
|
2121
|
+
if (!subjectChain && leadingDocumentation) {
|
|
2122
|
+
subjectChain = findMixedSubjectChainInDocumentationClause(text, clauseStart, clauseLimit, candidates, candidateIndexByStart);
|
|
2123
|
+
}
|
|
2124
|
+
const rangeStart = subjectChain
|
|
2125
|
+
? independentDocumentaryClauseStart(text, clauseStart, subjectChain, lineLimit, candidateIndexByStart) ?? clauseStart
|
|
2126
|
+
: clauseStart;
|
|
2127
|
+
const rangeEnd = subjectChain
|
|
2128
|
+
? explicitDocumentationClauseEnd(text, subjectChain.end, lineLimit, candidates, candidateIndexByStart, followups)
|
|
2129
|
+
: clauseLimit;
|
|
2130
|
+
ranges.push({ start: rangeStart, end: rangeEnd });
|
|
2131
|
+
if (rangeEnd >= lineLimit)
|
|
2132
|
+
break;
|
|
2133
|
+
clauseStart = rangeEnd + codePointAt(text, rangeEnd).length;
|
|
2134
|
+
continue;
|
|
2135
|
+
}
|
|
2136
|
+
if (clauseLimit >= lineLimit)
|
|
2137
|
+
break;
|
|
2138
|
+
clauseStart = clauseLimit + codePointAt(text, clauseLimit).length;
|
|
2139
|
+
}
|
|
2140
|
+
const next = nextLineStart(text, lineLimit);
|
|
2141
|
+
if (next <= lineStart)
|
|
2142
|
+
break;
|
|
2143
|
+
lineStart = next;
|
|
2144
|
+
}
|
|
2145
|
+
return ranges;
|
|
2146
|
+
}
|
|
2147
|
+
function directCandidateIndexes(text, candidates, referenceIndex, postposedNegations) {
|
|
2148
|
+
const inertRangeIndexes = collectInertRangeIndexes(text);
|
|
2149
|
+
const candidateIndexByStart = new Map();
|
|
2150
|
+
for (const [index, candidate] of candidates.entries())
|
|
2151
|
+
candidateIndexByStart.set(candidate.start, index);
|
|
2152
|
+
const embeddedPathOrUrlIndex = collectEmbeddedPathOrUrlMentionIndex(text, candidates);
|
|
2153
|
+
const indexes = new Set();
|
|
2154
|
+
const implicitDocumentationRanges = collectImplicitDocumentationLineRanges(text, candidates, candidateIndexByStart);
|
|
2155
|
+
const documentationRanges = [...implicitDocumentationRanges];
|
|
2156
|
+
const documentationFollowups = new Map();
|
|
2157
|
+
let capturedBlock = false;
|
|
2158
|
+
let latestInertEnd = -1;
|
|
2159
|
+
let latestDocumentationEnd = -1;
|
|
2160
|
+
const recordDocumentationRange = (range) => {
|
|
2161
|
+
documentationRanges.push(range);
|
|
2162
|
+
latestInertEnd = Math.max(latestInertEnd, range.end);
|
|
2163
|
+
latestDocumentationEnd = Math.max(latestDocumentationEnd, range.end);
|
|
2164
|
+
};
|
|
2165
|
+
let candidateDocumentationLineStart = -1;
|
|
2166
|
+
let candidateDocumentationLineEnd = -1;
|
|
2167
|
+
let candidateListDocumentationRange = null;
|
|
2168
|
+
let candidateLineMayContainMarkdownDocumentation = false;
|
|
2169
|
+
const ensureCandidateDocumentationLine = (candidate) => {
|
|
2170
|
+
if (candidate.start >= candidateDocumentationLineStart && candidate.start < candidateDocumentationLineEnd)
|
|
2171
|
+
return;
|
|
2172
|
+
candidateDocumentationLineStart = lineStartForPosition(text, candidate.start);
|
|
2173
|
+
candidateDocumentationLineEnd = lineEnd(text, candidate.end);
|
|
2174
|
+
candidateListDocumentationRange = listItemDocumentationTokenRange(text, candidate.start, candidate.end);
|
|
2175
|
+
const line = text.slice(candidateDocumentationLineStart, candidateDocumentationLineEnd);
|
|
2176
|
+
const followingStart = candidateDocumentationLineEnd < text.length
|
|
2177
|
+
? nextLineStart(text, candidateDocumentationLineEnd)
|
|
2178
|
+
: text.length;
|
|
2179
|
+
const followingLine = followingStart < text.length
|
|
2180
|
+
? text.slice(followingStart, lineEnd(text, followingStart))
|
|
2181
|
+
: '';
|
|
2182
|
+
candidateLineMayContainMarkdownDocumentation = /[\[\]|]/u.test(line)
|
|
2183
|
+
|| /^\s*#{1,6}\s/u.test(line)
|
|
2184
|
+
|| /^\s*(?:={3,}|-{3,})\s*$/u.test(followingLine)
|
|
2185
|
+
|| (line.includes('|') && isMarkdownTableDelimiter(followingLine));
|
|
2186
|
+
};
|
|
2187
|
+
const cachedCandidateDocumentationRange = (candidate) => {
|
|
2188
|
+
ensureCandidateDocumentationLine(candidate);
|
|
2189
|
+
const destinationEnd = inertRangeEndAt(referenceIndex.destinationRanges, candidate.start);
|
|
2190
|
+
if (destinationEnd !== null)
|
|
2191
|
+
return { start: candidate.start, end: destinationEnd };
|
|
2192
|
+
if (candidateListDocumentationRange
|
|
2193
|
+
&& candidate.start >= candidateListDocumentationRange.start
|
|
2194
|
+
&& candidate.end <= candidateListDocumentationRange.end) {
|
|
2195
|
+
return { start: candidate.start, end: candidateDocumentationLineEnd };
|
|
2196
|
+
}
|
|
2197
|
+
if (candidateLineMayContainMarkdownDocumentation) {
|
|
2198
|
+
const markdownRange = markdownDocumentationRange(text, candidate.start, candidate.end, referenceIndex);
|
|
2199
|
+
if (markdownRange)
|
|
2200
|
+
return markdownRange;
|
|
2201
|
+
}
|
|
2202
|
+
return isEmbeddedPathOrUrlMention(embeddedPathOrUrlIndex, candidate.start) ? { start: candidate.start, end: candidate.end } : null;
|
|
2203
|
+
};
|
|
2204
|
+
const addBlock = (start) => {
|
|
2205
|
+
let candidateIndex = candidateIndexByStart.get(start);
|
|
2206
|
+
if (candidateIndex === undefined || candidates[candidateIndex].reasons.size > 0 || isNegativeExplicitMention(candidates[candidateIndex], postposedNegations))
|
|
2207
|
+
return 'none';
|
|
2208
|
+
const added = [];
|
|
2209
|
+
const checkedPostposedSkills = new Set();
|
|
2210
|
+
let blockEnd = start;
|
|
2211
|
+
const blockLineLimit = lineEnd(text, start);
|
|
2212
|
+
while (candidateIndex !== undefined && candidates[candidateIndex].reasons.size === 0) {
|
|
2213
|
+
const candidate = candidates[candidateIndex];
|
|
2214
|
+
if (added.length > 0 && hasStrongDocumentationClauseBoundary(text, blockEnd, candidate.start)) {
|
|
2215
|
+
const candidateClauseEnd = explicitDocumentationSuffixClauseEnd(text, candidate.end, blockLineLimit, candidates, candidateIndexByStart, documentationFollowups);
|
|
2216
|
+
if (hasExplicitDocumentationSuffixAt(text, candidate.end, candidateClauseEnd))
|
|
2217
|
+
break;
|
|
2218
|
+
}
|
|
2219
|
+
const candidateDocumentationRange = cachedCandidateDocumentationRange(candidate);
|
|
2220
|
+
if (candidateDocumentationRange) {
|
|
2221
|
+
recordDocumentationRange(candidateDocumentationRange);
|
|
2222
|
+
if (added.length === 0)
|
|
2223
|
+
return 'documentation';
|
|
2224
|
+
break;
|
|
2225
|
+
}
|
|
2226
|
+
if (added.length > 0 && candidate.skill && !checkedPostposedSkills.has(candidate.skill) && hasPostposedExplicitNegation(postposedNegations, candidate))
|
|
2227
|
+
break;
|
|
2228
|
+
if (candidate.skill)
|
|
2229
|
+
checkedPostposedSkills.add(candidate.skill);
|
|
2230
|
+
indexes.add(candidateIndex);
|
|
2231
|
+
added.push(candidateIndex);
|
|
2232
|
+
blockEnd = candidates[candidateIndex].end;
|
|
2233
|
+
const nextStart = punctuationSeparatedCandidateStart(text, blockEnd);
|
|
2234
|
+
if (nextStart === null)
|
|
2235
|
+
break;
|
|
2236
|
+
candidateIndex = candidateIndexByStart.get(nextStart);
|
|
2237
|
+
}
|
|
2238
|
+
if (added.length === 0)
|
|
2239
|
+
return 'none';
|
|
2240
|
+
const documentationLineEnd = blockLineLimit;
|
|
2241
|
+
const subjectChain = collectMixedSubjectChain(text, candidates[added[0]].start, documentationLineEnd, candidates, candidateIndexByStart) ?? { start: candidates[added[0]].start, explicitIndexes: [], end: blockEnd };
|
|
2242
|
+
const addedSet = new Set(added);
|
|
2243
|
+
const documentationAdded = [...new Set([...added, ...subjectChain.explicitIndexes])];
|
|
2244
|
+
const coordinatedDocumentationAdded = subjectChain.explicitIndexes.filter((index) => !addedSet.has(index));
|
|
2245
|
+
let documentationBlockEnd = Math.max(blockEnd, subjectChain.end);
|
|
2246
|
+
let coordinatedStart = coordinatedDocumentationCandidateStart(text, documentationBlockEnd);
|
|
2247
|
+
while (coordinatedStart !== null) {
|
|
2248
|
+
const coordinatedIndex = candidateIndexByStart.get(coordinatedStart);
|
|
2249
|
+
if (coordinatedIndex === undefined || candidates[coordinatedIndex].reasons.size > 0)
|
|
2250
|
+
break;
|
|
2251
|
+
documentationAdded.push(coordinatedIndex);
|
|
2252
|
+
coordinatedDocumentationAdded.push(coordinatedIndex);
|
|
2253
|
+
documentationBlockEnd = candidates[coordinatedIndex].end;
|
|
2254
|
+
coordinatedStart = coordinatedDocumentationCandidateStart(text, documentationBlockEnd);
|
|
2255
|
+
}
|
|
2256
|
+
const documentationSuffixEnd = explicitDocumentationSuffixClauseEnd(text, documentationBlockEnd, documentationLineEnd, candidates, candidateIndexByStart, documentationFollowups);
|
|
2257
|
+
const documentationSuffix = documentationAdded.some((index) => candidates[index].skill !== null || isCompactSlashDocumentationCandidate(candidates[index]))
|
|
2258
|
+
&& hasExplicitDocumentationSuffixAt(text, documentationBlockEnd, documentationSuffixEnd);
|
|
2259
|
+
let documentationRange = null;
|
|
2260
|
+
if (documentationSuffix) {
|
|
2261
|
+
const documentationRangeEnd = explicitDocumentationClauseEnd(text, documentationBlockEnd, documentationLineEnd, candidates, candidateIndexByStart, documentationFollowups);
|
|
2262
|
+
documentationRange = {
|
|
2263
|
+
start,
|
|
2264
|
+
end: documentationRangeEnd,
|
|
2265
|
+
};
|
|
2266
|
+
}
|
|
2267
|
+
else if (isListItemDocumentation(text, start, documentationBlockEnd)) {
|
|
2268
|
+
documentationRange = { start, end: documentationLineEnd };
|
|
2269
|
+
}
|
|
2270
|
+
else {
|
|
2271
|
+
for (const index of coordinatedDocumentationAdded) {
|
|
2272
|
+
const markdownRange = markdownDocumentationRange(text, candidates[index].start, candidates[index].end, referenceIndex);
|
|
2273
|
+
if (!markdownRange)
|
|
2274
|
+
continue;
|
|
2275
|
+
documentationRange = documentationRange
|
|
2276
|
+
? { start: Math.min(documentationRange.start, markdownRange.start), end: Math.max(documentationRange.end, markdownRange.end) }
|
|
2277
|
+
: markdownRange;
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
if (documentationRange) {
|
|
2281
|
+
for (const index of documentationAdded)
|
|
2282
|
+
indexes.delete(index);
|
|
2283
|
+
recordDocumentationRange(documentationRange);
|
|
2284
|
+
return 'documentation';
|
|
2285
|
+
}
|
|
2286
|
+
if (added.length > 0) {
|
|
2287
|
+
capturedBlock = true;
|
|
2288
|
+
return 'direct';
|
|
2289
|
+
}
|
|
2290
|
+
return 'none';
|
|
2291
|
+
};
|
|
2292
|
+
addBlock(promptLeadingExplicitCandidateStart(text));
|
|
2293
|
+
const inertPromptRanges = boundedPredecessorRanges(text, referenceIndex);
|
|
2294
|
+
let inertPromptCursor = 0;
|
|
2295
|
+
let implicitDocumentationCursor = 0;
|
|
2296
|
+
for (const [candidateIndex, candidate] of candidates.entries()) {
|
|
2297
|
+
ensureCandidateDocumentationLine(candidate);
|
|
2298
|
+
while (inertPromptCursor < inertPromptRanges.length && inertPromptRanges[inertPromptCursor].start < candidate.start) {
|
|
2299
|
+
latestInertEnd = Math.max(latestInertEnd, inertPromptRanges[inertPromptCursor].end);
|
|
2300
|
+
inertPromptCursor += 1;
|
|
2301
|
+
}
|
|
2302
|
+
while (implicitDocumentationCursor < implicitDocumentationRanges.length && implicitDocumentationRanges[implicitDocumentationCursor].start < candidate.start) {
|
|
2303
|
+
latestInertEnd = Math.max(latestInertEnd, implicitDocumentationRanges[implicitDocumentationCursor].end);
|
|
2304
|
+
latestDocumentationEnd = Math.max(latestDocumentationEnd, implicitDocumentationRanges[implicitDocumentationCursor].end);
|
|
2305
|
+
implicitDocumentationCursor += 1;
|
|
2306
|
+
}
|
|
2307
|
+
if (candidate.start < latestDocumentationEnd)
|
|
2308
|
+
continue;
|
|
2309
|
+
if (indexes.has(candidateIndex)) {
|
|
2310
|
+
latestInertEnd = -1;
|
|
2311
|
+
latestDocumentationEnd = -1;
|
|
2312
|
+
continue;
|
|
2313
|
+
}
|
|
2314
|
+
if (capturedBlock)
|
|
2315
|
+
continue;
|
|
2316
|
+
if (isInertOrNegativeMention(candidate, postposedNegations)) {
|
|
2317
|
+
const structuralEnd = structuralInertRangeEnd(inertRangeIndexes, candidate.start);
|
|
2318
|
+
let predecessorEnd = structuralEnd ?? candidate.end;
|
|
2319
|
+
predecessorEnd = Math.max(predecessorEnd, postposedExplicitNegationEnd(postposedNegations, candidate) ?? -1);
|
|
2320
|
+
if (candidateLineMayContainMarkdownDocumentation
|
|
2321
|
+
&& text.lastIndexOf('[', candidate.start) >= candidateDocumentationLineStart
|
|
2322
|
+
&& text.indexOf(']', candidate.end) < candidateDocumentationLineEnd) {
|
|
2323
|
+
predecessorEnd = Math.max(predecessorEnd, markdownDocumentationRange(text, candidate.start, candidate.end, referenceIndex)?.end ?? -1);
|
|
2324
|
+
}
|
|
2325
|
+
latestInertEnd = Math.max(latestInertEnd, predecessorEnd);
|
|
2326
|
+
continue;
|
|
2327
|
+
}
|
|
2328
|
+
const documentationRange = cachedCandidateDocumentationRange(candidate);
|
|
2329
|
+
if (documentationRange) {
|
|
2330
|
+
recordDocumentationRange(documentationRange);
|
|
2331
|
+
continue;
|
|
2332
|
+
}
|
|
2333
|
+
if (!capturedBlock && latestInertEnd >= 0 && !isNegativeExplicitMention(candidate, postposedNegations)) {
|
|
2334
|
+
const lineLeading = leadingDirectiveCursor(text, candidateDocumentationLineStart, false).cursor === candidate.start;
|
|
2335
|
+
const documentationSeparated = latestDocumentationEnd >= 0
|
|
2336
|
+
&& hasAdjacentPredecessorSeparator(text, latestDocumentationEnd, candidate.start);
|
|
2337
|
+
if (documentationSeparated || (lineLeading && hasAdjacentPredecessorSeparator(text, latestInertEnd, candidate.start)) || clauseDirectiveStart(text, latestInertEnd, candidate.start)) {
|
|
2338
|
+
const addedBlock = addBlock(candidate.start);
|
|
2339
|
+
if (addedBlock !== 'documentation') {
|
|
2340
|
+
latestInertEnd = -1;
|
|
2341
|
+
latestDocumentationEnd = -1;
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
else {
|
|
2345
|
+
latestInertEnd = -1;
|
|
2346
|
+
latestDocumentationEnd = -1;
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
707
2350
|
return {
|
|
708
|
-
|
|
709
|
-
|
|
2351
|
+
directIndexes: indexes,
|
|
2352
|
+
documentationRanges: createInertRangeIndex(documentationRanges),
|
|
2353
|
+
documentationBlocks: documentationRanges,
|
|
710
2354
|
};
|
|
711
2355
|
}
|
|
2356
|
+
function freezeMatches(matches) {
|
|
2357
|
+
return Object.freeze(matches.map((match) => Object.freeze({ ...match })));
|
|
2358
|
+
}
|
|
2359
|
+
function freezeCandidates(candidates) {
|
|
2360
|
+
return Object.freeze(candidates.map((candidate) => Object.freeze({
|
|
2361
|
+
rawKeyword: candidate.rawKeyword,
|
|
2362
|
+
normalizedToken: candidate.normalizedToken,
|
|
2363
|
+
skill: candidate.skill,
|
|
2364
|
+
priority: candidate.priority,
|
|
2365
|
+
reasons: Object.freeze(KEYWORD_INERT_DIAGNOSTIC_ORDER.filter((reason) => candidate.reasons.has(reason))),
|
|
2366
|
+
})));
|
|
2367
|
+
}
|
|
2368
|
+
function lowerBound(values, value) {
|
|
2369
|
+
let lower = 0;
|
|
2370
|
+
let upper = values.length;
|
|
2371
|
+
while (lower < upper) {
|
|
2372
|
+
const middle = lower + Math.floor((upper - lower) / 2);
|
|
2373
|
+
if (values[middle] < value)
|
|
2374
|
+
lower = middle + 1;
|
|
2375
|
+
else
|
|
2376
|
+
upper = middle;
|
|
2377
|
+
}
|
|
2378
|
+
return lower;
|
|
2379
|
+
}
|
|
2380
|
+
function upperBound(values, value) {
|
|
2381
|
+
let lower = 0;
|
|
2382
|
+
let upper = values.length;
|
|
2383
|
+
while (lower < upper) {
|
|
2384
|
+
const middle = lower + Math.floor((upper - lower) / 2);
|
|
2385
|
+
if (values[middle] <= value)
|
|
2386
|
+
lower = middle + 1;
|
|
2387
|
+
else
|
|
2388
|
+
upper = middle;
|
|
2389
|
+
}
|
|
2390
|
+
return lower;
|
|
2391
|
+
}
|
|
2392
|
+
function lineIndexAt(lineStarts, position) {
|
|
2393
|
+
return Math.max(0, upperBound(lineStarts, position) - 1);
|
|
2394
|
+
}
|
|
2395
|
+
function implicitLineIndexAt(index, position) {
|
|
2396
|
+
return lineIndexAt(index.lineStarts, position);
|
|
2397
|
+
}
|
|
2398
|
+
function indexedBoundaryAtOrAfter(values, position, fallback) {
|
|
2399
|
+
return values[lowerBound(values, position)] ?? fallback;
|
|
2400
|
+
}
|
|
2401
|
+
function positiveContrastStartInRange(contrasts, start, end) {
|
|
2402
|
+
const contrast = contrasts[lowerBound(contrasts, start)];
|
|
2403
|
+
return contrast !== undefined && contrast < end ? contrast : null;
|
|
2404
|
+
}
|
|
2405
|
+
function collectImplicitClauseIndex(text, documentationBlocks) {
|
|
2406
|
+
const lineStarts = [];
|
|
2407
|
+
const lineEnds = [];
|
|
2408
|
+
const subjectStarts = [];
|
|
2409
|
+
const clauseEnds = [];
|
|
2410
|
+
const strongClauseEnds = [];
|
|
2411
|
+
let lineStart = 0;
|
|
2412
|
+
while (lineStart <= text.length) {
|
|
2413
|
+
const lineLimit = lineEnd(text, lineStart);
|
|
2414
|
+
lineStarts.push(lineStart);
|
|
2415
|
+
lineEnds.push(lineLimit);
|
|
2416
|
+
subjectStarts.push(lineStart);
|
|
2417
|
+
for (let cursor = lineStart; cursor < lineLimit;) {
|
|
2418
|
+
const character = codePointAt(text, cursor);
|
|
2419
|
+
if (isClauseBoundaryAt(text, cursor)) {
|
|
2420
|
+
clauseEnds.push(cursor);
|
|
2421
|
+
if (isPostposedSubjectBoundaryAt(text, cursor)) {
|
|
2422
|
+
strongClauseEnds.push(cursor);
|
|
2423
|
+
subjectStarts.push(cursor + character.length);
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
cursor += character.length;
|
|
2427
|
+
}
|
|
2428
|
+
if (lineLimit === text.length)
|
|
2429
|
+
break;
|
|
2430
|
+
lineStart = nextLineStart(text, lineLimit);
|
|
2431
|
+
}
|
|
2432
|
+
const positiveContrasts = [];
|
|
2433
|
+
const contrastScanner = new RegExp(`${ASCII_BUT}\\s+(?:${ASCII_PLEASE}\\s+)?(?:${ASCII_INSTEAD}\\s+)?(?=${ASCII_DIRECTIVE_COMMAND})`, 'gu');
|
|
2434
|
+
let contrast;
|
|
2435
|
+
while ((contrast = contrastScanner.exec(text)) !== null) {
|
|
2436
|
+
if (hasUnicodeGrammarTokenStart(text, contrast.index))
|
|
2437
|
+
positiveContrasts.push(contrast.index);
|
|
2438
|
+
}
|
|
2439
|
+
const negativeBlocks = [];
|
|
2440
|
+
const normalizedText = normalizeGrammarApostrophes(text);
|
|
2441
|
+
const prefixScanner = new RegExp(NEGATIVE_PREFIX_PATTERN.source, 'gu');
|
|
2442
|
+
let prefix;
|
|
2443
|
+
let prefixCoveredUntil = -1;
|
|
2444
|
+
while ((prefix = prefixScanner.exec(normalizedText)) !== null) {
|
|
2445
|
+
if (!hasUnicodeGrammarTokenBoundaries(normalizedText, prefix.index, prefixScanner.lastIndex)
|
|
2446
|
+
|| isDiscourseNegation(normalizedText, prefix.index, prefixScanner.lastIndex))
|
|
2447
|
+
continue;
|
|
2448
|
+
if (prefix.index < prefixCoveredUntil)
|
|
2449
|
+
continue;
|
|
2450
|
+
const lineIndex = lineIndexAt(lineStarts, prefix.index);
|
|
2451
|
+
const lineLimit = lineEnds[lineIndex] ?? text.length;
|
|
2452
|
+
const clauseEnd = Math.min(indexedBoundaryAtOrAfter(strongClauseEnds, prefixScanner.lastIndex, lineLimit), lineLimit);
|
|
2453
|
+
const positiveContrast = positiveContrastStartInRange(positiveContrasts, prefixScanner.lastIndex, clauseEnd);
|
|
2454
|
+
const exclusionTransition = exclusionPrefixDirectiveTransitionStart(text, prefix.index, prefixScanner.lastIndex, clauseEnd);
|
|
2455
|
+
const end = Math.min(positiveContrast ?? clauseEnd, exclusionTransition ?? clauseEnd);
|
|
2456
|
+
negativeBlocks.push({ start: prefix.index, end });
|
|
2457
|
+
prefixCoveredUntil = end;
|
|
2458
|
+
}
|
|
2459
|
+
const predicateScanner = new RegExp(POSTPOSED_NEGATIVE_PREDICATE.source, 'giu');
|
|
2460
|
+
const checkedSubjectStarts = new Set();
|
|
2461
|
+
let predicate;
|
|
2462
|
+
while ((predicate = predicateScanner.exec(normalizedText)) !== null) {
|
|
2463
|
+
const predicateTokenStart = firstGrammarTokenStart(normalizedText, predicate.index, predicateScanner.lastIndex);
|
|
2464
|
+
if (!hasUnicodeGrammarTokenBoundaries(normalizedText, predicateTokenStart, predicateScanner.lastIndex)
|
|
2465
|
+
|| !hasAsciiGrammarTokenCharacters(normalizedText, predicateTokenStart, predicateScanner.lastIndex))
|
|
2466
|
+
continue;
|
|
2467
|
+
const subjectStart = subjectStarts[Math.max(0, upperBound(subjectStarts, predicate.index) - 1)] ?? 0;
|
|
2468
|
+
if (checkedSubjectStarts.has(subjectStart))
|
|
2469
|
+
continue;
|
|
2470
|
+
checkedSubjectStarts.add(subjectStart);
|
|
2471
|
+
const lineIndex = lineIndexAt(lineStarts, predicate.index);
|
|
2472
|
+
const lineLimit = lineEnds[lineIndex] ?? text.length;
|
|
2473
|
+
const clauseEnd = Math.min(indexedBoundaryAtOrAfter(strongClauseEnds, predicateScanner.lastIndex, lineLimit), lineLimit);
|
|
2474
|
+
const subject = text.slice(subjectStart, predicate.index);
|
|
2475
|
+
if (hasAsciiDirectiveCommand(subject) || !IMPLICIT_POSTPOSED_SUBJECT_CHAIN.test(subject))
|
|
2476
|
+
continue;
|
|
2477
|
+
const positiveContrast = positiveContrastStartInRange(positiveContrasts, predicateScanner.lastIndex, clauseEnd);
|
|
2478
|
+
negativeBlocks.push({ start: subjectStart, end: positiveContrast ?? clauseEnd });
|
|
2479
|
+
}
|
|
2480
|
+
return {
|
|
2481
|
+
lineStarts,
|
|
2482
|
+
lineEnds,
|
|
2483
|
+
subjectStarts,
|
|
2484
|
+
clauseEnds,
|
|
2485
|
+
strongClauseEnds,
|
|
2486
|
+
documentationBlocks: createInertRangeIndex([...documentationBlocks]),
|
|
2487
|
+
negativeBlocks: createInertRangeIndex(negativeBlocks),
|
|
2488
|
+
};
|
|
2489
|
+
}
|
|
2490
|
+
function hasImplicitDocumentationFrame(text) {
|
|
2491
|
+
return /(?:^|[\s([{])(?:docs?|documentation|examples?|references?|guide|manual|document(?:s|ed|ing)?|describ(?:e|es|ed|ing)|mention(?:s|ed|ing)|explain(?:s|ed|ing)?)(?:\b|\s*:)/iu.test(text);
|
|
2492
|
+
}
|
|
2493
|
+
function hasIntroductoryDocumentationFrame(text) {
|
|
2494
|
+
return /^\s*(?:for\s+(?:example|instance|reference)|as\s+an?\s+example|according\s+to\s+(?:the\s+)?(?:docs?|documentation|guide|manual|reference)|(?:in|per)\s+(?:the\s+)?(?:docs?|documentation|guide|manual|reference))\s*(?:[,,،、::]|[—–-])\s*$/iu.test(text);
|
|
2495
|
+
}
|
|
2496
|
+
function implicitClauseRange(text, candidateStart, candidateEnd, clauses) {
|
|
2497
|
+
const lineIndex = implicitLineIndexAt(clauses, candidateStart);
|
|
2498
|
+
const lineStart = clauses.lineStarts[lineIndex] ?? 0;
|
|
2499
|
+
const logicalLineEnd = clauses.lineEnds[lineIndex] ?? text.length;
|
|
2500
|
+
let start = clauses.subjectStarts[Math.max(0, upperBound(clauses.subjectStarts, candidateStart) - 1)] ?? lineStart;
|
|
2501
|
+
let frameStart = start;
|
|
2502
|
+
const introductoryPrefix = /^[^\r\n,:,:،、—–-]*(?:[,,،、::]|[—–-])\s*/u.exec(text.slice(lineStart, candidateStart))?.[0];
|
|
2503
|
+
const introductoryRemainder = introductoryPrefix
|
|
2504
|
+
? text.slice(lineStart + introductoryPrefix.length, candidateStart)
|
|
2505
|
+
: '';
|
|
2506
|
+
const hasGoverningIntroductoryFrame = Boolean(introductoryPrefix
|
|
2507
|
+
&& hasIntroductoryDocumentationFrame(introductoryPrefix)
|
|
2508
|
+
&& !hasLogicalSentenceBoundary(introductoryRemainder));
|
|
2509
|
+
if (hasGoverningIntroductoryFrame)
|
|
2510
|
+
frameStart = lineStart;
|
|
2511
|
+
const discardFrame = new RegExp(`^\\s*(?:${ASCII_PLEASE}\\s+)?${EXCLUSION_PREFIX}`, 'u');
|
|
2512
|
+
const contrastText = text.slice(start, candidateStart);
|
|
2513
|
+
const contrastStart = latestPositiveContrastStart(contrastText);
|
|
2514
|
+
if (contrastStart >= 0) {
|
|
2515
|
+
const transitionStart = start + contrastStart;
|
|
2516
|
+
const discardMatch = discardFrame.exec(text.slice(start, transitionStart));
|
|
2517
|
+
if (!hasGoverningIntroductoryFrame
|
|
2518
|
+
&& discardMatch
|
|
2519
|
+
&& hasUnicodeGrammarTokenBoundaries(text, start + discardMatch.index, start + discardMatch.index + discardMatch[0].length)) {
|
|
2520
|
+
frameStart = transitionStart;
|
|
2521
|
+
}
|
|
2522
|
+
start = transitionStart;
|
|
2523
|
+
}
|
|
2524
|
+
const directivePrefix = text.slice(start, candidateStart);
|
|
2525
|
+
const directiveTransition = new RegExp(`(?:${ASCII_AND}|${ASCII_THEN})\\s+(?=(?:${ASCII_PLEASE}\\s+)?(?:${ASCII_INSTEAD}\\s+)?${ASCII_DIRECTIVE_COMMAND})[^\\r\\n\\u2028\\u2029]*$`, 'u').exec(directivePrefix);
|
|
2526
|
+
if (directiveTransition
|
|
2527
|
+
&& hasUnicodeGrammarTokenBoundaries(directivePrefix, directiveTransition.index, directiveTransition.index + directiveTransition[0].length)) {
|
|
2528
|
+
const transitionStart = start + directiveTransition.index;
|
|
2529
|
+
const hasNegativePrefix = hasUnicodeBoundedNegativePrefix(normalizeGrammarApostrophes(text.slice(frameStart, transitionStart)));
|
|
2530
|
+
const exclusionTransition = isExclusionPrefixDirectiveTransitionAt(text, frameStart, transitionStart, candidateStart);
|
|
2531
|
+
if (!hasGoverningIntroductoryFrame && (!hasNegativePrefix || exclusionTransition)) {
|
|
2532
|
+
frameStart = transitionStart;
|
|
2533
|
+
start = transitionStart;
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
let punctuationDirectiveStart = -1;
|
|
2537
|
+
for (let cursor = start; cursor < candidateStart;) {
|
|
2538
|
+
const character = codePointAt(text, cursor);
|
|
2539
|
+
if (isClauseBoundaryAt(text, cursor) || normalizedPunctuation(character) === ':') {
|
|
2540
|
+
const directiveStart = boundedHorizontalCursor(text, cursor + character.length, candidateStart);
|
|
2541
|
+
if (directiveCommandTargetStart(text, directiveStart, candidateStart) === candidateStart) {
|
|
2542
|
+
punctuationDirectiveStart = directiveStart;
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
cursor += character.length;
|
|
2546
|
+
}
|
|
2547
|
+
if (punctuationDirectiveStart >= 0) {
|
|
2548
|
+
if (!hasGoverningIntroductoryFrame)
|
|
2549
|
+
frameStart = punctuationDirectiveStart;
|
|
2550
|
+
start = punctuationDirectiveStart;
|
|
2551
|
+
}
|
|
2552
|
+
const end = Math.min(indexedBoundaryAtOrAfter(clauses.clauseEnds, candidateEnd, logicalLineEnd), logicalLineEnd);
|
|
2553
|
+
return { start, frameStart, end, governingDocumentationFrame: hasGoverningIntroductoryFrame };
|
|
2554
|
+
}
|
|
2555
|
+
function isImplicitListDocumentation(text, candidateStart) {
|
|
2556
|
+
const start = lineStartForPosition(text, candidateStart);
|
|
2557
|
+
const leading = leadingDirectiveCursor(text, start, false);
|
|
2558
|
+
if (!leading.listItem || leading.cursor > candidateStart)
|
|
2559
|
+
return false;
|
|
2560
|
+
const content = text.slice(leading.cursor, lineEnd(text, candidateStart));
|
|
2561
|
+
return /(?:\s*(?::|:|[—–])\s*\S|\b(?:is|are|means|refer(?:s)?\s+to|denote(?:s)?)\b).*\b(?:commands?|workflows?|skills?|modes?|files?|documentation)\b/iu.test(content);
|
|
2562
|
+
}
|
|
2563
|
+
function isImplicitDocumentationClause(text, matchStart, matchEnd, clause, referenceIndex) {
|
|
2564
|
+
const prefix = text.slice(clause.frameStart, matchStart);
|
|
2565
|
+
if (clause.governingDocumentationFrame)
|
|
2566
|
+
return true;
|
|
2567
|
+
if (hasImplicitDocumentationFrame(prefix))
|
|
2568
|
+
return true;
|
|
2569
|
+
const introductoryFrame = /^[^,,،、\r\n\u2028\u2029]*[,,،、]\s*/u.exec(prefix)?.[0];
|
|
2570
|
+
if (introductoryFrame && hasIntroductoryDocumentationFrame(introductoryFrame))
|
|
2571
|
+
return true;
|
|
2572
|
+
if (hasImplicitDocumentationSubjectPrefix(text.slice(matchStart, clause.end)))
|
|
2573
|
+
return true;
|
|
2574
|
+
const suffix = text.slice(matchEnd, clause.end);
|
|
2575
|
+
if (/^(?:(?:\s+(?:mode|workflow|skill|loop))?\s+(?:(?:is|are|means|refer(?:s)?\s+to|denote(?:s)?)\b.*\b(?:commands?|workflows?|skills?|modes?|files?|documentation)\b|(?:is|are)\s+(?:(?:(?:also|still)\s+)?(?:(?:its|an?|the)\s+)?alias(?:es)?|documented|described)\b|(?:appears?|occurs?|is\s+(?:also\s+)?mentioned)\b.*\b(?:docs?|documentation|examples?|references?|guide|manual)\b|(?:docs?|documentation|examples?|references?|guide|manual)\b)|(?:\s+(?:mode|workflow|skill|loop))?\s*\/\s*.*\b(?:is|are|means|refer(?:s)?\s+to|denote(?:s)?)\b.*\b(?:commands?|workflows?|skills?|modes?|files?|documentation)\b|(?:\s+(?:mode|workflow|skill|loop))?\s*(?::|[—–-])\s*\S.*\b(?:commands?|workflows?|skills?|modes?|files?|documentation)\b)/iu.test(suffix))
|
|
2576
|
+
return true;
|
|
2577
|
+
const lineStart = lineStartForPosition(text, matchStart);
|
|
2578
|
+
const line = text.slice(lineStart, lineEnd(text, matchEnd));
|
|
2579
|
+
const localEnd = matchEnd - lineStart;
|
|
2580
|
+
if (/^(?:\s+(?:mode|workflow|skill|loop))?\s*[—–-]\s*\S.*\b(?:commands?|workflows?|skills?|modes?|files?|documentation)\b/iu.test(line.slice(localEnd)))
|
|
2581
|
+
return true;
|
|
2582
|
+
if (isMarkdownDocumentationMention(text, matchStart, matchEnd, referenceIndex))
|
|
2583
|
+
return true;
|
|
2584
|
+
return false;
|
|
2585
|
+
}
|
|
2586
|
+
function hasPostposedImplicitNegation(suffix, prefix) {
|
|
2587
|
+
const normalizedSuffix = normalizeGrammarApostrophes(suffix);
|
|
2588
|
+
const predicate = POSTPOSED_NEGATIVE_PREDICATE.exec(normalizedSuffix);
|
|
2589
|
+
const predicateTokenStart = predicate
|
|
2590
|
+
? firstGrammarTokenStart(normalizedSuffix, predicate.index, predicate.index + predicate[0].length)
|
|
2591
|
+
: -1;
|
|
2592
|
+
if (!predicate
|
|
2593
|
+
|| !hasUnicodeGrammarTokenBoundaries(normalizedSuffix, predicateTokenStart, predicate.index + predicate[0].length)
|
|
2594
|
+
|| !hasAsciiGrammarTokenCharacters(normalizedSuffix, predicateTokenStart, predicate.index + predicate[0].length))
|
|
2595
|
+
return false;
|
|
2596
|
+
const subjectTail = suffix.slice(0, predicate.index);
|
|
2597
|
+
if (hasAsciiDirectiveCommand(subjectTail))
|
|
2598
|
+
return false;
|
|
2599
|
+
const coordinatedSubject = new RegExp(`^(?:\\s+${IMPLICIT_WORKFLOW_NOUN})?(?:\\s*(?:(?:[,,،、]|/)\\s*(?:${COORDINATED_SUBJECT_JOINER}\\s+)?|${COORDINATED_SUBJECT_JOINER}\\s+)${COORDINATED_WORKFLOW_SUBJECT}(?:\\s+${IMPLICIT_WORKFLOW_NOUN})?)*\\s*[,,、،]?\\s*$`, 'iu');
|
|
2600
|
+
if (!coordinatedSubject.test(subjectTail))
|
|
2601
|
+
return false;
|
|
2602
|
+
const independentCoordinatedClause = /^\s+(?:modes?|workflows?|skills?|loops?)?\s*[,,،、]\s*(?:and|or|nor)\b/iu.test(subjectTail)
|
|
2603
|
+
&& hasAsciiDirectiveCommand(prefix);
|
|
2604
|
+
return !independentCoordinatedClause;
|
|
2605
|
+
}
|
|
2606
|
+
function collectEmbeddedPathOrUrlMentionIndex(text, candidates) {
|
|
2607
|
+
const tokenStarts = new Map();
|
|
2608
|
+
const embeddedCandidateStarts = new Set();
|
|
2609
|
+
let candidateIndex = 0;
|
|
2610
|
+
let tokenStart = 0;
|
|
2611
|
+
let penultimateTokenCharacter = '';
|
|
2612
|
+
let previousTokenCharacter = '';
|
|
2613
|
+
let tokenContainsUrlScheme = false;
|
|
2614
|
+
for (let cursor = 0; cursor < text.length;) {
|
|
2615
|
+
while (candidateIndex < candidates.length && candidates[candidateIndex].start === cursor) {
|
|
2616
|
+
tokenStarts.set(cursor, tokenStart);
|
|
2617
|
+
if (tokenContainsUrlScheme || /[\\/?#=&]/u.test(previousTokenCharacter))
|
|
2618
|
+
embeddedCandidateStarts.add(cursor);
|
|
2619
|
+
candidateIndex += 1;
|
|
2620
|
+
}
|
|
2621
|
+
const character = codePointAt(text, cursor);
|
|
2622
|
+
if (SAFE_TOKEN_WHITESPACE.test(character)) {
|
|
2623
|
+
tokenStart = cursor + character.length;
|
|
2624
|
+
penultimateTokenCharacter = '';
|
|
2625
|
+
previousTokenCharacter = '';
|
|
2626
|
+
tokenContainsUrlScheme = false;
|
|
2627
|
+
}
|
|
2628
|
+
else {
|
|
2629
|
+
if (penultimateTokenCharacter === ':' && previousTokenCharacter === '/' && character === '/') {
|
|
2630
|
+
tokenContainsUrlScheme = true;
|
|
2631
|
+
}
|
|
2632
|
+
penultimateTokenCharacter = previousTokenCharacter;
|
|
2633
|
+
previousTokenCharacter = character;
|
|
2634
|
+
}
|
|
2635
|
+
cursor += character.length;
|
|
2636
|
+
}
|
|
2637
|
+
return { tokenStarts, embeddedCandidateStarts };
|
|
2638
|
+
}
|
|
2639
|
+
function isEmbeddedPathOrUrlMention(index, start) {
|
|
2640
|
+
return index.tokenStarts.has(start) && index.embeddedCandidateStarts.has(start);
|
|
2641
|
+
}
|
|
2642
|
+
function hasActiveExplicitLikeInvocation(candidates, documentationRanges, postposedNegations) {
|
|
2643
|
+
return candidates.some((candidate) => {
|
|
2644
|
+
if (isInInertRange(documentationRanges, candidate.start))
|
|
2645
|
+
return false;
|
|
2646
|
+
if ([...candidate.reasons].some((reason) => reason !== 'not-leading-region'))
|
|
2647
|
+
return false;
|
|
2648
|
+
if (isNegativeExplicitMention(candidate, postposedNegations))
|
|
2649
|
+
return false;
|
|
2650
|
+
return true;
|
|
2651
|
+
});
|
|
2652
|
+
}
|
|
2653
|
+
function hasActivePromptsInvocation(text, start, end, inertRangeIndexes, referenceIndex) {
|
|
2654
|
+
const pattern = new RegExp(PROMPTS_TOKEN_PATTERN.source, PROMPTS_TOKEN_PATTERN.flags);
|
|
2655
|
+
pattern.lastIndex = start;
|
|
2656
|
+
let match;
|
|
2657
|
+
while ((match = pattern.exec(text)) !== null && match.index < end) {
|
|
2658
|
+
const matchEnd = match.index + match[0].length;
|
|
2659
|
+
if (!isInactivePromptsMention(text, match.index, matchEnd, inertRangeIndexes, referenceIndex))
|
|
2660
|
+
return true;
|
|
2661
|
+
}
|
|
2662
|
+
return false;
|
|
2663
|
+
}
|
|
2664
|
+
function hasImplicitKeywordBoundaries(text, start, end) {
|
|
2665
|
+
const previous = codePointBefore(text, start);
|
|
2666
|
+
const next = codePointAt(text, end);
|
|
2667
|
+
return (!previous || (previous !== '$' && !TOKEN_CONTINUATION.test(previous))) && (!next || !TOKEN_CONTINUATION.test(next));
|
|
2668
|
+
}
|
|
2669
|
+
function isActiveImplicitMatch(text, matchStart, matchEnd, matchedKeyword, inertRangeIndexes, referenceIndex, clauses, postposedNegations) {
|
|
2670
|
+
if (isStructurallyInert(inertRangeIndexes, matchStart)
|
|
2671
|
+
|| isInInertRange(referenceIndex.destinationRanges, matchStart)
|
|
2672
|
+
|| isInInertRange(clauses.documentationBlocks, matchStart)
|
|
2673
|
+
|| (!isNegativePrefixExemptImplicitKeyword(matchedKeyword) && isInInertRange(clauses.negativeBlocks, matchStart))
|
|
2674
|
+
|| isInInertRange(postposedNegations.implicitBlocks, matchStart)
|
|
2675
|
+
|| isImplicitListDocumentation(text, matchStart))
|
|
2676
|
+
return null;
|
|
2677
|
+
if (hasOddImmediateBackslashes(text, matchStart))
|
|
2678
|
+
return null;
|
|
2679
|
+
const clause = implicitClauseRange(text, matchStart, matchEnd, clauses);
|
|
2680
|
+
const lineStart = clauses.lineStarts[implicitLineIndexAt(clauses, matchStart)] ?? 0;
|
|
2681
|
+
const prefix = text.slice(clause.start, matchStart);
|
|
2682
|
+
const effectivePrefix = prefix.trim() || text.slice(lineStart, Math.max(lineStart, clause.start - 1));
|
|
2683
|
+
if (!isNegativePrefixExemptImplicitKeyword(matchedKeyword) && hasUnicodeBoundedNegativePrefix(normalizeGrammarApostrophes(effectivePrefix)))
|
|
2684
|
+
return null;
|
|
2685
|
+
const suffix = text.slice(matchEnd, clause.end);
|
|
2686
|
+
const lineEnd = clauses.lineEnds[implicitLineIndexAt(clauses, matchStart)] ?? text.length;
|
|
2687
|
+
const lineSuffix = text.slice(matchEnd, lineEnd);
|
|
2688
|
+
if (hasPostposedImplicitNegation(lineSuffix, effectivePrefix))
|
|
2689
|
+
return null;
|
|
2690
|
+
if (/^(?:\s+(?:mode|workflow|skill|loop))?(?:는|은|이|가)?\s*(?:사용하지\s*마세요|사용하지\s*마|쓰지\s*마세요|쓰지\s*마)/u.test(suffix))
|
|
2691
|
+
return null;
|
|
2692
|
+
if (hasActivePromptsInvocation(text, clause.start, clause.end, inertRangeIndexes, referenceIndex))
|
|
2693
|
+
return null;
|
|
2694
|
+
if (isImplicitDocumentationClause(text, matchStart, matchEnd, clause, referenceIndex))
|
|
2695
|
+
return null;
|
|
2696
|
+
return clause;
|
|
2697
|
+
}
|
|
2698
|
+
function detectImplicitKeywords(normalizedText, explicitCandidates, referenceIndex, clauses, postposedNegations) {
|
|
2699
|
+
const implicit = [];
|
|
2700
|
+
const inertRangeIndexes = collectInertRangeIndexes(normalizedText);
|
|
2701
|
+
const explicitCandidateRanges = createInertRangeIndex(explicitCandidates.map((candidate) => ({ start: candidate.start, end: candidate.end })));
|
|
2702
|
+
for (const { keyword, pattern, skill, priority } of KEYWORD_MAP) {
|
|
2703
|
+
if (keyword.startsWith('$'))
|
|
2704
|
+
continue;
|
|
2705
|
+
const scanner = new RegExp(pattern.source, `${pattern.flags}g`);
|
|
2706
|
+
let match;
|
|
2707
|
+
while ((match = scanner.exec(normalizedText)) !== null) {
|
|
2708
|
+
const matchStart = match.index;
|
|
2709
|
+
const matchEnd = matchStart + match[0].length;
|
|
2710
|
+
if ((inertRangeEndAt(explicitCandidateRanges, matchStart) ?? -1) >= matchEnd)
|
|
2711
|
+
continue;
|
|
2712
|
+
if (match[0].toLowerCase() !== 'ulw' && !hasImplicitKeywordBoundaries(normalizedText, matchStart, matchEnd))
|
|
2713
|
+
continue;
|
|
2714
|
+
const clause = isActiveImplicitMatch(normalizedText, matchStart, matchEnd, match[0], inertRangeIndexes, referenceIndex, clauses, postposedNegations);
|
|
2715
|
+
if (!clause)
|
|
2716
|
+
continue;
|
|
2717
|
+
const clauseText = normalizedText.slice(clause.start, clause.end);
|
|
2718
|
+
if (!hasIntentContextForKeyword(clauseText, match[0].toLowerCase()))
|
|
2719
|
+
continue;
|
|
2720
|
+
implicit.push({ keyword: match[0], skill, priority });
|
|
2721
|
+
break;
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
const seenSkills = new Set();
|
|
2725
|
+
return implicit.sort(compareKeywordMatches).filter((match) => {
|
|
2726
|
+
if (seenSkills.has(match.skill))
|
|
2727
|
+
return false;
|
|
2728
|
+
seenSkills.add(match.skill);
|
|
2729
|
+
return true;
|
|
2730
|
+
});
|
|
2731
|
+
}
|
|
2732
|
+
function hasOmxQuestionAnsweredPrefix(text) {
|
|
2733
|
+
return /^\s*\[omx question answered\]/i.test(text);
|
|
2734
|
+
}
|
|
712
2735
|
function hasIntentContextForKeyword(text, keyword) {
|
|
713
2736
|
const k = keyword.toLowerCase();
|
|
714
2737
|
if (k === 'deep interview' || k === 'interview') {
|
|
@@ -724,58 +2747,76 @@ function hasIntentContextForKeyword(text, keyword) {
|
|
|
724
2747
|
return patterns.some((pattern) => pattern.test(text));
|
|
725
2748
|
}
|
|
726
2749
|
/**
|
|
727
|
-
*
|
|
728
|
-
*
|
|
729
|
-
* then appends implicit keyword matches sorted by priority.
|
|
2750
|
+
* Classify one prompt with the direct-only explicit grammar and immutable
|
|
2751
|
+
* diagnostics. Consumers must share this result rather than re-detecting.
|
|
730
2752
|
*/
|
|
731
|
-
export function
|
|
2753
|
+
export function classifyKeywordInput(text) {
|
|
732
2754
|
const normalizedText = normalizeWorkflowKeyboardTypos(text);
|
|
733
|
-
const
|
|
734
|
-
const
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
if (explicit.length > 0) {
|
|
742
|
-
return explicit;
|
|
2755
|
+
const referenceIndex = collectMarkdownReferenceIndex(normalizedText);
|
|
2756
|
+
const candidates = scanExplicitCandidates(normalizedText);
|
|
2757
|
+
const postposedNegations = collectPostposedExplicitNegationIndex(normalizedText, candidates);
|
|
2758
|
+
const { directIndexes, documentationRanges, documentationBlocks } = directCandidateIndexes(normalizedText, candidates, referenceIndex, postposedNegations);
|
|
2759
|
+
const implicitClauses = collectImplicitClauseIndex(normalizedText, documentationBlocks);
|
|
2760
|
+
for (const [index, candidate] of candidates.entries()) {
|
|
2761
|
+
if (!directIndexes.has(index))
|
|
2762
|
+
candidate.reasons.add('not-leading-region');
|
|
743
2763
|
}
|
|
744
|
-
const
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
continue;
|
|
750
|
-
implicit.push({
|
|
751
|
-
keyword: match[0],
|
|
752
|
-
skill,
|
|
753
|
-
priority,
|
|
754
|
-
});
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
const merged = [...explicit];
|
|
758
|
-
const sortedImplicit = implicit.sort(compareKeywordMatches);
|
|
759
|
-
for (const item of sortedImplicit) {
|
|
760
|
-
if (merged.some((existing) => existing.skill === item.skill))
|
|
2764
|
+
const explicitMatches = [];
|
|
2765
|
+
const explicitSkills = new Set();
|
|
2766
|
+
for (const index of directIndexes) {
|
|
2767
|
+
const candidate = candidates[index];
|
|
2768
|
+
if (!candidate.skill || candidate.priority === null || explicitSkills.has(candidate.skill))
|
|
761
2769
|
continue;
|
|
762
|
-
|
|
2770
|
+
explicitSkills.add(candidate.skill);
|
|
2771
|
+
explicitMatches.push({
|
|
2772
|
+
keyword: candidate.rawKeyword,
|
|
2773
|
+
skill: candidate.skill,
|
|
2774
|
+
priority: candidate.priority,
|
|
2775
|
+
});
|
|
763
2776
|
}
|
|
764
|
-
|
|
2777
|
+
const markedQuestionAnswer = hasOmxQuestionAnsweredPrefix(normalizedText);
|
|
2778
|
+
const directPromptsInvocation = hasDirectPromptsInvocation(normalizedText, collectInertRangeIndexes(normalizedText), referenceIndex);
|
|
2779
|
+
const reservedInput = markedQuestionAnswer
|
|
2780
|
+
? 'omx-question-answered'
|
|
2781
|
+
: directPromptsInvocation
|
|
2782
|
+
? 'prompts'
|
|
2783
|
+
: null;
|
|
2784
|
+
const hasExplicitLikeInvocation = candidates.length > 0;
|
|
2785
|
+
const hasActiveExplicitLike = hasActiveExplicitLikeInvocation(candidates, documentationRanges, postposedNegations);
|
|
2786
|
+
const finalMatches = reservedInput
|
|
2787
|
+
? []
|
|
2788
|
+
: explicitMatches.length > 0
|
|
2789
|
+
? explicitMatches
|
|
2790
|
+
: hasActiveExplicitLike
|
|
2791
|
+
? []
|
|
2792
|
+
: detectImplicitKeywords(normalizedText, candidates, referenceIndex, implicitClauses, postposedNegations);
|
|
2793
|
+
const implicitMatches = reservedInput || hasActiveExplicitLike
|
|
2794
|
+
? []
|
|
2795
|
+
: finalMatches;
|
|
2796
|
+
return Object.freeze({
|
|
2797
|
+
originalText: text,
|
|
2798
|
+
normalizedText,
|
|
2799
|
+
candidates: freezeCandidates(candidates),
|
|
2800
|
+
explicitMatches: freezeMatches(explicitMatches),
|
|
2801
|
+
hasExplicitLikeInvocation,
|
|
2802
|
+
reservedInput,
|
|
2803
|
+
implicitMatches: freezeMatches(implicitMatches),
|
|
2804
|
+
matches: freezeMatches(finalMatches),
|
|
2805
|
+
});
|
|
765
2806
|
}
|
|
766
|
-
/**
|
|
767
|
-
|
|
768
|
-
|
|
2807
|
+
/** Detect workflow matches using a fresh immutable input classification. */
|
|
2808
|
+
export function detectKeywords(text) {
|
|
2809
|
+
return [...classifyKeywordInput(text).matches];
|
|
2810
|
+
}
|
|
2811
|
+
/** Get the first match in classification order. */
|
|
769
2812
|
export function detectPrimaryKeyword(text) {
|
|
770
|
-
|
|
771
|
-
return matches.length > 0 ? matches[0] : null;
|
|
2813
|
+
return classifyKeywordInput(text).matches[0] ?? null;
|
|
772
2814
|
}
|
|
773
2815
|
function filterMatchesForTeamMode(matches, teamEnabled) {
|
|
774
|
-
return teamEnabled ? matches : matches.filter((entry) => entry.skill !== 'team');
|
|
2816
|
+
return teamEnabled ? [...matches] : matches.filter((entry) => entry.skill !== 'team');
|
|
775
2817
|
}
|
|
776
|
-
function detectPrimaryKeywordForTeamMode(
|
|
777
|
-
|
|
778
|
-
return matches[0] ?? null;
|
|
2818
|
+
function detectPrimaryKeywordForTeamMode(classification, teamEnabled) {
|
|
2819
|
+
return filterMatchesForTeamMode(classification.matches, teamEnabled)[0] ?? null;
|
|
779
2820
|
}
|
|
780
2821
|
function isActiveSkillContinuationPrompt(text) {
|
|
781
2822
|
const normalized = text.trim();
|
|
@@ -789,17 +2830,15 @@ function isNamedActiveSkillContinuationPrompt(text, skill) {
|
|
|
789
2830
|
return false;
|
|
790
2831
|
return new RegExp(`^[\\\\/]?\\s*${normalizedSkill}\\b(?:\\s+(?:keep\\s+going|continue|resume))(?:\\s+now)?[.!]?\\s*$`, 'i').test(text.trim());
|
|
791
2832
|
}
|
|
792
|
-
function
|
|
793
|
-
return /^\s*\[omx question answered\]/i.test(text.trim());
|
|
794
|
-
}
|
|
795
|
-
function shouldReusePreviousSkillForContinuation(text, previous) {
|
|
2833
|
+
function shouldReusePreviousSkillForContinuation(text, previous, classification) {
|
|
796
2834
|
const previousSkill = safeString(previous?.skill).trim();
|
|
797
2835
|
if (!previousSkill || previous?.active !== true || !isTrackedWorkflowMode(previousSkill)) {
|
|
798
2836
|
return false;
|
|
799
2837
|
}
|
|
800
2838
|
return isActiveSkillContinuationPrompt(text)
|
|
801
2839
|
|| isNamedActiveSkillContinuationPrompt(text, previousSkill)
|
|
802
|
-
|| (
|
|
2840
|
+
|| (classification.reservedInput === 'omx-question-answered'
|
|
2841
|
+
&& (previousSkill === 'autopilot' || previousSkill === 'deep-interview'));
|
|
803
2842
|
}
|
|
804
2843
|
function isAutopilotSupervisedChildSkill(skill) {
|
|
805
2844
|
return skill === 'code-review'
|
|
@@ -957,21 +2996,27 @@ function isDeepInterviewRuntimeConfig(value) {
|
|
|
957
2996
|
&& typeof candidate.sourcePath === 'string'
|
|
958
2997
|
&& candidate.sourcePath.trim().length > 0);
|
|
959
2998
|
}
|
|
960
|
-
function resolveContinuationKeywordMatch(text, previous, fallbackMatch) {
|
|
2999
|
+
function resolveContinuationKeywordMatch(text, previous, fallbackMatch, classification) {
|
|
961
3000
|
const previousSkill = safeString(previous?.skill).trim();
|
|
962
3001
|
if (!previousSkill || previous?.active !== true || !isTrackedWorkflowMode(previousSkill)) {
|
|
963
3002
|
return fallbackMatch;
|
|
964
3003
|
}
|
|
965
|
-
const markedQuestionAnswerContinuation =
|
|
966
|
-
&&
|
|
967
|
-
if (!markedQuestionAnswerContinuation &&
|
|
968
|
-
return
|
|
3004
|
+
const markedQuestionAnswerContinuation = classification.reservedInput === 'omx-question-answered'
|
|
3005
|
+
&& (previousSkill === 'autopilot' || previousSkill === 'deep-interview');
|
|
3006
|
+
if (classification.reservedInput || (!markedQuestionAnswerContinuation && classification.hasExplicitLikeInvocation)) {
|
|
3007
|
+
return markedQuestionAnswerContinuation
|
|
3008
|
+
? {
|
|
3009
|
+
keyword: safeString(previous.keyword).trim() || `$${previousSkill}`,
|
|
3010
|
+
skill: previousSkill,
|
|
3011
|
+
priority: 0,
|
|
3012
|
+
}
|
|
3013
|
+
: fallbackMatch;
|
|
969
3014
|
}
|
|
970
|
-
if (!
|
|
3015
|
+
if (!shouldReusePreviousSkillForContinuation(text, previous, classification) && !safeString(fallbackMatch?.keyword).trim().startsWith('$')) {
|
|
971
3016
|
return fallbackMatch;
|
|
972
3017
|
}
|
|
973
3018
|
return {
|
|
974
|
-
keyword: safeString(previous
|
|
3019
|
+
keyword: safeString(previous.keyword).trim() || `$${previousSkill}`,
|
|
975
3020
|
skill: previousSkill,
|
|
976
3021
|
priority: fallbackMatch?.priority ?? 0,
|
|
977
3022
|
};
|
|
@@ -997,29 +3042,81 @@ function resolveRequestedWorkflowSkills(requestedWorkflowSkills) {
|
|
|
997
3042
|
deferredSkills: requestedWorkflowSkills.filter((skill) => skill !== firstPlanningSkill),
|
|
998
3043
|
};
|
|
999
3044
|
}
|
|
1000
|
-
function selectRootSkillStateCopy(previousRoot, nextState, sessionId) {
|
|
3045
|
+
function selectRootSkillStateCopy(previousRoot, nextState, sessionId, suppressRootMutation = false) {
|
|
3046
|
+
if (suppressRootMutation)
|
|
3047
|
+
return null;
|
|
1001
3048
|
if (!sessionId)
|
|
1002
3049
|
return nextState;
|
|
1003
3050
|
if (previousRoot)
|
|
1004
3051
|
return previousRoot;
|
|
1005
3052
|
return null;
|
|
1006
3053
|
}
|
|
3054
|
+
async function preflightKeywordTargetState(stateDir, sessionId, context, nowIso) {
|
|
3055
|
+
const targetDir = join(stateDir, 'sessions', sessionId);
|
|
3056
|
+
const evidence = [];
|
|
3057
|
+
let filenames;
|
|
3058
|
+
try {
|
|
3059
|
+
filenames = await readdir(targetDir);
|
|
3060
|
+
}
|
|
3061
|
+
catch (error) {
|
|
3062
|
+
if (error.code === 'ENOENT')
|
|
3063
|
+
return context;
|
|
3064
|
+
return preflightSelectedTargetOwner(context, [{ ownerCodexSessionId: {} }], 'native', nowIso);
|
|
3065
|
+
}
|
|
3066
|
+
for (const filename of filenames) {
|
|
3067
|
+
if (!filename.endsWith('-state.json') && filename !== SKILL_ACTIVE_STATE_FILE)
|
|
3068
|
+
continue;
|
|
3069
|
+
try {
|
|
3070
|
+
const value = JSON.parse(await readFile(join(targetDir, filename), 'utf8'));
|
|
3071
|
+
evidence.push(...extractSelectedTargetOwnerEvidence(value));
|
|
3072
|
+
}
|
|
3073
|
+
catch {
|
|
3074
|
+
evidence.push({ ownerCodexSessionId: {} });
|
|
3075
|
+
}
|
|
3076
|
+
}
|
|
3077
|
+
return preflightSelectedTargetOwner(context, evidence, 'native', nowIso);
|
|
3078
|
+
}
|
|
1007
3079
|
export async function recordSkillActivation(input) {
|
|
3080
|
+
const classification = input.classification ?? classifyKeywordInput(input.text);
|
|
3081
|
+
if (classification.originalText !== input.text) {
|
|
3082
|
+
throw new Error('Keyword input classification text does not match activation text');
|
|
3083
|
+
}
|
|
3084
|
+
const resolvedPromptTurnContext = input.resolvedPromptTurnContext;
|
|
3085
|
+
if (resolvedPromptTurnContext && resolvedPromptTurnContext.status !== 'authorized')
|
|
3086
|
+
return null;
|
|
3087
|
+
if (resolvedPromptTurnContext && input.sessionId !== resolvedPromptTurnContext.authorization.targetSessionId)
|
|
3088
|
+
return null;
|
|
3089
|
+
const suppressRootMutation = resolvedPromptTurnContext?.authorization.globalSideEffects === 'suppress';
|
|
3090
|
+
const provenanceOwnerCodexSessionId = resolvedPromptTurnContext?.authorization.ownerCodexSessionId;
|
|
3091
|
+
const applyProvenanceOwner = (state) => (provenanceOwnerCodexSessionId
|
|
3092
|
+
? {
|
|
3093
|
+
...state,
|
|
3094
|
+
owner_codex_session_id: provenanceOwnerCodexSessionId,
|
|
3095
|
+
active_skills: state.active_skills?.map((entry) => ({ ...entry, owner_codex_session_id: provenanceOwnerCodexSessionId })),
|
|
3096
|
+
}
|
|
3097
|
+
: state);
|
|
1008
3098
|
const sourceCwd = input.sourceCwd ?? dirname(dirname(input.stateDir));
|
|
1009
3099
|
const rootStatePath = join(input.stateDir, SKILL_ACTIVE_STATE_FILE);
|
|
1010
3100
|
const sessionStatePath = input.sessionId
|
|
1011
3101
|
? join(input.stateDir, 'sessions', input.sessionId, SKILL_ACTIVE_STATE_FILE)
|
|
1012
3102
|
: null;
|
|
1013
|
-
|
|
3103
|
+
if (resolvedPromptTurnContext && input.sessionId) {
|
|
3104
|
+
const preflight = await preflightKeywordTargetState(input.stateDir, input.sessionId, resolvedPromptTurnContext, input.nowIso ?? new Date().toISOString());
|
|
3105
|
+
if (preflight.status === 'rejected') {
|
|
3106
|
+
await input.onProvenanceRejected?.(preflight.diagnostic);
|
|
3107
|
+
return null;
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
const previousRoot = suppressRootMutation ? null : await readExistingSkillState(rootStatePath);
|
|
1014
3111
|
const previousSession = sessionStatePath ? await readExistingSkillState(sessionStatePath) : null;
|
|
1015
3112
|
const previous = input.sessionId ? previousSession : previousRoot;
|
|
1016
3113
|
const teamMode = readTeamModeConfig(sourceCwd);
|
|
1017
|
-
const match = resolveContinuationKeywordMatch(input.text, previous, detectPrimaryKeywordForTeamMode(
|
|
3114
|
+
const match = resolveContinuationKeywordMatch(input.text, previous, detectPrimaryKeywordForTeamMode(classification, teamMode.enabled), classification);
|
|
1018
3115
|
if (!match)
|
|
1019
3116
|
return null;
|
|
1020
3117
|
const nowIso = input.nowIso ?? new Date().toISOString();
|
|
1021
3118
|
const hadDeepInterviewLock = previous?.skill === 'deep-interview' && previous?.input_lock?.active === true;
|
|
1022
|
-
const matches = filterMatchesForTeamMode(
|
|
3119
|
+
const matches = filterMatchesForTeamMode(classification.matches, teamMode.enabled);
|
|
1023
3120
|
const hasCancelIntent = matches.some((entry) => entry.skill === 'cancel');
|
|
1024
3121
|
if (hasCancelIntent && hadDeepInterviewLock) {
|
|
1025
3122
|
const state = {
|
|
@@ -1038,17 +3135,17 @@ export async function recordSkillActivation(input) {
|
|
|
1038
3135
|
...(previous?.input_lock ? { input_lock: releaseDeepInterviewInputLock(previous.input_lock, nowIso, 'abort') } : {}),
|
|
1039
3136
|
};
|
|
1040
3137
|
try {
|
|
1041
|
-
await writeSkillActiveStateCopiesForStateDir(input.stateDir, state, input.sessionId, selectRootSkillStateCopy(previousRoot, state, input.sessionId));
|
|
1042
|
-
await persistDeepInterviewModeState(input.stateDir, state, nowIso, previous, input);
|
|
3138
|
+
await writeSkillActiveStateCopiesForStateDir(input.stateDir, applyProvenanceOwner(state), input.sessionId, selectRootSkillStateCopy(previousRoot, state, input.sessionId, suppressRootMutation));
|
|
3139
|
+
await persistDeepInterviewModeState(input.stateDir, applyProvenanceOwner(state), nowIso, previous, input);
|
|
1043
3140
|
}
|
|
1044
3141
|
catch (error) {
|
|
1045
3142
|
console.warn('[omx] warning: failed to persist keyword activation state', error);
|
|
1046
3143
|
}
|
|
1047
|
-
return state;
|
|
3144
|
+
return applyProvenanceOwner(state);
|
|
1048
3145
|
}
|
|
1049
3146
|
const sameSkill = previous?.active === true && previous.skill === match.skill;
|
|
1050
3147
|
const sameKeyword = previous?.keyword?.toLowerCase() === match.keyword.toLowerCase();
|
|
1051
|
-
const sameSkillContinuation = sameSkill && shouldReusePreviousSkillForContinuation(input.text, previous);
|
|
3148
|
+
const sameSkillContinuation = sameSkill && shouldReusePreviousSkillForContinuation(input.text, previous, classification);
|
|
1052
3149
|
const matchedSeedConfig = STATEFUL_SKILL_SEED_CONFIG[match.skill];
|
|
1053
3150
|
const matchedModeState = matchedSeedConfig
|
|
1054
3151
|
? await readJsonStateIfExists(resolveSeedStateFilePath(input.stateDir, matchedSeedConfig.mode, input.sessionId, matchedSeedConfig.scope).absolutePath)
|
|
@@ -1056,9 +3153,12 @@ export async function recordSkillActivation(input) {
|
|
|
1056
3153
|
const matchedModeTerminal = matchedSeedConfig
|
|
1057
3154
|
? isResettableTerminalModeState(matchedModeState, matchedSeedConfig.mode)
|
|
1058
3155
|
: false;
|
|
3156
|
+
if (classification.reservedInput === 'omx-question-answered' && matchedModeTerminal)
|
|
3157
|
+
return null;
|
|
1059
3158
|
const preserveActivatedAt = sameSkill && !matchedModeTerminal && (sameKeyword || sameSkillContinuation);
|
|
1060
3159
|
const previousEntries = listActiveSkills(previous ?? {});
|
|
1061
3160
|
const previousWorkflowEntries = previousEntries.filter((entry) => (isTrackedWorkflowMode(entry.skill)
|
|
3161
|
+
&& (input.allowSecondaryAutopilot !== false || entry.skill !== 'autopilot' || entry.skill === match.skill)
|
|
1062
3162
|
&& (!input.sessionId
|
|
1063
3163
|
|| !safeString(entry.session_id).trim()
|
|
1064
3164
|
|| safeString(entry.session_id).trim() === safeString(input.sessionId).trim())));
|
|
@@ -1066,14 +3166,13 @@ export async function recordSkillActivation(input) {
|
|
|
1066
3166
|
const trackedMatchSkill = isTrackedWorkflowMatch ? match.skill : null;
|
|
1067
3167
|
const markedQuestionAnswerContinuation = sameSkill
|
|
1068
3168
|
&& (match.skill === 'autopilot' || match.skill === 'deep-interview')
|
|
1069
|
-
&&
|
|
1070
|
-
const normalizedInputText = isTrackedWorkflowMatch
|
|
1071
|
-
? normalizeWorkflowKeyboardTypos(input.text)
|
|
1072
|
-
: input.text;
|
|
3169
|
+
&& classification.reservedInput === 'omx-question-answered';
|
|
1073
3170
|
const workflowMatches = isTrackedWorkflowMatch && !markedQuestionAnswerContinuation
|
|
1074
|
-
?
|
|
3171
|
+
? classification.explicitMatches
|
|
1075
3172
|
.map((entry) => entry.skill)
|
|
1076
3173
|
.filter((skill) => teamMode.enabled || skill !== 'team')
|
|
3174
|
+
.filter((skill) => input.allowSecondaryTeam !== false || skill !== 'team' || skill === trackedMatchSkill)
|
|
3175
|
+
.filter((skill) => input.allowSecondaryAutopilot !== false || skill !== 'autopilot' || skill === trackedMatchSkill)
|
|
1077
3176
|
.filter(isTrackedWorkflowMode)
|
|
1078
3177
|
: [];
|
|
1079
3178
|
const resolvedWorkflowRequest = isTrackedWorkflowMatch
|
|
@@ -1092,7 +3191,7 @@ export async function recordSkillActivation(input) {
|
|
|
1092
3191
|
const deepInterviewConfig = willActivateDeepInterview
|
|
1093
3192
|
? reusableDeepInterviewConfig ?? resolveDeepInterviewRuntimeConfig({ cwd: sourceCwd, text: input.text })
|
|
1094
3193
|
: null;
|
|
1095
|
-
if (previous?.active === true && previous.skill === 'autopilot' && isAutopilotSupervisedChildSkill(match.skill)) {
|
|
3194
|
+
if (input.allowSecondaryAutopilot !== false && previous?.active === true && previous.skill === 'autopilot' && isAutopilotSupervisedChildSkill(match.skill)) {
|
|
1096
3195
|
try {
|
|
1097
3196
|
// Reconcile first so skill-active phase reflects the gate-held phase the
|
|
1098
3197
|
// autopilot detail state actually advanced to (a blocked advance keeps the
|
|
@@ -1122,8 +3221,8 @@ export async function recordSkillActivation(input) {
|
|
|
1122
3221
|
supervised_child_keyword: match.keyword,
|
|
1123
3222
|
supervised_child_skill: match.skill,
|
|
1124
3223
|
};
|
|
1125
|
-
await writeSkillActiveStateCopiesForStateDir(input.stateDir, nextState, input.sessionId, selectRootSkillStateCopy(previousRoot, nextState, input.sessionId));
|
|
1126
|
-
return nextState;
|
|
3224
|
+
await writeSkillActiveStateCopiesForStateDir(input.stateDir, applyProvenanceOwner(nextState), input.sessionId, selectRootSkillStateCopy(previousRoot, nextState, input.sessionId, suppressRootMutation));
|
|
3225
|
+
return applyProvenanceOwner(nextState);
|
|
1127
3226
|
}
|
|
1128
3227
|
catch (error) {
|
|
1129
3228
|
return {
|
|
@@ -1254,27 +3353,32 @@ export async function recordSkillActivation(input) {
|
|
|
1254
3353
|
...(primarySkill === 'deep-interview' && deepInterviewConfig ? { deep_interview_config: deepInterviewConfig } : {}),
|
|
1255
3354
|
};
|
|
1256
3355
|
try {
|
|
1257
|
-
|
|
3356
|
+
const ownedWorkflowState = applyProvenanceOwner(workflowState);
|
|
3357
|
+
let nextState = { ...ownedWorkflowState };
|
|
1258
3358
|
for (const requestedEntry of nextWorkflowEntries) {
|
|
1259
3359
|
const seeded = await persistStatefulSkillSeedState(input.stateDir, {
|
|
1260
|
-
...
|
|
3360
|
+
...ownedWorkflowState,
|
|
1261
3361
|
skill: requestedEntry.skill,
|
|
1262
3362
|
keyword: requestedEntry.skill === workflowState.skill ? workflowState.keyword : `$${requestedEntry.skill}`,
|
|
1263
3363
|
phase: requestedEntry.phase || workflowState.phase,
|
|
1264
3364
|
activated_at: requestedEntry.activated_at || workflowState.activated_at,
|
|
1265
3365
|
updated_at: requestedEntry.updated_at || workflowState.updated_at,
|
|
1266
3366
|
...(requestedEntry.skill === 'deep-interview' && deepInterviewConfig ? { deep_interview_config: deepInterviewConfig } : {}),
|
|
1267
|
-
}, nowIso, previous, input.text, sourceCwd, {
|
|
3367
|
+
}, nowIso, previous, input.text, sourceCwd, {
|
|
3368
|
+
activeContinuation: requestedEntry.skill === 'autopilot' && sameSkillContinuation,
|
|
3369
|
+
forceSessionScope: suppressRootMutation,
|
|
3370
|
+
});
|
|
1268
3371
|
if (requestedEntry.skill === workflowState.skill) {
|
|
1269
3372
|
nextState = {
|
|
1270
|
-
...
|
|
3373
|
+
...ownedWorkflowState,
|
|
1271
3374
|
initialized_mode: seeded.initialized_mode,
|
|
1272
3375
|
initialized_state_path: seeded.initialized_state_path,
|
|
1273
3376
|
};
|
|
1274
3377
|
}
|
|
1275
3378
|
}
|
|
3379
|
+
nextState = applyProvenanceOwner(nextState);
|
|
1276
3380
|
nextState.active_skills = buildActiveSkills(nextState);
|
|
1277
|
-
await writeSkillActiveStateCopiesForStateDir(input.stateDir, nextState, input.sessionId, selectRootSkillStateCopy(previousRoot, nextState, input.sessionId));
|
|
3381
|
+
await writeSkillActiveStateCopiesForStateDir(input.stateDir, nextState, input.sessionId, selectRootSkillStateCopy(previousRoot, nextState, input.sessionId, suppressRootMutation));
|
|
1278
3382
|
await persistDeepInterviewModeState(input.stateDir, nextState, nowIso, previous, input);
|
|
1279
3383
|
return nextState;
|
|
1280
3384
|
}
|
|
@@ -1309,11 +3413,16 @@ export async function recordSkillActivation(input) {
|
|
|
1309
3413
|
...(match.skill === 'deep-interview' && deepInterviewConfig ? { deep_interview_config: deepInterviewConfig } : {}),
|
|
1310
3414
|
};
|
|
1311
3415
|
try {
|
|
1312
|
-
const
|
|
1313
|
-
nextState
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
3416
|
+
const ownedState = applyProvenanceOwner(state);
|
|
3417
|
+
const nextState = await persistStatefulSkillSeedState(input.stateDir, ownedState, nowIso, previous, input.text, sourceCwd, {
|
|
3418
|
+
activeContinuation: match.skill === 'autopilot' && sameSkillContinuation,
|
|
3419
|
+
forceSessionScope: suppressRootMutation,
|
|
3420
|
+
});
|
|
3421
|
+
const ownedNextState = applyProvenanceOwner(nextState);
|
|
3422
|
+
ownedNextState.active_skills = buildActiveSkills(ownedNextState);
|
|
3423
|
+
await writeSkillActiveStateCopiesForStateDir(input.stateDir, ownedNextState, input.sessionId, selectRootSkillStateCopy(previousRoot, ownedNextState, input.sessionId, suppressRootMutation));
|
|
3424
|
+
await persistDeepInterviewModeState(input.stateDir, ownedNextState, nowIso, previous, input);
|
|
3425
|
+
return ownedNextState;
|
|
1317
3426
|
}
|
|
1318
3427
|
catch (error) {
|
|
1319
3428
|
console.warn('[omx] warning: failed to persist keyword activation state', error);
|