@herbertgao/pi-extensions 2026.9.6 → 2026.9.8
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 +3 -8
- package/THIRD_PARTY_NOTICES.md +0 -4
- package/node_modules/@narumitw/pi-btw/README.md +2 -0
- package/node_modules/@narumitw/pi-btw/dist/index.ts +284 -365
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +3 -3
- package/node_modules/@narumitw/pi-btw/package.json +52 -53
- package/node_modules/@narumitw/pi-btw/src/bring-to-main.ts +494 -547
- package/node_modules/@narumitw/pi-btw/src/btw.ts +814 -856
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +673 -674
- package/node_modules/@narumitw/pi-btw/src/keybindings.ts +228 -270
- package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +309 -318
- package/node_modules/@narumitw/pi-btw/src/menu.ts +416 -454
- package/node_modules/@narumitw/pi-btw/src/settings.ts +203 -219
- package/node_modules/@narumitw/pi-btw/src/side-thread.ts +173 -201
- package/node_modules/@narumitw/pi-btw/src/text.ts +21 -23
- package/node_modules/@narumitw/pi-btw/src/transcript-markdown.ts +65 -0
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +611 -662
- package/node_modules/grok-mermaid/CHANGELOG.md +46 -0
- package/node_modules/grok-mermaid/LICENSE +205 -0
- package/node_modules/grok-mermaid/README.md +191 -0
- package/node_modules/grok-mermaid/dist/ansi.d.ts +16 -0
- package/node_modules/grok-mermaid/dist/ansi.d.ts.map +1 -0
- package/node_modules/grok-mermaid/dist/ansi.js +23 -0
- package/node_modules/grok-mermaid/dist/ansi.js.map +1 -0
- package/node_modules/grok-mermaid/dist/canvas.d.ts +87 -0
- package/node_modules/grok-mermaid/dist/canvas.d.ts.map +1 -0
- package/node_modules/grok-mermaid/dist/canvas.js +366 -0
- package/node_modules/grok-mermaid/dist/canvas.js.map +1 -0
- package/node_modules/grok-mermaid/dist/graph.d.ts +74 -0
- package/node_modules/grok-mermaid/dist/graph.d.ts.map +1 -0
- package/node_modules/grok-mermaid/dist/graph.js +91 -0
- package/node_modules/grok-mermaid/dist/graph.js.map +1 -0
- package/node_modules/grok-mermaid/dist/index.d.ts +32 -0
- package/node_modules/grok-mermaid/dist/index.d.ts.map +1 -0
- package/node_modules/grok-mermaid/dist/index.js +100 -0
- package/node_modules/grok-mermaid/dist/index.js.map +1 -0
- package/node_modules/grok-mermaid/dist/labels.d.ts +62 -0
- package/node_modules/grok-mermaid/dist/labels.d.ts.map +1 -0
- package/node_modules/grok-mermaid/dist/labels.js +324 -0
- package/node_modules/grok-mermaid/dist/labels.js.map +1 -0
- package/node_modules/grok-mermaid/dist/layout-seq.d.ts +12 -0
- package/node_modules/grok-mermaid/dist/layout-seq.d.ts.map +1 -0
- package/node_modules/grok-mermaid/dist/layout-seq.js +194 -0
- package/node_modules/grok-mermaid/dist/layout-seq.js.map +1 -0
- package/node_modules/grok-mermaid/dist/layout.d.ts +87 -0
- package/node_modules/grok-mermaid/dist/layout.d.ts.map +1 -0
- package/node_modules/grok-mermaid/dist/layout.js +881 -0
- package/node_modules/grok-mermaid/dist/layout.js.map +1 -0
- package/node_modules/grok-mermaid/dist/parse.d.ts +83 -0
- package/node_modules/grok-mermaid/dist/parse.d.ts.map +1 -0
- package/node_modules/grok-mermaid/dist/parse.js +1151 -0
- package/node_modules/grok-mermaid/dist/parse.js.map +1 -0
- package/node_modules/grok-mermaid/dist/source-box.d.ts +18 -0
- package/node_modules/grok-mermaid/dist/source-box.d.ts.map +1 -0
- package/node_modules/grok-mermaid/dist/source-box.js +78 -0
- package/node_modules/grok-mermaid/dist/source-box.js.map +1 -0
- package/node_modules/grok-mermaid/dist/types.d.ts +42 -0
- package/node_modules/grok-mermaid/dist/types.d.ts.map +1 -0
- package/node_modules/grok-mermaid/dist/types.js +1 -0
- package/node_modules/grok-mermaid/dist/types.js.map +1 -0
- package/node_modules/grok-mermaid/dist/width-data.d.ts +2 -0
- package/node_modules/grok-mermaid/dist/width-data.d.ts.map +1 -0
- package/node_modules/grok-mermaid/dist/width-data.js +994 -0
- package/node_modules/grok-mermaid/dist/width-data.js.map +1 -0
- package/node_modules/grok-mermaid/dist/width.d.ts +18 -0
- package/node_modules/grok-mermaid/dist/width.d.ts.map +1 -0
- package/node_modules/grok-mermaid/dist/width.js +76 -0
- package/node_modules/grok-mermaid/dist/width.js.map +1 -0
- package/node_modules/grok-mermaid/package.json +49 -0
- package/node_modules/grok-mermaid/src/ansi.ts +34 -0
- package/node_modules/grok-mermaid/src/canvas.ts +373 -0
- package/node_modules/grok-mermaid/src/graph.ts +142 -0
- package/node_modules/grok-mermaid/src/index.ts +104 -0
- package/node_modules/grok-mermaid/src/labels.ts +326 -0
- package/node_modules/grok-mermaid/src/layout-seq.ts +203 -0
- package/node_modules/grok-mermaid/src/layout.ts +1015 -0
- package/node_modules/grok-mermaid/src/parse.ts +1189 -0
- package/node_modules/grok-mermaid/src/source-box.ts +89 -0
- package/node_modules/grok-mermaid/src/types.ts +43 -0
- package/node_modules/grok-mermaid/src/width-data.ts +993 -0
- package/node_modules/grok-mermaid/src/width.ts +74 -0
- package/node_modules/pi-lens/CHANGELOG.md +239 -0
- package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +3 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +30 -4
- package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +2 -0
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +26 -0
- package/node_modules/pi-lens/dist/clients/biome-client.js +1 -1
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +403 -35
- package/node_modules/pi-lens/dist/clients/bootstrap.js +6 -1
- package/node_modules/pi-lens/dist/clients/cascade-format.js +200 -4
- package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +10 -2
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +16 -1
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +12 -1
- package/node_modules/pi-lens/dist/clients/dispatch/ast-grep-catalog.js +65 -0
- package/node_modules/pi-lens/dist/clients/dispatch/auxiliary-lsp.js +28 -0
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +9 -2
- package/node_modules/pi-lens/dist/clients/dispatch/finding-policy.js +222 -0
- package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +389 -13
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +175 -25
- package/node_modules/pi-lens/dist/clients/dispatch/rule-ignores.js +62 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +21 -41
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +6 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +7 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -12
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +2 -21
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/types.js +4 -1
- package/node_modules/pi-lens/dist/clients/disposition-publish.js +1 -0
- package/node_modules/pi-lens/dist/clients/effective-config.js +1 -1
- package/node_modules/pi-lens/dist/clients/file-kinds.js +26 -1
- package/node_modules/pi-lens/dist/clients/file-role.js +21 -21
- package/node_modules/pi-lens/dist/clients/file-utils.js +156 -10
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +56 -9
- package/node_modules/pi-lens/dist/clients/format-service.js +39 -21
- package/node_modules/pi-lens/dist/clients/formatters.js +60 -13
- package/node_modules/pi-lens/dist/clients/generation-guard.js +2 -2
- package/node_modules/pi-lens/dist/clients/git-guard.js +11 -3
- package/node_modules/pi-lens/dist/clients/indent-retarget.js +78 -8
- package/node_modules/pi-lens/dist/clients/installer/index.js +333 -114
- package/node_modules/pi-lens/dist/clients/instance-reaper-state.js +7 -0
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +20 -10
- package/node_modules/pi-lens/dist/clients/language-profile.js +23 -1
- package/node_modules/pi-lens/dist/clients/language-registry.js +5 -1
- package/node_modules/pi-lens/dist/clients/latency-logger.js +4 -1
- package/node_modules/pi-lens/dist/clients/lens-engine.js +12 -3
- package/node_modules/pi-lens/dist/clients/lens-events.js +2 -1
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +79 -0
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/client.js +25 -21
- package/node_modules/pi-lens/dist/clients/lsp/config.js +2 -2
- package/node_modules/pi-lens/dist/clients/lsp/index.js +7 -0
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +16 -4
- package/node_modules/pi-lens/dist/clients/lsp/server.js +19 -2
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp-mutation.js +5 -3
- package/node_modules/pi-lens/dist/clients/map-with-concurrency.js +12 -8
- package/node_modules/pi-lens/dist/clients/mcp/session.js +36 -4
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +24 -7
- package/node_modules/pi-lens/dist/clients/observed-mutation.js +40 -2
- package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +23 -3
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +110 -15
- package/node_modules/pi-lens/dist/clients/path-utils.js +123 -3
- package/node_modules/pi-lens/dist/clients/performance-report.js +5 -1
- package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +1 -1
- package/node_modules/pi-lens/dist/clients/pipeline.js +74 -5
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +37 -5
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +145 -18
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/dead-code.js +4 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +59 -3
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +45 -2
- package/node_modules/pi-lens/dist/clients/read-guard.js +70 -11
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +147 -9
- package/node_modules/pi-lens/dist/clients/ruff-client.js +1 -1
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +33 -5
- package/node_modules/pi-lens/dist/clients/runtime-context.js +6 -2
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +77 -7
- package/node_modules/pi-lens/dist/clients/runtime-session.js +21 -2
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +43 -12
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +330 -85
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +147 -17
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +258 -5
- package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +6 -0
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +50 -5
- package/node_modules/pi-lens/dist/clients/sg-runner.js +23 -11
- package/node_modules/pi-lens/dist/clients/sgconfig.js +79 -2
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +6 -41
- package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +43 -0
- package/node_modules/pi-lens/dist/clients/tool-agreement.js +423 -0
- package/node_modules/pi-lens/dist/clients/tool-config.js +50 -0
- package/node_modules/pi-lens/dist/clients/tool-cwd.js +47 -76
- package/node_modules/pi-lens/dist/clients/tool-policy.js +163 -7
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +120 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +127 -189
- package/node_modules/pi-lens/dist/clients/widget-state.js +98 -0
- package/node_modules/pi-lens/dist/clients/word-index.js +5 -2
- package/node_modules/pi-lens/dist/clients/write-ordering-guard.js +7 -0
- package/node_modules/pi-lens/dist/index.js +27416 -24153
- package/node_modules/pi-lens/dist/mcp/server.js +5 -2
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +7 -1
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +168 -53
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +244 -72
- package/node_modules/pi-lens/docs/audit1.md +5 -5
- package/node_modules/pi-lens/docs/dependencies.md +11 -0
- package/node_modules/pi-lens/docs/dispositions.md +52 -0
- package/node_modules/pi-lens/docs/environment-variables.md +2 -2
- package/node_modules/pi-lens/docs/features.md +4 -4
- package/node_modules/pi-lens/docs/globalconfig.md +3 -1
- package/node_modules/pi-lens/docs/language-coverage.md +1 -0
- package/node_modules/pi-lens/docs/pi-lens-fixer.md +53 -94
- package/node_modules/pi-lens/docs/pi-lens-investigator.md +43 -38
- package/node_modules/pi-lens/docs/pi-lens-retro.md +97 -0
- package/node_modules/pi-lens/docs/pi-lens-reviewer.md +53 -66
- package/node_modules/pi-lens/docs/release-qa-baseline.md +22 -0
- package/node_modules/pi-lens/docs/settings.md +7 -4
- package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +1 -1
- package/node_modules/pi-lens/docs/usage.md +2 -0
- package/node_modules/pi-lens/package.json +1 -1
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/sql-injection.yml +24 -12
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +40 -0
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +15 -0
- package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +7 -0
- package/package.json +6 -11
- package/node_modules/@luxusai/pi-hindsight/CHANGELOG.md +0 -376
- package/node_modules/@luxusai/pi-hindsight/README.md +0 -92
- package/node_modules/@luxusai/pi-hindsight/docs/adr/001-memory-lifecycle-and-scope.md +0 -56
- package/node_modules/@luxusai/pi-hindsight/docs/adr/002-explicit-routing-strategy-seam.md +0 -169
- package/node_modules/@luxusai/pi-hindsight/docs/adr/003-tui-memory-mode-vocabulary.md +0 -107
- package/node_modules/@luxusai/pi-hindsight/docs/adr/004-lifeos-dual-bank-design.md +0 -89
- package/node_modules/@luxusai/pi-hindsight/docs/adr/005-domain-banks-and-agent-first-surface.md +0 -189
- package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark.webp +0 -0
- package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark@2x.webp +0 -0
- package/node_modules/@luxusai/pi-hindsight/docs/coding-memory-evaluation.md +0 -54
- package/node_modules/@luxusai/pi-hindsight/docs/compatibility.md +0 -75
- package/node_modules/@luxusai/pi-hindsight/docs/hindsight-core-functions.md +0 -300
- package/node_modules/@luxusai/pi-hindsight/docs/mission-and-mental-model-quality.md +0 -158
- package/node_modules/@luxusai/pi-hindsight/docs/next-opt-out-design.md +0 -164
- package/node_modules/@luxusai/pi-hindsight/docs/risky-memory-modes.md +0 -139
- package/node_modules/@luxusai/pi-hindsight/docs/starter-mental-model-suggestions.md +0 -74
- package/node_modules/@luxusai/pi-hindsight/docs/surface-reference.md +0 -261
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-operations.ts +0 -151
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-selection.ts +0 -18
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-settings-presenter.ts +0 -46
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-templates.ts +0 -383
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/banking.ts +0 -240
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/knowledge-page-seed.ts +0 -176
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/retain-strategies.ts +0 -178
- package/node_modules/@luxusai/pi-hindsight/extensions/client/client-retry.ts +0 -41
- package/node_modules/@luxusai/pi-hindsight/extensions/client/client.ts +0 -386
- package/node_modules/@luxusai/pi-hindsight/extensions/client/fetch-compat.ts +0 -39
- package/node_modules/@luxusai/pi-hindsight/extensions/client/timeout.ts +0 -34
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-defaults.ts +0 -140
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-model.ts +0 -61
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-registry.ts +0 -925
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-field-paths.ts +0 -247
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-normalize.ts +0 -547
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-writer.ts +0 -480
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config.ts +0 -182
- package/node_modules/@luxusai/pi-hindsight/extensions/config/setup-gate.ts +0 -86
- package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-execute.ts +0 -1010
- package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-parse.ts +0 -175
- package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-plan.ts +0 -425
- package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-presentation.ts +0 -210
- package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-sessions.ts +0 -817
- package/node_modules/@luxusai/pi-hindsight/extensions/index.ts +0 -25
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/git-seed.ts +0 -319
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-recall.ts +0 -196
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-retain.ts +0 -189
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-runtime.ts +0 -65
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle.ts +0 -260
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/mental-models.ts +0 -244
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/observation-scopes.ts +0 -59
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-cleanup.ts +0 -82
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-visibility.ts +0 -45
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall.ts +0 -331
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-cursor.ts +0 -354
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-job-builder.ts +0 -66
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-receipts.ts +0 -132
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain.ts +0 -228
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-bank-template-operations.ts +0 -74
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-config-operations.ts +0 -16
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-control-operations.ts +0 -648
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-diagnostics-operations.ts +0 -105
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-identity.ts +0 -68
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-service.ts +0 -71
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-types.ts +0 -13
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-recall-operations.ts +0 -162
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-retain-operations.ts +0 -131
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-scope.ts +0 -104
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-session-operations.ts +0 -37
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/operation-catalog.ts +0 -893
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/reflect-presenter.ts +0 -35
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/scope-migrate.ts +0 -177
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/tools.ts +0 -7
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/flush-presenter.ts +0 -21
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/jsonl-queue-store.ts +0 -112
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-delivery.ts +0 -111
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-lock.ts +0 -214
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-operations.ts +0 -70
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue.ts +0 -392
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/bank-template-presentation.ts +0 -45
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/commands.ts +0 -9
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/guided-setup.ts +0 -860
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/prefill-input.ts +0 -105
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-flow.ts +0 -189
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-server-probe.ts +0 -299
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-actions.ts +0 -201
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-facts.ts +0 -47
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-render.ts +0 -239
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-types.ts +0 -50
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui.ts +0 -259
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/tool-presenters.ts +0 -77
- package/node_modules/@luxusai/pi-hindsight/extensions/types.ts +0 -534
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/diagnostics.ts +0 -319
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/messages.ts +0 -325
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/sanitize.ts +0 -42
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-memory-meta.ts +0 -244
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-operations.ts +0 -56
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/session.ts +0 -50
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-fields.ts +0 -167
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-health.ts +0 -207
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/status.ts +0 -120
- package/node_modules/@luxusai/pi-hindsight/extensions/version.ts +0 -8
- package/node_modules/@luxusai/pi-hindsight/package.json +0 -118
- package/node_modules/@luxusai/pi-hindsight/skills/hindsight-memory-doctor/SKILL.md +0 -75
|
@@ -10,8 +10,13 @@ import { getProjectIgnoreMatcher, isExcludedDirName, } from "../clients/file-uti
|
|
|
10
10
|
import { getLSPService, groupFilesByPrimaryServer, runPerServerGroups, } from "../clients/lsp/index.js";
|
|
11
11
|
import { buildScopeKey, createWorkspaceDiagnosticsCacheContext, } from "../clients/lsp/workspace-diagnostics-cache.js";
|
|
12
12
|
import { getServersForFileWithConfig, primaryServerId, } from "../clients/lsp/config.js";
|
|
13
|
+
import { mapWithConcurrency } from "../clients/map-with-concurrency.js";
|
|
13
14
|
import { combineAbortSignals, withDeadline, } from "../clients/deadline-utils.js";
|
|
14
15
|
import { applyAuxiliarySuppressions, retagAuxiliaryDiagnostics, } from "../clients/dispatch/auxiliary-lsp.js";
|
|
16
|
+
import { applyLspFindingPolicy, loadProjectRulePolicyMap, } from "../clients/dispatch/finding-policy.js";
|
|
17
|
+
import { hasStrictDispositionMarks } from "../clients/diagnostic-dispositions.js";
|
|
18
|
+
import { recordDegradationOnce } from "../clients/degradation-ledger.js";
|
|
19
|
+
import { logLatency } from "../clients/latency-logger.js";
|
|
15
20
|
import { detectFileRole } from "../clients/file-role.js";
|
|
16
21
|
import { hashDiagnosticContent, touchCompletedConfirmationPolicy, touchCoverageGap, } from "../clients/lsp/diagnostic-binding.js";
|
|
17
22
|
import { classifyCascadeWaitTier } from "../clients/lsp/wait-policy/index.js";
|
|
@@ -100,46 +105,6 @@ function boundedPositiveInt(value, fallback, min, max) {
|
|
|
100
105
|
* for THIS tool's batch/directory sweep the same way #667 fixed it for the
|
|
101
106
|
* workspace-diagnostics sweep.
|
|
102
107
|
*/
|
|
103
|
-
async function mapWithConcurrency(items, concurrency, mapper, lspService, signal, onProgress) {
|
|
104
|
-
const results = [];
|
|
105
|
-
let completed = 0;
|
|
106
|
-
// Multiple original indices can map to the same file path (duplicate
|
|
107
|
-
// entries in an explicit `paths` batch) — track them as a per-file queue
|
|
108
|
-
// so each occurrence still lands in its own original slot.
|
|
109
|
-
const pendingIndices = new Map();
|
|
110
|
-
items.forEach((item, index) => {
|
|
111
|
-
const queue = pendingIndices.get(item);
|
|
112
|
-
if (queue)
|
|
113
|
-
queue.push(index);
|
|
114
|
-
else
|
|
115
|
-
pendingIndices.set(item, [index]);
|
|
116
|
-
});
|
|
117
|
-
const groups = groupFilesByPrimaryServer(items);
|
|
118
|
-
await runPerServerGroups(groups, concurrency, async (group) => {
|
|
119
|
-
if (signal?.aborted)
|
|
120
|
-
return;
|
|
121
|
-
const first = group.files[0];
|
|
122
|
-
if (first &&
|
|
123
|
-
lspService &&
|
|
124
|
-
!isWarmAttached() &&
|
|
125
|
-
typeof lspService.ensureWarmForSweep === "function") {
|
|
126
|
-
await lspService.ensureWarmForSweep(first, { signal });
|
|
127
|
-
if (signal?.aborted)
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
for (const item of group.files) {
|
|
131
|
-
// Honor cancellation (Escape / turn abort): stop pulling new items
|
|
132
|
-
// rather than grind the whole batch. Completed entries are returned.
|
|
133
|
-
if (signal?.aborted)
|
|
134
|
-
return;
|
|
135
|
-
const index = pendingIndices.get(item).shift();
|
|
136
|
-
results[index] = await mapper(item, index);
|
|
137
|
-
completed += 1;
|
|
138
|
-
onProgress?.(completed, items.length);
|
|
139
|
-
}
|
|
140
|
-
}, signal);
|
|
141
|
-
return results;
|
|
142
|
-
}
|
|
143
108
|
/**
|
|
144
109
|
* Project-ignore predicate rooted at `root`, fail-open. Lets a directory scan
|
|
145
110
|
* honor the user's `.pi-lens.json` / `.gitignore` patterns — not just the
|
|
@@ -331,7 +296,17 @@ onConfirmedNoBlockers, getService = getLSPService) {
|
|
|
331
296
|
},
|
|
332
297
|
};
|
|
333
298
|
}
|
|
334
|
-
async function collectDiagnosticsForFile(absPath, lspService,
|
|
299
|
+
async function collectDiagnosticsForFile(absPath, lspService,
|
|
300
|
+
/**
|
|
301
|
+
* #3041: project root the per-rule `ignores` globs (#965) are resolved
|
|
302
|
+
* against. ast-grep's LSP publishes per-document diagnostics without
|
|
303
|
+
* applying them, so this standalone `source=lsp` query has to — the same
|
|
304
|
+
* carve-out the NAPI runner applies on the same file. Positioned before the
|
|
305
|
+
* optional parameters so it is structurally REQUIRED: an optional
|
|
306
|
+
* `string | undefined` would silently disable the carve-out for whichever
|
|
307
|
+
* caller forgot to pass it.
|
|
308
|
+
*/
|
|
309
|
+
scanRoot, waitMs, serverScope = "all") {
|
|
335
310
|
let timedOut = false;
|
|
336
311
|
let content;
|
|
337
312
|
// `touchFile` is the authoritative collection boundary for every scope: it
|
|
@@ -360,7 +335,11 @@ async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScop
|
|
|
360
335
|
const scopedDiagnostics = serverScope === "primary"
|
|
361
336
|
? attached.response.diagnostics.filter((item) => item.serverId === primaryServerId(absPath))
|
|
362
337
|
: attached.response.diagnostics;
|
|
363
|
-
const filtered = applyAuxiliarySuppressions(scopedDiagnostics, content, {
|
|
338
|
+
const filtered = applyAuxiliarySuppressions(scopedDiagnostics, content, {
|
|
339
|
+
fileRole: detectFileRole(absPath, content),
|
|
340
|
+
filePath: absPath,
|
|
341
|
+
scanRoot,
|
|
342
|
+
});
|
|
364
343
|
return {
|
|
365
344
|
diagnostics: filtered,
|
|
366
345
|
timedOut: false,
|
|
@@ -420,6 +399,8 @@ async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScop
|
|
|
420
399
|
const filtered = content !== undefined
|
|
421
400
|
? applyAuxiliarySuppressions(diagnostics, content, {
|
|
422
401
|
fileRole: detectFileRole(absPath, content),
|
|
402
|
+
filePath: absPath,
|
|
403
|
+
scanRoot,
|
|
423
404
|
})
|
|
424
405
|
: diagnostics;
|
|
425
406
|
// #1095: surface the touch's content binding (only a touch that resolved
|
|
@@ -588,6 +569,97 @@ function demoteInferredForFile(file, diagnostics, cwd, lspService) {
|
|
|
588
569
|
service: lspService,
|
|
589
570
|
});
|
|
590
571
|
}
|
|
572
|
+
/**
|
|
573
|
+
* #3088: the probe lane's stored-disposition / rule-policy / inline-suppression
|
|
574
|
+
* gate — the same `clients/dispatch/finding-policy.ts` stack `mode=full` and
|
|
575
|
+
* the per-edit dispatcher apply, called once per file at the position
|
|
576
|
+
* `demoteInferredForFile` already established: AFTER the confirmation verdict
|
|
577
|
+
* (which asks "did the server answer for this content" and must not be
|
|
578
|
+
* influenced by a policy drop) and BEFORE the rendered output, the severity
|
|
579
|
+
* filter and `reconcileWidgetFromLspResult`. One filtered set for all three, so
|
|
580
|
+
* the text, the counts and the widget footer cannot disagree — and so the
|
|
581
|
+
* footer reconcile can no longer re-arm a finding the mark-time
|
|
582
|
+
* `reconcileWidgetDisposition` demoted.
|
|
583
|
+
*
|
|
584
|
+
* Fails OPEN: a filter that throws returns the unfiltered set plus one bounded
|
|
585
|
+
* degradation record. A finding that stays visible is recoverable; one silently
|
|
586
|
+
* hidden by a broken filter is the harm this lane exists to prevent
|
|
587
|
+
* (AGENTS.md shape 48).
|
|
588
|
+
*/
|
|
589
|
+
function applyProbeFindingPolicy(file, diagnostics, cwd, content,
|
|
590
|
+
/**
|
|
591
|
+
* Round 2 F1: the caller's severity threshold. The count reported to the
|
|
592
|
+
* agent must be scoped to the SAME threshold the rendered result is, or a
|
|
593
|
+
* `severity: "error"` probe of a repo carrying warning-level marks prints
|
|
594
|
+
* "suppressed by disposition: N … Not a clean verdict" on a result that IS
|
|
595
|
+
* clean at that threshold — the skill's own folder-check recipe would emit
|
|
596
|
+
* the banner on every check. The threshold is applied HERE, in the tool that
|
|
597
|
+
* owns both the render and the record, rather than in the three call sites
|
|
598
|
+
* (three copies of one subtraction) or in
|
|
599
|
+
* `clients/dispatch/finding-policy.ts`, which must stay threshold-free: its
|
|
600
|
+
* other caller (`mode=full`) has no severity axis at all.
|
|
601
|
+
*/
|
|
602
|
+
severity) {
|
|
603
|
+
const started = Date.now();
|
|
604
|
+
try {
|
|
605
|
+
const result = applyLspFindingPolicy(diagnostics, {
|
|
606
|
+
cwd,
|
|
607
|
+
filePath: file,
|
|
608
|
+
content,
|
|
609
|
+
policyMap: loadProjectRulePolicyMap(cwd),
|
|
610
|
+
fileRole: detectFileRole(file, content),
|
|
611
|
+
});
|
|
612
|
+
const inScopeBefore = applySeverityFilter(diagnostics, severity).length;
|
|
613
|
+
const suppressed = inScopeBefore - applySeverityFilter(result.kept, severity).length;
|
|
614
|
+
if (suppressed > 0) {
|
|
615
|
+
// One record per FILE that actually dropped something the caller would
|
|
616
|
+
// otherwise have SEEN, never one per finding (AGENTS.md "bounded
|
|
617
|
+
// observability"). `total` is the in-scope population for the same
|
|
618
|
+
// reason the count is, so the record and the rendered line agree.
|
|
619
|
+
logLatency({
|
|
620
|
+
type: "phase",
|
|
621
|
+
toolName: "lsp_diagnostics",
|
|
622
|
+
filePath: file,
|
|
623
|
+
phase: "lsp_probe_disposition_filter",
|
|
624
|
+
durationMs: Date.now() - started,
|
|
625
|
+
metadata: {
|
|
626
|
+
suppressed,
|
|
627
|
+
total: inScopeBefore,
|
|
628
|
+
},
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
return { kept: result.kept, inlineKept: result.inlineKept, suppressed };
|
|
632
|
+
}
|
|
633
|
+
catch (err) {
|
|
634
|
+
recordDegradationOnce({
|
|
635
|
+
kind: "lsp-probe-finding-policy",
|
|
636
|
+
subject: cwd,
|
|
637
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
638
|
+
});
|
|
639
|
+
return { kept: diagnostics, inlineKept: diagnostics, suppressed: 0 };
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* #3088 AC5/AC7: the content a cache REPLAY needs to evaluate STRICT
|
|
644
|
+
* (`false-positive`) disposition anchors, which hash the finding's own line.
|
|
645
|
+
* A cache hit means the file is unchanged since the entry was recorded, so this
|
|
646
|
+
* is the same content the recording touch read — but it is a disk read the
|
|
647
|
+
* replay path exists to avoid, so it is paid ONLY when the store actually holds
|
|
648
|
+
* a strict mark. With no marks (the overwhelmingly common case) the probe path
|
|
649
|
+
* adds zero I/O and the weak-anchored marks apply without content at all.
|
|
650
|
+
*/
|
|
651
|
+
function replayContentForStrictMarks(file, cwd) {
|
|
652
|
+
if (!hasStrictDispositionMarks(cwd))
|
|
653
|
+
return undefined;
|
|
654
|
+
try {
|
|
655
|
+
return fs.readFileSync(file, "utf-8");
|
|
656
|
+
}
|
|
657
|
+
catch {
|
|
658
|
+
// Fail open — an unreadable file degrades to the weak-anchored filter
|
|
659
|
+
// rather than hiding or dropping anything.
|
|
660
|
+
return undefined;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
591
663
|
function reconcileWidgetFromLspResult(file, rawDiags, confirmation, writeIndex, cwd, content,
|
|
592
664
|
// #1095: true when the result's content binding demonstrably mismatches disk
|
|
593
665
|
// (boundToCurrentDisk === false). Such a result — even a NON-EMPTY one, which
|
|
@@ -670,7 +742,13 @@ onConfirmedNoBlockers) {
|
|
|
670
742
|
// fresh touch does, so it gets the same demotion. Without this, replaying
|
|
671
743
|
// yesterday's cached blocker would re-cement an orphan file as blocking
|
|
672
744
|
// after mode=full had demoted it.
|
|
673
|
-
const
|
|
745
|
+
const demotedCached = await demoteInferredForFile(file, cached.diagnostics, cwd, lspService);
|
|
746
|
+
// #3088 AC5: a replay is served to the agent exactly like a fresh
|
|
747
|
+
// observation, so it passes the same filter. The cached set is already
|
|
748
|
+
// inline-suppression-clean (the record below stores `inlineKept`), so
|
|
749
|
+
// only the revocable store/config filters run here.
|
|
750
|
+
const cachedPolicy = applyProbeFindingPolicy(file, demotedCached, cwd, replayContentForStrictMarks(file, cwd), severity);
|
|
751
|
+
const cachedDiags = cachedPolicy.kept;
|
|
674
752
|
const filteredDiags = applySeverityFilter(cachedDiags, severity);
|
|
675
753
|
// #692: cached.diagnostics were already suppression-/skipTestFiles-
|
|
676
754
|
// filtered at write time (this same code path); no file content was
|
|
@@ -691,10 +769,13 @@ onConfirmedNoBlockers) {
|
|
|
691
769
|
diagnostics: diagnosticsToFileDiags(file, filteredDiags),
|
|
692
770
|
confirmation,
|
|
693
771
|
primaryServerId: primaryServerId(file),
|
|
772
|
+
...(cachedPolicy.suppressed > 0 && {
|
|
773
|
+
dispositionSuppressed: cachedPolicy.suppressed,
|
|
774
|
+
}),
|
|
694
775
|
};
|
|
695
776
|
}
|
|
696
777
|
}
|
|
697
|
-
const { diagnostics: rawDiags, timedOut, confirmedByTouch, unconfirmedServerIds, diagnosticsUnsupportedServerIds, content: collectedContent, binding, skipReason, } = await collectDiagnosticsForFile(file, lspService, waitMs, serverScope);
|
|
778
|
+
const { diagnostics: rawDiags, timedOut, confirmedByTouch, unconfirmedServerIds, diagnosticsUnsupportedServerIds, content: collectedContent, binding, skipReason, } = await collectDiagnosticsForFile(file, lspService, cwd, waitMs, serverScope);
|
|
698
779
|
const health = lspService.getDiagnosticsHealth?.(file);
|
|
699
780
|
// #570: a timed-out priming check is never a confirmed "clean" — treat it
|
|
700
781
|
// as unconfirmed without consulting the (unrelated) silent-tier
|
|
@@ -753,6 +834,9 @@ onConfirmedNoBlockers) {
|
|
|
753
834
|
}
|
|
754
835
|
// #1645 review F3: one demotion rule for every writer of the widget store.
|
|
755
836
|
effectiveRawDiags = await demoteInferredForFile(file, effectiveRawDiags, cwd, lspService);
|
|
837
|
+
// #3088: one filter for the output, the counts and the footer reconcile.
|
|
838
|
+
const policy = applyProbeFindingPolicy(file, effectiveRawDiags, cwd, collectedContent, severity);
|
|
839
|
+
effectiveRawDiags = policy.kept;
|
|
756
840
|
const filteredDiags = applySeverityFilter(effectiveRawDiags, severity);
|
|
757
841
|
const verdict = reconcileWidgetFromLspResult(file, effectiveRawDiags, confirmation, writeIndex, cwd, collectedContent, boundMismatch);
|
|
758
842
|
if (verdict.confirmed && !verdict.blocking) {
|
|
@@ -775,7 +859,14 @@ onConfirmedNoBlockers) {
|
|
|
775
859
|
confirmation !== "unconfirmed" &&
|
|
776
860
|
diagnosticsUnsupportedServerIds.length === 0 &&
|
|
777
861
|
unconfirmedServerIds.length === 0) {
|
|
778
|
-
|
|
862
|
+
// #3088: the entry records the INLINE-suppressed set, never the
|
|
863
|
+
// disposition/rule-policy-filtered one. An inline `pi-lens-ignore` comment
|
|
864
|
+
// cannot change without invalidating this content-keyed entry, so baking it
|
|
865
|
+
// in is safe and makes every later replay consistent with a fresh probe; a
|
|
866
|
+
// disposition mark or a `.pi-lens.json` rule can be revoked at any moment,
|
|
867
|
+
// so caching THEIR effect would keep a finding hidden after its mark was
|
|
868
|
+
// removed. The replay branch above re-applies those two on every serve.
|
|
869
|
+
cacheCtx.record(file, scopeKey, policy.inlineKept, stat.mtimeMs, collectedContent !== undefined
|
|
779
870
|
? hashDiagnosticContent(collectedContent)
|
|
780
871
|
: undefined, stat.size);
|
|
781
872
|
}
|
|
@@ -788,6 +879,9 @@ onConfirmedNoBlockers) {
|
|
|
788
879
|
...(skipReason !== undefined && { skipReason }),
|
|
789
880
|
primaryServerId: primaryServerId(file),
|
|
790
881
|
diagnosticsUnsupported: diagnosticsUnsupportedServerIds.length > 0,
|
|
882
|
+
...(policy.suppressed > 0 && {
|
|
883
|
+
dispositionSuppressed: policy.suppressed,
|
|
884
|
+
}),
|
|
791
885
|
};
|
|
792
886
|
}
|
|
793
887
|
async function runFileDiagnostics(absPath, severity, lspService, waitMs, nextWriteIndex, serverScope = "all", cwd = process.cwd(),
|
|
@@ -797,7 +891,7 @@ onConfirmedNoBlockers) {
|
|
|
797
891
|
// Reserve the token before awaiting this file's LSP result. The direct-file
|
|
798
892
|
// path performs its own confirmation/reconciliation below (#1198).
|
|
799
893
|
const writeIndex = nextWriteIndex?.();
|
|
800
|
-
const { diagnostics: rawDiags, timedOut, confirmedByTouch, unconfirmedServerIds, diagnosticsUnsupportedServerIds, content: collectedContent, binding, skipReason, } = await collectDiagnosticsForFile(absPath, lspService, waitMs, serverScope);
|
|
894
|
+
const { diagnostics: rawDiags, timedOut, confirmedByTouch, unconfirmedServerIds, diagnosticsUnsupportedServerIds, content: collectedContent, binding, skipReason, } = await collectDiagnosticsForFile(absPath, lspService, cwd, waitMs, serverScope);
|
|
801
895
|
const lspHealth = lspService.getDiagnosticsHealth?.(absPath);
|
|
802
896
|
const unavailable = lspUnavailableMessage(absPath, lspHealth);
|
|
803
897
|
// #533: an empty result needs a confirmed/unconfirmed verdict — a push-only,
|
|
@@ -857,6 +951,9 @@ onConfirmedNoBlockers) {
|
|
|
857
951
|
confirmation = "unconfirmed";
|
|
858
952
|
// #1645 review F3: one demotion rule for every writer of the widget store.
|
|
859
953
|
effectiveRawDiags = await demoteInferredForFile(absPath, effectiveRawDiags, cwd, lspService);
|
|
954
|
+
// #3088: one filter for the output, the counts and the footer reconcile.
|
|
955
|
+
const policy = applyProbeFindingPolicy(absPath, effectiveRawDiags, cwd, collectedContent, severity);
|
|
956
|
+
effectiveRawDiags = policy.kept;
|
|
860
957
|
const filtered = applySeverityFilter(effectiveRawDiags, severity);
|
|
861
958
|
const total = filtered.length;
|
|
862
959
|
const truncated = total > MAX_DIAGNOSTICS;
|
|
@@ -912,6 +1009,10 @@ onConfirmedNoBlockers) {
|
|
|
912
1009
|
const coverageLine = unconfirmedServerIds.length > 0
|
|
913
1010
|
? `Auxiliary coverage INCOMPLETE — ${[...unconfirmedServerIds].join(", ")} did not answer within the wait budget, so ${unconfirmedServerIds.length === 1 ? "its findings are" : "their findings are"} NOT included here. This is not a clean bill of health for ${unconfirmedServerIds.length === 1 ? "that scanner" : "those scanners"}; re-check after the next edit. waitMs can extend an ordinary wait, but it cannot override a session-demoted scanner.`
|
|
914
1011
|
: undefined;
|
|
1012
|
+
// #3088: the #1616 suppressed-bucket rule on this lane — a policy drop is
|
|
1013
|
+
// stated as a count, never left to read as "nothing was wrong here"
|
|
1014
|
+
// (AGENTS.md shape 10). Bounded: one line per call, whatever the count.
|
|
1015
|
+
const suppressedLine = dispositionSuppressedLine(policy.suppressed);
|
|
915
1016
|
let text;
|
|
916
1017
|
if (total === 0) {
|
|
917
1018
|
text = [
|
|
@@ -919,6 +1020,7 @@ onConfirmedNoBlockers) {
|
|
|
919
1020
|
"",
|
|
920
1021
|
unavailable ?? "No auxiliary findings.",
|
|
921
1022
|
...(coverageLine ? [coverageLine] : []),
|
|
1023
|
+
...(suppressedLine ? [suppressedLine] : []),
|
|
922
1024
|
].join("\n");
|
|
923
1025
|
}
|
|
924
1026
|
else {
|
|
@@ -932,6 +1034,8 @@ onConfirmedNoBlockers) {
|
|
|
932
1034
|
}
|
|
933
1035
|
if (coverageLine)
|
|
934
1036
|
lines.push("", coverageLine);
|
|
1037
|
+
if (suppressedLine)
|
|
1038
|
+
lines.push("", suppressedLine);
|
|
935
1039
|
if (unavailable)
|
|
936
1040
|
lines.unshift(unavailable, "");
|
|
937
1041
|
if (truncated) {
|
|
@@ -958,6 +1062,9 @@ onConfirmedNoBlockers) {
|
|
|
958
1062
|
code: d.code,
|
|
959
1063
|
})),
|
|
960
1064
|
totalDiagnostics: total,
|
|
1065
|
+
...(policy.suppressed > 0 && {
|
|
1066
|
+
dispositionSuppressed: policy.suppressed,
|
|
1067
|
+
}),
|
|
961
1068
|
truncated,
|
|
962
1069
|
unconfirmed,
|
|
963
1070
|
timedOut: unconfirmed ? timedOut : undefined,
|
|
@@ -1083,32 +1190,67 @@ async function collectBatchDiagnostics(files, severity, lspService, options) {
|
|
|
1083
1190
|
const resolvedCwd = options.cwd ?? process.cwd();
|
|
1084
1191
|
const cacheCtx = createWorkspaceDiagnosticsCacheContext(resolvedCwd);
|
|
1085
1192
|
const scopeKey = buildScopeKey(options.serverScope ?? "all");
|
|
1086
|
-
const
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1193
|
+
const resultsByIndex = new Map();
|
|
1194
|
+
let completed = 0;
|
|
1195
|
+
const pendingIndices = new Map();
|
|
1196
|
+
files.forEach((file, index) => {
|
|
1197
|
+
const queue = pendingIndices.get(file);
|
|
1198
|
+
if (queue)
|
|
1199
|
+
queue.push(index);
|
|
1200
|
+
else
|
|
1201
|
+
pendingIndices.set(file, [index]);
|
|
1202
|
+
});
|
|
1203
|
+
const groups = groupFilesByPrimaryServer(files);
|
|
1204
|
+
await runPerServerGroups(groups, options.concurrency, async (group) => {
|
|
1205
|
+
if (options.signal?.aborted)
|
|
1206
|
+
return;
|
|
1207
|
+
const first = group.files[0];
|
|
1208
|
+
if (first &&
|
|
1209
|
+
lspService &&
|
|
1210
|
+
!isWarmAttached() &&
|
|
1211
|
+
typeof lspService.ensureWarmForSweep === "function") {
|
|
1212
|
+
await lspService.ensureWarmForSweep(first, {
|
|
1213
|
+
signal: options.signal,
|
|
1214
|
+
});
|
|
1215
|
+
if (options.signal?.aborted)
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
await mapWithConcurrency(group.files, 1, async (file) => {
|
|
1219
|
+
// Keep duplicate explicit paths in their original result slots.
|
|
1220
|
+
const index = pendingIndices.get(file).shift();
|
|
1221
|
+
const work = collectFileDiagnosticResult(file, severity, lspService, options.waitMs, options.nextWriteIndex, options.serverScope, cacheCtx, scopeKey, resolvedCwd, options.onConfirmedNoBlockers);
|
|
1222
|
+
const bounded = withDeadline(work, {
|
|
1223
|
+
ms: batchFileDeadlineMs(),
|
|
1224
|
+
onTimeout: "undefined",
|
|
1225
|
+
onReject: "undefined",
|
|
1226
|
+
});
|
|
1227
|
+
const result = options.signal
|
|
1228
|
+
? await Promise.race([
|
|
1229
|
+
bounded,
|
|
1230
|
+
new Promise((resolve) => {
|
|
1231
|
+
if (options.signal?.aborted) {
|
|
1232
|
+
resolve(undefined);
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
options.signal?.addEventListener("abort", () => resolve(undefined), {
|
|
1236
|
+
once: true,
|
|
1237
|
+
});
|
|
1238
|
+
}),
|
|
1239
|
+
])
|
|
1240
|
+
: await bounded;
|
|
1241
|
+
resultsByIndex.set(index, result ??
|
|
1242
|
+
inconclusiveBatchResult(file, options.signal?.aborted
|
|
1243
|
+
? "Batch aborted before this file completed."
|
|
1244
|
+
: `File check exceeded ${batchFileDeadlineMs()}ms.`));
|
|
1245
|
+
completed += 1;
|
|
1246
|
+
options.onProgress?.(completed, files.length);
|
|
1247
|
+
}, options.signal);
|
|
1248
|
+
}, options.signal);
|
|
1249
|
+
// The retired local pool returned only slots whose mapper had run. Keep that
|
|
1250
|
+
// dense abort contract while restoring the original file order for callers.
|
|
1251
|
+
const results = [...resultsByIndex.entries()]
|
|
1252
|
+
.sort(([left], [right]) => left - right)
|
|
1253
|
+
.map(([, result]) => result);
|
|
1112
1254
|
// Persist whatever was recorded, including a partial/aborted sweep's
|
|
1113
1255
|
// already-completed files — same "don't throw away confirmed work"
|
|
1114
1256
|
// posture as `runWorkspaceDiagnostics`.
|
|
@@ -1167,6 +1309,9 @@ async function runBatchFileDiagnostics(absPaths, severity, lspService, options)
|
|
|
1167
1309
|
}
|
|
1168
1310
|
const { results, fileErrors, lspHealthWarnings, total, truncated, display, primaryDisplay, auxiliaryDisplay, clean, unconfirmed, timedOut, outcomeCounts, incompleteFiles, } = await collectBatchDiagnostics(absPaths, severity, lspService, options);
|
|
1169
1311
|
const navigationOnly = results.filter((result) => result.diagnosticsUnsupported).length;
|
|
1312
|
+
// #3088: the batch's own suppressed bucket — one summed line, never one per
|
|
1313
|
+
// file or per finding.
|
|
1314
|
+
const dispositionSuppressed = results.reduce((sum, result) => sum + (result.dispositionSuppressed ?? 0), 0);
|
|
1170
1315
|
const lines = [
|
|
1171
1316
|
`Files checked: ${results.length}`,
|
|
1172
1317
|
`Total diagnostics: ${total}`,
|
|
@@ -1221,6 +1366,9 @@ async function runBatchFileDiagnostics(absPaths, severity, lspService, options)
|
|
|
1221
1366
|
lines.push("", `... (${total - MAX_DIAGNOSTICS} more diagnostics not shown)`);
|
|
1222
1367
|
}
|
|
1223
1368
|
}
|
|
1369
|
+
const suppressedLine = dispositionSuppressedLine(dispositionSuppressed);
|
|
1370
|
+
if (suppressedLine)
|
|
1371
|
+
lines.push("", suppressedLine);
|
|
1224
1372
|
return {
|
|
1225
1373
|
content: [{ type: "text", text: lines.join("\n") }],
|
|
1226
1374
|
details: {
|
|
@@ -1234,6 +1382,7 @@ async function runBatchFileDiagnostics(absPaths, severity, lspService, options)
|
|
|
1234
1382
|
primaryDiagnosticsCount: primaryDisplay.length,
|
|
1235
1383
|
auxiliaryDiagnosticsCount: auxiliaryDisplay.length,
|
|
1236
1384
|
totalDiagnostics: total,
|
|
1385
|
+
...(dispositionSuppressed > 0 && { dispositionSuppressed }),
|
|
1237
1386
|
truncated,
|
|
1238
1387
|
cleanFiles: clean,
|
|
1239
1388
|
unconfirmedFiles: unconfirmed,
|
|
@@ -1308,6 +1457,9 @@ async function runDirectoryDiagnostics(absPath, severity, lspService, options) {
|
|
|
1308
1457
|
const filesToProcess = collectedFiles.slice(0, MAX_FILES);
|
|
1309
1458
|
const { results, fileErrors, lspHealthWarnings, total, truncated, display, primaryDisplay, auxiliaryDisplay, clean, unconfirmed, timedOut, } = await collectBatchDiagnostics(filesToProcess, severity, lspService, options);
|
|
1310
1459
|
const navigationOnly = results.filter((result) => result.diagnosticsUnsupported).length;
|
|
1460
|
+
// #3088: the directory scan's own suppressed bucket — one summed line.
|
|
1461
|
+
const dispositionSuppressed = results.reduce((sum, result) => sum + (result.dispositionSuppressed ?? 0), 0);
|
|
1462
|
+
const suppressedLine = dispositionSuppressedLine(dispositionSuppressed);
|
|
1311
1463
|
let text;
|
|
1312
1464
|
if (total === 0) {
|
|
1313
1465
|
// #533/#570: an unconfirmed-containing directory result must never
|
|
@@ -1326,6 +1478,7 @@ async function runDirectoryDiagnostics(absPath, severity, lspService, options) {
|
|
|
1326
1478
|
...lspHealthWarnings.slice(0, 10),
|
|
1327
1479
|
]
|
|
1328
1480
|
: [cleanLine]),
|
|
1481
|
+
...(suppressedLine ? ["", suppressedLine] : []),
|
|
1329
1482
|
].join("\n");
|
|
1330
1483
|
}
|
|
1331
1484
|
else {
|
|
@@ -1365,6 +1518,8 @@ async function runDirectoryDiagnostics(absPath, severity, lspService, options) {
|
|
|
1365
1518
|
if (truncated) {
|
|
1366
1519
|
lines.push("", `... (${total - MAX_DIAGNOSTICS} more diagnostics not shown)`);
|
|
1367
1520
|
}
|
|
1521
|
+
if (suppressedLine)
|
|
1522
|
+
lines.push("", suppressedLine);
|
|
1368
1523
|
text = lines.join("\n");
|
|
1369
1524
|
}
|
|
1370
1525
|
return {
|
|
@@ -1388,6 +1543,7 @@ async function runDirectoryDiagnostics(absPath, severity, lspService, options) {
|
|
|
1388
1543
|
primaryDiagnosticsCount: primaryDisplay.length,
|
|
1389
1544
|
auxiliaryDiagnosticsCount: auxiliaryDisplay.length,
|
|
1390
1545
|
totalDiagnostics: total,
|
|
1546
|
+
...(dispositionSuppressed > 0 && { dispositionSuppressed }),
|
|
1391
1547
|
truncated,
|
|
1392
1548
|
cleanFiles: clean,
|
|
1393
1549
|
unconfirmedFiles: unconfirmed,
|
|
@@ -1401,6 +1557,22 @@ async function runDirectoryDiagnostics(absPath, severity, lspService, options) {
|
|
|
1401
1557
|
};
|
|
1402
1558
|
}
|
|
1403
1559
|
// ── helpers ─────────────────────────────────────────────────────────────
|
|
1560
|
+
/**
|
|
1561
|
+
* #3088: the one rendering of the probe lane's policy drop, shared by the
|
|
1562
|
+
* single-file, batch and directory renders so the three cannot word the same
|
|
1563
|
+
* fact differently. Returns `undefined` when nothing was dropped — the #1616
|
|
1564
|
+
* rule asks for a count when there IS one, not a "0 suppressed" line on every
|
|
1565
|
+
* clean probe.
|
|
1566
|
+
*/
|
|
1567
|
+
function dispositionSuppressedLine(suppressed) {
|
|
1568
|
+
if (suppressed <= 0)
|
|
1569
|
+
return undefined;
|
|
1570
|
+
return (`suppressed by disposition: ${suppressed} finding(s) dropped from this ` +
|
|
1571
|
+
"result because they're marked false-positive/won't-fix, disabled by " +
|
|
1572
|
+
"`.pi-lens.json` rule policy, or suppressed by an inline `pi-lens-ignore` " +
|
|
1573
|
+
"comment. Not a clean verdict for those locations — they were found, " +
|
|
1574
|
+
"then intentionally hidden.");
|
|
1575
|
+
}
|
|
1404
1576
|
function applySeverityFilter(diags, severity) {
|
|
1405
1577
|
if (severity === "all")
|
|
1406
1578
|
return diags;
|
|
@@ -38,16 +38,16 @@ This document records structural inconsistencies and centralization gaps found w
|
|
|
38
38
|
|
|
39
39
|
---
|
|
40
40
|
|
|
41
|
-
### 3. Tree-sitter query loader uses a hand-rolled YAML parser
|
|
41
|
+
### 3. Tree-sitter query loader uses a hand-rolled YAML parser (partially resolved)
|
|
42
42
|
|
|
43
43
|
**Files:**
|
|
44
|
-
- `clients/tree-sitter-query-loader.ts` — `parseYaml()` and `extractMultilineValue()` are
|
|
44
|
+
- `clients/tree-sitter-query-loader.ts` — `parseYaml()` now calls `yaml.load` directly (refs #3054); the hand-rolled scanner and `extractMultilineValue()` are deleted.
|
|
45
45
|
- `clients/dispatch/runners/yaml-rule-parser.ts` — uses `js-yaml` for ast-grep rules
|
|
46
|
-
- `scripts/validate-rule-catalog.mjs` — uses regex to scrape YAML scalars
|
|
46
|
+
- `scripts/validate-rule-catalog.mjs` — still uses regex to scrape YAML scalars (unchanged by #3054; out of that PR's scope)
|
|
47
47
|
|
|
48
|
-
**Impact:**
|
|
48
|
+
**Impact:** `scripts/validate-rule-catalog.mjs` remains its own regex-based reader, so the tree-sitter and ast-grep rule catalogs now share one parser (`js-yaml`) while the validation script is a third, still-divergent implementation.
|
|
49
49
|
|
|
50
|
-
**Recommended fix:**
|
|
50
|
+
**Recommended fix:** Fold `scripts/validate-rule-catalog.mjs`'s scraping onto `js-yaml` too, the same shape #3054 applied to the query loader.
|
|
51
51
|
|
|
52
52
|
---
|
|
53
53
|
|
|
@@ -52,3 +52,14 @@ Auto-install behavior depends on gate type:
|
|
|
52
52
|
| `psscriptanalyzer` | PowerShell linting | Manual | — |
|
|
53
53
|
|
|
54
54
|
Additional language servers (gopls, ruby-lsp, solargraph, etc.) are auto-detected from PATH or installed via native package managers (`go install`, `gem install`) when their language is detected.
|
|
55
|
+
|
|
56
|
+
## Pip tool installation order
|
|
57
|
+
|
|
58
|
+
For pip-backed tools, pi-lens uses this order:
|
|
59
|
+
|
|
60
|
+
1. Use `pipx install` when `pipx` is available.
|
|
61
|
+
2. Create or reuse `<PI_LENS_HOME>/pip-tools` with `python3 -m venv`, then use that venv's `pip`.
|
|
62
|
+
3. Use `pip install --user` when the interpreter accepts a normal user install.
|
|
63
|
+
4. If PEP 668 refuses the user install, use `--user --break-system-packages` only with `PYTHONUSERBASE` set to the pi-lens-private `<PI_LENS_HOME>/pip-user` prefix.
|
|
64
|
+
|
|
65
|
+
Pi-lens never passes `--break-system-packages` to a system prefix. It adds the selected pipx, venv, or private-prefix `bin`/`Scripts` directory to the current process path so the availability probe resolves the installed tool.
|
|
@@ -52,6 +52,58 @@ per-disposition binding strength:
|
|
|
52
52
|
edits to the line and drift elsewhere in the file. (`suppress` is enforced
|
|
53
53
|
by the inline comment anyway; the store entry is an audit mirror.)
|
|
54
54
|
|
|
55
|
+
Both anchors also hash the producing `tool`, so a finding that changes hands
|
|
56
|
+
between tools gets a fresh anchor. One such change shipped in #3041: `mode:
|
|
57
|
+
"full"` used to render auxiliary-scanner findings (ast-grep, opengrep, zizmor,
|
|
58
|
+
typos) under the generic `tool: "lsp"` while every other surface already showed
|
|
59
|
+
them under their real tool id. It now shows the real id everywhere, so a mark
|
|
60
|
+
recorded against the old `lsp`-labelled copy no longer matches and the finding
|
|
61
|
+
gets one fresh chance to be re-marked — under the same `tool` the per-edit path
|
|
62
|
+
has always used.
|
|
63
|
+
|
|
64
|
+
## Which surfaces honor a mark
|
|
65
|
+
|
|
66
|
+
Every model-facing surface that renders a diagnostic applies the same filter
|
|
67
|
+
stack, in the same order: inline `pi-lens-ignore` comments, then the stored
|
|
68
|
+
dispositions, then the project's `.pi-lens.json` `rules.<id>.disable`/`select`
|
|
69
|
+
policy (`clients/dispatch/finding-policy.ts`). That covers the per-edit
|
|
70
|
+
feedback, `lens_diagnostics` `mode=delta`/`mode=all`/`mode=full`, and — since
|
|
71
|
+
#3088 — the `lens_diagnostics` `source=lsp` probe lane together with the legacy
|
|
72
|
+
`lsp_diagnostics` tool and the MCP `pilens_lsp_diagnostics` shim that share it.
|
|
73
|
+
Since #3102 it also covers the two PUSH surfaces that were still unfiltered:
|
|
74
|
+
the turn-end **late-auxiliary advisory** (findings an auxiliary LSP published
|
|
75
|
+
after its grace window, drained at the next `turn_end`) and the **cold-neighbour
|
|
76
|
+
cascade run** (`buildResolvedFoundCascadeRun`, built in the quiet-window
|
|
77
|
+
reconcile). Both are pushed rather than asked for, so when a mark suppresses
|
|
78
|
+
everything they had to say they say nothing at all — silence on a push surface
|
|
79
|
+
is not a claim that the file is clean, and the drop count is recorded in the
|
|
80
|
+
lane's own `late_auxiliary_findings` / `cascade_finding_policy` latency row. A
|
|
81
|
+
delivery that still has something to say states what it dropped inline.
|
|
82
|
+
|
|
83
|
+
Before #3088 the probe lane was the one exception: it returned the raw LSP
|
|
84
|
+
result, so a finding marked `false-positive` stayed hidden in `delta`/`full`
|
|
85
|
+
and re-appeared on every probe — the lane
|
|
86
|
+
`skills/pi-lens-lsp-navigation` steers agents to as PRIMARY. It now filters
|
|
87
|
+
like every other surface, its footer reconcile writes the FILTERED set (so a
|
|
88
|
+
probe can no longer re-arm a finding the mark demoted), and a drop is always
|
|
89
|
+
stated as a count:
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
suppressed by disposition: 1 finding(s) dropped from this result …
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Two properties of the probe lane are worth knowing:
|
|
96
|
+
|
|
97
|
+
- **A mark converges whichever surface you made it from.** The probe renders a
|
|
98
|
+
finding as `[<source>] (<code>)` while the widget footer and `mode=full`
|
|
99
|
+
render the canonical `tool: "lsp"` / `rule: "<source>:<code>"`, and `tool` is
|
|
100
|
+
optional on the mark tool. The probe filter matches every one of those
|
|
101
|
+
spellings, so a mark made from the probe's own output works, and so does one
|
|
102
|
+
made from any other surface.
|
|
103
|
+
- **A blocking finding still needs a strict mark.** `semantic: "blocking"`
|
|
104
|
+
findings are dropped only by a content-bound `false-positive` match, never by
|
|
105
|
+
a weak `suppress`/`defer` — on this lane too (#1625 F1).
|
|
106
|
+
|
|
55
107
|
## Suppression comments
|
|
56
108
|
|
|
57
109
|
`suppress` writes a pi-lens-owned ignore comment on the line immediately
|
|
@@ -47,9 +47,9 @@ review-graph, install-choices, etc.).
|
|
|
47
47
|
|
|
48
48
|
**Default resolution order:**
|
|
49
49
|
|
|
50
|
-
1. `$PILENS_DATA_DIR/<sanitized-cwd-slug>/` (if `PILENS_DATA_DIR` is set)
|
|
50
|
+
1. `$PILENS_DATA_DIR/<sanitized-cwd-slug>-<8-hex-hash>/` (if `PILENS_DATA_DIR` is set)
|
|
51
51
|
2. `<cwd>/.pi-lens/` (legacy — only if it already exists in the project)
|
|
52
|
-
3. `~/.pi-lens/projects/<sanitized-cwd-slug>/` (current default)
|
|
52
|
+
3. `~/.pi-lens/projects/<sanitized-cwd-slug>-<8-hex-hash>/` (current default)
|
|
53
53
|
|
|
54
54
|
**When to set it:** running pi with a local model server (llama.cpp,
|
|
55
55
|
Ollama, etc.) that monitors the project directory — cache-file churn
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
### LSP Support
|
|
4
4
|
|
|
5
|
-
pi-lens includes **
|
|
5
|
+
pi-lens includes **46 language server definitions** (including four cross-cutting *auxiliary* scanners that attach alongside the file's language server — Opengrep, ast-grep, zizmor, and typos — see below). LSP is **enabled by default**; use `--no-lsp` to disable it for a session. Servers are auto-discovered from PATH, project `node_modules`, and managed installs. When a server is not installed, pi-lens offers an interactive install prompt.
|
|
6
6
|
|
|
7
7
|
**LSP Idle Management:** LSP servers shut down after 240 seconds of inactivity (no files modified) to free resources. The timer resets when you resume editing, preventing cold-start penalties during active development.
|
|
8
8
|
|
|
@@ -19,13 +19,13 @@ pi-lens includes **45 language server definitions** (including four cross-cuttin
|
|
|
19
19
|
- **`capabilities`** — shows which operations are supported by the active LSP server(s) for a file, read directly from the cached `initialize` response (no round-trip).
|
|
20
20
|
- **Symbol column resolution** — passing `symbol: "myFunc"` instead of an exact `character` position resolves the correct column automatically. Use `symbol: "foo#2"` for the second occurrence of `foo` on the line.
|
|
21
21
|
|
|
22
|
-
LSP servers for: TypeScript, Deno, Python (pyright/basedpyright + jedi), Go, Rust, Ruby (ruby-lsp + solargraph), PHP, PowerShell, C# (omnisharp), F#, Java (JDT LS, with Lombok javaagent support when a Lombok jar is available), Kotlin, Swift, Dart, Lua, C/C++, Zig, Haskell, Elixir, Gleam, Markdown (marksman), OCaml, Clojure, CUE (syntax and parse diagnostics; evaluation errors via the cue-vet auxiliary runner), Terraform, Nix, Bash, Fish, CMake, Docker, YAML, JSON, HTML, TOML, Prisma, Vue, Svelte, CSS.
|
|
22
|
+
LSP servers for: TypeScript, Deno, Python (pyright/basedpyright + jedi), Go, Rust, Ruby (ruby-lsp + solargraph), PHP, PowerShell, C# (omnisharp), F#, Java (JDT LS, with Lombok javaagent support when a Lombok jar is available), Kotlin, Swift, Dart, Lua, C/C++, Zig, Haskell, Elixir, Gleam, Typst (tinymist), Markdown (marksman), OCaml, Clojure, CUE (syntax and parse diagnostics; evaluation errors via the cue-vet auxiliary runner), Terraform, Nix, Bash, Fish, CMake, Docker, YAML, JSON, HTML, TOML, Prisma, Vue, Svelte, CSS.
|
|
23
23
|
|
|
24
24
|
### Formatters
|
|
25
25
|
|
|
26
|
-
pi-lens auto-detects and runs **
|
|
26
|
+
pi-lens auto-detects and runs **35 formatters** based on project config:
|
|
27
27
|
|
|
28
|
-
biome, prettier, oxfmt, ruff, black, sqlfluff, gofmt, rustfmt, zig fmt, dart format, shfmt, nixfmt, mix format, ocamlformat, clang-format, ktlint, ktfmt, rubocop, standardrb, gleam format, terraform fmt, terragrunt-hcl, php-cs-fixer, csharpier, fantomas, swiftformat, stylua, ormolu, taplo, google-java-format, cljfmt, cmake-format, cue fmt, psscriptanalyzer-format
|
|
28
|
+
biome, prettier, oxfmt, ruff, black, sqlfluff, gofmt, rustfmt, zig fmt, dart format, shfmt, nixfmt, mix format, ocamlformat, clang-format, ktlint, ktfmt, rubocop, standardrb, gleam format, typstyle, terraform fmt, terragrunt-hcl, php-cs-fixer, csharpier, fantomas, swiftformat, stylua, ormolu, taplo, google-java-format, cljfmt, cmake-format, cue fmt, psscriptanalyzer-format
|
|
29
29
|
|
|
30
30
|
Detection rules:
|
|
31
31
|
|