@herbertgao/pi-extensions 2026.8.6 → 2026.8.8

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 (385) hide show
  1. package/README.md +8 -6
  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 +320 -22
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +79 -17
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +27 -0
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +66 -17
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
  15. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  16. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
  17. package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
  18. package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
  19. package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
  20. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
  21. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
  22. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +17 -13
  23. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
  24. package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
  25. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
  26. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
  27. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
  28. package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
  29. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
  30. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
  31. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +21 -6
  32. package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
  33. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +20 -0
  34. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +5 -4
  35. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +174 -100
  36. package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
  37. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
  38. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +5 -1
  39. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +10 -2
  40. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +10 -6
  41. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/tool-schema.md +11 -5
  42. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +5 -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 +140 -97
  47. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +63 -28
  48. package/node_modules/@juicesharp/rpiv-ask-user-question/state/selectors/projections.ts +22 -15
  49. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state-reducer.ts +11 -1
  50. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
  51. package/node_modules/@juicesharp/rpiv-ask-user-question/tool/response-envelope.ts +11 -0
  52. package/node_modules/@juicesharp/rpiv-ask-user-question/tool/types.ts +11 -0
  53. package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/multi-select-view.ts +31 -17
  54. package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/preview/preview-block-renderer.ts +15 -6
  55. package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/wrapping-select.ts +15 -6
  56. package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +86 -38
  57. package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +76 -9
  58. package/node_modules/@narumitw/pi-btw/README.md +120 -111
  59. package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
  60. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
  61. package/node_modules/@narumitw/pi-btw/package.json +10 -6
  62. package/node_modules/@narumitw/pi-btw/src/btw.ts +36 -40
  63. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
  64. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
  65. package/node_modules/@narumitw/pi-btw/src/menu.ts +45 -2
  66. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
  67. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +44 -1856
  68. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
  69. package/node_modules/@pi-plugins/fast-mode/package.json +4 -6
  70. package/node_modules/pi-lens/CHANGELOG.md +999 -0
  71. package/node_modules/pi-lens/README.md +117 -3
  72. package/node_modules/pi-lens/config/ruff/core.toml +42 -0
  73. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
  74. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +126 -13
  75. package/node_modules/pi-lens/dist/clients/agent-nudge.js +67 -11
  76. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
  77. package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
  78. package/node_modules/pi-lens/dist/clients/bash-file-access.js +381 -13
  79. package/node_modules/pi-lens/dist/clients/biome-client.js +61 -30
  80. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
  81. package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +129 -0
  82. package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
  83. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
  84. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +206 -0
  85. package/node_modules/pi-lens/dist/clients/cache-observability.js +353 -76
  86. package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
  87. package/node_modules/pi-lens/dist/clients/cascade-format.js +20 -1
  88. package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
  89. package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
  90. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
  91. package/node_modules/pi-lens/dist/clients/dead-code-client.js +123 -31
  92. package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
  93. package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
  94. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +84 -14
  95. package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +155 -0
  96. package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -3
  97. package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +8 -2
  98. package/node_modules/pi-lens/dist/clients/deps/typebox.js +8 -3
  99. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +147 -33
  100. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
  101. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +52 -2
  102. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +256 -88
  103. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
  104. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +9 -6
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +9 -7
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +8 -6
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +60 -53
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -2
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +25 -2
  122. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +20 -5
  123. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +44 -11
  124. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
  125. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
  126. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
  127. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +17 -8
  128. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +32 -4
  129. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +47 -3
  130. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +14 -4
  131. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +127 -28
  132. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +12 -7
  133. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
  134. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +275 -13
  135. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +21 -6
  136. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
  137. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +734 -64
  138. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
  139. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +188 -0
  140. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +9 -0
  141. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +21 -10
  142. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -2
  143. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
  144. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
  145. package/node_modules/pi-lens/dist/clients/extension-log.js +22 -1
  146. package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
  147. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +316 -0
  148. package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
  149. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
  150. package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
  151. package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
  152. package/node_modules/pi-lens/dist/clients/git-guard.js +31 -0
  153. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
  154. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +109 -9
  155. package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
  156. package/node_modules/pi-lens/dist/clients/host-ports.js +8 -0
  157. package/node_modules/pi-lens/dist/clients/installer/index.js +1114 -100
  158. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
  159. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
  160. package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
  161. package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
  162. package/node_modules/pi-lens/dist/clients/jscpd-client.js +87 -8
  163. package/node_modules/pi-lens/dist/clients/knip-client.js +310 -10
  164. package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
  165. package/node_modules/pi-lens/dist/clients/language-profile.js +9 -2
  166. package/node_modules/pi-lens/dist/clients/latency-logger.js +440 -11
  167. package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
  168. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
  169. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  170. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +128 -8
  171. package/node_modules/pi-lens/dist/clients/lsp/client.js +1660 -164
  172. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +83 -1
  173. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
  174. package/node_modules/pi-lens/dist/clients/lsp/index.js +2423 -151
  175. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
  176. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
  177. package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
  178. package/node_modules/pi-lens/dist/clients/lsp/server.js +277 -16
  179. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
  180. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
  181. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +79 -3
  182. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +43 -0
  183. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
  184. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
  185. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
  186. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
  187. package/node_modules/pi-lens/dist/clients/mcp/session.js +10 -2
  188. package/node_modules/pi-lens/dist/clients/module-report.js +22 -1
  189. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +114 -23
  190. package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
  191. package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
  192. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
  193. package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
  194. package/node_modules/pi-lens/dist/clients/pipeline.js +154 -33
  195. package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
  196. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
  197. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
  198. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +84 -14
  199. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
  200. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
  201. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +23 -9
  202. package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
  203. package/node_modules/pi-lens/dist/clients/project-report.js +62 -27
  204. package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
  205. package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
  206. package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
  207. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +8 -3
  208. package/node_modules/pi-lens/dist/clients/read-guard.js +253 -10
  209. package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
  210. package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
  211. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +194 -31
  212. package/node_modules/pi-lens/dist/clients/review-graph/query.js +52 -4
  213. package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +21 -0
  214. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +6 -3
  215. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +96 -7
  216. package/node_modules/pi-lens/dist/clients/runtime-context.js +8 -1
  217. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +352 -45
  218. package/node_modules/pi-lens/dist/clients/runtime-session.js +373 -9
  219. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
  220. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +212 -79
  221. package/node_modules/pi-lens/dist/clients/runtime-turn.js +620 -67
  222. package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
  223. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
  224. package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
  225. package/node_modules/pi-lens/dist/clients/security-scan-client.js +157 -24
  226. package/node_modules/pi-lens/dist/clients/session-event-guard.js +184 -0
  227. package/node_modules/pi-lens/dist/clients/sg-runner.js +116 -22
  228. package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
  229. package/node_modules/pi-lens/dist/clients/source-filter.js +6 -2
  230. package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
  231. package/node_modules/pi-lens/dist/clients/startup-scan.js +5 -2
  232. package/node_modules/pi-lens/dist/clients/startup-timing.js +19 -1
  233. package/node_modules/pi-lens/dist/clients/test-runner-client.js +151 -16
  234. package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
  235. package/node_modules/pi-lens/dist/clients/tool-policy.js +125 -20
  236. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
  237. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
  238. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +1 -0
  239. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
  240. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
  241. package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
  242. package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
  243. package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
  244. package/node_modules/pi-lens/dist/index.js +61407 -48577
  245. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +476 -57
  246. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +132 -43
  247. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
  248. package/node_modules/pi-lens/docs/agent-guide.md +6 -1
  249. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +515 -506
  250. package/node_modules/pi-lens/docs/dispositions.md +21 -0
  251. package/node_modules/pi-lens/docs/features.md +19 -5
  252. package/node_modules/pi-lens/docs/globalconfig.md +3 -0
  253. package/node_modules/pi-lens/docs/language-coverage.md +71 -5
  254. package/node_modules/pi-lens/docs/mcp.md +2 -2
  255. package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
  256. package/node_modules/pi-lens/docs/settings.md +19 -1
  257. package/node_modules/pi-lens/docs/usage.md +1 -0
  258. package/node_modules/pi-lens/package.json +27 -10
  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 +15 -1
  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-dupe-class-members-test.yml +33 -0
  266. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
  267. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
  268. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
  269. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
  270. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +2 -0
  271. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +2 -0
  272. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +2 -1
  273. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +2 -1
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
  288. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
  289. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
  290. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
  291. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +57 -12
  292. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
  293. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
  294. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
  295. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
  296. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
  297. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
  298. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
  299. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +22 -2
  300. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +23 -2
  301. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +33 -5
  302. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +34 -8
  303. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
  304. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
  305. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
  306. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
  307. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
  308. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
  309. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +6 -1
  310. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
  311. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
  312. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
  313. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
  314. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
  315. package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
  316. package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
  317. package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
  318. package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
  319. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +53 -1
  320. package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
  321. package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
  322. package/node_modules/pi-lens/scripts/install-selftest.mjs +99 -11
  323. package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +75 -0
  324. package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +285 -0
  325. package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +233 -0
  326. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +2 -0
  327. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +80 -3
  328. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +41 -0
  329. package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
  330. package/node_modules/pi-mcp-adapter/CHANGELOG.md +36 -0
  331. package/node_modules/pi-mcp-adapter/README.md +47 -5
  332. package/node_modules/pi-mcp-adapter/cli.js +163 -1
  333. package/node_modules/pi-mcp-adapter/commands.ts +128 -22
  334. package/node_modules/pi-mcp-adapter/config.ts +25 -7
  335. package/node_modules/pi-mcp-adapter/direct-tools.ts +5 -4
  336. package/node_modules/pi-mcp-adapter/index.ts +219 -32
  337. package/node_modules/pi-mcp-adapter/init.ts +36 -4
  338. package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
  339. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
  340. package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
  341. package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
  342. package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
  343. package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
  344. package/node_modules/pi-mcp-adapter/metadata-cache.ts +32 -21
  345. package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
  346. package/node_modules/pi-mcp-adapter/package.json +3 -1
  347. package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
  348. package/node_modules/pi-mcp-adapter/request-headers-command.ts +31 -37
  349. package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
  350. package/node_modules/pi-mcp-adapter/server-manager.ts +140 -2
  351. package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
  352. package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
  353. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
  354. package/node_modules/pi-mcp-adapter/types.ts +2 -0
  355. package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
  356. package/node_modules/pi-mcp-adapter/utils.ts +70 -0
  357. package/node_modules/pi-web-access/CHANGELOG.md +37 -0
  358. package/node_modules/pi-web-access/README.md +32 -13
  359. package/node_modules/pi-web-access/anysearch.ts +4 -2
  360. package/node_modules/pi-web-access/brave.ts +16 -4
  361. package/node_modules/pi-web-access/chrome-cookies.ts +86 -15
  362. package/node_modules/pi-web-access/curator-page.ts +6 -3
  363. package/node_modules/pi-web-access/curator-server.ts +4 -1
  364. package/node_modules/pi-web-access/data-uri-sanitize.ts +406 -0
  365. package/node_modules/pi-web-access/exa.ts +18 -7
  366. package/node_modules/pi-web-access/extract.ts +40 -5
  367. package/node_modules/pi-web-access/firecrawl.ts +18 -2
  368. package/node_modules/pi-web-access/gemini-search.ts +16 -4
  369. package/node_modules/pi-web-access/github-extract.ts +65 -36
  370. package/node_modules/pi-web-access/index.ts +60 -61
  371. package/node_modules/pi-web-access/openai-search.ts +17 -6
  372. package/node_modules/pi-web-access/package.json +1 -1
  373. package/node_modules/pi-web-access/page-query.ts +4 -2
  374. package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
  375. package/node_modules/pi-web-access/parallel.ts +2 -2
  376. package/node_modules/pi-web-access/pdf-extract.ts +18 -5
  377. package/node_modules/pi-web-access/query-rewrite.ts +51 -0
  378. package/node_modules/pi-web-access/serper.ts +211 -0
  379. package/node_modules/pi-web-access/ssrf-protection.ts +12 -2
  380. package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
  381. package/node_modules/pi-web-access/summary-review.ts +44 -22
  382. package/node_modules/pi-web-access/tavily.ts +16 -4
  383. package/node_modules/pi-web-access/utils.ts +87 -0
  384. package/node_modules/pi-web-access/valyu.ts +199 -0
  385. package/package.json +14 -14
@@ -1,11 +1,26 @@
1
+ import { SdkError, SdkErrorCode } from "@modelcontextprotocol/client";
1
2
  import { isServerDisabled, type ServerDefinition } from "./types.ts";
2
- import type { McpServerManager } from "./server-manager.ts";
3
+ import type { McpServerManager, ServerConnection } from "./server-manager.ts";
3
4
  import { hasPendingAuth } from "./mcp-auth-flow.ts";
4
5
  import { logger } from "./logger.ts";
5
- import { formatTerminalError, sanitizeTerminalText } from "./utils.ts";
6
+ import { formatTerminalError, parallelLimit, sanitizeTerminalText } from "./utils.ts";
7
+ import { isTerminatedSession } from "./session-recovery.ts";
6
8
 
7
- export type ReconnectCallback = (serverName: string) => void;
9
+ export type ReconnectCallback = (serverName: string) => void | Promise<void>;
8
10
  export type ReconnectFailureCallback = (serverName: string, error: unknown) => void;
11
+ export type HealthRestoredCallback = (serverName: string) => void | Promise<void>;
12
+ export type AuthRequiredCallback = (serverName: string) => void | Promise<void>;
13
+
14
+ const KEEP_ALIVE_RETRY_BASE_MS = 30_000;
15
+ const KEEP_ALIVE_RETRY_MAX_MS = 5 * 60_000;
16
+ const KEEP_ALIVE_CHECK_CONCURRENCY = 10;
17
+
18
+ interface RetryState {
19
+ attempts: number;
20
+ nextAttemptAt: number;
21
+ connection: ServerConnection | undefined;
22
+ status: ServerConnection["status"] | undefined;
23
+ }
9
24
 
10
25
  export class McpLifecycleManager {
11
26
  private keepAliveServers = new Map<string, ServerDefinition>();
@@ -15,9 +30,14 @@ export class McpLifecycleManager {
15
30
  private healthCheckInterval: NodeJS.Timeout | undefined;
16
31
  private onReconnect: ReconnectCallback | undefined;
17
32
  private onReconnectFailure: ReconnectFailureCallback | undefined;
33
+ private onHealthRestored: HealthRestoredCallback | undefined;
34
+ private onAuthRequired: AuthRequiredCallback | undefined;
18
35
  private onIdleShutdown: ((serverName: string) => void) | undefined;
19
36
  private activeHealthCheck: Promise<void> | undefined;
37
+ private activeConvergence: Promise<void> | undefined;
20
38
  private shutdownPromise: Promise<void> | undefined;
39
+ private retryStates = new Map<string, RetryState>();
40
+ private pendingMetadataPublications = new Set<string>();
21
41
  private stopped = false;
22
42
  private removeHealthAbortListener: (() => void) | undefined;
23
43
 
@@ -34,6 +54,14 @@ export class McpLifecycleManager {
34
54
  this.onReconnectFailure = callback;
35
55
  }
36
56
 
57
+ setHealthRestoredCallback(callback: HealthRestoredCallback): void {
58
+ this.onHealthRestored = callback;
59
+ }
60
+
61
+ setAuthRequiredCallback(callback: AuthRequiredCallback): void {
62
+ this.onAuthRequired = callback;
63
+ }
64
+
37
65
  markKeepAlive(name: string, definition: ServerDefinition): void {
38
66
  if (isServerDisabled(definition)) return;
39
67
  this.keepAliveServers.set(name, definition);
@@ -45,6 +73,14 @@ export class McpLifecycleManager {
45
73
  if (settings?.idleTimeout !== undefined) this.serverSettings.set(name, settings);
46
74
  }
47
75
 
76
+ unregisterServer(name: string): void {
77
+ this.allServers.delete(name);
78
+ this.keepAliveServers.delete(name);
79
+ this.serverSettings.delete(name);
80
+ this.retryStates.delete(name);
81
+ this.pendingMetadataPublications.delete(name);
82
+ }
83
+
48
84
  setGlobalIdleTimeout(minutes: number): void {
49
85
  this.globalIdleTimeout = minutes * 60 * 1000;
50
86
  }
@@ -82,29 +118,23 @@ export class McpLifecycleManager {
82
118
  this.healthCheckInterval.unref();
83
119
  }
84
120
 
85
- private async checkConnections(signal?: AbortSignal): Promise<void> {
121
+ async ensureConverged(signal?: AbortSignal): Promise<void> {
86
122
  if (this.stopped || signal?.aborted) return;
87
- for (const [name, definition] of this.keepAliveServers) {
88
- if (isServerDisabled(definition)) continue;
89
- const connection = this.manager.getConnection(name);
90
- if (!connection || connection.status !== "connected") {
91
- if (this.hasPendingAuthForServer(name)) {
92
- logger.debug(`Skipping reconnect for ${name} while OAuth authorization is pending`);
93
- continue;
94
- }
95
- try {
96
- await this.manager.connect(name, definition, signal);
97
- if (this.stopped || signal?.aborted) return;
98
- logger.debug(`Reconnected to ${name}`);
99
- this.onReconnect?.(name);
100
- } catch (error) {
101
- if (this.stopped || signal?.aborted) return;
102
- this.onReconnectFailure?.(name, error);
103
- const message = error instanceof Error ? error.message : String(error);
104
- console.error(`MCP: Failed to reconnect to ${name}: ${sanitizeTerminalText(message)}`);
105
- }
106
- }
123
+ if (this.activeConvergence) return this.activeConvergence;
124
+
125
+ const check = this.checkKeepAliveConnections(signal);
126
+ this.activeConvergence = check;
127
+ try {
128
+ await check;
129
+ } finally {
130
+ if (this.activeConvergence === check) this.activeConvergence = undefined;
107
131
  }
132
+ }
133
+
134
+ private async checkConnections(signal?: AbortSignal): Promise<void> {
135
+ if (this.stopped || signal?.aborted) return;
136
+ await this.ensureConverged(signal);
137
+ if (this.stopped || signal?.aborted) return;
108
138
 
109
139
  for (const [name] of this.allServers) {
110
140
  if (this.keepAliveServers.has(name)) continue;
@@ -117,6 +147,255 @@ export class McpLifecycleManager {
117
147
  }
118
148
  }
119
149
 
150
+ private async checkKeepAliveConnections(signal?: AbortSignal): Promise<void> {
151
+ if (this.stopped || signal?.aborted) return;
152
+ await parallelLimit(
153
+ [...this.keepAliveServers],
154
+ KEEP_ALIVE_CHECK_CONCURRENCY,
155
+ ([name, definition]) => this.checkKeepAliveConnection(name, definition, signal),
156
+ );
157
+ }
158
+
159
+ private async checkKeepAliveConnection(
160
+ name: string,
161
+ definition: ServerDefinition,
162
+ signal?: AbortSignal,
163
+ retrySuperseded = true,
164
+ ): Promise<void> {
165
+ if (isServerDisabled(definition) || this.stopped || signal?.aborted) return;
166
+ // Fence against unregisterServer racing an in-flight convergence pass.
167
+ // Identity comparison also rejects stale passes after a same-name
168
+ // replacement registration, which a name check would wrongly accept.
169
+ if (this.keepAliveServers.get(name) !== definition) return;
170
+ const connection = this.manager.getConnection(name);
171
+ if (connection?.status === "needs-auth") {
172
+ this.pendingMetadataPublications.delete(name);
173
+ return;
174
+ }
175
+ if (!this.shouldAttemptConnection(name, connection)) return;
176
+ if (!connection || connection.status !== "connected") {
177
+ if (this.hasPendingAuthForServer(name)) {
178
+ logger.debug(`Skipping reconnect for ${name} while OAuth authorization is pending`);
179
+ return;
180
+ }
181
+ let freshConnection: ServerConnection;
182
+ try {
183
+ freshConnection = await this.manager.connect(name, definition, signal);
184
+ } catch (error) {
185
+ if (this.stopped || signal?.aborted) return;
186
+ this.reportConnectionFailure(name, definition, error, "reconnect", this.manager.getConnection(name));
187
+ return;
188
+ }
189
+ if (this.stopped || signal?.aborted) return;
190
+ if (freshConnection.status === "needs-auth") {
191
+ await this.notifyAuthRequired(name, definition, freshConnection);
192
+ return;
193
+ }
194
+ if (freshConnection.status !== "connected") {
195
+ this.reportConnectionFailure(
196
+ name,
197
+ definition,
198
+ new Error(`MCP server ${name} did not return a connected session`),
199
+ "reconnect",
200
+ freshConnection,
201
+ );
202
+ return;
203
+ }
204
+ logger.debug(`Reconnected to ${name}`);
205
+ await this.publishConnectedMetadata(name, definition, freshConnection);
206
+ return;
207
+ }
208
+
209
+ if (this.pendingMetadataPublications.has(name)) {
210
+ await this.publishConnectedMetadata(name, definition, connection);
211
+ return;
212
+ }
213
+ if (!definition.url) return;
214
+ const hadSessionId = (connection.transport as { sessionId?: string } | undefined)?.sessionId != null;
215
+ let refreshResult: Awaited<ReturnType<McpServerManager["refreshTools"]>>;
216
+ try {
217
+ refreshResult = await this.manager.refreshTools(name, connection, signal);
218
+ } catch (error) {
219
+ if (this.stopped || signal?.aborted) return;
220
+ const current = this.manager.getConnection(name);
221
+ if (current !== connection || connection.status !== "connected") {
222
+ await this.handleSupersededConnection(name, definition, connection, signal, retrySuperseded);
223
+ return;
224
+ }
225
+ if (!shouldReconnectAfterRefresh(error, hadSessionId)) {
226
+ this.reportConnectionFailure(name, definition, error, "refresh", connection);
227
+ return;
228
+ }
229
+ if (this.hasPendingAuthForServer(name)) {
230
+ logger.debug(`Skipping reconnect for ${name} while OAuth authorization is pending`);
231
+ return;
232
+ }
233
+ let freshConnection: ServerConnection;
234
+ try {
235
+ freshConnection = await this.manager.reconnect(name, definition, connection, signal);
236
+ } catch (reconnectError) {
237
+ if (this.stopped || signal?.aborted) return;
238
+ this.reportConnectionFailure(name, definition, reconnectError, "reconnect", this.manager.getConnection(name));
239
+ return;
240
+ }
241
+ if (this.stopped || signal?.aborted) return;
242
+ if (freshConnection.status === "needs-auth") {
243
+ await this.notifyAuthRequired(name, definition, freshConnection);
244
+ return;
245
+ }
246
+ if (freshConnection.status !== "connected") {
247
+ this.reportConnectionFailure(
248
+ name,
249
+ definition,
250
+ new Error(`MCP server ${name} did not return a connected session`),
251
+ "reconnect",
252
+ freshConnection,
253
+ );
254
+ return;
255
+ }
256
+ logger.debug(`Reconnected stale MCP session for ${name}`);
257
+ await this.publishConnectedMetadata(name, definition, freshConnection);
258
+ return;
259
+ }
260
+
261
+ if (refreshResult === "superseded") {
262
+ await this.handleSupersededConnection(name, definition, connection, signal, retrySuperseded);
263
+ return;
264
+ }
265
+ if (refreshResult === "refresh-timeout") {
266
+ this.deferRefreshTimeout(name, definition, connection);
267
+ return;
268
+ }
269
+ if (this.keepAliveServers.get(name) !== definition) return;
270
+ if (this.retryStates.delete(name)) {
271
+ await this.onHealthRestored?.(name);
272
+ }
273
+ }
274
+
275
+ private async handleSupersededConnection(
276
+ name: string,
277
+ definition: ServerDefinition,
278
+ staleConnection: ServerConnection,
279
+ signal: AbortSignal | undefined,
280
+ retrySuperseded: boolean,
281
+ ): Promise<void> {
282
+ const current = this.manager.getConnection(name);
283
+ if (this.keepAliveServers.get(name) !== definition) return;
284
+ if (current === staleConnection && current.status === "connected") {
285
+ if (this.retryStates.delete(name)) await this.onHealthRestored?.(name);
286
+ return;
287
+ }
288
+ if (current?.status === "connected") {
289
+ await this.publishConnectedMetadata(name, definition, current);
290
+ return;
291
+ }
292
+ if (current?.status === "needs-auth") {
293
+ await this.notifyAuthRequired(name, definition, current);
294
+ return;
295
+ }
296
+ if (retrySuperseded) {
297
+ await this.checkKeepAliveConnection(name, definition, signal, false);
298
+ }
299
+ }
300
+
301
+ private async publishConnectedMetadata(name: string, definition: ServerDefinition, connection: ServerConnection): Promise<void> {
302
+ // Fence stale convergence passes by definition identity so disposal, and
303
+ // disposal followed by a same-name replacement, never re-track this
304
+ // server. Close the pass's own connection only when it is still current,
305
+ // so a replacement's connection is never touched.
306
+ if (this.keepAliveServers.get(name) !== definition) {
307
+ if (this.manager.getConnection(name) === connection) await this.manager.close(name);
308
+ return;
309
+ }
310
+ this.pendingMetadataPublications.add(name);
311
+ try {
312
+ await this.onReconnect?.(name);
313
+ this.pendingMetadataPublications.delete(name);
314
+ this.retryStates.delete(name);
315
+ } catch (error) {
316
+ if (this.stopped) return;
317
+ this.reportConnectionFailure(name, definition, error, "publish", connection);
318
+ }
319
+ }
320
+
321
+ private async notifyAuthRequired(name: string, definition: ServerDefinition, connection: ServerConnection): Promise<void> {
322
+ // Fence stale convergence passes by definition identity. Close the
323
+ // leftover needs-auth connection only while it is still the manager's
324
+ // current entry, so a replacement's connection is never touched and the
325
+ // stale client/transport cannot leak when a replacement connects later.
326
+ if (this.keepAliveServers.get(name) !== definition) {
327
+ if (this.manager.getConnection(name) === connection) await this.manager.close(name);
328
+ return;
329
+ }
330
+ this.pendingMetadataPublications.delete(name);
331
+ this.retryStates.delete(name);
332
+ try {
333
+ await this.onAuthRequired?.(name);
334
+ } catch (error) {
335
+ const message = error instanceof Error ? error.message : String(error);
336
+ logger.debug(`MCP: auth-required callback failed for ${name}: ${sanitizeTerminalText(message)}`);
337
+ }
338
+ }
339
+
340
+ private shouldAttemptConnection(name: string, connection: ServerConnection | undefined): boolean {
341
+ const retry = this.retryStates.get(name);
342
+ if (!retry) return true;
343
+ if (retry.connection !== connection || retry.status !== connection?.status) {
344
+ this.retryStates.delete(name);
345
+ return true;
346
+ }
347
+ return Date.now() >= retry.nextAttemptAt;
348
+ }
349
+
350
+ private reportConnectionFailure(
351
+ name: string,
352
+ definition: ServerDefinition,
353
+ error: unknown,
354
+ action: "refresh" | "reconnect" | "publish",
355
+ connection: ServerConnection | undefined,
356
+ ): void {
357
+ if (!this.recordRetry(name, definition, connection)) return;
358
+ this.onReconnectFailure?.(name, error);
359
+ const message = error instanceof Error ? error.message : String(error);
360
+ const target = action === "reconnect"
361
+ ? `reconnect to ${name}`
362
+ : action === "publish"
363
+ ? `publish metadata for ${name}`
364
+ : `refresh ${name}`;
365
+ console.error(`MCP: Failed to ${target}: ${sanitizeTerminalText(message)}`);
366
+ }
367
+
368
+ private deferRefreshTimeout(
369
+ name: string,
370
+ definition: ServerDefinition,
371
+ connection: ServerConnection | undefined,
372
+ ): void {
373
+ if (!this.recordRetry(name, definition, connection)) return;
374
+ logger.debug(`MCP: keep-alive tools/list refresh timed out for ${name}; retrying after backoff`);
375
+ }
376
+
377
+ private recordRetry(
378
+ name: string,
379
+ definition: ServerDefinition,
380
+ connection: ServerConnection | undefined,
381
+ ): boolean {
382
+ // Do not recreate retry/failure state from a stale convergence pass after
383
+ // disposal or a same-name replacement registration.
384
+ if (this.keepAliveServers.get(name) !== definition) return false;
385
+ const attempts = (this.retryStates.get(name)?.attempts ?? 0) + 1;
386
+ const delay = Math.min(
387
+ KEEP_ALIVE_RETRY_BASE_MS * 2 ** Math.min(attempts - 1, 10),
388
+ KEEP_ALIVE_RETRY_MAX_MS,
389
+ );
390
+ this.retryStates.set(name, {
391
+ attempts,
392
+ nextAttemptAt: Date.now() + delay,
393
+ connection,
394
+ status: connection?.status,
395
+ });
396
+ return true;
397
+ }
398
+
120
399
  private getIdleTimeout(name: string): number {
121
400
  const perServer = this.serverSettings.get(name)?.idleTimeout;
122
401
  if (perServer !== undefined) return perServer * 60 * 1000;
@@ -137,11 +416,23 @@ export class McpLifecycleManager {
137
416
  this.removeHealthAbortListener = undefined;
138
417
  await this.activeHealthCheck;
139
418
  this.activeHealthCheck = undefined;
419
+ await this.activeConvergence;
420
+ this.activeConvergence = undefined;
140
421
  this.onReconnect = undefined;
141
422
  this.onReconnectFailure = undefined;
423
+ this.onHealthRestored = undefined;
424
+ this.onAuthRequired = undefined;
142
425
  this.onIdleShutdown = undefined;
426
+ this.retryStates.clear();
427
+ this.pendingMetadataPublications.clear();
143
428
  if (typeof this.manager.closeAll === "function") {
144
429
  await this.manager.closeAll();
145
430
  }
146
431
  }
147
432
  }
433
+
434
+ function shouldReconnectAfterRefresh(error: unknown, hadSessionId: boolean): boolean {
435
+ if (isTerminatedSession(error, hadSessionId)) return true;
436
+ return error instanceof SdkError
437
+ && (error.code === SdkErrorCode.NotConnected || error.code === SdkErrorCode.ConnectionClosed);
438
+ }
@@ -18,6 +18,7 @@ import {
18
18
  waitForCallback,
19
19
  cancelPendingCallback,
20
20
  stopCallbackServer,
21
+ stopCallbackServerIfIdle,
21
22
  releaseCallbackServer,
22
23
  } from "./mcp-callback-server.ts"
23
24
  import {
@@ -387,7 +388,7 @@ export async function startAuth(
387
388
  } catch (error) {
388
389
  releaseCallbackServer(oauthState)
389
390
  try {
390
- await clearOAuthState(serverName, authStorageOptions)
391
+ await cleanupAndReleaseCallbackServerIfIdle(() => clearOAuthState(serverName, authStorageOptions))
391
392
  } catch (cleanupError) {
392
393
  throw new AggregateError([error, cleanupError], "OAuth startup cleanup failed")
393
394
  }
@@ -429,6 +430,7 @@ export async function startAuth(
429
430
  authProvider.deactivate()
430
431
  releaseCallbackServer(oauthState)
431
432
  await clearOAuthState(serverName, authStorageOptions)
433
+ await stopCallbackServerIfIdle()
432
434
  return { authorizationUrl: "" }
433
435
  }
434
436
  if (!capturedUrl) {
@@ -439,7 +441,7 @@ export async function startAuth(
439
441
  } catch (error) {
440
442
  authProvider.deactivate()
441
443
  try {
442
- await clearPendingAuth(runtime, serverName, oauthState, authStorageOptions)
444
+ await clearPendingAuthAndReleaseIfIdle(runtime, serverName, oauthState, authStorageOptions)
443
445
  } catch (cleanupError) {
444
446
  throw new AggregateError([error, cleanupError], "OAuth startup cleanup failed")
445
447
  }
@@ -463,7 +465,7 @@ async function setPendingAuth(
463
465
  state.pendingAuths.set(key, pendingAuth)
464
466
  state.pendingAuthStates.set(key, oauthState)
465
467
  const cleanupTimer = setTimeout(() => {
466
- void clearPendingAuth(runtime, serverName, oauthState, pendingAuth.authStorageOptions).catch(error => {
468
+ void clearPendingAuthAndReleaseIfIdle(runtime, serverName, oauthState, pendingAuth.authStorageOptions).catch(error => {
467
469
  console.error(`MCP Auth: Timed-out flow cleanup failed: ${formatTerminalError(error)}`)
468
470
  })
469
471
  }, MANUAL_AUTH_TIMEOUT_MS)
@@ -498,6 +500,37 @@ async function clearPendingAuth(runtime: McpOAuthRuntime, serverName: string, oa
498
500
  }
499
501
  }
500
502
 
503
+ async function clearPendingAuthAndReleaseIfIdle(
504
+ runtime: McpOAuthRuntime,
505
+ serverName: string,
506
+ oauthState: string | undefined,
507
+ fallbackStorageOptions: AuthStorageOptions = {},
508
+ ): Promise<void> {
509
+ await cleanupAndReleaseCallbackServerIfIdle(
510
+ () => clearPendingAuth(runtime, serverName, oauthState, fallbackStorageOptions),
511
+ )
512
+ }
513
+
514
+ async function cleanupAndReleaseCallbackServerIfIdle(cleanup: () => void | Promise<void>): Promise<void> {
515
+ let cleanupFailure: { error: unknown } | undefined
516
+ try {
517
+ await cleanup()
518
+ } catch (error) {
519
+ cleanupFailure = { error }
520
+ }
521
+
522
+ try {
523
+ await stopCallbackServerIfIdle()
524
+ } catch (releaseError) {
525
+ if (cleanupFailure) {
526
+ throw new AggregateError([cleanupFailure.error, releaseError], "OAuth callback cleanup failed")
527
+ }
528
+ throw releaseError
529
+ }
530
+
531
+ if (cleanupFailure) throw cleanupFailure.error
532
+ }
533
+
501
534
  function getSearchParamsFromInput(input: string): URLSearchParams | undefined {
502
535
  try {
503
536
  const url = new URL(input)
@@ -701,7 +734,7 @@ export async function completeAuth(
701
734
  } finally {
702
735
  if (!keepPendingForRetry) {
703
736
  try {
704
- await clearPendingAuth(runtime, serverName, oauthState, authStorageOptions)
737
+ await clearPendingAuthAndReleaseIfIdle(runtime, serverName, oauthState, authStorageOptions)
705
738
  } catch (cleanupError) {
706
739
  if (caughtError !== undefined) {
707
740
  throw new AggregateError([caughtError, cleanupError], "OAuth completion cleanup failed")
@@ -801,7 +834,7 @@ export async function authenticate(
801
834
  } catch (error) {
802
835
  if (oauthState) cancelPendingCallback(oauthState)
803
836
  try {
804
- await clearPendingAuth(runtime, serverName, oauthState, authStorageOptions)
837
+ await clearPendingAuthAndReleaseIfIdle(runtime, serverName, oauthState, authStorageOptions)
805
838
  } catch (cleanupError) {
806
839
  throw new AggregateError([error, cleanupError], "OAuth cancellation cleanup failed")
807
840
  }
@@ -922,7 +955,7 @@ export async function removeAuth(serverName: string, options: AuthenticateOption
922
955
  if (oauthState) {
923
956
  cancelPendingCallback(oauthState)
924
957
  }
925
- await clearPendingAuth(runtime, serverName, oauthState, authStorageOptions)
958
+ await clearPendingAuthAndReleaseIfIdle(runtime, serverName, oauthState, authStorageOptions)
926
959
  throwIfAborted(signal)
927
960
  clearAllCredentials(serverName, authStorageOptions)
928
961
  await clearOAuthState(serverName, authStorageOptions)