@herbertgao/pi-extensions 2026.8.6 → 2026.8.7
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 +5 -5
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +1 -1
- 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 +272 -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 +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +14 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +55 -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 +1 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +26 -10
- 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 +2 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +3 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +2 -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 +3 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +30 -7
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +30 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +26 -5
- 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-lens/CHANGELOG.md +909 -0
- package/node_modules/pi-lens/README.md +11 -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 +285 -8
- 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 +119 -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 +192 -0
- 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 +62 -13
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -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/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/helm-render.js +895 -0
- 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 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +23 -0
- 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 +14 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +20 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +22 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +10 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +18 -6
- 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 +72 -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 +9 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -1
- 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 +294 -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 +82 -6
- 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 +2 -0
- 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 +102 -7
- package/node_modules/pi-lens/dist/clients/lsp/client.js +1516 -159
- 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 +2274 -147
- 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 +8 -0
- 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 +5 -0
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
- 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 +1 -1
- package/node_modules/pi-lens/dist/clients/read-guard.js +184 -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/query.js +52 -4
- 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 +308 -45
- package/node_modules/pi-lens/dist/clients/runtime-session.js +332 -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 +575 -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/sg-runner.js +116 -22
- package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
- package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
- 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-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 +67738 -55739
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +466 -54
- 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 +10 -6
- 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/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 +23 -0
- package/node_modules/pi-web-access/README.md +27 -9
- 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/curator-page.ts +6 -3
- package/node_modules/pi-web-access/curator-server.ts +4 -1
- package/node_modules/pi-web-access/exa.ts +18 -7
- package/node_modules/pi-web-access/extract.ts +28 -3
- package/node_modules/pi-web-access/gemini-search.ts +16 -4
- package/node_modules/pi-web-access/index.ts +41 -57
- 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/query-rewrite.ts +51 -0
- package/node_modules/pi-web-access/serper.ts +211 -0
- 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 +13 -13
|
@@ -9,6 +9,31 @@ note: |
|
|
|
9
9
|
the `unsafe` keyword should be removed) or it is misplaced (an unsafe
|
|
10
10
|
operation lives outside an `unsafe { … }` block and should be wrapped).
|
|
11
11
|
Either case warrants review.
|
|
12
|
+
|
|
13
|
+
Exempt when a `/// # Safety` doc-comment section precedes the function:
|
|
14
|
+
Rust's own convention (rustdoc's `missing_safety_doc` lint, and
|
|
15
|
+
clippy's `undocumented_unsafe_blocks`) is that an `unsafe fn` states
|
|
16
|
+
its caller obligations in a `# Safety` doc section instead of wrapping
|
|
17
|
+
its whole body in a redundant `unsafe { ... }` block — the function
|
|
18
|
+
signature IS the unsafe boundary, the doc section is where the
|
|
19
|
+
contract lives.
|
|
20
|
+
|
|
21
|
+
2026-08-20 (review round, refs #1806): the first ship of this valve
|
|
22
|
+
used `follows: {stopBy: end, kind: line_comment, regex: '#\s*Safety'}`,
|
|
23
|
+
copying the `SAFETY:`-comment shape from `no-chained-type-assertions`
|
|
24
|
+
too literally. `stopBy: end` scans EVERY preceding sibling all the way
|
|
25
|
+
to the top of the file — one `# Safety` comment ANYWHERE earlier
|
|
26
|
+
(a stray file-top note, or a doc block that belongs to a DIFFERENT,
|
|
27
|
+
earlier function) exempted every `unsafe fn` after it. Probe: a
|
|
28
|
+
documented function followed by two undocumented ones scored 0 hits;
|
|
29
|
+
the two alone scored 2. Fixed by bounding the backward scan with
|
|
30
|
+
`stopBy: {not: {kind: line_comment}}` — it stops at the first
|
|
31
|
+
non-comment sibling, so only the CONTIGUOUS run of `///`/`//` lines
|
|
32
|
+
directly above the function is searched, never an earlier function's
|
|
33
|
+
doc block or an unrelated comment further up the file. (This valve
|
|
34
|
+
shipped with zero corpus hits either side in the original PR —
|
|
35
|
+
corpus silence isn't proof of correctness; the fixtures below are
|
|
36
|
+
the whole evidence, deliberately adversarial.)
|
|
12
37
|
rule:
|
|
13
38
|
all:
|
|
14
39
|
- kind: function_item
|
|
@@ -19,3 +44,10 @@ rule:
|
|
|
19
44
|
has:
|
|
20
45
|
kind: unsafe_block
|
|
21
46
|
stopBy: end
|
|
47
|
+
- not:
|
|
48
|
+
follows:
|
|
49
|
+
stopBy:
|
|
50
|
+
not:
|
|
51
|
+
kind: line_comment
|
|
52
|
+
kind: line_comment
|
|
53
|
+
regex: '#\s*Safety'
|
package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
id: require-safety-comment-for-as-unknown-as
|
|
2
|
+
language: TypeScript
|
|
3
|
+
severity: error
|
|
4
|
+
metadata:
|
|
5
|
+
category: pi-lens-self-scan
|
|
6
|
+
message: "'x as unknown as T' with no nearby SAFETY: comment — state the invariant TypeScript can't check"
|
|
7
|
+
note: |
|
|
8
|
+
Narrowed port of dmmulroy/anti-slop's
|
|
9
|
+
`require-safety-comment-for-type-assertion`
|
|
10
|
+
(src/rules/require-safety-comment-for-type-assertion.ts, MIT).
|
|
11
|
+
Upstream requires a `SAFETY:` comment before EVERY non-const type
|
|
12
|
+
assertion (`as`/angle-bracket), walking up through statement-owner
|
|
13
|
+
node kinds looking for a preceding comment. This port narrows the
|
|
14
|
+
target to `x as unknown as T` specifically — the two-hop cast through
|
|
15
|
+
`unknown`. The 2026-08-19 audit found 2,180 non-const assertions
|
|
16
|
+
repo-wide and ZERO `SAFETY:` comments; requiring one on every
|
|
17
|
+
assertion would mean authoring ~1,750 comments in one PR. `as unknown
|
|
18
|
+
as` is the form that actually launders evidence (routes through the
|
|
19
|
+
top type rather than a single verifiable hop), and it is the exact
|
|
20
|
+
shape AGENTS.md's defect shape 13 already asks for in prose: "when a
|
|
21
|
+
call site hands the policy an outcome it did NOT derive... justify it
|
|
22
|
+
in a comment at the call site." This rule makes that convention
|
|
23
|
+
checkable for its most evidence-destroying form.
|
|
24
|
+
|
|
25
|
+
2026-08-20 (refs #1727, #1777): promoted `hint` -> `error`. `error` is
|
|
26
|
+
the only tier that maps to semantic `blocking`
|
|
27
|
+
(`clients/dispatch/runners/ast-grep-napi.ts`), so AGENTS.md's severity
|
|
28
|
+
policy requires a documented zero-false-positive audit here. Two
|
|
29
|
+
changes make that audit come out clean.
|
|
30
|
+
|
|
31
|
+
1. STRUCTURAL SCOPING: test paths are excluded (`ignores:` below). In a
|
|
32
|
+
test, `x as unknown as T` is almost always a partial test double —
|
|
33
|
+
reaching into a private field or stubbing the two methods of a
|
|
34
|
+
surface the subject actually calls. The "invariant TypeScript can't
|
|
35
|
+
check" there is "this stub covers what the code under test touches",
|
|
36
|
+
which is the test's own subject matter, not a hidden runtime claim.
|
|
37
|
+
Four-corpus census (2026-08-20) confirms the shape concentrates in
|
|
38
|
+
test paths rather than assuming it:
|
|
39
|
+
|
|
40
|
+
| corpus | total | test-path | non-test | suppressed |
|
|
41
|
+
|---|---:|---:|---:|---:|
|
|
42
|
+
| pi-lens (`clients/`+`tests/`) | 305 | 289 | 16 | 95% |
|
|
43
|
+
| pi core (`packages/`) | 182 | 155 | 27 | 85% |
|
|
44
|
+
| opencode (`packages/`) | 194 | 154 | 40 | 79% |
|
|
45
|
+
| oh-my-pi (`packages/`) | 1803 | 1644 | 159 | 91% |
|
|
46
|
+
|
|
47
|
+
This is a FALSE-NEGATIVE bias, deliberately, and it is not small:
|
|
48
|
+
289 uncommented `as unknown as` sites in pi-lens's own `tests/`
|
|
49
|
+
now raise NO diagnostic at all, where each previously raised an
|
|
50
|
+
`error` through `no-chained-type-assertions.yml`'s `unknown` arm.
|
|
51
|
+
The same trade costs 1,644 sites on oh-my-pi. It is a path glob,
|
|
52
|
+
not a semantic check — ast-grep cannot verify a cast is really a
|
|
53
|
+
test double, only that it lives under a test path.
|
|
54
|
+
|
|
55
|
+
2. REPO-SIDE REMEDIATION: the 16 remaining `clients/` sites were read
|
|
56
|
+
individually and each was given a truthful `SAFETY:` comment
|
|
57
|
+
naming the specific invariant (an optional Node API absent from
|
|
58
|
+
`@types/node`, a two-phase-init field filled before first read, a
|
|
59
|
+
`Object.fromEntries` key-type loss, a process-global stash). None
|
|
60
|
+
was a comment written to silence the rule; where the cast had no
|
|
61
|
+
justification it was replaced instead
|
|
62
|
+
(`clients/runtime-context.ts`).
|
|
63
|
+
|
|
64
|
+
Post-narrowing census on pi-lens: 0 findings over `clients/` +
|
|
65
|
+
`tests/`. The rule is tagged `metadata.category: pi-lens-self-scan`,
|
|
66
|
+
so CI's `npm run astgrep:self-scan` lane keeps it at zero.
|
|
67
|
+
|
|
68
|
+
Placement contract: a `SAFETY:` comment may directly precede the cast,
|
|
69
|
+
its enclosing statement, or an object-literal member (`pair`) containing
|
|
70
|
+
the cast. Array elements and call arguments are also supported through the
|
|
71
|
+
direct-cast arm when the comment is immediately above the cast expression.
|
|
72
|
+
JSX attributes, class static blocks, and switch cases are not comment
|
|
73
|
+
anchors for this valve; place those comments on the enclosing statement.
|
|
74
|
+
Inline comments remain valid, for example `/* SAFETY: ... */ x as unknown
|
|
75
|
+
as T`. Upstream walks an arbitrary number of statement-owner levels looking
|
|
76
|
+
for ANY preceding comment in the file; this port only checks one level up
|
|
77
|
+
from the assertion and one level up from its immediate containing
|
|
78
|
+
statement or supported object member. There is NO dominance verification:
|
|
79
|
+
the rule proves a comment is adjacent, never that the comment is true or
|
|
80
|
+
that it describes this cast.
|
|
81
|
+
|
|
82
|
+
2026-08-20 (#1847, found in #1843's review): the "one level up from
|
|
83
|
+
its immediate containing statement" kind list omitted
|
|
84
|
+
`export_statement` and `public_field_definition`, so a `SAFETY:`
|
|
85
|
+
comment placed directly above an exported cast (`export const b =
|
|
86
|
+
(x as unknown as T).y;`) or a class-field cast (`bar: unknown = (x as
|
|
87
|
+
unknown as T).y;`) could not satisfy the valve — the rule is
|
|
88
|
+
`error`-tier and semantically `blocking`, so this left no escape for
|
|
89
|
+
those two shapes. Added both kinds. Verified the containing-statement
|
|
90
|
+
walk already covers casts nested deeper without a new kind: a cast
|
|
91
|
+
inside a `static {}` init block or an arrow-function body still
|
|
92
|
+
resolves to an ancestor `lexical_declaration`/`variable_declaration`
|
|
93
|
+
already in the list (probed with ast-grep's own `--rule` scan, not
|
|
94
|
+
reasoning about the grammar from memory), and a `SAFETY:` comment on
|
|
95
|
+
an `export const` nested inside a `namespace` block clears the valve
|
|
96
|
+
through the same `export_statement` kind — `stopBy: end` already
|
|
97
|
+
walks past the namespace wrapper to find it. `readonly`/`abstract`/
|
|
98
|
+
`static`/private-`#name` class fields all parse to the same
|
|
99
|
+
`public_field_definition` kind, so one entry covers all of them.
|
|
100
|
+
|
|
101
|
+
2026-08-20 (#1852 review, F1): the same defect shape one more time —
|
|
102
|
+
an enum member's initializer cast (`enum Foo { A = (x as unknown as
|
|
103
|
+
T).y }`) has no recognized ancestor either. The member's own kind is
|
|
104
|
+
`enum_assignment` (probed the same way: `ast-grep scan --rule` against
|
|
105
|
+
a real `enum`/`const enum`/`export enum` snippet rather than guessing
|
|
106
|
+
from the export/field precedent). One `enum_assignment` kind entry
|
|
107
|
+
covers plain, `const`, and `export` enums alike, the same way
|
|
108
|
+
`public_field_definition` covered every class-field modifier —
|
|
109
|
+
`enum_assignment` is the member-list node itself, unaffected by
|
|
110
|
+
keywords on the enclosing `enum_declaration`. `declare enum` members
|
|
111
|
+
have no initializer expression to cast, so there is nothing to probe
|
|
112
|
+
there.
|
|
113
|
+
|
|
114
|
+
Matched pair with `no-chained-type-assertions.yml`. As of 2026-08-20
|
|
115
|
+
the two PARTITION the assertion space instead of overlapping: this
|
|
116
|
+
rule owns `x as unknown as T` (with the `SAFETY:` escape valve); that
|
|
117
|
+
rule owns the concrete `x as A as B` chain, which has no escape valve
|
|
118
|
+
because it has no legitimate reading. Before the split both rules
|
|
119
|
+
matched the identical `as unknown as` site list (verified: 16/16
|
|
120
|
+
pi-lens, 182/182 pi, 194/194 opencode), so every uncommented site
|
|
121
|
+
raised two diagnostics for one defect.
|
|
122
|
+
|
|
123
|
+
2026-08-20 (#1834): both `follows` checks used `stopBy: end`, which
|
|
124
|
+
scans EVERY preceding sibling all the way to the top of the enclosing
|
|
125
|
+
block, not just the comment directly above the cast. A `SAFETY:`
|
|
126
|
+
comment attached to one cast silently exempted every LATER cast in the
|
|
127
|
+
same block, including casts on a different subject with no
|
|
128
|
+
justification of their own. Probe: `// SAFETY: ...` above `const a =
|
|
129
|
+
(y as unknown as string).length` followed by an undocumented `const b
|
|
130
|
+
= (x as unknown as string).length` scored 0 hits; `b`'s cast should
|
|
131
|
+
have been flagged. Fixed the same way as `redundant-unsafe-function`'s
|
|
132
|
+
identical valve (PR #1821, refs #1806): bound the backward scan with
|
|
133
|
+
`stopBy: {not: {kind: comment}}`, so it stops at the first non-comment
|
|
134
|
+
sibling and only ever searches the CONTIGUOUS comment run directly
|
|
135
|
+
above the cast (or its containing statement), never an earlier
|
|
136
|
+
statement's comment. The "Scope and known gap" note above already
|
|
137
|
+
described this contiguous-comment intent; the shipped pattern didn't
|
|
138
|
+
implement it.
|
|
139
|
+
|
|
140
|
+
2026-08-20 (#1870): the pair arm is bounded by the nearest `pair`. An
|
|
141
|
+
outer object member's SAFETY comment must not suppress a cast in a nested
|
|
142
|
+
member, and a nested member's comment must not suppress a parent cast.
|
|
143
|
+
The direct-cast arm remains the precise escape valve for comments adjacent
|
|
144
|
+
to casts in array elements and call arguments.
|
|
145
|
+
ignores:
|
|
146
|
+
- "**/*.test.ts"
|
|
147
|
+
- "**/*.test.tsx"
|
|
148
|
+
- "**/*.test.mts"
|
|
149
|
+
- "**/*.test.cts"
|
|
150
|
+
- "**/*.spec.ts"
|
|
151
|
+
- "**/*.spec.tsx"
|
|
152
|
+
- "**/tests/**"
|
|
153
|
+
- "**/test/**"
|
|
154
|
+
- "**/__tests__/**"
|
|
155
|
+
rule:
|
|
156
|
+
pattern: $X as unknown as $Y
|
|
157
|
+
not:
|
|
158
|
+
any:
|
|
159
|
+
- follows:
|
|
160
|
+
kind: comment
|
|
161
|
+
regex: 'SAFETY\s*:'
|
|
162
|
+
stopBy: { not: { kind: comment } }
|
|
163
|
+
- inside:
|
|
164
|
+
stopBy: { kind: pair }
|
|
165
|
+
any:
|
|
166
|
+
- kind: pair
|
|
167
|
+
follows:
|
|
168
|
+
kind: comment
|
|
169
|
+
regex: 'SAFETY\s*:'
|
|
170
|
+
stopBy: { not: { kind: comment } }
|
|
171
|
+
- inside:
|
|
172
|
+
stopBy: end
|
|
173
|
+
any:
|
|
174
|
+
- kind: expression_statement
|
|
175
|
+
- kind: lexical_declaration
|
|
176
|
+
- kind: variable_declaration
|
|
177
|
+
- kind: return_statement
|
|
178
|
+
- kind: export_statement
|
|
179
|
+
- kind: public_field_definition
|
|
180
|
+
- kind: enum_assignment
|
|
181
|
+
follows:
|
|
182
|
+
kind: comment
|
|
183
|
+
regex: 'SAFETY\s*:'
|
|
184
|
+
stopBy: { not: { kind: comment } }
|
|
@@ -5,6 +5,11 @@ message: void 0 for undefined - use undefined directly
|
|
|
5
5
|
metadata:
|
|
6
6
|
weight: 2
|
|
7
7
|
category: slop
|
|
8
|
+
note: |
|
|
9
|
+
Replacing `void 0` with `undefined` can change behavior when a local binding
|
|
10
|
+
shadows `undefined`. Shadowing `undefined` is itself a defect, and this fix
|
|
11
|
+
does not attempt to detect it.
|
|
8
12
|
rule:
|
|
9
13
|
kind: unary_expression
|
|
10
14
|
pattern: "void 0"
|
|
15
|
+
fix: undefined
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Regenerate with `npm run astgrep:self-scan -- --update-baseline` AFTER triaging every new entry (fix the underlying finding, or confirm it's a legitimate exception and document why in the same PR). Never regenerate to silently swallow an unreviewed hit.",
|
|
3
|
+
"generatedAt": "2026-08-19T20:44:05.206Z",
|
|
4
|
+
"allowed": []
|
|
5
|
+
}
|
|
@@ -202,6 +202,13 @@ function createState(files) {
|
|
|
202
202
|
aborted: 0,
|
|
203
203
|
timedOutSweeps: 0,
|
|
204
204
|
timedOutFilesTotal: 0,
|
|
205
|
+
// #1618: per-reason breakdown of the same total. Populated from each
|
|
206
|
+
// sweep's `unconfirmedByReason` metadata when present; a sweep logged
|
|
207
|
+
// by a pre-#1618 build carries no such field, so its files are
|
|
208
|
+
// bucketed under "budget (pre-#1618 build)" — the ABSENT field is
|
|
209
|
+
// itself the vintage signal, not an assumption that every one of
|
|
210
|
+
// those files really was a budget timeout.
|
|
211
|
+
unconfirmedByReason: counter(),
|
|
205
212
|
sweeps: [],
|
|
206
213
|
progress: [],
|
|
207
214
|
},
|
|
@@ -367,6 +374,27 @@ async function analyzeLatency(files, state) {
|
|
|
367
374
|
if (timedOut > 0) {
|
|
368
375
|
ws.timedOutSweeps += 1;
|
|
369
376
|
ws.timedOutFilesTotal += timedOut;
|
|
377
|
+
// #1618: attribute by the REAL per-reason tally when the build
|
|
378
|
+
// that wrote this log line has it — a service-destroyed file
|
|
379
|
+
// must never count toward "hit the per-file budget" the way it
|
|
380
|
+
// used to (the forensics tool that found #1618 in the first
|
|
381
|
+
// place read this exact field and mis-blamed budget exhaustion
|
|
382
|
+
// for what were mostly service-destroyed files).
|
|
383
|
+
const byReason = entry.metadata?.unconfirmedByReason;
|
|
384
|
+
if (byReason && typeof byReason === "object") {
|
|
385
|
+
for (const [reason, count] of Object.entries(byReason)) {
|
|
386
|
+
const n = Number(count) || 0;
|
|
387
|
+
if (n > 0) ws.unconfirmedByReason.inc(reason, n);
|
|
388
|
+
}
|
|
389
|
+
} else {
|
|
390
|
+
// Vintage-attribution fallback: no `unconfirmedByReason` means
|
|
391
|
+
// this line predates #1618 — the absent field IS the signal,
|
|
392
|
+
// not proof every file here was really a budget timeout.
|
|
393
|
+
ws.unconfirmedByReason.inc(
|
|
394
|
+
"budget (pre-#1618 build)",
|
|
395
|
+
timedOut,
|
|
396
|
+
);
|
|
397
|
+
}
|
|
370
398
|
state.smellTotals.inc("lsp-workspace-file-timeouts");
|
|
371
399
|
pushTop(
|
|
372
400
|
ws.sweeps,
|
|
@@ -1217,11 +1245,21 @@ function buildReport(state) {
|
|
|
1217
1245
|
"Full LSP workspace sweeps that logged a start but never a completion (hang/kill signature — the 8h-hang class #383 hardened)",
|
|
1218
1246
|
ws.progress.slice(0, limit),
|
|
1219
1247
|
);
|
|
1248
|
+
// #1618: "hit the per-file budget" used to be this smell's blanket
|
|
1249
|
+
// description regardless of WHY a file was unconfirmed — the exact
|
|
1250
|
+
// mislabeling the forensics pass on this class found (81/111 "budget"
|
|
1251
|
+
// files were actually service-destroyed). Render the real breakdown when
|
|
1252
|
+
// available.
|
|
1253
|
+
const unconfirmedReasonBreakdown = ws.unconfirmedByReason
|
|
1254
|
+
.top(limit)
|
|
1255
|
+
.map(({ key, count }) => `${key}=${count}`)
|
|
1256
|
+
.join(", ");
|
|
1220
1257
|
addSmell(
|
|
1221
1258
|
smells,
|
|
1222
1259
|
"lsp-workspace-file-timeouts",
|
|
1223
1260
|
smellCount("lsp-workspace-file-timeouts"),
|
|
1224
|
-
`Full LSP sweeps
|
|
1261
|
+
`Full LSP sweeps produced an unconfirmed file (${ws.timedOutFilesTotal} files across ${ws.timedOutSweeps} sweeps)` +
|
|
1262
|
+
(unconfirmedReasonBreakdown ? ` — by reason: ${unconfirmedReasonBreakdown}` : ""),
|
|
1225
1263
|
ws.sweeps.slice(0, limit),
|
|
1226
1264
|
);
|
|
1227
1265
|
|
|
@@ -1257,6 +1295,11 @@ function buildReport(state) {
|
|
|
1257
1295
|
aborted: ws.aborted,
|
|
1258
1296
|
timedOutSweeps: ws.timedOutSweeps,
|
|
1259
1297
|
timedOutFilesTotal: ws.timedOutFilesTotal,
|
|
1298
|
+
// #1618: the real per-reason breakdown of `timedOutFilesTotal`.
|
|
1299
|
+
// "budget (pre-#1618 build)" means those log lines predate the
|
|
1300
|
+
// per-reason tally entirely — an older build's absence of the field,
|
|
1301
|
+
// not a claim those files really timed out.
|
|
1302
|
+
unconfirmedByReason: ws.unconfirmedByReason.toJSON(),
|
|
1260
1303
|
},
|
|
1261
1304
|
},
|
|
1262
1305
|
cascade: {
|
|
@@ -1458,6 +1501,15 @@ function printReport(report) {
|
|
|
1458
1501
|
console.log(
|
|
1459
1502
|
` started=${ws.started} completed=${ws.completed} incomplete=${ws.incomplete} aborted=${ws.aborted} fileTimeouts=${ws.timedOutFilesTotal} (in ${ws.timedOutSweeps} sweeps)`,
|
|
1460
1503
|
);
|
|
1504
|
+
// #1618: never let a flat count alone read as "budget exhaustion" —
|
|
1505
|
+
// print the real per-reason split (or its absence, which itself means
|
|
1506
|
+
// every line here predates the tally).
|
|
1507
|
+
const reasons = Object.entries(ws.unconfirmedByReason ?? {});
|
|
1508
|
+
if (reasons.length) {
|
|
1509
|
+
console.log(
|
|
1510
|
+
` by reason: ${reasons.map(([reason, count]) => `${reason}=${count}`).join(", ")}`,
|
|
1511
|
+
);
|
|
1512
|
+
}
|
|
1461
1513
|
}
|
|
1462
1514
|
const wl = report.worklog;
|
|
1463
1515
|
if (wl && (wl.byModel.length || wl.byRuleModel.length)) {
|
|
@@ -39,6 +39,24 @@ export const SOURCE_OVERRIDES = {
|
|
|
39
39
|
url: "https://unpkg.com/@tree-sitter-grammars/tree-sitter-yaml@0.7.1/tree-sitter-yaml.wasm",
|
|
40
40
|
},
|
|
41
41
|
};
|
|
42
|
+
/**
|
|
43
|
+
* Grammars committed under `vendor/grammars/` rather than fetched.
|
|
44
|
+
*
|
|
45
|
+
* tree-sitter-cue: no published wasm exists — npm's `tree-sitter-cue` is a
|
|
46
|
+
* native binding, the `tree-sitter-wasms` aggregator has no CUE, and upstream
|
|
47
|
+
* cuts no releases — so we build it from a pinned commit (#1522).
|
|
48
|
+
*/
|
|
49
|
+
export const VENDORED_GRAMMARS = {
|
|
50
|
+
"tree-sitter-cue.wasm": {
|
|
51
|
+
repo: "https://github.com/eonpatapon/tree-sitter-cue",
|
|
52
|
+
commit: "dd7b90e0770ff18070c515937ba3c3d6d93db00e",
|
|
53
|
+
license: "MIT",
|
|
54
|
+
buildCommand: "npx tree-sitter-cli build --wasm",
|
|
55
|
+
sha256: "sha256:751f8cc8ccf72da760133e3d365562ff7bbf5b951e0b73568576fd159db7d601",
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
/** Directory the committed grammars live in, relative to the package root. */
|
|
59
|
+
export const VENDORED_DIR = "vendor/grammars";
|
|
42
60
|
/** The package a grammar's sidecar records (override or the global aggregator). */
|
|
43
61
|
export function expectedPackage(filename, manifest) {
|
|
44
62
|
return manifest.overrides?.[filename]?.package ?? SOURCE_OVERRIDES[filename]?.package ?? manifest.package;
|
|
@@ -210,6 +228,13 @@ async function regenerateManifest() {
|
|
|
210
228
|
version: TREE_SITTER_WASMS_VERSION,
|
|
211
229
|
grammars: sorted,
|
|
212
230
|
...(Object.keys(SOURCE_OVERRIDES).length ? { overrides: SOURCE_OVERRIDES } : {}),
|
|
231
|
+
// Re-emitted from the map above, not copied from the old manifest: a
|
|
232
|
+
// `--write-manifest` run on a tree-sitter-wasms bump must not silently
|
|
233
|
+
// drop the committed grammars' provenance, which would leave the guard
|
|
234
|
+
// with nothing to check.
|
|
235
|
+
...(Object.keys(VENDORED_GRAMMARS).length
|
|
236
|
+
? { vendored: VENDORED_GRAMMARS }
|
|
237
|
+
: {}),
|
|
213
238
|
};
|
|
214
239
|
writeFileSync(MANIFEST_PATH, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
215
240
|
console.error(`Wrote ${MANIFEST_PATH} (${GRAMMARS.length} grammars).`);
|
|
@@ -40,5 +40,14 @@
|
|
|
40
40
|
"version": "0.7.1",
|
|
41
41
|
"url": "https://unpkg.com/@tree-sitter-grammars/tree-sitter-yaml@0.7.1/tree-sitter-yaml.wasm"
|
|
42
42
|
}
|
|
43
|
+
},
|
|
44
|
+
"vendored": {
|
|
45
|
+
"tree-sitter-cue.wasm": {
|
|
46
|
+
"repo": "https://github.com/eonpatapon/tree-sitter-cue",
|
|
47
|
+
"commit": "dd7b90e0770ff18070c515937ba3c3d6d93db00e",
|
|
48
|
+
"license": "MIT",
|
|
49
|
+
"buildCommand": "npx tree-sitter-cli build --wasm",
|
|
50
|
+
"sha256": "sha256:751f8cc8ccf72da760133e3d365562ff7bbf5b951e0b73568576fd159db7d601"
|
|
51
|
+
}
|
|
43
52
|
}
|
|
44
53
|
}
|
|
@@ -62,6 +62,8 @@ Use these instead of writing raw YAML:
|
|
|
62
62
|
|
|
63
63
|
`hasKind` and `hasDescendantKind` are mutually exclusive on both tools — combining them errors.
|
|
64
64
|
|
|
65
|
+
⚠ `insideKind` searches ALL ancestors (`stopBy: end`) with no boundary of its own — on a deeply nested file it can escalate past the enclosing function you meant and match against an unrelated outer scope; scope with `paths` or a raw YAML `rule:` with its own `stopBy` boundary if that matters.
|
|
66
|
+
|
|
65
67
|
```
|
|
66
68
|
# console.log only inside functions
|
|
67
69
|
ast_grep_search pattern="console.log($MSG)" lang="typescript" insideKind="function_declaration"
|
|
@@ -13,7 +13,7 @@ Same `id` as a built-in overrides it. Multiple rules per file: separate with `--
|
|
|
13
13
|
```yaml
|
|
14
14
|
id: no-foo-bar
|
|
15
15
|
language: TypeScript # PascalCase — see languages below
|
|
16
|
-
severity: warning # error | warning | info
|
|
16
|
+
severity: warning # error | warning | hint | info — pick by evidence, see below
|
|
17
17
|
message: "Avoid foo.bar() — use baz() instead"
|
|
18
18
|
note: |
|
|
19
19
|
Longer explanation / fix guidance here.
|
|
@@ -21,6 +21,39 @@ rule:
|
|
|
21
21
|
pattern: foo.bar($ARG)
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
**Pick the severity by the evidence behind the rule, not by feel:**
|
|
25
|
+
|
|
26
|
+
- **`error`** — only with a documented zero-false-positive audit in the `note`.
|
|
27
|
+
Only `error` maps to semantic `blocking` and stops a turn.
|
|
28
|
+
- **`warning`** — a real finding with a known, bounded false-positive rate.
|
|
29
|
+
- **`hint` / `info`** — style opinions. They render as advisory text, never
|
|
30
|
+
block, and lose the report budget to warnings when a report is capped.
|
|
31
|
+
|
|
32
|
+
Full policy and the `error`-promotion procedure: AGENTS.md's "Severity policy
|
|
33
|
+
(#1777)" section. Read it before shipping anything above `warning`.
|
|
34
|
+
|
|
35
|
+
## Before promoting to error
|
|
36
|
+
|
|
37
|
+
Three things must all be true, and the rule's `note` must record them:
|
|
38
|
+
|
|
39
|
+
1. **A multi-corpus false-positive census**, not a single-tree count. Run the
|
|
40
|
+
rule over pi-lens's `clients/`/`tests/` plus at least one real external
|
|
41
|
+
codebase of the kind the rule targets, classify every hit, and put the
|
|
42
|
+
table in the note.
|
|
43
|
+
2. **Structural narrowing before exemption.** Suppress a legitimate idiom
|
|
44
|
+
with a relational constraint (`inside`/`has`/`follows`, scoped path
|
|
45
|
+
globs), not with prose telling readers to ignore the hit. Narrow first —
|
|
46
|
+
don't reach for a lower tier as the easy way out. `no-non-null-assertion`
|
|
47
|
+
was demoted to `hint` (`0124608a`), then reverted back to `warning` once
|
|
48
|
+
the same false positives were closed with a structural exclusion instead
|
|
49
|
+
(`b3e1fd79`).
|
|
50
|
+
3. **Self-scan wiring.** Tag the rule `metadata.category: pi-lens-self-scan`
|
|
51
|
+
so `npm run astgrep:self-scan` holds this tree at zero in CI. An `error`
|
|
52
|
+
rule that never runs against pi-lens's own source is an unaudited claim.
|
|
53
|
+
|
|
54
|
+
If the post-narrowing residual is still tens of legitimate hits, stop and
|
|
55
|
+
report the numbers instead of shipping at `error`.
|
|
56
|
+
|
|
24
57
|
## Language values
|
|
25
58
|
|
|
26
59
|
`TypeScript` `JavaScript` `Python` `Go` `Rust` `Java` `C` `Cpp` `CSharp` `Kotlin` `Ruby` `Php`
|
|
@@ -69,6 +102,13 @@ constraints: # metavariable regex constraints work
|
|
|
69
102
|
recursive descendant/ancestor search add `stopBy: end`. This is the #1 migration
|
|
70
103
|
gotcha — see the `has` note in `reference.md`.
|
|
71
104
|
|
|
105
|
+
⚠ **`stopBy: end` alone is not a boundary.** It's a search-depth control — how far
|
|
106
|
+
the walk searches — not a stop condition; the `any:` kind list only decides what
|
|
107
|
+
CAN satisfy the match, not where the walk halts. To scope a relation to the
|
|
108
|
+
nearest enclosing function (or any other boundary), give `stopBy` its own rule.
|
|
109
|
+
See "Scoping to the nearest enclosing X" in `reference.md` (#1794 F1 — this bug
|
|
110
|
+
shipped twice in one window).
|
|
111
|
+
|
|
72
112
|
## YAML quoting — REQUIRED (js-yaml will reject the rule otherwise)
|
|
73
113
|
|
|
74
114
|
The parser is a real YAML parser, so unquoted special chars throw and the rule is
|
|
@@ -104,13 +144,50 @@ The parser is a real YAML parser, so unquoted special chars throw and the rule i
|
|
|
104
144
|
|
|
105
145
|
`reference.md` (same directory) covers: ReDoS-safe regex authoring, node-text
|
|
106
146
|
string-escape quirks, `has`/`inside` `stopBy` defaults (and when to override
|
|
107
|
-
them), the
|
|
108
|
-
|
|
147
|
+
them), scoping a relation to the nearest enclosing node with a `stopBy`
|
|
148
|
+
boundary rule, the `-js` twin dedup behavior (#657), boolean-parameter
|
|
149
|
+
matching across the TS/JS grammars, and precision-over-recall heuristics for
|
|
109
150
|
denylist-shaped rules. Read it when a rule isn't matching (or over-matching)
|
|
110
151
|
the way you expect, or before shipping a `regex`/`has`-heavy rule.
|
|
111
152
|
|
|
153
|
+
## Testing a suppression
|
|
154
|
+
|
|
155
|
+
Every relational suppression (a `has`/`inside`/`not` exclusion for a
|
|
156
|
+
legitimate idiom) needs two fixtures per bound metavariable, not one:
|
|
157
|
+
|
|
158
|
+
1. **A same-binding valid case** — the idiom the exclusion is meant to
|
|
159
|
+
suppress, with the metavariable bound consistently (same receiver, same
|
|
160
|
+
key).
|
|
161
|
+
2. **A mutation-guard invalid case** — the same shape with the binding
|
|
162
|
+
broken: a different key, a different receiver, or a boundary-crossing
|
|
163
|
+
lookalike (the guard lives in the wrong scope). This proves the
|
|
164
|
+
exclusion checks the BINDING, not just the pattern's presence somewhere
|
|
165
|
+
in the file.
|
|
166
|
+
|
|
167
|
+
`rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml` is the model: alongside the
|
|
168
|
+
get-after-has/pop-after-length valid cases, it fixtures a different-key
|
|
169
|
+
guard, a different-map guard, and an outer-function guard that must NOT
|
|
170
|
+
suppress an inner closure — each one red if the corresponding binding check
|
|
171
|
+
is deleted.
|
|
172
|
+
|
|
173
|
+
Corpus silence is not evidence. A valve with zero corpus hits needs
|
|
174
|
+
adversarial fixtures MORE, not less — `redundant-unsafe-function` targets
|
|
175
|
+
Rust, so it has no pi-lens corpus to census against, and its `# Safety`
|
|
176
|
+
valve still shipped an unbounded backward scan that over-suppressed real
|
|
177
|
+
detections, caught only by adversarial fixtures in review (`00284bcc`). A
|
|
178
|
+
documented blind spot (an idiom the rule knowingly can't distinguish from a
|
|
179
|
+
bug) becomes an `invalid`-direction fixture with a comment naming the gap,
|
|
180
|
+
never silence.
|
|
181
|
+
|
|
182
|
+
Regenerate the catalog doc with `npm run docs:rule-catalogs` after adding or
|
|
183
|
+
changing a rule — never hand-edit the generated catalog.
|
|
184
|
+
|
|
112
185
|
## Validating a candidate rule against the REAL engine (not the warm MCP cache)
|
|
113
186
|
|
|
187
|
+
Live-binary discipline (AGENTS.md shape 16) applies here too: verify parsing
|
|
188
|
+
and match behavior against a real `ast-grep` run before you write it into a
|
|
189
|
+
rule note or a test fixture — a hand-written fixture pins a guess, not a fact.
|
|
190
|
+
|
|
114
191
|
```
|
|
115
192
|
|
|
116
193
|
# inspect how a PATTERN parses → find the node kind you actually need
|
|
@@ -92,6 +92,47 @@ grammars, and precision-over-recall heuristics for denylist-shaped rules.
|
|
|
92
92
|
the partition unique; flag only a single quantified atom inside the group).
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
+
## Scoping to the nearest enclosing X (#1794 F1)
|
|
96
|
+
|
|
97
|
+
`stopBy` controls how far the ancestor/descendant walk searches. It is not a
|
|
98
|
+
stop CONDITION. An `any:` kind list inside `inside`/`has` decides which
|
|
99
|
+
nodes the walk is ALLOWED to match — it does not tell the walk where to
|
|
100
|
+
halt. `stopBy: end` alone searches every ancestor up to the file root, so a
|
|
101
|
+
guard several scopes out can suppress a finding inside an unrelated closure.
|
|
102
|
+
|
|
103
|
+
To scope a relation to the nearest enclosing function (or any other
|
|
104
|
+
boundary), give `stopBy` its OWN rule — the same kind list used as the
|
|
105
|
+
match target — so the walk stops at the first satisfying ancestor and can
|
|
106
|
+
never escalate past it:
|
|
107
|
+
|
|
108
|
+
```yaml
|
|
109
|
+
inside:
|
|
110
|
+
stopBy: # the BOUNDARY: halts the walk here
|
|
111
|
+
any:
|
|
112
|
+
- kind: function_declaration
|
|
113
|
+
- kind: method_definition
|
|
114
|
+
- kind: arrow_function
|
|
115
|
+
- kind: function_expression
|
|
116
|
+
any: # the MATCH TARGET: same list, different job
|
|
117
|
+
- kind: function_declaration
|
|
118
|
+
- kind: method_definition
|
|
119
|
+
- kind: arrow_function
|
|
120
|
+
- kind: function_expression
|
|
121
|
+
has:
|
|
122
|
+
stopBy: end
|
|
123
|
+
pattern: $M.has($K)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
This is the fix for #1794 F1: an earlier `no-non-null-assertion` exclusion
|
|
127
|
+
used `stopBy: end` with only the `any:` kind list as the match target, so a
|
|
128
|
+
`.has()`/`.length` guard in an OUTER function suppressed a closure's `!`
|
|
129
|
+
several scopes in. The same defect shape — `stopBy: end` mistaken for a
|
|
130
|
+
boundary — shipped twice in the same 2026-08-20 window: once here, and once
|
|
131
|
+
in `redundant-unsafe-function`'s `# Safety` valve (an unbounded backward
|
|
132
|
+
comment scan, fixed in `00284bcc`). See
|
|
133
|
+
`rules/ast-grep-rules/rules/no-non-null-assertion.yml` for the full working
|
|
134
|
+
rule.
|
|
135
|
+
|
|
95
136
|
## Matching things a pattern can't express (#305)
|
|
96
137
|
|
|
97
138
|
```
|
|
Binary file
|
|
@@ -7,6 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.27.0] - 2026-08-20
|
|
11
|
+
|
|
12
|
+
### Highlights
|
|
13
|
+
- MCP servers can now come from packages, runtime extension APIs, or the usual config files.
|
|
14
|
+
- Static bearer tokens can use the OS credential store, with a stdin-only CLI for safer token management.
|
|
15
|
+
- Long-lived sessions recover better when remote MCP servers are slow, refreshed, or reconnected.
|
|
16
|
+
- OAuth flows clean up their callback listener when idle and work better inside nested terminal UI prompts.
|
|
17
|
+
- Search, metadata cache writes, direct-tool counts, and UI stream pruning now do less repeated work.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- `/pi-mcp` now works as an alias for `/mcp` when a host reserves `/mcp`. Thanks to [@inxeoz](https://github.com/inxeoz) for #391.
|
|
21
|
+
- `registerMcpServer({ pi, name, definition })` lets other extensions register and dispose session-scoped MCP servers at runtime. Registrations are proxy-tool-only, never persisted, and duplicate names fail closed. Thanks to [@bendavis78](https://github.com/bendavis78) and [@fmoda3](https://github.com/fmoda3) for the runtime API request in #376/#382.
|
|
22
|
+
- Pi packages can ship prefixed MCP server definitions with `pi.mcp` manifest entries, without asking users to edit MCP config files. Thanks to [@bendavis78](https://github.com/bendavis78) for #376 and [@fmoda3](https://github.com/fmoda3) for the manifest design.
|
|
23
|
+
- Static bearer tokens can opt into OS credential-store lookup with URL-bound records by setting `bearerTokenStore: true`. The new `pi-mcp-adapter token set|status|remove <server>` CLI reads tokens from stdin and never accepts a token as an argument. Thanks to [@AlexanderBartash](https://github.com/AlexanderBartash) for issue #366.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
- Search ranking now reuses normalized MCP tool fields and keyword tokens per catalog.
|
|
27
|
+
- Per-request header commands collect process cleanup data in one snapshot per pass, reducing cold HTTP connect overhead.
|
|
28
|
+
- Metadata cache saves write compact JSON while preserving atomic replacement and cross-process merges.
|
|
29
|
+
- High-frequency UI stream event-log pruning tracks the latest checkpoint event ID instead of rescanning retained patches.
|
|
30
|
+
- The MCP panel reuses direct-tool counts and token totals across renders while keeping toggle and reconnect updates immediate.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- Short-lived `mcpScript` workers no longer emit false unmanaged file-descriptor warnings on Node 24. Thanks to [@blalor](https://github.com/blalor) for PR #407.
|
|
34
|
+
- OAuth callback listeners are released after idle auth flows, and MCP pickers stay hidden while nested OAuth input is active. Thanks to [@trevorleibert-mixpanel](https://github.com/trevorleibert-mixpanel) for PRs #403 and #404.
|
|
35
|
+
- Request-header command cleanup can scan large process lists without overflowing `spawnSync`'s 1 MiB default buffer, which previously caused spurious `HTTP request headers command cleanup failed: ps exited with code unknown` refresh failures on busy hosts. Thanks to [@rtfpessoa](https://github.com/rtfpessoa) for PR #399.
|
|
36
|
+
- Slow but healthy remote keep-alive servers are no longer marked failed when a bounded tools/list refresh times out. Thanks to [@brightmeowso](https://github.com/brightmeowso) for #400.
|
|
37
|
+
- Cached metadata reconstruction now reuses one selector candidate index, avoiding repeated scans of large cached catalogs at startup.
|
|
38
|
+
- MCP status consumers no longer see a connected catalog before Pi's model-facing tool surface is current. The first connected status snapshot now waits for direct-tool synchronization. Thanks to [@dmorn](https://github.com/dmorn) for PR #380.
|
|
39
|
+
- JSON-string MCP tool-call arguments are normalized before approval and transport, preserving all fields and embedded quotes. Thanks to [@sebbean](https://github.com/sebbean) for PR #377.
|
|
40
|
+
- Session tool approvals are scoped to the approved argument payload instead of every later call to the same tool. Thanks to [@spaceshipmike](https://github.com/spaceshipmike) for #367.
|
|
41
|
+
- MCP panel commands no longer hang in RPC, JSON, and print modes when terminal-only custom UI is unavailable. Thanks to [@shixin-guo](https://github.com/shixin-guo) for PR #365.
|
|
42
|
+
- Compact MCP rows now show a bounded tool-input preview and skip leading blank output lines in collapsed result previews.
|
|
43
|
+
- MCP gateway requests nested inside proxy `args` are recovered instead of silently showing status, and invalid nested gateway requests now fail with guidance. Thanks to [@ibrmora](https://github.com/ibrmora) for #363.
|
|
44
|
+
- Remote keep-alive tool catalogs refresh before user input, adapter-triggered turns, and health checks. Expired Streamable HTTP sessions reconnect so long-lived Pi sessions can discover replacement catalogs without restarting. Thanks to [@dmorn](https://github.com/dmorn) for #369 and PR #370.
|
|
45
|
+
|
|
10
46
|
## [2.26.0] - 2026-08-14
|
|
11
47
|
|
|
12
48
|
### Added
|