@herbertgao/pi-extensions 2026.8.11 → 2026.8.13
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 +23 -10
- package/{node_modules/@herbertgao/pi-mermaid-open/LICENSE → THIRD_PARTY_NOTICES.md} +19 -1
- package/node_modules/@czottmann/pi-automode/CHANGELOG.md +15 -0
- package/node_modules/@czottmann/pi-automode/README.md +5 -3
- package/node_modules/@czottmann/pi-automode/docs/adr/ADR-001-permission-precedence-and-trust-boundaries.md +2 -0
- package/node_modules/@czottmann/pi-automode/docs/adr/ADR-002-global-config-in-extension-data-directory.md +60 -0
- package/node_modules/@czottmann/pi-automode/docs/adr/INDEX.md +1 -0
- package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +4 -4
- package/node_modules/@czottmann/pi-automode/docs/configuration.md +20 -4
- package/node_modules/@czottmann/pi-automode/docs/observability-logging.md +1 -1
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/bash.ts +692 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +181 -3
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +4 -1
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +143 -36
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +103 -148
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/paths.ts +32 -6
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/permissions.ts +344 -22
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode.ts +1 -0
- package/node_modules/@czottmann/pi-automode/package.json +4 -1
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -1
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +4 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +21 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/core.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +19 -19
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +4 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +2 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +10 -2
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +10 -0
- package/node_modules/@herbertgao/pi-subagents/README.md +21 -15
- package/node_modules/@herbertgao/pi-subagents/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +11 -8
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +184 -106
- package/node_modules/@herbertgao/pi-subagents/src/cross-extension-rpc.ts +31 -11
- package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +9 -1
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +156 -31
- package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +17 -0
- package/node_modules/@herbertgao/pi-subagents/src/model-resolver.ts +14 -0
- package/node_modules/@herbertgao/pi-subagents/src/schedule.ts +8 -0
- package/node_modules/@herbertgao/pi-subagents/src/settings.ts +32 -1
- package/node_modules/@herbertgao/pi-subagents/src/types.ts +17 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +23 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +259 -24
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
- package/node_modules/@luxusai/pi-hindsight/CHANGELOG.md +376 -0
- package/node_modules/@luxusai/pi-hindsight/README.md +92 -0
- package/node_modules/@luxusai/pi-hindsight/docs/adr/001-memory-lifecycle-and-scope.md +56 -0
- package/node_modules/@luxusai/pi-hindsight/docs/adr/002-explicit-routing-strategy-seam.md +169 -0
- package/node_modules/@luxusai/pi-hindsight/docs/adr/003-tui-memory-mode-vocabulary.md +107 -0
- package/node_modules/@luxusai/pi-hindsight/docs/adr/004-lifeos-dual-bank-design.md +89 -0
- package/node_modules/@luxusai/pi-hindsight/docs/adr/005-domain-banks-and-agent-first-surface.md +189 -0
- package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark.webp +0 -0
- package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark@2x.webp +0 -0
- package/node_modules/@luxusai/pi-hindsight/docs/coding-memory-evaluation.md +54 -0
- package/node_modules/@luxusai/pi-hindsight/docs/compatibility.md +75 -0
- package/node_modules/@luxusai/pi-hindsight/docs/hindsight-core-functions.md +300 -0
- package/node_modules/@luxusai/pi-hindsight/docs/mission-and-mental-model-quality.md +158 -0
- package/node_modules/@luxusai/pi-hindsight/docs/next-opt-out-design.md +164 -0
- package/node_modules/@luxusai/pi-hindsight/docs/risky-memory-modes.md +139 -0
- package/node_modules/@luxusai/pi-hindsight/docs/starter-mental-model-suggestions.md +74 -0
- package/node_modules/@luxusai/pi-hindsight/docs/surface-reference.md +261 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-operations.ts +151 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-selection.ts +18 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-settings-presenter.ts +46 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-templates.ts +383 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/banking.ts +240 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/knowledge-page-seed.ts +176 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/retain-strategies.ts +178 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/client/client-retry.ts +41 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/client/client.ts +386 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/client/fetch-compat.ts +39 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/client/timeout.ts +34 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-defaults.ts +140 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-model.ts +61 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-registry.ts +925 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-field-paths.ts +247 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-normalize.ts +547 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-writer.ts +480 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config.ts +182 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/setup-gate.ts +86 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-execute.ts +1010 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-parse.ts +175 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-plan.ts +425 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-presentation.ts +210 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-sessions.ts +817 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/index.ts +25 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/git-seed.ts +319 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-recall.ts +196 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-retain.ts +189 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-runtime.ts +65 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle.ts +260 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/mental-models.ts +244 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/observation-scopes.ts +59 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-cleanup.ts +82 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-visibility.ts +45 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall.ts +331 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-cursor.ts +354 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-job-builder.ts +66 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-receipts.ts +132 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain.ts +228 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-bank-template-operations.ts +74 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-config-operations.ts +16 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-control-operations.ts +648 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-diagnostics-operations.ts +105 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-identity.ts +68 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-service.ts +71 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-types.ts +13 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-recall-operations.ts +162 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-retain-operations.ts +131 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-scope.ts +104 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-session-operations.ts +37 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/operation-catalog.ts +893 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/reflect-presenter.ts +35 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/scope-migrate.ts +177 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/tools.ts +7 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/flush-presenter.ts +21 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/jsonl-queue-store.ts +112 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-delivery.ts +111 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-lock.ts +214 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-operations.ts +70 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue.ts +392 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/bank-template-presentation.ts +45 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/commands.ts +9 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/guided-setup.ts +860 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/prefill-input.ts +105 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-flow.ts +189 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-server-probe.ts +299 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-actions.ts +201 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-facts.ts +47 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-render.ts +239 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-types.ts +50 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui.ts +259 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/tool-presenters.ts +77 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/types.ts +534 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/diagnostics.ts +319 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/messages.ts +325 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/sanitize.ts +42 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-memory-meta.ts +244 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-operations.ts +56 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/session.ts +50 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-fields.ts +167 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-health.ts +207 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/status.ts +120 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/version.ts +8 -0
- package/node_modules/@luxusai/pi-hindsight/package.json +118 -0
- package/node_modules/@luxusai/pi-hindsight/skills/hindsight-memory-doctor/SKILL.md +75 -0
- package/node_modules/@narumitw/pi-btw/dist/index.ts +143 -46
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +3 -3
- package/node_modules/@narumitw/pi-btw/package.json +6 -6
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +136 -22
- package/node_modules/{@herbertgao → @tifan}/pi-copy-response/README.md +2 -4
- package/node_modules/{@herbertgao → @tifan}/pi-copy-response/package.json +5 -15
- package/node_modules/{@herbertgao → @tifan}/pi-handoff/README.md +4 -6
- package/node_modules/@tifan/pi-handoff/package.json +43 -0
- package/node_modules/{@herbertgao → @tifan}/pi-handoff/src/index.ts +1 -1
- package/node_modules/{@herbertgao → @tifan}/pi-inline-skills/README.md +2 -4
- package/node_modules/{@herbertgao → @tifan}/pi-inline-skills/package.json +5 -15
- package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/README.md +5 -7
- package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/package.json +5 -19
- package/node_modules/{@herbertgao → @tifan}/pi-preferred-thinking/README.md +4 -6
- package/node_modules/{@herbertgao → @tifan}/pi-preferred-thinking/package.json +6 -16
- package/node_modules/{@herbertgao → @tifan}/pi-preferred-thinking/src/index.ts +1 -6
- package/node_modules/{@herbertgao → @tifan}/pi-recap/README.md +4 -6
- package/node_modules/@tifan/pi-recap/package.json +42 -0
- package/node_modules/{@herbertgao → @tifan}/pi-recap/src/models.ts +1 -6
- package/node_modules/{@herbertgao → @tifan}/pi-rename/README.md +13 -8
- package/node_modules/@tifan/pi-rename/package.json +47 -0
- package/node_modules/@tifan/pi-rename/src/herdr-label.ts +4 -0
- package/node_modules/{@herbertgao → @tifan}/pi-rename/src/index.ts +4 -16
- package/node_modules/{@herbertgao → @tifan}/pi-rename/src/models.ts +1 -6
- package/node_modules/{@herbertgao → @tifan}/pi-titlebar-spinner/README.md +2 -4
- package/node_modules/{@herbertgao → @tifan}/pi-titlebar-spinner/package.json +5 -15
- package/node_modules/pi-lens/CHANGELOG.md +96 -1
- package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +2 -1
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +14 -5
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +48 -18
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +1 -3
- package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +16 -4
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +3 -1
- package/node_modules/pi-lens/dist/clients/biome-client.js +1 -3
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +21 -8
- package/node_modules/pi-lens/dist/clients/bounded-cache.js +24 -8
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +4 -3
- package/node_modules/pi-lens/dist/clients/cache-manager.js +6 -7
- package/node_modules/pi-lens/dist/clients/cache-observability.js +461 -66
- package/node_modules/pi-lens/dist/clients/call-graph.js +238 -63
- package/node_modules/pi-lens/dist/clients/codebase-model.js +13 -5
- package/node_modules/pi-lens/dist/clients/complexity-client.js +1 -3
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +19 -8
- package/node_modules/pi-lens/dist/clients/dead-code-logger.js +1 -2
- package/node_modules/pi-lens/dist/clients/deadline-utils.js +3 -1
- package/node_modules/pi-lens/dist/clients/debug-heap.js +8 -1
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +1 -1
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +11 -7
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +39 -2
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/auxiliary-lsp.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +13 -1
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +9 -4
- package/node_modules/pi-lens/dist/clients/dispatch/rules/error-swallowing.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/rules/pass-through-wrappers.js +6 -2
- package/node_modules/pi-lens/dist/clients/dispatch/rules/unsafe-boundary.js +31 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +5 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +10 -14
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +25 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +13 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +4 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +25 -10
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +28 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +6 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +212 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +8 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +10 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +23 -14
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +7 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +5 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +7 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +6 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +13 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +13 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +17 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +7 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +24 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +35 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +1 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +6 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/suppress-writer.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/types.js +6 -1
- package/node_modules/pi-lens/dist/clients/dispatch/utils/lsp-diagnostics.js +6 -2
- package/node_modules/pi-lens/dist/clients/extension-log.js +5 -3
- package/node_modules/pi-lens/dist/clients/feature-hints.js +8 -1
- package/node_modules/pi-lens/dist/clients/file-kinds.js +34 -129
- package/node_modules/pi-lens/dist/clients/file-utils.js +17 -1
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +57 -2
- package/node_modules/pi-lens/dist/clients/formatters.js +144 -27
- package/node_modules/pi-lens/dist/clients/freshness.js +38 -0
- package/node_modules/pi-lens/dist/clients/git-guard.js +43 -13
- package/node_modules/pi-lens/dist/clients/go-client.js +1 -3
- package/node_modules/pi-lens/dist/clients/grammar-source.js +1 -1
- package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +30 -4
- package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +1 -3
- package/node_modules/pi-lens/dist/clients/install-diagnostics.js +4 -2
- package/node_modules/pi-lens/dist/clients/installer/index.js +86 -77
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +5 -2
- package/node_modules/pi-lens/dist/clients/instance-registry.js +4 -2
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +6 -1
- package/node_modules/pi-lens/dist/clients/knip-client.js +29 -15
- package/node_modules/pi-lens/dist/clients/language-profile.js +4 -1
- package/node_modules/pi-lens/dist/clients/latency-logger.js +13 -2
- package/node_modules/pi-lens/dist/clients/lens-config.js +1 -1
- package/node_modules/pi-lens/dist/clients/lens-map.js +8 -3
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/config.js +4 -6
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +119 -32
- package/node_modules/pi-lens/dist/clients/lsp/index.js +94 -35
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +4 -1
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +11 -3
- package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +152 -0
- package/node_modules/pi-lens/dist/clients/lsp/server.js +19 -7
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +10 -2
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +9 -4
- package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +1 -3
- package/node_modules/pi-lens/dist/clients/lsp-mutation.js +10 -20
- package/node_modules/pi-lens/dist/clients/mcp/host-shim.js +1 -1
- package/node_modules/pi-lens/dist/clients/memory-sampler.js +73 -7
- package/node_modules/pi-lens/dist/clients/metrics-client.js +1 -3
- package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +8 -3
- package/node_modules/pi-lens/dist/clients/module-report-lsp.js +7 -1
- package/node_modules/pi-lens/dist/clients/module-report.js +14 -17
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +3 -5
- package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +220 -0
- package/node_modules/pi-lens/dist/clients/package-manager.js +6 -1
- package/node_modules/pi-lens/dist/clients/pipeline.js +57 -9
- package/node_modules/pi-lens/dist/clients/project-conventions.js +2 -8
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +10 -7
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +2 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +3 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +13 -9
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +3 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +5 -2
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +12 -5
- package/node_modules/pi-lens/dist/clients/project-snapshot-fingerprint.js +48 -0
- package/node_modules/pi-lens/dist/clients/project-snapshot-persist-worker.js +15 -1
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +472 -66
- package/node_modules/pi-lens/dist/clients/read-expansion.js +12 -2
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +5 -4
- package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +5 -2
- package/node_modules/pi-lens/dist/clients/read-guard.js +1 -1
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +1 -1
- package/node_modules/pi-lens/dist/clients/reverse-deps.js +6 -5
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +42 -17
- package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +8 -2
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +10 -1
- package/node_modules/pi-lens/dist/clients/review-graph/query.js +2 -1
- package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +4 -2
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +2 -2
- package/node_modules/pi-lens/dist/clients/ruff-client.js +6 -5
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +63 -31
- package/node_modules/pi-lens/dist/clients/runtime-context.js +12 -4
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +83 -4
- package/node_modules/pi-lens/dist/clients/runtime-session.js +14 -0
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +59 -3
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +148 -34
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +147 -6
- package/node_modules/pi-lens/dist/clients/rust-client.js +1 -3
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +150 -11
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +1 -3
- package/node_modules/pi-lens/dist/clients/session-summary.js +3 -1
- package/node_modules/pi-lens/dist/clients/sg-runner.js +1 -3
- package/node_modules/pi-lens/dist/clients/source-filter.js +10 -6
- package/node_modules/pi-lens/dist/clients/source-walker.js +1 -1
- package/node_modules/pi-lens/dist/clients/spawn-timeout-cooldown.js +96 -0
- package/node_modules/pi-lens/dist/clients/startup-scan.js +4 -1
- package/node_modules/pi-lens/dist/clients/tool-definition.js +7 -0
- package/node_modules/pi-lens/dist/clients/tool-policy.js +26 -11
- package/node_modules/pi-lens/dist/clients/tool-render.js +2 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +10 -4
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +12 -5
- package/node_modules/pi-lens/dist/clients/warm-attach.js +12 -5
- package/node_modules/pi-lens/dist/clients/widget-state.js +27 -11
- package/node_modules/pi-lens/dist/clients/word-index.js +3 -1
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +8 -2
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +9 -1
- package/node_modules/pi-lens/dist/i18n.js +13 -5
- package/node_modules/pi-lens/dist/index.js +10797 -8627
- package/node_modules/pi-lens/dist/mcp/server.js +3 -1
- package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +68 -12
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +21 -7
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +164 -35
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +24 -7
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +3 -1
- package/node_modules/pi-lens/dist/tools/module-report.js +1 -1
- package/node_modules/pi-lens/dist/tools/project-report.js +1 -1
- package/node_modules/pi-lens/dist/tools/symbol-search.js +5 -2
- package/node_modules/pi-lens/docs/durable-store-audit-1202.md +1 -1
- package/node_modules/pi-lens/docs/servercapabilities.md +1 -1
- package/node_modules/pi-lens/package.json +160 -156
- package/node_modules/pi-lens/rules/typos/_typos.toml +2 -2
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +31 -13
- package/node_modules/pi-lens/scripts/download-grammars.js +9 -3
- package/node_modules/pi-lens/scripts/rpc-load-check.mjs +30 -9
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +47 -0
- package/node_modules/pi-mcp-adapter/README.md +42 -13
- package/node_modules/pi-mcp-adapter/commands.ts +4 -2
- package/node_modules/pi-mcp-adapter/config.ts +45 -5
- package/node_modules/pi-mcp-adapter/direct-tools.ts +103 -92
- package/node_modules/pi-mcp-adapter/dist/agent-dir.d.ts +10 -0
- package/node_modules/pi-mcp-adapter/dist/agent-dir.js +63 -0
- package/node_modules/pi-mcp-adapter/dist/agent-dir.js.map +1 -0
- package/node_modules/pi-mcp-adapter/dist/agent-plugin-loader.d.ts +8 -0
- package/node_modules/pi-mcp-adapter/dist/agent-plugin-loader.js +356 -0
- package/node_modules/pi-mcp-adapter/dist/agent-plugin-loader.js.map +1 -0
- package/node_modules/pi-mcp-adapter/dist/config.d.ts +123 -0
- package/node_modules/pi-mcp-adapter/dist/config.js +1087 -0
- package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -0
- package/node_modules/pi-mcp-adapter/dist/metadata-cache.d.ts +19 -0
- package/node_modules/pi-mcp-adapter/dist/metadata-cache.js +319 -0
- package/node_modules/pi-mcp-adapter/dist/metadata-cache.js.map +1 -0
- package/node_modules/pi-mcp-adapter/dist/package-mcp-loader.d.ts +2 -0
- package/node_modules/pi-mcp-adapter/dist/package-mcp-loader.js +156 -0
- package/node_modules/pi-mcp-adapter/dist/package-mcp-loader.js.map +1 -0
- package/node_modules/pi-mcp-adapter/dist/resource-tools.d.ts +1 -0
- package/node_modules/pi-mcp-adapter/dist/resource-tools.js +15 -0
- package/node_modules/pi-mcp-adapter/dist/resource-tools.js.map +1 -0
- package/node_modules/pi-mcp-adapter/dist/types.d.ts +564 -0
- package/node_modules/pi-mcp-adapter/dist/types.js +287 -0
- package/node_modules/pi-mcp-adapter/dist/types.js.map +1 -0
- package/node_modules/pi-mcp-adapter/dist/ui-app-bridge-helpers.d.ts +6 -0
- package/node_modules/pi-mcp-adapter/dist/ui-app-bridge-helpers.js +37 -0
- package/node_modules/pi-mcp-adapter/dist/ui-app-bridge-helpers.js.map +1 -0
- package/node_modules/pi-mcp-adapter/dist/ui-stream-types.d.ts +104 -0
- package/node_modules/pi-mcp-adapter/dist/ui-stream-types.js +59 -0
- package/node_modules/pi-mcp-adapter/dist/ui-stream-types.js.map +1 -0
- package/node_modules/pi-mcp-adapter/dist/ui-tool-visibility.d.ts +4 -0
- package/node_modules/pi-mcp-adapter/dist/ui-tool-visibility.js +27 -0
- package/node_modules/pi-mcp-adapter/dist/ui-tool-visibility.js.map +1 -0
- package/node_modules/pi-mcp-adapter/dist/utils.d.ts +32 -0
- package/node_modules/pi-mcp-adapter/dist/utils.js +338 -0
- package/node_modules/pi-mcp-adapter/dist/utils.js.map +1 -0
- package/node_modules/pi-mcp-adapter/failure-backoff.ts +23 -0
- package/node_modules/pi-mcp-adapter/index.ts +204 -82
- package/node_modules/pi-mcp-adapter/init.ts +41 -30
- package/node_modules/pi-mcp-adapter/lifecycle.ts +16 -8
- package/node_modules/pi-mcp-adapter/mcp-code.ts +2 -0
- package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +66 -16
- package/node_modules/pi-mcp-adapter/mcp-output-guard.ts +95 -7
- package/node_modules/pi-mcp-adapter/mcp-probe.ts +18 -4
- package/node_modules/pi-mcp-adapter/mcp-references.ts +368 -0
- package/node_modules/pi-mcp-adapter/mcp-status.ts +8 -19
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +20 -12
- package/node_modules/pi-mcp-adapter/namespace-tools.ts +276 -0
- package/node_modules/pi-mcp-adapter/package.json +24 -6
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +66 -10
- package/node_modules/pi-mcp-adapter/search-ranking.ts +2 -0
- package/node_modules/pi-mcp-adapter/server-manager.ts +63 -12
- package/node_modules/pi-mcp-adapter/state.ts +1 -3
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +16 -2
- package/node_modules/pi-mcp-adapter/types.ts +48 -1
- package/node_modules/pi-mcp-adapter/ui-server.ts +3 -19
- package/node_modules/pi-mcp-adapter/ui-session.ts +2 -1
- package/node_modules/pi-mcp-adapter/utils.ts +21 -19
- package/node_modules/pi-web-access/CHANGELOG.md +26 -0
- package/node_modules/pi-web-access/README.md +71 -14
- package/node_modules/pi-web-access/chrome-cookies.ts +115 -35
- package/node_modules/pi-web-access/credential-source.ts +6 -2
- package/node_modules/pi-web-access/curator-page.ts +5 -3
- package/node_modules/pi-web-access/curator-server.ts +2 -1
- package/node_modules/pi-web-access/extract.ts +89 -9
- package/node_modules/pi-web-access/fetch-params.ts +13 -0
- package/node_modules/pi-web-access/gemini-adc.ts +298 -0
- package/node_modules/pi-web-access/gemini-api.ts +59 -15
- package/node_modules/pi-web-access/gemini-search.ts +58 -18
- package/node_modules/pi-web-access/gemini-url-context.ts +3 -2
- package/node_modules/pi-web-access/gemini-web-config.ts +57 -7
- package/node_modules/pi-web-access/gemini-web.ts +9 -3
- package/node_modules/pi-web-access/github-api.ts +5 -4
- package/node_modules/pi-web-access/github-issue-pr.ts +700 -0
- package/node_modules/pi-web-access/index.ts +403 -297
- package/node_modules/pi-web-access/kimi-search.ts +234 -0
- package/node_modules/pi-web-access/openai-search.ts +118 -21
- package/node_modules/pi-web-access/package.json +3 -2
- package/node_modules/pi-web-access/ssrf-protection.ts +4 -1
- package/node_modules/pi-web-access/utils.ts +307 -1
- package/node_modules/pi-web-access/youtube-extract.ts +2 -2
- package/package.json +46 -37
- package/node_modules/@herbertgao/pi-copy-response/CHANGELOG.md +0 -49
- package/node_modules/@herbertgao/pi-copy-response/LICENSE +0 -22
- package/node_modules/@herbertgao/pi-handoff/CHANGELOG.md +0 -83
- package/node_modules/@herbertgao/pi-handoff/LICENSE +0 -22
- package/node_modules/@herbertgao/pi-handoff/package.json +0 -60
- package/node_modules/@herbertgao/pi-inline-skills/CHANGELOG.md +0 -57
- package/node_modules/@herbertgao/pi-inline-skills/LICENSE +0 -22
- package/node_modules/@herbertgao/pi-mermaid-open/CHANGELOG.md +0 -39
- package/node_modules/@herbertgao/pi-preferred-thinking/CHANGELOG.md +0 -63
- package/node_modules/@herbertgao/pi-preferred-thinking/LICENSE +0 -22
- package/node_modules/@herbertgao/pi-recap/CHANGELOG.md +0 -101
- package/node_modules/@herbertgao/pi-recap/LICENSE +0 -22
- package/node_modules/@herbertgao/pi-recap/package.json +0 -55
- package/node_modules/@herbertgao/pi-rename/CHANGELOG.md +0 -49
- package/node_modules/@herbertgao/pi-rename/LICENSE +0 -22
- package/node_modules/@herbertgao/pi-rename/package.json +0 -63
- package/node_modules/@herbertgao/pi-titlebar-spinner/CHANGELOG.md +0 -25
- package/node_modules/@herbertgao/pi-titlebar-spinner/LICENSE +0 -22
- /package/node_modules/{@herbertgao → @tifan}/pi-copy-response/src/index.ts +0 -0
- /package/node_modules/{@herbertgao → @tifan}/pi-handoff/src/complete-text.ts +0 -0
- /package/node_modules/{@herbertgao → @tifan}/pi-handoff/src/session-query.ts +0 -0
- /package/node_modules/{@herbertgao → @tifan}/pi-inline-skills/src/index.ts +0 -0
- /package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/herdr-plugin/herdr-plugin.toml +0 -0
- /package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/herdr-plugin/viewer.mjs +0 -0
- /package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/src/index.ts +0 -0
- /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/index.ts +0 -0
- /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/model-picker.ts +0 -0
- /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/sanitize.ts +0 -0
- /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/tui.ts +0 -0
- /package/node_modules/{@herbertgao → @tifan}/pi-rename/src/model-picker.ts +0 -0
- /package/node_modules/{@herbertgao → @tifan}/pi-rename/src/naming.ts +0 -0
- /package/node_modules/{@herbertgao → @tifan}/pi-rename/src/sanitize.ts +0 -0
- /package/node_modules/{@herbertgao → @tifan}/pi-titlebar-spinner/src/index.ts +0 -0
|
@@ -8,7 +8,7 @@ function safeInlineJSON(data: unknown): string {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
function buildProviderButtons(
|
|
11
|
-
available: { all: boolean; openai: boolean; brave: boolean; parallel: boolean; "parallel-mcp": boolean; tinyfish: boolean; search1api: boolean; searchinfinity: boolean; querit: boolean; tavily: boolean; firecrawl: boolean; jina: boolean; serpdive: boolean; kagi: boolean; bocha: boolean; ollama: boolean; searxng: boolean; duckduckgo: boolean; perplexity: boolean; exa: boolean; gemini: boolean; anysearch: boolean; xai: boolean; brightdata: boolean; serpbase: boolean; serper: boolean; valyu: boolean },
|
|
11
|
+
available: { all: boolean; openai: boolean; brave: boolean; parallel: boolean; "parallel-mcp": boolean; tinyfish: boolean; search1api: boolean; searchinfinity: boolean; querit: boolean; tavily: boolean; firecrawl: boolean; jina: boolean; serpdive: boolean; kagi: boolean; bocha: boolean; ollama: boolean; searxng: boolean; duckduckgo: boolean; perplexity: boolean; exa: boolean; gemini: boolean; kimi: boolean; anysearch: boolean; xai: boolean; brightdata: boolean; serpbase: boolean; serper: boolean; valyu: boolean },
|
|
12
12
|
selected: string,
|
|
13
13
|
hasInitialQueries: boolean,
|
|
14
14
|
): string {
|
|
@@ -34,6 +34,7 @@ function buildProviderButtons(
|
|
|
34
34
|
{ value: "duckduckgo", label: "DuckDuckGo", available: available.duckduckgo },
|
|
35
35
|
{ value: "perplexity", label: "Perplexity", available: available.perplexity },
|
|
36
36
|
{ value: "gemini", label: "Gemini", available: available.gemini },
|
|
37
|
+
{ value: "kimi", label: "Kimi", available: available.kimi },
|
|
37
38
|
{ value: "anysearch", label: "AnySearch", available: available.anysearch },
|
|
38
39
|
{ value: "xai", label: "xAI", available: available.xai },
|
|
39
40
|
{ value: "brightdata", label: "Bright Data", available: available.brightdata },
|
|
@@ -58,7 +59,7 @@ export function generateCuratorPage(
|
|
|
58
59
|
queries: string[],
|
|
59
60
|
sessionToken: string,
|
|
60
61
|
timeout: number,
|
|
61
|
-
availableProviders: { all: boolean; openai: boolean; brave: boolean; parallel: boolean; "parallel-mcp": boolean; tinyfish: boolean; search1api: boolean; searchinfinity: boolean; querit: boolean; tavily: boolean; firecrawl: boolean; jina: boolean; serpdive: boolean; kagi: boolean; bocha: boolean; ollama: boolean; searxng: boolean; duckduckgo: boolean; perplexity: boolean; exa: boolean; gemini: boolean; anysearch: boolean; xai: boolean; brightdata: boolean; serpbase: boolean; serper: boolean; valyu: boolean },
|
|
62
|
+
availableProviders: { all: boolean; openai: boolean; brave: boolean; parallel: boolean; "parallel-mcp": boolean; tinyfish: boolean; search1api: boolean; searchinfinity: boolean; querit: boolean; tavily: boolean; firecrawl: boolean; jina: boolean; serpdive: boolean; kagi: boolean; bocha: boolean; ollama: boolean; searxng: boolean; duckduckgo: boolean; perplexity: boolean; exa: boolean; gemini: boolean; kimi: boolean; anysearch: boolean; xai: boolean; brightdata: boolean; serpbase: boolean; serper: boolean; valyu: boolean },
|
|
62
63
|
defaultProvider: string,
|
|
63
64
|
searchProvider: string,
|
|
64
65
|
summaryModels: Array<{ value: string; label: string }>,
|
|
@@ -1459,7 +1460,7 @@ const SCRIPT = `(function() {
|
|
|
1459
1460
|
var token = DATA.sessionToken;
|
|
1460
1461
|
var timeoutSec = DATA.timeout;
|
|
1461
1462
|
var queries = Array.isArray(DATA.queries) ? DATA.queries : [];
|
|
1462
|
-
var providers = ["all", "openai", "exa", "brave", "parallel", "parallel-mcp", "tinyfish", "search1api", "searchinfinity", "querit", "tavily", "firecrawl", "jina", "serpdive", "kagi", "bocha", "ollama", "searxng", "duckduckgo", "perplexity", "gemini", "anysearch", "xai", "brightdata", "serpbase", "serper", "valyu"];
|
|
1463
|
+
var providers = ["all", "openai", "exa", "brave", "parallel", "parallel-mcp", "tinyfish", "search1api", "searchinfinity", "querit", "tavily", "firecrawl", "jina", "serpdive", "kagi", "bocha", "ollama", "searxng", "duckduckgo", "perplexity", "gemini", "kimi", "anysearch", "xai", "brightdata", "serpbase", "serper", "valyu"];
|
|
1463
1464
|
var availProviders = DATA.availableProviders && typeof DATA.availableProviders === "object" ? DATA.availableProviders : {};
|
|
1464
1465
|
var workflow = "summary-review";
|
|
1465
1466
|
var initialDefaultProvider = typeof DATA.defaultProvider === "string" ? DATA.defaultProvider : "exa";
|
|
@@ -1682,6 +1683,7 @@ const SCRIPT = `(function() {
|
|
|
1682
1683
|
if (provider === "perplexity") return "Perplexity";
|
|
1683
1684
|
if (provider === "exa") return "Exa";
|
|
1684
1685
|
if (provider === "gemini") return "Gemini";
|
|
1686
|
+
if (provider === "kimi") return "Kimi";
|
|
1685
1687
|
if (provider === "anysearch") return "AnySearch";
|
|
1686
1688
|
if (provider === "xai") return "xAI";
|
|
1687
1689
|
if (provider === "brightdata") return "Bright Data";
|
|
@@ -18,7 +18,7 @@ export interface CuratorServerOptions {
|
|
|
18
18
|
queries: string[];
|
|
19
19
|
sessionToken: string;
|
|
20
20
|
timeout: number;
|
|
21
|
-
availableProviders: { all: boolean; openai: boolean; brave: boolean; parallel: boolean; "parallel-mcp": boolean; tinyfish: boolean; search1api: boolean; searchinfinity: boolean; querit: boolean; tavily: boolean; firecrawl: boolean; jina: boolean; serpdive: boolean; kagi: boolean; bocha: boolean; ollama: boolean; searxng: boolean; duckduckgo: boolean; perplexity: boolean; exa: boolean; gemini: boolean; anysearch: boolean; xai: boolean; brightdata: boolean; serpbase: boolean; serper: boolean; valyu: boolean };
|
|
21
|
+
availableProviders: { all: boolean; openai: boolean; brave: boolean; parallel: boolean; "parallel-mcp": boolean; tinyfish: boolean; search1api: boolean; searchinfinity: boolean; querit: boolean; tavily: boolean; firecrawl: boolean; jina: boolean; serpdive: boolean; kagi: boolean; bocha: boolean; ollama: boolean; searxng: boolean; duckduckgo: boolean; perplexity: boolean; exa: boolean; gemini: boolean; kimi: boolean; anysearch: boolean; xai: boolean; brightdata: boolean; serpbase: boolean; serper: boolean; valyu: boolean };
|
|
22
22
|
defaultProvider: string;
|
|
23
23
|
searchProvider: string;
|
|
24
24
|
summaryModels: Array<{ value: string; label: string }>;
|
|
@@ -292,6 +292,7 @@ export function startCuratorServer(
|
|
|
292
292
|
if (provider === "perplexity") return availableProviders.perplexity;
|
|
293
293
|
if (provider === "exa") return availableProviders.exa;
|
|
294
294
|
if (provider === "gemini") return availableProviders.gemini;
|
|
295
|
+
if (provider === "kimi") return availableProviders.kimi;
|
|
295
296
|
if (provider === "anysearch") return availableProviders.anysearch;
|
|
296
297
|
if (provider === "xai") return availableProviders.xai;
|
|
297
298
|
if (provider === "brightdata") return availableProviders.brightdata;
|
|
@@ -8,6 +8,7 @@ import { activityMonitor } from "./activity.ts";
|
|
|
8
8
|
import { extractRSCContent } from "./rsc-extract.ts";
|
|
9
9
|
import { extractPDFToMarkdown, isPDF, loadPDFConfig } from "./pdf-extract.ts";
|
|
10
10
|
import { extractGitHub } from "./github-extract.ts";
|
|
11
|
+
import { extractGitHubIssuePr } from "./github-issue-pr.ts";
|
|
11
12
|
import { isYouTubeURL, isYouTubeEnabled, extractYouTube, extractYouTubeFrame, extractYouTubeFrames, getYouTubeStreamInfo } from "./youtube-extract.ts";
|
|
12
13
|
import { CredentialResolutionError } from "./credential-source.ts";
|
|
13
14
|
import { extractWithUrlContext, extractWithGeminiWeb } from "./gemini-url-context.ts";
|
|
@@ -23,7 +24,7 @@ import { extractWithBrightDataUnlocker, isBrightDataUnlockerAvailable } from "./
|
|
|
23
24
|
import { isVideoFile, extractVideo, extractVideoFrame, getLocalVideoDuration } from "./video-extract.ts";
|
|
24
25
|
import { appendDeclaredWebLinks, discoverDeclaredWebLinks, type DeclaredWebLink } from "./declared-web-links.ts";
|
|
25
26
|
import { fetchRemoteUrl, loadFetchContentDomainPolicy, loadSsrfConfig, validateRemoteUrl, type DomainPolicy, type Lookup, type SsrfConfig } from "./ssrf-protection.ts";
|
|
26
|
-
import { formatSeconds, getWebSearchConfigPath } from "./utils.ts";
|
|
27
|
+
import { formatSeconds, getWebSearchConfigPath, type ProxiedRequestInit } from "./utils.ts";
|
|
27
28
|
import { isImageEnabled } from "./feature-config.ts";
|
|
28
29
|
import { assertAuthFetchUrl, authFetchRedirectGuard, type AuthFetchProfile } from "./auth-fetch.ts";
|
|
29
30
|
import { getBrowserCookiesForHosts, getLastBrowserCookieDiagnostic } from "./chrome-cookies.ts";
|
|
@@ -42,6 +43,13 @@ type FetchRouting = { providers: FetchProvider[]; allowRemoteHostedProviders: bo
|
|
|
42
43
|
const DEFAULT_FETCH_PROVIDER_ORDER: FetchProvider[] = ["http", "firecrawl", "jina", "tinyfish", "search1api", "querit", "kagi", "ollama", "parallel", "brightdata", "gemini"];
|
|
43
44
|
const REMOTE_HOSTED_FETCH_PROVIDERS = new Set<FetchProvider>(["jina", "tinyfish", "search1api", "querit", "kagi", "ollama", "parallel", "parallel-mcp", "brightdata", "gemini"]);
|
|
44
45
|
|
|
46
|
+
async function extractWithDefuddle(text: string, url: string): Promise<{ title: string; content: string } | null> {
|
|
47
|
+
const { Defuddle } = await import("defuddle/node");
|
|
48
|
+
const { document } = parseHTML(text);
|
|
49
|
+
const result = await Defuddle(document as unknown as Document, url, { markdown: true, useAsync: false });
|
|
50
|
+
return typeof result.content === "string" ? { title: result.title, content: result.content } : null;
|
|
51
|
+
}
|
|
52
|
+
|
|
45
53
|
export { loadSsrfConfig } from "./ssrf-protection.ts";
|
|
46
54
|
|
|
47
55
|
export function loadSsrfAllowRanges(): string[] {
|
|
@@ -183,6 +191,32 @@ function loadFetchRouting(): FetchRouting {
|
|
|
183
191
|
return { providers, allowRemoteHostedProviders: allowRemoteHostedProvidersValue === true };
|
|
184
192
|
}
|
|
185
193
|
|
|
194
|
+
/** Names of the search/fetch tools the caller has actually registered, so
|
|
195
|
+
* failure guidance never points at tools that do not exist in the session. */
|
|
196
|
+
export interface RegisteredToolNames {
|
|
197
|
+
webSearch?: string;
|
|
198
|
+
fetchContent?: string;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** Guidance for definitive origin 404/410 responses: no extraction provider
|
|
202
|
+
* can retrieve a page the origin says is gone, so point at the registered
|
|
203
|
+
* search/fetch tools (when the caller knows them) instead of provider config. */
|
|
204
|
+
function notFoundGuidance(result: ExtractedContent, toolNames?: RegisteredToolNames): string {
|
|
205
|
+
const lines = [
|
|
206
|
+
result.error ?? `HTTP ${result.status}`,
|
|
207
|
+
"",
|
|
208
|
+
`The origin server says this page does not exist (HTTP ${result.status}), so extraction providers cannot retrieve it.`,
|
|
209
|
+
];
|
|
210
|
+
if (toolNames?.webSearch && toolNames.fetchContent) {
|
|
211
|
+
lines.push(`The page may have moved or been renamed. Use ${toolNames.webSearch} to find the current URL, then retry ${toolNames.fetchContent} with it.`);
|
|
212
|
+
} else if (toolNames?.webSearch) {
|
|
213
|
+
lines.push(`The page may have moved or been renamed. Use ${toolNames.webSearch} to find the current URL.`);
|
|
214
|
+
} else {
|
|
215
|
+
lines.push("The page may have moved or been renamed. Find the current URL, then retry the fetch with it.");
|
|
216
|
+
}
|
|
217
|
+
return lines.join("\n");
|
|
218
|
+
}
|
|
219
|
+
|
|
186
220
|
function abortedResult(url: string): ExtractedContent {
|
|
187
221
|
return { url, title: "", content: "", error: "Aborted" };
|
|
188
222
|
}
|
|
@@ -227,6 +261,9 @@ export interface ExtractOptions {
|
|
|
227
261
|
mode?: "readable" | "raw" | "answer";
|
|
228
262
|
answerModel?: string;
|
|
229
263
|
authFetchProfile?: AuthFetchProfile;
|
|
264
|
+
toolNames?: RegisteredToolNames;
|
|
265
|
+
/** Optional http(s) proxy URL; routed through the curl-backed transport. */
|
|
266
|
+
proxy?: string;
|
|
230
267
|
/** Custom DNS resolver used for SSRF validation. Primarily a test seam. */
|
|
231
268
|
lookup?: Lookup;
|
|
232
269
|
}
|
|
@@ -585,6 +622,18 @@ export async function extractContent(
|
|
|
585
622
|
return { url, title: "", content: "", error: errorMessage(err) };
|
|
586
623
|
}
|
|
587
624
|
|
|
625
|
+
try {
|
|
626
|
+
const ghIssuePrResult = await extractGitHubIssuePr(url, signal, options);
|
|
627
|
+
if (ghIssuePrResult) return ghIssuePrResult;
|
|
628
|
+
if (signal?.aborted) return abortedResult(url);
|
|
629
|
+
} catch (err) {
|
|
630
|
+
const message = errorMessage(err);
|
|
631
|
+
if (isAbortError(err)) return abortedResult(url);
|
|
632
|
+
if (isConfigParseError(err)) {
|
|
633
|
+
return { url, title: "", content: "", error: message };
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
588
637
|
try {
|
|
589
638
|
const ghResult = await extractGitHub(url, signal, options?.forceClone);
|
|
590
639
|
if (ghResult) return ghResult;
|
|
@@ -856,6 +905,14 @@ export async function extractContent(
|
|
|
856
905
|
const finalHttpResult = httpResult as ExtractedContent | null;
|
|
857
906
|
if (finalHttpResult && declaredLinks.length > 0) return { ...finalHttpResult, error: null };
|
|
858
907
|
|
|
908
|
+
// A definitive 404/410 from the origin means no extraction provider can
|
|
909
|
+
// retrieve the page, so the provider-configuration checklist below would
|
|
910
|
+
// send users down the wrong path. Point at search instead.
|
|
911
|
+
if (finalHttpResult?.status === 404 || finalHttpResult?.status === 410) {
|
|
912
|
+
return { ...finalHttpResult, error: notFoundGuidance(finalHttpResult, options?.toolNames) };
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
const searchToolName = options?.toolNames?.webSearch;
|
|
859
916
|
const guidance = [
|
|
860
917
|
finalHttpResult?.error ?? "No fetch_content provider returned content",
|
|
861
918
|
...(firecrawlError ? [`Firecrawl fallback failed: ${firecrawlError}`] : []),
|
|
@@ -879,19 +936,17 @@ export async function extractContent(
|
|
|
879
936
|
` • Set brightdataApiKey and brightdataUnlockerZone in ${WEB_SEARCH_CONFIG_PATH} or BRIGHTDATA_API_KEY and BRIGHTDATA_UNLOCKER_ZONE`,
|
|
880
937
|
` • Set GEMINI_API_KEY in ${WEB_SEARCH_CONFIG_PATH}`,
|
|
881
938
|
" • Sign into gemini.google.com in Chrome",
|
|
882
|
-
|
|
939
|
+
...(searchToolName ? [` • Use ${searchToolName} to find content about this topic`] : []),
|
|
883
940
|
].join("\n");
|
|
884
941
|
return { ...(finalHttpResult ?? { url, title: "", content: "", error: null }), error: guidance };
|
|
885
942
|
}
|
|
886
943
|
|
|
887
944
|
function isLikelyJSRendered(html: string): boolean {
|
|
888
|
-
// Extract body content
|
|
889
945
|
const bodyMatch = html.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
|
|
890
946
|
if (!bodyMatch) return false;
|
|
891
947
|
|
|
892
948
|
const bodyHtml = bodyMatch[1];
|
|
893
949
|
|
|
894
|
-
// Strip tags to get text content
|
|
895
950
|
const textContent = bodyHtml
|
|
896
951
|
.replace(/<script[\s\S]*?<\/script>/gi, "")
|
|
897
952
|
.replace(/<style[\s\S]*?<\/style>/gi, "")
|
|
@@ -899,10 +954,8 @@ function isLikelyJSRendered(html: string): boolean {
|
|
|
899
954
|
.replace(/\s+/g, " ")
|
|
900
955
|
.trim();
|
|
901
956
|
|
|
902
|
-
// Count scripts
|
|
903
957
|
const scriptCount = (html.match(/<script/gi) || []).length;
|
|
904
958
|
|
|
905
|
-
// Heuristic: little text content but many scripts suggests JS rendering
|
|
906
959
|
return textContent.length < 500 && scriptCount > 3;
|
|
907
960
|
}
|
|
908
961
|
|
|
@@ -999,8 +1052,10 @@ async function extractViaHttp(
|
|
|
999
1052
|
const ssrf = loadSsrfConfig();
|
|
1000
1053
|
const domainPolicy = loadFetchContentDomainPolicy();
|
|
1001
1054
|
const authProfile = options?.authFetchProfile;
|
|
1002
|
-
const
|
|
1055
|
+
const trustEnvProxy = options?.proxy === undefined && ssrf.trustEnvProxy;
|
|
1056
|
+
const requestInit: ProxiedRequestInit = {
|
|
1003
1057
|
signal: controller.signal,
|
|
1058
|
+
__proxy: options?.proxy,
|
|
1004
1059
|
headers: {
|
|
1005
1060
|
"User-Agent": "OpenAI File Downloader, XaiImageApiFetch/1.0",
|
|
1006
1061
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
|
|
@@ -1014,13 +1069,13 @@ async function extractViaHttp(
|
|
|
1014
1069
|
},
|
|
1015
1070
|
};
|
|
1016
1071
|
const response = authProfile
|
|
1017
|
-
? await fetchAuthenticatedRemoteUrl(url, requestInit, { ssrf, domainPolicy, ...(options?.lookup ? { lookup: options.lookup } : {}) }, authProfile)
|
|
1072
|
+
? await fetchAuthenticatedRemoteUrl(url, requestInit, { ssrf: { ...ssrf, trustEnvProxy }, domainPolicy, ...(options?.lookup ? { lookup: options.lookup } : {}) }, authProfile)
|
|
1018
1073
|
: await fetchRemoteUrl(
|
|
1019
1074
|
url,
|
|
1020
1075
|
requestInit,
|
|
1021
1076
|
{
|
|
1022
1077
|
allowRanges: ssrf.allowRanges,
|
|
1023
|
-
trustEnvProxy
|
|
1078
|
+
trustEnvProxy,
|
|
1024
1079
|
domainPolicy,
|
|
1025
1080
|
...(options?.lookup ? { lookup: options.lookup } : {}),
|
|
1026
1081
|
},
|
|
@@ -1170,6 +1225,19 @@ async function extractViaHttp(
|
|
|
1170
1225
|
declaredLinks,
|
|
1171
1226
|
};
|
|
1172
1227
|
}
|
|
1228
|
+
controller.signal.throwIfAborted();
|
|
1229
|
+
const defuddleResult = await extractWithDefuddle(text, response.url || url);
|
|
1230
|
+
controller.signal.throwIfAborted();
|
|
1231
|
+
if (defuddleResult && defuddleResult.content.length >= MIN_USEFUL_CONTENT) {
|
|
1232
|
+
activityMonitor.logComplete(activityId, response.status);
|
|
1233
|
+
return {
|
|
1234
|
+
url,
|
|
1235
|
+
title: documentTitle || defuddleResult.title,
|
|
1236
|
+
content: appendDeclaredWebLinks(defuddleResult.content, declaredLinks),
|
|
1237
|
+
error: null,
|
|
1238
|
+
declaredLinks,
|
|
1239
|
+
};
|
|
1240
|
+
}
|
|
1173
1241
|
|
|
1174
1242
|
activityMonitor.logComplete(activityId, response.status);
|
|
1175
1243
|
const jsRendered = isLikelyJSRendered(text);
|
|
@@ -1203,6 +1271,18 @@ async function extractViaHttp(
|
|
|
1203
1271
|
declaredLinks,
|
|
1204
1272
|
};
|
|
1205
1273
|
}
|
|
1274
|
+
controller.signal.throwIfAborted();
|
|
1275
|
+
const defuddleResult = await extractWithDefuddle(text, response.url || url);
|
|
1276
|
+
controller.signal.throwIfAborted();
|
|
1277
|
+
if (defuddleResult && defuddleResult.content.length >= MIN_USEFUL_CONTENT) {
|
|
1278
|
+
return {
|
|
1279
|
+
url,
|
|
1280
|
+
title: article.title || documentTitle || defuddleResult.title,
|
|
1281
|
+
content: appendDeclaredWebLinks(defuddleResult.content, declaredLinks),
|
|
1282
|
+
error: null,
|
|
1283
|
+
declaredLinks,
|
|
1284
|
+
};
|
|
1285
|
+
}
|
|
1206
1286
|
return {
|
|
1207
1287
|
url,
|
|
1208
1288
|
title: article.title || documentTitle,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { normalizeProxyUrl } from "./utils.ts";
|
|
2
|
+
|
|
1
3
|
export interface FetchContentParams {
|
|
2
4
|
url?: unknown;
|
|
3
5
|
urls?: unknown;
|
|
@@ -9,6 +11,7 @@ export interface FetchContentParams {
|
|
|
9
11
|
mode?: unknown;
|
|
10
12
|
answerModel?: unknown;
|
|
11
13
|
auth?: unknown;
|
|
14
|
+
proxy?: unknown;
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
export interface NormalizedFetchContentParams {
|
|
@@ -22,6 +25,7 @@ export interface NormalizedFetchContentParams {
|
|
|
22
25
|
mode?: "readable" | "raw" | "answer";
|
|
23
26
|
answerModel?: string;
|
|
24
27
|
auth?: true | string;
|
|
28
|
+
proxy?: string;
|
|
25
29
|
};
|
|
26
30
|
}
|
|
27
31
|
|
|
@@ -39,6 +43,7 @@ export function normalizeFetchContentParams(params: FetchContentParams): Normali
|
|
|
39
43
|
const mode = normalizeMode(params.mode);
|
|
40
44
|
const answerModel = normalizeOptionalString(params.answerModel);
|
|
41
45
|
const auth = normalizeAuth(params.auth);
|
|
46
|
+
const proxy = normalizeProxy(params.proxy);
|
|
42
47
|
|
|
43
48
|
return {
|
|
44
49
|
urlList,
|
|
@@ -51,6 +56,7 @@ export function normalizeFetchContentParams(params: FetchContentParams): Normali
|
|
|
51
56
|
...(mode !== undefined ? { mode } : {}),
|
|
52
57
|
...(answerModel !== undefined ? { answerModel } : {}),
|
|
53
58
|
...(auth !== undefined ? { auth } : {}),
|
|
59
|
+
...(proxy !== undefined ? { proxy } : {}),
|
|
54
60
|
},
|
|
55
61
|
};
|
|
56
62
|
}
|
|
@@ -88,6 +94,13 @@ function normalizeAuth(value: unknown): true | string | undefined {
|
|
|
88
94
|
throw new Error("auth must be a profile name, true, or false");
|
|
89
95
|
}
|
|
90
96
|
|
|
97
|
+
function normalizeProxy(value: unknown): string | undefined {
|
|
98
|
+
if (value === undefined || value === false) return undefined;
|
|
99
|
+
if (value === null) throw new Error("proxy must be an http(s) proxy URL string");
|
|
100
|
+
const normalized = normalizeProxyUrl(value, "proxy");
|
|
101
|
+
return normalized ?? "";
|
|
102
|
+
}
|
|
103
|
+
|
|
91
104
|
function normalizeOptionalFrameCount(value: unknown): number | undefined {
|
|
92
105
|
if (typeof value !== "number" || !Number.isInteger(value) || value < 1 || value > 12) return undefined;
|
|
93
106
|
return value;
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { createSign } from "node:crypto";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { getWebSearchConfigPath } from "./utils.ts";
|
|
6
|
+
import { redactCredential, CredentialResolutionError } from "./credential-source.ts";
|
|
7
|
+
|
|
8
|
+
const CONFIG_PATH = getWebSearchConfigPath();
|
|
9
|
+
const DEFAULT_ADC_PATH = join(homedir(), ".config", "gcloud", "application_default_credentials.json");
|
|
10
|
+
const TOKEN_ENDPOINT = "https://oauth2.googleapis.com/token";
|
|
11
|
+
const VERTEX_HOST = "https://aiplatform.googleapis.com";
|
|
12
|
+
const VERTEX_API_VERSION = "v1";
|
|
13
|
+
const REFRESH_SKEW_MS = 60_000;
|
|
14
|
+
|
|
15
|
+
interface GeminiAdcConfig {
|
|
16
|
+
geminiAuth?: unknown;
|
|
17
|
+
geminiProject?: unknown;
|
|
18
|
+
geminiLocation?: unknown;
|
|
19
|
+
geminiApiKey?: unknown;
|
|
20
|
+
geminiBaseUrl?: unknown;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let cachedConfig: GeminiAdcConfig | null = null;
|
|
24
|
+
|
|
25
|
+
function loadConfig(): GeminiAdcConfig {
|
|
26
|
+
if (cachedConfig) return cachedConfig;
|
|
27
|
+
if (!existsSync(CONFIG_PATH)) {
|
|
28
|
+
cachedConfig = {};
|
|
29
|
+
return cachedConfig;
|
|
30
|
+
}
|
|
31
|
+
const raw = readFileSync(CONFIG_PATH, "utf-8");
|
|
32
|
+
try {
|
|
33
|
+
const parsed = JSON.parse(raw);
|
|
34
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
35
|
+
throw new Error("config root must be an object");
|
|
36
|
+
}
|
|
37
|
+
cachedConfig = parsed as GeminiAdcConfig;
|
|
38
|
+
} catch (err) {
|
|
39
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
40
|
+
throw new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);
|
|
41
|
+
}
|
|
42
|
+
return cachedConfig;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function normalizeIdentifier(value: unknown, envName: string): string | null {
|
|
46
|
+
if (typeof value === "string") {
|
|
47
|
+
const trimmed = value.trim();
|
|
48
|
+
if (trimmed) return trimmed;
|
|
49
|
+
}
|
|
50
|
+
const fromEnv = process.env[envName]?.trim();
|
|
51
|
+
return fromEnv ? fromEnv : null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function isAdcAuthSelected(): boolean {
|
|
55
|
+
return (loadConfig().geminiAuth ?? "").toString().trim().toLowerCase() === "adc";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function getAdcProject(): string | null {
|
|
59
|
+
return (
|
|
60
|
+
normalizeIdentifier(loadConfig().geminiProject, "GOOGLE_CLOUD_PROJECT") ??
|
|
61
|
+
normalizeIdentifier(null, "GCLOUD_PROJECT")
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function getAdcLocation(): string | null {
|
|
66
|
+
return normalizeIdentifier(loadConfig().geminiLocation, "GOOGLE_CLOUD_LOCATION");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function getAdcPath(): string {
|
|
70
|
+
return process.env.GOOGLE_APPLICATION_CREDENTIALS?.trim() || DEFAULT_ADC_PATH;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function getVertexApiBase(project: string, location: string): string {
|
|
74
|
+
return `${VERTEX_HOST}/${VERTEX_API_VERSION}/projects/${encodeURIComponent(project)}/locations/${encodeURIComponent(location)}/publishers/google`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function isVertexHost(origin: string): boolean {
|
|
78
|
+
return origin === VERTEX_HOST;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface AdcFile {
|
|
82
|
+
type?: string;
|
|
83
|
+
client_id?: string;
|
|
84
|
+
client_secret?: string;
|
|
85
|
+
refresh_token?: string;
|
|
86
|
+
client_email?: string;
|
|
87
|
+
private_key?: string;
|
|
88
|
+
private_key_id?: string;
|
|
89
|
+
token_uri?: string;
|
|
90
|
+
universe_domain?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function objectRecord(value: unknown): Record<string, unknown> | null {
|
|
94
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function stringField(record: Record<string, unknown>, name: string): string | undefined {
|
|
98
|
+
const value = record[name];
|
|
99
|
+
return typeof value === "string" ? value : undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function requiredString(record: Record<string, unknown>, name: string, context: string): string {
|
|
103
|
+
const value = stringField(record, name)?.trim();
|
|
104
|
+
if (!value) throw new Error(`${context} is missing ${name}`);
|
|
105
|
+
return value;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function parseAdcFile(raw: string): AdcFile {
|
|
109
|
+
const parsed = objectRecord(JSON.parse(raw));
|
|
110
|
+
if (!parsed) throw new Error("credential root must be an object");
|
|
111
|
+
const type = stringField(parsed, "type") ?? "authorized_user";
|
|
112
|
+
if (type === "authorized_user") {
|
|
113
|
+
return {
|
|
114
|
+
type,
|
|
115
|
+
client_id: requiredString(parsed, "client_id", "Gemini ADC authorized_user file"),
|
|
116
|
+
client_secret: requiredString(parsed, "client_secret", "Gemini ADC authorized_user file"),
|
|
117
|
+
refresh_token: requiredString(parsed, "refresh_token", "Gemini ADC authorized_user file"),
|
|
118
|
+
universe_domain: stringField(parsed, "universe_domain"),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
if (type === "service_account") {
|
|
122
|
+
return {
|
|
123
|
+
type,
|
|
124
|
+
client_email: requiredString(parsed, "client_email", "Gemini ADC service_account file"),
|
|
125
|
+
private_key: requiredString(parsed, "private_key", "Gemini ADC service_account file"),
|
|
126
|
+
private_key_id: stringField(parsed, "private_key_id"),
|
|
127
|
+
token_uri: stringField(parsed, "token_uri"),
|
|
128
|
+
universe_domain: stringField(parsed, "universe_domain"),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return { type };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function parseTokenExchangeResponse(text: string, context: string): CachedToken {
|
|
135
|
+
let raw: unknown;
|
|
136
|
+
try {
|
|
137
|
+
raw = JSON.parse(text);
|
|
138
|
+
} catch (err) {
|
|
139
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
140
|
+
throw new Error(`${context} returned invalid JSON: ${message}`);
|
|
141
|
+
}
|
|
142
|
+
const parsed = objectRecord(raw);
|
|
143
|
+
if (!parsed) throw new Error(`${context} returned a non-object response`);
|
|
144
|
+
const token = stringField(parsed, "access_token")?.trim();
|
|
145
|
+
if (!token) throw new Error(`${context} returned no access_token`);
|
|
146
|
+
const expiresIn = parsed.expires_in ?? 3600;
|
|
147
|
+
if (typeof expiresIn !== "number" || !Number.isFinite(expiresIn)) {
|
|
148
|
+
throw new Error(`${context} returned invalid expires_in`);
|
|
149
|
+
}
|
|
150
|
+
return { token, expiresAt: Date.now() + Math.max((expiresIn * 1000) - REFRESH_SKEW_MS, 60_000) };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function loadAdcFile(): Promise<AdcFile> {
|
|
154
|
+
const path = getAdcPath();
|
|
155
|
+
if (!path || !existsSync(path)) {
|
|
156
|
+
throw new Error(`Google Application Default Credentials file not found at ${path}`);
|
|
157
|
+
}
|
|
158
|
+
const raw = readFileSync(path, "utf-8");
|
|
159
|
+
try {
|
|
160
|
+
return parseAdcFile(raw);
|
|
161
|
+
} catch (err) {
|
|
162
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
163
|
+
throw new Error(`Failed to parse Google Application Default Credentials file at ${path}: ${message}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
interface CachedToken {
|
|
168
|
+
token: string;
|
|
169
|
+
expiresAt: number;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
let cachedToken: CachedToken | null = null;
|
|
173
|
+
|
|
174
|
+
export function clearAdcTokenCache(): void {
|
|
175
|
+
cachedToken = null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Classifies a failed OAuth token exchange. Only explicit credential/authorization
|
|
180
|
+
* rejections (400 invalid_client/invalid_grant/invalid_scope, 401, 403 denied)
|
|
181
|
+
* mean the configured credentials themselves were refused — a hard credential
|
|
182
|
+
* problem callers should surface rather than silently fall back. Everything else
|
|
183
|
+
* (429 rate limit, 404, 5xx, network failures, timeouts) is transient, so it is
|
|
184
|
+
* left as a plain Error and existing per-provider fallbacks keep working.
|
|
185
|
+
*/
|
|
186
|
+
const OAUTH_CREDENTIAL_REJECTION_STATUSES = new Set([400, 401, 403]);
|
|
187
|
+
|
|
188
|
+
function throwOnTokenExchangeFailure(res: Response, detail: string, status: number): never {
|
|
189
|
+
if (OAUTH_CREDENTIAL_REJECTION_STATUSES.has(status)) {
|
|
190
|
+
throw new CredentialResolutionError("Gemini ADC", "oauth-credential-rejected");
|
|
191
|
+
}
|
|
192
|
+
throw new Error(`Gemini ADC token exchange failed (${status}): ${detail.slice(0, 300)}`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function exchangeRefreshToken(cfg: AdcFile, signal?: AbortSignal): Promise<CachedToken> {
|
|
196
|
+
const body = new URLSearchParams({
|
|
197
|
+
client_id: cfg.client_id ?? "",
|
|
198
|
+
client_secret: cfg.client_secret ?? "",
|
|
199
|
+
refresh_token: cfg.refresh_token ?? "",
|
|
200
|
+
grant_type: "refresh_token",
|
|
201
|
+
});
|
|
202
|
+
const res = await fetch(TOKEN_ENDPOINT, {
|
|
203
|
+
method: "POST",
|
|
204
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
205
|
+
body,
|
|
206
|
+
signal,
|
|
207
|
+
});
|
|
208
|
+
const text = await res.text();
|
|
209
|
+
if (!res.ok) {
|
|
210
|
+
throwOnTokenExchangeFailure(res, text, res.status);
|
|
211
|
+
}
|
|
212
|
+
return parseTokenExchangeResponse(text, "Gemini ADC token exchange");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async function exchangeServiceAccountJwt(cfg: AdcFile, signal?: AbortSignal): Promise<CachedToken> {
|
|
216
|
+
if (!cfg.client_email || !cfg.private_key) {
|
|
217
|
+
throw new Error("Gemini ADC service_account file is missing client_email or private_key");
|
|
218
|
+
}
|
|
219
|
+
const now = Math.floor(Date.now() / 1000);
|
|
220
|
+
const header = { alg: "RS256", typ: "JWT" };
|
|
221
|
+
const claims = {
|
|
222
|
+
iss: cfg.client_email,
|
|
223
|
+
scope: "https://www.googleapis.com/auth/cloud-platform",
|
|
224
|
+
aud: TOKEN_ENDPOINT,
|
|
225
|
+
iat: now,
|
|
226
|
+
exp: now + 3600,
|
|
227
|
+
};
|
|
228
|
+
const encodePart = (obj: object): string =>
|
|
229
|
+
Buffer.from(JSON.stringify(obj)).toString("base64url");
|
|
230
|
+
const assertion = `${encodePart(header)}.${encodePart(claims)}`;
|
|
231
|
+
const signer = createSign("RSA-SHA256");
|
|
232
|
+
signer.update(assertion);
|
|
233
|
+
signer.end();
|
|
234
|
+
const signature = signer.sign(cfg.private_key, "base64url");
|
|
235
|
+
const jwt = `${assertion}.${signature}`;
|
|
236
|
+
|
|
237
|
+
const body = new URLSearchParams({
|
|
238
|
+
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
239
|
+
assertion: jwt,
|
|
240
|
+
});
|
|
241
|
+
const res = await fetch(cfg.token_uri || TOKEN_ENDPOINT, {
|
|
242
|
+
method: "POST",
|
|
243
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
244
|
+
body,
|
|
245
|
+
signal,
|
|
246
|
+
});
|
|
247
|
+
const text = await res.text();
|
|
248
|
+
if (!res.ok) {
|
|
249
|
+
throwOnTokenExchangeFailure(res, text, res.status);
|
|
250
|
+
}
|
|
251
|
+
return parseTokenExchangeResponse(text, "Gemini ADC service account token exchange");
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export async function getAdcAccessToken(signal?: AbortSignal): Promise<string> {
|
|
255
|
+
if (cachedToken && cachedToken.expiresAt > Date.now()) {
|
|
256
|
+
return cachedToken.token;
|
|
257
|
+
}
|
|
258
|
+
const cfg = await loadAdcFile();
|
|
259
|
+
const type = cfg.type ?? "authorized_user";
|
|
260
|
+
if (type === "authorized_user") {
|
|
261
|
+
cachedToken = await exchangeRefreshToken(cfg, signal);
|
|
262
|
+
} else if (type === "service_account") {
|
|
263
|
+
cachedToken = await exchangeServiceAccountJwt(cfg, signal);
|
|
264
|
+
} else {
|
|
265
|
+
throw new Error(`Gemini ADC unsupported credential type "${type}" (expected authorized_user or service_account)`);
|
|
266
|
+
}
|
|
267
|
+
return cachedToken.token;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export function isGeminiAdcAvailable(): boolean {
|
|
271
|
+
if (!isAdcAuthSelected()) return false;
|
|
272
|
+
// An explicitly configured Gemini API key takes precedence over ADC, so
|
|
273
|
+
// existing key-based setups and their unit tests keep working unchanged.
|
|
274
|
+
if (hasGeminiApiKeySource()) return false;
|
|
275
|
+
// An explicit base URL (gateway/relay/proxy) also wins over ADC: if the
|
|
276
|
+
// user deliberately routed Gemini somewhere, honor that routing.
|
|
277
|
+
if (hasExplicitApiBase()) return false;
|
|
278
|
+
if (!getAdcProject() || !getAdcLocation()) return false;
|
|
279
|
+
return existsSync(getAdcPath());
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function hasGeminiApiKeySource(): boolean {
|
|
283
|
+
const configured = loadConfig().geminiApiKey;
|
|
284
|
+
if (typeof configured === "string" && configured.trim()) return true;
|
|
285
|
+
const fromEnv = process.env.GEMINI_API_KEY?.trim();
|
|
286
|
+
return !!fromEnv;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function hasExplicitApiBase(): boolean {
|
|
290
|
+
const fromEnv = process.env.GOOGLE_GEMINI_BASE_URL?.trim();
|
|
291
|
+
if (fromEnv) return true;
|
|
292
|
+
const configured = loadConfig().geminiBaseUrl;
|
|
293
|
+
return typeof configured === "string" && configured.trim().length > 0;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export function redactAdcToken(text: string): string {
|
|
297
|
+
return cachedToken ? redactCredential(text, cachedToken.token) : text;
|
|
298
|
+
}
|