@astralyn/pi 0.87.1 → 0.87.3

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 (328) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/bundle/chunks/{chunk-CDMUKIXY.js → chunk-MJ45I4SM.js} +1 -1
  3. package/dist/bundle/chunks/{chunk-772GXEFD.js → chunk-TYOQD6VQ.js} +97 -84
  4. package/dist/bundle/chunks/{virtual-modules-LQO2MG3T.js → virtual-modules-NDGCHNG7.js} +1 -1
  5. package/dist/bundle/cli.js +1 -1
  6. package/dist/bundle/index.js +1 -1
  7. package/dist/bundle/rpc-entry.js +1 -1
  8. package/dist/config.d.ts +1 -1
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/config.js.map +1 -1
  11. package/dist/core/agent-session-runtime.d.ts +9 -0
  12. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  13. package/dist/core/agent-session-runtime.js +158 -157
  14. package/dist/core/agent-session-runtime.js.map +1 -1
  15. package/dist/core/agent-session.d.ts +14 -0
  16. package/dist/core/agent-session.d.ts.map +1 -1
  17. package/dist/core/agent-session.js +437 -434
  18. package/dist/core/agent-session.js.map +1 -1
  19. package/dist/core/background/types.d.ts +2 -0
  20. package/dist/core/background/types.d.ts.map +1 -1
  21. package/dist/core/background/types.js.map +1 -1
  22. package/dist/core/extensions/distribution-api.d.ts +41 -0
  23. package/dist/core/extensions/distribution-api.d.ts.map +1 -0
  24. package/dist/core/extensions/distribution-api.js +12 -0
  25. package/dist/core/extensions/distribution-api.js.map +1 -0
  26. package/dist/core/extensions/index.d.ts +1 -1
  27. package/dist/core/extensions/index.d.ts.map +1 -1
  28. package/dist/core/extensions/index.js.map +1 -1
  29. package/dist/core/extensions/loader.d.ts.map +1 -1
  30. package/dist/core/extensions/loader.js +1 -0
  31. package/dist/core/extensions/loader.js.map +1 -1
  32. package/dist/core/extensions/runner.d.ts.map +1 -1
  33. package/dist/core/extensions/runner.js +0 -2
  34. package/dist/core/extensions/runner.js.map +1 -1
  35. package/dist/core/extensions/types.d.ts +15 -45
  36. package/dist/core/extensions/types.d.ts.map +1 -1
  37. package/dist/core/extensions/types.js +1 -11
  38. package/dist/core/extensions/types.js.map +1 -1
  39. package/dist/core/extensions/virtual-modules.d.ts.map +1 -1
  40. package/dist/core/extensions/virtual-modules.js +2 -1
  41. package/dist/core/extensions/virtual-modules.js.map +1 -1
  42. package/dist/core/keybinding-registry.d.ts +11 -0
  43. package/dist/core/keybinding-registry.d.ts.map +1 -0
  44. package/dist/core/keybinding-registry.js +24 -0
  45. package/dist/core/keybinding-registry.js.map +1 -0
  46. package/dist/core/keybindings.d.ts +4 -64
  47. package/dist/core/keybindings.d.ts.map +1 -1
  48. package/dist/core/keybindings.js +2 -41
  49. package/dist/core/keybindings.js.map +1 -1
  50. package/dist/core/model-config.d.ts +70 -2
  51. package/dist/core/model-config.d.ts.map +1 -1
  52. package/dist/core/model-config.js +2 -26
  53. package/dist/core/model-config.js.map +1 -1
  54. package/dist/core/resource-loader.d.ts.map +1 -1
  55. package/dist/core/resource-loader.js +5 -11
  56. package/dist/core/resource-loader.js.map +1 -1
  57. package/dist/core/tools/bash.d.ts.map +1 -1
  58. package/dist/core/tools/bash.js +2 -2
  59. package/dist/core/tools/bash.js.map +1 -1
  60. package/dist/core/tools/shell-execution.d.ts +1 -0
  61. package/dist/core/tools/shell-execution.d.ts.map +1 -1
  62. package/dist/core/tools/shell-execution.js +21 -0
  63. package/dist/core/tools/shell-execution.js.map +1 -1
  64. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  65. package/dist/core/tools/tool-definition-wrapper.js +114 -1
  66. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  67. package/dist/core/trust-manager.d.ts.map +1 -1
  68. package/dist/core/trust-manager.js +11 -48
  69. package/dist/core/trust-manager.js.map +1 -1
  70. package/dist/extensions/background/actions.d.ts.map +1 -1
  71. package/dist/extensions/background/actions.js +107 -55
  72. package/dist/extensions/background/actions.js.map +1 -1
  73. package/dist/extensions/background/index.d.ts +2 -0
  74. package/dist/extensions/background/index.d.ts.map +1 -1
  75. package/dist/extensions/background/index.js +20 -3
  76. package/dist/extensions/background/index.js.map +1 -1
  77. package/dist/extensions/background/keybindings.d.ts +10 -0
  78. package/dist/extensions/background/keybindings.d.ts.map +1 -0
  79. package/dist/extensions/background/keybindings.js +14 -0
  80. package/dist/extensions/background/keybindings.js.map +1 -0
  81. package/dist/extensions/background/manager.d.ts +2 -0
  82. package/dist/extensions/background/manager.d.ts.map +1 -1
  83. package/dist/extensions/background/manager.js +1 -0
  84. package/dist/extensions/background/manager.js.map +1 -1
  85. package/dist/extensions/btw/controller.d.ts +1 -0
  86. package/dist/extensions/btw/controller.d.ts.map +1 -1
  87. package/dist/extensions/btw/controller.js +5 -5
  88. package/dist/extensions/btw/controller.js.map +1 -1
  89. package/dist/extensions/btw/index.js +1 -2
  90. package/dist/extensions/btw/index.js.map +1 -1
  91. package/dist/extensions/btw/keybindings.d.ts +10 -0
  92. package/dist/extensions/btw/keybindings.d.ts.map +1 -0
  93. package/dist/extensions/btw/keybindings.js +8 -0
  94. package/dist/extensions/btw/keybindings.js.map +1 -0
  95. package/dist/extensions/btw/panel.d.ts +1 -0
  96. package/dist/extensions/btw/panel.d.ts.map +1 -1
  97. package/dist/extensions/btw/panel.js +1 -0
  98. package/dist/extensions/btw/panel.js.map +1 -1
  99. package/dist/extensions/list-keybindings.d.ts +8 -0
  100. package/dist/extensions/list-keybindings.d.ts.map +1 -0
  101. package/dist/extensions/list-keybindings.js +8 -0
  102. package/dist/extensions/list-keybindings.js.map +1 -0
  103. package/dist/extensions/provider/compat-fields.d.ts.map +1 -1
  104. package/dist/extensions/provider/compat-fields.js +23 -3
  105. package/dist/extensions/provider/compat-fields.js.map +1 -1
  106. package/dist/extensions/provider/connection.d.ts.map +1 -1
  107. package/dist/extensions/provider/connection.js +1 -1
  108. package/dist/extensions/provider/connection.js.map +1 -1
  109. package/dist/extensions/provider/constants.d.ts +2 -0
  110. package/dist/extensions/provider/constants.d.ts.map +1 -1
  111. package/dist/extensions/provider/constants.js +2 -0
  112. package/dist/extensions/provider/constants.js.map +1 -1
  113. package/dist/extensions/provider/keybindings.d.ts +9 -0
  114. package/dist/extensions/provider/keybindings.d.ts.map +1 -0
  115. package/dist/extensions/provider/keybindings.js +12 -0
  116. package/dist/extensions/provider/keybindings.js.map +1 -0
  117. package/dist/extensions/provider/probe.d.ts +8 -4
  118. package/dist/extensions/provider/probe.d.ts.map +1 -1
  119. package/dist/extensions/provider/probe.js +169 -11
  120. package/dist/extensions/provider/probe.js.map +1 -1
  121. package/dist/extensions/provider/ui/builtin-data.d.ts +1 -0
  122. package/dist/extensions/provider/ui/builtin-data.d.ts.map +1 -1
  123. package/dist/extensions/provider/ui/builtin-data.js +1 -0
  124. package/dist/extensions/provider/ui/builtin-data.js.map +1 -1
  125. package/dist/extensions/provider/ui/compat.d.ts +1 -0
  126. package/dist/extensions/provider/ui/compat.d.ts.map +1 -1
  127. package/dist/extensions/provider/ui/compat.js +1 -0
  128. package/dist/extensions/provider/ui/compat.js.map +1 -1
  129. package/dist/extensions/provider/ui/dictionary.d.ts +1 -0
  130. package/dist/extensions/provider/ui/dictionary.d.ts.map +1 -1
  131. package/dist/extensions/provider/ui/dictionary.js +1 -0
  132. package/dist/extensions/provider/ui/dictionary.js.map +1 -1
  133. package/dist/extensions/provider/ui/editor.d.ts +1 -0
  134. package/dist/extensions/provider/ui/editor.d.ts.map +1 -1
  135. package/dist/extensions/provider/ui/editor.js +1 -0
  136. package/dist/extensions/provider/ui/editor.js.map +1 -1
  137. package/dist/extensions/provider/ui/fetch-models.d.ts +5 -3
  138. package/dist/extensions/provider/ui/fetch-models.d.ts.map +1 -1
  139. package/dist/extensions/provider/ui/fetch-models.js +28 -3
  140. package/dist/extensions/provider/ui/fetch-models.js.map +1 -1
  141. package/dist/extensions/provider/ui/model-fields.d.ts +1 -0
  142. package/dist/extensions/provider/ui/model-fields.d.ts.map +1 -1
  143. package/dist/extensions/provider/ui/model-fields.js +1 -0
  144. package/dist/extensions/provider/ui/model-fields.js.map +1 -1
  145. package/dist/extensions/provider/ui/model-options.d.ts +1 -0
  146. package/dist/extensions/provider/ui/model-options.d.ts.map +1 -1
  147. package/dist/extensions/provider/ui/model-options.js +1 -0
  148. package/dist/extensions/provider/ui/model-options.js.map +1 -1
  149. package/dist/extensions/provider/ui/provider-fields.d.ts +1 -0
  150. package/dist/extensions/provider/ui/provider-fields.d.ts.map +1 -1
  151. package/dist/extensions/provider/ui/provider-fields.js +1 -0
  152. package/dist/extensions/provider/ui/provider-fields.js.map +1 -1
  153. package/dist/extensions/question/dialog.d.ts +1 -0
  154. package/dist/extensions/question/dialog.d.ts.map +1 -1
  155. package/dist/extensions/question/dialog.js +1 -0
  156. package/dist/extensions/question/dialog.js.map +1 -1
  157. package/dist/extensions/question/index.d.ts.map +1 -1
  158. package/dist/extensions/question/index.js +3 -1
  159. package/dist/extensions/question/index.js.map +1 -1
  160. package/dist/extensions/question/keybindings.d.ts +2 -0
  161. package/dist/extensions/question/keybindings.d.ts.map +1 -0
  162. package/dist/extensions/question/keybindings.js +3 -0
  163. package/dist/extensions/question/keybindings.js.map +1 -0
  164. package/dist/extensions/question/schema.d.ts +18 -0
  165. package/dist/extensions/question/schema.d.ts.map +1 -1
  166. package/dist/extensions/question/schema.js +52 -0
  167. package/dist/extensions/question/schema.js.map +1 -1
  168. package/dist/extensions/subagent/index.d.ts.map +1 -1
  169. package/dist/extensions/subagent/index.js +3 -1
  170. package/dist/extensions/subagent/index.js.map +1 -1
  171. package/dist/extensions/subagent/resolve.d.ts +14 -1
  172. package/dist/extensions/subagent/resolve.d.ts.map +1 -1
  173. package/dist/extensions/subagent/resolve.js +32 -18
  174. package/dist/extensions/subagent/resolve.js.map +1 -1
  175. package/dist/extensions/subagent/runner.d.ts.map +1 -1
  176. package/dist/extensions/subagent/runner.js +4 -1
  177. package/dist/extensions/subagent/runner.js.map +1 -1
  178. package/dist/extensions/subagent/schema.d.ts +9 -0
  179. package/dist/extensions/subagent/schema.d.ts.map +1 -1
  180. package/dist/extensions/subagent/schema.js +30 -1
  181. package/dist/extensions/subagent/schema.js.map +1 -1
  182. package/dist/extensions/subagent/types.d.ts +2 -0
  183. package/dist/extensions/subagent/types.d.ts.map +1 -1
  184. package/dist/extensions/subagent/types.js.map +1 -1
  185. package/dist/extensions/todo/constants.d.ts +1 -1
  186. package/dist/extensions/todo/constants.d.ts.map +1 -1
  187. package/dist/extensions/todo/constants.js +8 -8
  188. package/dist/extensions/todo/constants.js.map +1 -1
  189. package/dist/extensions/todo/index.d.ts.map +1 -1
  190. package/dist/extensions/todo/index.js +1 -0
  191. package/dist/extensions/todo/index.js.map +1 -1
  192. package/dist/extensions/todo/schema.d.ts +30 -25
  193. package/dist/extensions/todo/schema.d.ts.map +1 -1
  194. package/dist/extensions/todo/schema.js +26 -20
  195. package/dist/extensions/todo/schema.js.map +1 -1
  196. package/dist/extensions/todo/state.d.ts +12 -8
  197. package/dist/extensions/todo/state.d.ts.map +1 -1
  198. package/dist/extensions/todo/state.js +255 -171
  199. package/dist/extensions/todo/state.js.map +1 -1
  200. package/dist/extensions/todo/view.d.ts +6 -2
  201. package/dist/extensions/todo/view.d.ts.map +1 -1
  202. package/dist/extensions/todo/view.js +234 -144
  203. package/dist/extensions/todo/view.js.map +1 -1
  204. package/dist/index.d.ts +1 -1
  205. package/dist/index.d.ts.map +1 -1
  206. package/dist/index.js.map +1 -1
  207. package/dist/modes/interactive/editor-host.d.ts +43 -0
  208. package/dist/modes/interactive/editor-host.d.ts.map +1 -0
  209. package/dist/modes/interactive/editor-host.js +83 -0
  210. package/dist/modes/interactive/editor-host.js.map +1 -0
  211. package/dist/modes/interactive/interactive-mode.d.ts +1 -11
  212. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  213. package/dist/modes/interactive/interactive-mode.js +300 -360
  214. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  215. package/dist/modes/interactive/tool-chat.d.ts +21 -0
  216. package/dist/modes/interactive/tool-chat.d.ts.map +1 -0
  217. package/dist/modes/interactive/tool-chat.js +58 -0
  218. package/dist/modes/interactive/tool-chat.js.map +1 -0
  219. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  220. package/dist/modes/rpc/rpc-mode.js +0 -2
  221. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  222. package/dist/utils/path-identity.d.ts +12 -0
  223. package/dist/utils/path-identity.d.ts.map +1 -0
  224. package/dist/utils/path-identity.js +63 -0
  225. package/dist/utils/path-identity.js.map +1 -0
  226. package/dist/utils/shell.d.ts +0 -1
  227. package/dist/utils/shell.d.ts.map +1 -1
  228. package/dist/utils/shell.js +0 -21
  229. package/dist/utils/shell.js.map +1 -1
  230. package/dist/utils/syntax-highlight.d.ts +2 -0
  231. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  232. package/dist/utils/syntax-highlight.js +2 -0
  233. package/dist/utils/syntax-highlight.js.map +1 -1
  234. package/docs/bundled/extensions/background.md +1 -1
  235. package/docs/bundled/extensions/provider.md +7 -3
  236. package/docs/bundled/extensions/question.md +1 -0
  237. package/docs/bundled/extensions/subagent.md +3 -1
  238. package/docs/bundled/extensions/todo.md +35 -23
  239. package/docs/extensions.md +17 -5
  240. package/examples/extensions/README.md +34 -14
  241. package/examples/extensions/auto-commit-on-exit.ts +1 -1
  242. package/examples/extensions/bash-spawn-hook.ts +2 -2
  243. package/examples/extensions/bookmark.ts +1 -1
  244. package/examples/extensions/border-status-editor.ts +6 -1
  245. package/examples/extensions/built-in-tool-renderer.ts +2 -2
  246. package/examples/extensions/claude-rules.ts +1 -1
  247. package/examples/extensions/commands.ts +1 -1
  248. package/examples/extensions/confirm-destructive.ts +1 -1
  249. package/examples/extensions/custom-compaction.ts +2 -2
  250. package/examples/extensions/custom-footer.ts +1 -1
  251. package/examples/extensions/custom-header.ts +2 -2
  252. package/examples/extensions/custom-provider-anthropic/index.ts +6 -6
  253. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  254. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  255. package/examples/extensions/custom-provider-gitlab-duo/index.ts +3 -3
  256. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  257. package/examples/extensions/dirty-repo-guard.ts +1 -1
  258. package/examples/extensions/doom-overlay/index.ts +1 -1
  259. package/examples/extensions/dynamic-resources/dynamic.json +3 -1
  260. package/examples/extensions/dynamic-resources/index.ts +1 -1
  261. package/examples/extensions/dynamic-tools.ts +1 -1
  262. package/examples/extensions/entry-renderer.ts +1 -1
  263. package/examples/extensions/event-bus.ts +1 -1
  264. package/examples/extensions/file-trigger.ts +1 -1
  265. package/examples/extensions/git-checkpoint.ts +1 -1
  266. package/examples/extensions/git-merge-and-resolve.ts +1 -1
  267. package/examples/extensions/github-issue-autocomplete.ts +1 -1
  268. package/examples/extensions/gondolin/index.ts +9 -7
  269. package/examples/extensions/gondolin/package-lock.json +2 -2
  270. package/examples/extensions/gondolin/package.json +1 -1
  271. package/examples/extensions/handoff.ts +2 -2
  272. package/examples/extensions/hello.ts +1 -1
  273. package/examples/extensions/hidden-thinking-label.ts +1 -1
  274. package/examples/extensions/inline-bash.ts +1 -1
  275. package/examples/extensions/input-transform-streaming.ts +1 -1
  276. package/examples/extensions/input-transform.ts +1 -1
  277. package/examples/extensions/interactive-shell.ts +1 -1
  278. package/examples/extensions/mac-system-theme.ts +1 -1
  279. package/examples/extensions/message-renderer.ts +1 -1
  280. package/examples/extensions/minimal-mode.ts +2 -2
  281. package/examples/extensions/modal-editor.ts +1 -1
  282. package/examples/extensions/model-status.ts +1 -1
  283. package/examples/extensions/notify.ts +1 -1
  284. package/examples/extensions/overlay-qa-tests.ts +3 -3
  285. package/examples/extensions/overlay-test.ts +1 -1
  286. package/examples/extensions/permission-gate.ts +1 -1
  287. package/examples/extensions/pirate.ts +1 -1
  288. package/examples/extensions/plan-mode/index.ts +1 -1
  289. package/examples/extensions/preset.ts +2 -2
  290. package/examples/extensions/project-trust.ts +3 -3
  291. package/examples/extensions/prompt-customizer.ts +1 -1
  292. package/examples/extensions/protected-paths.ts +1 -1
  293. package/examples/extensions/provider-payload.ts +1 -1
  294. package/examples/extensions/qna.ts +2 -2
  295. package/examples/extensions/question.ts +1 -1
  296. package/examples/extensions/questionnaire.ts +1 -1
  297. package/examples/extensions/rainbow-editor.ts +1 -1
  298. package/examples/extensions/reload-runtime.ts +1 -1
  299. package/examples/extensions/rpc-demo.ts +1 -1
  300. package/examples/extensions/sandbox/index.ts +2 -2
  301. package/examples/extensions/sandbox/package-lock.json +2 -2
  302. package/examples/extensions/sandbox/package.json +1 -1
  303. package/examples/extensions/send-user-message.ts +1 -1
  304. package/examples/extensions/session-name.ts +1 -1
  305. package/examples/extensions/shutdown-command.ts +1 -1
  306. package/examples/extensions/snake.ts +1 -1
  307. package/examples/extensions/space-invaders.ts +1 -1
  308. package/examples/extensions/ssh.ts +2 -2
  309. package/examples/extensions/status-line.ts +1 -1
  310. package/examples/extensions/structured-output.ts +1 -1
  311. package/examples/extensions/summarize.ts +2 -3
  312. package/examples/extensions/system-prompt-header.ts +1 -1
  313. package/examples/extensions/tic-tac-toe.ts +1 -1
  314. package/examples/extensions/timed-confirm.ts +1 -1
  315. package/examples/extensions/titlebar-spinner.ts +1 -1
  316. package/examples/extensions/todo.ts +1 -1
  317. package/examples/extensions/tool-override.ts +1 -1
  318. package/examples/extensions/tools.ts +2 -2
  319. package/examples/extensions/trigger-compact.ts +1 -1
  320. package/examples/extensions/truncated-tool.ts +4 -4
  321. package/examples/extensions/widget-placement.ts +1 -1
  322. package/examples/extensions/with-deps/index.ts +1 -1
  323. package/examples/extensions/with-deps/package-lock.json +2 -2
  324. package/examples/extensions/with-deps/package.json +1 -1
  325. package/examples/extensions/working-indicator.ts +1 -1
  326. package/examples/extensions/working-message-test.ts +1 -1
  327. package/npm-shrinkwrap.json +2 -2
  328. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"syntax-highlight.js","sourceRoot":"","sources":["../../src/utils/syntax-highlight.ts"],"names":[],"mappings":"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","sourcesContent":["import hljs from \"highlight.js/lib/index.js\";\nimport { decodeHtmlEntityAt } from \"./html.ts\";\n\nexport type HighlightFormatter = (text: string) => string;\nexport type HighlightTheme = Partial<Record<string, HighlightFormatter>>;\n\nexport interface HighlightOptions {\n\tlanguage?: string;\n\tignoreIllegals?: boolean;\n\tlanguageSubset?: string[];\n\ttheme?: HighlightTheme;\n}\n\nconst SPAN_CLOSE = \"</span>\";\nconst HIGHLIGHT_CLASS_PREFIX = \"hljs-\";\n\nfunction getScopeFromSpanTag(tag: string): string | undefined {\n\tconst match = /\\sclass\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/.exec(tag);\n\tconst classValue = match?.[1] ?? match?.[2];\n\tif (!classValue) {\n\t\treturn undefined;\n\t}\n\n\tfor (const className of classValue.split(/\\s+/)) {\n\t\tif (className.startsWith(HIGHLIGHT_CLASS_PREFIX)) {\n\t\t\treturn className.slice(HIGHLIGHT_CLASS_PREFIX.length);\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction getScopeFormatter(scope: string, theme: HighlightTheme): HighlightFormatter | undefined {\n\tconst exact = theme[scope];\n\tif (exact) {\n\t\treturn exact;\n\t}\n\n\tconst dotIndex = scope.indexOf(\".\");\n\tif (dotIndex !== -1) {\n\t\tconst prefixFormatter = theme[scope.slice(0, dotIndex)];\n\t\tif (prefixFormatter) {\n\t\t\treturn prefixFormatter;\n\t\t}\n\t}\n\n\tconst dashIndex = scope.indexOf(\"-\");\n\tif (dashIndex !== -1) {\n\t\tconst prefixFormatter = theme[scope.slice(0, dashIndex)];\n\t\tif (prefixFormatter) {\n\t\t\treturn prefixFormatter;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction getActiveFormatter(scopes: Array<string | undefined>, theme: HighlightTheme): HighlightFormatter | undefined {\n\tfor (let i = scopes.length - 1; i >= 0; i--) {\n\t\tconst scope = scopes[i];\n\t\tif (!scope) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst formatter = getScopeFormatter(scope, theme);\n\t\tif (formatter) {\n\t\t\treturn formatter;\n\t\t}\n\t}\n\treturn theme.default;\n}\n\nfunction isSpanOpenTagStart(html: string, index: number): boolean {\n\tif (!html.startsWith(\"<span\", index)) {\n\t\treturn false;\n\t}\n\tconst nextChar = html[index + \"<span\".length];\n\treturn nextChar === \">\" || nextChar === \" \" || nextChar === \"\\t\" || nextChar === \"\\n\" || nextChar === \"\\r\";\n}\n\nexport function renderHighlightedHtml(html: string, theme: HighlightTheme = {}): string {\n\tlet output = \"\";\n\tlet textBuffer = \"\";\n\tconst scopes: Array<string | undefined> = [];\n\n\tconst flushText = () => {\n\t\tif (!textBuffer) {\n\t\t\treturn;\n\t\t}\n\t\tconst formatter = getActiveFormatter(scopes, theme);\n\t\toutput += formatter ? formatter(textBuffer) : textBuffer;\n\t\ttextBuffer = \"\";\n\t};\n\n\tlet index = 0;\n\twhile (index < html.length) {\n\t\tif (isSpanOpenTagStart(html, index)) {\n\t\t\tconst tagEndIndex = html.indexOf(\">\", index + 5);\n\t\t\tif (tagEndIndex !== -1) {\n\t\t\t\tflushText();\n\t\t\t\tconst tag = html.slice(index, tagEndIndex + 1);\n\t\t\t\tconst scope = getScopeFromSpanTag(tag);\n\t\t\t\tscopes.push(scope);\n\t\t\t\tindex = tagEndIndex + 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (html.startsWith(SPAN_CLOSE, index)) {\n\t\t\tflushText();\n\t\t\tif (scopes.length > 0) {\n\t\t\t\tscopes.pop();\n\t\t\t}\n\t\t\tindex += SPAN_CLOSE.length;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (html[index] === \"&\") {\n\t\t\tconst decoded = decodeHtmlEntityAt(html, index);\n\t\t\tif (decoded) {\n\t\t\t\ttextBuffer += decoded.text;\n\t\t\t\tindex += decoded.length;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\ttextBuffer += html[index];\n\t\tindex++;\n\t}\n\n\tflushText();\n\treturn output;\n}\n\nexport function highlight(code: string, options: HighlightOptions = {}): string {\n\tconst html = options.language\n\t\t? hljs.highlight(code, {\n\t\t\t\tlanguage: options.language,\n\t\t\t\tignoreIllegals: options.ignoreIllegals,\n\t\t\t}).value\n\t\t: hljs.highlightAuto(code, options.languageSubset).value;\n\treturn renderHighlightedHtml(html, options.theme);\n}\n\nexport function supportsLanguage(name: string): boolean {\n\treturn hljs.getLanguage(name) !== undefined;\n}\n"]}
1
+ {"version":3,"file":"syntax-highlight.js","sourceRoot":"","sources":["../../src/utils/syntax-highlight.ts"],"names":[],"mappings":"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","sourcesContent":["import hljs from \"highlight.js/lib/index.js\";\nimport { decodeHtmlEntityAt } from \"./html.ts\";\n\nexport type HighlightFormatter = (text: string) => string;\nexport type HighlightTheme = Partial<Record<string, HighlightFormatter>>;\n\nexport interface HighlightOptions {\n\tlanguage?: string;\n\tignoreIllegals?: boolean;\n\tlanguageSubset?: string[];\n\ttheme?: HighlightTheme;\n}\n\nconst SPAN_CLOSE = \"</span>\";\nconst HIGHLIGHT_CLASS_PREFIX = \"hljs-\";\n\nfunction getScopeFromSpanTag(tag: string): string | undefined {\n\tconst match = /\\sclass\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/.exec(tag);\n\tconst classValue = match?.[1] ?? match?.[2];\n\tif (!classValue) {\n\t\treturn undefined;\n\t}\n\n\tfor (const className of classValue.split(/\\s+/)) {\n\t\tif (className.startsWith(HIGHLIGHT_CLASS_PREFIX)) {\n\t\t\treturn className.slice(HIGHLIGHT_CLASS_PREFIX.length);\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction getScopeFormatter(scope: string, theme: HighlightTheme): HighlightFormatter | undefined {\n\tconst exact = theme[scope];\n\tif (exact) {\n\t\treturn exact;\n\t}\n\n\tconst dotIndex = scope.indexOf(\".\");\n\tif (dotIndex !== -1) {\n\t\tconst prefixFormatter = theme[scope.slice(0, dotIndex)];\n\t\tif (prefixFormatter) {\n\t\t\treturn prefixFormatter;\n\t\t}\n\t}\n\n\tconst dashIndex = scope.indexOf(\"-\");\n\tif (dashIndex !== -1) {\n\t\tconst prefixFormatter = theme[scope.slice(0, dashIndex)];\n\t\tif (prefixFormatter) {\n\t\t\treturn prefixFormatter;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction getActiveFormatter(scopes: Array<string | undefined>, theme: HighlightTheme): HighlightFormatter | undefined {\n\tfor (let i = scopes.length - 1; i >= 0; i--) {\n\t\tconst scope = scopes[i];\n\t\tif (!scope) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst formatter = getScopeFormatter(scope, theme);\n\t\tif (formatter) {\n\t\t\treturn formatter;\n\t\t}\n\t}\n\treturn theme.default;\n}\n\nfunction isSpanOpenTagStart(html: string, index: number): boolean {\n\tif (!html.startsWith(\"<span\", index)) {\n\t\treturn false;\n\t}\n\tconst nextChar = html[index + \"<span\".length];\n\treturn nextChar === \">\" || nextChar === \" \" || nextChar === \"\\t\" || nextChar === \"\\n\" || nextChar === \"\\r\";\n}\n\nexport function renderHighlightedHtml(html: string, theme: HighlightTheme = {}): string {\n\tlet output = \"\";\n\tlet textBuffer = \"\";\n\tconst scopes: Array<string | undefined> = [];\n\n\tconst flushText = () => {\n\t\tif (!textBuffer) {\n\t\t\treturn;\n\t\t}\n\t\tconst formatter = getActiveFormatter(scopes, theme);\n\t\toutput += formatter ? formatter(textBuffer) : textBuffer;\n\t\ttextBuffer = \"\";\n\t};\n\n\tlet index = 0;\n\twhile (index < html.length) {\n\t\tif (isSpanOpenTagStart(html, index)) {\n\t\t\tconst tagEndIndex = html.indexOf(\">\", index + 5);\n\t\t\tif (tagEndIndex !== -1) {\n\t\t\t\tflushText();\n\t\t\t\tconst tag = html.slice(index, tagEndIndex + 1);\n\t\t\t\tconst scope = getScopeFromSpanTag(tag);\n\t\t\t\tscopes.push(scope);\n\t\t\t\tindex = tagEndIndex + 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (html.startsWith(SPAN_CLOSE, index)) {\n\t\t\tflushText();\n\t\t\tif (scopes.length > 0) {\n\t\t\t\tscopes.pop();\n\t\t\t}\n\t\t\tindex += SPAN_CLOSE.length;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (html[index] === \"&\") {\n\t\t\tconst decoded = decodeHtmlEntityAt(html, index);\n\t\t\tif (decoded) {\n\t\t\t\ttextBuffer += decoded.text;\n\t\t\t\tindex += decoded.length;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\ttextBuffer += html[index];\n\t\tindex++;\n\t}\n\n\tflushText();\n\treturn output;\n}\n\nexport function highlight(code: string, options: HighlightOptions = {}): string {\n\tconst html = options.language\n\t\t? hljs.highlight(code, {\n\t\t\t\tlanguage: options.language,\n\t\t\t\tignoreIllegals: options.ignoreIllegals,\n\t\t\t}).value\n\t\t: hljs.highlightAuto(code, options.languageSubset).value;\n\treturn renderHighlightedHtml(html, options.theme);\n}\n\nexport function supportsLanguage(name: string): boolean {\n\treturn hljs.getLanguage(name) !== undefined;\n}\n\n/** Every grammar loads statically with this module; kept so upstream callers stay unchanged. */\nexport async function loadAllHighlightLanguages(): Promise<void> {}\n"]}
@@ -40,7 +40,7 @@ Workers cannot start background work themselves. Their system prompt forbids it
40
40
  | `wait` | `taskId`, optional `waitMs`, `sinceBytes` | Waits within a deadline and returns status plus bounded output/report |
41
41
  | `kill` | `taskId` | Requests cancellation of the Bash task or entire Subagent group |
42
42
 
43
- Use the execution ID returned by the native tool or `bg list`. Worker IDs are display identities, not independent management targets.
43
+ Use the execution ID returned by the native tool or `bg list`. Worker IDs are display identities, not independent management targets. An unknown or stale `taskId` fails with the session's current tasks listed inline (active first, then recent finishes), so the next call can use a real ID without a separate list call; an ambiguous prefix lists exactly the tasks it matched.
44
44
 
45
45
  ```json
46
46
  { "action": "read", "taskId": "<execution-id>", "mode": "tail", "bytes": 8192 }
@@ -84,11 +84,15 @@ The active session model and its provider cannot be deleted or renamed; switch m
84
84
 
85
85
  For OpenAI-compatible APIs, discovery uses `GET {baseUrl}/models`. Anthropic Messages uses `{baseUrl}/v1/models`, without repeating an existing `/v1` suffix. The pane's idle action row shows the discovery URL; `Enter` starts the request. Without a `baseUrl`, the pane instead explains what to configure and discovery cannot start.
86
86
 
87
- Accepted catalog shapes are `data[]`, `models[]`, or a bare array. Entries can provide `id` or `slug`, plus an optional `name`, `display_name`, or `displayName`. Discovery imports identifiers and labels; model capabilities remain explicit configuration or opt-in built-in data. Native Google catalog shapes are not supported.
87
+ Accepted catalog shapes are `data[]`, `models[]`, or a bare array. Entries can provide `id` or `slug`, plus an optional `name`, `display_name`, or `displayName`. Alongside the identifier and label, discovery imports the metadata an entry declares under the common field names — `context_window` / `context_length` / `max_model_len`, `max_output_tokens` / `max_tokens`, image input via `input_modalities` or an explicit vision flag, and reasoning via a supported-effort list or a capability flag. Only positive integers count (`0`, `null`, decimals, and non-numeric values are ignored); where fields disagree the smallest value wins, because an overstated limit overflows requests while an understated one only compacts earlier. Native Google catalog shapes are not supported.
88
88
 
89
89
  - **Authentication:** Credentials resolve through Pi's canonical resolution chain. Header-only resolved authentication is supported, and the default scheme follows the API type. Unsaved connection changes block discovery. Raw `$VAR` or `!command` placeholders are never transmitted unresolved; discovery aborts if configured credentials cannot be resolved. Known resolved credentials are redacted from server errors.
90
- - **Limits:** Discovery has a 10-second deadline including preparation and authentication waits. Responses are bounded to 4 MiB (error payloads are bounded to 4 KiB and displayed up to 400 characters). Catalogs are capped at 2,000 models. A response declaring `has_more` is marked partial; further pages are not fetched automatically.
91
- - **Checklist import:** Discovered models appear in a searchable checklist. Models already configured in `models.json` are marked `Added` and cannot be checked. Confirming imports the checked models — or just the highlighted one when nothing is checked — as `{ id, name? }` records, saves immediately, and refreshes the provider runtime. `Esc` discards the results.
90
+ - **Anthropic-compatible gateways:** Anthropic Messages catalogs are often served OpenAI-style only, so a `401`, `403`, or `404` on the Anthropic path triggers exactly one retry with `Authorization: Bearer` at the same URL, or at the base URL with a trailing `/anthropic` removed. Both attempts stay on the original origin, an explicitly configured `Authorization` header is never overridden, and other API types are never retried. A failed retry reports both URLs and their status codes.
91
+ - **Pagination:** Anthropic catalogs answer with their `has_more` marker; discovery follows that marker through `after_id` (up to five pages) instead of reporting the first 20-entry page as partial. Every other catalog is fetched once and a response declaring `has_more` is still marked partial.
92
+ - **Limits:** Discovery has a 10-second deadline covering the whole attempt sequence, including preparation, authentication waits, retries, and pagination. Responses are bounded to 4 MiB (error payloads are bounded to 4 KiB and displayed up to 400 characters). Catalogs are capped at 2,000 models.
93
+ - **Checklist import:** Discovered models appear in a searchable checklist. Models already configured in `models.json` are marked `Added` and cannot be checked. Each row shows the metadata it declared, e.g. `deepseek-flash · DeepSeek-V4.1-Flash · 1.0M ctx · 393k out · img · think`. Confirming imports the checked models — or just the highlighted one when nothing is checked — with that metadata, saves immediately, and refreshes the provider runtime. `Esc` discards the results.
94
+
95
+ Imported metadata lands in the same fields the editor already manages, so `contextWindow`, `maxTokens`, `input`, and `reasoning` remain editable afterwards. Cost is never imported: catalog pricing dialects differ in both unit and precision, and a misread rate misreports spend by orders of magnitude.
92
96
 
93
97
  ## Use Built-in Data
94
98
 
@@ -51,4 +51,5 @@ Dialog footers use configured keybindings where Pi exposes them, format compact
51
51
  - Uses Pi's native `ctx.ui.custom()` lifecycle; no state is shared with another extension.
52
52
  - The render cache is keyed by terminal width **and height**, because preview height depends on available rows and Pi resize only requests a render. Preview markdown rendering is additionally memoized per text and dimensions so editor keystrokes don't re-parse previews.
53
53
  - `validateQuestions` defensively trims every visible text field and rejects whitespace-only content, then enforces case-insensitive uniqueness, reserved-label rejection, and the preview/multi-select conflict. The JSON schema separately carries non-empty, length, and count constraints before execution.
54
+ - `prepareArguments` normalizes the three unambiguous argument shapes models actually emit — a lone question written flat at the root wraps into `questions[0]`, a root-level `question` string fills a `questions[0]` object that lost its own `question` field, and a stringified `questions` array parses back into an array. The schema itself keeps a single object shape because strict constrained sampling (which the tool opts into) does not support object unions.
54
55
  - Dialog navigation follows Pi's injected select/input keybindings where applicable; compact footer labels show the first configured binding in a human-readable form. Custom actions such as Space-to-toggle remain explicit in the footer.
@@ -28,9 +28,11 @@ Each item has:
28
28
  prompt Required self-contained worker briefing
29
29
  description? Short task label for the /bg list, live rows, and report headings; derived from the prompt when omitted
30
30
  agent? explorer or general; defaults to explorer
31
- cwd? Directory inside the parent working directory
31
+ cwd? Worker directory; relative paths resolve against the parent working directory
32
32
  ```
33
33
 
34
+ A `cwd` inside the parent working directory runs with the parent session's project trust. A `cwd` outside it is allowed but runs untrusted: the worker never loads that directory's `.pi` project settings under the parent's trust conclusion. A missing or non-directory `cwd` fails the call and names the nearest existing parent directory.
35
+
34
36
  There is no separate single-task or parallel mode. One item launches one worker; multiple items launch concurrent workers. A session-scoped gate permits at most six active workers across all sibling `subagent` calls, so additional items wait for a slot. Results always follow input order, regardless of completion order.
35
37
 
36
38
  All tasks are preflighted before any worker starts. Profile, working-directory, model, thinking-level, or authentication failure in one item rejects the entire call without launching the other workers. Once execution begins, one worker failing does not cancel independent siblings.
@@ -2,24 +2,23 @@
2
2
 
3
3
  Adds a `todo` tool and `/todos` command for multi-step work. While unfinished tasks exist, a width-aware one-line widget stays above the editor; `/todos` shows the complete list on demand.
4
4
 
5
- ## Tool actions
5
+ ## Tool patches
6
6
 
7
- The tool has four actions:
7
+ One call applies one patch built from three optional groups:
8
8
 
9
- - `create` atomically adds one or more pending tasks from a single ordered `items` array. Each item requires a concise `subject` and a `description` of what done means.
10
- - `update` changes one task's `subject`, `description`, or `status`.
11
- - `list` returns every current task and its full description.
12
- - `delete` removes one or more task IDs from the current list.
9
+ - `create` atomically adds one or more tasks in input order. Each item requires a concise `subject` and a `description` of what done means; `status` defaults to `pending` and may be set explicitly, including `in_progress`.
10
+ - `update` edits one or more tasks by `id`. Blank or omitted `subject`/`description` fields keep the current values, so a status-only edit is `{"update": [{"id": 2, "status": "completed"}]}`.
11
+ - `delete` removes one or more task IDs. Deleting an ID that is already absent is a recorded no-op, not an error.
13
12
 
14
- Single and batch creation use the same shape:
13
+ Omit or leave empty any group the call does not need; calling with `{}` lists every task with its full description:
15
14
 
16
15
  ```json
17
16
  {
18
- "action": "create",
19
- "items": [
17
+ "create": [
20
18
  {
21
19
  "subject": "Implement config parsing",
22
- "description": "Valid config is parsed and invalid config is rejected"
20
+ "description": "Valid config is parsed and invalid config is rejected",
21
+ "status": "in_progress"
23
22
  },
24
23
  {
25
24
  "subject": "Verify config parsing",
@@ -29,11 +28,19 @@ Single and batch creation use the same shape:
29
28
  }
30
29
  ```
31
30
 
32
- Tasks have three statuses: `pending`, `in_progress`, and `completed`. Creation always starts at `pending`. `update` requires an ID and at least one replacement field; subjects and descriptions remain non-empty. Exactly one task may be `in_progress`; activating another automatically returns the previous active task to `pending` and reports that side effect. Any status can be reopened or corrected. `list` includes every task, ordered as active, pending by ID, then completed by ID.
31
+ ```json
32
+ { "update": [{ "id": 1, "status": "completed" }, { "id": 2, "status": "in_progress" }] }
33
+ ```
33
34
 
34
- Todo v2 intentionally has no dependency graph, owner, metadata, active-form label, tombstone, filtering, pagination, `get`, or `clear`. Keep tasks in intended execution order. When work is blocked, return it to `pending`, create a task that resolves the blocker, and activate that task instead.
35
+ ```json
36
+ { "delete": [3] }
37
+ ```
35
38
 
36
- `create` and `delete` are atomic: invalid input or a missing deletion ID leaves the list unchanged. Deletion removes an item from the current snapshot without reusing its ID. Older conversation branches still contain their earlier snapshots.
39
+ Tasks have three statuses: `pending`, `in_progress`, and `completed`. Exactly one task may be `in_progress`; one activation per call returns every other active task to `pending` and reports that side effect, while a call that tries to activate two tasks is rejected as a real contradiction. Any status can be reopened or corrected. Listing includes every task, ordered as active, pending by ID, then completed by ID.
40
+
41
+ Todo intentionally has no action discriminator, dependency graph, owner, metadata, active-form label, tombstone, filtering, pagination, `get`, or `clear`. Keep tasks in intended execution order. When work is blocked, return it to `pending`, create a task that resolves the blocker, and activate that task instead.
42
+
43
+ The whole patch is validated before anything is applied: invalid input leaves the list unchanged. Within one call, `delete` applies before `update` and `create`, so a same-call deletion frees capacity for the creation. A task cannot be edited twice or be both edited and deleted in one call. Deletion removes an item from the current snapshot without reusing its ID. Older conversation branches still contain their earlier snapshots.
37
44
 
38
45
  ## Presentation
39
46
 
@@ -57,27 +64,32 @@ Todos: 1 in progress, 3 pending, 2 completed
57
64
  Cover invalid redirects and session restoration
58
65
  ```
59
66
 
60
- Consecutive tool calls collapse into the native `todo` transcript group. Collapsed settled rows use result-aware v2 details to show actual created IDs and subjects, update status and automatic demotion, list counts, or deleted IDs. Expanding restores the complete call and native result: a created batch lists each task's ID, subject, and indented description, and a settled deletion names every removed task's ID and subject. Malformed or older details fall back to a bounded call summary.
67
+ Consecutive tool calls collapse into the native `todo` transcript group. Collapsed settled rows use result-aware details to show actual created IDs and subjects, update status and automatic demotion, list counts, deleted IDs, and auto-removed completed tasks. Expanding restores the complete call and native result: a created batch lists each task's ID, subject, and indented description, and a settled deletion names every removed task's ID and subject plus any IDs that were already absent. Malformed or older details fall back to a bounded call summary.
61
68
 
62
69
  ## Limits
63
70
 
64
- - At most 20 current tasks, including completed tasks.
65
- - At most 20 items in one `create` or IDs in one `delete`.
71
+ - At most 20 current tasks. When a call would push the list past 20, the oldest completed tasks are removed automatically to make room; only a list with more than 20 open tasks rejects the call.
72
+ - At most 20 items in one `create`, `update`, or `delete` group.
66
73
  - Subjects are limited to 160 characters.
67
74
  - Descriptions are limited to 500 characters.
68
75
  - Subject and description whitespace is normalized to one line.
69
76
  - Model-facing list output is bounded by those limits; no pagination is needed.
70
77
 
71
- Delete completed or obsolete tasks before the list reaches capacity; `create` past the limit fails with an error that names that remedy.
72
-
73
78
  ## Storage and replay
74
79
 
75
- Todo state is conversation-backed rather than stored in a separate database. Every successful tool result carries a full v2 snapshot:
80
+ Todo state is conversation-backed rather than stored in a separate database. Every successful tool result carries a full snapshot:
76
81
 
77
82
  ```ts
78
83
  {
79
- schemaVersion: 2,
80
- change: { /* create, update, list, or delete */ },
84
+ schemaVersion: 3,
85
+ change: {
86
+ created: [/* new task ids */],
87
+ updated: [/* { id, from, to } status transitions */],
88
+ deleted: [/* { id, subject } */],
89
+ absent: [/* delete ids already gone */],
90
+ evicted: [/* completed tasks auto-removed for capacity */],
91
+ demotedId: 5 /* only when an activation demoted another task */
92
+ },
81
93
  state: {
82
94
  items: [/* complete current list */],
83
95
  nextId: 7
@@ -85,8 +97,8 @@ Todo state is conversation-backed rather than stored in a separate database. Eve
85
97
  }
86
98
  ```
87
99
 
88
- The assistant tool call already stores the arguments, so result details do not duplicate `params` or `action`. The extension keeps one closure-scoped store for its runtime and replays the latest valid v2 snapshot from the current conversation branch on session start and `/tree` navigation. `/reload`, resume, and session replacement create a fresh extension runtime and replay that branch. Compaction does not require a separate replay handler because it does not change the live branch state.
100
+ The assistant tool call already stores the arguments, so result details do not duplicate the patch parameters. The extension keeps one closure-scoped store for its runtime and replays the latest valid v3 snapshot from the current conversation branch on session start and `/tree` navigation. `/reload`, resume, and session replacement create a fresh extension runtime and replay that branch. Compaction does not require a separate replay handler because it does not change the live branch state.
89
101
 
90
- Replay scans tail to head, validates the bounded state, and can fall back past a malformed v2 snapshot. Todo v1 snapshots are intentionally ignored and are not migrated; their historical tool-result text remains in the session transcript.
102
+ Replay scans tail to head, validates the bounded state, and can fall back past a malformed v3 snapshot. Snapshots from older schema versions (v1/v2) are intentionally ignored and are not migrated: restoring a conversation written before v3 starts with an empty list, while the historical tool-result text remains in the session transcript.
91
103
 
92
104
  Tool execution is sequential, so concurrent calls cannot race on the closure store. Validation failures throw before commit, allowing Pi to mark the result as an error while the previous snapshot remains authoritative.
@@ -2299,6 +2299,8 @@ async execute(toolCallId, params) {
2299
2299
 
2300
2300
  **Argument preparation:** `prepareArguments(args)` is optional. If defined, it runs before schema validation and before `execute()`. Use it to mimic an older accepted input shape when pi resumes an older session whose stored tool call arguments no longer match the current schema. Return the object you want validated against `parameters`. Keep the public schema strict. Do not add deprecated compatibility fields to `parameters` just to keep old resumed sessions working.
2301
2301
 
2302
+ **Validation feedback:** after `prepareArguments` runs, pi pre-validates the prepared arguments. When validation fails, the error the model sees names the legal fields next to each offending one (`tasks[0].prompt_extra is not a field; fields at tasks[0]: agent, prompt, description, cwd`) and bounds the echoed arguments to about 2KB, so large prompts are not reflected whole into the context.
2303
+
2302
2304
  Example: an older session may contain an `edit` tool call with top-level `oldText` and `newText`, while the current schema only accepts `edits: [{ oldText, newText }]`.
2303
2305
 
2304
2306
  ```typescript
@@ -2853,18 +2855,29 @@ pi.on("session_shutdown", () => {
2853
2855
 
2854
2856
  Return `{ consume: true }` to stop dispatch immediately. Return `{ data }` to replace the input seen by later listeners and then Pi's focused component; an empty replacement also prevents focused-component handling after listeners finish. In RPC, JSON, and print modes this is a no-op, so guard terminal-specific behavior with `ctx.mode === "tui"`.
2855
2857
 
2856
- Pass `{ scope: "editor" }` as the second argument to receive input only when the main editor has focus, no overlay is visible, and the editor is not showing autocomplete. Custom editors can expose `isShowingAutocomplete()` for that last check. Subscriptions are removed on extension UI teardown and follow TUI mode changes.
2858
+ Subscriptions are removed on extension UI teardown and follow TUI mode changes. For input that should reach you only while the user is typing in the main editor, use `ctx.ui.editorHost.onInput()` below.
2859
+
2860
+ ### Main Editor Host
2861
+
2862
+ `ctx.ui.editorHost` exposes the main editor. It is defined only where Pi renders the interactive editor, so check for it instead of checking the mode:
2863
+
2864
+ ```typescript
2865
+ const host = ctx.ui.editorHost;
2866
+ if (!host) return; // RPC, JSON, and print modes have no main editor
2867
+ const unsubscribeInput = host.onInput((data) => handleKey(data));
2868
+ const cursor = host.getCursor(); // { line, col }, zero-based; undefined if the editor does not expose it
2869
+ ```
2857
2870
 
2858
- ### Editor Submission
2871
+ `host.onInput(handler)` works like `onTerminalInput()` but only receives input when the main editor has focus, no overlay is visible, and the editor is not showing autocomplete. Custom editors can expose `getCursor()` and `isShowingAutocomplete()` for these checks.
2859
2872
 
2860
- `ctx.ui.onEditorSubmit(handler)` intercepts normalized, expanded editor text before command dispatch, editor history, streaming queues, and compaction queues. Enter and the configured follow-up shortcut use the same hook. It is TUI-only and does not intercept programmatic extension messages.
2873
+ `host.onSubmit(handler)` intercepts normalized, expanded editor text before command dispatch, editor history, streaming queues, and compaction queues. Enter and the configured follow-up shortcut use the same hook. It does not intercept programmatic extension messages.
2861
2874
 
2862
2875
  The event has `text`, `mode` (`"steer"` or `"followUp"`), and `kind` (`"prompt"`, `"command"`, or `"bash"`). Known built-in/extension commands, templates, and skills are classified as commands; unknown slash-prefixed text remains a prompt.
2863
2876
 
2864
2877
  Handlers run synchronously in registration order. Return `{ handled: true }` to claim and clear the input, or `{ handled: true, editorText }` to keep a draft. Return `undefined` to pass through. Start asynchronous work after making the synchronous claim. The first claim wins; a thrown error restores the input and stops dispatch instead of sending it to the main agent.
2865
2878
 
2866
2879
  ```typescript
2867
- const unsubscribe = ctx.ui.onEditorSubmit((event) => {
2880
+ const unsubscribe = ctx.ui.editorHost?.onSubmit((event) => {
2868
2881
  if (!panelOpen || event.kind !== "prompt") return undefined;
2869
2882
  if (busy) return { handled: true, editorText: event.text };
2870
2883
  void answerSideQuestion(event.text).catch(showSideError);
@@ -2936,7 +2949,6 @@ ctx.ui.setTitle("pi - my-project");
2936
2949
  // Editor text
2937
2950
  ctx.ui.setEditorText("Prefill text");
2938
2951
  const current = ctx.ui.getEditorText();
2939
- const cursor = ctx.ui.getEditorCursor(); // { line, col }, zero-based; undefined if unsupported
2940
2952
 
2941
2953
  // Paste into editor (triggers paste handling, including collapse for large content)
2942
2954
  ctx.ui.pasteToEditor("pasted content");
@@ -1,6 +1,6 @@
1
1
  # Extension Examples
2
2
 
3
- Example extensions for `@astralyn/pi`.
3
+ Example extensions for pi-coding-agent.
4
4
 
5
5
  ## Usage
6
6
 
@@ -35,13 +35,13 @@ cp permission-gate.ts ~/.pi/agent/extensions/
35
35
  | `question.ts` | Demonstrates `ctx.ui.select()` for asking the user questions with custom UI |
36
36
  | `questionnaire.ts` | Multi-question input with tab bar navigation between questions |
37
37
  | `tool-override.ts` | Override built-in tools (e.g., add logging/access control to `read`) |
38
- | `bash-spawn-hook.ts` | Wraps bash to adjust the command, cwd, and environment before execution |
39
38
  | `dynamic-tools.ts` | Register tools after startup (`session_start`) and at runtime via command, with prompt snippets and tool-specific prompt guidelines |
40
39
  | `structured-output.ts` | Final structured-output tool that returns `terminate: true` so the agent can end on the tool call |
41
40
  | `built-in-tool-renderer.ts` | Custom compact rendering for built-in tools (read, bash, edit, write) while keeping original behavior |
42
41
  | `minimal-mode.ts` | Override built-in tool rendering for minimal display (only tool calls, no output in collapsed mode) |
43
42
  | `truncated-tool.ts` | Wraps ripgrep with proper output truncation (50KB/2000 lines) |
44
43
  | `ssh.ts` | Delegate all tools to a remote machine via SSH using pluggable operations |
44
+ | `subagent/` | Delegate tasks to specialized subagents with isolated context windows |
45
45
 
46
46
  ### Commands & UI
47
47
 
@@ -51,18 +51,14 @@ cp permission-gate.ts ~/.pi/agent/extensions/
51
51
  | `plan-mode/` | Claude Code-style plan mode for read-only exploration with `/plan` command and step tracking |
52
52
  | `tools.ts` | Interactive `/tools` command to enable/disable tools with session persistence |
53
53
  | `handoff.ts` | Transfer context to a new focused session via `/handoff <goal>` |
54
- | `commands.ts` | Lists available slash commands, optionally filtered by source |
55
54
  | `qna.ts` | Extracts questions from last response into editor via `ctx.ui.setEditorText()` |
56
55
  | `status-line.ts` | Shows turn progress in footer via `ctx.ui.setStatus()` with themed colors |
57
- | `border-status-editor.ts` | Custom editor borders with working state, model, context, cwd, and Git branch |
58
56
  | `github-issue-autocomplete.ts` | Adds `#1234` issue completions by stacking a custom autocomplete provider that preloads open issues from `gh issue list` |
59
57
  | `widget-placement.ts` | Shows widgets above and below the editor via `ctx.ui.setWidget()` placement |
60
58
  | `hidden-thinking-label.ts` | Customizes the collapsed thinking label via `ctx.ui.setHiddenThinkingLabel()` |
61
59
  | `working-indicator.ts` | Customizes the streaming working indicator via `ctx.ui.setWorkingIndicator()` |
62
- | `working-message-test.ts` | Tests custom working-message and indicator persistence across loader recreation |
63
60
  | `model-status.ts` | Shows model changes in status bar via `model_select` hook |
64
61
  | `snake.ts` | Snake game with custom UI, keyboard handling, and session persistence |
65
- | `space-invaders.ts` | Space Invaders game with keyboard controls and session persistence |
66
62
  | `tic-tac-toe.ts` | Tic-tac-toe vs the agent with `executionMode: "sequential"` tools to prevent race conditions on shared cursor state |
67
63
  | `send-user-message.ts` | Demonstrates `pi.sendUserMessage()` for sending user messages from extensions |
68
64
  | `timed-confirm.ts` | Demonstrates AbortSignal for auto-dismissing `ctx.ui.confirm()` and `ctx.ui.select()` dialogs |
@@ -81,7 +77,6 @@ cp permission-gate.ts ~/.pi/agent/extensions/
81
77
  | `reload-runtime.ts` | Adds `/reload-runtime` and `reload_runtime` tool showing safe reload flow |
82
78
  | `interactive-shell.ts` | Run interactive commands (vim, htop) with full terminal via `user_bash` hook |
83
79
  | `inline-bash.ts` | Expands `!{command}` patterns in prompts via `input` event transformation |
84
- | `input-transform.ts` | Transforms or handles typed input through the `input` event |
85
80
  | `input-transform-streaming.ts` | Skips expensive input preprocessing for mid-stream steering via `streamingBehavior` |
86
81
 
87
82
  ### Git Integration
@@ -89,7 +84,6 @@ cp permission-gate.ts ~/.pi/agent/extensions/
89
84
  | Extension | Description |
90
85
  |-----------|-------------|
91
86
  | `git-checkpoint.ts` | Creates git stash checkpoints at each turn for code restoration on fork |
92
- | `git-merge-and-resolve.ts` | Fetches and merges the upstream branch after turns, then sends conflicts for resolution |
93
87
  | `auto-commit-on-exit.ts` | Auto-commits on exit using last assistant message for commit message |
94
88
 
95
89
  ### System Prompt & Compaction
@@ -97,9 +91,7 @@ cp permission-gate.ts ~/.pi/agent/extensions/
97
91
  | Extension | Description |
98
92
  |-----------|-------------|
99
93
  | `pirate.ts` | Demonstrates `systemPromptAppend` to dynamically modify system prompt |
100
- | `prompt-customizer.ts` | Adds context-aware guidance based on active tools and skills |
101
94
  | `claude-rules.ts` | Scans `.claude/rules/` folder and lists rules in system prompt |
102
- | `system-prompt-header.ts` | Shows the effective system-prompt length in the status area |
103
95
  | `custom-compaction.ts` | Custom compaction that summarizes entire conversation |
104
96
  | `trigger-compact.ts` | Triggers compaction when context usage exceeds 100k tokens and adds `/trigger-compact` command |
105
97
 
@@ -136,7 +128,6 @@ cp permission-gate.ts ~/.pi/agent/extensions/
136
128
  |-----------|-------------|
137
129
  | `custom-provider-anthropic/` | Custom Anthropic provider with OAuth support and custom streaming implementation |
138
130
  | `custom-provider-gitlab-duo/` | GitLab Duo provider using pi-ai's built-in Anthropic/OpenAI streaming via proxy |
139
- | `provider-payload.ts` | Logs provider request payloads and response headers to `.pi/provider-payload.log` |
140
131
 
141
132
  ### External Dependencies
142
133
 
@@ -150,11 +141,40 @@ cp permission-gate.ts ~/.pi/agent/extensions/
150
141
  See [docs/extensions.md](../../docs/extensions.md) for full documentation.
151
142
 
152
143
  ```typescript
153
- import type { ExtensionAPI } from "@astralyn/pi";
144
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
145
+ import { Type } from "typebox";
154
146
 
155
147
  export default function (pi: ExtensionAPI) {
156
- pi.on("session_start", (_event, ctx) => {
157
- ctx.ui.notify("Extension loaded!", "info");
148
+ // Subscribe to lifecycle events
149
+ pi.on("tool_call", async (event, ctx) => {
150
+ if (event.toolName === "bash" && event.input.command?.includes("rm -rf")) {
151
+ const ok = await ctx.ui.confirm("Dangerous!", "Allow rm -rf?");
152
+ if (!ok) return { block: true, reason: "Blocked by user" };
153
+ }
154
+ });
155
+
156
+ // Register custom tools
157
+ pi.registerTool({
158
+ name: "greet",
159
+ label: "Greeting",
160
+ description: "Generate a greeting",
161
+ parameters: Type.Object({
162
+ name: Type.String({ description: "Name to greet" }),
163
+ }),
164
+ async execute(toolCallId, params, signal, onUpdate, ctx) {
165
+ return {
166
+ content: [{ type: "text", text: `Hello, ${params.name}!` }],
167
+ details: {},
168
+ };
169
+ },
170
+ });
171
+
172
+ // Register commands
173
+ pi.registerCommand("hello", {
174
+ description: "Say hello",
175
+ handler: async (args, ctx) => {
176
+ ctx.ui.notify("Hello!", "info");
177
+ },
158
178
  });
159
179
  }
160
180
  ```
@@ -5,7 +5,7 @@
5
5
  * Uses the last assistant message to generate a commit message.
6
6
  */
7
7
 
8
- import type { ExtensionAPI } from "@astralyn/pi";
8
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
9
9
 
10
10
  export default function (pi: ExtensionAPI) {
11
11
  pi.on("session_shutdown", async (_event, ctx) => {
@@ -7,8 +7,8 @@
7
7
  * pi -e ./bash-spawn-hook.ts
8
8
  */
9
9
 
10
- import type { ExtensionAPI } from "@astralyn/pi";
11
- import { createBashTool } from "@astralyn/pi";
10
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
11
+ import { createBashTool } from "@earendil-works/pi-coding-agent";
12
12
 
13
13
  export default function (pi: ExtensionAPI) {
14
14
  const cwd = process.cwd();
@@ -7,7 +7,7 @@
7
7
  * Usage: /bookmark [label] - bookmark the last assistant message
8
8
  */
9
9
 
10
- import type { ExtensionAPI } from "@astralyn/pi";
10
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
11
11
 
12
12
  export default function (pi: ExtensionAPI) {
13
13
  pi.registerCommand("bookmark", {
@@ -1,4 +1,9 @@
1
- import { CustomEditor, type ExtensionAPI, type ExtensionContext, type KeybindingsManager } from "@astralyn/pi";
1
+ import {
2
+ CustomEditor,
3
+ type ExtensionAPI,
4
+ type ExtensionContext,
5
+ type KeybindingsManager,
6
+ } from "@earendil-works/pi-coding-agent";
2
7
  import type { Component, EditorTheme, TUI } from "@earendil-works/pi-tui";
3
8
  import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
4
9
 
@@ -25,8 +25,8 @@
25
25
  * pi -e ./built-in-tool-renderer.ts
26
26
  */
27
27
 
28
- import type { BashToolDetails, EditToolDetails, ExtensionAPI, ReadToolDetails } from "@astralyn/pi";
29
- import { createBashTool, createEditTool, createReadTool, createWriteTool } from "@astralyn/pi";
28
+ import type { BashToolDetails, EditToolDetails, ExtensionAPI, ReadToolDetails } from "@earendil-works/pi-coding-agent";
29
+ import { createBashTool, createEditTool, createReadTool, createWriteTool } from "@earendil-works/pi-coding-agent";
30
30
  import { Text } from "@earendil-works/pi-tui";
31
31
 
32
32
  export default function (pi: ExtensionAPI) {
@@ -19,7 +19,7 @@
19
19
 
20
20
  import * as fs from "node:fs";
21
21
  import * as path from "node:path";
22
- import type { ExtensionAPI } from "@astralyn/pi";
22
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
23
23
 
24
24
  /**
25
25
  * Recursively find all .md files in a directory
@@ -10,7 +10,7 @@
10
10
  * 3. Use /commands extensions to filter by source
11
11
  */
12
12
 
13
- import type { ExtensionAPI, SlashCommandInfo } from "@astralyn/pi";
13
+ import type { ExtensionAPI, SlashCommandInfo } from "@earendil-works/pi-coding-agent";
14
14
 
15
15
  export default function commandsExtension(pi: ExtensionAPI) {
16
16
  pi.registerCommand("commands", {
@@ -5,7 +5,7 @@
5
5
  * Demonstrates how to cancel session events using the before_* events.
6
6
  */
7
7
 
8
- import type { ExtensionAPI, SessionBeforeSwitchEvent, SessionMessageEntry } from "@astralyn/pi";
8
+ import type { ExtensionAPI, SessionBeforeSwitchEvent, SessionMessageEntry } from "@earendil-works/pi-coding-agent";
9
9
 
10
10
  export default function (pi: ExtensionAPI) {
11
11
  pi.on("session_before_switch", async (event: SessionBeforeSwitchEvent, ctx) => {
@@ -13,9 +13,9 @@
13
13
  * pi --extension examples/extensions/custom-compaction.ts
14
14
  */
15
15
 
16
- import type { ExtensionAPI } from "@astralyn/pi";
17
- import { convertToLlm, serializeConversation } from "@astralyn/pi";
18
16
  import { uuidv7 } from "@earendil-works/pi-ai";
17
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
18
+ import { convertToLlm, serializeConversation } from "@earendil-works/pi-coding-agent";
19
19
 
20
20
  export default function (pi: ExtensionAPI) {
21
21
  pi.on("session_before_compact", async (event, ctx) => {
@@ -8,8 +8,8 @@
8
8
  * Token stats come from ctx.sessionManager/ctx.model (already accessible).
9
9
  */
10
10
 
11
- import type { ExtensionAPI } from "@astralyn/pi";
12
11
  import type { AssistantMessage } from "@earendil-works/pi-ai";
12
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
13
13
  import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
14
14
 
15
15
  export default function (pi: ExtensionAPI) {
@@ -5,8 +5,8 @@
5
5
  * (logo + keybinding hints) with a custom component showing the pi mascot.
6
6
  */
7
7
 
8
- import type { ExtensionAPI, Theme } from "@astralyn/pi";
9
- import { VERSION } from "@astralyn/pi";
8
+ import type { ExtensionAPI, Theme } from "@earendil-works/pi-coding-agent";
9
+ import { VERSION } from "@earendil-works/pi-coding-agent";
10
10
 
11
11
  // --- PI MASCOT ---
12
12
  // Based on pi_mascot.ts - the pi agent character
@@ -8,22 +8,21 @@
8
8
  * - API key support via environment variable
9
9
  * - Two model definitions
10
10
  *
11
- * Usage (from the repository or package root):
11
+ * Usage:
12
12
  * # First install dependencies
13
- * npm install --prefix examples/extensions/custom-provider-anthropic
13
+ * cd packages/coding-agent/examples/extensions/custom-provider && npm install
14
14
  *
15
15
  * # With OAuth (run /login custom-anthropic first)
16
- * pi -e examples/extensions/custom-provider-anthropic
16
+ * pi -e ./packages/coding-agent/examples/extensions/custom-provider
17
17
  *
18
18
  * # With API key
19
- * CUSTOM_ANTHROPIC_API_KEY=sk-ant-... pi -e examples/extensions/custom-provider-anthropic
19
+ * CUSTOM_ANTHROPIC_API_KEY=sk-ant-... pi -e ./packages/coding-agent/examples/extensions/custom-provider
20
20
  *
21
21
  * Then use /model to select custom-anthropic/claude-sonnet-4-5
22
22
  */
23
23
 
24
24
  import Anthropic from "@anthropic-ai/sdk";
25
25
  import type { ContentBlockParam, MessageCreateParamsStreaming } from "@anthropic-ai/sdk/resources/messages.js";
26
- import type { ExtensionAPI } from "@astralyn/pi";
27
26
  import {
28
27
  type Api,
29
28
  type AssistantMessage,
@@ -47,6 +46,7 @@ import {
47
46
  type ToolResultMessage,
48
47
  type TranscriptContext,
49
48
  } from "@earendil-works/pi-ai";
49
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
50
50
 
51
51
  // =============================================================================
52
52
  // OAuth implementation adapted for the legacy extension compatibility interface.
@@ -157,7 +157,7 @@ async function refreshAnthropicToken(credentials: OAuthCredentials, signal: Abor
157
157
  }
158
158
 
159
159
  // =============================================================================
160
- // Streaming Implementation Using Public @earendil-works/pi-ai Exports
160
+ // Streaming Implementation (simplified from packages/ai/src/api/anthropic-messages.ts)
161
161
  // =============================================================================
162
162
 
163
163
  // Claude Code tool names for OAuth stealth mode
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider",
3
- "version": "0.84.3",
3
+ "version": "0.87.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-custom-provider",
9
- "version": "0.84.3",
9
+ "version": "0.87.1",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.52.0"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-anthropic",
3
3
  "private": true,
4
- "version": "0.84.3",
4
+ "version": "0.87.1",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -4,12 +4,11 @@
4
4
  * Provides access to GitLab Duo AI models (Claude and GPT) through GitLab's AI Gateway.
5
5
  * Delegates to pi-ai's built-in Anthropic and OpenAI streaming implementations.
6
6
  *
7
- * Usage (from the repository or package root):
8
- * pi -e examples/extensions/custom-provider-gitlab-duo
7
+ * Usage:
8
+ * pi -e ./packages/coding-agent/examples/extensions/custom-provider-gitlab-duo
9
9
  * # Then /login gitlab-duo, or set GITLAB_TOKEN=glpat-...
10
10
  */
11
11
 
12
- import type { ExtensionAPI } from "@astralyn/pi";
13
12
  import {
14
13
  type Api,
15
14
  type AssistantMessageEventStream,
@@ -23,6 +22,7 @@ import {
23
22
  type ThinkingLevelMap,
24
23
  type TranscriptContext,
25
24
  } from "@earendil-works/pi-ai/compat";
25
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
26
26
 
27
27
  // =============================================================================
28
28
  // Constants
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-gitlab-duo",
3
3
  "private": true,
4
- "version": "0.84.3",
4
+ "version": "0.87.1",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",