@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
|
@@ -763,6 +763,21 @@ function ensureUtf8ConsoleCodePageOnce() {
|
|
|
763
763
|
export function resetUtf8ConsoleCodePageStateForTests() {
|
|
764
764
|
utf8ConsoleCodePageApplied = false;
|
|
765
765
|
}
|
|
766
|
+
// #1656: post-exit pipe-idle wait constants. Node's "close" event only fires
|
|
767
|
+
// once every stdio fd referencing the child has been released — a
|
|
768
|
+
// daemonized descendant that inherited our stdout/stderr pipe (the Windows
|
|
769
|
+
// no-job-object case) can hold that fd open forever, hanging "close" even
|
|
770
|
+
// though the child we spawned is long dead. A fixed post-exit deadline
|
|
771
|
+
// avoids that hang but truncates a legitimately still-streaming child. The
|
|
772
|
+
// idle-grace construction (adopted from pi's `waitForChildProcess`) does
|
|
773
|
+
// neither: after "exit", wait for the pipes to go quiet — no data for
|
|
774
|
+
// EXIT_PIPE_IDLE_GRACE_MS, re-armed on every chunk — so a quiet inherited
|
|
775
|
+
// handle still releases after one grace window while an actively-writing
|
|
776
|
+
// descendant keeps being read. EXIT_PIPE_IDLE_MAX_WAIT_MS caps the total
|
|
777
|
+
// extra wait so a pathological, never-quiet descendant can't extend the
|
|
778
|
+
// caller's overall budget unboundedly.
|
|
779
|
+
const EXIT_PIPE_IDLE_GRACE_MS = 100;
|
|
780
|
+
const EXIT_PIPE_IDLE_MAX_WAIT_MS = 2000;
|
|
766
781
|
// ============================================================================
|
|
767
782
|
// ASYNC VERSION (Recommended - Non-blocking)
|
|
768
783
|
// ============================================================================
|
|
@@ -825,7 +840,18 @@ export async function safeSpawnAsync(command, args, options) {
|
|
|
825
840
|
let aborted = false;
|
|
826
841
|
let killed = false;
|
|
827
842
|
let outputTruncated = false;
|
|
828
|
-
|
|
843
|
+
// #1651 review: a single boolean the close/error handlers both check
|
|
844
|
+
// AND set, so whichever one decides the outcome first wins outright —
|
|
845
|
+
// the DECISION itself is shape-based (see the `close` handler below),
|
|
846
|
+
// this flag only stops the loser from resolving a second time.
|
|
847
|
+
let resolved = false;
|
|
848
|
+
// The most recent 'error' Error, captured the instant the event fires
|
|
849
|
+
// regardless of whether that handler goes on to resolve. The `close`
|
|
850
|
+
// handler's shape-based branch (code === null || code < 0) reads this
|
|
851
|
+
// when it decides FIRST, so a genuinely informative ENOENT/EACCES/etc.
|
|
852
|
+
// Error is used when it happens to already be available, instead of
|
|
853
|
+
// always falling back to a generic synthesized one.
|
|
854
|
+
let pendingSpawnError;
|
|
829
855
|
// #1109: the non-Windows SIGTERM→SIGKILL escalation timer (armed in
|
|
830
856
|
// killTree below). Stored per-call (never shared) so the close/error
|
|
831
857
|
// handlers can clear it if the child exits before it fires — same
|
|
@@ -841,6 +867,11 @@ export async function safeSpawnAsync(command, args, options) {
|
|
|
841
867
|
// any `await`, so a timer firing during the close handler's `await
|
|
842
868
|
// killPromise` still observes the flag correctly).
|
|
843
869
|
let closed = false;
|
|
870
|
+
// #1656: set only while the post-exit idle-pipe wait is active (see
|
|
871
|
+
// waitForPipeIdle below); the stdout/stderr "data" handlers call this to
|
|
872
|
+
// re-arm the grace timer on every chunk. `undefined` before exit / after
|
|
873
|
+
// the wait settles, so the calls below are no-ops outside that window.
|
|
874
|
+
let rearmIdleGrace;
|
|
844
875
|
const maxOutputBytes = options?.maxOutputBytes !== undefined &&
|
|
845
876
|
Number.isFinite(options.maxOutputBytes) &&
|
|
846
877
|
options.maxOutputBytes > 0
|
|
@@ -996,7 +1027,7 @@ export async function safeSpawnAsync(command, args, options) {
|
|
|
996
1027
|
lifetimeState.pids.add(child.pid);
|
|
997
1028
|
}
|
|
998
1029
|
// #620: bracket this spawn's lifetime with a short-interval CPU/RSS poll
|
|
999
|
-
// (started right here, stopped in
|
|
1030
|
+
// (started right here, stopped in finalize() below) so transient
|
|
1000
1031
|
// analyzer children (jscpd, knip, madge, gitleaks, etc.) — which live too
|
|
1001
1032
|
// briefly for heartbeat-cadence sampling to reliably catch — still get a
|
|
1002
1033
|
// peak/average resource reading. `startSpawnUsageSampler` itself is
|
|
@@ -1052,7 +1083,7 @@ export async function safeSpawnAsync(command, args, options) {
|
|
|
1052
1083
|
}
|
|
1053
1084
|
};
|
|
1054
1085
|
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
1055
|
-
// Output-cap kills are awaited by
|
|
1086
|
+
// Output-cap kills are awaited by finalize() below, just like
|
|
1056
1087
|
// timeout/abort kills. This keeps a noisy CLI from continuing in the
|
|
1057
1088
|
// background after its retained output has been bounded.
|
|
1058
1089
|
let killPromise;
|
|
@@ -1068,10 +1099,28 @@ export async function safeSpawnAsync(command, args, options) {
|
|
|
1068
1099
|
child.stdout?.on("data", (data) => {
|
|
1069
1100
|
stdout = appendOutput(stdout, data);
|
|
1070
1101
|
stopForOutputLimit();
|
|
1102
|
+
rearmIdleGrace?.();
|
|
1071
1103
|
});
|
|
1072
1104
|
child.stderr?.on("data", (data) => {
|
|
1073
1105
|
stderr = appendOutput(stderr, data);
|
|
1074
1106
|
stopForOutputLimit();
|
|
1107
|
+
rearmIdleGrace?.();
|
|
1108
|
+
});
|
|
1109
|
+
// #1673 review round 3 (F2): registered HERE, at spawn time, alongside
|
|
1110
|
+
// the other handlers above — not inside `waitForPipeIdle`. Real Node
|
|
1111
|
+
// emits `close` a fraction of a millisecond after `exit` (both fire in
|
|
1112
|
+
// the same "process exit" turn, well before any microtask), so a
|
|
1113
|
+
// listener attached inside `waitForPipeIdle` — which `finalize` only
|
|
1114
|
+
// reaches after `await killPromise`, at least one microtask later — is
|
|
1115
|
+
// always attaching to an event that has already happened. That's why
|
|
1116
|
+
// the round-2 `child.on("close", finish)` placed inside
|
|
1117
|
+
// `waitForPipeIdle` never actually caught a real spawn's `close` early:
|
|
1118
|
+
// every real call still paid the full grace window. Capturing the
|
|
1119
|
+
// boolean here, before any await, means `waitForPipeIdle` can check
|
|
1120
|
+
// "did close already happen" synchronously the moment it runs.
|
|
1121
|
+
let closeSeen = false;
|
|
1122
|
+
child.on("close", () => {
|
|
1123
|
+
closeSeen = true;
|
|
1075
1124
|
});
|
|
1076
1125
|
// Timeout handling - KILL the process, don't just abandon it
|
|
1077
1126
|
const timeoutId = setTimeout(() => {
|
|
@@ -1105,23 +1154,144 @@ export async function safeSpawnAsync(command, args, options) {
|
|
|
1105
1154
|
}
|
|
1106
1155
|
return summary;
|
|
1107
1156
|
};
|
|
1157
|
+
// #1656: wait for stdout/stderr to fall idle after exit instead of
|
|
1158
|
+
// waiting for Node's "close" event (see the constants' doc comment
|
|
1159
|
+
// above). Resolves immediately if the child has no pipes to drain.
|
|
1160
|
+
//
|
|
1161
|
+
// These timers stay REF'D, matching `timeoutId`/`escalationTimer`
|
|
1162
|
+
// elsewhere in this function: the caller's own settlement depends on
|
|
1163
|
+
// them firing, so unref'ing would let a short-lived host process (a
|
|
1164
|
+
// one-shot CLI whose only other in-flight work was this spawn) exit
|
|
1165
|
+
// the event loop before `finish` ever runs — silently abandoning this
|
|
1166
|
+
// promise instead of merely leaking a handle. Both paths to `finish`
|
|
1167
|
+
// clear both timers, so nothing outlives settlement either way.
|
|
1168
|
+
const waitForPipeIdle = () => {
|
|
1169
|
+
if (!child.stdout && !child.stderr)
|
|
1170
|
+
return Promise.resolve();
|
|
1171
|
+
// #1673 review round 3 (F2): `close` fires a fraction of a
|
|
1172
|
+
// millisecond after `exit` for a real Node child — well before
|
|
1173
|
+
// `finalize`'s `await killPromise` ever yields, i.e. before this
|
|
1174
|
+
// function is even called. By the time we get here, `closeSeen`
|
|
1175
|
+
// (set by the listener registered at spawn time, above) already
|
|
1176
|
+
// reflects reality for the overwhelming majority of real spawns:
|
|
1177
|
+
// nothing is holding this child's stdio open, so don't pay out the
|
|
1178
|
+
// 100ms grace window for a signal that already arrived.
|
|
1179
|
+
if (closeSeen)
|
|
1180
|
+
return Promise.resolve();
|
|
1181
|
+
return new Promise((finishIdleWait) => {
|
|
1182
|
+
let settled = false;
|
|
1183
|
+
let graceTimer;
|
|
1184
|
+
const capTimer = setTimeout(() => {
|
|
1185
|
+
finish();
|
|
1186
|
+
}, EXIT_PIPE_IDLE_MAX_WAIT_MS);
|
|
1187
|
+
const finish = () => {
|
|
1188
|
+
if (settled)
|
|
1189
|
+
return;
|
|
1190
|
+
settled = true;
|
|
1191
|
+
rearmIdleGrace = undefined;
|
|
1192
|
+
if (graceTimer)
|
|
1193
|
+
clearTimeout(graceTimer);
|
|
1194
|
+
clearTimeout(capTimer);
|
|
1195
|
+
// Optional chaining, not a bare call: `child` is a real Node
|
|
1196
|
+
// ChildProcess (always an EventEmitter, always has this) in
|
|
1197
|
+
// production, but several existing test doubles across the
|
|
1198
|
+
// suite fake stdio-bearing children as plain objects with only
|
|
1199
|
+
// the handful of methods (`on`, `kill`, ...) their scenario
|
|
1200
|
+
// needs — no `removeListener`. Skipping cleanup on those is
|
|
1201
|
+
// harmless (the fake is torn down with the test either way);
|
|
1202
|
+
// crashing here from inside a timer callback is not: it would
|
|
1203
|
+
// throw before `finishIdleWait()` runs, hanging every caller's
|
|
1204
|
+
// `safeSpawnAsync` promise (#1673 review round 2 caught this
|
|
1205
|
+
// live in tests/clients/installer/version-drift.test.ts).
|
|
1206
|
+
child.removeListener?.("close", finish);
|
|
1207
|
+
finishIdleWait();
|
|
1208
|
+
};
|
|
1209
|
+
// The `closeSeen` fast-path above catches the common case (close
|
|
1210
|
+
// already happened by the time we get here). This listener is
|
|
1211
|
+
// the fallback for the rare case where `close` genuinely lands
|
|
1212
|
+
// DURING the wait — e.g. a child whose stdio takes a beat
|
|
1213
|
+
// longer than usual to release, but still well under the grace
|
|
1214
|
+
// window. `close` is a stronger signal than "no data for
|
|
1215
|
+
// EXIT_PIPE_IDLE_GRACE_MS", so finishing on it here still beats
|
|
1216
|
+
// waiting out the timer. The anti-hang property is untouched
|
|
1217
|
+
// either way: a daemonized descendant holding the pipe open is
|
|
1218
|
+
// EXACTLY the case where `close` never fires at all, so the
|
|
1219
|
+
// grace/cap timers still bound that case as before.
|
|
1220
|
+
child.on("close", finish);
|
|
1221
|
+
rearmIdleGrace = () => {
|
|
1222
|
+
if (graceTimer)
|
|
1223
|
+
clearTimeout(graceTimer);
|
|
1224
|
+
graceTimer = setTimeout(finish, EXIT_PIPE_IDLE_GRACE_MS);
|
|
1225
|
+
};
|
|
1226
|
+
rearmIdleGrace();
|
|
1227
|
+
});
|
|
1228
|
+
};
|
|
1108
1229
|
// Process completion
|
|
1109
|
-
|
|
1110
|
-
|
|
1230
|
+
//
|
|
1231
|
+
// #1656 x #1651/#1670: finalize off BOTH `exit` and `close`, not just
|
|
1232
|
+
// one — each covers a shape the other misses.
|
|
1233
|
+
// - `exit` is what unblocks the #1656 hang: a daemonized descendant
|
|
1234
|
+
// that inherited our stdout/stderr pipe can hold that fd open
|
|
1235
|
+
// forever, so `close` (which waits for every fd referencing the
|
|
1236
|
+
// child to release) never fires even though the child we spawned
|
|
1237
|
+
// is long dead. `exit` always fires once the child itself exits,
|
|
1238
|
+
// independent of who still holds its pipes.
|
|
1239
|
+
// - `close` is still wired because a child that never actually
|
|
1240
|
+
// launched (bad binary, EACCES, ...) gets NO `exit` event at all —
|
|
1241
|
+
// Node only emits `error` then `close(code<0, null)` for that
|
|
1242
|
+
// shape (#1651/#1670's shape guard below decides from exactly
|
|
1243
|
+
// this). `exit`-only would make that guard unreachable.
|
|
1244
|
+
// Whichever fires first drives `finalize`; `settled` (distinct from
|
|
1245
|
+
// `resolved`, which `finalize` itself owns) stops the second event
|
|
1246
|
+
// from dispatching a redundant, concurrently-racing `finalize` call —
|
|
1247
|
+
// double-invoking it would double-run `waitForPipeIdle` and
|
|
1248
|
+
// `finishResourceUsage` against the same child.
|
|
1249
|
+
let settled = false;
|
|
1250
|
+
const onChildSettle = (code, signal) => {
|
|
1251
|
+
if (settled || resolved)
|
|
1111
1252
|
return;
|
|
1253
|
+
settled = true;
|
|
1112
1254
|
closed = true;
|
|
1113
1255
|
clearTimeout(timeoutId);
|
|
1114
1256
|
abortSignal?.removeEventListener("abort", onAbort);
|
|
1115
1257
|
if (child.pid)
|
|
1116
1258
|
lifetimeState.pids.delete(child.pid);
|
|
1259
|
+
void finalize(code, signal);
|
|
1260
|
+
};
|
|
1261
|
+
const finalize = async (code, signal) => {
|
|
1262
|
+
// Belt, not the decision: whichever path settles `resolved` FIRST
|
|
1263
|
+
// wins. A healthy run's outcome must never be discarded by a late,
|
|
1264
|
+
// unrelated 'error' (e.g. a post-exit kill() that itself failed
|
|
1265
|
+
// with EPERM, #1651 review F4) — so this only bails when something
|
|
1266
|
+
// else has ALREADY resolved, never on `error` merely having fired.
|
|
1117
1267
|
await killPromise;
|
|
1268
|
+
if (resolved)
|
|
1269
|
+
return;
|
|
1118
1270
|
// #1109: the child has exited — if killTree armed the non-Windows
|
|
1119
1271
|
// SIGTERM→SIGKILL escalation timer and it hasn't fired yet, clear it
|
|
1120
1272
|
// so it doesn't linger as a ref'd handle after this promise resolves.
|
|
1121
1273
|
if (escalationTimer)
|
|
1122
1274
|
clearTimeout(escalationTimer);
|
|
1275
|
+
// #1673 review F1: latch the verdict as DECIDED here, before the
|
|
1276
|
+
// idle-pipe wait — not after it. `code`/`signal`/`timedOut`/`aborted`
|
|
1277
|
+
// are already fixed by this point (they don't change during the
|
|
1278
|
+
// wait), so nothing below depends on staying unresolved across it.
|
|
1279
|
+
// Leaving `resolved` false across the wait would reopen the exact
|
|
1280
|
+
// race #1651 review F4 closed: a late, unrelated 'error' (e.g. a
|
|
1281
|
+
// post-exit kill() failing with EPERM) landing inside the
|
|
1282
|
+
// idle-grace window (bounded, but up to EXIT_PIPE_IDLE_MAX_WAIT_MS)
|
|
1283
|
+
// would steal an already-decided healthy verdict. Pre-#1656 that
|
|
1284
|
+
// race window was one microtask — the gap between `close` firing
|
|
1285
|
+
// and `resolve()` being called synchronously in the same handler.
|
|
1286
|
+
// This closes the window back down to that same shape instead of
|
|
1287
|
+
// widening it to the whole wait.
|
|
1288
|
+
resolved = true;
|
|
1289
|
+
await waitForPipeIdle();
|
|
1123
1290
|
const resourceUsage = finishResourceUsage();
|
|
1124
1291
|
const outputInfo = outputTruncated ? { outputTruncated: true } : {};
|
|
1292
|
+
// #1816: surface the signal name as a field on every path where one
|
|
1293
|
+
// exists, so callers can NAME it instead of scraping `error.message`.
|
|
1294
|
+
const signalInfo = signal ? { signal } : {};
|
|
1125
1295
|
if (timedOut) {
|
|
1126
1296
|
const cause = new Error(`Process timed out after ${timeout}ms (killed with ${signal || "SIGTERM"})`);
|
|
1127
1297
|
resolve({
|
|
@@ -1130,6 +1300,7 @@ export async function safeSpawnAsync(command, args, options) {
|
|
|
1130
1300
|
status: null,
|
|
1131
1301
|
error: cause,
|
|
1132
1302
|
failure: "timeout",
|
|
1303
|
+
...signalInfo,
|
|
1133
1304
|
spawnFailure: new SpawnFailureError("timeout", cause.message, cause),
|
|
1134
1305
|
...outputInfo,
|
|
1135
1306
|
resourceUsage,
|
|
@@ -1143,6 +1314,7 @@ export async function safeSpawnAsync(command, args, options) {
|
|
|
1143
1314
|
status: null,
|
|
1144
1315
|
error: cause,
|
|
1145
1316
|
failure: "aborted",
|
|
1317
|
+
...signalInfo,
|
|
1146
1318
|
spawnFailure: new SpawnFailureError("killed", cause.message, cause),
|
|
1147
1319
|
...outputInfo,
|
|
1148
1320
|
resourceUsage,
|
|
@@ -1156,17 +1328,58 @@ export async function safeSpawnAsync(command, args, options) {
|
|
|
1156
1328
|
status: null,
|
|
1157
1329
|
error: cause,
|
|
1158
1330
|
failure: "signal",
|
|
1331
|
+
...signalInfo,
|
|
1159
1332
|
spawnFailure: new SpawnFailureError("killed", cause.message, cause),
|
|
1160
1333
|
...outputInfo,
|
|
1161
1334
|
resourceUsage,
|
|
1162
1335
|
});
|
|
1163
1336
|
}
|
|
1337
|
+
else if (code === null || code < 0) {
|
|
1338
|
+
// #1651 review F3: a real completed process never exits with a
|
|
1339
|
+
// null or negative code (Node reports the negated libuv/errno for
|
|
1340
|
+
// a child that never launched — e.g. ENOENT: -2 on Linux, -4058
|
|
1341
|
+
// on Windows). This decides from that SHAPE alone, independent of
|
|
1342
|
+
// whether/when 'error' has fired — Node's docs leave the
|
|
1343
|
+
// 'error'/'close' ordering for a failed spawn unspecified, and a
|
|
1344
|
+
// same-microtask re-check (the #1651 first-round fix) still loses
|
|
1345
|
+
// if 'error' lands a tick later via setImmediate/nextTick.
|
|
1346
|
+
// Reuse `pendingSpawnError` when 'error' already landed (a more
|
|
1347
|
+
// informative Error — ENOENT vs EACCES vs other); otherwise
|
|
1348
|
+
// synthesize an ENOENT-shaped one so a genuinely missing tool is
|
|
1349
|
+
// never read as a clean, answered run.
|
|
1350
|
+
const cause = pendingSpawnError ?? synthesizeEnoentError(command);
|
|
1351
|
+
const spawnFailure = await classifySpawnFailure(cause, {
|
|
1352
|
+
command,
|
|
1353
|
+
cwd: options?.cwd,
|
|
1354
|
+
});
|
|
1355
|
+
resolve({
|
|
1356
|
+
stdout,
|
|
1357
|
+
stderr,
|
|
1358
|
+
status: code,
|
|
1359
|
+
error: cause,
|
|
1360
|
+
failure: "spawn",
|
|
1361
|
+
spawnFailure,
|
|
1362
|
+
...outputInfo,
|
|
1363
|
+
resourceUsage,
|
|
1364
|
+
});
|
|
1365
|
+
}
|
|
1164
1366
|
else {
|
|
1165
1367
|
resolve({ stdout, stderr, status: code, ...outputInfo, resourceUsage });
|
|
1166
1368
|
}
|
|
1167
|
-
}
|
|
1369
|
+
};
|
|
1370
|
+
child.on("exit", onChildSettle);
|
|
1371
|
+
child.on("close", onChildSettle);
|
|
1168
1372
|
child.on("error", (err) => {
|
|
1169
|
-
|
|
1373
|
+
// Capture unconditionally — even when `close` already resolved, this
|
|
1374
|
+
// keeps the most recent Error available for anyone reading state
|
|
1375
|
+
// mid-flight, and costs nothing (the assignment, not a resolve).
|
|
1376
|
+
pendingSpawnError = err;
|
|
1377
|
+
// A completed run's own verdict must never be downgraded by an
|
|
1378
|
+
// unrelated LATE error (#1651 review F4 — e.g. a post-exit kill()
|
|
1379
|
+
// failing with EPERM after `close(0, null)` already answered).
|
|
1380
|
+
if (resolved)
|
|
1381
|
+
return;
|
|
1382
|
+
resolved = true;
|
|
1170
1383
|
closed = true;
|
|
1171
1384
|
clearTimeout(timeoutId);
|
|
1172
1385
|
abortSignal?.removeEventListener("abort", onAbort);
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for "scratch/cache tree" exclusion, shared by every
|
|
3
|
+
* runner that hands a DIRECTORY to an external binary and lets that binary do
|
|
4
|
+
* its own tree walk.
|
|
5
|
+
*
|
|
6
|
+
* pi-lens's own in-process walkers (`source-filter.ts`/`source-walker.ts`,
|
|
7
|
+
* `getProjectIgnoreMatcher`) already route every entry through
|
|
8
|
+
* `isExcludedDirName`/`EXCLUDED_DIRS` (`file-utils.ts`) — that's how knip,
|
|
9
|
+
* jscpd, and the tree-sitter project scan skip `.pi/`, `node_modules/`, etc.
|
|
10
|
+
* But a runner that shells out with `cwd`/`--source <dir>` and lets the
|
|
11
|
+
* EXTERNAL tool walk (gitleaks `detect --source`, `trivy fs`, `opengrep scan
|
|
12
|
+
* <dir>`) bypasses that walker entirely — the tool sees the raw tree,
|
|
13
|
+
* including pi-ecosystem scratch/data directories that were never meant to be
|
|
14
|
+
* scan targets (#1562: `.pi/greedysearch-sources/` — a gitignored web-research
|
|
15
|
+
* cache — served a `YOUR_API_KEY` doc-example placeholder to the agent as a
|
|
16
|
+
* "leaked secret").
|
|
17
|
+
*
|
|
18
|
+
* This module derives each such runner's native exclude syntax from the SAME
|
|
19
|
+
* `EXCLUDED_DIRS` list `file-utils.ts` already uses for the in-process walk,
|
|
20
|
+
* rather than hand-maintaining a parallel per-tool list (the single-source-of-
|
|
21
|
+
* truth rule that #883 encodes — a hand-copied list is a defect in itself:
|
|
22
|
+
* `dead-code-client.ts`'s `VULTURE_EXCLUDES` had drifted from `EXCLUDED_DIRS`
|
|
23
|
+
* before this fix, e.g. missing `.pi`/`.claude`/`.next`).
|
|
24
|
+
*
|
|
25
|
+
* Deliberately NOT `.gitignore`-based: a secrets scanner (gitleaks, trivy's
|
|
26
|
+
* `secret` scanner) must still see an untracked `.env` with a real credential
|
|
27
|
+
* — `.env` is commonly gitignored, so blanket "respect .gitignore" would hide
|
|
28
|
+
* exactly the file classes these scanners exist to catch (#1562 design note).
|
|
29
|
+
* `EXCLUDED_DIRS` is a narrower, deliberate list of scratch/cache/vendor
|
|
30
|
+
* directory NAMES (`.pi`, `.claude`, `node_modules`, `dist`, …), not a
|
|
31
|
+
* gitignore pattern set.
|
|
32
|
+
*
|
|
33
|
+
* TWO exclusion tiers, not one (#1562 review-round F1) — `EXCLUDED_DIRS`
|
|
34
|
+
* itself conflates two different questions:
|
|
35
|
+
* - "don't bother INDEXING/LINTING/DEDUPING this" (the walker-parity
|
|
36
|
+
* exports below, `getScratchTreeGlobPatterns`/`getScratchTreeDirNames`/
|
|
37
|
+
* `getScratchTreeFnmatchPatterns`) — correctly broad: build output
|
|
38
|
+
* (`dist`, `build`, `out`, `target`, `coverage`), vendored source
|
|
39
|
+
* (`vendor`, `third_party`, `vendors`), and editor config (`.vscode`)
|
|
40
|
+
* are all noise for knip/jscpd/vulture.
|
|
41
|
+
* - "don't bother looking for SECRETS here" — a much narrower question.
|
|
42
|
+
* The first cut of this fix reused the walker-parity list for gitleaks's
|
|
43
|
+
* secrets-lane exclusion too, and a review probe caught it silently
|
|
44
|
+
* dropping real AWS-shaped secrets seeded in `dist/`, `vendor/`,
|
|
45
|
+
* `.vscode/`, `build/`, `out/`, `target/`, `third_party/`,
|
|
46
|
+
* `third-party/`, `coverage/` (0/9 kept, unlogged) — a bundler can bake
|
|
47
|
+
* a real key into `dist/`, `.vscode/launch.json` commonly carries a
|
|
48
|
+
* committed debug token, and a vendored tree can carry an upstream
|
|
49
|
+
* leak. `SECRETS_LANE_SCRATCH_DIR_NAMES`/`getSecretsLaneAllowlistPaths`/
|
|
50
|
+
* `isUnderSecretsLaneScratchTree` are the narrow tier gitleaks (or any
|
|
51
|
+
* future gitleaks-shaped secret scanner) must use instead — pi-ecosystem/
|
|
52
|
+
* agent data dirs, `node_modules`, `.git`, and generic build/package-
|
|
53
|
+
* manager CACHES only; every real-leak-surface directory above stays
|
|
54
|
+
* fully in scope.
|
|
55
|
+
*/
|
|
56
|
+
import { EXCLUDED_DIRS, getExcludedDirGlobs } from "./file-utils.js";
|
|
57
|
+
/** Directory-name entries only — drops glob entries (e.g. `*.dSYM`) that a
|
|
58
|
+
* bare directory-name/regex exclude can't express. */
|
|
59
|
+
function literalExcludedDirNames() {
|
|
60
|
+
return EXCLUDED_DIRS.filter((name) => !name.includes("*") && !name.includes("?"));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* `**\/name/**` glob patterns for tools that take doublestar globs
|
|
64
|
+
* (trivy `--skip-dirs`, opengrep/semgrep `--exclude`). Reuses
|
|
65
|
+
* `file-utils.ts`'s own glob derivation so both walkers and shell-out runners
|
|
66
|
+
* stay byte-for-byte in sync.
|
|
67
|
+
*/
|
|
68
|
+
export function getScratchTreeGlobPatterns() {
|
|
69
|
+
return getExcludedDirGlobs();
|
|
70
|
+
}
|
|
71
|
+
function escapeRegExp(literal) {
|
|
72
|
+
return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
73
|
+
}
|
|
74
|
+
/** Bare directory names, for tools (opengrep/semgrep `--exclude`) that treat a
|
|
75
|
+
* slash-free pattern as "this directory name, anywhere in the tree". */
|
|
76
|
+
export function getScratchTreeDirNames() {
|
|
77
|
+
return literalExcludedDirNames();
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Fnmatch-style glob patterns (`star/name/star`, not doublestar) for
|
|
81
|
+
* vulture's `--exclude` — the format `dead-code-client.ts` needs.
|
|
82
|
+
*/
|
|
83
|
+
export function getScratchTreeFnmatchPatterns() {
|
|
84
|
+
return literalExcludedDirNames().map((name) => `*/${name}/*`);
|
|
85
|
+
}
|
|
86
|
+
// --- Secrets-lane tier (#1562 review-round F1) ---
|
|
87
|
+
//
|
|
88
|
+
// Deliberately curated, NOT `EXCLUDED_DIRS`-derived: every name here must be
|
|
89
|
+
// individually justified as "never intentionally holds a first-party
|
|
90
|
+
// credential", not merely "not worth linting". See the module doc above for
|
|
91
|
+
// the walker-parity-vs-secrets-lane distinction and the 9-path probe that
|
|
92
|
+
// caught the original (too-broad) version of this fix.
|
|
93
|
+
export const SECRETS_LANE_SCRATCH_DIR_NAMES = [
|
|
94
|
+
// pi-ecosystem / coding-agent data + cache directories.
|
|
95
|
+
".pi",
|
|
96
|
+
".pi-lens",
|
|
97
|
+
".claude",
|
|
98
|
+
".codex",
|
|
99
|
+
".agents",
|
|
100
|
+
".worktrees",
|
|
101
|
+
".rescue",
|
|
102
|
+
".gstack",
|
|
103
|
+
".superpowers",
|
|
104
|
+
".guardrails",
|
|
105
|
+
".playwright-cli",
|
|
106
|
+
".playwright-mcp",
|
|
107
|
+
// git's own internal object storage — binary/compressed, not readable
|
|
108
|
+
// source; a byte-regex scan of it produces garbage, not real findings.
|
|
109
|
+
".git",
|
|
110
|
+
// Vendored/installed npm packages — third-party noise, not a first-party
|
|
111
|
+
// leak surface (unlike `vendor`/`third_party`, which are vendored SOURCE
|
|
112
|
+
// a project can carry an upstream leak in and stays in scope).
|
|
113
|
+
"node_modules",
|
|
114
|
+
// Generic build/package-manager CACHES — regenerated from source on every
|
|
115
|
+
// build/install, never a place a human commits a credential on purpose.
|
|
116
|
+
// Deliberately excludes build OUTPUT (`dist`/`build`/`out`/`target`/
|
|
117
|
+
// `coverage`) — a bundler/compiler CAN bake a real secret into output.
|
|
118
|
+
".turbo",
|
|
119
|
+
".cache",
|
|
120
|
+
".parcel-cache",
|
|
121
|
+
".svelte-kit",
|
|
122
|
+
".nuxt",
|
|
123
|
+
".yarn",
|
|
124
|
+
".pnpm-store",
|
|
125
|
+
".gradle",
|
|
126
|
+
".next",
|
|
127
|
+
".ruff_cache",
|
|
128
|
+
".tox",
|
|
129
|
+
".pytest_cache",
|
|
130
|
+
"venv",
|
|
131
|
+
".venv",
|
|
132
|
+
"__pycache__",
|
|
133
|
+
];
|
|
134
|
+
/**
|
|
135
|
+
* Regex patterns for gitleaks's `[allowlist] paths` config array, scoped to
|
|
136
|
+
* the narrow secrets-lane tier above (NOT the walker-parity list — see the
|
|
137
|
+
* module doc). Matched against the finding's relative path.
|
|
138
|
+
*
|
|
139
|
+
* #1562 review-round F4: gitleaks's `File` field preserves the OS-native
|
|
140
|
+
* separator from Go's directory walk — on Windows that's `\`, not `/` — so
|
|
141
|
+
* an anchor of only `(?:^|/)` never matches there. Both separators are
|
|
142
|
+
* accepted in the anchor and in the "rest of path" tail.
|
|
143
|
+
*/
|
|
144
|
+
export function getSecretsLaneAllowlistPaths() {
|
|
145
|
+
return SECRETS_LANE_SCRATCH_DIR_NAMES.map((name) => {
|
|
146
|
+
const escaped = escapeRegExp(name);
|
|
147
|
+
return `(?:^|[/\\\\])${escaped}(?:[/\\\\].*)?$`;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* True when any path segment of `relPath` (forward- or back-slash separated)
|
|
152
|
+
* is a secrets-lane scratch dir name. Used for the TS-side post-filter that
|
|
153
|
+
* backstops the generated gitleaks config — belt-and-suspenders because we
|
|
154
|
+
* can't exercise gitleaks's own TOML-regex engine in unit tests, only assert
|
|
155
|
+
* the config we hand it.
|
|
156
|
+
*/
|
|
157
|
+
export function isUnderSecretsLaneScratchTree(relPath) {
|
|
158
|
+
const names = new Set(SECRETS_LANE_SCRATCH_DIR_NAMES.map((n) => n.toLowerCase()));
|
|
159
|
+
const segments = relPath.split(/[/\\]/).filter(Boolean);
|
|
160
|
+
return segments.some((segment) => names.has(segment.toLowerCase()));
|
|
161
|
+
}
|
|
@@ -4,15 +4,31 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Search → edit is a common flow: the agent finds where something must change
|
|
6
6
|
* (ast_grep_search / lsp_navigation / grep), then edits exactly those lines.
|
|
7
|
-
* Those lines were genuinely shown, so they count as read — but ONLY
|
|
8
|
-
*
|
|
9
|
-
* region is still guarded.
|
|
7
|
+
* Those lines were genuinely shown, so they count as read — but ONLY the lines
|
|
8
|
+
* the search actually DELIVERED, never the whole file and never a blanket
|
|
9
|
+
* margin, so editing an unseen region is still guarded (#1904).
|
|
10
10
|
*/
|
|
11
11
|
import * as nodeFs from "node:fs";
|
|
12
12
|
import * as path from "node:path";
|
|
13
13
|
import { isPathIgnoredByProject } from "./file-utils.js";
|
|
14
14
|
import { isExternalOrVendorFile } from "./path-utils.js";
|
|
15
|
-
|
|
15
|
+
/** Clamp a delivered-context count to a usable non-negative integer. */
|
|
16
|
+
function normalizeMargin(value) {
|
|
17
|
+
if (value === undefined || !Number.isFinite(value))
|
|
18
|
+
return undefined;
|
|
19
|
+
return Math.max(0, Math.floor(value));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* #1904 item 2: this was 2, which credited every search hit as a 5-line read
|
|
23
|
+
* even though most searches print ONE line. The guard then let edits pass
|
|
24
|
+
* against lines the model never saw. Credit only delivered lines; callers that
|
|
25
|
+
* DID deliver context pass `contextBefore`/`contextAfter` per location.
|
|
26
|
+
*
|
|
27
|
+
* Note this is not the only slack in the system: `readCoversRange` in
|
|
28
|
+
* read-guard.ts still widens every read record by `config.contextLines` when it
|
|
29
|
+
* tests coverage, so a bare hit remains editable within that configured band.
|
|
30
|
+
*/
|
|
31
|
+
const DEFAULT_CONTEXT_MARGIN = 0;
|
|
16
32
|
/**
|
|
17
33
|
* Record each shown location as a read (± context margin). Resolves project-
|
|
18
34
|
* relative paths, skips external/vendor/ignored/non-existent files, and dedupes
|
|
@@ -39,11 +55,18 @@ export function registerSearchReads(readGuard, locations, opts) {
|
|
|
39
55
|
catch {
|
|
40
56
|
continue;
|
|
41
57
|
}
|
|
42
|
-
const
|
|
58
|
+
const marginBefore = normalizeMargin(loc.contextBefore) ?? margin;
|
|
59
|
+
const marginAfter = normalizeMargin(loc.contextAfter) ?? margin;
|
|
60
|
+
const creditReason = marginBefore === 0 && marginAfter === 0
|
|
61
|
+
? "match-lines-only"
|
|
62
|
+
: loc.contextBefore !== undefined || loc.contextAfter !== undefined
|
|
63
|
+
? "delivered-context-flags"
|
|
64
|
+
: "caller-margin";
|
|
65
|
+
const start = Math.max(1, Math.floor(loc.startLine) - marginBefore);
|
|
43
66
|
const endLine = Number.isFinite(loc.endLine)
|
|
44
67
|
? loc.endLine
|
|
45
68
|
: loc.startLine;
|
|
46
|
-
const end = Math.max(start, Math.floor(endLine) +
|
|
69
|
+
const end = Math.max(start, Math.floor(endLine) + marginAfter);
|
|
47
70
|
const limit = end - start + 1;
|
|
48
71
|
const key = `${abs}:${start}:${limit}`;
|
|
49
72
|
if (seen.has(key))
|
|
@@ -56,6 +79,11 @@ export function registerSearchReads(readGuard, locations, opts) {
|
|
|
56
79
|
effectiveOffset: start,
|
|
57
80
|
effectiveLimit: limit,
|
|
58
81
|
expandedByLsp: false,
|
|
82
|
+
searchCredit: {
|
|
83
|
+
marginBefore,
|
|
84
|
+
marginAfter,
|
|
85
|
+
reason: creditReason,
|
|
86
|
+
},
|
|
59
87
|
turnIndex: opts.turnIndex,
|
|
60
88
|
writeIndex: opts.writeIndex,
|
|
61
89
|
timestamp: Date.now(),
|