@herbertgao/pi-extensions 2026.8.4 → 2026.8.6

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 (360) hide show
  1. package/README.md +5 -5
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +11 -3
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +11 -3
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +53 -14
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
  14. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  15. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +18 -0
  16. package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
  17. package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
  18. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
  19. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
  20. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +20 -4
  21. package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
  22. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
  23. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
  24. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +15 -6
  25. package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
  26. package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
  27. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +9 -5
  28. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +2 -0
  29. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +20 -0
  30. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +6 -0
  31. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
  32. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  33. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
  34. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
  35. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
  36. package/node_modules/@narumitw/pi-btw/README.md +32 -24
  37. package/node_modules/@narumitw/pi-btw/package.json +6 -6
  38. package/node_modules/@narumitw/pi-btw/src/btw.ts +4 -2
  39. package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -13
  40. package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
  41. package/node_modules/pi-lens/CHANGELOG.md +2535 -954
  42. package/node_modules/pi-lens/README.md +13 -0
  43. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
  44. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +314 -0
  45. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
  46. package/node_modules/pi-lens/dist/clients/agent-nudge.js +14 -7
  47. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
  48. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
  49. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
  50. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
  51. package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
  52. package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
  53. package/node_modules/pi-lens/dist/clients/biome-client.js +136 -24
  54. package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
  55. package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
  56. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
  57. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +62 -6
  58. package/node_modules/pi-lens/dist/clients/bus-publish.js +19 -4
  59. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
  60. package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
  61. package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
  62. package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
  63. package/node_modules/pi-lens/dist/clients/cascade-format.js +57 -2
  64. package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
  65. package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
  66. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
  67. package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
  68. package/node_modules/pi-lens/dist/clients/console-guard-install.js +26 -0
  69. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
  70. package/node_modules/pi-lens/dist/clients/dead-code-client.js +137 -31
  71. package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
  72. package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
  73. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
  74. package/node_modules/pi-lens/dist/clients/dependency-checker.js +361 -77
  75. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +65 -13
  76. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +18 -4
  77. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +176 -29
  78. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
  79. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
  80. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
  81. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
  82. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
  83. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1172 -683
  84. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
  85. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
  86. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
  87. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
  88. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +47 -6
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +226 -0
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +69 -0
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +473 -42
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +97 -0
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
  114. package/node_modules/pi-lens/dist/clients/disposition-publish.js +18 -4
  115. package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
  116. package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
  117. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
  118. package/node_modules/pi-lens/dist/clients/extension-log.js +432 -0
  119. package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
  120. package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
  121. package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
  122. package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
  123. package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
  124. package/node_modules/pi-lens/dist/clients/format-events-publish.js +51 -7
  125. package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
  126. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
  127. package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
  128. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
  129. package/node_modules/pi-lens/dist/clients/git-guard.js +678 -11
  130. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
  131. package/node_modules/pi-lens/dist/clients/go-client.js +23 -40
  132. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +124 -7
  133. package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
  134. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
  135. package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
  136. package/node_modules/pi-lens/dist/clients/installer/index.js +395 -100
  137. package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
  138. package/node_modules/pi-lens/dist/clients/jscpd-client.js +27 -55
  139. package/node_modules/pi-lens/dist/clients/knip-client.js +58 -42
  140. package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
  141. package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
  142. package/node_modules/pi-lens/dist/clients/latency-logger.js +72 -1
  143. package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
  144. package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
  145. package/node_modules/pi-lens/dist/clients/lens-events.js +63 -9
  146. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
  147. package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
  148. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +73 -0
  149. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
  150. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
  151. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +59 -14
  152. package/node_modules/pi-lens/dist/clients/lsp/client.js +662 -56
  153. package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
  154. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +115 -0
  155. package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
  156. package/node_modules/pi-lens/dist/clients/lsp/index.js +2025 -800
  157. package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
  158. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  159. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
  160. package/node_modules/pi-lens/dist/clients/lsp/server.js +437 -86
  161. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +96 -0
  162. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
  163. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +18 -3
  164. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
  165. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
  166. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
  167. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +127 -32
  168. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
  169. package/node_modules/pi-lens/dist/clients/mcp/session.js +235 -14
  170. package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
  171. package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
  172. package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
  173. package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
  174. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
  175. package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
  176. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
  177. package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
  178. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
  179. package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
  180. package/node_modules/pi-lens/dist/clients/pipeline.js +76 -15
  181. package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
  182. package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
  183. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
  184. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +1 -1
  185. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
  186. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +23 -2
  187. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
  188. package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
  189. package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
  190. package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
  191. package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
  192. package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
  193. package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
  194. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
  195. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
  196. package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
  197. package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
  198. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
  199. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
  200. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
  201. package/node_modules/pi-lens/dist/clients/review-graph/query.js +24 -0
  202. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
  203. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
  204. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
  205. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
  206. package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
  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 +257 -77
  209. package/node_modules/pi-lens/dist/clients/runtime-context.js +129 -12
  210. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +242 -26
  211. package/node_modules/pi-lens/dist/clients/runtime-session.js +428 -117
  212. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
  213. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +342 -33
  214. package/node_modules/pi-lens/dist/clients/runtime-turn.js +619 -93
  215. package/node_modules/pi-lens/dist/clients/rust-client.js +23 -38
  216. package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
  217. package/node_modules/pi-lens/dist/clients/security-scan-client.js +90 -6
  218. package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
  219. package/node_modules/pi-lens/dist/clients/sg-runner.js +424 -196
  220. package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
  221. package/node_modules/pi-lens/dist/clients/smells-rollup.js +231 -0
  222. package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
  223. package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
  224. package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
  225. package/node_modules/pi-lens/dist/clients/startup-timing.js +7 -1
  226. package/node_modules/pi-lens/dist/clients/test-runner-client.js +469 -32
  227. package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
  228. package/node_modules/pi-lens/dist/clients/tool-policy.js +390 -39
  229. package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
  230. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
  231. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
  232. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
  233. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
  234. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
  235. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
  236. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
  237. package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
  238. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
  239. package/node_modules/pi-lens/dist/clients/warm-attach.js +50 -13
  240. package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
  241. package/node_modules/pi-lens/dist/clients/word-index.js +680 -81
  242. package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
  243. package/node_modules/pi-lens/dist/index.js +51785 -36118
  244. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
  245. package/node_modules/pi-lens/dist/mcp/server.js +219 -46
  246. package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
  247. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
  248. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
  249. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
  250. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +203 -38
  251. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +210 -42
  252. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
  253. package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
  254. package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
  255. package/node_modules/pi-lens/docs/agent-guide.md +40 -15
  256. package/node_modules/pi-lens/docs/agent-tools.md +21 -10
  257. package/node_modules/pi-lens/docs/analysisall.md +192 -0
  258. package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
  259. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +14 -3
  260. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
  261. package/node_modules/pi-lens/docs/environment-variables.md +44 -0
  262. package/node_modules/pi-lens/docs/fable.md +27 -0
  263. package/node_modules/pi-lens/docs/features.md +45 -3
  264. package/node_modules/pi-lens/docs/globalconfig.md +56 -1
  265. package/node_modules/pi-lens/docs/language-coverage.md +4 -3
  266. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
  267. package/node_modules/pi-lens/docs/mcp.md +37 -4
  268. package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
  269. package/node_modules/pi-lens/docs/settings.md +18 -1
  270. package/node_modules/pi-lens/docs/tools.md +4 -1
  271. package/node_modules/pi-lens/docs/usage.md +41 -5
  272. package/node_modules/pi-lens/docs/word-index.md +35 -0
  273. package/node_modules/pi-lens/package.json +10 -10
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +8 -0
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-js-test.yml +9 -0
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -0
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +7 -0
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +7 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +8 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +8 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-laundering-test.yml +11 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
  288. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
  289. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +21 -0
  290. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml +21 -0
  291. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -0
  292. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
  293. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
  294. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +9 -0
  295. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +9 -0
  296. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +13 -0
  297. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +16 -0
  298. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +27 -0
  299. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
  300. package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
  301. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
  302. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +134 -2
  303. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +10 -11
  304. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
  305. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +8 -114
  306. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +129 -0
  307. package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
  308. package/node_modules/pi-mcp-adapter/CHANGELOG.md +38 -0
  309. package/node_modules/pi-mcp-adapter/README.md +38 -4
  310. package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
  311. package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
  312. package/node_modules/pi-mcp-adapter/cli.js +25 -4
  313. package/node_modules/pi-mcp-adapter/commands.ts +15 -7
  314. package/node_modules/pi-mcp-adapter/config.ts +4 -4
  315. package/node_modules/pi-mcp-adapter/direct-tools.ts +58 -8
  316. package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
  317. package/node_modules/pi-mcp-adapter/index.ts +8 -3
  318. package/node_modules/pi-mcp-adapter/init.ts +29 -5
  319. package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
  320. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
  321. package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
  322. package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
  323. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
  324. package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +2 -1
  325. package/node_modules/pi-mcp-adapter/metadata-cache.ts +37 -4
  326. package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
  327. package/node_modules/pi-mcp-adapter/package.json +4 -3
  328. package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
  329. package/node_modules/pi-mcp-adapter/request-headers-command.ts +336 -0
  330. package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
  331. package/node_modules/pi-mcp-adapter/server-manager.ts +41 -7
  332. package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
  333. package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
  334. package/node_modules/pi-mcp-adapter/tool-metadata.ts +62 -4
  335. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
  336. package/node_modules/pi-mcp-adapter/types.ts +176 -27
  337. package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
  338. package/node_modules/pi-web-access/CHANGELOG.md +14 -0
  339. package/node_modules/pi-web-access/README.md +18 -12
  340. package/node_modules/pi-web-access/auth-fetch.ts +148 -0
  341. package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
  342. package/node_modules/pi-web-access/curator-page.ts +5 -3
  343. package/node_modules/pi-web-access/curator-server.ts +2 -1
  344. package/node_modules/pi-web-access/extract.ts +106 -34
  345. package/node_modules/pi-web-access/fetch-params.ts +17 -3
  346. package/node_modules/pi-web-access/firecrawl.ts +172 -12
  347. package/node_modules/pi-web-access/gemini-search.ts +18 -4
  348. package/node_modules/pi-web-access/index.ts +120 -48
  349. package/node_modules/pi-web-access/package.json +2 -2
  350. package/node_modules/pi-web-access/summary-review.ts +11 -5
  351. package/node_modules/pi-web-access/youtube-extract.ts +2 -2
  352. package/package.json +12 -13
  353. package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
  354. package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
  355. package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
  356. package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
  357. package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
  358. package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
  359. package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
  360. package/node_modules/pi-lens/dist/clients/types.js +0 -11
@@ -4,6 +4,7 @@ import { Type } from "typebox";
4
4
  import { StringEnum, complete, type Api, type ImageContent, type Model, type TextContent } from "@earendil-works/pi-ai/compat";
5
5
  import type { ExtractedContent, ExtractOptions } from "./extract.ts";
6
6
  import { normalizeFetchContentParams } from "./fetch-params.ts";
7
+ import { resolveAuthFetchProfile, type AuthFetchProfile } from "./auth-fetch.ts";
7
8
  import { findContent, type FindMode } from "./content-find.ts";
8
9
  import { answerFromPage } from "./page-query.ts";
9
10
  import { clearCloneCache } from "./github-extract.ts";
@@ -50,6 +51,7 @@ import { isSearch1APIAvailable } from "./search1api.ts";
50
51
  import { isSearchinfinityAvailable } from "./searchinfinity.ts";
51
52
  import { isQueritAvailable } from "./querit.ts";
52
53
  import { isTavilyAvailable } from "./tavily.ts";
54
+ import { isFirecrawlAvailable } from "./firecrawl.ts";
53
55
  import { isJinaSearchAvailable } from "./jina-search.ts";
54
56
  import { isSerpdiveAvailable } from "./serpdive.ts";
55
57
  import { isKagiAvailable } from "./kagi.ts";
@@ -154,6 +156,7 @@ interface ProviderAvailability {
154
156
  searchinfinity: boolean;
155
157
  querit: boolean;
156
158
  tavily: boolean;
159
+ firecrawl: boolean;
157
160
  jina: boolean;
158
161
  serpdive: boolean;
159
162
  searxng: boolean;
@@ -384,6 +387,7 @@ async function getProviderAvailability(ctx: ExtensionContext): Promise<ProviderA
384
387
  searchinfinity: isSearchinfinityAvailable(),
385
388
  querit: isQueritAvailable(),
386
389
  tavily: isTavilyAvailable(),
390
+ firecrawl: isFirecrawlAvailable(),
387
391
  jina: isJinaSearchAvailable(),
388
392
  serpdive: isSerpdiveAvailable(),
389
393
  kagi: isKagiAvailable(),
@@ -441,6 +445,7 @@ function firstAvailableProvider(available: ProviderAvailability, preferOpenAI: b
441
445
  if (available.searchinfinity) return "searchinfinity";
442
446
  if (available.querit) return "querit";
443
447
  if (available.tavily) return "tavily";
448
+ if (available.firecrawl) return "firecrawl";
444
449
  if (available.jina) return "jina";
445
450
  if (available.serpdive) return "serpdive";
446
451
  if (available.kagi) return "kagi";
@@ -496,6 +501,9 @@ function resolveProvider(
496
501
  if (provider === "tavily" && !available.tavily) {
497
502
  return firstAvailableProvider(available, preferOpenAI, "tavily");
498
503
  }
504
+ if (provider === "firecrawl" && !available.firecrawl) {
505
+ return firstAvailableProvider(available, preferOpenAI, "firecrawl");
506
+ }
499
507
  if (provider === "jina" && !available.jina) {
500
508
  return firstAvailableProvider(available, preferOpenAI, "jina");
501
509
  }
@@ -566,8 +574,8 @@ interface PendingCurate {
566
574
  const DEFAULT_MAX_INLINE_CONTENT_CHARS = 30_000;
567
575
  const MAX_INLINE_CONTENT_CHARS = 200_000;
568
576
 
569
- function getMaxInlineContentChars(): number {
570
- const value = loadConfig().maxInlineContentChars;
577
+ function getMaxInlineContentChars(config = loadConfig()): number {
578
+ const value = config.maxInlineContentChars;
571
579
  if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {
572
580
  return DEFAULT_MAX_INLINE_CONTENT_CHARS;
573
581
  }
@@ -578,6 +586,12 @@ function stripThumbnails(results: ExtractedContent[]): ExtractedContent[] {
578
586
  return results.map(({ thumbnail, frames, ...rest }) => rest);
579
587
  }
580
588
 
589
+ function storeFetchResult(pi: { appendEntry(type: string, data: unknown): void }, responseId: string, data: StoredSearchData & { type: "fetch"; urls: ExtractedContent[] }, authProfile?: AuthFetchProfile): boolean {
590
+ if (authProfile?.cache === "off") return false;
591
+ pi.appendEntry("web-search-results", storeFetchedContentResult(responseId, data));
592
+ return true;
593
+ }
594
+
581
595
  function initialContentSlice(content: string, maxChars: number): {
582
596
  text: string;
583
597
  endOffset: number;
@@ -608,6 +622,17 @@ function normalizeFindQueries(value: string | string[]): string[] {
608
622
  return queries;
609
623
  }
610
624
 
625
+ function formatInputValue(value: unknown): string {
626
+ if (typeof value === "string") return JSON.stringify(value);
627
+ if (typeof value === "number") return Number.isNaN(value) ? "NaN" : String(value);
628
+ try {
629
+ const serialized = JSON.stringify(value);
630
+ return serialized === undefined ? String(value) : serialized;
631
+ } catch {
632
+ return String(value);
633
+ }
634
+ }
635
+
611
636
  function formatSearchSummary(results: SearchResult[], answer: string): string {
612
637
  if (results.length === 0) {
613
638
  return answer ? `${answer}\n\n---\n\n**Sources:**\nNo sources returned.` : "No results found.";
@@ -1636,13 +1661,13 @@ export default function (pi: ExtensionAPI) {
1636
1661
  name: toolNames.webSearch,
1637
1662
  label: "Web Search",
1638
1663
  description:
1639
- `Search the web using OpenAI, Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Jina, SERPdive, Kagi, Bocha, Ollama, SearXNG, DuckDuckGo, Exa, Perplexity, Gemini, AnySearch, xAI, Bright Data, or SerpBase. Pass a provider array to search only those providers simultaneously, or use provider "all" to search every eligible provider except DuckDuckGo, AnySearch, xAI, Bright Data, and SerpBase. Returns an AI-synthesized answer with source citations. OpenAI search uses a Codex subscription or OpenAI API key; xAI search uses a SuperGrok/X Premium subscription or xAI API key. DuckDuckGo, AnySearch, xAI, Bright Data, and SerpBase are available only when explicitly selected. For comprehensive research, prefer queries (plural) with 2-4 varied angles over a single query — each query gets its own synthesized answer, so varying phrasing and scope gives much broader coverage. When includeContent is true, full page content is fetched in the background. Searches auto-open the interactive browser curator and stream results live; set workflow to "none" to skip curation or "auto-summary" for a model-generated summary without the browser curator. The configured provider is used when provider is omitted or set to auto; omit provider unless explicitly overriding it. Without a configured provider, auto-selects OpenAI when suitable and available, then Exa, Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Jina, SERPdive, Kagi, Bocha, Ollama, Perplexity, Gemini API, or Gemini Web. When SearXNG is configured, it is preferred first for local/private search.`,
1664
+ `Search the web using OpenAI, Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Kagi, Bocha, Ollama, SearXNG, DuckDuckGo, Exa, Perplexity, Gemini, AnySearch, xAI, Bright Data, or SerpBase. Pass a provider array to search only those providers simultaneously, or use provider "all" to search every eligible provider except DuckDuckGo, AnySearch, xAI, Bright Data, and SerpBase. Returns an AI-synthesized answer with source citations. OpenAI search uses a Codex subscription or OpenAI API key; xAI search uses a SuperGrok/X Premium subscription or xAI API key. DuckDuckGo, AnySearch, xAI, Bright Data, and SerpBase are available only when explicitly selected. For comprehensive research, prefer queries (plural) with 2-4 varied angles over a single query — each query gets its own synthesized answer, so varying phrasing and scope gives much broader coverage. When includeContent is true, full page content is fetched in the background. Searches auto-open the interactive browser curator and stream results live; set workflow to "none" to skip curation or "auto-summary" for a model-generated summary without the browser curator. The configured provider is used when provider is omitted or set to auto; omit provider unless explicitly overriding it. Without a configured provider, auto-selects OpenAI when suitable and available, then Exa, Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Kagi, Bocha, Ollama, Perplexity, Gemini API, or Gemini Web. When SearXNG is configured, it is preferred first for local/private search.`,
1640
1665
  promptSnippet:
1641
1666
  "Use for web research questions. Prefer {queries:[...]} with 2-4 varied angles over a single query for broader coverage. Omit provider unless explicitly overriding the configured default.",
1642
1667
  parameters: Type.Object({
1643
1668
  query: Type.Optional(Type.String({ description: "Single search query. For research tasks, prefer 'queries' with multiple varied angles instead." })),
1644
1669
  queries: Type.Optional(Type.Array(Type.String(), { description: "Multiple queries searched in sequence, each returning its own synthesized answer. Prefer this for research — vary phrasing, scope, and angle across 2-4 queries to maximize coverage. Good: ['React vs Vue performance benchmarks 2026', 'React vs Vue developer experience comparison', 'React ecosystem size vs Vue ecosystem']. Bad: ['React vs Vue', 'React vs Vue comparison', 'React vs Vue review'] (too similar, redundant results)." })),
1645
- numResults: Type.Optional(Type.Number({ description: "Results per query (default: 5, max: 20)" })),
1670
+ numResults: Type.Optional(Type.Integer({ minimum: 1, maximum: 20, description: "Results per query (default: 5, max: 20)" })),
1646
1671
  includeContent: Type.Optional(Type.Boolean({ description: "Fetch full page content (async)" })),
1647
1672
  recencyFilter: Type.Optional(
1648
1673
  StringEnum(["day", "week", "month", "year"], { description: "Filter by recency" }),
@@ -2212,7 +2237,7 @@ export default function (pi: ExtensionAPI) {
2212
2237
  parameters: Type.Object({
2213
2238
  claim: Type.String({ description: "The assertion to check against web sources." }),
2214
2239
  queries: Type.Optional(Type.Array(Type.String(), { description: "Search queries (default: the claim)." })),
2215
- numResults: Type.Optional(Type.Number({ description: "Results per query (default: 5, max: 20)." })),
2240
+ numResults: Type.Optional(Type.Integer({ minimum: 1, maximum: 20, description: "Results per query (default: 5, max: 20)." })),
2216
2241
  fetchContent: Type.Optional(Type.Boolean({ description: "Fetch up to 5 result pages for exact passage extraction." })),
2217
2242
  recencyFilter: Type.Optional(StringEnum(["day", "week", "month", "year"], { description: "Filter by recency." })),
2218
2243
  domainFilter: Type.Optional(Type.Array(Type.String(), { description: "Limit to domains; prefix with - to exclude." })),
@@ -2330,6 +2355,9 @@ export default function (pi: ExtensionAPI) {
2330
2355
  model: Type.Optional(Type.String({
2331
2356
  description: "Override the Gemini model for video/YouTube analysis (e.g. 'gemini-3.6-flash'). Defaults to config or gemini-3.6-flash.",
2332
2357
  })),
2358
+ auth: Type.Optional(Type.Union([Type.String(), Type.Boolean()], {
2359
+ description: "Opt into an authFetch profile for local browser-cookie fetching. Use a profile name, or true only when exactly one profile exists.",
2360
+ })),
2333
2361
  }),
2334
2362
 
2335
2363
  async execute(_toolCallId, params, signal, onUpdate, ctx): Promise<AgentToolResult<Record<string, unknown>>> {
@@ -2354,6 +2382,18 @@ export default function (pi: ExtensionAPI) {
2354
2382
  if (mode === "answer" && options.model) {
2355
2383
  return { content: [{ type: "text", text: "Error: use answerModel, not model, with mode answer." }], details: { error: "model is incompatible with mode answer" } };
2356
2384
  }
2385
+ if (mode === "answer" && options.auth !== undefined) {
2386
+ return { content: [{ type: "text", text: "Error: auth cannot be combined with mode answer." }], details: { error: "auth cannot be combined with mode answer" } };
2387
+ }
2388
+ let authFetchProfile: AuthFetchProfile | undefined;
2389
+ if (options.auth !== undefined) {
2390
+ try {
2391
+ authFetchProfile = resolveAuthFetchProfile(options.auth);
2392
+ } catch (err) {
2393
+ const error = err instanceof Error ? err.message : String(err);
2394
+ return { content: [{ type: "text", text: `Error: ${error}` }], details: { error } };
2395
+ }
2396
+ }
2357
2397
  if (urlList.length === 0) {
2358
2398
  return {
2359
2399
  content: [{ type: "text", text: "Error: No URL provided." }],
@@ -2366,13 +2406,13 @@ export default function (pi: ExtensionAPI) {
2366
2406
  details: { phase: "fetch", progress: 0 },
2367
2407
  });
2368
2408
 
2369
- const { answerModel: _answerModel, ...extractionOptions } = options;
2409
+ const { answerModel: _answerModel, auth: _auth, ...extractionOptions } = options;
2370
2410
  const fetchOptions = mode === "answer"
2371
2411
  ? (() => {
2372
2412
  const { prompt: _prompt, ...rest } = extractionOptions;
2373
- return rest;
2413
+ return { ...rest, ...(authFetchProfile ? { authFetchProfile } : {}) };
2374
2414
  })()
2375
- : extractionOptions;
2415
+ : { ...extractionOptions, ...(authFetchProfile ? { authFetchProfile } : {}) };
2376
2416
  const fetchResults = await fetchAllContent(urlList, signal, fetchOptions);
2377
2417
  const presentedResults = mode === "answer"
2378
2418
  ? await Promise.all(fetchResults.map(async result => {
@@ -2396,7 +2436,6 @@ export default function (pi: ExtensionAPI) {
2396
2436
  const successful = presentedResults.filter((r) => !r.error).length;
2397
2437
  const totalChars = presentedResults.reduce((sum, r) => sum + r.content.length, 0);
2398
2438
 
2399
- // ALWAYS store results (even for single URL)
2400
2439
  const responseId = generateId();
2401
2440
  const data = {
2402
2441
  id: responseId,
@@ -2404,7 +2443,7 @@ export default function (pi: ExtensionAPI) {
2404
2443
  timestamp: Date.now(),
2405
2444
  urls: stripThumbnails(fetchResults),
2406
2445
  } satisfies StoredSearchData & { type: "fetch"; urls: ExtractedContent[] };
2407
- pi.appendEntry("web-search-results", storeFetchedContentResult(responseId, data));
2446
+ const storedContent = storeFetchResult(pi, responseId, data, authFetchProfile);
2408
2447
 
2409
2448
  // Single URL: return content directly (possibly truncated) with responseId
2410
2449
  if (urlList.length === 1) {
@@ -2412,7 +2451,7 @@ export default function (pi: ExtensionAPI) {
2412
2451
  if (result.error) {
2413
2452
  return {
2414
2453
  content: [{ type: "text", text: `Error: ${result.error}` }],
2415
- details: { urls: urlList, urlCount: 1, successful: 0, error: result.error, responseId, prompt: params.prompt, timestamp: params.timestamp, frames: params.frames },
2454
+ details: { urls: urlList, urlCount: 1, successful: 0, error: result.error, ...(storedContent ? { responseId } : {}), prompt: params.prompt, timestamp: params.timestamp, frames: params.frames },
2416
2455
  };
2417
2456
  }
2418
2457
 
@@ -2423,9 +2462,11 @@ export default function (pi: ExtensionAPI) {
2423
2462
 
2424
2463
  if (truncated) {
2425
2464
  output += `\n\n---\nShowing ${slice.endOffset} of ${fullLength} chars, ${slice.shownBytes} of ${slice.totalBytes} bytes, and ${slice.shownLines} of ${slice.totalLines} lines. `;
2426
- output += getSearchContentEnabled
2427
- ? `Use ${toolNames.getSearchContent}({ responseId: "${responseId}", urlIndex: 0, offset: ${slice.endOffset} }) for the next slice.`
2428
- : "Content retrieval is not registered.";
2465
+ output += storedContent
2466
+ ? getSearchContentEnabled
2467
+ ? `Use ${toolNames.getSearchContent}({ responseId: "${responseId}", urlIndex: 0, offset: ${slice.endOffset} }) for the next slice.`
2468
+ : "Content retrieval is not registered."
2469
+ : "Authenticated fetch cache is off; repeat the fetch to read more.";
2429
2470
  }
2430
2471
 
2431
2472
  const content: Array<TextContent | ImageContent> = [];
@@ -2448,7 +2489,7 @@ export default function (pi: ExtensionAPI) {
2448
2489
  successful: 1,
2449
2490
  totalChars: fullLength,
2450
2491
  title: result.title,
2451
- responseId,
2492
+ ...(storedContent ? { responseId } : {}),
2452
2493
  truncated,
2453
2494
  hasImage: imageCount > 0,
2454
2495
  imageCount,
@@ -2476,19 +2517,21 @@ export default function (pi: ExtensionAPI) {
2476
2517
  output += `- ${title || url} (${content.length} chars)\n`;
2477
2518
  }
2478
2519
  }
2479
- output += getSearchContentEnabled
2480
- ? `\n---\nUse ${toolNames.getSearchContent}({ responseId: "${responseId}", urlIndex: 0 }) to retrieve bounded content slices.`
2481
- : "\n---\nContent retrieval is not registered.";
2520
+ output += storedContent
2521
+ ? getSearchContentEnabled
2522
+ ? `\n---\nUse ${toolNames.getSearchContent}({ responseId: "${responseId}", urlIndex: 0 }) to retrieve bounded content slices.`
2523
+ : "\n---\nContent retrieval is not registered."
2524
+ : "\n---\nAuthenticated fetch cache is off; repeat the fetch to read content.";
2482
2525
 
2483
2526
  return {
2484
2527
  content: [{ type: "text", text: output }],
2485
- details: { urls: urlList, urlCount: urlList.length, successful, totalChars, responseId },
2528
+ details: { urls: urlList, urlCount: urlList.length, successful, totalChars, ...(storedContent ? { responseId } : {}) },
2486
2529
  };
2487
2530
  },
2488
2531
 
2489
2532
  renderCall(args, theme) {
2490
2533
  const { urlList, options } = normalizeFetchContentParams(args);
2491
- const { prompt, timestamp, frames, model, mode, answerModel } = options;
2534
+ const { prompt, timestamp, frames, model, mode, answerModel, auth } = options;
2492
2535
  if (urlList.length === 0) {
2493
2536
  return new Text(theme.fg("toolTitle", theme.bold("fetch ")) + theme.fg("error", "(no URL)"), 0, 0);
2494
2537
  }
@@ -2525,6 +2568,9 @@ export default function (pi: ExtensionAPI) {
2525
2568
  if (answerModel) {
2526
2569
  lines.push(theme.fg("dim", " answer model: ") + theme.fg("warning", answerModel));
2527
2570
  }
2571
+ if (auth !== undefined) {
2572
+ lines.push(theme.fg("dim", " auth: ") + theme.fg("warning", auth === true ? "true" : auth));
2573
+ }
2528
2574
  return new Text(lines.join("\n"), 0, 0);
2529
2575
  },
2530
2576
 
@@ -2616,7 +2662,9 @@ export default function (pi: ExtensionAPI) {
2616
2662
  },
2617
2663
  });
2618
2664
 
2619
- if (getSearchContentEnabled) pi.registerTool({
2665
+ if (getSearchContentEnabled) {
2666
+ const maxInlineContentChars = getMaxInlineContentChars(initConfig);
2667
+ pi.registerTool({
2620
2668
  name: toolNames.getSearchContent,
2621
2669
  label: "Get Search Content",
2622
2670
  description: `Retrieve bounded content slices or find matching passages in a previous ${storedContentSources} call.`,
@@ -2625,11 +2673,11 @@ export default function (pi: ExtensionAPI) {
2625
2673
  parameters: Type.Object({
2626
2674
  responseId: Type.String({ description: `The responseId from ${storedContentSources}` }),
2627
2675
  query: Type.Optional(Type.String({ description: searchQueryDescription })),
2628
- queryIndex: Type.Optional(Type.Number({ description: "Get content for query at index" })),
2676
+ queryIndex: Type.Optional(Type.Integer({ minimum: 0, description: "Get content for query at index" })),
2629
2677
  url: Type.Optional(Type.String({ description: "Get content for this URL" })),
2630
- urlIndex: Type.Optional(Type.Number({ description: "Get content for URL at index" })),
2631
- offset: Type.Optional(Type.Number({ description: "Character offset for fetched URL content slices (default 0). Cannot be combined with findText." })),
2632
- limit: Type.Optional(Type.Number({ description: "Maximum characters to return for fetched URL content slices (default and max are set by maxInlineContentChars). Cannot be combined with findText." })),
2678
+ urlIndex: Type.Optional(Type.Integer({ minimum: 0, description: "Get content for URL at index" })),
2679
+ offset: Type.Optional(Type.Integer({ minimum: 0, description: "Character offset for fetched URL content slices (default 0). Cannot be combined with findText." })),
2680
+ limit: Type.Optional(Type.Integer({ minimum: 1, maximum: maxInlineContentChars, description: "Maximum characters to return for fetched URL content slices (default and max are set by maxInlineContentChars). Cannot be combined with findText." })),
2633
2681
  findText: Type.Optional(Type.Union([
2634
2682
  Type.String({ minLength: 1, maxLength: 500 }),
2635
2683
  Type.Array(Type.String({ minLength: 1, maxLength: 500 }), { minItems: 1, maxItems: 10 }),
@@ -2639,15 +2687,23 @@ export default function (pi: ExtensionAPI) {
2639
2687
 
2640
2688
  async execute(_toolCallId, params): Promise<AgentToolResult<Record<string, unknown>>> {
2641
2689
  if (params.findText !== undefined && (params.offset !== undefined || params.limit !== undefined)) {
2642
- return { content: [{ type: "text", text: "findText cannot be combined with offset or limit" }], details: { error: "Incompatible find options" } };
2690
+ const offset = formatInputValue(params.offset);
2691
+ const limit = formatInputValue(params.limit);
2692
+ return {
2693
+ content: [{ type: "text", text: `findText cannot be combined with offset or limit. Received offset=${offset}, limit=${limit}; omit offset and limit when using findText.` }],
2694
+ details: { error: "Incompatible find options" },
2695
+ };
2643
2696
  }
2644
2697
  if (params.findMode !== undefined && params.findText === undefined) {
2645
- return { content: [{ type: "text", text: "findMode requires findText" }], details: { error: "findMode requires findText" } };
2698
+ return {
2699
+ content: [{ type: "text", text: `findMode ${formatInputValue(params.findMode)} requires findText; provide findText or omit findMode.` }],
2700
+ details: { error: "findMode requires findText" },
2701
+ };
2646
2702
  }
2647
2703
  const data = getResult(params.responseId);
2648
2704
  if (!data) {
2649
2705
  return {
2650
- content: [{ type: "text", text: `Error: No stored results for "${params.responseId}"` }],
2706
+ content: [{ type: "text", text: `Error: No stored results for responseId ${formatInputValue(params.responseId)}. Use a responseId returned by ${storedContentSources}.` }],
2651
2707
  details: { error: "Not found", responseId: params.responseId },
2652
2708
  };
2653
2709
  }
@@ -2656,22 +2712,30 @@ export default function (pi: ExtensionAPI) {
2656
2712
  const artifact = getResearchArtifact(params.responseId);
2657
2713
  if (!artifact) {
2658
2714
  return {
2659
- content: [{ type: "text", text: `Error: artifact ${params.responseId} not found` }],
2715
+ content: [{ type: "text", text: `Error: stored research artifact for responseId ${formatInputValue(params.responseId)} was not found. Use a responseId returned by ${storedContentSources}.` }],
2660
2716
  details: { error: "Artifact not found", responseId: params.responseId },
2661
2717
  };
2662
2718
  }
2663
2719
  const serialized = JSON.stringify(artifact, null, 2);
2664
- const maxInlineContentChars = getMaxInlineContentChars();
2665
2720
  const offset = params.offset ?? 0;
2666
2721
  const limit = params.limit ?? maxInlineContentChars;
2667
2722
  if (!Number.isInteger(offset) || offset < 0) {
2668
- return { content: [{ type: "text", text: "offset must be a non-negative integer" }], details: { error: "Invalid offset", offset } };
2723
+ return {
2724
+ content: [{ type: "text", text: `Invalid offset: received ${formatInputValue(offset)} for responseId ${formatInputValue(params.responseId)}; offset must be a non-negative integer. Use 0 or a larger integer.` }],
2725
+ details: { error: "Invalid offset", offset },
2726
+ };
2669
2727
  }
2670
2728
  if (!Number.isInteger(limit) || limit <= 0 || limit > maxInlineContentChars) {
2671
- return { content: [{ type: "text", text: `limit must be an integer from 1 to ${maxInlineContentChars}` }], details: { error: "Invalid limit", limit, maxLimit: maxInlineContentChars } };
2729
+ return {
2730
+ content: [{ type: "text", text: `Invalid limit: received ${formatInputValue(limit)} for responseId ${formatInputValue(params.responseId)}; limit must be an integer from 1 to ${maxInlineContentChars}. Use a value in that range.` }],
2731
+ details: { error: "Invalid limit", limit, maxLimit: maxInlineContentChars },
2732
+ };
2672
2733
  }
2673
2734
  if (offset > serialized.length) {
2674
- return { content: [{ type: "text", text: `offset ${offset} is out of range (0-${serialized.length})` }], details: { error: "Offset out of range", offset, contentLength: serialized.length } };
2735
+ return {
2736
+ content: [{ type: "text", text: `Offset ${offset} is out of range for responseId ${formatInputValue(params.responseId)}. Received offset ${offset}; valid range is 0-${serialized.length}. Use an offset within that range.` }],
2737
+ details: { error: "Offset out of range", offset, contentLength: serialized.length },
2738
+ };
2675
2739
  }
2676
2740
  const endOffset = Math.min(offset + limit, serialized.length);
2677
2741
  const artifactSlice = serialized.slice(offset, endOffset);
@@ -2690,29 +2754,30 @@ export default function (pi: ExtensionAPI) {
2690
2754
  if (!queryData) {
2691
2755
  const available = data.queries.map((q) => `"${q.query}"`).join(", ");
2692
2756
  return {
2693
- content: [{ type: "text", text: `Query "${params.query}" not found. Available: ${available}` }],
2757
+ content: [{ type: "text", text: `Query ${formatInputValue(params.query)} was not found for responseId ${formatInputValue(params.responseId)}. Received query=${formatInputValue(params.query)}. Available queries: ${available || "none"}. Use one of the available queries or queryIndex.` }],
2694
2758
  details: { error: "Query not found" },
2695
2759
  };
2696
2760
  }
2697
2761
  } else if (params.queryIndex !== undefined) {
2698
2762
  queryData = data.queries[params.queryIndex];
2699
2763
  if (!queryData) {
2764
+ const available = data.queries.map((q, i) => `${i}: "${q.query}"`).join(", ");
2700
2765
  return {
2701
- content: [{ type: "text", text: `Index ${params.queryIndex} out of range (0-${data.queries.length - 1})` }],
2766
+ content: [{ type: "text", text: `Query index ${formatInputValue(params.queryIndex)} is out of range for responseId ${formatInputValue(params.responseId)}. Received queryIndex=${formatInputValue(params.queryIndex)}; valid indexes are 0-${data.queries.length - 1}. Available queries: ${available || "none"}. Use one of the available indexes.` }],
2702
2767
  details: { error: "Index out of range" },
2703
2768
  };
2704
2769
  }
2705
2770
  } else {
2706
2771
  const available = data.queries.map((q, i) => `${i}: "${q.query}"`).join(", ");
2707
2772
  return {
2708
- content: [{ type: "text", text: `Specify query or queryIndex. Available: ${available}` }],
2773
+ content: [{ type: "text", text: `Specify query or queryIndex for responseId ${formatInputValue(params.responseId)}. Available queries: ${available || "none"}.` }],
2709
2774
  details: { error: "No query specified" },
2710
2775
  };
2711
2776
  }
2712
2777
 
2713
2778
  if (queryData.error) {
2714
2779
  return {
2715
- content: [{ type: "text", text: `Error for "${queryData.query}": ${queryData.error}` }],
2780
+ content: [{ type: "text", text: `Error retrieving query ${formatInputValue(queryData.query)} from responseId ${formatInputValue(params.responseId)}: ${queryData.error}. Check the stored search result and retry with another query or queryIndex if needed.` }],
2716
2781
  details: { error: queryData.error, query: queryData.query },
2717
2782
  };
2718
2783
  }
@@ -2728,7 +2793,10 @@ export default function (pi: ExtensionAPI) {
2728
2793
  };
2729
2794
  } catch (err) {
2730
2795
  const error = err instanceof Error ? err.message : String(err);
2731
- return { content: [{ type: "text", text: error }], details: { error, query: queryData.query } };
2796
+ return {
2797
+ content: [{ type: "text", text: `Unable to find ${formatInputValue(params.findText)} in query ${formatInputValue(queryData.query)} for responseId ${formatInputValue(params.responseId)}: ${error}. Check findText and use a supported findMode.` }],
2798
+ details: { error, query: queryData.query },
2799
+ };
2732
2800
  }
2733
2801
  }
2734
2802
 
@@ -2748,7 +2816,7 @@ export default function (pi: ExtensionAPI) {
2748
2816
  if (!urlData) {
2749
2817
  const available = data.urls.map((u) => u.url).join("\n ");
2750
2818
  return {
2751
- content: [{ type: "text", text: `URL not found. Available:\n ${available}` }],
2819
+ content: [{ type: "text", text: `URL ${formatInputValue(params.url)} was not found for responseId ${formatInputValue(params.responseId)}. Received url=${formatInputValue(params.url)}. Available URLs:\n ${available || " none"}\nUse one of the available URLs or urlIndex.` }],
2752
2820
  details: { error: "URL not found" },
2753
2821
  };
2754
2822
  }
@@ -2756,22 +2824,23 @@ export default function (pi: ExtensionAPI) {
2756
2824
  selectedUrlIndex = params.urlIndex;
2757
2825
  urlData = data.urls[selectedUrlIndex];
2758
2826
  if (!urlData) {
2827
+ const available = data.urls.map((u, i) => `${i}: ${u.url}`).join("\n ");
2759
2828
  return {
2760
- content: [{ type: "text", text: `Index ${params.urlIndex} out of range (0-${data.urls.length - 1})` }],
2829
+ content: [{ type: "text", text: `URL index ${formatInputValue(params.urlIndex)} is out of range for responseId ${formatInputValue(params.responseId)}. Received urlIndex=${formatInputValue(params.urlIndex)}; valid indexes are 0-${data.urls.length - 1}. Available URLs:\n ${available || " none"}\nUse one of the available indexes.` }],
2761
2830
  details: { error: "Index out of range" },
2762
2831
  };
2763
2832
  }
2764
2833
  } else {
2765
2834
  const available = data.urls.map((u, i) => `${i}: ${u.url}`).join("\n ");
2766
2835
  return {
2767
- content: [{ type: "text", text: `Specify url or urlIndex. Available:\n ${available}` }],
2836
+ content: [{ type: "text", text: `Specify url or urlIndex for responseId ${formatInputValue(params.responseId)}. Available URLs:\n ${available || " none"}` }],
2768
2837
  details: { error: "No URL specified" },
2769
2838
  };
2770
2839
  }
2771
2840
 
2772
2841
  if (urlData.error) {
2773
2842
  return {
2774
- content: [{ type: "text", text: `Error for ${urlData.url}: ${urlData.error}` }],
2843
+ content: [{ type: "text", text: `Error retrieving URL ${formatInputValue(urlData.url)} from responseId ${formatInputValue(params.responseId)}: ${urlData.error}. Check the stored fetch result and retry with another URL or urlIndex if needed.` }],
2775
2844
  details: { error: urlData.error, url: urlData.url },
2776
2845
  };
2777
2846
  }
@@ -2786,28 +2855,30 @@ export default function (pi: ExtensionAPI) {
2786
2855
  };
2787
2856
  } catch (err) {
2788
2857
  const error = err instanceof Error ? err.message : String(err);
2789
- return { content: [{ type: "text", text: error }], details: { error, url: urlData.url } };
2858
+ return {
2859
+ content: [{ type: "text", text: `Unable to find ${formatInputValue(params.findText)} in URL ${formatInputValue(urlData.url)} for responseId ${formatInputValue(params.responseId)}: ${error}. Check findText and use a supported findMode.` }],
2860
+ details: { error, url: urlData.url },
2861
+ };
2790
2862
  }
2791
2863
  }
2792
2864
 
2793
- const maxInlineContentChars = getMaxInlineContentChars();
2794
2865
  const offset = params.offset ?? 0;
2795
2866
  const limit = params.limit ?? maxInlineContentChars;
2796
2867
  if (!Number.isInteger(offset) || offset < 0) {
2797
2868
  return {
2798
- content: [{ type: "text", text: "offset must be a non-negative integer" }],
2869
+ content: [{ type: "text", text: `Invalid offset: received ${formatInputValue(offset)} for URL ${formatInputValue(urlData.url)}; offset must be a non-negative integer. Use 0 or a larger integer.` }],
2799
2870
  details: { error: "Invalid offset", offset },
2800
2871
  };
2801
2872
  }
2802
2873
  if (!Number.isInteger(limit) || limit <= 0 || limit > maxInlineContentChars) {
2803
2874
  return {
2804
- content: [{ type: "text", text: `limit must be an integer from 1 to ${maxInlineContentChars}` }],
2875
+ content: [{ type: "text", text: `Invalid limit: received ${formatInputValue(limit)} for URL ${formatInputValue(urlData.url)}; limit must be an integer from 1 to ${maxInlineContentChars}. Use a value in that range.` }],
2805
2876
  details: { error: "Invalid limit", limit, maxLimit: maxInlineContentChars },
2806
2877
  };
2807
2878
  }
2808
2879
  if (offset > urlData.content.length) {
2809
2880
  return {
2810
- content: [{ type: "text", text: `offset ${offset} is out of range (0-${urlData.content.length})` }],
2881
+ content: [{ type: "text", text: `Offset ${offset} is out of range for URL ${formatInputValue(urlData.url)} in responseId ${formatInputValue(params.responseId)}. Received offset ${offset}; valid range is 0-${urlData.content.length}. Use an offset within that range.` }],
2811
2882
  details: { error: "Offset out of range", offset, contentLength: urlData.content.length },
2812
2883
  };
2813
2884
  }
@@ -2839,7 +2910,7 @@ export default function (pi: ExtensionAPI) {
2839
2910
  }
2840
2911
 
2841
2912
  return {
2842
- content: [{ type: "text", text: "Invalid stored data format" }],
2913
+ content: [{ type: "text", text: `Invalid stored data for responseId ${formatInputValue(params.responseId)}: received type ${formatInputValue(data.type)}. Use a responseId returned by ${storedContentSources}.` }],
2843
2914
  details: { error: "Invalid data" },
2844
2915
  };
2845
2916
  },
@@ -2916,6 +2987,7 @@ export default function (pi: ExtensionAPI) {
2916
2987
  return new Text(statusLine + "\n" + theme.fg("dim", preview), 0, 0);
2917
2988
  },
2918
2989
  });
2990
+ }
2919
2991
 
2920
2992
  if (isCommandEnabled(initConfig, "websearch")) pi.registerCommand("websearch", {
2921
2993
  description: "Open web search curator",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-web-access",
3
- "version": "0.22.0",
4
- "description": "Web search, URL fetching, GitHub repo cloning, PDF extraction, YouTube video understanding, and local video analysis for Pi coding agent. Supports OpenAI, Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Jina, SERPdive, Kagi, Ollama, AnySearch, Bright Data SERP, SerpBase, SearXNG, Firecrawl extraction, Exa, Perplexity, and Gemini.",
3
+ "version": "0.23.0",
4
+ "description": "Web search, URL fetching, GitHub repo cloning, PDF extraction, YouTube video understanding, and local video analysis for Pi coding agent. Supports OpenAI, Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Kagi, Ollama, AnySearch, Bright Data SERP, SerpBase, SearXNG, Exa, Perplexity, and Gemini.",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "test": "node --test",
@@ -4,6 +4,8 @@ import { findModelWithProviderRouting, loadEnabledModelPatterns, modelMatchesEna
4
4
  import type { QueryResultData } from "./storage.ts";
5
5
 
6
6
  type ProviderHeaders = Record<string, string | null>;
7
+ type CompleteFunction = typeof complete;
8
+ type SummaryModelRegistry = SummaryGenerationContext["modelRegistry"] & { complete?: CompleteFunction };
7
9
 
8
10
  const PREFERRED_SUMMARY_MODELS = [
9
11
  { provider: "anthropic", id: "claude-haiku-4-5" },
@@ -198,14 +200,14 @@ function parseModelSelector(value: string): { provider: string; id: string } {
198
200
  async function resolveSummaryModelCandidates(
199
201
  ctx: SummaryGenerationContext,
200
202
  modelOverride?: string,
201
- ): Promise<{ candidates: Array<{ model: Model<Api>; apiKey: string; headers?: ProviderHeaders }>; errors: string[] }> {
203
+ ): Promise<{ candidates: Array<{ model: Model<Api>; apiKey?: string; headers?: ProviderHeaders }>; errors: string[] }> {
202
204
  const enabledModelPatterns = loadEnabledModelPatterns(ctx);
203
205
  const specs: Array<{ provider: string; id: string }> = [];
204
206
  const normalizedOverride = typeof modelOverride === "string" ? modelOverride.trim() : "";
205
207
  if (normalizedOverride.length > 0) specs.push(parseModelSelector(normalizedOverride));
206
208
  specs.push(...PREFERRED_SUMMARY_MODELS);
207
209
 
208
- const candidates: Array<{ model: Model<Api>; apiKey: string; headers?: ProviderHeaders }> = [];
210
+ const candidates: Array<{ model: Model<Api>; apiKey?: string; headers?: ProviderHeaders }> = [];
209
211
  const errors: string[] = [];
210
212
  const seen = new Set<string>();
211
213
  for (const spec of specs) {
@@ -223,7 +225,7 @@ async function resolveSummaryModelCandidates(
223
225
  continue;
224
226
  }
225
227
  const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
226
- if (!auth.ok || !auth.apiKey) {
228
+ if (!auth.ok) {
227
229
  errors.push(`No API key available for summary model ${value}`);
228
230
  continue;
229
231
  }
@@ -275,13 +277,17 @@ export async function generateSummaryDraft(
275
277
  signal?: AbortSignal,
276
278
  modelOverride?: string,
277
279
  feedback?: string,
278
- completeFn: typeof complete = complete,
280
+ completeFn?: CompleteFunction,
279
281
  deadlineMs = SUMMARY_GENERATION_DEADLINE_MS,
280
282
  ): Promise<{ summary: string; meta: SummaryMeta }> {
281
283
  if (!ctx || !ctx.modelRegistry) {
282
284
  throw new Error("Summary generation context unavailable");
283
285
  }
284
286
 
287
+ const registry = ctx.modelRegistry as SummaryModelRegistry;
288
+ const usesRegistryComplete = !completeFn && typeof registry.complete === "function";
289
+ completeFn ??= usesRegistryComplete ? registry.complete!.bind(registry) as CompleteFunction : complete;
290
+
285
291
  const generationStartedAt = Date.now();
286
292
  const deadlineController = new AbortController();
287
293
  const deadlineMarker = Symbol("summary-generation-deadline");
@@ -349,7 +355,7 @@ export async function generateSummaryDraft(
349
355
  const response = await raceSummaryOperation(Promise.resolve(completeFn(
350
356
  model,
351
357
  { messages: [userMessage] },
352
- { apiKey, headers, signal: completionSignal },
358
+ usesRegistryComplete ? { signal: completionSignal } : { apiKey, headers, signal: completionSignal },
353
359
  )));
354
360
  if (response.stopReason === "aborted") {
355
361
  throw new Error("Aborted");
@@ -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.4",
3
+ "version": "2026.8.6",
4
4
  "description": "Aggregate installer for HerbertGao-maintained Pi extensions.",
5
5
  "keywords": [
6
6
  "extensions",
@@ -42,7 +42,7 @@
42
42
  "@earendil-works/pi-tui": "^0.84.1",
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.53",
45
+ "@herbertgao/pi-cc-extensions": "0.8.55",
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.3",
54
+ "@herbertgao/pi-subagents": "0.15.5",
55
55
  "@herbertgao/pi-titlebar-spinner": "0.1.3",
56
- "@juicesharp/rpiv-ask-user-question": "2.4.0",
57
- "@juicesharp/rpiv-config": "^2.4.0",
56
+ "@juicesharp/rpiv-ask-user-question": "2.6.0",
57
+ "@juicesharp/rpiv-config": "^2.6.0",
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.50.0",
65
- "@narumitw/pi-tui-kit": "^0.49.1",
64
+ "@narumitw/pi-btw": "0.52.0",
65
+ "@narumitw/pi-tui-kit": "^0.54.0",
66
66
  "@noble/ed25519": "^3.1.0",
67
67
  "@pi-plugins/fast-mode": "0.1.9",
68
68
  "@shikijs/cli": "^4.0.2",
@@ -77,14 +77,14 @@
77
77
  "jiti": "^2.7.0",
78
78
  "js-yaml": "^5.2.2",
79
79
  "linkedom": "^0.16.0",
80
- "minimatch": "^10.2.5",
80
+ "minimatch": "^10.2.6",
81
81
  "nanoid": "^5.0.0",
82
82
  "open": "^10.2.0",
83
83
  "p-limit": "^6.1.0",
84
84
  "pi-footer": "0.5.1",
85
- "pi-lens": "3.8.74",
86
- "pi-mcp-adapter": "2.23.0",
87
- "pi-web-access": "0.22.0",
85
+ "pi-lens": "4.0.1",
86
+ "pi-mcp-adapter": "2.26.0",
87
+ "pi-web-access": "0.23.0",
88
88
  "pidusage": "^4.0.1",
89
89
  "promise.try": "^2.0.1",
90
90
  "qrcode-terminal": "^0.12.0",
@@ -161,8 +161,7 @@
161
161
  "skills": [
162
162
  "./node_modules/@dietrichgebert/ponytail/skills",
163
163
  "./node_modules/pi-mcp-adapter/skills",
164
- "./node_modules/pi-lens/skills",
165
- "./node_modules/remote-pi/skills"
164
+ "./node_modules/pi-lens/skills"
166
165
  ]
167
166
  }
168
167
  }