@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
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { BoundedFifoMap } from "./bounded-cache.js";
|
|
4
|
+
import { findNearestMarkerRoot } from "./path-utils.js";
|
|
5
|
+
import { getDegradationLedgerGeneration } from "./degradation-ledger.js";
|
|
6
|
+
import { hasBlackConfig, hasClangFormatConfig, hasCljfmtConfig, hasCmakeFormatConfig, hasCsharpierConfig, hasDetektConfig, hasFantomasConfig, hasGoogleJavaFormatConfig, hasGradleKtlintPlugin, hasGolangciConfig, hasKtfmtConfig, hasKtlintConfig, hasMarkdownlintConfig, hasMixFormatConfig, hasOcamlformatConfig, hasOrmoluConfig, hasPhpCsFixerConfig, hasRubocopConfig, hasRuffConfig, hasSqlfluffConfig, hasStandardrbConfig, hasStyluaConfig, hasSwiftformatConfig, hasTaploConfig, hasTerraformConfig, } from "./tool-policy.js";
|
|
7
|
+
const NODE_PACKAGES = {
|
|
8
|
+
biome: "@biomejs/biome",
|
|
9
|
+
eslint: "eslint",
|
|
10
|
+
markdownlint: "markdownlint-cli2",
|
|
11
|
+
oxfmt: "oxfmt",
|
|
12
|
+
oxlint: "oxlint",
|
|
13
|
+
prettier: "prettier",
|
|
14
|
+
stylelint: "stylelint",
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The complete autonomous writer population. Keep this table declarative: a
|
|
18
|
+
* caller may ask about an LSP warning tool that is not in the autofix or
|
|
19
|
+
* formatter tables, and that must take the unknown-tool default below rather
|
|
20
|
+
* than accidentally becoming established (#3005).
|
|
21
|
+
*
|
|
22
|
+
* Config evidence is deliberately presence-based. The existing policy
|
|
23
|
+
* detectors own each format's syntax and scope; agreement only answers the
|
|
24
|
+
* narrower question of whether this project elected the tool. Node tools use
|
|
25
|
+
* the stronger lockfile identity check in `nodeAgreement`.
|
|
26
|
+
*/
|
|
27
|
+
export const TOOL_AGREEMENT_POLICIES = {
|
|
28
|
+
biome: { bucket: "node-lockfile", withoutEvidence: "decline" },
|
|
29
|
+
eslint: { bucket: "node-lockfile", withoutEvidence: "decline" },
|
|
30
|
+
markdownlint: {
|
|
31
|
+
bucket: "node-lockfile",
|
|
32
|
+
withoutEvidence: "decline",
|
|
33
|
+
check: hasMarkdownlintConfig,
|
|
34
|
+
},
|
|
35
|
+
oxfmt: { bucket: "node-lockfile", withoutEvidence: "decline" },
|
|
36
|
+
oxlint: { bucket: "node-lockfile", withoutEvidence: "decline" },
|
|
37
|
+
prettier: { bucket: "node-lockfile", withoutEvidence: "decline" },
|
|
38
|
+
stylelint: { bucket: "node-lockfile", withoutEvidence: "decline" },
|
|
39
|
+
ruff: {
|
|
40
|
+
bucket: "project-config",
|
|
41
|
+
withoutEvidence: "decline",
|
|
42
|
+
check: hasRuffConfig,
|
|
43
|
+
},
|
|
44
|
+
black: {
|
|
45
|
+
bucket: "project-config",
|
|
46
|
+
withoutEvidence: "decline",
|
|
47
|
+
check: hasBlackConfig,
|
|
48
|
+
},
|
|
49
|
+
sqlfluff: {
|
|
50
|
+
bucket: "project-config",
|
|
51
|
+
withoutEvidence: "decline",
|
|
52
|
+
check: hasSqlfluffConfig,
|
|
53
|
+
},
|
|
54
|
+
rubocop: {
|
|
55
|
+
bucket: "project-config",
|
|
56
|
+
withoutEvidence: "decline",
|
|
57
|
+
check: hasRubocopConfig,
|
|
58
|
+
},
|
|
59
|
+
standardrb: {
|
|
60
|
+
bucket: "project-config",
|
|
61
|
+
withoutEvidence: "decline",
|
|
62
|
+
check: hasStandardrbConfig,
|
|
63
|
+
},
|
|
64
|
+
ktlint: { bucket: "standalone-cli", withoutEvidence: "decline" },
|
|
65
|
+
// typstyle is a standalone formatter binary. Its smart-default policy is
|
|
66
|
+
// autonomous, so PATH or managed-install availability is sufficient
|
|
67
|
+
// agreement; it is not owned by a project manifest (#3037).
|
|
68
|
+
typstyle: { bucket: "standalone-cli", withoutEvidence: "decline" },
|
|
69
|
+
ktfmt: {
|
|
70
|
+
bucket: "project-config",
|
|
71
|
+
withoutEvidence: "decline",
|
|
72
|
+
check: hasKtfmtConfig,
|
|
73
|
+
},
|
|
74
|
+
"rust-clippy": {
|
|
75
|
+
bucket: "project-config",
|
|
76
|
+
withoutEvidence: "decline",
|
|
77
|
+
check: (cwd) => hasMarker(cwd, ["Cargo.toml"]),
|
|
78
|
+
},
|
|
79
|
+
"dart-analyze": {
|
|
80
|
+
bucket: "project-config",
|
|
81
|
+
withoutEvidence: "decline",
|
|
82
|
+
check: (cwd) => hasMarker(cwd, ["pubspec.yaml"]),
|
|
83
|
+
},
|
|
84
|
+
"golangci-lint": {
|
|
85
|
+
bucket: "project-config",
|
|
86
|
+
withoutEvidence: "decline",
|
|
87
|
+
check: hasGolangciConfig,
|
|
88
|
+
},
|
|
89
|
+
detekt: {
|
|
90
|
+
bucket: "project-config",
|
|
91
|
+
withoutEvidence: "decline",
|
|
92
|
+
check: hasDetektConfig,
|
|
93
|
+
},
|
|
94
|
+
gofmt: {
|
|
95
|
+
bucket: "project-config",
|
|
96
|
+
withoutEvidence: "decline",
|
|
97
|
+
check: (cwd) => hasMarker(cwd, ["go.mod"]),
|
|
98
|
+
},
|
|
99
|
+
rustfmt: {
|
|
100
|
+
bucket: "project-config",
|
|
101
|
+
withoutEvidence: "decline",
|
|
102
|
+
check: (cwd) => hasMarker(cwd, ["Cargo.toml"]),
|
|
103
|
+
},
|
|
104
|
+
zig: {
|
|
105
|
+
bucket: "project-config",
|
|
106
|
+
withoutEvidence: "decline",
|
|
107
|
+
check: (cwd) => hasMarker(cwd, ["build.zig"]),
|
|
108
|
+
},
|
|
109
|
+
dart: {
|
|
110
|
+
bucket: "project-config",
|
|
111
|
+
withoutEvidence: "decline",
|
|
112
|
+
check: (cwd) => hasMarker(cwd, ["pubspec.yaml"]),
|
|
113
|
+
},
|
|
114
|
+
shfmt: {
|
|
115
|
+
bucket: "project-config",
|
|
116
|
+
withoutEvidence: "decline",
|
|
117
|
+
check: (cwd) => hasMarker(cwd, [".editorconfig"]),
|
|
118
|
+
},
|
|
119
|
+
// nixfmt has no honest project marker. It remains in the population and is
|
|
120
|
+
// declined by the conservative absent-evidence path below.
|
|
121
|
+
nixfmt: { bucket: "project-config", withoutEvidence: "decline" },
|
|
122
|
+
mix: {
|
|
123
|
+
bucket: "project-config",
|
|
124
|
+
withoutEvidence: "decline",
|
|
125
|
+
check: hasMixFormatConfig,
|
|
126
|
+
},
|
|
127
|
+
ocamlformat: {
|
|
128
|
+
bucket: "project-config",
|
|
129
|
+
withoutEvidence: "decline",
|
|
130
|
+
check: hasOcamlformatConfig,
|
|
131
|
+
},
|
|
132
|
+
"clang-format": {
|
|
133
|
+
bucket: "project-config",
|
|
134
|
+
withoutEvidence: "decline",
|
|
135
|
+
check: hasClangFormatConfig,
|
|
136
|
+
},
|
|
137
|
+
gleam: {
|
|
138
|
+
bucket: "project-config",
|
|
139
|
+
withoutEvidence: "decline",
|
|
140
|
+
check: (cwd) => hasMarker(cwd, ["gleam.toml"]),
|
|
141
|
+
},
|
|
142
|
+
terraform: {
|
|
143
|
+
bucket: "project-config",
|
|
144
|
+
withoutEvidence: "decline",
|
|
145
|
+
check: hasTerraformConfig,
|
|
146
|
+
},
|
|
147
|
+
"terragrunt-hcl": {
|
|
148
|
+
bucket: "project-config",
|
|
149
|
+
withoutEvidence: "decline",
|
|
150
|
+
check: (cwd) => hasMarker(cwd, ["terragrunt.hcl", "terragrunt.hcl.json"]),
|
|
151
|
+
},
|
|
152
|
+
"php-cs-fixer": {
|
|
153
|
+
bucket: "project-config",
|
|
154
|
+
withoutEvidence: "decline",
|
|
155
|
+
check: hasPhpCsFixerConfig,
|
|
156
|
+
},
|
|
157
|
+
csharpier: {
|
|
158
|
+
bucket: "project-config",
|
|
159
|
+
withoutEvidence: "decline",
|
|
160
|
+
check: hasCsharpierConfig,
|
|
161
|
+
},
|
|
162
|
+
fantomas: {
|
|
163
|
+
bucket: "project-config",
|
|
164
|
+
withoutEvidence: "decline",
|
|
165
|
+
check: hasFantomasConfig,
|
|
166
|
+
},
|
|
167
|
+
swiftformat: {
|
|
168
|
+
bucket: "project-config",
|
|
169
|
+
withoutEvidence: "decline",
|
|
170
|
+
check: hasSwiftformatConfig,
|
|
171
|
+
},
|
|
172
|
+
stylua: {
|
|
173
|
+
bucket: "project-config",
|
|
174
|
+
withoutEvidence: "decline",
|
|
175
|
+
check: hasStyluaConfig,
|
|
176
|
+
},
|
|
177
|
+
ormolu: {
|
|
178
|
+
bucket: "project-config",
|
|
179
|
+
withoutEvidence: "decline",
|
|
180
|
+
check: hasOrmoluConfig,
|
|
181
|
+
},
|
|
182
|
+
taplo: {
|
|
183
|
+
bucket: "project-config",
|
|
184
|
+
withoutEvidence: "decline",
|
|
185
|
+
check: hasTaploConfig,
|
|
186
|
+
},
|
|
187
|
+
"google-java-format": {
|
|
188
|
+
bucket: "project-config",
|
|
189
|
+
withoutEvidence: "decline",
|
|
190
|
+
check: hasGoogleJavaFormatConfig,
|
|
191
|
+
},
|
|
192
|
+
cljfmt: {
|
|
193
|
+
bucket: "project-config",
|
|
194
|
+
withoutEvidence: "decline",
|
|
195
|
+
check: hasCljfmtConfig,
|
|
196
|
+
},
|
|
197
|
+
"cmake-format": {
|
|
198
|
+
bucket: "project-config",
|
|
199
|
+
withoutEvidence: "decline",
|
|
200
|
+
check: hasCmakeFormatConfig,
|
|
201
|
+
},
|
|
202
|
+
"psscriptanalyzer-format": {
|
|
203
|
+
bucket: "project-config",
|
|
204
|
+
withoutEvidence: "decline",
|
|
205
|
+
check: (cwd) => hasMarker(cwd, [
|
|
206
|
+
"PSScriptAnalyzerSettings.psd1",
|
|
207
|
+
"ScriptAnalyzerSettings.psd1",
|
|
208
|
+
]),
|
|
209
|
+
},
|
|
210
|
+
cue: {
|
|
211
|
+
bucket: "project-config",
|
|
212
|
+
withoutEvidence: "decline",
|
|
213
|
+
check: (cwd) => hasMarker(cwd, ["cue.mod"]),
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
function hasMarker(cwd, markers) {
|
|
217
|
+
return (findNearestMarkerRoot(cwd, markers, {
|
|
218
|
+
boundaries: [".git", ".hg", ".svn"],
|
|
219
|
+
}) !== null);
|
|
220
|
+
}
|
|
221
|
+
function readJson(filePath) {
|
|
222
|
+
if (!fs.existsSync(filePath))
|
|
223
|
+
return { kind: "missing" };
|
|
224
|
+
try {
|
|
225
|
+
const value = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
226
|
+
return value && typeof value === "object"
|
|
227
|
+
? { kind: "value", value: value }
|
|
228
|
+
: { kind: "unparseable" };
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
return {
|
|
232
|
+
kind: error instanceof SyntaxError ? "unparseable" : "unreadable",
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function declaredRange(pkg, name) {
|
|
237
|
+
for (const field of [
|
|
238
|
+
"dependencies",
|
|
239
|
+
"devDependencies",
|
|
240
|
+
"optionalDependencies",
|
|
241
|
+
]) {
|
|
242
|
+
const deps = pkg[field];
|
|
243
|
+
if (deps && typeof deps === "object") {
|
|
244
|
+
const range = deps[name];
|
|
245
|
+
if (typeof range === "string")
|
|
246
|
+
return range;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return undefined;
|
|
250
|
+
}
|
|
251
|
+
function parseCoreVersion(version) {
|
|
252
|
+
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
|
|
253
|
+
if (!match)
|
|
254
|
+
return undefined;
|
|
255
|
+
const parts = match.slice(1).map(Number);
|
|
256
|
+
if (parts.some((part) => !Number.isSafeInteger(part)))
|
|
257
|
+
return undefined;
|
|
258
|
+
return parts;
|
|
259
|
+
}
|
|
260
|
+
function exactOrSimpleRangeMatches(range, version) {
|
|
261
|
+
const clean = range.trim().replace(/^v/, "");
|
|
262
|
+
const actual = parseCoreVersion(version);
|
|
263
|
+
if (!actual)
|
|
264
|
+
return { matches: false, unsupported: version.includes("+") };
|
|
265
|
+
if (/^\d+\.\d+\.\d+$/.test(clean))
|
|
266
|
+
return { matches: clean === version, unsupported: false };
|
|
267
|
+
const caret = clean.match(/^\^(\d+)\.(\d+)\.(\d+)$/);
|
|
268
|
+
if (caret) {
|
|
269
|
+
const [major, minor, patch] = caret.slice(1).map(Number);
|
|
270
|
+
return {
|
|
271
|
+
matches: actual[0] === major &&
|
|
272
|
+
(major !== 0 || actual[1] === minor) &&
|
|
273
|
+
(major !== 0 || minor !== 0 || actual[2] === patch) &&
|
|
274
|
+
(actual[1] > minor || (actual[1] === minor && actual[2] >= patch)),
|
|
275
|
+
unsupported: false,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
const tilde = clean.match(/^~(\d+)\.(\d+)\.(\d+)$/);
|
|
279
|
+
if (tilde) {
|
|
280
|
+
const [major, minor, patch] = tilde.slice(1).map(Number);
|
|
281
|
+
return {
|
|
282
|
+
matches: actual[0] === major && actual[1] === minor && actual[2] >= patch,
|
|
283
|
+
unsupported: false,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
return { matches: false, unsupported: true };
|
|
287
|
+
}
|
|
288
|
+
function nodeAgreement(tool, root) {
|
|
289
|
+
const packageName = NODE_PACKAGES[tool];
|
|
290
|
+
if (!packageName)
|
|
291
|
+
return undefined;
|
|
292
|
+
const pkg = readJson(path.join(root, "package.json"));
|
|
293
|
+
if (pkg.kind === "unreadable" || pkg.kind === "unparseable") {
|
|
294
|
+
return {
|
|
295
|
+
decision: "decline",
|
|
296
|
+
subject: `node:${tool}`,
|
|
297
|
+
reason: `the project package.json is ${pkg.kind}; tool agreement cannot be established`,
|
|
298
|
+
reasonCode: `evidence-${pkg.kind}`,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
const range = pkg.kind === "value" ? declaredRange(pkg.value, packageName) : undefined;
|
|
302
|
+
if (!range)
|
|
303
|
+
return undefined;
|
|
304
|
+
const lock = readJson(path.join(root, "package-lock.json"));
|
|
305
|
+
if (lock.kind === "unreadable" || lock.kind === "unparseable") {
|
|
306
|
+
return {
|
|
307
|
+
decision: "decline",
|
|
308
|
+
subject: `node:${tool}`,
|
|
309
|
+
reason: `the project package-lock.json is ${lock.kind}; tool agreement cannot be established`,
|
|
310
|
+
reasonCode: `evidence-${lock.kind}`,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
const packages = lock.kind === "value" ? lock.value.packages : undefined;
|
|
314
|
+
const entry = packages && typeof packages === "object"
|
|
315
|
+
? packages[`node_modules/${packageName}`]
|
|
316
|
+
: undefined;
|
|
317
|
+
const version = entry && typeof entry === "object"
|
|
318
|
+
? entry.version
|
|
319
|
+
: undefined;
|
|
320
|
+
const comparison = typeof version === "string"
|
|
321
|
+
? exactOrSimpleRangeMatches(range, version)
|
|
322
|
+
: { matches: false, unsupported: false };
|
|
323
|
+
if (typeof version !== "string" || !comparison.matches) {
|
|
324
|
+
const reasonCode = typeof version === "string" && comparison.unsupported
|
|
325
|
+
? "evidence-unsupported"
|
|
326
|
+
: typeof version === "string" && version.includes("+")
|
|
327
|
+
? "evidence-unsupported"
|
|
328
|
+
: "evidence-unparseable";
|
|
329
|
+
const reason = typeof version === "string" && comparison.unsupported
|
|
330
|
+
? `the project declares ${packageName}@${range}, but the lockfile shape ${packageName}@${version} or its range is unsupported; tool agreement cannot be established`
|
|
331
|
+
: typeof version === "string" && parseCoreVersion(version)
|
|
332
|
+
? `the project declares ${packageName}@${range} in package.json, but the lockfile resolves ${packageName}@${version} in package-lock.json; agreement disagrees`
|
|
333
|
+
: `the project declares ${packageName}@${range} in package.json, but package-lock.json does not establish its resolved version; tool agreement cannot be established`;
|
|
334
|
+
return {
|
|
335
|
+
decision: "decline",
|
|
336
|
+
subject: `node:${tool}`,
|
|
337
|
+
reason,
|
|
338
|
+
reasonCode,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
return { decision: "established" };
|
|
342
|
+
}
|
|
343
|
+
/** Decide whether autofix has project evidence to act on. Never infers a CLI
|
|
344
|
+
* version from build-plugin metadata (#3000). */
|
|
345
|
+
export function establishToolAgreement(tool, cwd) {
|
|
346
|
+
const key = `${getDegradationLedgerGeneration()}\0${path.resolve(cwd)}\0${tool}`;
|
|
347
|
+
const cached = agreementCache.get(key);
|
|
348
|
+
if (cached)
|
|
349
|
+
return cached;
|
|
350
|
+
agreementResolutionCount += 1;
|
|
351
|
+
const policy = TOOL_AGREEMENT_POLICIES[tool];
|
|
352
|
+
if (!policy) {
|
|
353
|
+
const agreement = {
|
|
354
|
+
decision: "decline",
|
|
355
|
+
subject: `tool:${tool}`,
|
|
356
|
+
reason: "the autonomous writer is not registered with a project-evidence policy; tool agreement cannot be established",
|
|
357
|
+
reasonCode: "evidence-unsupported",
|
|
358
|
+
};
|
|
359
|
+
agreementCache.set(key, agreement);
|
|
360
|
+
return agreement;
|
|
361
|
+
}
|
|
362
|
+
let agreement = { decision: "established" };
|
|
363
|
+
if (tool === "ktlint") {
|
|
364
|
+
const ownership = hasGradleKtlintPlugin(cwd);
|
|
365
|
+
if (ownership.kind === "owned" || hasKtlintConfig(cwd)) {
|
|
366
|
+
agreement = {
|
|
367
|
+
decision: "decline",
|
|
368
|
+
subject: "kotlin:gradle-ktlint",
|
|
369
|
+
reason: "the project resolves ktlint through Gradle, so CLI agreement cannot be established from project data",
|
|
370
|
+
reasonCode: "evidence-unsupported",
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
else if (ownership.kind === "indeterminate") {
|
|
374
|
+
agreement = {
|
|
375
|
+
decision: "decline",
|
|
376
|
+
subject: "kotlin:gradle-ktlint",
|
|
377
|
+
reason: "Gradle ownership evidence is unreadable or exceeded its scan budget; tool agreement cannot be established",
|
|
378
|
+
reasonCode: "evidence-unreadable",
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (agreement.decision === "established" &&
|
|
383
|
+
policy.bucket === "node-lockfile") {
|
|
384
|
+
const root = findNearestMarkerRoot(cwd, ["package.json"], {
|
|
385
|
+
boundaries: [".git", ".hg", ".svn"],
|
|
386
|
+
});
|
|
387
|
+
const node = root ? nodeAgreement(tool, root) : undefined;
|
|
388
|
+
agreement = node ?? {
|
|
389
|
+
decision: "decline",
|
|
390
|
+
subject: `node:${tool}`,
|
|
391
|
+
reason: "the project has no package declaration and lockfile evidence for this tool",
|
|
392
|
+
reasonCode: "evidence-absent",
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
else if (agreement.decision === "established" &&
|
|
396
|
+
policy.bucket === "project-config" &&
|
|
397
|
+
(!policy.check || !policy.check(cwd))) {
|
|
398
|
+
agreement = {
|
|
399
|
+
decision: "decline",
|
|
400
|
+
subject: `project:${tool}`,
|
|
401
|
+
reason: "the project has no readable configuration or manifest evidence selecting this tool",
|
|
402
|
+
reasonCode: "evidence-absent",
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
/* Keep the branch below as a final assertion that no policy can bypass the
|
|
406
|
+
* registry. It also makes future bucket additions fail closed at runtime. */
|
|
407
|
+
if (agreement.decision === "established" && !policy.bucket) {
|
|
408
|
+
agreement = {
|
|
409
|
+
decision: "decline",
|
|
410
|
+
subject: `tool:${tool}`,
|
|
411
|
+
reason: "the tool evidence bucket is unsupported",
|
|
412
|
+
reasonCode: "evidence-unsupported",
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
agreementCache.set(key, agreement);
|
|
416
|
+
return agreement;
|
|
417
|
+
}
|
|
418
|
+
const agreementCache = new BoundedFifoMap(512);
|
|
419
|
+
let agreementResolutionCount = 0;
|
|
420
|
+
/** Test-only counter for the bounded hot-path resolution. */
|
|
421
|
+
export function _getAgreementResolutionCountForTests() {
|
|
422
|
+
return agreementResolutionCount;
|
|
423
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** Shared resolver for model-facing tool availability (#2800). */
|
|
2
2
|
import { readFlagConfigValue } from "./lens-flag-registry.js";
|
|
3
|
+
import { escapeRegExp } from "./string-utils.js";
|
|
3
4
|
/** The complete model-facing tool population on pi and MCP. */
|
|
4
5
|
export const TOOL_REGISTRY = [
|
|
5
6
|
{
|
|
@@ -140,6 +141,55 @@ export const TOOL_REGISTRY = [
|
|
|
140
141
|
},
|
|
141
142
|
];
|
|
142
143
|
export const LENS_TOOL_NAMES = TOOL_REGISTRY.map((tool) => tool.name);
|
|
144
|
+
/**
|
|
145
|
+
* Registry tools with a pi name but no MCP name are pi-only BY DECLARATION
|
|
146
|
+
* here, never by omission (#2535 F3). A missing entry used to degrade
|
|
147
|
+
* silently into the pi name on MCP, sending the agent to a dead call — the
|
|
148
|
+
* guard in tests/clients/adapter-aware-tool-names.test.ts fails on any
|
|
149
|
+
* pi-only row absent from this map, and `resolveLensToolName` resolves a
|
|
150
|
+
* known-but-unmapped host to `undefined` so callers omit instead of naming.
|
|
151
|
+
*/
|
|
152
|
+
export const PI_ONLY_TOOL_REASONS = {
|
|
153
|
+
ast_grep_outline: "pi situational tool with no MCP mirror; MCP parity deferred like read_enclosing was.",
|
|
154
|
+
lens_diagnostic_mark: "pi-lens-internal disposition tool; MCP has no equivalent surface (needs its own engine seam and tool route).",
|
|
155
|
+
pi_lens_activate_tools: "pi dynamic-tooling loader; MCP lists every tool statically, so there is nothing to activate.",
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Resolve the name an agent can call on the delivery host. Unknown names
|
|
159
|
+
* pass through unchanged (no registry identity). A known tool WITHOUT a
|
|
160
|
+
* mapping on the requested host resolves to `undefined` — the caller must
|
|
161
|
+
* omit or rephrase, never print a name the host cannot resolve.
|
|
162
|
+
*/
|
|
163
|
+
export function resolveLensToolName(name, host = "pi") {
|
|
164
|
+
const entry = TOOL_REGISTRY.find((tool) => tool.name === name || tool.piName === name || tool.mcpName === name);
|
|
165
|
+
if (!entry)
|
|
166
|
+
return name;
|
|
167
|
+
if (host === "mcp")
|
|
168
|
+
return entry.mcpName;
|
|
169
|
+
return entry.piName;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Render already-written advisory text for the delivery host (#2535). The pi
|
|
173
|
+
* host reads it back unchanged. For MCP, every whole-word pi tool name with
|
|
174
|
+
* an MCP mapping becomes its callable MCP name (driven by TOOL_REGISTRY,
|
|
175
|
+
* longest first — never a hand-maintained second map), and the pi-only
|
|
176
|
+
* activation clause is rephrased since MCP lists every tool statically.
|
|
177
|
+
* A pi-only name with no MCP surface never survives translation: it is
|
|
178
|
+
* either rephrased here or caught by the adapter-aware guard.
|
|
179
|
+
*/
|
|
180
|
+
export function translateGuidanceToolNames(content, host) {
|
|
181
|
+
if (host === "pi")
|
|
182
|
+
return content;
|
|
183
|
+
let text = content;
|
|
184
|
+
const byLength = [...TOOL_REGISTRY].sort((a, b) => (b.piName?.length ?? 0) - (a.piName?.length ?? 0));
|
|
185
|
+
for (const entry of byLength) {
|
|
186
|
+
if (typeof entry.piName !== "string" || typeof entry.mcpName !== "string") {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
text = text.replace(new RegExp(`\\b${escapeRegExp(entry.piName)}\\b`, "g"), entry.mcpName);
|
|
190
|
+
}
|
|
191
|
+
return text.replace("activate via pi_lens_activate_tools", "call directly");
|
|
192
|
+
}
|
|
143
193
|
export function toolRegistryEntryForPi(name) {
|
|
144
194
|
return TOOL_REGISTRY.find((tool) => tool.piName === name);
|
|
145
195
|
}
|
|
@@ -5,6 +5,7 @@ import { logExtension } from "./extension-log.js";
|
|
|
5
5
|
import { isRealGitMarker, isAtOrAboveHomeDir, isUnderDir, isWindowsPath, nameMatchesMarkerGlob, normalizeEphemeralMapKey, } from "./path-utils.js";
|
|
6
6
|
import { getDegradationLedgerGeneration, recordDegradationOnce, } from "./degradation-ledger.js";
|
|
7
7
|
import { createGenerationMap, createGenerationSource, } from "./generation-guard.js";
|
|
8
|
+
import { rootMarkersForFile } from "./language-profile.js";
|
|
8
9
|
export const FORMATTER_MARKERS = {
|
|
9
10
|
biome: ["biome.json", "biome.jsonc", "package.json", ".gitignore"],
|
|
10
11
|
prettier: [
|
|
@@ -82,70 +83,24 @@ export const FORMATTER_MARKERS = {
|
|
|
82
83
|
"settings.gradle.kts",
|
|
83
84
|
".gitignore",
|
|
84
85
|
],
|
|
85
|
-
|
|
86
|
-
const RUNNER_MARKERS = {
|
|
87
|
-
yamllint: [".yamllint", "yamllint.yaml", "yamllint.yml", "pyproject.toml"],
|
|
88
|
-
ruff: ["pyproject.toml", "ruff.toml", ".ruff.toml"],
|
|
89
|
-
"spellcheck/typos": ["_typos.toml", "typos.toml"],
|
|
90
|
-
biome: ["biome.json", "biome.jsonc", "package.json"],
|
|
91
|
-
oxlint: [".oxlintrc.json", "oxlint.config.js", "package.json"],
|
|
92
|
-
sqlfluff: [".sqlfluff", "pyproject.toml", "setup.cfg"],
|
|
93
|
-
prettier: [".prettierignore", "package.json"],
|
|
94
|
-
// #2894: cargo must run at the package root. This is the marker walk
|
|
95
|
-
// `rust-clippy.ts` used to do for itself with `findNearestContaining`.
|
|
96
|
-
"rust-clippy": ["Cargo.toml"],
|
|
86
|
+
typstyle: [".gitignore"],
|
|
97
87
|
};
|
|
98
88
|
const toolCwdGeneration = createGenerationSource("tool-cwd");
|
|
99
89
|
const logged = createGenerationMap("tool-cwd-resolution-log");
|
|
100
|
-
|
|
101
|
-
const markerWalkGenerations = createGenerationMap("tool-cwd-marker-walks");
|
|
102
|
-
let markerWalkCount = 0;
|
|
103
|
-
/** Pure key seam for ephemeral tool-cwd memo and log identity. */
|
|
90
|
+
/** Pure key seam for resolution-log and runner-advisory identity. */
|
|
104
91
|
export function _toolCwdEphemeralKey(parts) {
|
|
105
92
|
return parts.map(normalizeEphemeralMapKey).join("\0");
|
|
106
93
|
}
|
|
107
|
-
/** Test probe for the per-generation walk memo; not part of runtime behavior. */
|
|
108
|
-
export function _getToolCwdMarkerWalkCount() {
|
|
109
|
-
return markerWalkCount;
|
|
110
|
-
}
|
|
111
94
|
function syncGeneration() {
|
|
112
95
|
if (toolCwdGeneration.current() === getDegradationLedgerGeneration())
|
|
113
96
|
return;
|
|
114
|
-
markerWalks.clear();
|
|
115
|
-
markerWalkGenerations.clear();
|
|
116
97
|
logged.clear();
|
|
117
98
|
while (toolCwdGeneration.current() < getDegradationLedgerGeneration()) {
|
|
118
99
|
toolCwdGeneration.bump();
|
|
119
100
|
}
|
|
120
101
|
}
|
|
121
|
-
function
|
|
122
|
-
syncGeneration();
|
|
123
|
-
const key = _toolCwdEphemeralKey([
|
|
124
|
-
path.resolve(startDir),
|
|
125
|
-
...markers,
|
|
126
|
-
path.resolve(homeDir),
|
|
127
|
-
]);
|
|
128
|
-
const cached = markerWalks.get(key);
|
|
129
|
-
if (cached && markerWalkGenerations.current(key) !== 0) {
|
|
130
|
-
// A negative walk is not stable: a project marker can be created after
|
|
131
|
-
// the first resolution, so do not cache absence across calls. Positive
|
|
132
|
-
// results remain memoized and are still revalidated when their marker is
|
|
133
|
-
// deleted (#2894).
|
|
134
|
-
if (!cached.marker || !cached.root) {
|
|
135
|
-
markerWalks.delete(key);
|
|
136
|
-
markerWalkGenerations.forget(key);
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
// #2777: a marker can disappear during a session; do not reuse a stale root.
|
|
140
|
-
if (existsSync(path.join(cached.root, cached.marker)))
|
|
141
|
-
return cached;
|
|
142
|
-
markerWalks.delete(key);
|
|
143
|
-
markerWalkGenerations.forget(key);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
markerWalkCount++;
|
|
102
|
+
function walkMarkerRoot(startDir, markers, homeDir) {
|
|
147
103
|
let current = path.resolve(startDir);
|
|
148
|
-
let result = { root: null };
|
|
149
104
|
for (let depth = 0; depth < 64; depth++) {
|
|
150
105
|
if (isAtOrAboveHomeDir(current, homeDir))
|
|
151
106
|
break;
|
|
@@ -169,32 +124,27 @@ function findMarkerRoot(startDir, markers, homeDir) {
|
|
|
169
124
|
else {
|
|
170
125
|
found = existsSync(path.join(target, basename));
|
|
171
126
|
}
|
|
172
|
-
if (found)
|
|
173
|
-
|
|
174
|
-
markerWalks.set(key, result);
|
|
175
|
-
markerWalkGenerations.bump(key);
|
|
176
|
-
return result;
|
|
177
|
-
}
|
|
127
|
+
if (found)
|
|
128
|
+
return { root: current, marker };
|
|
178
129
|
}
|
|
179
130
|
const parentDir = path.dirname(current);
|
|
180
131
|
if (parentDir === current)
|
|
181
132
|
break;
|
|
182
133
|
current = parentDir;
|
|
183
134
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
135
|
+
return { root: null };
|
|
136
|
+
}
|
|
137
|
+
function findMarkerRoot(startDir, markers, homeDir) {
|
|
138
|
+
syncGeneration();
|
|
139
|
+
return walkMarkerRoot(startDir, markers, homeDir);
|
|
187
140
|
}
|
|
188
|
-
function markersFor(kind, tool, ctx) {
|
|
141
|
+
function markersFor(kind, tool, file, ctx) {
|
|
189
142
|
if (kind === "lsp")
|
|
190
143
|
return ctx.rootMarkers ?? [];
|
|
191
|
-
// #
|
|
192
|
-
//
|
|
193
|
-
// a caller that owns its own marker table — the test runner, whose
|
|
194
|
-
// `RUNNERS[x].configFiles` IS that table — passes it here rather than
|
|
195
|
-
// registering a second copy of the same data in this file.
|
|
144
|
+
// #2965: runner fallback uses the language table that also anchors the
|
|
145
|
+
// dispatch context. A caller-owned table remains an explicit override.
|
|
196
146
|
if (kind === "runner")
|
|
197
|
-
return ctx.rootMarkers ??
|
|
147
|
+
return ctx.rootMarkers ?? rootMarkersForFile(file, tool);
|
|
198
148
|
return FORMATTER_MARKERS[tool] ?? [".gitignore"];
|
|
199
149
|
}
|
|
200
150
|
function emitResolution(kind, tool, cwd, reason) {
|
|
@@ -239,9 +189,9 @@ export function resolveToolCwd(kind, tool, file, ctx) {
|
|
|
239
189
|
const serverRoot = rootPath.resolve(ctx.serverRoot);
|
|
240
190
|
if (!ctx.suppressTelemetry)
|
|
241
191
|
emitResolution(kind, tool, serverRoot, "server-root");
|
|
242
|
-
return serverRoot;
|
|
192
|
+
return { cwd: serverRoot };
|
|
243
193
|
}
|
|
244
|
-
const markers = markersFor(kind, tool, ctx);
|
|
194
|
+
const markers = markersFor(kind, tool, absoluteFile, ctx);
|
|
245
195
|
const markerResult = markers.length
|
|
246
196
|
? findMarkerRoot(fileDir, markers, ctx.allowHomeMarker ? path.parse(homeDir).root : homeDir)
|
|
247
197
|
: { root: null };
|
|
@@ -251,16 +201,34 @@ export function resolveToolCwd(kind, tool, file, ctx) {
|
|
|
251
201
|
const finalReason = `marker:${markerResult.marker ?? markers[0]}`;
|
|
252
202
|
if (!ctx.suppressTelemetry)
|
|
253
203
|
emitResolution(kind, tool, markerRoot, finalReason);
|
|
254
|
-
return
|
|
204
|
+
return {
|
|
205
|
+
cwd: markerRoot,
|
|
206
|
+
...(markerResult.marker !== undefined
|
|
207
|
+
? { marker: markerResult.marker }
|
|
208
|
+
: {}),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
const memo = ctx.toolCwdMemo;
|
|
212
|
+
if (memo && memo.gitRoot === undefined) {
|
|
213
|
+
const gitResult = findMarkerRoot(fileDir, [".git"], homeDir);
|
|
214
|
+
memo.gitRoot =
|
|
215
|
+
gitResult.root && isRealGitMarker(path.join(gitResult.root, ".git"))
|
|
216
|
+
? gitResult.root
|
|
217
|
+
: null;
|
|
255
218
|
}
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
219
|
+
const gitRoot = memo && memo.gitRoot !== undefined
|
|
220
|
+
? memo.gitRoot
|
|
221
|
+
: (() => {
|
|
222
|
+
const gitResult = findMarkerRoot(fileDir, [".git"], homeDir);
|
|
223
|
+
return gitResult.root &&
|
|
224
|
+
isRealGitMarker(path.join(gitResult.root, ".git"))
|
|
225
|
+
? gitResult.root
|
|
226
|
+
: null;
|
|
227
|
+
})();
|
|
260
228
|
if (gitRoot && (insideDispatch ? isUnderDir(gitRoot, dispatchRoot) : true)) {
|
|
261
229
|
if (!ctx.suppressTelemetry)
|
|
262
230
|
emitResolution(kind, tool, gitRoot, "git-root");
|
|
263
|
-
return gitRoot;
|
|
231
|
+
return { cwd: gitRoot, marker: ".git" };
|
|
264
232
|
}
|
|
265
233
|
if (insideDispatch) {
|
|
266
234
|
if (kind === "formatter") {
|
|
@@ -273,11 +241,11 @@ export function resolveToolCwd(kind, tool, file, ctx) {
|
|
|
273
241
|
reason: `${kind}:home-cap:${absoluteFile}`,
|
|
274
242
|
});
|
|
275
243
|
}
|
|
276
|
-
return fileDir;
|
|
244
|
+
return { cwd: fileDir };
|
|
277
245
|
}
|
|
278
246
|
if (!ctx.suppressTelemetry)
|
|
279
247
|
emitResolution(kind, tool, dispatchRoot, "dispatch-root");
|
|
280
|
-
return dispatchRoot;
|
|
248
|
+
return { cwd: dispatchRoot };
|
|
281
249
|
}
|
|
282
250
|
const reason = isUnderDir(fileDir, homeDir)
|
|
283
251
|
? "file-dir-fallback"
|
|
@@ -291,9 +259,12 @@ export function resolveToolCwd(kind, tool, file, ctx) {
|
|
|
291
259
|
});
|
|
292
260
|
if (!ctx.suppressTelemetry)
|
|
293
261
|
emitResolution(kind, tool, fallback, reason);
|
|
294
|
-
return fallback;
|
|
262
|
+
return { cwd: fallback };
|
|
295
263
|
}
|
|
296
264
|
/** Runner-shaped adapter kept at the same seam for every runner consumer. */
|
|
297
265
|
export function resolveRunnerCwd(ctx, tool) {
|
|
266
|
+
return resolveToolCwd("runner", tool, ctx.filePath, ctx).cwd;
|
|
267
|
+
}
|
|
268
|
+
export function resolveRunnerCwdWithReason(ctx, tool) {
|
|
298
269
|
return resolveToolCwd("runner", tool, ctx.filePath, ctx);
|
|
299
270
|
}
|