@herbertgao/pi-extensions 2026.8.4 → 2026.8.5
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/README.md +4 -4
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +10 -2
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +10 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +5 -8
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
- package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
- package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +15 -2
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
- package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
- package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
- package/node_modules/@narumitw/pi-btw/README.md +8 -7
- package/node_modules/@narumitw/pi-btw/package.json +2 -2
- package/node_modules/@narumitw/pi-btw/src/menu.ts +1 -0
- package/node_modules/pi-lens/CHANGELOG.md +2440 -954
- package/node_modules/pi-lens/README.md +13 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
- package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
- package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
- package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
- package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
- package/node_modules/pi-lens/dist/clients/biome-client.js +29 -25
- package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
- package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
- package/node_modules/pi-lens/dist/clients/bus-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
- package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
- package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
- package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
- package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
- package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
- package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
- package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/console-guard-install.js +14 -0
- package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
- package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +347 -75
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +61 -11
- package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +63 -20
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
- package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
- package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
- package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1085 -681
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
- package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
- package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +14 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +277 -26
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
- package/node_modules/pi-lens/dist/clients/disposition-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
- package/node_modules/pi-lens/dist/clients/extension-log.js +139 -0
- package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
- package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
- package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
- package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
- package/node_modules/pi-lens/dist/clients/format-events-publish.js +16 -3
- package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
- package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
- package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
- package/node_modules/pi-lens/dist/clients/git-guard.js +681 -11
- package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
- package/node_modules/pi-lens/dist/clients/go-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +8 -0
- package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
- package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
- package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +390 -99
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +31 -54
- package/node_modules/pi-lens/dist/clients/knip-client.js +15 -36
- package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
- package/node_modules/pi-lens/dist/clients/latency-logger.js +23 -1
- package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
- package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
- package/node_modules/pi-lens/dist/clients/lens-events.js +27 -4
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +30 -0
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/client.js +493 -48
- package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +86 -0
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
- package/node_modules/pi-lens/dist/clients/lsp/index.js +1807 -780
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
- package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
- package/node_modules/pi-lens/dist/clients/lsp/server.js +196 -32
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
- package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
- package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +123 -32
- package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
- package/node_modules/pi-lens/dist/clients/mcp/session.js +216 -8
- package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
- package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
- package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
- package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
- package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
- package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
- package/node_modules/pi-lens/dist/clients/pipeline.js +47 -13
- package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
- package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
- package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
- package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
- package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
- package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
- package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
- package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
- package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
- package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
- package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +107 -73
- package/node_modules/pi-lens/dist/clients/runtime-context.js +36 -12
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +74 -6
- package/node_modules/pi-lens/dist/clients/runtime-session.js +405 -117
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +218 -23
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +237 -64
- package/node_modules/pi-lens/dist/clients/rust-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
- package/node_modules/pi-lens/dist/clients/sg-runner.js +284 -174
- package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +224 -0
- package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
- package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
- package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
- package/node_modules/pi-lens/dist/clients/startup-timing.js +1 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +38 -8
- package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
- package/node_modules/pi-lens/dist/clients/tool-policy.js +388 -39
- package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
- package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
- package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
- package/node_modules/pi-lens/dist/clients/warm-attach.js +33 -13
- package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
- package/node_modules/pi-lens/dist/clients/word-index.js +391 -64
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
- package/node_modules/pi-lens/dist/index.js +49361 -36888
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
- package/node_modules/pi-lens/dist/mcp/server.js +211 -44
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +200 -36
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +153 -40
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
- package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
- package/node_modules/pi-lens/docs/agent-guide.md +2 -2
- package/node_modules/pi-lens/docs/agent-tools.md +21 -10
- package/node_modules/pi-lens/docs/analysisall.md +192 -0
- package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +5 -2
- package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
- package/node_modules/pi-lens/docs/environment-variables.md +44 -0
- package/node_modules/pi-lens/docs/fable.md +27 -0
- package/node_modules/pi-lens/docs/features.md +31 -2
- package/node_modules/pi-lens/docs/globalconfig.md +45 -1
- package/node_modules/pi-lens/docs/language-coverage.md +4 -3
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
- package/node_modules/pi-lens/docs/mcp.md +37 -4
- package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
- package/node_modules/pi-lens/docs/settings.md +12 -1
- package/node_modules/pi-lens/docs/tools.md +4 -1
- package/node_modules/pi-lens/docs/usage.md +18 -0
- package/node_modules/pi-lens/package.json +10 -10
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
- package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +55 -2
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +25 -0
- package/node_modules/pi-mcp-adapter/README.md +34 -3
- package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
- package/node_modules/pi-mcp-adapter/commands.ts +15 -7
- package/node_modules/pi-mcp-adapter/direct-tools.ts +54 -7
- package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
- package/node_modules/pi-mcp-adapter/index.ts +8 -3
- package/node_modules/pi-mcp-adapter/init.ts +29 -5
- package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
- package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
- package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +27 -4
- package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
- package/node_modules/pi-mcp-adapter/package.json +3 -3
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
- package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
- package/node_modules/pi-mcp-adapter/server-manager.ts +36 -7
- package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
- package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
- package/node_modules/pi-mcp-adapter/tool-metadata.ts +42 -4
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
- package/node_modules/pi-mcp-adapter/types.ts +93 -27
- package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
- package/package.json +11 -12
- package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
- package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
- package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
- package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
- package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
- package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
- package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
- package/node_modules/pi-lens/dist/clients/types.js +0 -11
|
@@ -1,8 +1,30 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { TERRAGRUNT_FILENAMES } from "./file-kinds.js";
|
|
3
4
|
import { logLatency } from "./latency-logger.js";
|
|
5
|
+
import { resolvePackagePath } from "./package-root.js";
|
|
4
6
|
import { findNearestContaining, walkUpDirs } from "./path-utils.js";
|
|
5
|
-
import {
|
|
7
|
+
import { loadProjectSnapshotWithoutWordIndex } from "./project-snapshot.js";
|
|
8
|
+
// Extension → formatter policy. This map, `FORMATTER_POLICY_BY_FILENAME`, and
|
|
9
|
+
// `AUTO_INSTALLABLE_DEFAULT_FORMATTERS` are the inverse of the formatter
|
|
10
|
+
// definitions in `clients/formatters.ts` (formatter → extensions). The two are
|
|
11
|
+
// bound by `tests/clients/formatter-policy-consistency.test.ts` (#1135, the
|
|
12
|
+
// #883/#209 single-source-of-truth class) so they cannot drift silently. All
|
|
13
|
+
// three are re-exported (read-only intent) via a single `export {}` below —
|
|
14
|
+
// deliberately NOT inline on these declarations, to keep the pre-existing,
|
|
15
|
+
// structural lookup-table duplication out of the PR's "new code" (SonarCloud).
|
|
16
|
+
//
|
|
17
|
+
// Two deliberate #1135 decisions live in the entries below, documented here so
|
|
18
|
+
// the rationale sits outside the duplicated run:
|
|
19
|
+
// - `.sass` offers ["biome", "prettier"] only — NOT oxfmt: oxfmt is absent
|
|
20
|
+
// from OXFMT_SUPPORTED_EXTENSIONS (oxfmt/prettier handle .css/.scss/.less,
|
|
21
|
+
// not the indented `.sass` syntax). It was previously hand-listed here,
|
|
22
|
+
// diverging from the oxfmt definition (inert, because `matching` filtered
|
|
23
|
+
// it out); dropped to bind the two.
|
|
24
|
+
// - `.fish` intentionally has NO entry. `fish-indent` is a LINT runner
|
|
25
|
+
// (getLinterPolicyForFile), not a FormatterInfo — a formatter policy naming
|
|
26
|
+
// it was a dead, unsatisfiable entry; fish reformatting runs via the
|
|
27
|
+
// linter/autofix path. Removed to keep extension→formatter consistent.
|
|
6
28
|
const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
7
29
|
[
|
|
8
30
|
".js",
|
|
@@ -133,7 +155,8 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
133
155
|
[
|
|
134
156
|
".sass",
|
|
135
157
|
{
|
|
136
|
-
|
|
158
|
+
// #1135: no oxfmt (see map header comment).
|
|
159
|
+
formatterNames: ["biome", "prettier"],
|
|
137
160
|
defaultFormatter: "biome",
|
|
138
161
|
defaultWhenUnconfigured: true,
|
|
139
162
|
gate: "smart-default",
|
|
@@ -230,7 +253,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
230
253
|
{
|
|
231
254
|
formatterNames: ["ktfmt", "ktlint"],
|
|
232
255
|
defaultFormatter: "ktlint",
|
|
233
|
-
defaultWhenUnconfigured:
|
|
256
|
+
defaultWhenUnconfigured: false,
|
|
234
257
|
gate: "smart-default",
|
|
235
258
|
},
|
|
236
259
|
],
|
|
@@ -239,7 +262,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
239
262
|
{
|
|
240
263
|
formatterNames: ["ktfmt", "ktlint"],
|
|
241
264
|
defaultFormatter: "ktlint",
|
|
242
|
-
defaultWhenUnconfigured:
|
|
265
|
+
defaultWhenUnconfigured: false,
|
|
243
266
|
gate: "smart-default",
|
|
244
267
|
},
|
|
245
268
|
],
|
|
@@ -248,7 +271,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
248
271
|
{
|
|
249
272
|
formatterNames: ["swiftformat"],
|
|
250
273
|
defaultFormatter: "swiftformat",
|
|
251
|
-
defaultWhenUnconfigured:
|
|
274
|
+
defaultWhenUnconfigured: false,
|
|
252
275
|
gate: "smart-default",
|
|
253
276
|
},
|
|
254
277
|
],
|
|
@@ -257,7 +280,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
257
280
|
{
|
|
258
281
|
formatterNames: ["fantomas"],
|
|
259
282
|
defaultFormatter: "fantomas",
|
|
260
|
-
defaultWhenUnconfigured:
|
|
283
|
+
defaultWhenUnconfigured: false,
|
|
261
284
|
gate: "smart-default",
|
|
262
285
|
},
|
|
263
286
|
],
|
|
@@ -266,7 +289,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
266
289
|
{
|
|
267
290
|
formatterNames: ["fantomas"],
|
|
268
291
|
defaultFormatter: "fantomas",
|
|
269
|
-
defaultWhenUnconfigured:
|
|
292
|
+
defaultWhenUnconfigured: false,
|
|
270
293
|
gate: "smart-default",
|
|
271
294
|
},
|
|
272
295
|
],
|
|
@@ -275,7 +298,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
275
298
|
{
|
|
276
299
|
formatterNames: ["fantomas"],
|
|
277
300
|
defaultFormatter: "fantomas",
|
|
278
|
-
defaultWhenUnconfigured:
|
|
301
|
+
defaultWhenUnconfigured: false,
|
|
279
302
|
gate: "smart-default",
|
|
280
303
|
},
|
|
281
304
|
],
|
|
@@ -284,7 +307,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
284
307
|
{
|
|
285
308
|
formatterNames: ["nixfmt"],
|
|
286
309
|
defaultFormatter: "nixfmt",
|
|
287
|
-
defaultWhenUnconfigured:
|
|
310
|
+
defaultWhenUnconfigured: false,
|
|
288
311
|
gate: "smart-default",
|
|
289
312
|
},
|
|
290
313
|
],
|
|
@@ -293,7 +316,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
293
316
|
{
|
|
294
317
|
formatterNames: ["mix"],
|
|
295
318
|
defaultFormatter: "mix",
|
|
296
|
-
defaultWhenUnconfigured:
|
|
319
|
+
defaultWhenUnconfigured: false,
|
|
297
320
|
gate: "smart-default",
|
|
298
321
|
},
|
|
299
322
|
],
|
|
@@ -302,7 +325,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
302
325
|
{
|
|
303
326
|
formatterNames: ["mix"],
|
|
304
327
|
defaultFormatter: "mix",
|
|
305
|
-
defaultWhenUnconfigured:
|
|
328
|
+
defaultWhenUnconfigured: false,
|
|
306
329
|
gate: "smart-default",
|
|
307
330
|
},
|
|
308
331
|
],
|
|
@@ -311,7 +334,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
311
334
|
{
|
|
312
335
|
formatterNames: ["mix"],
|
|
313
336
|
defaultFormatter: "mix",
|
|
314
|
-
defaultWhenUnconfigured:
|
|
337
|
+
defaultWhenUnconfigured: false,
|
|
315
338
|
gate: "smart-default",
|
|
316
339
|
},
|
|
317
340
|
],
|
|
@@ -320,7 +343,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
320
343
|
{
|
|
321
344
|
formatterNames: ["mix"],
|
|
322
345
|
defaultFormatter: "mix",
|
|
323
|
-
defaultWhenUnconfigured:
|
|
346
|
+
defaultWhenUnconfigured: false,
|
|
324
347
|
gate: "smart-default",
|
|
325
348
|
},
|
|
326
349
|
],
|
|
@@ -329,7 +352,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
329
352
|
{
|
|
330
353
|
formatterNames: ["mix"],
|
|
331
354
|
defaultFormatter: "mix",
|
|
332
|
-
defaultWhenUnconfigured:
|
|
355
|
+
defaultWhenUnconfigured: false,
|
|
333
356
|
gate: "smart-default",
|
|
334
357
|
},
|
|
335
358
|
],
|
|
@@ -419,7 +442,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
419
442
|
{
|
|
420
443
|
formatterNames: ["csharpier"],
|
|
421
444
|
defaultFormatter: "csharpier",
|
|
422
|
-
defaultWhenUnconfigured:
|
|
445
|
+
defaultWhenUnconfigured: false,
|
|
423
446
|
gate: "smart-default",
|
|
424
447
|
},
|
|
425
448
|
],
|
|
@@ -437,7 +460,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
437
460
|
{
|
|
438
461
|
formatterNames: ["ormolu"],
|
|
439
462
|
defaultFormatter: "ormolu",
|
|
440
|
-
defaultWhenUnconfigured:
|
|
463
|
+
defaultWhenUnconfigured: false,
|
|
441
464
|
gate: "smart-default",
|
|
442
465
|
},
|
|
443
466
|
],
|
|
@@ -446,7 +469,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
446
469
|
{
|
|
447
470
|
formatterNames: ["ormolu"],
|
|
448
471
|
defaultFormatter: "ormolu",
|
|
449
|
-
defaultWhenUnconfigured:
|
|
472
|
+
defaultWhenUnconfigured: false,
|
|
450
473
|
gate: "smart-default",
|
|
451
474
|
},
|
|
452
475
|
],
|
|
@@ -504,21 +527,12 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
504
527
|
gate: "smart-default",
|
|
505
528
|
},
|
|
506
529
|
],
|
|
507
|
-
[
|
|
508
|
-
".fish",
|
|
509
|
-
{
|
|
510
|
-
formatterNames: ["fish-indent"],
|
|
511
|
-
defaultFormatter: "fish-indent",
|
|
512
|
-
defaultWhenUnconfigured: true,
|
|
513
|
-
gate: "smart-default",
|
|
514
|
-
},
|
|
515
|
-
],
|
|
516
530
|
[
|
|
517
531
|
".toml",
|
|
518
532
|
{
|
|
519
533
|
formatterNames: ["taplo"],
|
|
520
534
|
defaultFormatter: "taplo",
|
|
521
|
-
defaultWhenUnconfigured:
|
|
535
|
+
defaultWhenUnconfigured: false,
|
|
522
536
|
gate: "smart-default",
|
|
523
537
|
},
|
|
524
538
|
],
|
|
@@ -527,7 +541,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
527
541
|
{
|
|
528
542
|
formatterNames: ["terraform"],
|
|
529
543
|
defaultFormatter: "terraform",
|
|
530
|
-
defaultWhenUnconfigured:
|
|
544
|
+
defaultWhenUnconfigured: false,
|
|
531
545
|
gate: "smart-default",
|
|
532
546
|
},
|
|
533
547
|
],
|
|
@@ -536,7 +550,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
536
550
|
{
|
|
537
551
|
formatterNames: ["terraform"],
|
|
538
552
|
defaultFormatter: "terraform",
|
|
539
|
-
defaultWhenUnconfigured:
|
|
553
|
+
defaultWhenUnconfigured: false,
|
|
540
554
|
gate: "smart-default",
|
|
541
555
|
},
|
|
542
556
|
],
|
|
@@ -617,7 +631,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
617
631
|
{
|
|
618
632
|
formatterNames: ["psscriptanalyzer-format"],
|
|
619
633
|
defaultFormatter: "psscriptanalyzer-format",
|
|
620
|
-
defaultWhenUnconfigured:
|
|
634
|
+
defaultWhenUnconfigured: false,
|
|
621
635
|
gate: "smart-default",
|
|
622
636
|
},
|
|
623
637
|
],
|
|
@@ -626,7 +640,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
626
640
|
{
|
|
627
641
|
formatterNames: ["psscriptanalyzer-format"],
|
|
628
642
|
defaultFormatter: "psscriptanalyzer-format",
|
|
629
|
-
defaultWhenUnconfigured:
|
|
643
|
+
defaultWhenUnconfigured: false,
|
|
630
644
|
gate: "smart-default",
|
|
631
645
|
},
|
|
632
646
|
],
|
|
@@ -635,7 +649,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
635
649
|
{
|
|
636
650
|
formatterNames: ["psscriptanalyzer-format"],
|
|
637
651
|
defaultFormatter: "psscriptanalyzer-format",
|
|
638
|
-
defaultWhenUnconfigured:
|
|
652
|
+
defaultWhenUnconfigured: false,
|
|
639
653
|
gate: "smart-default",
|
|
640
654
|
},
|
|
641
655
|
],
|
|
@@ -643,10 +657,15 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
|
|
|
643
657
|
// oxfmt supports these extensions — registered as a candidate formatter for each.
|
|
644
658
|
// Using a post-processing pass avoids repeating the same modification across
|
|
645
659
|
// many map entries (and keeps SonarCloud's duplication gate happy).
|
|
646
|
-
|
|
660
|
+
// This is the SINGLE SOURCE OF TRUTH for oxfmt's supported extensions — do not
|
|
661
|
+
// hand-maintain a second copy; `clients/formatters.ts`'s `oxfmtFormatter.extensions`
|
|
662
|
+
// imports and spreads this same Set (#1134; previously two parallel hand-maintained
|
|
663
|
+
// lists, the #883 single-source-of-truth class).
|
|
664
|
+
export const OXFMT_SUPPORTED_EXTENSIONS = new Set([
|
|
647
665
|
".js", ".jsx", ".mjs", ".cjs",
|
|
648
666
|
".ts", ".tsx", ".mts", ".cts",
|
|
649
667
|
".vue",
|
|
668
|
+
".svelte",
|
|
650
669
|
".css", ".scss", ".less",
|
|
651
670
|
".html", ".htm",
|
|
652
671
|
".json", ".jsonc",
|
|
@@ -662,6 +681,22 @@ FORMATTER_POLICY_BY_EXTENSION.set(".vue", {
|
|
|
662
681
|
defaultWhenUnconfigured: false,
|
|
663
682
|
gate: "config-first",
|
|
664
683
|
});
|
|
684
|
+
// Add .svelte entry (no prior formatter policy existed for this extension —
|
|
685
|
+
// docs/language-coverage.md previously listed no formatter). oxfmt is the only
|
|
686
|
+
// candidate; the loop below appends it since ".svelte" is in
|
|
687
|
+
// OXFMT_SUPPORTED_EXTENSIONS. Unlike the other oxfmt extensions, oxfmt's
|
|
688
|
+
// .svelte support is conditional on more than "a config file exists" — see
|
|
689
|
+
// `hasOxfmtSvelteConfig` below, gated in `formatters.ts`'s
|
|
690
|
+
// `hasExplicitFormatterConfig` (verified empirically against the real oxfmt
|
|
691
|
+
// npm binary; oxfmt exits non-zero on .svelte without BOTH the `svelte`
|
|
692
|
+
// package installed and the config's `svelte` flag enabled — an unconditional
|
|
693
|
+
// offer would guarantee a formatter failure, not a no-op).
|
|
694
|
+
FORMATTER_POLICY_BY_EXTENSION.set(".svelte", {
|
|
695
|
+
formatterNames: [],
|
|
696
|
+
defaultFormatter: "oxfmt",
|
|
697
|
+
defaultWhenUnconfigured: false,
|
|
698
|
+
gate: "config-first",
|
|
699
|
+
});
|
|
665
700
|
for (const [ext, policy] of FORMATTER_POLICY_BY_EXTENSION) {
|
|
666
701
|
if (OXFMT_SUPPORTED_EXTENSIONS.has(ext) && !policy.formatterNames.includes("oxfmt")) {
|
|
667
702
|
policy.formatterNames.push("oxfmt");
|
|
@@ -675,10 +710,30 @@ const AUTO_INSTALLABLE_DEFAULT_FORMATTERS = new Map([
|
|
|
675
710
|
["taplo", "taplo"],
|
|
676
711
|
["ktlint", "ktlint"],
|
|
677
712
|
]);
|
|
713
|
+
// `gate: "smart-default"` so a matched file is formatted only when nothing else
|
|
714
|
+
// claims it. Misdetection edge: `root.hcl` is filename-detected as terragrunt, so
|
|
715
|
+
// a non-terragrunt `root.hcl` gets smart-default formatted with `terragrunt hcl
|
|
716
|
+
// fmt`'s generic HCL canonicalization — a soft outcome (canonical HCL, no config
|
|
717
|
+
// semantics assumed), not a hard failure.
|
|
718
|
+
const TERRAGRUNT_FORMATTER_POLICY = {
|
|
719
|
+
formatterNames: ["terragrunt-hcl"],
|
|
720
|
+
defaultFormatter: "terragrunt-hcl",
|
|
721
|
+
defaultWhenUnconfigured: true,
|
|
722
|
+
gate: "smart-default",
|
|
723
|
+
};
|
|
724
|
+
const FORMATTER_POLICY_BY_FILENAME = new Map(TERRAGRUNT_FILENAMES.map((name) => [name, TERRAGRUNT_FORMATTER_POLICY]));
|
|
725
|
+
// Re-exported (read-only intent) for the #1135 drift guard. Kept as a single
|
|
726
|
+
// separate statement — NOT inline on the declarations above — so the touched
|
|
727
|
+
// lines don't fall at the head of the pre-existing lookup-table duplication and
|
|
728
|
+
// get counted as new duplicated code. Bindings are live, so position is safe.
|
|
729
|
+
export { AUTO_INSTALLABLE_DEFAULT_FORMATTERS, FORMATTER_POLICY_BY_EXTENSION, FORMATTER_POLICY_BY_FILENAME, };
|
|
678
730
|
export function getFormatterPolicyForExtension(ext) {
|
|
679
731
|
return FORMATTER_POLICY_BY_EXTENSION.get(ext.toLowerCase());
|
|
680
732
|
}
|
|
681
733
|
export function getFormatterPolicyForFile(filePath) {
|
|
734
|
+
const byFilename = FORMATTER_POLICY_BY_FILENAME.get(path.basename(filePath).toLowerCase());
|
|
735
|
+
if (byFilename)
|
|
736
|
+
return byFilename;
|
|
682
737
|
return getFormatterPolicyForExtension(path.extname(filePath));
|
|
683
738
|
}
|
|
684
739
|
export function getSmartDefaultFormatterName(filePath) {
|
|
@@ -773,8 +828,21 @@ const AUTOFIX_CAPABILITIES = new Map([
|
|
|
773
828
|
],
|
|
774
829
|
]);
|
|
775
830
|
const TOOL_EXECUTION_POLICY = new Map([
|
|
831
|
+
// Dispatch/LSP runners use the shared availability/install seam. These
|
|
832
|
+
// managed tools are missing-command repair candidates; probe failures still
|
|
833
|
+
// fail closed before this policy is consulted.
|
|
834
|
+
["pyright", { gate: "smart-default", autoInstall: true }],
|
|
835
|
+
["shellcheck", { gate: "smart-default", autoInstall: true }],
|
|
836
|
+
["shfmt", { gate: "smart-default", autoInstall: true }],
|
|
837
|
+
["tflint", { gate: "smart-default", autoInstall: true }],
|
|
838
|
+
["terragrunt", { gate: "smart-default", autoInstall: true }],
|
|
839
|
+
["trivy", { gate: "config-first", autoInstall: true }],
|
|
776
840
|
["biome", { gate: "smart-default", autoInstall: true }],
|
|
777
841
|
["ruff", { gate: "smart-default", autoInstall: true }],
|
|
842
|
+
["jscpd", { gate: "smart-default", autoInstall: true }],
|
|
843
|
+
["madge", { gate: "smart-default", autoInstall: true }],
|
|
844
|
+
["knip", { gate: "smart-default", autoInstall: true }],
|
|
845
|
+
["ast-grep", { gate: "smart-default", autoInstall: true }],
|
|
778
846
|
["oxlint", { gate: "smart-default", autoInstall: true }],
|
|
779
847
|
["stylelint", { gate: "smart-default", autoInstall: true }],
|
|
780
848
|
["sqlfluff", { gate: "smart-default", autoInstall: true }],
|
|
@@ -785,6 +853,7 @@ const TOOL_EXECUTION_POLICY = new Map([
|
|
|
785
853
|
["mypy", { gate: "config-first", autoInstall: true }],
|
|
786
854
|
["taplo", { gate: "smart-default", autoInstall: true }],
|
|
787
855
|
["hadolint", { gate: "smart-default", autoInstall: true }],
|
|
856
|
+
["helm", { gate: "smart-default", autoInstall: true }],
|
|
788
857
|
["htmlhint", { gate: "smart-default", autoInstall: true }],
|
|
789
858
|
["ktlint", { gate: "smart-default", autoInstall: true }],
|
|
790
859
|
// ktfmt is opt-in (a project's explicit formatting choice), so it only runs
|
|
@@ -1096,8 +1165,8 @@ export function getLinterPolicyForFile(filePath, context = {}) {
|
|
|
1096
1165
|
runnerNames: ["sqlfluff"],
|
|
1097
1166
|
preferredRunners: ["sqlfluff"],
|
|
1098
1167
|
defaultRunner: "sqlfluff",
|
|
1099
|
-
defaultWhenUnconfigured:
|
|
1100
|
-
gate: "
|
|
1168
|
+
defaultWhenUnconfigured: false,
|
|
1169
|
+
gate: "config-first",
|
|
1101
1170
|
};
|
|
1102
1171
|
}
|
|
1103
1172
|
if ([".rb", ".rake", ".gemspec", ".ru"].includes(ext)) {
|
|
@@ -1145,6 +1214,15 @@ export function getLinterPolicyForFile(filePath, context = {}) {
|
|
|
1145
1214
|
gate: "smart-default",
|
|
1146
1215
|
};
|
|
1147
1216
|
}
|
|
1217
|
+
if (TERRAGRUNT_FILENAMES.includes(path.basename(filePath).toLowerCase())) {
|
|
1218
|
+
return {
|
|
1219
|
+
runnerNames: ["terragrunt"],
|
|
1220
|
+
preferredRunners: ["terragrunt"],
|
|
1221
|
+
defaultRunner: "terragrunt",
|
|
1222
|
+
defaultWhenUnconfigured: true,
|
|
1223
|
+
gate: "smart-default",
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1148
1226
|
if ([".kt", ".kts"].includes(ext)) {
|
|
1149
1227
|
// When the project opts into ktfmt, ktfmt (a pure formatter wired as a safe
|
|
1150
1228
|
// autofix) owns Kotlin formatting; ktlint's lint steps aside so its style
|
|
@@ -1227,7 +1305,7 @@ export function getLinterPolicyForFile(filePath, context = {}) {
|
|
|
1227
1305
|
preferredRunners: ["tflint"],
|
|
1228
1306
|
defaultRunner: "tflint",
|
|
1229
1307
|
defaultWhenUnconfigured: true,
|
|
1230
|
-
gate: "smart-default",
|
|
1308
|
+
gate: context.hasTflintConfig ? "config-first" : "smart-default",
|
|
1231
1309
|
};
|
|
1232
1310
|
}
|
|
1233
1311
|
if ([".ex", ".exs", ".eex", ".heex", ".leex"].includes(ext)) {
|
|
@@ -1296,7 +1374,7 @@ export function getLinterPolicyForFile(filePath, context = {}) {
|
|
|
1296
1374
|
* start / project-seq bumps rather than on every read.
|
|
1297
1375
|
*/
|
|
1298
1376
|
export function getCachedProjectConventions(cwd) {
|
|
1299
|
-
const snapshot =
|
|
1377
|
+
const snapshot = loadProjectSnapshotWithoutWordIndex(cwd);
|
|
1300
1378
|
return snapshot?.conventions;
|
|
1301
1379
|
}
|
|
1302
1380
|
export function getLinterPolicyForCwd(filePath, cwd) {
|
|
@@ -1314,6 +1392,9 @@ export function getLinterPolicyForCwd(filePath, cwd) {
|
|
|
1314
1392
|
hasMypyConfig: hasMypyConfig(cwd),
|
|
1315
1393
|
hasDetektConfig: hasDetektConfig(cwd),
|
|
1316
1394
|
hasKtfmtConfig: hasKtfmtConfig(cwd),
|
|
1395
|
+
// From the file's directory, not cwd: a `.tflint.hcl` in a terraform
|
|
1396
|
+
// subdirectory is invisible to an upward walk that starts at the repo root.
|
|
1397
|
+
hasTflintConfig: hasTflintConfig(path.dirname(path.resolve(cwd, filePath))),
|
|
1317
1398
|
};
|
|
1318
1399
|
const policy = getLinterPolicyForFile(filePath, context);
|
|
1319
1400
|
if (policy) {
|
|
@@ -1412,8 +1493,8 @@ export function getAutofixPolicyForFile(filePath, context = {}) {
|
|
|
1412
1493
|
toolNames: ["sqlfluff"],
|
|
1413
1494
|
preferredTools: ["sqlfluff"],
|
|
1414
1495
|
defaultTool: "sqlfluff",
|
|
1415
|
-
defaultWhenUnconfigured:
|
|
1416
|
-
gate: "
|
|
1496
|
+
defaultWhenUnconfigured: false,
|
|
1497
|
+
gate: "config-first",
|
|
1417
1498
|
safe: true,
|
|
1418
1499
|
};
|
|
1419
1500
|
}
|
|
@@ -1428,6 +1509,16 @@ export function getAutofixPolicyForFile(filePath, context = {}) {
|
|
|
1428
1509
|
};
|
|
1429
1510
|
}
|
|
1430
1511
|
if ([".kt", ".kts"].includes(ext)) {
|
|
1512
|
+
if (context.hasKtlintConfig) {
|
|
1513
|
+
return {
|
|
1514
|
+
toolNames: ["ktlint", "ktfmt", "detekt"],
|
|
1515
|
+
preferredTools: ["ktlint"],
|
|
1516
|
+
defaultTool: "ktlint",
|
|
1517
|
+
defaultWhenUnconfigured: false,
|
|
1518
|
+
gate: "config-first",
|
|
1519
|
+
safe: true,
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1431
1522
|
// ktfmt is config-first and the project's explicit formatting choice, so it
|
|
1432
1523
|
// wins over both detekt and the ktlint smart-default when opted in (#129).
|
|
1433
1524
|
if (context.hasKtfmtConfig) {
|
|
@@ -1625,6 +1716,69 @@ export function hasOxfmtConfig(cwd) {
|
|
|
1625
1716
|
}
|
|
1626
1717
|
return false;
|
|
1627
1718
|
}
|
|
1719
|
+
// Empirically verified against the real `oxfmt` npm package (0.62.0), a
|
|
1720
|
+
// scratch fixture, and a plain `Component.svelte` — see PR body for the full
|
|
1721
|
+
// four-cell matrix. Both conditions are required; either alone always fails:
|
|
1722
|
+
// - no `svelte` package, no config flag -> exit 2 ("excluded by ignore rules")
|
|
1723
|
+
// - no `svelte` package, config flag on -> exit 2 ("Cannot find module 'svelte/compiler'")
|
|
1724
|
+
// - `svelte` package installed, no flag -> exit 2 ("excluded by ignore rules")
|
|
1725
|
+
// - `svelte` package installed, flag on -> exit 0, formats the file
|
|
1726
|
+
// Per https://oxc.rs/docs/guide/usage/formatter/language-support.html, oxfmt
|
|
1727
|
+
// also requires the npm-distributed binary (not the standalone GitHub-release
|
|
1728
|
+
// binary) for `.svelte` — pi-lens already resolves oxfmt via `findInNodeModules`/
|
|
1729
|
+
// `which`, which favors the npm-installed binary, so that requirement is not
|
|
1730
|
+
// separately re-checked here.
|
|
1731
|
+
//
|
|
1732
|
+
// Known limits of this line-match heuristic (#1134 P3 tail 1): it tolerates a
|
|
1733
|
+
// trailing `#`-comment after the value (`svelte = true # enable`), but it is
|
|
1734
|
+
// NOT a real TOML parser — a `svelte = true` occurrence nested under a
|
|
1735
|
+
// `[table]` section, or one embedded inside a multi-line/triple-quoted string
|
|
1736
|
+
// value, would still match and false-positive. Both are considered acceptable
|
|
1737
|
+
// risk: an oxfmt.toml sectioning `svelte` under a table is not a realistic
|
|
1738
|
+
// config shape for this single top-level boolean key, and a false positive
|
|
1739
|
+
// here only causes oxfmt to be OFFERED (still gated by oxfmt actually running
|
|
1740
|
+
// and the `svelte` package check above), never a silent formatter failure.
|
|
1741
|
+
const OXFMT_SVELTE_TOML_TRUE = /(^|\n)\s*svelte\s*=\s*true\s*(\s*#.*)?(\r?\n|$)/;
|
|
1742
|
+
export function hasOxfmtSvelteConfig(cwd) {
|
|
1743
|
+
// Monorepo asymmetry (#1134 P3 tail 2): this dependency check stops at the
|
|
1744
|
+
// NEAREST package.json (`hasNearestPackageJsonDependency`), while the
|
|
1745
|
+
// config walk below (`walkUpDirs`) continues all the way to the repo root.
|
|
1746
|
+
// A root-level `svelte` dependency combined with an oxfmt config at the
|
|
1747
|
+
// root, but invoked with a sub-package `cwd` that has its own
|
|
1748
|
+
// (svelte-less) package.json, under-offers oxfmt for that sub-package —
|
|
1749
|
+
// the same nearest-vs-root-walk asymmetry as the `.tflint.hcl` note in
|
|
1750
|
+
// `getLinterPolicyForCwd` above. This is untested/deliberately unfixed:
|
|
1751
|
+
// failing to offer a valid formatter is safe (never mis-offers one that
|
|
1752
|
+
// then fails at runtime), unlike the inverse.
|
|
1753
|
+
if (!hasNearestPackageJsonDependency(cwd, "svelte"))
|
|
1754
|
+
return false;
|
|
1755
|
+
for (const dir of walkUpDirs(cwd)) {
|
|
1756
|
+
const rcPath = path.join(dir, ".oxfmtrc.json");
|
|
1757
|
+
if (fs.existsSync(rcPath)) {
|
|
1758
|
+
try {
|
|
1759
|
+
const cfg = JSON.parse(fs.readFileSync(rcPath, "utf-8"));
|
|
1760
|
+
if (cfg.svelte === true)
|
|
1761
|
+
return true;
|
|
1762
|
+
}
|
|
1763
|
+
catch { }
|
|
1764
|
+
}
|
|
1765
|
+
// oxfmt.toml is TOML; pi-lens has no TOML parser dependency, so this is
|
|
1766
|
+
// a targeted line match for the single boolean key rather than a full
|
|
1767
|
+
// parse (same pragmatic style as hasVitePlusConfig's content.includes
|
|
1768
|
+
// check above) — presence of the file alone is NOT sufficient, since a
|
|
1769
|
+
// TOML config can omit `svelte` or set it false.
|
|
1770
|
+
const tomlPath = path.join(dir, "oxfmt.toml");
|
|
1771
|
+
if (fs.existsSync(tomlPath)) {
|
|
1772
|
+
try {
|
|
1773
|
+
const content = fs.readFileSync(tomlPath, "utf-8");
|
|
1774
|
+
if (OXFMT_SVELTE_TOML_TRUE.test(content))
|
|
1775
|
+
return true;
|
|
1776
|
+
}
|
|
1777
|
+
catch { }
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
return false;
|
|
1781
|
+
}
|
|
1628
1782
|
export function hasStylelintConfig(cwd) {
|
|
1629
1783
|
for (const dir of walkUpDirs(cwd)) {
|
|
1630
1784
|
if (STYLELINT_CONFIGS.some((cfg) => fs.existsSync(path.join(dir, cfg)))) {
|
|
@@ -1832,9 +1986,61 @@ export function hasRuffConfig(cwd) {
|
|
|
1832
1986
|
}
|
|
1833
1987
|
return false;
|
|
1834
1988
|
}
|
|
1989
|
+
/**
|
|
1990
|
+
* Shared config-args seam for the markdownlint lint AND autofix surfaces
|
|
1991
|
+
* (#1247). The lint runner (`markdownlint.ts`) and the autofix path
|
|
1992
|
+
* (`pipeline.ts` `tryMarkdownlintFix`) MUST both consume this builder so the
|
|
1993
|
+
* package-owned sensible-defaults config (`config/markdownlint/core.json`) can
|
|
1994
|
+
* never drift apart from the bare `--fix` invocation again.
|
|
1995
|
+
*/
|
|
1996
|
+
/**
|
|
1997
|
+
* Shared fallback shape for the config-args builders (#1247): when the
|
|
1998
|
+
* project has its own config the lint/autofix surfaces pass NO args (the
|
|
1999
|
+
* tool discovers it); otherwise both surfaces point at the package-owned
|
|
2000
|
+
* fallback so the tool never silently runs its default ruleset. One shape
|
|
2001
|
+
* here means the per-tool builders cannot drift from each other.
|
|
2002
|
+
*/
|
|
2003
|
+
function configArgsWithFallback(hasConfig, toolArgs, packageConfigPath) {
|
|
2004
|
+
return hasConfig
|
|
2005
|
+
? []
|
|
2006
|
+
: [...toolArgs, resolvePackagePath(import.meta.url, packageConfigPath)];
|
|
2007
|
+
}
|
|
2008
|
+
export function markdownlintConfigArgs(cwd) {
|
|
2009
|
+
return configArgsWithFallback(hasMarkdownlintConfig(cwd), ["--config"], "config/markdownlint/core.json");
|
|
2010
|
+
}
|
|
2011
|
+
/**
|
|
2012
|
+
* Shared config-args seam for the ruff lint AND autofix surfaces (#1247).
|
|
2013
|
+
* The lint runner (`ruff.ts`) and `ruffClient.fixFileAsync` MUST both consume
|
|
2014
|
+
* this builder so `config/ruff/core.toml` applies on `--fix` too.
|
|
2015
|
+
*/
|
|
2016
|
+
export function ruffConfigArgs(cwd) {
|
|
2017
|
+
return configArgsWithFallback(hasRuffConfig(cwd), ["--config"], "config/ruff/core.toml");
|
|
2018
|
+
}
|
|
2019
|
+
/**
|
|
2020
|
+
* Shared config-args seam for the biome lint AND autofix surfaces (#1247).
|
|
2021
|
+
* The lint runner (`biome-check.ts`) and `biomeClient.fixFileAsync` MUST both
|
|
2022
|
+
* consume this builder so the user's `biome.json(c)` — or the package-owned
|
|
2023
|
+
* `config/biome/core.jsonc` fallback — applies on `lint --write` too.
|
|
2024
|
+
*/
|
|
2025
|
+
export function biomeConfigArgs(cwd) {
|
|
2026
|
+
return [
|
|
2027
|
+
"--config-path=" +
|
|
2028
|
+
(getBiomeConfigPath(cwd) ??
|
|
2029
|
+
resolvePackagePath(import.meta.url, "config/biome/core.jsonc")),
|
|
2030
|
+
];
|
|
2031
|
+
}
|
|
1835
2032
|
export function hasGolangciConfig(cwd) {
|
|
1836
2033
|
return findNearestContaining(cwd, GOLANGCI_CONFIGS) !== undefined;
|
|
1837
2034
|
}
|
|
2035
|
+
// tflint ships built-in rules and runs without config, so `.tflint.hcl` is not
|
|
2036
|
+
// a prerequisite — it is the project electing tflint as its terraform linter,
|
|
2037
|
+
// which promotes the policy from smart-default to config-first. Takes a start
|
|
2038
|
+
// directory rather than the project cwd because tflint resolves config
|
|
2039
|
+
// per-directory: callers pass the EDITED FILE's directory so this agrees with
|
|
2040
|
+
// what the runner will actually hand tflint via `--config`.
|
|
2041
|
+
export function hasTflintConfig(startDir) {
|
|
2042
|
+
return findNearestContaining(startDir, [".tflint.hcl"]) !== undefined;
|
|
2043
|
+
}
|
|
1838
2044
|
export function hasClangFormatConfig(cwd) {
|
|
1839
2045
|
return (findNearestContaining(cwd, [".clang-format", "_clang-format"]) !== undefined);
|
|
1840
2046
|
}
|
|
@@ -1897,7 +2103,150 @@ const KTFMT_GRADLE_FILES = [
|
|
|
1897
2103
|
"settings.gradle.kts",
|
|
1898
2104
|
"settings.gradle",
|
|
1899
2105
|
];
|
|
2106
|
+
const KOTLIN_GRADLE_FILES = [
|
|
2107
|
+
"build.gradle.kts",
|
|
2108
|
+
"build.gradle",
|
|
2109
|
+
"settings.gradle.kts",
|
|
2110
|
+
"settings.gradle",
|
|
2111
|
+
];
|
|
2112
|
+
const spotlessKotlinConfigCache = new Map();
|
|
2113
|
+
let spotlessGradleReadCount = 0;
|
|
2114
|
+
/** Test-only observability for asserting the hot-path I/O bound. */
|
|
2115
|
+
export function _getSpotlessGradleReadCountForTests() {
|
|
2116
|
+
return spotlessGradleReadCount;
|
|
2117
|
+
}
|
|
2118
|
+
/**
|
|
2119
|
+
* Blank comments and quoted strings while preserving braces and newlines in
|
|
2120
|
+
* executable Gradle source. This is deliberately a small lexical pre-pass,
|
|
2121
|
+
* not a Groovy/Kotlin parser. In particular, statically disabled constructs
|
|
2122
|
+
* such as `if (false) { ktlint() }` remain a documented false-positive.
|
|
2123
|
+
*/
|
|
2124
|
+
function stripGradleCommentsAndStrings(source) {
|
|
2125
|
+
let result = "";
|
|
2126
|
+
let state = "code";
|
|
2127
|
+
let quote = "";
|
|
2128
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
2129
|
+
const char = source[index];
|
|
2130
|
+
const next = source[index + 1];
|
|
2131
|
+
if (state === "code") {
|
|
2132
|
+
if (char === "/" && next === "/") {
|
|
2133
|
+
result += " ";
|
|
2134
|
+
index += 1;
|
|
2135
|
+
state = "line-comment";
|
|
2136
|
+
}
|
|
2137
|
+
else if (char === "/" && next === "*") {
|
|
2138
|
+
result += " ";
|
|
2139
|
+
index += 1;
|
|
2140
|
+
state = "block-comment";
|
|
2141
|
+
}
|
|
2142
|
+
else if (char === '"' || char === "'") {
|
|
2143
|
+
result += " ";
|
|
2144
|
+
quote = char;
|
|
2145
|
+
state = "string";
|
|
2146
|
+
}
|
|
2147
|
+
else {
|
|
2148
|
+
result += char;
|
|
2149
|
+
}
|
|
2150
|
+
continue;
|
|
2151
|
+
}
|
|
2152
|
+
if (state === "line-comment") {
|
|
2153
|
+
if (char === "\n" || char === "\r") {
|
|
2154
|
+
result += char;
|
|
2155
|
+
state = "code";
|
|
2156
|
+
}
|
|
2157
|
+
else {
|
|
2158
|
+
result += " ";
|
|
2159
|
+
}
|
|
2160
|
+
continue;
|
|
2161
|
+
}
|
|
2162
|
+
if (state === "block-comment") {
|
|
2163
|
+
if (char === "*" && next === "/") {
|
|
2164
|
+
result += " ";
|
|
2165
|
+
index += 1;
|
|
2166
|
+
state = "code";
|
|
2167
|
+
}
|
|
2168
|
+
else {
|
|
2169
|
+
result += char === "\n" || char === "\r" ? char : " ";
|
|
2170
|
+
}
|
|
2171
|
+
continue;
|
|
2172
|
+
}
|
|
2173
|
+
if (char === "\\") {
|
|
2174
|
+
result += " ";
|
|
2175
|
+
if (index + 1 < source.length) {
|
|
2176
|
+
result += source[index + 1] === "\n" ? "\n" : " ";
|
|
2177
|
+
index += 1;
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
else if (char === quote) {
|
|
2181
|
+
result += " ";
|
|
2182
|
+
state = "code";
|
|
2183
|
+
}
|
|
2184
|
+
else {
|
|
2185
|
+
result += char === "\n" || char === "\r" ? char : " ";
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
return result;
|
|
2189
|
+
}
|
|
2190
|
+
function namedGradleBlockBodies(source, name) {
|
|
2191
|
+
const bodies = [];
|
|
2192
|
+
const startPattern = new RegExp(`\\b${name}\\s*\\{`, "g");
|
|
2193
|
+
for (const match of source.matchAll(startPattern)) {
|
|
2194
|
+
const open = source.indexOf("{", match.index);
|
|
2195
|
+
let depth = 1;
|
|
2196
|
+
for (let index = open + 1; index < source.length; index += 1) {
|
|
2197
|
+
if (source[index] === "{")
|
|
2198
|
+
depth += 1;
|
|
2199
|
+
if (source[index] === "}")
|
|
2200
|
+
depth -= 1;
|
|
2201
|
+
if (depth === 0) {
|
|
2202
|
+
bodies.push(source.slice(open + 1, index));
|
|
2203
|
+
break;
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
return bodies;
|
|
2208
|
+
}
|
|
2209
|
+
/**
|
|
2210
|
+
* Resolve the formatter elected by a Spotless `kotlin { ... }` block.
|
|
2211
|
+
* ktlint is the deterministic tie-break if a malformed project names both.
|
|
2212
|
+
*/
|
|
2213
|
+
export function getSpotlessKotlinFormatter(cwd) {
|
|
2214
|
+
for (const dir of walkUpDirs(cwd)) {
|
|
2215
|
+
for (const gradle of KOTLIN_GRADLE_FILES) {
|
|
2216
|
+
const filePath = path.join(dir, gradle);
|
|
2217
|
+
if (!fs.existsSync(filePath))
|
|
2218
|
+
continue;
|
|
2219
|
+
try {
|
|
2220
|
+
const mtime = fs.statSync(filePath).mtimeMs;
|
|
2221
|
+
let config = spotlessKotlinConfigCache.get(filePath);
|
|
2222
|
+
if (!config || config.mtime !== mtime) {
|
|
2223
|
+
const source = stripGradleCommentsAndStrings(fs.readFileSync(filePath, "utf-8"));
|
|
2224
|
+
spotlessGradleReadCount += 1;
|
|
2225
|
+
const kotlinBodies = namedGradleBlockBodies(source, "spotless").flatMap((spotless) => namedGradleBlockBodies(spotless, "kotlin"));
|
|
2226
|
+
config = {
|
|
2227
|
+
mtime,
|
|
2228
|
+
ktlintConfig: kotlinBodies.some((body) => /\bktlint\s*\(/.test(body)),
|
|
2229
|
+
ktfmtConfig: kotlinBodies.some((body) => /\bktfmt\s*\(/.test(body)),
|
|
2230
|
+
};
|
|
2231
|
+
spotlessKotlinConfigCache.set(filePath, config);
|
|
2232
|
+
}
|
|
2233
|
+
if (config.ktlintConfig)
|
|
2234
|
+
return "ktlint";
|
|
2235
|
+
if (config.ktfmtConfig)
|
|
2236
|
+
return "ktfmt";
|
|
2237
|
+
}
|
|
2238
|
+
catch { }
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
return undefined;
|
|
2242
|
+
}
|
|
2243
|
+
export function hasKtlintConfig(cwd) {
|
|
2244
|
+
return getSpotlessKotlinFormatter(cwd) === "ktlint";
|
|
2245
|
+
}
|
|
1900
2246
|
export function hasKtfmtConfig(cwd) {
|
|
2247
|
+
const spotlessFormatter = getSpotlessKotlinFormatter(cwd);
|
|
2248
|
+
if (spotlessFormatter)
|
|
2249
|
+
return spotlessFormatter === "ktfmt";
|
|
1901
2250
|
for (const dir of walkUpDirs(cwd)) {
|
|
1902
2251
|
if (KTFMT_CONFIG_FILES.some((cfg) => fs.existsSync(path.join(dir, cfg))))
|
|
1903
2252
|
return true;
|