@herbertgao/pi-extensions 2026.8.3 → 2026.8.5
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 +45 -4
- package/examples/pi-footer.json +275 -0
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +10 -2
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +10 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +5 -8
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
- package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
- package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +15 -2
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
- package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
- package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
- package/node_modules/@narumitw/pi-btw/README.md +8 -7
- package/node_modules/@narumitw/pi-btw/package.json +2 -2
- package/node_modules/@narumitw/pi-btw/src/menu.ts +1 -0
- package/node_modules/pi-footer/CHANGELOG.md +145 -0
- package/node_modules/pi-footer/LICENSE +21 -0
- package/node_modules/pi-footer/README.md +354 -0
- package/node_modules/pi-footer/package.json +68 -0
- package/node_modules/pi-footer/src/cache.ts +106 -0
- package/node_modules/pi-footer/src/colors.ts +237 -0
- package/node_modules/pi-footer/src/config.ts +202 -0
- package/node_modules/pi-footer/src/event-widgets.ts +41 -0
- package/node_modules/pi-footer/src/extension-statuses.ts +102 -0
- package/node_modules/pi-footer/src/git.ts +135 -0
- package/node_modules/pi-footer/src/index.ts +268 -0
- package/node_modules/pi-footer/src/metrics.ts +141 -0
- package/node_modules/pi-footer/src/presets.ts +383 -0
- package/node_modules/pi-footer/src/render.ts +114 -0
- package/node_modules/pi-footer/src/separators.ts +52 -0
- package/node_modules/pi-footer/src/types.ts +122 -0
- package/node_modules/pi-footer/src/ui/color-level-confirm.ts +22 -0
- package/node_modules/pi-footer/src/ui/color-options.ts +195 -0
- package/node_modules/pi-footer/src/ui/config-lifecycle.ts +61 -0
- package/node_modules/pi-footer/src/ui/edit-colors.ts +13 -0
- package/node_modules/pi-footer/src/ui/events.ts +35 -0
- package/node_modules/pi-footer/src/ui/extension-status-picker.ts +60 -0
- package/node_modules/pi-footer/src/ui/extension-statuses.ts +73 -0
- package/node_modules/pi-footer/src/ui/fields.ts +252 -0
- package/node_modules/pi-footer/src/ui/global-menu.ts +126 -0
- package/node_modules/pi-footer/src/ui/helpers.ts +44 -0
- package/node_modules/pi-footer/src/ui/layout.ts +17 -0
- package/node_modules/pi-footer/src/ui/line-list.ts +19 -0
- package/node_modules/pi-footer/src/ui/model.ts +64 -0
- package/node_modules/pi-footer/src/ui/navigation.ts +29 -0
- package/node_modules/pi-footer/src/ui/option-edit.ts +93 -0
- package/node_modules/pi-footer/src/ui/overlay-render.ts +103 -0
- package/node_modules/pi-footer/src/ui/screen-context.ts +18 -0
- package/node_modules/pi-footer/src/ui/screen-controller.ts +27 -0
- package/node_modules/pi-footer/src/ui/screen-render.ts +32 -0
- package/node_modules/pi-footer/src/ui/screen-state.ts +20 -0
- package/node_modules/pi-footer/src/ui/screen.ts +243 -0
- package/node_modules/pi-footer/src/ui/screens/add-widget.ts +92 -0
- package/node_modules/pi-footer/src/ui/screens/confirm-exit.ts +52 -0
- package/node_modules/pi-footer/src/ui/screens/controller.ts +12 -0
- package/node_modules/pi-footer/src/ui/screens/edit-colors.ts +68 -0
- package/node_modules/pi-footer/src/ui/screens/edit-widget.ts +115 -0
- package/node_modules/pi-footer/src/ui/screens/extension-status-row.ts +61 -0
- package/node_modules/pi-footer/src/ui/screens/global.ts +75 -0
- package/node_modules/pi-footer/src/ui/screens/line-list.ts +108 -0
- package/node_modules/pi-footer/src/ui/screens/main.ts +99 -0
- package/node_modules/pi-footer/src/ui/screens/terminal.ts +121 -0
- package/node_modules/pi-footer/src/ui/screens/widget-list.ts +154 -0
- package/node_modules/pi-footer/src/ui/terminal-menu.ts +32 -0
- package/node_modules/pi-footer/src/ui/theme.ts +48 -0
- package/node_modules/pi-footer/src/ui/title-bar.ts +100 -0
- package/node_modules/pi-footer/src/ui/widget-actions.ts +76 -0
- package/node_modules/pi-footer/src/ui.ts +66 -0
- package/node_modules/pi-footer/src/widgets/context.ts +28 -0
- package/node_modules/pi-footer/src/widgets/core/active-tools.ts +17 -0
- package/node_modules/pi-footer/src/widgets/core/context-window.ts +24 -0
- package/node_modules/pi-footer/src/widgets/core/cwd-basename.ts +19 -0
- package/node_modules/pi-footer/src/widgets/core/cwd.ts +108 -0
- package/node_modules/pi-footer/src/widgets/core/event.ts +34 -0
- package/node_modules/pi-footer/src/widgets/core/external-status.ts +102 -0
- package/node_modules/pi-footer/src/widgets/core/model-provider.ts +20 -0
- package/node_modules/pi-footer/src/widgets/core/model.ts +35 -0
- package/node_modules/pi-footer/src/widgets/core/provider.ts +17 -0
- package/node_modules/pi-footer/src/widgets/core/session-name.ts +17 -0
- package/node_modules/pi-footer/src/widgets/core/text-verbosity.ts +17 -0
- package/node_modules/pi-footer/src/widgets/core/thinking-level.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/ahead-behind.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/branch.ts +81 -0
- package/node_modules/pi-footer/src/widgets/git/clean.ts +19 -0
- package/node_modules/pi-footer/src/widgets/git/deletions.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/diff.ts +38 -0
- package/node_modules/pi-footer/src/widgets/git/insertions.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/remote.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/root.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/sha.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/staged.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/status.ts +19 -0
- package/node_modules/pi-footer/src/widgets/git/unstaged.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/untracked.ts +17 -0
- package/node_modules/pi-footer/src/widgets/instance.ts +118 -0
- package/node_modules/pi-footer/src/widgets/layout/custom-text.ts +18 -0
- package/node_modules/pi-footer/src/widgets/layout/flex-separator.ts +32 -0
- package/node_modules/pi-footer/src/widgets/layout/separator.ts +57 -0
- package/node_modules/pi-footer/src/widgets/layout/spacer.ts +31 -0
- package/node_modules/pi-footer/src/widgets/options.ts +122 -0
- package/node_modules/pi-footer/src/widgets/project/runtime.ts +361 -0
- package/node_modules/pi-footer/src/widgets/registry.ts +223 -0
- package/node_modules/pi-footer/src/widgets/session/assistant-messages.ts +17 -0
- package/node_modules/pi-footer/src/widgets/session/compactions.ts +17 -0
- package/node_modules/pi-footer/src/widgets/session/elapsed.ts +18 -0
- package/node_modules/pi-footer/src/widgets/session/last-activity.ts +18 -0
- package/node_modules/pi-footer/src/widgets/session/messages.ts +19 -0
- package/node_modules/pi-footer/src/widgets/session/session-id.ts +17 -0
- package/node_modules/pi-footer/src/widgets/session/session-start.ts +18 -0
- package/node_modules/pi-footer/src/widgets/session/tool-results.ts +17 -0
- package/node_modules/pi-footer/src/widgets/session/total-messages.ts +19 -0
- package/node_modules/pi-footer/src/widgets/session/total-time.ts +18 -0
- package/node_modules/pi-footer/src/widgets/session/user-messages.ts +17 -0
- package/node_modules/pi-footer/src/widgets/store.ts +26 -0
- package/node_modules/pi-footer/src/widgets/tokens/cache-hit-rate.ts +55 -0
- package/node_modules/pi-footer/src/widgets/tokens/cache-read.ts +18 -0
- package/node_modules/pi-footer/src/widgets/tokens/cache-write.ts +18 -0
- package/node_modules/pi-footer/src/widgets/tokens/context-bar.ts +108 -0
- package/node_modules/pi-footer/src/widgets/tokens/context-length.ts +26 -0
- package/node_modules/pi-footer/src/widgets/tokens/context-remaining.ts +29 -0
- package/node_modules/pi-footer/src/widgets/tokens/context.ts +29 -0
- package/node_modules/pi-footer/src/widgets/tokens/cost.ts +51 -0
- package/node_modules/pi-footer/src/widgets/tokens/input-speed.ts +25 -0
- package/node_modules/pi-footer/src/widgets/tokens/input-tokens.ts +18 -0
- package/node_modules/pi-footer/src/widgets/tokens/output-speed.ts +25 -0
- package/node_modules/pi-footer/src/widgets/tokens/output-tokens.ts +18 -0
- package/node_modules/pi-footer/src/widgets/tokens/tokens.ts +20 -0
- package/node_modules/pi-footer/src/widgets/tokens/total-speed.ts +25 -0
- package/node_modules/pi-footer/src/widgets/tokens/total-tokens.ts +18 -0
- package/node_modules/pi-footer/src/widgets/types.ts +181 -0
- package/node_modules/pi-footer/src/widgets/utils/colors.ts +11 -0
- package/node_modules/pi-footer/src/widgets/utils/context.ts +112 -0
- package/node_modules/pi-footer/src/widgets/utils/session.ts +19 -0
- package/node_modules/pi-footer/src/widgets/utils/token-format.ts +78 -0
- package/node_modules/pi-lens/CHANGELOG.md +2440 -954
- package/node_modules/pi-lens/README.md +13 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
- package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
- package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
- package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
- package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
- package/node_modules/pi-lens/dist/clients/biome-client.js +29 -25
- package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
- package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
- package/node_modules/pi-lens/dist/clients/bus-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
- package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
- package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
- package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
- package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
- package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
- package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
- package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/console-guard-install.js +14 -0
- package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
- package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +347 -75
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +61 -11
- package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +63 -20
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
- package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
- package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
- package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1085 -681
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
- package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
- package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
- 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 +154 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +14 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.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 +163 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +277 -26
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
- package/node_modules/pi-lens/dist/clients/disposition-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
- package/node_modules/pi-lens/dist/clients/extension-log.js +139 -0
- package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
- package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
- package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
- package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
- package/node_modules/pi-lens/dist/clients/format-events-publish.js +16 -3
- package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
- package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
- package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
- package/node_modules/pi-lens/dist/clients/git-guard.js +681 -11
- package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
- package/node_modules/pi-lens/dist/clients/go-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +8 -0
- package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
- package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
- package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +390 -99
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +31 -54
- package/node_modules/pi-lens/dist/clients/knip-client.js +15 -36
- package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
- package/node_modules/pi-lens/dist/clients/latency-logger.js +23 -1
- package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
- package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
- package/node_modules/pi-lens/dist/clients/lens-events.js +27 -4
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +30 -0
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/client.js +493 -48
- package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +86 -0
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
- package/node_modules/pi-lens/dist/clients/lsp/index.js +1807 -780
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
- package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
- package/node_modules/pi-lens/dist/clients/lsp/server.js +196 -32
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
- package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
- package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +123 -32
- package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
- package/node_modules/pi-lens/dist/clients/mcp/session.js +216 -8
- package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
- package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
- package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
- package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
- package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
- package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
- package/node_modules/pi-lens/dist/clients/pipeline.js +47 -13
- package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
- package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
- package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
- package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
- package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
- package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
- package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
- package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
- package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
- package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
- package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +107 -73
- package/node_modules/pi-lens/dist/clients/runtime-context.js +36 -12
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +74 -6
- package/node_modules/pi-lens/dist/clients/runtime-session.js +405 -117
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +218 -23
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +237 -64
- package/node_modules/pi-lens/dist/clients/rust-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
- package/node_modules/pi-lens/dist/clients/sg-runner.js +284 -174
- package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +224 -0
- package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
- package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
- package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
- package/node_modules/pi-lens/dist/clients/startup-timing.js +1 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +38 -8
- package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
- package/node_modules/pi-lens/dist/clients/tool-policy.js +388 -39
- package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
- package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
- package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
- package/node_modules/pi-lens/dist/clients/warm-attach.js +33 -13
- package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
- package/node_modules/pi-lens/dist/clients/word-index.js +391 -64
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
- package/node_modules/pi-lens/dist/index.js +49361 -36888
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
- package/node_modules/pi-lens/dist/mcp/server.js +211 -44
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +200 -36
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +153 -40
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
- package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
- package/node_modules/pi-lens/docs/agent-guide.md +2 -2
- package/node_modules/pi-lens/docs/agent-tools.md +21 -10
- package/node_modules/pi-lens/docs/analysisall.md +192 -0
- package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +5 -2
- package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
- package/node_modules/pi-lens/docs/environment-variables.md +44 -0
- package/node_modules/pi-lens/docs/fable.md +27 -0
- package/node_modules/pi-lens/docs/features.md +31 -2
- package/node_modules/pi-lens/docs/globalconfig.md +45 -1
- package/node_modules/pi-lens/docs/language-coverage.md +4 -3
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
- package/node_modules/pi-lens/docs/mcp.md +37 -4
- package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
- package/node_modules/pi-lens/docs/settings.md +12 -1
- package/node_modules/pi-lens/docs/tools.md +4 -1
- package/node_modules/pi-lens/docs/usage.md +18 -0
- package/node_modules/pi-lens/package.json +10 -10
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
- package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +55 -2
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +25 -0
- package/node_modules/pi-mcp-adapter/README.md +34 -3
- package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
- package/node_modules/pi-mcp-adapter/commands.ts +15 -7
- package/node_modules/pi-mcp-adapter/direct-tools.ts +54 -7
- package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
- package/node_modules/pi-mcp-adapter/index.ts +8 -3
- package/node_modules/pi-mcp-adapter/init.ts +29 -5
- package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
- package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
- package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +27 -4
- package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
- package/node_modules/pi-mcp-adapter/package.json +3 -3
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
- package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
- package/node_modules/pi-mcp-adapter/server-manager.ts +36 -7
- package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
- package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
- package/node_modules/pi-mcp-adapter/tool-metadata.ts +42 -4
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
- package/node_modules/pi-mcp-adapter/types.ts +93 -27
- package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
- package/package.json +17 -13
- package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
- package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
- package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
- package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
- package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
- package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
- package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
- package/node_modules/pi-lens/dist/clients/types.js +0 -11
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { McpExtensionState } from "./state.ts";
|
|
3
|
-
import { isServerDisabled, type McpAdapterOptions, type PromptMetadata, type ToolMetadata } from "./types.ts";
|
|
3
|
+
import { formatToolName, isServerDisabled, resolveToolPrefix, type McpAdapterOptions, type PromptMetadata, type ToolMetadata } from "./types.ts";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
5
5
|
import { cloneMcpConfig, loadMcpConfig } from "./config.ts";
|
|
6
6
|
import { ConsentManager } from "./consent-manager.ts";
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
} from "./metadata-cache.ts";
|
|
22
22
|
import { McpServerManager } from "./server-manager.ts";
|
|
23
23
|
import { buildToolMetadata, totalToolCount } from "./tool-metadata.ts";
|
|
24
|
+
import { resourceNameToToolName } from "./resource-tools.ts";
|
|
24
25
|
import { UiResourceHandler } from "./ui-resource-handler.ts";
|
|
25
26
|
import { formatMcpStatus, openUrl, parallelLimit, sanitizeTerminalText } from "./utils.ts";
|
|
26
27
|
import { logger } from "./logger.ts";
|
|
@@ -242,7 +243,7 @@ export async function initializeMcp(
|
|
|
242
243
|
|
|
243
244
|
const cachedEntry = cache?.servers?.[name];
|
|
244
245
|
if (cachedEntry && isServerCacheValid(cachedEntry, definition)) {
|
|
245
|
-
const metadata = reconstructToolMetadata(name, cachedEntry, prefix, definition);
|
|
246
|
+
const metadata = reconstructToolMetadata(name, cachedEntry, prefix, definition, config.mcpServers, cache ?? undefined);
|
|
246
247
|
toolMetadata.set(name, metadata);
|
|
247
248
|
if (Array.isArray(cachedEntry.resources)) {
|
|
248
249
|
resourceCounts.set(name, cachedEntry.resources.length);
|
|
@@ -288,6 +289,29 @@ export async function initializeMcp(
|
|
|
288
289
|
if (initialSignal?.aborted) return state;
|
|
289
290
|
owner.throwIfInactive();
|
|
290
291
|
|
|
292
|
+
const startupKnownMetadata = new Map<string, ToolMetadata[]>();
|
|
293
|
+
for (const { name, definition, connection } of results) {
|
|
294
|
+
if (!connection) continue;
|
|
295
|
+
const effectivePrefix = resolveToolPrefix(definition, prefix);
|
|
296
|
+
const metadata: ToolMetadata[] = [
|
|
297
|
+
...connection.tools.filter(tool => tool?.name).map(tool => ({
|
|
298
|
+
name: formatToolName(tool.name, name, effectivePrefix),
|
|
299
|
+
originalName: tool.name,
|
|
300
|
+
description: tool.description ?? "",
|
|
301
|
+
})),
|
|
302
|
+
...(definition.exposeResources !== false ? connection.resources.filter(resource => resource?.name && resource?.uri).map(resource => {
|
|
303
|
+
const originalName = `read_${resourceNameToToolName(resource.name)}`;
|
|
304
|
+
return {
|
|
305
|
+
name: formatToolName(originalName, name, effectivePrefix),
|
|
306
|
+
originalName,
|
|
307
|
+
description: resource.description ?? `Read resource: ${resource.uri}`,
|
|
308
|
+
resourceUri: resource.uri,
|
|
309
|
+
};
|
|
310
|
+
}) : []),
|
|
311
|
+
];
|
|
312
|
+
startupKnownMetadata.set(name, metadata);
|
|
313
|
+
}
|
|
314
|
+
|
|
291
315
|
for (const { name, definition, connection, error } of results) {
|
|
292
316
|
owner.throwIfInactive();
|
|
293
317
|
if (error || !connection) {
|
|
@@ -301,7 +325,7 @@ export async function initializeMcp(
|
|
|
301
325
|
continue;
|
|
302
326
|
}
|
|
303
327
|
|
|
304
|
-
const { metadata, failedTools } = buildToolMetadata(connection.tools, connection.resources, definition, name, prefix);
|
|
328
|
+
const { metadata, failedTools } = buildToolMetadata(connection.tools, connection.resources, definition, name, prefix, config.mcpServers, startupKnownMetadata, true);
|
|
305
329
|
toolMetadata.set(name, metadata);
|
|
306
330
|
resourceCounts.set(name, connection.resources.length);
|
|
307
331
|
if (!connection.promptDiscoveryFailed) {
|
|
@@ -327,7 +351,7 @@ export async function initializeMcp(
|
|
|
327
351
|
|
|
328
352
|
const connectedCount = results.filter(r => r.connection).length;
|
|
329
353
|
const failedCount = results.filter(r => r.error).length;
|
|
330
|
-
if (ui && connectedCount > 0) {
|
|
354
|
+
if (ui && connectedCount > 0 && config.settings?.notifyOnStartupConnect !== false) {
|
|
331
355
|
const totalTools = totalToolCount(state);
|
|
332
356
|
const msg = failedCount > 0
|
|
333
357
|
? `MCP: ${connectedCount}/${startupServers.length} servers connected (${totalTools} tools)`
|
|
@@ -437,7 +461,7 @@ export function updateServerMetadata(state: McpExtensionState, serverName: strin
|
|
|
437
461
|
|
|
438
462
|
const prefix = state.config.settings?.toolPrefix ?? "server";
|
|
439
463
|
|
|
440
|
-
const { metadata } = buildToolMetadata(connection.tools, connection.resources, definition, serverName, prefix);
|
|
464
|
+
const { metadata } = buildToolMetadata(connection.tools, connection.resources, definition, serverName, prefix, state.config.mcpServers, state.toolMetadata);
|
|
441
465
|
state.toolMetadata.set(serverName, metadata);
|
|
442
466
|
state.resourceCounts?.set(serverName, connection.resources.length);
|
|
443
467
|
if (!connection.promptDiscoveryFailed) {
|
|
@@ -19,7 +19,6 @@ export class McpLifecycleManager {
|
|
|
19
19
|
private activeHealthCheck: Promise<void> | undefined;
|
|
20
20
|
private shutdownPromise: Promise<void> | undefined;
|
|
21
21
|
private stopped = false;
|
|
22
|
-
private healthSignal: AbortSignal | undefined;
|
|
23
22
|
private removeHealthAbortListener: (() => void) | undefined;
|
|
24
23
|
|
|
25
24
|
constructor(
|
|
@@ -58,10 +57,8 @@ export class McpLifecycleManager {
|
|
|
58
57
|
const signal = typeof signalOrInterval === "number" ? undefined : signalOrInterval;
|
|
59
58
|
const intervalMs = typeof signalOrInterval === "number" ? signalOrInterval : maybeIntervalMs;
|
|
60
59
|
this.stopped = false;
|
|
61
|
-
this.healthSignal = signal;
|
|
62
60
|
if (signal?.aborted) {
|
|
63
61
|
this.stopped = true;
|
|
64
|
-
this.healthSignal = undefined;
|
|
65
62
|
return;
|
|
66
63
|
}
|
|
67
64
|
const stop = () => {
|
|
@@ -138,7 +135,6 @@ export class McpLifecycleManager {
|
|
|
138
135
|
this.healthCheckInterval = undefined;
|
|
139
136
|
this.removeHealthAbortListener?.();
|
|
140
137
|
this.removeHealthAbortListener = undefined;
|
|
141
|
-
this.healthSignal = undefined;
|
|
142
138
|
await this.activeHealthCheck;
|
|
143
139
|
this.activeHealthCheck = undefined;
|
|
144
140
|
this.onReconnect = undefined;
|
|
@@ -633,7 +633,6 @@ export async function completeAuthFromInput(
|
|
|
633
633
|
const signal = combineAbortSignals(runtime.signal, options.signal)
|
|
634
634
|
throwIfAborted(signal)
|
|
635
635
|
const key = getPendingAuthKey(serverName, fallbackAuthStorageOptions)
|
|
636
|
-
const authStorageOptions = runtimeState.pendingAuths.get(key)?.authStorageOptions ?? fallbackAuthStorageOptions
|
|
637
636
|
const oauthState = runtimeState.pendingAuthStates.get(key)
|
|
638
637
|
throwIfAborted(signal)
|
|
639
638
|
const parsed = parseAuthorizationRedirectInput(input, oauthState)
|
|
@@ -899,7 +898,7 @@ export async function getValidToken(
|
|
|
899
898
|
* @returns The current auth status
|
|
900
899
|
*/
|
|
901
900
|
export async function getAuthStatus(serverName: string, options: AuthenticateOptions = {}): Promise<AuthStatus> {
|
|
902
|
-
|
|
901
|
+
getRuntime(options)
|
|
903
902
|
const authStorageOptions = options.authStorageOptions ?? {}
|
|
904
903
|
const hasTokens = await hasStoredTokens(serverName, authStorageOptions)
|
|
905
904
|
if (!hasTokens) return "not_authenticated"
|
|
@@ -37,6 +37,7 @@ const KEYRING_RECOVERY_KEYCTL_ENV = 'PI_MCP_ADAPTER_KEYRING_RECOVERY_KEYCTL';
|
|
|
37
37
|
const KEYRING_RECOVERY_NODE_ENV = 'PI_MCP_ADAPTER_KEYRING_RECOVERY_NODE';
|
|
38
38
|
const KEYRING_RECOVERY_HELPER_ENV = 'PI_MCP_ADAPTER_KEYRING_RECOVERY_HELPER';
|
|
39
39
|
const TEST_LINUX_KEYRING_RECOVERY_ENV = 'PI_MCP_ADAPTER_TEST_LINUX_KEYRING_RECOVERY';
|
|
40
|
+
const AUTH_CACHE_DISABLED_ENV = 'PI_MCP_ADAPTER_DISABLE_AUTH_CACHE';
|
|
40
41
|
const KEYRING_RECOVERY_TIMEOUT_MS = 10_000;
|
|
41
42
|
const AUTH_CHUNK_MANIFEST_KEY = '__piMcpAdapterOAuthChunked';
|
|
42
43
|
|
|
@@ -148,8 +149,20 @@ interface AuthEntryChunkManifest {
|
|
|
148
149
|
let KeyringEntryClass: KeyringEntryConstructor | undefined;
|
|
149
150
|
const memoryAuthEntries = new Map<string, string>();
|
|
150
151
|
|
|
152
|
+
let testAuthSecretStoreReadCount = 0;
|
|
153
|
+
const authEntryCache = new Map<string, AuthEntry | undefined>();
|
|
154
|
+
|
|
155
|
+
function isAuthEntryCacheEnabled(): boolean {
|
|
156
|
+
return process.env[AUTH_CACHE_DISABLED_ENV] !== '1';
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function cloneAuthEntry(entry: AuthEntry | undefined): AuthEntry | undefined {
|
|
160
|
+
return entry === undefined ? undefined : structuredClone(entry);
|
|
161
|
+
}
|
|
162
|
+
|
|
151
163
|
const memoryAuthSecretStore: AuthSecretStore = {
|
|
152
164
|
read(account) {
|
|
165
|
+
testAuthSecretStoreReadCount++;
|
|
153
166
|
return memoryAuthEntries.get(account);
|
|
154
167
|
},
|
|
155
168
|
write(account, payload) {
|
|
@@ -175,6 +188,7 @@ const keyringAuthSecretStore: AuthSecretStore = {
|
|
|
175
188
|
/** Mimics the Windows Credential Manager per-value ceiling for tests. */
|
|
176
189
|
const sizeLimitedAuthSecretStore: AuthSecretStore = {
|
|
177
190
|
read(account) {
|
|
191
|
+
testAuthSecretStoreReadCount++;
|
|
178
192
|
return memoryAuthEntries.get(account);
|
|
179
193
|
},
|
|
180
194
|
write(account, payload) {
|
|
@@ -190,6 +204,7 @@ const sizeLimitedAuthSecretStore: AuthSecretStore = {
|
|
|
190
204
|
|
|
191
205
|
const unavailableAuthSecretStore: AuthSecretStore = {
|
|
192
206
|
read() {
|
|
207
|
+
testAuthSecretStoreReadCount++;
|
|
193
208
|
throw new Error('simulated secure credential store unavailable');
|
|
194
209
|
},
|
|
195
210
|
write() {
|
|
@@ -206,6 +221,7 @@ function createKeyRevokedTestError(): Error {
|
|
|
206
221
|
|
|
207
222
|
const keyRevokedAuthSecretStore: AuthSecretStore = {
|
|
208
223
|
read() {
|
|
224
|
+
testAuthSecretStoreReadCount++;
|
|
209
225
|
throw createKeyRevokedTestError();
|
|
210
226
|
},
|
|
211
227
|
write() {
|
|
@@ -218,6 +234,16 @@ const keyRevokedAuthSecretStore: AuthSecretStore = {
|
|
|
218
234
|
|
|
219
235
|
export function resetTestAuthSecretStore(): void {
|
|
220
236
|
memoryAuthEntries.clear();
|
|
237
|
+
authEntryCache.clear();
|
|
238
|
+
testAuthSecretStoreReadCount = 0;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export function resetAuthEntryCache(): void {
|
|
242
|
+
authEntryCache.clear();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export function getTestAuthSecretStoreReadCount(): number {
|
|
246
|
+
return testAuthSecretStoreReadCount;
|
|
221
247
|
}
|
|
222
248
|
|
|
223
249
|
export function getTestAuthSecretStoreEntries(): [string, string][] {
|
|
@@ -649,6 +675,19 @@ function writeSecureAuthEntryToStore(store: AuthSecretStore, serverName: string,
|
|
|
649
675
|
error,
|
|
650
676
|
);
|
|
651
677
|
}
|
|
678
|
+
|
|
679
|
+
publishAuthEntryToCache(serverName, payload);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function publishAuthEntryToCache(serverName: string, payload: string): void {
|
|
683
|
+
if (!isAuthEntryCacheEnabled()) return;
|
|
684
|
+
// Cache the same normalized shape a fresh persistent-store read returns.
|
|
685
|
+
const normalized = toAuthEntry(JSON.parse(payload) as unknown);
|
|
686
|
+
if (!normalized) {
|
|
687
|
+
authEntryCache.delete(serverName);
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
authEntryCache.set(serverName, cloneAuthEntry(normalized));
|
|
652
691
|
}
|
|
653
692
|
|
|
654
693
|
function writeSecureAuthEntry(serverName: string, entry: AuthEntry): void {
|
|
@@ -704,12 +743,23 @@ function readAuthEntry(
|
|
|
704
743
|
options?: AuthStorageOptions,
|
|
705
744
|
behavior: { migrateLegacy?: boolean } = {},
|
|
706
745
|
): AuthEntry | undefined {
|
|
746
|
+
// Status-only reads deliberately bypass the cache because they do not
|
|
747
|
+
// migrate legacy entries.
|
|
748
|
+
const cacheable = behavior.migrateLegacy !== false && isAuthEntryCacheEnabled();
|
|
749
|
+
if (cacheable && authEntryCache.has(serverName)) {
|
|
750
|
+
return cloneAuthEntry(authEntryCache.get(serverName));
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
let entry: AuthEntry | undefined;
|
|
707
754
|
try {
|
|
708
|
-
|
|
755
|
+
entry = readAuthEntryFromStore(getAuthSecretStore(), serverName, options, behavior);
|
|
709
756
|
} catch (error) {
|
|
710
757
|
if (!shouldAttemptLinuxKeyringRecovery(error)) throw error;
|
|
711
|
-
|
|
758
|
+
entry = readAuthEntryFromStore(linuxKeyringRecoveryAuthSecretStore, serverName, options, behavior);
|
|
712
759
|
}
|
|
760
|
+
|
|
761
|
+
if (cacheable) authEntryCache.set(serverName, cloneAuthEntry(entry));
|
|
762
|
+
return entry;
|
|
713
763
|
}
|
|
714
764
|
|
|
715
765
|
/**
|
|
@@ -794,9 +844,17 @@ export function removeAuthEntry(serverName: string, options?: AuthStorageOptions
|
|
|
794
844
|
if (!shouldAttemptLinuxKeyringRecovery(error)) throw error;
|
|
795
845
|
removeAuthEntryFromStore(linuxKeyringRecoveryAuthSecretStore, serverName);
|
|
796
846
|
}
|
|
847
|
+
authEntryCache.delete(serverName);
|
|
797
848
|
removeLegacyAuthEntry(serverName, options);
|
|
798
849
|
}
|
|
799
850
|
|
|
851
|
+
/**
|
|
852
|
+
* Forget a cached entry so the next ordinary read reloads secure storage.
|
|
853
|
+
*/
|
|
854
|
+
export function invalidateAuthEntryCache(serverName: string): void {
|
|
855
|
+
authEntryCache.delete(serverName);
|
|
856
|
+
}
|
|
857
|
+
|
|
800
858
|
/**
|
|
801
859
|
* Update tokens for a server.
|
|
802
860
|
*/
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
2
2
|
import { copyToClipboard } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { createPanelKeys, type PanelKeybindings, type PanelKeys } from "./panel-keys.ts";
|
|
4
|
-
import { isServerDisabled, isToolAllowed } from "./types.ts";
|
|
4
|
+
import { getToolNameCandidates, isServerDisabled, isToolAllowed, resolveToolPrefix } from "./types.ts";
|
|
5
5
|
import type { McpConfig, McpPanelCallbacks, McpPanelResult, ServerProvenance, ToolPrefix } from "./types.ts";
|
|
6
6
|
import { resourceNameToToolName } from "./resource-tools.ts";
|
|
7
7
|
import { sanitizeTerminalText, stripOscSequences } from "./utils.ts";
|
|
8
|
-
import type
|
|
8
|
+
import { isServerCacheValid, type MetadataCache, type ServerCacheEntry, type CachedTool } from "./metadata-cache.ts";
|
|
9
|
+
import { isUiToolVisibleToModel } from "./ui-tool-visibility.ts";
|
|
9
10
|
|
|
10
11
|
interface PanelTheme {
|
|
11
12
|
border: string;
|
|
@@ -170,8 +171,8 @@ class McpPanel {
|
|
|
170
171
|
private static readonly INACTIVITY_MS = 60_000;
|
|
171
172
|
|
|
172
173
|
constructor(
|
|
173
|
-
config: McpConfig,
|
|
174
|
-
cache: MetadataCache | null,
|
|
174
|
+
private config: McpConfig,
|
|
175
|
+
private cache: MetadataCache | null,
|
|
175
176
|
provenance: Map<string, ServerProvenance>,
|
|
176
177
|
private callbacks: McpPanelCallbacks,
|
|
177
178
|
tui: { requestRender(): void },
|
|
@@ -187,7 +188,8 @@ class McpPanel {
|
|
|
187
188
|
for (const [serverName, definition] of Object.entries(config.mcpServers)) {
|
|
188
189
|
if (this.authOnly && !callbacks.canAuthenticate(serverName)) continue;
|
|
189
190
|
const prov = provenance.get(serverName);
|
|
190
|
-
const
|
|
191
|
+
const cachedEntry = this.cache?.servers?.[serverName];
|
|
192
|
+
const serverCache = cachedEntry && isServerCacheValid(cachedEntry, definition) ? cachedEntry : undefined;
|
|
191
193
|
|
|
192
194
|
const globalDirect = config.settings?.directTools;
|
|
193
195
|
let toolFilter: true | string[] | false = false;
|
|
@@ -200,7 +202,8 @@ class McpPanel {
|
|
|
200
202
|
const tools: ToolState[] = [];
|
|
201
203
|
if (serverCache && !this.authOnly && !isServerDisabled(definition)) {
|
|
202
204
|
for (const tool of serverCache.tools ?? []) {
|
|
203
|
-
if (!
|
|
205
|
+
if (!isUiToolVisibleToModel(tool.uiVisibility)) continue;
|
|
206
|
+
if (!isToolAllowed(tool.name, serverName, this.prefix, definition.includeTools, definition.excludeTools, this.getOtherCurrentCandidates(serverName, definition, serverCache, tool.name))) {
|
|
204
207
|
continue;
|
|
205
208
|
}
|
|
206
209
|
|
|
@@ -216,7 +219,7 @@ class McpPanel {
|
|
|
216
219
|
if (definition.exposeResources !== false) {
|
|
217
220
|
for (const resource of serverCache.resources ?? []) {
|
|
218
221
|
const baseName = `read_${resourceNameToToolName(resource.name)}`;
|
|
219
|
-
if (!isToolAllowed(baseName, serverName, this.prefix, definition.includeTools, definition.excludeTools)) {
|
|
222
|
+
if (!isToolAllowed(baseName, serverName, this.prefix, definition.includeTools, definition.excludeTools, this.getOtherCurrentCandidates(serverName, definition, serverCache, baseName))) {
|
|
220
223
|
continue;
|
|
221
224
|
}
|
|
222
225
|
|
|
@@ -563,6 +566,8 @@ class McpPanel {
|
|
|
563
566
|
if (server.connectionStatus === "connected") {
|
|
564
567
|
const entry = this.callbacks.refreshCacheAfterReconnect(server.name);
|
|
565
568
|
if (entry) {
|
|
569
|
+
this.cache ??= { version: 1, servers: {} };
|
|
570
|
+
this.cache.servers[server.name] = entry;
|
|
566
571
|
this.rebuildServerTools(server, entry);
|
|
567
572
|
}
|
|
568
573
|
server.hasCachedData = true;
|
|
@@ -636,13 +641,44 @@ class McpPanel {
|
|
|
636
641
|
this.cursorIndex = Math.max(0, Math.min(this.visibleItems.length - 1, this.cursorIndex + delta));
|
|
637
642
|
}
|
|
638
643
|
|
|
644
|
+
private getOtherCurrentCandidates(
|
|
645
|
+
serverName: string,
|
|
646
|
+
definition: McpConfig["mcpServers"][string],
|
|
647
|
+
currentEntry: ServerCacheEntry,
|
|
648
|
+
toolName: string,
|
|
649
|
+
): Set<string> {
|
|
650
|
+
const candidates = new Set<string>();
|
|
651
|
+
for (const [otherServerName, otherDefinition] of Object.entries(this.config.mcpServers)) {
|
|
652
|
+
if (isServerDisabled(otherDefinition)) continue;
|
|
653
|
+
const cachedEntry = this.cache?.servers?.[otherServerName];
|
|
654
|
+
const entry = otherServerName === serverName
|
|
655
|
+
? currentEntry
|
|
656
|
+
: cachedEntry && isServerCacheValid(cachedEntry, otherDefinition) ? cachedEntry : undefined;
|
|
657
|
+
if (!entry) continue;
|
|
658
|
+
const otherPrefix = resolveToolPrefix(otherDefinition, this.prefix);
|
|
659
|
+
for (const tool of entry.tools ?? []) {
|
|
660
|
+
if (!isUiToolVisibleToModel(tool.uiVisibility)) continue;
|
|
661
|
+
for (const candidate of getToolNameCandidates(tool.name, otherServerName, otherPrefix, false)) candidates.add(candidate);
|
|
662
|
+
}
|
|
663
|
+
if (otherDefinition.exposeResources !== false) {
|
|
664
|
+
for (const resource of entry.resources ?? []) {
|
|
665
|
+
const baseName = `read_${resourceNameToToolName(resource.name)}`;
|
|
666
|
+
for (const candidate of getToolNameCandidates(baseName, otherServerName, otherPrefix, false)) candidates.add(candidate);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
for (const candidate of getToolNameCandidates(toolName, serverName, resolveToolPrefix(definition, this.prefix), false)) candidates.delete(candidate);
|
|
671
|
+
return candidates;
|
|
672
|
+
}
|
|
673
|
+
|
|
639
674
|
private rebuildServerTools(server: ServerState, entry: ServerCacheEntry): void {
|
|
640
675
|
const existingState = new Map<string, boolean>();
|
|
641
676
|
for (const t of server.tools) existingState.set(t.name, t.isDirect);
|
|
642
677
|
|
|
643
678
|
const newTools: ToolState[] = [];
|
|
644
679
|
for (const tool of entry.tools ?? []) {
|
|
645
|
-
if (!
|
|
680
|
+
if (!isUiToolVisibleToModel(tool.uiVisibility)) continue;
|
|
681
|
+
if (!isToolAllowed(tool.name, server.name, this.prefix, server.includeTools, server.excludeTools, this.getOtherCurrentCandidates(server.name, server, entry, tool.name))) {
|
|
646
682
|
continue;
|
|
647
683
|
}
|
|
648
684
|
|
|
@@ -660,7 +696,7 @@ class McpPanel {
|
|
|
660
696
|
if (server.exposeResources) {
|
|
661
697
|
for (const resource of entry.resources ?? []) {
|
|
662
698
|
const baseName = `read_${resourceNameToToolName(resource.name)}`;
|
|
663
|
-
if (!isToolAllowed(baseName, server.name, this.prefix, server.includeTools, server.excludeTools)) {
|
|
699
|
+
if (!isToolAllowed(baseName, server.name, this.prefix, server.includeTools, server.excludeTools, this.getOtherCurrentCandidates(server.name, server, entry, baseName))) {
|
|
664
700
|
continue;
|
|
665
701
|
}
|
|
666
702
|
|
|
@@ -106,23 +106,25 @@ const capturedConsole = Object.freeze({
|
|
|
106
106
|
debug: (...args) => emit(`[console.debug] ${formatWithOptions({ colors: false, depth: 4 }, ...args)}`),
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
109
|
+
void (async () => {
|
|
110
|
+
try {
|
|
111
|
+
const context = vm.createContext(Object.assign(Object.create(null), {
|
|
112
|
+
tools,
|
|
113
|
+
emit,
|
|
114
|
+
console: capturedConsole,
|
|
115
|
+
}), {
|
|
116
|
+
codeGeneration: { strings: false, wasm: false },
|
|
117
|
+
name: "mcpScript",
|
|
118
|
+
});
|
|
119
|
+
const script = new vm.Script(`(async () => {\n${workerData.code}\n})()`, { filename: "mcpScript.js" });
|
|
120
|
+
const returnValue = await Promise.resolve(script.runInContext(context));
|
|
121
|
+
parentPort.postMessage(returnValue === undefined
|
|
122
|
+
? { type: "done" }
|
|
123
|
+
: { type: "done", returnBlock: toContentBlock(returnValue) });
|
|
124
|
+
} catch (error) {
|
|
125
|
+
parentPort.postMessage({
|
|
126
|
+
type: "error",
|
|
127
|
+
message: error instanceof Error ? error.message : String(error),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
})();
|
|
@@ -19,7 +19,7 @@ import type {
|
|
|
19
19
|
ToolMetadata,
|
|
20
20
|
PromptMetadata,
|
|
21
21
|
} from "./types.ts";
|
|
22
|
-
import { formatPromptCommandName, formatToolName, isServerDisabled, isToolAllowed, resolveToolPrefix, type ToolPrefix } from "./types.ts";
|
|
22
|
+
import { formatPromptCommandName, formatToolName, getToolNameCandidates, isServerDisabled, isToolAllowed, resolveToolPrefix, type ToolPrefix } from "./types.ts";
|
|
23
23
|
import { resourceNameToToolName } from "./resource-tools.ts";
|
|
24
24
|
import {
|
|
25
25
|
extractToolUiStreamMode,
|
|
@@ -177,18 +177,41 @@ export function reconstructToolMetadata(
|
|
|
177
177
|
serverName: string,
|
|
178
178
|
entry: ServerCacheEntry,
|
|
179
179
|
prefix: ToolPrefix,
|
|
180
|
-
definition: Pick<ServerEntry, "exposeResources" | "includeTools" | "excludeTools" | "toolPrefix"
|
|
180
|
+
definition: Pick<ServerEntry, "exposeResources" | "includeTools" | "excludeTools" | "toolPrefix">,
|
|
181
|
+
configuredServers?: Record<string, ServerEntry>,
|
|
182
|
+
cache?: MetadataCache,
|
|
181
183
|
): ToolMetadata[] {
|
|
182
184
|
const metadata: ToolMetadata[] = [];
|
|
183
185
|
const seenNames = new Set<string>();
|
|
184
186
|
const effectivePrefix = resolveToolPrefix(definition, prefix);
|
|
187
|
+
const getOtherCurrentCandidates = (toolName: string): Set<string> | undefined => {
|
|
188
|
+
if (!configuredServers || !cache) return undefined;
|
|
189
|
+
const candidates = new Set<string>();
|
|
190
|
+
for (const [otherServerName, otherDefinition] of Object.entries(configuredServers)) {
|
|
191
|
+
const otherEntry = cache.servers[otherServerName];
|
|
192
|
+
if (!otherEntry || !isServerCacheValid(otherEntry, otherDefinition) || isServerDisabled(otherDefinition)) continue;
|
|
193
|
+
const otherPrefix = resolveToolPrefix(otherDefinition, prefix);
|
|
194
|
+
for (const otherTool of otherEntry.tools ?? []) {
|
|
195
|
+
if (!isUiToolVisibleToModel(otherTool.uiVisibility)) continue;
|
|
196
|
+
for (const candidate of getToolNameCandidates(otherTool.name, otherServerName, otherPrefix, false)) candidates.add(candidate);
|
|
197
|
+
}
|
|
198
|
+
if (otherDefinition.exposeResources !== false) {
|
|
199
|
+
for (const resource of otherEntry.resources ?? []) {
|
|
200
|
+
const baseName = `read_${resourceNameToToolName(resource.name)}`;
|
|
201
|
+
for (const candidate of getToolNameCandidates(baseName, otherServerName, otherPrefix, false)) candidates.add(candidate);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
for (const candidate of getToolNameCandidates(toolName, serverName, effectivePrefix, false)) candidates.delete(candidate);
|
|
206
|
+
return candidates;
|
|
207
|
+
};
|
|
185
208
|
|
|
186
209
|
for (const tool of entry.tools ?? []) {
|
|
187
210
|
if (!tool?.name) continue;
|
|
188
211
|
if (!isUiToolVisibleToModel(tool.uiVisibility)) {
|
|
189
212
|
continue;
|
|
190
213
|
}
|
|
191
|
-
if (!isToolAllowed(tool.name, serverName, effectivePrefix, definition.includeTools, definition.excludeTools)) {
|
|
214
|
+
if (!isToolAllowed(tool.name, serverName, effectivePrefix, definition.includeTools, definition.excludeTools, getOtherCurrentCandidates(tool.name))) {
|
|
192
215
|
continue;
|
|
193
216
|
}
|
|
194
217
|
|
|
@@ -213,7 +236,7 @@ export function reconstructToolMetadata(
|
|
|
213
236
|
for (const resource of entry.resources ?? []) {
|
|
214
237
|
if (!resource?.name || !resource?.uri) continue;
|
|
215
238
|
const baseName = `read_${resourceNameToToolName(resource.name)}`;
|
|
216
|
-
if (!isToolAllowed(baseName, serverName, effectivePrefix, definition.includeTools, definition.excludeTools)) {
|
|
239
|
+
if (!isToolAllowed(baseName, serverName, effectivePrefix, definition.includeTools, definition.excludeTools, getOtherCurrentCandidates(baseName))) {
|
|
217
240
|
continue;
|
|
218
241
|
}
|
|
219
242
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// npx-resolver.ts - Resolve npx/npm exec binaries to avoid npm parent processes
|
|
2
|
-
import { existsSync, readFileSync, realpathSync, readdirSync, statSync, writeFileSync, renameSync, mkdirSync, openSync, readSync, closeSync } from "node:fs";
|
|
2
|
+
import { existsSync, readFileSync, realpathSync, readdirSync, statSync, writeFileSync, renameSync, mkdirSync, openSync, readSync, closeSync, unlinkSync } from "node:fs";
|
|
3
3
|
import { join, dirname, extname, resolve, sep } from "node:path";
|
|
4
4
|
import { getAgentPath } from "./agent-dir.ts";
|
|
5
5
|
import { throwIfAborted } from "./abort.ts";
|
|
6
6
|
import crossSpawn from "cross-spawn";
|
|
7
7
|
|
|
8
|
-
const CACHE_VERSION =
|
|
8
|
+
const CACHE_VERSION = 2;
|
|
9
9
|
const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
10
10
|
const EXACT_PACKAGE_VERSION_RE = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z][0-9A-Za-z.-]*)?(?:\+[0-9A-Za-z][0-9A-Za-z.-]*)?$/;
|
|
11
11
|
|
|
@@ -53,7 +53,7 @@ export async function resolveNpxBinary(
|
|
|
53
53
|
if (!parsed) return null;
|
|
54
54
|
|
|
55
55
|
const packageSpec = parsePackageSpec(parsed.packageSpec);
|
|
56
|
-
const cacheKey = JSON.stringify([command,
|
|
56
|
+
const cacheKey = JSON.stringify([command, parsed.packageSpec, parsed.binName ?? ""]);
|
|
57
57
|
const cache = loadCache();
|
|
58
58
|
const cached = cache?.entries?.[cacheKey];
|
|
59
59
|
|
|
@@ -434,41 +434,96 @@ function getNpxCachePath(): string {
|
|
|
434
434
|
return getAgentPath("mcp-npx-cache.json");
|
|
435
435
|
}
|
|
436
436
|
|
|
437
|
-
function
|
|
438
|
-
const cachePath = getNpxCachePath();
|
|
437
|
+
function readNpxCachePayload(cachePath: string): unknown | null {
|
|
439
438
|
if (!existsSync(cachePath)) return null;
|
|
440
439
|
try {
|
|
441
|
-
|
|
442
|
-
if (!raw || typeof raw !== "object") return null;
|
|
443
|
-
if (raw.version !== CACHE_VERSION) return null;
|
|
444
|
-
if (!raw.entries || typeof raw.entries !== "object") return null;
|
|
445
|
-
return raw as NpxCache;
|
|
440
|
+
return JSON.parse(readFileSync(cachePath, "utf-8")) as unknown;
|
|
446
441
|
} catch {
|
|
447
442
|
return null;
|
|
448
443
|
}
|
|
449
444
|
}
|
|
450
445
|
|
|
451
|
-
function
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
446
|
+
function asRecord(value: unknown): Record<string, unknown> | null {
|
|
447
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
448
|
+
? value as Record<string, unknown>
|
|
449
|
+
: null;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function createCacheEntries(): Record<string, NpxCacheEntry> {
|
|
453
|
+
return Object.create(null) as Record<string, NpxCacheEntry>;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function toNpxCacheEntry(value: unknown): NpxCacheEntry | null {
|
|
457
|
+
const raw = asRecord(value);
|
|
458
|
+
if (!raw) return null;
|
|
459
|
+
if (typeof raw.resolvedBin !== "string") return null;
|
|
460
|
+
if (typeof raw.resolvedAt !== "number" || !Number.isFinite(raw.resolvedAt)) return null;
|
|
461
|
+
if (typeof raw.isJs !== "boolean") return null;
|
|
462
|
+
if (raw.packageVersion !== undefined && typeof raw.packageVersion !== "string") return null;
|
|
463
|
+
return {
|
|
464
|
+
resolvedBin: raw.resolvedBin,
|
|
465
|
+
resolvedAt: raw.resolvedAt,
|
|
466
|
+
...(raw.packageVersion !== undefined ? { packageVersion: raw.packageVersion } : {}),
|
|
467
|
+
isJs: raw.isJs,
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function toNpxCache(value: unknown): NpxCache | null {
|
|
472
|
+
const raw = asRecord(value);
|
|
473
|
+
if (!raw || raw.version !== CACHE_VERSION) return null;
|
|
474
|
+
const rawEntries = asRecord(raw.entries);
|
|
475
|
+
if (!rawEntries) return null;
|
|
476
|
+
|
|
477
|
+
const entries = createCacheEntries();
|
|
478
|
+
for (const [key, rawEntry] of Object.entries(rawEntries)) {
|
|
479
|
+
const entry = toNpxCacheEntry(rawEntry);
|
|
480
|
+
if (entry) entries[key] = entry;
|
|
481
|
+
}
|
|
482
|
+
return { version: CACHE_VERSION, entries };
|
|
483
|
+
}
|
|
455
484
|
|
|
456
|
-
|
|
485
|
+
function clearLegacyCache(): boolean {
|
|
486
|
+
const cachePath = getNpxCachePath();
|
|
487
|
+
const raw = asRecord(readNpxCachePayload(cachePath));
|
|
488
|
+
if (raw?.version !== 1) return false;
|
|
457
489
|
try {
|
|
458
|
-
|
|
459
|
-
const existing = JSON.parse(readFileSync(cachePath, "utf-8")) as NpxCache;
|
|
460
|
-
if (existing && existing.version === CACHE_VERSION && existing.entries) {
|
|
461
|
-
merged.entries = { ...existing.entries };
|
|
462
|
-
}
|
|
463
|
-
}
|
|
490
|
+
unlinkSync(cachePath);
|
|
464
491
|
} catch {
|
|
465
|
-
|
|
492
|
+
try {
|
|
493
|
+
writeFileSync(cachePath, "", "utf-8");
|
|
494
|
+
} catch {
|
|
495
|
+
// Cache cleanup is best effort; resolution must still proceed.
|
|
496
|
+
}
|
|
466
497
|
}
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
467
500
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
501
|
+
clearLegacyCache();
|
|
502
|
+
|
|
503
|
+
function loadCache(): NpxCache | null {
|
|
504
|
+
if (clearLegacyCache()) return null;
|
|
505
|
+
|
|
506
|
+
return toNpxCache(readNpxCachePayload(getNpxCachePath()));
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function saveCacheEntry(key: string, entry: NpxCacheEntry): void {
|
|
510
|
+
try {
|
|
511
|
+
const cachePath = getNpxCachePath();
|
|
512
|
+
const dir = dirname(cachePath);
|
|
513
|
+
mkdirSync(dir, { recursive: true });
|
|
514
|
+
|
|
515
|
+
const existing = toNpxCache(readNpxCachePayload(cachePath));
|
|
516
|
+
const entries = createCacheEntries();
|
|
517
|
+
if (existing) Object.assign(entries, existing.entries);
|
|
518
|
+
const merged: NpxCache = { version: CACHE_VERSION, entries };
|
|
519
|
+
|
|
520
|
+
merged.entries[key] = entry;
|
|
521
|
+
const tmpPath = `${cachePath}.${process.pid}.tmp`;
|
|
522
|
+
writeFileSync(tmpPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
523
|
+
renameSync(tmpPath, cachePath);
|
|
524
|
+
} catch {
|
|
525
|
+
// Cache writes are best effort; resolution must still proceed.
|
|
526
|
+
}
|
|
472
527
|
}
|
|
473
528
|
|
|
474
529
|
function safeRealpath(path: string): string {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-mcp-adapter",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.25.0",
|
|
4
4
|
"description": "MCP (Model Context Protocol) adapter extension for Pi coding agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./index.ts",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"test": "vitest run",
|
|
35
35
|
"test:watch": "vitest",
|
|
36
36
|
"test:coverage": "vitest run --coverage",
|
|
37
|
-
"test:oauth": "PI_MCP_ADAPTER_TEST_AUTH_STORE=memory node --import tsx --test --test-concurrency=1 oauth-public-api.test.ts mcp-auth.test.ts mcp-auth-flow.test.ts mcp-callback-server.test.ts mcp-oauth-provider.test.ts",
|
|
38
|
-
"test:oauth-provider": "PI_MCP_ADAPTER_TEST_AUTH_STORE=memory node --import tsx --test mcp-oauth-provider.test.ts",
|
|
37
|
+
"test:oauth": "PI_MCP_ADAPTER_TEST_AUTH_STORE=memory PI_MCP_ADAPTER_DISABLE_AUTH_CACHE=1 node --import tsx --test --test-concurrency=1 oauth-public-api.test.ts mcp-auth.test.ts mcp-auth-flow.test.ts mcp-callback-server.test.ts mcp-oauth-provider.test.ts",
|
|
38
|
+
"test:oauth-provider": "PI_MCP_ADAPTER_TEST_AUTH_STORE=memory PI_MCP_ADAPTER_DISABLE_AUTH_CACHE=1 node --import tsx --test mcp-oauth-provider.test.ts",
|
|
39
39
|
"test:conformance": "bash conformance/run.sh"
|
|
40
40
|
},
|
|
41
41
|
"repository": {
|