@oh-my-pi/pi-coding-agent 15.10.10 → 15.10.12

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 (415) hide show
  1. package/CHANGELOG.md +142 -7
  2. package/dist/cli.js +23108 -0
  3. package/dist/tokenizers.linux-x64-gnu-xcjh3jwk.node +0 -0
  4. package/dist/types/async/job-manager.d.ts +18 -0
  5. package/dist/types/cli/args.d.ts +2 -1
  6. package/dist/types/cli/dry-balance-cli.d.ts +1 -1
  7. package/dist/types/cli/gallery-cli.d.ts +1 -1
  8. package/dist/types/cli/gallery-fixtures/types.d.ts +1 -1
  9. package/dist/types/cli/usage-cli.d.ts +72 -0
  10. package/dist/types/cli-commands.d.ts +12 -0
  11. package/dist/types/commands/launch.d.ts +5 -1
  12. package/dist/types/commands/read.d.ts +1 -1
  13. package/dist/types/commands/usage.d.ts +25 -0
  14. package/dist/types/config/api-key-resolver.d.ts +3 -0
  15. package/dist/types/config/append-only-context-mode.d.ts +2 -1
  16. package/dist/types/config/model-discovery.d.ts +55 -0
  17. package/dist/types/config/model-registry.d.ts +8 -219
  18. package/dist/types/config/model-resolver.d.ts +34 -10
  19. package/dist/types/config/model-roles.d.ts +28 -0
  20. package/dist/types/config/models-config-schema.d.ts +523 -42
  21. package/dist/types/config/models-config.d.ts +385 -0
  22. package/dist/types/config/settings-schema.d.ts +41 -8
  23. package/dist/types/config/settings.d.ts +8 -1
  24. package/dist/types/debug/log-viewer.d.ts +1 -1
  25. package/dist/types/debug/raw-sse.d.ts +1 -1
  26. package/dist/types/edit/hashline/noop-loop-guard.d.ts +72 -0
  27. package/dist/types/eval/backend.d.ts +0 -2
  28. package/dist/types/eval/idle-timeout.d.ts +0 -4
  29. package/dist/types/eval/js/shared/rewrite-imports.d.ts +6 -6
  30. package/dist/types/eval/py/executor.d.ts +5 -0
  31. package/dist/types/eval/py/kernel.d.ts +6 -1
  32. package/dist/types/eval/py/runtime.d.ts +9 -0
  33. package/dist/types/exec/bash-executor.d.ts +2 -0
  34. package/dist/types/export/html/template.generated.d.ts +1 -1
  35. package/dist/types/extensibility/extensions/runner.d.ts +3 -2
  36. package/dist/types/extensibility/extensions/types.d.ts +6 -3
  37. package/dist/types/hindsight/mental-models.d.ts +17 -8
  38. package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
  39. package/dist/types/internal-urls/types.d.ts +1 -1
  40. package/dist/types/lsp/edits.d.ts +9 -0
  41. package/dist/types/lsp/index.d.ts +2 -2
  42. package/dist/types/lsp/types.d.ts +2 -0
  43. package/dist/types/lsp/utils.d.ts +3 -0
  44. package/dist/types/mcp/json-rpc.d.ts +5 -0
  45. package/dist/types/memory-backend/index.d.ts +1 -0
  46. package/dist/types/memory-backend/runtime.d.ts +4 -0
  47. package/dist/types/memory-backend/types.d.ts +66 -1
  48. package/dist/types/mnemopi/state.d.ts +11 -1
  49. package/dist/types/modes/components/agent-dashboard.d.ts +1 -1
  50. package/dist/types/modes/components/assistant-message.d.ts +3 -1
  51. package/dist/types/modes/components/bash-execution.d.ts +1 -1
  52. package/dist/types/modes/components/copy-selector.d.ts +1 -1
  53. package/dist/types/modes/components/dynamic-border.d.ts +1 -1
  54. package/dist/types/modes/components/extensions/extension-dashboard.d.ts +1 -1
  55. package/dist/types/modes/components/extensions/extension-list.d.ts +1 -1
  56. package/dist/types/modes/components/extensions/inspector-panel.d.ts +1 -1
  57. package/dist/types/modes/components/footer.d.ts +1 -1
  58. package/dist/types/modes/components/hook-editor.d.ts +5 -0
  59. package/dist/types/modes/components/hook-input.d.ts +4 -0
  60. package/dist/types/modes/components/hook-selector.d.ts +1 -1
  61. package/dist/types/modes/components/model-selector.d.ts +1 -1
  62. package/dist/types/modes/components/plan-review-overlay.d.ts +1 -1
  63. package/dist/types/modes/components/session-observer-overlay.d.ts +1 -1
  64. package/dist/types/modes/components/session-selector.d.ts +1 -1
  65. package/dist/types/modes/components/status-line/component.d.ts +1 -1
  66. package/dist/types/modes/components/tiny-title-download-progress.d.ts +1 -1
  67. package/dist/types/modes/components/transcript-container.d.ts +25 -6
  68. package/dist/types/modes/components/tree-selector.d.ts +1 -1
  69. package/dist/types/modes/components/user-message-selector.d.ts +1 -1
  70. package/dist/types/modes/components/user-message.d.ts +2 -1
  71. package/dist/types/modes/components/visual-truncate.d.ts +1 -1
  72. package/dist/types/modes/components/welcome.d.ts +19 -3
  73. package/dist/types/modes/controllers/mcp-command-controller.d.ts +1 -1
  74. package/dist/types/modes/controllers/streaming-reveal.d.ts +1 -1
  75. package/dist/types/modes/index.d.ts +3 -3
  76. package/dist/types/modes/interactive-mode.d.ts +8 -3
  77. package/dist/types/modes/oauth-manual-input.d.ts +7 -0
  78. package/dist/types/modes/rpc/rpc-client.d.ts +39 -2
  79. package/dist/types/modes/rpc/rpc-mode.d.ts +31 -2
  80. package/dist/types/modes/rpc/rpc-subagents.d.ts +24 -0
  81. package/dist/types/modes/rpc/rpc-types.d.ts +75 -1
  82. package/dist/types/modes/setup-wizard/index.d.ts +5 -1
  83. package/dist/types/modes/setup-wizard/lazy.d.ts +2 -0
  84. package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +1 -1
  85. package/dist/types/modes/setup-wizard/scenes/types.d.ts +1 -1
  86. package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +1 -1
  87. package/dist/types/modes/setup-wizard/wizard-overlay.d.ts +1 -1
  88. package/dist/types/modes/types.d.ts +4 -1
  89. package/dist/types/secrets/index.d.ts +1 -1
  90. package/dist/types/secrets/obfuscator.d.ts +8 -2
  91. package/dist/types/session/agent-session.d.ts +15 -3
  92. package/dist/types/session/auth-broker-config.d.ts +4 -0
  93. package/dist/types/session/session-manager.d.ts +1 -1
  94. package/dist/types/session/streaming-output.d.ts +23 -0
  95. package/dist/types/slash-commands/acp-builtins.d.ts +16 -0
  96. package/dist/types/slash-commands/builtin-registry.d.ts +1 -0
  97. package/dist/types/slash-commands/helpers/stats-dashboard.d.ts +13 -0
  98. package/dist/types/slash-commands/types.d.ts +1 -1
  99. package/dist/types/ssh/connection-manager.d.ts +8 -0
  100. package/dist/types/system-prompt.d.ts +2 -0
  101. package/dist/types/task/executor.d.ts +1 -0
  102. package/dist/types/task/index.d.ts +2 -2
  103. package/dist/types/task/parallel.d.ts +2 -2
  104. package/dist/types/task/types.d.ts +8 -0
  105. package/dist/types/task/worktree.d.ts +2 -0
  106. package/dist/types/thinking.d.ts +4 -0
  107. package/dist/types/tiny/title-client.d.ts +11 -0
  108. package/dist/types/tiny/title-protocol.d.ts +1 -0
  109. package/dist/types/tools/ask.d.ts +4 -0
  110. package/dist/types/tools/conflict-detect.d.ts +16 -0
  111. package/dist/types/tools/github-cache.d.ts +7 -0
  112. package/dist/types/tools/index.d.ts +6 -0
  113. package/dist/types/tools/sqlite-reader.d.ts +3 -0
  114. package/dist/types/tui/output-block.d.ts +3 -3
  115. package/dist/types/utils/changelog.d.ts +8 -0
  116. package/dist/types/utils/git.d.ts +15 -2
  117. package/dist/types/utils/title-generator.d.ts +3 -2
  118. package/dist/types/web/scrapers/readthedocs.d.ts +3 -0
  119. package/dist/types/web/scrapers/types.d.ts +12 -0
  120. package/dist/types/web/search/providers/codex.d.ts +1 -1
  121. package/dist/types/web/search/providers/gemini.d.ts +1 -1
  122. package/examples/extensions/tools.ts +5 -4
  123. package/package.json +14 -11
  124. package/scripts/build-binary.ts +18 -23
  125. package/scripts/bundle-dist.ts +81 -0
  126. package/scripts/{dev-launch → omp} +1 -1
  127. package/scripts/{dev-launch-preload.ts → omp.ts} +1 -1
  128. package/src/async/job-manager.ts +57 -3
  129. package/src/auto-thinking/classifier.ts +1 -0
  130. package/src/autoresearch/dashboard.ts +1 -1
  131. package/src/autoresearch/prompt-setup.md +6 -6
  132. package/src/autoresearch/prompt.md +6 -6
  133. package/src/capability/fs.ts +10 -0
  134. package/src/cli/args.ts +4 -1
  135. package/src/cli/auth-gateway-cli.ts +1 -3
  136. package/src/cli/dry-balance-cli.ts +1 -1
  137. package/src/cli/gallery-cli.ts +1 -1
  138. package/src/cli/gallery-fixtures/fs.ts +1 -1
  139. package/src/cli/gallery-fixtures/types.ts +5 -1
  140. package/src/cli/list-models.ts +2 -1
  141. package/src/cli/usage-cli.ts +603 -0
  142. package/src/cli-commands.ts +30 -0
  143. package/src/cli.ts +76 -13
  144. package/src/commands/complete.ts +1 -1
  145. package/src/commands/launch.ts +5 -1
  146. package/src/commands/read.ts +6 -3
  147. package/src/commands/usage.ts +35 -0
  148. package/src/commit/agentic/agent.ts +1 -1
  149. package/src/commit/model-selection.ts +4 -3
  150. package/src/config/api-key-resolver.ts +8 -6
  151. package/src/config/append-only-context-mode.ts +6 -12
  152. package/src/config/model-discovery.ts +554 -0
  153. package/src/config/model-registry.ts +320 -1041
  154. package/src/config/model-resolver.ts +173 -156
  155. package/src/config/model-roles.ts +74 -0
  156. package/src/config/models-config-schema.ts +57 -8
  157. package/src/config/models-config.ts +129 -0
  158. package/src/config/settings-schema.ts +61 -19
  159. package/src/config/settings.ts +98 -4
  160. package/src/dap/client.ts +124 -37
  161. package/src/dap/session.ts +259 -158
  162. package/src/debug/log-viewer.ts +1 -1
  163. package/src/debug/raw-sse.ts +1 -1
  164. package/src/edit/diff.ts +47 -3
  165. package/src/edit/hashline/block-resolver.ts +20 -1
  166. package/src/edit/hashline/diff.ts +36 -1
  167. package/src/edit/hashline/execute.ts +47 -4
  168. package/src/edit/hashline/noop-loop-guard.ts +99 -0
  169. package/src/edit/index.ts +16 -1
  170. package/src/edit/modes/patch.ts +52 -0
  171. package/src/edit/modes/replace.ts +56 -22
  172. package/src/edit/notebook.ts +22 -2
  173. package/src/edit/renderer.ts +36 -10
  174. package/src/eval/__tests__/completion-bridge.test.ts +1 -1
  175. package/src/eval/backend.ts +0 -2
  176. package/src/eval/completion-bridge.ts +3 -1
  177. package/src/eval/idle-timeout.ts +2 -9
  178. package/src/eval/js/context-manager.ts +6 -8
  179. package/src/eval/js/executor.ts +6 -2
  180. package/src/eval/js/index.ts +0 -2
  181. package/src/eval/js/shared/helpers.ts +5 -6
  182. package/src/eval/js/shared/local-module-loader.ts +1 -1
  183. package/src/eval/js/shared/prelude.txt +62 -1
  184. package/src/eval/js/shared/rewrite-imports.ts +40 -22
  185. package/src/eval/js/shared/runtime.ts +1 -1
  186. package/src/eval/py/executor.ts +29 -7
  187. package/src/eval/py/index.ts +6 -3
  188. package/src/eval/py/kernel.ts +43 -4
  189. package/src/eval/py/runner.py +107 -3
  190. package/src/eval/py/runtime.ts +37 -0
  191. package/src/exec/bash-executor.ts +85 -4
  192. package/src/export/html/template.generated.ts +1 -1
  193. package/src/export/html/template.js +3 -1
  194. package/src/extensibility/extensions/get-commands-handler.ts +2 -1
  195. package/src/extensibility/extensions/runner.ts +6 -1
  196. package/src/extensibility/extensions/types.ts +6 -2
  197. package/src/extensibility/plugins/legacy-pi-compat.ts +20 -3
  198. package/src/hindsight/bank.ts +17 -2
  199. package/src/hindsight/mental-models.ts +59 -12
  200. package/src/hindsight/state.ts +6 -1
  201. package/src/internal-urls/artifact-protocol.ts +11 -2
  202. package/src/internal-urls/docs-index.generated.ts +11 -11
  203. package/src/internal-urls/issue-pr-protocol.ts +12 -5
  204. package/src/internal-urls/router.ts +1 -1
  205. package/src/internal-urls/types.ts +1 -1
  206. package/src/lib/xai-http.ts +1 -1
  207. package/src/lsp/client.ts +118 -38
  208. package/src/lsp/clients/biome-client.ts +101 -39
  209. package/src/lsp/edits.ts +143 -95
  210. package/src/lsp/index.ts +31 -22
  211. package/src/lsp/render.ts +1 -1
  212. package/src/lsp/types.ts +2 -0
  213. package/src/lsp/utils.ts +28 -10
  214. package/src/main.ts +183 -23
  215. package/src/mcp/json-rpc.ts +35 -5
  216. package/src/mcp/transports/stdio.ts +7 -1
  217. package/src/memories/index.ts +4 -1
  218. package/src/memory-backend/index.ts +1 -0
  219. package/src/memory-backend/local-backend.ts +9 -0
  220. package/src/memory-backend/off-backend.ts +9 -0
  221. package/src/memory-backend/runtime.ts +66 -0
  222. package/src/memory-backend/types.ts +81 -1
  223. package/src/mnemopi/backend.ts +176 -7
  224. package/src/mnemopi/state.ts +38 -2
  225. package/src/modes/acp/acp-agent.ts +119 -11
  226. package/src/modes/components/agent-dashboard.ts +10 -7
  227. package/src/modes/components/assistant-message.ts +32 -28
  228. package/src/modes/components/bash-execution.ts +1 -1
  229. package/src/modes/components/copy-selector.ts +1 -1
  230. package/src/modes/components/diff.ts +13 -2
  231. package/src/modes/components/dynamic-border.ts +12 -3
  232. package/src/modes/components/extensions/extension-dashboard.ts +8 -5
  233. package/src/modes/components/extensions/extension-list.ts +1 -1
  234. package/src/modes/components/extensions/inspector-panel.ts +1 -1
  235. package/src/modes/components/footer.ts +4 -2
  236. package/src/modes/components/history-search.ts +1 -1
  237. package/src/modes/components/hook-editor.ts +8 -0
  238. package/src/modes/components/hook-input.ts +8 -0
  239. package/src/modes/components/hook-selector.ts +2 -2
  240. package/src/modes/components/model-selector.ts +4 -2
  241. package/src/modes/components/plan-review-overlay.ts +1 -1
  242. package/src/modes/components/session-observer-overlay.ts +2 -2
  243. package/src/modes/components/session-selector.ts +1 -1
  244. package/src/modes/components/settings-selector.ts +5 -1
  245. package/src/modes/components/status-line/component.ts +119 -35
  246. package/src/modes/components/tiny-title-download-progress.ts +1 -1
  247. package/src/modes/components/transcript-container.ts +258 -53
  248. package/src/modes/components/tree-selector.ts +3 -3
  249. package/src/modes/components/user-message-selector.ts +1 -1
  250. package/src/modes/components/user-message.ts +17 -5
  251. package/src/modes/components/visual-truncate.ts +1 -1
  252. package/src/modes/components/welcome.ts +108 -26
  253. package/src/modes/controllers/command-controller.ts +11 -4
  254. package/src/modes/controllers/event-controller.ts +73 -4
  255. package/src/modes/controllers/input-controller.ts +2 -1
  256. package/src/modes/controllers/mcp-command-controller.ts +39 -4
  257. package/src/modes/controllers/selector-controller.ts +1 -1
  258. package/src/modes/controllers/streaming-reveal.ts +85 -18
  259. package/src/modes/index.ts +3 -21
  260. package/src/modes/interactive-mode.ts +42 -18
  261. package/src/modes/oauth-manual-input.ts +30 -3
  262. package/src/modes/rpc/rpc-client.ts +154 -3
  263. package/src/modes/rpc/rpc-mode.ts +97 -12
  264. package/src/modes/rpc/rpc-subagents.ts +265 -0
  265. package/src/modes/rpc/rpc-types.ts +81 -1
  266. package/src/modes/setup-wizard/index.ts +12 -2
  267. package/src/modes/setup-wizard/lazy.ts +16 -0
  268. package/src/modes/setup-wizard/scenes/glyph.ts +1 -1
  269. package/src/modes/setup-wizard/scenes/providers.ts +1 -1
  270. package/src/modes/setup-wizard/scenes/sign-in.ts +1 -1
  271. package/src/modes/setup-wizard/scenes/theme.ts +1 -1
  272. package/src/modes/setup-wizard/scenes/types.ts +1 -1
  273. package/src/modes/setup-wizard/scenes/web-search.ts +1 -1
  274. package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
  275. package/src/modes/types.ts +4 -1
  276. package/src/prompts/agents/explore.md +2 -2
  277. package/src/prompts/agents/librarian.md +1 -2
  278. package/src/prompts/agents/oracle.md +1 -1
  279. package/src/prompts/agents/plan.md +5 -5
  280. package/src/prompts/agents/task.md +5 -5
  281. package/src/prompts/ci-green-request.md +5 -7
  282. package/src/prompts/goals/goal-budget-limit.md +2 -2
  283. package/src/prompts/goals/goal-continuation.md +4 -4
  284. package/src/prompts/goals/goal-mode-active.md +1 -1
  285. package/src/prompts/memories/read-path.md +1 -1
  286. package/src/prompts/memories/stage_one_system.md +2 -2
  287. package/src/prompts/review-custom-request.md +1 -1
  288. package/src/prompts/system/agent-creation-architect.md +2 -2
  289. package/src/prompts/system/auto-continue.md +1 -1
  290. package/src/prompts/system/background-tan-dispatch.md +1 -1
  291. package/src/prompts/system/btw-user.md +2 -2
  292. package/src/prompts/system/commit-message-system.md +13 -1
  293. package/src/prompts/system/custom-system-prompt.md +1 -1
  294. package/src/prompts/system/eager-todo.md +2 -2
  295. package/src/prompts/system/irc-incoming.md +1 -1
  296. package/src/prompts/system/manual-continue.md +1 -1
  297. package/src/prompts/system/omfg-user.md +3 -4
  298. package/src/prompts/system/orchestrate-notice.md +9 -9
  299. package/src/prompts/system/plan-mode-active.md +4 -4
  300. package/src/prompts/system/plan-mode-subagent.md +4 -5
  301. package/src/prompts/system/plan-mode-tool-decision-reminder.md +1 -1
  302. package/src/prompts/system/project-prompt.md +2 -2
  303. package/src/prompts/system/subagent-system-prompt.md +4 -4
  304. package/src/prompts/system/system-prompt.md +13 -24
  305. package/src/prompts/system/title-system.md +2 -2
  306. package/src/prompts/system/ttsr-tool-reminder.md +1 -1
  307. package/src/prompts/system/workflow-notice.md +1 -1
  308. package/src/prompts/tools/ast-edit.md +1 -1
  309. package/src/prompts/tools/ast-grep.md +2 -2
  310. package/src/prompts/tools/bash.md +5 -7
  311. package/src/prompts/tools/browser.md +7 -7
  312. package/src/prompts/tools/debug.md +1 -1
  313. package/src/prompts/tools/eval.md +3 -3
  314. package/src/prompts/tools/find.md +0 -1
  315. package/src/prompts/tools/github.md +8 -7
  316. package/src/prompts/tools/goal.md +1 -1
  317. package/src/prompts/tools/image-gen.md +1 -1
  318. package/src/prompts/tools/inspect-image-system.md +1 -1
  319. package/src/prompts/tools/irc.md +15 -15
  320. package/src/prompts/tools/lsp.md +2 -2
  321. package/src/prompts/tools/patch.md +2 -2
  322. package/src/prompts/tools/read.md +3 -4
  323. package/src/prompts/tools/recall.md +1 -1
  324. package/src/prompts/tools/reflect.md +1 -1
  325. package/src/prompts/tools/render-mermaid.md +2 -2
  326. package/src/prompts/tools/replace.md +4 -10
  327. package/src/prompts/tools/rewind.md +2 -2
  328. package/src/prompts/tools/search-tool-bm25.md +1 -9
  329. package/src/prompts/tools/search.md +0 -1
  330. package/src/prompts/tools/ssh.md +0 -4
  331. package/src/prompts/tools/task.md +2 -3
  332. package/src/prompts/tools/todo.md +1 -1
  333. package/src/sdk.ts +31 -11
  334. package/src/secrets/index.ts +8 -1
  335. package/src/secrets/obfuscator.ts +39 -18
  336. package/src/session/agent-session.ts +223 -64
  337. package/src/session/auth-broker-config.ts +30 -1
  338. package/src/session/session-manager.ts +2 -2
  339. package/src/session/streaming-output.ts +188 -11
  340. package/src/slash-commands/acp-builtins.ts +24 -0
  341. package/src/slash-commands/builtin-registry.ts +40 -0
  342. package/src/slash-commands/helpers/stats-dashboard.ts +85 -0
  343. package/src/slash-commands/types.ts +1 -1
  344. package/src/ssh/connection-manager.ts +27 -0
  345. package/src/system-prompt.ts +14 -0
  346. package/src/task/commands.ts +2 -1
  347. package/src/task/executor.ts +74 -65
  348. package/src/task/index.ts +146 -68
  349. package/src/task/parallel.ts +3 -3
  350. package/src/task/render.ts +20 -5
  351. package/src/task/types.ts +9 -0
  352. package/src/task/worktree.ts +64 -56
  353. package/src/thinking.ts +9 -1
  354. package/src/tiny/title-client.ts +60 -16
  355. package/src/tiny/title-protocol.ts +1 -1
  356. package/src/tiny/worker.ts +6 -4
  357. package/src/tools/archive-reader.ts +30 -2
  358. package/src/tools/ask.ts +104 -21
  359. package/src/tools/ast-edit.ts +25 -5
  360. package/src/tools/auto-generated-guard.ts +20 -3
  361. package/src/tools/bash-interactive.ts +27 -7
  362. package/src/tools/bash.ts +100 -18
  363. package/src/tools/browser/launch.ts +11 -2
  364. package/src/tools/browser/readable.ts +19 -2
  365. package/src/tools/browser/registry.ts +4 -1
  366. package/src/tools/browser/render.ts +2 -2
  367. package/src/tools/browser/tab-supervisor.ts +55 -16
  368. package/src/tools/conflict-detect.ts +50 -4
  369. package/src/tools/debug.ts +1 -1
  370. package/src/tools/eval-render.ts +5 -5
  371. package/src/tools/eval.ts +0 -2
  372. package/src/tools/fetch.ts +33 -10
  373. package/src/tools/gh-cache-invalidation.ts +63 -8
  374. package/src/tools/gh-renderer.ts +1 -1
  375. package/src/tools/gh.ts +172 -29
  376. package/src/tools/github-cache.ts +70 -6
  377. package/src/tools/image-gen.ts +14 -13
  378. package/src/tools/index.ts +13 -1
  379. package/src/tools/inspect-image.ts +1 -0
  380. package/src/tools/irc.ts +5 -1
  381. package/src/tools/job.ts +1 -1
  382. package/src/tools/read.ts +202 -61
  383. package/src/tools/render-utils.ts +3 -3
  384. package/src/tools/resolve.ts +1 -1
  385. package/src/tools/search.ts +92 -29
  386. package/src/tools/sqlite-reader.ts +17 -5
  387. package/src/tools/ssh.ts +8 -8
  388. package/src/tools/todo.ts +38 -8
  389. package/src/tools/write.ts +118 -18
  390. package/src/tui/output-block.ts +4 -4
  391. package/src/utils/changelog.ts +27 -1
  392. package/src/utils/commit-message-generator.ts +1 -0
  393. package/src/utils/file-mentions.ts +2 -1
  394. package/src/utils/git.ts +267 -13
  395. package/src/utils/title-generator.ts +24 -5
  396. package/src/web/scrapers/arxiv.ts +1 -1
  397. package/src/web/scrapers/go-pkg.ts +1 -1
  398. package/src/web/scrapers/iacr.ts +1 -1
  399. package/src/web/scrapers/readthedocs.ts +1 -1
  400. package/src/web/scrapers/twitter.ts +2 -1
  401. package/src/web/scrapers/types.ts +87 -8
  402. package/src/web/scrapers/wikipedia.ts +1 -1
  403. package/src/web/scrapers/youtube.ts +6 -1
  404. package/src/web/search/index.ts +1 -1
  405. package/src/web/search/providers/codex.ts +2 -1
  406. package/src/web/search/providers/gemini.ts +2 -3
  407. package/src/web/search/render.ts +8 -6
  408. package/dist/types/config/model-equivalence.d.ts +0 -24
  409. package/dist/types/config/model-id-affixes.d.ts +0 -12
  410. package/dist/types/config/model-provider-priority.d.ts +0 -1
  411. package/dist/types/exec/idle-timeout-watchdog.d.ts +0 -18
  412. package/src/config/model-equivalence.ts +0 -875
  413. package/src/config/model-id-affixes.ts +0 -81
  414. package/src/config/model-provider-priority.ts +0 -56
  415. package/src/exec/idle-timeout-watchdog.ts +0 -126
@@ -51,8 +51,23 @@ from typing import Any
51
51
  # Frame writer
52
52
  # ---------------------------------------------------------------------------
53
53
 
54
- _RAW_STDOUT = sys.__stdout__
54
+ # Frames travel on a private dup of the original stdout. fd 1 itself is then
55
+ # repointed at a capture pipe: child processes spawned by user code without
56
+ # stdout=PIPE inherit fd 1, and their output is forwarded to the host as
57
+ # regular stdout frames by a drain thread instead of being written raw into
58
+ # the NDJSON channel (where it would be dropped as invalid JSON — or worse,
59
+ # spoof a frame). The wire protocol is unchanged: the host still reads NDJSON
60
+ # frames from the subprocess stdout.
55
61
  _RAW_STDERR = sys.__stderr__
62
+ try:
63
+ _FRAME_FD = os.dup(sys.__stdout__.fileno())
64
+ _RAW_STDOUT = os.fdopen(_FRAME_FD, "w", encoding="utf-8", errors="backslashreplace")
65
+ _CAPTURE_READ_FD, _capture_write_fd = os.pipe()
66
+ os.dup2(_capture_write_fd, sys.__stdout__.fileno())
67
+ os.close(_capture_write_fd)
68
+ except (AttributeError, OSError, ValueError, io.UnsupportedOperation):
69
+ _RAW_STDOUT = sys.__stdout__
70
+ _CAPTURE_READ_FD = None
56
71
  _OUT_LOCK = threading.Lock()
57
72
 
58
73
 
@@ -78,11 +93,22 @@ def _emit(frame: dict) -> None:
78
93
 
79
94
 
80
95
  class _StreamProxy(io.TextIOBase):
81
- """Emit each ``write()`` as a typed frame tied to the current request."""
96
+ """Emit ``write()`` data as typed frames tied to the current request.
97
+
98
+ Writes are coalesced per request: a frame is emitted once the buffer holds
99
+ a complete line (everything up to the last newline goes out together) or
100
+ grows past ``_MAX_BUFFER`` bytes, so the common ``print()`` pair of
101
+ ``write(text)`` + ``write("\\n")`` costs one frame instead of two. Partial
102
+ lines are bounded by ``flush()`` and the end-of-request flush.
103
+ """
104
+
105
+ _MAX_BUFFER = 8192
82
106
 
83
107
  def __init__(self, kind: str) -> None:
84
108
  super().__init__()
85
109
  self._kind = kind
110
+ self._lock = threading.Lock()
111
+ self._buffers: dict[str, str] = {}
86
112
 
87
113
  def writable(self) -> bool: # noqa: D401 - protocol method
88
114
  return True
@@ -100,12 +126,44 @@ class _StreamProxy(io.TextIOBase):
100
126
  _RAW_STDERR.write(data)
101
127
  _RAW_STDERR.flush()
102
128
  return len(data)
103
- _emit({"type": self._kind, "id": rid, "data": data})
129
+ emit_text = None
130
+ with self._lock:
131
+ buf = self._buffers.pop(rid, "") + data
132
+ if len(buf) >= self._MAX_BUFFER:
133
+ emit_text = buf
134
+ else:
135
+ nl = buf.rfind("\n")
136
+ if nl >= 0:
137
+ emit_text = buf[: nl + 1]
138
+ rest = buf[nl + 1 :]
139
+ if rest:
140
+ self._buffers[rid] = rest
141
+ else:
142
+ self._buffers[rid] = buf
143
+ if emit_text:
144
+ _emit({"type": self._kind, "id": rid, "data": emit_text})
104
145
  return len(data)
105
146
 
106
147
  def flush(self) -> None: # noqa: D401 - protocol method
148
+ rid = _CURRENT_RID.get()
149
+ if rid is not None:
150
+ self.flush_rid(rid)
107
151
  return None
108
152
 
153
+ def flush_rid(self, rid: str) -> None:
154
+ """Flush any buffered partial line for ``rid`` as its own frame."""
155
+ with self._lock:
156
+ buf = self._buffers.pop(rid, None)
157
+ if buf:
158
+ _emit({"type": self._kind, "id": rid, "data": buf})
159
+
160
+
161
+ def _flush_stream_proxies(rid: str) -> None:
162
+ """Drain buffered proxy output for ``rid`` (called before its done frame)."""
163
+ for stream in (sys.stdout, sys.stderr):
164
+ if isinstance(stream, _StreamProxy):
165
+ stream.flush_rid(rid)
166
+
109
167
 
110
168
  # ---------------------------------------------------------------------------
111
169
  # Runner state
@@ -125,6 +183,10 @@ class _RunnerState:
125
183
  self.last_install_marker: int = 0
126
184
  self.loop: asyncio.AbstractEventLoop | None = None
127
185
  self.active_executions: int = 0
186
+ # Best-effort attribution target for captured fd-1 bytes (child
187
+ # processes inheriting stdout). With overlapping requests the most
188
+ # recently started one wins — strictly better than dropping the bytes.
189
+ self.capture_rid: str | None = None
128
190
 
129
191
 
130
192
  _CURRENT_RID: contextvars.ContextVar[str | None] = contextvars.ContextVar("omp_current_rid", default=None)
@@ -132,6 +194,42 @@ _CURRENT_RID: contextvars.ContextVar[str | None] = contextvars.ContextVar("omp_c
132
194
  _STATE = _RunnerState()
133
195
 
134
196
 
197
+ def _drain_captured_stdout() -> None:
198
+ """Forward bytes written to the captured fd 1 as stdout frames.
199
+
200
+ Runs on a daemon thread for the life of the process. Child processes that
201
+ inherit fd 1 (any ``subprocess`` call without ``stdout=PIPE``) land here.
202
+ """
203
+ if _CAPTURE_READ_FD is None:
204
+ return
205
+ import codecs
206
+
207
+ decoder = codecs.getincrementaldecoder("utf-8")("replace")
208
+ while True:
209
+ try:
210
+ chunk = os.read(_CAPTURE_READ_FD, 65536)
211
+ except OSError:
212
+ return
213
+ if not chunk:
214
+ return
215
+ text = decoder.decode(chunk)
216
+ if not text:
217
+ continue
218
+ rid = _STATE.capture_rid
219
+ if rid is None:
220
+ _RAW_STDERR.write(text)
221
+ _RAW_STDERR.flush()
222
+ else:
223
+ _emit({"type": "stdout", "id": rid, "data": text})
224
+
225
+
226
+ def _start_capture_drain() -> None:
227
+ if _CAPTURE_READ_FD is None:
228
+ return
229
+ thread = threading.Thread(target=_drain_captured_stdout, name="omp-fd1-capture", daemon=True)
230
+ thread.start()
231
+
232
+
135
233
  # ---------------------------------------------------------------------------
136
234
  # Magic source transformer
137
235
  # ---------------------------------------------------------------------------
@@ -880,6 +978,7 @@ def _start_parent_watchdog() -> None:
880
978
  async def _handle_request_async(req: dict) -> None:
881
979
  rid = str(req.get("id"))
882
980
  token = _CURRENT_RID.set(rid)
981
+ _STATE.capture_rid = rid
883
982
  _STATE.user_ns["__omp_run_id__"] = rid
884
983
  _STATE.cancel_requested = False
885
984
  _STATE.execution_count += 1
@@ -934,6 +1033,7 @@ async def _handle_request_async(req: dict) -> None:
934
1033
  except Exception:
935
1034
  pass
936
1035
 
1036
+ _flush_stream_proxies(rid)
937
1037
  _emit({
938
1038
  "type": "done",
939
1039
  "id": rid,
@@ -942,6 +1042,9 @@ async def _handle_request_async(req: dict) -> None:
942
1042
  "cancelled": cancelled,
943
1043
  })
944
1044
  finally:
1045
+ if _STATE.capture_rid == rid:
1046
+ _STATE.capture_rid = None
1047
+ _flush_stream_proxies(rid)
945
1048
  _CURRENT_RID.reset(token)
946
1049
 
947
1050
 
@@ -986,6 +1089,7 @@ async def _main_async() -> None:
986
1089
  sys.stderr = _StreamProxy("stderr")
987
1090
  _install_idle_sigint()
988
1091
  _start_parent_watchdog()
1092
+ _start_capture_drain()
989
1093
 
990
1094
  stdin = sys.__stdin__
991
1095
  if stdin is None:
@@ -5,6 +5,7 @@
5
5
  * for both the shared gateway and local kernel spawning.
6
6
  */
7
7
  import * as fs from "node:fs";
8
+ import * as os from "node:os";
8
9
  import * as path from "node:path";
9
10
  import { $env, $which, getPythonEnvDir } from "@oh-my-pi/pi-utils";
10
11
 
@@ -182,6 +183,42 @@ function venvBinDir(venvPath: string): string {
182
183
  return process.platform === "win32" ? path.join(venvPath, "Scripts") : path.join(venvPath, "bin");
183
184
  }
184
185
 
186
+ function detectExplicitVenv(pythonPath: string): { venvPath: string; binDir: string } | undefined {
187
+ const binDir = path.dirname(pythonPath);
188
+ const venvPath = path.dirname(binDir);
189
+ if (fs.existsSync(path.join(venvPath, "pyvenv.cfg"))) {
190
+ return { venvPath, binDir };
191
+ }
192
+ return undefined;
193
+ }
194
+
195
+ /**
196
+ * Resolve an explicitly configured interpreter (`python.interpreter`) into a
197
+ * runtime, bypassing discovery. Does not probe or validate the executable —
198
+ * callers must check it actually runs. `~` expands to the home directory and
199
+ * relative paths resolve against `cwd`. When the interpreter sits inside a
200
+ * virtualenv (a `pyvenv.cfg` above its bin dir), the venv activation env is
201
+ * applied so subprocesses and `pip` resolve consistently.
202
+ */
203
+ export function resolveExplicitPythonRuntime(
204
+ interpreter: string,
205
+ cwd: string,
206
+ baseEnv: Record<string, string | undefined>,
207
+ ): PythonRuntime {
208
+ const expanded =
209
+ interpreter === "~"
210
+ ? os.homedir()
211
+ : interpreter.startsWith("~/")
212
+ ? path.join(os.homedir(), interpreter.slice(2))
213
+ : interpreter;
214
+ const pythonPath = path.isAbsolute(expanded) ? expanded : path.resolve(cwd, expanded);
215
+ const venv = detectExplicitVenv(pythonPath);
216
+ if (venv) {
217
+ return { pythonPath, env: applyVenvEnv(baseEnv, venv.venvPath, venv.binDir), venvPath: venv.venvPath };
218
+ }
219
+ return { pythonPath, env: { ...baseEnv } };
220
+ }
221
+
185
222
  /**
186
223
  * Enumerate candidate Python runtimes in priority order: an active/project venv,
187
224
  * the managed `~/.omp/python-env`, then the system interpreter on PATH. Every
@@ -6,6 +6,7 @@
6
6
  import * as fs from "node:fs/promises";
7
7
  import { ExponentialYield } from "@oh-my-pi/pi-agent-core/utils/yield";
8
8
  import { executeShell, type MinimizerOptions, Shell, type ShellRunResult } from "@oh-my-pi/pi-natives";
9
+ import { isExecutable, type ShellConfig } from "@oh-my-pi/pi-utils/procmgr";
9
10
  import { Settings, type ShellMinimizerSettings } from "../config/settings";
10
11
  import { OutputSink } from "../session/streaming-output";
11
12
  import { resolveOutputMaxColumns, resolveOutputSinkHeadBytes } from "../tools/output-meta";
@@ -22,6 +23,8 @@ export interface BashExecutorOptions {
22
23
  sessionKey?: string;
23
24
  /** Additional environment variables to inject */
24
25
  env?: Record<string, string>;
26
+ /** Run through the configured user shell instead of brush parsing directly. */
27
+ useUserShell?: boolean;
25
28
  /** Artifact path/id for full output storage */
26
29
  artifactPath?: string;
27
30
  artifactId?: string;
@@ -95,13 +98,86 @@ export function buildMinimizerOptions(group: ShellMinimizerSettings): MinimizerO
95
98
  only: group.only.length > 0 ? group.only : undefined,
96
99
  except: group.except.length > 0 ? group.except : undefined,
97
100
  maxCaptureBytes: group.maxCaptureBytes,
101
+ sourceOutlineLevel: group.sourceOutlineLevel === "default" ? undefined : group.sourceOutlineLevel,
102
+ legacyFilters: group.legacyFilters,
103
+ };
104
+ }
105
+
106
+ function shellBasename(shell: string): string {
107
+ return shell.replace(/\\/g, "/").split("/").pop()?.toLowerCase() ?? "";
108
+ }
109
+
110
+ function isBashShell(shell: string): boolean {
111
+ const basename = shellBasename(shell);
112
+ return basename.includes("bash");
113
+ }
114
+
115
+ function needsInteractiveShellArg(shell: string): boolean {
116
+ const basename = shellBasename(shell);
117
+ return basename.includes("zsh");
118
+ }
119
+
120
+ function supportsAutoUserShell(shell: string): boolean {
121
+ const basename = shellBasename(shell);
122
+ return basename.includes("bash") || basename.includes("zsh") || basename.includes("fish");
123
+ }
124
+
125
+ function hasInteractiveShellArg(args: string[]): boolean {
126
+ return args.some(arg => arg === "--interactive" || /^-[^-]*i/.test(arg));
127
+ }
128
+
129
+ function ensureInteractiveShellArgs(shell: string, args: string[]): string[] {
130
+ if (!needsInteractiveShellArg(shell) || hasInteractiveShellArg(args)) return args;
131
+
132
+ const commandIndex = args.findIndex(arg => arg === "-c" || arg === "--command");
133
+ if (commandIndex !== -1) {
134
+ return [...args.slice(0, commandIndex), "-i", ...args.slice(commandIndex)];
135
+ }
136
+
137
+ const compactCommandIndex = args.findIndex(arg => /^-[^-]*c[^-]*$/.test(arg));
138
+ if (compactCommandIndex !== -1) {
139
+ return args.map((arg, index) => (index === compactCommandIndex ? arg.replace("c", "ic") : arg));
140
+ }
141
+
142
+ return [...args, "-i"];
143
+ }
144
+
145
+ function quoteShellArg(value: string): string {
146
+ return `'${value.replace(/'/g, "'\\''")}'`;
147
+ }
148
+
149
+ function buildUserShellCommand(shell: string, args: string[], command: string): string {
150
+ return [shell, ...ensureInteractiveShellArgs(shell, args), command].map(quoteShellArg).join(" ");
151
+ }
152
+
153
+ function resolveUserShellConfig(settings: Settings, baseConfig: ShellConfig): ShellConfig {
154
+ const customShellPath = settings.get("shellPath");
155
+ const envShell = Bun.env.SHELL;
156
+ if (customShellPath || process.platform === "win32" || !envShell || envShell === baseConfig.shell) {
157
+ return baseConfig;
158
+ }
159
+ if (!supportsAutoUserShell(envShell) || !isExecutable(envShell)) {
160
+ return baseConfig;
161
+ }
162
+
163
+ return {
164
+ ...baseConfig,
165
+ shell: envShell,
166
+ env: {
167
+ ...baseConfig.env,
168
+ SHELL: envShell,
169
+ },
98
170
  };
99
171
  }
100
172
 
101
173
  export async function executeBash(command: string, options?: BashExecutorOptions): Promise<BashResult> {
102
174
  const settings = await Settings.init();
103
- const { shell, env: shellEnv, prefix } = settings.getShellConfig();
104
- const snapshotPath = shell.includes("bash") ? await getOrCreateSnapshot(shell, shellEnv) : null;
175
+ const baseShellConfig = settings.getShellConfig();
176
+ const shellConfig =
177
+ options?.useUserShell === true ? resolveUserShellConfig(settings, baseShellConfig) : baseShellConfig;
178
+ const { shell, args, env: shellEnv, prefix } = shellConfig;
179
+ const bashShell = isBashShell(shell);
180
+ const snapshotPath = bashShell ? await getOrCreateSnapshot(shell, shellEnv) : null;
105
181
 
106
182
  const minimizer = buildMinimizerOptions(settings.getGroup("shellMinimizer"));
107
183
 
@@ -110,7 +186,10 @@ export async function executeBash(command: string, options?: BashExecutorOptions
110
186
 
111
187
  // Apply command prefix if configured
112
188
  const prefixedCommand = prefix ? `${prefix} ${command}` : command;
113
- const finalCommand = prefixedCommand;
189
+ const finalCommand =
190
+ options?.useUserShell === true && !bashShell
191
+ ? buildUserShellCommand(shell, args, prefixedCommand)
192
+ : prefixedCommand;
114
193
 
115
194
  // Create output sink for truncation and artifact handling
116
195
  const sink = new OutputSink({
@@ -314,7 +393,9 @@ export async function executeBash(command: string, options?: BashExecutorOptions
314
393
  if (userSignal) {
315
394
  userSignal.removeEventListener("abort", abortHandler);
316
395
  }
317
- if (resetSession) {
396
+ if (resetSession || options?.sessionKey?.includes(":async:")) {
397
+ // `:async:` keys are per-job (jobId is unique), so the Shell would
398
+ // otherwise stay in the process-global map forever after completion.
318
399
  shellSessions.delete(sessionKey);
319
400
  }
320
401
  }