@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
@@ -12,7 +12,7 @@ export type ContextPart = {
12
12
  color: "accent" | "success" | "warning" | "muted" | "dim";
13
13
  };
14
14
 
15
- type PreviewKey = "systemPrompt" | "tools" | "contextFiles" | "skills";
15
+ type PreviewKey = "systemPrompt" | "tools" | "toolResults" | "contextFiles" | "skills";
16
16
 
17
17
  type ContextPreview = {
18
18
  key: PreviewKey;
@@ -303,6 +303,48 @@ export function scaleParts(parts: ContextPart[], target: number): ContextPart[]
303
303
  return scaled;
304
304
  }
305
305
 
306
+ export function resolveUsedTokens(
307
+ usage: { tokens: number | null; percent: number | null } | undefined,
308
+ estimated: number,
309
+ contextWindow: number,
310
+ ): number {
311
+ const reported = usage?.tokens;
312
+ const fromPercent =
313
+ usage?.percent !== null && usage?.percent !== undefined && contextWindow > 0
314
+ ? Math.round((usage.percent / 100) * contextWindow)
315
+ : undefined;
316
+ let resolved = reported ?? fromPercent ?? estimated;
317
+ if (reported !== null && reported !== undefined && fromPercent !== undefined) {
318
+ const tolerance = Math.max(32, Math.round(contextWindow * 0.001));
319
+ if (Math.abs(reported - fromPercent) > tolerance) resolved = fromPercent;
320
+ }
321
+ if (estimated > 0 && resolved < estimated * 0.25) return estimated;
322
+ return resolved;
323
+ }
324
+
325
+ export function capParts(parts: ContextPart[], target: number, fixedPrefix = 0): ContextPart[] {
326
+ const fixed = parts.slice(0, fixedPrefix);
327
+ const variable = parts.slice(fixedPrefix);
328
+ const fixedTokens = fixed.reduce((sum, part) => sum + part.tokens, 0);
329
+ const variableTarget = Math.max(0, target - fixedTokens);
330
+ const estimated = variable.reduce((sum, part) => sum + part.tokens, 0);
331
+ if (estimated <= variableTarget || estimated === 0) return parts;
332
+ if (variableTarget === 0) return [...fixed, ...variable.map((part) => ({ ...part, tokens: 0 }))];
333
+ let previous = 0;
334
+ let cumulative = 0;
335
+ const capped = variable.map((part, index) => {
336
+ cumulative += part.tokens;
337
+ const next =
338
+ index === variable.length - 1
339
+ ? variableTarget
340
+ : Math.round((cumulative / estimated) * variableTarget);
341
+ const tokens = next - previous;
342
+ previous = next;
343
+ return { ...part, tokens };
344
+ });
345
+ return [...fixed, ...capped];
346
+ }
347
+
306
348
  export function formatTokens(tokens: number): string {
307
349
  if (tokens < 1_000) return String(tokens);
308
350
  if (tokens < 100_000) return `${(tokens / 1_000).toFixed(1)}k`;
@@ -326,13 +368,14 @@ type ContextBreakdown = {
326
368
  parts: ContextPart[];
327
369
  options: SystemPromptOptions;
328
370
  systemPrompt: string;
371
+ toolResults: string;
329
372
  };
330
373
 
331
374
  /**
332
375
  * Single pass over prompt options + session entries. Returns options/systemPrompt
333
376
  * so the /context UI does not re-fetch or re-stringify the same sources.
334
377
  */
335
- function collectContextBreakdown(ctx: ExtensionCommandContext): ContextBreakdown {
378
+ export function collectContextBreakdown(ctx: ExtensionCommandContext): ContextBreakdown {
336
379
  const options = (ctx.getSystemPromptOptions?.() ?? {}) as SystemPromptOptions;
337
380
  const systemPrompt = typeof ctx.getSystemPrompt === "function" ? ctx.getSystemPrompt() : "";
338
381
 
@@ -361,12 +404,16 @@ function collectContextBreakdown(ctx: ExtensionCommandContext): ContextBreakdown
361
404
  let assistant = 0;
362
405
  let toolResults = 0;
363
406
  let summaries = 0;
407
+ const toolResultPreview: string[] = [];
364
408
  for (const entry of ctx.sessionManager.buildContextEntries()) {
365
409
  if (entry.type === "message") {
366
410
  const tokens = estimateTokens(entry.message);
367
411
  if (entry.message.role === "user") user += tokens;
368
412
  else if (entry.message.role === "assistant") assistant += tokens;
369
413
  else toolResults += tokens;
414
+ if (entry.message.role === "toolResult") {
415
+ toolResultPreview.push(`## Tool result\n\n${JSON.stringify(entry.message, null, 2)}`);
416
+ }
370
417
  } else if (entry.type === "compaction" || entry.type === "branch_summary") {
371
418
  summaries += tokenEstimate(entry);
372
419
  }
@@ -388,6 +435,7 @@ function collectContextBreakdown(ctx: ExtensionCommandContext): ContextBreakdown
388
435
  parts: parts.filter((part) => part.tokens > 0),
389
436
  options,
390
437
  systemPrompt,
438
+ toolResults: toolResultPreview.join("\n\n") || "No tool results in the current context.",
391
439
  };
392
440
  }
393
441
 
@@ -398,10 +446,25 @@ export default function contextUsageExtension(pi: ExtensionAPI) {
398
446
  const usage = ctx.getContextUsage();
399
447
  const contextWindow = usage?.contextWindow ?? ctx.model?.contextWindow ?? 0;
400
448
  const breakdown = collectContextBreakdown(ctx);
401
- const used = usage?.tokens ?? breakdown.parts.reduce((sum, part) => sum + part.tokens, 0);
402
- const parts = scaleParts(breakdown.parts, used);
449
+ const estimated = breakdown.parts.reduce((sum, part) => sum + part.tokens, 0);
450
+ const fixedParts = breakdown.parts.filter(
451
+ (part) => part.label === "System prompt" || part.label === "Tools",
452
+ );
453
+ const variableParts = breakdown.parts.filter(
454
+ (part) => part.label !== "System prompt" && part.label !== "Tools",
455
+ );
456
+ const orderedParts = [...fixedParts, ...variableParts];
457
+ const fixedTokens = fixedParts.reduce((sum, part) => sum + part.tokens, 0);
458
+ const used = Math.max(resolveUsedTokens(usage, estimated, contextWindow), fixedTokens);
459
+ const parts = capParts(orderedParts, used, fixedParts.length);
460
+ const attributed = parts.reduce((sum, part) => sum + part.tokens, 0);
461
+ const other = Math.max(0, used - attributed);
403
462
  const free = Math.max(0, contextWindow - used);
404
- const allParts = [...parts, { label: "Free space", tokens: free, color: "dim" as const }];
463
+ const allParts = [
464
+ ...parts,
465
+ { label: "Other", tokens: other, color: "muted" as const },
466
+ { label: "Free space", tokens: free, color: "dim" as const },
467
+ ];
405
468
 
406
469
  if (ctx.mode !== "tui") {
407
470
  const lines = allParts.map((part) => `${part.label}: ${formatTokens(part.tokens)} tokens`);
@@ -456,6 +519,12 @@ export default function contextUsageExtension(pi: ExtensionAPI) {
456
519
  title: "Tools",
457
520
  content: toolContent.join("\n\n") || "No active tools.",
458
521
  },
522
+ {
523
+ key: "toolResults",
524
+ label: "Tool results",
525
+ title: "Tool Results",
526
+ content: breakdown.toolResults,
527
+ },
459
528
  {
460
529
  key: "contextFiles",
461
530
  label: "Context files",
@@ -331,70 +331,93 @@ function editWriteExpandedCard(theme: any): any {
331
331
  );
332
332
  }
333
333
 
334
- /** compact 展开卡:外卡片保持 userMessageBg 原色;内部 tool call card(addToolChild)
335
- * 背景更深一层且只覆盖内容区(左右内缩、上下限首尾文本行),形成嵌套层次。
336
- * 逐行重建背景同时修复嵌套 Box 的右侧截断。 */
337
- function expandedToolCard(theme: any): any {
334
+ /** compact 展开卡:保留本地嵌套工具背景,并记录 thinking 的点击行区间。 */
335
+ function layoutExpandedToolCard(
336
+ theme: any,
337
+ children: any[],
338
+ width: number,
339
+ ): { lines: string[]; hits: Array<{ child: any; start: number; end: number }> } {
338
340
  const slot = "userMessageBg";
339
341
  const toolBgAnsi = darkenBgAnsi(theme, slot);
342
+ const innerWidth = Math.max(0, width - 2);
343
+ const lines: string[] = [];
344
+ const hits: Array<{ child: any; start: number; end: number }> = [];
345
+ lines.push(paddedBackgroundRow(theme, slot, "", width));
346
+ let skipLeadingBlank = true;
347
+ for (const child of children) {
348
+ const childLines = child.render(innerWidth);
349
+ if (!child.__ccToolCard) {
350
+ let start = 0;
351
+ if (skipLeadingBlank) {
352
+ while (start < childLines.length && !hasVisibleText(childLines[start])) start++;
353
+ skipLeadingBlank = false;
354
+ }
355
+ const rangeStart = lines.length;
356
+ for (let i = start; i < childLines.length; i++) {
357
+ lines.push(paddedBackgroundRow(theme, slot, childLines[i], width));
358
+ }
359
+ if (lines.length > rangeStart) hits.push({ child, start: rangeStart, end: lines.length });
360
+ continue;
361
+ }
362
+ skipLeadingBlank = false;
363
+ let first = -1;
364
+ let last = -1;
365
+ for (let i = 0; i < childLines.length; i++) {
366
+ if (hasVisibleText(childLines[i])) {
367
+ if (first < 0) first = i;
368
+ last = i;
369
+ }
370
+ }
371
+ if (first < 0) {
372
+ for (const line of childLines) {
373
+ lines.push(paddedBackgroundRow(theme, slot, line, width));
374
+ }
375
+ continue;
376
+ }
377
+ lines.push(paddedBackgroundRow(theme, slot, "", width));
378
+ lines.push(toolCardBgRow(theme, slot, toolBgAnsi, "", width));
379
+ for (let i = first; i <= last; i++) {
380
+ lines.push(toolCardBgRow(theme, slot, toolBgAnsi, childLines[i], width));
381
+ }
382
+ lines.push(toolCardBgRow(theme, slot, toolBgAnsi, "", width));
383
+ }
384
+ lines.push(paddedBackgroundRow(theme, slot, "", width));
385
+ return { lines, hits };
386
+ }
387
+
388
+ function compactRoundCard(
389
+ cardItems: Array<{ child?: any; tool?: any }>,
390
+ toolRender: (tool: any, width: number) => string[],
391
+ ): any {
340
392
  const children: any[] = [];
393
+ for (const item of cardItems) {
394
+ if (item.child) children.push(item.child);
395
+ else if (item.tool) {
396
+ const tool = item.tool;
397
+ children.push({
398
+ __ccToolCard: true,
399
+ render: (innerWidth: number) => toolRender(tool, innerWidth),
400
+ invalidate: () => tool.invalidate?.(),
401
+ });
402
+ }
403
+ }
341
404
  return {
342
405
  children,
343
- addChild(child: any) {
344
- children.push(child);
345
- },
346
- addToolChild(child: any) {
347
- child.__ccToolCard = true;
348
- children.push(child);
349
- },
350
406
  render(width: number): string[] {
351
- const innerWidth = Math.max(0, width - 2);
352
- const lines: string[] = [];
353
- lines.push(paddedBackgroundRow(theme, slot, "", width));
354
- // 展开不再显示摘要行:跳过第一个 child 的首行空白,避免白占一行
355
- let skipLeadingBlank = true;
356
- for (const child of children) {
357
- const childLines = child.render(innerWidth);
358
- if (!child.__ccToolCard) {
359
- let start = 0;
360
- if (skipLeadingBlank) {
361
- while (start < childLines.length && !hasVisibleText(childLines[start])) start++;
362
- skipLeadingBlank = false;
363
- }
364
- for (let i = start; i < childLines.length; i++) {
365
- lines.push(paddedBackgroundRow(theme, slot, childLines[i], width));
366
- }
367
- continue;
368
- }
369
- // 工具卡:前导 1 空行 + 首尾文本行之间的内容区(深色);不保留尾随,
370
- // 相邻工具卡之间正好 1 空行,底部由卡片 padding 收尾。
371
- skipLeadingBlank = false;
372
- let first = -1;
373
- let last = -1;
374
- for (let i = 0; i < childLines.length; i++) {
375
- if (hasVisibleText(childLines[i])) {
376
- if (first < 0) first = i;
377
- last = i;
378
- }
379
- }
380
- if (first < 0) {
381
- for (const line of childLines) {
382
- lines.push(paddedBackgroundRow(theme, slot, line, width));
383
- }
384
- continue;
385
- }
386
- lines.push(paddedBackgroundRow(theme, slot, "", width));
387
- // 子卡片内部上下各 1 行深色 padding
388
- lines.push(toolCardBgRow(theme, slot, toolBgAnsi, "", width));
389
- for (let i = first; i <= last; i++) {
390
- lines.push(toolCardBgRow(theme, slot, toolBgAnsi, childLines[i], width));
391
- }
392
- lines.push(toolCardBgRow(theme, slot, toolBgAnsi, "", width));
407
+ return ["", ...layoutExpandedToolCard(themeOf(), children, width).lines];
408
+ },
409
+ childAtRow(localRow: number, width: number) {
410
+ if (localRow < 1) return null;
411
+ const row = localRow - 1;
412
+ const { hits } = layoutExpandedToolCard(themeOf(), children, width);
413
+ for (const hit of hits) {
414
+ if (row >= hit.start && row < hit.end) return hit.child;
393
415
  }
394
- lines.push(paddedBackgroundRow(theme, slot, "", width));
395
- return lines;
416
+ return null;
417
+ },
418
+ invalidate() {
419
+ for (const child of children) child.invalidate?.();
396
420
  },
397
- invalidate() {},
398
421
  };
399
422
  }
400
423
 
@@ -930,27 +953,21 @@ export function installCompactMode(deps: CompactModeInstallDeps): CompactModeHoo
930
953
  tool.updateDisplay?.();
931
954
  }
932
955
  }
933
- round.anchor.contentContainer.addChild({
934
- render(width: number): string[] {
935
- const theme = themeOf();
936
- const box = expandedToolCard(theme);
937
- for (const child of assistantChildren) box.addChild(child);
938
- const ids = roundToolCallIds(round);
939
- for (const tool of trackedToolComponents) {
940
- if (!ids.has(tool.toolCallId) || EDIT_WRITE_TOOLS.has(String(tool.toolName ?? ""))) {
941
- continue;
942
- }
943
- box.addToolChild({
944
- render: (innerWidth: number) => patch.toolOriginalRender.call(tool, innerWidth),
945
- invalidate: () => tool.invalidate?.(),
946
- });
947
- }
948
- return ["", ...box.render(width)];
949
- },
950
- invalidate() {
951
- for (const child of assistantChildren) child.invalidate?.();
952
- },
953
- });
956
+ const cardItems: Array<{ child?: any; tool?: any }> = assistantChildren.map((child) => ({
957
+ child,
958
+ }));
959
+ const roundIds = roundToolCallIds(round);
960
+ for (const tool of trackedToolComponents) {
961
+ if (!roundIds.has(tool.toolCallId) || EDIT_WRITE_TOOLS.has(String(tool.toolName ?? ""))) {
962
+ continue;
963
+ }
964
+ cardItems.push({ tool });
965
+ }
966
+ round.anchor.contentContainer.addChild(
967
+ compactRoundCard(cardItems, (tool, innerWidth) =>
968
+ patch.toolOriginalRender.call(tool, innerWidth),
969
+ ),
970
+ );
954
971
  // 展开卡内工具会显示 error,外层仍挂 abort/length,避免只藏在折叠工具里。
955
972
  appendStopStatus(round.anchor, stopStatus);
956
973
  return;
@@ -80,14 +80,20 @@ function renderAdmonition(lines: string[], i: number): { output: string[]; next:
80
80
  // 裸 URL 转可点击超链接
81
81
  // ============================================================================
82
82
 
83
- const URL_RE = /(?<!<)(?<!\]\()https?:\/\/[^\s<>'"|,。;:!?、」』】]+/g;
84
- const TRIM_URL_RE = /[.,;:!?】」』"']+$/;
83
+ const URL_RE = /(?<!<)(?<!\]\()https?:\/\/[^\s<>'"|,。;:!?、」』】()【】《》『』「」]+/g;
84
+ const TRIM_URL_RE = /[.,;:!?】」』"'》)}]+$/;
85
85
 
86
86
  /** 去掉 URL 尾部标点;括号按平衡保留(如 Wikipedia 链接含括号)。 */
87
87
  function trimUrl(url: string): string {
88
88
  let t = url.replace(TRIM_URL_RE, "");
89
- while (t.endsWith(")") && (t.match(/\(/g)?.length ?? 0) < (t.match(/\)/g)?.length ?? 0)) {
90
- t = t.slice(0, -1);
89
+ while (true) {
90
+ if (t.endsWith(")") && (t.match(/\(/g)?.length ?? 0) < (t.match(/\)/g)?.length ?? 0)) {
91
+ t = t.slice(0, -1);
92
+ } else if (t.endsWith("]") && (t.match(/\[/g)?.length ?? 0) < (t.match(/\]/g)?.length ?? 0)) {
93
+ t = t.slice(0, -1);
94
+ } else {
95
+ break;
96
+ }
91
97
  }
92
98
  return t;
93
99
  }
@@ -246,6 +252,41 @@ function deCircled(markdown: string): string {
246
252
  return output.join("\n");
247
253
  }
248
254
 
255
+ // ============================================================================
256
+ // 跨行链接规整
257
+ // ============================================================================
258
+
259
+ const MULTILINE_LINK_RE = /\[([^\]\n]*(?:\n[^\]\n]*)+)\](?=\()/g;
260
+
261
+ /** 防止 Markdown 跨行链接把行尾填充空格纳入 OSC 8 点击区。 */
262
+ function normalizeMultilineLinks(markdown: string): string {
263
+ const out: string[] = [];
264
+ let prose: string[] = [];
265
+ let fence: MarkdownFence | undefined;
266
+ const flush = () => {
267
+ if (prose.length === 0) return;
268
+ out.push(
269
+ prose.join("\n").replace(MULTILINE_LINK_RE, (_match, label: string) => {
270
+ const normalized = label.replace(/[ \t]*\n[ \t]*/g, " ").trim();
271
+ return `[${normalized}]`;
272
+ }),
273
+ );
274
+ prose = [];
275
+ };
276
+ for (const line of markdown.split("\n")) {
277
+ const scanned = scanMarkdownFence(line, fence);
278
+ fence = scanned.fence;
279
+ if (scanned.protected) {
280
+ flush();
281
+ out.push(line);
282
+ } else {
283
+ prose.push(line);
284
+ }
285
+ }
286
+ flush();
287
+ return out.join("\n");
288
+ }
289
+
249
290
  // ============================================================================
250
291
  // 注册
251
292
  // ============================================================================
@@ -255,8 +296,9 @@ export default function (pi: ExtensionAPI): void {
255
296
  // 所以三个转换合并为一次注册,内部按序链式执行。
256
297
  pi.registerMarkdownTransformer((markdown, context) => {
257
298
  const { messageType, isStreaming = false } = context ?? {};
258
- // 与官方推荐一致:thinking 块与流式中间态不转换
259
- if (messageType === "assistant-thinking" || isStreaming) return markdown;
299
+ if (messageType === "assistant-thinking") return markdown;
300
+ markdown = normalizeMultilineLinks(markdown);
301
+ if (isStreaming) return markdown;
260
302
  // 0. 圈数字转半角括号(Nerd Font 补丁字形缺陷规避)
261
303
  markdown = deCircled(markdown);
262
304
  // 1. Mermaid 方言渲染
@@ -135,7 +135,7 @@ export function installMessageDisplayRendering(): () => void {
135
135
  }
136
136
 
137
137
  /** 三个消息组件共享的结构特征;CustomMessageComponent 用 rebuild 无 updateDisplay,不命中。 */
138
- function isMessageDisplayComponent(value: any): boolean {
138
+ export function isMessageDisplayComponent(value: any): boolean {
139
139
  return Boolean(
140
140
  value &&
141
141
  typeof value === "object" &&
@@ -1,3 +1,4 @@
1
+ import { ThinkingPreviewBlock } from "../../feature/compact-thinking.ts";
1
2
  import { setHoveredCompactAssistant } from "../compact-mode.ts";
2
3
  import {
3
4
  isExpandedToolIoView,
@@ -43,6 +44,16 @@ export function setHoveredToolGroup(group: ToolGroupComponent | null): boolean {
43
44
  return true;
44
45
  }
45
46
 
47
+ let hoveredThinking: ThinkingPreviewBlock | null = null;
48
+
49
+ export function setHoveredThinking(block: ThinkingPreviewBlock | null): boolean {
50
+ if (block === hoveredThinking) return false;
51
+ hoveredThinking?.setHintHovered(false);
52
+ hoveredThinking = block;
53
+ block?.setHintHovered(true);
54
+ return true;
55
+ }
56
+
46
57
  let hoveredToolIoView: ExpandedToolIoView | null = null;
47
58
  let hoveredToolIoSection: ToolIoSection | null = null;
48
59
 
@@ -98,6 +109,7 @@ export function cachedFullscreenComponentAtRow(
98
109
  export type FullscreenHoverTarget =
99
110
  | { kind: "button" }
100
111
  | { kind: "group"; component: ToolGroupComponent }
112
+ | { kind: "thinking"; component: ThinkingPreviewBlock }
101
113
  | { kind: "assistant"; component: any }
102
114
  | {
103
115
  kind: "tool";
@@ -119,6 +131,8 @@ export function applyFullscreenHover(tui: any, target: FullscreenHoverTarget | n
119
131
  }
120
132
  const nextGroup = target?.kind === "group" ? target.component : null;
121
133
  if (setHoveredToolGroup(nextGroup)) changed = true;
134
+ const nextThinking = target?.kind === "thinking" ? target.component : null;
135
+ if (setHoveredThinking(nextThinking)) changed = true;
122
136
  const nextAssistant = target?.kind === "assistant" ? target.component : null;
123
137
  if (setHoveredCompactAssistant(nextAssistant)) changed = true;
124
138
  const nextView = target?.kind === "tool" ? target.view : null;
@@ -1,6 +1,8 @@
1
+ import { ThinkingPreviewBlock } from "../../feature/compact-thinking.ts";
1
2
  import { hasActiveTextPreview, showTextPreview } from "../../feature/context.ts";
2
3
  import { ToolGroupComponent } from "../tool/grouping.ts";
3
4
  import { isCompactAssistantComponent, setHoveredCompactAssistant } from "../compact-mode.ts";
5
+ import { isMessageDisplayComponent } from "../message-display.ts";
4
6
  import { config } from "../../config/config.ts";
5
7
  import { isLazyProxyTui } from "../../utils/fullscreen-detect.ts";
6
8
  import { setToolTuiFullscreen } from "../show-more-hint.ts";
@@ -55,6 +57,7 @@ import {
55
57
  sharedToolHoverState,
56
58
  setHoveredToolCallId,
57
59
  setHoveredToolGroup,
60
+ setHoveredThinking,
58
61
  setHoveredToolIo,
59
62
  type FullscreenHoverTarget,
60
63
  } from "./hover.ts";
@@ -151,6 +154,34 @@ function updateToolSummaryHover(tui: any, packet: SgrMousePacket): void {
151
154
  tui.requestRender?.();
152
155
  }
153
156
 
157
+ const EXPAND_PANEL_DOUBLE_CLICK_MS = 400;
158
+ let lastExpandPanelClick: { card: any; at: number } | null = null;
159
+
160
+ function isExpandPanelDoubleClick(card: any): boolean {
161
+ const now = Date.now();
162
+ const prev = lastExpandPanelClick;
163
+ lastExpandPanelClick = { card, at: now };
164
+ return Boolean(prev && prev.card === card && now - prev.at <= EXPAND_PANEL_DOUBLE_CLICK_MS);
165
+ }
166
+
167
+ function clearExpandPanelDoubleClick(): void {
168
+ lastExpandPanelClick = null;
169
+ }
170
+
171
+ function collapseExpandedCard(tui: any, card: any): boolean {
172
+ if (!isExpandPanelDoubleClick(card)) return false;
173
+ card.setExpanded(false);
174
+ setHoveredToolCallId(null);
175
+ setHoveredToolGroup(null);
176
+ setHoveredThinking(null);
177
+ setHoveredToolIo(null, null);
178
+ setHoveredCompactAssistant(null);
179
+ card.invalidate?.();
180
+ tui.requestRender?.();
181
+ clearExpandPanelDoubleClick();
182
+ return true;
183
+ }
184
+
154
185
  function toggleToolAtMouseClick(tui: any, packet: SgrMousePacket): boolean {
155
186
  const region = interactionRegionAt(packet);
156
187
  if (!region) return false;
@@ -158,19 +189,12 @@ function toggleToolAtMouseClick(tui: any, packet: SgrMousePacket): boolean {
158
189
  if (region.kind === "show-more") return tryOpenToolIoShowMore(region);
159
190
  const component = region.component;
160
191
  if (!component) return false;
161
- const width = Math.max(1, Number(tui?.terminal?.columns) || 80);
162
- if (region.kind === "expanded-card") {
163
- component.setExpanded(false);
164
- setHoveredToolCallId(null);
165
- setHoveredToolGroup(null);
166
- setHoveredToolIo(null, null);
167
- component.invalidate?.();
168
- tui.requestRender?.();
169
- return true;
170
- }
192
+ if (region.kind === "expanded-card") return collapseExpandedCard(tui, component);
171
193
  component.setExpanded(true);
194
+ clearExpandPanelDoubleClick();
172
195
  setHoveredToolCallId(null);
173
196
  setHoveredToolGroup(null);
197
+ setHoveredThinking(null);
174
198
  setHoveredToolIo(null, null);
175
199
  component.invalidate?.();
176
200
  tui.requestRender?.();
@@ -241,10 +265,10 @@ const FULLSCREEN_VIEWPORT_PATCH = Symbol("ccstyle.fullscreen-viewport-patch");
241
265
  const FULLSCREEN_WHEEL_SCROLL_ORIGINAL = Symbol("ccstyle.fullscreen-wheel-scroll-original");
242
266
 
243
267
  /**
244
- * 官方 fullscreen 工具卡点击:collapsed hint 点击展开
245
- * (有且仅保持一个展开:展开前收起其他工具卡),expanded 整卡二次点击收起,
246
- * 截断头 show-more 打开全量预览;回到底部按钮 scrollToBottom。
247
- * 滚动条列、含 OSC8 链接行、非工具区域放行官方。
268
+ * 官方 fullscreen 工具卡点击:collapsed hint 单击展开
269
+ * (有且仅保持一个展开:展开前收起其他工具卡),expanded 整卡双击收起,
270
+ * 截断头 show-more 单击打开全量预览;回到底部按钮 scrollToBottom。
271
+ * 滚动条列、含 OSC8 链接行、非工具区域、展开卡单击放行官方。
248
272
  */
249
273
  function handleFullscreenToolClick(tui: any, packet: SgrMousePacket): boolean {
250
274
  const layout = tui.currentLayout;
@@ -274,7 +298,9 @@ function handleFullscreenToolClick(tui: any, packet: SgrMousePacket): boolean {
274
298
  const isTool = isToolExecutionComponent(component);
275
299
  const isGroup = component instanceof ToolGroupComponent;
276
300
  const isAssistant = isCompactAssistantComponent(component);
277
- if (!isTool && !isGroup && !isAssistant) return false;
301
+ const isThinking = component instanceof ThinkingPreviewBlock;
302
+ const isMessage = isMessageDisplayComponent(component);
303
+ if (!isTool && !isGroup && !isAssistant && !isThinking && !isMessage) return false;
278
304
  if (!component.expanded) {
279
305
  // collapsed 仅按钮文本可展开,不能把同一行正文/留白变成点击区。
280
306
  const hint = collapsedHintHitbox(line);
@@ -284,11 +310,14 @@ function handleFullscreenToolClick(tui: any, packet: SgrMousePacket): boolean {
284
310
  collectFullscreenToolCards(hit.box.component, others);
285
311
  for (const other of others) {
286
312
  if (other !== component && other.expanded) {
313
+ // 展开 round 内 thinking 时不要把外层 compact 卡收起。
314
+ if (isThinking && isCompactAssistantComponent(other)) continue;
287
315
  other.setExpanded(false);
288
316
  other.invalidate?.();
289
317
  }
290
318
  }
291
319
  component.setExpanded(true);
320
+ clearExpandPanelDoubleClick();
292
321
  } else {
293
322
  // 普通工具截断头 show-more:打开全量预览(不收起)。
294
323
  const view = isTool ? component.resultRendererComponent : null;
@@ -310,12 +339,13 @@ function handleFullscreenToolClick(tui: any, packet: SgrMousePacket): boolean {
310
339
  }
311
340
  }
312
341
  }
313
- // 整卡二次点击:内部工具仍归所属 group,保持整体展开/收起语义。
314
- card.setExpanded(false);
342
+ // 双击收起:内部工具仍归所属 group。单击放行官方(选择/链接)。
343
+ return collapseExpandedCard(tui, card);
315
344
  }
316
345
  // 点击后清 hover 高亮。
317
346
  setHoveredToolCallId(null);
318
347
  setHoveredToolGroup(null);
348
+ setHoveredThinking(null);
319
349
  setHoveredToolIo(null, null);
320
350
  setHoveredCompactAssistant(null);
321
351
  card.invalidate?.();
@@ -361,6 +391,8 @@ function handleFullscreenToolHover(tui: any, packet: SgrMousePacket): void {
361
391
  );
362
392
  if (component instanceof ToolGroupComponent) {
363
393
  if (overHint) target = { kind: "group", component };
394
+ } else if (component instanceof ThinkingPreviewBlock) {
395
+ if (component.expanded || overHint) target = { kind: "thinking", component };
364
396
  } else if (isToolExecutionComponent(component)) {
365
397
  let view: ExpandedToolIoView | null = null;
366
398
  let section: ToolIoSection | null = null;
@@ -384,6 +416,9 @@ function handleFullscreenToolHover(tui: any, packet: SgrMousePacket): void {
384
416
  } else if (isCompactAssistantComponent(component)) {
385
417
  // compact 摘要行:折叠时仅提示文字高亮,展开卡整体高亮。
386
418
  if (component.expanded || overHint) target = { kind: "assistant", component };
419
+ } else if (isMessageDisplayComponent(component)) {
420
+ // skill/compaction/branch:折叠只点 hint;展开后双击收起。
421
+ if (component.expanded || overHint) target = { kind: "assistant", component };
387
422
  }
388
423
  }
389
424
  }
@@ -779,8 +814,10 @@ export function teardownToolMouseInteraction(
779
814
  toolMouseInputUnsubscribe = null;
780
815
  setHoveredToolCallId(null);
781
816
  setHoveredToolGroup(null);
817
+ setHoveredThinking(null);
782
818
  setHoveredToolIo(null, null);
783
819
  setHoveredCompactAssistant(null);
820
+ clearExpandPanelDoubleClick();
784
821
  try {
785
822
  if (isLazyProxyTui(getToolMouseTui())) releaseFullscreenToolMouseMotion(getToolMouseTui());
786
823
  else getToolMouseTui()?.terminal?.write?.(TOOL_MOUSE_DISABLE);
@@ -804,6 +841,7 @@ export function teardownToolMouseInteraction(
804
841
  /** off 模式清理:清空 hover 与回到底部按钮状态(跨模块 rebind 统一经由此函数)。 */
805
842
  export function resetToolHoverState(): void {
806
843
  setHoveredToolCallId(null);
844
+ setHoveredThinking(null);
807
845
  setHoveredCompactAssistant(null);
808
846
  setScrollButtonVisible(false);
809
847
  setScrollButtonHovered(false);