@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
package/src/task/types.ts CHANGED
@@ -2,6 +2,7 @@ import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
2
  import type { Usage } from "@oh-my-pi/pi-ai";
3
3
  import { $env } from "@oh-my-pi/pi-utils";
4
4
  import * as z from "zod/v4";
5
+ import type { AgentSessionEvent } from "../session/agent-session";
5
6
  import { getTaskSimpleModeCapabilities, type TaskSimpleMode } from "./simple-mode";
6
7
  import type { NestedRepoPatch } from "./worktree";
7
8
 
@@ -41,11 +42,18 @@ export interface SubagentProgressPayload {
41
42
  agent: string;
42
43
  agentSource: AgentSource;
43
44
  task: string;
45
+ parentToolCallId?: string;
44
46
  assignment?: string;
45
47
  progress: AgentProgress;
46
48
  sessionFile?: string;
47
49
  }
48
50
 
51
+ /** Payload emitted on TASK_SUBAGENT_EVENT_CHANNEL */
52
+ export interface SubagentEventPayload {
53
+ id: string;
54
+ event: AgentSessionEvent;
55
+ }
56
+
49
57
  /** Payload emitted on TASK_SUBAGENT_LIFECYCLE_CHANNEL */
50
58
  export interface SubagentLifecyclePayload {
51
59
  id: string;
@@ -54,6 +62,7 @@ export interface SubagentLifecyclePayload {
54
62
  description?: string;
55
63
  status: "started" | "completed" | "failed" | "aborted";
56
64
  sessionFile?: string;
65
+ parentToolCallId?: string;
57
66
  index: number;
58
67
  }
59
68
 
@@ -5,6 +5,7 @@ import * as path from "node:path";
5
5
  import * as natives from "@oh-my-pi/pi-natives";
6
6
  import { getWorktreeDir, hashPath, logger, Snowflake } from "@oh-my-pi/pi-utils";
7
7
  import * as git from "../utils/git";
8
+ import { mapWithConcurrencyLimit } from "./parallel";
8
9
 
9
10
  const { IsoBackendKind } = natives;
10
11
  type IsoBackendKind = natives.IsoBackendKind;
@@ -82,16 +83,16 @@ async function discoverNestedRepos(repoRoot: string): Promise<string[]> {
82
83
  async function captureUntrackedPatch(repoRoot: string, untracked: readonly string[]): Promise<string> {
83
84
  if (untracked.length === 0) return "";
84
85
  const nullPath = getGitNoIndexNullPath();
85
- const untrackedDiffs = await Promise.all(
86
- untracked.map(entry =>
87
- git.diff(repoRoot, {
88
- allowFailure: true,
89
- binary: true,
90
- noIndex: { left: nullPath, right: entry },
91
- }),
92
- ),
86
+ // Bound concurrent git spawns; large untracked sets would otherwise fork one
87
+ // process per file at once.
88
+ const { results: untrackedDiffs } = await mapWithConcurrencyLimit([...untracked], 8, entry =>
89
+ git.diff(repoRoot, {
90
+ allowFailure: true,
91
+ binary: true,
92
+ noIndex: { left: nullPath, right: entry },
93
+ }),
93
94
  );
94
- return untrackedDiffs.filter(diff => diff.trim()).join("\n");
95
+ return untrackedDiffs.filter((diff): diff is string => !!diff?.trim()).join("\n");
95
96
  }
96
97
 
97
98
  async function captureRepoBaseline(repoRoot: string): Promise<RepoBaseline> {
@@ -427,6 +428,8 @@ export interface MergeBranchResult {
427
428
  merged: string[];
428
429
  failed: string[];
429
430
  conflict?: string;
431
+ /** Set when cherry-picks landed on HEAD but restoring the stashed working tree failed. */
432
+ stashConflict?: string;
430
433
  }
431
434
 
432
435
  /**
@@ -438,64 +441,69 @@ export async function mergeTaskBranches(
438
441
  repoRoot: string,
439
442
  branches: Array<{ branchName: string; taskId: string; description?: string }>,
440
443
  ): Promise<MergeBranchResult> {
441
- const merged: string[] = [];
442
- const failed: string[] = [];
444
+ // Serialize against other in-process git mutations on this repo: concurrent
445
+ // background merges interleaving stash push/pop + cherry-pick would corrupt
446
+ // the working tree (lost uncommitted changes, mixed-up stash entries).
447
+ return git.withRepoLock(repoRoot, async () => {
448
+ const merged: string[] = [];
449
+ const failed: string[] = [];
443
450
 
444
- // Stash dirty working tree so cherry-pick can operate on a clean HEAD.
445
- // Without this, cherry-pick refuses to run when uncommitted changes exist.
446
- const didStash = await git.stash.push(repoRoot, "omp-task-merge");
451
+ // Stash dirty working tree so cherry-pick can operate on a clean HEAD.
452
+ // Without this, cherry-pick refuses to run when uncommitted changes exist.
453
+ const didStash = await git.stash.push(repoRoot, "omp-task-merge");
447
454
 
448
- let conflictResult: MergeBranchResult | undefined;
455
+ let conflictResult: MergeBranchResult | undefined;
449
456
 
450
- try {
451
- for (const { branchName } of branches) {
452
- try {
453
- await git.cherryPick(repoRoot, branchName);
454
- } catch (err) {
457
+ try {
458
+ for (const { branchName } of branches) {
455
459
  try {
456
- await git.cherryPick.abort(repoRoot);
457
- } catch {
458
- /* no state to abort */
459
- }
460
- const stderr =
461
- err instanceof git.GitCommandError
462
- ? err.result.stderr.trim()
463
- : err instanceof Error
464
- ? err.message
465
- : String(err);
466
- failed.push(branchName);
467
- conflictResult = {
468
- merged,
469
- failed: [...failed, ...branches.slice(merged.length + failed.length).map(b => b.branchName)],
470
- conflict: `${branchName}: ${stderr}`,
471
- };
472
- break;
473
- }
474
-
475
- merged.push(branchName);
476
- }
477
- } finally {
478
- if (didStash) {
479
- try {
480
- await git.stash.pop(repoRoot, { index: true });
481
- } catch {
482
- // Stash-pop conflicts mean the replayed changes clash with the user's
483
- // uncommitted edits. Treat this as a merge failure so the caller preserves
484
- // recovery branches instead of reporting success and deleting them.
485
- logger.warn("Failed to restore stashed changes after task merge; stash entry preserved");
486
- if (!conflictResult) {
460
+ await git.cherryPick(repoRoot, branchName);
461
+ } catch (err) {
462
+ try {
463
+ await git.cherryPick.abort(repoRoot);
464
+ } catch {
465
+ /* no state to abort */
466
+ }
467
+ const stderr =
468
+ err instanceof git.GitCommandError
469
+ ? err.result.stderr.trim()
470
+ : err instanceof Error
471
+ ? err.message
472
+ : String(err);
473
+ failed.push(branchName);
487
474
  conflictResult = {
488
475
  merged,
489
- failed: merged,
490
- conflict:
491
- "stash pop: cherry-picked changes conflict with uncommitted edits. Run `git stash pop` and resolve manually.",
476
+ failed: [...failed, ...branches.slice(merged.length + failed.length).map(b => b.branchName)],
477
+ conflict: `${branchName}: ${stderr}`,
492
478
  };
479
+ break;
480
+ }
481
+
482
+ merged.push(branchName);
483
+ }
484
+ } finally {
485
+ if (didStash) {
486
+ try {
487
+ await git.stash.pop(repoRoot, { index: true });
488
+ } catch {
489
+ // Stash-pop conflicts mean the replayed changes clash with the user's
490
+ // uncommitted edits. The cherry-picked commits are already on HEAD, so
491
+ // the merged branches DID land — report them as merged and surface the
492
+ // stash conflict separately instead of claiming they are unmerged.
493
+ logger.warn("Failed to restore stashed changes after task merge; stash entry preserved");
494
+ const stashConflict =
495
+ "stash pop: cherry-picked changes conflict with uncommitted edits. The merged commits are on HEAD; run `git stash pop` and resolve manually.";
496
+ if (conflictResult) {
497
+ conflictResult.stashConflict = stashConflict;
498
+ } else {
499
+ conflictResult = { merged, failed: [], stashConflict };
500
+ }
493
501
  }
494
502
  }
495
503
  }
496
- }
497
504
 
498
- return conflictResult ?? { merged, failed };
505
+ return conflictResult ?? { merged, failed };
506
+ });
499
507
  }
500
508
 
501
509
  /** Clean up temporary task branches. */
package/src/thinking.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type ResolvedThinkingLevel, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
- import { clampThinkingLevelForModel, Effort, getSupportedEfforts, type Model, THINKING_EFFORTS } from "@oh-my-pi/pi-ai";
2
+ import { Effort, type Model, THINKING_EFFORTS } from "@oh-my-pi/pi-ai";
3
+ import { clampThinkingLevelForModel, getSupportedEfforts } from "@oh-my-pi/pi-catalog/model-thinking";
3
4
 
4
5
  /**
5
6
  * Metadata used to render thinking selector values in the coding-agent UI.
@@ -70,6 +71,13 @@ export function toReasoningEffort(level: ThinkingLevel | undefined): Effort | un
70
71
  return level;
71
72
  }
72
73
 
74
+ /**
75
+ * True when a selector explicitly requests provider-side reasoning disablement.
76
+ */
77
+ export function shouldDisableReasoning(level: ThinkingLevel | undefined): boolean {
78
+ return level === ThinkingLevel.Off;
79
+ }
80
+
73
81
  /**
74
82
  * Resolves a selector against the current model while preserving explicit "off".
75
83
  */
@@ -1,5 +1,5 @@
1
1
  import * as path from "node:path";
2
- import { $env, isCompiledBinary, logger } from "@oh-my-pi/pi-utils";
2
+ import { $env, isBunTestRuntime, isCompiledBinary, logger, workerHostEntry } from "@oh-my-pi/pi-utils";
3
3
  import type { Subprocess } from "bun";
4
4
  import { settings } from "../config/settings";
5
5
  import { tinyModelDeviceSettingToEnv } from "./device";
@@ -39,6 +39,17 @@ export interface TinyTitleDownloadOptions {
39
39
  onProgress?: (event: TinyTitleProgressEvent) => void;
40
40
  }
41
41
 
42
+ /**
43
+ * Per-request controls for {@link TinyTitleClient.generate}.
44
+ *
45
+ * Carries the optional abort signal and title-system-prompt override used by
46
+ * callers that customize automatic session-title generation.
47
+ */
48
+ export interface TinyTitleGenerateOptions {
49
+ signal?: AbortSignal;
50
+ systemPrompt?: string;
51
+ }
52
+
42
53
  // Cold-starting the worker subprocess from a compiled binary (decompress + module
43
54
  // graph load) is slow on contended CI runners — the macos-15-intel release smoke
44
55
  // blew past 5s while arm64/linux/win passed. The probe only needs to prove the
@@ -46,6 +57,14 @@ export interface TinyTitleDownloadOptions {
46
57
  // generous bound removes the flake without weakening the check.
47
58
  const SMOKE_TEST_TIMEOUT_MS = 30_000;
48
59
 
60
+ function normalizeTinyTitleGenerateOptions(
61
+ options: AbortSignal | TinyTitleGenerateOptions | undefined,
62
+ ): TinyTitleGenerateOptions {
63
+ if (!options) return {};
64
+ if ("aborted" in options && "addEventListener" in options) return { signal: options };
65
+ return options;
66
+ }
67
+
49
68
  /**
50
69
  * Hidden subcommand on the main CLI that boots the tiny-model worker in the
51
70
  * spawned subprocess. Kept in sync with the dispatch in `cli.ts`.
@@ -108,17 +127,28 @@ function tinyWorkerEnv(): Record<string, string> {
108
127
  for (const key in overlay) merged[key] = overlay[key];
109
128
  return merged;
110
129
  }
130
+ interface TinyWorkerSpawnCommand {
131
+ cmd: string[];
132
+ cwd?: string;
133
+ }
111
134
 
112
135
  /**
113
- * Resolve the argv used to relaunch the agent CLI into tiny-worker mode. In a
114
- * compiled binary the entry point is the binary itself; in dev/source the
115
- * spawned `bun` needs the absolute path to `cli.ts` so it can resolve module
116
- * imports against the on-disk source tree.
136
+ * Resolve the command used to relaunch the agent CLI into tiny-worker mode.
137
+ * In a compiled binary the entry point is the binary itself (no script arg).
138
+ * Otherwise re-enter the declared worker-host entry (source cli.ts or
139
+ * npm-bundle cli.js) with a cwd-relative script path — Bun's subprocess IPC
140
+ * is more reliable that way than with an absolute `.ts` entry under
141
+ * `bun test` — and fall back to this package's own `src/cli.ts` when no host
142
+ * entry is declared (bun test, SDK embedding).
117
143
  */
118
- function tinyWorkerSpawnCmd(): string[] {
119
- if (isCompiledBinary()) return [process.execPath, TINY_WORKER_ARG];
120
- const cliPath = path.resolve(import.meta.dir, "..", "cli.ts");
121
- return [process.execPath, cliPath, TINY_WORKER_ARG];
144
+ function tinyWorkerSpawnCmd(): TinyWorkerSpawnCommand {
145
+ if (isCompiledBinary()) return { cmd: [process.execPath, TINY_WORKER_ARG] };
146
+ const hostEntry = workerHostEntry();
147
+ if (hostEntry) {
148
+ return { cmd: [process.execPath, path.basename(hostEntry), TINY_WORKER_ARG], cwd: path.dirname(hostEntry) };
149
+ }
150
+ const packageRoot = path.resolve(import.meta.dir, "..", "..");
151
+ return { cmd: [process.execPath, "src/cli.ts", TINY_WORKER_ARG], cwd: packageRoot };
122
152
  }
123
153
 
124
154
  interface SpawnedSubprocess {
@@ -143,8 +173,10 @@ export function createTinyTitleSubprocess(): SpawnedSubprocess {
143
173
  const inbound = new Set<(message: TinyTitleWorkerOutbound) => void>();
144
174
  const errors = new Set<(error: Error) => void>();
145
175
  const intentionalExit = { value: false };
176
+ const spawnCommand = tinyWorkerSpawnCmd();
146
177
  const proc = Bun.spawn({
147
- cmd: tinyWorkerSpawnCmd(),
178
+ cmd: spawnCommand.cmd,
179
+ cwd: spawnCommand.cwd,
148
180
  env: tinyWorkerEnv(),
149
181
  stdin: "ignore",
150
182
  stdout: "ignore",
@@ -175,7 +207,9 @@ export function createTinyTitleSubprocess(): SpawnedSubprocess {
175
207
  });
176
208
  // Don't keep the parent event loop alive on account of an idle worker; the
177
209
  // agent dispose path calls `terminate()` explicitly when shutting down.
178
- proc.unref();
210
+ // Bun's test runner can starve IPC delivery for unref'd subprocesses, so
211
+ // keep it referenced only under tests that assert the ping/pong contract.
212
+ if (!isBunTestRuntime()) proc.unref();
179
213
  return { proc, inbound, errors, intentionalExit };
180
214
  }
181
215
 
@@ -280,9 +314,16 @@ export class TinyTitleClient {
280
314
  return () => this.#progressListeners.delete(listener);
281
315
  }
282
316
 
283
- async generate(modelKey: string, message: string, signal?: AbortSignal): Promise<string | null> {
317
+ async generate(modelKey: string, message: string, signal?: AbortSignal): Promise<string | null>;
318
+ async generate(modelKey: string, message: string, options?: TinyTitleGenerateOptions): Promise<string | null>;
319
+ async generate(
320
+ modelKey: string,
321
+ message: string,
322
+ optionsOrSignal?: AbortSignal | TinyTitleGenerateOptions,
323
+ ): Promise<string | null> {
324
+ const options = normalizeTinyTitleGenerateOptions(optionsOrSignal);
284
325
  if (!isTinyTitleLocalModelKey(modelKey)) return null;
285
- if (signal?.aborted) return null;
326
+ if (options.signal?.aborted) return null;
286
327
 
287
328
  try {
288
329
  const worker = this.#ensureWorker();
@@ -295,12 +336,15 @@ export class TinyTitleClient {
295
336
  this.#pending.delete(id);
296
337
  pending.resolve(null);
297
338
  };
298
- signal?.addEventListener("abort", abort, { once: true });
339
+ options.signal?.addEventListener("abort", abort, { once: true });
299
340
  try {
300
- worker.send({ type: "generate", id, modelKey, message });
341
+ const request: TinyTitleWorkerInbound = options.systemPrompt
342
+ ? { type: "generate", id, modelKey, message, systemPrompt: options.systemPrompt }
343
+ : { type: "generate", id, modelKey, message };
344
+ worker.send(request);
301
345
  return await promise;
302
346
  } finally {
303
- signal?.removeEventListener("abort", abort);
347
+ options.signal?.removeEventListener("abort", abort);
304
348
  this.#pending.delete(id);
305
349
  }
306
350
  } catch (error) {
@@ -29,7 +29,7 @@ export interface TinyTitleProgressEvent {
29
29
 
30
30
  export type TinyTitleWorkerInbound =
31
31
  | { type: "ping"; id: string }
32
- | { type: "generate"; id: string; modelKey: TinyTitleLocalModelKey; message: string }
32
+ | { type: "generate"; id: string; modelKey: TinyTitleLocalModelKey; message: string; systemPrompt?: string }
33
33
  | { type: "complete"; id: string; modelKey: TinyLocalModelKey; prompt: string; maxTokens?: number }
34
34
  | { type: "download"; id: string; modelKey: TinyLocalModelKey };
35
35
 
@@ -436,9 +436,10 @@ async function loadPipeline(
436
436
  return loaded;
437
437
  }
438
438
 
439
- function buildPrompt(generator: TextGenerationPipeline, message: string): string {
439
+ function buildPrompt(generator: TextGenerationPipeline, message: string, systemPrompt?: string): string {
440
+ const selectedSystemPrompt = systemPrompt?.trim() || TINY_TITLE_SYSTEM_PROMPT;
440
441
  const chat = [
441
- { role: "system", content: TINY_TITLE_SYSTEM_PROMPT },
442
+ { role: "system", content: selectedSystemPrompt },
442
443
  { role: "user", content: formatTitleUserMessage(message) },
443
444
  ];
444
445
  const chatTemplateOptions = {
@@ -464,9 +465,10 @@ async function generateTitle(
464
465
  requestId: string,
465
466
  modelKey: TinyTitleLocalModelKey,
466
467
  message: string,
468
+ systemPrompt?: string,
467
469
  ): Promise<string | null> {
468
470
  const generator = await loadPipeline(modelKey, transport, requestId);
469
- const promptText = buildPrompt(generator, message);
471
+ const promptText = buildPrompt(generator, message, systemPrompt);
470
472
  const transformers = await loadTransformers(transport, requestId, modelKey);
471
473
  const output = (await generator(promptText, {
472
474
  max_new_tokens: TITLE_MAX_NEW_TOKENS,
@@ -548,7 +550,7 @@ async function handleQueuedRequest(
548
550
  transport.send({ type: "completion", id: request.id, text });
549
551
  return;
550
552
  }
551
- const title = await generateTitle(transport, request.id, request.modelKey, request.message);
553
+ const title = await generateTitle(transport, request.id, request.modelKey, request.message, request.systemPrompt);
552
554
  transport.send({ type: "title", id: request.id, title });
553
555
  } catch (error) {
554
556
  transport.send({ type: "error", id: request.id, error: errorText(error) });
@@ -6,6 +6,19 @@ import { inflateSync, strFromU8 } from "fflate";
6
6
  import { formatBytes } from "./render-utils";
7
7
  import { ToolError } from "./tool-errors";
8
8
 
9
+ /**
10
+ * Cap on the on-disk size of tar/tar.gz archives, which are loaded fully into
11
+ * memory (and decompressed by `Bun.Archive`) just to index entries. ZIP is
12
+ * exempt: it is read via ranged central-directory access.
13
+ */
14
+ const MAX_TAR_ARCHIVE_BYTES = 256 * 1024 * 1024;
15
+ /**
16
+ * Cap on a single archive member's declared (uncompressed) size. The declared
17
+ * size is attacker-controlled metadata — a crafted ZIP entry can claim
18
+ * multi-GB sizes that would be allocated up front before any data inflates.
19
+ */
20
+ const MAX_ARCHIVE_MEMBER_BYTES = 64 * 1024 * 1024;
21
+
9
22
  export type ArchiveFormat = "zip" | "tar" | "tar.gz";
10
23
 
11
24
  export interface ArchivePathCandidate {
@@ -646,6 +659,11 @@ export class ArchiveReader {
646
659
  if (!entry.storage) {
647
660
  throw new ToolError(`Archive file '${normalizedPath}' has no readable storage`);
648
661
  }
662
+ if (entry.size > MAX_ARCHIVE_MEMBER_BYTES) {
663
+ throw new ToolError(
664
+ `Archive member '${normalizedPath}' is too large to extract in memory (${formatBytes(entry.size)} > ${formatBytes(MAX_ARCHIVE_MEMBER_BYTES)} limit)`,
665
+ );
666
+ }
649
667
 
650
668
  const bytes =
651
669
  entry.storage.type === "tar"
@@ -668,8 +686,18 @@ export async function openArchive(filePath: string): Promise<ArchiveReader> {
668
686
  throw new ToolError(`Unsupported archive format: ${filePath}`);
669
687
  }
670
688
 
671
- const entries =
672
- format === "zip" ? await readZipEntries(filePath) : await readTarEntries(await Bun.file(filePath).bytes());
689
+ if (format === "zip") {
690
+ return new ArchiveReader(format, await readZipEntries(filePath));
691
+ }
692
+
693
+ const file = Bun.file(filePath);
694
+ const archiveSize = file.size;
695
+ if (archiveSize > MAX_TAR_ARCHIVE_BYTES) {
696
+ throw new ToolError(
697
+ `Archive is too large to read in memory (${formatBytes(archiveSize)} > ${formatBytes(MAX_TAR_ARCHIVE_BYTES)} limit)`,
698
+ );
699
+ }
700
+ const entries = await readTarEntries(await file.bytes());
673
701
  return new ArchiveReader(format, entries);
674
702
  }
675
703