@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
|
@@ -81,10 +81,13 @@
|
|
|
81
81
|
* Refs: #585, #313 (the SecurityScanClient de-dupe prerequisite), #1004
|
|
82
82
|
*/
|
|
83
83
|
import * as fs from "node:fs";
|
|
84
|
+
import * as os from "node:os";
|
|
84
85
|
import * as path from "node:path";
|
|
85
86
|
import { applyDispositionsMultiFile } from "../diagnostic-dispositions.js";
|
|
86
87
|
import { getKnipIgnorePatterns } from "../file-utils.js";
|
|
87
|
-
import { isAtOrAboveHomeDir } from "../path-utils.js";
|
|
88
|
+
import { isAtOrAboveHomeDir, realpathOrResolve } from "../path-utils.js";
|
|
89
|
+
import { isSameOrWithin } from "../lsp/server.js";
|
|
90
|
+
import { incrementDegradationCount } from "../degradation-ledger.js";
|
|
88
91
|
import { GitleaksClient } from "../gitleaks-client.js";
|
|
89
92
|
import { GovulncheckClient } from "../govulncheck-client.js";
|
|
90
93
|
import { isToolInstallAllowedByTrust, projectTrustDenialReason, } from "../project-trust.js";
|
|
@@ -134,7 +137,48 @@ function pushUnique(list, id) {
|
|
|
134
137
|
* spawns).
|
|
135
138
|
*/
|
|
136
139
|
export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, signal, options = {}) {
|
|
137
|
-
const
|
|
140
|
+
const requestedRoot = options.analysisRoot === undefined
|
|
141
|
+
? cwd
|
|
142
|
+
: path.resolve(cwd, options.analysisRoot);
|
|
143
|
+
let analysisRoot;
|
|
144
|
+
let analysisRootValidation;
|
|
145
|
+
if (options.analysisRoot !== undefined) {
|
|
146
|
+
try {
|
|
147
|
+
if (!fs.statSync(requestedRoot).isDirectory()) {
|
|
148
|
+
throw new Error("is not a directory");
|
|
149
|
+
}
|
|
150
|
+
analysisRoot = fs.realpathSync(requestedRoot);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
154
|
+
const reason = `the explicit analysis root ${requestedRoot} is unavailable or ${detail}`;
|
|
155
|
+
analysisRootValidation = {
|
|
156
|
+
state: "undecided",
|
|
157
|
+
root: requestedRoot,
|
|
158
|
+
reason,
|
|
159
|
+
};
|
|
160
|
+
incrementDegradationCount({
|
|
161
|
+
kind: "lens-diagnostics-analysis-root-rejected",
|
|
162
|
+
subject: requestedRoot,
|
|
163
|
+
reason,
|
|
164
|
+
});
|
|
165
|
+
return {
|
|
166
|
+
analysisRootValidation,
|
|
167
|
+
diagnostics: [],
|
|
168
|
+
runners: [],
|
|
169
|
+
analyzed: [],
|
|
170
|
+
authoritativeCoverage: [],
|
|
171
|
+
cold: [...ANALYZER_IDS],
|
|
172
|
+
coldReasons: Object.fromEntries(ANALYZER_IDS.map((id) => [id, reason])),
|
|
173
|
+
failed: [],
|
|
174
|
+
timings: {},
|
|
175
|
+
analysisRootError: reason,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
analysisRoot = realpathOrResolve(cwd);
|
|
181
|
+
}
|
|
138
182
|
// #747: refuse to spawn any heavyweight analyzer when the analysis root is
|
|
139
183
|
// at — or above — the home directory (the #250/#253 escape class). Every
|
|
140
184
|
// analyzer here treats `analysisRoot` as a whole tree to walk; from $HOME
|
|
@@ -144,26 +188,58 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
144
188
|
// / review-graph's buildOrUpdateGraph; like the latter, there is no safe
|
|
145
189
|
// substitute root to fall back to — the caller's `paths` scope only filters
|
|
146
190
|
// REPORTED results, it never narrows what these analyzers walk.
|
|
147
|
-
const unsafeRootReason = "the
|
|
148
|
-
|
|
191
|
+
const unsafeRootReason = "the analysis root resolves at or above the home directory; heavyweight analyzers refuse to walk from there (#747)";
|
|
192
|
+
const homeRoot = realpathOrResolve(options.homeDir ?? os.homedir());
|
|
193
|
+
if (options.analysisRoot !== undefined) {
|
|
194
|
+
const unsafeExplicitRoot = !isSameOrWithin(homeRoot, analysisRoot) ||
|
|
195
|
+
isSameOrWithin(analysisRoot, homeRoot);
|
|
196
|
+
analysisRootValidation = unsafeExplicitRoot
|
|
197
|
+
? {
|
|
198
|
+
state: "unsafe",
|
|
199
|
+
root: analysisRoot,
|
|
200
|
+
reason: "explicit analysis root must be strictly contained by the canonical home directory",
|
|
201
|
+
}
|
|
202
|
+
: { state: "safe", root: analysisRoot };
|
|
203
|
+
}
|
|
204
|
+
else if (isAtOrAboveHomeDir(analysisRoot, options.homeDir)) {
|
|
205
|
+
analysisRootValidation = {
|
|
206
|
+
state: "unsafe",
|
|
207
|
+
root: analysisRoot,
|
|
208
|
+
reason: unsafeRootReason,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
analysisRootValidation = { state: "safe", root: analysisRoot };
|
|
213
|
+
}
|
|
214
|
+
if (analysisRootValidation.state !== "safe") {
|
|
215
|
+
incrementDegradationCount({
|
|
216
|
+
kind: "lens-diagnostics-analysis-root-rejected",
|
|
217
|
+
subject: analysisRoot,
|
|
218
|
+
reason: analysisRootValidation.reason,
|
|
219
|
+
});
|
|
149
220
|
return {
|
|
221
|
+
analysisRootValidation,
|
|
150
222
|
diagnostics: [],
|
|
151
223
|
runners: [],
|
|
152
224
|
analyzed: [],
|
|
225
|
+
authoritativeCoverage: [],
|
|
153
226
|
cold: [...ANALYZER_IDS],
|
|
154
227
|
coldReasons: Object.fromEntries(ANALYZER_IDS.map((id) => [id, unsafeRootReason])),
|
|
155
228
|
failed: [],
|
|
156
229
|
timings: {},
|
|
157
|
-
unsafeRoot:
|
|
230
|
+
unsafeRoot: analysisRootValidation.state === "unsafe",
|
|
158
231
|
};
|
|
159
232
|
}
|
|
160
233
|
const diagnostics = [];
|
|
161
234
|
const runners = [];
|
|
162
235
|
const analyzed = [];
|
|
236
|
+
const authoritativeCoverage = [];
|
|
163
237
|
const cold = [];
|
|
164
238
|
// #1623: the specific reason each `cold` id was skipped, captured at the
|
|
165
239
|
// gate that decided it — see FreshProjectDiagnosticsResult.coldReasons.
|
|
166
240
|
const coldReasons = {};
|
|
241
|
+
const partial = [];
|
|
242
|
+
const partialReasons = {};
|
|
167
243
|
const failed = [];
|
|
168
244
|
const timings = {};
|
|
169
245
|
// #1623: ms-old each id's data was when this call read it, for lanes that
|
|
@@ -190,6 +266,10 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
190
266
|
pushUnique(cold, id);
|
|
191
267
|
coldReasons[id] = reason;
|
|
192
268
|
}
|
|
269
|
+
function markPartial(id, reason) {
|
|
270
|
+
pushUnique(partial, id);
|
|
271
|
+
partialReasons[id] = reason;
|
|
272
|
+
}
|
|
193
273
|
/**
|
|
194
274
|
* `analysedRoot` is the client's own opt-in `AnalysedRootSignal` (#2154),
|
|
195
275
|
* never a property of reaching this function: `success: true` is also what
|
|
@@ -198,9 +278,21 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
198
278
|
* id that did not analyse the root simply carries no authority to retire a
|
|
199
279
|
* retained finding.
|
|
200
280
|
*/
|
|
201
|
-
function record(id, adapted, elapsedMs, analysedRoot) {
|
|
202
|
-
if (analysedRoot)
|
|
281
|
+
function record(id, adapted, elapsedMs, analysedRoot, analysis) {
|
|
282
|
+
if (analysedRoot) {
|
|
203
283
|
pushUnique(analyzed, id);
|
|
284
|
+
if (analysis?.analyzedFiles !== undefined &&
|
|
285
|
+
analysis.analyzedFiles.length > 0) {
|
|
286
|
+
const root = realpathOrResolve(analysisRoot);
|
|
287
|
+
authoritativeCoverage.push({
|
|
288
|
+
runnerId: id,
|
|
289
|
+
root,
|
|
290
|
+
files: new Set(analysis.analyzedFiles.map((file) => {
|
|
291
|
+
return realpathOrResolve(file);
|
|
292
|
+
})),
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
204
296
|
timings[id] = (timings[id] ?? 0) + elapsedMs;
|
|
205
297
|
const kept = applyDispositionsMultiFile(adapted, analysisRoot, (d) => d.filePath);
|
|
206
298
|
const suppressedHere = adapted.length - kept.length;
|
|
@@ -217,6 +309,9 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
217
309
|
function recordFailed(id, result) {
|
|
218
310
|
failed.push({
|
|
219
311
|
id,
|
|
312
|
+
...("reason" in result && result.reason !== undefined
|
|
313
|
+
? { reason: result.reason }
|
|
314
|
+
: {}),
|
|
220
315
|
summary: "summary" in result && typeof result.summary === "string"
|
|
221
316
|
? result.summary
|
|
222
317
|
: "analyzer reported an unsuccessful run",
|
|
@@ -245,7 +340,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
245
340
|
cacheManager.writeCache("knip", result, analysisRoot, {
|
|
246
341
|
scanDurationMs: Date.now() - startMs,
|
|
247
342
|
});
|
|
248
|
-
record("knip", knipIssuesToProjectDiagnostics(analysisRoot, result.issues ?? []), Date.now() - startMs, true);
|
|
343
|
+
record("knip", knipIssuesToProjectDiagnostics(analysisRoot, result.issues ?? []), Date.now() - startMs, true, result);
|
|
249
344
|
}),
|
|
250
345
|
// jscpd — duplicate code detection. Cache key varies with TS-project
|
|
251
346
|
// detection, exactly mirroring session_start's own logic.
|
|
@@ -269,7 +364,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
269
364
|
cacheManager.writeCache(scannerKey, result, analysisRoot, {
|
|
270
365
|
scanDurationMs: Date.now() - startMs,
|
|
271
366
|
});
|
|
272
|
-
record("jscpd", jscpdResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, true);
|
|
367
|
+
record("jscpd", jscpdResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, true, result);
|
|
273
368
|
}),
|
|
274
369
|
// madge — circular-dependency detection.
|
|
275
370
|
task("madge", async () => {
|
|
@@ -282,7 +377,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
282
377
|
cacheManager.writeCache("madge", result, analysisRoot, {
|
|
283
378
|
scanDurationMs: Date.now() - startMs,
|
|
284
379
|
});
|
|
285
|
-
record("madge", circularDepsToProjectDiagnostics(analysisRoot, result.circular ?? []), Date.now() - startMs, result.analyzed === true);
|
|
380
|
+
record("madge", circularDepsToProjectDiagnostics(analysisRoot, result.circular ?? []), Date.now() - startMs, result.analyzed === true, result);
|
|
286
381
|
}),
|
|
287
382
|
// gitleaks — committed-secrets detection. session_start/per-edit stay
|
|
288
383
|
// config-gated per #130's strict default (GitleaksClient.hasGitleaksSignal),
|
|
@@ -313,7 +408,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
313
408
|
cacheManager.writeCache("gitleaks", result, analysisRoot, {
|
|
314
409
|
scanDurationMs: Date.now() - startMs,
|
|
315
410
|
});
|
|
316
|
-
record("gitleaks", gitleaksResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, result.analyzed === true);
|
|
411
|
+
record("gitleaks", gitleaksResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, result.analyzed === true, result);
|
|
317
412
|
}),
|
|
318
413
|
// govulncheck — Go module CVE detection. Go-module-gated per #132.
|
|
319
414
|
task("govulncheck", async () => {
|
|
@@ -345,7 +440,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
345
440
|
cacheManager.writeCache("govulncheck", result, analysisRoot, {
|
|
346
441
|
scanDurationMs: Date.now() - startMs,
|
|
347
442
|
});
|
|
348
|
-
record("govulncheck", govulncheckResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, result.analyzed === true);
|
|
443
|
+
record("govulncheck", govulncheckResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, result.analyzed === true, result);
|
|
349
444
|
}),
|
|
350
445
|
// opengrep — full-workspace semgrep-grade security/quality findings via a
|
|
351
446
|
// single project-wide CLI scan (#584). Structurally always-on: mirrors
|
|
@@ -372,10 +467,31 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
372
467
|
recordFailed("opengrep", result);
|
|
373
468
|
return;
|
|
374
469
|
}
|
|
470
|
+
if (result.analyzed !== true) {
|
|
471
|
+
// A usable partial report with no scanned paths carries findings but
|
|
472
|
+
// no retirement authority. Keep those findings visible and mark the
|
|
473
|
+
// producer partial so the renderer does not call it cold/not-run.
|
|
474
|
+
const reason = result.summary ??
|
|
475
|
+
result.reason ??
|
|
476
|
+
"opengrep did not analyse this root";
|
|
477
|
+
if (result.partial)
|
|
478
|
+
markPartial("opengrep", reason);
|
|
479
|
+
else
|
|
480
|
+
markCold("opengrep", reason);
|
|
481
|
+
record("opengrep", opengrepResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, false, result);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
if (result.partial) {
|
|
485
|
+
markPartial("opengrep", result.summary ??
|
|
486
|
+
result.reason ??
|
|
487
|
+
"opengrep scan coverage is incomplete");
|
|
488
|
+
record("opengrep", opengrepResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, true, result);
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
375
491
|
cacheManager.writeCache("opengrep", result, analysisRoot, {
|
|
376
492
|
scanDurationMs: Date.now() - startMs,
|
|
377
493
|
});
|
|
378
|
-
record("opengrep", opengrepResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, result.analyzed === true);
|
|
494
|
+
record("opengrep", opengrepResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, result.analyzed === true, result);
|
|
379
495
|
}),
|
|
380
496
|
// trivy — dependency CVE detection. Explicit opt-in per #131.
|
|
381
497
|
task("trivy", async () => {
|
|
@@ -396,7 +512,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
396
512
|
cacheManager.writeCache("trivy", result, analysisRoot, {
|
|
397
513
|
scanDurationMs: Date.now() - startMs,
|
|
398
514
|
});
|
|
399
|
-
record("trivy", trivyResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, result.analyzed === true);
|
|
515
|
+
record("trivy", trivyResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, result.analyzed === true, result);
|
|
400
516
|
}),
|
|
401
517
|
// dead-code — cross-file dead-code for non-JS/TS languages (#127).
|
|
402
518
|
// Each client self-gates via detect(); only matching-language projects
|
|
@@ -415,10 +531,13 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
415
531
|
recordFailed("dead-code", result);
|
|
416
532
|
return;
|
|
417
533
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
534
|
+
if (result.analyzed === true) {
|
|
535
|
+
cacheManager.writeCache(cacheKey, result, analysisRoot, {
|
|
536
|
+
scanDurationMs: Date.now() - startMs,
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
const adapted = deadCodeResultToProjectDiagnostics(analysisRoot, result);
|
|
540
|
+
record("dead-code", adapted, Date.now() - startMs, result.analyzed === true, result);
|
|
422
541
|
}));
|
|
423
542
|
}),
|
|
424
543
|
// test-runner — CACHE-READ only, unlike every task above (#1004). Its
|
|
@@ -494,11 +613,15 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
494
613
|
for (const id of abortedIds)
|
|
495
614
|
pushUnique(cold, id);
|
|
496
615
|
return {
|
|
616
|
+
analysisRootValidation,
|
|
497
617
|
diagnostics,
|
|
498
618
|
runners,
|
|
499
619
|
analyzed,
|
|
620
|
+
authoritativeCoverage,
|
|
500
621
|
cold,
|
|
501
622
|
coldReasons,
|
|
623
|
+
partial,
|
|
624
|
+
partialReasons,
|
|
502
625
|
failed,
|
|
503
626
|
timings,
|
|
504
627
|
cachedAgeMs,
|
|
@@ -509,11 +632,15 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
509
632
|
};
|
|
510
633
|
}
|
|
511
634
|
return {
|
|
635
|
+
analysisRootValidation,
|
|
512
636
|
diagnostics,
|
|
513
637
|
runners,
|
|
514
638
|
analyzed,
|
|
639
|
+
authoritativeCoverage,
|
|
515
640
|
cold,
|
|
516
641
|
coldReasons,
|
|
642
|
+
partial,
|
|
643
|
+
partialReasons,
|
|
517
644
|
failed,
|
|
518
645
|
timings,
|
|
519
646
|
cachedAgeMs,
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
+
function deadCodeRunnerId(language) {
|
|
3
|
+
return `dead-code-${language}`;
|
|
4
|
+
}
|
|
2
5
|
function deadCodeMessage(issue) {
|
|
3
6
|
if (issue.category === "unlisted")
|
|
4
7
|
return `Unlisted dependency ${issue.name}`;
|
|
@@ -25,7 +28,7 @@ export function deadCodeIssueToProjectDiagnostic(cwd, issue, language) {
|
|
|
25
28
|
severity: blocking ? "error" : "warning",
|
|
26
29
|
semantic: blocking ? "blocking" : "warning",
|
|
27
30
|
tool: "dead-code",
|
|
28
|
-
runner:
|
|
31
|
+
runner: deadCodeRunnerId(language),
|
|
29
32
|
rule: `dead-code:${issue.category}`,
|
|
30
33
|
message: deadCodeMessage(issue),
|
|
31
34
|
source: "project-scan",
|
|
@@ -16,6 +16,7 @@ import { logTreeSitter, logTreeSitterCacheStats, } from "../tree-sitter-logger.j
|
|
|
16
16
|
import { queriesForLanguage, queryLoader, } from "../tree-sitter-query-loader.js";
|
|
17
17
|
import { EXT_TO_LANG, getSharedTreeSitterClient, isTreeSitterWasmAborted, } from "../tree-sitter-shared.js";
|
|
18
18
|
import { PROJECT_DIAGNOSTICS_CACHE_VERSION, saveProjectDiagnosticsSnapshot, } from "./cache.js";
|
|
19
|
+
import { hashDiagnosticContent } from "../lsp/diagnostic-binding.js";
|
|
19
20
|
// Side-effect import: registers fact providers and fact rules.
|
|
20
21
|
import "../dispatch/integration.js";
|
|
21
22
|
// Skip files this large: matches the per-edit ast-grep runner's guard so a single
|
|
@@ -111,6 +112,7 @@ async function scanFileMajorRules(cwd, files, signal) {
|
|
|
111
112
|
const treeSitter = [];
|
|
112
113
|
const factRules = [];
|
|
113
114
|
const astGrep = [];
|
|
115
|
+
const fingerprints = {};
|
|
114
116
|
const sgModule = await loadSg();
|
|
115
117
|
let phaseOneFilesScanned = 0;
|
|
116
118
|
let astGrepFilesScanned = 0;
|
|
@@ -238,13 +240,34 @@ async function scanFileMajorRules(cwd, files, signal) {
|
|
|
238
240
|
continue;
|
|
239
241
|
if (langId || factEligible)
|
|
240
242
|
phaseOneFilesScanned++;
|
|
243
|
+
// #2154 (#3060 round 2 F1): read the BYTES once, then decode. The
|
|
244
|
+
// fingerprint below must record the file's ON-DISK length, because
|
|
245
|
+
// that is what the reader compares against `statSync().size`. A
|
|
246
|
+
// length taken from the decoded STRING disagrees for every file
|
|
247
|
+
// holding a byte that is not valid UTF-8 — one such byte decodes to
|
|
248
|
+
// a 3-byte U+FFFD — so the size check could never match and every
|
|
249
|
+
// row from that file was retired on every cached read, for a file
|
|
250
|
+
// nobody touched. That is the DROP direction this store's own
|
|
251
|
+
// reconcile doc calls the worse one. `buf.length` equals
|
|
252
|
+
// `stat.size` for every file; both sides then hash the same lossy
|
|
253
|
+
// decode, so an unchanged file still matches exactly.
|
|
241
254
|
let content;
|
|
255
|
+
let contentBytes;
|
|
242
256
|
try {
|
|
243
|
-
|
|
257
|
+
const buf = fs.readFileSync(filePath);
|
|
258
|
+
contentBytes = buf.length;
|
|
259
|
+
content = buf.toString("utf-8");
|
|
244
260
|
}
|
|
245
261
|
catch {
|
|
246
262
|
content = null;
|
|
263
|
+
contentBytes = undefined;
|
|
247
264
|
}
|
|
265
|
+
// #2154: how many rows existed BEFORE this file was scanned, so the
|
|
266
|
+
// fingerprint below is written only for files that actually produced
|
|
267
|
+
// one — the snapshot keeps no row for any other file, and an entry
|
|
268
|
+
// for a file with no row is dead weight in a record that is read on
|
|
269
|
+
// every `refreshRunners=cached` call.
|
|
270
|
+
const rowsBeforeFile = treeSitter.length + factRules.length + astGrep.length;
|
|
248
271
|
try {
|
|
249
272
|
await scanTreeSitterFile(filePath, langId, content);
|
|
250
273
|
if (isTreeSitterWasmAborted()) {
|
|
@@ -293,6 +316,18 @@ async function scanFileMajorRules(cwd, files, signal) {
|
|
|
293
316
|
...graphIr,
|
|
294
317
|
});
|
|
295
318
|
}
|
|
319
|
+
// #2154: bind this file's rows to the bytes they were computed
|
|
320
|
+
// from. Only reachable with `content` in hand, which is the point
|
|
321
|
+
// — the fingerprint must describe what the rules READ, never what
|
|
322
|
+
// disk holds by the time the scan ends.
|
|
323
|
+
if (content !== null &&
|
|
324
|
+
contentBytes !== undefined &&
|
|
325
|
+
treeSitter.length + factRules.length + astGrep.length > rowsBeforeFile) {
|
|
326
|
+
fingerprints[filePath] = {
|
|
327
|
+
sizeBytes: contentBytes,
|
|
328
|
+
contentHash: hashDiagnosticContent(content),
|
|
329
|
+
};
|
|
330
|
+
}
|
|
296
331
|
filesScanned++;
|
|
297
332
|
}
|
|
298
333
|
finally {
|
|
@@ -312,7 +347,14 @@ async function scanFileMajorRules(cwd, files, signal) {
|
|
|
312
347
|
};
|
|
313
348
|
if (!client) {
|
|
314
349
|
await scan();
|
|
315
|
-
return {
|
|
350
|
+
return {
|
|
351
|
+
treeSitter,
|
|
352
|
+
factRules,
|
|
353
|
+
astGrep,
|
|
354
|
+
filesScanned,
|
|
355
|
+
wasmAborted,
|
|
356
|
+
fingerprints,
|
|
357
|
+
};
|
|
316
358
|
}
|
|
317
359
|
const startedAt = Date.now();
|
|
318
360
|
await client.withParseCacheMeasurement(scan, (stats) => {
|
|
@@ -348,7 +390,14 @@ async function scanFileMajorRules(cwd, files, signal) {
|
|
|
348
390
|
// `astGrepFilesScanned` still feed the `project_diagnostics_scan` record
|
|
349
391
|
// above (`astGrep` sub-field), so this cost stays observable without a
|
|
350
392
|
// second, always-zero record to carry it.
|
|
351
|
-
return {
|
|
393
|
+
return {
|
|
394
|
+
treeSitter,
|
|
395
|
+
factRules,
|
|
396
|
+
astGrep,
|
|
397
|
+
filesScanned,
|
|
398
|
+
wasmAborted,
|
|
399
|
+
fingerprints,
|
|
400
|
+
};
|
|
352
401
|
}
|
|
353
402
|
export async function scanProjectDiagnostics(options) {
|
|
354
403
|
const cwd = path.resolve(options.cwd);
|
|
@@ -395,6 +444,7 @@ export async function scanProjectDiagnostics(options) {
|
|
|
395
444
|
// scan stops promptly when the agent/user aborts (#341).
|
|
396
445
|
const runners = [];
|
|
397
446
|
const diagnostics = [];
|
|
447
|
+
let fileFingerprints = {};
|
|
398
448
|
let wasmAborted = false;
|
|
399
449
|
let filesScanned = files.length;
|
|
400
450
|
if (!signal?.aborted) {
|
|
@@ -409,6 +459,11 @@ export async function scanProjectDiagnostics(options) {
|
|
|
409
459
|
diagnostics.push(...scanned.astGrep);
|
|
410
460
|
runners.push("ast-grep-napi");
|
|
411
461
|
}
|
|
462
|
+
// #2154: keep a fingerprint only for a file that still has a row after
|
|
463
|
+
// the ast-grep discard above, so the record cannot claim to describe a
|
|
464
|
+
// file whose only rows were dropped.
|
|
465
|
+
const rowFiles = new Set(diagnostics.map((d) => d.filePath));
|
|
466
|
+
fileFingerprints = Object.fromEntries(Object.entries(scanned.fingerprints).filter(([file]) => rowFiles.has(file)));
|
|
412
467
|
}
|
|
413
468
|
const snapshot = {
|
|
414
469
|
version: PROJECT_DIAGNOSTICS_CACHE_VERSION,
|
|
@@ -418,6 +473,7 @@ export async function scanProjectDiagnostics(options) {
|
|
|
418
473
|
diagnostics,
|
|
419
474
|
filesScanned,
|
|
420
475
|
runners,
|
|
476
|
+
fileFingerprints,
|
|
421
477
|
};
|
|
422
478
|
// #760: only present when true — keeps existing snapshots/serializations
|
|
423
479
|
// byte-identical for the untruncated (normal) case.
|
|
@@ -63,7 +63,7 @@ import * as os from "node:os";
|
|
|
63
63
|
import * as path from "node:path";
|
|
64
64
|
import { toPositiveFinite } from "./env-utils.js";
|
|
65
65
|
import { FRESHNESS_CADENCE_MS } from "./freshness-cadence.js";
|
|
66
|
-
import { assignFlagConfigSection, flagConfigSectionKeys, GLOBAL_NON_FLAG_CONFIG_SECTIONS, LENS_FLAGS, PROJECT_FOREIGN_CONFIG_NAMESPACES, PROJECT_FOREIGN_NAMESPACE_HONORED_KEYS, PROJECT_NON_FLAG_CONFIG_SECTIONS, PROJECT_SCOPED_LENS_FLAGS, readFlagConfigValue, } from "./lens-flag-registry.js";
|
|
66
|
+
import { assignFlagConfigSection, flagConfigSectionKeys, GLOBAL_NON_FLAG_CONFIG_SECTIONS, GLOBAL_ONLY_NON_FLAG_KEYS, hasFlagConfigPath, LENS_FLAGS, PROJECT_FOREIGN_CONFIG_NAMESPACES, PROJECT_FOREIGN_NAMESPACE_HONORED_KEYS, PROJECT_NON_FLAG_CONFIG_SECTIONS, PROJECT_SCOPED_LENS_FLAGS, readFlagConfigValue, } from "./lens-flag-registry.js";
|
|
67
67
|
import { configSearchDirs, getPiLensGlobalConfigPath, PROJECT_CONFIG_BASENAMES, PROJECT_CONFIG_LOCATIONS, } from "./config-locations.js";
|
|
68
68
|
import { deprecationRecords, ignoredRecordCollector, projectLocationFor, readConfigDocument, reportConfigReadFailure, reportPiLensConfigRecords, resolveOnePiLensConfigDocument, } from "./config-resolve.js";
|
|
69
69
|
import { finalizeRecords, } from "./config-core/records.js";
|
|
@@ -704,6 +704,15 @@ function parseConfigFile(configPath) {
|
|
|
704
704
|
// `lsp.enabled`.
|
|
705
705
|
const projectScoped = new Set(PROJECT_SCOPED_LENS_FLAGS.map((spec) => spec.configKey));
|
|
706
706
|
const globalScopeOnlyFlagKeys = LENS_FLAGS.map((spec) => spec.configKey).filter((configKey) => !projectScoped.has(configKey));
|
|
707
|
+
// Non-flag global-only keys sitting inside an otherwise project-recognized
|
|
708
|
+
// section (#3131) — `actionableWarnings.autoFix.maxFixes` is not a
|
|
709
|
+
// `LENS_FLAGS` entry (no CLI flag, not boolean), so it is invisible to the
|
|
710
|
+
// derivation above. `GLOBAL_ONLY_NON_FLAG_KEYS` is the single place that
|
|
711
|
+
// population is enumerated instead of a second hand-typed list here.
|
|
712
|
+
const globalScopeOnlyDottedKeys = [
|
|
713
|
+
...globalScopeOnlyFlagKeys,
|
|
714
|
+
...GLOBAL_ONLY_NON_FLAG_KEYS,
|
|
715
|
+
];
|
|
707
716
|
// The literal path is derived, not hand-typed (#2426 review round 3, S1):
|
|
708
717
|
// under `PI_LENS_CONFIG_PATH` the canonical global config is NOT
|
|
709
718
|
// `~/.pi-lens/config.json`, and a hardcoded string in this notice would name
|
|
@@ -735,9 +744,43 @@ function parseConfigFile(configPath) {
|
|
|
735
744
|
if (honored.includes(key))
|
|
736
745
|
continue;
|
|
737
746
|
const dotted = `${namespace}.${key}`;
|
|
738
|
-
warnUnhonoredKey(dotted,
|
|
747
|
+
warnUnhonoredKey(dotted, globalScopeOnlyDottedKeys.some((configKey) => configKey === dotted || configKey.startsWith(`${dotted}.`)));
|
|
739
748
|
}
|
|
740
749
|
}
|
|
750
|
+
// MIXED-SCOPE SECTIONS (#3112, #3131). A section can be project-scoped as a
|
|
751
|
+
// whole and still hold a global-only setting: `tools` carries the
|
|
752
|
+
// project-owned per-tool `enabled` leaves AND the global `tools.lazy`
|
|
753
|
+
// (`--no-lazy-tools`), the same split `lsp` has (#2426 review round 2, F3);
|
|
754
|
+
// `actionableWarnings` carries the project-owned `autoFix.enabled` AND the
|
|
755
|
+
// global-only `autoFix.maxFixes`, which is not even a flag (#3131). The
|
|
756
|
+
// top-level scan above sees only the SECTION name, so a global-only setting
|
|
757
|
+
// written inside a recognized project section was dropped with no signal at
|
|
758
|
+
// all — the thing `docs/configuration.md` promises never happens.
|
|
759
|
+
//
|
|
760
|
+
// WHICH sub-keys those are is DERIVED from the registry — `LENS_FLAGS` for
|
|
761
|
+
// flag keys, `GLOBAL_ONLY_NON_FLAG_KEYS` for the rest — never listed here,
|
|
762
|
+
// so there is no second scope table to drift from the first. A key whose
|
|
763
|
+
// SECTION is not recognized at project scope is skipped: the top-level
|
|
764
|
+
// scan already reported that whole section, and a second notice naming the
|
|
765
|
+
// same setting twice under two spellings is the duplicate-notice noise #2426
|
|
766
|
+
// review round 6 removed. Everything else under a recognized section is left
|
|
767
|
+
// to that section's own parser — `readToolConfig` reports an unknown tool
|
|
768
|
+
// name under its own code (`PILENS_CFG_0009`).
|
|
769
|
+
//
|
|
770
|
+
// An enumerated-honored-keys namespace (`lsp`) needs no skip here: the loop
|
|
771
|
+
// above reports the very same dotted key with the very same reason, and
|
|
772
|
+
// `warnIgnoredConfigOnce`'s latch collapses the two into one notice. A skip
|
|
773
|
+
// for it was written and then deleted — mutating it out changed no output.
|
|
774
|
+
for (const configKey of globalScopeOnlyDottedKeys) {
|
|
775
|
+
const dotIndex = configKey.indexOf(".");
|
|
776
|
+
if (dotIndex < 0)
|
|
777
|
+
continue;
|
|
778
|
+
if (!knownProjectKeys.has(configKey.slice(0, dotIndex)))
|
|
779
|
+
continue;
|
|
780
|
+
if (!hasFlagConfigPath(obj, configKey))
|
|
781
|
+
continue;
|
|
782
|
+
warnUnhonoredKey(configKey, true);
|
|
783
|
+
}
|
|
741
784
|
return {
|
|
742
785
|
config: {
|
|
743
786
|
...(toolConfig === undefined ? {} : { tools: toolConfig }),
|