@herbertgao/pi-extensions 2026.8.13 → 2026.8.15

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 (263) hide show
  1. package/README.md +19 -14
  2. package/THIRD_PARTY_NOTICES.md +0 -1
  3. package/node_modules/@czottmann/pi-automode/CHANGELOG.md +19 -0
  4. package/node_modules/@czottmann/pi-automode/README.md +5 -1
  5. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +126 -13
  6. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +7 -3
  7. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +2 -0
  8. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +134 -23
  9. package/node_modules/@czottmann/pi-automode/package.json +1 -1
  10. package/node_modules/@herbertgao/{pi-stash → pi-bark}/LICENSE +4 -5
  11. package/node_modules/@herbertgao/pi-bark/README.md +44 -0
  12. package/node_modules/@herbertgao/pi-bark/assets/pi-icon.png +0 -0
  13. package/node_modules/@herbertgao/pi-bark/package.json +53 -0
  14. package/node_modules/@herbertgao/pi-bark/src/index.ts +178 -0
  15. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +1 -1
  16. package/node_modules/@herbertgao/pi-cc-extensions/README.md +1 -1
  17. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  18. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
  19. package/node_modules/@herbertgao/pi-subagents/package.json +2 -1
  20. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +8 -1
  21. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  22. package/node_modules/@narumitw/pi-btw/README.md +125 -88
  23. package/node_modules/@narumitw/pi-btw/dist/index.ts +140 -45
  24. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +2 -2
  25. package/node_modules/@narumitw/pi-btw/package.json +5 -8
  26. package/node_modules/@narumitw/pi-btw/src/btw.ts +31 -26
  27. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +106 -17
  28. package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -2
  29. package/node_modules/@narumitw/pi-btw/src/settings.ts +16 -0
  30. package/node_modules/@tifan/pi-handoff/README.md +36 -13
  31. package/node_modules/@tifan/pi-handoff/package.json +2 -2
  32. package/node_modules/@tifan/pi-handoff/src/index.ts +160 -4
  33. package/node_modules/@tifan/pi-preferred-thinking/README.md +1 -1
  34. package/node_modules/@tifan/pi-preferred-thinking/package.json +1 -1
  35. package/node_modules/@tifan/pi-preferred-thinking/src/index.ts +15 -2
  36. package/node_modules/@tifan/pi-recap/README.md +1 -1
  37. package/node_modules/@tifan/pi-recap/package.json +2 -2
  38. package/node_modules/@tifan/pi-recap/src/index.ts +15 -0
  39. package/node_modules/@tifan/pi-rename/README.md +42 -21
  40. package/node_modules/@tifan/pi-rename/package.json +1 -1
  41. package/node_modules/@tifan/pi-rename/src/index.ts +62 -11
  42. package/node_modules/@tifan/pi-rename/src/language.ts +18 -0
  43. package/node_modules/@tifan/pi-rename/src/models.ts +69 -13
  44. package/node_modules/@tifan/pi-rename/src/naming.ts +36 -7
  45. package/node_modules/@tifan/pi-rename/src/sanitize.ts +22 -14
  46. package/node_modules/pi-lens/CHANGELOG.md +320 -0
  47. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +79 -0
  48. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +16 -1
  49. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +13 -6
  50. package/node_modules/pi-lens/dist/clients/availability-probe-flight.js +12 -0
  51. package/node_modules/pi-lens/dist/clients/biome-client.js +7 -0
  52. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +20 -0
  53. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +56 -19
  54. package/node_modules/pi-lens/dist/clients/build-identity.js +95 -0
  55. package/node_modules/pi-lens/dist/clients/bus-publish.js +3 -0
  56. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +2 -1
  57. package/node_modules/pi-lens/dist/clients/cache-observability.js +2 -1
  58. package/node_modules/pi-lens/dist/clients/cascade-logger.js +15 -1
  59. package/node_modules/pi-lens/dist/clients/dead-code-client.js +14 -11
  60. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +56 -4
  61. package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +14 -0
  62. package/node_modules/pi-lens/dist/clients/dependency-checker.js +20 -3
  63. package/node_modules/pi-lens/dist/clients/deps/minimatch.js +1 -1
  64. package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +39 -0
  65. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +150 -9
  66. package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +231 -9
  67. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +205 -100
  68. package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +87 -0
  69. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +21 -5
  70. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +174 -55
  71. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +5 -1
  72. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +16 -3
  73. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +54 -9
  74. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +1 -3
  75. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +37 -1
  76. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -1
  77. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +11 -4
  78. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +4 -0
  79. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +8 -3
  80. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +76 -25
  81. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +4 -0
  82. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +19 -7
  83. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +7 -13
  84. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +51 -17
  85. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +66 -1
  86. package/node_modules/pi-lens/dist/clients/file-utils.js +157 -7
  87. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +5 -0
  88. package/node_modules/pi-lens/dist/clients/formatters.js +28 -3
  89. package/node_modules/pi-lens/dist/clients/git-guard.js +197 -47
  90. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +32 -1
  91. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +5 -1
  92. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +7 -0
  93. package/node_modules/pi-lens/dist/clients/installer/index.js +131 -34
  94. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +3 -1
  95. package/node_modules/pi-lens/dist/clients/instance-reaper.js +4 -13
  96. package/node_modules/pi-lens/dist/clients/instance-registry-lock.js +145 -0
  97. package/node_modules/pi-lens/dist/clients/instance-registry.js +432 -122
  98. package/node_modules/pi-lens/dist/clients/jscpd-client.js +6 -1
  99. package/node_modules/pi-lens/dist/clients/language-profile.js +4 -2
  100. package/node_modules/pi-lens/dist/clients/latency-logger.js +19 -1
  101. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  102. package/node_modules/pi-lens/dist/clients/lens-map.js +3 -1
  103. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +4 -0
  104. package/node_modules/pi-lens/dist/clients/lsp/client.js +516 -31
  105. package/node_modules/pi-lens/dist/clients/lsp/config.js +25 -2
  106. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +9 -4
  107. package/node_modules/pi-lens/dist/clients/lsp/index.js +509 -182
  108. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +5 -0
  109. package/node_modules/pi-lens/dist/clients/lsp/launch.js +36 -8
  110. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +116 -4
  111. package/node_modules/pi-lens/dist/clients/lsp/server.js +142 -13
  112. package/node_modules/pi-lens/dist/clients/lsp/session-roots.js +99 -0
  113. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +16 -6
  114. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +32 -23
  115. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +16 -2
  116. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +12 -6
  117. package/node_modules/pi-lens/dist/clients/mcp/session.js +14 -1
  118. package/node_modules/pi-lens/dist/clients/memory-sampler.js +23 -1
  119. package/node_modules/pi-lens/dist/clients/message-end-attribution.js +30 -0
  120. package/node_modules/pi-lens/dist/clients/metrics-history.js +21 -4
  121. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +232 -18
  122. package/node_modules/pi-lens/dist/clients/package-manager.js +6 -18
  123. package/node_modules/pi-lens/dist/clients/path-keyed-map.js +14 -1
  124. package/node_modules/pi-lens/dist/clients/path-utils.js +32 -0
  125. package/node_modules/pi-lens/dist/clients/pipeline.js +0 -8
  126. package/node_modules/pi-lens/dist/clients/process-singletons.js +210 -0
  127. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +2 -1
  128. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +10 -4
  129. package/node_modules/pi-lens/dist/clients/project-snapshot.js +33 -11
  130. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +24 -2
  131. package/node_modules/pi-lens/dist/clients/read-guard.js +74 -7
  132. package/node_modules/pi-lens/dist/clients/recent-touches.js +17 -5
  133. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +639 -62
  134. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +5 -1
  135. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +21 -1
  136. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +68 -0
  137. package/node_modules/pi-lens/dist/clients/runtime-session.js +30 -12
  138. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +15 -0
  139. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +106 -7
  140. package/node_modules/pi-lens/dist/clients/runtime-turn.js +242 -27
  141. package/node_modules/pi-lens/dist/clients/safe-spawn.js +158 -18
  142. package/node_modules/pi-lens/dist/clients/security-scan-client.js +48 -17
  143. package/node_modules/pi-lens/dist/clients/session-lifecycle.js +238 -42
  144. package/node_modules/pi-lens/dist/clients/sg-runner.js +27 -15
  145. package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +338 -0
  146. package/node_modules/pi-lens/dist/clients/spawn-output-cap.js +37 -0
  147. package/node_modules/pi-lens/dist/clients/spawn-timeout-cooldown.js +15 -1
  148. package/node_modules/pi-lens/dist/clients/startup-scan.js +6 -7
  149. package/node_modules/pi-lens/dist/clients/startup-timing.js +69 -4
  150. package/node_modules/pi-lens/dist/clients/string-utils.js +20 -0
  151. package/node_modules/pi-lens/dist/clients/test-runner-client.js +419 -88
  152. package/node_modules/pi-lens/dist/clients/tool-policy.js +1 -1
  153. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +11 -5
  154. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +17 -1
  155. package/node_modules/pi-lens/dist/clients/warm-attach.js +8 -10
  156. package/node_modules/pi-lens/dist/clients/word-index-logger.js +13 -1
  157. package/node_modules/pi-lens/dist/clients/word-index-store.js +448 -0
  158. package/node_modules/pi-lens/dist/clients/word-index.js +582 -104
  159. package/node_modules/pi-lens/dist/clients/workspace-topology.js +17 -0
  160. package/node_modules/pi-lens/dist/clients/zizmor-config.js +26 -6
  161. package/node_modules/pi-lens/dist/index.js +11243 -6651
  162. package/node_modules/pi-lens/dist/mcp/build-staleness.js +8 -7
  163. package/node_modules/pi-lens/dist/mcp/cli.js +3 -1
  164. package/node_modules/pi-lens/dist/mcp/server.js +6 -1
  165. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +4 -0
  166. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +14 -5
  167. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +3 -1
  168. package/node_modules/pi-lens/docs/agent-guide.md +4 -2
  169. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +41 -10
  170. package/node_modules/pi-lens/docs/astplayground.md +26 -17
  171. package/node_modules/pi-lens/package.json +5 -1
  172. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/c-no-malloc-free-test.yml +20 -0
  173. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/cpp-no-malloc-free-test.yml +25 -0
  174. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/cpp-no-printf-test.yml +19 -0
  175. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-no-fmt-println-test.yml +19 -0
  176. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-no-panic-in-lib-test.yml +17 -0
  177. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-no-underscore-func-name-test.yml +18 -0
  178. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-prefer-errors-is-test.yml +15 -0
  179. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-prefer-string-builder-test.yml +21 -0
  180. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/hyphenated-svg-attribute-test.yml +11 -0
  181. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-lateinit-test.yml +17 -0
  182. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-nullable-boolean-test.yml +15 -0
  183. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-println-test.yml +19 -0
  184. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-unnecessary-let-test.yml +7 -0
  185. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-unsafe-cast-test.yml +7 -0
  186. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-var-test.yml +7 -0
  187. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-prefer-data-class-test.yml +25 -0
  188. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-prefer-is-empty-test.yml +11 -0
  189. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-important-test.yml +21 -0
  190. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-types-test.yml +30 -0
  191. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-string-concat-in-loop-test.yml +100 -0
  192. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-system-out-println-test.yml +7 -0
  193. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/prefer-string-is-empty-test.yml +7 -0
  194. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/python-optional-type-test.yml +9 -0
  195. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/reducible-list-comprehension-test.yml +11 -0
  196. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ruby-symbol-to-proc-candidate-test.yml +10 -0
  197. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/rust-no-chars-enumerate-test.yml +7 -0
  198. package/node_modules/pi-lens/rules/ast-grep-rules/rules/c-no-malloc-free.yml +39 -0
  199. package/node_modules/pi-lens/rules/ast-grep-rules/rules/cpp-no-malloc-free.yml +45 -0
  200. package/node_modules/pi-lens/rules/ast-grep-rules/rules/cpp-no-printf.yml +41 -0
  201. package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-no-fmt-println.yml +43 -0
  202. package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-no-panic-in-lib.yml +41 -0
  203. package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-no-underscore-func-name.yml +35 -0
  204. package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-prefer-errors-is.yml +40 -0
  205. package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-prefer-string-builder.yml +43 -0
  206. package/node_modules/pi-lens/rules/ast-grep-rules/rules/hyphenated-svg-attribute.yml +32 -0
  207. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-lateinit.yml +37 -0
  208. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-nullable-boolean.yml +33 -0
  209. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-println.yml +42 -0
  210. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-unnecessary-let.yml +28 -0
  211. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-unsafe-cast.yml +28 -0
  212. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-var.yml +35 -0
  213. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-prefer-data-class.yml +66 -0
  214. package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-prefer-is-empty.yml +35 -0
  215. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-important.yml +21 -0
  216. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-types.yml +33 -0
  217. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-string-concat-in-loop.yml +90 -0
  218. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-system-out-println.yml +16 -0
  219. package/node_modules/pi-lens/rules/ast-grep-rules/rules/prefer-string-is-empty.yml +11 -0
  220. package/node_modules/pi-lens/rules/ast-grep-rules/rules/python-optional-type.yml +22 -0
  221. package/node_modules/pi-lens/rules/ast-grep-rules/rules/reducible-list-comprehension.yml +29 -0
  222. package/node_modules/pi-lens/rules/ast-grep-rules/rules/ruby-symbol-to-proc-candidate.yml +25 -0
  223. package/node_modules/pi-lens/rules/ast-grep-rules/rules/rust-no-chars-enumerate.yml +19 -0
  224. package/node_modules/pi-mcp-adapter/CHANGELOG.md +35 -0
  225. package/node_modules/pi-mcp-adapter/README.md +5 -2
  226. package/node_modules/pi-mcp-adapter/cli.js +4 -4
  227. package/node_modules/pi-mcp-adapter/commands.ts +1 -1
  228. package/node_modules/pi-mcp-adapter/config.ts +1 -0
  229. package/node_modules/pi-mcp-adapter/dist/config.js +1 -0
  230. package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -1
  231. package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.d.ts +24 -0
  232. package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.js +336 -0
  233. package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.js.map +1 -0
  234. package/node_modules/pi-mcp-adapter/dist/types.d.ts +3 -1
  235. package/node_modules/pi-mcp-adapter/dist/types.js.map +1 -1
  236. package/node_modules/pi-mcp-adapter/index.ts +90 -6
  237. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +124 -32
  238. package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +0 -2
  239. package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +89 -0
  240. package/node_modules/pi-mcp-adapter/mcp-references.ts +9 -1
  241. package/node_modules/pi-mcp-adapter/package.json +1 -1
  242. package/node_modules/pi-mcp-adapter/proxy-modes.ts +62 -22
  243. package/node_modules/pi-mcp-adapter/request-headers-command.ts +1 -1
  244. package/node_modules/pi-mcp-adapter/server-manager.ts +6 -0
  245. package/node_modules/pi-mcp-adapter/types.ts +3 -1
  246. package/node_modules/pi-web-access/CHANGELOG.md +42 -0
  247. package/node_modules/pi-web-access/README.md +26 -10
  248. package/node_modules/pi-web-access/curator-page.ts +12 -3
  249. package/node_modules/pi-web-access/curator-server.ts +3 -1
  250. package/node_modules/pi-web-access/extract.ts +88 -13
  251. package/node_modules/pi-web-access/gemini-search.ts +10 -5
  252. package/node_modules/pi-web-access/github-extract.ts +47 -3
  253. package/node_modules/pi-web-access/index.ts +40 -40
  254. package/node_modules/pi-web-access/package.json +1 -1
  255. package/node_modules/pi-web-access/page-query.ts +61 -8
  256. package/node_modules/pi-web-access/xcrawl.ts +264 -0
  257. package/package.json +19 -22
  258. package/node_modules/@herbertgao/pi-stash/README.md +0 -34
  259. package/node_modules/@herbertgao/pi-stash/package.json +0 -51
  260. package/node_modules/@herbertgao/pi-stash/src/index.ts +0 -118
  261. package/node_modules/@tifan/pi-titlebar-spinner/README.md +0 -24
  262. package/node_modules/@tifan/pi-titlebar-spinner/package.json +0 -39
  263. package/node_modules/@tifan/pi-titlebar-spinner/src/index.ts +0 -49
@@ -1,6 +1,11 @@
1
+ import { randomUUID } from "node:crypto"
1
2
  import type { AgentMessage } from "@earendil-works/pi-agent-core"
2
3
  import type { Message } from "@earendil-works/pi-ai/compat"
3
- import { sanitizeRenameText } from "@tifan/pi-rename/naming"
4
+ import {
5
+ generateRename,
6
+ getUserMessageContext,
7
+ resolveInitialModelConfig,
8
+ } from "@tifan/pi-rename/naming"
4
9
  import type {
5
10
  ExtensionAPI,
6
11
  ExtensionCommandContext,
@@ -10,6 +15,7 @@ import {
10
15
  BorderedLoader,
11
16
  convertToLlm,
12
17
  serializeConversation,
18
+ SessionManager,
13
19
  sessionEntryToContextMessages,
14
20
  } from "@earendil-works/pi-coding-agent"
15
21
  import { completeText } from "./complete-text.js"
@@ -77,6 +83,17 @@ async function nextHandoffPath(slug: string): Promise<string> {
77
83
  throw new Error("Could not allocate a unique handoff file path")
78
84
  }
79
85
 
86
+ async function generateSessionName(
87
+ ctx: ExtensionCommandContext,
88
+ messages: readonly AgentMessage[],
89
+ ): Promise<string> {
90
+ const context = getUserMessageContext(messages)
91
+ if (!context) return "handoff-session"
92
+
93
+ const result = await generateRename(ctx, resolveInitialModelConfig(), context)
94
+ return result?.name ?? "handoff-session"
95
+ }
96
+
80
97
  function buildNewSessionPrompt(handoffPath: string): string {
81
98
  return [
82
99
  "Continue from this handoff:",
@@ -85,6 +102,133 @@ function buildNewSessionPrompt(handoffPath: string): string {
85
102
  ].join("\n\n")
86
103
  }
87
104
 
105
+ type HerdrTabCreateResponse = {
106
+ result?: {
107
+ root_pane?: {
108
+ pane_id?: unknown
109
+ }
110
+ }
111
+ }
112
+
113
+ function getHerdrWorkspaceId(): string | undefined {
114
+ if (process.env["HERDR_ENV"] !== "1") return undefined
115
+
116
+ const workspaceId = process.env["HERDR_WORKSPACE_ID"]?.trim()
117
+ if (!workspaceId) {
118
+ throw new Error("Herdr workspace context is unavailable")
119
+ }
120
+ return workspaceId
121
+ }
122
+
123
+ function getHerdrRootPaneId(stdout: string): string | undefined {
124
+ try {
125
+ const response = JSON.parse(stdout) as HerdrTabCreateResponse
126
+ const paneId = response.result?.root_pane?.pane_id
127
+ return typeof paneId === "string" && paneId.trim() ? paneId : undefined
128
+ } catch {
129
+ return undefined
130
+ }
131
+ }
132
+
133
+ function getCommandError(stdout: string, stderr: string): string {
134
+ return stderr.trim() || stdout.trim() || "unknown error"
135
+ }
136
+
137
+ async function startHandoffInHerdr(options: {
138
+ pi: ExtensionAPI
139
+ ctx: ExtensionCommandContext
140
+ handoffPath: string
141
+ parentSession: string | undefined
142
+ sessionName: string
143
+ workspaceId: string
144
+ }): Promise<void> {
145
+ const childSessionManager = SessionManager.create(
146
+ options.ctx.cwd,
147
+ undefined,
148
+ options.parentSession
149
+ ? { parentSession: options.parentSession }
150
+ : undefined,
151
+ )
152
+ const childSessionPath = childSessionManager.getSessionFile()
153
+ const childSessionHeader = childSessionManager.getHeader()
154
+ if (!childSessionPath || !childSessionHeader) {
155
+ throw new Error("Could not create a persisted handoff session")
156
+ }
157
+ await mkdir(childSessionManager.getSessionDir(), { recursive: true })
158
+ await writeFile(childSessionPath, `${JSON.stringify(childSessionHeader)}\n`, {
159
+ flag: "wx",
160
+ })
161
+
162
+ const createdTab = await options.pi.exec(
163
+ "herdr",
164
+ [
165
+ "tab",
166
+ "create",
167
+ "--workspace",
168
+ options.workspaceId,
169
+ "--cwd",
170
+ options.ctx.cwd,
171
+ "--label",
172
+ options.sessionName,
173
+ "--focus",
174
+ ],
175
+ { timeout: 5_000 },
176
+ )
177
+ if (createdTab.code !== 0) {
178
+ throw new Error(
179
+ `Could not create Herdr tab: ${getCommandError(createdTab.stdout, createdTab.stderr)}`,
180
+ )
181
+ }
182
+
183
+ const rootPaneId = getHerdrRootPaneId(createdTab.stdout)
184
+ if (!rootPaneId) {
185
+ throw new Error("Could not find the new Herdr tab's root pane")
186
+ }
187
+
188
+ const agentName = `handoff-${randomUUID().slice(0, 8)}`
189
+ const model = options.ctx.model!
190
+
191
+ const startedAgent = await options.pi.exec(
192
+ "herdr",
193
+ [
194
+ "agent",
195
+ "start",
196
+ agentName,
197
+ "--kind",
198
+ "pi",
199
+ "--pane",
200
+ rootPaneId,
201
+ "--",
202
+ "--session",
203
+ childSessionPath,
204
+ "--name",
205
+ options.sessionName,
206
+ "--provider",
207
+ model.provider,
208
+ "--model",
209
+ model.id,
210
+ ],
211
+ { timeout: 35_000 },
212
+ )
213
+ if (startedAgent.code !== 0) {
214
+ throw new Error(
215
+ `Could not start Pi in Herdr tab: ${getCommandError(startedAgent.stdout, startedAgent.stderr)}`,
216
+ )
217
+ }
218
+
219
+ const promptedAgent = await options.pi.exec("herdr", [
220
+ "agent",
221
+ "prompt",
222
+ agentName,
223
+ buildNewSessionPrompt(options.handoffPath),
224
+ ])
225
+ if (promptedAgent.code !== 0) {
226
+ throw new Error(
227
+ `Could not send the handoff prompt: ${getCommandError(promptedAgent.stdout, promptedAgent.stderr)}`,
228
+ )
229
+ }
230
+ }
231
+
88
232
  function buildDocumentWithMetadata(options: {
89
233
  generated: string
90
234
  focus: string
@@ -250,9 +394,7 @@ async function runHandoff(
250
394
  return
251
395
  }
252
396
 
253
- const sessionName =
254
- sanitizeRenameText(ctx.sessionManager.getSessionName() ?? focus) ||
255
- "handoff-session"
397
+ const sessionName = await generateSessionName(ctx, messages)
256
398
  const handoffPath = await nextHandoffPath(sessionName)
257
399
  const document = buildDocumentWithMetadata({
258
400
  generated,
@@ -262,6 +404,20 @@ async function runHandoff(
262
404
  })
263
405
  await writeFile(handoffPath, document, "utf8")
264
406
 
407
+ const herdrWorkspaceId = getHerdrWorkspaceId()
408
+ if (herdrWorkspaceId) {
409
+ await startHandoffInHerdr({
410
+ pi,
411
+ ctx,
412
+ handoffPath,
413
+ parentSession,
414
+ sessionName,
415
+ workspaceId: herdrWorkspaceId,
416
+ })
417
+ ctx.ui.notify(`Handoff opened in a new Herdr tab: ${handoffPath}`, "info")
418
+ return
419
+ }
420
+
265
421
  await ctx.newSession({
266
422
  ...(parentSession ? { parentSession } : {}),
267
423
  setup: async (sessionManager) => {
@@ -41,7 +41,7 @@ The extension requires `enabledModels` to exist before it can save a pin. If
41
41
  the selected model is not listed, it adds an exact entry without removing other
42
42
  models or patterns.
43
43
 
44
- The old `~/.config/pi/extensions/pi-preferred-thinking.json` file is no longer
44
+ The old `$PI_CODING_AGENT_DIR/extensions/pi-preferred-thinking.json` file is no longer
45
45
  read. Existing users must move preferences to `enabledModels` or set them with
46
46
  `/preferred-thinking`.
47
47
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tifan/pi-preferred-thinking",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Set and apply per-model thinking levels from Pi's native settings.",
5
5
  "keywords": [
6
6
  "pi",
@@ -138,6 +138,15 @@ function showHint(ctx: ExtensionContext, modelKey: string): void {
138
138
  }, HINT_DURATION_MS)
139
139
  }
140
140
 
141
+ function hasExplicitSubagentThinking(): boolean {
142
+ return (
143
+ Boolean(process.env["PI_SUBAGENT_ID"]) &&
144
+ process.argv.some(
145
+ (arg) => arg === "--thinking" || arg.startsWith("--thinking="),
146
+ )
147
+ )
148
+ }
149
+
141
150
  function applyPreferredThinking(
142
151
  pi: ExtensionAPI,
143
152
  ctx: ExtensionContext,
@@ -210,11 +219,15 @@ export default function (pi: ExtensionAPI): void {
210
219
 
211
220
  pi.on("session_start", async (_event, ctx) => {
212
221
  nudgedModels.clear()
213
- if (ctx.model) applyPreferredThinking(pi, ctx, ctx.model)
222
+ if (ctx.model && !hasExplicitSubagentThinking()) {
223
+ applyPreferredThinking(pi, ctx, ctx.model)
224
+ }
214
225
  })
215
226
 
216
227
  pi.on("model_select", async (event, ctx) => {
217
- applyPreferredThinking(pi, ctx, event.model)
228
+ if (!hasExplicitSubagentThinking()) {
229
+ applyPreferredThinking(pi, ctx, event.model)
230
+ }
218
231
  })
219
232
 
220
233
  pi.on("session_shutdown", async (_event, ctx) => {
@@ -44,7 +44,7 @@ Run `/recap config` to choose a different model.
44
44
 
45
45
  After you choose a model, `pi-recap` uses only that model. Choose `Use default` in `/recap config` to return to the default.
46
46
 
47
- You can also edit `~/.config/pi/extensions/pi-recap.json` manually:
47
+ You can also edit `$PI_CODING_AGENT_DIR/extensions/pi-recap.json` manually:
48
48
 
49
49
  ```json
50
50
  {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tifan/pi-recap",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "description": "One-line session recap on demand or after you have been away.",
5
5
  "keywords": [
6
6
  "pi",
@@ -29,7 +29,7 @@
29
29
  "provenance": true
30
30
  },
31
31
  "peerDependencies": {
32
- "@earendil-works/pi-coding-agent": ">=0.84.2"
32
+ "@earendil-works/pi-coding-agent": ">=0.84.3"
33
33
  },
34
34
  "engines": {
35
35
  "node": ">=20"
@@ -100,6 +100,7 @@ interface RecapState {
100
100
  visible: boolean
101
101
  stale: boolean
102
102
  lastRecapCurrent: boolean
103
+ skipNextAwayRecap: boolean
103
104
  abortController: AbortController | undefined
104
105
  awayTimer: ReturnType<typeof setTimeout> | undefined
105
106
  }
@@ -113,6 +114,7 @@ function createRecapState(): RecapState {
113
114
  visible: false,
114
115
  stale: false,
115
116
  lastRecapCurrent: false,
117
+ skipNextAwayRecap: false,
116
118
  abortController: undefined,
117
119
  awayTimer: undefined,
118
120
  }
@@ -140,6 +142,7 @@ function resetRecapSession(ctx: ExtensionContext, state: RecapState): void {
140
142
  state.visible = false
141
143
  state.stale = false
142
144
  state.lastRecapCurrent = false
145
+ state.skipNextAwayRecap = false
143
146
  clearAwayTimer(state)
144
147
  abortPendingGeneration(state)
145
148
  clearWidget(ctx)
@@ -551,13 +554,25 @@ export default function (pi: ExtensionAPI): void {
551
554
  state.runId++
552
555
  state.stale = false
553
556
  state.lastRecapCurrent = false
557
+ state.skipNextAwayRecap = false
554
558
  clearAwayTimer(state)
555
559
  abortPendingGeneration(state)
556
560
  hideRecap(ctx, state)
557
561
  clearNoModelWarning(ctx)
558
562
  })
559
563
 
564
+ pi.on("session_compact_failed", (event) => {
565
+ if (event.willRetry) return
566
+ state.skipNextAwayRecap = true
567
+ clearAwayTimer(state)
568
+ })
569
+
560
570
  pi.on("agent_settled", (_event, ctx) => {
571
+ if (state.skipNextAwayRecap) {
572
+ state.skipNextAwayRecap = false
573
+ return
574
+ }
575
+
561
576
  state.stale = true
562
577
  scheduleAwayRecap(pi, ctx, state)
563
578
  })
@@ -1,6 +1,6 @@
1
1
  # @tifan/pi-rename
2
2
 
3
- Generate session names for pi and Herdr.
3
+ Generate short pi session names and rename the current Herdr pane or tab to match.
4
4
 
5
5
  ## Install
6
6
 
@@ -8,61 +8,82 @@ Generate session names for pi and Herdr.
8
8
  pi install npm:@tifan/pi-rename
9
9
  ```
10
10
 
11
- This package requires Pi 0.84.2 or newer.
11
+ Requires Pi 0.84.2 or newer.
12
12
 
13
- ## How it works
13
+ ## Usage
14
14
 
15
- Run `/rename` to generate a fresh hyphen-separated session name. The extension applies the name to the pi session and, when pi is running inside Herdr, to the current pane and tab when it is the tab's only pane, or to the current pane in a split tab.
15
+ Run:
16
16
 
17
- When a named session starts or resumes in Herdr, the extension applies the saved pi session name when the target still has its default or temporary startup label.
17
+ ```text
18
+ /rename
19
+ ```
18
20
 
19
- `/rename` builds naming context from the first user message plus up to three latest user messages. It ignores assistant replies, tool output, and attachments. Before sending context to the rename model, it redacts common secrets.
21
+ The extension:
20
22
 
21
- If the rename model is unavailable, `/rename` falls back to a local name from the latest user message.
23
+ - Builds context from the first user message and up to three latest user messages.
24
+ - Ignores assistant replies, tool output, and attachments.
25
+ - Redacts common secrets before sending context to the model.
26
+ - Creates a lowercase, hyphen-separated name of up to 30 characters.
27
+ - Falls back to the latest user message when the naming model is unavailable.
22
28
 
23
29
  ## Commands
24
30
 
25
31
  - `/rename`: Generate and apply a session name.
26
32
  - `/rename status`: Show model and rename status.
27
33
  - `/rename config`: Choose a rename model.
34
+ - `/rename config language <auto|BCP-47>`: Set session-name language.
28
35
  - `/rename help`: List rename commands.
29
36
 
30
- Manual names are not supported. Use pi's built-in `/name` command when you want an exact name.
37
+ Use pi's built-in `/name` command when you want to set an exact name.
31
38
 
32
39
  ## Configuration
33
40
 
34
- Out of the box, `pi-rename` uses this default model: `openai-codex/gpt-5.6-luna`.
41
+ Default model:
42
+
43
+ ```text
44
+ openai-codex/gpt-5.6-luna
45
+ ```
46
+
47
+ Use `/rename config` to choose another model or reset to the default.
48
+
49
+ To preserve existing behavior, names use ASCII when no language is configured. Set an output language with a BCP 47 tag, or use `auto` to follow latest user message language:
35
50
 
36
- Run `/rename config` to choose a different model.
51
+ ```bash
52
+ /rename config language <BCP-47-tag>
53
+ /rename config language auto
54
+ ```
37
55
 
38
- After you choose a model, `pi-rename` uses only that model. Choose `Use default` in `/rename config` to return to the default.
56
+ `auto` and non-`en` tags preserve Unicode letters and numbers. If rename model is unavailable, fallback uses latest user message and does not translate it.
39
57
 
40
58
  You can also edit `$PI_CODING_AGENT_DIR/extensions/pi-rename.json` manually:
41
59
 
42
60
  ```json
43
61
  {
44
- "model": "openai-codex/gpt-5.6-luna"
62
+ "model": "openai-codex/gpt-5.6-luna",
63
+ "language": "auto"
45
64
  }
46
65
  ```
47
66
 
48
- ## Herdr behavior
67
+ Use `"language": "en"` for ASCII compatibility mode. Missing or invalid language values also fall back to `en`.
49
68
 
50
- Herdr tab renaming requires the `herdr` CLI. If it is unavailable, the extension still renames the pi session.
51
-
52
- The extension uses `HERDR_PANE_ID` to find the current Herdr pane. With one pane in the tab, it renames both the pane and tab. With sibling panes, it renames only the current pane.
69
+ ## Herdr behavior
53
70
 
54
- On session startup or resume, it does not overwrite custom Herdr labels. It replaces only Herdr's default or temporary startup labels, so saved session names still apply.
71
+ - Requires the `herdr` CLI.
72
+ - With one pane, renames both the pane and tab.
73
+ - In a split tab, renames only the current pane.
74
+ - Does not replace custom labels on startup or resume.
75
+ - Replaces default or temporary startup labels.
76
+ - Keeps the last name when pi exits.
55
77
 
56
- If your launcher gives Pi a temporary Herdr label, it must set `HERDR_TEMPORARY_LABEL` before starting Pi. The value must match the label shown in Herdr. In Bash, pass it to Pi inline:
78
+ For temporary launcher labels, set `HERDR_TEMPORARY_LABEL`:
57
79
 
58
80
  ```bash
59
81
  HERDR_TEMPORARY_LABEL="my-project (pi)" pi
60
82
  ```
61
83
 
62
- If you do not set this variable, `pi-rename` replaces only Herdr's default label.
63
- On quit, the target keeps the last session name.
84
+ Without it, only Herdr's default label is replaced.
64
85
 
65
- If pi is not running inside Herdr, only the pi session name is updated.
86
+ Outside Herdr, only the pi session is renamed.
66
87
 
67
88
  ## Release notes
68
89
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tifan/pi-rename",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Generate pi session names and rename the current Herdr tab.",
5
5
  "keywords": [
6
6
  "herdr",
@@ -12,14 +12,20 @@ import type {
12
12
  import { buildSessionContext } from "@earendil-works/pi-coding-agent"
13
13
  import { pickRenameModel } from "./model-picker.js"
14
14
  import {
15
- deleteRenameConfig,
15
+ DEFAULT_RENAME_LANGUAGE,
16
+ parseRenameLanguage,
17
+ type RenameLanguage,
18
+ } from "./language.js"
19
+ import {
20
+ deleteModelPreference,
16
21
  formatAuthModelKey,
17
22
  formatModelPreference,
18
23
  formatRenameModelKey,
19
24
  getAuthenticatedTextModelPreferences,
20
25
  getRenameModelAuth,
21
- resolveInitialModelConfig,
26
+ resolveInitialRenameConfig,
22
27
  saveModelPreference,
28
+ saveRenameLanguage,
23
29
  type RenameModelConfig,
24
30
  } from "./models.js"
25
31
  import { isTemporaryHerdrLabel } from "./herdr-label.js"
@@ -32,6 +38,7 @@ interface SessionContextReader {
32
38
 
33
39
  interface RenameState {
34
40
  modelConfig: RenameModelConfig
41
+ language: RenameLanguage
35
42
  }
36
43
 
37
44
  const RENAME_SUBCOMMANDS: AutocompleteItem[] = [
@@ -55,6 +62,7 @@ const RENAME_SUBCOMMANDS: AutocompleteItem[] = [
55
62
  function createRenameState(): RenameState {
56
63
  return {
57
64
  modelConfig: { kind: "missing" },
65
+ language: DEFAULT_RENAME_LANGUAGE,
58
66
  }
59
67
  }
60
68
 
@@ -241,7 +249,12 @@ async function runRenameCommand(
241
249
  })
242
250
  }
243
251
  try {
244
- const result = await generateRename(ctx, state.modelConfig, context)
252
+ const result = await generateRename(
253
+ ctx,
254
+ state.modelConfig,
255
+ context,
256
+ state.language,
257
+ )
245
258
  if (!result) {
246
259
  ctx.ui.notify("Could not generate a session name.", "error")
247
260
  return
@@ -315,7 +328,7 @@ async function configureRenameModel(
315
328
 
316
329
  try {
317
330
  if (result.action === "default") {
318
- deleteRenameConfig()
331
+ deleteModelPreference()
319
332
  state.modelConfig = { kind: "missing" }
320
333
  ctx.ui.notify("Rename model reset to default.", "info")
321
334
  return
@@ -334,6 +347,28 @@ async function configureRenameModel(
334
347
  }
335
348
  }
336
349
 
350
+ function configureRenameLanguage(
351
+ ctx: ExtensionContext,
352
+ state: RenameState,
353
+ value: string | undefined,
354
+ ): void {
355
+ const language = parseRenameLanguage(value)
356
+ if (!language) {
357
+ ctx.ui.notify("Use /rename config language <auto|BCP-47>", "error")
358
+ return
359
+ }
360
+
361
+ try {
362
+ saveRenameLanguage(language)
363
+ state.language = language
364
+ ctx.ui.notify(`Rename language set to ${language}.`, "info")
365
+ } catch (error) {
366
+ const reason =
367
+ error instanceof SyntaxError ? "invalid JSON" : "write failed"
368
+ ctx.ui.notify(`Could not update rename config: ${reason}.`, "error")
369
+ }
370
+ }
371
+
337
372
  async function notifyRenameStatus(
338
373
  ctx: ExtensionContext,
339
374
  state: RenameState,
@@ -365,6 +400,7 @@ async function notifyRenameStatus(
365
400
  "pi-rename status",
366
401
  selectedModelLine,
367
402
  activeModelLine,
403
+ `language: ${state.language}`,
368
404
  herdrLine,
369
405
  contextLine,
370
406
  ].join("\n"),
@@ -377,20 +413,22 @@ function registerRenameCommand(pi: ExtensionAPI, state: RenameState): void {
377
413
  description: "generate a session name",
378
414
  getArgumentCompletions: getRenameArgumentCompletions,
379
415
  handler: async (args, ctx) => {
380
- const action = args.trim().split(/\s+/u)[0]?.toLowerCase() ?? ""
416
+ const [action = "", ...actionArgs] = args.trim().split(/\s+/u)
417
+ const normalizedAction = action.toLowerCase()
381
418
 
382
- if (!action) {
419
+ if (!normalizedAction) {
383
420
  await runRenameCommand(pi, ctx, state)
384
421
  return
385
422
  }
386
423
 
387
- if (action === "help") {
424
+ if (normalizedAction === "help") {
388
425
  ctx.ui.notify(
389
426
  [
390
427
  "pi-rename commands",
391
428
  "/rename - generate and apply a session name",
392
429
  "/rename status - show model and rename status",
393
430
  "/rename config - choose the rename model",
431
+ "/rename config language <auto|BCP-47> - set name language",
394
432
  "/rename help - show this help",
395
433
  ].join("\n"),
396
434
  "info",
@@ -398,13 +436,24 @@ function registerRenameCommand(pi: ExtensionAPI, state: RenameState): void {
398
436
  return
399
437
  }
400
438
 
401
- if (action === "status") {
439
+ if (normalizedAction === "status") {
402
440
  await notifyRenameStatus(ctx, state)
403
441
  return
404
442
  }
405
443
 
406
- if (action === "config") {
407
- await configureRenameModel(ctx, state)
444
+ if (normalizedAction === "config") {
445
+ const [setting, value, extra] = actionArgs
446
+ if (!setting) {
447
+ await configureRenameModel(ctx, state)
448
+ return
449
+ }
450
+
451
+ if (setting.toLowerCase() === "language" && !extra) {
452
+ configureRenameLanguage(ctx, state, value)
453
+ return
454
+ }
455
+
456
+ ctx.ui.notify("Use /rename config language <auto|BCP-47>", "error")
408
457
  return
409
458
  }
410
459
 
@@ -419,7 +468,9 @@ export default function (pi: ExtensionAPI): void {
419
468
  registerRenameCommand(pi, state)
420
469
 
421
470
  pi.on("session_start", async () => {
422
- state.modelConfig = resolveInitialModelConfig()
471
+ const initialConfig = resolveInitialRenameConfig()
472
+ state.modelConfig = initialConfig.modelConfig
473
+ state.language = initialConfig.language
423
474
 
424
475
  const sessionName = pi.getSessionName()?.trim()
425
476
  if (!sessionName) return
@@ -0,0 +1,18 @@
1
+ export const DEFAULT_RENAME_LANGUAGE = "en"
2
+ export type RenameLanguage = string
3
+
4
+ export function parseRenameLanguage(
5
+ value: unknown,
6
+ ): RenameLanguage | undefined {
7
+ if (typeof value !== "string") return undefined
8
+
9
+ const trimmed = value.trim()
10
+ if (trimmed.toLowerCase() === "auto") return "auto"
11
+ if (!trimmed) return undefined
12
+
13
+ try {
14
+ return Intl.getCanonicalLocales(trimmed)[0]
15
+ } catch {
16
+ return undefined
17
+ }
18
+ }