@oh-my-pi/pi-coding-agent 6.9.69 → 8.0.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 (502) hide show
  1. package/CHANGELOG.md +219 -51
  2. package/README.md +1 -1
  3. package/docs/hooks.md +2 -2
  4. package/docs/sdk.md +1 -1
  5. package/examples/sdk/04-skills.ts +1 -1
  6. package/package.json +10 -10
  7. package/scripts/format-prompts.ts +143 -0
  8. package/scripts/generate-template.ts +1 -1
  9. package/src/cli/args.ts +3 -3
  10. package/src/cli/config-cli.ts +4 -4
  11. package/src/cli/file-processor.ts +3 -3
  12. package/src/cli/list-models.ts +2 -2
  13. package/src/cli/plugin-cli.ts +3 -3
  14. package/src/cli/session-picker.ts +2 -2
  15. package/src/cli/setup-cli.ts +2 -2
  16. package/src/cli/stats-cli.ts +1 -1
  17. package/src/cli/update-cli.ts +2 -2
  18. package/src/{core → config}/keybindings.ts +1 -1
  19. package/src/{core → config}/model-registry.ts +8 -1
  20. package/src/{core → config}/model-resolver.ts +3 -3
  21. package/src/{core → config}/prompt-templates.ts +2 -2
  22. package/src/{core → config}/settings-manager.ts +6 -6
  23. package/src/{core/cursor/exec-bridge.ts → cursor.ts} +4 -4
  24. package/src/discovery/agents-md.ts +4 -4
  25. package/src/discovery/builtin.ts +17 -17
  26. package/src/discovery/claude.ts +12 -12
  27. package/src/discovery/cline.ts +6 -6
  28. package/src/discovery/codex.ts +21 -21
  29. package/src/discovery/cursor.ts +9 -9
  30. package/src/discovery/gemini.ts +9 -9
  31. package/src/discovery/github.ts +6 -6
  32. package/src/discovery/helpers.ts +4 -4
  33. package/src/discovery/index.ts +16 -16
  34. package/src/discovery/mcp-json.ts +4 -4
  35. package/src/discovery/ssh.ts +4 -4
  36. package/src/discovery/vscode.ts +4 -4
  37. package/src/discovery/windsurf.ts +6 -6
  38. package/src/{core/tools/exa → exa}/company.ts +2 -3
  39. package/src/{core/tools/exa → exa}/index.ts +2 -2
  40. package/src/{core/tools/exa → exa}/linkedin.ts +2 -3
  41. package/src/{core/tools/exa → exa}/mcp-client.ts +2 -2
  42. package/src/{core/tools/exa → exa}/render.ts +3 -3
  43. package/src/{core/tools/exa → exa}/researcher.ts +1 -1
  44. package/src/{core/tools/exa → exa}/search.ts +2 -10
  45. package/src/{core/tools/exa → exa}/websets.ts +1 -1
  46. package/src/{core → exec}/bash-executor.ts +23 -7
  47. package/src/{core → export}/custom-share.ts +1 -1
  48. package/src/{core/export-html → export/html}/index.ts +3 -3
  49. package/src/{core → export}/ttsr.ts +2 -2
  50. package/src/{core → extensibility}/custom-commands/bundled/review/index.ts +4 -4
  51. package/src/{core → extensibility}/custom-commands/loader.ts +3 -3
  52. package/src/{core → extensibility}/custom-commands/types.ts +1 -1
  53. package/src/{core → extensibility}/custom-tools/loader.ts +9 -9
  54. package/src/{core → extensibility}/custom-tools/types.ts +6 -6
  55. package/src/{core → extensibility}/custom-tools/wrapper.ts +1 -1
  56. package/src/{core → extensibility}/extensions/loader.ts +8 -8
  57. package/src/{core → extensibility}/extensions/runner.ts +3 -3
  58. package/src/{core → extensibility}/extensions/types.ts +15 -15
  59. package/src/{core → extensibility}/extensions/wrapper.ts +1 -1
  60. package/src/{core → extensibility}/hooks/index.ts +1 -1
  61. package/src/{core → extensibility}/hooks/loader.ts +7 -7
  62. package/src/{core → extensibility}/hooks/runner.ts +4 -4
  63. package/src/{core → extensibility}/hooks/types.ts +9 -9
  64. package/src/{core → extensibility}/plugins/doctor.ts +1 -1
  65. package/src/{core → extensibility}/plugins/installer.ts +2 -3
  66. package/src/{core → extensibility}/plugins/paths.ts +1 -1
  67. package/src/{core → extensibility}/skills.ts +8 -48
  68. package/src/{core → extensibility}/slash-commands.ts +6 -6
  69. package/src/index.ts +127 -128
  70. package/src/internal-urls/agent-protocol.ts +126 -0
  71. package/src/internal-urls/artifact-protocol.ts +93 -0
  72. package/src/internal-urls/index.ts +28 -0
  73. package/src/internal-urls/json-query.ts +126 -0
  74. package/src/internal-urls/router.ts +69 -0
  75. package/src/internal-urls/rule-protocol.ts +56 -0
  76. package/src/internal-urls/skill-protocol.ts +112 -0
  77. package/src/internal-urls/types.ts +48 -0
  78. package/src/{core/python-executor.ts → ipy/executor.ts} +74 -13
  79. package/src/{core/python-gateway-coordinator.ts → ipy/gateway-coordinator.ts} +40 -270
  80. package/src/{core/python-kernel.ts → ipy/kernel.ts} +38 -10
  81. package/src/{core/python-prelude.py → ipy/prelude.py} +201 -8
  82. package/src/ipy/prelude.ts +3 -0
  83. package/src/{core/tools/lsp → lsp}/client.ts +7 -6
  84. package/src/{core/tools/lsp → lsp}/clients/biome-client.ts +1 -1
  85. package/src/{core/tools/lsp → lsp}/clients/index.ts +1 -1
  86. package/src/{core/tools/lsp → lsp}/clients/lsp-linter-client.ts +4 -4
  87. package/src/{core/tools/lsp → lsp}/config.ts +1 -1
  88. package/src/{core/tools/lsp → lsp}/index.ts +29 -17
  89. package/src/{core/tools/lsp → lsp}/render.ts +2 -2
  90. package/src/{core/tools/lsp → lsp}/types.ts +14 -16
  91. package/src/{core/tools/lsp → lsp}/utils.ts +1 -1
  92. package/src/main.ts +12 -12
  93. package/src/{core/mcp → mcp}/config.ts +8 -8
  94. package/src/{core/mcp → mcp}/loader.ts +5 -6
  95. package/src/{core/mcp → mcp}/manager.ts +2 -2
  96. package/src/{core/mcp → mcp}/tool-bridge.ts +35 -6
  97. package/src/{core/mcp → mcp}/tool-cache.ts +1 -1
  98. package/src/{core/mcp → mcp}/transports/http.ts +7 -1
  99. package/src/{core/mcp → mcp}/transports/stdio.ts +1 -1
  100. package/src/{core/mcp → mcp}/types.ts +1 -1
  101. package/src/migrations.ts +2 -2
  102. package/src/modes/{interactive/components → components}/armin.ts +1 -1
  103. package/src/modes/{interactive/components → components}/assistant-message.ts +1 -1
  104. package/src/modes/{interactive/components → components}/bash-execution.ts +37 -29
  105. package/src/modes/{interactive/components → components}/bordered-loader.ts +1 -1
  106. package/src/modes/{interactive/components → components}/branch-summary-message.ts +2 -2
  107. package/src/modes/{interactive/components → components}/compaction-summary-message.ts +2 -2
  108. package/src/modes/{interactive/components → components}/custom-message.ts +3 -3
  109. package/src/modes/{interactive/components → components}/diff.ts +1 -1
  110. package/src/modes/{interactive/components → components}/dynamic-border.ts +1 -1
  111. package/src/modes/{interactive/components → components}/extensions/extension-dashboard.ts +3 -3
  112. package/src/modes/{interactive/components → components}/extensions/extension-list.ts +2 -2
  113. package/src/modes/{interactive/components → components}/extensions/inspector-panel.ts +1 -1
  114. package/src/modes/{interactive/components → components}/extensions/state-manager.ts +11 -17
  115. package/src/modes/{interactive/components → components}/extensions/types.ts +1 -1
  116. package/src/modes/{interactive/components → components}/footer.ts +3 -3
  117. package/src/modes/{interactive/components → components}/history-search.ts +2 -2
  118. package/src/modes/{interactive/components → components}/hook-editor.ts +1 -1
  119. package/src/modes/{interactive/components → components}/hook-input.ts +1 -1
  120. package/src/modes/{interactive/components → components}/hook-message.ts +3 -3
  121. package/src/modes/{interactive/components → components}/hook-selector.ts +1 -1
  122. package/src/modes/{interactive/components → components}/keybinding-hints.ts +2 -2
  123. package/src/modes/{interactive/components → components}/login-dialog.ts +1 -1
  124. package/src/modes/{interactive/components → components}/model-selector.ts +5 -5
  125. package/src/modes/{interactive/components → components}/oauth-selector.ts +2 -2
  126. package/src/modes/{interactive/components → components}/plugin-settings.ts +3 -3
  127. package/src/modes/{interactive/components → components}/python-execution.ts +35 -24
  128. package/src/modes/{interactive/components → components}/queue-mode-selector.ts +1 -1
  129. package/src/modes/{interactive/components → components}/read-tool-group.ts +2 -2
  130. package/src/modes/{interactive/components → components}/session-selector.ts +3 -3
  131. package/src/modes/{interactive/components → components}/settings-defs.ts +2 -2
  132. package/src/modes/{interactive/components → components}/settings-selector.ts +2 -2
  133. package/src/modes/{interactive/components → components}/show-images-selector.ts +1 -1
  134. package/src/modes/{interactive/components → components}/status-line/segments.ts +2 -2
  135. package/src/modes/{interactive/components → components}/status-line/separators.ts +1 -1
  136. package/src/modes/{interactive/components → components}/status-line/types.ts +2 -2
  137. package/src/modes/{interactive/components → components}/status-line-segment-editor.ts +2 -2
  138. package/src/modes/{interactive/components → components}/status-line.ts +3 -3
  139. package/src/modes/{interactive/components → components}/theme-selector.ts +1 -1
  140. package/src/modes/{interactive/components → components}/thinking-selector.ts +1 -1
  141. package/src/modes/{interactive/components → components}/todo-display.ts +3 -4
  142. package/src/modes/{interactive/components → components}/todo-reminder.ts +2 -2
  143. package/src/modes/{interactive/components → components}/tool-execution.ts +8 -8
  144. package/src/modes/{interactive/components → components}/tree-selector.ts +3 -3
  145. package/src/modes/{interactive/components → components}/ttsr-notification.ts +2 -2
  146. package/src/modes/{interactive/components → components}/user-message-selector.ts +1 -1
  147. package/src/modes/{interactive/components → components}/user-message.ts +1 -1
  148. package/src/modes/{interactive/components → components}/welcome.ts +2 -2
  149. package/src/modes/{interactive/controllers → controllers}/command-controller.ts +381 -30
  150. package/src/modes/{interactive/controllers → controllers}/event-controller.ts +9 -9
  151. package/src/modes/{interactive/controllers → controllers}/extension-ui-controller.ts +8 -8
  152. package/src/modes/{interactive/controllers → controllers}/input-controller.ts +61 -13
  153. package/src/modes/{interactive/controllers → controllers}/selector-controller.ts +16 -16
  154. package/src/modes/index.ts +1 -1
  155. package/src/modes/{interactive/interactive-mode.ts → interactive-mode.ts} +20 -15
  156. package/src/modes/print-mode.ts +1 -1
  157. package/src/modes/rpc/rpc-client.ts +3 -3
  158. package/src/modes/rpc/rpc-mode.ts +3 -3
  159. package/src/modes/rpc/rpc-types.ts +3 -3
  160. package/src/modes/{interactive/theme → theme}/theme.ts +1 -1
  161. package/src/modes/{interactive/types.ts → types.ts} +10 -10
  162. package/src/modes/{interactive/utils → utils}/ui-helpers.ts +20 -27
  163. package/src/{core/tools/patch → patch}/applicator.ts +1 -1
  164. package/src/{core/tools/patch → patch}/diff.ts +1 -1
  165. package/src/{core/tools/patch → patch}/index.ts +31 -36
  166. package/src/{core/tools/patch → patch}/shared.ts +9 -6
  167. package/src/prompts/agents/explore.md +83 -46
  168. package/src/prompts/agents/init.md +9 -4
  169. package/src/prompts/agents/plan.md +8 -7
  170. package/src/prompts/agents/reviewer.md +36 -18
  171. package/src/prompts/agents/task.md +4 -4
  172. package/src/prompts/compaction/branch-summary-preamble.md +0 -1
  173. package/src/prompts/review-request.md +0 -1
  174. package/src/prompts/system/custom-system-prompt.md +2 -14
  175. package/src/prompts/system/file-operations.md +0 -2
  176. package/src/prompts/system/system-prompt.md +182 -171
  177. package/src/prompts/system/web-search.md +26 -0
  178. package/src/prompts/tools/ask.md +31 -24
  179. package/src/prompts/tools/bash.md +20 -17
  180. package/src/prompts/tools/calculator.md +9 -5
  181. package/src/prompts/tools/fetch.md +16 -0
  182. package/src/prompts/tools/find.md +15 -5
  183. package/src/prompts/tools/gemini-image.md +21 -6
  184. package/src/prompts/tools/grep.md +28 -12
  185. package/src/prompts/tools/lsp.md +35 -14
  186. package/src/prompts/tools/patch.md +39 -41
  187. package/src/prompts/tools/python.md +59 -77
  188. package/src/prompts/tools/read.md +23 -22
  189. package/src/prompts/tools/replace.md +19 -12
  190. package/src/prompts/tools/ssh.md +21 -28
  191. package/src/prompts/tools/task.md +54 -44
  192. package/src/prompts/tools/todo-write.md +52 -163
  193. package/src/prompts/tools/web-search.md +16 -9
  194. package/src/prompts/tools/write.md +13 -2
  195. package/src/{core/sdk.ts → sdk.ts} +65 -34
  196. package/src/{core → session}/agent-session.ts +157 -41
  197. package/src/{core → session}/agent-storage.ts +2 -2
  198. package/src/session/artifacts.ts +110 -0
  199. package/src/{core → session}/auth-storage.ts +525 -203
  200. package/src/{core → session}/compaction/branch-summarization.ts +5 -5
  201. package/src/{core → session}/compaction/compaction.ts +6 -6
  202. package/src/{core → session}/compaction/utils.ts +3 -3
  203. package/src/{core → session}/history-storage.ts +1 -1
  204. package/src/{core → session}/messages.ts +6 -8
  205. package/src/{core → session}/session-manager.ts +2 -2
  206. package/src/{core → session}/storage-migration.ts +2 -2
  207. package/src/session/streaming-output.ts +177 -0
  208. package/src/{core/ssh → ssh}/connection-manager.ts +1 -1
  209. package/src/{core/ssh → ssh}/ssh-executor.ts +19 -4
  210. package/src/{core/ssh → ssh}/sshfs-mount.ts +1 -1
  211. package/src/{core/system-prompt.ts → system-prompt.ts} +8 -37
  212. package/src/{core/tools/task → task}/agents.ts +8 -8
  213. package/src/{core/tools/task → task}/commands.ts +5 -6
  214. package/src/{core/tools/task → task}/discovery.ts +3 -3
  215. package/src/{core/tools/task → task}/executor.ts +34 -44
  216. package/src/{core/tools/task → task}/index.ts +206 -50
  217. package/src/{core/tools/task → task}/render.ts +80 -23
  218. package/src/{core/tools/task → task}/subprocess-tool-registry.ts +1 -1
  219. package/src/task/template.ts +47 -0
  220. package/src/{core/tools/task → task}/types.ts +19 -27
  221. package/src/{core/tools/task → task}/worker-protocol.ts +8 -4
  222. package/src/{core/tools/task → task}/worker.ts +34 -29
  223. package/src/task/worktree.ts +166 -0
  224. package/src/{core/tools → tools}/ask.ts +13 -21
  225. package/src/{core/tools → tools}/bash-interceptor.ts +1 -1
  226. package/src/{core/tools → tools}/bash.ts +61 -63
  227. package/src/{core/tools → tools}/calculator.ts +4 -4
  228. package/src/{core/tools → tools}/complete.ts +1 -1
  229. package/src/{core/tools → tools}/context.ts +2 -2
  230. package/src/{core/tools/web-fetch.ts → tools/fetch.ts} +97 -76
  231. package/src/{core/tools → tools}/find.ts +96 -107
  232. package/src/{core/tools → tools}/gemini-image.ts +420 -29
  233. package/src/{core/tools → tools}/grep.ts +155 -164
  234. package/src/{core/tools → tools}/index.ts +63 -56
  235. package/src/tools/list-limit.ts +40 -0
  236. package/src/{core/tools → tools}/ls.ts +44 -35
  237. package/src/{core/tools → tools}/notebook.ts +3 -3
  238. package/src/tools/output-meta.ts +443 -0
  239. package/src/tools/output-utils.ts +63 -0
  240. package/src/{core/tools → tools}/python.ts +106 -89
  241. package/src/tools/read.ts +882 -0
  242. package/src/{core/tools → tools}/render-utils.ts +1 -1
  243. package/src/{core/tools → tools}/renderers.ts +8 -10
  244. package/src/{core/tools → tools}/review.ts +2 -2
  245. package/src/{core/tools → tools}/ssh.ts +56 -59
  246. package/src/{core/tools → tools}/todo-write.ts +12 -23
  247. package/src/tools/tool-errors.ts +95 -0
  248. package/src/tools/tool-result.ts +92 -0
  249. package/src/{core/tools → tools}/truncate.ts +2 -2
  250. package/src/{core/tools → tools}/write.ts +15 -13
  251. package/src/utils/changelog.ts +1 -1
  252. package/src/{core → utils}/file-mentions.ts +4 -4
  253. package/src/utils/image-convert.ts +1 -1
  254. package/src/utils/image-resize.ts +1 -1
  255. package/src/utils/shell.ts +1 -1
  256. package/src/{core → utils}/title-generator.ts +4 -4
  257. package/src/utils/tools-manager.ts +1 -1
  258. package/src/{core/tools/web-scrapers → web/scrapers}/choosealicense.ts +1 -1
  259. package/src/{core/tools/web-scrapers → web/scrapers}/twitter.ts +3 -2
  260. package/src/{core/tools/web-scrapers → web/scrapers}/types.ts +4 -2
  261. package/src/{core/tools/web-scrapers → web/scrapers}/utils.ts +1 -1
  262. package/src/{core/tools/web-scrapers → web/scrapers}/youtube.ts +14 -13
  263. package/src/{core/tools/web-search → web/search}/auth.ts +4 -4
  264. package/src/{core/tools/web-search → web/search}/index.ts +22 -71
  265. package/src/{core/tools/web-search → web/search}/providers/anthropic.ts +7 -10
  266. package/src/{core/tools/web-search → web/search}/providers/exa.ts +2 -2
  267. package/src/{core/tools/web-search → web/search}/providers/perplexity.ts +4 -16
  268. package/src/{core/tools/web-search → web/search}/render.ts +3 -3
  269. package/scripts/migrate-sessions.sh +0 -93
  270. package/src/core/index.ts +0 -56
  271. package/src/core/python-prelude.ts +0 -3
  272. package/src/core/ssh-executor.ts +0 -5
  273. package/src/core/streaming-output.ts +0 -115
  274. package/src/core/tools/output.ts +0 -519
  275. package/src/core/tools/read.ts +0 -717
  276. package/src/core/tools/task/template.ts +0 -37
  277. package/src/prompts/tools/output.md +0 -47
  278. package/src/prompts/tools/web-fetch.md +0 -9
  279. /package/src/{core/tools/exa → exa}/types.ts +0 -0
  280. /package/src/{core → exec}/exec.ts +0 -0
  281. /package/src/{core/export-html → export/html}/template.css +0 -0
  282. /package/src/{core/export-html → export/html}/template.generated.ts +0 -0
  283. /package/src/{core/export-html → export/html}/template.html +0 -0
  284. /package/src/{core/export-html → export/html}/template.js +0 -0
  285. /package/src/{core/export-html → export/html}/template.macro.ts +0 -0
  286. /package/src/{core/export-html → export/html}/vendor/highlight.min.js +0 -0
  287. /package/src/{core/export-html → export/html}/vendor/marked.min.js +0 -0
  288. /package/src/{core → extensibility}/custom-commands/index.ts +0 -0
  289. /package/src/{core → extensibility}/custom-tools/index.ts +0 -0
  290. /package/src/{core → extensibility}/extensions/index.ts +0 -0
  291. /package/src/{core → extensibility}/hooks/tool-wrapper.ts +0 -0
  292. /package/src/{core → extensibility}/plugins/index.ts +0 -0
  293. /package/src/{core → extensibility}/plugins/loader.ts +0 -0
  294. /package/src/{core → extensibility}/plugins/manager.ts +0 -0
  295. /package/src/{core → extensibility}/plugins/parser.ts +0 -0
  296. /package/src/{core → extensibility}/plugins/types.ts +0 -0
  297. /package/src/{core/python-modules.ts → ipy/modules.ts} +0 -0
  298. /package/src/{core/tools/lsp → lsp}/defaults.json +0 -0
  299. /package/src/{core/tools/lsp → lsp}/edits.ts +0 -0
  300. /package/src/{core/tools/lsp → lsp}/lspmux.ts +0 -0
  301. /package/src/{core/tools/lsp → lsp}/rust-analyzer.ts +0 -0
  302. /package/src/{core/mcp → mcp}/client.ts +0 -0
  303. /package/src/{core/mcp → mcp}/index.ts +0 -0
  304. /package/src/{core/mcp → mcp}/json-rpc.ts +0 -0
  305. /package/src/{core/mcp → mcp}/transports/index.ts +0 -0
  306. /package/src/modes/{interactive/components → components}/countdown-timer.ts +0 -0
  307. /package/src/modes/{interactive/components → components}/custom-editor.ts +0 -0
  308. /package/src/modes/{interactive/components → components}/extensions/index.ts +0 -0
  309. /package/src/modes/{interactive/components → components}/index.ts +0 -0
  310. /package/src/modes/{interactive/components → components}/status-line/index.ts +0 -0
  311. /package/src/modes/{interactive/components → components}/status-line/presets.ts +0 -0
  312. /package/src/modes/{interactive/components → components}/visual-truncate.ts +0 -0
  313. /package/src/modes/{interactive/theme → theme}/dark.json +0 -0
  314. /package/src/modes/{interactive/theme → theme}/defaults/alabaster.json +0 -0
  315. /package/src/modes/{interactive/theme → theme}/defaults/amethyst.json +0 -0
  316. /package/src/modes/{interactive/theme → theme}/defaults/anthracite.json +0 -0
  317. /package/src/modes/{interactive/theme → theme}/defaults/basalt.json +0 -0
  318. /package/src/modes/{interactive/theme → theme}/defaults/birch.json +0 -0
  319. /package/src/modes/{interactive/theme → theme}/defaults/dark-abyss.json +0 -0
  320. /package/src/modes/{interactive/theme → theme}/defaults/dark-arctic.json +0 -0
  321. /package/src/modes/{interactive/theme → theme}/defaults/dark-aurora.json +0 -0
  322. /package/src/modes/{interactive/theme → theme}/defaults/dark-catppuccin.json +0 -0
  323. /package/src/modes/{interactive/theme → theme}/defaults/dark-cavern.json +0 -0
  324. /package/src/modes/{interactive/theme → theme}/defaults/dark-copper.json +0 -0
  325. /package/src/modes/{interactive/theme → theme}/defaults/dark-cosmos.json +0 -0
  326. /package/src/modes/{interactive/theme → theme}/defaults/dark-cyberpunk.json +0 -0
  327. /package/src/modes/{interactive/theme → theme}/defaults/dark-dracula.json +0 -0
  328. /package/src/modes/{interactive/theme → theme}/defaults/dark-eclipse.json +0 -0
  329. /package/src/modes/{interactive/theme → theme}/defaults/dark-ember.json +0 -0
  330. /package/src/modes/{interactive/theme → theme}/defaults/dark-equinox.json +0 -0
  331. /package/src/modes/{interactive/theme → theme}/defaults/dark-forest.json +0 -0
  332. /package/src/modes/{interactive/theme → theme}/defaults/dark-github.json +0 -0
  333. /package/src/modes/{interactive/theme → theme}/defaults/dark-gruvbox.json +0 -0
  334. /package/src/modes/{interactive/theme → theme}/defaults/dark-lavender.json +0 -0
  335. /package/src/modes/{interactive/theme → theme}/defaults/dark-lunar.json +0 -0
  336. /package/src/modes/{interactive/theme → theme}/defaults/dark-midnight.json +0 -0
  337. /package/src/modes/{interactive/theme → theme}/defaults/dark-monochrome.json +0 -0
  338. /package/src/modes/{interactive/theme → theme}/defaults/dark-monokai.json +0 -0
  339. /package/src/modes/{interactive/theme → theme}/defaults/dark-nebula.json +0 -0
  340. /package/src/modes/{interactive/theme → theme}/defaults/dark-nord.json +0 -0
  341. /package/src/modes/{interactive/theme → theme}/defaults/dark-ocean.json +0 -0
  342. /package/src/modes/{interactive/theme → theme}/defaults/dark-one.json +0 -0
  343. /package/src/modes/{interactive/theme → theme}/defaults/dark-rainforest.json +0 -0
  344. /package/src/modes/{interactive/theme → theme}/defaults/dark-reef.json +0 -0
  345. /package/src/modes/{interactive/theme → theme}/defaults/dark-retro.json +0 -0
  346. /package/src/modes/{interactive/theme → theme}/defaults/dark-rose-pine.json +0 -0
  347. /package/src/modes/{interactive/theme → theme}/defaults/dark-sakura.json +0 -0
  348. /package/src/modes/{interactive/theme → theme}/defaults/dark-slate.json +0 -0
  349. /package/src/modes/{interactive/theme → theme}/defaults/dark-solarized.json +0 -0
  350. /package/src/modes/{interactive/theme → theme}/defaults/dark-solstice.json +0 -0
  351. /package/src/modes/{interactive/theme → theme}/defaults/dark-starfall.json +0 -0
  352. /package/src/modes/{interactive/theme → theme}/defaults/dark-sunset.json +0 -0
  353. /package/src/modes/{interactive/theme → theme}/defaults/dark-swamp.json +0 -0
  354. /package/src/modes/{interactive/theme → theme}/defaults/dark-synthwave.json +0 -0
  355. /package/src/modes/{interactive/theme → theme}/defaults/dark-taiga.json +0 -0
  356. /package/src/modes/{interactive/theme → theme}/defaults/dark-terminal.json +0 -0
  357. /package/src/modes/{interactive/theme → theme}/defaults/dark-tokyo-night.json +0 -0
  358. /package/src/modes/{interactive/theme → theme}/defaults/dark-tundra.json +0 -0
  359. /package/src/modes/{interactive/theme → theme}/defaults/dark-twilight.json +0 -0
  360. /package/src/modes/{interactive/theme → theme}/defaults/dark-volcanic.json +0 -0
  361. /package/src/modes/{interactive/theme → theme}/defaults/graphite.json +0 -0
  362. /package/src/modes/{interactive/theme → theme}/defaults/index.ts +0 -0
  363. /package/src/modes/{interactive/theme → theme}/defaults/light-arctic.json +0 -0
  364. /package/src/modes/{interactive/theme → theme}/defaults/light-aurora-day.json +0 -0
  365. /package/src/modes/{interactive/theme → theme}/defaults/light-canyon.json +0 -0
  366. /package/src/modes/{interactive/theme → theme}/defaults/light-catppuccin.json +0 -0
  367. /package/src/modes/{interactive/theme → theme}/defaults/light-cirrus.json +0 -0
  368. /package/src/modes/{interactive/theme → theme}/defaults/light-coral.json +0 -0
  369. /package/src/modes/{interactive/theme → theme}/defaults/light-cyberpunk.json +0 -0
  370. /package/src/modes/{interactive/theme → theme}/defaults/light-dawn.json +0 -0
  371. /package/src/modes/{interactive/theme → theme}/defaults/light-dunes.json +0 -0
  372. /package/src/modes/{interactive/theme → theme}/defaults/light-eucalyptus.json +0 -0
  373. /package/src/modes/{interactive/theme → theme}/defaults/light-forest.json +0 -0
  374. /package/src/modes/{interactive/theme → theme}/defaults/light-frost.json +0 -0
  375. /package/src/modes/{interactive/theme → theme}/defaults/light-github.json +0 -0
  376. /package/src/modes/{interactive/theme → theme}/defaults/light-glacier.json +0 -0
  377. /package/src/modes/{interactive/theme → theme}/defaults/light-gruvbox.json +0 -0
  378. /package/src/modes/{interactive/theme → theme}/defaults/light-haze.json +0 -0
  379. /package/src/modes/{interactive/theme → theme}/defaults/light-honeycomb.json +0 -0
  380. /package/src/modes/{interactive/theme → theme}/defaults/light-lagoon.json +0 -0
  381. /package/src/modes/{interactive/theme → theme}/defaults/light-lavender.json +0 -0
  382. /package/src/modes/{interactive/theme → theme}/defaults/light-meadow.json +0 -0
  383. /package/src/modes/{interactive/theme → theme}/defaults/light-mint.json +0 -0
  384. /package/src/modes/{interactive/theme → theme}/defaults/light-monochrome.json +0 -0
  385. /package/src/modes/{interactive/theme → theme}/defaults/light-ocean.json +0 -0
  386. /package/src/modes/{interactive/theme → theme}/defaults/light-one.json +0 -0
  387. /package/src/modes/{interactive/theme → theme}/defaults/light-opal.json +0 -0
  388. /package/src/modes/{interactive/theme → theme}/defaults/light-orchard.json +0 -0
  389. /package/src/modes/{interactive/theme → theme}/defaults/light-paper.json +0 -0
  390. /package/src/modes/{interactive/theme → theme}/defaults/light-prism.json +0 -0
  391. /package/src/modes/{interactive/theme → theme}/defaults/light-retro.json +0 -0
  392. /package/src/modes/{interactive/theme → theme}/defaults/light-sand.json +0 -0
  393. /package/src/modes/{interactive/theme → theme}/defaults/light-savanna.json +0 -0
  394. /package/src/modes/{interactive/theme → theme}/defaults/light-solarized.json +0 -0
  395. /package/src/modes/{interactive/theme → theme}/defaults/light-soleil.json +0 -0
  396. /package/src/modes/{interactive/theme → theme}/defaults/light-sunset.json +0 -0
  397. /package/src/modes/{interactive/theme → theme}/defaults/light-synthwave.json +0 -0
  398. /package/src/modes/{interactive/theme → theme}/defaults/light-tokyo-night.json +0 -0
  399. /package/src/modes/{interactive/theme → theme}/defaults/light-wetland.json +0 -0
  400. /package/src/modes/{interactive/theme → theme}/defaults/light-zenith.json +0 -0
  401. /package/src/modes/{interactive/theme → theme}/defaults/limestone.json +0 -0
  402. /package/src/modes/{interactive/theme → theme}/defaults/mahogany.json +0 -0
  403. /package/src/modes/{interactive/theme → theme}/defaults/marble.json +0 -0
  404. /package/src/modes/{interactive/theme → theme}/defaults/obsidian.json +0 -0
  405. /package/src/modes/{interactive/theme → theme}/defaults/onyx.json +0 -0
  406. /package/src/modes/{interactive/theme → theme}/defaults/pearl.json +0 -0
  407. /package/src/modes/{interactive/theme → theme}/defaults/porcelain.json +0 -0
  408. /package/src/modes/{interactive/theme → theme}/defaults/quartz.json +0 -0
  409. /package/src/modes/{interactive/theme → theme}/defaults/sandstone.json +0 -0
  410. /package/src/modes/{interactive/theme → theme}/defaults/titanium.json +0 -0
  411. /package/src/modes/{interactive/theme → theme}/light.json +0 -0
  412. /package/src/modes/{interactive/theme → theme}/theme-schema.json +0 -0
  413. /package/src/{core/tools/patch → patch}/fuzzy.ts +0 -0
  414. /package/src/{core/tools/patch → patch}/normalize.ts +0 -0
  415. /package/src/{core/tools/patch → patch}/normative.ts +0 -0
  416. /package/src/{core/tools/patch → patch}/parser.ts +0 -0
  417. /package/src/{core/tools/patch → patch}/types.ts +0 -0
  418. /package/src/{core → session}/compaction/index.ts +0 -0
  419. /package/src/{core → session}/session-storage.ts +0 -0
  420. /package/src/{core/tools/task → task}/name-generator.ts +0 -0
  421. /package/src/{core/tools/task → task}/omp-command.ts +0 -0
  422. /package/src/{core/tools/task → task}/parallel.ts +0 -0
  423. /package/src/{core/tools → tools}/jtd-to-json-schema.ts +0 -0
  424. /package/src/{core/tools → tools}/path-utils.ts +0 -0
  425. /package/src/{core → utils}/event-bus.ts +0 -0
  426. /package/src/{core → utils}/frontmatter.ts +0 -0
  427. /package/src/{core → utils}/terminal-notify.ts +0 -0
  428. /package/src/{core → utils}/timings.ts +0 -0
  429. /package/src/{core → utils}/utils.ts +0 -0
  430. /package/src/{core/tools/web-scrapers → web/scrapers}/artifacthub.ts +0 -0
  431. /package/src/{core/tools/web-scrapers → web/scrapers}/arxiv.ts +0 -0
  432. /package/src/{core/tools/web-scrapers → web/scrapers}/aur.ts +0 -0
  433. /package/src/{core/tools/web-scrapers → web/scrapers}/biorxiv.ts +0 -0
  434. /package/src/{core/tools/web-scrapers → web/scrapers}/bluesky.ts +0 -0
  435. /package/src/{core/tools/web-scrapers → web/scrapers}/brew.ts +0 -0
  436. /package/src/{core/tools/web-scrapers → web/scrapers}/cheatsh.ts +0 -0
  437. /package/src/{core/tools/web-scrapers → web/scrapers}/chocolatey.ts +0 -0
  438. /package/src/{core/tools/web-scrapers → web/scrapers}/cisa-kev.ts +0 -0
  439. /package/src/{core/tools/web-scrapers → web/scrapers}/clojars.ts +0 -0
  440. /package/src/{core/tools/web-scrapers → web/scrapers}/coingecko.ts +0 -0
  441. /package/src/{core/tools/web-scrapers → web/scrapers}/crates-io.ts +0 -0
  442. /package/src/{core/tools/web-scrapers → web/scrapers}/crossref.ts +0 -0
  443. /package/src/{core/tools/web-scrapers → web/scrapers}/devto.ts +0 -0
  444. /package/src/{core/tools/web-scrapers → web/scrapers}/discogs.ts +0 -0
  445. /package/src/{core/tools/web-scrapers → web/scrapers}/discourse.ts +0 -0
  446. /package/src/{core/tools/web-scrapers → web/scrapers}/dockerhub.ts +0 -0
  447. /package/src/{core/tools/web-scrapers → web/scrapers}/fdroid.ts +0 -0
  448. /package/src/{core/tools/web-scrapers → web/scrapers}/firefox-addons.ts +0 -0
  449. /package/src/{core/tools/web-scrapers → web/scrapers}/flathub.ts +0 -0
  450. /package/src/{core/tools/web-scrapers → web/scrapers}/github-gist.ts +0 -0
  451. /package/src/{core/tools/web-scrapers → web/scrapers}/github.ts +0 -0
  452. /package/src/{core/tools/web-scrapers → web/scrapers}/gitlab.ts +0 -0
  453. /package/src/{core/tools/web-scrapers → web/scrapers}/go-pkg.ts +0 -0
  454. /package/src/{core/tools/web-scrapers → web/scrapers}/hackage.ts +0 -0
  455. /package/src/{core/tools/web-scrapers → web/scrapers}/hackernews.ts +0 -0
  456. /package/src/{core/tools/web-scrapers → web/scrapers}/hex.ts +0 -0
  457. /package/src/{core/tools/web-scrapers → web/scrapers}/huggingface.ts +0 -0
  458. /package/src/{core/tools/web-scrapers → web/scrapers}/iacr.ts +0 -0
  459. /package/src/{core/tools/web-scrapers → web/scrapers}/index.ts +0 -0
  460. /package/src/{core/tools/web-scrapers → web/scrapers}/jetbrains-marketplace.ts +0 -0
  461. /package/src/{core/tools/web-scrapers → web/scrapers}/lemmy.ts +0 -0
  462. /package/src/{core/tools/web-scrapers → web/scrapers}/lobsters.ts +0 -0
  463. /package/src/{core/tools/web-scrapers → web/scrapers}/mastodon.ts +0 -0
  464. /package/src/{core/tools/web-scrapers → web/scrapers}/maven.ts +0 -0
  465. /package/src/{core/tools/web-scrapers → web/scrapers}/mdn.ts +0 -0
  466. /package/src/{core/tools/web-scrapers → web/scrapers}/metacpan.ts +0 -0
  467. /package/src/{core/tools/web-scrapers → web/scrapers}/musicbrainz.ts +0 -0
  468. /package/src/{core/tools/web-scrapers → web/scrapers}/npm.ts +0 -0
  469. /package/src/{core/tools/web-scrapers → web/scrapers}/nuget.ts +0 -0
  470. /package/src/{core/tools/web-scrapers → web/scrapers}/nvd.ts +0 -0
  471. /package/src/{core/tools/web-scrapers → web/scrapers}/ollama.ts +0 -0
  472. /package/src/{core/tools/web-scrapers → web/scrapers}/open-vsx.ts +0 -0
  473. /package/src/{core/tools/web-scrapers → web/scrapers}/opencorporates.ts +0 -0
  474. /package/src/{core/tools/web-scrapers → web/scrapers}/openlibrary.ts +0 -0
  475. /package/src/{core/tools/web-scrapers → web/scrapers}/orcid.ts +0 -0
  476. /package/src/{core/tools/web-scrapers → web/scrapers}/osv.ts +0 -0
  477. /package/src/{core/tools/web-scrapers → web/scrapers}/packagist.ts +0 -0
  478. /package/src/{core/tools/web-scrapers → web/scrapers}/pub-dev.ts +0 -0
  479. /package/src/{core/tools/web-scrapers → web/scrapers}/pubmed.ts +0 -0
  480. /package/src/{core/tools/web-scrapers → web/scrapers}/pypi.ts +0 -0
  481. /package/src/{core/tools/web-scrapers → web/scrapers}/rawg.ts +0 -0
  482. /package/src/{core/tools/web-scrapers → web/scrapers}/readthedocs.ts +0 -0
  483. /package/src/{core/tools/web-scrapers → web/scrapers}/reddit.ts +0 -0
  484. /package/src/{core/tools/web-scrapers → web/scrapers}/repology.ts +0 -0
  485. /package/src/{core/tools/web-scrapers → web/scrapers}/rfc.ts +0 -0
  486. /package/src/{core/tools/web-scrapers → web/scrapers}/rubygems.ts +0 -0
  487. /package/src/{core/tools/web-scrapers → web/scrapers}/searchcode.ts +0 -0
  488. /package/src/{core/tools/web-scrapers → web/scrapers}/sec-edgar.ts +0 -0
  489. /package/src/{core/tools/web-scrapers → web/scrapers}/semantic-scholar.ts +0 -0
  490. /package/src/{core/tools/web-scrapers → web/scrapers}/snapcraft.ts +0 -0
  491. /package/src/{core/tools/web-scrapers → web/scrapers}/sourcegraph.ts +0 -0
  492. /package/src/{core/tools/web-scrapers → web/scrapers}/spdx.ts +0 -0
  493. /package/src/{core/tools/web-scrapers → web/scrapers}/spotify.ts +0 -0
  494. /package/src/{core/tools/web-scrapers → web/scrapers}/stackoverflow.ts +0 -0
  495. /package/src/{core/tools/web-scrapers → web/scrapers}/terraform.ts +0 -0
  496. /package/src/{core/tools/web-scrapers → web/scrapers}/tldr.ts +0 -0
  497. /package/src/{core/tools/web-scrapers → web/scrapers}/vimeo.ts +0 -0
  498. /package/src/{core/tools/web-scrapers → web/scrapers}/vscode-marketplace.ts +0 -0
  499. /package/src/{core/tools/web-scrapers → web/scrapers}/w3c.ts +0 -0
  500. /package/src/{core/tools/web-scrapers → web/scrapers}/wikidata.ts +0 -0
  501. /package/src/{core/tools/web-scrapers → web/scrapers}/wikipedia.ts +0 -0
  502. /package/src/{core/tools/web-search → web/search}/types.ts +0 -0
@@ -3,12 +3,12 @@ import { delimiter, join } from "node:path";
3
3
  import { logger } from "@oh-my-pi/pi-utils";
4
4
  import { $, type Subprocess } from "bun";
5
5
  import { nanoid } from "nanoid";
6
- import { getShellConfig, killProcessTree } from "../utils/shell";
7
- import { getOrCreateSnapshot } from "../utils/shell-snapshot";
8
- import { acquireSharedGateway, releaseSharedGateway } from "./python-gateway-coordinator";
9
- import { loadPythonModules } from "./python-modules";
10
- import { PYTHON_PRELUDE } from "./python-prelude";
11
- import { htmlToBasicMarkdown } from "./tools/web-scrapers/types";
6
+ import { getShellConfig, killProcessTree } from "$c/utils/shell";
7
+ import { getOrCreateSnapshot } from "$c/utils/shell-snapshot";
8
+ import { htmlToBasicMarkdown } from "$c/web/scrapers/types";
9
+ import { acquireSharedGateway, releaseSharedGateway } from "./gateway-coordinator";
10
+ import { loadPythonModules } from "./modules";
11
+ import { PYTHON_PRELUDE } from "./prelude";
12
12
 
13
13
  const TEXT_ENCODER = new TextEncoder();
14
14
  const TEXT_DECODER = new TextDecoder();
@@ -511,7 +511,7 @@ export class PythonKernel {
511
511
 
512
512
  const externalConfig = getExternalGatewayConfig();
513
513
  if (externalConfig) {
514
- return PythonKernel.startWithExternalGateway(externalConfig, options.cwd);
514
+ return PythonKernel.startWithExternalGateway(externalConfig, options.cwd, options.env);
515
515
  }
516
516
 
517
517
  // Try shared gateway first (unless explicitly disabled)
@@ -519,7 +519,7 @@ export class PythonKernel {
519
519
  try {
520
520
  const sharedResult = await acquireSharedGateway(options.cwd);
521
521
  if (sharedResult) {
522
- return PythonKernel.startWithSharedGateway(sharedResult.url, options.cwd);
522
+ return PythonKernel.startWithSharedGateway(sharedResult.url, options.cwd, options.env);
523
523
  }
524
524
  } catch (err) {
525
525
  logger.warn("Failed to acquire shared gateway, falling back to local", {
@@ -531,7 +531,11 @@ export class PythonKernel {
531
531
  return PythonKernel.startWithLocalGateway(options);
532
532
  }
533
533
 
534
- private static async startWithExternalGateway(config: ExternalGatewayConfig, cwd: string): Promise<PythonKernel> {
534
+ private static async startWithExternalGateway(
535
+ config: ExternalGatewayConfig,
536
+ cwd: string,
537
+ env?: Record<string, string | undefined>,
538
+ ): Promise<PythonKernel> {
535
539
  const headers: Record<string, string> = { "Content-Type": "application/json" };
536
540
  if (config.token) {
537
541
  headers.Authorization = `token ${config.token}`;
@@ -554,6 +558,7 @@ export class PythonKernel {
554
558
 
555
559
  try {
556
560
  await kernel.connectWebSocket();
561
+ await kernel.initializeKernelEnvironment(cwd, env);
557
562
  kernel.startHeartbeat();
558
563
  const preludeResult = await kernel.execute(PYTHON_PRELUDE, { silent: true, storeHistory: false });
559
564
  if (preludeResult.cancelled || preludeResult.status === "error") {
@@ -567,7 +572,11 @@ export class PythonKernel {
567
572
  }
568
573
  }
569
574
 
570
- private static async startWithSharedGateway(gatewayUrl: string, cwd: string): Promise<PythonKernel> {
575
+ private static async startWithSharedGateway(
576
+ gatewayUrl: string,
577
+ cwd: string,
578
+ env?: Record<string, string | undefined>,
579
+ ): Promise<PythonKernel> {
571
580
  const createResponse = await fetch(`${gatewayUrl}/api/kernels`, {
572
581
  method: "POST",
573
582
  headers: { "Content-Type": "application/json" },
@@ -586,6 +595,7 @@ export class PythonKernel {
586
595
 
587
596
  try {
588
597
  await kernel.connectWebSocket();
598
+ await kernel.initializeKernelEnvironment(cwd, env);
589
599
  kernel.startHeartbeat();
590
600
  const preludeResult = await kernel.execute(PYTHON_PRELUDE, { silent: true, storeHistory: false });
591
601
  if (preludeResult.cancelled || preludeResult.status === "error") {
@@ -702,6 +712,7 @@ export class PythonKernel {
702
712
 
703
713
  try {
704
714
  await kernel.connectWebSocket();
715
+ await kernel.initializeKernelEnvironment(options.cwd, options.env);
705
716
  kernel.startHeartbeat();
706
717
  const preludeResult = await kernel.execute(PYTHON_PRELUDE, { silent: true, storeHistory: false });
707
718
  if (preludeResult.cancelled || preludeResult.status === "error") {
@@ -802,6 +813,23 @@ export class PythonKernel {
802
813
  return promise;
803
814
  }
804
815
 
816
+ private async initializeKernelEnvironment(cwd: string, env?: Record<string, string | undefined>): Promise<void> {
817
+ const envEntries = Object.entries(env ?? {}).filter(([, value]) => value !== undefined);
818
+ const envPayload = Object.fromEntries(envEntries);
819
+ const initScript = [
820
+ "import os, sys",
821
+ `__omp_cwd = ${JSON.stringify(cwd)}`,
822
+ "os.chdir(__omp_cwd)",
823
+ `__omp_env = ${JSON.stringify(envPayload)}`,
824
+ "for __omp_key, __omp_val in __omp_env.items():\n os.environ[__omp_key] = __omp_val",
825
+ "if __omp_cwd not in sys.path:\n sys.path.insert(0, __omp_cwd)",
826
+ ].join("\n");
827
+ const result = await this.execute(initScript, { silent: true, storeHistory: false });
828
+ if (result.cancelled || result.status === "error") {
829
+ throw new Error("Failed to initialize Python kernel environment");
830
+ }
831
+ }
832
+
805
833
  private abortPendingExecutions(reason: string): void {
806
834
  if (this.#pendingExecutions.size === 0) return;
807
835
  for (const cancel of this.#pendingExecutions.values()) {
@@ -24,14 +24,6 @@ if "__omp_prelude_loaded__" not in globals():
24
24
  _emit_status("pwd", path=str(p))
25
25
  return p
26
26
 
27
- @_category("Navigation")
28
- def cd(path: str | Path) -> Path:
29
- """Change directory."""
30
- p = Path(path).expanduser().resolve()
31
- os.chdir(p)
32
- _emit_status("cd", path=str(p))
33
- return p
34
-
35
27
  @_category("Shell")
36
28
  def env(key: str | None = None, value: str | None = None):
37
29
  """Get/set environment variables."""
@@ -914,6 +906,207 @@ if "__omp_prelude_loaded__" not in globals():
914
906
  _emit_status("git_has_changes", has_changes=has_changes)
915
907
  return has_changes
916
908
 
909
+ @_category("Agent")
910
+ def output(
911
+ *ids: str,
912
+ format: str = "raw",
913
+ query: str | None = None,
914
+ offset: int | None = None,
915
+ limit: int | None = None,
916
+ ) -> str | dict | list[dict]:
917
+ """Read task/agent output by ID. Returns text or JSON depending on format.
918
+
919
+ Args:
920
+ *ids: Output IDs to read (e.g., 'explore_0', 'reviewer_1')
921
+ format: 'raw' (default), 'json' (dict with metadata), 'stripped' (no ANSI)
922
+ query: jq-like query for JSON outputs (e.g., '.endpoints[0].file')
923
+ offset: Line number to start reading from (1-indexed)
924
+ limit: Maximum number of lines to read
925
+
926
+ Returns:
927
+ Single ID: str (format='raw'/'stripped') or dict (format='json')
928
+ Multiple IDs: list of dict with 'id' and 'content'/'data' keys
929
+
930
+ Examples:
931
+ output('explore_0') # Read as raw text
932
+ output('reviewer_0', format='json') # Read with metadata
933
+ output('explore_0', query='.files[0]') # Extract JSON field
934
+ output('explore_0', offset=10, limit=20) # Lines 10-29
935
+ output('explore_0', 'reviewer_1') # Read multiple outputs
936
+ """
937
+ session_file = os.environ.get("OMP_SESSION_FILE")
938
+ if not session_file:
939
+ _emit_status("output", error="No session file available")
940
+ raise RuntimeError("No session - output artifacts unavailable")
941
+
942
+ artifacts_dir = session_file.rsplit(".", 1)[0] # Strip .jsonl extension
943
+ if not Path(artifacts_dir).exists():
944
+ _emit_status("output", error="Artifacts directory not found", path=artifacts_dir)
945
+ raise RuntimeError(f"No artifacts directory found: {artifacts_dir}")
946
+
947
+ if not ids:
948
+ _emit_status("output", error="No IDs provided")
949
+ raise ValueError("At least one output ID is required")
950
+
951
+ if query and (offset is not None or limit is not None):
952
+ _emit_status("output", error="query cannot be combined with offset/limit")
953
+ raise ValueError("query cannot be combined with offset/limit")
954
+
955
+ results: list[dict] = []
956
+ not_found: list[str] = []
957
+
958
+ for output_id in ids:
959
+ output_path = Path(artifacts_dir) / f"{output_id}.md"
960
+ if not output_path.exists():
961
+ not_found.append(output_id)
962
+ continue
963
+
964
+ raw_content = output_path.read_text(encoding="utf-8")
965
+ raw_lines = raw_content.splitlines()
966
+ total_lines = len(raw_lines)
967
+
968
+ selected_content = raw_content
969
+ range_info: dict | None = None
970
+
971
+ # Handle query
972
+ if query:
973
+ try:
974
+ json_value = json.loads(raw_content)
975
+ except json.JSONDecodeError as e:
976
+ _emit_status("output", id=output_id, error=f"Not valid JSON: {e}")
977
+ raise ValueError(f"Output {output_id} is not valid JSON: {e}")
978
+
979
+ # Apply jq-like query
980
+ result_value = _apply_query(json_value, query)
981
+ try:
982
+ selected_content = json.dumps(result_value, indent=2) if result_value is not None else "null"
983
+ except (TypeError, ValueError):
984
+ selected_content = str(result_value)
985
+
986
+ # Handle offset/limit
987
+ elif offset is not None or limit is not None:
988
+ start_line = max(1, offset or 1)
989
+ if start_line > total_lines:
990
+ _emit_status("output", id=output_id, error=f"Offset {start_line} beyond end ({total_lines} lines)")
991
+ raise ValueError(f"Offset {start_line} is beyond end of output ({total_lines} lines) for {output_id}")
992
+
993
+ effective_limit = limit if limit is not None else total_lines - start_line + 1
994
+ end_line = min(total_lines, start_line + effective_limit - 1)
995
+ selected_lines = raw_lines[start_line - 1 : end_line]
996
+ selected_content = "\n".join(selected_lines)
997
+ range_info = {"start_line": start_line, "end_line": end_line, "total_lines": total_lines}
998
+
999
+ # Strip ANSI codes if requested
1000
+ if format == "stripped":
1001
+ import re
1002
+ selected_content = re.sub(r"\x1b\[[0-9;]*m", "", selected_content)
1003
+
1004
+ # Build result
1005
+ if format == "json":
1006
+ result_data = {
1007
+ "id": output_id,
1008
+ "path": str(output_path),
1009
+ "line_count": total_lines if not query else len(selected_content.splitlines()),
1010
+ "char_count": len(raw_content) if not query else len(selected_content),
1011
+ "content": selected_content,
1012
+ }
1013
+ if range_info:
1014
+ result_data["range"] = range_info
1015
+ if query:
1016
+ result_data["query"] = query
1017
+ results.append(result_data)
1018
+ else:
1019
+ results.append({"id": output_id, "content": selected_content})
1020
+
1021
+ # Handle not found
1022
+ if not_found:
1023
+ available = sorted(
1024
+ [f.stem for f in Path(artifacts_dir).glob("*.md")]
1025
+ )
1026
+ error_msg = f"Output not found: {', '.join(not_found)}"
1027
+ if available:
1028
+ error_msg += f"\n\nAvailable outputs: {', '.join(available[:20])}"
1029
+ if len(available) > 20:
1030
+ error_msg += f" (and {len(available) - 20} more)"
1031
+ _emit_status("output", not_found=not_found, available_count=len(available))
1032
+ raise FileNotFoundError(error_msg)
1033
+
1034
+ # Return format
1035
+ if len(ids) == 1:
1036
+ if format == "json":
1037
+ _emit_status("output", id=ids[0], chars=results[0]["char_count"])
1038
+ return results[0]
1039
+ _emit_status("output", id=ids[0], chars=len(results[0]["content"]))
1040
+ return results[0]["content"]
1041
+
1042
+ # Multiple IDs
1043
+ if format == "json":
1044
+ total_chars = sum(r["char_count"] for r in results)
1045
+ _emit_status("output", count=len(results), total_chars=total_chars)
1046
+ return results
1047
+
1048
+ combined_output: list[dict] = []
1049
+ for r in results:
1050
+ combined_output.append({"id": r["id"], "content": r["content"]})
1051
+ total_chars = sum(len(r["content"]) for r in combined_output)
1052
+ _emit_status("output", count=len(combined_output), total_chars=total_chars)
1053
+ return combined_output
1054
+
1055
+ def _apply_query(data: any, query: str) -> any:
1056
+ """Apply jq-like query to data. Supports .key, [index], and chaining."""
1057
+ if not query:
1058
+ return data
1059
+
1060
+ query = query.strip()
1061
+ if query.startswith("."):
1062
+ query = query[1:]
1063
+ if not query:
1064
+ return data
1065
+
1066
+ # Parse query into tokens
1067
+ tokens = []
1068
+ current_token = ""
1069
+ i = 0
1070
+ while i < len(query):
1071
+ ch = query[i]
1072
+ if ch == ".":
1073
+ if current_token:
1074
+ tokens.append(("key", current_token))
1075
+ current_token = ""
1076
+ elif ch == "[":
1077
+ if current_token:
1078
+ tokens.append(("key", current_token))
1079
+ current_token = ""
1080
+ # Find matching ]
1081
+ j = i + 1
1082
+ while j < len(query) and query[j] != "]":
1083
+ j += 1
1084
+ bracket_content = query[i+1:j]
1085
+ if bracket_content.startswith('"') and bracket_content.endswith('"'):
1086
+ tokens.append(("key", bracket_content[1:-1]))
1087
+ else:
1088
+ tokens.append(("index", int(bracket_content)))
1089
+ i = j
1090
+ else:
1091
+ current_token += ch
1092
+ i += 1
1093
+ if current_token:
1094
+ tokens.append(("key", current_token))
1095
+
1096
+ # Apply tokens
1097
+ current = data
1098
+ for token_type, value in tokens:
1099
+ if token_type == "index":
1100
+ if not isinstance(current, list) or value >= len(current):
1101
+ return None
1102
+ current = current[value]
1103
+ elif token_type == "key":
1104
+ if not isinstance(current, dict) or value not in current:
1105
+ return None
1106
+ current = current[value]
1107
+
1108
+ return current
1109
+
917
1110
  def __omp_prelude_docs__() -> list[dict[str, str]]:
918
1111
  """Return prelude helper docs for templating. Discovers functions by _omp_category attribute."""
919
1112
  helpers: list[dict[str, str]] = []
@@ -0,0 +1,3 @@
1
+ import pythonPrelude from "./prelude.py" with { type: "text" };
2
+
3
+ export const PYTHON_PRELUDE = pythonPrelude;
@@ -1,5 +1,6 @@
1
1
  import * as fs from "node:fs";
2
2
  import { logger } from "@oh-my-pi/pi-utils";
3
+ import { ToolAbortError, throwIfAborted } from "$c/tools/tool-errors";
3
4
  import { applyWorkspaceEdit } from "./edits";
4
5
  import { getLspmuxCommand, isLspmuxSupported } from "./lspmux";
5
6
  import type {
@@ -547,7 +548,7 @@ export async function syncContent(
547
548
  ): Promise<void> {
548
549
  const uri = fileToUri(filePath);
549
550
  const lockKey = `${client.name}:${uri}`;
550
- signal?.throwIfAborted();
551
+ throwIfAborted(signal);
551
552
 
552
553
  const existingLock = fileOperationLocks.get(lockKey);
553
554
  if (existingLock) {
@@ -563,7 +564,7 @@ export async function syncContent(
563
564
  if (!info) {
564
565
  // Open file with provided content instead of reading from disk
565
566
  const languageId = detectLanguageId(filePath);
566
- signal?.throwIfAborted();
567
+ throwIfAborted(signal);
567
568
  await sendNotification(client, "textDocument/didOpen", {
568
569
  textDocument: {
569
570
  uri,
@@ -578,7 +579,7 @@ export async function syncContent(
578
579
  }
579
580
 
580
581
  const version = ++info.version;
581
- signal?.throwIfAborted();
582
+ throwIfAborted(signal);
582
583
  await sendNotification(client, "textDocument/didChange", {
583
584
  textDocument: { uri, version },
584
585
  contentChanges: [{ text: content }],
@@ -603,7 +604,7 @@ export async function notifySaved(client: LspClient, filePath: string, signal?:
603
604
  const info = client.openFiles.get(uri);
604
605
  if (!info) return; // File not open, nothing to notify
605
606
 
606
- signal?.throwIfAborted();
607
+ throwIfAborted(signal);
607
608
  await sendNotification(client, "textDocument/didSave", {
608
609
  textDocument: { uri },
609
610
  });
@@ -698,7 +699,7 @@ export async function sendRequest(
698
699
  // Atomically increment and capture request ID
699
700
  const id = ++client.requestId;
700
701
  if (signal?.aborted) {
701
- const reason = signal.reason instanceof Error ? signal.reason : new Error("Operation aborted");
702
+ const reason = signal.reason instanceof Error ? signal.reason : new ToolAbortError();
702
703
  return Promise.reject(reason);
703
704
  }
704
705
 
@@ -724,7 +725,7 @@ export async function sendRequest(
724
725
  }
725
726
  if (timeout) clearTimeout(timeout);
726
727
  cleanup();
727
- const reason = signal?.reason instanceof Error ? signal.reason : new Error("Operation aborted");
728
+ const reason = signal?.reason instanceof Error ? signal.reason : new ToolAbortError();
728
729
  reject(reason);
729
730
  };
730
731
 
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import path from "node:path";
7
- import type { Diagnostic, DiagnosticSeverity, LinterClient, ServerConfig } from "../types";
7
+ import type { Diagnostic, DiagnosticSeverity, LinterClient, ServerConfig } from "$c/lsp/types";
8
8
 
9
9
  // =============================================================================
10
10
  // Biome JSON Output Types
@@ -8,7 +8,7 @@
8
8
  export { BiomeClient } from "./biome-client";
9
9
  export { LspLinterClient } from "./lsp-linter-client";
10
10
 
11
- import type { LinterClient, ServerConfig } from "../types";
11
+ import type { LinterClient, ServerConfig } from "$c/lsp/types";
12
12
  import { LspLinterClient } from "./lsp-linter-client";
13
13
 
14
14
  // Cache of linter clients by server name + cwd
@@ -3,10 +3,10 @@
3
3
  * Uses the Language Server Protocol for formatting and diagnostics.
4
4
  */
5
5
 
6
- import { getOrCreateClient, notifySaved, sendRequest, syncContent } from "../client";
7
- import { applyTextEditsToString } from "../edits";
8
- import type { Diagnostic, LinterClient, LspClient, ServerConfig, TextEdit } from "../types";
9
- import { fileToUri } from "../utils";
6
+ import { getOrCreateClient, notifySaved, sendRequest, syncContent } from "$c/lsp/client";
7
+ import { applyTextEditsToString } from "$c/lsp/edits";
8
+ import type { Diagnostic, LinterClient, LspClient, ServerConfig, TextEdit } from "$c/lsp/types";
9
+ import { fileToUri } from "$c/lsp/utils";
10
10
 
11
11
  /** Default formatting options for LSP */
12
12
  const DEFAULT_FORMAT_OPTIONS = {
@@ -3,7 +3,7 @@ import { basename, extname, join } from "node:path";
3
3
  import { logger } from "@oh-my-pi/pi-utils";
4
4
  import { YAML } from "bun";
5
5
  import { globSync } from "glob";
6
- import { getConfigDirPaths } from "../../../config";
6
+ import { getConfigDirPaths } from "$c/config";
7
7
  import { BiomeClient } from "./clients/biome-client";
8
8
  import DEFAULTS from "./defaults.json" with { type: "json" };
9
9
  import type { ServerConfig } from "./types";
@@ -4,11 +4,12 @@ import path from "node:path";
4
4
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
5
5
  import { logger, once, untilAborted } from "@oh-my-pi/pi-utils";
6
6
  import type { BunFile } from "bun";
7
- import { type Theme, theme } from "../../../modes/interactive/theme/theme";
8
- import lspDescription from "../../../prompts/tools/lsp.md" with { type: "text" };
9
- import { renderPromptTemplate } from "../../prompt-templates";
10
- import type { ToolSession } from "../index";
11
- import { resolveToCwd } from "../path-utils";
7
+ import { renderPromptTemplate } from "$c/config/prompt-templates";
8
+ import { type Theme, theme } from "$c/modes/theme/theme";
9
+ import lspDescription from "$c/prompts/tools/lsp.md" with { type: "text" };
10
+ import type { ToolSession } from "$c/tools/index";
11
+ import { resolveToCwd } from "$c/tools/path-utils";
12
+ import { throwIfAborted } from "$c/tools/tool-errors";
12
13
  import {
13
14
  ensureFileOpen,
14
15
  getActiveClients,
@@ -152,15 +153,15 @@ async function syncFileContent(
152
153
  servers: Array<[string, ServerConfig]>,
153
154
  signal?: AbortSignal,
154
155
  ): Promise<void> {
155
- signal?.throwIfAborted();
156
+ throwIfAborted(signal);
156
157
  await Promise.allSettled(
157
158
  servers.map(async ([_serverName, serverConfig]) => {
158
- signal?.throwIfAborted();
159
+ throwIfAborted(signal);
159
160
  if (serverConfig.createClient) {
160
161
  return;
161
162
  }
162
163
  const client = await getOrCreateClient(serverConfig, cwd);
163
- signal?.throwIfAborted();
164
+ throwIfAborted(signal);
164
165
  await syncContent(client, absolutePath, content, signal);
165
166
  }),
166
167
  );
@@ -180,10 +181,10 @@ async function notifyFileSaved(
180
181
  servers: Array<[string, ServerConfig]>,
181
182
  signal?: AbortSignal,
182
183
  ): Promise<void> {
183
- signal?.throwIfAborted();
184
+ throwIfAborted(signal);
184
185
  await Promise.allSettled(
185
186
  servers.map(async ([_serverName, serverConfig]) => {
186
- signal?.throwIfAborted();
187
+ throwIfAborted(signal);
187
188
  if (serverConfig.createClient) {
188
189
  return;
189
190
  }
@@ -243,6 +244,14 @@ function getLspServerForFile(config: LspConfig, filePath: string): [string, Serv
243
244
 
244
245
  const FILE_SEARCH_MAX_DEPTH = 5;
245
246
  const IGNORED_DIRS = new Set(["node_modules", "target", "dist", "build", ".git"]);
247
+ const DIAGNOSTIC_MESSAGE_LIMIT = 50;
248
+
249
+ function limitDiagnosticMessages(messages: string[]): string[] {
250
+ if (messages.length <= DIAGNOSTIC_MESSAGE_LIMIT) {
251
+ return messages;
252
+ }
253
+ return messages.slice(0, DIAGNOSTIC_MESSAGE_LIMIT);
254
+ }
246
255
 
247
256
  function findFileByExtensions(baseDir: string, extensions: string[], maxDepth: number): string | null {
248
257
  const normalized = extensions.map((ext) => ext.toLowerCase());
@@ -334,7 +343,7 @@ async function waitForDiagnostics(
334
343
  ): Promise<Diagnostic[]> {
335
344
  const start = Date.now();
336
345
  while (Date.now() - start < timeoutMs) {
337
- signal?.throwIfAborted();
346
+ throwIfAborted(signal);
338
347
  const diagnostics = client.diagnostics.get(uri);
339
348
  const versionOk = minVersion === undefined || client.diagnosticsVersion > minVersion;
340
349
  if (diagnostics !== undefined && versionOk) return diagnostics;
@@ -513,7 +522,7 @@ async function getDiagnosticsForFile(
513
522
  // Wait for diagnostics from all servers in parallel
514
523
  const results = await Promise.allSettled(
515
524
  servers.map(async ([serverName, serverConfig]) => {
516
- signal?.throwIfAborted();
525
+ throwIfAborted(signal);
517
526
  // Use custom linter client if configured
518
527
  if (serverConfig.createClient) {
519
528
  const linterClient = getLinterClient(serverName, serverConfig, cwd);
@@ -523,7 +532,7 @@ async function getDiagnosticsForFile(
523
532
 
524
533
  // Default: use LSP
525
534
  const client = await getOrCreateClient(serverConfig, cwd);
526
- signal?.throwIfAborted();
535
+ throwIfAborted(signal);
527
536
  // Content already synced + didSave sent, wait for fresh diagnostics
528
537
  const minVersion = minVersions?.get(serverName);
529
538
  const diagnostics = await waitForDiagnostics(client, uri, 3000, signal, minVersion);
@@ -563,12 +572,13 @@ async function getDiagnosticsForFile(
563
572
  }
564
573
 
565
574
  const formatted = uniqueDiagnostics.map((d) => formatDiagnostic(d, relPath));
575
+ const limited = limitDiagnosticMessages(formatted);
566
576
  const summary = formatDiagnosticsSummary(uniqueDiagnostics);
567
577
  const hasErrors = uniqueDiagnostics.some((d) => d.severity === 1);
568
578
 
569
579
  return {
570
580
  server: serverNames.join(", "),
571
- messages: formatted,
581
+ messages: limited,
572
582
  summary,
573
583
  errored: hasErrors,
574
584
  };
@@ -612,7 +622,7 @@ async function formatContent(
612
622
 
613
623
  for (const [serverName, serverConfig] of servers) {
614
624
  try {
615
- signal?.throwIfAborted();
625
+ throwIfAborted(signal);
616
626
  // Use custom linter client if configured
617
627
  if (serverConfig.createClient) {
618
628
  const linterClient = getLinterClient(serverName, serverConfig, cwd);
@@ -621,7 +631,7 @@ async function formatContent(
621
631
 
622
632
  // Default: use LSP
623
633
  const client = await getOrCreateClient(serverConfig, cwd);
624
- signal?.throwIfAborted();
634
+ throwIfAborted(signal);
625
635
 
626
636
  const caps = client.serverCapabilities;
627
637
  if (!caps?.documentFormattingProvider) {
@@ -788,16 +798,18 @@ function mergeDiagnostics(
788
798
 
789
799
  let summary = options.enableDiagnostics ? "no issues" : "OK";
790
800
  let errored = false;
801
+ let limitedMessages = messages;
791
802
  if (messages.length > 0) {
792
803
  const summaryInfo = summarizeDiagnosticMessages(messages);
793
804
  summary = summaryInfo.summary;
794
805
  errored = summaryInfo.errored;
806
+ limitedMessages = limitDiagnosticMessages(messages);
795
807
  }
796
808
  const formatter = hasFormatter ? (formatted ? FileFormatResult.FORMATTED : FileFormatResult.UNCHANGED) : undefined;
797
809
 
798
810
  return {
799
811
  server: servers.size > 0 ? Array.from(servers).join(", ") : undefined,
800
- messages,
812
+ messages: limitedMessages,
801
813
  summary,
802
814
  errored,
803
815
  formatter,
@@ -11,8 +11,8 @@
11
11
  import type { AgentToolResult, RenderResultOptions } from "@oh-my-pi/pi-agent-core";
12
12
  import { Text } from "@oh-my-pi/pi-tui";
13
13
  import { highlight, supportsLanguage } from "cli-highlight";
14
- import { getLanguageFromPath, type Theme } from "../../../modes/interactive/theme/theme";
15
- import { formatExpandHint, formatMoreItems, TRUNCATE_LENGTHS, truncate } from "../render-utils";
14
+ import { getLanguageFromPath, type Theme } from "$c/modes/theme/theme";
15
+ import { formatExpandHint, formatMoreItems, TRUNCATE_LENGTHS, truncate } from "$c/tools/render-utils";
16
16
  import type { LspParams, LspToolDetails } from "./types";
17
17
 
18
18
  // =============================================================================
@@ -30,23 +30,21 @@ export const lspSchema = Type.Object({
30
30
  "related_tests",
31
31
  "reload_workspace",
32
32
  ],
33
- { description: "LSP action to perform" },
34
- ),
35
- files: Type.Optional(Type.Array(Type.String({ description: "File paths for diagnostics" }))),
36
- file: Type.Optional(Type.String({ description: "File path for file-specific actions" })),
37
- line: Type.Optional(Type.Number({ description: "1-based line number" })),
38
- column: Type.Optional(Type.Number({ description: "1-based column number" })),
39
- end_line: Type.Optional(Type.Number({ description: "1-based end line number for ranges" })),
40
- end_character: Type.Optional(Type.Number({ description: "1-based end column number for ranges" })),
41
- query: Type.Optional(Type.String({ description: "Search query for symbols/SSR pattern" })),
42
- new_name: Type.Optional(Type.String({ description: "New name for rename action" })),
43
- replacement: Type.Optional(Type.String({ description: "Replacement for SSR action" })),
44
- kind: Type.Optional(Type.String({ description: "Code action kind filter (quickfix, refactor, source)" })),
45
- apply: Type.Optional(Type.Boolean({ description: "Apply edits instead of preview (default: true)" })),
46
- action_index: Type.Optional(Type.Number({ description: "Index of code action to apply" })),
47
- include_declaration: Type.Optional(
48
- Type.Boolean({ description: "Include declaration in references (default: true)" }),
33
+ { description: "LSP operation" },
49
34
  ),
35
+ files: Type.Optional(Type.Array(Type.String({ description: "File path" }))),
36
+ file: Type.Optional(Type.String({ description: "File path" })),
37
+ line: Type.Optional(Type.Number({ description: "Line number (1-indexed)" })),
38
+ column: Type.Optional(Type.Number({ description: "Column number (1-indexed)" })),
39
+ end_line: Type.Optional(Type.Number({ description: "End line for range (1-indexed)" })),
40
+ end_character: Type.Optional(Type.Number({ description: "End column for range (1-indexed)" })),
41
+ query: Type.Optional(Type.String({ description: "Search query or SSR pattern" })),
42
+ new_name: Type.Optional(Type.String({ description: "New name for rename" })),
43
+ replacement: Type.Optional(Type.String({ description: "Replacement text for SSR" })),
44
+ kind: Type.Optional(Type.String({ description: "Action kind: quickfix, refactor, source" })),
45
+ apply: Type.Optional(Type.Boolean({ description: "Apply edits (default: true)" })),
46
+ action_index: Type.Optional(Type.Number({ description: "Index of action to apply" })),
47
+ include_declaration: Type.Optional(Type.Boolean({ description: "Include declaration in refs (default: true)" })),
50
48
  });
51
49
 
52
50
  export type LspParams = Static<typeof lspSchema>;
@@ -1,5 +1,5 @@
1
1
  import path from "node:path";
2
- import { type Theme, theme } from "../../../modes/interactive/theme/theme";
2
+ import { type Theme, theme } from "$c/modes/theme/theme";
3
3
  import type {
4
4
  Diagnostic,
5
5
  DiagnosticSeverity,