lazycodex-ai 5.1.47 → 5.1.51
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/dist/cli/index.js +1194 -752
- package/dist/cli/service-auth/accounts-gate.d.ts +11 -0
- package/dist/cli/service-auth/commands.d.ts +2 -4
- package/dist/cli/service-auth/index.d.ts +1 -1
- package/dist/cli/service-auth/keystore.d.ts +26 -2
- package/dist/cli/service-auth/protocol.d.ts +7 -1
- package/dist/cli/service-auth/session.d.ts +6 -0
- package/dist/cli/service-auth/signed-out-marker.d.ts +11 -0
- package/dist/cli-node/index.js +1194 -752
- package/package.json +3 -1
- package/packages/lsp-core/package.json +45 -0
- package/packages/lsp-core/src/index.ts +30 -0
- package/packages/lsp-core/src/lsp/bun-command-output.ts +82 -0
- package/packages/lsp-core/src/lsp/bun-project-checks.test.ts +170 -0
- package/packages/lsp-core/src/lsp/bun-project-checks.ts +223 -0
- package/packages/lsp-core/src/lsp/cleanup-errors.test.ts +18 -0
- package/packages/lsp-core/src/lsp/cleanup-errors.ts +14 -0
- package/packages/lsp-core/src/lsp/client-diagnostics-concurrency.integration.test.ts +52 -0
- package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +471 -0
- package/packages/lsp-core/src/lsp/client-diagnostics-pull-timeout.test.ts +64 -0
- package/packages/lsp-core/src/lsp/client-wrapper-outside-cwd.test.ts +78 -0
- package/packages/lsp-core/src/lsp/client-wrapper.test.ts +213 -0
- package/packages/lsp-core/src/lsp/client-wrapper.ts +290 -0
- package/packages/lsp-core/src/lsp/client.ts +398 -0
- package/packages/lsp-core/src/lsp/config-loader.ts +254 -0
- package/packages/lsp-core/src/lsp/connection.ts +95 -0
- package/packages/lsp-core/src/lsp/constants.ts +17 -0
- package/packages/lsp-core/src/lsp/controlled-clock-test-support.ts +90 -0
- package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +221 -0
- package/packages/lsp-core/src/lsp/directory-diagnostics.ts +187 -0
- package/packages/lsp-core/src/lsp/effective-extension.ts +10 -0
- package/packages/lsp-core/src/lsp/errors.ts +89 -0
- package/packages/lsp-core/src/lsp/fake-bun-test-support.ts +102 -0
- package/packages/lsp-core/src/lsp/fixtures/diagnostics-freshness-contract-probe.ts +283 -0
- package/packages/lsp-core/src/lsp/fixtures/disposed-stdin-epipe-probe.ts +28 -0
- package/packages/lsp-core/src/lsp/fixtures/workspace-edit-contract-probe.ts +196 -0
- package/packages/lsp-core/src/lsp/fixtures/workspace-edit-server.mjs +234 -0
- package/packages/lsp-core/src/lsp/format-document.test.ts +143 -0
- package/packages/lsp-core/src/lsp/format-document.ts +90 -0
- package/packages/lsp-core/src/lsp/formatters.ts +144 -0
- package/packages/lsp-core/src/lsp/infer-extension.ts +66 -0
- package/packages/lsp-core/src/lsp/json-rpc-connection-cancellation.test.ts +97 -0
- package/packages/lsp-core/src/lsp/json-rpc-connection.ts +369 -0
- package/packages/lsp-core/src/lsp/language-mappings.ts +173 -0
- package/packages/lsp-core/src/lsp/manager-lifecycle.test.ts +262 -0
- package/packages/lsp-core/src/lsp/manager-max-clients.test.ts +151 -0
- package/packages/lsp-core/src/lsp/manager.ts +495 -0
- package/packages/lsp-core/src/lsp/outside-context-workspace.ts +33 -0
- package/packages/lsp-core/src/lsp/process-pipe-errors.test.ts +21 -0
- package/packages/lsp-core/src/lsp/process-signal-cleanup.ts +21 -0
- package/packages/lsp-core/src/lsp/process.ts +221 -0
- package/packages/lsp-core/src/lsp/server-definitions.ts +205 -0
- package/packages/lsp-core/src/lsp/server-install-state.ts +67 -0
- package/packages/lsp-core/src/lsp/server-installation.test.ts +376 -0
- package/packages/lsp-core/src/lsp/server-installation.ts +218 -0
- package/packages/lsp-core/src/lsp/server-resolution-local-binary.test.ts +170 -0
- package/packages/lsp-core/src/lsp/server-resolution.ts +117 -0
- package/packages/lsp-core/src/lsp/startup-failure.ts +1 -0
- package/packages/lsp-core/src/lsp/timer-provider.ts +13 -0
- package/packages/lsp-core/src/lsp/transport-protocol.ts +52 -0
- package/packages/lsp-core/src/lsp/transport-request-timeout.test.ts +73 -0
- package/packages/lsp-core/src/lsp/transport.ts +339 -0
- package/packages/lsp-core/src/lsp/types.ts +134 -0
- package/packages/lsp-core/src/lsp/utils.test.ts +72 -0
- package/packages/lsp-core/src/lsp/utils.ts +40 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-failure.ts +19 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-lease.integration.test.ts +218 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-sync.integration.test.ts +113 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-test-support.ts +194 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit.integration.test.ts +163 -0
- package/packages/lsp-core/src/lsp/workspace-document-state.test.ts +150 -0
- package/packages/lsp-core/src/lsp/workspace-document-state.ts +392 -0
- package/packages/lsp-core/src/lsp/workspace-edit-adversarial.test.ts +132 -0
- package/packages/lsp-core/src/lsp/workspace-edit-commit.test.ts +140 -0
- package/packages/lsp-core/src/lsp/workspace-edit-commit.ts +220 -0
- package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.test.ts +56 -0
- package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.ts +30 -0
- package/packages/lsp-core/src/lsp/workspace-edit-fingerprint.ts +44 -0
- package/packages/lsp-core/src/lsp/workspace-edit-options.test.ts +147 -0
- package/packages/lsp-core/src/lsp/workspace-edit-parse-helpers.ts +59 -0
- package/packages/lsp-core/src/lsp/workspace-edit-parser.ts +130 -0
- package/packages/lsp-core/src/lsp/workspace-edit-path.ts +98 -0
- package/packages/lsp-core/src/lsp/workspace-edit-plan-types.ts +60 -0
- package/packages/lsp-core/src/lsp/workspace-edit-plan.ts +73 -0
- package/packages/lsp-core/src/lsp/workspace-edit-prevalidation.test.ts +174 -0
- package/packages/lsp-core/src/lsp/workspace-edit-resource-parser.ts +89 -0
- package/packages/lsp-core/src/lsp/workspace-edit-simulation.ts +183 -0
- package/packages/lsp-core/src/lsp/workspace-edit-snapshot.ts +53 -0
- package/packages/lsp-core/src/lsp/workspace-edit-text.ts +125 -0
- package/packages/lsp-core/src/lsp/workspace-edit-types.ts +121 -0
- package/packages/lsp-core/src/lsp/workspace-edit.characterization.test.ts +95 -0
- package/packages/lsp-core/src/lsp/workspace-edit.ts +55 -0
- package/packages/lsp-core/src/lsp/workspace-markers.ts +18 -0
- package/packages/lsp-core/src/lsp/workspace-mutation-controller.ts +182 -0
- package/packages/lsp-core/src/mcp-protocol-pin.test.ts +97 -0
- package/packages/lsp-core/src/mcp.ts +122 -0
- package/packages/lsp-core/src/missing-dependency-result.test.ts +135 -0
- package/packages/lsp-core/src/missing-dependency-result.ts +79 -0
- package/packages/lsp-core/src/post-edit/file-location.ts +55 -0
- package/packages/lsp-core/src/post-edit/index.ts +3 -0
- package/packages/lsp-core/src/post-edit/not-installed-guidance.ts +36 -0
- package/packages/lsp-core/src/post-edit/not-installed.test.ts +224 -0
- package/packages/lsp-core/src/post-edit/orchestration.test.ts +157 -0
- package/packages/lsp-core/src/post-edit/orchestration.ts +205 -0
- package/packages/lsp-core/src/request-context.test.ts +200 -0
- package/packages/lsp-core/src/request-context.ts +235 -0
- package/packages/lsp-core/src/tool-surface.test.ts +173 -0
- package/packages/lsp-core/src/tools/bun-directory-diagnostics.test.ts +113 -0
- package/packages/lsp-core/src/tools/bun-directory-diagnostics.ts +75 -0
- package/packages/lsp-core/src/tools/definitions.ts +156 -0
- package/packages/lsp-core/src/tools/diagnostics.ts +133 -0
- package/packages/lsp-core/src/tools/format.test.ts +56 -0
- package/packages/lsp-core/src/tools/format.ts +56 -0
- package/packages/lsp-core/src/tools/index.ts +11 -0
- package/packages/lsp-core/src/tools/install-decision.ts +39 -0
- package/packages/lsp-core/src/tools/navigation.ts +88 -0
- package/packages/lsp-core/src/tools/parameters.test.ts +51 -0
- package/packages/lsp-core/src/tools/parameters.ts +49 -0
- package/packages/lsp-core/src/tools/rename.ts +69 -0
- package/packages/lsp-core/src/tools/result.ts +5 -0
- package/packages/lsp-core/src/tools/runtime.ts +21 -0
- package/packages/lsp-core/src/tools/schema.ts +9 -0
- package/packages/lsp-core/src/tools/status.ts +28 -0
- package/packages/lsp-core/src/tools/symbols.ts +99 -0
- package/packages/lsp-core/src/tools/types.ts +116 -0
- package/packages/lsp-core/src/tools.ts +1 -0
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/README.md +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/SKILL.md +7 -7
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +2 -2
- package/packages/omo-codex/plugin/components/telemetry/README.md +2 -2
- package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +52 -15
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +52 -19
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +2 -9
- package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +4 -13
- package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +0 -2
- package/packages/omo-codex/plugin/components/telemetry/test/codex-hook-diagnostics.test.ts +0 -3
- package/packages/omo-codex/plugin/components/telemetry/test/codex-hook.test.ts +3 -8
- package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +3 -0
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +16 -16
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/shared/package.json +1 -1
- package/packages/omo-codex/plugin/skills/ast-grep/README.md +1 -1
- package/packages/omo-codex/plugin/skills/ast-grep/install.ps1 +5 -3
- package/packages/omo-codex/plugin/skills/ast-grep/install.sh +4 -5
- package/packages/omo-codex/plugin/skills/ast-grep/references/install.md +2 -2
- package/packages/omo-codex/plugin/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +5 -4
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +11 -11
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +2 -2
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/codex.md +4 -4
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
- package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +34 -12
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +2 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/component-catalogs.md +14 -10
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +19 -6
- package/packages/omo-codex/plugin/skills/frontend/references/design/grounding.md +29 -0
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
- package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
- package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +7 -7
- package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +5 -4
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +2 -2
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/__main__.py +9 -6
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/summary.py +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +4 -4
- package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +3 -0
- package/packages/omo-codex/plugin/skills/ulw-research/AGENTS.md +8 -4
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +7 -259
- package/packages/omo-codex/plugin/skills/ulw-research/references/deliverable-phase.md +68 -24
- package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
- package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger.md +42 -8
- package/packages/omo-codex/plugin/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/references/markdown-blocks.md +12 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/report-gates.md +14 -6
- package/packages/omo-codex/plugin/skills/ulw-research/references/research-collection.md +195 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/research-delivery.md +123 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/contracts.mjs +16 -15
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-hiding.mjs +158 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-lite.mjs +4 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/entities.mjs +13 -4
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-fill.mjs +96 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-meaning.mjs +26 -30
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-polish.mjs +46 -19
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-verify.mjs +37 -6
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands.mjs +40 -62
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-derive.mjs +7 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-fill.mjs +9 -6
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-locate.mjs +15 -9
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-policy.mjs +183 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-static.mjs +10 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-lite.mjs +6 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-markup.mjs +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-text-map.mjs +140 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/md-lite.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/number-grammar.mjs +33 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/numerals.mjs +18 -7
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome-start.mjs +66 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome.mjs +11 -22
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/placeholder.mjs +18 -6
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/polish-apply.mjs +3 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-decode.mjs +110 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-locator.mjs +47 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools.mjs +7 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-commands.mjs +87 -29
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-refresh.mjs +82 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-view.mjs +89 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/sources-citation.mjs +203 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/units.mjs +14 -3
- package/packages/omo-codex/plugin/test/payload-equivalence.test.mjs +6 -4
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +4 -3
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +338 -237
- package/packages/prompts-core/prompts/ultrawork/codex.md +3 -0
- package/packages/shared-skills/skill-source-filter.mjs +6 -2
- package/packages/shared-skills/skills/ast-grep/README.md +1 -1
- package/packages/shared-skills/skills/ast-grep/install.ps1 +5 -3
- package/packages/shared-skills/skills/ast-grep/install.sh +4 -5
- package/packages/shared-skills/skills/ast-grep/references/install.md +2 -2
- package/packages/shared-skills/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
- package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +5 -4
- package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +11 -11
- package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +2 -2
- package/packages/shared-skills/skills/coding-agent-sessions/references/codex.md +4 -4
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
- package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +1 -1
- package/packages/shared-skills/skills/frontend/SKILL.md +34 -12
- package/packages/shared-skills/skills/frontend/references/design/README.md +2 -2
- package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +2 -1
- package/packages/shared-skills/skills/frontend/references/design/component-catalogs.md +14 -10
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +19 -6
- package/packages/shared-skills/skills/frontend/references/design/grounding.md +29 -0
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
- package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +5 -4
- package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +2 -2
- package/packages/shared-skills/skills/ultimate-browsing/engine/__main__.py +9 -6
- package/packages/shared-skills/skills/ultimate-browsing/engine/summary.py +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +4 -4
- package/packages/shared-skills/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
- package/packages/shared-skills/skills/ulw-research/AGENTS.md +8 -4
- package/packages/shared-skills/skills/ulw-research/SKILL.md +7 -259
- package/packages/shared-skills/skills/ulw-research/references/deliverable-phase.md +68 -24
- package/packages/shared-skills/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
- package/packages/shared-skills/skills/ulw-research/references/fact-ledger.md +42 -8
- package/packages/shared-skills/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
- package/packages/shared-skills/skills/ulw-research/references/markdown-blocks.md +12 -0
- package/packages/shared-skills/skills/ulw-research/references/report-gates.md +14 -6
- package/packages/shared-skills/skills/ulw-research/references/research-collection.md +195 -0
- package/packages/shared-skills/skills/ulw-research/references/research-delivery.md +123 -0
- package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
- package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.test.ts +37 -2
- package/packages/shared-skills/skills/ulw-research/scripts/claim-prefix.test.ts +76 -0
- package/packages/shared-skills/skills/ulw-research/scripts/contracts-validation.test.ts +83 -0
- package/packages/shared-skills/skills/ulw-research/scripts/contracts.mjs +16 -15
- package/packages/shared-skills/skills/ulw-research/scripts/contracts.test.ts +6 -109
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-altered.test.ts +154 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-originals.test.ts +297 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe-classes.test.ts +361 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.test.ts +218 -0
- package/packages/shared-skills/skills/ulw-research/scripts/copy-returns-fidelity-policy.test.ts +156 -0
- package/packages/shared-skills/skills/ulw-research/scripts/copy-returns-polish.test.ts +10 -9
- package/packages/shared-skills/skills/ulw-research/scripts/css-hiding.mjs +158 -0
- package/packages/shared-skills/skills/ulw-research/scripts/css-lite.mjs +4 -2
- package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
- package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
- package/packages/shared-skills/skills/ulw-research/scripts/entities.mjs +13 -4
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-fill.mjs +96 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-meaning.mjs +26 -30
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-polish.mjs +46 -19
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-verify.mjs +37 -6
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands.mjs +40 -62
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.mjs +7 -2
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
- package/packages/shared-skills/skills/ulw-research/scripts/fact-fill.mjs +9 -6
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fact-locate.mjs +15 -9
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-policy.mjs +183 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
- package/packages/shared-skills/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
- package/packages/shared-skills/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
- package/packages/shared-skills/skills/ulw-research/scripts/gates-static.mjs +10 -1
- package/packages/shared-skills/skills/ulw-research/scripts/html-lite.mjs +6 -2
- package/packages/shared-skills/skills/ulw-research/scripts/html-markup.mjs +2 -2
- package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.mjs +140 -0
- package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
- package/packages/shared-skills/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
- package/packages/shared-skills/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
- package/packages/shared-skills/skills/ulw-research/scripts/md-lite.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.mjs +33 -0
- package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
- package/packages/shared-skills/skills/ulw-research/scripts/numerals.mjs +18 -7
- package/packages/shared-skills/skills/ulw-research/scripts/numerals.test.ts +3 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.mjs +66 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome.mjs +11 -22
- package/packages/shared-skills/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
- package/packages/shared-skills/skills/ulw-research/scripts/placeholder.mjs +18 -6
- package/packages/shared-skills/skills/ulw-research/scripts/polish-apply.mjs +3 -2
- package/packages/shared-skills/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
- package/packages/shared-skills/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
- package/packages/shared-skills/skills/ulw-research/scripts/raw-decode.mjs +110 -0
- package/packages/shared-skills/skills/ulw-research/scripts/raw-locator.mjs +47 -0
- package/packages/shared-skills/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools.mjs +7 -1
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools.test.ts +6 -560
- package/packages/shared-skills/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-commands.mjs +87 -29
- package/packages/shared-skills/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-refresh.mjs +82 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
- package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
- package/packages/shared-skills/skills/ulw-research/scripts/source-view.mjs +89 -0
- package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.mjs +203 -0
- package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
- package/packages/shared-skills/skills/ulw-research/scripts/units.mjs +14 -3
- package/packages/shared-skills/skills/ulw-research/scripts/units.test.ts +10 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/amp_redirect_stub.html +0 -7
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/search_interstitial.html +0 -19
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_available.json +0 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_snapshot.html +0 -1128
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_fetch_chain.py +0 -77
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +0 -86
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +0 -279
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate.py +0 -252
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate_validators.py +0 -78
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { PostEditFileLocation } from "./file-location.js";
|
|
2
|
+
|
|
3
|
+
export interface PostEditNotInstalledOutcome {
|
|
4
|
+
readonly kind: "not_installed";
|
|
5
|
+
readonly serverId: string;
|
|
6
|
+
readonly installDecisionTool: boolean;
|
|
7
|
+
/** A recorded install decision; absent while the user has not decided. */
|
|
8
|
+
readonly decision?: "declined" | "allowed";
|
|
9
|
+
readonly text: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface NotInstalledGuidanceState {
|
|
13
|
+
readonly notInstalledServers: Set<string>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Decides whether a missing-server nudge reaches the model.
|
|
18
|
+
*
|
|
19
|
+
* Recorded decisions keep their own text. Undecided nudges are skipped for files outside a project
|
|
20
|
+
* (no marked root, the agent's config dir, or a temp dir) because a repo-local install there would
|
|
21
|
+
* create a manifest in HOME or a temp dir. Without a decision tool nothing can be recorded, so a
|
|
22
|
+
* server is nudged at most once per session state.
|
|
23
|
+
*/
|
|
24
|
+
export function notInstalledGuidance(
|
|
25
|
+
filePath: string,
|
|
26
|
+
outcome: PostEditNotInstalledOutcome,
|
|
27
|
+
state: NotInstalledGuidanceState,
|
|
28
|
+
locateFile: ((filePath: string) => PostEditFileLocation) | undefined,
|
|
29
|
+
): string | undefined {
|
|
30
|
+
if (outcome.decision !== undefined) return outcome.text;
|
|
31
|
+
if (locateFile !== undefined && locateFile(filePath) !== "project") return undefined;
|
|
32
|
+
if (outcome.installDecisionTool) return outcome.text;
|
|
33
|
+
if (state.notInstalledServers.has(outcome.serverId)) return undefined;
|
|
34
|
+
state.notInstalledServers.add(outcome.serverId);
|
|
35
|
+
return outcome.text;
|
|
36
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { afterEach, describe, expect, it } from "bun:test";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
classifyPostEditFileLocation,
|
|
8
|
+
collectPostEditDiagnostics,
|
|
9
|
+
createPostEditNotConfiguredCache,
|
|
10
|
+
type PostEditDiagnosticsOutcome,
|
|
11
|
+
type PostEditFileLocation,
|
|
12
|
+
resetPostEditNotConfiguredCache,
|
|
13
|
+
} from "./index.js";
|
|
14
|
+
|
|
15
|
+
const tempDirectories: string[] = [];
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
for (const directory of tempDirectories.splice(0)) {
|
|
19
|
+
rmSync(directory, { recursive: true, force: true });
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
function tempRoot(prefix: string): string {
|
|
24
|
+
const root = mkdtempSync(join(tmpdir(), prefix));
|
|
25
|
+
tempDirectories.push(root);
|
|
26
|
+
return root;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function touch(path: string, text = ""): string {
|
|
30
|
+
mkdirSync(join(path, ".."), { recursive: true });
|
|
31
|
+
writeFileSync(path, text);
|
|
32
|
+
return path;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const FULL_NUDGE = [
|
|
36
|
+
"LSP server 'typescript' for .ts is NOT INSTALLED.",
|
|
37
|
+
"To install in THIS repository (preferred, no global install needed):",
|
|
38
|
+
"ACTION REQUIRED: ASK THE USER whether to install this LSP server.",
|
|
39
|
+
].join("\n");
|
|
40
|
+
|
|
41
|
+
function notInstalled(
|
|
42
|
+
serverId: string,
|
|
43
|
+
overrides: Partial<Extract<PostEditDiagnosticsOutcome, { kind: "not_installed" }>> = {},
|
|
44
|
+
): PostEditDiagnosticsOutcome {
|
|
45
|
+
return {
|
|
46
|
+
kind: "not_installed",
|
|
47
|
+
serverId,
|
|
48
|
+
installDecisionTool: false,
|
|
49
|
+
text: `${FULL_NUDGE} (${serverId})`,
|
|
50
|
+
...overrides,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function at(location: PostEditFileLocation): () => PostEditFileLocation {
|
|
55
|
+
return () => location;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
describe("classifyPostEditFileLocation", () => {
|
|
59
|
+
it("#given a file with no workspace marker above it #when classified #then it is outside any project", () => {
|
|
60
|
+
const root = tempRoot("lsp-postedit-noproject-");
|
|
61
|
+
const file = touch(join(root, "scratch", "note.mjs"));
|
|
62
|
+
|
|
63
|
+
expect(classifyPostEditFileLocation(file, { cwd: root, agentDirs: [], tempDirs: [] })).toBe("outside_project");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("#given a file under the agent config dir inside a git repository #when classified #then the agent config dir wins", () => {
|
|
67
|
+
const root = tempRoot("lsp-postedit-agentdir-");
|
|
68
|
+
mkdirSync(join(root, ".git"));
|
|
69
|
+
const agentDir = join(root, ".omo", "agent");
|
|
70
|
+
const file = touch(join(agentDir, "models.json"), "{}\n");
|
|
71
|
+
|
|
72
|
+
expect(classifyPostEditFileLocation(file, { cwd: root, agentDirs: [agentDir], tempDirs: [] })).toBe(
|
|
73
|
+
"agent_config",
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("#given a temp dir holding a stray package.json #when a scratch file there is classified #then it is a temp file", () => {
|
|
78
|
+
const temp = tempRoot("lsp-postedit-temp-");
|
|
79
|
+
touch(join(temp, "package.json"), "{}\n");
|
|
80
|
+
const file = touch(join(temp, "rules_test.mjs"));
|
|
81
|
+
|
|
82
|
+
expect(classifyPostEditFileLocation(file, { cwd: temp, agentDirs: [], tempDirs: [temp] })).toBe("temp");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("#given the default temp dirs #when an OS temp file is classified #then the canonical temp dir matches", () => {
|
|
86
|
+
const root = tempRoot("lsp-postedit-ostemp-");
|
|
87
|
+
const file = touch(join(root, "scratch.mjs"));
|
|
88
|
+
|
|
89
|
+
expect(classifyPostEditFileLocation(file, { cwd: root, agentDirs: [] })).toBe("temp");
|
|
90
|
+
if (process.platform !== "win32") {
|
|
91
|
+
const slashTmp = join("/tmp", `lsp-postedit-missing-${process.pid}`, "rules_test.mjs");
|
|
92
|
+
expect(classifyPostEditFileLocation(slashTmp, { cwd: root, agentDirs: [] })).toBe("temp");
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
for (const marker of ["package.json", ".git"] as const) {
|
|
97
|
+
it(`#given a ${marker} directly in HOME #when a home-level file is classified #then HOME is not its project`, () => {
|
|
98
|
+
const home = tempRoot("lsp-postedit-home-");
|
|
99
|
+
if (marker === ".git") mkdirSync(join(home, ".git"));
|
|
100
|
+
else touch(join(home, marker), "{}\n");
|
|
101
|
+
const topLevel = touch(join(home, "notes.ts"));
|
|
102
|
+
const nested = touch(join(home, "scratch", "draft.ts"));
|
|
103
|
+
|
|
104
|
+
const options = { cwd: home, agentDirs: [], tempDirs: [], homeDirs: [home] };
|
|
105
|
+
expect(classifyPostEditFileLocation(topLevel, options)).toBe("outside_project");
|
|
106
|
+
expect(classifyPostEditFileLocation(nested, options)).toBe("outside_project");
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
it("#given a marked HOME and a project under it #when a project file is classified #then it is still a project", () => {
|
|
111
|
+
const home = tempRoot("lsp-postedit-homeproject-");
|
|
112
|
+
mkdirSync(join(home, ".git"));
|
|
113
|
+
touch(join(home, "work", "app", "package.json"), "{}\n");
|
|
114
|
+
const file = touch(join(home, "work", "app", "src", "a.ts"));
|
|
115
|
+
|
|
116
|
+
expect(classifyPostEditFileLocation(file, { cwd: home, agentDirs: [], tempDirs: [], homeDirs: [home] })).toBe(
|
|
117
|
+
"project",
|
|
118
|
+
);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("#given a project with its own marker inside a temp dir #when classified #then it is a project", () => {
|
|
122
|
+
const temp = tempRoot("lsp-postedit-tempproject-");
|
|
123
|
+
const project = join(temp, "checkout");
|
|
124
|
+
touch(join(project, "package.json"), "{}\n");
|
|
125
|
+
const file = touch(join(project, "src", "a.ts"));
|
|
126
|
+
|
|
127
|
+
expect(classifyPostEditFileLocation(file, { cwd: project, agentDirs: [], tempDirs: [temp] })).toBe("project");
|
|
128
|
+
expect(classifyPostEditFileLocation("src/a.ts", { cwd: project, agentDirs: [], tempDirs: [temp] })).toBe(
|
|
129
|
+
"project",
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe("collectPostEditDiagnostics not-installed guidance", () => {
|
|
135
|
+
for (const location of ["outside_project", "agent_config", "temp"] as const) {
|
|
136
|
+
it(`#given a missing server for a ${location} file #when diagnostics run #then the install nudge is skipped`, async () => {
|
|
137
|
+
const result = await collectPostEditDiagnostics({
|
|
138
|
+
filePaths: ["file.ts"],
|
|
139
|
+
runDiagnostics: async () => notInstalled("typescript"),
|
|
140
|
+
locateFile: at(location),
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
expect(result.blocks).toEqual([]);
|
|
144
|
+
expect(result.observations).toEqual([{ filePath: "file.ts", kind: "not_installed" }]);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
it("#given a missing server for a project file #when diagnostics run #then today's full guidance is kept", async () => {
|
|
149
|
+
const result = await collectPostEditDiagnostics({
|
|
150
|
+
filePaths: ["src/a.ts"],
|
|
151
|
+
runDiagnostics: async () => notInstalled("typescript"),
|
|
152
|
+
locateFile: at("project"),
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(result.blocks).toEqual([{ filePath: "src/a.ts", diagnostics: `${FULL_NUDGE} (typescript)`, blocking: false }]);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("#given no decision tool #when repeated edits hit missing servers #then each server is nudged once per session", async () => {
|
|
159
|
+
const cache = createPostEditNotConfiguredCache();
|
|
160
|
+
const serverFor = (filePath: string): string => (filePath.endsWith(".json") ? "biome" : "typescript");
|
|
161
|
+
const run = (filePaths: readonly string[]) =>
|
|
162
|
+
collectPostEditDiagnostics({
|
|
163
|
+
filePaths,
|
|
164
|
+
cache,
|
|
165
|
+
runDiagnostics: async (filePath) => notInstalled(serverFor(filePath)),
|
|
166
|
+
locateFile: at("project"),
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const first = await run(["a.ts", "b.ts"]);
|
|
170
|
+
const second = await run(["c.ts", "d.json"]);
|
|
171
|
+
const third = await run(["e.json", "f.ts"]);
|
|
172
|
+
|
|
173
|
+
expect(first.blocks.map((block) => block.filePath)).toEqual(["a.ts"]);
|
|
174
|
+
expect(second.blocks.map((block) => block.filePath)).toEqual(["d.json"]);
|
|
175
|
+
expect(third.blocks).toEqual([]);
|
|
176
|
+
|
|
177
|
+
resetPostEditNotConfiguredCache(cache);
|
|
178
|
+
const afterReset = await run(["g.ts"]);
|
|
179
|
+
expect(afterReset.blocks.map((block) => block.filePath)).toEqual(["g.ts"]);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("#given a decision tool #when repeated edits hit a missing server #then every edit keeps the guidance", async () => {
|
|
183
|
+
const cache = createPostEditNotConfiguredCache();
|
|
184
|
+
const run = (filePath: string) =>
|
|
185
|
+
collectPostEditDiagnostics({
|
|
186
|
+
filePaths: [filePath],
|
|
187
|
+
cache,
|
|
188
|
+
runDiagnostics: async () => notInstalled("typescript", { installDecisionTool: true }),
|
|
189
|
+
locateFile: at("project"),
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
expect((await run("a.ts")).blocks).toHaveLength(1);
|
|
193
|
+
expect((await run("b.ts")).blocks).toHaveLength(1);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
for (const decision of ["declined", "allowed"] as const) {
|
|
197
|
+
it(`#given a recorded ${decision} decision #when edits repeat anywhere #then that branch's text is unchanged every time`, async () => {
|
|
198
|
+
const cache = createPostEditNotConfiguredCache();
|
|
199
|
+
const text = `LSP server 'typescript' ${decision} branch text`;
|
|
200
|
+
const outcomes: PostEditFileLocation[] = ["project", "outside_project", "project"];
|
|
201
|
+
const blocks: string[] = [];
|
|
202
|
+
for (const location of outcomes) {
|
|
203
|
+
const result = await collectPostEditDiagnostics({
|
|
204
|
+
filePaths: ["a.ts"],
|
|
205
|
+
cache,
|
|
206
|
+
runDiagnostics: async () => notInstalled("typescript", { decision, text }),
|
|
207
|
+
locateFile: at(location),
|
|
208
|
+
});
|
|
209
|
+
blocks.push(...result.blocks.map((block) => block.diagnostics));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
expect(blocks).toEqual([text, text, text]);
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
it("#given no file locator #when a missing server is reported #then the full guidance is kept", async () => {
|
|
217
|
+
const result = await collectPostEditDiagnostics({
|
|
218
|
+
filePaths: ["a.ts"],
|
|
219
|
+
runDiagnostics: async () => notInstalled("typescript"),
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
expect(result.blocks).toEqual([{ filePath: "a.ts", diagnostics: `${FULL_NUDGE} (typescript)`, blocking: false }]);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
collectPostEditDiagnostics,
|
|
5
|
+
createPostEditNotConfiguredCache,
|
|
6
|
+
resetPostEditNotConfiguredCache,
|
|
7
|
+
} from "./orchestration.js";
|
|
8
|
+
|
|
9
|
+
describe("collectPostEditDiagnostics", () => {
|
|
10
|
+
it("#given rendered not_configured text #when the same extension is checked again #then the text is not cached", async () => {
|
|
11
|
+
const cache = createPostEditNotConfiguredCache();
|
|
12
|
+
let calls = 0;
|
|
13
|
+
|
|
14
|
+
const first = await collectPostEditDiagnostics({
|
|
15
|
+
filePaths: ["a.foo"],
|
|
16
|
+
cache,
|
|
17
|
+
runDiagnostics: async () => {
|
|
18
|
+
calls += 1;
|
|
19
|
+
return "No LSP server configured for extension: .foo\n\nordinary text from a renderer";
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
const second = await collectPostEditDiagnostics({
|
|
23
|
+
filePaths: ["b.foo"],
|
|
24
|
+
cache,
|
|
25
|
+
runDiagnostics: async () => {
|
|
26
|
+
calls += 1;
|
|
27
|
+
return "diagnostic for b.foo";
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
expect(calls).toBe(2);
|
|
32
|
+
expect(first.blocks).toEqual([
|
|
33
|
+
{ filePath: "a.foo", diagnostics: "No LSP server configured for extension: .foo\n\nordinary text from a renderer", blocking: true },
|
|
34
|
+
]);
|
|
35
|
+
expect(second.blocks).toEqual([{ filePath: "b.foo", diagnostics: "diagnostic for b.foo", blocking: true }]);
|
|
36
|
+
expect([...cache.notConfiguredExtensions]).toEqual([]);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("#given duplicate edited paths #when diagnostics run #then first seen paths are processed once and blocks stay ordered", async () => {
|
|
40
|
+
const calls: string[] = [];
|
|
41
|
+
|
|
42
|
+
const result = await collectPostEditDiagnostics({
|
|
43
|
+
filePaths: ["a.ts", "b.ts", "a.ts", "c.ts"],
|
|
44
|
+
runDiagnostics: async (filePath: string) => {
|
|
45
|
+
calls.push(filePath);
|
|
46
|
+
return filePath === "b.ts" ? "No diagnostics found" : `diagnostic for ${filePath}`;
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
expect(calls).toEqual(["a.ts", "b.ts", "c.ts"]);
|
|
51
|
+
expect(result.blocks).toEqual([
|
|
52
|
+
{ filePath: "a.ts", diagnostics: "diagnostic for a.ts", blocking: true },
|
|
53
|
+
{ filePath: "c.ts", diagnostics: "diagnostic for c.ts", blocking: true },
|
|
54
|
+
]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("#given many edited paths #when diagnostics run #then concurrency is bounded to four and failures isolate", async () => {
|
|
58
|
+
let active = 0;
|
|
59
|
+
let maxActive = 0;
|
|
60
|
+
|
|
61
|
+
const result = await collectPostEditDiagnostics({
|
|
62
|
+
filePaths: ["a.ts", "b.ts", "c.ts", "d.ts", "e.ts", "f.ts"],
|
|
63
|
+
runDiagnostics: async (filePath: string) => {
|
|
64
|
+
active += 1;
|
|
65
|
+
maxActive = Math.max(maxActive, active);
|
|
66
|
+
await Promise.resolve();
|
|
67
|
+
active -= 1;
|
|
68
|
+
if (filePath === "c.ts") throw new Error("server exploded");
|
|
69
|
+
return filePath === "e.ts" ? "No diagnostics found" : `diagnostic for ${filePath}`;
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
expect(maxActive).toBe(4);
|
|
74
|
+
expect(result.blocks).toEqual([
|
|
75
|
+
{ filePath: "a.ts", diagnostics: "diagnostic for a.ts", blocking: true },
|
|
76
|
+
{ filePath: "b.ts", diagnostics: "diagnostic for b.ts", blocking: true },
|
|
77
|
+
{ filePath: "c.ts", diagnostics: "server exploded", blocking: true },
|
|
78
|
+
{ filePath: "d.ts", diagnostics: "diagnostic for d.ts", blocking: true },
|
|
79
|
+
{ filePath: "f.ts", diagnostics: "diagnostic for f.ts", blocking: true },
|
|
80
|
+
]);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("#given structured not_configured diagnostics #when cache is reused and reset #then only not_configured is cached", async () => {
|
|
84
|
+
const cache = createPostEditNotConfiguredCache();
|
|
85
|
+
const calls: string[] = [];
|
|
86
|
+
const responses = new Map<string, string | { readonly kind: "not_configured"; readonly extension: string }>([
|
|
87
|
+
["a.foo", { kind: "not_configured", extension: ".foo" }],
|
|
88
|
+
["b.foo", "diagnostic should be skipped"],
|
|
89
|
+
["c.bar", "LSP server 'bar' for .bar is NOT INSTALLED."],
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
const first = await collectPostEditDiagnostics({
|
|
93
|
+
filePaths: ["a.foo", "c.bar"],
|
|
94
|
+
cache,
|
|
95
|
+
runDiagnostics: async (filePath: string) => {
|
|
96
|
+
calls.push(filePath);
|
|
97
|
+
return responses.get(filePath) ?? "No diagnostics found";
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expect(calls).toEqual(["a.foo", "c.bar"]);
|
|
102
|
+
expect(first.blocks).toEqual([{ filePath: "c.bar", diagnostics: "LSP server 'bar' for .bar is NOT INSTALLED.", blocking: true }]);
|
|
103
|
+
|
|
104
|
+
const cached = await collectPostEditDiagnostics({
|
|
105
|
+
filePaths: ["b.foo"],
|
|
106
|
+
cache,
|
|
107
|
+
runDiagnostics: async (filePath: string) => {
|
|
108
|
+
calls.push(filePath);
|
|
109
|
+
return responses.get(filePath) ?? "No diagnostics found";
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
expect(cached.blocks).toEqual([]);
|
|
114
|
+
expect(calls).toEqual(["a.foo", "c.bar"]);
|
|
115
|
+
|
|
116
|
+
responses.set("a.foo", "No diagnostics found");
|
|
117
|
+
resetPostEditNotConfiguredCache(cache);
|
|
118
|
+
const second = await collectPostEditDiagnostics({
|
|
119
|
+
filePaths: ["a.foo", "b.foo"],
|
|
120
|
+
cache,
|
|
121
|
+
runDiagnostics: async (filePath: string) => {
|
|
122
|
+
calls.push(filePath);
|
|
123
|
+
return responses.get(filePath) ?? "No diagnostics found";
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
expect(second.blocks).toEqual([{ filePath: "b.foo", diagnostics: "diagnostic should be skipped", blocking: true }]);
|
|
128
|
+
expect(calls).toEqual(["a.foo", "c.bar", "a.foo", "b.foo"]);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("#given non-not_configured failures #when cache is reused #then every failure retries", async () => {
|
|
132
|
+
const cache = createPostEditNotConfiguredCache();
|
|
133
|
+
let calls = 0;
|
|
134
|
+
|
|
135
|
+
const first = await collectPostEditDiagnostics({
|
|
136
|
+
filePaths: ["a.foo"],
|
|
137
|
+
cache,
|
|
138
|
+
runDiagnostics: async () => {
|
|
139
|
+
calls += 1;
|
|
140
|
+
return "LSP server 'foo' for .foo is NOT INSTALLED.";
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
const second = await collectPostEditDiagnostics({
|
|
144
|
+
filePaths: ["b.foo"],
|
|
145
|
+
cache,
|
|
146
|
+
runDiagnostics: async () => {
|
|
147
|
+
calls += 1;
|
|
148
|
+
throw new Error("daemon unavailable");
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
expect(calls).toBe(2);
|
|
153
|
+
expect(first.blocks).toEqual([{ filePath: "a.foo", diagnostics: "LSP server 'foo' for .foo is NOT INSTALLED.", blocking: true }]);
|
|
154
|
+
expect(second.blocks).toEqual([{ filePath: "b.foo", diagnostics: "daemon unavailable", blocking: true }]);
|
|
155
|
+
expect([...cache.notConfiguredExtensions]).toEqual([]);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { extname } from "node:path";
|
|
2
|
+
|
|
3
|
+
import type { PostEditFileLocation } from "./file-location.js";
|
|
4
|
+
import { notInstalledGuidance, type PostEditNotInstalledOutcome } from "./not-installed-guidance.js";
|
|
5
|
+
|
|
6
|
+
const DEFAULT_MAX_CONCURRENCY = 4;
|
|
7
|
+
const CLEAN_DIAGNOSTICS_TEXT = "No diagnostics found";
|
|
8
|
+
|
|
9
|
+
export type PostEditDiagnosticsOutcome =
|
|
10
|
+
| string
|
|
11
|
+
| {
|
|
12
|
+
readonly kind: "not_configured";
|
|
13
|
+
readonly extension: string;
|
|
14
|
+
}
|
|
15
|
+
| PostEditNotInstalledOutcome;
|
|
16
|
+
|
|
17
|
+
export type DiagnosticsRunner = (filePath: string) => Promise<PostEditDiagnosticsOutcome>;
|
|
18
|
+
|
|
19
|
+
export interface PostEditDiagnosticsBlock {
|
|
20
|
+
readonly filePath: string;
|
|
21
|
+
readonly diagnostics: string;
|
|
22
|
+
/** False for missing-server guidance: it is feedback for the model, not a defect in the edit. */
|
|
23
|
+
readonly blocking: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface PostEditDiagnosticsObservation {
|
|
27
|
+
readonly filePath: string;
|
|
28
|
+
readonly kind: "block" | "clean" | "not_configured" | "not_installed";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface PostEditDiagnosticsResult {
|
|
32
|
+
readonly blocks: readonly PostEditDiagnosticsBlock[];
|
|
33
|
+
readonly observations: readonly PostEditDiagnosticsObservation[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface PostEditNotConfiguredCache {
|
|
37
|
+
readonly notConfiguredExtensions: Set<string>;
|
|
38
|
+
readonly notInstalledServers: Set<string>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface CollectPostEditDiagnosticsInput {
|
|
42
|
+
readonly filePaths: readonly string[];
|
|
43
|
+
readonly runDiagnostics: DiagnosticsRunner;
|
|
44
|
+
readonly cache?: PostEditNotConfiguredCache;
|
|
45
|
+
readonly maxConcurrency?: number;
|
|
46
|
+
readonly locateFile?: (filePath: string) => PostEditFileLocation;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface IndexedFilePath {
|
|
50
|
+
readonly index: number;
|
|
51
|
+
readonly filePath: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
interface IndexedDiagnostics {
|
|
55
|
+
readonly index: number;
|
|
56
|
+
readonly filePath: string;
|
|
57
|
+
readonly outcome: PostEditDiagnosticsOutcome;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function createPostEditNotConfiguredCache(): PostEditNotConfiguredCache {
|
|
61
|
+
return { notConfiguredExtensions: new Set(), notInstalledServers: new Set() };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function resetPostEditNotConfiguredCache(cache: PostEditNotConfiguredCache): void {
|
|
65
|
+
cache.notConfiguredExtensions.clear();
|
|
66
|
+
cache.notInstalledServers.clear();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function collectPostEditDiagnostics(
|
|
70
|
+
input: CollectPostEditDiagnosticsInput,
|
|
71
|
+
): Promise<PostEditDiagnosticsResult> {
|
|
72
|
+
const cache = input.cache === undefined ? createPostEditNotConfiguredCache() : input.cache;
|
|
73
|
+
const filePaths = firstSeenDiagnosticTargets(input.filePaths, cache);
|
|
74
|
+
const results = await runBoundedDiagnostics(filePaths, input.runDiagnostics, input.maxConcurrency);
|
|
75
|
+
const blocks: PostEditDiagnosticsBlock[] = [];
|
|
76
|
+
const observations: PostEditDiagnosticsObservation[] = [];
|
|
77
|
+
|
|
78
|
+
for (const result of results) {
|
|
79
|
+
const outcome = result.outcome;
|
|
80
|
+
const classification =
|
|
81
|
+
typeof outcome !== "string" && outcome.kind === "not_installed"
|
|
82
|
+
? classifyNotInstalled(notInstalledGuidance(result.filePath, outcome, cache, input.locateFile))
|
|
83
|
+
: classifyDiagnostics(outcome);
|
|
84
|
+
switch (classification.kind) {
|
|
85
|
+
case "not_installed":
|
|
86
|
+
observations.push({ filePath: result.filePath, kind: "not_installed" });
|
|
87
|
+
break;
|
|
88
|
+
case "clean":
|
|
89
|
+
observations.push({ filePath: result.filePath, kind: "clean" });
|
|
90
|
+
break;
|
|
91
|
+
case "not_configured":
|
|
92
|
+
cache.notConfiguredExtensions.add(classification.extension);
|
|
93
|
+
observations.push({ filePath: result.filePath, kind: "not_configured" });
|
|
94
|
+
break;
|
|
95
|
+
case "block":
|
|
96
|
+
blocks.push({ filePath: result.filePath, diagnostics: classification.diagnostics, blocking: true });
|
|
97
|
+
observations.push({ filePath: result.filePath, kind: "block" });
|
|
98
|
+
break;
|
|
99
|
+
case "guidance":
|
|
100
|
+
blocks.push({ filePath: result.filePath, diagnostics: classification.text, blocking: false });
|
|
101
|
+
observations.push({ filePath: result.filePath, kind: "block" });
|
|
102
|
+
break;
|
|
103
|
+
default: {
|
|
104
|
+
const exhaustive: never = classification;
|
|
105
|
+
return exhaustive;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return { blocks, observations };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function firstSeenDiagnosticTargets(
|
|
114
|
+
filePaths: readonly string[],
|
|
115
|
+
cache: PostEditNotConfiguredCache,
|
|
116
|
+
): readonly IndexedFilePath[] {
|
|
117
|
+
const seen = new Set<string>();
|
|
118
|
+
const targets: IndexedFilePath[] = [];
|
|
119
|
+
for (const filePath of filePaths) {
|
|
120
|
+
if (filePath.length === 0 || seen.has(filePath)) continue;
|
|
121
|
+
seen.add(filePath);
|
|
122
|
+
const extension = extensionKey(filePath);
|
|
123
|
+
if (extension !== undefined && cache.notConfiguredExtensions.has(extension)) continue;
|
|
124
|
+
targets.push({ index: targets.length, filePath });
|
|
125
|
+
}
|
|
126
|
+
return targets;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function runBoundedDiagnostics(
|
|
130
|
+
filePaths: readonly IndexedFilePath[],
|
|
131
|
+
runDiagnostics: DiagnosticsRunner,
|
|
132
|
+
maxConcurrency: number | undefined,
|
|
133
|
+
): Promise<readonly IndexedDiagnostics[]> {
|
|
134
|
+
const results: IndexedDiagnostics[] = [];
|
|
135
|
+
const workerCount = Math.min(Math.max(1, maxConcurrency ?? DEFAULT_MAX_CONCURRENCY), filePaths.length);
|
|
136
|
+
let nextIndex = 0;
|
|
137
|
+
|
|
138
|
+
async function worker(): Promise<void> {
|
|
139
|
+
for (;;) {
|
|
140
|
+
const target = filePaths[nextIndex];
|
|
141
|
+
nextIndex += 1;
|
|
142
|
+
if (target === undefined) return;
|
|
143
|
+
results[target.index] = {
|
|
144
|
+
index: target.index,
|
|
145
|
+
filePath: target.filePath,
|
|
146
|
+
outcome: await collectFileDiagnostics(target.filePath, runDiagnostics),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
152
|
+
return results.filter((result) => result !== undefined);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function collectFileDiagnostics(
|
|
156
|
+
filePath: string,
|
|
157
|
+
runDiagnostics: DiagnosticsRunner,
|
|
158
|
+
): Promise<PostEditDiagnosticsOutcome> {
|
|
159
|
+
try {
|
|
160
|
+
return normalizeDiagnosticsOutcome(await runDiagnostics(filePath));
|
|
161
|
+
} catch (error) {
|
|
162
|
+
if (error instanceof Error) return formatDiagnosticsError(error);
|
|
163
|
+
return normalizeDiagnosticsText(String(error));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function normalizeDiagnosticsOutcome(outcome: PostEditDiagnosticsOutcome): PostEditDiagnosticsOutcome {
|
|
168
|
+
if (typeof outcome === "string") return normalizeDiagnosticsText(outcome);
|
|
169
|
+
if (outcome.kind === "not_installed") return { ...outcome, text: normalizeDiagnosticsText(outcome.text) };
|
|
170
|
+
return outcome;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function classifyNotInstalled(
|
|
174
|
+
guidance: string | undefined,
|
|
175
|
+
): { readonly kind: "not_installed" } | { readonly kind: "guidance"; readonly text: string } {
|
|
176
|
+
return guidance === undefined ? { kind: "not_installed" } : { kind: "guidance", text: guidance };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function normalizeDiagnosticsText(text: string): string {
|
|
180
|
+
return text.trim();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function formatDiagnosticsError(error: Error): string {
|
|
184
|
+
const message = normalizeDiagnosticsText(error.message);
|
|
185
|
+
return message.length > 0 ? message : normalizeDiagnosticsText(String(error));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function classifyDiagnostics(
|
|
189
|
+
outcome: Exclude<PostEditDiagnosticsOutcome, PostEditNotInstalledOutcome>,
|
|
190
|
+
):
|
|
191
|
+
| { readonly kind: "clean" }
|
|
192
|
+
| { readonly kind: "not_configured"; readonly extension: string }
|
|
193
|
+
| { readonly kind: "block"; readonly diagnostics: string } {
|
|
194
|
+
if (typeof outcome !== "string") {
|
|
195
|
+
return { kind: "not_configured", extension: outcome.extension };
|
|
196
|
+
}
|
|
197
|
+
const diagnostics = outcome;
|
|
198
|
+
if (diagnostics.length === 0 || diagnostics === CLEAN_DIAGNOSTICS_TEXT) return { kind: "clean" };
|
|
199
|
+
return { kind: "block", diagnostics };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function extensionKey(filePath: string): string | undefined {
|
|
203
|
+
const extension = extname(filePath).toLowerCase();
|
|
204
|
+
return extension.length === 0 ? undefined : extension;
|
|
205
|
+
}
|