@herbertgao/pi-extensions 2026.9.1 → 2026.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/THIRD_PARTY_NOTICES.md +24 -0
- package/node_modules/@herbertgao/sol-pi/LICENSE +19 -0
- package/node_modules/@herbertgao/sol-pi/README.md +159 -0
- package/node_modules/@herbertgao/sol-pi/SECURITY.md +26 -0
- package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +19 -0
- package/node_modules/@herbertgao/sol-pi/agents-install.md +150 -0
- package/node_modules/@herbertgao/sol-pi/assets/sol-pi-hero.png +0 -0
- package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +69 -0
- package/node_modules/@herbertgao/sol-pi/docs/configuration.md +75 -0
- package/node_modules/@herbertgao/sol-pi/package.json +76 -0
- package/node_modules/@herbertgao/sol-pi/scripts/check-pi-compat.mjs +32 -0
- package/node_modules/@herbertgao/sol-pi/scripts/check-sol-pi-config.mjs +120 -0
- package/node_modules/@herbertgao/sol-pi/sol-pi.example.json +10 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/config.ts +135 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/file-queue.ts +74 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +185 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/then-run.ts +128 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/archive.ts +53 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/candidate.ts +101 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/config.ts +71 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/index.ts +220 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/journal.ts +25 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/provider.ts +164 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/receipt.ts +177 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/index.ts +227 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/ledger.ts +20 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/observation.ts +252 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/economics.ts +237 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +455 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/index.ts +49 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/plan.ts +79 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +208 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/tools.ts +100 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/index.ts +42 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/runtime-paths.ts +17 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/tui.ts +71 -0
- package/node_modules/@narumitw/pi-btw/README.md +57 -141
- package/node_modules/@narumitw/pi-btw/dist/index.ts +478 -43
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +4 -4
- package/node_modules/@narumitw/pi-btw/docs/workflows.md +74 -0
- package/node_modules/@narumitw/pi-btw/package.json +2 -1
- package/node_modules/@narumitw/pi-btw/src/btw.ts +28 -3
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +32 -2
- package/node_modules/@narumitw/pi-btw/src/keybindings.ts +330 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +136 -19
- package/node_modules/@narumitw/pi-btw/src/settings.ts +32 -0
- package/node_modules/@narumitw/pi-btw/src/side-thread.ts +57 -5
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +52 -30
- package/node_modules/pi-lens/CHANGELOG.md +260 -0
- package/node_modules/pi-lens/README.md +13 -8
- package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +3 -1
- package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +1 -1
- package/node_modules/pi-lens/dist/clients/analysed-root.js +1 -0
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +1 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +1 -8
- package/node_modules/pi-lens/dist/clients/ast-grep-types.js +2 -0
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +133 -1
- package/node_modules/pi-lens/dist/clients/biome-client.js +13 -2
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +0 -6
- package/node_modules/pi-lens/dist/clients/bootstrap.js +4 -4
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +1 -1
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +2 -5
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +1 -9
- package/node_modules/pi-lens/dist/clients/cache-observability.js +122 -6
- package/node_modules/pi-lens/dist/clients/cargo-manifest.js +2 -2
- package/node_modules/pi-lens/dist/clients/cascade-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/child-unref.js +1 -19
- package/node_modules/pi-lens/dist/clients/complexity-client.js +5 -0
- package/node_modules/pi-lens/dist/clients/config-core/index.js +11 -8
- package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +1 -1
- package/node_modules/pi-lens/dist/clients/config-core/provenance.js +2 -9
- package/node_modules/pi-lens/dist/clients/config-core/records.js +1 -1
- package/node_modules/pi-lens/dist/clients/config-core/schema.js +3 -5
- package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +3 -1
- package/node_modules/pi-lens/dist/clients/config-resolve.js +10 -7
- package/node_modules/pi-lens/dist/clients/config-schema.js +56 -2
- package/node_modules/pi-lens/dist/clients/config-warn.js +2 -2
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +8 -1
- package/node_modules/pi-lens/dist/clients/dead-code-logger.js +0 -4
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +5 -1
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +1 -1
- package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +0 -4
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +38 -41
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +18 -1
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +0 -6
- package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +0 -3
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-complexity.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-fan-out.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +7 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +19 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +15 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +3 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +12 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +5 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +5 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +1 -64
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +8 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils.js +0 -21
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +2 -20
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +5 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/utils/format-utils.js +2 -2
- package/node_modules/pi-lens/dist/clients/disposition-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/effective-config.js +12 -2
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +2 -2
- package/node_modules/pi-lens/dist/clients/extension-log.js +2 -0
- package/node_modules/pi-lens/dist/clients/file-kinds.js +1 -38
- package/node_modules/pi-lens/dist/clients/file-role.js +18 -1
- package/node_modules/pi-lens/dist/clients/file-time.js +1 -1
- package/node_modules/pi-lens/dist/clients/file-utils.js +5 -1
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +4 -0
- package/node_modules/pi-lens/dist/clients/format-service.js +0 -1
- package/node_modules/pi-lens/dist/clients/formatters.js +66 -93
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +3 -4
- package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -0
- package/node_modules/pi-lens/dist/clients/git-guard.js +5 -0
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +42 -6
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +48 -7
- package/node_modules/pi-lens/dist/clients/grammar-source.js +3 -3
- package/node_modules/pi-lens/dist/clients/installer/index.js +416 -61
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +84 -18
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +6 -6
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +9 -1
- package/node_modules/pi-lens/dist/clients/knip-client.js +9 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +12 -11
- package/node_modules/pi-lens/dist/clients/language-registry.js +5 -1
- package/node_modules/pi-lens/dist/clients/latency-logger.js +7 -7
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -1
- package/node_modules/pi-lens/dist/clients/lens-config.js +23 -0
- package/node_modules/pi-lens/dist/clients/lens-engine.js +3 -4
- package/node_modules/pi-lens/dist/clients/lens-events.js +1 -1
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +18 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +1 -1
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +0 -36
- package/node_modules/pi-lens/dist/clients/lsp/client.js +4 -3
- package/node_modules/pi-lens/dist/clients/lsp/config.js +37 -7
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +24 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +79 -1
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +3 -3
- package/node_modules/pi-lens/dist/clients/lsp/index.js +491 -64
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/language.js +0 -8
- package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +0 -2
- package/node_modules/pi-lens/dist/clients/lsp/server.js +62 -15
- package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +0 -1
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +5 -5
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +6 -0
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +37 -4
- package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +1 -1
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +3 -0
- package/node_modules/pi-lens/dist/clients/mcp/session.js +2 -0
- package/node_modules/pi-lens/dist/clients/metrics-history.js +28 -107
- package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +1 -1
- package/node_modules/pi-lens/dist/clients/module-report.js +1 -1
- package/node_modules/pi-lens/dist/clients/mutating-tool.js +3 -3
- package/node_modules/pi-lens/dist/clients/mutation-attribution.js +3 -3
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +0 -4
- package/node_modules/pi-lens/dist/clients/observed-mutation.js +9 -9
- package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +2 -6
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +2 -0
- package/node_modules/pi-lens/dist/clients/opengrep-config.js +1 -1
- package/node_modules/pi-lens/dist/clients/package-manager.js +2 -1
- package/node_modules/pi-lens/dist/clients/path-utils.js +23 -2
- package/node_modules/pi-lens/dist/clients/performance-report.js +2 -2
- package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +9 -4
- package/node_modules/pi-lens/dist/clients/pipeline.js +5 -4
- package/node_modules/pi-lens/dist/clients/project-changes.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +38 -10
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +10 -9
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +49 -1
- package/node_modules/pi-lens/dist/clients/project-scan-policy.js +3 -51
- package/node_modules/pi-lens/dist/clients/python-provenance.js +1 -1
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +3 -1
- package/node_modules/pi-lens/dist/clients/read-guard.js +5 -2
- package/node_modules/pi-lens/dist/clients/recent-touches.js +2 -2
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +3 -5
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +1 -1
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +2 -0
- package/node_modules/pi-lens/dist/clients/ruff-client.js +18 -9
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +10 -1
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +5 -0
- package/node_modules/pi-lens/dist/clients/runtime-session.js +58 -14
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +11 -1
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +4 -1
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +48 -1
- package/node_modules/pi-lens/dist/clients/sanitize.js +0 -11
- package/node_modules/pi-lens/dist/clients/scan-utils.js +1 -56
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -2
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +69 -1
- package/node_modules/pi-lens/dist/clients/session-summary.js +0 -24
- package/node_modules/pi-lens/dist/clients/sg-runner.js +2 -1
- package/node_modules/pi-lens/dist/clients/sgconfig.js +1 -5
- package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +1 -1
- package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +108 -0
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +2 -2
- package/node_modules/pi-lens/dist/clients/startup-scan.js +2 -10
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +291 -76
- package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +77 -72
- package/node_modules/pi-lens/dist/clients/tool-config.js +199 -0
- package/node_modules/pi-lens/dist/clients/tool-cwd.js +299 -0
- package/node_modules/pi-lens/dist/clients/tool-policy.js +1 -1
- package/node_modules/pi-lens/dist/clients/tool-probe.js +53 -0
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +42 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +1 -52
- package/node_modules/pi-lens/dist/clients/trivy-client.js +9 -1
- package/node_modules/pi-lens/dist/clients/tui-fit.js +0 -4
- package/node_modules/pi-lens/dist/clients/turn-context.js +52 -0
- package/node_modules/pi-lens/dist/clients/user-notify.js +0 -4
- package/node_modules/pi-lens/dist/clients/widget-state.js +4 -3
- package/node_modules/pi-lens/dist/clients/word-index-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/word-index-store.js +3 -7
- package/node_modules/pi-lens/dist/clients/word-index.js +9 -16
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +1 -1
- package/node_modules/pi-lens/dist/index.js +19969 -17481
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -2
- package/node_modules/pi-lens/dist/mcp/build-staleness.js +1 -1
- package/node_modules/pi-lens/dist/mcp/server.js +135 -159
- package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +1 -1
- package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +1 -1
- package/node_modules/pi-lens/dist/tools/activate-tools.js +10 -7
- package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +2 -13
- package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +8 -13
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +83 -39
- package/node_modules/pi-lens/dist/tools/effective-config.js +4 -3
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +1 -10
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +354 -86
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +54 -112
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +20 -44
- package/node_modules/pi-lens/dist/tools/lsp-structured-output.js +3 -3
- package/node_modules/pi-lens/dist/tools/module-report.js +5 -9
- package/node_modules/pi-lens/dist/tools/project-report.js +9 -17
- package/node_modules/pi-lens/dist/tools/render-compact.js +281 -2
- package/node_modules/pi-lens/dist/tools/symbol-search.js +3 -4
- package/node_modules/pi-lens/docs/agent-guide.md +3 -4
- package/node_modules/pi-lens/docs/agent-tools.md +46 -22
- package/node_modules/pi-lens/docs/configuration.md +9 -0
- package/node_modules/pi-lens/docs/environment-variables.md +0 -5
- package/node_modules/pi-lens/docs/features.md +5 -5
- package/node_modules/pi-lens/docs/globalconfig.md +31 -1
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +9 -1
- package/node_modules/pi-lens/docs/mcp.md +13 -1
- package/node_modules/pi-lens/docs/pi-lens-fixer.md +71 -0
- package/node_modules/pi-lens/docs/pi-lens-investigator.md +15 -0
- package/node_modules/pi-lens/docs/pi-lens-monitor.md +88 -0
- package/node_modules/pi-lens/docs/pi-lens-reviewer.md +41 -0
- package/node_modules/pi-lens/docs/pi-lens-subagent.md +21 -2
- package/node_modules/pi-lens/docs/public-api-stability.md +1 -0
- package/node_modules/pi-lens/docs/real-harness.md +46 -0
- package/node_modules/pi-lens/docs/release-qa-baseline.md +17 -5
- package/node_modules/pi-lens/docs/servercapabilities.md +2 -3
- package/node_modules/pi-lens/docs/settings.md +37 -2
- package/node_modules/pi-lens/docs/tools_improvement2.md +4 -4
- package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +1 -1
- package/node_modules/pi-lens/docs/usage.md +13 -3
- package/node_modules/pi-lens/docs/word-index.md +1 -1
- package/node_modules/pi-lens/package.json +15 -15
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/sql-injection.yml +7 -3
- package/node_modules/pi-lens/rules/typos/_typos.toml +4 -2
- package/node_modules/pi-lens/scripts/lib/skills-predicate.mjs +1 -1
- package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +1 -1
- package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +4 -2
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +8 -6
- package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +19 -9
- package/node_modules/pi-web-access/CHANGELOG.md +29 -0
- package/node_modules/pi-web-access/README.md +33 -22
- package/node_modules/pi-web-access/abortable.ts +17 -0
- package/node_modules/pi-web-access/crawl4ai.ts +204 -0
- package/node_modules/pi-web-access/credential-source.ts +1 -0
- package/node_modules/pi-web-access/curator-page.ts +20 -2
- package/node_modules/pi-web-access/curator-run.ts +44 -0
- package/node_modules/pi-web-access/curator-server.ts +3 -1
- package/node_modules/pi-web-access/duckduckgo.ts +1 -1
- package/node_modules/pi-web-access/extract.ts +57 -12
- package/node_modules/pi-web-access/fetch-params.ts +1 -1
- package/node_modules/pi-web-access/gemini-search.ts +9 -5
- package/node_modules/pi-web-access/index.ts +25 -18
- package/node_modules/pi-web-access/openai-search.ts +35 -13
- package/node_modules/pi-web-access/package.json +2 -2
- package/node_modules/pi-web-access/page-query.ts +5 -2
- package/node_modules/pi-web-access/query-rewrite.ts +5 -2
- package/node_modules/pi-web-access/serpapi.ts +220 -0
- package/node_modules/pi-web-access/ssrf-protection.ts +5 -1
- package/node_modules/pi-web-access/storage.ts +10 -0
- package/node_modules/pi-web-access/summary-review.ts +34 -21
- package/node_modules/pi-web-access/utils.ts +6 -4
- package/package.json +7 -4
- package/node_modules/pi-lens/dist/tools/ast-dump.js +0 -103
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
import { readFile } from "node:fs/promises";
|
|
7
|
+
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
8
|
+
import { type BashToolOptions, createBashToolDefinition, type ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
9
|
+
import { Type } from "typebox";
|
|
10
|
+
import { withFusedFileQueue } from "./file-queue.ts";
|
|
11
|
+
|
|
12
|
+
export const THEN_RUN_SUCCEEDED = "[then_run:succeeded]";
|
|
13
|
+
export const THEN_RUN_FAILED = "[then_run:failed]";
|
|
14
|
+
export const THEN_RUN_SKIPPED = "[then_run:skipped]";
|
|
15
|
+
|
|
16
|
+
export interface ThenRunInput {
|
|
17
|
+
command: string;
|
|
18
|
+
timeout?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function createThenRunSchema(description: string) {
|
|
22
|
+
return Type.Optional(
|
|
23
|
+
Type.Object(
|
|
24
|
+
{
|
|
25
|
+
command: Type.String({ description: "Bash command to run" }),
|
|
26
|
+
timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (optional, no default timeout)" })),
|
|
27
|
+
},
|
|
28
|
+
{ description },
|
|
29
|
+
),
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function errorText(error: unknown): string {
|
|
34
|
+
return error instanceof Error ? error.message : String(error);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function resultText(result: AgentToolResult<unknown>): string {
|
|
38
|
+
return result.content
|
|
39
|
+
.filter((block) => block.type === "text")
|
|
40
|
+
.map((block) => block.text)
|
|
41
|
+
.join("\n");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function thenRunSkippedError(error: unknown): Error {
|
|
45
|
+
return new Error(
|
|
46
|
+
`${errorText(error)}\n\n${THEN_RUN_SKIPPED} The file mutation did not complete successfully; the command was not run.`,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function fileSha256(path: string): Promise<string> {
|
|
51
|
+
return createHash("sha256").update(await readFile(path)).digest("hex");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function assertUnchangedBeforeCommand(
|
|
55
|
+
path: string,
|
|
56
|
+
yieldForInterference: () => Promise<void> = () => new Promise<void>((resolve) => setImmediate(resolve)),
|
|
57
|
+
): Promise<void> {
|
|
58
|
+
try {
|
|
59
|
+
const mutationHash = await fileSha256(path);
|
|
60
|
+
await yieldForInterference();
|
|
61
|
+
const commandHash = await fileSha256(path);
|
|
62
|
+
if (mutationHash !== commandHash) {
|
|
63
|
+
throw new Error("target content changed after the fused mutation");
|
|
64
|
+
}
|
|
65
|
+
} catch (error) {
|
|
66
|
+
throw new Error(`${THEN_RUN_SKIPPED} ${errorText(error)}; the command was not run.`, { cause: error });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Apply a file mutation and, when the model asked for one, run its follow-up
|
|
72
|
+
* command before returning a single observation.
|
|
73
|
+
*
|
|
74
|
+
* Both steps run inside one SoL-Pi queue slot for `absolutePath`, so another
|
|
75
|
+
* fused mutation of the same file cannot interleave. Pi's built-in mutation
|
|
76
|
+
* tool keeps its own queue; the two queues are not nested.
|
|
77
|
+
*/
|
|
78
|
+
export async function executeMutationThenRun<TDetails>({
|
|
79
|
+
toolCallId,
|
|
80
|
+
absolutePath,
|
|
81
|
+
thenRun,
|
|
82
|
+
mutate,
|
|
83
|
+
bashOptions,
|
|
84
|
+
signal,
|
|
85
|
+
ctx,
|
|
86
|
+
}: {
|
|
87
|
+
toolCallId: string;
|
|
88
|
+
absolutePath: string;
|
|
89
|
+
thenRun: ThenRunInput | undefined;
|
|
90
|
+
mutate: () => Promise<AgentToolResult<TDetails>>;
|
|
91
|
+
bashOptions: BashToolOptions | undefined;
|
|
92
|
+
signal: AbortSignal | undefined;
|
|
93
|
+
ctx: ExtensionContext;
|
|
94
|
+
}): Promise<AgentToolResult<TDetails>> {
|
|
95
|
+
return withFusedFileQueue(absolutePath, async () => {
|
|
96
|
+
let mutationResult: AgentToolResult<TDetails>;
|
|
97
|
+
try {
|
|
98
|
+
mutationResult = await mutate();
|
|
99
|
+
} catch (error) {
|
|
100
|
+
if (thenRun !== undefined) {
|
|
101
|
+
throw thenRunSkippedError(error);
|
|
102
|
+
}
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (thenRun === undefined) {
|
|
107
|
+
return mutationResult;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
await assertUnchangedBeforeCommand(absolutePath);
|
|
111
|
+
const bash = createBashToolDefinition(ctx.cwd, bashOptions);
|
|
112
|
+
try {
|
|
113
|
+
// pi-lens-ignore: sql-injection
|
|
114
|
+
const bashResult = await bash.execute(`${toolCallId}:then_run`, thenRun, signal, undefined, ctx);
|
|
115
|
+
const output = resultText(bashResult);
|
|
116
|
+
return {
|
|
117
|
+
...mutationResult,
|
|
118
|
+
content: [
|
|
119
|
+
...mutationResult.content,
|
|
120
|
+
{ type: "text", text: output ? `${THEN_RUN_SUCCEEDED}\n${output}` : THEN_RUN_SUCCEEDED },
|
|
121
|
+
],
|
|
122
|
+
};
|
|
123
|
+
} catch (error) {
|
|
124
|
+
const mutationOutput = resultText(mutationResult);
|
|
125
|
+
throw new Error([mutationOutput, THEN_RUN_FAILED, errorText(error)].filter(Boolean).join("\n\n"), { cause: error });
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/archive.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { isRecord, type ReducerConfig, sha256 } from "./config.ts";
|
|
8
|
+
|
|
9
|
+
export interface ArchiveObject {
|
|
10
|
+
readonly hash: string;
|
|
11
|
+
readonly bytes: number;
|
|
12
|
+
readonly chars: number;
|
|
13
|
+
readonly lines: number;
|
|
14
|
+
readonly path: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Archived logs live under SoL-Pi's session-derived runtime directory.
|
|
19
|
+
*/
|
|
20
|
+
export function archiveRoot(config: ReducerConfig): string {
|
|
21
|
+
return config.storeRoot;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Store the raw log under its own content hash.
|
|
26
|
+
*
|
|
27
|
+
* Every quote in a receipt is checked against this archive, and the receipt
|
|
28
|
+
* points the frontier agent back at this path for exact readback. An existing
|
|
29
|
+
* object with the same name but different bytes is an integrity failure, not a
|
|
30
|
+
* cache hit.
|
|
31
|
+
*/
|
|
32
|
+
export async function archiveBody(root: string, body: string): Promise<ArchiveObject> {
|
|
33
|
+
const hash = sha256(body);
|
|
34
|
+
const objectDir = join(root, "objects", hash.slice(0, 2));
|
|
35
|
+
const path = join(objectDir, `${hash}.txt`);
|
|
36
|
+
await mkdir(objectDir, { recursive: true, mode: 0o700 });
|
|
37
|
+
try {
|
|
38
|
+
await writeFile(path, body, { encoding: "utf8", flag: "wx", mode: 0o600 });
|
|
39
|
+
} catch (error) {
|
|
40
|
+
if (!isRecord(error) || error.code !== "EEXIST") throw error;
|
|
41
|
+
const existing = await readFile(path, "utf8");
|
|
42
|
+
if (existing !== body || sha256(existing) !== hash) {
|
|
43
|
+
throw new Error(`Reducer archive integrity failure: ${path}`, { cause: error });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
hash,
|
|
48
|
+
bytes: Buffer.byteLength(body, "utf8"),
|
|
49
|
+
chars: body.length,
|
|
50
|
+
lines: body.length === 0 ? 0 : body.split("\n").length,
|
|
51
|
+
path,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
import { lstat, readFile, realpath } from "node:fs/promises";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import { basename, dirname } from "node:path";
|
|
8
|
+
import type { ToolResultEvent } from "@earendil-works/pi-coding-agent";
|
|
9
|
+
import { recordValue } from "./config.ts";
|
|
10
|
+
|
|
11
|
+
/** Markers written by the action-fusion extension around a fused command's output. */
|
|
12
|
+
const THEN_RUN_SUCCEEDED = "[then_run:succeeded]";
|
|
13
|
+
const THEN_RUN_FAILED = "[then_run:failed]";
|
|
14
|
+
|
|
15
|
+
export interface ReducibleToolResult {
|
|
16
|
+
readonly command: string;
|
|
17
|
+
readonly body: string;
|
|
18
|
+
/** Put the receipt back where the raw output was, leaving the rest of the result alone. */
|
|
19
|
+
readonly projectReceipt: (receipt: string) => ToolResultEvent["content"];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function textContent(event: ToolResultEvent): string {
|
|
23
|
+
return event.content
|
|
24
|
+
.filter((item): item is { type: "text"; text: string } => item.type === "text")
|
|
25
|
+
.map((item) => item.text)
|
|
26
|
+
.join("\n");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function detailsFullOutputPath(details: unknown): string | undefined {
|
|
30
|
+
const value = recordValue(details, "fullOutputPath");
|
|
31
|
+
return typeof value === "string" ? value : undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function safePiBashTempPath(path: string | undefined): Promise<boolean> {
|
|
35
|
+
if (!path || !/^pi-bash-[^/\\]+\.log$/u.test(basename(path))) return false;
|
|
36
|
+
try {
|
|
37
|
+
const [candidate, root, status] = await Promise.all([realpath(path), realpath(tmpdir()), lstat(path)]);
|
|
38
|
+
return status.isFile() && !status.isSymbolicLink() && dirname(candidate) === root;
|
|
39
|
+
} catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Prefer the untruncated file pi wrote for a large bash result, so evidence is
|
|
46
|
+
* checked against the exact bytes the command produced rather than a preview.
|
|
47
|
+
*/
|
|
48
|
+
async function exactBodyFromInline(inline: string, details: unknown): Promise<string> {
|
|
49
|
+
const detailsPath = detailsFullOutputPath(details);
|
|
50
|
+
const inlineMatch = inline.match(/Full output:\s*([^\]\r\n]+)/u);
|
|
51
|
+
const candidate = detailsPath ?? inlineMatch?.[1]?.trim();
|
|
52
|
+
if (!candidate || !(await safePiBashTempPath(candidate))) return inline;
|
|
53
|
+
try {
|
|
54
|
+
return await readFile(candidate, "utf8");
|
|
55
|
+
} catch {
|
|
56
|
+
return inline;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Identify the log inside a tool result: either a plain bash result, or the
|
|
62
|
+
* command output appended by a fused `edit`/`write` call.
|
|
63
|
+
*/
|
|
64
|
+
export async function reducibleToolResult(event: ToolResultEvent): Promise<ReducibleToolResult | undefined> {
|
|
65
|
+
if (event.toolName === "bash") {
|
|
66
|
+
const command = typeof event.input.command === "string" ? event.input.command : "";
|
|
67
|
+
if (!command) return undefined;
|
|
68
|
+
const inline = textContent(event);
|
|
69
|
+
return {
|
|
70
|
+
command,
|
|
71
|
+
body: await exactBodyFromInline(inline, event.details),
|
|
72
|
+
projectReceipt: (receipt) => [{ type: "text", text: receipt }],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (event.toolName !== "write" && event.toolName !== "edit") return undefined;
|
|
76
|
+
const thenRun = recordValue(event.input, "then_run");
|
|
77
|
+
const commandValue = recordValue(thenRun, "command");
|
|
78
|
+
if (typeof commandValue !== "string" || !commandValue) return undefined;
|
|
79
|
+
const marker = event.isError ? THEN_RUN_FAILED : THEN_RUN_SUCCEEDED;
|
|
80
|
+
for (let index = 0; index < event.content.length; index++) {
|
|
81
|
+
const block = event.content[index];
|
|
82
|
+
if (!block || block.type !== "text") continue;
|
|
83
|
+
const markerIndex = block.text.indexOf(marker);
|
|
84
|
+
if (markerIndex < 0) continue;
|
|
85
|
+
const suffixStart = markerIndex + marker.length;
|
|
86
|
+
const suffix = block.text.slice(suffixStart);
|
|
87
|
+
const separator = suffix.match(/^(?:\r?\n)+/u)?.[0] ?? "\n";
|
|
88
|
+
const inline = suffix.slice(separator === "\n" && !suffix.startsWith("\n") ? 0 : separator.length);
|
|
89
|
+
return {
|
|
90
|
+
command: commandValue,
|
|
91
|
+
body: await exactBodyFromInline(inline, event.details),
|
|
92
|
+
projectReceipt: (receipt) =>
|
|
93
|
+
event.content.map((content, contentIndex) =>
|
|
94
|
+
contentIndex === index && content.type === "text"
|
|
95
|
+
? { ...content, text: `${content.text.slice(0, suffixStart)}${separator}${receipt}` }
|
|
96
|
+
: content,
|
|
97
|
+
),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/config.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
|
|
9
|
+
export const REDUCER_EVENT_TYPE = "sol-pi-evidence-preserving-reducer-v1" as const;
|
|
10
|
+
export const REDUCER_EVENT_SCHEMA = "sol-pi-evidence-preserving-reducer/1" as const;
|
|
11
|
+
export const REDUCER_RECEIPT_SCHEMA = "sol-pi-evidence-receipt/1" as const;
|
|
12
|
+
export const REDUCER_RECEIPT_PREFIX = "sol_pi_evidence_receipt_v1" as const;
|
|
13
|
+
|
|
14
|
+
export const MAX_EVIDENCE_ITEMS = 12;
|
|
15
|
+
export const MAX_QUOTE_CHARS = 600;
|
|
16
|
+
|
|
17
|
+
const DEFAULT_MIN_BYTES = 4_096;
|
|
18
|
+
const DEFAULT_MAX_CHARS = 600_000;
|
|
19
|
+
const DEFAULT_MAX_OUTPUT_TOKENS = 2_048;
|
|
20
|
+
const DEFAULT_TIMEOUT_MS = 90_000;
|
|
21
|
+
|
|
22
|
+
export const DEFAULT_REDUCER_PROVIDER = ["openai", "codex"].join("-");
|
|
23
|
+
export const DEFAULT_REDUCER_MODEL = ["gpt-5.6", "luna"].join("-");
|
|
24
|
+
|
|
25
|
+
export const DIAGNOSTIC_COMMAND =
|
|
26
|
+
/(?:^|[;&|()\s])(?:lake\s+build|lake\s+env\s+lean|lean|coq|cargo(?:\s+(?:build|test|check))?|zig\s+build|pytest|python(?:3)?\s+-m\s+(?:pytest|unittest|py_compile)|ctest|cmake\s+--build|ninja|make|npm\s+test|pnpm\s+test|yarn\s+test|go\s+test|bazel\s+test)(?:\s|$)/i;
|
|
27
|
+
|
|
28
|
+
export const FAILURE_SIGNAL = /error|failed|failure|fatal|exception|panic|timeout|unsolved|type mismatch|assert/i;
|
|
29
|
+
export const LIKELY_SECRET = /(?:api[_-]?key|authorization|bearer|access[_-]?token|secret)[^\n]{0,32}[=:][^\n]+/i;
|
|
30
|
+
|
|
31
|
+
export interface ReducerConfig {
|
|
32
|
+
readonly maxChars: number;
|
|
33
|
+
readonly maxOutputTokens: number;
|
|
34
|
+
readonly minBytes: number;
|
|
35
|
+
readonly reducerModel: string;
|
|
36
|
+
readonly reducerProvider: string;
|
|
37
|
+
readonly runId: string;
|
|
38
|
+
readonly storeRoot: string;
|
|
39
|
+
readonly timeoutMs: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface ReducerConfigOptions {
|
|
43
|
+
readonly reducerModel?: string;
|
|
44
|
+
readonly reducerProvider?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function sha256(value: string): string {
|
|
48
|
+
return createHash("sha256").update(value, "utf8").digest("hex");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
52
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// pi-lens-ignore: no-unknown-returns
|
|
56
|
+
export function recordValue(value: unknown, key: string): unknown {
|
|
57
|
+
return isRecord(value) ? value[key] : undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function loadReducerConfig(runtimeDirectory: string, options: ReducerConfigOptions = {}): ReducerConfig {
|
|
61
|
+
return Object.freeze({
|
|
62
|
+
maxChars: DEFAULT_MAX_CHARS,
|
|
63
|
+
maxOutputTokens: DEFAULT_MAX_OUTPUT_TOKENS,
|
|
64
|
+
minBytes: DEFAULT_MIN_BYTES,
|
|
65
|
+
reducerModel: options.reducerModel ?? DEFAULT_REDUCER_MODEL,
|
|
66
|
+
reducerProvider: options.reducerProvider ?? DEFAULT_REDUCER_PROVIDER,
|
|
67
|
+
runId: sha256(runtimeDirectory).slice(0, 16),
|
|
68
|
+
storeRoot: join(runtimeDirectory, "evidence-preserving-reducer"),
|
|
69
|
+
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
70
|
+
});
|
|
71
|
+
}
|
package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/index.ts
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Evidence-Preserving Reducer - delegate the first read of a long build or test
|
|
7
|
+
* log to the configured reducer model, then verify what comes back.
|
|
8
|
+
*
|
|
9
|
+
* In build and test trajectories only a few lines of a long log change the next
|
|
10
|
+
* decision. This extension archives the raw log, sends it through the reducer
|
|
11
|
+
* provider/model selected by the top-level SoL-Pi config, and accepts the
|
|
12
|
+
* resulting receipt only when every quoted line is found byte for byte in the
|
|
13
|
+
* archive. A receipt that cannot be checked is discarded and the original
|
|
14
|
+
* output reaches the frontier agent untouched.
|
|
15
|
+
*
|
|
16
|
+
* Delegation therefore never requires trusting a fluent summary.
|
|
17
|
+
*
|
|
18
|
+
* The top-level SoL-Pi config enables this mechanism. Provider selection and
|
|
19
|
+
* authentication remain with Pi; storage and run identity come from the session.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type {
|
|
23
|
+
ExtensionAPI,
|
|
24
|
+
ExtensionContext,
|
|
25
|
+
ExtensionFactory,
|
|
26
|
+
ToolResultEvent,
|
|
27
|
+
} from "@earendil-works/pi-coding-agent";
|
|
28
|
+
import { runtimeRoot } from "../../runtime-paths.ts";
|
|
29
|
+
import { formatSavingsBytes, showSolPiSavings } from "../../tui.ts";
|
|
30
|
+
import { archiveBody, archiveRoot } from "./archive.ts";
|
|
31
|
+
import { reducibleToolResult } from "./candidate.ts";
|
|
32
|
+
import {
|
|
33
|
+
DIAGNOSTIC_COMMAND,
|
|
34
|
+
isRecord,
|
|
35
|
+
LIKELY_SECRET,
|
|
36
|
+
loadReducerConfig,
|
|
37
|
+
REDUCER_RECEIPT_SCHEMA,
|
|
38
|
+
type ReducerConfig,
|
|
39
|
+
type ReducerConfigOptions,
|
|
40
|
+
sha256,
|
|
41
|
+
} from "./config.ts";
|
|
42
|
+
import { createJournal, type Journal } from "./journal.ts";
|
|
43
|
+
import { callReducer, type ProviderResult } from "./provider.ts";
|
|
44
|
+
import { receiptText, validateReceipt } from "./receipt.ts";
|
|
45
|
+
|
|
46
|
+
export interface ReducedToolResult {
|
|
47
|
+
readonly content: ToolResultEvent["content"];
|
|
48
|
+
readonly details: Record<string, unknown>;
|
|
49
|
+
readonly isError: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type EvidencePreservingReducerOptions = ReducerConfigOptions;
|
|
53
|
+
|
|
54
|
+
function errorName(error: unknown): string | undefined {
|
|
55
|
+
return isRecord(error) && typeof error.name === "string" ? error.name : undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function reduceToolResult(
|
|
59
|
+
journal: Journal,
|
|
60
|
+
config: ReducerConfig,
|
|
61
|
+
event: ToolResultEvent,
|
|
62
|
+
context: ExtensionContext,
|
|
63
|
+
): Promise<ReducedToolResult | undefined> {
|
|
64
|
+
const reducible = await reducibleToolResult(event);
|
|
65
|
+
if (!reducible || !DIAGNOSTIC_COMMAND.test(reducible.command)) return undefined;
|
|
66
|
+
const { body, command } = reducible;
|
|
67
|
+
if (Buffer.byteLength(body, "utf8") < config.minBytes) return undefined;
|
|
68
|
+
if (body.length > config.maxChars) {
|
|
69
|
+
journal("fallback", { reason: "source-over-max-chars", sourceChars: body.length, maxChars: config.maxChars });
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
if (LIKELY_SECRET.test(body)) {
|
|
73
|
+
journal("fallback", { reason: "likely-secret" });
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const archive = await archiveBody(archiveRoot(config), body);
|
|
78
|
+
journal("candidate", {
|
|
79
|
+
toolCallId: event.toolCallId,
|
|
80
|
+
commandSha256: sha256(command),
|
|
81
|
+
isError: event.isError,
|
|
82
|
+
sourceSha256: archive.hash,
|
|
83
|
+
sourceBytes: archive.bytes,
|
|
84
|
+
sourceLines: archive.lines,
|
|
85
|
+
sourcePath: archive.path,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
let provider: ProviderResult;
|
|
89
|
+
try {
|
|
90
|
+
provider = await callReducer(config, command, event.isError, archive, body, context);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
const name = errorName(error);
|
|
93
|
+
journal("fallback", {
|
|
94
|
+
toolCallId: event.toolCallId,
|
|
95
|
+
sourceSha256: archive.hash,
|
|
96
|
+
reason:
|
|
97
|
+
name === "AbortError"
|
|
98
|
+
? "model-call-timeout"
|
|
99
|
+
: name === "ReducerModelUnavailableError"
|
|
100
|
+
? "reducer-model-unavailable"
|
|
101
|
+
: "model-call-exception",
|
|
102
|
+
});
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
journal("provider_response", {
|
|
107
|
+
toolCallId: event.toolCallId,
|
|
108
|
+
sourceSha256: archive.hash,
|
|
109
|
+
provider: provider.provider,
|
|
110
|
+
model: provider.model,
|
|
111
|
+
stopReason: provider.stopReason,
|
|
112
|
+
errorMessage: provider.errorMessage,
|
|
113
|
+
usage: provider.usage,
|
|
114
|
+
});
|
|
115
|
+
if (!provider.ok) {
|
|
116
|
+
journal("fallback", {
|
|
117
|
+
toolCallId: event.toolCallId,
|
|
118
|
+
sourceSha256: archive.hash,
|
|
119
|
+
reason: "model-response-error",
|
|
120
|
+
stopReason: provider.stopReason,
|
|
121
|
+
errorMessage: provider.errorMessage,
|
|
122
|
+
});
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const checked = validateReceipt(provider.outputText, archive, body, event.isError);
|
|
127
|
+
if (!checked.ok) {
|
|
128
|
+
journal("fallback", {
|
|
129
|
+
toolCallId: event.toolCallId,
|
|
130
|
+
sourceSha256: archive.hash,
|
|
131
|
+
reason: checked.reason,
|
|
132
|
+
usage: provider.usage,
|
|
133
|
+
});
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
const receipt = receiptText(command, archive, checked.value, provider);
|
|
137
|
+
const receiptBytes = Buffer.byteLength(receipt, "utf8");
|
|
138
|
+
if (receiptBytes >= archive.bytes) {
|
|
139
|
+
journal("fallback", {
|
|
140
|
+
toolCallId: event.toolCallId,
|
|
141
|
+
sourceSha256: archive.hash,
|
|
142
|
+
reason: "receipt-not-smaller",
|
|
143
|
+
receiptBytes,
|
|
144
|
+
sourceBytes: archive.bytes,
|
|
145
|
+
usage: provider.usage,
|
|
146
|
+
});
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
journal("applied", {
|
|
150
|
+
toolCallId: event.toolCallId,
|
|
151
|
+
commandSha256: sha256(command),
|
|
152
|
+
sourceSha256: archive.hash,
|
|
153
|
+
sourceBytes: archive.bytes,
|
|
154
|
+
receiptSha256: sha256(receipt),
|
|
155
|
+
receiptBytes,
|
|
156
|
+
evidenceCount: checked.value.evidence.length,
|
|
157
|
+
uncertain: checked.value.uncertain,
|
|
158
|
+
usage: provider.usage,
|
|
159
|
+
});
|
|
160
|
+
showSolPiSavings(context, "Luna Delegating", formatSavingsBytes(archive.bytes - receiptBytes));
|
|
161
|
+
return {
|
|
162
|
+
content: reducible.projectReceipt(receipt),
|
|
163
|
+
isError: event.isError,
|
|
164
|
+
details: {
|
|
165
|
+
...(isRecord(event.details) ? event.details : {}),
|
|
166
|
+
evidencePreservingReducer: {
|
|
167
|
+
schema: REDUCER_RECEIPT_SCHEMA,
|
|
168
|
+
sourceSha256: archive.hash,
|
|
169
|
+
sourceBytes: archive.bytes,
|
|
170
|
+
receiptSha256: sha256(receipt),
|
|
171
|
+
receiptBytes,
|
|
172
|
+
evidenceCount: checked.value.evidence.length,
|
|
173
|
+
uncertain: checked.value.uncertain,
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function createEvidencePreservingReducerExtension(options: EvidencePreservingReducerOptions = {}): ExtensionFactory {
|
|
180
|
+
return (pi: ExtensionAPI) => {
|
|
181
|
+
const states = new Map<string, { config: ReducerConfig; journal: Journal }>();
|
|
182
|
+
pi.on("tool_result", (event, context) => {
|
|
183
|
+
let root: string;
|
|
184
|
+
try {
|
|
185
|
+
root = runtimeRoot(context);
|
|
186
|
+
} catch {
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
let state = states.get(root);
|
|
190
|
+
if (!state) {
|
|
191
|
+
const config = loadReducerConfig(root, options);
|
|
192
|
+
state = { config, journal: createJournal(pi, config) };
|
|
193
|
+
states.set(root, state);
|
|
194
|
+
}
|
|
195
|
+
return reduceToolResult(state.journal, state.config, event, context);
|
|
196
|
+
});
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export type { ArchiveObject } from "./archive.ts";
|
|
201
|
+
export {
|
|
202
|
+
DIAGNOSTIC_COMMAND,
|
|
203
|
+
loadReducerConfig,
|
|
204
|
+
REDUCER_EVENT_SCHEMA,
|
|
205
|
+
REDUCER_EVENT_TYPE,
|
|
206
|
+
REDUCER_RECEIPT_PREFIX,
|
|
207
|
+
REDUCER_RECEIPT_SCHEMA,
|
|
208
|
+
type ReducerConfigOptions,
|
|
209
|
+
type ReducerConfig,
|
|
210
|
+
} from "./config.ts";
|
|
211
|
+
export { validateReceipt } from "./receipt.ts";
|
|
212
|
+
|
|
213
|
+
export function registerEvidencePreservingReducer(
|
|
214
|
+
pi: ExtensionAPI,
|
|
215
|
+
options: EvidencePreservingReducerOptions = {},
|
|
216
|
+
): void {
|
|
217
|
+
createEvidencePreservingReducerExtension(options)(pi);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export default registerEvidencePreservingReducer;
|
package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/journal.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
6
|
+
import { REDUCER_EVENT_SCHEMA, REDUCER_EVENT_TYPE, type ReducerConfig } from "./config.ts";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Append one non-context session entry per decision the reducer made.
|
|
10
|
+
*
|
|
11
|
+
* The entries never enter the LLM context. They record which results were
|
|
12
|
+
* candidates, which were delegated, and why each fallback happened.
|
|
13
|
+
*/
|
|
14
|
+
export type Journal = (kind: string, data?: Record<string, unknown>) => void;
|
|
15
|
+
|
|
16
|
+
export function createJournal(pi: ExtensionAPI, config: ReducerConfig): Journal {
|
|
17
|
+
return (kind, data = {}) => {
|
|
18
|
+
pi.appendEntry(REDUCER_EVENT_TYPE, {
|
|
19
|
+
schema: REDUCER_EVENT_SCHEMA,
|
|
20
|
+
runId: config.runId,
|
|
21
|
+
kind,
|
|
22
|
+
...data,
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
}
|