@herbertgao/pi-extensions 2026.8.5 → 2026.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (389) hide show
  1. package/README.md +5 -5
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -2
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -2
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +19 -7
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +30 -9
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +272 -22
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +48 -6
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +1 -1
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +14 -0
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +55 -17
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
  15. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
  16. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
  17. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  18. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +16 -0
  19. package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
  20. package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
  21. package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
  22. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
  23. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
  24. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +22 -15
  25. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
  26. package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
  27. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
  28. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
  29. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
  30. package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
  31. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
  32. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
  33. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +34 -10
  34. package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
  35. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +29 -5
  36. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +3 -0
  37. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +46 -10
  38. package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
  39. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
  40. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +8 -1
  41. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +3 -1
  42. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +2 -2
  43. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
  44. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
  45. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
  46. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +3 -1
  47. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +30 -7
  48. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
  49. package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +30 -4
  50. package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +26 -5
  51. package/node_modules/@narumitw/pi-btw/README.md +119 -103
  52. package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
  53. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
  54. package/node_modules/@narumitw/pi-btw/package.json +13 -9
  55. package/node_modules/@narumitw/pi-btw/src/btw.ts +40 -42
  56. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
  57. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
  58. package/node_modules/@narumitw/pi-btw/src/menu.ts +78 -15
  59. package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
  60. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
  61. package/node_modules/pi-lens/CHANGELOG.md +1004 -0
  62. package/node_modules/pi-lens/README.md +11 -3
  63. package/node_modules/pi-lens/config/ruff/core.toml +42 -0
  64. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
  65. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +427 -0
  66. package/node_modules/pi-lens/dist/clients/agent-nudge.js +79 -16
  67. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
  68. package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
  69. package/node_modules/pi-lens/dist/clients/bash-file-access.js +285 -8
  70. package/node_modules/pi-lens/dist/clients/biome-client.js +176 -37
  71. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
  72. package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +119 -0
  73. package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
  74. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
  75. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +192 -0
  76. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +62 -6
  77. package/node_modules/pi-lens/dist/clients/bus-publish.js +11 -3
  78. package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
  79. package/node_modules/pi-lens/dist/clients/cascade-format.js +76 -2
  80. package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
  81. package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
  82. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
  83. package/node_modules/pi-lens/dist/clients/console-guard-install.js +16 -4
  84. package/node_modules/pi-lens/dist/clients/dead-code-client.js +249 -52
  85. package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
  86. package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
  87. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +62 -13
  88. package/node_modules/pi-lens/dist/clients/dependency-checker.js +43 -9
  89. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +153 -37
  90. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
  91. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
  92. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +165 -11
  93. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +325 -72
  94. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
  95. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +81 -41
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -0
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +23 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +14 -0
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +20 -0
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +22 -0
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +10 -0
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +18 -6
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +488 -0
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +84 -0
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
  122. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +943 -93
  123. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
  124. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +72 -0
  125. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +106 -0
  126. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +9 -0
  127. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -1
  128. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
  129. package/node_modules/pi-lens/dist/clients/disposition-publish.js +10 -3
  130. package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
  131. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
  132. package/node_modules/pi-lens/dist/clients/extension-log.js +317 -3
  133. package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
  134. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +294 -0
  135. package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
  136. package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
  137. package/node_modules/pi-lens/dist/clients/format-events-publish.js +39 -8
  138. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
  139. package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
  140. package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
  141. package/node_modules/pi-lens/dist/clients/git-guard.js +49 -21
  142. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
  143. package/node_modules/pi-lens/dist/clients/go-client.js +21 -39
  144. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +219 -10
  145. package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
  146. package/node_modules/pi-lens/dist/clients/host-ports.js +9 -1
  147. package/node_modules/pi-lens/dist/clients/installer/index.js +1119 -101
  148. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
  149. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
  150. package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
  151. package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
  152. package/node_modules/pi-lens/dist/clients/jscpd-client.js +86 -15
  153. package/node_modules/pi-lens/dist/clients/knip-client.js +361 -24
  154. package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
  155. package/node_modules/pi-lens/dist/clients/language-profile.js +2 -0
  156. package/node_modules/pi-lens/dist/clients/latency-logger.js +487 -9
  157. package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
  158. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
  159. package/node_modules/pi-lens/dist/clients/lens-events.js +56 -25
  160. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
  161. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +45 -2
  162. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
  163. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +160 -20
  164. package/node_modules/pi-lens/dist/clients/lsp/client.js +1666 -148
  165. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +111 -0
  166. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
  167. package/node_modules/pi-lens/dist/clients/lsp/index.js +2496 -171
  168. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
  169. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
  170. package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
  171. package/node_modules/pi-lens/dist/clients/lsp/server.js +517 -69
  172. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
  173. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
  174. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +172 -0
  175. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
  176. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +61 -3
  177. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
  178. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
  179. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
  180. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
  181. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +4 -0
  182. package/node_modules/pi-lens/dist/clients/mcp/session.js +39 -18
  183. package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
  184. package/node_modules/pi-lens/dist/clients/module-report.js +8 -0
  185. package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
  186. package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
  187. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
  188. package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
  189. package/node_modules/pi-lens/dist/clients/pipeline.js +178 -30
  190. package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
  191. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
  192. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
  193. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +85 -15
  194. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
  195. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +23 -2
  196. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
  197. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +5 -0
  198. package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
  199. package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
  200. package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
  201. package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
  202. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +1 -1
  203. package/node_modules/pi-lens/dist/clients/read-guard.js +184 -10
  204. package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
  205. package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
  206. package/node_modules/pi-lens/dist/clients/review-graph/query.js +76 -4
  207. package/node_modules/pi-lens/dist/clients/run-duration.js +55 -0
  208. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +248 -13
  209. package/node_modules/pi-lens/dist/clients/runtime-context.js +112 -12
  210. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +472 -61
  211. package/node_modules/pi-lens/dist/clients/runtime-session.js +359 -13
  212. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
  213. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +269 -22
  214. package/node_modules/pi-lens/dist/clients/runtime-turn.js +948 -87
  215. package/node_modules/pi-lens/dist/clients/rust-client.js +21 -37
  216. package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
  217. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
  218. package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
  219. package/node_modules/pi-lens/dist/clients/security-scan-client.js +224 -8
  220. package/node_modules/pi-lens/dist/clients/sg-runner.js +249 -37
  221. package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
  222. package/node_modules/pi-lens/dist/clients/smells-rollup.js +18 -11
  223. package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
  224. package/node_modules/pi-lens/dist/clients/startup-timing.js +26 -2
  225. package/node_modules/pi-lens/dist/clients/test-runner-client.js +574 -32
  226. package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
  227. package/node_modules/pi-lens/dist/clients/tool-policy.js +127 -20
  228. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
  229. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
  230. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
  231. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
  232. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
  233. package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
  234. package/node_modules/pi-lens/dist/clients/warm-attach.js +17 -0
  235. package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
  236. package/node_modules/pi-lens/dist/clients/word-index.js +305 -33
  237. package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
  238. package/node_modules/pi-lens/dist/index.js +64677 -49484
  239. package/node_modules/pi-lens/dist/mcp/server.js +8 -2
  240. package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
  241. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
  242. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
  243. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +469 -56
  244. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +190 -46
  245. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
  246. package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
  247. package/node_modules/pi-lens/docs/agent-guide.md +44 -14
  248. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +518 -501
  249. package/node_modules/pi-lens/docs/dispositions.md +21 -0
  250. package/node_modules/pi-lens/docs/features.md +33 -6
  251. package/node_modules/pi-lens/docs/globalconfig.md +14 -0
  252. package/node_modules/pi-lens/docs/language-coverage.md +71 -5
  253. package/node_modules/pi-lens/docs/mcp.md +2 -2
  254. package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
  255. package/node_modules/pi-lens/docs/settings.md +25 -1
  256. package/node_modules/pi-lens/docs/usage.md +24 -5
  257. package/node_modules/pi-lens/docs/word-index.md +35 -0
  258. package/node_modules/pi-lens/package.json +10 -6
  259. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
  260. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
  261. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
  262. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
  263. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +22 -0
  264. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
  265. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-js-test.yml +9 -0
  266. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -0
  267. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
  268. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
  269. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
  270. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
  271. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
  272. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +9 -0
  273. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +9 -0
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +9 -0
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +9 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-laundering-test.yml +11 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
  288. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
  289. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
  290. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
  291. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
  292. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
  293. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
  294. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +66 -0
  295. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
  296. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml +21 -0
  297. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -0
  298. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
  299. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
  300. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
  301. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
  302. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
  303. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
  304. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +29 -0
  305. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +30 -0
  306. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +41 -0
  307. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +42 -0
  308. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
  309. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
  310. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
  311. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
  312. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
  313. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
  314. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +32 -0
  315. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
  316. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
  317. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
  318. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
  319. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
  320. package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
  321. package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
  322. package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
  323. package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
  324. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +132 -1
  325. package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
  326. package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
  327. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +12 -11
  328. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
  329. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +87 -116
  330. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +170 -0
  331. package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
  332. package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
  333. package/node_modules/pi-mcp-adapter/CHANGELOG.md +49 -0
  334. package/node_modules/pi-mcp-adapter/README.md +51 -6
  335. package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
  336. package/node_modules/pi-mcp-adapter/cli.js +188 -5
  337. package/node_modules/pi-mcp-adapter/commands.ts +128 -22
  338. package/node_modules/pi-mcp-adapter/config.ts +28 -10
  339. package/node_modules/pi-mcp-adapter/direct-tools.ts +23 -19
  340. package/node_modules/pi-mcp-adapter/index.ts +219 -32
  341. package/node_modules/pi-mcp-adapter/init.ts +36 -4
  342. package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
  343. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
  344. package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
  345. package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
  346. package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
  347. package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
  348. package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +2 -1
  349. package/node_modules/pi-mcp-adapter/metadata-cache.ts +46 -25
  350. package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
  351. package/node_modules/pi-mcp-adapter/package.json +4 -1
  352. package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
  353. package/node_modules/pi-mcp-adapter/request-headers-command.ts +330 -0
  354. package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
  355. package/node_modules/pi-mcp-adapter/server-manager.ts +145 -2
  356. package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
  357. package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
  358. package/node_modules/pi-mcp-adapter/tool-metadata.ts +38 -18
  359. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
  360. package/node_modules/pi-mcp-adapter/types.ts +95 -10
  361. package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
  362. package/node_modules/pi-mcp-adapter/utils.ts +70 -0
  363. package/node_modules/pi-web-access/CHANGELOG.md +37 -0
  364. package/node_modules/pi-web-access/README.md +38 -14
  365. package/node_modules/pi-web-access/anysearch.ts +4 -2
  366. package/node_modules/pi-web-access/auth-fetch.ts +148 -0
  367. package/node_modules/pi-web-access/brave.ts +16 -4
  368. package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
  369. package/node_modules/pi-web-access/curator-page.ts +8 -3
  370. package/node_modules/pi-web-access/curator-server.ts +5 -1
  371. package/node_modules/pi-web-access/exa.ts +18 -7
  372. package/node_modules/pi-web-access/extract.ts +134 -37
  373. package/node_modules/pi-web-access/fetch-params.ts +17 -3
  374. package/node_modules/pi-web-access/firecrawl.ts +172 -12
  375. package/node_modules/pi-web-access/gemini-search.ts +33 -7
  376. package/node_modules/pi-web-access/index.ts +160 -104
  377. package/node_modules/pi-web-access/package.json +2 -2
  378. package/node_modules/pi-web-access/page-query.ts +4 -2
  379. package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
  380. package/node_modules/pi-web-access/parallel.ts +2 -2
  381. package/node_modules/pi-web-access/query-rewrite.ts +51 -0
  382. package/node_modules/pi-web-access/serper.ts +211 -0
  383. package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
  384. package/node_modules/pi-web-access/summary-review.ts +51 -23
  385. package/node_modules/pi-web-access/tavily.ts +16 -4
  386. package/node_modules/pi-web-access/utils.ts +87 -0
  387. package/node_modules/pi-web-access/valyu.ts +199 -0
  388. package/node_modules/pi-web-access/youtube-extract.ts +2 -2
  389. package/package.json +13 -13
@@ -1,13 +1,20 @@
1
- import { complete, type Api, type Message, type Model } from "@earendil-works/pi-ai/compat";
1
+ import { clampThinkingLevel, type ModelThinkingLevel, type ThinkingLevel } from "@earendil-works/pi-ai";
2
+ import { complete, completeSimple, type Api, type Message, type Model } from "@earendil-works/pi-ai/compat";
2
3
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
3
- import { findModelWithProviderRouting, loadEnabledModelPatterns, modelMatchesEnabledPatterns } from "./summary-model-scope.ts";
4
+ import { findModelWithProviderRouting, loadEnabledModelPatterns, modelMatchesEnabledPatterns, splitThinkingSuffix, type SummaryThinkingLevel } from "./summary-model-scope.ts";
4
5
  import type { QueryResultData } from "./storage.ts";
5
6
 
6
7
  type ProviderHeaders = Record<string, string | null>;
8
+ type CompleteFunction = typeof complete;
9
+ type SummaryModelRegistry = SummaryGenerationContext["modelRegistry"] & { complete?: CompleteFunction };
7
10
 
8
11
  const PREFERRED_SUMMARY_MODELS = [
9
12
  { provider: "anthropic", id: "claude-haiku-4-5" },
10
- { provider: "openai-codex", id: "gpt-5.3-codex-spark" },
13
+ { provider: "openai-codex", id: "gpt-5.6-luna" },
14
+ { provider: "openai-codex", id: "gpt-5.6-terra" },
15
+ { provider: "google", id: "gemini-3.6-flash" },
16
+ { provider: "openai", id: "gpt-5-mini" },
17
+ { provider: "deepseek", id: "deepseek-v4-flash" },
11
18
  ] as const;
12
19
 
13
20
  export const SUMMARY_GENERATION_DEADLINE_MS = 30_000;
@@ -184,28 +191,35 @@ export function buildDeterministicSummary(results: QueryResultData[]): { summary
184
191
  };
185
192
  }
186
193
 
187
- function parseModelSelector(value: string): { provider: string; id: string } {
188
- const slashIndex = value.indexOf("/");
189
- if (slashIndex <= 0 || slashIndex >= value.length - 1) {
194
+ function parseModelSelector(value: string): { provider: string; id: string; thinkingLevel?: SummaryThinkingLevel } {
195
+ const selector = splitThinkingSuffix(value);
196
+ const slashIndex = selector.value.indexOf("/");
197
+ if (slashIndex <= 0 || slashIndex >= selector.value.length - 1) {
190
198
  throw new Error(`Invalid summary model: ${value}. Use provider/model-id.`);
191
199
  }
192
200
  return {
193
- provider: value.slice(0, slashIndex),
194
- id: value.slice(slashIndex + 1),
201
+ provider: selector.value.slice(0, slashIndex),
202
+ id: selector.value.slice(slashIndex + 1),
203
+ thinkingLevel: selector.thinkingLevel,
195
204
  };
196
205
  }
197
206
 
207
+ function resolveThinkingLevel(model: Model<Api>, requested?: SummaryThinkingLevel): ModelThinkingLevel | undefined {
208
+ if (!requested) return undefined;
209
+ return clampThinkingLevel(model, requested as ModelThinkingLevel);
210
+ }
211
+
198
212
  async function resolveSummaryModelCandidates(
199
213
  ctx: SummaryGenerationContext,
200
214
  modelOverride?: string,
201
- ): Promise<{ candidates: Array<{ model: Model<Api>; apiKey: string; headers?: ProviderHeaders }>; errors: string[] }> {
215
+ ): Promise<{ candidates: Array<{ model: Model<Api>; apiKey?: string; headers?: ProviderHeaders; thinkingLevel?: SummaryThinkingLevel }>; errors: string[] }> {
202
216
  const enabledModelPatterns = loadEnabledModelPatterns(ctx);
203
- const specs: Array<{ provider: string; id: string }> = [];
217
+ const specs: Array<{ provider: string; id: string; thinkingLevel?: SummaryThinkingLevel }> = [];
204
218
  const normalizedOverride = typeof modelOverride === "string" ? modelOverride.trim() : "";
205
219
  if (normalizedOverride.length > 0) specs.push(parseModelSelector(normalizedOverride));
206
220
  specs.push(...PREFERRED_SUMMARY_MODELS);
207
221
 
208
- const candidates: Array<{ model: Model<Api>; apiKey: string; headers?: ProviderHeaders }> = [];
222
+ const candidates: Array<{ model: Model<Api>; apiKey?: string; headers?: ProviderHeaders; thinkingLevel?: SummaryThinkingLevel }> = [];
209
223
  const errors: string[] = [];
210
224
  const seen = new Set<string>();
211
225
  for (const spec of specs) {
@@ -223,11 +237,11 @@ async function resolveSummaryModelCandidates(
223
237
  continue;
224
238
  }
225
239
  const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
226
- if (!auth.ok || !auth.apiKey) {
240
+ if (!auth.ok) {
227
241
  errors.push(`No API key available for summary model ${value}`);
228
242
  continue;
229
243
  }
230
- candidates.push({ model, apiKey: auth.apiKey, headers: auth.headers });
244
+ candidates.push({ model, apiKey: auth.apiKey, headers: auth.headers, thinkingLevel: spec.thinkingLevel });
231
245
  }
232
246
  return { candidates, errors };
233
247
  }
@@ -275,13 +289,18 @@ export async function generateSummaryDraft(
275
289
  signal?: AbortSignal,
276
290
  modelOverride?: string,
277
291
  feedback?: string,
278
- completeFn: typeof complete = complete,
292
+ completeFn?: CompleteFunction,
279
293
  deadlineMs = SUMMARY_GENERATION_DEADLINE_MS,
280
294
  ): Promise<{ summary: string; meta: SummaryMeta }> {
281
295
  if (!ctx || !ctx.modelRegistry) {
282
296
  throw new Error("Summary generation context unavailable");
283
297
  }
284
298
 
299
+ const registry = ctx.modelRegistry as SummaryModelRegistry;
300
+ const customCompleteFn = completeFn !== undefined;
301
+ const usesRegistryComplete = !customCompleteFn && typeof registry.complete === "function";
302
+ completeFn ??= usesRegistryComplete ? registry.complete!.bind(registry) as CompleteFunction : complete;
303
+
285
304
  const generationStartedAt = Date.now();
286
305
  const deadlineController = new AbortController();
287
306
  const deadlineMarker = Symbol("summary-generation-deadline");
@@ -337,7 +356,7 @@ export async function generateSummaryDraft(
337
356
  }
338
357
 
339
358
  let lastError = resolved.errors.at(-1);
340
- for (const { model, apiKey, headers } of resolved.candidates) {
359
+ for (const { model, apiKey, headers, thinkingLevel } of resolved.candidates) {
341
360
  const startedAt = Date.now();
342
361
  try {
343
362
  const userMessage: Message = {
@@ -345,25 +364,34 @@ export async function generateSummaryDraft(
345
364
  content: [{ type: "text", text: prompt }],
346
365
  timestamp: Date.now(),
347
366
  };
367
+ const requestedThinkingLevel = resolveThinkingLevel(model, thinkingLevel);
368
+ const enabledThinkingLevel = requestedThinkingLevel && requestedThinkingLevel !== "off"
369
+ ? requestedThinkingLevel as ThinkingLevel
370
+ : undefined;
371
+ const completionOptions = {
372
+ ...(usesRegistryComplete ? {} : { apiKey, headers }),
373
+ signal: completionSignal,
374
+ ...(requestedThinkingLevel ? { reasoning: requestedThinkingLevel } : {}),
375
+ ...(enabledThinkingLevel ? { reasoningEffort: enabledThinkingLevel } : {}),
376
+ };
377
+ const completion = thinkingLevel !== undefined && !customCompleteFn && !usesRegistryComplete
378
+ ? completeSimple(model, { messages: [userMessage] }, { apiKey, headers, signal: completionSignal, ...(enabledThinkingLevel ? { reasoning: enabledThinkingLevel } : {}) })
379
+ : completeFn(model, { messages: [userMessage] }, completionOptions);
348
380
 
349
- const response = await raceSummaryOperation(Promise.resolve(completeFn(
350
- model,
351
- { messages: [userMessage] },
352
- { apiKey, headers, signal: completionSignal },
353
- )));
381
+ const response = await raceSummaryOperation(Promise.resolve(completion));
354
382
  if (response.stopReason === "aborted") {
355
383
  throw new Error("Aborted");
356
384
  }
357
385
 
358
386
  const contentParts = Array.isArray(response.content) ? response.content : [];
359
387
  const summary = contentParts
360
- .map(part => getTextFromContentPart(part))
361
- .filter(text => text.trim().length > 0)
388
+ .map((part: unknown) => getTextFromContentPart(part))
389
+ .filter((text: string) => text.trim().length > 0)
362
390
  .join("\n")
363
391
  .trim();
364
392
 
365
393
  if (summary.length === 0) {
366
- const partTypes = contentParts.map(part => getContentPartType(part));
394
+ const partTypes = contentParts.map((part: unknown) => getContentPartType(part));
367
395
  const typesLabel = partTypes.length > 0 ? partTypes.join(", ") : "none";
368
396
  throw new Error(`Summary model returned empty response (content parts: ${typesLabel})`);
369
397
  }
@@ -3,14 +3,15 @@ import { activityMonitor } from "./activity.ts";
3
3
  import type { ExtractedContent } from "./extract.ts";
4
4
  import type { SearchOptions, SearchResponse } from "./perplexity.ts";
5
5
  import { hasCredentialSource, redactCredential, resolveCredential } from "./credential-source.ts";
6
- import { getWebSearchConfigPath } from "./utils.ts";
6
+ import { fetchWithCredentialRedirects, getWebSearchConfigPath, resolveApiBaseUrl } from "./utils.ts";
7
7
 
8
- const TAVILY_API_URL = "https://api.tavily.com/search";
8
+ const TAVILY_API_BASE_URL = "https://api.tavily.com";
9
9
  const CONFIG_PATH = getWebSearchConfigPath();
10
10
  const SEARCH_TIMEOUT_MS = 60_000;
11
11
 
12
12
  interface WebSearchConfig {
13
13
  tavilyApiKey?: unknown;
14
+ tavilyBaseUrl?: unknown;
14
15
  }
15
16
 
16
17
  interface TavilyResult {
@@ -57,6 +58,16 @@ async function getApiKey(signal?: AbortSignal): Promise<string | null> {
57
58
  });
58
59
  }
59
60
 
61
+ function getApiUrl(): string {
62
+ return `${resolveApiBaseUrl({
63
+ configKey: "tavilyBaseUrl",
64
+ configuredValue: loadConfig().tavilyBaseUrl,
65
+ defaultValue: TAVILY_API_BASE_URL,
66
+ environmentKey: "TAVILY_BASE_URL",
67
+ environmentValue: process.env.TAVILY_BASE_URL,
68
+ })}/search`;
69
+ }
70
+
60
71
  async function requireApiKey(signal?: AbortSignal): Promise<string> {
61
72
  const apiKey = await getApiKey(signal);
62
73
  if (!apiKey) {
@@ -152,6 +163,7 @@ export function isTavilyAvailable(): boolean {
152
163
  }
153
164
 
154
165
  export async function searchWithTavily(query: string, options: TavilySearchOptions = {}): Promise<SearchResponse> {
166
+ const apiUrl = getApiUrl();
155
167
  const apiKey = await requireApiKey(options.signal);
156
168
  const numResults = normalizeCount(options.numResults);
157
169
  const body: Record<string, unknown> = {
@@ -167,7 +179,7 @@ export async function searchWithTavily(query: string, options: TavilySearchOptio
167
179
  const activityId = activityMonitor.logStart({ type: "api", query });
168
180
  let response: Response;
169
181
  try {
170
- response = await fetch(TAVILY_API_URL, {
182
+ response = await fetchWithCredentialRedirects(apiUrl, {
171
183
  method: "POST",
172
184
  headers: {
173
185
  "Authorization": `Bearer ${apiKey}`,
@@ -175,7 +187,7 @@ export async function searchWithTavily(query: string, options: TavilySearchOptio
175
187
  },
176
188
  body: JSON.stringify(body),
177
189
  signal: requestSignal(options.signal),
178
- });
190
+ }, ["Authorization"]);
179
191
  } catch (err) {
180
192
  const message = errorMessage(err);
181
193
  const redactedMessage = redactCredential(message, apiKey);
@@ -12,6 +12,93 @@ export function getWebSearchConfigPath(): string {
12
12
  return join(getWebSearchConfigDir(), "web-search.json");
13
13
  }
14
14
 
15
+ interface ApiBaseUrlOptions {
16
+ configKey: string;
17
+ configuredValue: unknown;
18
+ defaultValue: string;
19
+ environmentKey: string;
20
+ environmentValue: string | undefined;
21
+ }
22
+
23
+ export function resolveApiBaseUrl(options: ApiBaseUrlOptions): string {
24
+ const fromEnvironment = options.environmentValue !== undefined;
25
+ const value = fromEnvironment ? options.environmentValue : options.configuredValue;
26
+ if (value === undefined) return options.defaultValue;
27
+
28
+ const source = fromEnvironment
29
+ ? options.environmentKey
30
+ : `${options.configKey} in ${getWebSearchConfigPath()}`;
31
+ if (typeof value !== "string" || value.trim().length === 0) {
32
+ throw new Error(`${source} must be an absolute HTTP(S) URL`);
33
+ }
34
+
35
+ let url: URL;
36
+ try {
37
+ url = new URL(value.trim());
38
+ } catch {
39
+ throw new Error(`${source} must be an absolute HTTP(S) URL`);
40
+ }
41
+ if (url.protocol !== "https:") {
42
+ throw new Error(`${source} must be an absolute HTTPS URL`);
43
+ }
44
+ if (url.username || url.password) {
45
+ throw new Error(`${source} must not include credentials`);
46
+ }
47
+ if (url.search || url.hash) {
48
+ throw new Error(`${source} must not include query parameters or fragments`);
49
+ }
50
+
51
+ url.search = "";
52
+ url.hash = "";
53
+ url.pathname = url.pathname.replace(/\/+$/, "");
54
+ return url.toString().replace(/\/+$/, "");
55
+ }
56
+
57
+ const API_REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
58
+ const API_REQUEST_BODY_HEADERS = ["Content-Encoding", "Content-Language", "Content-Location", "Content-Type"];
59
+ const MAX_API_REDIRECTS = 5;
60
+
61
+ export async function fetchWithCredentialRedirects(
62
+ url: string,
63
+ init: RequestInit,
64
+ credentialHeaders: readonly string[],
65
+ ): Promise<Response> {
66
+ let current = new URL(url);
67
+ let requestInit = init;
68
+
69
+ for (let redirects = 0; ; redirects++) {
70
+ const response = await fetch(current, { ...requestInit, redirect: "manual" });
71
+ if (!API_REDIRECT_STATUSES.has(response.status)) return response;
72
+
73
+ const location = response.headers.get("location");
74
+ if (!location) return response;
75
+ if (redirects === MAX_API_REDIRECTS) {
76
+ throw new Error(`Too many API redirects from ${url}`);
77
+ }
78
+
79
+ const next = new URL(location, current);
80
+ if (next.protocol !== "http:" && next.protocol !== "https:") {
81
+ throw new Error(`API redirect from ${current.origin} must use HTTP(S)`);
82
+ }
83
+ const method = requestInit.method?.toUpperCase() ?? "GET";
84
+ if (
85
+ ((response.status === 301 || response.status === 302) && method === "POST")
86
+ || (response.status === 303 && method !== "GET" && method !== "HEAD")
87
+ ) {
88
+ const headers = new Headers(requestInit.headers);
89
+ for (const name of API_REQUEST_BODY_HEADERS) headers.delete(name);
90
+ const { body: _body, ...withoutBody } = requestInit;
91
+ requestInit = { ...withoutBody, method: "GET", headers };
92
+ }
93
+ if (next.origin !== current.origin) {
94
+ const headers = new Headers(requestInit.headers);
95
+ for (const name of credentialHeaders) headers.delete(name);
96
+ requestInit = { ...requestInit, headers };
97
+ }
98
+ current = next;
99
+ }
100
+ }
101
+
15
102
  export interface CuratorNetworkConfig {
16
103
  /** Whether remote access was opted into via curatorRemote. */
17
104
  enabled: boolean;
@@ -0,0 +1,199 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { activityMonitor } from "./activity.ts";
3
+ import type { ExtractedContent } from "./extract.ts";
4
+ import type { SearchOptions, SearchResponse } from "./perplexity.ts";
5
+ import { hasCredentialSource, redactCredential, resolveCredential } from "./credential-source.ts";
6
+ import { getWebSearchConfigPath } from "./utils.ts";
7
+
8
+ const VALYU_SEARCH_URL = "https://api.valyu.ai/v1/search";
9
+ const CONFIG_PATH = getWebSearchConfigPath();
10
+ const SEARCH_TIMEOUT_MS = 60_000;
11
+ const MAX_SNIPPET_CHARS = 2_500;
12
+ const MAX_CONTENT_CHARS = 4_000;
13
+
14
+ interface WebSearchConfig {
15
+ valyuApiKey?: unknown;
16
+ }
17
+
18
+ interface ValyuResult {
19
+ title?: unknown;
20
+ url?: unknown;
21
+ description?: unknown;
22
+ content?: unknown;
23
+ }
24
+
25
+ let cachedConfig: WebSearchConfig | null = null;
26
+
27
+ function loadConfig(): WebSearchConfig {
28
+ if (cachedConfig) return cachedConfig;
29
+ if (!existsSync(CONFIG_PATH)) {
30
+ cachedConfig = {};
31
+ return cachedConfig;
32
+ }
33
+ const raw = readFileSync(CONFIG_PATH, "utf-8");
34
+ let parsed: unknown;
35
+ try {
36
+ parsed = JSON.parse(raw);
37
+ } catch (err) {
38
+ const message = err instanceof Error ? err.message : String(err);
39
+ throw new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);
40
+ }
41
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
42
+ throw new Error(`Invalid config in ${CONFIG_PATH}: expected a JSON object`);
43
+ }
44
+ cachedConfig = parsed as WebSearchConfig;
45
+ return cachedConfig;
46
+ }
47
+
48
+ async function getApiKey(signal?: AbortSignal): Promise<string | null> {
49
+ return resolveCredential({
50
+ provider: "Valyu",
51
+ configuredValue: loadConfig().valyuApiKey,
52
+ environmentValue: process.env.VALYU_API_KEY,
53
+ signal,
54
+ });
55
+ }
56
+
57
+ async function requireApiKey(signal?: AbortSignal): Promise<string> {
58
+ const apiKey = await getApiKey(signal);
59
+ if (!apiKey) {
60
+ throw new Error(
61
+ "Valyu API key not found. Either:\n" +
62
+ ` 1. Create ${CONFIG_PATH} with { "valyuApiKey": "your-key" }\n` +
63
+ " 2. Set VALYU_API_KEY environment variable\n" +
64
+ "Get a key at https://platform.valyu.ai",
65
+ );
66
+ }
67
+ return apiKey;
68
+ }
69
+
70
+ function normalizeCount(value: number | undefined): number {
71
+ if (typeof value !== "number" || !Number.isFinite(value)) return 5;
72
+ return Math.max(1, Math.min(Math.floor(value), 20));
73
+ }
74
+
75
+ function normalizeDomain(value: string): string | null {
76
+ let input = value.trim().toLowerCase();
77
+ if (!input) return null;
78
+ if (input.startsWith("-")) input = input.slice(1).trim();
79
+ if (!input) return null;
80
+ try {
81
+ const parsed = input.includes("://") ? new URL(input) : new URL(`https://${input}`);
82
+ input = parsed.hostname;
83
+ } catch {
84
+ input = input.split("/")[0]?.split(":")[0] ?? "";
85
+ }
86
+ input = input.replace(/^\.+|\.+$/g, "");
87
+ return /^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/i.test(input) ? input : null;
88
+ }
89
+
90
+ function mapDomainFilter(domainFilter: string[] | undefined): { included_sources?: string[]; excluded_sources?: string[] } {
91
+ if (!domainFilter?.length) return {};
92
+ const included_sources: string[] = [];
93
+ const excluded_sources: string[] = [];
94
+ for (const raw of domainFilter) {
95
+ const domain = normalizeDomain(raw);
96
+ if (!domain) continue;
97
+ const target = raw.trim().startsWith("-") ? excluded_sources : included_sources;
98
+ if (!target.includes(domain)) target.push(domain);
99
+ }
100
+ return {
101
+ ...(included_sources.length > 0 ? { included_sources } : {}),
102
+ ...(excluded_sources.length > 0 ? { excluded_sources } : {}),
103
+ };
104
+ }
105
+
106
+ function recencyToStartDate(filter: SearchOptions["recencyFilter"]): string | undefined {
107
+ if (!filter) return undefined;
108
+ const days = { day: 1, week: 7, month: 30, year: 365 }[filter];
109
+ return days ? new Date(Date.now() - days * 86_400_000).toISOString().slice(0, 10) : undefined;
110
+ }
111
+
112
+ function text(value: unknown, limit: number): string {
113
+ return typeof value === "string" ? value.replace(/\s+/g, " ").trim().slice(0, limit) : "";
114
+ }
115
+
116
+ function errorMessage(err: unknown): string {
117
+ return err instanceof Error ? err.message : String(err);
118
+ }
119
+
120
+ function invalidResponse(message: string): Error {
121
+ return new Error(`Valyu API returned invalid response: ${message}`);
122
+ }
123
+
124
+ function parseResponse(value: unknown): ValyuResult[] {
125
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw invalidResponse("expected an object envelope");
126
+ const envelope = value as Record<string, unknown>;
127
+ if (envelope.success !== true) throw invalidResponse("expected success true");
128
+ if (!Array.isArray(envelope.results)) throw invalidResponse("expected results array");
129
+ return envelope.results as ValyuResult[];
130
+ }
131
+
132
+ function buildAnswer(results: SearchResponse["results"]): string {
133
+ return results.map((result) => result.snippet
134
+ ? `${result.snippet}\nSource: ${result.title} (${result.url})`
135
+ : `Source: ${result.title} (${result.url})`).join("\n\n");
136
+ }
137
+
138
+ export function isValyuAvailable(): boolean {
139
+ return hasCredentialSource({ provider: "Valyu", configuredValue: loadConfig().valyuApiKey, environmentValue: process.env.VALYU_API_KEY });
140
+ }
141
+
142
+ export async function searchWithValyu(query: string, options: SearchOptions & { includeContent?: boolean } = {}): Promise<SearchResponse> {
143
+ const apiKey = await requireApiKey(options.signal);
144
+ const numResults = normalizeCount(options.numResults);
145
+ const startDate = recencyToStartDate(options.recencyFilter);
146
+ const activityId = activityMonitor.logStart({ type: "api", query });
147
+ let response: Response;
148
+ try {
149
+ response = await fetch(VALYU_SEARCH_URL, {
150
+ method: "POST",
151
+ headers: { "x-api-key": apiKey, "Content-Type": "application/json", Accept: "application/json" },
152
+ body: JSON.stringify({ query, max_num_results: numResults, ...mapDomainFilter(options.domainFilter), ...(startDate ? { start_date: startDate } : {}) }),
153
+ signal: options.signal ? AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS), options.signal]) : AbortSignal.timeout(SEARCH_TIMEOUT_MS),
154
+ });
155
+ } catch (err) {
156
+ const message = errorMessage(err);
157
+ const redactedMessage = redactCredential(message, apiKey);
158
+ if (redactedMessage.toLowerCase().includes("abort")) activityMonitor.logComplete(activityId, 0);
159
+ else activityMonitor.logError(activityId, redactedMessage);
160
+ if (redactedMessage === message) throw err;
161
+ const redactedError = new Error(redactedMessage);
162
+ if (err instanceof Error) redactedError.name = err.name;
163
+ throw redactedError;
164
+ }
165
+ if (!response.ok) {
166
+ activityMonitor.logComplete(activityId, response.status);
167
+ const errorText = redactCredential(await response.text(), apiKey);
168
+ throw new Error(`Valyu API error ${response.status}: ${errorText.slice(0, 300)}`);
169
+ }
170
+ let rawData: unknown;
171
+ try {
172
+ rawData = await response.json();
173
+ } catch (err) {
174
+ activityMonitor.logComplete(activityId, response.status);
175
+ throw new Error(`Valyu API returned invalid JSON: ${errorMessage(err)}`);
176
+ }
177
+ let entries: ValyuResult[];
178
+ try {
179
+ entries = parseResponse(rawData);
180
+ } catch (err) {
181
+ activityMonitor.logComplete(activityId, response.status);
182
+ throw err;
183
+ }
184
+ activityMonitor.logComplete(activityId, response.status);
185
+ const results: SearchResponse["results"] = [];
186
+ const inlineContent: ExtractedContent[] = [];
187
+ for (const entry of entries) {
188
+ if (!entry || typeof entry !== "object") continue;
189
+ const url = text(entry.url, Number.MAX_SAFE_INTEGER);
190
+ if (!url) continue;
191
+ const title = text(entry.title, Number.MAX_SAFE_INTEGER) || `Source ${results.length + 1}`;
192
+ const content = text(entry.content, MAX_CONTENT_CHARS);
193
+ const description = text(entry.description, MAX_SNIPPET_CHARS);
194
+ results.push({ title, url, snippet: (content || description).slice(0, MAX_SNIPPET_CHARS) });
195
+ if (options.includeContent && content) inlineContent.push({ url, title, content, error: null });
196
+ if (results.length >= numResults) break;
197
+ }
198
+ return { answer: buildAnswer(results), results, ...(inlineContent.length > 0 ? { inlineContent } : {}) };
199
+ }
@@ -132,7 +132,7 @@ export async function extractYouTube(
132
132
 
133
133
  const error = attemptErrors.length > 0
134
134
  ? ["Could not extract YouTube video content.", "", ...attemptErrors.map(message => `- ${message}`)].join("\n")
135
- : "Could not extract YouTube video content. Sign into Google in Chrome for automatic access, or set GEMINI_API_KEY.";
135
+ : "Could not extract YouTube video content. Sign into Google in a supported Chromium browser for automatic access, or set GEMINI_API_KEY.";
136
136
  activityMonitor.logError(activityId, error);
137
137
  return { url, title: "", content: "", error };
138
138
  }
@@ -311,7 +311,7 @@ async function tryPerplexity(
311
311
 
312
312
  const content =
313
313
  `# Video Summary (via Perplexity)\n\n${answer}\n\n` +
314
- `*Full video understanding requires Gemini access. Set GEMINI_API_KEY or sign into Google in Chrome.*`;
314
+ `*Full video understanding requires Gemini access. Set GEMINI_API_KEY or sign into Google in a supported Chromium browser.*`;
315
315
 
316
316
  return {
317
317
  url,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@herbertgao/pi-extensions",
3
- "version": "2026.8.5",
3
+ "version": "2026.8.7",
4
4
  "description": "Aggregate installer for HerbertGao-maintained Pi extensions.",
5
5
  "keywords": [
6
6
  "extensions",
@@ -38,11 +38,11 @@
38
38
  "@ast-grep/napi": "^0.45.0",
39
39
  "@czottmann/pi-automode": "1.11.0",
40
40
  "@dietrichgebert/ponytail": "4.9.0",
41
- "@earendil-works/pi-coding-agent": "^0.84.1",
42
- "@earendil-works/pi-tui": "^0.84.1",
41
+ "@earendil-works/pi-coding-agent": "^0.84.2",
42
+ "@earendil-works/pi-tui": "^0.84.2",
43
43
  "@effect/platform-node": "4.0.0-beta.103",
44
44
  "@effect/platform-node-shared": "4.0.0-beta.103",
45
- "@herbertgao/pi-cc-extensions": "0.8.54",
45
+ "@herbertgao/pi-cc-extensions": "0.8.56",
46
46
  "@herbertgao/pi-copy-response": "0.2.6",
47
47
  "@herbertgao/pi-handoff": "1.1.2",
48
48
  "@herbertgao/pi-inline-skills": "1.0.5",
@@ -51,18 +51,18 @@
51
51
  "@herbertgao/pi-recap": "0.4.4",
52
52
  "@herbertgao/pi-rename": "0.4.2",
53
53
  "@herbertgao/pi-stash": "0.1.1",
54
- "@herbertgao/pi-subagents": "0.15.4",
54
+ "@herbertgao/pi-subagents": "0.16.0",
55
55
  "@herbertgao/pi-titlebar-spinner": "0.1.3",
56
- "@juicesharp/rpiv-ask-user-question": "2.5.2",
57
- "@juicesharp/rpiv-config": "^2.5.2",
56
+ "@juicesharp/rpiv-ask-user-question": "2.6.4",
57
+ "@juicesharp/rpiv-config": "^2.6.4",
58
58
  "@modelcontextprotocol/client": "2.0.0",
59
59
  "@modelcontextprotocol/core": "2.0.0",
60
60
  "@modelcontextprotocol/ext-apps": "^1.2.2",
61
61
  "@modelcontextprotocol/sdk": "^1.29.0",
62
62
  "@mozilla/readability": "^0.6.0",
63
63
  "@napi-rs/keyring": "^1.3.0",
64
- "@narumitw/pi-btw": "0.51.0",
65
- "@narumitw/pi-tui-kit": "^0.54.0",
64
+ "@narumitw/pi-btw": "0.55.0",
65
+ "@narumitw/pi-tui-kit": "^0.56.0",
66
66
  "@noble/ed25519": "^3.1.0",
67
67
  "@pi-plugins/fast-mode": "0.1.9",
68
68
  "@shikijs/cli": "^4.0.2",
@@ -82,9 +82,9 @@
82
82
  "open": "^10.2.0",
83
83
  "p-limit": "^6.1.0",
84
84
  "pi-footer": "0.5.1",
85
- "pi-lens": "4.0.0",
86
- "pi-mcp-adapter": "2.25.0",
87
- "pi-web-access": "0.22.0",
85
+ "pi-lens": "4.1.0",
86
+ "pi-mcp-adapter": "2.27.0",
87
+ "pi-web-access": "0.24.0",
88
88
  "pidusage": "^4.0.1",
89
89
  "promise.try": "^2.0.1",
90
90
  "qrcode-terminal": "^0.12.0",
@@ -145,7 +145,7 @@
145
145
  "./node_modules/@herbertgao/pi-subagents/src/index.ts",
146
146
  "./node_modules/@herbertgao/pi-titlebar-spinner/src/index.ts",
147
147
  "./node_modules/@juicesharp/rpiv-ask-user-question/index.ts",
148
- "./node_modules/@narumitw/pi-btw/src/index.ts",
148
+ "./node_modules/@narumitw/pi-btw/dist/index.ts",
149
149
  "./node_modules/@pi-plugins/fast-mode/dist/index.mjs",
150
150
  "./node_modules/pi-mcp-adapter/index.ts",
151
151
  "./node_modules/pi-lens/dist/index.js",