@herbertgao/pi-extensions 2026.9.20 → 2026.10.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 (357) hide show
  1. package/README.md +18 -13
  2. package/THIRD_PARTY_NOTICES.md +31 -5
  3. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-audit.md +1 -1
  4. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-debt.md +1 -1
  5. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-gain.md +1 -1
  6. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-review.md +1 -1
  7. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail.md +1 -1
  8. package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/index.js +4 -0
  9. package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail-frontmatter.cjs +43 -3
  10. package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail.mjs +142 -59
  11. package/node_modules/@dietrichgebert/ponytail/.qoder-plugin/plugin.json +1 -1
  12. package/node_modules/@dietrichgebert/ponytail/README.es.md +87 -204
  13. package/node_modules/@dietrichgebert/ponytail/README.ja.md +212 -0
  14. package/node_modules/@dietrichgebert/ponytail/README.ko.md +92 -226
  15. package/node_modules/@dietrichgebert/ponytail/README.md +58 -244
  16. package/node_modules/@dietrichgebert/ponytail/README.zh-CN.md +212 -0
  17. package/node_modules/@dietrichgebert/ponytail/hooks/claude-codex-hooks.json +3 -3
  18. package/node_modules/@dietrichgebert/ponytail/hooks/copilot-hooks.json +4 -4
  19. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-activate.js +63 -16
  20. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-config.js +8 -7
  21. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-mode-tracker.js +46 -23
  22. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-runtime.js +39 -7
  23. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-subagent.js +20 -3
  24. package/node_modules/@dietrichgebert/ponytail/hooks/qoder-hooks.json +3 -3
  25. package/node_modules/@dietrichgebert/ponytail/package.json +2 -2
  26. package/node_modules/@dietrichgebert/ponytail/pi-extension/index.js +47 -17
  27. package/node_modules/@dietrichgebert/ponytail/scripts/uninstall.js +21 -7
  28. package/node_modules/@dietrichgebert/ponytail/skills/plugin.json +5 -0
  29. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-audit/SKILL.md +7 -2
  30. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-debt/SKILL.md +1 -1
  31. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-gain/SKILL.md +16 -14
  32. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-help/SKILL.md +3 -3
  33. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-review/SKILL.md +12 -7
  34. package/node_modules/@herbertgao/pi-bark/README.md +39 -3
  35. package/node_modules/@herbertgao/pi-bark/package.json +1 -1
  36. package/node_modules/@herbertgao/pi-bark/src/index.ts +275 -15
  37. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +50 -50
  38. package/node_modules/@herbertgao/pi-cc-extensions/README.md +7 -7
  39. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +25 -2
  40. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +24 -1
  41. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -4
  42. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/footer.ts +47 -5
  43. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/mcp-chip.ts +136 -0
  44. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +56 -11
  45. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +36 -4
  46. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +11 -2
  47. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/codemode.ts +303 -0
  48. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-header.ts +1 -1
  49. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-highlight.ts +36 -0
  50. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-presentation.ts +2 -2
  51. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-write-render.ts +2 -2
  52. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/index.ts +88 -34
  53. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/line-width-safety.ts +6 -5
  54. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-execution.ts +1 -1
  55. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +31 -6
  56. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/message-display.ts +3 -3
  57. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/names.ts +3 -0
  58. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +173 -36
  59. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/ansi-text.ts +1 -0
  60. package/node_modules/@herbertgao/pi-cc-extensions/package.json +6 -4
  61. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
  62. package/node_modules/@herbertgao/pi-subagents/package.json +1 -1
  63. package/node_modules/@herbertgao/pi-subagents/src/mention-clone.ts +3 -2
  64. package/node_modules/@herbertgao/sol-pi/CONTRIBUTING.md +22 -0
  65. package/node_modules/@herbertgao/sol-pi/README.md +36 -17
  66. package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +10 -6
  67. package/node_modules/@herbertgao/sol-pi/agents-install.md +15 -12
  68. package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +24 -8
  69. package/node_modules/@herbertgao/sol-pi/docs/configuration.md +2 -2
  70. package/node_modules/@herbertgao/sol-pi/docs/star-history.md +18 -0
  71. package/node_modules/@herbertgao/sol-pi/package.json +4 -2
  72. package/node_modules/@herbertgao/sol-pi/scripts/check-sol-pi-config.mjs +1 -1
  73. package/node_modules/@herbertgao/sol-pi/src/sol-pi/config.ts +1 -1
  74. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/file-queue.ts +23 -4
  75. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +32 -1
  76. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/then-run.ts +3 -2
  77. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/observation.ts +1 -1
  78. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/economics.ts +27 -7
  79. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +137 -41
  80. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/index.ts +1 -0
  81. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/plan.ts +2 -1
  82. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/projection.ts +58 -0
  83. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +28 -6
  84. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/tools.ts +2 -1
  85. package/node_modules/@herbertgao/sol-pi/src/sol-pi/runtime-paths.ts +15 -2
  86. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  87. package/node_modules/@narumitw/pi-caffeinate/package.json +4 -4
  88. package/node_modules/@pi-plugins/fast-mode/README.md +7 -1
  89. package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts.map +1 -1
  90. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +7 -1
  91. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
  92. package/node_modules/@pi-plugins/fast-mode/package.json +5 -5
  93. package/node_modules/pi-antigravity/README.md +3 -0
  94. package/node_modules/pi-antigravity/package.json +8 -8
  95. package/node_modules/pi-antigravity/src/auth/oauth.ts +6 -3
  96. package/node_modules/pi-antigravity/src/index.ts +114 -110
  97. package/node_modules/pi-antigravity/src/stream/stream.ts +1 -1
  98. package/node_modules/pi-antigravity/src/utils/util.ts +18 -1
  99. package/node_modules/pi-multi-account/CHANGELOG.md +20 -0
  100. package/node_modules/pi-multi-account/README.md +46 -8
  101. package/node_modules/pi-multi-account/config-file-transaction.ts +42 -0
  102. package/node_modules/pi-multi-account/index.ts +255 -269
  103. package/node_modules/pi-multi-account/model-pins.ts +36 -0
  104. package/node_modules/pi-multi-account/package.json +9 -7
  105. package/node_modules/pi-multi-account/slot-proxy-auth.ts +12 -2
  106. package/node_modules/pi-multi-account/slot-proxy.ts +27 -5
  107. package/node_modules/pi-typesafe/README.md +1 -1
  108. package/node_modules/pi-typesafe/dist/backends.d.ts +15 -5
  109. package/node_modules/pi-typesafe/dist/backends.js +18 -0
  110. package/node_modules/pi-typesafe/dist/client.d.ts +4 -3
  111. package/node_modules/pi-typesafe/dist/client.js +22 -7
  112. package/node_modules/pi-typesafe/dist/index.d.ts +2 -2
  113. package/node_modules/pi-typesafe/dist/index.js +1 -1
  114. package/node_modules/pi-typesafe/dist/usage.d.ts +14 -4
  115. package/node_modules/pi-typesafe/dist/usage.js +147 -42
  116. package/node_modules/pi-typesafe/package.json +1 -1
  117. package/node_modules/pi-web-access/CHANGELOG.md +65 -0
  118. package/node_modules/pi-web-access/README.md +63 -14
  119. package/node_modules/pi-web-access/brave-rate-limit.ts +176 -0
  120. package/node_modules/pi-web-access/brave.ts +28 -11
  121. package/node_modules/pi-web-access/curator-page.ts +5 -1
  122. package/node_modules/pi-web-access/curator-server.ts +2 -0
  123. package/node_modules/pi-web-access/declared-web-links.ts +2 -2
  124. package/node_modules/pi-web-access/degoog.ts +323 -0
  125. package/node_modules/pi-web-access/dist/index.js +3647 -2740
  126. package/node_modules/pi-web-access/dist/mcp-cli.js +27443 -0
  127. package/node_modules/pi-web-access/exa.ts +5 -1
  128. package/node_modules/pi-web-access/extract.ts +41 -3
  129. package/node_modules/pi-web-access/firecrawl.ts +35 -4
  130. package/node_modules/pi-web-access/gemini-search.ts +36 -16
  131. package/node_modules/pi-web-access/gemini-web.ts +14 -9
  132. package/node_modules/pi-web-access/index.ts +164 -1207
  133. package/node_modules/pi-web-access/keenable.ts +221 -0
  134. package/node_modules/pi-web-access/mcp-cli.ts +40 -0
  135. package/node_modules/pi-web-access/mcp-server.ts +81 -0
  136. package/node_modules/pi-web-access/mcp-tool-definitions.ts +117 -0
  137. package/node_modules/pi-web-access/openai-search.ts +58 -11
  138. package/node_modules/pi-web-access/package.json +23 -5
  139. package/node_modules/pi-web-access/perplexity.ts +64 -56
  140. package/node_modules/pi-web-access/summary-review.ts +8 -2
  141. package/node_modules/pi-web-access/tool-arguments.ts +20 -0
  142. package/node_modules/pi-web-access/video-extract.ts +1 -1
  143. package/node_modules/pi-web-access/web-tool-contract.ts +86 -0
  144. package/node_modules/pi-web-access/web-tool-core.ts +1502 -0
  145. package/node_modules/pi-web-access/youtube-extract.ts +2 -5
  146. package/node_modules/{@herbertgao/resume-from → resume-from}/README.md +16 -12
  147. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/adapter.d.ts +0 -5
  148. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/adapter.js +2 -3
  149. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/contract.d.ts +2 -2
  150. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/reader.d.ts +3 -0
  151. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/reader.js +27 -15
  152. package/node_modules/{@herbertgao/resume-from/dist/adapters/codex → resume-from/dist/adapters/claude-code}/redaction.js +16 -3
  153. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/writer.d.ts +2 -4
  154. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/writer.js +1 -1
  155. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/contract.d.ts +2 -4
  156. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/index.js +1 -2
  157. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/read.d.ts +16 -0
  158. package/node_modules/resume-from/dist/adapters/codex/read.js +723 -0
  159. package/node_modules/{@herbertgao/resume-from/dist/adapters/pi → resume-from/dist/adapters/codex}/redaction.js +16 -3
  160. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/rollout.d.ts +44 -4
  161. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/rollout.js +88 -4
  162. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/write.d.ts +2 -2
  163. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/write.js +2 -2
  164. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/contract.d.ts +5 -1
  165. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/adapter.js +10 -6
  166. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/contract.d.ts +2 -2
  167. package/node_modules/{@herbertgao/resume-from/dist/adapters/claude-code → resume-from/dist/adapters/pi}/redaction.js +16 -3
  168. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/serialize.d.ts +2 -4
  169. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/serialize.js +2 -2
  170. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/render.d.ts +1 -1
  171. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/render.js +4 -4
  172. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/runner.js +2 -2
  173. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/contract.d.ts +2 -2
  174. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/command.js +31 -8
  175. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/wiring.d.ts +1 -1
  176. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/wiring.js +1 -2
  177. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/confirmation.d.ts +4 -1
  178. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/confirmation.js +2 -2
  179. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/contract.d.ts +8 -6
  180. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/contract.d.ts +10 -5
  181. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/finder.d.ts +2 -1
  182. package/node_modules/resume-from/dist/import/discovery/finder.js +269 -0
  183. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/contract.d.ts +3 -3
  184. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/lander.js +3 -3
  185. package/node_modules/resume-from/dist/import/pipeline.d.ts +28 -0
  186. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/pipeline.js +31 -11
  187. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/builder.d.ts +2 -2
  188. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/builder.js +9 -5
  189. package/node_modules/resume-from/dist/import/preview/warnings.d.ts +14 -0
  190. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/warnings.js +26 -20
  191. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/wiring.js +12 -2
  192. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/contract.d.ts +9 -3
  193. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/git.d.ts +4 -4
  194. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/git.js +7 -4
  195. package/node_modules/resume-from/dist/platform/repo/reader.d.ts +3 -0
  196. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/reader.js +60 -20
  197. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/session/contract.d.ts +8 -1
  198. package/node_modules/{@herbertgao/resume-from → resume-from}/package.json +19 -32
  199. package/node_modules/{@herbertgao/resume-from → resume-from}/shims/pi/extensions/resume-from.js +2 -2
  200. package/package.json +21 -21
  201. package/node_modules/@dietrichgebert/ponytail/assets/benchmark-3model.svg +0 -21
  202. package/node_modules/@dietrichgebert/ponytail/assets/benchmark-agentic.svg +0 -62
  203. package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.png +0 -0
  204. package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.svg +0 -115
  205. package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt-dark.svg +0 -27
  206. package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt.svg +0 -27
  207. package/node_modules/@dietrichgebert/ponytail/assets/logo.png +0 -0
  208. package/node_modules/@dietrichgebert/ponytail/assets/retriever-icon.png +0 -0
  209. package/node_modules/@dietrichgebert/ponytail/assets/retriever-logo-dark.svg +0 -4
  210. package/node_modules/@dietrichgebert/ponytail/assets/retriever-logo-light.svg +0 -4
  211. package/node_modules/@dietrichgebert/ponytail/assets/social-preview.png +0 -0
  212. package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-es.png +0 -0
  213. package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-ko.png +0 -0
  214. package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner.png +0 -0
  215. package/node_modules/@herbertgao/resume-from/dist/adapters/codex/read.js +0 -270
  216. package/node_modules/@herbertgao/resume-from/dist/import/discovery/finder.js +0 -129
  217. package/node_modules/@herbertgao/resume-from/dist/import/pipeline.d.ts +0 -17
  218. package/node_modules/@herbertgao/resume-from/dist/import/preview/warnings.d.ts +0 -11
  219. package/node_modules/@herbertgao/resume-from/dist/platform/repo/reader.d.ts +0 -8
  220. /package/node_modules/{@herbertgao/resume-from → resume-from}/LICENSE +0 -0
  221. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/contract.js +0 -0
  222. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/entries.d.ts +0 -0
  223. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/entries.js +0 -0
  224. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/index.d.ts +0 -0
  225. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/index.js +0 -0
  226. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/layout.d.ts +0 -0
  227. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/layout.js +0 -0
  228. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/readback.d.ts +0 -0
  229. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/readback.js +0 -0
  230. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/redaction.d.ts +0 -0
  231. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/validation.d.ts +0 -0
  232. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/validation.js +0 -0
  233. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/contract.js +0 -0
  234. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/index.d.ts +0 -0
  235. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/readback.d.ts +0 -0
  236. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/readback.js +0 -0
  237. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/redaction.d.ts +0 -0
  238. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/validation.d.ts +0 -0
  239. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/validation.js +0 -0
  240. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/contract.js +0 -0
  241. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/adapter.d.ts +0 -0
  242. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/contract.js +0 -0
  243. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/format.d.ts +0 -0
  244. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/format.js +0 -0
  245. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/index.d.ts +0 -0
  246. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/index.js +0 -0
  247. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/parse.d.ts +0 -0
  248. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/parse.js +0 -0
  249. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/redaction.d.ts +0 -0
  250. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/validate.d.ts +0 -0
  251. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/validate.js +0 -0
  252. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/bin.d.ts +0 -0
  253. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/bin.js +0 -0
  254. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/contract.d.ts +0 -0
  255. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/contract.js +0 -0
  256. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/agents.d.ts +0 -0
  257. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/agents.js +0 -0
  258. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/args.d.ts +0 -0
  259. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/args.js +0 -0
  260. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/contract.d.ts +0 -0
  261. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/contract.js +0 -0
  262. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/index.d.ts +0 -0
  263. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/index.js +0 -0
  264. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/presentation.d.ts +0 -0
  265. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/presentation.js +0 -0
  266. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/runner.d.ts +0 -0
  267. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/contract.js +0 -0
  268. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/entry.d.ts +0 -0
  269. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/entry.js +0 -0
  270. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/index.d.ts +0 -0
  271. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/index.js +0 -0
  272. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/command.d.ts +0 -0
  273. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/contract.d.ts +0 -0
  274. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/contract.js +0 -0
  275. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/index.d.ts +0 -0
  276. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/index.js +0 -0
  277. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/picker.d.ts +0 -0
  278. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/picker.js +0 -0
  279. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/presentation.d.ts +0 -0
  280. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/presentation.js +0 -0
  281. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/register.d.ts +0 -0
  282. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/register.js +0 -0
  283. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/ui.d.ts +0 -0
  284. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/ui.js +0 -0
  285. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/profile.d.ts +0 -0
  286. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/profile.js +0 -0
  287. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/registry.d.ts +0 -0
  288. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/registry.js +0 -0
  289. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/contract.js +0 -0
  290. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/contract.js +0 -0
  291. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/errors.d.ts +0 -0
  292. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/errors.js +0 -0
  293. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/homes.d.ts +0 -0
  294. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/homes.js +0 -0
  295. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/index.d.ts +0 -0
  296. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/index.js +0 -0
  297. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/ordering.d.ts +0 -0
  298. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/ordering.js +0 -0
  299. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/errors.d.ts +0 -0
  300. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/errors.js +0 -0
  301. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/index.d.ts +0 -0
  302. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/index.js +0 -0
  303. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/contract.js +0 -0
  304. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/errors.d.ts +0 -0
  305. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/errors.js +0 -0
  306. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/handover.d.ts +0 -0
  307. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/handover.js +0 -0
  308. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/index.d.ts +0 -0
  309. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/index.js +0 -0
  310. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/lander.d.ts +0 -0
  311. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/marker.d.ts +0 -0
  312. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/marker.js +0 -0
  313. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/contract.d.ts +0 -0
  314. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/contract.js +0 -0
  315. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/format.d.ts +0 -0
  316. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/format.js +0 -0
  317. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/index.d.ts +0 -0
  318. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/index.js +0 -0
  319. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/contract.d.ts +0 -0
  320. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/contract.js +0 -0
  321. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/index.d.ts +0 -0
  322. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/index.js +0 -0
  323. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/rules.d.ts +0 -0
  324. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/rules.js +0 -0
  325. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/wiring.d.ts +0 -0
  326. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/index.d.ts +0 -0
  327. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/index.js +0 -0
  328. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/contract.d.ts +0 -0
  329. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/contract.js +0 -0
  330. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/defaults.d.ts +0 -0
  331. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/defaults.js +0 -0
  332. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/errors.d.ts +0 -0
  333. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/errors.js +0 -0
  334. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/index.d.ts +0 -0
  335. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/index.js +0 -0
  336. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/loader.d.ts +0 -0
  337. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/loader.js +0 -0
  338. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/paths.d.ts +0 -0
  339. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/paths.js +0 -0
  340. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/validate.d.ts +0 -0
  341. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/validate.js +0 -0
  342. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/contract.js +0 -0
  343. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/index.d.ts +0 -0
  344. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/index.js +0 -0
  345. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/contract.d.ts +0 -0
  346. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/contract.js +0 -0
  347. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/file-committer.d.ts +0 -0
  348. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/file-committer.js +0 -0
  349. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/index.d.ts +0 -0
  350. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/index.js +0 -0
  351. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/contract.d.ts +0 -0
  352. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/contract.js +0 -0
  353. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/estimator.d.ts +0 -0
  354. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/estimator.js +0 -0
  355. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/index.d.ts +0 -0
  356. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/index.js +0 -0
  357. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/session/contract.js +0 -0
@@ -0,0 +1,36 @@
1
+ /** Explicit routing preferences; never foreground selections or authorization for a cheaper tier. */
2
+ import { mutateConfigFile } from "./config-file-transaction.ts";
3
+
4
+ export function validModelPinScope(scope: string): boolean {
5
+ return /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(scope);
6
+ }
7
+
8
+ export function normalizeModelPins(value: unknown): Record<string, string> {
9
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
10
+ return Object.fromEntries(Object.entries(value).filter(([scope, model]) =>
11
+ validModelPinScope(scope) && typeof model === "string" && model.trim().length > 0 &&
12
+ !/[\s\x00-\x1f]/.test(model.trim()),
13
+ ).map(([scope, model]) => [scope, (model as string).trim()]));
14
+ }
15
+
16
+ /** Change only one group's pin through the shared extension configuration transaction. */
17
+ export function persistModelPin(
18
+ path: string,
19
+ scope: string,
20
+ model: string | undefined,
21
+ canCommit: () => boolean = () => true,
22
+ ): Record<string, string> {
23
+ if (!validModelPinScope(scope) || (model !== undefined && normalizeModelPins({ [scope]: model })[scope] !== model)) {
24
+ throw new Error("invalid model pin");
25
+ }
26
+ const next = mutateConfigFile(path, disk => {
27
+ if (disk.pinnedModels !== undefined && (!disk.pinnedModels || typeof disk.pinnedModels !== "object" || Array.isArray(disk.pinnedModels))) {
28
+ throw new Error("pinnedModels must be an object");
29
+ }
30
+ const pins = { ...disk.pinnedModels };
31
+ if (model === undefined) delete pins[scope];
32
+ else pins[scope] = model;
33
+ return { pinnedModels: pins };
34
+ }, canCommit);
35
+ return normalizeModelPins(next.pinnedModels);
36
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-multi-account",
3
- "version": "1.23.2",
3
+ "version": "1.24.0",
4
4
  "description": "Automatic multi-account failover & rotation for Pi Agent across Anthropic (Claude), OpenAI/ChatGPT Codex, Kimi For Coding, Cursor, Qwen/Alibaba, and Ollama. Auto-discovers authenticated accounts, grows the rotation on login, and drops accounts on logout, expiry, or quota/rate-limit errors",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -45,7 +45,9 @@
45
45
  "provider-payload-stream.ts",
46
46
  "auth-file-transaction.ts",
47
47
  "state-file-transaction.ts",
48
+ "config-file-transaction.ts",
48
49
  "model-catalog.ts",
50
+ "model-pins.ts",
49
51
  "usage.ts",
50
52
  "cursor-bridge.ts",
51
53
  "cursor-model-name.ts",
@@ -78,13 +80,13 @@
78
80
  "access": "public"
79
81
  },
80
82
  "peerDependencies": {
81
- "@earendil-works/pi-coding-agent": "*",
82
- "@earendil-works/pi-ai": "*"
83
+ "@earendil-works/pi-ai": "*",
84
+ "@earendil-works/pi-coding-agent": "*"
83
85
  },
84
86
  "devDependencies": {
85
- "@earendil-works/pi-coding-agent": "0.85.1",
86
- "@earendil-works/pi-ai": "0.85.1",
87
- "@types/node": "^22.20.1",
87
+ "@earendil-works/pi-ai": "0.87.1",
88
+ "@earendil-works/pi-coding-agent": "0.87.1",
89
+ "@types/node": "^22.20.4",
88
90
  "typescript": "^6.0.3"
89
91
  },
90
92
  "pi": {
@@ -93,7 +95,7 @@
93
95
  ]
94
96
  },
95
97
  "dependencies": {
96
- "@bufbuild/protobuf": "^2.14.0",
98
+ "@bufbuild/protobuf": "^2.15.0",
97
99
  "proper-lockfile": "4.1.2"
98
100
  },
99
101
  "overrides": {
@@ -28,6 +28,7 @@ import {
28
28
  } from "./cursor-bridge.ts";
29
29
  import {
30
30
  needsChildFacingApiKey,
31
+ isPlaceholderFor,
31
32
  placeholderKeyFor,
32
33
  proxyFamilyFor,
33
34
  type ProxyFamily,
@@ -67,7 +68,7 @@ export function isChildFacingPlaceholder(
67
68
  entry: AuthBlob | undefined,
68
69
  family: ProxyFamily,
69
70
  ): boolean {
70
- return entry?.type === "api_key" && entry.key === placeholderKeyFor(family);
71
+ return entry?.type === "api_key" && isPlaceholderFor(family, entry.key);
71
72
  }
72
73
 
73
74
  export function isChildFacingPlaceholderForSlot(
@@ -75,7 +76,9 @@ export function isChildFacingPlaceholderForSlot(
75
76
  slotId: string,
76
77
  ): boolean {
77
78
  const key = childFacingPlaceholderKey(slotId);
78
- return !!key && entry?.type === "api_key" && entry.key === key;
79
+ const family = proxyFamilyFor(slotId);
80
+ return !!key && entry?.type === "api_key" &&
81
+ (family ? isPlaceholderFor(family, entry.key) : entry.key === key);
79
82
  }
80
83
 
81
84
  /** What the parent should use for refresh/upstream: sidecar OAuth wins over a child-facing placeholder. */
@@ -101,6 +104,13 @@ export function applyShadowPlan(
101
104
  return { auth: { ...auth }, sidecar: { ...sidecar }, changed: false };
102
105
  }
103
106
  const entry = auth[slotId];
107
+ const hidden = sidecar[slotId];
108
+ if (isChildFacingPlaceholderForSlot(entry, slotId) && entry?.key !== facing.key &&
109
+ hidden?.type === "oauth" && typeof hidden.access === "string" && hidden.access.length > 0) {
110
+ // Upgrade only a publication backed by the parent's actual OAuth blob. Never rewrite a
111
+ // user's real API key or replace the hidden credential with a placeholder during migration.
112
+ return { auth: { ...auth, [slotId]: facing }, sidecar: { ...sidecar }, changed: true };
113
+ }
104
114
  if (entry?.type === "oauth" && typeof entry.access === "string" && entry.access.length > 0) {
105
115
  return {
106
116
  auth: { ...auth, [slotId]: facing },
@@ -36,6 +36,14 @@
36
36
  */
37
37
  export const PROXY_PLACEHOLDER_KEY = "pi-multi-account-proxy";
38
38
 
39
+ /**
40
+ * Non-secret Anthropic placeholder with the shape Pi's native transport recognizes as OAuth.
41
+ * Request identity, tool-name conversion and response mapping all depend on this marker; adding
42
+ * a Bearer header at the proxy is too late. The proxy replaces it with the real token on egress.
43
+ * The legacy generic placeholder remains recognizable for restoration during an upgrade.
44
+ */
45
+ export const ANTHROPIC_PROXY_PLACEHOLDER_KEY = "sk-ant-oat01-pi-multi-account-proxy";
46
+
39
47
  /**
40
48
  * The `apiKey` published for a **Codex** slot.
41
49
  *
@@ -60,9 +68,10 @@ export const PROXY_PLACEHOLDER_JWT = [
60
68
  "",
61
69
  ].join(".");
62
70
 
63
- /** Either published placeholder — neither is a credential, both mark "a child we published for". */
71
+ /** Current or legacy published placeholder — none is a real credential. */
64
72
  export function isPublishedPlaceholder(value: string | undefined): boolean {
65
- return value === PROXY_PLACEHOLDER_KEY || value === PROXY_PLACEHOLDER_JWT;
73
+ return value === PROXY_PLACEHOLDER_KEY || value === PROXY_PLACEHOLDER_JWT ||
74
+ value === ANTHROPIC_PROXY_PLACEHOLDER_KEY;
66
75
  }
67
76
 
68
77
  export type ProxyFamily = "anthropic" | "codex";
@@ -273,7 +282,14 @@ export function shapeUpstreamRequest(args: {
273
282
  }
274
283
  }
275
284
 
276
- return { ok: true, url: `${base}${rest}`, headers };
285
+ // Image tools append these endpoints directly to the slot base; chat already sends /codex.
286
+ // Leave all other paths and families intact, including usage requests.
287
+ const upstreamRest =
288
+ route.family === "codex" && /^\/images\/(?:generations|edits)(?:\?.*)?$/.test(rest)
289
+ ? `/codex${rest}`
290
+ : rest;
291
+
292
+ return { ok: true, url: `${base}${upstreamRest}`, headers };
277
293
  }
278
294
 
279
295
  /** Keep any beta flags the caller asked for, and add ours once. */
@@ -289,7 +305,13 @@ function mergeBeta(existing: string | undefined, required: string): string {
289
305
 
290
306
  /** The `apiKey` to publish for a slot of this family. */
291
307
  export function placeholderKeyFor(family: ProxyFamily): string {
292
- return family === "codex" ? PROXY_PLACEHOLDER_JWT : PROXY_PLACEHOLDER_KEY;
308
+ return family === "codex" ? PROXY_PLACEHOLDER_JWT : ANTHROPIC_PROXY_PLACEHOLDER_KEY;
309
+ }
310
+
311
+ /** Recognize the previous Anthropic publication without mistaking real tokens for placeholders. */
312
+ export function isPlaceholderFor(family: ProxyFamily, value: unknown): boolean {
313
+ return value === placeholderKeyFor(family) ||
314
+ (family === "anthropic" && value === PROXY_PLACEHOLDER_KEY);
293
315
  }
294
316
 
295
317
  /** The `models.json` route to publish for a slot served by this proxy. */
@@ -305,7 +327,7 @@ export function isOwnLoopbackPublication(
305
327
  if (!existing || typeof existing !== "object") return false;
306
328
  const rec = existing as Record<string, unknown>;
307
329
  return (
308
- rec.apiKey === placeholderKeyFor(family) &&
330
+ isPlaceholderFor(family, rec.apiKey) &&
309
331
  typeof rec.baseUrl === "string" &&
310
332
  rec.baseUrl.startsWith("http://127.0.0.1:")
311
333
  );
@@ -142,7 +142,7 @@ if (!answer.ok) return { skipped: answer.errorCode === "budget" }; // never thr
142
142
 
143
143
  Your extension owns its own user consent and budget; `/typesafe enable` applies only to this package's tool. Check `authState()` rather than your own consent flag before you report that judgments are on.
144
144
 
145
- Judgments can also go through OpenRouter: `createTypeSafe({ backend: "openrouter" })` sends them to `openrouter.ai` with the key from `OPENROUTER_API_KEY`. Command Code serves the same protocol: `createTypeSafe({ backend: "commandcode" })` sends them to `api.commandcode.ai` with the key from `COMMANDCODE_API_KEY` and the model `typesafe/jev`. Or pass a `BackendEndpoint` object as `backend` to name any host that serves the protocol: it brings its own key variable, never reads `TYPESAFE_API_KEY`, and `backendHost()` reports its destination host for your consent text. These backends have no login store, so `/typesafe login` does not apply to them. Pass the same `backend` to `authState`, `keySituation`, and `ensureApiKey`, or the status you report describes the TypeSafe key while the requests use another one. The `/typesafe` commands and the `typesafe_evaluate` tool always use the TypeSafe backend. Every export — the client, `ask`, batching, the usage ledger, auth state, and the `pi-typesafe/calibrate` and `pi-typesafe/ui` entry points — is in [docs/api.md](docs/api.md).
145
+ Judgments can also go through OpenRouter: `createTypeSafe({ backend: "openrouter" })` sends them to `openrouter.ai` with the key from `OPENROUTER_API_KEY`. Command Code serves the same protocol: `createTypeSafe({ backend: "commandcode" })` sends them to `api.commandcode.ai` with the key from `COMMANDCODE_API_KEY` and the model `typesafe/jev`. So does Liquid AI: `createTypeSafe({ backend: "liquid" })` sends them to `api.liquid.ai` with the key from `LIQUID_API_KEY` and the model `d1:free`, which is free; pass `model: "d1"` for the paid model, priced at $0.040 per million input tokens. Liquid counts the state once per question, where TypeSafe counts it once per request, so a request with N questions costs about N times the state on Liquid. Speed, measured on 2026-10-03 with one request at a time: `d1:free` took a median of about 14 seconds and sometimes failed with HTTP 504 after about 46 seconds, while `d1` took about 0.5 seconds. With `d1:free`, raise `timeoutMs` above its 15-second default, or pass `model: "d1"`. Or pass a `BackendEndpoint` object as `backend` to name any host that serves the protocol: it brings its own key variable, never reads `TYPESAFE_API_KEY`, and `backendHost()` reports its destination host for your consent text. These backends have no login store, so `/typesafe login` does not apply to them. Pass the same `backend` to `authState`, `keySituation`, and `ensureApiKey`, or the status you report describes the TypeSafe key while the requests use another one. The `/typesafe` commands and the `typesafe_evaluate` tool always use the TypeSafe backend. Every export — the client, `ask`, batching, the usage ledger, auth state, and the `pi-typesafe/calibrate` and `pi-typesafe/ui` entry points — is in [docs/api.md](docs/api.md).
146
146
 
147
147
  ## Development
148
148
 
@@ -1,6 +1,6 @@
1
- export type TypeSafeBackend = "typesafe" | "openrouter" | "commandcode";
1
+ export type TypeSafeBackend = "typesafe" | "openrouter" | "commandcode" | "liquid";
2
2
  export interface BackendConfig {
3
- /** Human name for status lines: "TypeSafe", "OpenRouter", "Command Code". */
3
+ /** Human name for status lines: "TypeSafe", "OpenRouter", "Command Code", "Liquid AI". */
4
4
  label: string;
5
5
  host: string;
6
6
  /** The environment variable that carries this backend's key. Absent means the TypeSafe key resolution applies. */
@@ -16,6 +16,11 @@ export interface BackendConfig {
16
16
  /** Whether the model list checks the key. A public list accepts any key, so it proves nothing. Absent means it does. */
17
17
  modelsVerifyKey?: boolean;
18
18
  }
19
+ /** A registry entry: a backend config that can also name a price per model. Caller-supplied endpoints carry none. */
20
+ export interface RegistryBackendConfig extends BackendConfig {
21
+ /** USD per million input tokens, by the model id as it is sent. A model with no entry is priced at DEFAULT_USD_PER_MTOK. */
22
+ prices?: Readonly<Record<string, number>>;
23
+ }
19
24
  /** A caller-supplied endpoint that serves the Jev decisions protocol. Passed per call; never added to the registry. */
20
25
  export interface BackendEndpoint extends BackendConfig {
21
26
  /** Required. The environment variable with this endpoint's key. Must not be TYPESAFE_API_KEY. */
@@ -26,7 +31,7 @@ export interface BackendEndpoint extends BackendConfig {
26
31
  /** A registry name or a caller-supplied endpoint. */
27
32
  export type BackendSpec = TypeSafeBackend | BackendEndpoint;
28
33
  /** A backend resolved and validated: what the client will actually use. */
29
- export interface ResolvedBackend extends BackendConfig {
34
+ export interface ResolvedBackend extends RegistryBackendConfig {
30
35
  /** Registry name, absent for a caller-supplied endpoint. */
31
36
  readonly name?: TypeSafeBackend;
32
37
  /** Origin only: scheme, host, and port. */
@@ -42,9 +47,9 @@ export declare const DEFAULT_BACKEND: TypeSafeBackend;
42
47
  /** The environment variable and login store that the default backend reads. */
43
48
  export declare const TYPESAFE_KEY_ENV = "TYPESAFE_API_KEY";
44
49
  /** Registry of known judgment backends. Callers pass a `BackendEndpoint` for a host this registry does not name. */
45
- export declare const DECISIONS_BACKENDS: Record<TypeSafeBackend, BackendConfig>;
50
+ export declare const DECISIONS_BACKENDS: Record<TypeSafeBackend, RegistryBackendConfig>;
46
51
  /** The registry entry for a backend name; a `configuration` error for a name the registry does not know. */
47
- export declare function backendConfig(name: TypeSafeBackend): BackendConfig;
52
+ export declare function backendConfig(name: TypeSafeBackend): RegistryBackendConfig;
48
53
  /**
49
54
  * The model id to send for a caller's `model` on this backend. OpenRouter routes a bare Jev id under the `typesafe`
50
55
  * author: `jev-latest` becomes its alias form `~typesafe/jev-latest`, and a bare `jev-<major>.<minor>` — with or
@@ -55,6 +60,11 @@ export declare function backendConfig(name: TypeSafeBackend): BackendConfig;
55
60
  export declare function backendModelId(backend: TypeSafeBackend, model: string): string;
56
61
  /** The model a client sends when the caller names none: the backend's own default, in the form that backend accepts. */
57
62
  export declare function defaultModelId(backend: TypeSafeBackend): string;
63
+ /**
64
+ * The registry's price for a model, in USD per million input tokens, or undefined when the backend names none.
65
+ * `model` is the id as sent. A caller-supplied endpoint has no prices.
66
+ */
67
+ export declare function backendPrice(backend: ResolvedBackend, model: string): number | undefined;
58
68
  /**
59
69
  * Whether a backend's key comes from the TypeSafe resolution (`TYPESAFE_API_KEY`, then the login store) or only from
60
70
  * its own environment variable. Only the TypeSafe backend has a login store; every other backend is environment-only.
@@ -26,6 +26,15 @@ export const DECISIONS_BACKENDS = {
26
26
  modelsIdField: "id",
27
27
  modelsVerifyKey: false,
28
28
  },
29
+ liquid: {
30
+ label: "Liquid AI",
31
+ host: "https://api.liquid.ai",
32
+ keyEnv: "LIQUID_API_KEY",
33
+ path: "/decisions/v1/systemone",
34
+ modelsPath: "/decisions/v1/models",
35
+ modelsVerifyKey: true,
36
+ prices: { d1: 0.04, "d1:free": 0 },
37
+ },
29
38
  };
30
39
  /** The registry entry for a backend name; a `configuration` error for a name the registry does not know. */
31
40
  export function backendConfig(name) {
@@ -39,6 +48,7 @@ const DEFAULT_MODEL = {
39
48
  typesafe: "jev-latest",
40
49
  openrouter: "typesafe/jev-1.13",
41
50
  commandcode: "typesafe/jev",
51
+ liquid: "d1:free",
42
52
  };
43
53
  /**
44
54
  * The model id to send for a caller's `model` on this backend. OpenRouter routes a bare Jev id under the `typesafe`
@@ -61,6 +71,14 @@ export function backendModelId(backend, model) {
61
71
  export function defaultModelId(backend) {
62
72
  return backendModelId(backend, DEFAULT_MODEL[backend]);
63
73
  }
74
+ /**
75
+ * The registry's price for a model, in USD per million input tokens, or undefined when the backend names none.
76
+ * `model` is the id as sent. A caller-supplied endpoint has no prices.
77
+ */
78
+ export function backendPrice(backend, model) {
79
+ const prices = backend.prices;
80
+ return prices !== undefined && Object.hasOwn(prices, model) ? prices[model] : undefined;
81
+ }
64
82
  /**
65
83
  * Whether a backend's key comes from the TypeSafe resolution (`TYPESAFE_API_KEY`, then the login store) or only from
66
84
  * its own environment variable. Only the TypeSafe backend has a login store; every other backend is environment-only.
@@ -2,8 +2,8 @@ import type { Fetch, Questions, SystemOneRequest, SystemOneResult } from "@types
2
2
  import type { BackendSpec } from "./backends.js";
3
3
  import type { BatchEvaluation, BatchOptions } from "./batch.js";
4
4
  import type { BlockedCap, SpendCaps, UsageLedger, UsageReport } from "./usage.js";
5
- export { backendHost, resolveBackend, DECISIONS_BACKENDS, DEFAULT_BACKEND } from "./backends.js";
6
- export type { BackendConfig, BackendEndpoint, BackendSpec, ResolvedBackend, TypeSafeBackend } from "./backends.js";
5
+ export { backendHost, backendPrice, resolveBackend, DECISIONS_BACKENDS, DEFAULT_BACKEND } from "./backends.js";
6
+ export type { BackendConfig, BackendEndpoint, BackendSpec, RegistryBackendConfig, ResolvedBackend, TypeSafeBackend } from "./backends.js";
7
7
  export interface TypeSafeOptions {
8
8
  /** Defaults to TYPESAFE_API_KEY, then the key saved by `/typesafe login`; never returned. */
9
9
  apiKey?: string;
@@ -23,7 +23,7 @@ export interface TypeSafeOptions {
23
23
  maxInputTokensPerDay?: number;
24
24
  /** Estimated spend per local day, in US dollars. Unlimited by default. */
25
25
  maxUsdPerDay?: number;
26
- /** Price used for the cost estimate and the USD cap. Default: DEFAULT_USD_PER_MTOK. */
26
+ /** Price in USD per million input tokens, used for every request's cost and the USD cap; 0 means free. Default: the backend's price for the model sent, else DEFAULT_USD_PER_MTOK. */
27
27
  usdPerMTok?: number;
28
28
  /** The usage ledger; defaults to the store next to the key. Injected by tests. */
29
29
  ledger?: UsageLedger;
@@ -50,6 +50,7 @@ export interface SpendReport {
50
50
  readonly session: UsageSnapshot;
51
51
  readonly today: UsageReport;
52
52
  readonly caps: SpendCaps;
53
+ /** The price of this client's default model. A request that names another model may be priced differently. */
53
54
  readonly usdPerMTok: number;
54
55
  readonly blocked?: BlockedCap;
55
56
  }
@@ -1,12 +1,12 @@
1
1
  import { TypeSafeClient } from "@typesafe-ai/sdk";
2
2
  import { recordAuthFailure, recordAuthVerified } from "./auth.js";
3
- import { TYPESAFE_KEY_ENV, backendModelId, resolveBackend, usesTypesafeKey } from "./backends.js";
3
+ import { TYPESAFE_KEY_ENV, backendModelId, backendPrice, resolveBackend, usesTypesafeKey } from "./backends.js";
4
4
  import { evaluateAll, evaluateMany } from "./batch.js";
5
5
  import { keySituation } from "./credentials.js";
6
6
  import { TypeSafeIntegrationError, safeError } from "./errors.js";
7
7
  import { DEFAULT_MAX_INPUT_BYTES, assertWithinByteLimit, prepareEvaluationRequest } from "./schema.js";
8
8
  import { DEFAULT_USD_PER_MTOK, capsFromEnvironment, estimateUsd, mergeCaps, openUsageLedger } from "./usage.js";
9
- export { backendHost, resolveBackend, DECISIONS_BACKENDS, DEFAULT_BACKEND } from "./backends.js";
9
+ export { backendHost, backendPrice, resolveBackend, DECISIONS_BACKENDS, DEFAULT_BACKEND } from "./backends.js";
10
10
  /** The paths the SDK appends to whatever base URL it is given. */
11
11
  const SDK_PATH = "/v1/systemone";
12
12
  const SDK_MODELS_PATH = "/v1/models";
@@ -63,6 +63,12 @@ function positiveInteger(value, label) {
63
63
  }
64
64
  return value;
65
65
  }
66
+ function nonNegativeNumber(value, label) {
67
+ if (!Number.isFinite(value) || value < 0) {
68
+ throw new TypeSafeIntegrationError("configuration", `${label} must be a non-negative number.`);
69
+ }
70
+ return value;
71
+ }
66
72
  function positiveNumber(value, label) {
67
73
  if (!Number.isFinite(value) || value <= 0) {
68
74
  throw new TypeSafeIntegrationError("configuration", `${label} must be a positive number.`);
@@ -138,7 +144,7 @@ export function createTypeSafe(options = {}) {
138
144
  const timeout = positiveInteger(options.timeoutMs ?? 15_000, "timeoutMs");
139
145
  const maxInputBytes = positiveInteger(options.maxInputBytes ?? DEFAULT_MAX_INPUT_BYTES, "maxInputBytes");
140
146
  const maxRequests = positiveInteger(options.maxRequests ?? DEFAULT_MAX_REQUESTS, "maxRequests");
141
- const usdPerMTok = positiveNumber(options.usdPerMTok ?? DEFAULT_USD_PER_MTOK, "usdPerMTok");
147
+ const callerRate = options.usdPerMTok === undefined ? undefined : nonNegativeNumber(options.usdPerMTok, "usdPerMTok");
142
148
  const caps = mergeCaps({
143
149
  maxRequests,
144
150
  ...(options.maxRequestsPerDay === undefined ? {} : { maxRequestsPerDay: positiveInteger(options.maxRequestsPerDay, "maxRequestsPerDay") }),
@@ -165,12 +171,17 @@ export function createTypeSafe(options = {}) {
165
171
  logLevel: "off",
166
172
  ...(transport ? { fetch: transport } : {}),
167
173
  });
168
- const ledger = options.ledger ?? openUsageLedger({ usdPerMTok });
174
+ // The caller's price wins; else the backend's price for the model sent; else the default. Each request is priced alone.
175
+ const rateFor = (sent) => callerRate ?? backendPrice(backend, sent) ?? DEFAULT_USD_PER_MTOK;
176
+ const usdPerMTok = rateFor(model);
177
+ // The ledger's own rate only estimates input tokens that carry no recorded cost, so it follows the caller's price alone.
178
+ const ledger = options.ledger ?? openUsageLedger(callerRate === undefined ? {} : { usdPerMTok: callerRate });
179
+ let sessionUsd = 0;
169
180
  const usage = { requestsStarted: 0, requestsSucceeded: 0, requestsFailed: 0, inputTokens: 0, outputTokens: 0 };
170
181
  // Auth state writes are deduplicated: one verification record per process, one record per distinct failure.
171
182
  let verificationRecorded = false;
172
183
  let lastFailureRecorded;
173
- const snapshot = () => ({ ...usage, estimatedUsd: estimateUsd(usage.inputTokens, usdPerMTok) });
184
+ const snapshot = () => ({ ...usage, estimatedUsd: Math.round(sessionUsd * 1e6) / 1e6 });
174
185
  const blocked = () => (usage.requestsStarted >= maxRequests ? undefined : ledger.blocked(caps));
175
186
  const typesafe = {
176
187
  getUsage: snapshot,
@@ -203,7 +214,8 @@ export function createTypeSafe(options = {}) {
203
214
  async evaluate(input, callOptions = {}) {
204
215
  const validated = prepareEvaluationRequest(input, { maxInputBytes });
205
216
  // A per-request model meets the same mapping as the client default; the schema already limited the caller's own id.
206
- const body = JSON.stringify({ ...validated, model: validated.model === undefined ? model : mapModel(validated.model) });
217
+ const sentModel = validated.model === undefined ? model : mapModel(validated.model);
218
+ const body = JSON.stringify({ ...validated, model: sentModel });
207
219
  assertWithinByteLimit(body, maxInputBytes);
208
220
  if (callOptions.signal?.aborted)
209
221
  throw new TypeSafeIntegrationError("aborted", "TypeSafe request cancelled before submission.");
@@ -227,7 +239,10 @@ export function createTypeSafe(options = {}) {
227
239
  usage.requestsSucceeded += 1;
228
240
  usage.inputTokens += result.usage.input_tokens;
229
241
  usage.outputTokens += result.usage.output_tokens;
230
- ledger.recordSuccess(result.usage.input_tokens, result.usage.output_tokens);
242
+ // Unrounded: a small request must still count toward the cap.
243
+ const cost = (result.usage.input_tokens * rateFor(sentModel)) / 1e6;
244
+ sessionUsd += cost;
245
+ ledger.recordSuccess(result.usage.input_tokens, result.usage.output_tokens, cost);
231
246
  if (!verificationRecorded) {
232
247
  verificationRecorded = true;
233
248
  recordAuthVerified();
@@ -1,5 +1,5 @@
1
- export { createTypeSafe, backendHost, resolveBackend, DEFAULT_MAX_REQUESTS, DECISIONS_BACKENDS, DEFAULT_BACKEND } from "./client.js";
2
- export type { TypeSafe, TypeSafeOptions, EvaluationOptions, Evaluation, UsageSnapshot, SpendReport, TypeSafeBackend, BackendConfig, BackendEndpoint, BackendSpec, ResolvedBackend, } from "./client.js";
1
+ export { createTypeSafe, backendHost, backendPrice, resolveBackend, DEFAULT_MAX_REQUESTS, DECISIONS_BACKENDS, DEFAULT_BACKEND } from "./client.js";
2
+ export type { TypeSafe, TypeSafeOptions, EvaluationOptions, Evaluation, UsageSnapshot, SpendReport, TypeSafeBackend, BackendConfig, BackendEndpoint, BackendSpec, RegistryBackendConfig, ResolvedBackend, } from "./client.js";
3
3
  export { ask, DEFAULT_ASK_TIMEOUT_MS } from "./ask.js";
4
4
  export type { AskAnswer, AskOptions, Judge } from "./ask.js";
5
5
  export { fanOut, DEFAULT_CONCURRENCY, evaluateMany, evaluateAll, chunkEvaluationRequest } from "./batch.js";
@@ -1,4 +1,4 @@
1
- export { createTypeSafe, backendHost, resolveBackend, DEFAULT_MAX_REQUESTS, DECISIONS_BACKENDS, DEFAULT_BACKEND } from "./client.js";
1
+ export { createTypeSafe, backendHost, backendPrice, resolveBackend, DEFAULT_MAX_REQUESTS, DECISIONS_BACKENDS, DEFAULT_BACKEND } from "./client.js";
2
2
  export { ask, DEFAULT_ASK_TIMEOUT_MS } from "./ask.js";
3
3
  export { fanOut, DEFAULT_CONCURRENCY, evaluateMany, evaluateAll, chunkEvaluationRequest } from "./batch.js";
4
4
  export { authState, authStatePath, clearAuthState, describeAuth, recordAuthFailure, recordAuthVerified } from "./auth.js";
@@ -40,6 +40,10 @@ export declare function usagePath(): string;
40
40
  /** Input-token cost, rounded to a micro-dollar so the number stays readable. */
41
41
  export declare function estimateUsd(inputTokens: number, usdPerMTok: number): number;
42
42
  export declare function emptyTotals(): UsageTotals;
43
+ /** Longest an update waits for the ledger lock. A request that cannot get it keeps its delta and adds it with the next update. */
44
+ export declare const LOCK_WAIT_MS = 200;
45
+ /** A lock this old belongs to a process that died while holding it; the next update takes it over. */
46
+ export declare const LOCK_STALE_MS = 5000;
43
47
  /** The caps a headless run may set without code: `PI_TYPESAFE_MAX_USD_PER_DAY` and its siblings. */
44
48
  export declare function capsFromEnvironment(env?: NodeJS.ProcessEnv): SpendCaps;
45
49
  /** Environment first for day caps, then the explicit option; a cap is never raised by the environment. */
@@ -49,12 +53,15 @@ export interface UsageLedgerOptions {
49
53
  path?: string;
50
54
  /** Clock for the local day and for rollover; injectable for tests. */
51
55
  now?: () => Date;
56
+ /** Rate for input tokens that have no recorded cost: requests recorded without one, and days from an older ledger file. Default: DEFAULT_USD_PER_MTOK. */
52
57
  usdPerMTok?: number;
53
58
  }
54
59
  /**
55
- * One day of persisted request, token, and cost totals, plus the caps that stop the next request. The in-memory copy is
56
- * authoritative for this process; the file is the cross-process, across-restart record. Reads are defensive, writes are
57
- * atomic and best-effort, and a day rolls over on the local date, so a long eval cannot accumulate forever unnoticed.
60
+ * One day of persisted request, token, and cost totals, plus the caps that stop the next request. The file is the
61
+ * record for every process: each update adds its delta to the file's current content under a lock, and `today()`,
62
+ * `blocked()`, and `describe()` read the file, so a cap counts every process that writes it. A delta that cannot be
63
+ * written in time (the lock is held, or the file is unwritable) stays in this process and is added with its next
64
+ * update. Reads are defensive, writes are atomic and best-effort, and a day rolls over on the local date.
58
65
  */
59
66
  export interface UsageLedger {
60
67
  readonly path: string;
@@ -63,11 +70,14 @@ export interface UsageLedger {
63
70
  today(): UsageReport;
64
71
  /** Count the attempt before it is submitted; a request that never returns still counts. */
65
72
  recordStart(): void;
66
- recordSuccess(inputTokens: number, outputTokens: number): void;
73
+ /** `usd` is this request's cost at its own price; without it the request is estimated at the ledger's rate. */
74
+ recordSuccess(inputTokens: number, outputTokens: number, usd?: number): void;
67
75
  recordFailure(): void;
68
76
  /** The reached day cap that blocks the next request, or undefined. The caller owns the caps. */
69
77
  blocked(caps: SpendCaps): BlockedCap | undefined;
70
78
  /** One line for status output: today's requests, tokens, and cost, with the caps that apply. */
71
79
  describe(caps?: SpendCaps): string;
80
+ /** Add to the file any delta this process still holds. Updates do this themselves; call it before the process exits. */
81
+ flush?(): void;
72
82
  }
73
83
  export declare function openUsageLedger(options?: UsageLedgerOptions): UsageLedger;