@herbertgao/pi-extensions 2026.8.6 → 2026.8.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 +8 -6
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +19 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +30 -9
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +320 -22
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +79 -17
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +27 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +66 -17
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
- package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
- package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
- package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +17 -13
- package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
- package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
- package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
- package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
- package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
- package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +21 -6
- package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
- package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +20 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +5 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +174 -100
- package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +5 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +10 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +10 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/tool-schema.md +11 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +5 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +140 -97
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +63 -28
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/selectors/projections.ts +22 -15
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state-reducer.ts +11 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/response-envelope.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/types.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/multi-select-view.ts +31 -17
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/preview/preview-block-renderer.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/wrapping-select.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +86 -38
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +76 -9
- package/node_modules/@narumitw/pi-btw/README.md +120 -111
- package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
- package/node_modules/@narumitw/pi-btw/package.json +10 -6
- package/node_modules/@narumitw/pi-btw/src/btw.ts +36 -40
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
- package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +45 -2
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +44 -1856
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/package.json +4 -6
- package/node_modules/pi-lens/CHANGELOG.md +999 -0
- package/node_modules/pi-lens/README.md +117 -3
- package/node_modules/pi-lens/config/ruff/core.toml +42 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +126 -13
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +67 -11
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
- package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +381 -13
- package/node_modules/pi-lens/dist/clients/biome-client.js +61 -30
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
- package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +129 -0
- package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +206 -0
- package/node_modules/pi-lens/dist/clients/cache-observability.js +353 -76
- package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
- package/node_modules/pi-lens/dist/clients/cascade-format.js +20 -1
- package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
- package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
- package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +123 -31
- package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
- package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +84 -14
- package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -3
- package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +8 -2
- package/node_modules/pi-lens/dist/clients/deps/typebox.js +8 -3
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +147 -33
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +52 -2
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +256 -88
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +9 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +9 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +8 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +60 -53
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +25 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +20 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +44 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +17 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +32 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +47 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +14 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +127 -28
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +12 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +275 -13
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +21 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +734 -64
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +188 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +9 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +21 -10
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
- package/node_modules/pi-lens/dist/clients/extension-log.js +22 -1
- package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +316 -0
- package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
- package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
- package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
- package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
- package/node_modules/pi-lens/dist/clients/git-guard.js +31 -0
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +109 -9
- package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
- package/node_modules/pi-lens/dist/clients/host-ports.js +8 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +1114 -100
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
- package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +87 -8
- package/node_modules/pi-lens/dist/clients/knip-client.js +310 -10
- package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +9 -2
- package/node_modules/pi-lens/dist/clients/latency-logger.js +440 -11
- package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +128 -8
- package/node_modules/pi-lens/dist/clients/lsp/client.js +1660 -164
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +83 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
- package/node_modules/pi-lens/dist/clients/lsp/index.js +2423 -151
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
- package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
- package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
- package/node_modules/pi-lens/dist/clients/lsp/server.js +277 -16
- package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
- package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +79 -3
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +43 -0
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
- package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
- package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
- package/node_modules/pi-lens/dist/clients/mcp/session.js +10 -2
- package/node_modules/pi-lens/dist/clients/module-report.js +22 -1
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +114 -23
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
- package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
- package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
- package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
- package/node_modules/pi-lens/dist/clients/pipeline.js +154 -33
- package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +84 -14
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +23 -9
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
- package/node_modules/pi-lens/dist/clients/project-report.js +62 -27
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
- package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +8 -3
- package/node_modules/pi-lens/dist/clients/read-guard.js +253 -10
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
- package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +194 -31
- package/node_modules/pi-lens/dist/clients/review-graph/query.js +52 -4
- package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +21 -0
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +6 -3
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +96 -7
- package/node_modules/pi-lens/dist/clients/runtime-context.js +8 -1
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +352 -45
- package/node_modules/pi-lens/dist/clients/runtime-session.js +373 -9
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +212 -79
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +620 -67
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
- package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
- package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +157 -24
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +184 -0
- package/node_modules/pi-lens/dist/clients/sg-runner.js +116 -22
- package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
- package/node_modules/pi-lens/dist/clients/source-filter.js +6 -2
- package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
- package/node_modules/pi-lens/dist/clients/startup-scan.js +5 -2
- package/node_modules/pi-lens/dist/clients/startup-timing.js +19 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +151 -16
- package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
- package/node_modules/pi-lens/dist/clients/tool-policy.js +125 -20
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +1 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
- package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
- package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
- package/node_modules/pi-lens/dist/index.js +61407 -48577
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +476 -57
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +132 -43
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
- package/node_modules/pi-lens/docs/agent-guide.md +6 -1
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +515 -506
- package/node_modules/pi-lens/docs/dispositions.md +21 -0
- package/node_modules/pi-lens/docs/features.md +19 -5
- package/node_modules/pi-lens/docs/globalconfig.md +3 -0
- package/node_modules/pi-lens/docs/language-coverage.md +71 -5
- package/node_modules/pi-lens/docs/mcp.md +2 -2
- package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
- package/node_modules/pi-lens/docs/settings.md +19 -1
- package/node_modules/pi-lens/docs/usage.md +1 -0
- package/node_modules/pi-lens/package.json +27 -10
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +15 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +2 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +2 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +57 -12
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +22 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +23 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +33 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +34 -8
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +6 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +53 -1
- package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
- package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
- package/node_modules/pi-lens/scripts/install-selftest.mjs +99 -11
- package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +75 -0
- package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +285 -0
- package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +233 -0
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +2 -0
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +80 -3
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +41 -0
- package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +36 -0
- package/node_modules/pi-mcp-adapter/README.md +47 -5
- package/node_modules/pi-mcp-adapter/cli.js +163 -1
- package/node_modules/pi-mcp-adapter/commands.ts +128 -22
- package/node_modules/pi-mcp-adapter/config.ts +25 -7
- package/node_modules/pi-mcp-adapter/direct-tools.ts +5 -4
- package/node_modules/pi-mcp-adapter/index.ts +219 -32
- package/node_modules/pi-mcp-adapter/init.ts +36 -4
- package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
- package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
- package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
- package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +32 -21
- package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
- package/node_modules/pi-mcp-adapter/package.json +3 -1
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +31 -37
- package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
- package/node_modules/pi-mcp-adapter/server-manager.ts +140 -2
- package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
- package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
- package/node_modules/pi-mcp-adapter/types.ts +2 -0
- package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
- package/node_modules/pi-mcp-adapter/utils.ts +70 -0
- package/node_modules/pi-web-access/CHANGELOG.md +37 -0
- package/node_modules/pi-web-access/README.md +32 -13
- package/node_modules/pi-web-access/anysearch.ts +4 -2
- package/node_modules/pi-web-access/brave.ts +16 -4
- package/node_modules/pi-web-access/chrome-cookies.ts +86 -15
- package/node_modules/pi-web-access/curator-page.ts +6 -3
- package/node_modules/pi-web-access/curator-server.ts +4 -1
- package/node_modules/pi-web-access/data-uri-sanitize.ts +406 -0
- package/node_modules/pi-web-access/exa.ts +18 -7
- package/node_modules/pi-web-access/extract.ts +40 -5
- package/node_modules/pi-web-access/firecrawl.ts +18 -2
- package/node_modules/pi-web-access/gemini-search.ts +16 -4
- package/node_modules/pi-web-access/github-extract.ts +65 -36
- package/node_modules/pi-web-access/index.ts +60 -61
- package/node_modules/pi-web-access/openai-search.ts +17 -6
- package/node_modules/pi-web-access/package.json +1 -1
- package/node_modules/pi-web-access/page-query.ts +4 -2
- package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
- package/node_modules/pi-web-access/parallel.ts +2 -2
- package/node_modules/pi-web-access/pdf-extract.ts +18 -5
- package/node_modules/pi-web-access/query-rewrite.ts +51 -0
- package/node_modules/pi-web-access/serper.ts +211 -0
- package/node_modules/pi-web-access/ssrf-protection.ts +12 -2
- package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
- package/node_modules/pi-web-access/summary-review.ts +44 -22
- package/node_modules/pi-web-access/tavily.ts +16 -4
- package/node_modules/pi-web-access/utils.ts +87 -0
- package/node_modules/pi-web-access/valyu.ts +199 -0
- package/package.json +14 -14
|
@@ -4,6 +4,7 @@ import * as path from "node:path";
|
|
|
4
4
|
import { logLatency } from "./latency-logger.js";
|
|
5
5
|
import { normalizeMapKey, toProjectRelativePath } from "./path-utils.js";
|
|
6
6
|
import { resolveRunnerPath } from "./dispatch/runner-context.js";
|
|
7
|
+
import { MTIME_DRIFT_TOLERANCE_MS } from "./blocker-freshness.js";
|
|
7
8
|
export const MAX_ADVISORY_AFFECTED_FILES = 256;
|
|
8
9
|
export function advisoryPathKey(filePath, cwd) {
|
|
9
10
|
return normalizeMapKey(path.resolve(cwd, filePath));
|
|
@@ -199,9 +200,34 @@ export function validateAdvisoryProvenance(record, cwd, runtime) {
|
|
|
199
200
|
export const MAX_FINDING_PATH_STATS = MAX_ADVISORY_AFFECTED_FILES;
|
|
200
201
|
/** How many dead paths a single drop record names before it stops. */
|
|
201
202
|
const MAX_LOGGED_DEAD_PATHS = 3;
|
|
202
|
-
|
|
203
|
+
/**
|
|
204
|
+
* One stat, one verdict. With `scannedAtMs` supplied, a surviving file whose
|
|
205
|
+
* mtime is newer than the scan reports `stale`.
|
|
206
|
+
*
|
|
207
|
+
* The boundary is `mtime > scannedAt + MTIME_DRIFT_TOLERANCE_MS`: a file
|
|
208
|
+
* scanned AT `scannedAt`, or written within the tolerance window of the scan
|
|
209
|
+
* timestamp being captured, reads live; genuinely past it reads stale.
|
|
210
|
+
*
|
|
211
|
+
* #1708: a bare +1ms tolerance — the convention `reconcileProjectDiagnosticsSnapshot`
|
|
212
|
+
* (clients/project-diagnostics/cache.ts:98) still uses, and the one this gate
|
|
213
|
+
* originally cited-but-withheld ("over-demoting costs a line number,
|
|
214
|
+
* under-demoting replays a false coordinate — the cheaper error wins the
|
|
215
|
+
* tie") — was not enough: on Windows a file's mtime can LEAD the immediately
|
|
216
|
+
* following `Date.now()` read by up to ~11.4ms, the same host skew
|
|
217
|
+
* `MTIME_DRIFT_TOLERANCE_MS` (`blocker-freshness.ts`) was raised to 50ms for
|
|
218
|
+
* (#1491/#1498). At +1ms this gate still demoted a real STOP-blocker (a
|
|
219
|
+
* trivy secret, #1628) to ACTION NEEDED, flaking
|
|
220
|
+
* tests/clients/runtime-turn-secrets-disposition.test.ts. Reusing the shared
|
|
221
|
+
* constant — rather than a second hand-tuned number — keeps one source of
|
|
222
|
+
* truth for the measured skew.
|
|
223
|
+
*/
|
|
224
|
+
export function findingPathFreshness(resolvedPath, scannedAtMs) {
|
|
203
225
|
try {
|
|
204
|
-
fs.statSync(resolvedPath);
|
|
226
|
+
const stat = fs.statSync(resolvedPath);
|
|
227
|
+
if (scannedAtMs !== undefined &&
|
|
228
|
+
stat.mtimeMs > scannedAtMs + MTIME_DRIFT_TOLERANCE_MS) {
|
|
229
|
+
return "stale";
|
|
230
|
+
}
|
|
205
231
|
return "live";
|
|
206
232
|
}
|
|
207
233
|
catch (error) {
|
|
@@ -211,14 +237,37 @@ export function findingPathExistence(resolvedPath) {
|
|
|
211
237
|
return code === "ENOENT" || code === "ENOTDIR" ? "missing" : "unknown";
|
|
212
238
|
}
|
|
213
239
|
}
|
|
240
|
+
/** Existence-only probe. Retained for callers that have no scan timestamp. */
|
|
241
|
+
export function findingPathExistence(resolvedPath) {
|
|
242
|
+
return findingPathFreshness(resolvedPath);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Parse a scan timestamp into epoch ms, or `undefined` when it cannot be
|
|
246
|
+
* trusted. `undefined` disables the staleness arm — never demote on a bad
|
|
247
|
+
* clock.
|
|
248
|
+
*/
|
|
249
|
+
export function parseScannedAtMs(scannedAt) {
|
|
250
|
+
if (scannedAt === undefined || scannedAt === null || scannedAt === "") {
|
|
251
|
+
return undefined;
|
|
252
|
+
}
|
|
253
|
+
const ms = typeof scannedAt === "number" ? scannedAt : Date.parse(scannedAt);
|
|
254
|
+
return Number.isFinite(ms) ? ms : undefined;
|
|
255
|
+
}
|
|
214
256
|
/**
|
|
215
|
-
* Partition findings into `{live, dropped}` by
|
|
216
|
-
*
|
|
217
|
-
* the partition rules are unit-testable without a filesystem.
|
|
257
|
+
* Partition findings into `{live, stale, dropped}` by what the path each one
|
|
258
|
+
* names looks like now. Pure apart from the `fs.statSync` probe, which is
|
|
259
|
+
* injectable so the partition rules are unit-testable without a filesystem.
|
|
260
|
+
*
|
|
261
|
+
* The stat memo lives in local `Map`s built fresh on every call — per delivery,
|
|
262
|
+
* never per process. A module-level cache here would be the process-lifetime
|
|
263
|
+
* latch shape: it would pin the first verdict for a path and re-serve it for
|
|
264
|
+
* every later turn, which is the very defect this gate exists to close.
|
|
218
265
|
*/
|
|
219
266
|
export function partitionFindingsByCitedPath(args) {
|
|
220
267
|
const limit = args.maxUniquePaths ?? MAX_FINDING_PATH_STATS;
|
|
221
|
-
const probe = args.existence ??
|
|
268
|
+
const probe = args.existence ?? findingPathFreshness;
|
|
269
|
+
const scannedAtMs = parseScannedAtMs(args.scannedAt);
|
|
270
|
+
const onMissing = args.onMissing ?? "drop";
|
|
222
271
|
// Two dedup layers, cheapest first. `rawVerdicts` collapses findings that
|
|
223
272
|
// cite the IDENTICAL string with zero filesystem work — the dominant case
|
|
224
273
|
// (#1460's live record: 126 findings over a handful of distinct `file`
|
|
@@ -232,8 +281,10 @@ export function partitionFindingsByCitedPath(args) {
|
|
|
232
281
|
const rawVerdicts = new Map();
|
|
233
282
|
const verdicts = new Map();
|
|
234
283
|
const live = [];
|
|
284
|
+
const stale = [];
|
|
235
285
|
const dropped = [];
|
|
236
286
|
const deadPaths = [];
|
|
287
|
+
const stalePaths = [];
|
|
237
288
|
let truncated = false;
|
|
238
289
|
for (const finding of args.findings) {
|
|
239
290
|
const cited = args.citedPath(finding);
|
|
@@ -261,20 +312,38 @@ export function partitionFindingsByCitedPath(args) {
|
|
|
261
312
|
verdict = "live";
|
|
262
313
|
}
|
|
263
314
|
else {
|
|
264
|
-
verdict = probe(resolved);
|
|
315
|
+
verdict = probe(resolved, scannedAtMs);
|
|
316
|
+
// A store that treats deletion as evidence-loss rather than
|
|
317
|
+
// remediation-loss folds `missing` into the demote arm here, so
|
|
318
|
+
// every downstream list and record sees one consistent verdict.
|
|
319
|
+
if (verdict === "missing" && onMissing === "demote") {
|
|
320
|
+
verdict = "stale";
|
|
321
|
+
}
|
|
265
322
|
verdicts.set(key, verdict);
|
|
266
323
|
if (verdict === "missing")
|
|
267
324
|
deadPaths.push(resolved);
|
|
325
|
+
else if (verdict === "stale")
|
|
326
|
+
stalePaths.push(resolved);
|
|
268
327
|
}
|
|
269
328
|
}
|
|
270
329
|
rawVerdicts.set(cited, verdict);
|
|
271
330
|
}
|
|
272
331
|
if (verdict === "missing")
|
|
273
332
|
dropped.push(finding);
|
|
333
|
+
else if (verdict === "stale")
|
|
334
|
+
stale.push(finding);
|
|
274
335
|
else
|
|
275
336
|
live.push(finding);
|
|
276
337
|
}
|
|
277
|
-
return {
|
|
338
|
+
return {
|
|
339
|
+
live,
|
|
340
|
+
stale,
|
|
341
|
+
dropped,
|
|
342
|
+
deadPaths,
|
|
343
|
+
stalePaths,
|
|
344
|
+
statCount: verdicts.size,
|
|
345
|
+
truncated,
|
|
346
|
+
};
|
|
278
347
|
}
|
|
279
348
|
/**
|
|
280
349
|
* Delivery-seam wrapper: partition, then emit one bounded `finding_dead_path_drop`
|
|
@@ -285,27 +354,71 @@ export function partitionFindingsByCitedPath(args) {
|
|
|
285
354
|
* store per delivery, with a capped path sample; never one per finding.
|
|
286
355
|
*/
|
|
287
356
|
export function dropFindingsForMissingPaths(args) {
|
|
357
|
+
// No `scannedAt` — existence-only, so `partition.stale` is always empty.
|
|
358
|
+
const partition = partitionFindingsByCitedPath(args);
|
|
359
|
+
emitDeadPathDropRecord(args.store, args.cwd, partition);
|
|
360
|
+
return partition.live;
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Delivery-seam wrapper with the #1622 freshness verdict. Emits at most one
|
|
364
|
+
* `finding_dead_path_drop` and one `finding_stale_line_demote` record per store
|
|
365
|
+
* per delivery, each with a capped path sample; never one per finding.
|
|
366
|
+
*
|
|
367
|
+
* Callers that have no scan timestamp keep using `dropFindingsForMissingPaths`.
|
|
368
|
+
*/
|
|
369
|
+
export function gateFindingsByPathFreshness(args) {
|
|
288
370
|
const partition = partitionFindingsByCitedPath(args);
|
|
371
|
+
emitDeadPathDropRecord(args.store, args.cwd, partition);
|
|
372
|
+
emitStaleLineDemoteRecord(args.store, args.cwd, args.scannedAt, partition);
|
|
373
|
+
return { live: partition.live, stale: partition.stale };
|
|
374
|
+
}
|
|
375
|
+
function emitDeadPathDropRecord(store, cwd, partition) {
|
|
289
376
|
if (partition.dropped.length === 0)
|
|
290
|
-
return
|
|
377
|
+
return;
|
|
291
378
|
logLatency({
|
|
292
379
|
type: "phase",
|
|
293
380
|
phase: "finding_dead_path_drop",
|
|
294
|
-
filePath:
|
|
381
|
+
filePath: cwd,
|
|
295
382
|
durationMs: 0,
|
|
296
383
|
metadata: {
|
|
297
|
-
store
|
|
384
|
+
store,
|
|
298
385
|
droppedDeadPaths: partition.dropped.length,
|
|
299
386
|
deadPathCount: partition.deadPaths.length,
|
|
300
387
|
deliveredCount: partition.live.length,
|
|
301
388
|
statCount: partition.statCount,
|
|
302
389
|
samplePaths: partition.deadPaths
|
|
303
390
|
.slice(0, MAX_LOGGED_DEAD_PATHS)
|
|
304
|
-
.map((deadPath) => toProjectRelativePath(deadPath,
|
|
391
|
+
.map((deadPath) => toProjectRelativePath(deadPath, cwd)),
|
|
392
|
+
...(partition.truncated ? { truncated: true } : {}),
|
|
393
|
+
},
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* #1622 criterion 5: the demote path gets the same record shape as the drop
|
|
398
|
+
* path. Before this, a stale-line replay window was reconstructible only by
|
|
399
|
+
* proxy — the blocker payload is written nowhere.
|
|
400
|
+
*/
|
|
401
|
+
function emitStaleLineDemoteRecord(store, cwd, scannedAt, partition) {
|
|
402
|
+
if (partition.stale.length === 0)
|
|
403
|
+
return;
|
|
404
|
+
logLatency({
|
|
405
|
+
type: "phase",
|
|
406
|
+
phase: "finding_stale_line_demote",
|
|
407
|
+
filePath: cwd,
|
|
408
|
+
durationMs: 0,
|
|
409
|
+
metadata: {
|
|
410
|
+
store,
|
|
411
|
+
demotedStalePaths: partition.stale.length,
|
|
412
|
+
stalePathCount: partition.stalePaths.length,
|
|
413
|
+
deliveredCount: partition.live.length,
|
|
414
|
+
statCount: partition.statCount,
|
|
415
|
+
samplePaths: partition.stalePaths
|
|
416
|
+
.slice(0, MAX_LOGGED_DEAD_PATHS)
|
|
417
|
+
.map((stalePath) => toProjectRelativePath(stalePath, cwd)),
|
|
418
|
+
...(scannedAt === undefined ? {} : { scannedAt: String(scannedAt) }),
|
|
305
419
|
...(partition.truncated ? { truncated: true } : {}),
|
|
306
420
|
},
|
|
307
421
|
});
|
|
308
|
-
return partition.live;
|
|
309
422
|
}
|
|
310
423
|
export function provenanceStamp(provenance) {
|
|
311
424
|
if (!isWellFormed(provenance))
|
|
@@ -68,12 +68,17 @@ function recordTouchedEvent(payload, getReadGuard) {
|
|
|
68
68
|
// recorded via the cross-process feed, now also reported by this
|
|
69
69
|
// session's own bus, upgrades to "local".
|
|
70
70
|
existing.origin = "local";
|
|
71
|
+
// #1464: a fresh touch invalidates any content already delivered for
|
|
72
|
+
// this path (the default deferred format at agent_end, a cascade
|
|
73
|
+
// autofix) — those bytes no longer describe the file.
|
|
74
|
+
existing.contentDelivered = false;
|
|
71
75
|
}
|
|
72
76
|
else {
|
|
73
77
|
_touched.set(mapKey, {
|
|
74
78
|
displayPath: rawPath,
|
|
75
79
|
reasons: new Set([payload.reason]),
|
|
76
80
|
origin: "local",
|
|
81
|
+
contentDelivered: false,
|
|
77
82
|
});
|
|
78
83
|
}
|
|
79
84
|
}
|
|
@@ -112,16 +117,47 @@ export function recordCrossProcessTouches(entries) {
|
|
|
112
117
|
existing.reasons.add(entry.reason);
|
|
113
118
|
// "local" is sticky (see AccumulatedFileOrigin) — never downgrade an
|
|
114
119
|
// already-local entry back to cross-process.
|
|
120
|
+
// #1464: a foreign process touching this file invalidates whatever
|
|
121
|
+
// content this session's write path already delivered for it.
|
|
122
|
+
existing.contentDelivered = false;
|
|
115
123
|
}
|
|
116
124
|
else {
|
|
117
125
|
_touched.set(mapKey, {
|
|
118
126
|
displayPath: entry.path,
|
|
119
127
|
reasons: new Set([entry.reason]),
|
|
120
128
|
origin: "cross-process",
|
|
129
|
+
contentDelivered: false,
|
|
121
130
|
});
|
|
122
131
|
}
|
|
123
132
|
}
|
|
124
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Record the write path's authoritative-content attachment outcome for one
|
|
136
|
+
* path (#1464).
|
|
137
|
+
*
|
|
138
|
+
* `attached` is the SAME boolean that drove the attachment in
|
|
139
|
+
* `handleToolResult` (clients/runtime-tool-result.ts) — this module never
|
|
140
|
+
* re-derives it from config, byte counts, or the aggregate budget. `true`
|
|
141
|
+
* means the post-fix bytes went out in the write's own tool result and the
|
|
142
|
+
* agent already holds them, so "re-read before editing" is noise. `false` is
|
|
143
|
+
* the size cap and the per-command aggregate budget degrading an attachment
|
|
144
|
+
* to a re-read warning: there the nudge is the whole signal, and calling this
|
|
145
|
+
* with `false` re-arms a path an earlier per-file decision had suppressed
|
|
146
|
+
* (the bash multi-file case, where the outer budget loop overrides the inner
|
|
147
|
+
* per-file "attached").
|
|
148
|
+
*
|
|
149
|
+
* Marks an EXISTING accumulator entry only. `publishFilesTouched` fires
|
|
150
|
+
* synchronously inside the `runPipeline` call this decision belongs to (pi's
|
|
151
|
+
* event bus is a plain `EventEmitter`), so the entry is already there for any
|
|
152
|
+
* path the relevance filter admitted; a path with no entry has nothing to
|
|
153
|
+
* suppress. Deferred-edit autofix at `agent_end` never reaches here — it
|
|
154
|
+
* attaches nothing, so it keeps nudging.
|
|
155
|
+
*/
|
|
156
|
+
export function noteAuthoritativeContentAttachment(filePath, attached) {
|
|
157
|
+
const entry = _touched.get(normalizeMapKey(filePath));
|
|
158
|
+
if (entry)
|
|
159
|
+
entry.contentDelivered = attached;
|
|
160
|
+
}
|
|
125
161
|
/**
|
|
126
162
|
* Subscribe to `pilens:files:touched` on pi's shared event bus. Called once
|
|
127
163
|
* at extension factory time from index.ts, mirroring `wireBusEmitter`'s
|
|
@@ -191,17 +227,29 @@ export function wireAgentNudgeSubscriber(args) {
|
|
|
191
227
|
* very first call of a fresh `agent_start` — so the accumulator surviving
|
|
192
228
|
* across run boundaries is exactly what makes that cross-run delivery work.
|
|
193
229
|
* Empty accumulator ⇒ returns undefined ⇒ zero bytes injected.
|
|
230
|
+
*
|
|
231
|
+
* #1464: paths whose post-fix content the write path already attached to its
|
|
232
|
+
* OWN tool result are dropped from the batch here (see
|
|
233
|
+
* `noteAuthoritativeContentAttachment`) — the agent holds those bytes, so
|
|
234
|
+
* "re-read before editing" would spend context to re-fetch what it has. A
|
|
235
|
+
* batch that is ENTIRELY such paths injects nothing.
|
|
194
236
|
*/
|
|
195
237
|
export function consumeAgentNudge(dbg) {
|
|
196
|
-
const
|
|
238
|
+
const drained = Array.from(_touched.values());
|
|
197
239
|
_touched.clear();
|
|
198
240
|
const filesFiltered = _relevanceFilteredCount;
|
|
199
241
|
_relevanceFilteredCount = 0;
|
|
200
242
|
if (!isAgentNudgeEnabled())
|
|
201
243
|
return undefined;
|
|
202
|
-
if (
|
|
244
|
+
if (drained.length === 0)
|
|
203
245
|
return undefined;
|
|
204
246
|
try {
|
|
247
|
+
// #1464: a write whose post-fix bytes were attached to its own tool
|
|
248
|
+
// result already told the agent everything this nudge would. Drop those
|
|
249
|
+
// paths from the message but keep counting them, so over-suppression is
|
|
250
|
+
// visible in telemetry instead of only in the absence of complaints.
|
|
251
|
+
const entries = drained.filter((e) => !e.contentDelivered);
|
|
252
|
+
const filesContentDelivered = drained.length - entries.length;
|
|
205
253
|
const filesTotal = entries.length;
|
|
206
254
|
const shown = entries.slice(0, MAX_NAMES_SHOWN);
|
|
207
255
|
const remaining = filesTotal - shown.length;
|
|
@@ -225,15 +273,6 @@ export function consumeAgentNudge(dbg) {
|
|
|
225
273
|
: names.join(", ");
|
|
226
274
|
const crossProcessCount = entries.filter((e) => e.origin === "cross-process").length;
|
|
227
275
|
const localCount = filesTotal - crossProcessCount;
|
|
228
|
-
// Three-way attribution (see the function doc): never assign a local
|
|
229
|
-
// file to another instance — a mixed batch keeps the local base framing
|
|
230
|
-
// and calls out the cross-process portion by exact count.
|
|
231
|
-
const attribution = localCount === 0
|
|
232
|
-
? "by an automatic run outside your turn"
|
|
233
|
-
: crossProcessCount === 0
|
|
234
|
-
? "after your last turn"
|
|
235
|
-
: `after your last turn (${crossProcessCount} of them by an automatic run outside it)`;
|
|
236
|
-
const message = `pi-lens: ${filesTotal} file(s) were ${verbLabel} ${attribution}: ${nameList} — working-tree changes to these are expected; re-read before editing.`;
|
|
237
276
|
logLatency({
|
|
238
277
|
type: "phase",
|
|
239
278
|
filePath: "<pi-lens>",
|
|
@@ -246,6 +285,10 @@ export function consumeAgentNudge(dbg) {
|
|
|
246
285
|
// never read/edited) — NOT the display overflow, which is
|
|
247
286
|
// filesTotal - filesShown.
|
|
248
287
|
filesFiltered,
|
|
288
|
+
// #1464: drops because the write's own tool result already carried
|
|
289
|
+
// the post-fix bytes. A third, distinct count: these paths passed
|
|
290
|
+
// the relevance filter and were accumulated, then suppressed here.
|
|
291
|
+
filesContentDelivered,
|
|
249
292
|
reasonMix: Array.from(allReasons),
|
|
250
293
|
// #492: origin mix so cross-process pickup rate is observable
|
|
251
294
|
// alongside the existing relevance-filter metric.
|
|
@@ -253,6 +296,19 @@ export function consumeAgentNudge(dbg) {
|
|
|
253
296
|
originCrossProcess: crossProcessCount,
|
|
254
297
|
},
|
|
255
298
|
});
|
|
299
|
+
// Everything drained was delivered in a write's own tool result — the
|
|
300
|
+
// row above records that it happened, and zero bytes get injected.
|
|
301
|
+
if (filesTotal === 0)
|
|
302
|
+
return undefined;
|
|
303
|
+
// Three-way attribution (see the function doc): never assign a local
|
|
304
|
+
// file to another instance — a mixed batch keeps the local base framing
|
|
305
|
+
// and calls out the cross-process portion by exact count.
|
|
306
|
+
const attribution = localCount === 0
|
|
307
|
+
? "by an automatic run outside your turn"
|
|
308
|
+
: crossProcessCount === 0
|
|
309
|
+
? "after your last turn"
|
|
310
|
+
: `after your last turn (${crossProcessCount} of them by an automatic run outside it)`;
|
|
311
|
+
const message = `pi-lens: ${filesTotal} file(s) were ${verbLabel} ${attribution}: ${nameList} — working-tree changes to these are expected; re-read before editing.`;
|
|
256
312
|
return {
|
|
257
313
|
messages: [
|
|
258
314
|
{
|
|
@@ -176,9 +176,12 @@ export class AstGrepClient {
|
|
|
176
176
|
* Each path is scanned independently; results are merged.
|
|
177
177
|
*/
|
|
178
178
|
async tempScanDetailed(dir, ruleYaml, options = {}) {
|
|
179
|
-
//
|
|
180
|
-
// match-only seam working. The
|
|
181
|
-
//
|
|
179
|
+
// SAFETY: keep tests and older embedders that replace the runner with the
|
|
180
|
+
// historic match-only seam working. The cast only makes
|
|
181
|
+
// `tempScanDetailedAsync` OPTIONAL on the runner surface — it claims
|
|
182
|
+
// nothing about the method existing. The call site below checks for it
|
|
183
|
+
// before invoking, and the production SgRunner always has it, so a
|
|
184
|
+
// failure there cannot be mistaken for an empty result.
|
|
182
185
|
const detailed = this.runner.tempScanDetailedAsync;
|
|
183
186
|
if (detailed) {
|
|
184
187
|
return detailed.call(this.runner, dir, "agent-rule", ruleYaml, 30_000, options);
|
|
@@ -568,12 +571,15 @@ message: found
|
|
|
568
571
|
return "";
|
|
569
572
|
const errors = diags.filter((d) => d.severity === "error");
|
|
570
573
|
const warnings = diags.filter((d) => d.severity === "warning");
|
|
574
|
+
const infos = diags.filter((d) => d.severity === "info");
|
|
571
575
|
const hints = diags.filter((d) => d.severity === "hint");
|
|
572
576
|
let output = `[ast-grep] ${diags.length} structural issue(s)`;
|
|
573
577
|
if (errors.length)
|
|
574
578
|
output += ` — ${errors.length} error(s)`;
|
|
575
579
|
if (warnings.length)
|
|
576
580
|
output += ` — ${warnings.length} warning(s)`;
|
|
581
|
+
if (infos.length)
|
|
582
|
+
output += ` — ${infos.length} info(s)`;
|
|
577
583
|
if (hints.length)
|
|
578
584
|
output += ` — ${hints.length} hint(s)`;
|
|
579
585
|
output += ":\n";
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
* cycles still lose updates: each writer publishes the state it computed
|
|
39
39
|
* from the snapshot it read, and last-rename-wins silently discards the
|
|
40
40
|
* other's mutation. Callers needing this must serialize themselves (see
|
|
41
|
-
* `
|
|
41
|
+
* `registryChildMutationTail` in `instance-registry.ts`).
|
|
42
42
|
* - **No ordering.** Nothing sequences concurrent writers, within or across
|
|
43
43
|
* processes. The winner is whichever `rename` lands last, which is not
|
|
44
44
|
* necessarily the write that started or finished last.
|
|
@@ -143,7 +143,10 @@ export function writeFileAtomic(targetPath, data, options) {
|
|
|
143
143
|
const bestEffort = options?.bestEffort ?? true;
|
|
144
144
|
const tmpPath = stagePathFor(targetPath);
|
|
145
145
|
try {
|
|
146
|
-
fs.writeFileSync(tmpPath, data,
|
|
146
|
+
fs.writeFileSync(tmpPath, data, {
|
|
147
|
+
encoding: typeof data === "string" ? "utf-8" : undefined,
|
|
148
|
+
mode: options?.mode,
|
|
149
|
+
});
|
|
147
150
|
fs.renameSync(tmpPath, targetPath);
|
|
148
151
|
}
|
|
149
152
|
catch (err) {
|
|
@@ -167,7 +170,10 @@ export async function writeFileAtomicAsync(targetPath, data, options) {
|
|
|
167
170
|
const bestEffort = options?.bestEffort ?? true;
|
|
168
171
|
const tmpPath = stagePathFor(targetPath);
|
|
169
172
|
try {
|
|
170
|
-
await fs.promises.writeFile(tmpPath, data,
|
|
173
|
+
await fs.promises.writeFile(tmpPath, data, {
|
|
174
|
+
encoding: typeof data === "string" ? "utf-8" : undefined,
|
|
175
|
+
mode: options?.mode,
|
|
176
|
+
});
|
|
171
177
|
await fs.promises.rename(tmpPath, targetPath);
|
|
172
178
|
}
|
|
173
179
|
catch (err) {
|