@herbertgao/pi-extensions 2026.8.15 → 2026.9.1

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 (351) hide show
  1. package/README.md +4 -1
  2. package/THIRD_PARTY_NOTICES.md +26 -0
  3. package/node_modules/@czottmann/pi-automode/CHANGELOG.md +13 -1
  4. package/node_modules/@czottmann/pi-automode/README.md +20 -0
  5. package/node_modules/@czottmann/pi-automode/docs/GLOSSARY.md +1 -1
  6. package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +2 -1
  7. package/node_modules/@czottmann/pi-automode/docs/defaults.md +3 -2
  8. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +38 -2
  9. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +5 -3
  10. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +11 -3
  11. package/node_modules/@czottmann/pi-automode/package.json +1 -1
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +20 -0
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +46 -3
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +55 -17
  15. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/packets.ts +6 -0
  16. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/scroll.ts +5 -0
  17. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +34 -30
  18. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  19. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  20. package/node_modules/@narumitw/pi-btw/README.md +5 -1
  21. package/node_modules/@narumitw/pi-btw/dist/index.ts +143 -14
  22. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +3 -3
  23. package/node_modules/@narumitw/pi-btw/package.json +4 -4
  24. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +158 -7
  25. package/node_modules/@narumitw/pi-btw/src/text.ts +18 -0
  26. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +5 -16
  27. package/node_modules/@narumitw/pi-caffeinate/LICENSE +21 -0
  28. package/node_modules/@narumitw/pi-caffeinate/README.md +224 -0
  29. package/node_modules/@narumitw/pi-caffeinate/dist/index.ts +1112 -0
  30. package/node_modules/@narumitw/pi-caffeinate/dist/index.ts.map +7 -0
  31. package/node_modules/@narumitw/pi-caffeinate/package.json +53 -0
  32. package/node_modules/@narumitw/pi-caffeinate/src/caffeinate.ts +811 -0
  33. package/node_modules/@narumitw/pi-caffeinate/src/dbus-inhibit.ts +153 -0
  34. package/node_modules/@narumitw/pi-caffeinate/src/index.ts +1 -0
  35. package/node_modules/@narumitw/pi-caffeinate/src/inhibitor-process.ts +43 -0
  36. package/node_modules/@narumitw/pi-caffeinate/src/inhibitors.ts +167 -0
  37. package/node_modules/@narumitw/pi-caffeinate/src/settings.ts +202 -0
  38. package/node_modules/@pi-plugins/fast-mode/README.md +5 -3
  39. package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts.map +1 -1
  40. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +20 -55
  41. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
  42. package/node_modules/@pi-plugins/fast-mode/package.json +1 -1
  43. package/node_modules/@tifan/pi-handoff/README.md +6 -3
  44. package/node_modules/@tifan/pi-handoff/package.json +1 -1
  45. package/node_modules/@tifan/pi-handoff/src/index.ts +8 -3
  46. package/node_modules/pi-lens/CHANGELOG.md +988 -0
  47. package/node_modules/pi-lens/README.md +3 -0
  48. package/node_modules/pi-lens/config/biome/core.jsonc +11 -2
  49. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +13 -1
  50. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +2 -2
  51. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +927 -80
  52. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +13 -4
  53. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +123 -3
  54. package/node_modules/pi-lens/dist/clients/ast-grep-rule-manager.js +60 -5
  55. package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +2 -2
  56. package/node_modules/pi-lens/dist/clients/bash-file-access.js +1 -3
  57. package/node_modules/pi-lens/dist/clients/biome-client.js +9 -2
  58. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +14 -0
  59. package/node_modules/pi-lens/dist/clients/bootstrap.js +509 -73
  60. package/node_modules/pi-lens/dist/clients/bounded-cache.js +152 -12
  61. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +59 -4
  62. package/node_modules/pi-lens/dist/clients/bundled-resource-health.js +113 -0
  63. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +2 -2
  64. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +31 -4
  65. package/node_modules/pi-lens/dist/clients/cache-manager.js +105 -6
  66. package/node_modules/pi-lens/dist/clients/cache-observability.js +44 -18
  67. package/node_modules/pi-lens/dist/clients/cargo-manifest.js +422 -0
  68. package/node_modules/pi-lens/dist/clients/cascade-logger.js +2 -2
  69. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +13 -3
  70. package/node_modules/pi-lens/dist/clients/complexity-client.js +16 -5
  71. package/node_modules/pi-lens/dist/clients/config-core/deny.js +221 -0
  72. package/node_modules/pi-lens/dist/clients/config-core/index.js +47 -0
  73. package/node_modules/pi-lens/dist/clients/config-core/merge.js +357 -0
  74. package/node_modules/pi-lens/dist/clients/config-core/normalize.js +340 -0
  75. package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +248 -0
  76. package/node_modules/pi-lens/dist/clients/config-core/provenance.js +171 -0
  77. package/node_modules/pi-lens/dist/clients/config-core/records.js +218 -0
  78. package/node_modules/pi-lens/dist/clients/config-core/resolve.js +125 -0
  79. package/node_modules/pi-lens/dist/clients/config-core/safe-object.js +78 -0
  80. package/node_modules/pi-lens/dist/clients/config-core/schema.js +167 -0
  81. package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +281 -0
  82. package/node_modules/pi-lens/dist/clients/config-locations.js +160 -0
  83. package/node_modules/pi-lens/dist/clients/config-resolve.js +789 -0
  84. package/node_modules/pi-lens/dist/clients/config-schema.js +197 -0
  85. package/node_modules/pi-lens/dist/clients/config-warn.js +407 -0
  86. package/node_modules/pi-lens/dist/clients/dead-code-client.js +19 -14
  87. package/node_modules/pi-lens/dist/clients/dead-code-logger.js +2 -2
  88. package/node_modules/pi-lens/dist/clients/deadline-utils.js +178 -0
  89. package/node_modules/pi-lens/dist/clients/debug-handles.js +2 -2
  90. package/node_modules/pi-lens/dist/clients/debug-heap.js +3 -3
  91. package/node_modules/pi-lens/dist/clients/deferred-lsp-work.js +106 -0
  92. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +113 -7
  93. package/node_modules/pi-lens/dist/clients/dependency-checker.js +8 -19
  94. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +12 -9
  95. package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +14 -4
  96. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +162 -18
  97. package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +97 -0
  98. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +9 -7
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +0 -1
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +380 -26
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +0 -1
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +0 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +0 -1
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +0 -1
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +0 -1
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +0 -1
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +0 -1
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +0 -1
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +0 -1
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/fact-rules.js +0 -1
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +0 -1
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +0 -1
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +1 -3
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +0 -1
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +0 -1
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +0 -1
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +0 -1
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +0 -1
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +0 -1
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +0 -1
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +0 -1
  122. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +0 -1
  123. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +0 -1
  124. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +13 -18
  125. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +0 -1
  126. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +0 -1
  127. package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +0 -1
  128. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -1
  129. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +7 -4
  130. package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +0 -1
  131. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +0 -1
  132. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +1 -3
  133. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +0 -1
  134. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +0 -1
  135. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +0 -1
  136. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +0 -1
  137. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +0 -1
  138. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +0 -1
  139. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +0 -1
  140. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +0 -1
  141. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +0 -1
  142. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +0 -1
  143. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +0 -1
  144. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +0 -1
  145. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +3 -0
  146. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +3 -4
  147. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +194 -80
  148. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +84 -15
  149. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +0 -1
  150. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +0 -1
  151. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +0 -1
  152. package/node_modules/pi-lens/dist/clients/disposition-logger.js +3 -3
  153. package/node_modules/pi-lens/dist/clients/effective-config.js +403 -0
  154. package/node_modules/pi-lens/dist/clients/error-class.js +23 -0
  155. package/node_modules/pi-lens/dist/clients/event-loop-hold.js +274 -0
  156. package/node_modules/pi-lens/dist/clients/extension-log.js +2 -2
  157. package/node_modules/pi-lens/dist/clients/feature-hints.js +2 -1
  158. package/node_modules/pi-lens/dist/clients/file-time.js +6 -1
  159. package/node_modules/pi-lens/dist/clients/file-utils.js +112 -9
  160. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +50 -13
  161. package/node_modules/pi-lens/dist/clients/format-service.js +6 -1
  162. package/node_modules/pi-lens/dist/clients/formatters.js +276 -102
  163. package/node_modules/pi-lens/dist/clients/freshness-cadence.js +17 -0
  164. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +114 -19
  165. package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -9
  166. package/node_modules/pi-lens/dist/clients/git-guard.js +1 -1
  167. package/node_modules/pi-lens/dist/clients/go-client.js +39 -0
  168. package/node_modules/pi-lens/dist/clients/gradle-ktfmt-style.js +252 -0
  169. package/node_modules/pi-lens/dist/clients/hashline-anchor.js +424 -0
  170. package/node_modules/pi-lens/dist/clients/hook-budgets.js +76 -0
  171. package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +5 -2
  172. package/node_modules/pi-lens/dist/clients/host-ports.js +1 -1
  173. package/node_modules/pi-lens/dist/clients/installer/index.js +71 -52
  174. package/node_modules/pi-lens/dist/clients/instance-reaper.js +104 -230
  175. package/node_modules/pi-lens/dist/clients/instance-registry.js +6 -3
  176. package/node_modules/pi-lens/dist/clients/language-registry.js +595 -0
  177. package/node_modules/pi-lens/dist/clients/latency-logger.js +160 -2
  178. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +13 -0
  179. package/node_modules/pi-lens/dist/clients/lens-config.js +141 -30
  180. package/node_modules/pi-lens/dist/clients/lens-engine.js +30 -37
  181. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +59 -6
  182. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -2
  183. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +3 -1
  184. package/node_modules/pi-lens/dist/clients/lsp/client.js +168 -30
  185. package/node_modules/pi-lens/dist/clients/lsp/config.js +483 -158
  186. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +1 -1
  187. package/node_modules/pi-lens/dist/clients/lsp/edits.js +15 -2
  188. package/node_modules/pi-lens/dist/clients/lsp/index.js +676 -71
  189. package/node_modules/pi-lens/dist/clients/lsp/language.js +18 -169
  190. package/node_modules/pi-lens/dist/clients/lsp/launch.js +2 -1
  191. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +5 -16
  192. package/node_modules/pi-lens/dist/clients/lsp/server.js +284 -147
  193. package/node_modules/pi-lens/dist/clients/lsp/session-roots.js +116 -23
  194. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +2 -7
  195. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +9 -2
  196. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +1 -1
  197. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +163 -21
  198. package/node_modules/pi-lens/dist/clients/map-with-concurrency.js +36 -0
  199. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +33 -4
  200. package/node_modules/pi-lens/dist/clients/mcp/session.js +5 -16
  201. package/node_modules/pi-lens/dist/clients/memory-sampler.js +8 -3
  202. package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +2 -4
  203. package/node_modules/pi-lens/dist/clients/module-report.js +20 -45
  204. package/node_modules/pi-lens/dist/clients/mutating-tool.js +651 -0
  205. package/node_modules/pi-lens/dist/clients/mutation-attribution.js +368 -0
  206. package/node_modules/pi-lens/dist/clients/mutation-bridge.js +240 -0
  207. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +247 -20
  208. package/node_modules/pi-lens/dist/clients/observed-mutation-sources.js +101 -0
  209. package/node_modules/pi-lens/dist/clients/observed-mutation.js +1215 -0
  210. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +68 -22
  211. package/node_modules/pi-lens/dist/clients/opengrep-config.js +4 -0
  212. package/node_modules/pi-lens/dist/clients/package-manager.js +195 -26
  213. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +359 -80
  214. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +23 -7
  215. package/node_modules/pi-lens/dist/clients/path-keyed-map.js +21 -2
  216. package/node_modules/pi-lens/dist/clients/path-utils.js +428 -13
  217. package/node_modules/pi-lens/dist/clients/persist-debounce.js +8 -1
  218. package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +114 -0
  219. package/node_modules/pi-lens/dist/clients/pipeline.js +77 -16
  220. package/node_modules/pi-lens/dist/clients/probe-home-state.js +228 -0
  221. package/node_modules/pi-lens/dist/clients/process-bridge.js +66 -0
  222. package/node_modules/pi-lens/dist/clients/process-snapshot.js +68 -0
  223. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +4 -3
  224. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +27 -3
  225. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +51 -20
  226. package/node_modules/pi-lens/dist/clients/project-lens-config.js +393 -122
  227. package/node_modules/pi-lens/dist/clients/project-snapshot.js +52 -24
  228. package/node_modules/pi-lens/dist/clients/python-environment.js +217 -0
  229. package/node_modules/pi-lens/dist/clients/python-provenance.js +639 -0
  230. package/node_modules/pi-lens/dist/clients/quiet-window.js +6 -1
  231. package/node_modules/pi-lens/dist/clients/read-bridge.js +13 -21
  232. package/node_modules/pi-lens/dist/clients/read-expansion.js +9 -46
  233. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +15 -4
  234. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +364 -212
  235. package/node_modules/pi-lens/dist/clients/read-guard.js +21 -0
  236. package/node_modules/pi-lens/dist/clients/resource-sampler.js +195 -96
  237. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +152 -109
  238. package/node_modules/pi-lens/dist/clients/review-graph/service.js +55 -3
  239. package/node_modules/pi-lens/dist/clients/review-graph/shared-extraction-ir.js +7 -15
  240. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +10 -74
  241. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +9 -3
  242. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +18 -2
  243. package/node_modules/pi-lens/dist/clients/runtime-context.js +49 -16
  244. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +25 -6
  245. package/node_modules/pi-lens/dist/clients/runtime-session.js +139 -22
  246. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +168 -35
  247. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +797 -243
  248. package/node_modules/pi-lens/dist/clients/runtime-turn.js +1028 -53
  249. package/node_modules/pi-lens/dist/clients/rust-client.js +31 -0
  250. package/node_modules/pi-lens/dist/clients/safe-spawn.js +33 -10
  251. package/node_modules/pi-lens/dist/clients/sanitize.js +7 -1
  252. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +1 -3
  253. package/node_modules/pi-lens/dist/clients/security-scan-client.js +3 -0
  254. package/node_modules/pi-lens/dist/clients/session-lifecycle.js +1 -1
  255. package/node_modules/pi-lens/dist/clients/session-start-observability.js +79 -0
  256. package/node_modules/pi-lens/dist/clients/sessionstart-logger.js +12 -3
  257. package/node_modules/pi-lens/dist/clients/sgconfig.js +6 -1
  258. package/node_modules/pi-lens/dist/clients/skills-resolver.js +105 -0
  259. package/node_modules/pi-lens/dist/clients/smells-rollup.js +2 -2
  260. package/node_modules/pi-lens/dist/clients/string-utils.js +13 -0
  261. package/node_modules/pi-lens/dist/clients/subagent-mode.js +17 -4
  262. package/node_modules/pi-lens/dist/clients/test-runner-client.js +176 -39
  263. package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +239 -0
  264. package/node_modules/pi-lens/dist/clients/tool-definition.js +41 -1
  265. package/node_modules/pi-lens/dist/clients/tool-policy.js +91 -21
  266. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +40 -40
  267. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +86 -48
  268. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +2 -2
  269. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +81 -1
  270. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +51 -46
  271. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +28 -0
  272. package/node_modules/pi-lens/dist/clients/typos-config.js +5 -0
  273. package/node_modules/pi-lens/dist/clients/user-notify.js +6 -2
  274. package/node_modules/pi-lens/dist/clients/widget-state.js +191 -26
  275. package/node_modules/pi-lens/dist/clients/word-index-logger.js +2 -2
  276. package/node_modules/pi-lens/dist/clients/word-index-store.js +20 -5
  277. package/node_modules/pi-lens/dist/clients/word-index.js +243 -31
  278. package/node_modules/pi-lens/dist/clients/workspace-topology.js +8 -1
  279. package/node_modules/pi-lens/dist/clients/zizmor-config.js +3 -0
  280. package/node_modules/pi-lens/dist/index.js +64335 -54300
  281. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -1
  282. package/node_modules/pi-lens/dist/mcp/server.js +127 -5
  283. package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +583 -0
  284. package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +129 -0
  285. package/node_modules/pi-lens/dist/tools/effective-config.js +89 -0
  286. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +95 -24
  287. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +67 -80
  288. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +37 -16
  289. package/node_modules/pi-lens/dist/tools/shared.js +0 -1
  290. package/node_modules/pi-lens/docs/agent-guide.md +64 -1
  291. package/node_modules/pi-lens/docs/configuration.md +222 -0
  292. package/node_modules/pi-lens/docs/dependencies.md +3 -3
  293. package/node_modules/pi-lens/docs/features.md +44 -5
  294. package/node_modules/pi-lens/docs/language-coverage.md +2 -2
  295. package/node_modules/pi-lens/docs/pi-lens-fixer.md +25 -0
  296. package/node_modules/pi-lens/docs/pi-lens-investigator.md +25 -0
  297. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +27 -0
  298. package/node_modules/pi-lens/docs/pi-lens-subagent.md +38 -0
  299. package/node_modules/pi-lens/docs/pi-lens-warden.md +55 -0
  300. package/node_modules/pi-lens/docs/public-api-stability.md +359 -0
  301. package/node_modules/pi-lens/docs/release-qa-baseline.md +182 -0
  302. package/node_modules/pi-lens/docs/subagent-compat.md +110 -30
  303. package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +2 -2
  304. package/node_modules/pi-lens/package.json +15 -23
  305. package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-cross-language-method.yml +3 -3
  306. package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-hallucinated-import.yml +2 -2
  307. package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-sql-injection.yml +12 -2
  308. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +192 -1
  309. package/node_modules/pi-lens/scripts/install-selftest.mjs +58 -2
  310. package/node_modules/pi-lens/scripts/lib/skills-predicate.mjs +129 -0
  311. package/node_modules/pi-lens/scripts/rpc-load-check.mjs +3 -1
  312. package/node_modules/pi-mcp-adapter/CHANGELOG.md +27 -0
  313. package/node_modules/pi-mcp-adapter/README.md +13 -13
  314. package/node_modules/pi-mcp-adapter/commands.ts +58 -21
  315. package/node_modules/pi-mcp-adapter/config.ts +18 -4
  316. package/node_modules/pi-mcp-adapter/direct-tools.ts +26 -6
  317. package/node_modules/pi-mcp-adapter/dist/config.d.ts +4 -0
  318. package/node_modules/pi-mcp-adapter/dist/config.js +13 -4
  319. package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -1
  320. package/node_modules/pi-mcp-adapter/dist/types.d.ts +11 -3
  321. package/node_modules/pi-mcp-adapter/dist/types.js.map +1 -1
  322. package/node_modules/pi-mcp-adapter/error-signal.ts +15 -4
  323. package/node_modules/pi-mcp-adapter/errors.ts +141 -0
  324. package/node_modules/pi-mcp-adapter/host-html-template.ts +58 -5
  325. package/node_modules/pi-mcp-adapter/index.ts +2 -3
  326. package/node_modules/pi-mcp-adapter/init.ts +5 -0
  327. package/node_modules/pi-mcp-adapter/mcp-panel.ts +30 -9
  328. package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +66 -28
  329. package/node_modules/pi-mcp-adapter/mcp-status.ts +2 -0
  330. package/node_modules/pi-mcp-adapter/package.json +2 -1
  331. package/node_modules/pi-mcp-adapter/proxy-modes.ts +66 -13
  332. package/node_modules/pi-mcp-adapter/sandbox-proxy-template.ts +217 -0
  333. package/node_modules/pi-mcp-adapter/server-manager.ts +337 -6
  334. package/node_modules/pi-mcp-adapter/skills/mcp-scripting/SKILL.md +1 -0
  335. package/node_modules/pi-mcp-adapter/types.ts +18 -3
  336. package/node_modules/pi-mcp-adapter/ui-resource-handler.ts +18 -2
  337. package/node_modules/pi-mcp-adapter/ui-server.ts +179 -54
  338. package/node_modules/pi-mcp-adapter/ui-session.ts +28 -8
  339. package/node_modules/pi-web-access/CHANGELOG.md +28 -0
  340. package/node_modules/pi-web-access/README.md +62 -15
  341. package/node_modules/pi-web-access/curator-page.ts +3 -1
  342. package/node_modules/pi-web-access/curator-server.ts +5 -1
  343. package/node_modules/pi-web-access/gemini-search.ts +8 -4
  344. package/node_modules/pi-web-access/github-extract.ts +242 -1
  345. package/node_modules/pi-web-access/index.ts +118 -64
  346. package/node_modules/pi-web-access/mistral-search.ts +281 -0
  347. package/node_modules/pi-web-access/package.json +2 -2
  348. package/node_modules/pi-web-access/perplexity.ts +14 -1
  349. package/node_modules/pi-web-access/utils.ts +23 -6
  350. package/node_modules/pi-web-access/xai-search.ts +96 -33
  351. package/package.json +15 -11
@@ -2,21 +2,14 @@ import { getAgentDir } from "@earendil-works/pi-coding-agent";
2
2
  import * as NodeServices from "@effect/platform-node/NodeServices";
3
3
  import { Array, Cause, Data, Effect, Exit, FileSystem, Inspectable, Match, Order, Path, Predicate, Record, Schema, String, pipe } from "effect";
4
4
  //#region ../../tooling/shared/src/run.ts
5
- const ABORT_MESSAGE = "Operation aborted";
6
5
  function causeMessage(cause) {
7
- if (Cause.hasInterruptsOnly(cause)) return ABORT_MESSAGE;
6
+ if (Cause.hasInterruptsOnly(cause)) return "Operation aborted";
8
7
  if (Cause.hasDies(cause)) return Cause.pretty(cause);
9
8
  return cause.reasons.filter(Cause.isFailReason).map(({ error }) => {
10
9
  if (error instanceof Error) return error.message || error.name;
11
10
  return typeof error === "string" ? error : Inspectable.toStringUnknown(error);
12
11
  }).join("\n");
13
12
  }
14
- /**
15
- * For boundaries where pi reports rejections but expected failures should
16
- * degrade gracefully (event hooks, commands, background work). Expected
17
- * failures and interrupts never reject. Without `onError` they vanish, while
18
- * defects rethrow so pi's handler boundary reports the bug.
19
- */
20
13
  async function runHandler(effect, options) {
21
14
  const exit = await Effect.runPromiseExit(effect);
22
15
  if (Exit.isSuccess(exit)) return exit.value;
@@ -26,11 +19,6 @@ async function runHandler(effect, options) {
26
19
  }
27
20
  //#endregion
28
21
  //#region ../../tooling/shared/src/config.ts
29
- /**
30
- * A missing config file yields `defaults` silently. An unreadable or invalid
31
- * one warns and yields `defaults`, so a typo downgrades the extension rather
32
- * than breaking it.
33
- */
34
22
  const loadExtensionConfig = Effect.fnUntraced(function* (_ctx, schema, name, _defaults) {
35
23
  const fs = yield* FileSystem.FileSystem;
36
24
  const file = (yield* Path.Path).join(getAgentDir(), "extensions", `${name}.json`);
@@ -44,44 +32,16 @@ const loadExtensionConfig = Effect.fnUntraced(function* (_ctx, schema, name, _de
44
32
  //#region ../../tooling/shared/src/statusline.ts
45
33
  const WIDGET_KEY = "pi-plugins:statusline";
46
34
  const REGISTRY_KEY = Symbol.for("@pi-plugins/statusline-registry");
47
- function registry() {
48
- const store = globalThis;
49
- store[REGISTRY_KEY] ??= /* @__PURE__ */ new Map();
50
- return store[REGISTRY_KEY];
51
- }
52
- const byKey = Order.mapInput(Order.String, ([key]) => key);
53
35
  function side(segments, align) {
54
- return pipe(Array.fromIterable(segments), Array.filter(([, segment]) => segment.align === align), Array.sortBy(byKey), Array.map(([, segment]) => segment.text), Array.join(" · "));
36
+ return pipe(Array.fromIterable(segments), Array.filter(([, segment]) => segment.align === align), Array.sortBy(Order.mapInput(Order.String, ([key]) => key)), Array.map(([, segment]) => segment.text), Array.join(" · "));
55
37
  }
56
- /** Terminal columns of plain text (code points, no ANSI). */
57
38
  function textWidth(text) {
58
39
  return Array.fromIterable(text).length;
59
40
  }
60
- function truncate(text, columns) {
61
- return pipe(Array.fromIterable(text), Array.take(columns), Array.join(""));
62
- }
63
- /**
64
- * Lays out `left ... right` across `width`: left indented one column to match
65
- * pi's built-in widget rows, right flush against the terminal edge to match
66
- * pi's footer. Falls back to one truncated `left · right` run when too narrow.
67
- */
68
- function renderLine(segments, width, theme) {
69
- const left = side(segments, "left");
70
- const right = side(segments, "right");
71
- const margin = Math.min(width, 1);
72
- const inner = width - margin;
73
- const gap = inner - textWidth(left) - textWidth(right);
74
- const minGap = String.isNonEmpty(left) && String.isNonEmpty(right) ? 2 : 0;
75
- const line = String.isNonEmpty(right) && gap >= minGap ? `${left}${" ".repeat(gap)}${right}` : truncate(pipe([left, right], Array.filter(String.isNonEmpty), Array.join(" · ")), Math.max(inner, 0));
76
- return " ".repeat(margin) + theme.fg("dim", line);
77
- }
78
- /**
79
- * Adds, replaces (`segment`), or removes (`undefined`) a keyed segment on a
80
- * single status line above the editor shared across pi-plugins extensions,
81
- * instead of each plugin stacking its own widget row.
82
- */
83
41
  function setStatuslineSegment(ctx, key, segment) {
84
- const segments = registry();
42
+ const store = globalThis;
43
+ store[REGISTRY_KEY] ??= /* @__PURE__ */ new Map();
44
+ const segments = store[REGISTRY_KEY];
85
45
  if (segment === void 0) segments.delete(key);
86
46
  else segments.set(key, segment);
87
47
  if (!ctx.hasUI) return;
@@ -90,8 +50,17 @@ function setStatuslineSegment(ctx, key, segment) {
90
50
  return;
91
51
  }
92
52
  ctx.ui.setWidget(WIDGET_KEY, (_tui, theme) => ({
93
- render: (width) => [renderLine(segments, width, theme)],
94
- invalidate: () => {}
53
+ invalidate: () => {},
54
+ render: (width) => {
55
+ const left = side(segments, "left");
56
+ const right = side(segments, "right");
57
+ const margin = Math.min(width, 1);
58
+ const inner = width - margin;
59
+ const gap = inner - textWidth(left) - textWidth(right);
60
+ const minGap = String.isNonEmpty(left) && String.isNonEmpty(right) ? 2 : 0;
61
+ const line = String.isNonEmpty(right) && gap >= minGap ? `${left}${" ".repeat(gap)}${right}` : pipe([left, right], Array.filter(String.isNonEmpty), Array.join(" · "), Array.fromIterable, Array.take(Math.max(inner, 0)), Array.join(""));
62
+ return [" ".repeat(margin) + theme.fg("dim", line)];
63
+ }
95
64
  }));
96
65
  }
97
66
  //#endregion
@@ -102,30 +71,26 @@ const COMMAND_ARGS = [
102
71
  "off",
103
72
  "status"
104
73
  ];
105
- /** Status-line segment shown above the editor while fast mode is active. */
106
74
  const SEGMENT_KEY = EXTENSION_ID;
107
75
  const SEGMENT_LABEL = "[fast mode]";
108
76
  const FastModeConfig = Schema.Struct({
109
77
  enabled: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))),
110
- /** `provider/model-id` keys that fast mode applies to. */
111
78
  models: Schema.Array(Schema.String).pipe(Schema.withDecodingDefault(Effect.succeed([
112
79
  "openai/gpt-5.4",
113
80
  "openai/gpt-5.5",
114
81
  "openai/gpt-5.6-sol",
115
82
  "openai/gpt-5.6-terra",
116
83
  "openai/gpt-5.6-luna",
84
+ "openai/gpt-6-astra",
117
85
  "openai-codex/gpt-5.4",
118
86
  "openai-codex/gpt-5.5",
119
87
  "openai-codex/gpt-5.6-sol",
120
88
  "openai-codex/gpt-5.6-terra",
121
- "openai-codex/gpt-5.6-luna"
89
+ "openai-codex/gpt-5.6-luna",
90
+ "openai-codex/gpt-6-astra"
122
91
  ]))),
123
- /** Show a `fast mode` indicator above the editor while active. */
124
92
  showStatus: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(true)))
125
93
  });
126
- function modelKey(model) {
127
- return `${model.provider}/${model.id}`;
128
- }
129
94
  const Eligibility = Data.taggedEnum();
130
95
  const FAST_APPLICATORS = {
131
96
  "openai-responses": applyOpenAIPriorityTier,
@@ -142,7 +107,7 @@ function fastMode(pi) {
142
107
  let enabled = false;
143
108
  function checkEligibility(model) {
144
109
  if (!model) return Eligibility.Ineligible({ message: "no model is selected" });
145
- const key = modelKey(model);
110
+ const key = `${model.provider}/${model.id}`;
146
111
  if (!config.models.includes(key)) return Eligibility.Ineligible({ message: `${key} is not in the configured models` });
147
112
  const apply = FAST_APPLICATORS[model.api];
148
113
  if (!apply) return Eligibility.Ineligible({ message: `the ${model.api} API has no fast-mode support` });
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../tooling/shared/src/run.ts","../../../tooling/shared/src/config.ts","../../../tooling/shared/src/statusline.ts","../src/index.ts"],"sourcesContent":["import { Cause, Effect, Exit, Inspectable } from 'effect'\n\n// What pi's own tools throw for a cancelled run, so interrupted plugin runs\n// read like interrupted builtins.\nconst ABORT_MESSAGE = 'Operation aborted'\n\nexport interface RunOptions {\n readonly signal?: AbortSignal | undefined\n}\n\n// Defects keep their stack because they are bugs, and win over failures in a\n// mixed cause.\nfunction causeMessage(cause: Cause.Cause<unknown>): string {\n if (Cause.hasInterruptsOnly(cause)) {\n return ABORT_MESSAGE\n }\n if (Cause.hasDies(cause)) {\n return Cause.pretty(cause)\n }\n return cause.reasons\n .filter(Cause.isFailReason)\n .map(({ error }) => {\n if (error instanceof Error) {\n return error.message || error.name\n }\n return typeof error === 'string' ? error : Inspectable.toStringUnknown(error)\n })\n .join('\\n')\n}\n\n/**\n * Failure rejects with an `Error` whose message is what the model reads back\n * as the tool result, so it is written for the model rather than for a log.\n */\nexport async function runTool<A, E>(\n effect: Effect.Effect<A, E>,\n options?: RunOptions,\n): Promise<A> {\n const exit = await Effect.runPromiseExit(effect, options)\n if (Exit.isFailure(exit)) {\n throw new Error(causeMessage(exit.cause))\n }\n return exit.value\n}\n\nexport interface RunHandlerOptions<B> {\n readonly onError?: (message: string) => B\n}\n\n/**\n * For boundaries where pi reports rejections but expected failures should\n * degrade gracefully (event hooks, commands, background work). Expected\n * failures and interrupts never reject. Without `onError` they vanish, while\n * defects rethrow so pi's handler boundary reports the bug.\n */\nexport async function runHandler<A, E, B = undefined>(\n effect: Effect.Effect<A, E>,\n options?: RunHandlerOptions<B>,\n): Promise<A | B> {\n const exit = await Effect.runPromiseExit(effect)\n if (Exit.isSuccess(exit)) {\n return exit.value\n }\n if (options?.onError) {\n return options.onError(causeMessage(exit.cause))\n }\n const die = exit.cause.reasons.find(Cause.isDieReason)\n if (die !== undefined) {\n throw die.defect\n }\n return undefined as B\n}\n","import type { ExtensionContext } from '@earendil-works/pi-coding-agent'\nimport { getAgentDir } from '@earendil-works/pi-coding-agent'\nimport * as NodeServices from '@effect/platform-node/NodeServices'\nimport { Effect, FileSystem, Path, PlatformError, Schema } from 'effect'\nimport { runHandler } from './run'\n\n/**\n * A missing config file yields `defaults` silently. An unreadable or invalid\n * one warns and yields `defaults`, so a typo downgrades the extension rather\n * than breaking it.\n */\nexport const loadExtensionConfig = Effect.fnUntraced(\n function* <S extends Schema.Codec<unknown>>(\n _ctx: ExtensionContext,\n schema: S,\n name: string,\n _defaults: S['Type'],\n ): Effect.fn.Return<\n S['Type'],\n Schema.SchemaError | PlatformError.PlatformError,\n FileSystem.FileSystem | Path.Path\n > {\n const fs = yield* FileSystem.FileSystem\n const path = yield* Path.Path\n const file = path.join(getAgentDir(), 'extensions', `${name}.json`)\n const contents = yield* fs.readFileString(file)\n return yield* Schema.decodeEffect(Schema.fromJsonString(schema))(contents)\n },\n (load, ctx, _schema, name, defaults) =>\n runHandler(\n load.pipe(\n Effect.catchIf(\n (error) =>\n error._tag === 'PlatformError' && error.reason._tag === 'NotFound',\n () => Effect.succeed(defaults),\n ),\n Effect.provide(NodeServices.layer),\n ),\n {\n onError: (message) => {\n if (ctx.hasUI) {\n ctx.ui.notify(`Ignoring invalid ${name} config: ${message}`, 'warning')\n }\n return defaults\n },\n },\n ),\n)\n","import type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent'\nimport { Array, Order, pipe, String } from 'effect'\n\n/**\n * One entry on the shared status line. `text` must be plain (un-styled) text —\n * the whole row is dimmed uniformly so segments from different plugins share\n * one look.\n */\nexport interface StatuslineSegment {\n readonly text: string\n readonly align: 'left' | 'right'\n}\n\nconst WIDGET_KEY = 'pi-plugins:statusline'\n\n// Each plugin bundles its own copy of this module; `Symbol.for` on\n// `globalThis` gives them all the same registry inside one pi process.\nconst REGISTRY_KEY = Symbol.for('@pi-plugins/statusline-registry')\n\ntype Registry = Map<string, StatuslineSegment>\n\nfunction registry(): Registry {\n const store = globalThis as { [REGISTRY_KEY]?: Registry }\n store[REGISTRY_KEY] ??= new Map()\n return store[REGISTRY_KEY]\n}\n\nconst byKey = Order.mapInput(\n Order.String,\n ([key]: readonly [string, StatuslineSegment]) => key,\n)\n\nfunction side(segments: Registry, align: StatuslineSegment['align']): string {\n return pipe(\n Array.fromIterable(segments),\n Array.filter(([, segment]) => segment.align === align),\n Array.sortBy(byKey),\n Array.map(([, segment]) => segment.text),\n Array.join(' · '),\n )\n}\n\n/** Terminal columns of plain text (code points, no ANSI). */\nfunction textWidth(text: string): number {\n return Array.fromIterable(text).length\n}\n\nfunction truncate(text: string, columns: number): string {\n return pipe(Array.fromIterable(text), Array.take(columns), Array.join(''))\n}\n\n/**\n * Lays out `left ... right` across `width`: left indented one column to match\n * pi's built-in widget rows, right flush against the terminal edge to match\n * pi's footer. Falls back to one truncated `left · right` run when too narrow.\n */\nfunction renderLine(segments: Registry, width: number, theme: Theme): string {\n const left = side(segments, 'left')\n const right = side(segments, 'right')\n\n const margin = Math.min(width, 1)\n const inner = width - margin\n const gap = inner - textWidth(left) - textWidth(right)\n const minGap = String.isNonEmpty(left) && String.isNonEmpty(right) ? 2 : 0\n\n const line =\n String.isNonEmpty(right) && gap >= minGap\n ? `${left}${' '.repeat(gap)}${right}`\n : truncate(\n pipe([left, right], Array.filter(String.isNonEmpty), Array.join(' · ')),\n Math.max(inner, 0),\n )\n\n return ' '.repeat(margin) + theme.fg('dim', line)\n}\n\n/**\n * Adds, replaces (`segment`), or removes (`undefined`) a keyed segment on a\n * single status line above the editor shared across pi-plugins extensions,\n * instead of each plugin stacking its own widget row.\n */\nexport function setStatuslineSegment(\n ctx: ExtensionContext,\n key: string,\n segment: StatuslineSegment | undefined,\n): void {\n const segments = registry()\n if (segment === undefined) {\n segments.delete(key)\n } else {\n segments.set(key, segment)\n }\n\n if (!ctx.hasUI) {\n return\n }\n\n if (segments.size === 0) {\n ctx.ui.setWidget(WIDGET_KEY, undefined)\n return\n }\n\n ctx.ui.setWidget(WIDGET_KEY, (_tui, theme) => ({\n render: (width: number) => [renderLine(segments, width, theme)],\n invalidate: () => {},\n }))\n}\n","import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent'\nimport { loadExtensionConfig } from '@pi-plugins/shared/config'\nimport { setStatuslineSegment } from '@pi-plugins/shared/statusline'\nimport {\n Array,\n Data,\n Effect,\n Match,\n pipe,\n Predicate,\n Record,\n Schema,\n String,\n} from 'effect'\n\nconst EXTENSION_ID = 'fast-mode'\nconst COMMAND_ARGS = ['on', 'off', 'status'] as const\n/** Status-line segment shown above the editor while fast mode is active. */\nconst SEGMENT_KEY = EXTENSION_ID\nconst SEGMENT_LABEL = '[fast mode]'\n\nconst FastModeConfig = Schema.Struct({\n enabled: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))),\n /** `provider/model-id` keys that fast mode applies to. */\n models: Schema.Array(Schema.String).pipe(\n Schema.withDecodingDefault(\n Effect.succeed([\n 'openai/gpt-5.4',\n 'openai/gpt-5.5',\n 'openai/gpt-5.6-sol',\n 'openai/gpt-5.6-terra',\n 'openai/gpt-5.6-luna',\n 'openai-codex/gpt-5.4',\n 'openai-codex/gpt-5.5',\n 'openai-codex/gpt-5.6-sol',\n 'openai-codex/gpt-5.6-terra',\n 'openai-codex/gpt-5.6-luna',\n ]),\n ),\n ),\n /** Show a `fast mode` indicator above the editor while active. */\n showStatus: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(true))),\n})\ntype FastModeConfig = typeof FastModeConfig.Type\n\ntype ActiveModel = NonNullable<ExtensionContext['model']>\ntype FastModeApi = 'openai-responses' | 'openai-codex-responses'\n\nfunction modelKey(model: ActiveModel): string {\n return `${model.provider}/${model.id}`\n}\n\n/**\n * Rewrites a provider request payload to ask for fast inference, returning the\n * replacement payload — or `undefined` to leave the request untouched.\n */\ntype Applicator = (\n payload: Record<string, unknown>,\n model: ActiveModel,\n) => Record<string, unknown> | undefined\n\n/** Whether fast mode can apply to the active model. */\ntype Eligibility = Data.TaggedEnum<{\n Eligible: { readonly apply: Applicator }\n Ineligible: { readonly message: string }\n}>\nconst Eligibility = Data.taggedEnum<Eligibility>()\n\nconst FAST_APPLICATORS: Record<string, Applicator> = {\n 'openai-responses': applyOpenAIPriorityTier,\n 'openai-codex-responses': applyOpenAIPriorityTier,\n} satisfies Record<FastModeApi, Applicator>\n\nfunction applyOpenAIPriorityTier(\n payload: Record<string, unknown>,\n): Record<string, unknown> | undefined {\n // If the request already has a `service_tier`, leave it untouched.\n return Record.has(payload, 'service_tier')\n ? undefined\n : { ...payload, service_tier: 'priority' }\n}\n\nexport default function fastMode(pi: ExtensionAPI) {\n let config = Schema.decodeUnknownSync(FastModeConfig)({})\n let enabled = false\n\n function checkEligibility(model: ExtensionContext['model']): Eligibility {\n if (!model) {\n return Eligibility.Ineligible({ message: 'no model is selected' })\n }\n\n const key = modelKey(model)\n if (!config.models.includes(key)) {\n return Eligibility.Ineligible({\n message: `${key} is not in the configured models`,\n })\n }\n\n const apply = FAST_APPLICATORS[model.api]\n if (!apply) {\n return Eligibility.Ineligible({\n message: `the ${model.api} API has no fast-mode support`,\n })\n }\n\n return Eligibility.Eligible({ apply })\n }\n\n function updateStatus(ctx: ExtensionContext): void {\n if (!ctx.hasUI) {\n return\n }\n\n const active =\n config.showStatus &&\n enabled &&\n Eligibility.$is('Eligible')(checkEligibility(ctx.model))\n\n setStatuslineSegment(\n ctx,\n SEGMENT_KEY,\n active ? { text: SEGMENT_LABEL, align: 'right' } : undefined,\n )\n }\n\n function notifyState(ctx: ExtensionContext): void {\n const model = ctx.model\n const name = model?.name ?? '(none)'\n const message = !enabled\n ? `Fast mode is off. Current model: ${name}.`\n : Eligibility.$match(checkEligibility(model), {\n Eligible: () => `Fast mode is on for ${name}.`,\n Ineligible: ({ message: reason }) => {\n const models = config.models.join(', ') || 'none'\n return `Fast mode is on, but inactive: ${reason}. Configured models: ${models}.`\n },\n })\n\n ctx.ui.notify(message, 'info')\n }\n\n pi.on('session_start', async (_event, ctx) => {\n config = await loadExtensionConfig(ctx, FastModeConfig, EXTENSION_ID, config)\n enabled = pi.getFlag('fast') === true || config.enabled\n updateStatus(ctx)\n })\n\n pi.on('model_select', (_event, ctx) => {\n updateStatus(ctx)\n })\n\n pi.on('before_provider_request', (event, ctx) => {\n const model = ctx.model\n if (!enabled || !model) {\n return undefined\n }\n\n const eligibility = checkEligibility(model)\n if (\n Eligibility.$is('Ineligible')(eligibility) ||\n !Predicate.isObject(event.payload) ||\n event.payload['model'] !== model.id\n ) {\n return undefined\n }\n\n return eligibility.apply(event.payload, model)\n })\n\n pi.registerFlag('fast', {\n description: 'Start with fast mode enabled',\n type: 'boolean',\n default: false,\n })\n\n pi.registerCommand('fast', {\n description:\n 'Toggle fast mode (faster, costlier inference) for configured models',\n getArgumentCompletions: (prefix) => {\n const items = pipe(\n COMMAND_ARGS,\n Array.filter(String.startsWith(prefix)),\n Array.map((arg) => ({ value: arg, label: arg })),\n )\n\n return Array.match(items, {\n onNonEmpty: (matched) => [...matched],\n onEmpty: () => null,\n })\n },\n handler: async (args, ctx) => {\n Match.value(args.trim().toLowerCase()).pipe(\n Match.whenOr('', 'on', 'off', (cmd) => {\n enabled = cmd === '' ? !enabled : cmd === 'on'\n updateStatus(ctx)\n notifyState(ctx)\n }),\n Match.when('status', () => notifyState(ctx)),\n Match.orElse(() => ctx.ui.notify('Usage: /fast [on|off|status]', 'warning')),\n )\n },\n })\n}\n"],"mappings":";;;;AAIA,MAAM,gBAAgB;AAQtB,SAAS,aAAa,OAAqC;CACzD,IAAI,MAAM,kBAAkB,KAAK,GAC/B,OAAO;CAET,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,MAAM,OAAO,KAAK;CAE3B,OAAO,MAAM,QACV,OAAO,MAAM,YAAY,CAAC,CAC1B,KAAK,EAAE,YAAY;EAClB,IAAI,iBAAiB,OACnB,OAAO,MAAM,WAAW,MAAM;EAEhC,OAAO,OAAO,UAAU,WAAW,QAAQ,YAAY,gBAAgB,KAAK;CAC9E,CAAC,CAAC,CACD,KAAK,IAAI;AACd;;;;;;;AA2BA,eAAsB,WACpB,QACA,SACgB;CAChB,MAAM,OAAO,MAAM,OAAO,eAAe,MAAM;CAC/C,IAAI,KAAK,UAAU,IAAI,GACrB,OAAO,KAAK;CAEd,IAAI,SAAS,SACX,OAAO,QAAQ,QAAQ,aAAa,KAAK,KAAK,CAAC;CAEjD,MAAM,MAAM,KAAK,MAAM,QAAQ,KAAK,MAAM,WAAW;CACrD,IAAI,QAAQ,KAAA,GACV,MAAM,IAAI;AAGd;;;;;;;;AC5DA,MAAa,sBAAsB,OAAO,WACxC,WACE,MACA,QACA,MACA,WAKA;CACA,MAAM,KAAK,OAAO,WAAW;CAE7B,MAAM,QAAO,OADO,KAAK,KAAA,CACP,KAAK,YAAY,GAAG,cAAc,GAAG,KAAK,MAAM;CAClE,MAAM,WAAW,OAAO,GAAG,eAAe,IAAI;CAC9C,OAAO,OAAO,OAAO,aAAa,OAAO,eAAe,MAAM,CAAC,CAAC,CAAC,QAAQ;AAC3E,IACC,MAAM,KAAK,SAAS,MAAM,aACzB,WACE,KAAK,KACH,OAAO,SACJ,UACC,MAAM,SAAS,mBAAmB,MAAM,OAAO,SAAS,kBACpD,OAAO,QAAQ,QAAQ,CAC/B,GACA,OAAO,QAAQ,aAAa,KAAK,CACnC,GACA,EACE,UAAU,YAAY;CACpB,IAAI,IAAI,OACN,IAAI,GAAG,OAAO,oBAAoB,KAAK,WAAW,WAAW,SAAS;CAExE,OAAO;AACT,EACF,CACF,CACJ;;;AClCA,MAAM,aAAa;AAInB,MAAM,eAAe,OAAO,IAAI,iCAAiC;AAIjE,SAAS,WAAqB;CAC5B,MAAM,QAAQ;CACd,MAAM,kCAAkB,IAAI,IAAI;CAChC,OAAO,MAAM;AACf;AAEA,MAAM,QAAQ,MAAM,SAClB,MAAM,SACL,CAAC,SAA+C,GACnD;AAEA,SAAS,KAAK,UAAoB,OAA2C;CAC3E,OAAO,KACL,MAAM,aAAa,QAAQ,GAC3B,MAAM,QAAQ,GAAG,aAAa,QAAQ,UAAU,KAAK,GACrD,MAAM,OAAO,KAAK,GAClB,MAAM,KAAK,GAAG,aAAa,QAAQ,IAAI,GACvC,MAAM,KAAK,KAAK,CAClB;AACF;;AAGA,SAAS,UAAU,MAAsB;CACvC,OAAO,MAAM,aAAa,IAAI,CAAC,CAAC;AAClC;AAEA,SAAS,SAAS,MAAc,SAAyB;CACvD,OAAO,KAAK,MAAM,aAAa,IAAI,GAAG,MAAM,KAAK,OAAO,GAAG,MAAM,KAAK,EAAE,CAAC;AAC3E;;;;;;AAOA,SAAS,WAAW,UAAoB,OAAe,OAAsB;CAC3E,MAAM,OAAO,KAAK,UAAU,MAAM;CAClC,MAAM,QAAQ,KAAK,UAAU,OAAO;CAEpC,MAAM,SAAS,KAAK,IAAI,OAAO,CAAC;CAChC,MAAM,QAAQ,QAAQ;CACtB,MAAM,MAAM,QAAQ,UAAU,IAAI,IAAI,UAAU,KAAK;CACrD,MAAM,SAAS,OAAO,WAAW,IAAI,KAAK,OAAO,WAAW,KAAK,IAAI,IAAI;CAEzE,MAAM,OACJ,OAAO,WAAW,KAAK,KAAK,OAAO,SAC/B,GAAG,OAAO,IAAI,OAAO,GAAG,IAAI,UAC5B,SACE,KAAK,CAAC,MAAM,KAAK,GAAG,MAAM,OAAO,OAAO,UAAU,GAAG,MAAM,KAAK,KAAK,CAAC,GACtE,KAAK,IAAI,OAAO,CAAC,CACnB;CAEN,OAAO,IAAI,OAAO,MAAM,IAAI,MAAM,GAAG,OAAO,IAAI;AAClD;;;;;;AAOA,SAAgB,qBACd,KACA,KACA,SACM;CACN,MAAM,WAAW,SAAS;CAC1B,IAAI,YAAY,KAAA,GACd,SAAS,OAAO,GAAG;MAEnB,SAAS,IAAI,KAAK,OAAO;CAG3B,IAAI,CAAC,IAAI,OACP;CAGF,IAAI,SAAS,SAAS,GAAG;EACvB,IAAI,GAAG,UAAU,YAAY,KAAA,CAAS;EACtC;CACF;CAEA,IAAI,GAAG,UAAU,aAAa,MAAM,WAAW;EAC7C,SAAS,UAAkB,CAAC,WAAW,UAAU,OAAO,KAAK,CAAC;EAC9D,kBAAkB,CAAC;CACrB,EAAE;AACJ;;;AC3FA,MAAM,eAAe;AACrB,MAAM,eAAe;CAAC;CAAM;CAAO;AAAQ;;AAE3C,MAAM,cAAc;AACpB,MAAM,gBAAgB;AAEtB,MAAM,iBAAiB,OAAO,OAAO;CACnC,SAAS,OAAO,QAAQ,KAAK,OAAO,oBAAoB,OAAO,QAAQ,KAAK,CAAC,CAAC;;CAE9E,QAAQ,OAAO,MAAM,OAAO,MAAM,CAAC,CAAC,KAClC,OAAO,oBACL,OAAO,QAAQ;EACb;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CACH,CACF;;CAEA,YAAY,OAAO,QAAQ,KAAK,OAAO,oBAAoB,OAAO,QAAQ,IAAI,CAAC,CAAC;AAClF,CAAC;AAMD,SAAS,SAAS,OAA4B;CAC5C,OAAO,GAAG,MAAM,SAAS,GAAG,MAAM;AACpC;AAgBA,MAAM,cAAc,KAAK,WAAwB;AAEjD,MAAM,mBAA+C;CACnD,oBAAoB;CACpB,0BAA0B;AAC5B;AAEA,SAAS,wBACP,SACqC;CAErC,OAAO,OAAO,IAAI,SAAS,cAAc,IACrC,KAAA,IACA;EAAE,GAAG;EAAS,cAAc;CAAW;AAC7C;AAEA,SAAwB,SAAS,IAAkB;CACjD,IAAI,SAAS,OAAO,kBAAkB,cAAc,CAAC,CAAC,CAAC,CAAC;CACxD,IAAI,UAAU;CAEd,SAAS,iBAAiB,OAA+C;EACvE,IAAI,CAAC,OACH,OAAO,YAAY,WAAW,EAAE,SAAS,uBAAuB,CAAC;EAGnE,MAAM,MAAM,SAAS,KAAK;EAC1B,IAAI,CAAC,OAAO,OAAO,SAAS,GAAG,GAC7B,OAAO,YAAY,WAAW,EAC5B,SAAS,GAAG,IAAI,kCAClB,CAAC;EAGH,MAAM,QAAQ,iBAAiB,MAAM;EACrC,IAAI,CAAC,OACH,OAAO,YAAY,WAAW,EAC5B,SAAS,OAAO,MAAM,IAAI,+BAC5B,CAAC;EAGH,OAAO,YAAY,SAAS,EAAE,MAAM,CAAC;CACvC;CAEA,SAAS,aAAa,KAA6B;EACjD,IAAI,CAAC,IAAI,OACP;EAGF,MAAM,SACJ,OAAO,cACP,WACA,YAAY,IAAI,UAAU,CAAC,CAAC,iBAAiB,IAAI,KAAK,CAAC;EAEzD,qBACE,KACA,aACA,SAAS;GAAE,MAAM;GAAe,OAAO;EAAQ,IAAI,KAAA,CACrD;CACF;CAEA,SAAS,YAAY,KAA6B;EAChD,MAAM,QAAQ,IAAI;EAClB,MAAM,OAAO,OAAO,QAAQ;EAC5B,MAAM,UAAU,CAAC,UACb,oCAAoC,KAAK,KACzC,YAAY,OAAO,iBAAiB,KAAK,GAAG;GAC1C,gBAAgB,uBAAuB,KAAK;GAC5C,aAAa,EAAE,SAAS,aAAa;IAEnC,OAAO,kCAAkC,OAAO,uBADjC,OAAO,OAAO,KAAK,IAAI,KAAK,OACmC;GAChF;EACF,CAAC;EAEL,IAAI,GAAG,OAAO,SAAS,MAAM;CAC/B;CAEA,GAAG,GAAG,iBAAiB,OAAO,QAAQ,QAAQ;EAC5C,SAAS,MAAM,oBAAoB,KAAK,gBAAgB,cAAc,MAAM;EAC5E,UAAU,GAAG,QAAQ,MAAM,MAAM,QAAQ,OAAO;EAChD,aAAa,GAAG;CAClB,CAAC;CAED,GAAG,GAAG,iBAAiB,QAAQ,QAAQ;EACrC,aAAa,GAAG;CAClB,CAAC;CAED,GAAG,GAAG,4BAA4B,OAAO,QAAQ;EAC/C,MAAM,QAAQ,IAAI;EAClB,IAAI,CAAC,WAAW,CAAC,OACf;EAGF,MAAM,cAAc,iBAAiB,KAAK;EAC1C,IACE,YAAY,IAAI,YAAY,CAAC,CAAC,WAAW,KACzC,CAAC,UAAU,SAAS,MAAM,OAAO,KACjC,MAAM,QAAQ,aAAa,MAAM,IAEjC;EAGF,OAAO,YAAY,MAAM,MAAM,SAAS,KAAK;CAC/C,CAAC;CAED,GAAG,aAAa,QAAQ;EACtB,aAAa;EACb,MAAM;EACN,SAAS;CACX,CAAC;CAED,GAAG,gBAAgB,QAAQ;EACzB,aACE;EACF,yBAAyB,WAAW;GAClC,MAAM,QAAQ,KACZ,cACA,MAAM,OAAO,OAAO,WAAW,MAAM,CAAC,GACtC,MAAM,KAAK,SAAS;IAAE,OAAO;IAAK,OAAO;GAAI,EAAE,CACjD;GAEA,OAAO,MAAM,MAAM,OAAO;IACxB,aAAa,YAAY,CAAC,GAAG,OAAO;IACpC,eAAe;GACjB,CAAC;EACH;EACA,SAAS,OAAO,MAAM,QAAQ;GAC5B,MAAM,MAAM,KAAK,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KACrC,MAAM,OAAO,IAAI,MAAM,QAAQ,QAAQ;IACrC,UAAU,QAAQ,KAAK,CAAC,UAAU,QAAQ;IAC1C,aAAa,GAAG;IAChB,YAAY,GAAG;GACjB,CAAC,GACD,MAAM,KAAK,gBAAgB,YAAY,GAAG,CAAC,GAC3C,MAAM,aAAa,IAAI,GAAG,OAAO,gCAAgC,SAAS,CAAC,CAC7E;EACF;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../tooling/shared/src/run.ts","../../../tooling/shared/src/config.ts","../../../tooling/shared/src/statusline.ts","../src/index.ts"],"sourcesContent":["import { Cause, Effect, Exit, Inspectable } from 'effect'\n\nexport interface RunOptions {\n readonly signal?: AbortSignal | undefined\n}\n\nfunction causeMessage(cause: Cause.Cause<unknown>): string {\n if (Cause.hasInterruptsOnly(cause)) {\n // What pi's own tools throw for a cancelled run.\n return 'Operation aborted'\n }\n if (Cause.hasDies(cause)) {\n return Cause.pretty(cause)\n }\n return cause.reasons\n .filter(Cause.isFailReason)\n .map(({ error }) => {\n if (error instanceof Error) {\n return error.message || error.name\n }\n return typeof error === 'string' ? error : Inspectable.toStringUnknown(error)\n })\n .join('\\n')\n}\n\n/** The rejection message is what the model reads back as the tool result. */\nexport async function runTool<A, E>(\n effect: Effect.Effect<A, E>,\n options?: RunOptions,\n): Promise<A> {\n const exit = await Effect.runPromiseExit(effect, options)\n if (Exit.isFailure(exit)) {\n throw new Error(causeMessage(exit.cause))\n }\n return exit.value\n}\n\nexport interface RunHandlerOptions<B> {\n readonly onError?: (message: string) => B\n}\n\nexport async function runHandler<A, E, B = undefined>(\n effect: Effect.Effect<A, E>,\n options?: RunHandlerOptions<B>,\n): Promise<A | B> {\n const exit = await Effect.runPromiseExit(effect)\n if (Exit.isSuccess(exit)) {\n return exit.value\n }\n if (options?.onError) {\n return options.onError(causeMessage(exit.cause))\n }\n const die = exit.cause.reasons.find(Cause.isDieReason)\n if (die !== undefined) {\n throw die.defect\n }\n return undefined as B\n}\n","import type { ExtensionContext } from '@earendil-works/pi-coding-agent'\nimport { getAgentDir } from '@earendil-works/pi-coding-agent'\nimport * as NodeServices from '@effect/platform-node/NodeServices'\nimport { Effect, FileSystem, Path, PlatformError, Schema } from 'effect'\nimport { runHandler } from './run'\n\nexport const loadExtensionConfig = Effect.fnUntraced(\n function* <S extends Schema.Codec<unknown>>(\n _ctx: ExtensionContext,\n schema: S,\n name: string,\n _defaults: S['Type'],\n ): Effect.fn.Return<\n S['Type'],\n Schema.SchemaError | PlatformError.PlatformError,\n FileSystem.FileSystem | Path.Path\n > {\n const fs = yield* FileSystem.FileSystem\n const path = yield* Path.Path\n const file = path.join(getAgentDir(), 'extensions', `${name}.json`)\n const contents = yield* fs.readFileString(file)\n return yield* Schema.decodeEffect(Schema.fromJsonString(schema))(contents)\n },\n (load, ctx, _schema, name, defaults) =>\n runHandler(\n load.pipe(\n Effect.catchIf(\n (error) =>\n error._tag === 'PlatformError' && error.reason._tag === 'NotFound',\n () => Effect.succeed(defaults),\n ),\n Effect.provide(NodeServices.layer),\n ),\n {\n onError: (message) => {\n if (ctx.hasUI) {\n ctx.ui.notify(`Ignoring invalid ${name} config: ${message}`, 'warning')\n }\n return defaults\n },\n },\n ),\n)\n","import type { ExtensionContext } from '@earendil-works/pi-coding-agent'\nimport { Array, Order, pipe, String } from 'effect'\n\nexport interface StatuslineSegment {\n /** Plain text: the whole row is dimmed uniformly across plugins. */\n readonly text: string\n readonly align: 'left' | 'right'\n}\n\nconst WIDGET_KEY = 'pi-plugins:statusline'\n\n// Each plugin bundles its own copy of this module, so `Symbol.for` on\n// `globalThis` gives them all the same registry inside one pi process.\nconst REGISTRY_KEY = Symbol.for('@pi-plugins/statusline-registry')\n\ntype Registry = Map<string, StatuslineSegment>\n\nfunction side(segments: Registry, align: StatuslineSegment['align']): string {\n return pipe(\n Array.fromIterable(segments),\n Array.filter(([, segment]) => segment.align === align),\n Array.sortBy(\n Order.mapInput(\n Order.String,\n ([key]: readonly [string, StatuslineSegment]) => key,\n ),\n ),\n Array.map(([, segment]) => segment.text),\n Array.join(' · '),\n )\n}\n\nfunction textWidth(text: string): number {\n return Array.fromIterable(text).length\n}\n\nexport function setStatuslineSegment(\n ctx: ExtensionContext,\n key: string,\n segment: StatuslineSegment | undefined,\n): void {\n const store = globalThis as { [REGISTRY_KEY]?: Registry }\n store[REGISTRY_KEY] ??= new Map()\n const segments = store[REGISTRY_KEY]\n if (segment === undefined) {\n segments.delete(key)\n } else {\n segments.set(key, segment)\n }\n\n if (!ctx.hasUI) {\n return\n }\n\n if (segments.size === 0) {\n ctx.ui.setWidget(WIDGET_KEY, undefined)\n return\n }\n\n ctx.ui.setWidget(WIDGET_KEY, (_tui, theme) => ({\n invalidate: () => {},\n render: (width: number) => {\n const left = side(segments, 'left')\n const right = side(segments, 'right')\n\n // Left indented one column like pi's widget rows, right flush like pi's footer.\n const margin = Math.min(width, 1)\n const inner = width - margin\n const gap = inner - textWidth(left) - textWidth(right)\n const minGap = String.isNonEmpty(left) && String.isNonEmpty(right) ? 2 : 0\n\n const line =\n String.isNonEmpty(right) && gap >= minGap\n ? `${left}${' '.repeat(gap)}${right}`\n : pipe(\n [left, right],\n Array.filter(String.isNonEmpty),\n Array.join(' · '),\n Array.fromIterable,\n Array.take(Math.max(inner, 0)),\n Array.join(''),\n )\n\n return [' '.repeat(margin) + theme.fg('dim', line)]\n },\n }))\n}\n","import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent'\nimport { loadExtensionConfig } from '@pi-plugins/shared/config'\nimport { setStatuslineSegment } from '@pi-plugins/shared/statusline'\nimport {\n Array,\n Data,\n Effect,\n Match,\n pipe,\n Predicate,\n Record,\n Schema,\n String,\n} from 'effect'\n\nconst EXTENSION_ID = 'fast-mode'\nconst COMMAND_ARGS = ['on', 'off', 'status'] as const\nconst SEGMENT_KEY = EXTENSION_ID\nconst SEGMENT_LABEL = '[fast mode]'\n\nconst FastModeConfig = Schema.Struct({\n enabled: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))),\n models: Schema.Array(Schema.String).pipe(\n Schema.withDecodingDefault(\n Effect.succeed([\n 'openai/gpt-5.4',\n 'openai/gpt-5.5',\n 'openai/gpt-5.6-sol',\n 'openai/gpt-5.6-terra',\n 'openai/gpt-5.6-luna',\n 'openai/gpt-6-astra',\n 'openai-codex/gpt-5.4',\n 'openai-codex/gpt-5.5',\n 'openai-codex/gpt-5.6-sol',\n 'openai-codex/gpt-5.6-terra',\n 'openai-codex/gpt-5.6-luna',\n 'openai-codex/gpt-6-astra',\n ]),\n ),\n ),\n showStatus: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(true))),\n})\ntype FastModeConfig = typeof FastModeConfig.Type\n\ntype ActiveModel = NonNullable<ExtensionContext['model']>\ntype FastModeApi = 'openai-responses' | 'openai-codex-responses'\n\ntype Applicator = (\n payload: Record<string, unknown>,\n model: ActiveModel,\n) => Record<string, unknown> | undefined\n\ntype Eligibility = Data.TaggedEnum<{\n Eligible: { readonly apply: Applicator }\n Ineligible: { readonly message: string }\n}>\nconst Eligibility = Data.taggedEnum<Eligibility>()\n\nconst FAST_APPLICATORS: Record<string, Applicator> = {\n 'openai-responses': applyOpenAIPriorityTier,\n 'openai-codex-responses': applyOpenAIPriorityTier,\n} satisfies Record<FastModeApi, Applicator>\n\nfunction applyOpenAIPriorityTier(\n payload: Record<string, unknown>,\n): Record<string, unknown> | undefined {\n return Record.has(payload, 'service_tier')\n ? undefined\n : { ...payload, service_tier: 'priority' }\n}\n\nexport default function fastMode(pi: ExtensionAPI) {\n let config = Schema.decodeUnknownSync(FastModeConfig)({})\n let enabled = false\n\n function checkEligibility(model: ExtensionContext['model']): Eligibility {\n if (!model) {\n return Eligibility.Ineligible({ message: 'no model is selected' })\n }\n\n const key = `${model.provider}/${model.id}`\n if (!config.models.includes(key)) {\n return Eligibility.Ineligible({\n message: `${key} is not in the configured models`,\n })\n }\n\n const apply = FAST_APPLICATORS[model.api]\n if (!apply) {\n return Eligibility.Ineligible({\n message: `the ${model.api} API has no fast-mode support`,\n })\n }\n\n return Eligibility.Eligible({ apply })\n }\n\n function updateStatus(ctx: ExtensionContext): void {\n if (!ctx.hasUI) {\n return\n }\n\n const active =\n config.showStatus &&\n enabled &&\n Eligibility.$is('Eligible')(checkEligibility(ctx.model))\n\n setStatuslineSegment(\n ctx,\n SEGMENT_KEY,\n active ? { text: SEGMENT_LABEL, align: 'right' } : undefined,\n )\n }\n\n function notifyState(ctx: ExtensionContext): void {\n const model = ctx.model\n const name = model?.name ?? '(none)'\n const message = !enabled\n ? `Fast mode is off. Current model: ${name}.`\n : Eligibility.$match(checkEligibility(model), {\n Eligible: () => `Fast mode is on for ${name}.`,\n Ineligible: ({ message: reason }) => {\n const models = config.models.join(', ') || 'none'\n return `Fast mode is on, but inactive: ${reason}. Configured models: ${models}.`\n },\n })\n\n ctx.ui.notify(message, 'info')\n }\n\n pi.on('session_start', async (_event, ctx) => {\n config = await loadExtensionConfig(ctx, FastModeConfig, EXTENSION_ID, config)\n enabled = pi.getFlag('fast') === true || config.enabled\n updateStatus(ctx)\n })\n\n pi.on('model_select', (_event, ctx) => {\n updateStatus(ctx)\n })\n\n pi.on('before_provider_request', (event, ctx) => {\n const model = ctx.model\n if (!enabled || !model) {\n return undefined\n }\n\n const eligibility = checkEligibility(model)\n if (\n Eligibility.$is('Ineligible')(eligibility) ||\n !Predicate.isObject(event.payload) ||\n event.payload['model'] !== model.id\n ) {\n return undefined\n }\n\n return eligibility.apply(event.payload, model)\n })\n\n pi.registerFlag('fast', {\n description: 'Start with fast mode enabled',\n type: 'boolean',\n default: false,\n })\n\n pi.registerCommand('fast', {\n description:\n 'Toggle fast mode (faster, costlier inference) for configured models',\n getArgumentCompletions: (prefix) => {\n const items = pipe(\n COMMAND_ARGS,\n Array.filter(String.startsWith(prefix)),\n Array.map((arg) => ({ value: arg, label: arg })),\n )\n\n return Array.match(items, {\n onNonEmpty: (matched) => [...matched],\n onEmpty: () => null,\n })\n },\n handler: async (args, ctx) => {\n Match.value(args.trim().toLowerCase()).pipe(\n Match.whenOr('', 'on', 'off', (cmd) => {\n enabled = cmd === '' ? !enabled : cmd === 'on'\n updateStatus(ctx)\n notifyState(ctx)\n }),\n Match.when('status', () => notifyState(ctx)),\n Match.orElse(() => ctx.ui.notify('Usage: /fast [on|off|status]', 'warning')),\n )\n },\n })\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-plugins/fast-mode",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Fast service-tier extension for pi-agent.",
5
5
  "keywords": [
6
6
  "fast",
@@ -30,7 +30,7 @@ The marker is consumed before the prompt reaches the agent.
30
30
  - The focus is used in the handoff document.
31
31
  - A handoff document is written under the OS temp directory.
32
32
  - A new session starts automatically from the document.
33
- - When Pi runs inside Herdr, the handoff opens in a new focused tab. The current parent session stays available in its original tab.
33
+ - When Pi runs inside Herdr, the handoff opens in a new tab without changing focus. The current parent session stays available in its original tab.
34
34
  - The handoff session keeps the parent-session link and selected provider/model when available.
35
35
  - Outside Herdr, the current session is replaced.
36
36
 
@@ -45,9 +45,12 @@ Handoff uses the same naming logic as `/rename`:
45
45
  - Uses the first user message and up to three latest user messages.
46
46
  - Reads the model from `$PI_CODING_AGENT_DIR/extensions/pi-rename.json`.
47
47
  - Uses `openai-codex/gpt-5.6-luna` when no config exists.
48
- - Produces lowercase, hyphen-separated names of up to 30 characters.
48
+ - Produces a name such as `[handoff] fix-auth-callback`.
49
+ - Keeps the generated base name under 30 characters before adding the prefix.
49
50
  - Falls back to the latest user message if the naming model is unavailable.
50
- - Uses `handoff-session` when no usable user text exists.
51
+ - Uses `[handoff] handoff-session` when no usable user text exists.
52
+
53
+ The handoff artifact filename uses the unprefixed base name. If you run `/rename` in the new session, it replaces the complete name and can remove the `[handoff]` prefix.
51
54
 
52
55
  Install `@tifan/pi-rename` separately only if you want its `/rename` and `/rename config` commands.
53
56
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tifan/pi-handoff",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "description": "Transfer pi session context to a new session and query past sessions.",
5
5
  "keywords": [
6
6
  "handoff",
@@ -26,6 +26,11 @@ import { join } from "node:path"
26
26
 
27
27
  const HANDOFF_SKILL_COMMAND = "skill:handoff"
28
28
  const HANDOFF_BRIDGE_COMMAND = "__pi-handoff-session"
29
+ export const HANDOFF_SESSION_PREFIX = "[handoff] "
30
+
31
+ export function formatHandoffSessionName(baseName: string): string {
32
+ return `${HANDOFF_SESSION_PREFIX}${baseName}`
33
+ }
29
34
 
30
35
  const HANDOFF_SYSTEM_PROMPT = `You are a context transfer assistant. Generate a handoff markdown document for a fresh coding agent.
31
36
 
@@ -170,7 +175,6 @@ async function startHandoffInHerdr(options: {
170
175
  options.ctx.cwd,
171
176
  "--label",
172
177
  options.sessionName,
173
- "--focus",
174
178
  ],
175
179
  { timeout: 5_000 },
176
180
  )
@@ -394,8 +398,9 @@ async function runHandoff(
394
398
  return
395
399
  }
396
400
 
397
- const sessionName = await generateSessionName(ctx, messages)
398
- const handoffPath = await nextHandoffPath(sessionName)
401
+ const baseSessionName = await generateSessionName(ctx, messages)
402
+ const sessionName = formatHandoffSessionName(baseSessionName)
403
+ const handoffPath = await nextHandoffPath(baseSessionName)
399
404
  const document = buildDocumentWithMetadata({
400
405
  generated,
401
406
  focus,