pi-ui-extend 0.1.1

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 (420) hide show
  1. package/README.md +307 -0
  2. package/bin/pix.mjs +219 -0
  3. package/dist/app/app.d.ts +96 -0
  4. package/dist/app/app.js +871 -0
  5. package/dist/app/blink-controller.d.ts +23 -0
  6. package/dist/app/blink-controller.js +82 -0
  7. package/dist/app/cli.d.ts +8 -0
  8. package/dist/app/cli.js +83 -0
  9. package/dist/app/clipboard.d.ts +1 -0
  10. package/dist/app/clipboard.js +24 -0
  11. package/dist/app/command-controller.d.ts +18 -0
  12. package/dist/app/command-controller.js +58 -0
  13. package/dist/app/command-host.d.ts +44 -0
  14. package/dist/app/command-host.js +1 -0
  15. package/dist/app/command-model-actions.d.ts +12 -0
  16. package/dist/app/command-model-actions.js +176 -0
  17. package/dist/app/command-navigation-actions.d.ts +19 -0
  18. package/dist/app/command-navigation-actions.js +267 -0
  19. package/dist/app/command-registry.d.ts +32 -0
  20. package/dist/app/command-registry.js +225 -0
  21. package/dist/app/command-runtime.d.ts +5 -0
  22. package/dist/app/command-runtime.js +32 -0
  23. package/dist/app/command-session-actions.d.ts +20 -0
  24. package/dist/app/command-session-actions.js +295 -0
  25. package/dist/app/constants.d.ts +52 -0
  26. package/dist/app/constants.js +103 -0
  27. package/dist/app/conversation-entry-renderer.d.ts +21 -0
  28. package/dist/app/conversation-entry-renderer.js +81 -0
  29. package/dist/app/conversation-shell-renderer.d.ts +5 -0
  30. package/dist/app/conversation-shell-renderer.js +43 -0
  31. package/dist/app/conversation-tool-renderer.d.ts +16 -0
  32. package/dist/app/conversation-tool-renderer.js +216 -0
  33. package/dist/app/conversation-viewport.d.ts +55 -0
  34. package/dist/app/conversation-viewport.js +252 -0
  35. package/dist/app/dcp-stats.d.ts +2 -0
  36. package/dist/app/dcp-stats.js +116 -0
  37. package/dist/app/editor-layout-renderer.d.ts +31 -0
  38. package/dist/app/editor-layout-renderer.js +211 -0
  39. package/dist/app/editor-panels.d.ts +4 -0
  40. package/dist/app/editor-panels.js +130 -0
  41. package/dist/app/extension-actions-controller.d.ts +22 -0
  42. package/dist/app/extension-actions-controller.js +60 -0
  43. package/dist/app/extension-event-bus.d.ts +3 -0
  44. package/dist/app/extension-event-bus.js +23 -0
  45. package/dist/app/extension-ui-controller.d.ts +57 -0
  46. package/dist/app/extension-ui-controller.js +532 -0
  47. package/dist/app/file-link-opener.d.ts +2 -0
  48. package/dist/app/file-link-opener.js +66 -0
  49. package/dist/app/file-links.d.ts +10 -0
  50. package/dist/app/file-links.js +117 -0
  51. package/dist/app/guards.d.ts +3 -0
  52. package/dist/app/guards.js +9 -0
  53. package/dist/app/icons.d.ts +37 -0
  54. package/dist/app/icons.js +97 -0
  55. package/dist/app/id.d.ts +1 -0
  56. package/dist/app/id.js +4 -0
  57. package/dist/app/image-click-targets.d.ts +5 -0
  58. package/dist/app/image-click-targets.js +32 -0
  59. package/dist/app/image-opener.d.ts +2 -0
  60. package/dist/app/image-opener.js +64 -0
  61. package/dist/app/input-action-controller.d.ts +47 -0
  62. package/dist/app/input-action-controller.js +209 -0
  63. package/dist/app/input-controller.d.ts +60 -0
  64. package/dist/app/input-controller.js +425 -0
  65. package/dist/app/input-paste-handler.d.ts +27 -0
  66. package/dist/app/input-paste-handler.js +146 -0
  67. package/dist/app/menu-items-controller.d.ts +32 -0
  68. package/dist/app/menu-items-controller.js +182 -0
  69. package/dist/app/message-content.d.ts +8 -0
  70. package/dist/app/message-content.js +115 -0
  71. package/dist/app/model-ref.d.ts +13 -0
  72. package/dist/app/model-ref.js +50 -0
  73. package/dist/app/model-usage-controller.d.ts +35 -0
  74. package/dist/app/model-usage-controller.js +99 -0
  75. package/dist/app/model-usage-status.d.ts +125 -0
  76. package/dist/app/model-usage-status.js +749 -0
  77. package/dist/app/mouse-controller.d.ts +182 -0
  78. package/dist/app/mouse-controller.js +968 -0
  79. package/dist/app/native-modifiers.d.ts +3 -0
  80. package/dist/app/native-modifiers.js +60 -0
  81. package/dist/app/nerd-font-controller.d.ts +11 -0
  82. package/dist/app/nerd-font-controller.js +90 -0
  83. package/dist/app/popup-action-controller.d.ts +44 -0
  84. package/dist/app/popup-action-controller.js +278 -0
  85. package/dist/app/popup-menu-controller.d.ts +183 -0
  86. package/dist/app/popup-menu-controller.js +1070 -0
  87. package/dist/app/prompt-enhancer-controller.d.ts +40 -0
  88. package/dist/app/prompt-enhancer-controller.js +215 -0
  89. package/dist/app/queued-message-controller.d.ts +62 -0
  90. package/dist/app/queued-message-controller.js +377 -0
  91. package/dist/app/render-controller.d.ts +41 -0
  92. package/dist/app/render-controller.js +378 -0
  93. package/dist/app/render-text.d.ts +19 -0
  94. package/dist/app/render-text.js +67 -0
  95. package/dist/app/request-history.d.ts +23 -0
  96. package/dist/app/request-history.js +131 -0
  97. package/dist/app/runtime.d.ts +39 -0
  98. package/dist/app/runtime.js +195 -0
  99. package/dist/app/screen-selection.d.ts +6 -0
  100. package/dist/app/screen-selection.js +9 -0
  101. package/dist/app/screen-styler.d.ts +34 -0
  102. package/dist/app/screen-styler.js +168 -0
  103. package/dist/app/scroll-controller.d.ts +51 -0
  104. package/dist/app/scroll-controller.js +207 -0
  105. package/dist/app/session-event-controller.d.ts +69 -0
  106. package/dist/app/session-event-controller.js +338 -0
  107. package/dist/app/session-history.d.ts +23 -0
  108. package/dist/app/session-history.js +164 -0
  109. package/dist/app/session-lifecycle-controller.d.ts +55 -0
  110. package/dist/app/session-lifecycle-controller.js +116 -0
  111. package/dist/app/session-search.d.ts +24 -0
  112. package/dist/app/session-search.js +215 -0
  113. package/dist/app/shell-command.d.ts +27 -0
  114. package/dist/app/shell-command.js +176 -0
  115. package/dist/app/shell-controller.d.ts +28 -0
  116. package/dist/app/shell-controller.js +124 -0
  117. package/dist/app/slash-commands.d.ts +6 -0
  118. package/dist/app/slash-commands.js +75 -0
  119. package/dist/app/startup-checks.d.ts +8 -0
  120. package/dist/app/startup-checks.js +59 -0
  121. package/dist/app/startup-info.d.ts +3 -0
  122. package/dist/app/startup-info.js +176 -0
  123. package/dist/app/status-controller.d.ts +35 -0
  124. package/dist/app/status-controller.js +105 -0
  125. package/dist/app/status-line-renderer.d.ts +68 -0
  126. package/dist/app/status-line-renderer.js +453 -0
  127. package/dist/app/subagents-files.d.ts +10 -0
  128. package/dist/app/subagents-files.js +193 -0
  129. package/dist/app/subagents-model.d.ts +23 -0
  130. package/dist/app/subagents-model.js +224 -0
  131. package/dist/app/subagents-widget-controller.d.ts +43 -0
  132. package/dist/app/subagents-widget-controller.js +311 -0
  133. package/dist/app/tab-line-renderer.d.ts +26 -0
  134. package/dist/app/tab-line-renderer.js +222 -0
  135. package/dist/app/tabs-controller.d.ts +100 -0
  136. package/dist/app/tabs-controller.js +885 -0
  137. package/dist/app/terminal-controller.d.ts +40 -0
  138. package/dist/app/terminal-controller.js +135 -0
  139. package/dist/app/terminal-edit-shortcuts.d.ts +23 -0
  140. package/dist/app/terminal-edit-shortcuts.js +138 -0
  141. package/dist/app/terminal-output-buffer.d.ts +20 -0
  142. package/dist/app/terminal-output-buffer.js +52 -0
  143. package/dist/app/toast-controller.d.ts +13 -0
  144. package/dist/app/toast-controller.js +40 -0
  145. package/dist/app/toast-renderer.d.ts +9 -0
  146. package/dist/app/toast-renderer.js +79 -0
  147. package/dist/app/todo-model.d.ts +22 -0
  148. package/dist/app/todo-model.js +179 -0
  149. package/dist/app/todo-widget-controller.d.ts +21 -0
  150. package/dist/app/todo-widget-controller.js +59 -0
  151. package/dist/app/tool-block-renderer.d.ts +26 -0
  152. package/dist/app/tool-block-renderer.js +439 -0
  153. package/dist/app/types.d.ts +550 -0
  154. package/dist/app/types.js +1 -0
  155. package/dist/app/update.d.ts +36 -0
  156. package/dist/app/update.js +315 -0
  157. package/dist/app/voice-controller.d.ts +52 -0
  158. package/dist/app/voice-controller.js +600 -0
  159. package/dist/app/workspace-actions-controller.d.ts +40 -0
  160. package/dist/app/workspace-actions-controller.js +215 -0
  161. package/dist/app/workspace-undo.d.ts +44 -0
  162. package/dist/app/workspace-undo.js +215 -0
  163. package/dist/config.d.ts +62 -0
  164. package/dist/config.js +527 -0
  165. package/dist/context-progress-bar.d.ts +17 -0
  166. package/dist/context-progress-bar.js +48 -0
  167. package/dist/default-pix-config.d.ts +1 -0
  168. package/dist/default-pix-config.js +375 -0
  169. package/dist/fuzzy.d.ts +23 -0
  170. package/dist/fuzzy.js +165 -0
  171. package/dist/input-editor-files.d.ts +15 -0
  172. package/dist/input-editor-files.js +62 -0
  173. package/dist/input-editor.d.ts +186 -0
  174. package/dist/input-editor.js +835 -0
  175. package/dist/main.d.ts +1 -0
  176. package/dist/main.js +12 -0
  177. package/dist/markdown-format.d.ts +22 -0
  178. package/dist/markdown-format.js +542 -0
  179. package/dist/sdk.d.ts +3 -0
  180. package/dist/sdk.js +1 -0
  181. package/dist/syntax-highlight.d.ts +22 -0
  182. package/dist/syntax-highlight.js +528 -0
  183. package/dist/terminal-width.d.ts +6 -0
  184. package/dist/terminal-width.js +245 -0
  185. package/dist/theme.d.ts +56 -0
  186. package/dist/theme.js +118 -0
  187. package/dist/tool-renderers/apply-patch.d.ts +2 -0
  188. package/dist/tool-renderers/apply-patch.js +36 -0
  189. package/dist/tool-renderers/ast.d.ts +2 -0
  190. package/dist/tool-renderers/ast.js +5 -0
  191. package/dist/tool-renderers/compress.d.ts +2 -0
  192. package/dist/tool-renderers/compress.js +126 -0
  193. package/dist/tool-renderers/index.d.ts +3 -0
  194. package/dist/tool-renderers/index.js +44 -0
  195. package/dist/tool-renderers/question.d.ts +2 -0
  196. package/dist/tool-renderers/question.js +88 -0
  197. package/dist/tool-renderers/read.d.ts +2 -0
  198. package/dist/tool-renderers/read.js +36 -0
  199. package/dist/tool-renderers/repo.d.ts +2 -0
  200. package/dist/tool-renderers/repo.js +13 -0
  201. package/dist/tool-renderers/shell.d.ts +3 -0
  202. package/dist/tool-renderers/shell.js +27 -0
  203. package/dist/tool-renderers/skill.d.ts +2 -0
  204. package/dist/tool-renderers/skill.js +132 -0
  205. package/dist/tool-renderers/subagents.d.ts +2 -0
  206. package/dist/tool-renderers/subagents.js +51 -0
  207. package/dist/tool-renderers/todo.d.ts +2 -0
  208. package/dist/tool-renderers/todo.js +9 -0
  209. package/dist/tool-renderers/types.d.ts +42 -0
  210. package/dist/tool-renderers/types.js +1 -0
  211. package/dist/tool-renderers/utils.d.ts +31 -0
  212. package/dist/tool-renderers/utils.js +230 -0
  213. package/dist/tool-renderers/web.d.ts +3 -0
  214. package/dist/tool-renderers/web.js +9 -0
  215. package/dist/tool-renderers/write.d.ts +2 -0
  216. package/dist/tool-renderers/write.js +42 -0
  217. package/dist/ui.d.ts +56 -0
  218. package/dist/ui.js +94 -0
  219. package/docs/release.md +81 -0
  220. package/extensions/question/contract.ts +100 -0
  221. package/extensions/question/index.ts +34 -0
  222. package/extensions/question/render.ts +28 -0
  223. package/extensions/question/result.ts +86 -0
  224. package/extensions/question/tool-description.ts +11 -0
  225. package/extensions/question/tui.ts +629 -0
  226. package/extensions/question/types.ts +123 -0
  227. package/extensions/session-title/config.ts +169 -0
  228. package/extensions/session-title/index.ts +459 -0
  229. package/extensions/terminal-bell/index.ts +315 -0
  230. package/external/pi-tools-suite/README.md +242 -0
  231. package/external/pi-tools-suite/index.ts +1 -0
  232. package/external/pi-tools-suite/licenses/ollama-pi-web-search.MIT +21 -0
  233. package/external/pi-tools-suite/licenses/opencode-mystatus-MIT.txt +21 -0
  234. package/external/pi-tools-suite/package.json +53 -0
  235. package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +194 -0
  236. package/external/pi-tools-suite/src/antigravity-auth/commands.ts +80 -0
  237. package/external/pi-tools-suite/src/antigravity-auth/constants.ts +26 -0
  238. package/external/pi-tools-suite/src/antigravity-auth/headers.ts +20 -0
  239. package/external/pi-tools-suite/src/antigravity-auth/index.ts +104 -0
  240. package/external/pi-tools-suite/src/antigravity-auth/models.ts +86 -0
  241. package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +305 -0
  242. package/external/pi-tools-suite/src/antigravity-auth/payload.ts +423 -0
  243. package/external/pi-tools-suite/src/antigravity-auth/status.ts +78 -0
  244. package/external/pi-tools-suite/src/antigravity-auth/stream.ts +302 -0
  245. package/external/pi-tools-suite/src/antigravity-auth/types.ts +113 -0
  246. package/external/pi-tools-suite/src/ast-grep/index.ts +6 -0
  247. package/external/pi-tools-suite/src/ast-grep/render.ts +70 -0
  248. package/external/pi-tools-suite/src/ast-grep/schema.ts +109 -0
  249. package/external/pi-tools-suite/src/ast-grep/tool.ts +345 -0
  250. package/external/pi-tools-suite/src/ast-grep/types.ts +55 -0
  251. package/external/pi-tools-suite/src/ast-grep/utils.ts +65 -0
  252. package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +222 -0
  253. package/external/pi-tools-suite/src/async-subagents/commands.ts +518 -0
  254. package/external/pi-tools-suite/src/async-subagents/constants.ts +11 -0
  255. package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +74 -0
  256. package/external/pi-tools-suite/src/async-subagents/core/attachment-bridge.ts +133 -0
  257. package/external/pi-tools-suite/src/async-subagents/core/cleanup.ts +66 -0
  258. package/external/pi-tools-suite/src/async-subagents/core/concurrency.ts +90 -0
  259. package/external/pi-tools-suite/src/async-subagents/core/config.ts +819 -0
  260. package/external/pi-tools-suite/src/async-subagents/core/log-limits.ts +166 -0
  261. package/external/pi-tools-suite/src/async-subagents/core/model-fallback.ts +133 -0
  262. package/external/pi-tools-suite/src/async-subagents/core/paths.ts +47 -0
  263. package/external/pi-tools-suite/src/async-subagents/core/pi-invocation.ts +35 -0
  264. package/external/pi-tools-suite/src/async-subagents/core/presets.ts +67 -0
  265. package/external/pi-tools-suite/src/async-subagents/core/process.ts +15 -0
  266. package/external/pi-tools-suite/src/async-subagents/core/prompt.ts +66 -0
  267. package/external/pi-tools-suite/src/async-subagents/core/registry.ts +224 -0
  268. package/external/pi-tools-suite/src/async-subagents/core/retry.ts +191 -0
  269. package/external/pi-tools-suite/src/async-subagents/core/routing.ts +259 -0
  270. package/external/pi-tools-suite/src/async-subagents/core/sessions.ts +138 -0
  271. package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +688 -0
  272. package/external/pi-tools-suite/src/async-subagents/core/state.ts +281 -0
  273. package/external/pi-tools-suite/src/async-subagents/core/stop.ts +131 -0
  274. package/external/pi-tools-suite/src/async-subagents/core/structured-result.ts +237 -0
  275. package/external/pi-tools-suite/src/async-subagents/core/tool-guard.ts +34 -0
  276. package/external/pi-tools-suite/src/async-subagents/core/types.ts +150 -0
  277. package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +184 -0
  278. package/external/pi-tools-suite/src/async-subagents/core/utils.ts +11 -0
  279. package/external/pi-tools-suite/src/async-subagents/format.ts +41 -0
  280. package/external/pi-tools-suite/src/async-subagents/index.ts +422 -0
  281. package/external/pi-tools-suite/src/async-subagents/lib.ts +88 -0
  282. package/external/pi-tools-suite/src/async-subagents/live.ts +10 -0
  283. package/external/pi-tools-suite/src/async-subagents/polling.ts +83 -0
  284. package/external/pi-tools-suite/src/async-subagents/render.ts +230 -0
  285. package/external/pi-tools-suite/src/async-subagents/subagent-overlay.ts +77 -0
  286. package/external/pi-tools-suite/src/async-subagents/tasks.ts +120 -0
  287. package/external/pi-tools-suite/src/async-subagents/tools/cleanup.ts +99 -0
  288. package/external/pi-tools-suite/src/async-subagents/tools/result.ts +179 -0
  289. package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +372 -0
  290. package/external/pi-tools-suite/src/async-subagents/tools/status.ts +60 -0
  291. package/external/pi-tools-suite/src/async-subagents/tools/stop.ts +79 -0
  292. package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +152 -0
  293. package/external/pi-tools-suite/src/async-subagents/tools/wait.ts +67 -0
  294. package/external/pi-tools-suite/src/async-subagents/types.ts +45 -0
  295. package/external/pi-tools-suite/src/async-subagents/ui.ts +5 -0
  296. package/external/pi-tools-suite/src/compress/commands.ts +440 -0
  297. package/external/pi-tools-suite/src/compress/compress-tool.ts +368 -0
  298. package/external/pi-tools-suite/src/compress/compression-blocks.ts +524 -0
  299. package/external/pi-tools-suite/src/compress/config.ts +310 -0
  300. package/external/pi-tools-suite/src/compress/dcp-tui-filter.ts +498 -0
  301. package/external/pi-tools-suite/src/compress/index.ts +397 -0
  302. package/external/pi-tools-suite/src/compress/prompts.ts +269 -0
  303. package/external/pi-tools-suite/src/compress/pruner-candidates.ts +176 -0
  304. package/external/pi-tools-suite/src/compress/pruner-compression-blocks.ts +260 -0
  305. package/external/pi-tools-suite/src/compress/pruner-message-ids.ts +147 -0
  306. package/external/pi-tools-suite/src/compress/pruner-metadata.ts +268 -0
  307. package/external/pi-tools-suite/src/compress/pruner-nudge.ts +315 -0
  308. package/external/pi-tools-suite/src/compress/pruner-tools.ts +263 -0
  309. package/external/pi-tools-suite/src/compress/pruner-types.ts +25 -0
  310. package/external/pi-tools-suite/src/compress/pruner.ts +92 -0
  311. package/external/pi-tools-suite/src/compress/state.ts +486 -0
  312. package/external/pi-tools-suite/src/compress/ui.ts +308 -0
  313. package/external/pi-tools-suite/src/config.ts +176 -0
  314. package/external/pi-tools-suite/src/context-usage.ts +31 -0
  315. package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +355 -0
  316. package/external/pi-tools-suite/src/index.ts +46 -0
  317. package/external/pi-tools-suite/src/lib/lsp.ts +62 -0
  318. package/external/pi-tools-suite/src/lib/project.ts +42 -0
  319. package/external/pi-tools-suite/src/lib/tool-args.ts +137 -0
  320. package/external/pi-tools-suite/src/lsp/_shared/config.ts +156 -0
  321. package/external/pi-tools-suite/src/lsp/_shared/glob.ts +60 -0
  322. package/external/pi-tools-suite/src/lsp/_shared/output.ts +102 -0
  323. package/external/pi-tools-suite/src/lsp/_shared/paths.ts +138 -0
  324. package/external/pi-tools-suite/src/lsp/_shared/runner.ts +64 -0
  325. package/external/pi-tools-suite/src/lsp/_shared/template.ts +23 -0
  326. package/external/pi-tools-suite/src/lsp/_shared/trust.ts +116 -0
  327. package/external/pi-tools-suite/src/lsp/_shared/types.ts +98 -0
  328. package/external/pi-tools-suite/src/lsp/async.ts +29 -0
  329. package/external/pi-tools-suite/src/lsp/child-process.ts +81 -0
  330. package/external/pi-tools-suite/src/lsp/client.ts +340 -0
  331. package/external/pi-tools-suite/src/lsp/constants.ts +9 -0
  332. package/external/pi-tools-suite/src/lsp/diagnostics-store.ts +64 -0
  333. package/external/pi-tools-suite/src/lsp/documents.ts +24 -0
  334. package/external/pi-tools-suite/src/lsp/index.ts +31 -0
  335. package/external/pi-tools-suite/src/lsp/lsp-utils.ts +37 -0
  336. package/external/pi-tools-suite/src/lsp/manager.ts +190 -0
  337. package/external/pi-tools-suite/src/lsp/mutation-events.ts +78 -0
  338. package/external/pi-tools-suite/src/lsp/renderer.ts +1 -0
  339. package/external/pi-tools-suite/src/lsp/tool-result.ts +6 -0
  340. package/external/pi-tools-suite/src/lsp/tsserver.ts +107 -0
  341. package/external/pi-tools-suite/src/lsp/types.ts +15 -0
  342. package/external/pi-tools-suite/src/model-tools/apply-patch.ts +590 -0
  343. package/external/pi-tools-suite/src/model-tools/index.ts +430 -0
  344. package/external/pi-tools-suite/src/model-tools/path-utils.ts +6 -0
  345. package/external/pi-tools-suite/src/model-tools/tool-args.ts +11 -0
  346. package/external/pi-tools-suite/src/prompt-commands/index.ts +349 -0
  347. package/external/pi-tools-suite/src/repo-discovery/index.ts +384 -0
  348. package/external/pi-tools-suite/src/repo-discovery/project.ts +7 -0
  349. package/external/pi-tools-suite/src/startup-section.ts +13 -0
  350. package/external/pi-tools-suite/src/terminal-bell/index.ts +309 -0
  351. package/external/pi-tools-suite/src/todo/index.ts +201 -0
  352. package/external/pi-tools-suite/src/todo/state/auto-clear.ts +13 -0
  353. package/external/pi-tools-suite/src/todo/state/invariants.ts +21 -0
  354. package/external/pi-tools-suite/src/todo/state/persistence.ts +94 -0
  355. package/external/pi-tools-suite/src/todo/state/replay.ts +38 -0
  356. package/external/pi-tools-suite/src/todo/state/selectors.ts +49 -0
  357. package/external/pi-tools-suite/src/todo/state/state-reducer.ts +362 -0
  358. package/external/pi-tools-suite/src/todo/state/state.ts +18 -0
  359. package/external/pi-tools-suite/src/todo/state/store.ts +52 -0
  360. package/external/pi-tools-suite/src/todo/state/task-graph.ts +57 -0
  361. package/external/pi-tools-suite/src/todo/todo.ts +487 -0
  362. package/external/pi-tools-suite/src/todo/tool/response-envelope.ts +143 -0
  363. package/external/pi-tools-suite/src/todo/tool/types.ts +188 -0
  364. package/external/pi-tools-suite/src/todo/view/format.ts +18 -0
  365. package/external/pi-tools-suite/src/todo/view/labels.ts +13 -0
  366. package/external/pi-tools-suite/src/tool-descriptions.ts +369 -0
  367. package/external/pi-tools-suite/src/usage/index.ts +152 -0
  368. package/external/pi-tools-suite/src/usage/lib/copilot.ts +535 -0
  369. package/external/pi-tools-suite/src/usage/lib/google.ts +478 -0
  370. package/external/pi-tools-suite/src/usage/lib/openai.ts +268 -0
  371. package/external/pi-tools-suite/src/usage/lib/types.ts +114 -0
  372. package/external/pi-tools-suite/src/usage/lib/utils.ts +134 -0
  373. package/external/pi-tools-suite/src/usage/lib/zhipu.ts +228 -0
  374. package/external/pi-tools-suite/src/web-search/index.ts +397 -0
  375. package/package.json +89 -0
  376. package/skills/context7/SKILL.md +69 -0
  377. package/skills/context7/scripts/context7.sh +73 -0
  378. package/skills/handoff/SKILL.md +15 -0
  379. package/skills/pdf/LICENSE.txt +30 -0
  380. package/skills/pdf/SKILL.md +314 -0
  381. package/skills/pdf/forms.md +294 -0
  382. package/skills/pdf/reference.md +612 -0
  383. package/skills/pdf/scripts/check_bounding_boxes.py +65 -0
  384. package/skills/pdf/scripts/check_fillable_fields.py +11 -0
  385. package/skills/pdf/scripts/convert_pdf_to_images.py +33 -0
  386. package/skills/pdf/scripts/create_validation_image.py +37 -0
  387. package/skills/pdf/scripts/extract_form_field_info.py +122 -0
  388. package/skills/pdf/scripts/extract_form_structure.py +115 -0
  389. package/skills/pdf/scripts/fill_fillable_fields.py +98 -0
  390. package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
  391. package/skills/playwright-cli/SKILL.md +388 -0
  392. package/skills/playwright-cli/references/element-attributes.md +23 -0
  393. package/skills/playwright-cli/references/playwright-tests.md +39 -0
  394. package/skills/playwright-cli/references/request-mocking.md +87 -0
  395. package/skills/playwright-cli/references/running-code.md +241 -0
  396. package/skills/playwright-cli/references/session-management.md +225 -0
  397. package/skills/playwright-cli/references/spec-driven-testing.md +305 -0
  398. package/skills/playwright-cli/references/storage-state.md +275 -0
  399. package/skills/playwright-cli/references/test-generation.md +134 -0
  400. package/skills/playwright-cli/references/tracing.md +139 -0
  401. package/skills/playwright-cli/references/video-recording.md +143 -0
  402. package/skills/simplify/SKILL.md +51 -0
  403. package/skills/skill-creator/LICENSE.txt +202 -0
  404. package/skills/skill-creator/SKILL.md +485 -0
  405. package/skills/skill-creator/agents/analyzer.md +274 -0
  406. package/skills/skill-creator/agents/comparator.md +202 -0
  407. package/skills/skill-creator/agents/grader.md +223 -0
  408. package/skills/skill-creator/assets/eval_review.html +146 -0
  409. package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  410. package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  411. package/skills/skill-creator/references/schemas.md +430 -0
  412. package/skills/skill-creator/scripts/__init__.py +0 -0
  413. package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  414. package/skills/skill-creator/scripts/generate_report.py +326 -0
  415. package/skills/skill-creator/scripts/improve_description.py +247 -0
  416. package/skills/skill-creator/scripts/package_skill.py +136 -0
  417. package/skills/skill-creator/scripts/quick_validate.py +103 -0
  418. package/skills/skill-creator/scripts/run_eval.py +310 -0
  419. package/skills/skill-creator/scripts/run_loop.py +328 -0
  420. package/skills/skill-creator/scripts/utils.py +47 -0
@@ -0,0 +1,179 @@
1
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
2
+ import { Type } from "@mariozechner/pi-ai";
3
+ import * as path from "node:path";
4
+ import { ASYNC_SUBAGENT_TOOL_DESCRIPTIONS } from "../../tool-descriptions.js";
5
+ import { readResult, resolveSubagentAgentRunDir, validateBasename } from "../lib.js";
6
+ import type { AgentResult } from "../lib.js";
7
+ import type { StructuredFileReference, StructuredFinding, StructuredRisk } from "../core/types.js";
8
+ import { INLINE_RENDERING } from "../constants.js";
9
+ import { truncate } from "../format.js";
10
+ import { emptyToolSlot } from "../ui.js";
11
+
12
+ const MAX_COMPACT_FINDINGS = 10;
13
+ const MAX_COMPACT_FILES = 20;
14
+ const MAX_COMPACT_RISKS = 10;
15
+ const MAX_COMPACT_NEXT_ACTIONS = 10;
16
+
17
+ interface ResultArtifactPaths {
18
+ resultMd: string;
19
+ resultJson: string;
20
+ stderrLog: string;
21
+ }
22
+
23
+ export function registerResultTool(pi: ExtensionAPI): void {
24
+ pi.registerTool({
25
+ ...ASYNC_SUBAGENT_TOOL_DESCRIPTIONS.resultAction,
26
+ ...INLINE_RENDERING,
27
+ parameters: Type.Object({
28
+ runDir: Type.Optional(Type.String({ description: "Run directory path. If omitted, resolves agentId through the project sub-agent registry under .pi/subagents/registry.json, falling back to scanning .pi/subagents/." })),
29
+ agentId: Type.String({ description: "Agent ID to read" }),
30
+ compact: Type.Optional(Type.Boolean({ description: "Return summary and artifact paths instead of raw output (default true); set false for full result/stderr", default: true })),
31
+ }),
32
+
33
+ async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
34
+ validateBasename(params.agentId, "agentId");
35
+ const runDir = resolveSubagentAgentRunDir(ctx.cwd, params.agentId, params.runDir);
36
+ const result = readResult(runDir, params.agentId);
37
+
38
+ if (!result) {
39
+ return {
40
+ content: [{ type: "text", text: `Agent "${params.agentId}" not found in ${runDir}` }],
41
+ details: { runDir, agentId: params.agentId },
42
+ isError: true,
43
+ };
44
+ }
45
+
46
+ const parts: string[] = [];
47
+ parts.push(`Agent: ${params.agentId}`);
48
+ parts.push(`Status: ${result.state.status}`);
49
+ if (result.exitCode !== undefined) parts.push(`Exit code: ${result.exitCode}`);
50
+ if (result.state.retryCount) parts.push(`Retries: ${result.state.retryCount}`);
51
+
52
+ if (result.state.status === "running") {
53
+ parts.push("\nAgent is still running. Wait for it to finish or inspect the artifact paths below.");
54
+ }
55
+ const artifacts = buildArtifactPaths(ctx.cwd, runDir, params.agentId);
56
+
57
+ // Include structured metadata when available
58
+ if (result.structured) {
59
+ const s = result.structured;
60
+ if (s.durationSeconds !== undefined) parts.push(`Duration: ${s.durationSeconds}s`);
61
+ if (s.subagentType) parts.push(`Type: ${s.subagentType}`);
62
+ if (s.model) parts.push(`Model: ${s.model}`);
63
+ if (s.resultTruncated) parts.push(`Result truncated: ${s.resultOriginalBytes} bytes → maxResultBytes`);
64
+ if (params.compact === false) {
65
+ if (s.summary) parts.push(`Summary: ${s.summary}`);
66
+ if (s.confidence) parts.push(`Confidence: ${s.confidence}`);
67
+ if (s.findings?.length) parts.push(`Structured findings: ${s.findings.length}`);
68
+ if (s.files?.length) parts.push(`Referenced files: ${s.files.length}`);
69
+ if (s.nextActions?.length) parts.push(`Next actions: ${s.nextActions.length}`);
70
+ }
71
+ }
72
+
73
+ if (params.compact !== false) {
74
+ appendCompactResult(parts, result, artifacts, params.agentId);
75
+ } else if (result.result) {
76
+ parts.push(`\n--- Result ---\n${result.result}`);
77
+ } else {
78
+ parts.push("\n--- No result yet ---");
79
+ }
80
+
81
+ if (params.compact === false && result.stderr) {
82
+ parts.push(`\n--- Stderr ---\n${result.stderr}`);
83
+ }
84
+
85
+ return {
86
+ content: [{ type: "text", text: parts.join("\n") }],
87
+ details: {
88
+ runDir,
89
+ agentId: params.agentId,
90
+ state: result.state,
91
+ exitCode: result.exitCode,
92
+ structured: result.structured,
93
+ artifacts,
94
+ },
95
+ };
96
+ },
97
+
98
+ renderCall() {
99
+ return emptyToolSlot();
100
+ },
101
+
102
+ renderResult() {
103
+ // Result reads should enrich the assistant's answer, not add one mini-block per agent.
104
+ return emptyToolSlot();
105
+ },
106
+ });
107
+ }
108
+
109
+ function buildArtifactPaths(cwd: string, runDir: string, agentId: string): ResultArtifactPaths {
110
+ const agentDir = path.join(runDir, agentId);
111
+ return {
112
+ resultMd: displayPath(cwd, path.join(agentDir, "result.md")),
113
+ resultJson: displayPath(cwd, path.join(agentDir, "result.json")),
114
+ stderrLog: displayPath(cwd, path.join(agentDir, "stderr.log")),
115
+ };
116
+ }
117
+
118
+ function displayPath(cwd: string, filePath: string): string {
119
+ const relative = path.relative(cwd, filePath);
120
+ if (relative && !relative.startsWith("..") && !path.isAbsolute(relative)) return relative;
121
+ return filePath;
122
+ }
123
+
124
+ function appendCompactResult(parts: string[], result: AgentResult, artifacts: ResultArtifactPaths, agentId: string): void {
125
+ const structured = result.structured;
126
+
127
+ if (structured?.summary) {
128
+ parts.push(`\nSummary:\n${structured.summary}`);
129
+ } else if (result.result !== undefined) {
130
+ parts.push("\nSummary:\n(summary unavailable; see the full result artifact below)");
131
+ } else {
132
+ parts.push("\n--- No result yet ---");
133
+ }
134
+
135
+ if (structured?.confidence) parts.push(`Confidence: ${structured.confidence}`);
136
+ if (structured?.findings?.length) appendList(parts, "Findings", structured.findings, formatFinding, MAX_COMPACT_FINDINGS);
137
+ if (structured?.files?.length) appendList(parts, "Referenced files", structured.files, formatFileReference, MAX_COMPACT_FILES);
138
+ if (structured?.risks?.length) appendList(parts, "Risks", structured.risks, formatRisk, MAX_COMPACT_RISKS);
139
+ if (structured?.nextActions?.length) appendList(parts, "Next actions", structured.nextActions, (action) => truncate(action, 500), MAX_COMPACT_NEXT_ACTIONS);
140
+
141
+ if (result.stderr) {
142
+ parts.push("\nStderr:");
143
+ if (structured?.stderrPreview) parts.push(`Preview: ${structured.stderrPreview}`);
144
+ parts.push(`Full stderr: ${artifacts.stderrLog}`);
145
+ }
146
+
147
+ parts.push("\nArtifacts:");
148
+ parts.push(`${result.result !== undefined ? "Full result" : "Full result (not written yet)"}: ${artifacts.resultMd}`);
149
+ parts.push(`${structured ? "Structured result" : "Structured result (not available yet)"}: ${artifacts.resultJson}`);
150
+ parts.push(`To read full output: subagents({ action: "result", agentId: "${agentId}", compact: false })`);
151
+ }
152
+
153
+ function appendList<T>(parts: string[], title: string, items: readonly T[], format: (item: T) => string, limit: number): void {
154
+ const visible = items.slice(0, limit);
155
+ parts.push(`\n${title}:`);
156
+ for (const item of visible) parts.push(`- ${format(item)}`);
157
+ if (items.length > visible.length) parts.push(`- ... ${items.length - visible.length} more in result.json`);
158
+ }
159
+
160
+ function formatFinding(finding: StructuredFinding): string {
161
+ const suffixes: string[] = [];
162
+ if (finding.severity) suffixes.push(`severity=${finding.severity}`);
163
+ if (finding.file) suffixes.push(`file=${formatFileLocation(finding.file, finding.line)}`);
164
+ const suffix = suffixes.length ? ` (${suffixes.join(", ")})` : "";
165
+ return `${truncate(finding.text, 500)}${suffix}`;
166
+ }
167
+
168
+ function formatFileReference(file: StructuredFileReference): string {
169
+ return formatFileLocation(file.path, file.line);
170
+ }
171
+
172
+ function formatRisk(risk: StructuredRisk): string {
173
+ const severity = risk.severity ? `[${risk.severity}] ` : "";
174
+ return `${severity}${truncate(risk.text, 500)}`;
175
+ }
176
+
177
+ function formatFileLocation(filePath: string, line?: number): string {
178
+ return line ? `${filePath}:${line}` : filePath;
179
+ }
@@ -0,0 +1,372 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
4
+ import { Type } from "@mariozechner/pi-ai";
5
+ import { Text } from "@mariozechner/pi-tui";
6
+ import { ASYNC_SUBAGENT_TOOL_DESCRIPTIONS } from "../../tool-descriptions.js";
7
+ import type { AgentCompletionHandler, AgentTask, ResolvedAgentTaskConfig, Semaphore, SpawnedAgent } from "../lib.js";
8
+ import {
9
+ createRunDir,
10
+ createSemaphore,
11
+ currentModelRef,
12
+ DEFAULT_MAX_CONCURRENT,
13
+ getActiveSubagentPresetName,
14
+ getAgentState,
15
+ getRunState,
16
+ getSessionSubagentPresetOverride,
17
+ loadSubagentConfig,
18
+ recordSubagentRun,
19
+ resolveAgentTaskConfig,
20
+ resolveRunDir,
21
+ routeSubagentTasks,
22
+ selectSessionModelWithFallback,
23
+ shouldForceCurrentSubagentModel,
24
+ spawnAgent,
25
+ stopAgents,
26
+ writePromptFile,
27
+ writeStructuredResult,
28
+ } from "../lib.js";
29
+ import { spawnAgentWithRetry } from "../core/retry.js";
30
+ import { DEFAULT_SPAWN_WATCH_SECONDS, DEFAULT_UPDATE_INTERVAL_SECONDS, INLINE_RENDERING } from "../constants.js";
31
+ import { formatAgentStatus } from "../format.js";
32
+ import { getLiveRun } from "../live.js";
33
+ import { clampWatchSeconds, pollRunWithUpdates } from "../polling.js";
34
+ import { renderPlainRunSummary, renderSubagentRun, renderSubagentSpawnPrompts } from "../render.js";
35
+ import { normalizeAgentTasks, toTaskPreviews } from "../tasks.js";
36
+ import { emptyToolSlot } from "../ui.js";
37
+ import type { LiveAgent, SubagentRunRenderDetails } from "../types.js";
38
+
39
+ interface LaunchQueuedAgentOptions {
40
+ resolved: ResolvedAgentTaskConfig;
41
+ runDir: string;
42
+ cwd: string;
43
+ parentSession?: string;
44
+ semaphore: Semaphore;
45
+ signal?: AbortSignal;
46
+ onResult: (result: Pick<SpawnedAgent, "pid" | "agentDir">) => void;
47
+ onComplete: AgentCompletionHandler;
48
+ onCancelled: (reason: string) => void;
49
+ onLaunchError: (error: unknown) => void;
50
+ onUpdate: () => void;
51
+ }
52
+
53
+ const PROJECT_SEMAPHORES = new Map<string, Semaphore>();
54
+
55
+ function getProjectSemaphore(cwd: string, limit: number): Semaphore {
56
+ const key = path.resolve(cwd);
57
+ const existing = PROJECT_SEMAPHORES.get(key);
58
+ if (existing && existing.limit === normalizedLimit(limit)) return existing;
59
+ if (existing && (existing.active > 0 || existing.waiting > 0)) return existing;
60
+ const semaphore = createSemaphore(limit);
61
+ PROJECT_SEMAPHORES.set(key, semaphore);
62
+ return semaphore;
63
+ }
64
+
65
+ function normalizedLimit(limit: number): number {
66
+ return limit > 0 ? limit : 0;
67
+ }
68
+
69
+ async function launchQueuedAgent(options: LaunchQueuedAgentOptions): Promise<void> {
70
+ const { resolved, runDir, cwd, parentSession, semaphore, signal, onResult, onComplete, onCancelled, onLaunchError, onUpdate } = options;
71
+ let slotAcquired = false;
72
+ try {
73
+ await semaphore.acquire(signal);
74
+ slotAcquired = true;
75
+ let slotReleased = false;
76
+ const releaseSlot = () => {
77
+ if (slotReleased) return;
78
+ slotReleased = true;
79
+ semaphore.release();
80
+ };
81
+ const completionHandler: AgentCompletionHandler = (completion) => {
82
+ releaseSlot();
83
+ onComplete(completion);
84
+ };
85
+ const skipReason = launchSkipReason(runDir, resolved.task.id);
86
+ if (skipReason) {
87
+ releaseSlot();
88
+ onCancelled(skipReason);
89
+ onUpdate();
90
+ return;
91
+ }
92
+
93
+ const spawnOptions = { parentSession, maxResultBytes: resolved.maxResultBytes, timeoutMs: resolved.timeoutMs };
94
+ if (resolved.retry.maxRetries > 0 || resolved.fallbackModels.length > 0) {
95
+ const retryResult = spawnAgentWithRetry(
96
+ runDir,
97
+ resolved.task,
98
+ cwd,
99
+ completionHandler,
100
+ {
101
+ retry: resolved.retry,
102
+ extraArgs: resolved.extraArgs,
103
+ fallbackModels: resolved.fallbackModels,
104
+ signal,
105
+ ...spawnOptions,
106
+ },
107
+ );
108
+ onResult(retryResult.initial);
109
+ retryResult.done.catch(onLaunchError);
110
+ } else {
111
+ const result = spawnAgent(runDir, resolved.task, cwd, resolved.extraArgs, undefined, completionHandler, spawnOptions);
112
+ onResult(result);
113
+ }
114
+ onUpdate();
115
+ } catch (error) {
116
+ if (slotAcquired) semaphore.release();
117
+ if (errorMessage(error) === "Aborted") onCancelled("launch aborted before a concurrency slot opened");
118
+ else onLaunchError(error);
119
+ onUpdate();
120
+ }
121
+ }
122
+
123
+ function launchSkipReason(runDir: string, agentId: string): string | undefined {
124
+ if (!fs.existsSync(runDir)) return "run directory was removed before launch";
125
+ const state = getAgentState(runDir, agentId, { includeLineCounts: false });
126
+ if (state?.status === "stopped") return "agent was stopped before launch";
127
+ return undefined;
128
+ }
129
+
130
+ function writeLaunchFailure(runDir: string, task: AgentTask, message: string, maxResultBytes?: number): void {
131
+ const agentDir = path.join(runDir, task.id);
132
+ fs.mkdirSync(agentDir, { recursive: true });
133
+ const now = new Date().toISOString();
134
+ fs.writeFileSync(path.join(agentDir, "prompt.md"), `Launch failed before sub-agent process started.\n\n${message}\n`, "utf-8");
135
+ fs.writeFileSync(path.join(agentDir, "result.md"), message, "utf-8");
136
+ fs.writeFileSync(path.join(agentDir, "stderr.log"), `${message}\n`, "utf-8");
137
+ fs.writeFileSync(path.join(agentDir, "exit_code"), "1", "utf-8");
138
+ fs.writeFileSync(path.join(agentDir, "started_at"), now, "utf-8");
139
+ fs.writeFileSync(path.join(agentDir, "finished_at"), now, "utf-8");
140
+ const state = getAgentState(runDir, task.id) ?? { id: task.id, status: "failed" as const, exitCode: 1 };
141
+ writeStructuredResult({ agentDir, agentId: task.id, state, subagentType: task.subagentType, model: task.model, maxResultBytes });
142
+ }
143
+
144
+ function errorMessage(error: unknown): string {
145
+ return error instanceof Error ? error.message : String(error);
146
+ }
147
+
148
+ function applySessionModelFallback(resolved: ResolvedAgentTaskConfig): ResolvedAgentTaskConfig {
149
+ const selected = selectSessionModelWithFallback(resolved.task.model, resolved.fallbackModels);
150
+ if (!selected || !selected.fellBack) return resolved;
151
+ return {
152
+ ...resolved,
153
+ task: {
154
+ ...resolved.task,
155
+ model: selected.model,
156
+ },
157
+ };
158
+ }
159
+
160
+ function timeoutMsFromSeconds(value: unknown): number | undefined {
161
+ return typeof value === "number" && Number.isFinite(value) && value > 0
162
+ ? Math.max(1, Math.round(value * 1000))
163
+ : undefined;
164
+ }
165
+
166
+ const AgentTaskSchema = Type.Object({
167
+ id: Type.Optional(Type.String({ description: "Short identifier for this agent (used as directory name). If omitted, the spawn action assigns agent-1, agent-2, etc." })),
168
+ task: Type.String({ description: "Focused task description for the sub-agent" }),
169
+ scope: Type.Optional(Type.String({ description: "Relevant files/areas for this task" })),
170
+ subagentType: Type.Optional(Type.String({ description: "Logical sub-agent type/profile from config. Usually omit this so the router selects from the current config; set only for an explicit user-requested role, vision/image handling, deterministic tests, or another concrete override." })),
171
+ model: Type.Optional(Type.String({ description: "Explicit model override for this sub-agent. Prefer subagentType for reusable routing." })),
172
+ thinking: Type.Optional(Type.String({ description: "Per-agent thinking level override (off, minimal, low, medium, high, xhigh)." })),
173
+ promptAppend: Type.Optional(Type.String({ description: "Extra prompt instructions appended after the generated/type prompt." })),
174
+ promptOverride: Type.Optional(Type.String({ description: "Full prompt replacement for this sub-agent. Prefer configuring this per subagentType." })),
175
+ focus: Type.Optional(Type.String({ description: "For vision sub-agents: what to pay special attention to while inspecting attached images." })),
176
+ attention: Type.Optional(Type.String({ description: "Alias for focus, accepted for compatibility." })),
177
+ imagePaths: Type.Optional(Type.Array(Type.String(), { description: "Local image paths to attach to this sub-agent prompt (jpg, png, gif, or webp). Relative paths resolve from cwd." })),
178
+ tools: Type.Optional(Type.Array(Type.String(), { description: "Tool names to enable (e.g. ['read','grep','bash'])" })),
179
+ extraArgs: Type.Optional(Type.Array(Type.String(), { description: "Additional pi CLI args for this sub-agent" })),
180
+ timeoutSeconds: Type.Optional(Type.Number({ description: "Per-agent wall-clock timeout in seconds. Overrides config/default timeout for this task." })),
181
+ parentObjective: Type.Optional(Type.String({ description: "Parent task context (default: 'current user task')" })),
182
+ });
183
+
184
+ export function registerSpawnTool(
185
+ pi: ExtensionAPI,
186
+ liveAgents: Map<string, Map<string, LiveAgent>>,
187
+ handleAgentCompletion: AgentCompletionHandler,
188
+ onLiveAgentsChange?: () => void,
189
+ ): void {
190
+ pi.registerTool({
191
+ ...ASYNC_SUBAGENT_TOOL_DESCRIPTIONS.spawnAction,
192
+ ...INLINE_RENDERING,
193
+ parameters: Type.Object({
194
+ tasks: Type.Array(AgentTaskSchema, { description: "Agent tasks to spawn" }),
195
+ runDir: Type.Optional(Type.String({ description: "Existing run directory. Creates new one if omitted." })),
196
+ slug: Type.Optional(Type.String({ description: "Slug for new run directory name" })),
197
+ thinking: Type.Optional(Type.String({ description: "Thinking level for sub-agents (off, minimal, low, medium, high, xhigh)" })),
198
+ extraArgs: Type.Optional(Type.Array(Type.String(), { description: "Additional pi CLI args for sub-agents" })),
199
+ timeoutSeconds: Type.Optional(Type.Number({ description: "Wall-clock timeout in seconds for every spawned agent in this call. Task-level timeoutSeconds overrides this." })),
200
+ watchSeconds: Type.Optional(Type.Number({ description: "Live update watch window after spawning (default/max 300s; 0 returns immediately)", default: DEFAULT_SPAWN_WATCH_SECONDS })),
201
+ }),
202
+
203
+ async execute(_toolCallId, params, signal, onUpdate, ctx) {
204
+ const parentSession = typeof ctx.sessionManager?.getSessionFile === "function"
205
+ ? ctx.sessionManager.getSessionFile()
206
+ : undefined;
207
+ const runDir = params.runDir
208
+ ? resolveRunDir(ctx.cwd, params.runDir)
209
+ : createRunDir(ctx.cwd, params.slug);
210
+
211
+ const normalized = normalizeAgentTasks(params.tasks);
212
+ if (normalized.error) {
213
+ return {
214
+ content: [{ type: "text", text: normalized.error }],
215
+ details: {},
216
+ isError: true,
217
+ };
218
+ }
219
+ const config = loadSubagentConfig(ctx.cwd);
220
+ const activePresetName = getActiveSubagentPresetName();
221
+ const activePreset = activePresetName ? config.presets?.[activePresetName] : undefined;
222
+ if (getSessionSubagentPresetOverride() && !activePreset) {
223
+ return {
224
+ content: [{ type: "text", text: `AGENTS_PRESET=${activePresetName} does not match any preset in asyncSubagents config.` }],
225
+ details: {},
226
+ isError: true,
227
+ };
228
+ }
229
+ const forceCurrentModel = shouldForceCurrentSubagentModel();
230
+ const forcedModel = forceCurrentModel ? currentModelRef((ctx as { model?: unknown }).model) : undefined;
231
+ if (forceCurrentModel && !forcedModel) {
232
+ return {
233
+ content: [{ type: "text", text: "ASYNC_SUBAGENTS_FORCE_CURRENT_MODEL is enabled, but the current parent model is unavailable." }],
234
+ details: {},
235
+ isError: true,
236
+ };
237
+ }
238
+ const routed = await routeSubagentTasks(normalized.tasks ?? [], config, ctx as any, signal ?? undefined);
239
+ const timeoutMs = timeoutMsFromSeconds(params.timeoutSeconds);
240
+ const resolvedTasks = routed.tasks.map((task) => applySessionModelFallback(
241
+ resolveAgentTaskConfig(task, config, {
242
+ preset: activePreset,
243
+ thinking: params.thinking,
244
+ extraArgs: Array.isArray(params.extraArgs) ? params.extraArgs : [],
245
+ forcedModel,
246
+ timeoutMs,
247
+ }),
248
+ ));
249
+ const tasks: AgentTask[] = resolvedTasks.map((resolved) => resolved.task);
250
+ const taskPreviews = toTaskPreviews(tasks);
251
+ const results: { id: string; pid: number; agentDir: string }[] = [];
252
+ const maxConcurrent = config.maxConcurrent ?? DEFAULT_MAX_CONCURRENT;
253
+ const semaphore = getProjectSemaphore(ctx.cwd, maxConcurrent);
254
+ const launchErrors: { id: string; error: string }[] = [];
255
+ recordSubagentRun(ctx.cwd, runDir, tasks.map((task) => task.id));
256
+
257
+ // Materialize prompts up front so queued agents appear as planned in status/wait
258
+ // output before their semaphore slot opens.
259
+ for (const task of tasks) writePromptFile(runDir, task);
260
+ const liveRun = getLiveRun(liveAgents, runDir);
261
+
262
+ for (const resolved of resolvedTasks) {
263
+ const task = resolved.task;
264
+ const preview = taskPreviews.find((item) => item.id === task.id);
265
+ let resolveCompleted: () => void = () => {};
266
+ const completed = new Promise<void>((resolve) => {
267
+ resolveCompleted = resolve;
268
+ });
269
+ liveRun.set(task.id, { runDir, agentId: task.id, preview, parentSession, completed });
270
+
271
+ void launchQueuedAgent({
272
+ resolved,
273
+ runDir,
274
+ cwd: ctx.cwd,
275
+ parentSession,
276
+ semaphore,
277
+ signal: signal ?? undefined,
278
+ onResult: (result) => results.push({ id: task.id, pid: result.pid, agentDir: result.agentDir }),
279
+ onComplete: (completion) => {
280
+ resolveCompleted();
281
+ handleAgentCompletion(completion);
282
+ },
283
+ onCancelled: () => {
284
+ stopAgents(runDir, [task.id], { signal: "SIGTERM" });
285
+ resolveCompleted();
286
+ liveRun.delete(task.id);
287
+ if (liveRun.size === 0) liveAgents.delete(runDir);
288
+ },
289
+ onLaunchError: (error) => {
290
+ const message = errorMessage(error);
291
+ launchErrors.push({ id: task.id, error: message });
292
+ writeLaunchFailure(runDir, task, message, resolved.maxResultBytes);
293
+ resolveCompleted();
294
+ liveRun.delete(task.id);
295
+ if (liveRun.size === 0) liveAgents.delete(runDir);
296
+ },
297
+ onUpdate: () => {
298
+ onLiveAgentsChange?.();
299
+ const partialDetails: SubagentRunRenderDetails = {
300
+ runDir,
301
+ agents: getRunState(runDir).agents,
302
+ tasks: taskPreviews,
303
+ mode: "spawn",
304
+ };
305
+ onUpdate?.({
306
+ content: [{ type: "text", text: renderPlainRunSummary(partialDetails) }],
307
+ details: partialDetails,
308
+ });
309
+ },
310
+ });
311
+ }
312
+
313
+ // Let immediately available semaphore slots start before the first status poll.
314
+ await Promise.resolve();
315
+
316
+ const state = await pollRunWithUpdates(runDir, undefined, {
317
+ mode: "spawn",
318
+ tasks: taskPreviews,
319
+ timeoutSeconds: clampWatchSeconds(params.watchSeconds),
320
+ intervalSeconds: DEFAULT_UPDATE_INTERVAL_SECONDS,
321
+ signal: signal ?? undefined,
322
+ onUpdate,
323
+ });
324
+ const details: SubagentRunRenderDetails = { runDir, agents: state.agents, tasks: taskPreviews, mode: "spawn" };
325
+ onLiveAgentsChange?.();
326
+ const hasActiveOrQueued = state.agents.some((agent) => agent.status === "planned" || agent.status === "running" || agent.status === "retrying");
327
+ const lines = [
328
+ `Scheduled ${tasks.length} agent(s) in ${runDir}`,
329
+ `Started ${results.length} agent(s) so far; maxConcurrent=${semaphore.limit} (project-wide).`,
330
+ ...(routed.usedLlm
331
+ ? [`LLM-routed ${Object.keys(routed.routes).length} inferred subagent type(s).`]
332
+ : []),
333
+ ...(routed.warnings.length > 0 ? [`Routing fallback: ${routed.warnings.join(" ")}`] : []),
334
+ "",
335
+ ...state.agents.map(
336
+ (a) => `${formatAgentStatus(a.status)} ${a.id}${a.pid ? ` (pid ${a.pid})` : ""}`,
337
+ ),
338
+ ...(launchErrors.length > 0
339
+ ? ["", "Launch errors:", ...launchErrors.map((item) => `- ${item.id}: ${item.error}`)]
340
+ : []),
341
+ "",
342
+ hasActiveOrQueued
343
+ ? "Agents continue running or queued in the background after this watch window."
344
+ : "All scheduled agents are no longer running or queued.",
345
+ `Use subagents({ action: "status" }) for the latest project run, or include runDir: "${runDir}" for an exact run.`,
346
+ "Use subagents({ action: \"result\", agentId: \"<agent-id>\" }) to read output; runDir is optional because .pi/subagents/registry.json maps agent IDs to their latest run.",
347
+ ];
348
+
349
+ return {
350
+ content: [{ type: "text", text: lines.join("\n") }],
351
+ details,
352
+ };
353
+ },
354
+
355
+ renderCall() {
356
+ return emptyToolSlot();
357
+ },
358
+
359
+ renderResult(result, opts, theme) {
360
+ const details = result.details as SubagentRunRenderDetails | undefined;
361
+ if (!details) {
362
+ const fallback = result.content[0] && result.content[0].type === "text" ? result.content[0].text : "(no output)";
363
+ return new Text(fallback, 0, 0);
364
+ }
365
+ if (details.mode === "spawn") {
366
+ return renderSubagentSpawnPrompts(details, opts, theme);
367
+ }
368
+
369
+ return renderSubagentRun(details, opts, theme);
370
+ },
371
+ });
372
+ }
@@ -0,0 +1,60 @@
1
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
2
+ import { Type } from "@mariozechner/pi-ai";
3
+ import { Text } from "@mariozechner/pi-tui";
4
+ import { ASYNC_SUBAGENT_TOOL_DESCRIPTIONS } from "../../tool-descriptions.js";
5
+ import { getRunState, resolveSubagentRunDir, validateBasename } from "../lib.js";
6
+ import { INLINE_RENDERING } from "../constants.js";
7
+ import { formatAgentStatus } from "../format.js";
8
+ import { emptyToolSlot } from "../ui.js";
9
+ import type { SubagentRunRenderDetails } from "../types.js";
10
+
11
+ export function registerStatusTool(pi: ExtensionAPI): void {
12
+ pi.registerTool({
13
+ ...ASYNC_SUBAGENT_TOOL_DESCRIPTIONS.statusAction,
14
+ ...INLINE_RENDERING,
15
+ parameters: Type.Object({
16
+ runDir: Type.Optional(Type.String({ description: "Run directory path. If omitted, uses the latest project sub-agent run from .pi/subagents/registry.json or .pi/subagents/." })),
17
+ agentIds: Type.Optional(Type.Array(Type.String(), { description: "Filter to specific agent IDs" })),
18
+ }),
19
+
20
+ async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
21
+ const runDir = resolveSubagentRunDir(ctx.cwd, params.runDir);
22
+ if (params.agentIds) {
23
+ for (const id of params.agentIds) validateBasename(id, "agentId");
24
+ }
25
+ const state = getRunState(runDir, params.agentIds);
26
+
27
+ if (state.agents.length === 0) {
28
+ return {
29
+ content: [{ type: "text", text: "No agents found in run directory." }],
30
+ details: { runDir, agents: [], mode: "status" } satisfies SubagentRunRenderDetails,
31
+ };
32
+ }
33
+
34
+ const lines = state.agents.map((a) => {
35
+ let line = `${formatAgentStatus(a.status)} ${a.id}`;
36
+ if (a.pid) line += ` (pid ${a.pid})`;
37
+ if (a.exitCode !== undefined) line += ` exit=${a.exitCode}`;
38
+ if (a.startedAt) line += ` started=${a.startedAt}`;
39
+ if (a.finishedAt) line += ` finished=${a.finishedAt}`;
40
+ return line;
41
+ });
42
+
43
+ return {
44
+ content: [{ type: "text", text: lines.join("\n") }],
45
+ details: { runDir, agents: state.agents, mode: "status" } satisfies SubagentRunRenderDetails,
46
+ };
47
+ },
48
+
49
+ renderCall() {
50
+ return emptyToolSlot();
51
+ },
52
+
53
+ renderResult(result) {
54
+ const details = result.details as SubagentRunRenderDetails | undefined;
55
+ if (!details || details.agents.length === 0) return new Text("No agents found.", 0, 0);
56
+ // The spawn action is the only visible run panel. Status checks feed the model, not the chat UI.
57
+ return emptyToolSlot();
58
+ },
59
+ });
60
+ }