@astralyn/pi 1.1.0 → 1.3.0

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 (290) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/dist/bundle/chunks/anthropic-messages-MSB6JBS2.js +6 -0
  3. package/dist/bundle/chunks/{azure-openai-responses-CH74HGP4.js → azure-openai-responses-ATZ757I2.js} +1 -1
  4. package/dist/bundle/chunks/bedrock-converse-stream.js +14 -11
  5. package/dist/bundle/chunks/{chunk-H35KWBT5.js → chunk-4XZYHGVN.js} +1 -1
  6. package/dist/bundle/chunks/{chunk-MAC4N3BW.js → chunk-7UBIBLPN.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-KAC2YPTW.js → chunk-J75WV3FL.js} +1 -1
  8. package/dist/bundle/chunks/{chunk-EJEOEBSJ.js → chunk-KSCGI7JW.js} +2 -2
  9. package/dist/bundle/chunks/chunk-LUYFHZ6W.js +11 -0
  10. package/dist/bundle/chunks/{chunk-TEAAYBTS.js → chunk-NM2KGRFS.js} +1 -1
  11. package/dist/bundle/chunks/chunk-Q74S7ILH.js +2 -0
  12. package/dist/bundle/chunks/{chunk-QLU3LESZ.js → chunk-QDDSFJ35.js} +1 -1
  13. package/dist/bundle/chunks/{chunk-D3XW5X3Z.js → chunk-R2KES7LS.js} +175 -244
  14. package/dist/bundle/chunks/{chunk-5B3S5DVL.js → chunk-SA2AQYEI.js} +5 -2
  15. package/dist/bundle/chunks/{chunk-C2ARIVS3.js → chunk-YHRHHXFG.js} +1 -1
  16. package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-XO45ZT3V.js → cloudflare-workers-ai-system-one-HGOVFZDC.js} +1 -1
  17. package/dist/bundle/chunks/codemode-worker.js +17 -9
  18. package/dist/bundle/chunks/github-copilot.js +1 -1
  19. package/dist/bundle/chunks/{google-generative-ai-VVO64ZRQ.js → google-generative-ai-QRLQ4MCJ.js} +1 -1
  20. package/dist/bundle/chunks/{google-vertex-LKS5NUHA.js → google-vertex-L3T6EGTL.js} +1 -1
  21. package/dist/bundle/chunks/mistral-conversations-6E6SS3WF.js +5 -0
  22. package/dist/bundle/chunks/openai-codex-responses-4GUO76XJ.js +10 -0
  23. package/dist/bundle/chunks/{openai-completions-7HTTU6FH.js → openai-completions-O4TKZCIM.js} +1 -1
  24. package/dist/bundle/chunks/{openai-decisions-776H4VDZ.js → openai-decisions-TVCDIPZX.js} +1 -1
  25. package/dist/bundle/chunks/openai-responses-VBQKJFNO.js +3 -0
  26. package/dist/bundle/chunks/{pi-messages-ZXNERWJG.js → pi-messages-3POWZ43C.js} +1 -1
  27. package/dist/bundle/chunks/{typesafe-system-one-2DQLG4R2.js → typesafe-system-one-LWPJYTJP.js} +1 -1
  28. package/dist/bundle/chunks/{virtual-modules-2NHGQRS6.js → virtual-modules-TG53AOL4.js} +1 -1
  29. package/dist/bundle/cli.js +1 -1
  30. package/dist/bundle/index.js +1 -1
  31. package/dist/bundle/rpc-entry.js +1 -1
  32. package/dist/cli/credential-print.d.ts.map +1 -1
  33. package/dist/cli/credential-print.js +4 -4
  34. package/dist/cli/credential-print.js.map +1 -1
  35. package/dist/core/agent-session.d.ts +18 -3
  36. package/dist/core/agent-session.d.ts.map +1 -1
  37. package/dist/core/agent-session.js +98 -62
  38. package/dist/core/agent-session.js.map +1 -1
  39. package/dist/core/auth-storage.d.ts.map +1 -1
  40. package/dist/core/auth-storage.js +20 -13
  41. package/dist/core/auth-storage.js.map +1 -1
  42. package/dist/core/bug-report.d.ts +9 -1
  43. package/dist/core/bug-report.d.ts.map +1 -1
  44. package/dist/core/compaction/utils.d.ts +6 -0
  45. package/dist/core/compaction/utils.d.ts.map +1 -1
  46. package/dist/core/compaction/utils.js +7 -8
  47. package/dist/core/compaction/utils.js.map +1 -1
  48. package/dist/core/export-html/template.js +21 -16
  49. package/dist/core/extensions/index.d.ts +1 -1
  50. package/dist/core/extensions/index.d.ts.map +1 -1
  51. package/dist/core/extensions/index.js.map +1 -1
  52. package/dist/core/extensions/runner.d.ts +4 -2
  53. package/dist/core/extensions/runner.d.ts.map +1 -1
  54. package/dist/core/extensions/runner.js +2 -3
  55. package/dist/core/extensions/runner.js.map +1 -1
  56. package/dist/core/extensions/types.d.ts +31 -7
  57. package/dist/core/extensions/types.d.ts.map +1 -1
  58. package/dist/core/extensions/types.js.map +1 -1
  59. package/dist/core/key-id-schema.d.ts +6 -0
  60. package/dist/core/key-id-schema.d.ts.map +1 -0
  61. package/dist/core/key-id-schema.js +16 -0
  62. package/dist/core/key-id-schema.js.map +1 -0
  63. package/dist/core/keybinding-registry.d.ts +4 -3
  64. package/dist/core/keybinding-registry.d.ts.map +1 -1
  65. package/dist/core/keybinding-registry.js +4 -3
  66. package/dist/core/keybinding-registry.js.map +1 -1
  67. package/dist/core/keybindings-schema.d.ts +4 -0
  68. package/dist/core/keybindings-schema.d.ts.map +1 -0
  69. package/dist/core/keybindings-schema.js +16 -0
  70. package/dist/core/keybindings-schema.js.map +1 -0
  71. package/dist/core/keybindings.d.ts +258 -81
  72. package/dist/core/keybindings.d.ts.map +1 -1
  73. package/dist/core/keybindings.js +27 -24
  74. package/dist/core/keybindings.js.map +1 -1
  75. package/dist/core/model-config.d.ts +729 -180
  76. package/dist/core/model-config.d.ts.map +1 -1
  77. package/dist/core/model-config.js +18 -179
  78. package/dist/core/model-config.js.map +1 -1
  79. package/dist/core/model-resolver.d.ts +56 -43
  80. package/dist/core/model-resolver.d.ts.map +1 -1
  81. package/dist/core/model-resolver.js +247 -352
  82. package/dist/core/model-resolver.js.map +1 -1
  83. package/dist/core/model-runtime.d.ts.map +1 -1
  84. package/dist/core/model-runtime.js +11 -6
  85. package/dist/core/model-runtime.js.map +1 -1
  86. package/dist/core/package-manager.d.ts.map +1 -1
  87. package/dist/core/package-manager.js +3 -3
  88. package/dist/core/package-manager.js.map +1 -1
  89. package/dist/core/project-trust.d.ts.map +1 -1
  90. package/dist/core/project-trust.js +2 -1
  91. package/dist/core/project-trust.js.map +1 -1
  92. package/dist/core/prompt-templates.d.ts.map +1 -1
  93. package/dist/core/prompt-templates.js +7 -2
  94. package/dist/core/prompt-templates.js.map +1 -1
  95. package/dist/core/remote-catalog-provider.d.ts +12 -1
  96. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  97. package/dist/core/remote-catalog-provider.js +82 -24
  98. package/dist/core/remote-catalog-provider.js.map +1 -1
  99. package/dist/core/resource-loader.d.ts.map +1 -1
  100. package/dist/core/resource-loader.js +7 -2
  101. package/dist/core/resource-loader.js.map +1 -1
  102. package/dist/core/settings-defaults.d.ts +66 -0
  103. package/dist/core/settings-defaults.d.ts.map +1 -0
  104. package/dist/core/settings-defaults.js +67 -0
  105. package/dist/core/settings-defaults.js.map +1 -0
  106. package/dist/core/settings-manager.d.ts +6 -149
  107. package/dist/core/settings-manager.d.ts.map +1 -1
  108. package/dist/core/settings-manager.js +59 -44
  109. package/dist/core/settings-manager.js.map +1 -1
  110. package/dist/core/settings-schema.d.ts +233 -0
  111. package/dist/core/settings-schema.d.ts.map +1 -0
  112. package/dist/core/settings-schema.js +298 -0
  113. package/dist/core/settings-schema.js.map +1 -0
  114. package/dist/core/slash-commands.js +1 -1
  115. package/dist/core/slash-commands.js.map +1 -1
  116. package/dist/core/tools/render-utils.d.ts +20 -0
  117. package/dist/core/tools/render-utils.d.ts.map +1 -1
  118. package/dist/core/tools/render-utils.js +67 -0
  119. package/dist/core/tools/render-utils.js.map +1 -1
  120. package/dist/core/tools/renderers/bash.d.ts.map +1 -1
  121. package/dist/core/tools/renderers/bash.js +21 -50
  122. package/dist/core/tools/renderers/bash.js.map +1 -1
  123. package/dist/core/tools/renderers/read.d.ts.map +1 -1
  124. package/dist/core/tools/renderers/read.js +7 -11
  125. package/dist/core/tools/renderers/read.js.map +1 -1
  126. package/dist/extensions/btw/keybindings.d.ts +2 -2
  127. package/dist/extensions/btw/keybindings.d.ts.map +1 -1
  128. package/dist/extensions/btw/keybindings.js.map +1 -1
  129. package/dist/extensions/codemode/execute.d.ts.map +1 -1
  130. package/dist/extensions/codemode/execute.js +76 -45
  131. package/dist/extensions/codemode/execute.js.map +1 -1
  132. package/dist/extensions/codemode/index.d.ts.map +1 -1
  133. package/dist/extensions/codemode/index.js +3 -7
  134. package/dist/extensions/codemode/index.js.map +1 -1
  135. package/dist/extensions/codemode/renderer.d.ts +2 -2
  136. package/dist/extensions/codemode/renderer.d.ts.map +1 -1
  137. package/dist/extensions/codemode/renderer.js +9 -3
  138. package/dist/extensions/codemode/renderer.js.map +1 -1
  139. package/dist/extensions/codemode/tool.d.ts +6 -12
  140. package/dist/extensions/codemode/tool.d.ts.map +1 -1
  141. package/dist/extensions/codemode/tool.js +44 -32
  142. package/dist/extensions/codemode/tool.js.map +1 -1
  143. package/dist/extensions/list-keybindings.d.ts +2 -2
  144. package/dist/extensions/list-keybindings.d.ts.map +1 -1
  145. package/dist/extensions/list-keybindings.js.map +1 -1
  146. package/dist/extensions/mcp/cli.js +5 -8
  147. package/dist/extensions/mcp/cli.js.map +1 -1
  148. package/dist/extensions/mcp/index.d.ts.map +1 -1
  149. package/dist/extensions/mcp/index.js +25 -34
  150. package/dist/extensions/mcp/index.js.map +1 -1
  151. package/dist/extensions/mcp/resources.d.ts +0 -6
  152. package/dist/extensions/mcp/resources.d.ts.map +1 -1
  153. package/dist/extensions/mcp/resources.js +1 -1
  154. package/dist/extensions/mcp/resources.js.map +1 -1
  155. package/dist/extensions/mcp/runtime.d.ts +3 -6
  156. package/dist/extensions/mcp/runtime.d.ts.map +1 -1
  157. package/dist/extensions/mcp/runtime.js +4 -39
  158. package/dist/extensions/mcp/runtime.js.map +1 -1
  159. package/dist/extensions/mcp/tools.d.ts +2 -3
  160. package/dist/extensions/mcp/tools.d.ts.map +1 -1
  161. package/dist/extensions/mcp/tools.js +62 -6
  162. package/dist/extensions/mcp/tools.js.map +1 -1
  163. package/dist/extensions/provider/keybindings.d.ts +2 -2
  164. package/dist/extensions/provider/keybindings.d.ts.map +1 -1
  165. package/dist/extensions/provider/keybindings.js.map +1 -1
  166. package/dist/extensions/search/code-search.d.ts +0 -2
  167. package/dist/extensions/search/code-search.d.ts.map +1 -1
  168. package/dist/extensions/search/code-search.js +2 -2
  169. package/dist/extensions/search/code-search.js.map +1 -1
  170. package/dist/extensions/search/command.js +2 -2
  171. package/dist/extensions/search/command.js.map +1 -1
  172. package/dist/extensions/search/index.d.ts.map +1 -1
  173. package/dist/extensions/search/index.js +14 -11
  174. package/dist/extensions/search/index.js.map +1 -1
  175. package/dist/extensions/search/workspace.d.ts +11 -10
  176. package/dist/extensions/search/workspace.d.ts.map +1 -1
  177. package/dist/extensions/search/workspace.js +259 -141
  178. package/dist/extensions/search/workspace.js.map +1 -1
  179. package/dist/extensions/tool-search/index.d.ts.map +1 -1
  180. package/dist/extensions/tool-search/index.js +1 -6
  181. package/dist/extensions/tool-search/index.js.map +1 -1
  182. package/dist/extensions/tool-search/tool.d.ts +0 -2
  183. package/dist/extensions/tool-search/tool.d.ts.map +1 -1
  184. package/dist/extensions/tool-search/tool.js +2 -4
  185. package/dist/extensions/tool-search/tool.js.map +1 -1
  186. package/dist/index.d.ts +2 -1
  187. package/dist/index.d.ts.map +1 -1
  188. package/dist/index.js +1 -0
  189. package/dist/index.js.map +1 -1
  190. package/dist/main.d.ts.map +1 -1
  191. package/dist/main.js +4 -3
  192. package/dist/main.js.map +1 -1
  193. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  194. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  195. package/dist/modes/interactive/components/settings-selector.js +13 -2
  196. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  197. package/dist/modes/interactive/components/status-indicator.d.ts +1 -1
  198. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  199. package/dist/modes/interactive/components/status-indicator.js +2 -2
  200. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  201. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  202. package/dist/modes/interactive/components/tree-selector.js +2 -9
  203. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  204. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  205. package/dist/modes/interactive/interactive-mode.js +20 -8
  206. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  207. package/dist/modes/interactive/session-share.d.ts.map +1 -1
  208. package/dist/modes/interactive/session-share.js +9 -2
  209. package/dist/modes/interactive/session-share.js.map +1 -1
  210. package/dist/modes/interactive/tasks/layout.d.ts +2 -0
  211. package/dist/modes/interactive/tasks/layout.d.ts.map +1 -1
  212. package/dist/modes/interactive/tasks/layout.js +32 -6
  213. package/dist/modes/interactive/tasks/layout.js.map +1 -1
  214. package/dist/modes/interactive/tasks/manager.d.ts.map +1 -1
  215. package/dist/modes/interactive/tasks/manager.js +20 -2
  216. package/dist/modes/interactive/tasks/manager.js.map +1 -1
  217. package/dist/modes/interactive/theme/dark.json +1 -1
  218. package/dist/modes/interactive/theme/light.json +1 -1
  219. package/dist/modes/interactive/theme/theme-schema.d.ts +28 -0
  220. package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -0
  221. package/dist/modes/interactive/theme/theme-schema.js +105 -0
  222. package/dist/modes/interactive/theme/theme-schema.js.map +1 -0
  223. package/dist/modes/interactive/theme/theme-tokens.d.ts +257 -0
  224. package/dist/modes/interactive/theme/theme-tokens.d.ts.map +1 -0
  225. package/dist/modes/interactive/theme/theme-tokens.js +94 -0
  226. package/dist/modes/interactive/theme/theme-tokens.js.map +1 -0
  227. package/dist/modes/interactive/theme/theme.d.ts +13 -16
  228. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  229. package/dist/modes/interactive/theme/theme.js +23 -31
  230. package/dist/modes/interactive/theme/theme.js.map +1 -1
  231. package/dist/modes/print-mode.d.ts.map +1 -1
  232. package/dist/modes/print-mode.js +4 -0
  233. package/dist/modes/print-mode.js.map +1 -1
  234. package/dist/utils/clipboard.d.ts.map +1 -1
  235. package/dist/utils/clipboard.js +6 -1
  236. package/dist/utils/clipboard.js.map +1 -1
  237. package/docs/bundled/extensions/search.md +2 -1
  238. package/docs/bundled/tasks.md +1 -1
  239. package/docs/codemode.md +2 -1
  240. package/docs/compaction.md +2 -2
  241. package/docs/development.md +0 -13
  242. package/docs/docs.json +12 -0
  243. package/docs/environment-variables.md +2 -3
  244. package/docs/extensions.md +11 -5
  245. package/docs/keybindings.md +1 -0
  246. package/docs/llama-cpp.md +1 -1
  247. package/docs/mcp.md +1 -1
  248. package/docs/models.md +1 -0
  249. package/docs/nvidia-rtx-llama-cpp.md +96 -0
  250. package/docs/providers.md +17 -1
  251. package/docs/sdk.md +0 -27
  252. package/docs/sessions.md +1 -1
  253. package/docs/settings.md +4 -3
  254. package/docs/themes.md +4 -2
  255. package/docs/tui.md +1 -1
  256. package/docs/usage.md +7 -5
  257. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  258. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  259. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  260. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  261. package/examples/extensions/gondolin/package-lock.json +2 -2
  262. package/examples/extensions/gondolin/package.json +1 -1
  263. package/examples/extensions/minimal-mode.ts +4 -5
  264. package/examples/extensions/overlay-test.ts +2 -2
  265. package/examples/extensions/plan-mode/index.ts +6 -2
  266. package/examples/extensions/sandbox/package-lock.json +2 -2
  267. package/examples/extensions/sandbox/package.json +1 -1
  268. package/examples/extensions/with-deps/package-lock.json +2 -2
  269. package/examples/extensions/with-deps/package.json +1 -1
  270. package/npm-shrinkwrap.json +151 -199
  271. package/package.json +8 -20
  272. package/schemas/keybindings.schema.json +453 -0
  273. package/schemas/models.schema.json +1157 -0
  274. package/schemas/settings.schema.json +800 -0
  275. package/schemas/theme.schema.json +365 -0
  276. package/dist/bundle/chunks/anthropic-messages-3K3DWVY6.js +0 -6
  277. package/dist/bundle/chunks/chunk-3MMB5I7J.js +0 -11
  278. package/dist/bundle/chunks/mistral-conversations-NJUOG4ET.js +0 -5
  279. package/dist/bundle/chunks/openai-codex-responses-TZWBTTYM.js +0 -10
  280. package/dist/bundle/chunks/openai-responses-7A6BAQ5X.js +0 -3
  281. package/dist/modes/interactive/theme/theme-json.d.ts +0 -85
  282. package/dist/modes/interactive/theme/theme-json.d.ts.map +0 -1
  283. package/dist/modes/interactive/theme/theme-json.js +0 -132
  284. package/dist/modes/interactive/theme/theme-json.js.map +0 -1
  285. package/dist/modes/interactive/theme/theme-schema.json +0 -361
  286. package/examples/plugins/pi-example-plugin/README.md +0 -38
  287. package/examples/plugins/pi-example-plugin/package.json +0 -10
  288. package/examples/plugins/pi-example-plugin/src/contract.ts +0 -13
  289. package/examples/plugins/pi-example-plugin/src/session.ts +0 -24
  290. package/examples/plugins/pi-example-plugin/src/tui.ts +0 -31
@@ -1 +1 @@
1
- {"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../src/utils/clipboard.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { unlinkSync, writeFileSync } from \"node:fs\";\nimport { platform, tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { getNativeClipboard } from \"@earendil-works/pi-tui\";\nimport { runClipboardCommand } from \"./clipboard-command.ts\";\nimport { isWSL } from \"./wsl.ts\";\n\nconst MAX_OSC52_ENCODED_LENGTH = 100_000;\n\nfunction isRemoteSession(env: NodeJS.ProcessEnv): boolean {\n\treturn Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION);\n}\n\nfunction emitOsc52(text: string): boolean {\n\tconst encoded = Buffer.from(text).toString(\"base64\");\n\tif (encoded.length > MAX_OSC52_ENCODED_LENGTH) {\n\t\treturn false;\n\t}\n\tprocess.stdout.write(`\\x1b]52;c;${encoded}\\x07`);\n\treturn true;\n}\n\n/**\n * WSL without WSLg has no Linux display, so the Windows clipboard is written through\n * interop. PowerShell reads the text from a file because `clip.exe` and PowerShell stdin\n * decode piped bytes with the console code page, which mangles non-ASCII UTF-8.\n */\nasync function copyViaWindowsClipboard(text: string): Promise<boolean> {\n\tconst tmpFile = join(tmpdir(), `pi-wsl-clip-${randomUUID()}.txt`);\n\ttry {\n\t\twriteFileSync(tmpFile, text, { encoding: \"utf8\", mode: 0o600 });\n\t\tconst winPath = (await runClipboardCommand(\"wslpath\", [\"-w\", tmpFile], { timeoutMs: 1000 }))\n\t\t\t?.toString(\"utf8\")\n\t\t\t.trim();\n\t\tif (!winPath) return false;\n\t\tconst script = `Set-Clipboard -Value ([System.IO.File]::ReadAllText('${winPath.replaceAll(\"'\", \"''\")}', [System.Text.Encoding]::UTF8))`;\n\t\tconst result = await runClipboardCommand(\"powershell.exe\", [\"-NoProfile\", \"-Command\", script], {\n\t\t\ttimeoutMs: 5000,\n\t\t});\n\t\treturn result !== undefined;\n\t} catch {\n\t\treturn false;\n\t} finally {\n\t\ttry {\n\t\t\tunlinkSync(tmpFile);\n\t\t} catch {\n\t\t\t// The file may not have been created.\n\t\t}\n\t}\n}\n\n/** Read plain text from the system clipboard. */\nexport async function readClipboardText(): Promise<string | null> {\n\tconst commands: [string, string[]][] = [];\n\t// Termux reports platform \"android\", not \"linux\" (#10391).\n\tif (process.env.TERMUX_VERSION) commands.push([\"termux-clipboard-get\", []]);\n\tif (platform() === \"linux\") {\n\t\tif (process.env.WAYLAND_DISPLAY) commands.push([\"wl-paste\", [\"--no-newline\", \"--type\", \"text\"]]);\n\t\tif (process.env.DISPLAY) {\n\t\t\tcommands.push([\"xclip\", [\"-selection\", \"clipboard\", \"-out\"]], [\"xsel\", [\"--clipboard\", \"--output\"]]);\n\t\t}\n\t}\n\tfor (const [command, args] of commands) {\n\t\tconst bytes = await runClipboardCommand(command, args, { timeoutMs: 5000 });\n\t\tif (bytes !== undefined) return bytes.toString(\"utf8\") || null;\n\t}\n\ttry {\n\t\treturn (await getNativeClipboard()?.getText()) || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** Read file paths, such as Finder file copies, from the native clipboard. */\nexport async function readClipboardFilePaths(): Promise<string[] | null> {\n\tconst paths = await getNativeClipboard()?.getFilePaths?.();\n\treturn paths?.length ? paths : null;\n}\n\nexport async function copyToClipboard(text: string): Promise<void> {\n\tconst p = platform();\n\tconst env = process.env;\n\tlet copied = false;\n\t// Direct writes precede OSC 52 so the terminal cannot race the native writer.\n\t// Linux tools retain clipboard selection ownership after this call returns.\n\tif (p !== \"linux\") {\n\t\ttry {\n\t\t\tconst clipboard = getNativeClipboard();\n\t\t\tif (clipboard?.setText) {\n\t\t\t\tawait clipboard.setText(text);\n\t\t\t\tcopied = true;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Try platform commands next.\n\t\t}\n\t}\n\tif (!copied) {\n\t\tconst commands: [string, string[]][] = [];\n\t\tif (p === \"darwin\") commands.push([\"pbcopy\", []]);\n\t\telse if (p === \"win32\") commands.push([\"clip\", []]);\n\t\telse {\n\t\t\tif (env.TERMUX_VERSION) commands.push([\"termux-clipboard-set\", []]);\n\t\t\tif (env.WAYLAND_DISPLAY) commands.push([\"wl-copy\", []]);\n\t\t\tif (env.DISPLAY) {\n\t\t\t\tcommands.push([\"xclip\", [\"-selection\", \"clipboard\"]], [\"xsel\", [\"--clipboard\", \"--input\"]]);\n\t\t\t}\n\t\t}\n\t\tfor (const [command, args] of commands) {\n\t\t\tif ((await runClipboardCommand(command, args, { input: text, timeoutMs: 5000 })) !== undefined) {\n\t\t\t\tcopied = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tlet osc52Emitted = false;\n\tif (!copied && p === \"linux\" && isWSL(env)) {\n\t\t// Windows Terminal supports OSC 52; prefer it over the slower PowerShell round trip.\n\t\tif (env.WT_SESSION) osc52Emitted = emitOsc52(text);\n\t\tcopied = osc52Emitted || (await copyViaWindowsClipboard(text));\n\t}\n\t// OSC 52 cannot be verified, so a desktop session with a display reports the failure\n\t// instead (#9618). Without a display the terminal is the only clipboard route (containers,\n\t// WSL without WSLg), and remote sessions always emit it to reach the client clipboard.\n\tconst headless = p === \"linux\" && !env.DISPLAY && !env.WAYLAND_DISPLAY && !env.TERMUX_VERSION;\n\tlet oversized = false;\n\tif (!osc52Emitted && (isRemoteSession(env) || (!copied && headless))) {\n\t\tif (emitOsc52(text)) copied = true;\n\t\telse oversized = true;\n\t}\n\tif (copied) return;\n\tif (oversized) throw new Error(\"Clipboard unavailable: text exceeds the OSC 52 size limit\");\n\tif (env.TERMUX_VERSION) {\n\t\tthrow new Error(\"Clipboard unavailable: install the Termux:API app and `termux-api` package\");\n\t}\n\tif (p === \"linux\") {\n\t\tif (env.WAYLAND_DISPLAY) {\n\t\t\tthrow new Error(\"Clipboard unavailable: install `wl-clipboard` (`wl-copy`) or check Wayland access\");\n\t\t}\n\t\tif (env.DISPLAY) {\n\t\t\tthrow new Error(\"Clipboard unavailable: install `xclip` or `xsel`, or check X11 access\");\n\t\t}\n\t}\n\tthrow new Error(\"Clipboard unavailable\");\n}\n"]}
1
+ {"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../src/utils/clipboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEjC,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAEzC;;;;GAIG;AACH,SAAS,eAAe,CAAC,GAAsB;IAC9C,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,eAAe,IAAI,GAAG,CAAC,kBAAkB,KAAK,GAAG,CAAC,CAAC;AAC/G,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC9B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACrD,IAAI,OAAO,CAAC,MAAM,GAAG,wBAAwB,EAAE,CAAC;QAC/C,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,OAAO,MAAM,CAAC,CAAC;IACjD,OAAO,IAAI,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,uBAAuB,CAAC,IAAY;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,eAAe,UAAU,EAAE,MAAM,CAAC,CAAC;IAClE,IAAI,CAAC;QACJ,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,CAAC,MAAM,mBAAmB,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3F,EAAE,QAAQ,CAAC,MAAM,CAAC;aACjB,IAAI,EAAE,CAAC;QACT,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAC3B,MAAM,MAAM,GAAG,wDAAwD,OAAO,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,mCAAmC,CAAC;QACxI,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,gBAAgB,EAAE,CAAC,YAAY,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE;YAC9F,SAAS,EAAE,IAAI;SACf,CAAC,CAAC;QACH,OAAO,MAAM,KAAK,SAAS,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACV,IAAI,CAAC;YACJ,UAAU,CAAC,OAAO,CAAC,CAAC;QACrB,CAAC;QAAC,MAAM,CAAC;YACR,sCAAsC;QACvC,CAAC;IACF,CAAC;AACF,CAAC;AAED,iDAAiD;AACjD,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACtC,MAAM,QAAQ,GAAyB,EAAE,CAAC;IAC1C,2DAA2D;IAC3D,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC,CAAC;IAC5E,IAAI,QAAQ,EAAE,KAAK,OAAO,EAAE,CAAC;QAC5B,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe;YAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC,cAAc,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;QACjG,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YACzB,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;QACtG,CAAC;IACF,CAAC;IACD,KAAK,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5E,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC;IAChE,CAAC;IACD,IAAI,CAAC;QACJ,OAAO,CAAC,MAAM,kBAAkB,EAAE,EAAE,OAAO,EAAE,CAAC,IAAI,IAAI,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC;AAED,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAC3C,MAAM,KAAK,GAAG,MAAM,kBAAkB,EAAE,EAAE,YAAY,EAAE,EAAE,CAAC;IAC3D,OAAO,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IACjD,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC;IACrB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACxB,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,8EAA8E;IAC9E,4EAA4E;IAC5E,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC;QACnB,IAAI,CAAC;YACJ,MAAM,SAAS,GAAG,kBAAkB,EAAE,CAAC;YACvC,IAAI,SAAS,EAAE,OAAO,EAAE,CAAC;gBACxB,MAAM,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC9B,MAAM,GAAG,IAAI,CAAC;YACf,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,8BAA8B;QAC/B,CAAC;IACF,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,MAAM,QAAQ,GAAyB,EAAE,CAAC;QAC1C,IAAI,CAAC,KAAK,QAAQ;YAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC;aAC7C,IAAI,CAAC,KAAK,OAAO;YAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;aAC/C,CAAC;YACL,IAAI,GAAG,CAAC,cAAc;gBAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC,CAAC;YACpE,IAAI,GAAG,CAAC,eAAe;gBAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;YACxD,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;gBACjB,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;YAC7F,CAAC;QACF,CAAC;QACD,KAAK,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;YACxC,IAAI,CAAC,MAAM,mBAAmB,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;gBAChG,MAAM,GAAG,IAAI,CAAC;gBACd,MAAM;YACP,CAAC;QACF,CAAC;IACF,CAAC;IACD,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5C,qFAAqF;QACrF,IAAI,GAAG,CAAC,UAAU;YAAE,YAAY,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,GAAG,YAAY,IAAI,CAAC,MAAM,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC;IAChE,CAAC;IACD,qFAAqF;IACrF,2FAA2F;IAC3F,uFAAuF;IACvF,MAAM,QAAQ,GAAG,CAAC,KAAK,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,eAAe,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC;IAC9F,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,CAAC,YAAY,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,QAAQ,CAAC,CAAC,EAAE,CAAC;QACtE,IAAI,SAAS,CAAC,IAAI,CAAC;YAAE,MAAM,GAAG,IAAI,CAAC;;YAC9B,SAAS,GAAG,IAAI,CAAC;IACvB,CAAC;IACD,IAAI,MAAM;QAAE,OAAO;IACnB,IAAI,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC5F,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;IAC/F,CAAC;IACD,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC;QACnB,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,mFAAmF,CAAC,CAAC;QACtG,CAAC;QACD,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;QAC1F,CAAC;IACF,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;AAC1C,CAAC","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { unlinkSync, writeFileSync } from \"node:fs\";\nimport { platform, tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { getNativeClipboard } from \"@earendil-works/pi-tui\";\nimport { runClipboardCommand } from \"./clipboard-command.ts\";\nimport { isWSL } from \"./wsl.ts\";\n\nconst MAX_OSC52_ENCODED_LENGTH = 100_000;\n\n/**\n * Remote sessions also emit OSC 52 so the client terminal receives the copy. PI_CLIPBOARD_OSC52=1\n * covers remote clients that leave no SSH markers, such as multiplexer attaches (#10114, #10835)\n * or IDE daemons (#10826).\n */\nfunction isRemoteSession(env: NodeJS.ProcessEnv): boolean {\n\treturn Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION || env.PI_CLIPBOARD_OSC52 === \"1\");\n}\n\nfunction emitOsc52(text: string): boolean {\n\tconst encoded = Buffer.from(text).toString(\"base64\");\n\tif (encoded.length > MAX_OSC52_ENCODED_LENGTH) {\n\t\treturn false;\n\t}\n\tprocess.stdout.write(`\\x1b]52;c;${encoded}\\x07`);\n\treturn true;\n}\n\n/**\n * WSL without WSLg has no Linux display, so the Windows clipboard is written through\n * interop. PowerShell reads the text from a file because `clip.exe` and PowerShell stdin\n * decode piped bytes with the console code page, which mangles non-ASCII UTF-8.\n */\nasync function copyViaWindowsClipboard(text: string): Promise<boolean> {\n\tconst tmpFile = join(tmpdir(), `pi-wsl-clip-${randomUUID()}.txt`);\n\ttry {\n\t\twriteFileSync(tmpFile, text, { encoding: \"utf8\", mode: 0o600 });\n\t\tconst winPath = (await runClipboardCommand(\"wslpath\", [\"-w\", tmpFile], { timeoutMs: 1000 }))\n\t\t\t?.toString(\"utf8\")\n\t\t\t.trim();\n\t\tif (!winPath) return false;\n\t\tconst script = `Set-Clipboard -Value ([System.IO.File]::ReadAllText('${winPath.replaceAll(\"'\", \"''\")}', [System.Text.Encoding]::UTF8))`;\n\t\tconst result = await runClipboardCommand(\"powershell.exe\", [\"-NoProfile\", \"-Command\", script], {\n\t\t\ttimeoutMs: 5000,\n\t\t});\n\t\treturn result !== undefined;\n\t} catch {\n\t\treturn false;\n\t} finally {\n\t\ttry {\n\t\t\tunlinkSync(tmpFile);\n\t\t} catch {\n\t\t\t// The file may not have been created.\n\t\t}\n\t}\n}\n\n/** Read plain text from the system clipboard. */\nexport async function readClipboardText(): Promise<string | null> {\n\tconst commands: [string, string[]][] = [];\n\t// Termux reports platform \"android\", not \"linux\" (#10391).\n\tif (process.env.TERMUX_VERSION) commands.push([\"termux-clipboard-get\", []]);\n\tif (platform() === \"linux\") {\n\t\tif (process.env.WAYLAND_DISPLAY) commands.push([\"wl-paste\", [\"--no-newline\", \"--type\", \"text\"]]);\n\t\tif (process.env.DISPLAY) {\n\t\t\tcommands.push([\"xclip\", [\"-selection\", \"clipboard\", \"-out\"]], [\"xsel\", [\"--clipboard\", \"--output\"]]);\n\t\t}\n\t}\n\tfor (const [command, args] of commands) {\n\t\tconst bytes = await runClipboardCommand(command, args, { timeoutMs: 5000 });\n\t\tif (bytes !== undefined) return bytes.toString(\"utf8\") || null;\n\t}\n\ttry {\n\t\treturn (await getNativeClipboard()?.getText()) || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** Read file paths, such as Finder file copies, from the native clipboard. */\nexport async function readClipboardFilePaths(): Promise<string[] | null> {\n\tconst paths = await getNativeClipboard()?.getFilePaths?.();\n\treturn paths?.length ? paths : null;\n}\n\nexport async function copyToClipboard(text: string): Promise<void> {\n\tconst p = platform();\n\tconst env = process.env;\n\tlet copied = false;\n\t// Direct writes precede OSC 52 so the terminal cannot race the native writer.\n\t// Linux tools retain clipboard selection ownership after this call returns.\n\tif (p !== \"linux\") {\n\t\ttry {\n\t\t\tconst clipboard = getNativeClipboard();\n\t\t\tif (clipboard?.setText) {\n\t\t\t\tawait clipboard.setText(text);\n\t\t\t\tcopied = true;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Try platform commands next.\n\t\t}\n\t}\n\tif (!copied) {\n\t\tconst commands: [string, string[]][] = [];\n\t\tif (p === \"darwin\") commands.push([\"pbcopy\", []]);\n\t\telse if (p === \"win32\") commands.push([\"clip\", []]);\n\t\telse {\n\t\t\tif (env.TERMUX_VERSION) commands.push([\"termux-clipboard-set\", []]);\n\t\t\tif (env.WAYLAND_DISPLAY) commands.push([\"wl-copy\", []]);\n\t\t\tif (env.DISPLAY) {\n\t\t\t\tcommands.push([\"xclip\", [\"-selection\", \"clipboard\"]], [\"xsel\", [\"--clipboard\", \"--input\"]]);\n\t\t\t}\n\t\t}\n\t\tfor (const [command, args] of commands) {\n\t\t\tif ((await runClipboardCommand(command, args, { input: text, timeoutMs: 5000 })) !== undefined) {\n\t\t\t\tcopied = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tlet osc52Emitted = false;\n\tif (!copied && p === \"linux\" && isWSL(env)) {\n\t\t// Windows Terminal supports OSC 52; prefer it over the slower PowerShell round trip.\n\t\tif (env.WT_SESSION) osc52Emitted = emitOsc52(text);\n\t\tcopied = osc52Emitted || (await copyViaWindowsClipboard(text));\n\t}\n\t// OSC 52 cannot be verified, so a desktop session with a display reports the failure\n\t// instead (#9618). Without a display the terminal is the only clipboard route (containers,\n\t// WSL without WSLg), and remote sessions always emit it to reach the client clipboard.\n\tconst headless = p === \"linux\" && !env.DISPLAY && !env.WAYLAND_DISPLAY && !env.TERMUX_VERSION;\n\tlet oversized = false;\n\tif (!osc52Emitted && (isRemoteSession(env) || (!copied && headless))) {\n\t\tif (emitOsc52(text)) copied = true;\n\t\telse oversized = true;\n\t}\n\tif (copied) return;\n\tif (oversized) throw new Error(\"Clipboard unavailable: text exceeds the OSC 52 size limit\");\n\tif (env.TERMUX_VERSION) {\n\t\tthrow new Error(\"Clipboard unavailable: install the Termux:API app and `termux-api` package\");\n\t}\n\tif (p === \"linux\") {\n\t\tif (env.WAYLAND_DISPLAY) {\n\t\t\tthrow new Error(\"Clipboard unavailable: install `wl-clipboard` (`wl-copy`) or check Wayland access\");\n\t\t}\n\t\tif (env.DISPLAY) {\n\t\t\tthrow new Error(\"Clipboard unavailable: install `xclip` or `xsel`, or check X11 access\");\n\t\t}\n\t}\n\tthrow new Error(\"Clipboard unavailable\");\n}\n"]}
@@ -25,13 +25,14 @@ Without a credential, a session starts with both tools turned off. Signing in tu
25
25
 
26
26
  ## code_search
27
27
 
28
- `code_search` sends your query and a directory tree of the working directory (up to three levels, without dependency, build, and `.gitignore`d directories) to Devin's SWE-grep model. The model plans up to three rounds of up to eight read-only commands, `rg`, `readfile`, and `tree`, which run on your machine, and then answers with files and line ranges. The result is a reading list to verify, not evidence.
28
+ `code_search` sends your query and a directory tree of the working directory (up to three levels) to Devin's SWE-grep model. The model plans up to three rounds of up to eight read-only commands, `rg`, `readfile`, and `tree`, which run on your machine, and then answers with files and line ranges. The result is a reading list to verify, not evidence.
29
29
 
30
30
  What leaves your machine: the query, the directory tree, and the output of the commands the model runs, including the file contents it reads.
31
31
 
32
32
  Enforced locally, not by Devin:
33
33
 
34
34
  - **Confinement.** Every path the model names must resolve inside the searched directory, both as written and after following symlinks.
35
+ - **Ignored files stay local.** The tree, `rg`, and `readfile` see only the files ripgrep would search: anything excluded by `.gitignore`, `.ignore`, or `.rgignore` (even outside a git repository) is neither listed, searched, nor read, even when the model names it. So, at any depth and with or without an ignore file, are `.git` and dependency and cache directories such as `node_modules`, `.venv`, and `__pycache__`. To hide more, such as a committed `vendor/` directory, add it to `.ignore`.
35
36
  - **Read-only.** The three commands are the only operations; there is no shell and no write.
36
37
  - **Bounded output.** Each command result is capped at 40 lines of 200 characters, and each request times out after 30 seconds.
37
38
 
@@ -61,7 +61,7 @@ Selection follows the task when it finishes; new work does not steal focus or re
61
61
 
62
62
  At 100 columns or more, the task list sits beside an inspector. **Output** shows the result directly; **Details** holds the full command, directory, task ID, log location and executor-specific details. Each task and tab keeps its reading position for the lifetime of the panel. Tab switches between the two panes, preserving the right-hand tab. Left/Right switch Output/Details only when the inspector has focus.
63
63
 
64
- The focused pane has a highlighted border. Task selection uses a persistent row background, and the selected right-hand tab uses an underline; neither changes when focus moves. When the system theme has no background colors, the selected row uses inverse text. There are no focus arrows or extra title colors. Narrow terminals show one pane at full width with the same Tab navigation and no focus highlight. The inspector includes task context when the list is hidden. Escape closes the panel from either pane. The minimum supported size is 60 columns by 14 rows.
64
+ The focused pane has a highlighted border. Task selection uses a persistent row background, and the selected right-hand tab uses an underline; neither changes when focus moves. When the system theme has no background colors, the selected row uses inverse text. There are no focus arrows or extra title colors. Narrow terminals show one pane at full width with the same Tab navigation and no focus highlight. The inspector includes task context when the list is hidden. Escape closes the panel from either pane. The minimum supported size is 60 columns by 14 rows; below it, a centered dialog asks for a larger window and covers the screen, because the panel keeps input focus while open.
65
65
 
66
66
  Bash and PowerShell show live plain-text output. Other executors show their published result, and a task without a command is labeled by its title. Missing logs fall back to the saved result. Task status, failure reasons and output-read errors remain distinct.
67
67
 
package/docs/codemode.md CHANGED
@@ -6,7 +6,7 @@ The `codemode` tool lets the model write a JavaScript script that calls pi's oth
6
6
 
7
7
  The tool input is raw JavaScript source, not JSON and not a markdown code fence. It runs as the body of an async function in a QuickJS sandbox, so top-level `await` and `return` work. The sandbox has no Node APIs, file system, network, or timers; scripts reach the outside world only through tools and `models`.
8
8
 
9
- A script may start with an options line:
9
+ A script may start with an options line. It must be the first line; an options line anywhere else fails the call before the script runs:
10
10
 
11
11
  ```js
12
12
  // @options: {"max_output_tokens": 2000, "timeout_ms": 60000}
@@ -224,5 +224,6 @@ for (const block of result.output) {
224
224
  ## Limits
225
225
 
226
226
  - A script's VM has 256 MB of memory. Running out throws `InternalError: out of memory`; filter or aggregate large data instead of accumulating it.
227
+ - At most two codemode workers may be alive across all sessions in one pi process. A cancelled worker occupies its slot until it exits. At capacity, new scripts fail immediately without starting another worker; retry after an existing worker exits.
227
228
  - A script that waits on a promise that can never settle (no tool call pending) fails immediately, since there are no timers.
228
229
  - Scripts cannot start other `codemode` scripts.
@@ -288,7 +288,6 @@ Before summarization, the exported `serializeConversation()` function serializes
288
288
 
289
289
  ```
290
290
  [User]: What they said
291
- [Assistant thinking]: Internal reasoning
292
291
  [Assistant]: Response text
293
292
  [Assistant tool calls]: read(path="foo.ts"); edit(path="bar.ts", ...)
294
293
  [Tool result]: Output from tool
@@ -296,6 +295,8 @@ Before summarization, the exported `serializeConversation()` function serializes
296
295
 
297
296
  This prevents the model from treating it as a conversation to continue.
298
297
 
298
+ Thinking blocks are omitted. Providers return summaries of the real reasoning, and replayed thinking is often not part of the model's live context, so including it could make the summarization request larger than the context it summarizes.
299
+
299
300
  Tool results are truncated to 2000 characters during serialization. Content beyond that limit is replaced with a marker indicating how many characters were truncated. This keeps summarization requests within reasonable token budgets, since tool results (especially from `read` and `bash`) are typically the largest contributors to context size.
300
301
 
301
302
  ## Custom Summarization via Extensions
@@ -354,7 +355,6 @@ pi.on("session_before_compact", async (event, ctx) => {
354
355
  );
355
356
  // Returns:
356
357
  // [User]: message text
357
- // [Assistant thinking]: thinking content
358
358
  // [Assistant]: response text
359
359
  // [Assistant tool calls]: read(path="..."); bash(command="...")
360
360
  // [Tool result]: output text
@@ -39,19 +39,6 @@ npm run test:isolated
39
39
 
40
40
  The isolated runner preserves individual arguments and forwards them to Vitest, isolates home/configuration/cache/credentials, and preflights its required tools. Interactive verification requirements are defined by the repository's `AGENTS.md`.
41
41
 
42
- ## Experimental remote harness
43
-
44
- Server/client integration is source-only. On a POSIX system:
45
-
46
- ```bash
47
- PI_EXPERIMENTAL=1 npm run dev -- server
48
- PI_EXPERIMENTAL=1 npm run dev -- client
49
- ```
50
-
51
- The source launcher uses `src/experimental/cli.ts` and falls back to the stable CLI for ordinary commands. `PI_SERVER_DIR` selects the server profile/socket directory (default `~/.pi/server`); `PI_SERVER_ID` selects the server ID when `--server-id` is omitted. The durable server requires POSIX process APIs.
52
-
53
- The `client` and `experimental/plugin` package subpaths resolve under the `source` condition in a checkout. Their implementations and commands are excluded from distributed builds; the local SDK and stdio RPC remain supported. The development-only libraries are installed when preparing a source checkout.
54
-
55
42
  ## Repository layout
56
43
 
57
44
  - `src/**`: runtime and source-only experimental code.
package/docs/docs.json CHANGED
@@ -15,6 +15,10 @@
15
15
  "title": "Using Pi",
16
16
  "path": "usage.md"
17
17
  },
18
+ {
19
+ "title": "Sessions",
20
+ "path": "sessions.md"
21
+ },
18
22
  {
19
23
  "title": "Providers",
20
24
  "path": "providers.md"
@@ -23,6 +27,10 @@
23
27
  "title": "llama.cpp",
24
28
  "path": "llama-cpp.md"
25
29
  },
30
+ {
31
+ "title": "NVIDIA RTX",
32
+ "path": "nvidia-rtx-llama-cpp.md"
33
+ },
26
34
  {
27
35
  "title": "Security",
28
36
  "path": "security.md"
@@ -80,6 +88,10 @@
80
88
  "title": "Statusline",
81
89
  "path": "bundled/extensions/statusline.md"
82
90
  },
91
+ {
92
+ "title": "Search",
93
+ "path": "bundled/extensions/search.md"
94
+ },
83
95
  {
84
96
  "title": "Bundled themes",
85
97
  "path": "bundled/themes.md"
@@ -86,8 +86,9 @@ These variables are read by Pi itself:
86
86
  | `PI_TELEMETRY` | Override optional provider attribution headers: `1`/`true`/`yes` or `0`/`false`/`no`. This does not disable version checks |
87
87
  | `PI_CACHE_RETENTION` | Set to `long` for extended provider prompt caching where supported |
88
88
  | `PI_SHARE_VIEWER_URL` | Override the base URL used by `/share` |
89
- | `PI_RADIUS_GATEWAY` | Override the Radius gateway origin used by `/bug` uploads and Radius relay connections |
89
+ | `PI_RADIUS_GATEWAY` | Override the Radius gateway origin used by `/bug` uploads |
90
90
  | `PI_HARDWARE_CURSOR` | Set to `1` to show the hardware cursor; see [Terminal setup](terminal-setup.md) |
91
+ | `PI_CLIPBOARD_OSC52` | Set to `1` to also send copied text to the terminal with OSC 52 after the local clipboard write, as Pi does over SSH. Use it when a remote client reaches Pi without SSH variables, such as a multiplexer attached from another machine or a remote IDE daemon |
91
92
  | `PI_HYPERLINKS` | Override OSC 8 hyperlink detection with `1`, `0`, or `auto` |
92
93
  | `PI_PROGRAM_STATUS` | Override OSC 7501 program status detection: `1` always reports, `0` never reports; otherwise Pi reports only after the terminal confirms support. See [Terminal setup](terminal-setup.md#program-status) |
93
94
  | `PI_IMAGE_PROTOCOL` | Override inline image detection with `kitty`, `iterm2`, `none`, or `auto` |
@@ -97,5 +98,3 @@ These variables are read by Pi itself:
97
98
  | `HTTP_PROXY`, `HTTPS_PROXY` | Proxy outbound HTTP requests |
98
99
 
99
100
  Provider credentials such as `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, and provider-specific configuration are listed in [Providers](providers.md#environment-variables-or-auth-file).
100
-
101
- `PI_SERVER_DIR` and `PI_SERVER_ID` apply only to the source-only [experimental remote harness](development.md#experimental-remote-harness).
@@ -555,6 +555,10 @@ pi.on("before_agent_start", async (event, ctx) => {
555
555
  // event.systemPrompt - current chained system prompt for this handler
556
556
  // (includes changes from earlier before_agent_start handlers)
557
557
  // event.systemPromptOptions - structured options used to build the system prompt
558
+ // event.messageType - what started the run: "user" (a prompt or
559
+ // pi.sendUserMessage(), with prompt and images) or "custom"
560
+ // (pi.sendMessage(..., { triggerTurn: true }), with the starting message and
561
+ // no prompt); a returned message is added to either kind of run
558
562
  // .customPrompt - exact prompt prefix from --system-prompt, SYSTEM.md, or custom templates
559
563
  // .forceSystemPrompt - optional exact replacement for the complete prompt
560
564
  // .selectedTools - tools currently active in the prompt
@@ -586,7 +590,7 @@ Inside `before_agent_start`, `event.systemPrompt` and `ctx.getSystemPrompt()` bo
586
590
 
587
591
  #### agent_start / agent_end / agent_before_settle / agent_settled
588
592
 
589
- `agent_start` fires when a low-level agent run begins. `agent_end` fires when that run ends, but Pi may still auto-retry, auto-compact and retry, or continue with queued follow-up messages. `agent_before_settle` is the final actionable boundary: it can append session entries and request one continuation. `agent_settled` is final and notification-only; use it for status integrations that need to know Pi will not continue running automatically.
593
+ `agent_start` fires when a low-level agent run begins. Pi counts as busy while a run starts, including the compaction check and `before_agent_start`, so messages sent meanwhile go into the starting run. `agent_end` fires when that run ends, but Pi may still auto-retry, auto-compact and retry, or continue with queued follow-up messages. `agent_before_settle` is the final actionable boundary: it can append session entries and request one continuation. `agent_settled` is final and notification-only; use it for status integrations that need to know Pi will not continue running automatically.
590
594
 
591
595
  ```typescript
592
596
  pi.on("agent_start", async (_event, ctx) => {});
@@ -3220,9 +3224,9 @@ A tool can run other tools with `ctx.executeTool(name, args, { signal, onUpdate
3220
3224
  - `deferred`: like `codemode`, but codemode tools do not list it; `tool_search` can find and activate it.
3221
3225
  - `hidden`: registered but unreachable. Re-register a tool with `exposure: "hidden"` to withdraw it, since tools cannot be unregistered.
3222
3226
 
3223
- `namespace: { name, description, instructions }` groups related tools, as MCP servers do. Codemode tools list a namespace under one heading with its `description`. `instructions` holds longer usage guidance; it is not listed, and codemode scripts read it with `describeNamespace(name)`.
3227
+ `namespace: { name, aliases, description, instructions }` groups related tools, as MCP servers do. Codemode tools list a namespace under one heading with its `description`. `instructions` holds longer usage guidance; it is not listed, and codemode scripts read it with `describeNamespace(name)`. `aliases` are other names scripts may look the namespace up by, for example the server name `docs` for `mcp__docs`; a name and the same name as a script identifier (`my-docs`, `my_docs`) match alike.
3224
3228
 
3225
- Registering a `direct` or `model-only` tool activates it; the other exposures are not activated on registration. The active set (`pi.getActiveTools()`, `pi.setActiveTools()`) is the set of tools declared to the model. `pi.getAllTools()` reports each tool's `exposure`, `namespace`, and `annotations`.
3229
+ Registering a `direct` or `model-only` tool activates it; the other exposures are not activated on registration. The active set (`pi.getActiveTools()`, `pi.setActiveTools()`) is the set of tools declared to the model. `pi.getAllTools()` reports each tool's `exposure`, `namespace`, `annotations`, and `reachesTools`.
3226
3230
 
3227
3231
  `annotations` are hints about what a tool does, with the meaning of MCP tool annotations: `readOnlyHint`, `destructiveHint`, `idempotentHint`, and `openWorldHint`. MCP tools carry the hints their server declares. Missing hints take the MCP defaults: a tool is not read-only, and may be destructive and reach an open world. The hints are not verified, but a permission extension can use them to decide which calls to confirm. This confirms the calls Codex asks approval for:
3228
3232
 
@@ -3238,7 +3242,9 @@ pi.on("tool_call", async (event, ctx) => {
3238
3242
  });
3239
3243
  ```
3240
3244
 
3241
- A tool that orchestrates other tools can adjust what the model sees while it is active with `prepareLoadout(loadout)`. It runs whenever the active tools change and receives the declared tools, the callable tools, and every registered tool with its exposure, namespace, and prompt guidelines. It returns replacement `descriptions` for declared tools (including its own) and `hiddenDeclarations`: active tools whose declarations requests leave out while they stay active and callable. The default system prompt leaves hidden tools out of its tool list and rules, and names no tool in the skills hint when the file reader is hidden, so the orchestrating tool should present their guidelines itself. `codemode` uses only this hook, `exposure`, and `ctx.executeTool()`, so another tool can implement the same behavior under a different name.
3245
+ A tool that orchestrates other tools can adjust what the model sees while it is active with `prepareLoadout(loadout)`. It runs whenever the active tools change and receives the declared tools, the callable tools, and every registered tool with its exposure, namespace, and prompt guidelines. It returns replacement `descriptions` for declared tools (including its own) and `hiddenDeclarations`: active tools whose declarations requests leave out while they stay active and callable. The default system prompt leaves hidden tools out of its tool list and rules, and names no tool in the skills hint when the file reader is hidden, so the orchestrating tool should present their guidelines itself. `codemode` uses only this hook, `exposure`, `reachesTools`, and `ctx.executeTool()`, so another tool can implement the same behavior under a different name.
3246
+
3247
+ A tool that reaches other tools declares which ones a call may reach with `reachesTools(input)`: `"all"`, or the words of the input that may name them, where a word refers to every tool or namespace whose name it contains. `codemode` returns `"all"` for scripts that search or list tools and the words of the script otherwise; `tool_search` always returns `"all"`. Extensions that register tools late use it from their `tool_call` handler to finish registering the tools a call needs before it runs, as the MCP extension does for servers that are still connecting. The MCP extension also activates `codemode` or `tool_search` for MCP tools only when the tool of that name declares `reachesTools`.
3242
3248
 
3243
3249
  ### Tool renderer resolution
3244
3250
 
@@ -3255,7 +3261,7 @@ pi.unregisterMcpServer("jira");
3255
3261
 
3256
3262
  Servers registered while the extension loads connect when the session starts, together with the `mcp.json` servers; servers registered later connect right away, and `pi.unregisterMcpServer()` closes the connection and makes the server's tools unreachable. Registrations are not saved: register again on every load, for example based on the extension's own settings. A server in `mcp.json` with the same name takes precedence, and `/mcp` shows the override. Registering the same name again replaces the extension's earlier registration; names registered by another extension, invalid names, and invalid configs throw.
3257
3263
 
3258
- The built-in MCP support connects registered servers. When nothing does, because another extension replaced it (see [MCP](mcp.md#other-mcp-extensions)), each registration is reported as an extension error. Other MCP extensions can connect registered servers too: read them with `pi.getMcpServers()` on `session_start` and handle the `mcp_servers_change` event for later changes.
3264
+ The built-in MCP support connects registered servers. When nothing does, because another extension replaced it (see [MCP](mcp.md#replace-the-built-in-mcp-support)), each registration is reported as an extension error. Other MCP extensions can connect registered servers too: read them with `pi.getMcpServers()` on `session_start` and handle the `mcp_servers_change` event for later changes.
3259
3265
 
3260
3266
  ### Provider stream events
3261
3267
 
@@ -244,6 +244,7 @@ Create `~/.pi/agent/keybindings.json`:
244
244
 
245
245
  ```json
246
246
  {
247
+ "$schema": "https://raw.githubusercontent.com/ming-kang/pi/main/schemas/keybindings.schema.json",
247
248
  "tui.editor.historyPrevious": "ctrl+p",
248
249
  "tui.editor.historyNext": "ctrl+n",
249
250
  "tui.editor.deleteWordBackward": ["ctrl+w", "alt+backspace"]
package/docs/llama-cpp.md CHANGED
@@ -41,7 +41,7 @@ A single-file model can sit directly in the model directory. Put multimodal and
41
41
  └── large-model-Q4_K_M-00003-of-00003.gguf
42
42
  ```
43
43
 
44
- Restart the router after manually adding files. For per-model context sizes and other options, use [llama.cpp model presets](https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md#model-presets).
44
+ Restart the router after manually adding files. For per-model context sizes and other options, use [llama.cpp model presets](https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md#model-presets). For settings tuned to a specific NVIDIA GPU and model, see [Run Pi with NVIDIA RTX and llama.cpp](nvidia-rtx-llama-cpp.md).
45
45
 
46
46
  ## Configure Pi
47
47
 
package/docs/mcp.md CHANGED
@@ -265,7 +265,7 @@ Changes to enabled state or exposure apply only to the current session. A file-c
265
265
 
266
266
  An installed extension that registers `/mcp`, such as `pi-mcp-adapter`, replaces the built-in MCP support for sessions. Pi then does not read `mcp.json` or connect its servers in a session, and `/mcp` belongs to the extension. Remove the extension to restore the built-in behavior. To disable built-in MCP support without a replacement, disable `mcp` under Built-in in `pi config`, set `"extensions": ["-builtin:mcp"]` in [settings](settings.md#resources), or pass `--no-mcp` to disable it for one run.
267
267
 
268
- An extension that registers `codemode` or `tool_search` similarly replaces the built-in tool with that name. Shell-level `pi mcp` commands always use the built-in implementation.
268
+ An extension that registers `codemode` or `tool_search` similarly replaces the built-in tool with that name. Pi activates the replacement for MCP servers, and waits for the servers its calls need, only when it declares [`reachesTools`](extensions.md#tool-exposure). Shell-level `pi mcp` commands always use the built-in implementation.
269
269
 
270
270
  ### Use MCP from the SDK
271
271
 
package/docs/models.md CHANGED
@@ -31,6 +31,7 @@ For local OpenAI-compatible servers such as Ollama, LM Studio, and vLLM, each mo
31
31
 
32
32
  ```json
33
33
  {
34
+ "$schema": "https://raw.githubusercontent.com/ming-kang/pi/main/schemas/models.schema.json",
34
35
  "providers": {
35
36
  "ollama": {
36
37
  "baseUrl": "http://localhost:11434/v1",
@@ -0,0 +1,96 @@
1
+ # Run Pi with NVIDIA RTX and llama.cpp
2
+
3
+ [NVIDIA Local AI Inference Recipes](https://nvidia.github.io/local-ai-inference-recipes/index.html) provides llama.cpp settings tuned for specific NVIDIA hardware and models. Each recipe gives a single-model `llama-server` command. Pi works with the llama.cpp router, which can serve and manage several models, so this guide converts the recipe command into a router preset.
4
+
5
+ The examples below use Windows PowerShell. See [Local Models with llama.cpp](llama-cpp.md) for Pi's complete router and model-management reference.
6
+
7
+ ## Before you begin
8
+
9
+ 1. Open the [recipe catalog](https://nvidia.github.io/local-ai-inference-recipes/index.html), select your hardware, operating system, and model, then choose **llama.cpp**. Check the prerequisites and memory requirements. Keep the recipe's launch command for the conversion below.
10
+ 2. Install llama.cpp with the recipe's setup instructions. The recipe's settings depend on its build, for example CUDA support or speculative decoding options.
11
+ 3. Run `llama-server --help` and check that it lists `--models-preset`. Without it, the build cannot load the recipe as a router preset. Use a newer build that still meets the recipe's requirements.
12
+ 4. Install Pi with the [Quickstart](quickstart.md). On native Windows, also see [Run Pi on Windows](windows.md).
13
+
14
+ ## Convert the recipe to a preset
15
+
16
+ A preset lists the settings for one or more models. Each section name becomes the model ID shown in Pi. Save the preset next to `llama-server`, or pass its full path when starting the router.
17
+
18
+ Convert each option from the recipe command into one preset line:
19
+
20
+ - Remove the leading dashes: `--ctx-size 65536` becomes `ctx-size = 65536`.
21
+ - Write options without a value as `true`: `--jinja` becomes `jinja = true`.
22
+ - Remove quotes and PowerShell line-continuation backticks around values.
23
+ - Leave out `--host` and `--port`. They belong on the router command line.
24
+ - Add `load-on-startup = true` so the router loads the model when it starts.
25
+ - Replace short model-file options with their long preset keys:
26
+
27
+ | Recipe option | Preset key |
28
+ |---|---|
29
+ | `-hf` | `hf-repo` |
30
+ | `-hff` | `hf-file` |
31
+ | `-hfrd` | `hf-repo-draft` |
32
+ | `--spec-draft-model` | `spec-draft-model` |
33
+
34
+ For example, this recipe command:
35
+
36
+ ```powershell
37
+ llama-server.exe -hf "unsloth/Qwen3.8-27B-GGUF" `
38
+ -hff "Qwen3.8-27B-UD-Q4_K_M.gguf" `
39
+ -hfrd "z-lab/Qwen3.8-27B-DFlash2-GGUF" `
40
+ --spec-draft-model "Qwen3.8-27B-DFlash2-Q4_K_M.gguf" `
41
+ --no-mmproj `
42
+ --host 127.0.0.1 `
43
+ --port 9931 `
44
+ --batch-size 4096 `
45
+ --ubatch-size 1024 `
46
+ --ctx-size 65536 `
47
+ --parallel 1 `
48
+ -ngl 999 `
49
+ --jinja `
50
+ --chat-template-kwargs '{"preserve_thinking":true}' `
51
+ --spec-type draft-dflash `
52
+ --spec-draft-n-max 7 `
53
+ --spec-draft-backend-sampling
54
+ ```
55
+
56
+ becomes `qwen3.8-27b.ini`:
57
+
58
+ ```ini
59
+ version = 1
60
+
61
+ [qwen3.8-27b]
62
+ load-on-startup = true
63
+ hf-repo = unsloth/Qwen3.8-27B-GGUF
64
+ hf-file = Qwen3.8-27B-UD-Q4_K_M.gguf
65
+ hf-repo-draft = z-lab/Qwen3.8-27B-DFlash2-GGUF
66
+ spec-draft-model = Qwen3.8-27B-DFlash2-Q4_K_M.gguf
67
+ no-mmproj = true
68
+ batch-size = 4096
69
+ ubatch-size = 1024
70
+ ctx-size = 65536
71
+ parallel = 1
72
+ ngl = 999
73
+ jinja = true
74
+ chat-template-kwargs = {"preserve_thinking":true}
75
+ spec-type = draft-dflash
76
+ spec-draft-n-max = 7
77
+ spec-draft-backend-sampling = true
78
+ ```
79
+
80
+ ## Start the router
81
+
82
+ Open PowerShell in the llama.cpp folder and run:
83
+
84
+ ```powershell
85
+ .\llama-server.exe --models-preset qwen3.8-27b.ini --host 127.0.0.1 --port 8080
86
+ ```
87
+
88
+ If the recipe requires a Hugging Face token, set `$env:HF_TOKEN` in the same PowerShell window before starting the router. On its first start, the router downloads the model files.
89
+
90
+ Use the [router health checks](llama-cpp.md#troubleshooting) to confirm that the server is ready. In Windows PowerShell, use `curl.exe` rather than `curl`, which PowerShell maps to a different command. The model is ready when `/models` lists `qwen3.8-27b` with the status `loaded`.
91
+
92
+ ## Use the model in Pi
93
+
94
+ Follow [Configure Pi](llama-cpp.md#configure-pi) and connect to `http://127.0.0.1:8080`. The preset section name is the model ID, so select `qwen3.8-27b` in `/model` for this example.
95
+
96
+ NVIDIA recipe memory settings assume that only the selected model uses the GPU. If `/llama` shows other loaded models, unload them before using the recipe model.
package/docs/providers.md CHANGED
@@ -60,6 +60,22 @@ When the browser runs on another machine, select the copy code login method in `
60
60
  - On remote or headless machines (for example over SSH), paste the final redirect URL or authorization code into the login prompt when the browser cannot reach the loopback callback
61
61
  - `OPENROUTER_API_KEY` remains available through **Use an API key**
62
62
 
63
+ With a key, Pi lists only the OpenRouter chat models that key may use, with the key's context size, max output, and prices. These come from OpenRouter's `/models/user` endpoint and reflect guardrails and provider restrictions set in OpenRouter. Image and classifier models are not filtered.
64
+
65
+ Pi refreshes the list in the background at startup in interactive mode, when `/model` opens, after `/login`, and on `pi update --models`. The last list is saved and used offline and in `pi -p` and RPC mode. After switching keys outside `/login`, the previous key's list stays until the next refresh.
66
+
67
+ Regional endpoints filter models to their region. To use one, set the base URL in [`models.json`](models.md):
68
+
69
+ ```json
70
+ {
71
+ "providers": {
72
+ "openrouter": { "baseUrl": "https://us.openrouter.ai/api/v1" }
73
+ }
74
+ }
75
+ ```
76
+
77
+ If the base URL rejects the key at `/models/user` or does not have that endpoint, for example a proxy configured as the OpenRouter base URL, Pi lists every OpenRouter model.
78
+
63
79
  ### Radius
64
80
 
65
81
  Radius is a service by Earendil Works, the builders of upstream Pi. It provides an AI gateway with organization-level controls and analytics, and artifacts for sharing what you create with Pi. It is in early alpha; see [radius.earendil.com](https://radius.earendil.com).
@@ -224,7 +240,7 @@ The `azure` provider serves both Azure OpenAI Responses deployments and Azure AI
224
240
 
225
241
  Pi sends the model ID as the deployment name. If a deployment has a different name, map it with `AZURE_OPENAI_DEPLOYMENT_NAME_MAP`.
226
242
 
227
- To use a Foundry model that Pi does not include, add it under `azure` in [`models.json`](models.md#configure-a-compatible-endpoint) with `api: "openai-completions"`. Custom models require a `baseUrl`; `AZURE_OPENAI_BASE_URL` and `AZURE_OPENAI_RESOURCE_NAME` take priority over it when set:
243
+ To use a Foundry model that Pi does not include, add it under `azure` in [`models.json`](models.md#provider-configuration) with `api: "openai-completions"`. Custom models require a `baseUrl`; `AZURE_OPENAI_BASE_URL` and `AZURE_OPENAI_RESOURCE_NAME` take priority over it when set:
228
244
 
229
245
  ```json
230
246
  {
package/docs/sdk.md CHANGED
@@ -188,33 +188,6 @@ session = runtime.session;
188
188
  unsubscribe = session.subscribe(() => {});
189
189
  ```
190
190
 
191
- ### Experimental Remote Sessions
192
-
193
- The `@astralyn/pi/client` subpath provides a lifecycle controller and transcript reducers for applications that connect to a remote Pi server. It is available only in a source checkout under the `source` condition, together with `@astralyn/pi/experimental/plugin`; neither subpath is a published runtime export. See [Experimental remote harness](development.md#experimental-remote-harness). Transport and protocol primitives come from the exact `@earendil-works/pi-client` and `@earendil-works/pi-protocol` dependencies.
194
-
195
- ```typescript
196
- import { PiClient } from "@earendil-works/pi-client";
197
- import { createUnixTransportFactory } from "@earendil-works/pi-client/unix";
198
- import { RemoteSession } from "@astralyn/pi/client";
199
-
200
- await using client = await PiClient.connect({
201
- transportFactory: createUnixTransportFactory({ path: "/tmp/pi.sock" }),
202
- });
203
- await using session = await RemoteSession.create(client, {
204
- cwd: "/workspace/project",
205
- });
206
-
207
- const unsubscribe = session.subscribe(({ lifecycle, snapshot, transcript }) => {
208
- console.log(lifecycle.status, snapshot?.phase, transcript.length);
209
- });
210
- await session.submit("Inspect this project");
211
- unsubscribe();
212
- ```
213
-
214
- Use `RemoteSession.open(client, sessionId)` to acquire an existing session. The controller serializes open/create/submit/model/thinking operations, selects prompt versus steering behavior from the remote phase, supports abort and reconnect, and releases its exclusive session lease on disposal. `createTranscriptState()`, `applyTranscriptSnapshot()`, `applyTranscriptProgress()`, and `selectTranscript()` are also exported for lower-level clients that manage transcript state directly.
215
-
216
- This API is experimental. Match client and server protocol versions, bound transport queues and frame sizes, authenticate the transport, and treat peers as untrusted.
217
-
218
191
  ### Prompting and Message Queueing
219
192
 
220
193
  `PromptOptions` controls prompt expansion, queueing behavior while streaming, and prompt preflight notifications:
package/docs/sessions.md CHANGED
@@ -32,7 +32,7 @@ For the JSONL file format and SessionManager API, see [Session Format](session-f
32
32
  | `/clone` | Duplicate the current active branch into a new session |
33
33
  | `/compact [prompt]` | Summarize older context; see [Compaction](compaction.md) |
34
34
  | `/export [file]` | Export session to HTML |
35
- | `/share` | Upload as private GitHub gist with shareable HTML link |
35
+ | `/share` | Upload the session for a shareable HTML link; a Radius artifact when signed in, otherwise a private GitHub gist (see [`sessionShareDestination`](settings.md#sessions)) |
36
36
  | `/bug [description]` | Report a bug to the Pi developers; see [Reporting Bugs](#reporting-bugs) |
37
37
 
38
38
  ## Resuming and Deleting Sessions
package/docs/settings.md CHANGED
@@ -7,7 +7,7 @@ Pi uses JSON settings files with project settings overriding global settings. JS
7
7
  | `~/.pi/agent/settings.json` | Global (all projects) |
8
8
  | `.pi/settings.json` | Project (current directory) |
9
9
 
10
- Edit directly or use `/settings` for common options.
10
+ Edit directly or use `/settings` for common options. Add `"$schema": "https://raw.githubusercontent.com/ming-kang/pi/main/schemas/settings.schema.json"` to `settings.json` for editor validation and completion.
11
11
 
12
12
  ## Project Trust
13
13
 
@@ -90,7 +90,7 @@ Selecting a model or thinking level with Enter changes only the current session.
90
90
  | `editorPaddingX` | number | `0` | Horizontal padding for input editor (0-3) |
91
91
  | `outputPad` | number | `1` | Horizontal padding for messages, `!` command output, and summary blocks, and for tool output that renders its own shell (0 or 1) |
92
92
  | `autocompleteMaxVisible` | number | `5` | Max visible items in autocomplete dropdown (3-20) |
93
- | `showHardwareCursor` | boolean | `false` | Show the terminal cursor while TUI positions it for IME support |
93
+ | `showHardwareCursor` | boolean | `false` | Use the terminal cursor instead of Pi's drawn cursor. Pi still positions it for IME support |
94
94
  | `tuiMode` | string | `"fullscreen"` | Interactive TUI mode: `"fullscreen"` or `"regular"`. Changes from `/settings` apply immediately; `--tui-mode` overrides this setting at startup |
95
95
  | `fullscreenExitOutput` | string | `"transcript"` | Fullscreen exit output: `"transcript"` prints the final transcript and resume hint, while `"resume-hint"` restores the previous screen and prints only the resume hint. Has no effect in regular TUI mode |
96
96
  | `fullscreenScrollbar` | string | `"auto"` | Fullscreen transcript scrollbar: `"auto"` shows it temporarily while scrolling, `"always"` reserves the rightmost column and keeps it visible, and `"hidden"` hides it. Has no effect in regular TUI mode |
@@ -308,6 +308,7 @@ An empty array starts with no built-in tools while preserving extension and SDK
308
308
  | Setting | Type | Default | Description |
309
309
  |---------|------|---------|-------------|
310
310
  | `sessionDir` | string | - | Directory where session files are stored. Accepts absolute or relative paths, plus `~`. |
311
+ | `sessionShareDestination` | `"auto" \| "gist" \| "radius"` | `"auto"` | Destination used by `/share`. `auto` uses Radius when signed in and otherwise creates a private GitHub gist. `gist` always uses a gist. `radius` requires Radius authentication and never falls back to a gist. |
311
312
 
312
313
  ```json
313
314
  { "sessionDir": ".pi/sessions" }
@@ -442,7 +443,7 @@ This replaces `bash` with `powershell` and enables `grep`: `["-bash", "+powershe
442
443
 
443
444
  `/reload` enables tools newly added to `defaultTools`. It does not disable tools removed from it or re-enable unchanged tools you turned off. `--tools` with plain names, `--no-tools`, and `--no-builtin-tools` override `defaultTools`, also on reload.
444
445
 
445
- CLI tool options override this setting for one invocation. `--tools` with only `+name` and `-name` entries changes the resolved `defaultTools` selection instead, for example `pi --tools +codemode`. On `/reload`, these entries apply to the reloaded setting too, so a tool removed with `-name` stays removed. See [Command Line](usage.md#tools).
446
+ CLI tool options override this setting for one invocation. `--tools` with only `+name` and `-name` entries changes the resolved `defaultTools` selection instead, for example `pi --tools +codemode`. On `/reload`, these entries apply to the reloaded setting too, so a tool removed with `-name` stays removed. See [Command Line](usage.md#tool-options).
446
447
 
447
448
  | Setting | Default | Meaning |
448
449
  |---|---|---|
package/docs/themes.md CHANGED
@@ -69,7 +69,7 @@ vim ~/.pi/agent/themes/my-theme.json
69
69
 
70
70
  ```json
71
71
  {
72
- "$schema": "https://raw.githubusercontent.com/ming-kang/pi/main/src/modes/interactive/theme/theme-schema.json",
72
+ "$schema": "https://raw.githubusercontent.com/ming-kang/pi/main/schemas/theme.schema.json",
73
73
  "name": "my-theme",
74
74
  "vars": {
75
75
  "primary": "#00aaff",
@@ -143,7 +143,7 @@ vim ~/.pi/agent/themes/my-theme.json
143
143
 
144
144
  ```json
145
145
  {
146
- "$schema": "https://raw.githubusercontent.com/ming-kang/pi/main/src/modes/interactive/theme/theme-schema.json",
146
+ "$schema": "https://raw.githubusercontent.com/ming-kang/pi/main/schemas/theme.schema.json",
147
147
  "name": "my-theme",
148
148
  "vars": {
149
149
  "blue": "#0066cc",
@@ -165,6 +165,8 @@ vim ~/.pi/agent/themes/my-theme.json
165
165
 
166
166
  The `$schema` field enables editor auto-completion and validation.
167
167
 
168
+ Theme objects are strict: only documented top-level fields and color tokens are accepted. Define reusable custom colors under `vars`; custom keys under `colors` or `export` and additional top-level metadata are rejected.
169
+
168
170
  ## Color Tokens
169
171
 
170
172
  Every theme must define all 51 required color tokens. The optional tokens preserve compatibility with existing themes: `thinkingMax` falls back to `thinkingXhigh`, `scrollbarThumb` and `searchMatchBg` fall back to `selectedBg`, and `searchMatchText` falls back to `text`. Other search matches use `searchMatchText` on `searchMatchBg` with an underline; the current match reverses that foreground/background pair and uses bold text.
package/docs/tui.md CHANGED
@@ -51,7 +51,7 @@ class CursorCell implements Component, Focusable {
51
51
  }
52
52
  ```
53
53
 
54
- When a focused component has a `focused` property, TUI sets it and looks for `CURSOR_MARKER` in its rendered lines to position the hardware cursor. `Input` and `Editor` already implement this. An extension can query or change the injected TUI's hardware-cursor setting with `tui.getShowHardwareCursor()` and `tui.setShowHardwareCursor(enabled)`; changing it affects the whole application UI.
54
+ When a focused component has a `focused` property, TUI sets it and looks for `CURSOR_MARKER` in its rendered lines to position the hardware cursor. Wrap the cursor cell in `renderFakeCursor()` so the TUI draws it in reverse video, or hides it after `CURSOR_MARKER` when the hardware cursor is shown. `Input` and `Editor` already implement this. An extension can query or change the injected TUI's hardware-cursor setting with `tui.getShowHardwareCursor()` and `tui.setShowHardwareCursor(enabled)`; changing it affects the whole application UI.
55
55
 
56
56
  A container that owns an `Input` or `Editor` must forward both focus and input to its child. `Container` only groups and renders children; it does not route input for them.
57
57
 
package/docs/usage.md CHANGED
@@ -133,7 +133,7 @@ Use `/trust` in interactive mode to save a project trust decision for future ses
133
133
 
134
134
  Use `/export [file]` to write a session to HTML.
135
135
 
136
- Use `/share` to upload a private GitHub gist with a shareable HTML link.
136
+ Use `/share` to upload the session and get a shareable HTML link. By default, Radius authentication makes the artifact visible to your Radius organization; otherwise, Pi creates a private GitHub gist through the GitHub CLI. The [`sessionShareDestination`](settings.md#sessions) setting can force either destination. Review the session first because it can contain prompts, tool output, file contents, and credentials exposed during the conversation.
137
137
 
138
138
  If you use pi for open source work and want to publish sessions for model, prompt, tool, and evaluation research, see [`badlogic/pi-share-hf`](https://github.com/badlogic/pi-share-hf). It publishes sessions to Hugging Face datasets.
139
139
 
@@ -176,6 +176,8 @@ See [Pi Packages](packages.md) for package sources and security notes.
176
176
 
177
177
  `--mode` accepts only `text`, `json`, or `rpc`. A missing or invalid value is reported as an error and pi exits with a nonzero status instead of falling back to another mode.
178
178
 
179
+ Print mode writes errors to stderr. A final assistant response with an `error` or `aborted` stop reason exits nonzero; a response cut off at the model's output token limit (a `length` stop reason) still prints its partial text to stdout, warns on stderr, and also exits nonzero.
180
+
179
181
  In print mode, pi also reads piped stdin and merges it into the initial prompt:
180
182
 
181
183
  ```bash
@@ -187,10 +189,10 @@ cat README.md | pi -p "Summarize this text"
187
189
  | Option | Description |
188
190
  |--------|-------------|
189
191
  | `--provider <name>` | Provider to search for `--model`, such as `anthropic` or `openai`; requires `--model` |
190
- | `--model <pattern>` | Model pattern or ID; supports `provider/id` and optional `:<thinking>` |
191
- | `--api-key <key>` | API key, overriding environment variables |
192
+ | `--model <pattern>` | Model pattern or ID; supports `provider/id` and optional `:<thinking>`. If several providers match, Pi prefers the one with credentials, otherwise it asks for `--provider` |
193
+ | `--api-key <key>` | API key, overriding environment variables; does not choose between providers that offer the same model |
192
194
  | `--thinking <level>` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max` |
193
- | `--models <patterns>` | Comma-separated patterns for Ctrl+P cycling |
195
+ | `--models <patterns>` | Comma-separated patterns for Ctrl+P cycling; a model offered by several providers is added for each, with a warning |
194
196
  | `--list-models [search]` | List available models |
195
197
 
196
198
  ### Session Options
@@ -367,6 +369,6 @@ These commands work outside a session, so agents can run them through `bash`. Se
367
369
  | `pi mcp login <server> [--timeout <seconds>]` | Sign in to an OAuth server: open the authorization page and wait for the browser (default 300 seconds); a terminal also accepts the pasted redirect URL |
368
370
  | `pi mcp logout <server>` | Delete the stored OAuth credentials of a server |
369
371
 
370
- `add` and `remove` change `~/.pi/agent/mcp.json`, or `.pi/mcp.json` in the current directory with `--local` (`-l`). `add` also takes `--exposure <mode>` (see [Exposure](mcp.md#exposure)) and `--description <text>` and does not connect; run `pi mcp list` to check the server.
372
+ `add` and `remove` change `~/.pi/agent/mcp.json`, or `.pi/mcp.json` in the current directory with `--local` (`-l`). `add` also takes `--exposure <mode>` (see [Exposure](mcp.md#control-tool-exposure)) and `--description <text>` and does not connect; run `pi mcp list` to check the server.
371
373
 
372
374
  Project `.pi/mcp.json` files are only read for projects that are already trusted.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-custom-provider",
9
- "version": "1.1.0",
9
+ "version": "1.3.0",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.52.0"
12
12
  }