@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
|
@@ -401,7 +401,7 @@ async function fileView(absolute, resolved, homeDir, workspaceCwd, lspConfig) {
|
|
|
401
401
|
resolvedCwd: homeRelativePath(resolveToolCwd("runner", id, absolute, {
|
|
402
402
|
cwd: workspaceCwd,
|
|
403
403
|
suppressTelemetry: true,
|
|
404
|
-
}), homeDir),
|
|
404
|
+
}).cwd, homeDir),
|
|
405
405
|
}));
|
|
406
406
|
return {
|
|
407
407
|
path: homeRelativePath(absolute, homeDir),
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
* Centralized file type detection to avoid duplication across clients.
|
|
5
5
|
* Maps file extensions and paths to semantic file kinds.
|
|
6
6
|
*/
|
|
7
|
-
import { basename, extname } from "node:path";
|
|
7
|
+
import { basename, extname, win32 } from "node:path";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import { isWindowsPath } from "./path-utils.js";
|
|
10
|
+
import { findNearestDirWithMarker } from "./workspace-topology.js";
|
|
8
11
|
// --- Extension Maps ---
|
|
9
12
|
export const KIND_EXTENSIONS = {
|
|
10
13
|
clojure: [".clj", ".cljc", ".cljs", ".edn"],
|
|
@@ -40,6 +43,9 @@ export const KIND_EXTENSIONS = {
|
|
|
40
43
|
".cu",
|
|
41
44
|
// HIP
|
|
42
45
|
".hip",
|
|
46
|
+
// CUDA/HIP header convention; clang's driver table omits `.cuh`, but
|
|
47
|
+
// projects use it for C++ headers that must remain in the cxx kind (#2986).
|
|
48
|
+
".cuh",
|
|
43
49
|
// Objective-C
|
|
44
50
|
".m",
|
|
45
51
|
".mm",
|
|
@@ -179,6 +185,22 @@ export const SPECIAL_FILENAMES = [
|
|
|
179
185
|
})),
|
|
180
186
|
];
|
|
181
187
|
// --- Detection Functions ---
|
|
188
|
+
/**
|
|
189
|
+
* Helm renders YAML-looking files as Go templates before they become YAML.
|
|
190
|
+
* Require the shared chart-root marker before promoting a YAML template, so
|
|
191
|
+
* ordinary repositories can use a `templates/` directory without entering
|
|
192
|
+
* Helm dispatch. `.tpl` remains extension-classified below.
|
|
193
|
+
*/
|
|
194
|
+
export function isHelmYamlTemplatePath(filePath) {
|
|
195
|
+
const templatesSegment = isWindowsPath(filePath)
|
|
196
|
+
? /[\\/]templates[\\/]/i
|
|
197
|
+
: /\/templates\//i;
|
|
198
|
+
if (!templatesSegment.test(filePath) || !/\.ya?ml$/i.test(filePath)) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
const pathApi = isWindowsPath(filePath) ? win32 : path;
|
|
202
|
+
return Boolean(findNearestDirWithMarker(pathApi.dirname(filePath), "chartYamlPath"));
|
|
203
|
+
}
|
|
182
204
|
/**
|
|
183
205
|
* Detect the file kind from a file path.
|
|
184
206
|
* Returns the semantic file kind or undefined if unknown.
|
|
@@ -187,6 +209,9 @@ export function detectFileKind(filePath) {
|
|
|
187
209
|
if (!filePath || typeof filePath !== "string") {
|
|
188
210
|
return undefined;
|
|
189
211
|
}
|
|
212
|
+
if (isHelmYamlTemplatePath(filePath)) {
|
|
213
|
+
return "helm-template";
|
|
214
|
+
}
|
|
190
215
|
// Check special filenames first
|
|
191
216
|
const base = basename(filePath);
|
|
192
217
|
for (const { pattern, kind } of SPECIAL_FILENAMES) {
|
|
@@ -34,6 +34,24 @@ function isTypeStub(content) {
|
|
|
34
34
|
/^export\s+type\s+\{/.test(l));
|
|
35
35
|
return typeOnlyLines.length / lines.length >= 0.75;
|
|
36
36
|
}
|
|
37
|
+
// Shared filename predicate (#2928). The parity test iterates the runner's
|
|
38
|
+
// discovery table; additional conventions are pinned in file-role.test.ts.
|
|
39
|
+
// Keep the case-preserved basename for CamelCase suffixes (contest.java is source).
|
|
40
|
+
function testFileNameMatches(rawBase, base) {
|
|
41
|
+
return (base.includes(".test.") ||
|
|
42
|
+
base.includes(".spec.") ||
|
|
43
|
+
base.includes("_test.") ||
|
|
44
|
+
base.includes("_spec.") ||
|
|
45
|
+
base.startsWith("test_") ||
|
|
46
|
+
base.startsWith("spec_") ||
|
|
47
|
+
/(Test|Tests|TestCase)\.(java|kt|kts|cs|fs|php)$/.test(rawBase));
|
|
48
|
+
}
|
|
49
|
+
/** Filename-only classification for consumers with their own directory policy. */
|
|
50
|
+
export function isTestFileName(filePath) {
|
|
51
|
+
const windowsShaped = isWindowsPath(filePath);
|
|
52
|
+
const rawBase = windowsShaped ? win32.basename(filePath) : basename(filePath);
|
|
53
|
+
return testFileNameMatches(rawBase, rawBase.toLowerCase());
|
|
54
|
+
}
|
|
37
55
|
/**
|
|
38
56
|
* Classify the structural role of a file. Pass `content` for higher
|
|
39
57
|
* accuracy (enables generated-code detection, barrel detection, etc.).
|
|
@@ -57,27 +75,9 @@ export function detectFileRole(filePath, content) {
|
|
|
57
75
|
.replace(/\\/g, "/")
|
|
58
76
|
.toLowerCase();
|
|
59
77
|
// --- Test ---
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// see #2928 for the single-classifier fold:
|
|
64
|
-
// - `_test.` infix: Go (`*_test.go`), pytest (`*_test.py`), ExUnit
|
|
65
|
-
// (`*_test.exs`), Dart (`*_test.dart`). The underscore anchor keeps
|
|
66
|
-
// this precise: `contest.py` and `latest.ts` do not match.
|
|
67
|
-
// - `_spec.` infix: RSpec (`*_spec.rb`).
|
|
68
|
-
// - CamelCase `*Test(s).<ext>` suffix, matched case-SENSITIVELY on the
|
|
69
|
-
// raw basename: JUnit/Surefire (`*Test.java`, `*TestCase.java`),
|
|
70
|
-
// Kotlin (`*Test.kt`), dotnet (`*Test.cs`/`*Tests.cs`), PHPUnit
|
|
71
|
-
// (`*Test.php`). Case matters: Surefire's `*Test.java` does not match
|
|
72
|
-
// `contest.java`, so neither do we.
|
|
73
|
-
if (base.includes(".test.") ||
|
|
74
|
-
base.includes(".spec.") ||
|
|
75
|
-
base.includes("_test.") ||
|
|
76
|
-
base.includes("_spec.") ||
|
|
77
|
-
base.startsWith("test_") ||
|
|
78
|
-
base.startsWith("spec_") ||
|
|
79
|
-
/(Test|Tests|TestCase)\.(java|kt|kts|cs|fs|php)$/.test(rawBase) ||
|
|
80
|
-
dir.includes("/__tests__/") ||
|
|
78
|
+
// #2928: dirname has no trailing slash; match direct __tests__ children too.
|
|
79
|
+
if (testFileNameMatches(rawBase, base) ||
|
|
80
|
+
/(^|[\\/])__tests__([\\/]|$)/.test(dir) ||
|
|
81
81
|
dir.includes("/test/") ||
|
|
82
82
|
dir.includes("/tests/") ||
|
|
83
83
|
dir.includes("/spec/") ||
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
* Shared file path utilities for pi-lens
|
|
3
3
|
*/
|
|
4
4
|
import * as fs from "node:fs";
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
5
6
|
import * as os from "node:os";
|
|
6
7
|
import * as path from "node:path";
|
|
7
8
|
import { Minimatch } from "./deps/minimatch.js";
|
|
9
|
+
import { detectFileRole } from "./file-role.js";
|
|
8
10
|
import { FRESHNESS_CADENCE_MS } from "./freshness-cadence.js";
|
|
9
11
|
import { isInSpawnTimeoutCooldown, noteSpawnTimeout, } from "./spawn-timeout-cooldown.js";
|
|
10
12
|
import { collectTrackedFiles, getTrackedFilesSnapshot, } from "./git-tracked-ignore.js";
|
|
@@ -22,7 +24,7 @@ import { safeSpawnAsync } from "./safe-spawn.js";
|
|
|
22
24
|
* Override: set PILENS_DATA_DIR=/some/path — each project gets its own
|
|
23
25
|
* subdirectory named after a sanitized form of its absolute path, e.g.
|
|
24
26
|
* PILENS_DATA_DIR=~/.pi-lens/projects
|
|
25
|
-
* → ~/.pi-lens/projects/home-user-myapp
|
|
27
|
+
* → ~/.pi-lens/projects/home-user-myapp-<8-hex-hash>/
|
|
26
28
|
*
|
|
27
29
|
* This keeps project folders clean and avoids creating .pi-lens folders
|
|
28
30
|
* inside user projects.
|
|
@@ -34,14 +36,150 @@ export function getProjectDataDir(cwd) {
|
|
|
34
36
|
return legacyProjectDir;
|
|
35
37
|
}
|
|
36
38
|
const base = configuredBase || path.join(getGlobalPiLensDir(), "projects");
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
+
const resolvedBase = base.trim();
|
|
40
|
+
const memoKey = `${resolvedBase}\0${path.resolve(cwd)}`;
|
|
41
|
+
const cached = settledDataDirs.get(memoKey);
|
|
42
|
+
if (cached !== undefined)
|
|
43
|
+
return cached;
|
|
44
|
+
const canonical = canonicalProjectRoot(cwd);
|
|
45
|
+
const readable = projectDataDirReadableSlug(canonical.root);
|
|
46
|
+
const hash = projectDataDirRootHash(canonical.root);
|
|
47
|
+
const slug = `${readable || "default"}-${hash}`;
|
|
48
|
+
const dir = path.join(resolvedBase, slug);
|
|
49
|
+
const settled = settleProjectDataDir(resolvedBase, readable || "default", dir, memoKey, canonical.fallback);
|
|
50
|
+
return settled;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The human-readable half of the project data-dir slug: the absolute root
|
|
54
|
+
* with separators folded to dashes and anything else stripped.
|
|
55
|
+
*
|
|
56
|
+
* #2874: this form ALONE is not an identity — `src/pi-lens` and
|
|
57
|
+
* `src/pi/lens` fold to the same string. It is only ever combined with
|
|
58
|
+
* {@link projectDataDirRootHash}. Never use it as a directory name alone.
|
|
59
|
+
*/
|
|
60
|
+
function projectDataDirReadableSlug(canonicalRoot) {
|
|
61
|
+
const normalized = normalizeFilePath(canonicalRoot);
|
|
62
|
+
return normalized
|
|
39
63
|
.replace(/^[a-z]:/i, "") // strip Windows drive letter
|
|
40
64
|
.replace(/\/+/g, "-") // separators → dashes
|
|
41
65
|
.replace(/[^A-Za-z0-9-]/g, "") // strip anything else
|
|
42
66
|
.replace(/^-+/, "") // trim leading dashes
|
|
43
67
|
.replace(/-+$/, ""); // trim trailing dashes
|
|
44
|
-
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The canonical root is the resolved absolute path for both slug halves.
|
|
71
|
+
* `realpathSync` is probed only to expose a fallback boundary failure; using
|
|
72
|
+
* its result would let one root spelling change identity when the boundary
|
|
73
|
+
* recovers. The hash is the first 8 hex chars of SHA-256 over that root. A
|
|
74
|
+
* collision needs the same readable slug and the same 32-bit prefix, so the
|
|
75
|
+
* practical collision population is readable-slug twin pairs. Pinned on
|
|
76
|
+
* purpose because changing it renames every directory.
|
|
77
|
+
*/
|
|
78
|
+
function canonicalProjectRoot(cwd) {
|
|
79
|
+
const resolved = path.resolve(cwd);
|
|
80
|
+
try {
|
|
81
|
+
// Probe the root, but keep the resolved spelling as the identity in both
|
|
82
|
+
// success and fallback cases. Resolving only on success would let a
|
|
83
|
+
// transient boundary failure choose a second data directory.
|
|
84
|
+
fs.realpathSync(resolved);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// Best-effort: the root may not exist yet.
|
|
88
|
+
return { root: resolved, fallback: true };
|
|
89
|
+
}
|
|
90
|
+
return { root: resolved, fallback: false };
|
|
91
|
+
}
|
|
92
|
+
function projectDataDirRootHash(canonicalRoot) {
|
|
93
|
+
return createHash("sha256").update(canonicalRoot).digest("hex").slice(0, 8);
|
|
94
|
+
}
|
|
95
|
+
const pendingDataDirMigrations = [];
|
|
96
|
+
const settledDataDirs = new Map();
|
|
97
|
+
export function resetProjectDataDirSessionState() {
|
|
98
|
+
pendingDataDirMigrations.splice(0);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* One-time upgrade from a pre-#2874 slug directory to its hashed name.
|
|
102
|
+
* When the old directory exists and the new one does not, the state moves
|
|
103
|
+
* with one atomic `renameSync` (same parent, so same filesystem). When both
|
|
104
|
+
* exist the new one wins and nothing moves. Either case queues one
|
|
105
|
+
* {@link ProjectDataDirMigration} for the session-start drain, which emits
|
|
106
|
+
* the `data_dir_migrated` record. Best-effort throughout: on any failure the
|
|
107
|
+
* caller gets the pre-existing directory and behavior is unchanged.
|
|
108
|
+
*
|
|
109
|
+
* No ledger import here on purpose: `probe-home-state.ts` documents that a
|
|
110
|
+
* direct edge between this module and `degradation-ledger.ts` in either
|
|
111
|
+
* direction adds `no-client-cycles` violations, so the record is emitted by
|
|
112
|
+
* the drain site in `runtime-session.ts` instead.
|
|
113
|
+
*/
|
|
114
|
+
function settleProjectDataDir(base, oldSlug, dir, memoKey, identityFallback) {
|
|
115
|
+
const oldDir = path.join(base, oldSlug);
|
|
116
|
+
const newExists = fs.existsSync(dir);
|
|
117
|
+
const oldExists = fs.existsSync(oldDir);
|
|
118
|
+
if (!oldExists) {
|
|
119
|
+
if (identityFallback && pendingDataDirMigrations.length < 32) {
|
|
120
|
+
pendingDataDirMigrations.push({
|
|
121
|
+
to: dir,
|
|
122
|
+
outcome: "identity-fallback",
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
// Steady state: nothing to migrate from.
|
|
126
|
+
settledDataDirs.set(memoKey, dir);
|
|
127
|
+
return dir;
|
|
128
|
+
}
|
|
129
|
+
if (!newExists) {
|
|
130
|
+
try {
|
|
131
|
+
fs.renameSync(oldDir, dir);
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
if (error.code === "ENOENT") {
|
|
135
|
+
if (fs.existsSync(dir)) {
|
|
136
|
+
settledDataDirs.set(memoKey, dir);
|
|
137
|
+
return dir;
|
|
138
|
+
}
|
|
139
|
+
if (fs.existsSync(oldDir))
|
|
140
|
+
return oldDir;
|
|
141
|
+
return dir;
|
|
142
|
+
}
|
|
143
|
+
// Best-effort: retain the old directory and publish one bounded
|
|
144
|
+
// failure notice for this process's memo key.
|
|
145
|
+
if (pendingDataDirMigrations.length < 32) {
|
|
146
|
+
pendingDataDirMigrations.push({
|
|
147
|
+
to: dir,
|
|
148
|
+
outcome: "rename-failed",
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
settledDataDirs.set(memoKey, oldDir);
|
|
152
|
+
return oldDir;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Either the rename just moved the state, or both directories already
|
|
156
|
+
// existed and the new one wins. Queue one migration for the drain.
|
|
157
|
+
settledDataDirs.set(memoKey, dir);
|
|
158
|
+
if (pendingDataDirMigrations.length < 32) {
|
|
159
|
+
pendingDataDirMigrations.push({
|
|
160
|
+
to: dir,
|
|
161
|
+
outcome: newExists ? "coexisting" : "renamed",
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
return dir;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Drain the queued {@link ProjectDataDirMigration}s, clearing the queue.
|
|
168
|
+
* Called once per session start by `handleSessionStart`; each queued outcome is
|
|
169
|
+
* therefore recorded at most once per session. Test-only callers must not rely
|
|
170
|
+
* on queue depth across drains.
|
|
171
|
+
*/
|
|
172
|
+
export function drainProjectDataDirMigrations() {
|
|
173
|
+
return pendingDataDirMigrations.splice(0);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Test-only reset for the settled-directory memo. The memo is a pure
|
|
177
|
+
* performance cache (one `existsSync` pair saved per latched directory), so
|
|
178
|
+
* clearing it changes no observable behavior — it lets a test stage an
|
|
179
|
+
* old-slug directory AFTER learning the new name, then resolve again.
|
|
180
|
+
*/
|
|
181
|
+
export function _resetProjectDataDirMemoForTests() {
|
|
182
|
+
settledDataDirs.clear();
|
|
45
183
|
}
|
|
46
184
|
/**
|
|
47
185
|
* The project-data path to SHOW an agent or a human, for a file that
|
|
@@ -167,6 +305,14 @@ export const EXCLUDED_DIRS = [
|
|
|
167
305
|
".next",
|
|
168
306
|
".pi-lens",
|
|
169
307
|
".pi", // pi agent directory
|
|
308
|
+
// The SAME agent, rebranded: pi derives its config-dir name as
|
|
309
|
+
// `pkg.piConfig?.configDir || ".pi"` (pi-coding-agent 0.85.1,
|
|
310
|
+
// `dist/bundle/chunks/chunk-JVUZSMYM.js`), so a redistribution spells its
|
|
311
|
+
// `<configDir>/agent/sessions` history `.omp/agent/sessions` instead.
|
|
312
|
+
// #3112: a project-local one was walked entry-by-entry and spent the whole
|
|
313
|
+
// startup-scan entry budget, so a five-file project reported
|
|
314
|
+
// `too-many-entries` and never warmed its caches.
|
|
315
|
+
".omp",
|
|
170
316
|
".ruff_cache", // Python linter cache
|
|
171
317
|
".worktrees",
|
|
172
318
|
".claude",
|
|
@@ -871,15 +1017,15 @@ export async function detectFileChangedAfterCommand(filePath, command, args, cwd
|
|
|
871
1017
|
* Check if file path is a test/fixture/mock file.
|
|
872
1018
|
* Used by secrets scanner, rate command, and dispatch runners
|
|
873
1019
|
* to skip these files (false positives on fake credentials, etc).
|
|
1020
|
+
*
|
|
1021
|
+
* Delegate naming/directory classification to file-role (#2928). Fixtures,
|
|
1022
|
+
* mocks and test helpers remain this skip gate's separate policy.
|
|
874
1023
|
*/
|
|
875
1024
|
export function isTestFile(filePath) {
|
|
1025
|
+
if (detectFileRole(filePath) === "test")
|
|
1026
|
+
return true;
|
|
876
1027
|
const normalized = filePath.replace(/\\/g, "/");
|
|
877
|
-
return (normalized.includes("
|
|
878
|
-
normalized.includes(".spec.") ||
|
|
879
|
-
normalized.includes("/test/") ||
|
|
880
|
-
normalized.includes("/tests/") ||
|
|
881
|
-
normalized.includes("__tests__/") ||
|
|
882
|
-
normalized.includes("test-utils") ||
|
|
1028
|
+
return (normalized.includes("test-utils") ||
|
|
883
1029
|
normalized.startsWith("test-") ||
|
|
884
1030
|
normalized.includes(".fixture.") ||
|
|
885
1031
|
normalized.includes(".mock."));
|
|
@@ -270,8 +270,17 @@ export const DELIVERY_SURFACES = {
|
|
|
270
270
|
// drifting edit already re-touched the file — a fresh pending pair
|
|
271
271
|
// supersedes this one), with both drop arms counted in the
|
|
272
272
|
// `late_auxiliary_findings` latency record rather than silenced.
|
|
273
|
+
//
|
|
274
|
+
// #3102: freshness is only half the gate. The survivors also take the shared
|
|
275
|
+
// `clients/dispatch/finding-policy.ts` stack (inline `pi-lens-ignore` →
|
|
276
|
+
// stored dispositions → `.pi-lens.json` rule policy) the per-edit dispatcher,
|
|
277
|
+
// `mode=full` and the `source=lsp` probe lane apply — without it a finding
|
|
278
|
+
// the agent marked `false-positive` re-reported on every drain. Per #3088
|
|
279
|
+
// round-2 F4, the evidence is the CALL TEXT of that filter, which exists
|
|
280
|
+
// nowhere else in this file: a bare `applyFindingPolicy` would also be
|
|
281
|
+
// satisfied by an import line or an unrelated caller.
|
|
273
282
|
"runtime-turn:late-auxiliary-findings": gated(RUNTIME_TURN_FILE, "Turn-end late-auxiliary LSP findings (collect-later probe of aux " +
|
|
274
|
-
"client caches whose grace window expired).", ["gateFindingsByPathFreshness"], ['store: "late-auxiliary-findings"']),
|
|
283
|
+
"client caches whose grace window expired).", ["gateFindingsByPathFreshness", "applyFindingPolicy"], ['store: "late-auxiliary-findings"', "applyFindingPolicy(gate.live, {"]),
|
|
275
284
|
"runtime-turn:late-runner-findings": gated(RUNTIME_TURN_FILE, "Turn-end CLI runner findings collected after the post-write path.", ["gateFindingsByPathFreshness"], ['store: "late-runner-findings"'], { evidenceMin: 2 }),
|
|
276
285
|
"runtime-turn:cascade-blocker": labeled(RUNTIME_TURN_FILE, "Turn-end 🧪 cascade neighbor blocker.", "Cascade results settle synchronously this turn where possible " +
|
|
277
286
|
"(`settleCascadeRuns`), but an unsettled compute can carry over to a " +
|
|
@@ -289,6 +298,37 @@ export const DELIVERY_SURFACES = {
|
|
|
289
298
|
status: "partial",
|
|
290
299
|
partialReason: "Same cascade carry-over caveat as runtime-turn:cascade-blocker.",
|
|
291
300
|
}),
|
|
301
|
+
// #3102: the cold-neighbour cascade run is BUILT here, in the quiet-window
|
|
302
|
+
// reconcile (`onResolvedFound` in index.ts), a turn earlier than the
|
|
303
|
+
// `runtime-turn:cascade-blocker` render that finally carries it — so it is
|
|
304
|
+
// its own delivery lane, and it was the one that rendered raw LSP findings
|
|
305
|
+
// with no policy filter at all. The evidence is the CALL TEXT of the shared
|
|
306
|
+
// filter (#3088 round-2 F4): a bare `applyFindingPolicy` would also be
|
|
307
|
+
// satisfied by the import line.
|
|
308
|
+
"cascade-format:resolved-found-run": gated("clients/cascade-format.ts", "Cold-neighbour ERROR diagnostics formatted into the turn-end cascade " +
|
|
309
|
+
"run by `buildResolvedFoundCascadeRun` (quiet-window reconcile of a " +
|
|
310
|
+
"cascade touch that skipped its in-lane wait).", ["applyFindingPolicy"], ["applyFindingPolicy(retained, {"]),
|
|
311
|
+
// #3157: the IN-LANE cascade — a different delivery lane from the
|
|
312
|
+
// quiet-window run above, and the one #3102's sweep cleared WRONGLY. Its four
|
|
313
|
+
// display sites (passive cold snapshot, fresh touch, touch-error fallback,
|
|
314
|
+
// degraded fallback) assemble `CascadeNeighborResult.diagnostics` and reach
|
|
315
|
+
// the agent through `formatCascadeNeighborDiagnostics` without ever entering
|
|
316
|
+
// the dispatcher's `applyOutputFilters` pipeline: the sweep's file-level
|
|
317
|
+
// verdict ("the per-edit dispatch path, which already filters in
|
|
318
|
+
// dispatcher.ts") was true only of the per-edit RUNNER output in
|
|
319
|
+
// `runners/lsp.ts`, which is a different call site in a different file.
|
|
320
|
+
//
|
|
321
|
+
// Evidence is the CALL TEXT (#3088 round-2 F4), counted: `cascadeDisplay(` is
|
|
322
|
+
// the one seam all four sites route through, so `evidenceMin: 4` is the count
|
|
323
|
+
// of display sites in the file and dropping ANY of them back to a raw
|
|
324
|
+
// `convertLspDiagnostics` reds this suite. Identity-stubbing the callee
|
|
325
|
+
// instead is caught behaviourally — it reds twelve cases in
|
|
326
|
+
// `tests/clients/inlane-cascade-finding-policy.test.ts`, which is a stronger
|
|
327
|
+
// signal than the R2 proximity heuristic. Residual, stated: a FIFTH display
|
|
328
|
+
// site that open-codes the conversion keeps the count at 4 and is caught by
|
|
329
|
+
// review, not by this row.
|
|
330
|
+
"dispatch-integration:in-lane-cascade": gated("clients/dispatch/integration.ts", "In-lane per-edit cascade neighbour ERROR diagnostics, rendered into the " +
|
|
331
|
+
"turn-end cascade block by `computeCascadeForFile`.", ["applyCascadeDisplayPolicy"], ["cascadeDisplay("], { evidenceMin: 4 }),
|
|
292
332
|
"runtime-turn:call-graph-advisory": labeled(RUNTIME_TURN_FILE, "Turn-end 📊 call-graph impact advisory.", "`runtime.callGraph` is a session-lifetime in-memory structure; this " +
|
|
293
333
|
"round does not verify or gate ITS OWN freshness policy (how/when it " +
|
|
294
334
|
"incorporates edits made earlier in the session).", "live", [], {
|
|
@@ -296,13 +336,15 @@ export const DELIVERY_SURFACES = {
|
|
|
296
336
|
partialReason: "call-graph freshness/invalidation policy is out of this PR's scope — " +
|
|
297
337
|
"tracked as a follow-up, not silently assumed fresh.",
|
|
298
338
|
}),
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
339
|
+
// #3088 round 2 F4: this row used to name `applyDispositions`/`applyRulePolicy`
|
|
340
|
+
// with whole-file evidence literals. Once #3088 folded mode=full's stack onto
|
|
341
|
+
// `applyFindingPolicy`, those two literals survived only in UNRELATED
|
|
342
|
+
// mode=delta helpers in the same file, so deleting the entire policy stack out
|
|
343
|
+
// of `applyInlineSuppressionsToSummaries` left this gate — and the ratchet —
|
|
344
|
+
// green while five behaviour cases redded. The evidence is now the call text
|
|
345
|
+
// of the merge's own filter, which exists nowhere else in the file.
|
|
346
|
+
"lens-diagnostics:mode-full": gated(LENS_DIAGNOSTICS_FILE, "`lens_diagnostics mode=full` report.", ["applyFindingPolicy", "reconcileProjectDiagnosticsSnapshot"], [
|
|
347
|
+
"applyFindingPolicy(summary.diagnostics, {",
|
|
306
348
|
"reconcileProjectDiagnosticsSnapshot(",
|
|
307
349
|
]),
|
|
308
350
|
"lens-diagnostics:mode-all": gated(LENS_DIAGNOSTICS_FILE, "`lens_diagnostics mode=all` report (widget-state read).", ["reconcileStaleWidgetFiles", "reconcileStaleWidgetDependencyBlockers"], ["reconcileStaleWidgetFiles(", "reconcileStaleWidgetDependencyBlockers("]),
|
|
@@ -342,13 +384,18 @@ export const DELIVERY_SURFACES = {
|
|
|
342
384
|
"the shared workspace-diagnostics cache: createWorkspaceDiagnosticsCacheContext " +
|
|
343
385
|
"is the tool's entry, and its lookup() applies the #671/#672 freshness stack " +
|
|
344
386
|
"(own-file mtime + reverse-dependency mtimes via isEntryFresh) plus the " +
|
|
345
|
-
"#1095 content binding.
|
|
387
|
+
"#1095 content binding. #3088: every route out of this tool — fresh, " +
|
|
388
|
+
"cache replay, single file, directory — also passes applyProbeFindingPolicy, " +
|
|
389
|
+
"the stored-disposition / .pi-lens.json rule-policy / inline pi-lens-ignore " +
|
|
390
|
+
"stack the per-edit dispatch path and mode=full apply.", [
|
|
346
391
|
"createWorkspaceDiagnosticsCacheContext",
|
|
347
392
|
"isEntryFresh",
|
|
348
393
|
"cacheCtx.lookup",
|
|
394
|
+
"applyProbeFindingPolicy",
|
|
349
395
|
], [
|
|
350
396
|
"createWorkspaceDiagnosticsCacheContext(resolvedCwd)",
|
|
351
397
|
"cacheCtx.lookup(file, scopeKey)",
|
|
398
|
+
"applyProbeFindingPolicy(",
|
|
352
399
|
]),
|
|
353
400
|
"git-guard:commit-blocked": labeled("clients/git-guard.ts", "Git-guard commit/push 🔴 COMMIT BLOCKED verdict (--lens-guard).", "Synchronous preflight rejection returned inline with the failed git " +
|
|
354
401
|
"command — no stored state is delivered, so nothing can go stale between " +
|
|
@@ -15,6 +15,7 @@ import * as path from "node:path";
|
|
|
15
15
|
import { recordFormatter } from "./widget-state.js";
|
|
16
16
|
import { FileTime } from "./file-time.js";
|
|
17
17
|
import { loadFormatters } from "./formatters-lazy.js";
|
|
18
|
+
import { bounded } from "./deadline-utils.js";
|
|
18
19
|
// --- Configuration ---
|
|
19
20
|
/** Reserved for future batching; formatting currently runs one selected formatter per file. */
|
|
20
21
|
const DEFAULT_FORMATTER_CONCURRENCY = 1;
|
|
@@ -69,7 +70,7 @@ export class FormatService {
|
|
|
69
70
|
};
|
|
70
71
|
}
|
|
71
72
|
// Run formatters with limited concurrency
|
|
72
|
-
const results = await this.runFormattersWithConcurrency(absolutePath, formatters);
|
|
73
|
+
const results = await this.runFormattersWithConcurrency(absolutePath, formatters, DEFAULT_FORMATTER_CONCURRENCY, options.signal, options.budgetMs, options.hook);
|
|
73
74
|
// Record new file state after formatting
|
|
74
75
|
this.fileTime.read(absolutePath);
|
|
75
76
|
for (const [index, result] of results.entries()) {
|
|
@@ -84,7 +85,7 @@ export class FormatService {
|
|
|
84
85
|
name: formatters[i].name,
|
|
85
86
|
success: r.success,
|
|
86
87
|
changed: r.changed,
|
|
87
|
-
error: r.error,
|
|
88
|
+
...(r.error === undefined ? {} : { error: r.error }),
|
|
88
89
|
outcome: r.outcome,
|
|
89
90
|
})),
|
|
90
91
|
anyChanged,
|
|
@@ -94,25 +95,46 @@ export class FormatService {
|
|
|
94
95
|
/**
|
|
95
96
|
* Run the selected formatter with timeout protection.
|
|
96
97
|
*/
|
|
97
|
-
async runFormattersWithConcurrency(filePath, formatters, _concurrency = DEFAULT_FORMATTER_CONCURRENCY) {
|
|
98
|
+
async runFormattersWithConcurrency(filePath, formatters, _concurrency = DEFAULT_FORMATTER_CONCURRENCY, signal, budgetMs = 30_000, hook = "tool_result_edit") {
|
|
98
99
|
const results = [];
|
|
100
|
+
const startedAt = Date.now();
|
|
99
101
|
for (const formatter of formatters) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
const remainingMs = budgetMs - (Date.now() - startedAt);
|
|
103
|
+
if (remainingMs <= 0) {
|
|
104
|
+
results.push({
|
|
105
|
+
success: false,
|
|
106
|
+
changed: false,
|
|
107
|
+
outcome: "failed",
|
|
108
|
+
error: `Formatter aggregate budget exhausted before ${formatter.name}`,
|
|
109
|
+
});
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
// The shared bound owns both the aggregate timer and abort listener.
|
|
113
|
+
// This keeps one total formatter budget per file instead of re-arming a
|
|
114
|
+
// 30s timer for every formatter.
|
|
106
115
|
try {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
const result = await bounded(loadFormatters().then(({ formatFile }) => formatFile(filePath, formatter)), {
|
|
117
|
+
ms: remainingMs,
|
|
118
|
+
signal,
|
|
119
|
+
hook,
|
|
120
|
+
label: "formatter-aggregate",
|
|
110
121
|
});
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
122
|
+
if (result)
|
|
123
|
+
results.push(result);
|
|
124
|
+
else if (signal?.aborted) {
|
|
125
|
+
// Caller cancellation is intentional. Do not turn Escape into a
|
|
126
|
+
// formatter failure or requeue record.
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
results.push({
|
|
131
|
+
success: false,
|
|
132
|
+
changed: false,
|
|
133
|
+
outcome: "failed",
|
|
134
|
+
error: `Formatter ${formatter.name} exceeded aggregate budget`,
|
|
135
|
+
});
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
116
138
|
}
|
|
117
139
|
catch (error) {
|
|
118
140
|
// A timeout or thrown error here is a real failure (#2413): the
|
|
@@ -125,10 +147,6 @@ export class FormatService {
|
|
|
125
147
|
error: error instanceof Error ? error.message : String(error),
|
|
126
148
|
});
|
|
127
149
|
}
|
|
128
|
-
finally {
|
|
129
|
-
if (formatTimer)
|
|
130
|
-
clearTimeout(formatTimer);
|
|
131
|
-
}
|
|
132
150
|
}
|
|
133
151
|
return results;
|
|
134
152
|
}
|