@ashx-j/lunr-dev 0.2.13-dev.8.1 → 0.2.16-dev.9.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 (339) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/dist/builtin-extensions/ashxj-tui.d.ts +14 -0
  3. package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
  4. package/dist/builtin-extensions/ashxj-tui.js +37 -3
  5. package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
  6. package/dist/builtin-extensions/index.d.ts +1 -15
  7. package/dist/builtin-extensions/index.d.ts.map +1 -1
  8. package/dist/builtin-extensions/index.js +7 -21
  9. package/dist/builtin-extensions/index.js.map +1 -1
  10. package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.d.ts.map +1 -1
  11. package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js +6 -2
  12. package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js.map +1 -1
  13. package/dist/builtin-extensions/pi-lsp-extension/src/index.d.ts +4 -0
  14. package/dist/builtin-extensions/pi-lsp-extension/src/index.d.ts.map +1 -1
  15. package/dist/builtin-extensions/pi-lsp-extension/src/index.js +163 -169
  16. package/dist/builtin-extensions/pi-lsp-extension/src/index.js.map +1 -1
  17. package/dist/builtin-extensions/pi-lsp-extension/src/runtime.d.ts +46 -0
  18. package/dist/builtin-extensions/pi-lsp-extension/src/runtime.d.ts.map +1 -0
  19. package/dist/builtin-extensions/pi-lsp-extension/src/runtime.js +109 -0
  20. package/dist/builtin-extensions/pi-lsp-extension/src/runtime.js.map +1 -0
  21. package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.d.ts +7 -0
  22. package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.d.ts.map +1 -0
  23. package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.js +211 -0
  24. package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.js.map +1 -0
  25. package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.d.ts +0 -5
  26. package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.d.ts.map +1 -1
  27. package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.js +0 -202
  28. package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.js.map +1 -1
  29. package/dist/builtin-extensions/pi-mcp-adapter/index.d.ts.map +1 -1
  30. package/dist/builtin-extensions/pi-mcp-adapter/index.js +251 -94
  31. package/dist/builtin-extensions/pi-mcp-adapter/index.js.map +1 -1
  32. package/dist/builtin-extensions/pi-mcp-adapter/init.d.ts +4 -1
  33. package/dist/builtin-extensions/pi-mcp-adapter/init.d.ts.map +1 -1
  34. package/dist/builtin-extensions/pi-mcp-adapter/init.js +10 -3
  35. package/dist/builtin-extensions/pi-mcp-adapter/init.js.map +1 -1
  36. package/dist/builtin-extensions/pi-mcp-adapter/metadata-cache.d.ts.map +1 -1
  37. package/dist/builtin-extensions/pi-mcp-adapter/metadata-cache.js +6 -1
  38. package/dist/builtin-extensions/pi-mcp-adapter/metadata-cache.js.map +1 -1
  39. package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.d.ts.map +1 -1
  40. package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.js +2 -1
  41. package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.js.map +1 -1
  42. package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.d.ts +1 -1
  43. package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.d.ts.map +1 -1
  44. package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.js +1 -1
  45. package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.js.map +1 -1
  46. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +1 -1
  47. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  48. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +38 -14
  49. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  50. package/dist/builtin-extensions/pi-subagents/src/shared/fork-context.d.ts.map +1 -1
  51. package/dist/builtin-extensions/pi-subagents/src/shared/fork-context.js +1 -1
  52. package/dist/builtin-extensions/pi-subagents/src/shared/fork-context.js.map +1 -1
  53. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts +1 -1
  54. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
  55. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +1 -1
  56. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
  57. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +1 -1
  58. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
  59. package/dist/builtin-extensions/pi-subagents/src/tui/render.js +2 -1
  60. package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
  61. package/dist/builtin-extensions/pi-subagents/src/watchdog/review.d.ts +1 -1
  62. package/dist/builtin-extensions/pi-subagents/src/watchdog/review.d.ts.map +1 -1
  63. package/dist/builtin-extensions/pi-subagents/src/watchdog/review.js +2 -1
  64. package/dist/builtin-extensions/pi-subagents/src/watchdog/review.js.map +1 -1
  65. package/dist/builtin-extensions/pi-web-access/extract.d.ts.map +1 -1
  66. package/dist/builtin-extensions/pi-web-access/extract.js +105 -54
  67. package/dist/builtin-extensions/pi-web-access/extract.js.map +1 -1
  68. package/dist/builtin-extensions/pi-web-access/gemini-search.d.ts +1 -1
  69. package/dist/builtin-extensions/pi-web-access/gemini-search.d.ts.map +1 -1
  70. package/dist/builtin-extensions/pi-web-access/gemini-search.js +82 -65
  71. package/dist/builtin-extensions/pi-web-access/gemini-search.js.map +1 -1
  72. package/dist/builtin-extensions/pi-web-access/github-extract.d.ts.map +1 -1
  73. package/dist/builtin-extensions/pi-web-access/github-extract.js +2 -0
  74. package/dist/builtin-extensions/pi-web-access/github-extract.js.map +1 -1
  75. package/dist/builtin-extensions/pi-web-access/index.d.ts.map +1 -1
  76. package/dist/builtin-extensions/pi-web-access/index.js +167 -77
  77. package/dist/builtin-extensions/pi-web-access/index.js.map +1 -1
  78. package/dist/builtin-extensions/pi-web-access/lazy.d.ts +18 -0
  79. package/dist/builtin-extensions/pi-web-access/lazy.d.ts.map +1 -0
  80. package/dist/builtin-extensions/pi-web-access/lazy.js +19 -0
  81. package/dist/builtin-extensions/pi-web-access/lazy.js.map +1 -0
  82. package/dist/builtin-extensions/pi-web-access/session-cleanup.d.ts +6 -0
  83. package/dist/builtin-extensions/pi-web-access/session-cleanup.d.ts.map +1 -0
  84. package/dist/builtin-extensions/pi-web-access/session-cleanup.js +17 -0
  85. package/dist/builtin-extensions/pi-web-access/session-cleanup.js.map +1 -0
  86. package/dist/catalog/publication.json +12 -12
  87. package/dist/cli-runtime.d.ts +3 -0
  88. package/dist/cli-runtime.d.ts.map +1 -0
  89. package/dist/cli-runtime.js +73 -0
  90. package/dist/cli-runtime.js.map +1 -0
  91. package/dist/cli.d.ts.map +1 -1
  92. package/dist/cli.js +14 -53
  93. package/dist/cli.js.map +1 -1
  94. package/dist/config.d.ts +1 -0
  95. package/dist/config.d.ts.map +1 -1
  96. package/dist/config.js +1 -0
  97. package/dist/config.js.map +1 -1
  98. package/dist/core/agent-session.d.ts +3 -0
  99. package/dist/core/agent-session.d.ts.map +1 -1
  100. package/dist/core/agent-session.js +56 -12
  101. package/dist/core/agent-session.js.map +1 -1
  102. package/dist/core/compaction/compaction.d.ts.map +1 -1
  103. package/dist/core/compaction/compaction.js +10 -5
  104. package/dist/core/compaction/compaction.js.map +1 -1
  105. package/dist/core/extensions/host-static.d.ts.map +1 -1
  106. package/dist/core/extensions/host-static.js +34 -12
  107. package/dist/core/extensions/host-static.js.map +1 -1
  108. package/dist/core/extensions/loader.d.ts +1 -2
  109. package/dist/core/extensions/loader.d.ts.map +1 -1
  110. package/dist/core/extensions/loader.js +10 -64
  111. package/dist/core/extensions/loader.js.map +1 -1
  112. package/dist/core/extensions/types.d.ts +2 -2
  113. package/dist/core/extensions/types.d.ts.map +1 -1
  114. package/dist/core/extensions/types.js.map +1 -1
  115. package/dist/core/footer-data-provider.d.ts.map +1 -1
  116. package/dist/core/footer-data-provider.js +2 -0
  117. package/dist/core/footer-data-provider.js.map +1 -1
  118. package/dist/core/permissions.d.ts +0 -2
  119. package/dist/core/permissions.d.ts.map +1 -1
  120. package/dist/core/permissions.js +10 -18
  121. package/dist/core/permissions.js.map +1 -1
  122. package/dist/core/sdk.d.ts +1 -1
  123. package/dist/core/sdk.d.ts.map +1 -1
  124. package/dist/core/sdk.js +1 -1
  125. package/dist/core/sdk.js.map +1 -1
  126. package/dist/core/slash-commands.d.ts.map +1 -1
  127. package/dist/core/slash-commands.js +0 -1
  128. package/dist/core/slash-commands.js.map +1 -1
  129. package/dist/core/timings.d.ts +2 -1
  130. package/dist/core/timings.d.ts.map +1 -1
  131. package/dist/core/timings.js +17 -2
  132. package/dist/core/timings.js.map +1 -1
  133. package/dist/gateway/commands.d.ts +1 -1
  134. package/dist/gateway/commands.d.ts.map +1 -1
  135. package/dist/gateway/commands.js +1 -18
  136. package/dist/gateway/commands.js.map +1 -1
  137. package/dist/main.d.ts +2 -2
  138. package/dist/main.d.ts.map +1 -1
  139. package/dist/main.js +57 -48
  140. package/dist/main.js.map +1 -1
  141. package/dist/modes/interactive/interactive-mode.d.ts +12 -21
  142. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  143. package/dist/modes/interactive/interactive-mode.js +120 -144
  144. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  145. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  146. package/dist/modes/interactive/theme/theme.js +95 -84
  147. package/dist/modes/interactive/theme/theme.js.map +1 -1
  148. package/dist/node-runtime/agent-session-services-IFJMSX7Z.js +36 -0
  149. package/dist/node-runtime/benchmark-request-UC7PD3V3.js +57 -0
  150. package/dist/node-runtime/brave-UWDA3I22.js +143 -0
  151. package/dist/node-runtime/builtin-extensions-LYZ3BFWQ.js +28 -0
  152. package/dist/node-runtime/chunk-2QKLKMKC.js +173 -0
  153. package/dist/node-runtime/chunk-3GHXVUAK.js +21 -0
  154. package/dist/node-runtime/chunk-3RCWXWAY.js +466 -0
  155. package/dist/node-runtime/chunk-3WFAEVKS.js +115 -0
  156. package/dist/node-runtime/chunk-3X3KZKMI.js +49 -0
  157. package/dist/node-runtime/chunk-4HXHDDCF.js +16 -0
  158. package/dist/node-runtime/chunk-4TLO4PO2.js +3427 -0
  159. package/dist/node-runtime/chunk-4ZWGEEAS.js +69 -0
  160. package/dist/node-runtime/chunk-53YJI7JU.js +137 -0
  161. package/dist/node-runtime/chunk-5P7PZMRU.js +610 -0
  162. package/dist/node-runtime/chunk-7N3YHTYF.js +26 -0
  163. package/dist/node-runtime/chunk-7NBZ5P7I.js +24 -0
  164. package/dist/node-runtime/chunk-A2KQXUJD.js +105 -0
  165. package/dist/node-runtime/chunk-AD6VXAO7.js +342 -0
  166. package/dist/node-runtime/chunk-AHSTJBIB.js +64 -0
  167. package/dist/node-runtime/chunk-AJX357CL.js +20211 -0
  168. package/dist/node-runtime/chunk-ARC4KOTI.js +11178 -0
  169. package/dist/node-runtime/chunk-AUXVGBO4.js +19 -0
  170. package/dist/node-runtime/chunk-AY6CAJSL.js +30 -0
  171. package/dist/node-runtime/chunk-BHO7O6E5.js +296 -0
  172. package/dist/node-runtime/chunk-BI3DHYCN.js +8845 -0
  173. package/dist/node-runtime/chunk-BR7YDUKA.js +109 -0
  174. package/dist/node-runtime/chunk-BRJX2PRC.js +53 -0
  175. package/dist/node-runtime/chunk-C4O2RSQQ.js +37 -0
  176. package/dist/node-runtime/chunk-CCZJ3PYY.js +17 -0
  177. package/dist/node-runtime/chunk-CDFZEWPU.js +8388 -0
  178. package/dist/node-runtime/chunk-CGBXPL3E.js +1171 -0
  179. package/dist/node-runtime/chunk-CJECDQKP.js +19 -0
  180. package/dist/node-runtime/chunk-DAPBPCBP.js +53 -0
  181. package/dist/node-runtime/chunk-DDGMHUOW.js +305 -0
  182. package/dist/node-runtime/chunk-DMMTJQMQ.js +43 -0
  183. package/dist/node-runtime/chunk-DVGWF6A2.js +1180 -0
  184. package/dist/node-runtime/chunk-ECD5L7YI.js +1369 -0
  185. package/dist/node-runtime/chunk-EDBJNRSM.js +46 -0
  186. package/dist/node-runtime/chunk-F4VQFJI2.js +1269 -0
  187. package/dist/node-runtime/chunk-FVDOXRUD.js +96 -0
  188. package/dist/node-runtime/chunk-GZQHMEWL.js +126 -0
  189. package/dist/node-runtime/chunk-H2EOZYMP.js +57 -0
  190. package/dist/node-runtime/chunk-HQCKFM2O.js +56 -0
  191. package/dist/node-runtime/chunk-HYHJIRDW.js +19 -0
  192. package/dist/node-runtime/chunk-I6R76AG7.js +22 -0
  193. package/dist/node-runtime/chunk-IPA627GP.js +296 -0
  194. package/dist/node-runtime/chunk-JHYKXIMM.js +378 -0
  195. package/dist/node-runtime/chunk-KKSIVROT.js +88 -0
  196. package/dist/node-runtime/chunk-LZAW4ZX3.js +633 -0
  197. package/dist/node-runtime/chunk-M3LZLQW2.js +98 -0
  198. package/dist/node-runtime/chunk-MGWCVY6Y.js +47 -0
  199. package/dist/node-runtime/chunk-MJQDX3BA.js +72 -0
  200. package/dist/node-runtime/chunk-MKKH27PH.js +8956 -0
  201. package/dist/node-runtime/chunk-MX3GJNXJ.js +986 -0
  202. package/dist/node-runtime/chunk-N77MY65L.js +966 -0
  203. package/dist/node-runtime/chunk-NUIFPZWX.js +209 -0
  204. package/dist/node-runtime/chunk-OBMWP3I5.js +68 -0
  205. package/dist/node-runtime/chunk-OR4L3IB2.js +42 -0
  206. package/dist/node-runtime/chunk-PBC2Y6GS.js +903 -0
  207. package/dist/node-runtime/chunk-PCGNAY2O.js +1324 -0
  208. package/dist/node-runtime/chunk-PCIGF2XK.js +250 -0
  209. package/dist/node-runtime/chunk-PGAJ5MO5.js +7558 -0
  210. package/dist/node-runtime/chunk-PL6JKXWI.js +3622 -0
  211. package/dist/node-runtime/chunk-PVCDKGR6.js +55 -0
  212. package/dist/node-runtime/chunk-Q4Q6D4IY.js +364 -0
  213. package/dist/node-runtime/chunk-Q5ZU2VRT.js +83 -0
  214. package/dist/node-runtime/chunk-QFWG2RVL.js +5477 -0
  215. package/dist/node-runtime/chunk-QH42CDX3.js +9451 -0
  216. package/dist/node-runtime/chunk-RQ2Q5IYR.js +72 -0
  217. package/dist/node-runtime/chunk-RQ5DNUNG.js +429 -0
  218. package/dist/node-runtime/chunk-RRIZE6QQ.js +17 -0
  219. package/dist/node-runtime/chunk-SN6G4OU6.js +4753 -0
  220. package/dist/node-runtime/chunk-SWSN6HAB.js +53 -0
  221. package/dist/node-runtime/chunk-TQNSPERU.js +949 -0
  222. package/dist/node-runtime/chunk-VRB2IYGG.js +53 -0
  223. package/dist/node-runtime/chunk-VSELYKWU.js +772 -0
  224. package/dist/node-runtime/chunk-W3CVH5RX.js +62 -0
  225. package/dist/node-runtime/chunk-WJVFOIB5.js +24921 -0
  226. package/dist/node-runtime/chunk-WOVTOV5P.js +5653 -0
  227. package/dist/node-runtime/chunk-XBWPBZBN.js +125 -0
  228. package/dist/node-runtime/chunk-XTHQ7XR7.js +509 -0
  229. package/dist/node-runtime/chunk-YF63P5ZT.js +864 -0
  230. package/dist/node-runtime/chunk-YSKSB3BJ.js +295 -0
  231. package/dist/node-runtime/chunk-ZCHMJ34K.js +130 -0
  232. package/dist/node-runtime/chunk-ZKMFUD3Q.js +2834 -0
  233. package/dist/node-runtime/cli-runtime.js +81 -0
  234. package/dist/node-runtime/clipboard-OZ63BBC6.js +12 -0
  235. package/dist/node-runtime/clipboard-image-7QR6GXVA.js +13 -0
  236. package/dist/node-runtime/command-L3LAHDIH.js +13 -0
  237. package/dist/node-runtime/commands-RL5YBW5I.js +291 -0
  238. package/dist/node-runtime/config-FMEOZSWE.js +77 -0
  239. package/dist/node-runtime/curator-server-XCM43VEF.js +3816 -0
  240. package/dist/node-runtime/customize-XEXL2DGQ.js +12 -0
  241. package/dist/node-runtime/direct-tool-executor-JVDXTO7A.js +188 -0
  242. package/dist/node-runtime/exa-LL64QZR2.js +329 -0
  243. package/dist/node-runtime/export-html-KR26FOUZ.js +150 -0
  244. package/dist/node-runtime/extension-input-RV5N6APL.js +14 -0
  245. package/dist/node-runtime/extension-selector-CPD5LWDD.js +14 -0
  246. package/dist/node-runtime/extract-XLQSJN4V.js +17 -0
  247. package/dist/node-runtime/file-sync-HCOP2QVF.js +117 -0
  248. package/dist/node-runtime/gateway-X2TI5X7F.js +2484 -0
  249. package/dist/node-runtime/gemini-api-QE7ANVDZ.js +29 -0
  250. package/dist/node-runtime/gemini-search-U7SUMPQA.js +330 -0
  251. package/dist/node-runtime/gemini-url-context-PXWCBQHK.js +103 -0
  252. package/dist/node-runtime/gemini-web-MM446SEH.js +14 -0
  253. package/dist/node-runtime/github-extract-F64RZOEA.js +619 -0
  254. package/dist/node-runtime/goal-CZQ7FFQJ.js +1831 -0
  255. package/dist/node-runtime/index.js +859 -0
  256. package/dist/node-runtime/init-NJV2T55N.js +28 -0
  257. package/dist/node-runtime/install-cli-TH7IJJQQ.js +308 -0
  258. package/dist/node-runtime/interactive-mode-KOM35YF2.js +56 -0
  259. package/dist/node-runtime/interactive-view-U6OILKF3.js +249 -0
  260. package/dist/node-runtime/lsp-manager-3ASUSO4T.js +1104 -0
  261. package/dist/node-runtime/lunr-cron-YJ5UHYRD.js +268 -0
  262. package/dist/node-runtime/main.js +54 -0
  263. package/dist/node-runtime/mcp-auth-flow-QIXHW6QN.js +32 -0
  264. package/dist/node-runtime/mcp-panel-IIGMXQGP.js +501 -0
  265. package/dist/node-runtime/mcp-setup-panel-FEK7663I.js +355 -0
  266. package/dist/node-runtime/memory-cap-3S4XRLNP.js +20 -0
  267. package/dist/node-runtime/model-tiers-NJLHUEGK.js +20 -0
  268. package/dist/node-runtime/openai-search-B3MSNCQA.js +288 -0
  269. package/dist/node-runtime/package-manager-cli-TZZHJCVI.js +749 -0
  270. package/dist/node-runtime/parallel-AI2MNSCU.js +265 -0
  271. package/dist/node-runtime/parser-manager-TQHWYDH7.js +152 -0
  272. package/dist/node-runtime/pdf-extract-IPE6H4HP.js +57 -0
  273. package/dist/node-runtime/perplexity-QVJW3I35.js +12 -0
  274. package/dist/node-runtime/pi-intercom-EEMBGQID.js +2215 -0
  275. package/dist/node-runtime/pi-mcp-adapter-QFB37AVN.js +422 -0
  276. package/dist/node-runtime/pi-ollama-cloud-4VZRMULP.js +1440 -0
  277. package/dist/node-runtime/pi-prompt-template-model-4QT4LLXF.js +3946 -0
  278. package/dist/node-runtime/pi-subagents-7XJ4H53P.js +6023 -0
  279. package/dist/node-runtime/pi-web-access-DPGAVKOA.js +1864 -0
  280. package/dist/node-runtime/print-mode-VWIRFDAC.js +12 -0
  281. package/dist/node-runtime/proxy-modes-HEEFK4KC.js +685 -0
  282. package/dist/node-runtime/rpc-entry.js +62 -0
  283. package/dist/node-runtime/rpc-mode-SJNSOA4G.js +13 -0
  284. package/dist/node-runtime/runtime-bridges-PPHNBFWL.js +14 -0
  285. package/dist/node-runtime/session-manager-MQNBYACL.js +35 -0
  286. package/dist/node-runtime/session-selector-5AZLJS6U.js +14 -0
  287. package/dist/node-runtime/settings-manager-5LF2VQWC.js +21 -0
  288. package/dist/node-runtime/src-Y7JSCK64.js +2407 -0
  289. package/dist/node-runtime/subagent-executor-5RNDEPIJ.js +8483 -0
  290. package/dist/node-runtime/summary-review-YSMXKITO.js +228 -0
  291. package/dist/node-runtime/tavily-WEZFVFP7.js +154 -0
  292. package/dist/node-runtime/timings-UAD5BEAS.js +16 -0
  293. package/dist/node-runtime/tool-renderer-MV5O452K.js +204 -0
  294. package/dist/node-runtime/update-cli-A253SZ7P.js +73 -0
  295. package/dist/node-runtime/v4-5MNC3H7G.js +424 -0
  296. package/dist/node-runtime/video-extract-OYT5WKS5.js +304 -0
  297. package/dist/node-runtime/workspace-index-6DBXSTJ6.js +163 -0
  298. package/dist/node-runtime/youtube-extract-TQYKGFGS.js +264 -0
  299. package/dist/startup/benchmark-request.d.ts +3 -0
  300. package/dist/startup/benchmark-request.d.ts.map +1 -0
  301. package/dist/startup/benchmark-request.js +65 -0
  302. package/dist/startup/benchmark-request.js.map +1 -0
  303. package/dist/startup/interactive-view.d.ts +55 -0
  304. package/dist/startup/interactive-view.d.ts.map +1 -0
  305. package/dist/startup/interactive-view.js +332 -0
  306. package/dist/startup/interactive-view.js.map +1 -0
  307. package/dist/startup/launch-routing.d.ts.map +1 -1
  308. package/dist/startup/launch-routing.js +9 -10
  309. package/dist/startup/launch-routing.js.map +1 -1
  310. package/dist/startup/startup-milestones.d.ts +1 -1
  311. package/dist/startup/startup-milestones.d.ts.map +1 -1
  312. package/dist/startup/startup-milestones.js +3 -2
  313. package/dist/startup/startup-milestones.js.map +1 -1
  314. package/dist/utils/await-with-abort.d.ts +2 -0
  315. package/dist/utils/await-with-abort.d.ts.map +1 -0
  316. package/dist/utils/await-with-abort.js +19 -0
  317. package/dist/utils/await-with-abort.js.map +1 -0
  318. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  319. package/dist/utils/syntax-highlight.js +10 -4
  320. package/dist/utils/syntax-highlight.js.map +1 -1
  321. package/docs/compaction.md +5 -3
  322. package/docs/development.md +5 -1
  323. package/docs/features.md +0 -1
  324. package/docs/interactive-startup.md +98 -0
  325. package/docs/usage.md +0 -1
  326. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  327. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  328. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  329. package/examples/extensions/gondolin/package-lock.json +2 -2
  330. package/examples/extensions/gondolin/package.json +1 -1
  331. package/examples/extensions/sandbox/package-lock.json +2 -2
  332. package/examples/extensions/sandbox/package.json +1 -1
  333. package/examples/extensions/with-deps/package-lock.json +2 -2
  334. package/examples/extensions/with-deps/package.json +1 -1
  335. package/package.json +20 -20
  336. package/dist/core/swarm.d.ts +0 -23
  337. package/dist/core/swarm.d.ts.map +0 -1
  338. package/dist/core/swarm.js +0 -45
  339. package/dist/core/swarm.js.map +0 -1
@@ -0,0 +1,3946 @@
1
+ import { createRequire as __lunrRequire } from "node:module"; const require = __lunrRequire(import.meta.url);
2
+ import {
3
+ parseFrontmatter
4
+ } from "./chunk-QFWG2RVL.js";
5
+ import {
6
+ minimatch
7
+ } from "./chunk-CGBXPL3E.js";
8
+ import {
9
+ CONFIG_DIR_NAME,
10
+ getAgentDir
11
+ } from "./chunk-PCIGF2XK.js";
12
+ import "./chunk-Q4Q6D4IY.js";
13
+ import "./chunk-BRJX2PRC.js";
14
+
15
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/index.js
16
+ import { existsSync as existsSync4 } from "node:fs";
17
+ import { resolve as resolvePath } from "node:path";
18
+
19
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/args.js
20
+ function extractLoopCount(argsString) {
21
+ let loopCount = null, loopFound = !1, fresh = !1, noConverge = !1, tokensToRemove = [], loopTokenRanges = [], i = 0;
22
+ for (; i < argsString.length; ) {
23
+ let char = argsString[i];
24
+ if (char === '"' || char === "'") {
25
+ let quote = char;
26
+ for (i++; i < argsString.length && argsString[i] !== quote; )
27
+ i++;
28
+ i < argsString.length && i++;
29
+ continue;
30
+ }
31
+ if (/\s/.test(char)) {
32
+ i++;
33
+ continue;
34
+ }
35
+ let tokenStart = i;
36
+ for (; i < argsString.length && !/\s/.test(argsString[i]); )
37
+ i++;
38
+ let token = argsString.slice(tokenStart, i);
39
+ if (token.startsWith("--loop=")) {
40
+ loopTokenRanges.push({ start: tokenStart, end: i });
41
+ let value = token.slice(7);
42
+ if (/^\d+$/.test(value)) {
43
+ let parsed = parseInt(value, 10);
44
+ parsed >= 1 && parsed <= 999 && !loopFound && (loopFound = !0, loopCount = parsed);
45
+ }
46
+ continue;
47
+ }
48
+ if (token === "--loop") {
49
+ let lookahead = i;
50
+ for (; lookahead < argsString.length && /\s/.test(argsString[lookahead]); )
51
+ lookahead++;
52
+ if (lookahead < argsString.length && argsString[lookahead] !== '"' && argsString[lookahead] !== "'") {
53
+ let nextTokenStart = lookahead;
54
+ for (; lookahead < argsString.length && !/\s/.test(argsString[lookahead]); )
55
+ lookahead++;
56
+ let nextToken = argsString.slice(nextTokenStart, lookahead);
57
+ if (/^\d+$/.test(nextToken)) {
58
+ loopTokenRanges.push({ start: tokenStart, end: i }, { start: nextTokenStart, end: lookahead });
59
+ let parsed = parseInt(nextToken, 10);
60
+ parsed >= 1 && parsed <= 999 && !loopFound && (loopFound = !0, loopCount = parsed), i = lookahead;
61
+ continue;
62
+ }
63
+ }
64
+ loopTokenRanges.push({ start: tokenStart, end: i }), loopFound || (loopFound = !0, loopCount = null);
65
+ continue;
66
+ }
67
+ token === "--fresh" && (fresh = !0, tokensToRemove.push({ start: tokenStart, end: i })), token === "--no-converge" && (noConverge = !0, tokensToRemove.push({ start: tokenStart, end: i }));
68
+ }
69
+ if (!loopFound)
70
+ return null;
71
+ let allRanges = [...tokensToRemove, ...loopTokenRanges];
72
+ allRanges.sort((a, b) => b.start - a.start);
73
+ let cleaned = argsString;
74
+ for (let { start, end } of allRanges)
75
+ cleaned = cleaned.slice(0, start) + cleaned.slice(end);
76
+ let converge = !noConverge;
77
+ return { args: cleaned.trim(), loopCount, fresh, converge };
78
+ }
79
+ function extractLoopFlags(argsString) {
80
+ let fresh = !1, noConverge = !1, tokensToRemove = [], i = 0;
81
+ for (; i < argsString.length; ) {
82
+ let char = argsString[i];
83
+ if (char === '"' || char === "'") {
84
+ let quote = char;
85
+ for (i++; i < argsString.length && argsString[i] !== quote; )
86
+ i++;
87
+ i < argsString.length && i++;
88
+ continue;
89
+ }
90
+ if (/\s/.test(char)) {
91
+ i++;
92
+ continue;
93
+ }
94
+ let tokenStart = i;
95
+ for (; i < argsString.length && !/\s/.test(argsString[i]); )
96
+ i++;
97
+ let token = argsString.slice(tokenStart, i);
98
+ token === "--fresh" && (fresh = !0, tokensToRemove.push({ start: tokenStart, end: i })), token === "--no-converge" && (noConverge = !0, tokensToRemove.push({ start: tokenStart, end: i }));
99
+ }
100
+ tokensToRemove.sort((a, b) => b.start - a.start);
101
+ let cleaned = argsString;
102
+ for (let { start, end } of tokensToRemove)
103
+ cleaned = cleaned.slice(0, start) + cleaned.slice(end);
104
+ return { args: cleaned.trim(), fresh, converge: !noConverge };
105
+ }
106
+ function extractBooleanFlag(argsString, flag) {
107
+ let found = !1, tokensToRemove = [], i = 0;
108
+ for (; i < argsString.length; ) {
109
+ let char = argsString[i];
110
+ if (char === '"' || char === "'") {
111
+ let quote = char;
112
+ for (i++; i < argsString.length && argsString[i] !== quote; )
113
+ i++;
114
+ i < argsString.length && i++;
115
+ continue;
116
+ }
117
+ if (/\s/.test(char)) {
118
+ i++;
119
+ continue;
120
+ }
121
+ let tokenStart = i;
122
+ for (; i < argsString.length && !/\s/.test(argsString[i]); )
123
+ i++;
124
+ argsString.slice(tokenStart, i) === flag && (found = !0, tokensToRemove.push({ start: tokenStart, end: i }));
125
+ }
126
+ if (tokensToRemove.length === 0)
127
+ return { args: argsString.trim(), found: !1 };
128
+ tokensToRemove.sort((a, b) => b.start - a.start);
129
+ let cleaned = argsString;
130
+ for (let { start, end } of tokensToRemove)
131
+ cleaned = cleaned.slice(0, start) + cleaned.slice(end);
132
+ return { args: cleaned.trim(), found };
133
+ }
134
+ function extractChainContextFlag(argsString) {
135
+ let { args, found } = extractBooleanFlag(argsString, "--chain-context");
136
+ return { args, chainContext: found };
137
+ }
138
+ function extractWorktreeFlag(argsString) {
139
+ let { args, found } = extractBooleanFlag(argsString, "--worktree");
140
+ return { args, worktree: found };
141
+ }
142
+ function extractSubagentOverride(argsString) {
143
+ let override, cwdRaw, modelRaw, fork = !1, tokensToRemove = [], i = 0;
144
+ for (; i < argsString.length; ) {
145
+ let char = argsString[i];
146
+ if (char === '"' || char === "'") {
147
+ let quote = char;
148
+ for (i++; i < argsString.length && argsString[i] !== quote; )
149
+ i++;
150
+ i < argsString.length && i++;
151
+ continue;
152
+ }
153
+ if (/\s/.test(char)) {
154
+ i++;
155
+ continue;
156
+ }
157
+ let tokenStart = i;
158
+ for (; i < argsString.length && !/\s/.test(argsString[i]); )
159
+ i++;
160
+ let token = argsString.slice(tokenStart, i);
161
+ if (token === "--subagent") {
162
+ tokensToRemove.push({ start: tokenStart, end: i }), override = { enabled: !0 };
163
+ continue;
164
+ }
165
+ if (token.startsWith("--subagent=") || token.startsWith("--subagent:")) {
166
+ tokensToRemove.push({ start: tokenStart, end: i });
167
+ let value = (token.includes("="), token.slice(11));
168
+ override = value ? { enabled: !0, agent: value } : { enabled: !0 };
169
+ continue;
170
+ }
171
+ if (token.startsWith("--cwd=")) {
172
+ tokensToRemove.push({ start: tokenStart, end: i }), cwdRaw = token.slice(6) || void 0;
173
+ continue;
174
+ }
175
+ if (token.startsWith("--model=")) {
176
+ tokensToRemove.push({ start: tokenStart, end: i }), modelRaw = token.slice(8) || void 0;
177
+ continue;
178
+ }
179
+ if (token === "--fork") {
180
+ tokensToRemove.push({ start: tokenStart, end: i }), fork = !0;
181
+ continue;
182
+ }
183
+ }
184
+ if (tokensToRemove.length === 0)
185
+ return { args: argsString.trim() };
186
+ tokensToRemove.sort((a, b) => b.start - a.start);
187
+ let cleaned = argsString;
188
+ for (let { start, end } of tokensToRemove)
189
+ cleaned = cleaned.slice(0, start) + cleaned.slice(end);
190
+ return fork && !override && (override = { enabled: !0 }), {
191
+ args: cleaned.trim(),
192
+ ...override ? { override } : {},
193
+ ...cwdRaw !== void 0 ? { cwd: cwdRaw } : {},
194
+ ...modelRaw !== void 0 ? { model: modelRaw } : {},
195
+ ...fork ? { fork: !0 } : {}
196
+ };
197
+ }
198
+ function parseLineupOverrideSlots(raw, target, mode, errors) {
199
+ let label = `--${target === "finalApplier" ? "final-applier" : `${target}${mode === "append" ? "-append" : ""}`}`;
200
+ if (!raw) {
201
+ errors.push(`Invalid ${label}: expected ${target === "finalApplier" ? "a slot object or a one-element JSON array" : "a JSON array of slot objects"}.`);
202
+ return;
203
+ }
204
+ let parsed;
205
+ try {
206
+ parsed = JSON.parse(raw);
207
+ } catch (error) {
208
+ let message = error instanceof Error ? error.message : String(error);
209
+ errors.push(`Invalid ${label}: expected valid JSON (${message}).`);
210
+ return;
211
+ }
212
+ let entries = target === "finalApplier" ? Array.isArray(parsed) ? parsed.length === 1 ? parsed : null : [parsed] : Array.isArray(parsed) && parsed.length > 0 ? parsed : null;
213
+ if (!entries) {
214
+ errors.push(target === "finalApplier" ? `Invalid ${label}: expected a slot object or a one-element JSON array.` : `Invalid ${label}: expected a non-empty JSON array.`);
215
+ return;
216
+ }
217
+ let slots = [];
218
+ for (let i = 0; i < entries.length; i++) {
219
+ let entry = entries[i];
220
+ if (!entry || typeof entry != "object" || Array.isArray(entry)) {
221
+ errors.push(`Invalid ${label}: slot ${i + 1} must be an object.`);
222
+ return;
223
+ }
224
+ let slot = entry;
225
+ if (slot.agent !== void 0 && slot.subagent !== void 0) {
226
+ errors.push(`Invalid ${label}: slot ${i + 1} cannot combine "agent" and "subagent".`);
227
+ return;
228
+ }
229
+ let agent;
230
+ if (typeof slot.agent == "string" && slot.agent.trim())
231
+ agent = slot.agent.trim();
232
+ else if (slot.agent !== void 0) {
233
+ errors.push(`Invalid ${label}: slot ${i + 1} requires a non-empty string "agent".`);
234
+ return;
235
+ }
236
+ if (!agent && slot.subagent !== void 0)
237
+ if (slot.subagent === !0)
238
+ agent = target === "reviewers" ? "reviewer" : "delegate";
239
+ else if (typeof slot.subagent == "string" && slot.subagent.trim())
240
+ agent = slot.subagent.trim();
241
+ else {
242
+ errors.push(`Invalid ${label}: slot ${i + 1} requires "subagent" to be true or a non-empty string.`);
243
+ return;
244
+ }
245
+ if (!agent) {
246
+ errors.push(`Invalid ${label}: slot ${i + 1} requires "agent" or "subagent".`);
247
+ return;
248
+ }
249
+ let model = typeof slot.model == "string" && slot.model.trim() ? slot.model.trim() : void 0, task = typeof slot.task == "string" && slot.task.trim() ? slot.task.trim() : void 0, taskSuffix = typeof slot.taskSuffix == "string" && slot.taskSuffix.trim() ? slot.taskSuffix.trim() : void 0;
250
+ if (target === "finalApplier" && slot.cwd !== void 0) {
251
+ errors.push(`Invalid ${label}: slot ${i + 1} "cwd" is not supported.`);
252
+ return;
253
+ }
254
+ let cwd = typeof slot.cwd == "string" && slot.cwd.trim() ? slot.cwd.trim() : void 0, count;
255
+ if (slot.count !== void 0) {
256
+ if (target === "finalApplier") {
257
+ errors.push(`Invalid ${label}: slot ${i + 1} "count" is not supported.`);
258
+ return;
259
+ }
260
+ let rawCount = slot.count;
261
+ if (typeof rawCount != "number" || !Number.isInteger(rawCount) || rawCount < 1) {
262
+ errors.push(`Invalid ${label}: slot ${i + 1} "count" must be an integer greater than or equal to 1.`);
263
+ return;
264
+ }
265
+ count = rawCount;
266
+ }
267
+ slots.push({
268
+ agent,
269
+ ...model ? { model } : {},
270
+ ...task ? { task } : {},
271
+ ...taskSuffix ? { taskSuffix } : {},
272
+ ...cwd ? { cwd } : {},
273
+ ...count !== void 0 ? { count } : {}
274
+ });
275
+ }
276
+ return { target, mode, slots };
277
+ }
278
+ var LINEUP_OVERRIDE_FLAGS = [
279
+ { flag: "--workers-append=", target: "workers", mode: "append" },
280
+ { flag: "--reviewers-append=", target: "reviewers", mode: "append" },
281
+ { flag: "--workers=", target: "workers", mode: "replace" },
282
+ { flag: "--reviewers=", target: "reviewers", mode: "replace" },
283
+ { flag: "--final-applier=", target: "finalApplier", mode: "replace" }
284
+ ];
285
+ function readQuotedValue(input, start) {
286
+ let quote = input[start];
287
+ if (quote !== '"' && quote !== "'")
288
+ return;
289
+ let i = start + 1;
290
+ for (; i < input.length; ) {
291
+ let char = input[i];
292
+ if (char === "\\") {
293
+ i += 2;
294
+ continue;
295
+ }
296
+ if (char === quote)
297
+ return {
298
+ value: input.slice(start + 1, i),
299
+ end: i + 1
300
+ };
301
+ i++;
302
+ }
303
+ }
304
+ function readBalancedValue(input, start, open, close) {
305
+ if (input[start] !== open)
306
+ return;
307
+ let depth = 0, inQuote = null;
308
+ for (let i = start; i < input.length; i++) {
309
+ let char = input[i];
310
+ if (inQuote) {
311
+ if (char === "\\") {
312
+ i++;
313
+ continue;
314
+ }
315
+ char === inQuote && (inQuote = null);
316
+ continue;
317
+ }
318
+ if (char === '"' || char === "'") {
319
+ inQuote = char;
320
+ continue;
321
+ }
322
+ if (char === open) {
323
+ depth++;
324
+ continue;
325
+ }
326
+ if (char === close && (depth--, depth === 0))
327
+ return {
328
+ value: input.slice(start, i + 1),
329
+ end: i + 1
330
+ };
331
+ }
332
+ }
333
+ function readLineupOverrideValue(input, start) {
334
+ if (start >= input.length)
335
+ return { value: "", end: start };
336
+ let bracketed = readBalancedValue(input, start, "[", "]");
337
+ if (bracketed)
338
+ return bracketed;
339
+ let braced = readBalancedValue(input, start, "{", "}");
340
+ if (braced)
341
+ return braced;
342
+ let quoted = readQuotedValue(input, start);
343
+ if (quoted)
344
+ return quoted;
345
+ let end = start;
346
+ for (; end < input.length && !/\s/.test(input[end]); )
347
+ end++;
348
+ return {
349
+ value: input.slice(start, end),
350
+ end
351
+ };
352
+ }
353
+ function parseLineupOverrideToken(input, start) {
354
+ for (let spec of LINEUP_OVERRIDE_FLAGS) {
355
+ if (!input.startsWith(spec.flag, start))
356
+ continue;
357
+ let valueStart = start + spec.flag.length, parsedValue = readLineupOverrideValue(input, valueStart);
358
+ return {
359
+ target: spec.target,
360
+ mode: spec.mode,
361
+ raw: parsedValue.value,
362
+ end: parsedValue.end
363
+ };
364
+ }
365
+ }
366
+ function extractLineupOverrides(argsString) {
367
+ let actions = [], errors = [], tokensToRemove = [], i = 0;
368
+ for (; i < argsString.length; ) {
369
+ let char = argsString[i];
370
+ if (char === '"' || char === "'") {
371
+ let quote = char;
372
+ for (i++; i < argsString.length && argsString[i] !== quote; )
373
+ i++;
374
+ i < argsString.length && i++;
375
+ continue;
376
+ }
377
+ if (/\s/.test(char)) {
378
+ i++;
379
+ continue;
380
+ }
381
+ let token = parseLineupOverrideToken(argsString, i);
382
+ if (token) {
383
+ tokensToRemove.push({ start: i, end: token.end });
384
+ let action = parseLineupOverrideSlots(token.raw, token.target, token.mode, errors);
385
+ action && actions.push(action), i = token.end;
386
+ continue;
387
+ }
388
+ for (; i < argsString.length && !/\s/.test(argsString[i]); )
389
+ i++;
390
+ }
391
+ tokensToRemove.sort((a, b) => b.start - a.start);
392
+ let cleaned = argsString;
393
+ for (let { start, end } of tokensToRemove)
394
+ cleaned = cleaned.slice(0, start) + cleaned.slice(end);
395
+ return { args: cleaned.trim(), actions, errors };
396
+ }
397
+ function parseCommandArgs(argsString) {
398
+ let args = [], current = "", inQuote = null;
399
+ for (let i = 0; i < argsString.length; i++) {
400
+ let char = argsString[i];
401
+ inQuote ? char === inQuote ? inQuote = null : current += char : char === '"' || char === "'" ? inQuote = char : /\s/.test(char) ? current && (args.push(current), current = "") : current += char;
402
+ }
403
+ return current && args.push(current), args;
404
+ }
405
+ function substituteArgs(content, args) {
406
+ let result = content;
407
+ result = result.replace(/\$(\d+)/g, (_, num) => {
408
+ let index = parseInt(num, 10) - 1;
409
+ return args[index] ?? "";
410
+ }), result = result.replace(/\$\{@:(\d+)(?::(\d+))?\}/g, (_, startStr, lengthStr) => {
411
+ let start = parseInt(startStr, 10) - 1;
412
+ if (start < 0 && (start = 0), lengthStr) {
413
+ let length = parseInt(lengthStr, 10);
414
+ return args.slice(start, start + length).join(" ");
415
+ }
416
+ return args.slice(start).join(" ");
417
+ });
418
+ let allArgs = args.join(" ");
419
+ return result = result.replace(/\$ARGUMENTS/g, allArgs), result = result.replace(/\$@/g, allArgs), result = result.replace(/@\$/g, allArgs), result;
420
+ }
421
+
422
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/chain-parser.js
423
+ function scanSegmentTokens(segment) {
424
+ let tokens = [], i = 0;
425
+ for (; i < segment.length; ) {
426
+ for (; i < segment.length && /\s/.test(segment[i]); )
427
+ i++;
428
+ if (i >= segment.length)
429
+ break;
430
+ let start = i, inQuote = null, value = "", sawQuoted = !1, sawUnquoted = !1;
431
+ for (; i < segment.length; ) {
432
+ let char = segment[i];
433
+ if (inQuote) {
434
+ char === inQuote ? inQuote = null : value += char, i++;
435
+ continue;
436
+ }
437
+ if (char === '"' || char === "'") {
438
+ inQuote = char, sawQuoted = !0, i++;
439
+ continue;
440
+ }
441
+ if (/\s/.test(char))
442
+ break;
443
+ value += char, sawUnquoted = !0, i++;
444
+ }
445
+ tokens.push({
446
+ start,
447
+ end: i,
448
+ value,
449
+ quoted: sawQuoted && !sawUnquoted
450
+ });
451
+ }
452
+ return tokens;
453
+ }
454
+ function extractStepFlags(segment) {
455
+ let tokens = scanSegmentTokens(segment), loopTokenRanges = [], withContextTokenRanges = [], loopCount, withContext = !1;
456
+ for (let i = 1; i < tokens.length; i++) {
457
+ let token = tokens[i];
458
+ if (!token.quoted) {
459
+ if (token.value === "--with-context") {
460
+ withContext = !0, withContextTokenRanges.push({ start: token.start, end: token.end });
461
+ continue;
462
+ }
463
+ if (token.value.startsWith("--loop=")) {
464
+ loopTokenRanges.push({ start: token.start, end: token.end });
465
+ let value = token.value.slice(7);
466
+ if (!/^\d+$/.test(value))
467
+ continue;
468
+ let parsed = parseInt(value, 10);
469
+ parsed >= 1 && parsed <= 999 && loopCount === void 0 && (loopCount = parsed);
470
+ continue;
471
+ }
472
+ if (token.value === "--loop") {
473
+ if (loopTokenRanges.push({ start: token.start, end: token.end }), i + 1 < tokens.length) {
474
+ let next = tokens[i + 1];
475
+ if (!next.quoted && /^\d+$/.test(next.value)) {
476
+ loopTokenRanges.push({ start: next.start, end: next.end });
477
+ let parsed = parseInt(next.value, 10);
478
+ parsed >= 1 && parsed <= 999 && loopCount === void 0 && (loopCount = parsed), i++;
479
+ continue;
480
+ }
481
+ }
482
+ loopCount === void 0 && (loopCount = null);
483
+ continue;
484
+ }
485
+ }
486
+ }
487
+ let loopRangesToRemove = loopCount !== void 0 ? loopTokenRanges : [];
488
+ if (loopRangesToRemove.length === 0 && withContextTokenRanges.length === 0)
489
+ return { cleanedSegment: segment, withContext: !1 };
490
+ let rangesToRemove = [...loopRangesToRemove, ...withContextTokenRanges].sort((a, b) => b.start - a.start), cleanedSegment = segment;
491
+ for (let { start, end } of rangesToRemove)
492
+ cleanedSegment = `${cleanedSegment.slice(0, start)}${cleanedSegment.slice(end)}`;
493
+ return { cleanedSegment: cleanedSegment.trim(), loopCount, withContext };
494
+ }
495
+ function splitByTopLevelSeparator(input, separator) {
496
+ let parts = [], start = 0, inQuote = null, parenDepth = 0;
497
+ for (let i = 0; i < input.length; i++) {
498
+ let char = input[i];
499
+ if (inQuote) {
500
+ char === inQuote && (inQuote = null);
501
+ continue;
502
+ }
503
+ if (char === '"' || char === "'") {
504
+ inQuote = char;
505
+ continue;
506
+ }
507
+ if (char === "(") {
508
+ parenDepth++;
509
+ continue;
510
+ }
511
+ if (char === ")" && parenDepth > 0) {
512
+ parenDepth--;
513
+ continue;
514
+ }
515
+ parenDepth === 0 && i <= input.length - separator.length && input.startsWith(separator, i) && (parts.push(input.slice(start, i)), start = i + separator.length, i += separator.length - 1);
516
+ }
517
+ return parts.push(input.slice(start)), parts;
518
+ }
519
+ function findMatchingParen(segment, openIndex) {
520
+ let inQuote = null, depth = 0;
521
+ for (let i = openIndex; i < segment.length; i++) {
522
+ let char = segment[i];
523
+ if (inQuote) {
524
+ char === inQuote && (inQuote = null);
525
+ continue;
526
+ }
527
+ if (char === '"' || char === "'") {
528
+ inQuote = char;
529
+ continue;
530
+ }
531
+ if (char === "(") {
532
+ depth++;
533
+ continue;
534
+ }
535
+ if (char === ")" && (depth--, depth === 0))
536
+ return i;
537
+ }
538
+ return -1;
539
+ }
540
+ function parseSingleStepSegment(segment) {
541
+ let { cleanedSegment, loopCount, withContext } = extractStepFlags(segment), tokens = parseCommandArgs(cleanedSegment);
542
+ if (tokens.length !== 0)
543
+ return { name: tokens[0], args: tokens.slice(1), loopCount, ...withContext ? { withContext: !0 } : {} };
544
+ }
545
+ function parseParallelStepSegment(segment) {
546
+ if (!/^parallel\s*\(/.test(segment))
547
+ return;
548
+ let openIndex = segment.indexOf("(");
549
+ if (openIndex < 0)
550
+ return;
551
+ let closeIndex = findMatchingParen(segment, openIndex);
552
+ if (closeIndex < 0 || segment.slice(closeIndex + 1).trim().length > 0)
553
+ return;
554
+ let inner = segment.slice(openIndex + 1, closeIndex).trim();
555
+ if (!inner)
556
+ return;
557
+ let parsedSteps = [];
558
+ for (let rawEntry of splitByTopLevelSeparator(inner, ",")) {
559
+ let entry = rawEntry.trim();
560
+ if (!entry || /^parallel\s*\(/.test(entry))
561
+ return;
562
+ let parsed = parseSingleStepSegment(entry);
563
+ if (!parsed)
564
+ return;
565
+ parsedSteps.push(parsed);
566
+ }
567
+ if (parsedSteps.length !== 0)
568
+ return { parallel: parsedSteps };
569
+ }
570
+ function parseChainSegment(segment) {
571
+ let parallelStep = parseParallelStepSegment(segment);
572
+ if (parallelStep)
573
+ return parallelStep;
574
+ if (!/^parallel\s*\(/.test(segment))
575
+ return parseSingleStepSegment(segment);
576
+ }
577
+ function parseChainSteps(args) {
578
+ let sharedArgsSplit = splitByTopLevelSeparator(args, " -- "), templatesPart = sharedArgsSplit[0], argsPart = sharedArgsSplit.length > 1 ? sharedArgsSplit.slice(1).join(" -- ") : "", invalidSegments = [], steps = [];
579
+ for (let rawSegment of splitByTopLevelSeparator(templatesPart, "->")) {
580
+ let segment = rawSegment.trim();
581
+ if (!segment) {
582
+ invalidSegments.push(rawSegment);
583
+ continue;
584
+ }
585
+ let parsedSegment = parseChainSegment(segment);
586
+ if (!parsedSegment) {
587
+ invalidSegments.push(segment);
588
+ continue;
589
+ }
590
+ steps.push(parsedSegment);
591
+ }
592
+ return { steps, sharedArgs: parseCommandArgs(argsPart), invalidSegments };
593
+ }
594
+ function parseChainDeclaration(chain) {
595
+ let invalidSegments = [], steps = [];
596
+ for (let rawSegment of splitByTopLevelSeparator(chain, "->")) {
597
+ let segment = rawSegment.trim();
598
+ if (!segment) {
599
+ invalidSegments.push(rawSegment);
600
+ continue;
601
+ }
602
+ let parsedSegment = parseChainSegment(segment);
603
+ if (!parsedSegment) {
604
+ invalidSegments.push(segment);
605
+ continue;
606
+ }
607
+ steps.push(parsedSegment);
608
+ }
609
+ return { steps, invalidSegments };
610
+ }
611
+
612
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/subagent-runtime.js
613
+ var PROMPT_TEMPLATE_SUBAGENT_REQUEST_EVENT = "prompt-template:subagent:request", PROMPT_TEMPLATE_SUBAGENT_STARTED_EVENT = "prompt-template:subagent:started", PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT = "prompt-template:subagent:response", PROMPT_TEMPLATE_SUBAGENT_UPDATE_EVENT = "prompt-template:subagent:update", PROMPT_TEMPLATE_SUBAGENT_CANCEL_EVENT = "prompt-template:subagent:cancel", PROMPT_TEMPLATE_SUBAGENT_MESSAGE_TYPE = "prompt-template-subagent", DEFAULT_SUBAGENT_NAME = "delegate", delegatedLiveState = /* @__PURE__ */ new Map();
614
+ function updateDelegatedLiveState(requestId, update) {
615
+ let now = Date.now(), existing = delegatedLiveState.get(requestId) ?? {
616
+ recentOutput: [],
617
+ recentTools: [],
618
+ toolCount: 0,
619
+ durationMs: 0,
620
+ tokens: 0,
621
+ taskProgress: [],
622
+ startedAt: now,
623
+ updatedAt: now
624
+ }, next = {
625
+ ...existing,
626
+ ...update,
627
+ recentOutput: update.recentOutput ?? existing.recentOutput,
628
+ recentTools: update.recentTools ?? existing.recentTools,
629
+ model: update.model ?? existing.model,
630
+ toolCount: update.toolCount ?? existing.toolCount,
631
+ durationMs: update.durationMs ?? now - existing.startedAt,
632
+ tokens: update.tokens ?? existing.tokens,
633
+ taskProgress: update.taskProgress ?? existing.taskProgress,
634
+ startedAt: existing.startedAt,
635
+ updatedAt: now
636
+ };
637
+ delegatedLiveState.set(requestId, next);
638
+ }
639
+ function appendDelegatedLiveOutput(requestId, line) {
640
+ if (!line || !line.trim() || line.trim() === "(running...)")
641
+ return;
642
+ let fallbackNow = Date.now(), existing = delegatedLiveState.get(requestId) ?? {
643
+ recentOutput: [],
644
+ recentTools: [],
645
+ toolCount: 0,
646
+ durationMs: 0,
647
+ tokens: 0,
648
+ taskProgress: [],
649
+ startedAt: fallbackNow,
650
+ updatedAt: fallbackNow
651
+ }, recentOutput = [...existing.recentOutput, line];
652
+ delegatedLiveState.set(requestId, {
653
+ ...existing,
654
+ recentOutput,
655
+ updatedAt: Date.now()
656
+ });
657
+ }
658
+ function getDelegatedLiveState(requestId) {
659
+ return delegatedLiveState.get(requestId);
660
+ }
661
+ function clearDelegatedLiveState(requestId) {
662
+ delegatedLiveState.delete(requestId);
663
+ }
664
+
665
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/loop-utils.js
666
+ function collectAssistantActions(messages, filesRead, filesWritten) {
667
+ let commandCount = 0, lastText = "";
668
+ for (let msg of messages)
669
+ if (msg.role === "assistant")
670
+ for (let block of msg.content) {
671
+ if (block.type === "text") {
672
+ lastText = block.text;
673
+ continue;
674
+ }
675
+ if (block.type !== "toolCall")
676
+ continue;
677
+ if (block.name === "bash") {
678
+ commandCount++;
679
+ continue;
680
+ }
681
+ let path = block.arguments.path;
682
+ block.name === "read" && path && filesRead.add(path), (block.name === "write" || block.name === "edit") && path && filesWritten.add(path);
683
+ }
684
+ return { commandCount, lastText };
685
+ }
686
+ function delegatedDetails(entry) {
687
+ if (entry.type === "custom_message" && entry.customType === PROMPT_TEMPLATE_SUBAGENT_MESSAGE_TYPE && !(!entry.details || typeof entry.details != "object"))
688
+ return entry.details;
689
+ }
690
+ function collectSummaryData(entries) {
691
+ let filesRead = /* @__PURE__ */ new Set(), filesWritten = /* @__PURE__ */ new Set(), commandCount = 0, lastAssistantText = "";
692
+ for (let entry of entries) {
693
+ if (entry.type === "message") {
694
+ let msg = entry.message;
695
+ if (msg.role !== "assistant")
696
+ continue;
697
+ let collected = collectAssistantActions([msg], filesRead, filesWritten);
698
+ commandCount += collected.commandCount, collected.lastText && (lastAssistantText = collected.lastText);
699
+ continue;
700
+ }
701
+ let delegated = delegatedDetails(entry);
702
+ if (!delegated)
703
+ continue;
704
+ let messageGroups = delegated.parallelResults && delegated.parallelResults.length > 0 ? delegated.parallelResults.map((result) => result.messages ?? []) : delegated.messages ? [delegated.messages] : [];
705
+ for (let messages of messageGroups) {
706
+ let collected = collectAssistantActions(messages, filesRead, filesWritten);
707
+ commandCount += collected.commandCount, collected.lastText && (lastAssistantText = collected.lastText);
708
+ }
709
+ typeof delegated.text == "string" && delegated.text.trim() && (lastAssistantText = delegated.text);
710
+ }
711
+ return {
712
+ filesRead,
713
+ filesWritten,
714
+ commandCount,
715
+ lastAssistantText
716
+ };
717
+ }
718
+ function formatSummary(header, entries, preserveOutcome = !1) {
719
+ let { filesRead, filesWritten, commandCount, lastAssistantText } = collectSummaryData(entries), summary = header, actionParts = [];
720
+ if (filesRead.size > 0 && actionParts.push(`read ${filesRead.size} file(s)`), filesWritten.size > 0 && actionParts.push(`modified ${[...filesWritten].join(", ")}`), commandCount > 0 && actionParts.push(`ran ${commandCount} command(s)`), actionParts.length > 0 && (summary += `
721
+ Actions: ${actionParts.join(", ")}.`), lastAssistantText) {
722
+ let cleaned = preserveOutcome ? lastAssistantText.replace(/\r\n?/g, `
723
+ `).trim() : lastAssistantText.replace(/\n+/g, " ").trim(), outcome = preserveOutcome || cleaned.length <= 500 ? cleaned : `${cleaned.slice(0, 500)}...`;
724
+ summary += `
725
+ Outcome: ${outcome}`;
726
+ }
727
+ return summary;
728
+ }
729
+ function generateIterationSummary(entries, task, iteration, totalIterations) {
730
+ let header = totalIterations !== null ? `[Loop iteration ${iteration}/${totalIterations}]
731
+ Task: "${task}"` : `[Loop iteration ${iteration}]
732
+ Task: "${task}"`;
733
+ return formatSummary(header, entries);
734
+ }
735
+ function generateBoomerangSummary(entries, task) {
736
+ return formatSummary(`[Boomerang]
737
+ Task: "${task}"`, entries, !0);
738
+ }
739
+ function generateChainStepSummary(entries, stepLabel, stepNumber) {
740
+ return formatSummary(`Step ${stepNumber} \u2014 ${stepLabel}:`, entries);
741
+ }
742
+ function didIterationMakeChanges(entries) {
743
+ for (let entry of entries) {
744
+ if (entry.type === "message") {
745
+ if (entry.message.role !== "assistant")
746
+ continue;
747
+ for (let block of entry.message.content)
748
+ if (block.type === "toolCall" && (block.name === "write" || block.name === "edit"))
749
+ return !0;
750
+ continue;
751
+ }
752
+ let delegated = delegatedDetails(entry);
753
+ if (!delegated)
754
+ continue;
755
+ if (delegated.changed === !0)
756
+ return !0;
757
+ let delegatedGroups = delegated.parallelResults && delegated.parallelResults.length > 0 ? delegated.parallelResults.map((result) => result.messages ?? []) : [delegated.messages ?? []];
758
+ for (let messages of delegatedGroups)
759
+ for (let message of messages)
760
+ if (message.role === "assistant") {
761
+ for (let block of message.content)
762
+ if (block.type === "toolCall" && (block.name === "write" || block.name === "edit"))
763
+ return !0;
764
+ }
765
+ }
766
+ return !1;
767
+ }
768
+ function getIterationEntries(ctx, startId) {
769
+ let branch = ctx.sessionManager.getBranch();
770
+ if (!startId)
771
+ return branch;
772
+ let startIdx = branch.findIndex((e) => e.id === startId);
773
+ return startIdx < 0 ? branch : branch.slice(startIdx + 1);
774
+ }
775
+ function wasIterationAborted(entries) {
776
+ for (let entry of entries)
777
+ if (!(entry.type !== "message" || entry.message.role !== "assistant") && entry.message.stopReason === "aborted")
778
+ return !0;
779
+ return !1;
780
+ }
781
+
782
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/model-selection.js
783
+ var PREFERRED_PROVIDERS = ["openai-codex", "anthropic", "github-copilot", "openrouter"];
784
+ function isSameModel(a, b) {
785
+ return a.provider === b.provider && a.id === b.id;
786
+ }
787
+ function modelSpecMatches(modelSpec, model) {
788
+ let slashIndex = modelSpec.indexOf("/");
789
+ if (slashIndex !== -1) {
790
+ let provider = modelSpec.slice(0, slashIndex), modelId = modelSpec.slice(slashIndex + 1);
791
+ return provider === model.provider && modelId === model.id;
792
+ }
793
+ return modelSpec === model.id;
794
+ }
795
+ function orderMatchesByProviderPreference(models) {
796
+ let prioritized = [], seen = /* @__PURE__ */ new Set();
797
+ for (let provider of PREFERRED_PROVIDERS)
798
+ for (let model of models) {
799
+ let key = `${model.provider}/${model.id}`;
800
+ model.provider === provider && !seen.has(key) && (prioritized.push(model), seen.add(key));
801
+ }
802
+ for (let model of models) {
803
+ let key = `${model.provider}/${model.id}`;
804
+ seen.has(key) || (prioritized.push(model), seen.add(key));
805
+ }
806
+ return prioritized;
807
+ }
808
+ function getModelCandidates(modelSpec, registry) {
809
+ let slashIndex = modelSpec.indexOf("/");
810
+ if (slashIndex !== -1) {
811
+ let provider = modelSpec.slice(0, slashIndex), modelId = modelSpec.slice(slashIndex + 1);
812
+ if (!provider || !modelId)
813
+ return [];
814
+ if (modelId.split("/").some((segment) => segment.length === 0))
815
+ return [];
816
+ let model = registry.find(provider, modelId);
817
+ return model ? [model] : [];
818
+ }
819
+ let allMatches = registry.getAll().filter((model) => model.id === modelSpec);
820
+ return allMatches.length <= 1 ? allMatches : orderMatchesByProviderPreference(allMatches);
821
+ }
822
+ async function hasUsableAuth(model, registry) {
823
+ return registry.getAvailable().some((candidate) => isSameModel(candidate, model)) ? !0 : registry.isUsingOAuth(model) ? registry.hasConfiguredAuth ? registry.hasConfiguredAuth(model) : registry.getApiKeyAndHeaders ? (await registry.getApiKeyAndHeaders(model)).ok : !1 : !1;
824
+ }
825
+ async function selectModelCandidate(modelSpecs, currentModel, registry) {
826
+ if (currentModel && modelSpecs.some((spec) => modelSpecMatches(spec, currentModel)))
827
+ return { model: currentModel, alreadyActive: !0 };
828
+ for (let spec of modelSpecs)
829
+ for (let model of getModelCandidates(spec, registry))
830
+ if (await hasUsableAuth(model, registry))
831
+ return { model, alreadyActive: !1 };
832
+ }
833
+ function getResolvedModelRef(model) {
834
+ return { provider: model.provider, id: model.id };
835
+ }
836
+
837
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/notifications.js
838
+ function notify(ctx, message, type = "info") {
839
+ if (ctx?.hasUI) {
840
+ ctx.ui.notify(message, type);
841
+ return;
842
+ }
843
+ process.stderr.write(`${message}
844
+ `);
845
+ }
846
+ function summarizePromptDiagnostics(diagnostics) {
847
+ if (diagnostics.length === 0)
848
+ return;
849
+ let lines = diagnostics.slice(0, 4).map((diagnostic) => `- ${diagnostic.message}`), remaining = diagnostics.length - lines.length;
850
+ return remaining > 0 && lines.push(`- ... and ${remaining} more prompt template issue(s)`), [`[pi-prompt-template-model] Found ${diagnostics.length} prompt template issue(s):`, ...lines].join(`
851
+ `);
852
+ }
853
+ function diagnosticsFingerprint(diagnostics) {
854
+ return diagnostics.map((diagnostic) => diagnostic.key).sort().join(`
855
+ `);
856
+ }
857
+
858
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/template-conditionals.js
859
+ function isValidSpec(spec) {
860
+ if (!spec || /\s/.test(spec))
861
+ return !1;
862
+ if (spec.includes("*")) {
863
+ let segments = spec.split("/");
864
+ return segments.length === 2 && segments[0].length > 0 && segments[1] === "*";
865
+ }
866
+ let slashIndex = spec.indexOf("/");
867
+ if (slashIndex === -1)
868
+ return !0;
869
+ if (slashIndex === 0)
870
+ return !1;
871
+ let modelId = spec.slice(slashIndex + 1);
872
+ return !(modelId.length === 0 || modelId.split("/").some((segment) => segment.length === 0));
873
+ }
874
+ function matchSpec(spec, model) {
875
+ return spec === `${model.provider}/${model.id}` || spec === model.id || spec === `${model.provider}/*`;
876
+ }
877
+ function parseIfModelTag(tagContent) {
878
+ let cursor = 0, attributes = /* @__PURE__ */ new Map();
879
+ for (; cursor < tagContent.length; ) {
880
+ for (; cursor < tagContent.length && /\s/.test(tagContent[cursor]); )
881
+ cursor++;
882
+ if (cursor >= tagContent.length)
883
+ break;
884
+ let nameStart = cursor;
885
+ for (; cursor < tagContent.length && /[a-z-]/.test(tagContent[cursor]); )
886
+ cursor++;
887
+ if (nameStart === cursor)
888
+ return { ok: !1, error: { message: "Invalid `<if-model>` attribute syntax." } };
889
+ let name = tagContent.slice(nameStart, cursor);
890
+ for (; cursor < tagContent.length && /\s/.test(tagContent[cursor]); )
891
+ cursor++;
892
+ if (tagContent[cursor] !== "=")
893
+ return { ok: !1, error: { message: `Attribute "${name}" in \`<if-model>\` must use =.` } };
894
+ for (cursor++; cursor < tagContent.length && /\s/.test(tagContent[cursor]); )
895
+ cursor++;
896
+ if (tagContent[cursor] !== '"')
897
+ return { ok: !1, error: { message: `Attribute "${name}" in \`<if-model>\` must use double quotes.` } };
898
+ cursor++;
899
+ let valueStart = cursor;
900
+ for (; cursor < tagContent.length && tagContent[cursor] !== '"'; )
901
+ cursor++;
902
+ if (cursor >= tagContent.length)
903
+ return { ok: !1, error: { message: "Unterminated quoted attribute in `<if-model>`." } };
904
+ let value = tagContent.slice(valueStart, cursor);
905
+ if (cursor++, attributes.has(name))
906
+ return { ok: !1, error: { message: `Duplicate attribute "${name}" in \`<if-model>\`.` } };
907
+ attributes.set(name, value);
908
+ }
909
+ if (!attributes.has("is"))
910
+ return { ok: !1, error: { message: "`<if-model>` requires an `is` attribute." } };
911
+ for (let name of attributes.keys())
912
+ if (name !== "is")
913
+ return { ok: !1, error: { message: `Unknown attribute "${name}" in \`<if-model>\`.` } };
914
+ let specs = attributes.get("is").split(",").map((spec) => spec.trim()).filter(Boolean);
915
+ if (specs.length === 0)
916
+ return { ok: !1, error: { message: "`<if-model>` must declare at least one model spec." } };
917
+ for (let spec of specs)
918
+ if (!isValidSpec(spec))
919
+ return { ok: !1, error: { message: `Invalid model spec ${JSON.stringify(spec)} in \`<if-model>\`.` } };
920
+ return { type: "open", specs };
921
+ }
922
+ function isDirectiveBoundaryChar(char) {
923
+ return char === void 0 || char === ">" || /\s/.test(char);
924
+ }
925
+ function readToken(input, index) {
926
+ if (input.startsWith("</if-model>", index))
927
+ return { token: { type: "close" }, length: 11 };
928
+ if (input.startsWith("</if-model", index) && isDirectiveBoundaryChar(input[index + 10]))
929
+ return { ok: !1, error: { message: "`</if-model>` cannot have attributes or extra characters." } };
930
+ if (input.startsWith("<else>", index))
931
+ return { token: { type: "else" }, length: 6 };
932
+ if (input.startsWith("<else", index) && isDirectiveBoundaryChar(input[index + 5]))
933
+ return { ok: !1, error: { message: "`<else>` cannot have attributes or extra characters." } };
934
+ if (input.startsWith("</else>", index))
935
+ return { ok: !1, error: { message: "`</else>` is not valid. `<else>` is a separator, not a container - use `<else>content</if-model>` instead." } };
936
+ if (input.startsWith("</else", index) && isDirectiveBoundaryChar(input[index + 6]))
937
+ return { ok: !1, error: { message: "`</else>` is not valid. `<else>` is a separator, not a container - use `<else>content</if-model>` instead." } };
938
+ if (!input.startsWith("<if-model", index))
939
+ return;
940
+ let closeIndex = input.indexOf(">", index);
941
+ if (closeIndex === -1)
942
+ return { ok: !1, error: { message: "Missing closing `>` for `<if-model>`." } };
943
+ let nextChar = input[index + 9];
944
+ if (nextChar !== void 0 && nextChar !== ">" && !/\s/.test(nextChar))
945
+ return;
946
+ let tagContent = input.slice(index + 9, closeIndex), parsed = parseIfModelTag(tagContent);
947
+ return "ok" in parsed && !parsed.ok ? parsed : { token: parsed, length: closeIndex - index + 1 };
948
+ }
949
+ function appendNode(stack, root, node) {
950
+ let frame = stack[stack.length - 1];
951
+ if (!frame) {
952
+ root.push(node);
953
+ return;
954
+ }
955
+ frame.inElse ? frame.falsy.push(node) : frame.truthy.push(node);
956
+ }
957
+ function parseNodes(input) {
958
+ let root = [], stack = [], cursor = 0, textStart = 0;
959
+ for (; cursor < input.length; ) {
960
+ if (input[cursor] !== "<") {
961
+ cursor++;
962
+ continue;
963
+ }
964
+ let tokenResult = readToken(input, cursor);
965
+ if (!tokenResult) {
966
+ cursor++;
967
+ continue;
968
+ }
969
+ if ("ok" in tokenResult && !tokenResult.ok)
970
+ return tokenResult;
971
+ textStart < cursor && appendNode(stack, root, { type: "text", value: input.slice(textStart, cursor) });
972
+ let { token, length } = tokenResult;
973
+ if (token.type === "open")
974
+ stack.push({ specs: token.specs, truthy: [], falsy: [], inElse: !1 });
975
+ else if (token.type === "else") {
976
+ let frame = stack[stack.length - 1];
977
+ if (!frame)
978
+ return { ok: !1, error: { message: "Found orphan `<else>` outside `<if-model>`." } };
979
+ if (frame.inElse)
980
+ return { ok: !1, error: { message: "Found multiple `<else>` tags in one `<if-model>` block." } };
981
+ frame.inElse = !0;
982
+ } else {
983
+ let frame = stack.pop();
984
+ if (!frame)
985
+ return { ok: !1, error: { message: "Found closing `</if-model>` without a matching `<if-model>`." } };
986
+ appendNode(stack, root, { type: "if", specs: frame.specs, truthy: frame.truthy, falsy: frame.falsy });
987
+ }
988
+ cursor += length, textStart = cursor;
989
+ }
990
+ return textStart < input.length && appendNode(stack, root, { type: "text", value: input.slice(textStart) }), stack.length > 0 ? { ok: !1, error: { message: "Missing closing `</if-model>` tag." } } : { ok: !0, nodes: root };
991
+ }
992
+ function renderNodes(nodes, model) {
993
+ let output = "";
994
+ for (let node of nodes) {
995
+ if (node.type === "text") {
996
+ output += node.value;
997
+ continue;
998
+ }
999
+ let branch = node.specs.some((spec) => matchSpec(spec, model)) ? node.truthy : node.falsy;
1000
+ output += renderNodes(branch, model);
1001
+ }
1002
+ return output;
1003
+ }
1004
+ function renderTemplateConditionals(content, model, commandName) {
1005
+ if (!content.includes("<if-model") && !content.includes("<else") && !content.includes("</if-model") && !content.includes("</else"))
1006
+ return { content };
1007
+ let parsed = parseNodes(content);
1008
+ if (parsed.ok)
1009
+ return { content: renderNodes(parsed.nodes, model) };
1010
+ let label = commandName ? ` in prompt \`${commandName}\`` : "", error = parsed.error;
1011
+ return {
1012
+ content,
1013
+ error: `Invalid <if-model> markup${label}: ${error.message}`
1014
+ };
1015
+ }
1016
+
1017
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/prompt-execution.js
1018
+ function renderPromptForResolvedModel(prompt, args, model) {
1019
+ let rendered = renderTemplateConditionals(prompt.content, getResolvedModelRef(model), prompt.name), content = substituteArgs(rendered.content, args);
1020
+ return content.trim().length === 0 ? {
1021
+ empty: `Prompt \`${prompt.name}\` rendered to an empty message.`,
1022
+ warning: rendered.error
1023
+ } : {
1024
+ content,
1025
+ warning: rendered.error
1026
+ };
1027
+ }
1028
+ function sameModel(a, b) {
1029
+ return !a || !b ? a === b : a.provider === b.provider && a.id === b.id;
1030
+ }
1031
+ async function preparePromptExecution(prompt, args, currentModel, modelRegistry, options) {
1032
+ let selectedModel = prompt.models.length === 0 ? (() => {
1033
+ let inheritedModel = options !== void 0 && Object.hasOwn(options, "inheritedModel") ? options.inheritedModel : currentModel;
1034
+ return inheritedModel ? {
1035
+ model: inheritedModel,
1036
+ alreadyActive: sameModel(currentModel, inheritedModel)
1037
+ } : {
1038
+ message: `Prompt \`${prompt.name}\` has no \`model\` configured and there is no active session model to inherit.`
1039
+ };
1040
+ })() : await selectModelCandidate(prompt.models, currentModel, modelRegistry);
1041
+ if (!selectedModel)
1042
+ return;
1043
+ if ("message" in selectedModel)
1044
+ return selectedModel;
1045
+ let rendered = renderPromptForResolvedModel(prompt, args, selectedModel.model);
1046
+ return rendered.empty ? {
1047
+ message: rendered.empty,
1048
+ warning: rendered.warning
1049
+ } : {
1050
+ selectedModel,
1051
+ content: rendered.content ?? "",
1052
+ warning: rendered.warning
1053
+ };
1054
+ }
1055
+
1056
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.js
1057
+ import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from "node:fs";
1058
+ import { homedir } from "node:os";
1059
+ import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
1060
+ var VALID_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"], RESERVED_COMMAND_NAMES = /* @__PURE__ */ new Set([
1061
+ "chain-prompts",
1062
+ "prompt-tool",
1063
+ "settings",
1064
+ "model",
1065
+ "scoped-models",
1066
+ "export",
1067
+ "share",
1068
+ "copy",
1069
+ "name",
1070
+ "session",
1071
+ "hotkeys",
1072
+ "fork",
1073
+ "tree",
1074
+ "login",
1075
+ "logout",
1076
+ // lunr: /auth and /deauth aliases of /login and /logout
1077
+ "auth",
1078
+ "deauth",
1079
+ "new",
1080
+ "compact",
1081
+ "resume",
1082
+ "reload",
1083
+ "quit",
1084
+ // lunr: /exit alias of /quit
1085
+ "exit",
1086
+ "mode",
1087
+ "manual",
1088
+ "yolo",
1089
+ "auto",
1090
+ "processes",
1091
+ "rollback"
1092
+ ]);
1093
+ function createDiagnostic(code, filePath, source, message) {
1094
+ return {
1095
+ code,
1096
+ message,
1097
+ filePath,
1098
+ source,
1099
+ key: `${code}:${filePath}:${message}`
1100
+ };
1101
+ }
1102
+ function lexicalCompare(a, b) {
1103
+ return a < b ? -1 : a > b ? 1 : 0;
1104
+ }
1105
+ function normalizeStringField(field, value, filePath, source, diagnostics) {
1106
+ if (value === void 0)
1107
+ return;
1108
+ if (typeof value != "string") {
1109
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: expected a string.`));
1110
+ return;
1111
+ }
1112
+ let normalized = value.trim();
1113
+ return normalized.length > 0 ? normalized : void 0;
1114
+ }
1115
+ function isValidModelSelectionSpec(spec) {
1116
+ if (!spec || spec.includes("*") || /\s/.test(spec))
1117
+ return !1;
1118
+ let slashIndex = spec.indexOf("/");
1119
+ if (slashIndex === -1)
1120
+ return !0;
1121
+ if (slashIndex === 0)
1122
+ return !1;
1123
+ let modelId = spec.slice(slashIndex + 1);
1124
+ return !(modelId.length === 0 || modelId.split("/").some((segment) => segment.length === 0));
1125
+ }
1126
+ function normalizeFrontmatterRecord(value, filePath, source, diagnostics) {
1127
+ if (value && typeof value == "object" && !Array.isArray(value))
1128
+ return value;
1129
+ diagnostics.push(createDiagnostic("invalid-frontmatter", filePath, source, `Skipping prompt template at ${filePath}: frontmatter must be a key-value object.`));
1130
+ }
1131
+ function normalizeModelSpecs(value, filePath, source, diagnostics) {
1132
+ if (value === void 0)
1133
+ return;
1134
+ if (typeof value != "string") {
1135
+ diagnostics.push(createDiagnostic("invalid-model", filePath, source, `Skipping prompt template at ${filePath}: frontmatter field "model" must be a string.`));
1136
+ return;
1137
+ }
1138
+ let models = value.split(",").map((item) => item.trim()).filter(Boolean);
1139
+ if (models.length === 0) {
1140
+ diagnostics.push(createDiagnostic("empty-model", filePath, source, `Skipping prompt template at ${filePath}: frontmatter field "model" is empty.`));
1141
+ return;
1142
+ }
1143
+ let invalidSpec = models.find((model) => !isValidModelSelectionSpec(model));
1144
+ if (invalidSpec) {
1145
+ diagnostics.push(createDiagnostic("invalid-model-spec", filePath, source, `Skipping prompt template at ${filePath}: invalid model spec ${JSON.stringify(invalidSpec)} in frontmatter field "model".`));
1146
+ return;
1147
+ }
1148
+ return models;
1149
+ }
1150
+ function normalizeRestore(value, filePath, source, diagnostics) {
1151
+ if (value === void 0)
1152
+ return !0;
1153
+ if (typeof value == "boolean")
1154
+ return value;
1155
+ if (typeof value == "string") {
1156
+ let normalized = value.trim().toLowerCase();
1157
+ if (normalized === "true")
1158
+ return !0;
1159
+ if (normalized === "false")
1160
+ return !1;
1161
+ }
1162
+ return diagnostics.push(createDiagnostic("invalid-restore", filePath, source, `Using default restore=true for ${filePath}: frontmatter field "restore" must be true or false.`)), !0;
1163
+ }
1164
+ function normalizeFresh(value, filePath, source, diagnostics) {
1165
+ if (value === void 0)
1166
+ return !1;
1167
+ if (typeof value == "boolean")
1168
+ return value;
1169
+ if (typeof value == "string") {
1170
+ let normalized = value.trim().toLowerCase();
1171
+ if (normalized === "true")
1172
+ return !0;
1173
+ if (normalized === "false")
1174
+ return !1;
1175
+ }
1176
+ return diagnostics.push(createDiagnostic("invalid-fresh", filePath, source, `Using default fresh=false for ${filePath}: frontmatter field "fresh" must be true or false.`)), !1;
1177
+ }
1178
+ function normalizeRotate(value, filePath, source, diagnostics) {
1179
+ if (value === void 0)
1180
+ return !1;
1181
+ if (typeof value == "boolean")
1182
+ return value;
1183
+ if (typeof value == "string") {
1184
+ let normalized = value.trim().toLowerCase();
1185
+ if (normalized === "true")
1186
+ return !0;
1187
+ if (normalized === "false")
1188
+ return !1;
1189
+ }
1190
+ return diagnostics.push(createDiagnostic("invalid-rotate", filePath, source, `Using default rotate=false for ${filePath}: frontmatter field "rotate" must be true or false.`)), !1;
1191
+ }
1192
+ function normalizeBoomerang(value, filePath, source, diagnostics) {
1193
+ if (value === void 0)
1194
+ return !1;
1195
+ if (typeof value == "boolean")
1196
+ return value;
1197
+ if (typeof value == "string") {
1198
+ let normalized = value.trim().toLowerCase();
1199
+ if (normalized === "true")
1200
+ return !0;
1201
+ if (normalized === "false")
1202
+ return !1;
1203
+ }
1204
+ return diagnostics.push(createDiagnostic("invalid-boomerang", filePath, source, `Using default boomerang=false for ${filePath}: frontmatter field "boomerang" must be true or false.`)), !1;
1205
+ }
1206
+ function normalizeLoop(value, filePath, source, diagnostics) {
1207
+ if (value === void 0)
1208
+ return;
1209
+ if (value === !0 || typeof value == "string" && value.trim().toLowerCase() === "unlimited")
1210
+ return null;
1211
+ let normalizedValue;
1212
+ if (typeof value == "number" ? normalizedValue = value : typeof value == "string" && /^\d+$/.test(value.trim()) && (normalizedValue = parseInt(value.trim(), 10)), normalizedValue !== void 0 && Number.isInteger(normalizedValue) && normalizedValue >= 1 && normalizedValue <= 999)
1213
+ return normalizedValue;
1214
+ diagnostics.push(createDiagnostic("invalid-loop", filePath, source, `Ignoring invalid loop value in ${filePath}: frontmatter field "loop" must be an integer between 1 and 999, true, or "unlimited".`));
1215
+ }
1216
+ function normalizeParallel(value, filePath, source, diagnostics) {
1217
+ if (value === void 0)
1218
+ return;
1219
+ let normalizedValue;
1220
+ if (typeof value == "number" ? normalizedValue = value : typeof value == "string" && /^\d+$/.test(value.trim()) && (normalizedValue = parseInt(value.trim(), 10)), normalizedValue !== void 0 && Number.isInteger(normalizedValue) && normalizedValue >= 2)
1221
+ return normalizedValue;
1222
+ diagnostics.push(createDiagnostic("invalid-parallel", filePath, source, `Ignoring invalid parallel value in ${filePath}: frontmatter field "parallel" must be an integer greater than or equal to 2.`));
1223
+ }
1224
+ function normalizeStringArrayField(field, value, filePath, source, diagnostics) {
1225
+ if (value === void 0)
1226
+ return [];
1227
+ if (!Array.isArray(value)) {
1228
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: expected an array of strings.`));
1229
+ return;
1230
+ }
1231
+ let args = [];
1232
+ for (let entry of value) {
1233
+ if (typeof entry != "string") {
1234
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: expected an array of strings.`));
1235
+ return;
1236
+ }
1237
+ args.push(entry);
1238
+ }
1239
+ return args;
1240
+ }
1241
+ function normalizeDeterministicHandoff(value, filePath, source, diagnostics) {
1242
+ if (value === void 0)
1243
+ return "always";
1244
+ if (typeof value == "string") {
1245
+ let normalized = value.trim().toLowerCase();
1246
+ if (normalized === "always" || normalized === "never" || normalized === "on-success" || normalized === "on-failure")
1247
+ return normalized;
1248
+ }
1249
+ return diagnostics.push(createDiagnostic("invalid-deterministic-handoff", filePath, source, `Using default deterministic handoff=always for ${filePath}: expected "always", "never", "on-success", or "on-failure".`)), "always";
1250
+ }
1251
+ function normalizeTimeoutMs(value, filePath, source, diagnostics) {
1252
+ if (value === void 0)
1253
+ return;
1254
+ let timeoutMs;
1255
+ if (typeof value == "number" && (timeoutMs = value), typeof value == "string" && /^\d+$/.test(value.trim()) && (timeoutMs = parseInt(value.trim(), 10)), timeoutMs !== void 0 && Number.isInteger(timeoutMs) && timeoutMs >= 1)
1256
+ return timeoutMs;
1257
+ diagnostics.push(createDiagnostic("invalid-deterministic-timeout", filePath, source, `Ignoring invalid deterministic timeout in ${filePath}: expected an integer greater than or equal to 1 (milliseconds).`));
1258
+ }
1259
+ function normalizeDeterministicEnv(value, filePath, source, diagnostics) {
1260
+ if (value === void 0)
1261
+ return;
1262
+ if (!value || typeof value != "object" || Array.isArray(value)) {
1263
+ diagnostics.push(createDiagnostic("invalid-deterministic-env", filePath, source, `Ignoring invalid deterministic env in ${filePath}: expected an object with string/number/boolean values.`));
1264
+ return;
1265
+ }
1266
+ let env = {};
1267
+ for (let [key, raw] of Object.entries(value)) {
1268
+ if (!key.trim()) {
1269
+ diagnostics.push(createDiagnostic("invalid-deterministic-env", filePath, source, `Ignoring invalid deterministic env in ${filePath}: env keys must be non-empty strings.`));
1270
+ return;
1271
+ }
1272
+ if (typeof raw != "string" && typeof raw != "number" && typeof raw != "boolean") {
1273
+ diagnostics.push(createDiagnostic("invalid-deterministic-env", filePath, source, `Ignoring invalid deterministic env in ${filePath}: env value for ${JSON.stringify(key)} must be a string, number, or boolean.`));
1274
+ return;
1275
+ }
1276
+ env[key] = String(raw);
1277
+ }
1278
+ return Object.keys(env).length > 0 ? env : void 0;
1279
+ }
1280
+ function normalizeDeterministicNonInteractive(value, filePath, source, diagnostics) {
1281
+ if (value === void 0)
1282
+ return !0;
1283
+ if (typeof value == "boolean")
1284
+ return value;
1285
+ if (typeof value == "string") {
1286
+ let normalized = value.trim().toLowerCase();
1287
+ if (normalized === "true")
1288
+ return !0;
1289
+ if (normalized === "false")
1290
+ return !1;
1291
+ }
1292
+ return diagnostics.push(createDiagnostic("invalid-deterministic-non-interactive", filePath, source, `Using default deterministic nonInteractive=true for ${filePath}: expected true or false.`)), !0;
1293
+ }
1294
+ function normalizeDeterministicRunValue(value, filePath, source, diagnostics) {
1295
+ if (typeof value == "string") {
1296
+ let command2 = value.trim();
1297
+ if (command2)
1298
+ return { kind: "run", command: command2 };
1299
+ diagnostics.push(createDiagnostic("invalid-deterministic-run", filePath, source, `Ignoring invalid deterministic run value in ${filePath}: expected a non-empty string or an object with command/args.`));
1300
+ return;
1301
+ }
1302
+ if (!value || typeof value != "object" || Array.isArray(value)) {
1303
+ diagnostics.push(createDiagnostic("invalid-deterministic-run", filePath, source, `Ignoring invalid deterministic run value in ${filePath}: expected a non-empty string or an object with command/args.`));
1304
+ return;
1305
+ }
1306
+ let record = value, command = normalizeStringField("deterministic.run.command", record.command, filePath, source, diagnostics);
1307
+ if (!command) {
1308
+ diagnostics.push(createDiagnostic("invalid-deterministic-run", filePath, source, `Ignoring invalid deterministic run value in ${filePath}: expected object field "command" to be a non-empty string.`));
1309
+ return;
1310
+ }
1311
+ let args = normalizeStringArrayField("deterministic.run.args", record.args, filePath, source, diagnostics);
1312
+ if (!args)
1313
+ return;
1314
+ let shell = !1;
1315
+ if (record.shell !== void 0)
1316
+ if (typeof record.shell == "boolean")
1317
+ shell = record.shell;
1318
+ else {
1319
+ diagnostics.push(createDiagnostic("invalid-deterministic-run", filePath, source, `Ignoring invalid deterministic run value in ${filePath}: object field "shell" must be true or false.`));
1320
+ return;
1321
+ }
1322
+ return { kind: "command", command, args, shell };
1323
+ }
1324
+ function normalizeDeterministicScriptValue(value, filePath, source, diagnostics) {
1325
+ if (typeof value == "string") {
1326
+ let path2 = value.trim();
1327
+ if (path2)
1328
+ return { kind: "script", path: path2, args: [] };
1329
+ diagnostics.push(createDiagnostic("invalid-deterministic-script", filePath, source, `Ignoring invalid deterministic script value in ${filePath}: expected a non-empty string or an object with path/args.`));
1330
+ return;
1331
+ }
1332
+ if (!value || typeof value != "object" || Array.isArray(value)) {
1333
+ diagnostics.push(createDiagnostic("invalid-deterministic-script", filePath, source, `Ignoring invalid deterministic script value in ${filePath}: expected a non-empty string or an object with path/args.`));
1334
+ return;
1335
+ }
1336
+ let record = value, path = normalizeStringField("deterministic.script.path", record.path, filePath, source, diagnostics);
1337
+ if (!path) {
1338
+ diagnostics.push(createDiagnostic("invalid-deterministic-script", filePath, source, `Ignoring invalid deterministic script value in ${filePath}: expected object field "path" to be a non-empty string.`));
1339
+ return;
1340
+ }
1341
+ let args = normalizeStringArrayField("deterministic.script.args", record.args, filePath, source, diagnostics);
1342
+ if (args)
1343
+ return { kind: "script", path, args };
1344
+ }
1345
+ function normalizeDeterministic(frontmatter, filePath, source, diagnostics) {
1346
+ let hasNested = Object.hasOwn(frontmatter, "deterministic"), hasRun = Object.hasOwn(frontmatter, "run"), hasScript = Object.hasOwn(frontmatter, "script"), hasHandoff = Object.hasOwn(frontmatter, "handoff"), hasTimeout = Object.hasOwn(frontmatter, "timeout"), hasEnv = Object.hasOwn(frontmatter, "env"), hasNonInteractive = Object.hasOwn(frontmatter, "nonInteractive");
1347
+ if (!hasNested && !hasRun && !hasScript && !hasHandoff && !hasTimeout && !hasEnv && !hasNonInteractive)
1348
+ return;
1349
+ hasNested && (hasRun || hasScript || hasHandoff || hasTimeout || hasEnv || hasNonInteractive) && diagnostics.push(createDiagnostic("invalid-deterministic-mixed-shorthand", filePath, source, `Ignoring top-level deterministic shorthand in ${filePath}: use either "deterministic" or top-level run/script/handoff/timeout/env/nonInteractive, not both.`));
1350
+ let record;
1351
+ if (hasNested) {
1352
+ let raw = frontmatter.deterministic;
1353
+ if (!raw || typeof raw != "object" || Array.isArray(raw)) {
1354
+ diagnostics.push(createDiagnostic("invalid-deterministic", filePath, source, `Ignoring invalid deterministic config in ${filePath}: frontmatter field "deterministic" must be an object.`));
1355
+ return;
1356
+ }
1357
+ record = raw;
1358
+ } else
1359
+ record = {
1360
+ run: frontmatter.run,
1361
+ script: frontmatter.script,
1362
+ handoff: frontmatter.handoff,
1363
+ timeout: frontmatter.timeout,
1364
+ env: frontmatter.env,
1365
+ nonInteractive: frontmatter.nonInteractive
1366
+ };
1367
+ let runValue = Object.hasOwn(record, "run") ? record.run : void 0, scriptValue = Object.hasOwn(record, "script") ? record.script : void 0;
1368
+ if (runValue !== void 0 && scriptValue !== void 0) {
1369
+ diagnostics.push(createDiagnostic("invalid-deterministic", filePath, source, `Ignoring deterministic config in ${filePath}: "run" and "script" cannot be declared together.`));
1370
+ return;
1371
+ }
1372
+ let execution = runValue !== void 0 ? normalizeDeterministicRunValue(runValue, filePath, source, diagnostics) : scriptValue !== void 0 ? normalizeDeterministicScriptValue(scriptValue, filePath, source, diagnostics) : void 0;
1373
+ if (!execution) {
1374
+ diagnostics.push(createDiagnostic("invalid-deterministic", filePath, source, `Ignoring deterministic config in ${filePath}: expected either "run" or "script".`));
1375
+ return;
1376
+ }
1377
+ let handoff = normalizeDeterministicHandoff(record.handoff, filePath, source, diagnostics), timeoutMs = normalizeTimeoutMs(record.timeout, filePath, source, diagnostics), cwd = normalizeCwd(record.cwd, filePath, source, diagnostics), env = normalizeDeterministicEnv(record.env, filePath, source, diagnostics), nonInteractive = normalizeDeterministicNonInteractive(record.nonInteractive, filePath, source, diagnostics);
1378
+ return {
1379
+ execution,
1380
+ handoff,
1381
+ nonInteractive,
1382
+ ...timeoutMs !== void 0 ? { timeoutMs } : {},
1383
+ ...cwd ? { cwd } : {},
1384
+ ...env ? { env } : {}
1385
+ };
1386
+ }
1387
+ function normalizeLineupSlot(value, field, filePath, source, diagnostics, index) {
1388
+ if (!value || typeof value != "object" || Array.isArray(value)) {
1389
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: slot ${index + 1} must be an object.`));
1390
+ return;
1391
+ }
1392
+ let slot = value;
1393
+ if (slot.agent !== void 0 && slot.subagent !== void 0) {
1394
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: slot ${index + 1} cannot combine "agent" and "subagent".`));
1395
+ return;
1396
+ }
1397
+ let agent;
1398
+ if (typeof slot.agent == "string" && slot.agent.trim())
1399
+ agent = slot.agent.trim();
1400
+ else if (slot.agent !== void 0) {
1401
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: slot ${index + 1} requires a non-empty string "agent".`));
1402
+ return;
1403
+ }
1404
+ if (!agent && slot.subagent !== void 0)
1405
+ if (slot.subagent === !0)
1406
+ agent = field === "reviewers" ? "reviewer" : "delegate";
1407
+ else if (typeof slot.subagent == "string" && slot.subagent.trim())
1408
+ agent = slot.subagent.trim();
1409
+ else {
1410
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: slot ${index + 1} requires "subagent" to be true or a non-empty string.`));
1411
+ return;
1412
+ }
1413
+ agent || (agent = field === "reviewers" ? "reviewer" : "delegate");
1414
+ let normalized = {
1415
+ agent
1416
+ };
1417
+ if (slot.model !== void 0) {
1418
+ if (typeof slot.model != "string" || !slot.model.trim()) {
1419
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: slot ${index + 1} has an invalid "model".`));
1420
+ return;
1421
+ }
1422
+ let modelSpec = slot.model.trim();
1423
+ if (!isValidModelSelectionSpec(modelSpec)) {
1424
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: slot ${index + 1} has invalid model spec ${JSON.stringify(modelSpec)}.`));
1425
+ return;
1426
+ }
1427
+ normalized.model = modelSpec;
1428
+ }
1429
+ if (slot.task !== void 0) {
1430
+ if (typeof slot.task != "string") {
1431
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: slot ${index + 1} has a non-string "task".`));
1432
+ return;
1433
+ }
1434
+ let task = slot.task.trim();
1435
+ task && (normalized.task = task);
1436
+ }
1437
+ if (slot.taskSuffix !== void 0) {
1438
+ if (typeof slot.taskSuffix != "string") {
1439
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: slot ${index + 1} has a non-string "taskSuffix".`));
1440
+ return;
1441
+ }
1442
+ let taskSuffix = slot.taskSuffix.trim();
1443
+ taskSuffix && (normalized.taskSuffix = taskSuffix);
1444
+ }
1445
+ if (slot.cwd !== void 0) {
1446
+ if (typeof slot.cwd != "string") {
1447
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: slot ${index + 1} has a non-string "cwd".`));
1448
+ return;
1449
+ }
1450
+ let cwdRaw = slot.cwd.trim();
1451
+ if (cwdRaw) {
1452
+ let expanded = expandCwdPath(cwdRaw);
1453
+ if (!expanded) {
1454
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: slot ${index + 1} "cwd" must be an absolute path.`));
1455
+ return;
1456
+ }
1457
+ normalized.cwd = expanded;
1458
+ }
1459
+ }
1460
+ if (slot.count !== void 0) {
1461
+ let count;
1462
+ if (typeof slot.count == "number" ? count = slot.count : typeof slot.count == "string" && /^\d+$/.test(slot.count.trim()) && (count = parseInt(slot.count.trim(), 10)), count === void 0 || !Number.isInteger(count) || count < 1) {
1463
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: slot ${index + 1} "count" must be an integer greater than or equal to 1.`));
1464
+ return;
1465
+ }
1466
+ normalized.count = count;
1467
+ }
1468
+ return normalized;
1469
+ }
1470
+ function normalizeLineup(value, field, filePath, source, diagnostics) {
1471
+ if (value === void 0)
1472
+ return;
1473
+ if (!Array.isArray(value)) {
1474
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: expected an array of slot objects.`));
1475
+ return;
1476
+ }
1477
+ if (value.length === 0) {
1478
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring invalid ${field} value in ${filePath}: expected at least one slot.`));
1479
+ return;
1480
+ }
1481
+ let slots = [];
1482
+ for (let i = 0; i < value.length; i++) {
1483
+ let normalized = normalizeLineupSlot(value[i], field, filePath, source, diagnostics, i);
1484
+ if (!normalized)
1485
+ return;
1486
+ slots.push(normalized);
1487
+ }
1488
+ return slots;
1489
+ }
1490
+ function normalizeFinalApplier(value, filePath, source, diagnostics) {
1491
+ if (value === void 0)
1492
+ return;
1493
+ let normalized = normalizeLineupSlot(value, "finalApplier", filePath, source, diagnostics, 0);
1494
+ if (!normalized)
1495
+ return;
1496
+ let slot = value;
1497
+ if (Object.hasOwn(slot, "count")) {
1498
+ diagnostics.push(createDiagnostic("invalid-final-applier", filePath, source, `Ignoring invalid finalApplier value in ${filePath}: slot 1 "count" is not supported.`));
1499
+ return;
1500
+ }
1501
+ if (Object.hasOwn(slot, "cwd")) {
1502
+ diagnostics.push(createDiagnostic("invalid-final-applier", filePath, source, `Ignoring invalid finalApplier value in ${filePath}: slot 1 "cwd" is not supported.`));
1503
+ return;
1504
+ }
1505
+ return normalized;
1506
+ }
1507
+ function normalizeBestOfN(value, filePath, source, diagnostics) {
1508
+ if (value !== void 0) {
1509
+ if (value && typeof value == "object" && !Array.isArray(value))
1510
+ return value;
1511
+ diagnostics.push(createDiagnostic("invalid-best-of-n", filePath, source, `Ignoring invalid bestOfN value in ${filePath}: frontmatter field "bestOfN" must be an object.`));
1512
+ }
1513
+ }
1514
+ function pushLegacyCompareFieldDiagnostic(field, filePath, source, diagnostics) {
1515
+ diagnostics.push(createDiagnostic(`invalid-${field}`, filePath, source, `Ignoring top-level ${field} in ${filePath}: compare template authoring moved to "bestOfN.${field}".`));
1516
+ }
1517
+ function normalizeConverge(value, filePath, source, diagnostics) {
1518
+ if (value === void 0)
1519
+ return !0;
1520
+ if (typeof value == "boolean")
1521
+ return value;
1522
+ if (typeof value == "string") {
1523
+ let normalized = value.trim().toLowerCase();
1524
+ if (normalized === "true")
1525
+ return !0;
1526
+ if (normalized === "false")
1527
+ return !1;
1528
+ }
1529
+ return diagnostics.push(createDiagnostic("invalid-converge", filePath, source, `Using default converge=true for ${filePath}: frontmatter field "converge" must be true or false.`)), !0;
1530
+ }
1531
+ function normalizeWorktree(value, filePath, source, diagnostics) {
1532
+ if (value === void 0)
1533
+ return !1;
1534
+ if (typeof value == "boolean")
1535
+ return value;
1536
+ if (typeof value == "string") {
1537
+ let normalized = value.trim().toLowerCase();
1538
+ if (normalized === "true")
1539
+ return !0;
1540
+ if (normalized === "false")
1541
+ return !1;
1542
+ }
1543
+ return diagnostics.push(createDiagnostic("invalid-worktree", filePath, source, `Using default worktree=false for ${filePath}: frontmatter field "worktree" must be true or false.`)), !1;
1544
+ }
1545
+ function normalizeSubagent(value, filePath, source, diagnostics) {
1546
+ if (value === void 0)
1547
+ return;
1548
+ if (value === !0)
1549
+ return !0;
1550
+ if (value === !1)
1551
+ return;
1552
+ if (typeof value != "string") {
1553
+ diagnostics.push(createDiagnostic("invalid-subagent", filePath, source, `Ignoring invalid subagent value in ${filePath}: frontmatter field "subagent" must be true or a non-empty string.`));
1554
+ return;
1555
+ }
1556
+ let normalized = value.trim();
1557
+ if (!normalized) {
1558
+ diagnostics.push(createDiagnostic("invalid-subagent", filePath, source, `Ignoring invalid subagent value in ${filePath}: frontmatter field "subagent" must be true or a non-empty string.`));
1559
+ return;
1560
+ }
1561
+ return normalized;
1562
+ }
1563
+ function expandCwdPath(raw) {
1564
+ let expanded = raw.startsWith("~/") ? join(homedir(), raw.slice(2)) : raw;
1565
+ return isAbsolute(expanded) ? expanded : void 0;
1566
+ }
1567
+ function normalizeCwd(value, filePath, source, diagnostics) {
1568
+ if (value === void 0)
1569
+ return;
1570
+ if (typeof value != "string") {
1571
+ diagnostics.push(createDiagnostic("invalid-cwd", filePath, source, `Ignoring invalid cwd in ${filePath}: expected a string.`));
1572
+ return;
1573
+ }
1574
+ let trimmed = value.trim();
1575
+ if (!trimmed)
1576
+ return;
1577
+ let expanded = expandCwdPath(trimmed);
1578
+ if (!expanded) {
1579
+ diagnostics.push(createDiagnostic("invalid-cwd", filePath, source, `Ignoring cwd in ${filePath}: must be an absolute path.`));
1580
+ return;
1581
+ }
1582
+ return expanded;
1583
+ }
1584
+ function normalizeInheritContext(value, filePath, source, diagnostics) {
1585
+ if (value === void 0)
1586
+ return !1;
1587
+ if (typeof value == "boolean")
1588
+ return value;
1589
+ if (typeof value == "string") {
1590
+ let normalized = value.trim().toLowerCase();
1591
+ if (normalized === "true")
1592
+ return !0;
1593
+ if (normalized === "false")
1594
+ return !1;
1595
+ }
1596
+ return diagnostics.push(createDiagnostic("invalid-inherit-context", filePath, source, `Using default inheritContext=false for ${filePath}: frontmatter field "inheritContext" must be true or false.`)), !1;
1597
+ }
1598
+ function normalizeChain(value, filePath, source, diagnostics) {
1599
+ if (value === void 0)
1600
+ return;
1601
+ if (typeof value != "string") {
1602
+ diagnostics.push(createDiagnostic("invalid-chain", filePath, source, `Ignoring invalid chain value in ${filePath}: frontmatter field "chain" must be a string.`));
1603
+ return;
1604
+ }
1605
+ let normalized = value.trim();
1606
+ if (normalized.length > 0)
1607
+ return normalized;
1608
+ diagnostics.push(createDiagnostic("empty-chain", filePath, source, `Ignoring invalid chain value in ${filePath}: frontmatter field "chain" must be a non-empty string.`));
1609
+ }
1610
+ function normalizeChainContext(value, filePath, source, diagnostics) {
1611
+ if (value !== void 0) {
1612
+ if (typeof value == "string" && value.trim().toLowerCase() === "summary")
1613
+ return "summary";
1614
+ diagnostics.push(createDiagnostic("invalid-chain-context", filePath, source, `Ignoring invalid chainContext value in ${filePath}: frontmatter field "chainContext" must be "summary".`));
1615
+ }
1616
+ }
1617
+ function normalizeThinking(value, filePath, source, diagnostics) {
1618
+ let thinking = normalizeStringField("thinking", value, filePath, source, diagnostics);
1619
+ if (thinking === void 0)
1620
+ return;
1621
+ let normalized = thinking.toLowerCase();
1622
+ if (VALID_THINKING_LEVELS.includes(normalized))
1623
+ return normalized;
1624
+ diagnostics.push(createDiagnostic("invalid-thinking", filePath, source, `Ignoring invalid thinking level in ${filePath}: ${JSON.stringify(thinking)}.`));
1625
+ }
1626
+ function normalizeThinkingLevels(value, modelCount, filePath, source, diagnostics) {
1627
+ if (typeof value != "string")
1628
+ return;
1629
+ let levels = value.split(",").map((item) => item.trim()).filter(Boolean), invalidLevel = levels.find((level) => !VALID_THINKING_LEVELS.includes(level.toLowerCase()));
1630
+ if (invalidLevel) {
1631
+ diagnostics.push(createDiagnostic("invalid-thinking-levels", filePath, source, `Ignoring invalid thinking level in ${filePath}: ${JSON.stringify(invalidLevel)}.`));
1632
+ return;
1633
+ }
1634
+ if (levels.length !== modelCount) {
1635
+ diagnostics.push(createDiagnostic("invalid-thinking-level-count", filePath, source, `Ignoring comma-separated thinking levels in ${filePath}: expected ${modelCount} entries to match frontmatter field "model".`));
1636
+ return;
1637
+ }
1638
+ return levels.map((level) => level.toLowerCase());
1639
+ }
1640
+ function expandConfiguredPromptPath(rawPath, baseDir) {
1641
+ let trimmed = rawPath.trim(), expanded = trimmed === "~" ? homedir() : trimmed.startsWith("~/") ? join(homedir(), trimmed.slice(2)) : trimmed;
1642
+ return isAbsolute(expanded) ? resolve(expanded) : resolve(baseDir, expanded);
1643
+ }
1644
+ function isSettingsPromptPattern(value) {
1645
+ return value.startsWith("!") || value.startsWith("+") || value.startsWith("-") || value.includes("*") || value.includes("?");
1646
+ }
1647
+ function isSettingsPromptOverridePattern(value) {
1648
+ return value.startsWith("!") || value.startsWith("+") || value.startsWith("-");
1649
+ }
1650
+ function toPosixPath(path) {
1651
+ return path.replace(/\\/g, "/");
1652
+ }
1653
+ function normalizeExactPromptPattern(pattern) {
1654
+ let normalized = pattern.startsWith("./") || pattern.startsWith(".\\") ? pattern.slice(2) : pattern;
1655
+ return toPosixPath(normalized);
1656
+ }
1657
+ function matchesPromptPattern(filePath, pattern, baseDir) {
1658
+ let normalizedPattern = toPosixPath(pattern), rel = toPosixPath(relative(baseDir, filePath)), name = basename(filePath), filePathPosix = toPosixPath(filePath);
1659
+ return [rel, name, filePathPosix].some((candidate) => minimatch(candidate, normalizedPattern));
1660
+ }
1661
+ function matchesExactPromptPattern(filePath, pattern, baseDir) {
1662
+ let normalizedPattern = normalizeExactPromptPattern(pattern), rel = toPosixPath(relative(baseDir, filePath)), filePathPosix = toPosixPath(filePath);
1663
+ return normalizedPattern === rel || normalizedPattern === filePathPosix;
1664
+ }
1665
+ function shouldLoadPromptFile(filePath, patterns, baseDir) {
1666
+ let includes = [], excludes = [], forceIncludes = [], forceExcludes = [];
1667
+ for (let pattern of patterns)
1668
+ pattern.startsWith("+") ? forceIncludes.push(pattern.slice(1)) : pattern.startsWith("-") ? forceExcludes.push(pattern.slice(1)) : pattern.startsWith("!") ? excludes.push(pattern.slice(1)) : includes.push(pattern);
1669
+ let enabled = includes.length === 0 || includes.some((pattern) => matchesPromptPattern(filePath, pattern, baseDir));
1670
+ return excludes.some((pattern) => matchesPromptPattern(filePath, pattern, baseDir)) && (enabled = !1), forceIncludes.some((pattern) => matchesExactPromptPattern(filePath, pattern, baseDir)) && (enabled = !0), forceExcludes.some((pattern) => matchesExactPromptPattern(filePath, pattern, baseDir)) && (enabled = !1), enabled;
1671
+ }
1672
+ function createPromptFileFilter(patterns, baseDir) {
1673
+ return patterns.length === 0 ? void 0 : (filePath) => shouldLoadPromptFile(filePath, patterns, baseDir);
1674
+ }
1675
+ function loadConfiguredPromptPaths(settingsPath, source, baseDir, diagnostics) {
1676
+ if (!existsSync(settingsPath))
1677
+ return { paths: [], patterns: [] };
1678
+ let rawSettings;
1679
+ try {
1680
+ rawSettings = readFileSync(settingsPath, "utf-8");
1681
+ } catch (error) {
1682
+ return diagnostics.push(createDiagnostic("unreadable-settings", settingsPath, source, `Skipping prompt settings at ${settingsPath}: ${error instanceof Error ? error.message : String(error)}.`)), { paths: [], patterns: [] };
1683
+ }
1684
+ let parsed;
1685
+ try {
1686
+ parsed = JSON.parse(rawSettings);
1687
+ } catch (error) {
1688
+ return diagnostics.push(createDiagnostic("invalid-settings-json", settingsPath, source, `Skipping prompt settings at ${settingsPath}: ${error instanceof Error ? error.message : String(error)}.`)), { paths: [], patterns: [] };
1689
+ }
1690
+ if (!parsed || typeof parsed != "object" || Array.isArray(parsed))
1691
+ return diagnostics.push(createDiagnostic("invalid-settings", settingsPath, source, `Skipping prompt settings at ${settingsPath}: settings must be a JSON object.`)), { paths: [], patterns: [] };
1692
+ let prompts = parsed.prompts;
1693
+ if (prompts === void 0)
1694
+ return { paths: [], patterns: [] };
1695
+ if (!Array.isArray(prompts))
1696
+ return diagnostics.push(createDiagnostic("invalid-settings-prompts", settingsPath, source, `Ignoring prompts in ${settingsPath}: expected "prompts" to be an array of strings.`)), { paths: [], patterns: [] };
1697
+ let configuredPaths = [], patterns = [];
1698
+ for (let index = 0; index < prompts.length; index++) {
1699
+ let rawPath = prompts[index];
1700
+ if (typeof rawPath != "string" || rawPath.trim().length === 0) {
1701
+ diagnostics.push(createDiagnostic("invalid-settings-prompt-entry", settingsPath, source, `Ignoring prompts[${index}] in ${settingsPath}: expected a non-empty string.`));
1702
+ continue;
1703
+ }
1704
+ let trimmed = rawPath.trim();
1705
+ if (isSettingsPromptPattern(trimmed)) {
1706
+ patterns.push(trimmed);
1707
+ continue;
1708
+ }
1709
+ configuredPaths.push({
1710
+ rawPath: trimmed,
1711
+ resolvedPath: expandConfiguredPromptPath(trimmed, baseDir),
1712
+ settingsPath,
1713
+ source,
1714
+ baseDir
1715
+ });
1716
+ }
1717
+ return { paths: configuredPaths.map((path) => ({ ...path, patterns })), patterns };
1718
+ }
1719
+ function canonicalizePromptFile(filePath) {
1720
+ try {
1721
+ return realpathSync(filePath);
1722
+ } catch {
1723
+ return resolve(filePath);
1724
+ }
1725
+ }
1726
+ function loadPromptsWithModelFromDir(dir, source, includePlainPrompts, subdir = "", visitedDirectories = /* @__PURE__ */ new Set(), onlyFileName, seenFiles, shouldLoadFile) {
1727
+ let prompts = [], diagnostics = [];
1728
+ if (!existsSync(dir))
1729
+ return { prompts, diagnostics };
1730
+ let canonicalDir;
1731
+ try {
1732
+ canonicalDir = realpathSync(dir);
1733
+ } catch (error) {
1734
+ return diagnostics.push(createDiagnostic("unreadable-directory", dir, source, `Skipping prompt directory ${dir}: ${error instanceof Error ? error.message : String(error)}.`)), { prompts, diagnostics };
1735
+ }
1736
+ if (visitedDirectories.has(canonicalDir))
1737
+ return diagnostics.push(createDiagnostic("directory-cycle", dir, source, `Skipping already visited prompt directory at ${dir}.`)), { prompts, diagnostics };
1738
+ visitedDirectories.add(canonicalDir);
1739
+ try {
1740
+ let entries = readdirSync(dir, { withFileTypes: !0 }).sort((a, b) => lexicalCompare(a.name, b.name));
1741
+ for (let entry of entries) {
1742
+ if (onlyFileName && entry.name !== onlyFileName)
1743
+ continue;
1744
+ let fullPath = join(dir, entry.name), isFile = entry.isFile(), isDirectory = entry.isDirectory();
1745
+ if (entry.isSymbolicLink())
1746
+ try {
1747
+ let stats = statSync(fullPath);
1748
+ isFile = stats.isFile(), isDirectory = stats.isDirectory();
1749
+ } catch (error) {
1750
+ diagnostics.push(createDiagnostic("unreadable-symlink", fullPath, source, `Skipping unreadable symlink at ${fullPath}: ${error instanceof Error ? error.message : String(error)}.`));
1751
+ continue;
1752
+ }
1753
+ if (isDirectory) {
1754
+ if (onlyFileName)
1755
+ continue;
1756
+ let nextSubdir = subdir ? `${subdir}:${entry.name}` : entry.name, nested = loadPromptsWithModelFromDir(fullPath, source, includePlainPrompts, nextSubdir, visitedDirectories, void 0, seenFiles, shouldLoadFile);
1757
+ prompts.push(...nested.prompts), diagnostics.push(...nested.diagnostics);
1758
+ continue;
1759
+ }
1760
+ if (!isFile || !entry.name.endsWith(".md") || shouldLoadFile && !shouldLoadFile(fullPath))
1761
+ continue;
1762
+ let canonicalFile = canonicalizePromptFile(fullPath);
1763
+ if (!seenFiles?.has(canonicalFile)) {
1764
+ seenFiles?.add(canonicalFile);
1765
+ try {
1766
+ let rawContent = readFileSync(fullPath, "utf-8"), parsed = parseFrontmatter(rawContent), frontmatter = normalizeFrontmatterRecord(parsed.frontmatter, fullPath, source, diagnostics);
1767
+ if (!frontmatter)
1768
+ continue;
1769
+ let { body } = parsed, chain = normalizeChain(frontmatter.chain, fullPath, source, diagnostics), parsedChainDeclarationResult, chainContext = chain ? normalizeChainContext(frontmatter.chainContext, fullPath, source, diagnostics) : void 0;
1770
+ if (chain && /\bparallel\s*\(/.test(chain) && (parsedChainDeclarationResult = parseChainDeclaration(chain), parsedChainDeclarationResult.invalidSegments.length > 0 || parsedChainDeclarationResult.steps.length === 0)) {
1771
+ diagnostics.push(createDiagnostic("invalid-chain-declaration", fullPath, source, `Skipping prompt template at ${fullPath}: invalid chain declaration segment ${JSON.stringify(parsedChainDeclarationResult.invalidSegments[0] ?? chain)}.`));
1772
+ continue;
1773
+ }
1774
+ let subagent = normalizeSubagent(frontmatter.subagent, fullPath, source, diagnostics), cwd = normalizeCwd(frontmatter.cwd, fullPath, source, diagnostics), inheritContext = normalizeInheritContext(frontmatter.inheritContext, fullPath, source, diagnostics), parallel = normalizeParallel(frontmatter.parallel, fullPath, source, diagnostics), hasBestOfN = Object.hasOwn(frontmatter, "bestOfN"), bestOfN = normalizeBestOfN(frontmatter.bestOfN, fullPath, source, diagnostics), deterministic = normalizeDeterministic(frontmatter, fullPath, source, diagnostics), hasLegacyWorkers = Object.hasOwn(frontmatter, "workers"), hasLegacyReviewers = Object.hasOwn(frontmatter, "reviewers"), hasLegacyFinalApplier = Object.hasOwn(frontmatter, "finalApplier"), hasLegacyCompareFields = hasLegacyWorkers || hasLegacyReviewers || hasLegacyFinalApplier;
1775
+ hasLegacyWorkers && pushLegacyCompareFieldDiagnostic("workers", fullPath, source, diagnostics), hasLegacyReviewers && pushLegacyCompareFieldDiagnostic("reviewers", fullPath, source, diagnostics), hasLegacyFinalApplier && pushLegacyCompareFieldDiagnostic("finalApplier", fullPath, source, diagnostics), hasBestOfN && Object.hasOwn(frontmatter, "worktree") && diagnostics.push(createDiagnostic("invalid-worktree", fullPath, source, `Ignoring top-level worktree in ${fullPath}: use "bestOfN.worktree" for compare template authoring.`));
1776
+ let workers = normalizeLineup(hasBestOfN ? bestOfN?.workers : void 0, "workers", fullPath, source, diagnostics), reviewers = normalizeLineup(hasBestOfN ? bestOfN?.reviewers : void 0, "reviewers", fullPath, source, diagnostics), finalApplier = normalizeFinalApplier(hasBestOfN ? bestOfN?.finalApplier : void 0, fullPath, source, diagnostics), safeWorkers = workers, safeReviewers = reviewers, safeFinalApplier = finalApplier;
1777
+ chain && subagent !== void 0 && (diagnostics.push(createDiagnostic("invalid-subagent-chain", fullPath, source, `Ignoring subagent in ${fullPath}: frontmatter fields "chain" and "subagent" cannot be combined.`)), subagent = void 0), chain && deterministic !== void 0 && (diagnostics.push(createDiagnostic("invalid-deterministic-chain", fullPath, source, `Ignoring deterministic config in ${fullPath}: frontmatter field "deterministic" cannot be combined with "chain".`)), deterministic = void 0), chain && (safeWorkers !== void 0 || safeReviewers !== void 0 || safeFinalApplier !== void 0) && (diagnostics.push(createDiagnostic("invalid-lineup-chain", fullPath, source, `Ignoring compare lineup config in ${fullPath}: frontmatter fields "workers"/"reviewers"/"finalApplier" cannot be combined with "chain".`)), safeWorkers = void 0, safeReviewers = void 0, safeFinalApplier = void 0), subagent !== void 0 && (safeWorkers !== void 0 || safeReviewers !== void 0 || safeFinalApplier !== void 0) && (diagnostics.push(createDiagnostic("invalid-lineup-subagent", fullPath, source, `Ignoring compare lineup config in ${fullPath}: frontmatter fields "workers"/"reviewers"/"finalApplier" cannot be combined with "subagent".`)), safeWorkers = void 0, safeReviewers = void 0, safeFinalApplier = void 0), subagent !== void 0 && deterministic !== void 0 && (diagnostics.push(createDiagnostic("invalid-deterministic-subagent", fullPath, source, `Ignoring deterministic config in ${fullPath}: frontmatter field "deterministic" cannot be combined with "subagent".`)), deterministic = void 0), subagent === void 0 && inheritContext && diagnostics.push(createDiagnostic("invalid-inherit-context", fullPath, source, `Ignoring inheritContext in ${fullPath}: frontmatter field "inheritContext" requires "subagent".`));
1778
+ let safeParallel = parallel;
1779
+ safeParallel !== void 0 && chain && (diagnostics.push(createDiagnostic("invalid-parallel", fullPath, source, `Ignoring parallel in ${fullPath}: frontmatter field "parallel" cannot be combined with "chain".`)), safeParallel = void 0), safeParallel !== void 0 && subagent === void 0 && (diagnostics.push(createDiagnostic("invalid-parallel", fullPath, source, `Ignoring parallel in ${fullPath}: frontmatter field "parallel" requires "subagent".`)), safeParallel = void 0), safeParallel !== void 0 && (safeWorkers !== void 0 || safeReviewers !== void 0 || safeFinalApplier !== void 0) && (diagnostics.push(createDiagnostic("invalid-lineup-parallel", fullPath, source, `Ignoring compare lineup config in ${fullPath}: frontmatter fields "workers"/"reviewers"/"finalApplier" cannot be combined with "parallel".`)), safeWorkers = void 0, safeReviewers = void 0, safeFinalApplier = void 0), safeParallel !== void 0 && deterministic !== void 0 && (diagnostics.push(createDiagnostic("invalid-deterministic-parallel", fullPath, source, `Ignoring deterministic config in ${fullPath}: frontmatter field "deterministic" cannot be combined with "parallel".`)), deterministic = void 0);
1780
+ let hasLineup = safeWorkers !== void 0 || safeReviewers !== void 0 || safeFinalApplier !== void 0;
1781
+ if (!hasBestOfN && hasLegacyCompareFields) {
1782
+ diagnostics.push(createDiagnostic("invalid-compare-frontmatter", fullPath, source, `Skipping prompt template at ${fullPath}: compare template authoring moved under "bestOfN:".`));
1783
+ continue;
1784
+ }
1785
+ if (hasBestOfN && !hasLineup) {
1786
+ diagnostics.push(createDiagnostic("invalid-best-of-n", fullPath, source, `Skipping prompt template at ${fullPath}: "bestOfN" did not produce a valid compare configuration.`));
1787
+ continue;
1788
+ }
1789
+ !chain && subagent === void 0 && !hasLineup && cwd && (deterministic ? deterministic = { ...deterministic, ...deterministic.cwd ? {} : { cwd } } : diagnostics.push(createDiagnostic("invalid-cwd", fullPath, source, `Ignoring cwd in ${fullPath}: frontmatter field "cwd" requires "subagent", "chain", or compare lineups ("workers"/"reviewers"/"finalApplier").`)));
1790
+ let hasModelField = Object.hasOwn(frontmatter, "model"), parsedModels = chain ? [] : normalizeModelSpecs(frontmatter.model, fullPath, source, diagnostics);
1791
+ if (!chain && hasModelField && !parsedModels)
1792
+ continue;
1793
+ let models = chain ? [] : parsedModels ?? [], rotate = chain ? !1 : normalizeRotate(frontmatter.rotate, fullPath, source, diagnostics), name = entry.name.slice(0, -3);
1794
+ if (RESERVED_COMMAND_NAMES.has(name)) {
1795
+ diagnostics.push(createDiagnostic("reserved-command-name", fullPath, source, `Skipping prompt template at ${fullPath}: command name "${name}" is reserved.`));
1796
+ continue;
1797
+ }
1798
+ let safeInheritContext = subagent !== void 0 && inheritContext, safeCwd = chain || subagent !== void 0 || hasLineup ? cwd : void 0, description = normalizeStringField("description", frontmatter.description, fullPath, source, diagnostics) ?? "", skill = chain ? void 0 : normalizeStringField("skill", frontmatter.skill, fullPath, source, diagnostics), thinking, thinkingLevels;
1799
+ chain || (rotate && typeof frontmatter.thinking == "string" && frontmatter.thinking.includes(",") ? thinkingLevels = normalizeThinkingLevels(frontmatter.thinking, models.length, fullPath, source, diagnostics) : thinking = normalizeThinking(frontmatter.thinking, fullPath, source, diagnostics));
1800
+ let restore = normalizeRestore(frontmatter.restore, fullPath, source, diagnostics), fresh = normalizeFresh(frontmatter.fresh, fullPath, source, diagnostics), loop = normalizeLoop(frontmatter.loop, fullPath, source, diagnostics), converge = normalizeConverge(frontmatter.converge, fullPath, source, diagnostics), boomerang = normalizeBoomerang(frontmatter.boomerang, fullPath, source, diagnostics);
1801
+ chain && boomerang && (diagnostics.push(createDiagnostic("invalid-boomerang-chain", fullPath, source, `Ignoring boomerang in ${fullPath}: frontmatter fields "chain" and "boomerang" cannot be combined.`)), boomerang = !1), loop !== void 0 && deterministic !== void 0 && (diagnostics.push(createDiagnostic("invalid-deterministic-loop", fullPath, source, `Ignoring deterministic config in ${fullPath}: frontmatter field "deterministic" cannot be combined with "loop" in v1.`)), deterministic = void 0);
1802
+ let worktreeInput = hasBestOfN ? bestOfN?.worktree : frontmatter.worktree, worktree = normalizeWorktree(worktreeInput, fullPath, source, diagnostics), safeWorktree;
1803
+ if (worktree)
1804
+ if (chain) {
1805
+ let parsedChain = parsedChainDeclarationResult ?? parseChainDeclaration(chain), hasParallelStep = parsedChain.steps.some((step) => "parallel" in step);
1806
+ parsedChain.invalidSegments.length > 0 || parsedChain.steps.length === 0 || !hasParallelStep ? diagnostics.push(createDiagnostic("invalid-worktree", fullPath, source, `Ignoring worktree in ${fullPath}: frontmatter field "worktree" requires either "chain" with at least one parallel() step, "subagent" with frontmatter field "parallel", or compare lineups ("workers"/"reviewers"/"finalApplier").`)) : safeWorktree = !0;
1807
+ } else subagent !== void 0 && safeParallel !== void 0 || hasLineup ? safeWorktree = !0 : diagnostics.push(createDiagnostic("invalid-worktree", fullPath, source, `Ignoring worktree in ${fullPath}: frontmatter field "worktree" requires either "chain" with at least one parallel() step, "subagent" with frontmatter field "parallel", or compare lineups ("workers"/"reviewers"/"finalApplier").`));
1808
+ let hasModelConditionalDirectives = /<if-model(?:\s|>)|<else(?:\s|>)|<\/if-model\s*>|<\/else(?:\s|>)/.test(body);
1809
+ if (!chain && !hasModelField && !(skill !== void 0 || thinking !== void 0 || fresh === !0 || loop !== void 0 || converge === !1 || boomerang === !0 || safeParallel !== void 0 || deterministic !== void 0 || hasLineup || safeWorktree === !0 || subagent !== void 0 || safeInheritContext || hasModelConditionalDirectives) && !includePlainPrompts)
1810
+ continue;
1811
+ prompts.push({
1812
+ name,
1813
+ description,
1814
+ content: body,
1815
+ models,
1816
+ chain: chain || void 0,
1817
+ chainContext,
1818
+ restore,
1819
+ skill,
1820
+ thinking,
1821
+ thinkingLevels,
1822
+ rotate: rotate || void 0,
1823
+ fresh: fresh || void 0,
1824
+ loop: loop !== void 0 ? loop : void 0,
1825
+ converge: converge === !1 ? !1 : void 0,
1826
+ boomerang: boomerang || void 0,
1827
+ parallel: safeParallel,
1828
+ worktree: safeWorktree,
1829
+ deterministic,
1830
+ subagent,
1831
+ inheritContext: safeInheritContext || void 0,
1832
+ cwd: safeCwd || void 0,
1833
+ workers: safeWorkers,
1834
+ reviewers: safeReviewers,
1835
+ finalApplier: safeFinalApplier,
1836
+ source,
1837
+ subdir: subdir || void 0,
1838
+ filePath: fullPath
1839
+ });
1840
+ } catch (error) {
1841
+ diagnostics.push(createDiagnostic("invalid-prompt-file", fullPath, source, `Skipping prompt template at ${fullPath}: ${error instanceof Error ? error.message : String(error)}.`));
1842
+ }
1843
+ }
1844
+ }
1845
+ } catch (error) {
1846
+ diagnostics.push(createDiagnostic("unreadable-directory", dir, source, `Skipping prompt directory ${dir}: ${error instanceof Error ? error.message : String(error)}.`));
1847
+ }
1848
+ return { prompts, diagnostics };
1849
+ }
1850
+ function loadPromptsWithModelFromConfiguredPath(configuredPath, includePlainPrompts, seenFiles) {
1851
+ let diagnostics = [], { rawPath, resolvedPath, settingsPath, source, baseDir, patterns } = configuredPath, shouldLoadFile = createPromptFileFilter(patterns, baseDir);
1852
+ if (!existsSync(resolvedPath))
1853
+ return diagnostics.push(createDiagnostic("missing-prompt-path", resolvedPath, source, `Skipping configured prompt path ${JSON.stringify(rawPath)} from ${settingsPath}: resolved path ${resolvedPath} does not exist.`)), { prompts: [], diagnostics };
1854
+ let stats;
1855
+ try {
1856
+ stats = statSync(resolvedPath);
1857
+ } catch (error) {
1858
+ return diagnostics.push(createDiagnostic("unreadable-prompt-path", resolvedPath, source, `Skipping configured prompt path ${JSON.stringify(rawPath)} from ${settingsPath}: ${error instanceof Error ? error.message : String(error)}.`)), { prompts: [], diagnostics };
1859
+ }
1860
+ return stats.isDirectory() ? loadPromptsWithModelFromDir(resolvedPath, source, includePlainPrompts, "", /* @__PURE__ */ new Set(), void 0, seenFiles, shouldLoadFile) : !stats.isFile() || !resolvedPath.endsWith(".md") ? (diagnostics.push(createDiagnostic("invalid-prompt-path", resolvedPath, source, `Skipping configured prompt path ${JSON.stringify(rawPath)} from ${settingsPath}: expected a directory or .md file.`)), { prompts: [], diagnostics }) : loadPromptsWithModelFromDir(dirname(resolvedPath), source, includePlainPrompts, "", /* @__PURE__ */ new Set(), basename(resolvedPath), seenFiles, shouldLoadFile);
1861
+ }
1862
+ function loadPromptsWithModel(cwd, includePlainPrompts = !1) {
1863
+ let agentDir = getAgentDir(), globalDir = join(agentDir, "prompts"), projectBaseDir = resolve(cwd, CONFIG_DIR_NAME), projectDir = join(projectBaseDir, "prompts"), promptMap = /* @__PURE__ */ new Map(), diagnostics = [], seenPromptFiles = /* @__PURE__ */ new Set();
1864
+ function addPrompt(prompt) {
1865
+ let existing = promptMap.get(prompt.name);
1866
+ if (!existing) {
1867
+ promptMap.set(prompt.name, prompt);
1868
+ return;
1869
+ }
1870
+ existing.source === prompt.source && diagnostics.push(createDiagnostic("duplicate-command-name", prompt.filePath, prompt.source, `Skipping ${prompt.source} prompt template "${prompt.name}" at ${prompt.filePath} because it conflicts with ${existing.filePath}.`));
1871
+ }
1872
+ function addResult(result) {
1873
+ diagnostics.push(...result.diagnostics);
1874
+ for (let prompt of result.prompts)
1875
+ addPrompt(prompt);
1876
+ }
1877
+ let projectSettingsPaths = loadConfiguredPromptPaths(join(projectBaseDir, "settings.json"), "project", projectBaseDir, diagnostics), globalSettingsPaths = loadConfiguredPromptPaths(join(agentDir, "settings.json"), "user", agentDir, diagnostics), projectDefaultFilter = createPromptFileFilter(projectSettingsPaths.patterns.filter(isSettingsPromptOverridePattern), projectBaseDir), globalDefaultFilter = createPromptFileFilter(globalSettingsPaths.patterns.filter(isSettingsPromptOverridePattern), agentDir);
1878
+ for (let configuredPath of projectSettingsPaths.paths)
1879
+ addResult(loadPromptsWithModelFromConfiguredPath(configuredPath, includePlainPrompts, seenPromptFiles));
1880
+ addResult(loadPromptsWithModelFromDir(projectDir, "project", includePlainPrompts, "", /* @__PURE__ */ new Set(), void 0, seenPromptFiles, projectDefaultFilter));
1881
+ for (let configuredPath of globalSettingsPaths.paths)
1882
+ addResult(loadPromptsWithModelFromConfiguredPath(configuredPath, includePlainPrompts, seenPromptFiles));
1883
+ return addResult(loadPromptsWithModelFromDir(globalDir, "user", includePlainPrompts, "", /* @__PURE__ */ new Set(), void 0, seenPromptFiles, globalDefaultFilter)), { prompts: promptMap, diagnostics };
1884
+ }
1885
+ function effectiveLineupCount(slots) {
1886
+ return slots?.reduce((total, slot) => total + (slot.count ?? 1), 0) ?? 0;
1887
+ }
1888
+ function buildPromptCommandDescription(prompt) {
1889
+ let sourceLabel = prompt.subdir ? `(${prompt.source}:${prompt.subdir})` : `(${prompt.source})`;
1890
+ if (prompt.chain) {
1891
+ let chainContextLabel = prompt.chainContext ? ` ${prompt.chainContext}` : "", cwdLabel2 = prompt.cwd ? ` cwd:${prompt.cwd}` : "", worktreeLabel2 = prompt.worktree ? " worktree" : "", details2 = `[chain: ${prompt.chain}${chainContextLabel}${cwdLabel2}${worktreeLabel2}] ${sourceLabel}`;
1892
+ return prompt.description ? `${prompt.description} ${details2}` : details2;
1893
+ }
1894
+ let modelLabel = prompt.models.length > 0 ? prompt.models.map((model) => model.split("/").pop() || model).join("|") : "current", rotateLabel = prompt.rotate ? " rotate" : "", skillLabel = prompt.skill ? ` +${prompt.skill}` : "", thinkingValue = prompt.thinkingLevels ? prompt.thinkingLevels.join(",") : prompt.thinking, thinkingLabel = thinkingValue ? ` ${thinkingValue}` : "", loopLabel = prompt.loop !== void 0 ? ` loop:${prompt.loop === null ? "unlimited" : prompt.loop}` : "", boomerangLabel = prompt.boomerang ? " boomerang" : "", subagentLabel = prompt.subagent ? ` subagent:${prompt.subagent === !0 ? "delegate" : prompt.subagent}` : "", parallelLabel = prompt.parallel !== void 0 ? ` parallel:${prompt.parallel}` : "", deterministicLabel = prompt.deterministic ? ` deterministic-step:${prompt.deterministic.handoff}` : "", workersLabel = prompt.workers ? ` workers:${effectiveLineupCount(prompt.workers)}` : "", reviewersLabel = prompt.reviewers ? ` reviewers:${effectiveLineupCount(prompt.reviewers)}` : "", finalApplierLabel = prompt.finalApplier ? " final-applier" : "", cwdLabel = prompt.cwd ? ` cwd:${prompt.cwd}` : "", inheritContextLabel = prompt.inheritContext ? " fork" : "", worktreeLabel = prompt.worktree ? " worktree" : "", details = `[${modelLabel}${rotateLabel}${thinkingLabel}${skillLabel}${loopLabel}${boomerangLabel}${subagentLabel}${parallelLabel}${deterministicLabel}${workersLabel}${reviewersLabel}${finalApplierLabel}${cwdLabel}${inheritContextLabel}${worktreeLabel}] ${sourceLabel}`;
1895
+ return prompt.description ? `${prompt.description} ${details}` : details;
1896
+ }
1897
+ function getSkillCandidates(baseDir, skillName) {
1898
+ return [join(baseDir, skillName, "SKILL.md"), join(baseDir, `${skillName}.md`)];
1899
+ }
1900
+ function* walkAncestors(startDir, stopDir) {
1901
+ let current = startDir;
1902
+ for (; ; ) {
1903
+ if (yield current, stopDir && current === stopDir)
1904
+ return;
1905
+ let parent = dirname(current);
1906
+ if (parent === current)
1907
+ return;
1908
+ current = parent;
1909
+ }
1910
+ }
1911
+ function findRepoRoot(startDir) {
1912
+ for (let dir of walkAncestors(startDir))
1913
+ if (existsSync(join(dir, ".git")))
1914
+ return dir;
1915
+ }
1916
+ function findFirstExisting(paths) {
1917
+ for (let path of paths)
1918
+ if (existsSync(path))
1919
+ return path;
1920
+ }
1921
+ function resolveSkillPath(skillName, cwd) {
1922
+ let projectDir = resolve(cwd), projectPiSkill = findFirstExisting(getSkillCandidates(resolve(projectDir, CONFIG_DIR_NAME, "skills"), skillName));
1923
+ if (projectPiSkill)
1924
+ return projectPiSkill;
1925
+ let repoRoot = findRepoRoot(projectDir);
1926
+ for (let dir of walkAncestors(projectDir, repoRoot)) {
1927
+ let projectAgentsSkill = findFirstExisting(getSkillCandidates(join(dir, ".agents", "skills"), skillName));
1928
+ if (projectAgentsSkill)
1929
+ return projectAgentsSkill;
1930
+ }
1931
+ let globalPiSkill = findFirstExisting(getSkillCandidates(join(getAgentDir(), "skills"), skillName));
1932
+ return globalPiSkill || findFirstExisting(getSkillCandidates(join(homedir(), ".agents", "skills"), skillName));
1933
+ }
1934
+ function readSkillContent(skillPath) {
1935
+ let raw = readFileSync(skillPath, "utf-8");
1936
+ return parseFrontmatter(raw).body;
1937
+ }
1938
+
1939
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/skill-loaded-renderer.js
1940
+ import { Box, Container, Spacer, Text } from "@ashx-j/lunr-tui";
1941
+ var SKILL_PREVIEW_LINES = 5;
1942
+ function renderSkillLoaded(message, options, theme) {
1943
+ let container = new Container();
1944
+ if (!message.details)
1945
+ return container.addChild(new Spacer(1)), container.addChild(new Text(theme.fg("warning", "Skill loaded message is missing details."), 0, 0)), container;
1946
+ let { skillName, skillContent, skillPath } = message.details;
1947
+ container.addChild(new Spacer(1));
1948
+ let box = new Box(1, 1, (text) => theme.bg("toolSuccessBg", text));
1949
+ box.addChild(new Text(theme.fg("toolTitle", theme.bold(`Skill loaded: ${skillName}`)), 0, 0)), box.addChild(new Text(theme.fg("toolOutput", ` ${skillPath}`), 0, 0)), box.addChild(new Spacer(1));
1950
+ let lines = skillContent.split(`
1951
+ `);
1952
+ if (options.expanded)
1953
+ box.addChild(new Text(lines.map((line) => theme.fg("toolOutput", line)).join(`
1954
+ `), 0, 0));
1955
+ else {
1956
+ let previewLines = lines.slice(0, SKILL_PREVIEW_LINES), remaining = lines.length - SKILL_PREVIEW_LINES;
1957
+ box.addChild(new Text(previewLines.map((line) => theme.fg("toolOutput", line)).join(`
1958
+ `), 0, 0)), remaining > 0 && box.addChild(new Text(theme.fg("warning", `
1959
+ ... (${remaining} more lines)`), 0, 0));
1960
+ }
1961
+ return container.addChild(box), container;
1962
+ }
1963
+
1964
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/tool-manager.js
1965
+ import { mkdirSync, readFileSync as readFileSync2, writeFileSync } from "node:fs";
1966
+ import { join as join2 } from "node:path";
1967
+ import { Type } from "typebox";
1968
+ function createToolManager(pi, deps) {
1969
+ let toolEnabled = !1, toolGuidance = null, toolRegistered = !1, toolQueuedCommand = null, configPath = join2(getAgentDir(), "prompt-template-model.json");
1970
+ try {
1971
+ let rawConfig = JSON.parse(readFileSync2(configPath, "utf-8"));
1972
+ if (rawConfig && typeof rawConfig == "object") {
1973
+ let config = rawConfig;
1974
+ typeof config.toolEnabled == "boolean" && (toolEnabled = config.toolEnabled), typeof config.toolGuidance == "string" && (toolGuidance = config.toolGuidance);
1975
+ }
1976
+ } catch (error) {
1977
+ error.code !== "ENOENT" && process.stderr.write(`[pi-prompt-template-model] Failed to read ${configPath}: ${error instanceof Error ? error.message : String(error)}
1978
+ `);
1979
+ }
1980
+ function saveToolConfig() {
1981
+ try {
1982
+ mkdirSync(getAgentDir(), { recursive: !0 }), writeFileSync(configPath, JSON.stringify({ toolEnabled, toolGuidance }, null, 2));
1983
+ } catch (error) {
1984
+ process.stderr.write(`[pi-prompt-template-model] Failed to write ${configPath}: ${error instanceof Error ? error.message : String(error)}
1985
+ `);
1986
+ }
1987
+ }
1988
+ function ensureRegistered() {
1989
+ toolRegistered || (toolRegistered = !0, pi.registerTool({
1990
+ name: "run-prompt",
1991
+ label: "Run Prompt",
1992
+ description: "Run a prompt template command. Pass the template name and any arguments. Supports --loop for loops (e.g. 'deslop --loop 5', 'deslop --loop=5', 'deslop --loop' for unlimited until convergence with a 999-iteration cap), --fresh for context collapse between iterations, and --no-converge to disable early stopping for bounded loops. Supports runtime delegation override via --subagent, --subagent=<name>, or --subagent:<name>. Use 'chain-prompts template1 -> template2' for chaining and add --chain-context to pass previous step summaries into delegated steps.",
1993
+ promptSnippet: "Use this to run slash/prompt templates by name with args (including --loop/--fresh and chain-prompts flows) when the user asks to execute a prompt template.",
1994
+ parameters: Type.Object({
1995
+ command: Type.String({
1996
+ description: "Template name and arguments (e.g. 'deslop --loop 5 --fresh', 'deslop --subagent:worker', 'deslop --subagent', 'chain-prompts analyze -> fix --chain-context', 'chain-prompts analyze -> fix --loop=3')"
1997
+ })
1998
+ }),
1999
+ execute: async (_id, params) => {
2000
+ if (!toolEnabled)
2001
+ return {
2002
+ content: [{ type: "text", text: "run-prompt tool is disabled. User must run `/prompt-tool on` to enable." }],
2003
+ details: {}
2004
+ };
2005
+ if (deps.isActive())
2006
+ return {
2007
+ content: [{ type: "text", text: "A prompt command is already running. Wait for it to complete." }],
2008
+ details: {}
2009
+ };
2010
+ if (!deps.getStoredCtx())
2011
+ return {
2012
+ content: [{ type: "text", text: "No command context. Run any prompt command first to initialize." }],
2013
+ details: {},
2014
+ isError: !0
2015
+ };
2016
+ let commandParam = params.command, command = typeof commandParam == "string" ? commandParam.trim() : "";
2017
+ return command ? toolQueuedCommand ? {
2018
+ content: [{ type: "text", text: "A prompt command is already queued. Wait for it to execute." }],
2019
+ details: {},
2020
+ isError: !0
2021
+ } : (toolQueuedCommand = command, {
2022
+ content: [{ type: "text", text: `Prompt command queued: "${command}". Will execute when this turn ends.` }],
2023
+ details: {}
2024
+ }) : {
2025
+ content: [{ type: "text", text: "No command specified." }],
2026
+ details: {},
2027
+ isError: !0
2028
+ };
2029
+ }
2030
+ }));
2031
+ }
2032
+ function registerCommand() {
2033
+ pi.registerCommand("prompt-tool", {
2034
+ description: "Manage the run-prompt tool (agent-accessible prompt execution)",
2035
+ handler: async (args, ctx) => {
2036
+ deps.setStoredCtx(ctx);
2037
+ let trimmed = args.trim();
2038
+ if (trimmed === "on" || trimmed.startsWith("on ")) {
2039
+ toolEnabled = !0, ensureRegistered();
2040
+ let guidanceRaw = trimmed.slice(2).trim();
2041
+ guidanceRaw ? (toolGuidance = guidanceRaw.replace(/^["']|["']$/g, ""), notify(ctx, `run-prompt tool enabled with guidance: "${toolGuidance}"`, "info")) : notify(ctx, "run-prompt tool enabled.", "info"), saveToolConfig();
2042
+ return;
2043
+ }
2044
+ if (trimmed === "off") {
2045
+ toolEnabled = !1, saveToolConfig(), notify(ctx, "run-prompt tool disabled.", "info");
2046
+ return;
2047
+ }
2048
+ if (trimmed === "guidance" || trimmed.startsWith("guidance ")) {
2049
+ trimmed === "guidance" || trimmed === "guidance show" ? toolGuidance ? notify(ctx, `Current guidance: "${toolGuidance}"`, "info") : notify(ctx, "No guidance set. Use `/prompt-tool guidance <text>` to set.", "info") : trimmed === "guidance clear" ? (toolGuidance = null, saveToolConfig(), notify(ctx, "Guidance cleared.", "info")) : (toolGuidance = trimmed.slice(8).trim().replace(/^["']|["']$/g, ""), saveToolConfig(), notify(ctx, `Guidance set: "${toolGuidance}"`, "info"));
2050
+ return;
2051
+ }
2052
+ if (!trimmed) {
2053
+ if (toolEnabled) {
2054
+ let guidanceInfo = toolGuidance ? ` | Guidance: "${toolGuidance}"` : "";
2055
+ notify(ctx, `run-prompt tool is enabled${guidanceInfo}`, "info");
2056
+ } else
2057
+ notify(ctx, "run-prompt tool is disabled", "info");
2058
+ return;
2059
+ }
2060
+ notify(ctx, "Usage: /prompt-tool [on [guidance] | off | guidance [text|clear]]", "error");
2061
+ }
2062
+ });
2063
+ }
2064
+ async function processQueue(ctx, restoreFn) {
2065
+ if (!toolQueuedCommand)
2066
+ return !1;
2067
+ let storedCtx = deps.getStoredCtx();
2068
+ if (!storedCtx)
2069
+ return toolQueuedCommand = null, !1;
2070
+ let command = toolQueuedCommand;
2071
+ toolQueuedCommand = null, await restoreFn();
2072
+ try {
2073
+ await deps.executeCommand(command, storedCtx);
2074
+ } catch (error) {
2075
+ notify(ctx, `Failed to execute queued prompt command "${command}": ${error instanceof Error ? error.message : String(error)}`, "error");
2076
+ }
2077
+ return !0;
2078
+ }
2079
+ return {
2080
+ isEnabled() {
2081
+ return toolEnabled;
2082
+ },
2083
+ getGuidance() {
2084
+ return toolGuidance;
2085
+ },
2086
+ hasQueuedCommand() {
2087
+ return toolQueuedCommand !== null;
2088
+ },
2089
+ clearQueue() {
2090
+ toolQueuedCommand = null;
2091
+ },
2092
+ ensureRegistered,
2093
+ registerCommand,
2094
+ processQueue
2095
+ };
2096
+ }
2097
+
2098
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/subagent-step.js
2099
+ import { existsSync as existsSync2 } from "node:fs";
2100
+ import { randomUUID } from "node:crypto";
2101
+ import { Key, matchesKey } from "@ashx-j/lunr-tui";
2102
+
2103
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/subagent-widget.js
2104
+ import { Box as Box2, Container as Container2, Spacer as Spacer2, Text as Text2 } from "@ashx-j/lunr-tui";
2105
+ var DELEGATED_WIDGET_KEY = "prompt-subagent-progress";
2106
+ function formatDuration(ms) {
2107
+ let seconds = Math.floor(ms / 1e3);
2108
+ if (seconds < 60)
2109
+ return `${seconds}s`;
2110
+ let minutes = Math.floor(seconds / 60), remaining = seconds % 60;
2111
+ return `${minutes}m${remaining}s`;
2112
+ }
2113
+ function formatTokens(n) {
2114
+ return n ? n >= 1e3 ? `${(n / 1e3).toFixed(1)}k` : String(n) : "0";
2115
+ }
2116
+ function normalizeModelLabel(model) {
2117
+ if (model)
2118
+ return model.includes("/") ? model.split("/").pop() : model;
2119
+ }
2120
+ function formatToolCall(tool, args) {
2121
+ let safeArgs = args ?? "";
2122
+ switch (tool) {
2123
+ case "bash": {
2124
+ let cmd = safeArgs.replace(/[\n\t]/g, " ").trim();
2125
+ return `$ ${cmd.length > 80 ? cmd.slice(0, 80) + "..." : cmd}`;
2126
+ }
2127
+ case "read":
2128
+ return `[read: ${safeArgs}]`;
2129
+ case "write":
2130
+ return `[write: ${safeArgs}]`;
2131
+ case "edit":
2132
+ return `[edit: ${safeArgs}]`;
2133
+ default: {
2134
+ let short = safeArgs.length > 60 ? safeArgs.slice(0, 60) + "..." : safeArgs;
2135
+ return `[${tool}: ${short}]`;
2136
+ }
2137
+ }
2138
+ }
2139
+ function stateKey(state, elapsed) {
2140
+ if (!state)
2141
+ return "none";
2142
+ let elapsedBucket = Math.floor(elapsed / 1e3), tool = state.currentTool ?? "", outputLen = state.recentOutput.length, outputTail = state.recentOutput.length > 0 ? state.recentOutput[state.recentOutput.length - 1]?.slice(0, 80) ?? "" : "", toolsLen = state.recentTools.length, taskProgressKey = state.taskProgress.map((entry) => {
2143
+ let recentOutputLines = (entry.recentOutputLines ?? []).slice(-3).join("\u241F"), recentTool = entry.recentTools?.[entry.recentTools.length - 1];
2144
+ return [
2145
+ entry.index ?? "",
2146
+ entry.agent,
2147
+ entry.status ?? "",
2148
+ entry.currentTool ?? "",
2149
+ entry.toolCount ?? 0,
2150
+ entry.tokens ?? 0,
2151
+ entry.model ?? "",
2152
+ recentTool?.tool ?? "",
2153
+ recentTool?.args ?? "",
2154
+ recentOutputLines
2155
+ ].join(":");
2156
+ }).join("|");
2157
+ return `${state.status}|${tool}|${state.toolCount}|${state.tokens}|${outputLen}:${outputTail}|${toolsLen}|${state.model ?? ""}|${taskProgressKey}|${elapsedBucket}`;
2158
+ }
2159
+ function getParallelPreviewLimits(taskCount) {
2160
+ return taskCount <= 2 ? { tools: 3, output: 6 } : taskCount <= 4 ? { tools: 2, output: 4 } : { tools: 2, output: 3 };
2161
+ }
2162
+ function resolveTaskProgress(taskProgress, task, index) {
2163
+ return taskProgress.find((entry) => entry.index === index) ?? taskProgress.find((entry) => entry.index === void 0 && entry.agent === task.agent) ?? taskProgress[index];
2164
+ }
2165
+ function getTaskOutputLines(progress) {
2166
+ return progress ? progress.recentOutputLines && progress.recentOutputLines.length > 0 ? progress.recentOutputLines.filter((line) => line.trim()) : progress.recentOutput?.trim() ? progress.recentOutput.split(`
2167
+ `).filter((line) => line.trim()) : [] : [];
2168
+ }
2169
+ function getTaskHeader(index, task, progress, theme) {
2170
+ let status = progress?.status ?? "pending", modelLabel = normalizeModelLabel(progress?.model ?? task.model), modelSuffix = modelLabel ? ` ${theme.fg("dim", modelLabel)}` : "", label = `task ${index + 1} \xB7 ${task.agent}`;
2171
+ return status === "running" ? `${theme.fg("toolTitle", label)}${modelSuffix} ${theme.fg("warning", "running")}` : status === "completed" ? `${theme.fg("toolTitle", label)}${modelSuffix} ${theme.fg("success", "completed")}` : status === "failed" ? `${theme.fg("toolTitle", label)}${modelSuffix} ${theme.fg("error", "failed")}` : `${theme.fg("toolTitle", label)}${modelSuffix} ${theme.fg("dim", status)}`;
2172
+ }
2173
+ function addParallelTaskPreview(box, task, progress, index, taskCount, theme) {
2174
+ box.addChild(new Text2(getTaskHeader(index, task, progress, theme), 0, 0));
2175
+ let limits = getParallelPreviewLimits(taskCount);
2176
+ if (!progress) {
2177
+ box.addChild(new Text2(theme.fg("dim", " waiting for updates"), 0, 0));
2178
+ return;
2179
+ }
2180
+ progress.currentTool && box.addChild(new Text2(theme.fg("warning", ` > ${formatToolCall(progress.currentTool, progress.currentToolArgs ?? "")}`), 0, 0));
2181
+ let recentTools = (progress.recentTools ?? []).slice(-limits.tools);
2182
+ for (let tool of recentTools)
2183
+ box.addChild(new Text2(theme.fg("dim", ` ${formatToolCall(tool.tool, tool.args)}`), 0, 0));
2184
+ let outputLines = getTaskOutputLines(progress), visibleOutputLines = outputLines.slice(-limits.output);
2185
+ for (let line of visibleOutputLines)
2186
+ box.addChild(new Text2(theme.fg("dim", ` ${line}`), 0, 0));
2187
+ let hiddenLineCount = outputLines.length - visibleOutputLines.length;
2188
+ if (hiddenLineCount > 0 && box.addChild(new Text2(theme.fg("warning", ` ... (${hiddenLineCount} older line${hiddenLineCount === 1 ? "" : "s"})`), 0, 0)), !progress.currentTool && recentTools.length === 0 && visibleOutputLines.length === 0)
2189
+ if (progress.status === "completed") {
2190
+ let toolCount = progress.toolCount ?? 0;
2191
+ box.addChild(new Text2(theme.fg("dim", ` completed (${toolCount} tool${toolCount === 1 ? "" : "s"})`), 0, 0));
2192
+ } else progress.status === "failed" ? box.addChild(new Text2(theme.fg("error", " task failed"), 0, 0)) : box.addChild(new Text2(theme.fg("dim", " waiting for output"), 0, 0));
2193
+ }
2194
+ function rebuildBox(box, agent, contextSuffix, taskPreview, parallelTasks, isParallel, state, elapsed, theme, requestModel) {
2195
+ box.clear();
2196
+ let taskProgress = state?.taskProgress ?? [], baseToolCount = state?.toolCount ?? 0, baseTokens = state?.tokens ?? 0, parallelToolCount = taskProgress.reduce((sum, entry) => sum + (entry.toolCount ?? 0), 0), parallelTokens = taskProgress.reduce((sum, entry) => sum + (entry.tokens ?? 0), 0), toolCount = isParallel && parallelToolCount > 0 ? parallelToolCount : baseToolCount, tokens = isParallel && parallelTokens > 0 ? parallelTokens : baseTokens, tokensLabel = formatTokens(tokens), duration = formatDuration(elapsed), isThinking = toolCount === 0 && tokens === 0, icon = theme.fg("warning", "..."), modelLabel = isParallel ? requestModel : normalizeModelLabel(state?.model ?? requestModel), modelSuffix = modelLabel ? ` ${theme.fg("dim", modelLabel)}` : "", stats = isThinking ? `thinking, ${duration}` : `${toolCount} tool${toolCount === 1 ? "" : "s"}, ${tokensLabel} tok, ${duration}`;
2197
+ if (isParallel) {
2198
+ let runningLabel = `parallel ${taskProgress.filter((entry) => entry.status === "completed").length}/${parallelTasks.length} running`;
2199
+ box.addChild(new Text2(`${icon} ${theme.fg("toolTitle", theme.bold(runningLabel))}${contextSuffix}${modelSuffix} | ${stats}`, 0, 0));
2200
+ } else
2201
+ box.addChild(new Text2(`${icon} ${theme.fg("toolTitle", theme.bold(agent))}${contextSuffix}${modelSuffix} | ${stats}`, 0, 0));
2202
+ if (box.addChild(new Spacer2(1)), isParallel || (box.addChild(new Text2(theme.fg("dim", `Task: ${taskPreview}`), 0, 0)), box.addChild(new Spacer2(1))), isParallel) {
2203
+ for (let index = 0; index < parallelTasks.length; index++) {
2204
+ let task = parallelTasks[index], progress = resolveTaskProgress(taskProgress, task, index);
2205
+ addParallelTaskPreview(box, task, progress, index, parallelTasks.length, theme), index < parallelTasks.length - 1 && box.addChild(new Spacer2(1));
2206
+ }
2207
+ return;
2208
+ }
2209
+ let recentTools = state?.recentTools ?? [];
2210
+ for (let tool of recentTools)
2211
+ box.addChild(new Text2(theme.fg("dim", formatToolCall(tool.tool, tool.args)), 0, 0));
2212
+ if (state?.currentTool) {
2213
+ let active = formatToolCall(state.currentTool, state.currentToolArgs ?? "");
2214
+ box.addChild(new Text2(theme.fg("warning", `> ${active}`), 0, 0));
2215
+ }
2216
+ if (state && state.recentOutput.length > 0) {
2217
+ (recentTools.length > 0 || state.currentTool) && box.addChild(new Spacer2(1));
2218
+ for (let line of state.recentOutput)
2219
+ box.addChild(new Text2(theme.fg("dim", ` ${line}`), 0, 0));
2220
+ }
2221
+ }
2222
+ function createDelegatedProgressWidget(requestId, agent, context, task, tasks, theme, model) {
2223
+ let contextSuffix = context === "fork" ? theme.fg("warning", " [fork]") : "", taskPreview = task.length > 200 ? `${task.slice(0, 200)}...` : task, parallelTasks = tasks ?? [], isParallel = parallelTasks.length > 0, parallelModels = [...new Set(parallelTasks.map((task2) => normalizeModelLabel(task2.model)).filter((entry) => !!entry))], requestModel = isParallel ? parallelModels.length === 1 ? parallelModels[0] : void 0 : normalizeModelLabel(model), container = new Container2();
2224
+ container.addChild(new Spacer2(1));
2225
+ let box = new Box2(1, 1, (text) => theme.bg("toolPendingBg", text));
2226
+ container.addChild(box);
2227
+ let lastKey = "";
2228
+ return container.render = (width) => {
2229
+ let state = getDelegatedLiveState(requestId), elapsed = state ? Date.now() - state.startedAt : 0, key = stateKey(state, elapsed);
2230
+ return key !== lastKey && (lastKey = key, rebuildBox(box, agent, contextSuffix, taskPreview, parallelTasks, isParallel, state, elapsed, theme, requestModel)), Container2.prototype.render.call(container, width);
2231
+ }, container;
2232
+ }
2233
+
2234
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/subagent-step.js
2235
+ function extractTextFromBlocks(content) {
2236
+ for (let i = content.length - 1; i >= 0; i--) {
2237
+ let block = content[i];
2238
+ if (block.type === "text") {
2239
+ let trimmed = block.text.trim();
2240
+ if (trimmed)
2241
+ return trimmed;
2242
+ }
2243
+ }
2244
+ return "";
2245
+ }
2246
+ function extractDelegatedText(messages) {
2247
+ for (let i = messages.length - 1; i >= 0; i--) {
2248
+ let message = messages[i];
2249
+ if (message.role !== "assistant")
2250
+ continue;
2251
+ let text = extractTextFromBlocks(message.content);
2252
+ if (text)
2253
+ return text;
2254
+ }
2255
+ return "";
2256
+ }
2257
+ function delegatedMessagesChanged(messages) {
2258
+ for (let message of messages)
2259
+ if (message.role === "assistant") {
2260
+ for (let block of message.content)
2261
+ if (block.type === "toolCall" && (block.name === "write" || block.name === "edit"))
2262
+ return !0;
2263
+ }
2264
+ return !1;
2265
+ }
2266
+ function coerceMessages(messages) {
2267
+ return Array.isArray(messages) ? messages : [];
2268
+ }
2269
+ function coerceParallelResults(parallelResults) {
2270
+ return Array.isArray(parallelResults) ? parallelResults.map((result) => {
2271
+ let messages = coerceMessages(result.messages);
2272
+ return {
2273
+ agent: result.agent,
2274
+ text: extractDelegatedText(messages),
2275
+ messages,
2276
+ isError: result.isError === !0,
2277
+ errorText: result.errorText
2278
+ };
2279
+ }) : [];
2280
+ }
2281
+ function renderParallelDelegatedText(results) {
2282
+ return results.map((result, index) => {
2283
+ let body = extractDelegatedText(result.messages) || "(no assistant text)";
2284
+ return `=== Parallel Task ${index + 1} (${result.agent}) ===
2285
+ ${body}`;
2286
+ }).join(`
2287
+
2288
+ `);
2289
+ }
2290
+ function resolveDelegationName(prompt, override) {
2291
+ if (override)
2292
+ return override.agent || (typeof prompt.subagent == "string" ? prompt.subagent : DEFAULT_SUBAGENT_NAME);
2293
+ if (prompt.subagent === !0)
2294
+ return DEFAULT_SUBAGENT_NAME;
2295
+ if (typeof prompt.subagent == "string")
2296
+ return prompt.subagent;
2297
+ }
2298
+ async function prepareDelegatedTask(task, ctx, currentModel, override, inheritedModel, taskPreamble) {
2299
+ let requestedAgent = resolveDelegationName(task.prompt, override);
2300
+ if (!requestedAgent)
2301
+ throw new Error(`Prompt \`${task.prompt.name}\` is not configured for delegated execution.`);
2302
+ let effectiveCwd = task.prompt.cwd ?? ctx.cwd;
2303
+ if (effectiveCwd !== ctx.cwd && !existsSync2(effectiveCwd))
2304
+ throw new Error(`cwd directory does not exist: ${effectiveCwd}`);
2305
+ let agent = requestedAgent, preparationOptions = inheritedModel === void 0 ? void 0 : { inheritedModel }, prepared = await preparePromptExecution(task.prompt, task.args, currentModel, ctx.modelRegistry, preparationOptions);
2306
+ if (!prepared)
2307
+ throw new Error(`No available model from: ${task.prompt.models.join(", ")}`);
2308
+ if ("message" in prepared)
2309
+ throw prepared.warning && notify(ctx, prepared.warning, "warning"), new Error(prepared.message);
2310
+ prepared.warning && notify(ctx, prepared.warning, "warning");
2311
+ let taskText = prepared.content;
2312
+ return !task.prompt.inheritContext && taskPreamble && (taskText = `${taskPreamble}
2313
+
2314
+ ---
2315
+
2316
+ ${prepared.content}`), task.taskPrefix && (taskText = `${task.taskPrefix}
2317
+
2318
+ ${taskText}`), {
2319
+ promptName: task.prompt.name,
2320
+ agent,
2321
+ task: taskText,
2322
+ context: task.prompt.inheritContext ? "fork" : "fresh",
2323
+ model: `${prepared.selectedModel.model.provider}/${prepared.selectedModel.model.id}`,
2324
+ cwd: effectiveCwd
2325
+ };
2326
+ }
2327
+ function formatProgressStatus(update) {
2328
+ if (update.currentTool)
2329
+ return `running ${update.currentTool}${update.currentToolArgs ? ` ${update.currentToolArgs}` : ""}`;
2330
+ if (update.taskProgress?.some((task) => task.status === "running"))
2331
+ return "running";
2332
+ if (update.toolCount && update.toolCount > 0)
2333
+ return `completed ${update.toolCount} tool${update.toolCount === 1 ? "" : "s"}`;
2334
+ }
2335
+ function formatParallelProgressStatus(update) {
2336
+ return !update.taskProgress || update.taskProgress.length === 0 ? void 0 : `parallel ${update.taskProgress.filter((task) => task.status === "completed").length}/${update.taskProgress.length} running`;
2337
+ }
2338
+ function hasOwn(value, key) {
2339
+ return Object.prototype.hasOwnProperty.call(value, key);
2340
+ }
2341
+ function sanitizeOutputLines(lines) {
2342
+ return !lines || lines.length === 0 ? [] : lines.filter((line) => typeof line == "string" && line.trim() && line.trim() !== "(running...)");
2343
+ }
2344
+ function collectNewOutputLines(previous, next) {
2345
+ let previousLines = sanitizeOutputLines(previous), nextLines = sanitizeOutputLines(next);
2346
+ if (nextLines.length === 0)
2347
+ return [];
2348
+ if (previousLines.length === 0)
2349
+ return nextLines;
2350
+ let overlapLimit = Math.min(previousLines.length, nextLines.length);
2351
+ for (let overlap = overlapLimit; overlap > 0; overlap--) {
2352
+ let matches = !0;
2353
+ for (let index = 0; index < overlap; index++)
2354
+ if (previousLines[previousLines.length - overlap + index] !== nextLines[index]) {
2355
+ matches = !1;
2356
+ break;
2357
+ }
2358
+ if (matches)
2359
+ return nextLines.slice(overlap);
2360
+ }
2361
+ return nextLines;
2362
+ }
2363
+ function mergeTaskProgress(requestTasks, existingProgress, incomingProgress) {
2364
+ if (!requestTasks || requestTasks.length === 0)
2365
+ return incomingProgress;
2366
+ let merged = requestTasks.map((task, index) => {
2367
+ let existing = existingProgress?.find((entry) => entry.index === index) ?? existingProgress?.[index] ?? existingProgress?.find((entry) => entry.agent === task.agent);
2368
+ return {
2369
+ index,
2370
+ agent: task.agent,
2371
+ status: existing?.status ?? "pending",
2372
+ currentTool: existing?.currentTool,
2373
+ currentToolArgs: existing?.currentToolArgs,
2374
+ recentOutput: existing?.recentOutput,
2375
+ recentOutputLines: existing?.recentOutputLines,
2376
+ recentTools: existing?.recentTools,
2377
+ model: existing?.model ?? task.model,
2378
+ toolCount: existing?.toolCount,
2379
+ durationMs: existing?.durationMs,
2380
+ tokens: existing?.tokens
2381
+ };
2382
+ });
2383
+ if (!incomingProgress || incomingProgress.length === 0)
2384
+ return merged;
2385
+ let consumed = /* @__PURE__ */ new Set();
2386
+ for (let entry of incomingProgress) {
2387
+ let targetIndex = typeof entry.index == "number" && entry.index >= 0 && entry.index < merged.length ? entry.index : -1;
2388
+ if (targetIndex < 0 && (targetIndex = merged.findIndex((task, index) => task.agent === entry.agent && !consumed.has(index))), targetIndex < 0)
2389
+ continue;
2390
+ consumed.add(targetIndex);
2391
+ let current = merged[targetIndex];
2392
+ merged[targetIndex] = {
2393
+ index: targetIndex,
2394
+ agent: current.agent,
2395
+ status: entry.status ?? current.status,
2396
+ currentTool: hasOwn(entry, "currentTool") ? entry.currentTool : current.currentTool,
2397
+ currentToolArgs: hasOwn(entry, "currentToolArgs") ? entry.currentToolArgs : current.currentToolArgs,
2398
+ recentOutput: entry.recentOutput ?? current.recentOutput,
2399
+ recentOutputLines: entry.recentOutputLines ?? current.recentOutputLines,
2400
+ recentTools: entry.recentTools ?? current.recentTools,
2401
+ model: entry.model ?? current.model,
2402
+ toolCount: entry.toolCount ?? current.toolCount,
2403
+ durationMs: entry.durationMs ?? current.durationMs,
2404
+ tokens: entry.tokens ?? current.tokens
2405
+ };
2406
+ }
2407
+ return merged;
2408
+ }
2409
+ async function requestDelegatedRun(pi, ctx, request, signal) {
2410
+ return await new Promise((resolve3, reject) => {
2411
+ let requestLabel = request.tasks && request.tasks.length > 0 ? `parallel(${request.tasks.length})` : request.agent, done = !1, started = !1, startTimeoutMs = Number(process.env.PI_PROMPT_SUBAGENT_START_TIMEOUT_MS ?? "15000"), effectiveTimeout = Number.isFinite(startTimeoutMs) && startTimeoutMs > 0 ? startTimeoutMs : 15e3, startTimeout = setTimeout(() => {
2412
+ finish(() => reject(new Error(`Delegated subagent \`${requestLabel}\` did not start within ${Math.round(effectiveTimeout / 1e3)}s. Check that the pi-subagents extension is loaded.`)));
2413
+ }, effectiveTimeout), onStarted = (data) => {
2414
+ done || !data || typeof data != "object" || data.requestId !== request.requestId || (started = !0, clearTimeout(startTimeout), updateDelegatedLiveState(request.requestId, {
2415
+ status: "running...",
2416
+ toolCount: 0,
2417
+ recentOutput: [],
2418
+ taskProgress: request.tasks?.map((task, index) => ({ index, agent: task.agent, status: "pending" })) ?? []
2419
+ }), showWidget());
2420
+ }, onResponse = (data) => {
2421
+ if (done || !data || typeof data != "object")
2422
+ return;
2423
+ let payload = data;
2424
+ payload.requestId === request.requestId && (clearTimeout(startTimeout), updateDelegatedLiveState(request.requestId, {
2425
+ status: payload.isError ? "failed" : "completed",
2426
+ taskProgress: payload.parallelResults?.map((result, index) => ({
2427
+ index,
2428
+ agent: result.agent,
2429
+ status: result.isError ? "failed" : "completed"
2430
+ }))
2431
+ }), clearWidget(), finish(() => resolve3(payload)));
2432
+ }, lastProgressStatus = "", widgetSet = !1, refreshTimer = null, showWidget = () => {
2433
+ !ctx.hasUI || widgetSet || (widgetSet = !0, ctx.ui.setWidget(DELEGATED_WIDGET_KEY, (_tui, theme) => createDelegatedProgressWidget(request.requestId, request.agent, request.context, request.task, request.tasks, theme, preparedTasks[0]?.model), { placement: "aboveEditor" }), refreshTimer = setInterval(() => {
2434
+ if (done)
2435
+ return;
2436
+ let statusLine = lastProgressStatus || "running...";
2437
+ ctx.ui.setStatus("prompt-subagent", `delegating to ${requestLabel} \xB7 ${statusLine}`);
2438
+ }, 1e3));
2439
+ }, clearWidget = () => {
2440
+ refreshTimer && (clearInterval(refreshTimer), refreshTimer = null), ctx.hasUI && widgetSet && (ctx.ui.setWidget(DELEGATED_WIDGET_KEY, void 0), widgetSet = !1);
2441
+ }, onUpdate = (data) => {
2442
+ if (done || !data || typeof data != "object")
2443
+ return;
2444
+ let update = data;
2445
+ if (update.requestId !== request.requestId)
2446
+ return;
2447
+ let previousTaskProgress = getDelegatedLiveState(request.requestId)?.taskProgress, mergedTaskProgress = mergeTaskProgress(request.tasks, previousTaskProgress, update.taskProgress), isParallel = (request.tasks?.length ?? 0) > 0, progressStatus = isParallel ? formatParallelProgressStatus({
2448
+ ...update,
2449
+ taskProgress: mergedTaskProgress
2450
+ }) ?? formatProgressStatus(update) : formatProgressStatus(update);
2451
+ if (progressStatus && (lastProgressStatus = progressStatus), updateDelegatedLiveState(request.requestId, {
2452
+ status: progressStatus ?? (lastProgressStatus || "running..."),
2453
+ currentTool: update.currentTool,
2454
+ currentToolArgs: update.currentToolArgs,
2455
+ recentTools: update.recentTools,
2456
+ model: update.model,
2457
+ toolCount: update.toolCount,
2458
+ durationMs: update.durationMs,
2459
+ tokens: update.tokens,
2460
+ taskProgress: mergedTaskProgress
2461
+ }), isParallel || (update.recentOutputLines && update.recentOutputLines.length > 0 ? updateDelegatedLiveState(request.requestId, {
2462
+ recentOutput: sanitizeOutputLines(update.recentOutputLines)
2463
+ }) : appendDelegatedLiveOutput(request.requestId, update.recentOutput)), isParallel && mergedTaskProgress)
2464
+ for (let task of mergedTaskProgress) {
2465
+ let previousTask = previousTaskProgress?.find((entry) => entry.index === task.index) ?? previousTaskProgress?.find((entry) => entry.agent === task.agent), newOutputLines = collectNewOutputLines(previousTask?.recentOutputLines, task.recentOutputLines);
2466
+ if (newOutputLines.length > 0) {
2467
+ for (let line of newOutputLines)
2468
+ appendDelegatedLiveOutput(request.requestId, line);
2469
+ continue;
2470
+ }
2471
+ !task.recentOutput || task.recentOutput === previousTask?.recentOutput || appendDelegatedLiveOutput(request.requestId, task.recentOutput);
2472
+ }
2473
+ if (!ctx.hasUI)
2474
+ return;
2475
+ let statusLine = progressStatus ?? (lastProgressStatus || "running...");
2476
+ ctx.ui.setStatus("prompt-subagent", `delegating to ${requestLabel} \xB7 ${statusLine}`);
2477
+ }, onTerminalInput = ctx.hasUI ? ctx.ui.onTerminalInput((input) => {
2478
+ if (matchesKey(input, Key.escape))
2479
+ return pi.events.emit(PROMPT_TEMPLATE_SUBAGENT_CANCEL_EVENT, {
2480
+ requestId: request.requestId,
2481
+ reason: "escape"
2482
+ }), finish(() => reject(new Error("Delegated prompt cancelled."))), { consume: !0 };
2483
+ }) : void 0, unsubscribeStarted = pi.events.on(PROMPT_TEMPLATE_SUBAGENT_STARTED_EVENT, onStarted), unsubscribeResponse = pi.events.on(PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT, onResponse), unsubscribeUpdate = pi.events.on(PROMPT_TEMPLATE_SUBAGENT_UPDATE_EVENT, onUpdate), onAbort, finish = (next) => {
2484
+ done || (done = !0, clearTimeout(startTimeout), unsubscribeStarted(), unsubscribeResponse(), unsubscribeUpdate(), onTerminalInput?.(), clearWidget(), signal && onAbort && signal.removeEventListener("abort", onAbort), next());
2485
+ };
2486
+ if (onAbort = () => {
2487
+ pi.events.emit(PROMPT_TEMPLATE_SUBAGENT_CANCEL_EVENT, {
2488
+ requestId: request.requestId,
2489
+ reason: "abort"
2490
+ }), finish(() => reject(new Error("Delegated prompt cancelled.")));
2491
+ }, signal) {
2492
+ if (signal.aborted) {
2493
+ onAbort();
2494
+ return;
2495
+ }
2496
+ signal.addEventListener("abort", onAbort, { once: !0 });
2497
+ }
2498
+ if (pi.events.emit(PROMPT_TEMPLATE_SUBAGENT_REQUEST_EVENT, request), !(!started && done) && !started) {
2499
+ finish(() => reject(new Error(`No loaded pi-subagents bridge responded for \`${requestLabel}\`. Install or load pi-subagents and make sure no extension name conflicts are blocking it.`)));
2500
+ return;
2501
+ }
2502
+ });
2503
+ }
2504
+ async function executeSubagentPromptStep(options) {
2505
+ let { pi, ctx, currentModel, override, signal, inheritedModel, taskPreamble, allowPartialFailures } = options, isParallelRequest = "parallel" in options, tasks = isParallelRequest ? options.parallel : [{ prompt: options.prompt, args: options.args }];
2506
+ if (tasks.length === 0)
2507
+ return;
2508
+ let preparedTasks2 = [];
2509
+ for (let task of tasks) {
2510
+ let preparedTask = await prepareDelegatedTask(task, ctx, currentModel, override, inheritedModel, taskPreamble);
2511
+ preparedTasks2.push(preparedTask);
2512
+ }
2513
+ let requestContext = preparedTasks2[0].context, requestCwd = preparedTasks2[0].cwd;
2514
+ for (let preparedTask of preparedTasks2) {
2515
+ if (preparedTask.context !== requestContext)
2516
+ throw new Error("Parallel delegated prompts must share the same inheritContext setting.");
2517
+ if (options.worktree === !0 && preparedTask.cwd !== requestCwd)
2518
+ throw new Error("Parallel delegated prompts with worktree enabled must share the same cwd setting.");
2519
+ }
2520
+ let request = {
2521
+ requestId: randomUUID(),
2522
+ agent: preparedTasks2[0].agent,
2523
+ task: preparedTasks2[0].task,
2524
+ ...isParallelRequest ? {
2525
+ tasks: preparedTasks2.map((task) => ({
2526
+ agent: task.agent,
2527
+ task: task.task,
2528
+ tier: "standard",
2529
+ cwd: task.cwd
2530
+ }))
2531
+ } : {},
2532
+ context: requestContext,
2533
+ tier: "standard",
2534
+ cwd: requestCwd,
2535
+ ...options.worktree ? { worktree: !0 } : {}
2536
+ }, promptLabel = preparedTasks2.map((task) => task.promptName).join(", "), statusLabel = isParallelRequest ? `parallel(${preparedTasks2.length})` : preparedTasks2[0].agent;
2537
+ ctx.hasUI && (ctx.ui.setStatus("prompt-subagent", `delegating to ${statusLabel}`), ctx.ui.setWorkingMessage(isParallelRequest ? `Running delegated parallel prompts with ${statusLabel}...` : `Running delegated prompt with ${statusLabel}...`)), notify(ctx, isParallelRequest ? `Delegating parallel prompts (${promptLabel})` : `Delegating prompt \`${preparedTasks2[0].promptName}\` to subagent \`${preparedTasks2[0].agent}\``, "info");
2538
+ try {
2539
+ let response = await requestDelegatedRun(pi, ctx, request, signal);
2540
+ if (response.isError)
2541
+ throw new Error(`Delegated prompt execution failed: ${response.errorText || "unknown delegated error"}`);
2542
+ if (isParallelRequest) {
2543
+ let parallelResults = coerceParallelResults(response.parallelResults);
2544
+ if (parallelResults.length === 0)
2545
+ throw new Error("Delegated parallel execution returned no results.");
2546
+ let failures = parallelResults.filter((result) => result.isError);
2547
+ if (!allowPartialFailures && failures.length > 0) {
2548
+ let failureText = failures.map((failure) => `${failure.agent}: ${failure.errorText || "unknown delegated error"}`).join("; ");
2549
+ throw new Error(`Delegated parallel execution failed: ${failureText}`);
2550
+ }
2551
+ let text2 = response.contentText?.trim() || renderParallelDelegatedText(parallelResults), changed2 = parallelResults.some((result) => delegatedMessagesChanged(result.messages)) || text2.includes("=== Worktree Changes ===");
2552
+ return pi.sendMessage({
2553
+ customType: PROMPT_TEMPLATE_SUBAGENT_MESSAGE_TYPE,
2554
+ content: text2,
2555
+ display: !0,
2556
+ details: {
2557
+ requestId: response.requestId,
2558
+ agent: request.agent,
2559
+ task: preparedTasks2.map((task) => task.task).join(`
2560
+
2561
+ `),
2562
+ context: response.context,
2563
+ model: response.model,
2564
+ messages: [],
2565
+ parallelResults,
2566
+ text: text2,
2567
+ changed: changed2,
2568
+ isError: !1,
2569
+ errorText: response.errorText
2570
+ }
2571
+ }), {
2572
+ changed: changed2,
2573
+ text: text2,
2574
+ agent: request.agent,
2575
+ parallelResults
2576
+ };
2577
+ }
2578
+ let messages = coerceMessages(response.messages), text = extractDelegatedText(messages);
2579
+ if (!text)
2580
+ throw new Error("Delegated subagent returned no assistant text.");
2581
+ let changed = delegatedMessagesChanged(messages);
2582
+ return pi.sendMessage({
2583
+ customType: PROMPT_TEMPLATE_SUBAGENT_MESSAGE_TYPE,
2584
+ content: text,
2585
+ display: !0,
2586
+ details: {
2587
+ requestId: response.requestId,
2588
+ agent: preparedTasks2[0].agent,
2589
+ task: request.task,
2590
+ context: response.context,
2591
+ model: response.model,
2592
+ messages,
2593
+ text,
2594
+ changed,
2595
+ isError: !1,
2596
+ errorText: response.errorText
2597
+ }
2598
+ }), {
2599
+ changed,
2600
+ text,
2601
+ agent: preparedTasks2[0].agent
2602
+ };
2603
+ } catch (error) {
2604
+ let cause = error instanceof Error ? error : new Error(String(error)), responseText = cause.message;
2605
+ throw isParallelRequest ? new Error(`Parallel delegated prompts (${promptLabel}) failed: ${responseText}`, { cause }) : new Error(`Prompt \`${preparedTasks2[0].promptName}\` delegated subagent \`${preparedTasks2[0].agent}\` failed: ${responseText}`, { cause });
2606
+ } finally {
2607
+ clearDelegatedLiveState(request.requestId), ctx.hasUI && (ctx.ui.setStatus("prompt-subagent", void 0), ctx.ui.setWorkingMessage());
2608
+ }
2609
+ }
2610
+
2611
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/subagent-renderer.js
2612
+ import { Box as Box3, Container as Container3, Spacer as Spacer3, Text as Text3 } from "@ashx-j/lunr-tui";
2613
+ var DEFAULT_AGENT = "delegate", PREVIEW_LINES = 8;
2614
+ function extractTextContent(content) {
2615
+ if (typeof content == "string")
2616
+ return content;
2617
+ if (!Array.isArray(content))
2618
+ return "";
2619
+ let lines = [];
2620
+ for (let part of content) {
2621
+ if (!part || typeof part != "object" || part.type !== "text")
2622
+ continue;
2623
+ let text = part.text;
2624
+ typeof text == "string" && lines.push(text);
2625
+ }
2626
+ return lines.join(`
2627
+ `);
2628
+ }
2629
+ function formatToolCall2(name, args) {
2630
+ switch (name) {
2631
+ case "bash": {
2632
+ let cmd = String(args.command ?? "").replace(/[\n\t]/g, " ").trim();
2633
+ return `$ ${cmd.length > 80 ? cmd.slice(0, 80) + "..." : cmd}`;
2634
+ }
2635
+ case "read":
2636
+ return `[read: ${args.path ?? args.file_path ?? ""}]`;
2637
+ case "write":
2638
+ return `[write: ${args.path ?? args.file_path ?? ""}]`;
2639
+ case "edit":
2640
+ return `[edit: ${args.path ?? args.file_path ?? ""}]`;
2641
+ case "grep":
2642
+ return `[grep: /${args.pattern ?? ""}/ in ${args.path ?? "."}]`;
2643
+ case "find":
2644
+ return `[find: ${args.pattern ?? ""} in ${args.path ?? "."}]`;
2645
+ case "ls":
2646
+ return `[ls: ${args.path ?? "."}]`;
2647
+ default: {
2648
+ let a = JSON.stringify(args).slice(0, 50);
2649
+ return `[${name}: ${a}${JSON.stringify(args).length > 50 ? "..." : ""}]`;
2650
+ }
2651
+ }
2652
+ }
2653
+ function extractToolCalls(messages) {
2654
+ let calls = [];
2655
+ for (let msg of messages)
2656
+ if (!(msg.role !== "assistant" || !Array.isArray(msg.content)))
2657
+ for (let block of msg.content)
2658
+ block.type === "toolCall" && block.name && calls.push(formatToolCall2(block.name, block.arguments ?? {}));
2659
+ return calls;
2660
+ }
2661
+ function extractAssistantText(messages) {
2662
+ for (let i = messages.length - 1; i >= 0; i--) {
2663
+ let msg = messages[i];
2664
+ if (msg.role !== "assistant")
2665
+ continue;
2666
+ let text = extractTextContent(msg.content);
2667
+ if (text.trim())
2668
+ return text;
2669
+ }
2670
+ return "";
2671
+ }
2672
+ function extractUsage(messages) {
2673
+ let input = 0, output = 0, cacheRead = 0, cacheWrite = 0, cost = 0, turns = 0, model;
2674
+ for (let msg of messages)
2675
+ msg.role === "assistant" && (turns++, msg.usage && (input += msg.usage.input ?? 0, output += msg.usage.output ?? 0, cacheRead += msg.usage.cacheRead ?? 0, cacheWrite += msg.usage.cacheWrite ?? 0, cost += msg.usage.cost?.total ?? 0), msg.model && (model = msg.model));
2676
+ return { input, output, cacheRead, cacheWrite, cost, model, turns };
2677
+ }
2678
+ function formatTokensShort(n) {
2679
+ return n >= 1e3 ? `${Math.round(n / 1e3)}k` : String(n);
2680
+ }
2681
+ function renderDelegatedSubagentResult(message, options, theme) {
2682
+ let details = message.details, parallelResults = details?.parallelResults ?? [], hasParallelResults = parallelResults.length > 0, agent = hasParallelResults ? "parallel" : details?.agent ?? DEFAULT_AGENT, context = details?.context === "fork" ? theme.fg("warning", " [fork]") : "", messages = hasParallelResults ? parallelResults.flatMap((result) => result.messages ?? []) : details?.messages ?? [], text = extractTextContent(message.content), usage = extractUsage(messages), toolCalls = extractToolCalls(messages), toolCount = toolCalls.length, tokensLabel = `${formatTokensShort(usage.output)} tok`, container = new Container3();
2683
+ container.addChild(new Spacer3(1));
2684
+ let box = new Box3(1, 1, (text2) => theme.bg("toolSuccessBg", text2)), icon = theme.fg("success", "ok"), stats = hasParallelResults ? `${parallelResults.length} task${parallelResults.length === 1 ? "" : "s"}, ${toolCount} tool${toolCount === 1 ? "" : "s"}, ${tokensLabel}` : `${toolCount} tool${toolCount === 1 ? "" : "s"}, ${tokensLabel}`;
2685
+ if (box.addChild(new Text3(`${icon} ${theme.fg("toolTitle", theme.bold(agent))}${context} | ${stats}`, 0, 0)), box.addChild(new Spacer3(1)), details?.task) {
2686
+ let taskPreview = details.task.length > 120 ? `${details.task.slice(0, 120)}...` : details.task;
2687
+ box.addChild(new Text3(theme.fg("dim", `Task: ${taskPreview}`), 0, 0)), box.addChild(new Spacer3(1));
2688
+ }
2689
+ if (hasParallelResults)
2690
+ for (let index = 0; index < parallelResults.length; index++) {
2691
+ let result = parallelResults[index], taskLabel = result.agent || `task-${index + 1}`;
2692
+ box.addChild(new Text3(theme.fg("toolTitle", `=== Task ${index + 1}: ${taskLabel} ===`), 0, 0));
2693
+ let taskMessages = result.messages ?? [], taskText = extractAssistantText(taskMessages);
2694
+ if (result.isError) {
2695
+ let errorText = result.errorText || "Task failed.";
2696
+ box.addChild(new Text3(theme.fg("error", errorText), 0, 0)), box.addChild(new Spacer3(1));
2697
+ continue;
2698
+ }
2699
+ if (!taskText) {
2700
+ box.addChild(new Text3(theme.fg("dim", "(no assistant text)"), 0, 0)), box.addChild(new Spacer3(1));
2701
+ continue;
2702
+ }
2703
+ let lines = taskText.split(`
2704
+ `);
2705
+ options.expanded || lines.length <= PREVIEW_LINES ? box.addChild(new Text3(theme.fg("toolOutput", taskText), 0, 0)) : (box.addChild(new Text3(theme.fg("toolOutput", lines.slice(0, PREVIEW_LINES).join(`
2706
+ `)), 0, 0)), box.addChild(new Text3(theme.fg("warning", `
2707
+ ... (${lines.length - PREVIEW_LINES} more lines \u2014 Ctrl+O to expand)`), 0, 0))), box.addChild(new Spacer3(1));
2708
+ }
2709
+ else {
2710
+ if (toolCalls.length > 0) {
2711
+ let showCalls = options.expanded ? toolCalls : toolCalls.slice(0, 5);
2712
+ for (let call of showCalls)
2713
+ box.addChild(new Text3(theme.fg("dim", call), 0, 0));
2714
+ !options.expanded && toolCalls.length > 5 && box.addChild(new Text3(theme.fg("warning", `... (${toolCalls.length - 5} more tool calls)`), 0, 0)), box.addChild(new Spacer3(1));
2715
+ }
2716
+ if (text) {
2717
+ let lines = text.split(`
2718
+ `);
2719
+ options.expanded || lines.length <= PREVIEW_LINES ? box.addChild(new Text3(theme.fg("toolOutput", text), 0, 0)) : (box.addChild(new Text3(theme.fg("toolOutput", lines.slice(0, PREVIEW_LINES).join(`
2720
+ `)), 0, 0)), box.addChild(new Text3(theme.fg("warning", `
2721
+ ... (${lines.length - PREVIEW_LINES} more lines \u2014 Ctrl+O to expand)`), 0, 0))), box.addChild(new Spacer3(1));
2722
+ }
2723
+ }
2724
+ let statsLine = `${usage.turns} turn${usage.turns === 1 ? "" : "s"} in:${usage.input} out:${usage.output} R${formatTokensShort(usage.cacheRead)} W${formatTokensShort(usage.cacheWrite)}${usage.cost ? ` $${usage.cost.toFixed(4)}` : ""} ${usage.model ?? details?.model ?? ""}`;
2725
+ return box.addChild(new Text3(theme.fg("dim", statsLine), 0, 0)), container.addChild(box), container;
2726
+ }
2727
+
2728
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/deterministic-step.js
2729
+ import { spawn } from "node:child_process";
2730
+ import { existsSync as existsSync3 } from "node:fs";
2731
+ import { dirname as dirname2, isAbsolute as isAbsolute2, resolve as resolve2 } from "node:path";
2732
+ var PROMPT_TEMPLATE_DETERMINISTIC_MESSAGE_TYPE = "prompt-template-deterministic", PROMPT_TEMPLATE_DETERMINISTIC_COMPLETION_MESSAGE_TYPE = "prompt-template-deterministic-complete", DEFAULT_MAX_CAPTURE_STDOUT_CHARS = 16e3, DEFAULT_MAX_CAPTURE_STDERR_CHARS = 16e3, DEFAULT_TIMEOUT_KILL_AFTER_MS = 1e3;
2733
+ function createCapturedOutput(maxChars) {
2734
+ return {
2735
+ text: "",
2736
+ totalChars: 0,
2737
+ totalNewlines: 0,
2738
+ trailingNewlineRun: 0,
2739
+ sawNonNewline: !1,
2740
+ truncated: !1,
2741
+ maxChars
2742
+ };
2743
+ }
2744
+ function appendCapturedOutput(output, chunk) {
2745
+ if (!chunk)
2746
+ return;
2747
+ output.totalChars += chunk.length;
2748
+ let newlines = chunk.match(/\n/g)?.length ?? 0;
2749
+ output.totalNewlines += newlines, /[^\n]/.test(chunk) && (output.sawNonNewline = !0);
2750
+ let trailingRun = chunk.match(/\n+$/)?.[0].length ?? 0;
2751
+ if (trailingRun === 0 ? output.trailingNewlineRun = 0 : trailingRun === chunk.length ? output.trailingNewlineRun += trailingRun : output.trailingNewlineRun = trailingRun, output.text.length < output.maxChars) {
2752
+ let remaining = output.maxChars - output.text.length;
2753
+ output.text += chunk.slice(0, remaining);
2754
+ }
2755
+ output.totalChars > output.maxChars && (output.truncated = !0);
2756
+ }
2757
+ function capturedLineCount(output) {
2758
+ return output.totalChars === 0 ? 0 : output.sawNonNewline ? output.totalNewlines - output.trailingNewlineRun + 1 : 1;
2759
+ }
2760
+ function countLines(value) {
2761
+ if (!value)
2762
+ return 0;
2763
+ let normalized = value.replace(/\n+$/g, "");
2764
+ return normalized ? normalized.split(`
2765
+ `).length : 1;
2766
+ }
2767
+ function buildTextPreview(label, value, totalChars, maxChars) {
2768
+ let shownChars = Math.min(value.length, maxChars), preview = value.slice(0, shownChars), omittedChars = Math.max(0, totalChars - shownChars);
2769
+ return omittedChars === 0 ? { text: preview, truncated: !1, omittedChars: 0 } : {
2770
+ text: `${preview}
2771
+ ...[${label} truncated, ${omittedChars} more chars omitted]`,
2772
+ truncated: !0,
2773
+ omittedChars
2774
+ };
2775
+ }
2776
+ function shellQuote(value) {
2777
+ return `'${value.replace(/'/g, `'"'"'`)}'`;
2778
+ }
2779
+ function formatDeterministicExecution(execution, resolvedScriptPath) {
2780
+ switch (execution.kind) {
2781
+ case "run":
2782
+ return execution.command;
2783
+ case "command": {
2784
+ let parts = [execution.command, ...execution.args].map((part) => shellQuote(part));
2785
+ return execution.shell ? `${parts.join(" ")} (shell)` : parts.join(" ");
2786
+ }
2787
+ case "script":
2788
+ return [resolvedScriptPath ?? execution.path, ...execution.args].map((part) => shellQuote(part)).join(" ");
2789
+ }
2790
+ }
2791
+ function shouldHandoffToLlm(step, result) {
2792
+ switch (step.handoff) {
2793
+ case "always":
2794
+ return !0;
2795
+ case "never":
2796
+ return !1;
2797
+ case "on-success":
2798
+ return result.exitCode === 0;
2799
+ case "on-failure":
2800
+ return result.exitCode !== 0;
2801
+ }
2802
+ }
2803
+ function buildOutputPreambleSectionFromResult(label, value, meta, maxChars) {
2804
+ let preview = buildTextPreview(label, value, meta.totalChars, maxChars);
2805
+ return [
2806
+ `[${label}]`,
2807
+ `lineCount: ${meta.totalLines}`,
2808
+ `charCount: ${meta.totalChars}`,
2809
+ `truncated: ${preview.truncated ? "true" : "false"}`,
2810
+ preview.truncated ? `omittedChars: ${preview.omittedChars}` : void 0,
2811
+ "preview:",
2812
+ preview.text || "(empty)"
2813
+ ];
2814
+ }
2815
+ function buildDeterministicPreamble(result, options = {}) {
2816
+ let maxStdoutChars = options.maxStdoutChars ?? 8e3, maxStderrChars = options.maxStderrChars ?? 4e3, command = formatDeterministicExecution(result.execution, result.resolvedScriptPath);
2817
+ return [
2818
+ "[Deterministic step]",
2819
+ `status: ${result.exitCode === 0 ? "succeeded" : "failed"}`,
2820
+ `executionKind: ${result.execution.kind}`,
2821
+ `command: ${command.includes(`
2822
+ `) ? JSON.stringify(command) : command}`,
2823
+ result.resolvedScriptPath ? `resolvedScript: ${result.resolvedScriptPath}` : void 0,
2824
+ `cwd: ${result.cwd}`,
2825
+ `nonInteractive: ${result.nonInteractive ? "true" : "false"}`,
2826
+ `exitCode: ${result.exitCode}`,
2827
+ result.signal ? `signal: ${result.signal}` : void 0,
2828
+ `durationMs: ${result.durationMs}`,
2829
+ `timedOut: ${result.timedOut ? "true" : "false"}`,
2830
+ "",
2831
+ ...buildOutputPreambleSectionFromResult("stdout", result.stdout, {
2832
+ totalChars: result.stdoutTotalChars,
2833
+ totalLines: result.stdoutTotalLines
2834
+ }, maxStdoutChars),
2835
+ "",
2836
+ ...buildOutputPreambleSectionFromResult("stderr", result.stderr, {
2837
+ totalChars: result.stderrTotalChars,
2838
+ totalLines: result.stderrTotalLines
2839
+ }, maxStderrChars)
2840
+ ].filter((line) => line !== void 0).join(`
2841
+ `);
2842
+ }
2843
+ function resolveScriptPath(prompt, cwd, execution) {
2844
+ if (isAbsolute2(execution.path))
2845
+ return execution.path;
2846
+ let promptRelative = resolve2(dirname2(prompt.filePath), execution.path);
2847
+ return existsSync3(promptRelative) ? promptRelative : resolve2(cwd, execution.path);
2848
+ }
2849
+ function buildDeterministicEnv(step) {
2850
+ let nonInteractiveDefaults = step.nonInteractive ? {
2851
+ CI: "1",
2852
+ GIT_TERMINAL_PROMPT: "0",
2853
+ PAGER: "cat",
2854
+ GIT_PAGER: "cat"
2855
+ } : {};
2856
+ return {
2857
+ ...process.env,
2858
+ ...nonInteractiveDefaults,
2859
+ ...step.env ?? {}
2860
+ };
2861
+ }
2862
+ function spawnProcess(command, args, options) {
2863
+ return spawn(command, args, {
2864
+ cwd: options.cwd,
2865
+ shell: options.shell ?? !1,
2866
+ env: options.env,
2867
+ stdio: ["ignore", "pipe", "pipe"]
2868
+ });
2869
+ }
2870
+ async function runDeterministicStep(prompt, step, cwd) {
2871
+ let startedAt = Date.now(), execution = step.execution, resolvedCwd = step.cwd ?? cwd, env = buildDeterministicEnv(step), resolvedScriptPath = execution.kind === "script" ? resolveScriptPath(prompt, resolvedCwd, execution) : void 0, child = execution.kind === "run" ? spawnProcess("/bin/bash", ["-lc", execution.command], { cwd: resolvedCwd, env }) : execution.kind === "command" ? spawnProcess(execution.command, execution.args, { cwd: resolvedCwd, shell: execution.shell, env }) : spawnProcess(resolvedScriptPath, execution.args, { cwd: resolvedCwd, env }), stdout = createCapturedOutput(DEFAULT_MAX_CAPTURE_STDOUT_CHARS), stderr = createCapturedOutput(DEFAULT_MAX_CAPTURE_STDERR_CHARS), timedOut = !1, timeoutKillHandle;
2872
+ child.stdout.on("data", (chunk) => {
2873
+ appendCapturedOutput(stdout, chunk.toString());
2874
+ }), child.stderr.on("data", (chunk) => {
2875
+ appendCapturedOutput(stderr, chunk.toString());
2876
+ });
2877
+ let timeoutHandle = step.timeoutMs ? setTimeout(() => {
2878
+ timedOut = !0, child.kill("SIGTERM"), timeoutKillHandle = setTimeout(() => {
2879
+ child.kill("SIGKILL");
2880
+ }, DEFAULT_TIMEOUT_KILL_AFTER_MS);
2881
+ }, step.timeoutMs) : void 0;
2882
+ return await new Promise((resolveResult) => {
2883
+ let settled = !1;
2884
+ child.on("error", (error) => {
2885
+ settled || (settled = !0, timeoutHandle && clearTimeout(timeoutHandle), timeoutKillHandle && clearTimeout(timeoutKillHandle), resolveResult({
2886
+ execution,
2887
+ cwd: resolvedCwd,
2888
+ nonInteractive: step.nonInteractive,
2889
+ resolvedScriptPath,
2890
+ exitCode: 1,
2891
+ stdout: stdout.text,
2892
+ stdoutTotalChars: stdout.totalChars,
2893
+ stdoutTotalLines: capturedLineCount(stdout),
2894
+ stdoutTruncated: stdout.truncated,
2895
+ stderr: stderr.text ? `${stderr.text}
2896
+ ${error.message}` : error.message,
2897
+ stderrTotalChars: stderr.totalChars + (stderr.text ? error.message.length + 1 : error.message.length),
2898
+ stderrTotalLines: countLines(stderr.text ? `${stderr.text}
2899
+ ${error.message}` : error.message),
2900
+ stderrTruncated: stderr.truncated,
2901
+ durationMs: Date.now() - startedAt,
2902
+ timedOut
2903
+ }));
2904
+ }), child.on("close", (exitCode, signal) => {
2905
+ settled || (settled = !0, timeoutHandle && clearTimeout(timeoutHandle), timeoutKillHandle && clearTimeout(timeoutKillHandle), resolveResult({
2906
+ execution,
2907
+ cwd: resolvedCwd,
2908
+ nonInteractive: step.nonInteractive,
2909
+ resolvedScriptPath,
2910
+ exitCode: exitCode ?? (timedOut ? 124 : 1),
2911
+ signal: signal ?? void 0,
2912
+ stdout: stdout.text,
2913
+ stdoutTotalChars: stdout.totalChars,
2914
+ stdoutTotalLines: capturedLineCount(stdout),
2915
+ stdoutTruncated: stdout.truncated,
2916
+ stderr: stderr.text,
2917
+ stderrTotalChars: stderr.totalChars,
2918
+ stderrTotalLines: capturedLineCount(stderr),
2919
+ stderrTruncated: stderr.truncated,
2920
+ durationMs: Date.now() - startedAt,
2921
+ timedOut
2922
+ }));
2923
+ });
2924
+ });
2925
+ }
2926
+
2927
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/deterministic-renderer.js
2928
+ import { Box as Box4, Container as Container4, Spacer as Spacer4, Text as Text4 } from "@ashx-j/lunr-tui";
2929
+ var PREVIEW_LINES2 = 8;
2930
+ function formatDuration2(durationMs) {
2931
+ return durationMs < 1e3 ? `${durationMs}ms` : durationMs < 1e4 ? `${(durationMs / 1e3).toFixed(1)}s` : `${Math.round(durationMs / 1e3)}s`;
2932
+ }
2933
+ function buildCapturedOutputLabel(label, meta) {
2934
+ if (meta.totalChars === 0)
2935
+ return `${label} \xB7 empty`;
2936
+ let lineCount = meta.totalLines, charCount = meta.totalChars.toLocaleString(), truncated = meta.truncated ? " \xB7 capped" : "";
2937
+ return `${label} \xB7 ${lineCount} line${lineCount === 1 ? "" : "s"} \xB7 ${charCount} chars${truncated}`;
2938
+ }
2939
+ function renderOutputSection(box, label, value, meta, options, theme) {
2940
+ if (box.addChild(new Text4(theme.fg("toolTitle", buildCapturedOutputLabel(label, meta)), 0, 0)), !value) {
2941
+ box.addChild(new Text4(theme.fg("dim", "(empty)"), 0, 0));
2942
+ return;
2943
+ }
2944
+ let lines = value.split(`
2945
+ `);
2946
+ if (options.expanded || lines.length <= PREVIEW_LINES2) {
2947
+ box.addChild(new Text4(theme.fg("toolOutput", value), 0, 0)), meta.truncated && box.addChild(new Text4(theme.fg("warning", `
2948
+ ... (stored preview capped, ${Math.max(0, meta.totalChars - value.length)} more chars hidden)`), 0, 0));
2949
+ return;
2950
+ }
2951
+ box.addChild(new Text4(theme.fg("toolOutput", lines.slice(0, PREVIEW_LINES2).join(`
2952
+ `)), 0, 0)), box.addChild(new Text4(theme.fg("warning", `
2953
+ ... (${lines.length - PREVIEW_LINES2} more lines hidden \u2014 Ctrl+O to expand)`), 0, 0)), meta.truncated && box.addChild(new Text4(theme.fg("warning", `
2954
+ ... (stored preview capped, ${Math.max(0, meta.totalChars - value.length)} more chars hidden)`), 0, 0));
2955
+ }
2956
+ function renderDeterministicResult(message, options, theme) {
2957
+ let details = message.details, container = new Container4();
2958
+ if (container.addChild(new Spacer4(1)), !details)
2959
+ return container.addChild(new Text4(theme.fg("warning", "Deterministic step message is missing details."), 0, 0)), container;
2960
+ let failed = details.exitCode !== 0, box = new Box4(1, 1, (text) => theme.bg(failed ? "toolPendingBg" : "toolSuccessBg", text)), icon = theme.fg(failed ? "error" : "success", failed ? "fail" : "ok"), status = failed ? "failed" : "succeeded", title = formatDeterministicExecution(details.execution, details.resolvedScriptPath);
2961
+ return box.addChild(new Text4(`${icon} ${theme.fg("toolTitle", theme.bold("deterministic"))} | ${status} \xB7 exit ${details.exitCode} \xB7 ${formatDuration2(details.durationMs)}`, 0, 0)), box.addChild(new Spacer4(1)), box.addChild(new Text4(theme.fg("dim", `command: ${title}`), 0, 0)), details.resolvedScriptPath && box.addChild(new Text4(theme.fg("dim", `script: ${details.resolvedScriptPath}`), 0, 0)), box.addChild(new Text4(theme.fg("dim", `cwd: ${details.cwd}`), 0, 0)), details.signal && box.addChild(new Text4(theme.fg("dim", `signal: ${details.signal}`), 0, 0)), details.timedOut && box.addChild(new Text4(theme.fg("error", "timeout reached before the process exited"), 0, 0)), box.addChild(new Text4(theme.fg("dim", `nonInteractive: ${details.nonInteractive ? "true" : "false"}`), 0, 0)), box.addChild(new Spacer4(1)), renderOutputSection(box, "stdout", details.stdout, {
2962
+ totalChars: details.stdoutTotalChars,
2963
+ totalLines: details.stdoutTotalLines,
2964
+ truncated: details.stdoutTruncated
2965
+ }, options, theme), box.addChild(new Spacer4(1)), renderOutputSection(box, "stderr", details.stderr, {
2966
+ totalChars: details.stderrTotalChars,
2967
+ totalLines: details.stderrTotalLines,
2968
+ truncated: details.stderrTruncated
2969
+ }, options, theme), container.addChild(box), container;
2970
+ }
2971
+ function renderDeterministicCompletion(message, _options, theme) {
2972
+ let details = message.details, container = new Container4();
2973
+ if (container.addChild(new Spacer4(1)), !details)
2974
+ return container.addChild(new Text4(theme.fg("warning", "Deterministic completion message is missing details."), 0, 0)), container;
2975
+ let failed = details.status === "failed", box = new Box4(1, 1, (text) => theme.bg(failed ? "toolPendingBg" : "toolSuccessBg", text)), icon = theme.fg(failed ? "error" : "success", failed ? "fail" : "ok");
2976
+ return box.addChild(new Text4(`${icon} ${theme.fg("toolTitle", theme.bold("deterministic complete"))} | ${details.status} \xB7 exit ${details.exitCode}`, 0, 0)), box.addChild(new Spacer4(1)), box.addChild(new Text4(theme.fg("dim", `prompt: ${details.promptName}`), 0, 0)), box.addChild(new Text4(theme.fg("dim", "model handoff: skipped"), 0, 0)), details.timedOut && box.addChild(new Text4(theme.fg("error", "the command hit its timeout before completion"), 0, 0)), container.addChild(box), container;
2977
+ }
2978
+
2979
+ // packages/coding-agent/dist/builtin-extensions/pi-prompt-template-model/index.js
2980
+ var DEFAULT_COMPARE_REVIEWER_TASK = [
2981
+ "Review the worker variants and produce findings only.",
2982
+ "Required output:",
2983
+ "1. Summarize concrete strengths with patch/diff evidence, including worktree change summaries when present.",
2984
+ "2. Call out concrete correctness risks and regression risks.",
2985
+ "3. Extract cherry-pick ideas from non-winning variants.",
2986
+ "4. Do not rank variants or select a winner.",
2987
+ "5. Do not include manual apply commands."
2988
+ ].join(`
2989
+ `), DEFAULT_COMPARE_FINAL_APPLIER_TASK = [
2990
+ "Apply the final implementation directly in the current repo.",
2991
+ "Required output:",
2992
+ "1. Pick the best single variant or synthesize/cherry-pick across variants.",
2993
+ "2. Apply changes directly on the current branch.",
2994
+ "3. Keep edits minimal and focused on the implementation task.",
2995
+ "4. Run obvious relevant verification when practical.",
2996
+ "5. Report changed files and verification commands run."
2997
+ ].join(`
2998
+ `);
2999
+ function promptModelExtension(pi) {
3000
+ let prompts = /* @__PURE__ */ new Map(), chainPrompts = /* @__PURE__ */ new Map(), previousModel, previousThinking, pendingSkillMessage, runtimeModel, chainActive = !1, loopState = null, freshCollapse = null, boomerangCollapse = null, accumulatedSummaries = [], lastDiagnostics = "", storedCommandCtx = null, UNLIMITED_LOOP_CAP = 999, toolManager = createToolManager(pi, {
3001
+ isActive: () => !!(loopState || chainActive),
3002
+ getStoredCtx: () => storedCommandCtx,
3003
+ setStoredCtx: (ctx) => {
3004
+ storedCommandCtx = ctx;
3005
+ },
3006
+ executeCommand: executeToolCommand
3007
+ });
3008
+ function sameModel2(a, b) {
3009
+ return !a || !b ? a === b : a.provider === b.provider && a.id === b.id;
3010
+ }
3011
+ function getCurrentModel(ctx) {
3012
+ return runtimeModel ?? ctx.model;
3013
+ }
3014
+ pi.registerMessageRenderer("skill-loaded", renderSkillLoaded), pi.registerMessageRenderer(PROMPT_TEMPLATE_SUBAGENT_MESSAGE_TYPE, renderDelegatedSubagentResult), pi.registerMessageRenderer(PROMPT_TEMPLATE_DETERMINISTIC_MESSAGE_TYPE, renderDeterministicResult), pi.registerMessageRenderer(PROMPT_TEMPLATE_DETERMINISTIC_COMPLETION_MESSAGE_TYPE, renderDeterministicCompletion);
3015
+ function registerPromptCommand(name) {
3016
+ pi.registerCommand(name, {
3017
+ description: buildPromptCommandDescription(prompts.get(name)),
3018
+ handler: async (args, ctx) => {
3019
+ await runPromptCommand(name, args, ctx);
3020
+ }
3021
+ });
3022
+ }
3023
+ function refreshPrompts(cwd, ctx) {
3024
+ let result = loadPromptsWithModel(cwd), chainResult = loadPromptsWithModel(cwd, !0);
3025
+ prompts = result.prompts, chainPrompts = chainResult.prompts;
3026
+ for (let name of prompts.keys())
3027
+ registerPromptCommand(name);
3028
+ let summary = summarizePromptDiagnostics(result.diagnostics), fingerprint = diagnosticsFingerprint(result.diagnostics);
3029
+ summary && fingerprint !== lastDiagnostics && notify(ctx, summary, "warning"), lastDiagnostics = fingerprint;
3030
+ }
3031
+ function consumePendingSkillMessage() {
3032
+ if (!pendingSkillMessage)
3033
+ return;
3034
+ let message = pendingSkillMessage;
3035
+ return pendingSkillMessage = void 0, message;
3036
+ }
3037
+ function normalizeSkillName(skillName) {
3038
+ return skillName.startsWith("skill:") ? skillName.slice(6) : skillName;
3039
+ }
3040
+ function isPathResolvableSkillName(skillName) {
3041
+ return !(skillName === "." || skillName === ".." || skillName.includes("/") || skillName.includes("\\"));
3042
+ }
3043
+ function resolveRegisteredSkillPath(skillName) {
3044
+ let normalizedSkillName = normalizeSkillName(skillName);
3045
+ if (!normalizedSkillName)
3046
+ return;
3047
+ let candidates = /* @__PURE__ */ new Set([normalizedSkillName, `skill:${normalizedSkillName}`]);
3048
+ for (let command of pi.getCommands()) {
3049
+ if (command.source !== "skill")
3050
+ continue;
3051
+ let sourceInfo = "sourceInfo" in command ? command.sourceInfo : void 0;
3052
+ if (sourceInfo?.path && candidates.has(command.name))
3053
+ return sourceInfo.path;
3054
+ }
3055
+ }
3056
+ function resolveSkillMessage(skillName, cwd) {
3057
+ if (!skillName)
3058
+ return { kind: "none" };
3059
+ let normalizedSkillName = normalizeSkillName(skillName);
3060
+ if (!normalizedSkillName)
3061
+ return { kind: "error", error: `Skill "${skillName}" not found` };
3062
+ let skillPath = resolveRegisteredSkillPath(skillName) ?? (isPathResolvableSkillName(normalizedSkillName) ? resolveSkillPath(normalizedSkillName, cwd) : void 0);
3063
+ if (!skillPath)
3064
+ return { kind: "error", error: `Skill "${skillName}" not found` };
3065
+ try {
3066
+ let skillContent = readSkillContent(skillPath);
3067
+ return {
3068
+ kind: "ready",
3069
+ message: {
3070
+ customType: "skill-loaded",
3071
+ content: `<skill name="${normalizedSkillName}">
3072
+ ${skillContent}
3073
+ </skill>`,
3074
+ display: !0,
3075
+ details: { skillName: normalizedSkillName, skillContent, skillPath }
3076
+ }
3077
+ };
3078
+ } catch (error) {
3079
+ return {
3080
+ kind: "error",
3081
+ error: `Failed to read skill "${skillName}": ${error instanceof Error ? error.message : String(error)}`
3082
+ };
3083
+ }
3084
+ }
3085
+ async function waitForTurnStart(ctx) {
3086
+ for (; ctx.isIdle(); )
3087
+ await new Promise((resolve3) => setTimeout(resolve3, 10));
3088
+ }
3089
+ function shouldDelegatePrompt(prompt, override) {
3090
+ return prompt.subagent !== void 0 || override?.enabled === !0;
3091
+ }
3092
+ function isParallelChainStep(step) {
3093
+ return "parallel" in step;
3094
+ }
3095
+ async function executePromptStep(prompt, args, ctx, currentModel, override, inheritedModel, taskPreamble, loopContext, promptTurnRestore) {
3096
+ let deterministicPreamble;
3097
+ if (prompt.deterministic)
3098
+ try {
3099
+ let deterministicResult = await runDeterministicStep(prompt, prompt.deterministic, ctx.cwd), deterministicPreambleText = buildDeterministicPreamble(deterministicResult);
3100
+ if (pi.sendMessage({
3101
+ customType: PROMPT_TEMPLATE_DETERMINISTIC_MESSAGE_TYPE,
3102
+ content: deterministicPreambleText,
3103
+ display: !0,
3104
+ details: deterministicResult
3105
+ }), !shouldHandoffToLlm(prompt.deterministic, deterministicResult))
3106
+ return pi.sendMessage({
3107
+ customType: PROMPT_TEMPLATE_DETERMINISTIC_COMPLETION_MESSAGE_TYPE,
3108
+ content: `[Deterministic complete: ${prompt.name}]`,
3109
+ display: !0,
3110
+ details: {
3111
+ promptName: prompt.name,
3112
+ exitCode: deterministicResult.exitCode,
3113
+ timedOut: deterministicResult.timedOut,
3114
+ status: deterministicResult.exitCode === 0 ? "succeeded" : "failed"
3115
+ }
3116
+ }), { changed: !1 };
3117
+ deterministicPreamble = deterministicPreambleText;
3118
+ } catch (error) {
3119
+ return notify(ctx, `Deterministic step failed: ${error instanceof Error ? error.message : String(error)}`, "error"), "aborted";
3120
+ }
3121
+ let combinedTaskPreamble = [taskPreamble, deterministicPreamble].filter(Boolean).join(`
3122
+
3123
+ `);
3124
+ if (shouldDelegatePrompt(prompt, override))
3125
+ try {
3126
+ let delegated = prompt.parallel && prompt.parallel > 1 ? await executeSubagentPromptStep({
3127
+ pi,
3128
+ ctx,
3129
+ currentModel,
3130
+ override,
3131
+ signal: ctx.signal,
3132
+ inheritedModel,
3133
+ taskPreamble: combinedTaskPreamble || void 0,
3134
+ parallel: Array.from({ length: prompt.parallel }, (_, index) => ({
3135
+ prompt,
3136
+ args,
3137
+ taskPrefix: `[Parallel subagent ${index + 1}/${prompt.parallel}]`
3138
+ })),
3139
+ worktree: prompt.worktree === !0
3140
+ }) : await executeSubagentPromptStep({
3141
+ pi,
3142
+ prompt,
3143
+ args,
3144
+ ctx,
3145
+ currentModel,
3146
+ override,
3147
+ signal: ctx.signal,
3148
+ inheritedModel,
3149
+ taskPreamble: combinedTaskPreamble || void 0
3150
+ });
3151
+ return delegated ? { changed: delegated.changed, text: delegated.text } : (notify(ctx, `Prompt \`${prompt.name}\` is not configured for delegated execution.`, "error"), "aborted");
3152
+ } catch (error) {
3153
+ return notify(ctx, error instanceof Error ? error.message : String(error), "error"), { changed: !1 };
3154
+ }
3155
+ let prepared = inheritedModel === void 0 ? await preparePromptExecution(prompt, args, currentModel, ctx.modelRegistry) : await preparePromptExecution(prompt, args, currentModel, ctx.modelRegistry, { inheritedModel });
3156
+ if (!prepared)
3157
+ return notify(ctx, `No available model from: ${prompt.models.join(", ")}`, "error"), "aborted";
3158
+ if ("message" in prepared)
3159
+ return prepared.warning && notify(ctx, prepared.warning, "warning"), notify(ctx, prepared.message, "error"), "aborted";
3160
+ prepared.warning && notify(ctx, prepared.warning, "warning");
3161
+ let skillResolution = resolveSkillMessage(prompt.skill, ctx.cwd);
3162
+ if (skillResolution.kind === "error")
3163
+ return notify(ctx, skillResolution.error, "error"), "aborted";
3164
+ if (!prepared.selectedModel.alreadyActive) {
3165
+ if (!await pi.setModel(prepared.selectedModel.model))
3166
+ return notify(ctx, `Failed to switch to model ${prepared.selectedModel.model.provider}/${prepared.selectedModel.model.id}`, "error"), "aborted";
3167
+ runtimeModel = prepared.selectedModel.model;
3168
+ }
3169
+ if (prompt.thinking && pi.setThinkingLevel(prompt.thinking), pendingSkillMessage = skillResolution.kind === "ready" ? skillResolution.message : void 0, promptTurnRestore) {
3170
+ let currentModel2 = getCurrentModel(ctx);
3171
+ promptTurnRestore.originalModel && currentModel2 && !sameModel2(promptTurnRestore.originalModel, currentModel2) && (previousModel = promptTurnRestore.originalModel, previousThinking = promptTurnRestore.originalThinking), prompt.thinking && previousThinking === void 0 && prompt.thinking !== promptTurnRestore.originalThinking && (previousThinking = promptTurnRestore.originalThinking);
3172
+ }
3173
+ let startId = ctx.sessionManager.getLeafId(), effectiveContent = combinedTaskPreamble ? `${combinedTaskPreamble}
3174
+
3175
+ ${prepared.content}` : prepared.content, content = loopContext ? `[${loopContext}]
3176
+
3177
+ ${effectiveContent}` : effectiveContent;
3178
+ pi.sendUserMessage(content), await waitForTurnStart(ctx), await ctx.waitForIdle();
3179
+ let entries = getIterationEntries(ctx, startId);
3180
+ return wasIterationAborted(entries) ? "aborted" : { changed: didIterationMakeChanges(entries) };
3181
+ }
3182
+ async function restoreSessionState(ctx, originalModel, originalThinking, currentModel, currentThinking) {
3183
+ let restoredParts = [], shouldRestoreThinking = originalThinking !== void 0 && (currentThinking === void 0 || currentThinking !== originalThinking);
3184
+ originalModel && !sameModel2(originalModel, currentModel) && (await pi.setModel(originalModel) ? (runtimeModel = originalModel, restoredParts.push(originalModel.id)) : notify(ctx, `Failed to restore model ${originalModel.provider}/${originalModel.id}`, "error")), shouldRestoreThinking && (restoredParts.push(`thinking:${originalThinking}`), pi.setThinkingLevel(originalThinking)), restoredParts.length > 0 && notify(ctx, `Restored to ${restoredParts.join(", ")}`, "info");
3185
+ }
3186
+ async function restoreAfterExecution(ctx, shouldRestore, originalModel, originalThinking, currentModel, currentThinking, errorState, phase) {
3187
+ if (!shouldRestore)
3188
+ return errorState;
3189
+ try {
3190
+ await restoreSessionState(ctx, originalModel, originalThinking, currentModel, currentThinking);
3191
+ } catch (error) {
3192
+ return errorState.hasError ? (notify(ctx, `Failed to restore session state after ${phase} error: ${error instanceof Error ? error.message : String(error)}`, "error"), errorState) : { hasError: !0, error };
3193
+ }
3194
+ return errorState;
3195
+ }
3196
+ function notifyLoopCompletion(ctx, completedIterations, totalIterations, effectiveMax, converged, requireMultipleIterations) {
3197
+ if (converged) {
3198
+ let convergedLabel = totalIterations !== null ? `${completedIterations}/${totalIterations}` : `${completedIterations}`;
3199
+ notify(ctx, `Loop converged at ${convergedLabel} (no changes)`, "info");
3200
+ return;
3201
+ }
3202
+ if (completedIterations !== 0 && !(requireMultipleIterations && effectiveMax <= 1)) {
3203
+ if (totalIterations !== null) {
3204
+ notify(ctx, `Loop finished: ${completedIterations}/${totalIterations} iterations`, "info");
3205
+ return;
3206
+ }
3207
+ if (completedIterations === effectiveMax) {
3208
+ notify(ctx, `Loop finished: ${completedIterations} iterations (cap reached)`, "info");
3209
+ return;
3210
+ }
3211
+ notify(ctx, `Loop finished: ${completedIterations} iterations`, "info");
3212
+ }
3213
+ }
3214
+ function updateLoopStatus(ctx) {
3215
+ if (ctx.hasUI)
3216
+ if (loopState) {
3217
+ let suffix = loopState.rotationLabel ? ` \xB7 ${loopState.rotationLabel}` : "", label = loopState.totalIterations !== null ? `loop ${loopState.currentIteration}/${loopState.totalIterations}${suffix}` : `loop ${loopState.currentIteration}${suffix}`;
3218
+ ctx.ui.setStatus("prompt-loop", ctx.ui.theme.fg("warning", label));
3219
+ } else
3220
+ ctx.ui.setStatus("prompt-loop", void 0);
3221
+ }
3222
+ async function executeToolCommand(command, ctx) {
3223
+ let stripped = command.startsWith("/") ? command.slice(1) : command, spaceIdx = stripped.indexOf(" "), name = spaceIdx >= 0 ? stripped.slice(0, spaceIdx) : stripped, args = spaceIdx >= 0 ? stripped.slice(spaceIdx + 1) : "";
3224
+ name === "chain-prompts" ? await runChainCommand(args, ctx) : await runPromptCommand(name, args, ctx);
3225
+ }
3226
+ function cloneLineup(slots) {
3227
+ return slots?.map((slot) => ({ ...slot }));
3228
+ }
3229
+ function expandLineupCounts(slots) {
3230
+ let expanded = [];
3231
+ for (let slot of slots) {
3232
+ let { count, ...concreteSlot } = slot;
3233
+ for (let index = 0; index < (count ?? 1); index++)
3234
+ expanded.push({ ...concreteSlot });
3235
+ }
3236
+ return expanded;
3237
+ }
3238
+ function applyLineupActions(defaultSlots, actions, target) {
3239
+ let lineup = cloneLineup(defaultSlots);
3240
+ for (let action of actions) {
3241
+ if (action.target !== target)
3242
+ continue;
3243
+ let incoming = action.slots.map((slot) => ({ ...slot }));
3244
+ lineup = action.mode === "replace" ? incoming : [...lineup ?? [], ...incoming];
3245
+ }
3246
+ return lineup;
3247
+ }
3248
+ function applyFinalApplierAction(defaultSlot, actions) {
3249
+ let slot = defaultSlot ? { ...defaultSlot } : void 0;
3250
+ for (let action of actions)
3251
+ action.target === "finalApplier" && (slot = action.slots[0] ? { ...action.slots[0] } : void 0);
3252
+ return slot;
3253
+ }
3254
+ async function resolveCompareBaseModel(prompt, currentModel, ctx, modelOverride) {
3255
+ let requestedModels = modelOverride ? [modelOverride] : prompt.models;
3256
+ if (requestedModels.length > 0) {
3257
+ let selected = await selectModelCandidate(requestedModels, currentModel, ctx.modelRegistry);
3258
+ if (!selected) {
3259
+ notify(ctx, `No available model from: ${requestedModels.join(", ")}`, "error");
3260
+ return;
3261
+ }
3262
+ return selected.model;
3263
+ }
3264
+ if (currentModel)
3265
+ return currentModel;
3266
+ notify(ctx, `Prompt \`${prompt.name}\` requires an active model or a runtime --model override.`, "error");
3267
+ }
3268
+ function resolveCompareCwd(raw, ctx) {
3269
+ return expandCwdPath(raw) ?? resolvePath(ctx.cwd, raw);
3270
+ }
3271
+ function normalizeLineupCwds(slots, defaultCwd, ctx) {
3272
+ let normalized = [];
3273
+ for (let slot of slots) {
3274
+ let slotCwd = slot.cwd ? resolveCompareCwd(slot.cwd, ctx) : defaultCwd;
3275
+ if (!existsSync4(slotCwd)) {
3276
+ notify(ctx, `cwd directory does not exist: ${slotCwd}`, "error");
3277
+ return;
3278
+ }
3279
+ normalized.push({
3280
+ ...slot,
3281
+ cwd: slotCwd
3282
+ });
3283
+ }
3284
+ return normalized;
3285
+ }
3286
+ function formatCompareSlotLabel(slot, fallbackAgent) {
3287
+ return slot.model ? `${fallbackAgent}, ${slot.model}` : fallbackAgent;
3288
+ }
3289
+ function renderComparePhaseResults(label, entries) {
3290
+ return entries.map(({ index, slot, result }) => {
3291
+ let body = result.text || "(no assistant text)";
3292
+ return `=== ${label} ${index + 1} (${formatCompareSlotLabel(slot, result.agent)}) ===
3293
+ ${body}`;
3294
+ }).join(`
3295
+
3296
+ `);
3297
+ }
3298
+ function formatPhaseFailureSummary(label, entries) {
3299
+ if (entries.length !== 0)
3300
+ return [
3301
+ `[${label} failures]`,
3302
+ ...entries.map(({ index, slot, result }) => `- ${label} ${index + 1} (${formatCompareSlotLabel(slot, result.agent)}): ${result.errorText || "unknown delegated error"}`)
3303
+ ].join(`
3304
+ `);
3305
+ }
3306
+ function extractSuccessfulWorktreeChanges(aggregateText, successfulIndexes) {
3307
+ if (!aggregateText)
3308
+ return;
3309
+ let marker = "=== Worktree Changes ===", markerIndex = aggregateText.indexOf(marker);
3310
+ if (markerIndex < 0)
3311
+ return;
3312
+ let worktreeText = aggregateText.slice(markerIndex + marker.length).trim();
3313
+ if (!worktreeText)
3314
+ return;
3315
+ let successfulTaskNumbers = new Set(successfulIndexes.map((index) => index + 1)), sections = worktreeText.split(/\n(?=--- Task \d+ \()/).map((section) => section.trim()).filter(Boolean).filter((section) => {
3316
+ let match = section.match(/^--- Task (\d+) \(/);
3317
+ return match ? successfulTaskNumbers.has(parseInt(match[1], 10)) : !1;
3318
+ });
3319
+ if (sections.length !== 0)
3320
+ return `${marker}
3321
+
3322
+ ${sections.join(`
3323
+
3324
+ `)}`;
3325
+ }
3326
+ function buildReviewerPreamble(sharedTask, workerAggregation, workerFailureSummary) {
3327
+ return [
3328
+ "[Original implementation task]",
3329
+ sharedTask,
3330
+ "",
3331
+ "[Worker outputs and worktree summaries]",
3332
+ workerAggregation,
3333
+ ...workerFailureSummary ? ["", workerFailureSummary] : []
3334
+ ].join(`
3335
+ `);
3336
+ }
3337
+ function buildFinalApplierPreamble(sharedTask, workerAggregation, workerFailureSummary, reviewerAggregation, reviewerFailureSummary) {
3338
+ return [
3339
+ "[Original implementation task]",
3340
+ sharedTask,
3341
+ "",
3342
+ "[Worker outputs and worktree summaries]",
3343
+ workerAggregation,
3344
+ ...workerFailureSummary ? ["", workerFailureSummary] : [],
3345
+ "",
3346
+ "[Reviewer findings]",
3347
+ reviewerAggregation ?? "All reviewer runs failed. Synthesize directly from the worker variants.",
3348
+ ...reviewerFailureSummary ? ["", reviewerFailureSummary] : [],
3349
+ "",
3350
+ "[Final apply instructions]",
3351
+ "Pick one winner or synthesize/cherry-pick from multiple variants, apply the final patch directly in the current repo, keep edits minimal, run obvious relevant verification when practical, and report changed files plus verification run."
3352
+ ].join(`
3353
+ `);
3354
+ }
3355
+ function buildLineupSlotTask(baseTask, slot, taskArgs) {
3356
+ let effectiveBaseTask = slot.task ? substituteArgs(slot.task, taskArgs) : baseTask;
3357
+ return slot.taskSuffix ? `${effectiveBaseTask}
3358
+
3359
+ ${substituteArgs(slot.taskSuffix, taskArgs)}` : effectiveBaseTask;
3360
+ }
3361
+ function buildComparePrompt(base, options) {
3362
+ return {
3363
+ ...base,
3364
+ name: options.name,
3365
+ content: options.task,
3366
+ models: options.model ? [options.model] : [],
3367
+ chain: void 0,
3368
+ chainContext: void 0,
3369
+ parallel: void 0,
3370
+ worktree: void 0,
3371
+ subagent: options.agent,
3372
+ inheritContext: options.inheritContext ? !0 : void 0,
3373
+ cwd: options.cwd,
3374
+ workers: void 0,
3375
+ reviewers: void 0,
3376
+ finalApplier: void 0
3377
+ };
3378
+ }
3379
+ async function runComparePrompt(name, prompt, args, ctx, currentModel, runtime) {
3380
+ runtime.subagentOverride && notify(ctx, "--subagent is not supported for compare prompts (ignored)", "warning"), runtime.fork && notify(ctx, "--fork is not supported for compare prompts (ignored)", "warning");
3381
+ let lineupExtraction = extractLineupOverrides(args);
3382
+ if (lineupExtraction.errors.length > 0) {
3383
+ for (let error of lineupExtraction.errors)
3384
+ notify(ctx, error, "error");
3385
+ return;
3386
+ }
3387
+ let taskArgs = parseCommandArgs(lineupExtraction.args), compareCwd = runtime.cwd ?? prompt.cwd ?? ctx.cwd;
3388
+ if (name === "parallel-patch-compare-at-path") {
3389
+ if (taskArgs.length === 0) {
3390
+ notify(ctx, "parallel-patch-compare-at-path requires a repo path as the first argument.", "error");
3391
+ return;
3392
+ }
3393
+ if (runtime.cwd && notify(ctx, "--cwd is ignored for parallel-patch-compare-at-path (using first positional path).", "warning"), compareCwd = resolveCompareCwd(taskArgs[0], ctx), taskArgs = taskArgs.slice(1), taskArgs.length === 0) {
3394
+ notify(ctx, "parallel-patch-compare-at-path requires an implementation task after the repo path.", "error");
3395
+ return;
3396
+ }
3397
+ }
3398
+ if (!existsSync4(compareCwd)) {
3399
+ notify(ctx, `cwd directory does not exist: ${compareCwd}`, "error");
3400
+ return;
3401
+ }
3402
+ let baseModel = await resolveCompareBaseModel(prompt, currentModel, ctx, runtime.model);
3403
+ if (!baseModel)
3404
+ return;
3405
+ let rendered = renderPromptForResolvedModel(prompt, taskArgs, baseModel);
3406
+ if (rendered.warning && notify(ctx, rendered.warning, "warning"), rendered.empty || !rendered.content) {
3407
+ notify(ctx, rendered.empty ?? `Prompt \`${prompt.name}\` rendered to an empty message.`, "error");
3408
+ return;
3409
+ }
3410
+ let sharedTask = rendered.content, requestedWorkers = applyLineupActions(prompt.workers, lineupExtraction.actions, "workers") ?? [], requestedReviewers = applyLineupActions(prompt.reviewers, lineupExtraction.actions, "reviewers") ?? [], requestedFinalApplier = applyFinalApplierAction(prompt.finalApplier, lineupExtraction.actions);
3411
+ if (requestedFinalApplier && prompt.worktree !== !0) {
3412
+ notify(ctx, "Compare prompts with finalApplier require worktree: true.", "error");
3413
+ return;
3414
+ }
3415
+ let workerSlots = expandLineupCounts(requestedWorkers.length > 0 ? requestedWorkers : [{ agent: DEFAULT_SUBAGENT_NAME }]), reviewerSlots = expandLineupCounts(requestedReviewers.length > 0 ? requestedReviewers : [{ agent: "reviewer" }]), normalizedWorkers = normalizeLineupCwds(workerSlots, compareCwd, ctx);
3416
+ if (!normalizedWorkers)
3417
+ return;
3418
+ let normalizedReviewers = normalizeLineupCwds(reviewerSlots, compareCwd, ctx);
3419
+ if (!normalizedReviewers)
3420
+ return;
3421
+ let normalizedFinalApplier = requestedFinalApplier ? {
3422
+ ...requestedFinalApplier,
3423
+ cwd: compareCwd
3424
+ } : void 0;
3425
+ if (prompt.worktree === !0 && new Set(normalizedWorkers.map((slot) => slot.cwd)).size > 1) {
3426
+ notify(ctx, "worktree compare runs require all worker slots to use the same cwd.", "error");
3427
+ return;
3428
+ }
3429
+ try {
3430
+ let workerResult = await executeSubagentPromptStep({
3431
+ pi,
3432
+ ctx,
3433
+ currentModel: baseModel,
3434
+ signal: ctx.signal,
3435
+ worktree: prompt.worktree === !0,
3436
+ allowPartialFailures: !0,
3437
+ parallel: normalizedWorkers.map((slot, index) => ({
3438
+ prompt: buildComparePrompt(prompt, {
3439
+ name: `${prompt.name}-worker-${index + 1}`,
3440
+ agent: slot.agent,
3441
+ task: buildLineupSlotTask(sharedTask, slot, taskArgs),
3442
+ model: slot.model,
3443
+ cwd: slot.cwd,
3444
+ inheritContext: !0
3445
+ }),
3446
+ args: []
3447
+ }))
3448
+ }), workerPairs = (workerResult?.parallelResults ?? []).map((result, index) => ({
3449
+ index,
3450
+ slot: normalizedWorkers[index],
3451
+ result
3452
+ }));
3453
+ if (workerPairs.length === 0)
3454
+ return;
3455
+ let successfulWorkers = workerPairs.filter((entry) => !entry.result.isError), failedWorkers = workerPairs.filter((entry) => entry.result.isError);
3456
+ if (successfulWorkers.length === 0) {
3457
+ notify(ctx, "Compare worker phase failed: all worker slots failed.", "error");
3458
+ return;
3459
+ }
3460
+ let successfulWorkerText = [
3461
+ renderComparePhaseResults("Worker", successfulWorkers),
3462
+ extractSuccessfulWorktreeChanges(workerResult.text, successfulWorkers.map((entry) => entry.index))
3463
+ ].filter((value) => !!value).join(`
3464
+
3465
+ `), workerFailureSummary = formatPhaseFailureSummary("Worker", failedWorkers), reviewerPreamble = buildReviewerPreamble(sharedTask, successfulWorkerText, workerFailureSummary), reviewerPairs = ((await executeSubagentPromptStep({
3466
+ pi,
3467
+ ctx,
3468
+ currentModel: baseModel,
3469
+ signal: ctx.signal,
3470
+ taskPreamble: reviewerPreamble,
3471
+ allowPartialFailures: !0,
3472
+ parallel: normalizedReviewers.map((slot, index) => ({
3473
+ prompt: buildComparePrompt(prompt, {
3474
+ name: `${prompt.name}-reviewer-${index + 1}`,
3475
+ agent: slot.agent,
3476
+ task: buildLineupSlotTask(DEFAULT_COMPARE_REVIEWER_TASK, slot, taskArgs),
3477
+ model: slot.model,
3478
+ cwd: slot.cwd,
3479
+ inheritContext: !1
3480
+ }),
3481
+ args: []
3482
+ }))
3483
+ }))?.parallelResults ?? []).map((result, index) => ({
3484
+ index,
3485
+ slot: normalizedReviewers[index],
3486
+ result
3487
+ }));
3488
+ if (reviewerPairs.length === 0)
3489
+ return;
3490
+ let successfulReviewers = reviewerPairs.filter((entry) => !entry.result.isError), failedReviewers = reviewerPairs.filter((entry) => entry.result.isError), successfulReviewerText = successfulReviewers.length > 0 ? renderComparePhaseResults("Reviewer", successfulReviewers) : void 0, reviewerFailureSummary = formatPhaseFailureSummary("Reviewer", failedReviewers);
3491
+ if (!normalizedFinalApplier) {
3492
+ if (!successfulReviewerText) {
3493
+ notify(ctx, "Compare reviewer phase failed: all reviewer slots failed.", "error");
3494
+ return;
3495
+ }
3496
+ let finalText = reviewerFailureSummary ? `${successfulReviewerText}
3497
+
3498
+ ${reviewerFailureSummary}` : successfulReviewerText;
3499
+ pi.sendUserMessage(`[Compare review complete: ${name}]
3500
+
3501
+ ${finalText}`), await waitForTurnStart(ctx), await ctx.waitForIdle();
3502
+ return;
3503
+ }
3504
+ let finalResult = await executeSubagentPromptStep({
3505
+ pi,
3506
+ ctx,
3507
+ currentModel: baseModel,
3508
+ signal: ctx.signal,
3509
+ taskPreamble: buildFinalApplierPreamble(sharedTask, successfulWorkerText, workerFailureSummary, successfulReviewerText, reviewerFailureSummary),
3510
+ prompt: buildComparePrompt(prompt, {
3511
+ name: `${prompt.name}-final-applier`,
3512
+ agent: normalizedFinalApplier.agent,
3513
+ task: buildLineupSlotTask(DEFAULT_COMPARE_FINAL_APPLIER_TASK, normalizedFinalApplier, taskArgs),
3514
+ model: normalizedFinalApplier.model,
3515
+ cwd: compareCwd,
3516
+ inheritContext: !1
3517
+ }),
3518
+ args: []
3519
+ });
3520
+ if (!finalResult?.text)
3521
+ return;
3522
+ pi.sendUserMessage(`[Compare apply complete: ${name}]
3523
+
3524
+ ${finalResult.text}`), await waitForTurnStart(ctx), await ctx.waitForIdle();
3525
+ } catch (error) {
3526
+ notify(ctx, error instanceof Error ? error.message : String(error), "error");
3527
+ }
3528
+ }
3529
+ async function collapseBoomerangPrompt(ctx, name, targetId, previousSummaries = []) {
3530
+ if (!targetId) {
3531
+ notify(ctx, `Cannot boomerang prompt \`${name}\`: no session entry to return to.`, "warning");
3532
+ return;
3533
+ }
3534
+ boomerangCollapse = { targetId, task: name, previousSummaries };
3535
+ try {
3536
+ globalThis.__boomerangCollapseInProgress = !0, (await ctx.navigateTree(targetId, { summarize: !0 })).cancelled && notify(ctx, `Boomerang cancelled for prompt \`${name}\``, "warning");
3537
+ } finally {
3538
+ globalThis.__boomerangCollapseInProgress = !1, boomerangCollapse = null;
3539
+ }
3540
+ }
3541
+ async function runPromptLoop(name, cleanedArgs, totalIterations, freshFlag, converge, ctx, subagentOverride, cwdOverride, promptOverrides) {
3542
+ refreshPrompts(ctx.cwd, ctx);
3543
+ let initialPrompt = prompts.get(name);
3544
+ if (!initialPrompt) {
3545
+ notify(ctx, `Prompt "${name}" no longer exists`, "error");
3546
+ return;
3547
+ }
3548
+ let savedModel = getCurrentModel(ctx), savedThinking = pi.getThinkingLevel(), currentModel = savedModel, currentThinking = savedThinking, shouldRestore = initialPrompt.restore, useFresh = freshFlag || initialPrompt.fresh === !0, shouldBoomerang = initialPrompt.boomerang === !0, effectiveMax = totalIterations ?? UNLIMITED_LOOP_CAP, isUnlimited = totalIterations === null, useConverge = converge && initialPrompt.converge !== !1, anchorId = useFresh || shouldBoomerang ? ctx.sessionManager.getLeafId() : null;
3549
+ loopState = { currentIteration: 1, totalIterations }, accumulatedSummaries = [], updateLoopStatus(ctx);
3550
+ let completedIterations = 0, converged = !1, loopErrorState = { hasError: !1, error: void 0 }, lastDelegatedText, loopAborted = !1, boomerangPreviousSummaries = [];
3551
+ try {
3552
+ for (let i = 0; i < effectiveMax; i++) {
3553
+ loopState.currentIteration = i + 1;
3554
+ let iterationLabel = totalIterations !== null ? `${i + 1}/${totalIterations}` : `${i + 1}`;
3555
+ refreshPrompts(ctx.cwd, ctx);
3556
+ let prompt = prompts.get(name);
3557
+ if (!prompt) {
3558
+ notify(ctx, `Prompt "${name}" no longer exists`, "error"), loopAborted = !0;
3559
+ break;
3560
+ }
3561
+ let effectivePrompt = { ...prompt, ...cwdOverride ? { cwd: cwdOverride } : {}, ...promptOverrides }, iterationPrompt = effectivePrompt;
3562
+ if (loopState.rotationLabel = void 0, effectivePrompt.rotate && effectivePrompt.models.length > 1) {
3563
+ let rotationIndex = i % effectivePrompt.models.length, rotatedThinking = effectivePrompt.thinkingLevels ? effectivePrompt.thinkingLevels[rotationIndex] : effectivePrompt.thinking;
3564
+ iterationPrompt = {
3565
+ ...effectivePrompt,
3566
+ models: [effectivePrompt.models[rotationIndex]],
3567
+ thinking: rotatedThinking
3568
+ };
3569
+ let shortModel = effectivePrompt.models[rotationIndex].split("/").pop() || effectivePrompt.models[rotationIndex], thinkingLabel = rotatedThinking ? ` ${rotatedThinking}` : "";
3570
+ loopState.rotationLabel = `${shortModel}${thinkingLabel}`;
3571
+ }
3572
+ updateLoopStatus(ctx);
3573
+ let rotationSuffix = loopState.rotationLabel ? ` [${loopState.rotationLabel}]` : "";
3574
+ notify(ctx, `Loop ${iterationLabel}: ${name}${rotationSuffix}`, "info");
3575
+ let loopContext = loopState.rotationLabel ? `Loop ${iterationLabel} \xB7 ${loopState.rotationLabel}` : `Loop ${iterationLabel}`, iterationStartId = ctx.sessionManager.getLeafId(), stepResult = await executePromptStep(iterationPrompt, parseCommandArgs(cleanedArgs), ctx, currentModel, subagentOverride, void 0, void 0, loopContext);
3576
+ if (stepResult === "aborted") {
3577
+ loopAborted = !0;
3578
+ break;
3579
+ }
3580
+ let delegatedStep = shouldDelegatePrompt(iterationPrompt, subagentOverride);
3581
+ delegatedStep && (lastDelegatedText = stepResult.text), currentModel = getCurrentModel(ctx), currentThinking = pi.getThinkingLevel(), completedIterations++;
3582
+ let iterationChanged = delegatedStep ? stepResult.changed : didIterationMakeChanges(getIterationEntries(ctx, iterationStartId));
3583
+ if (useConverge && (isUnlimited || effectiveMax > 1) && !iterationChanged) {
3584
+ converged = !0;
3585
+ break;
3586
+ }
3587
+ if (useFresh && anchorId && i < effectiveMax - 1) {
3588
+ freshCollapse = { targetId: anchorId, task: name, iteration: i + 1, totalIterations };
3589
+ let result = await ctx.navigateTree(anchorId, { summarize: !0 });
3590
+ if (freshCollapse = null, result.cancelled) {
3591
+ loopAborted = !0, notify(ctx, "Loop cancelled", "warning");
3592
+ break;
3593
+ }
3594
+ }
3595
+ }
3596
+ } catch (error) {
3597
+ loopErrorState = { hasError: !0, error };
3598
+ } finally {
3599
+ loopErrorState = await restoreAfterExecution(ctx, shouldRestore, savedModel, savedThinking, getCurrentModel(ctx), pi.getThinkingLevel(), loopErrorState, "loop"), boomerangPreviousSummaries = accumulatedSummaries, loopState = null, pendingSkillMessage = void 0, freshCollapse = null, boomerangCollapse = null, accumulatedSummaries = [], updateLoopStatus(ctx), loopErrorState.hasError || notifyLoopCompletion(ctx, completedIterations, totalIterations, effectiveMax, converged, !1);
3600
+ }
3601
+ if (lastDelegatedText && !loopErrorState.hasError && !loopAborted) {
3602
+ let label = converged ? `Delegated loop converged after ${completedIterations} iteration(s): ${name}` : `Delegated loop completed ${completedIterations} iteration(s): ${name}`;
3603
+ pi.sendUserMessage(`[${label}]
3604
+
3605
+ ${lastDelegatedText}`), await waitForTurnStart(ctx), await ctx.waitForIdle();
3606
+ }
3607
+ if (!loopErrorState.hasError && !loopAborted && shouldBoomerang && await collapseBoomerangPrompt(ctx, name, anchorId, boomerangPreviousSummaries), loopErrorState.hasError)
3608
+ throw loopErrorState.error;
3609
+ }
3610
+ async function runSharedChainExecution(steps, sharedArgs, totalIterations, fresh, converge, shouldRestore, ctx, subagentOverride, cwdOverride, chainContextEnabled = !1, chainTemplateWorktree = !1, cliWorktree = !1) {
3611
+ let worktreeEnabled = chainTemplateWorktree || cliWorktree;
3612
+ worktreeEnabled && !steps.some(isParallelChainStep) && (notify(ctx, "--worktree ignored: chain has no parallel() steps", "warning"), worktreeEnabled = !1);
3613
+ let flattenChainSteps = () => {
3614
+ let flattened = [];
3615
+ for (let step of steps)
3616
+ isParallelChainStep(step) ? flattened.push(...step.parallel) : flattened.push(step);
3617
+ return flattened;
3618
+ }, validateChainSteps = () => {
3619
+ let missingTemplates = flattenChainSteps().filter((step) => !chainPrompts.has(step.name));
3620
+ if (missingTemplates.length > 0)
3621
+ return notify(ctx, `Templates not found: ${missingTemplates.map((step) => step.name).join(", ")}`, "error"), !1;
3622
+ for (let step of steps) {
3623
+ if (isParallelChainStep(step)) {
3624
+ for (let parallelStep of step.parallel) {
3625
+ if (parallelStep.loopCount !== void 0)
3626
+ return notify(ctx, `Step "${parallelStep.name}" in parallel() does not support per-task --loop.`, "error"), !1;
3627
+ if (parallelStep.withContext === !0)
3628
+ return notify(ctx, `Step "${parallelStep.name}" in parallel() does not support per-task --with-context.`, "error"), !1;
3629
+ let stepPrompt2 = chainPrompts.get(parallelStep.name);
3630
+ if (stepPrompt2) {
3631
+ if (stepPrompt2.chain)
3632
+ return notify(ctx, `Step "${parallelStep.name}" is a chain template. Chain nesting is not supported.`, "error"), !1;
3633
+ if (!shouldDelegatePrompt(stepPrompt2, subagentOverride))
3634
+ return notify(ctx, `Step "${parallelStep.name}" in parallel() must use delegated execution (subagent).`, "error"), !1;
3635
+ }
3636
+ }
3637
+ continue;
3638
+ }
3639
+ let stepPrompt = chainPrompts.get(step.name);
3640
+ if (stepPrompt && stepPrompt.chain)
3641
+ return notify(ctx, `Step "${step.name}" is a chain template. Chain nesting is not supported.`, "error"), !1;
3642
+ }
3643
+ return !0;
3644
+ };
3645
+ if (!validateChainSteps())
3646
+ return;
3647
+ let originalModel = getCurrentModel(ctx), chainInheritedModel = originalModel, originalThinking = pi.getThinkingLevel(), currentModel = originalModel, currentThinking = originalThinking;
3648
+ chainActive = !0, pendingSkillMessage = void 0;
3649
+ let effectiveMax = totalIterations ?? UNLIMITED_LOOP_CAP, isUnlimited = totalIterations === null, useConverge = converge, anchorId = fresh ? ctx.sessionManager.getLeafId() : null, chainStepNames = steps.map((step) => isParallelChainStep(step) ? `parallel(${step.parallel.map((item) => item.name).join(", ")})` : step.name).join(" -> "), completedIterations = 0, converged = !1, chainErrorState = { hasError: !1, error: void 0 }, lastDelegatedText, chainAborted = !1;
3650
+ effectiveMax > 1 && (loopState = { currentIteration: 1, totalIterations }, accumulatedSummaries = [], updateLoopStatus(ctx));
3651
+ try {
3652
+ for (let iteration = 0; iteration < effectiveMax; iteration++) {
3653
+ if (effectiveMax > 1 && (loopState.currentIteration = iteration + 1, updateLoopStatus(ctx), refreshPrompts(ctx.cwd, ctx), !validateChainSteps())) {
3654
+ chainAborted = !0;
3655
+ break;
3656
+ }
3657
+ let templates = steps.map((step) => isParallelChainStep(step) ? {
3658
+ kind: "parallel",
3659
+ tasks: step.parallel.map((item) => ({
3660
+ name: item.name,
3661
+ args: item.args,
3662
+ prompt: {
3663
+ ...chainPrompts.get(item.name),
3664
+ ...cwdOverride ? { cwd: cwdOverride } : {}
3665
+ }
3666
+ }))
3667
+ } : {
3668
+ kind: "single",
3669
+ singleStep: {
3670
+ prompt: {
3671
+ ...chainPrompts.get(step.name),
3672
+ ...cwdOverride ? { cwd: cwdOverride } : {}
3673
+ },
3674
+ stepArgs: step.args,
3675
+ stepLoop: step.loopCount !== void 0 ? step.loopCount : 1,
3676
+ stepWithContext: step.withContext === !0
3677
+ }
3678
+ }), chainStepSummaries = [], aborted = !1, iterationChanged = !1, loopPrefix = "";
3679
+ effectiveMax > 1 && (loopPrefix = `Loop ${totalIterations !== null ? `${iteration + 1}/${totalIterations}` : `${iteration + 1}`}, `);
3680
+ for (let [index, stepTemplate] of templates.entries()) {
3681
+ let stepNumber = index + 1;
3682
+ if (stepTemplate.kind === "parallel") {
3683
+ let stepNames = stepTemplate.tasks.map((task) => task.name).join(", "), stepLabel = `parallel(${stepNames})`;
3684
+ notify(ctx, `${loopPrefix}Step ${stepNumber}/${templates.length}: parallel(${stepNames})`, "info"), ctx.hasUI && ctx.ui.setStatus("prompt-chain", ctx.ui.theme.fg("warning", `step ${stepNumber}/${templates.length}: parallel(${stepNames})`));
3685
+ let stepStartId2 = ctx.sessionManager.getLeafId(), taskPreamble, isForkedParallelContext = stepTemplate.tasks.some((task) => task.prompt.inheritContext === !0);
3686
+ chainContextEnabled && !isForkedParallelContext && chainStepSummaries.length > 0 && (taskPreamble = `[Previous chain steps]
3687
+
3688
+ ${chainStepSummaries.join(`
3689
+
3690
+ `)}`);
3691
+ let delegated;
3692
+ try {
3693
+ delegated = await executeSubagentPromptStep({
3694
+ pi,
3695
+ ctx,
3696
+ currentModel,
3697
+ override: subagentOverride,
3698
+ signal: ctx.signal,
3699
+ inheritedModel: chainInheritedModel,
3700
+ parallel: stepTemplate.tasks.map((task) => ({
3701
+ prompt: task.prompt,
3702
+ args: task.args.length > 0 ? task.args : sharedArgs
3703
+ })),
3704
+ taskPreamble,
3705
+ worktree: worktreeEnabled
3706
+ });
3707
+ } catch (error) {
3708
+ notify(ctx, error instanceof Error ? error.message : String(error), "error"), aborted = !0;
3709
+ break;
3710
+ }
3711
+ if (!delegated) {
3712
+ notify(ctx, "Parallel chain step was not delegated.", "error"), aborted = !0;
3713
+ break;
3714
+ }
3715
+ lastDelegatedText = delegated.text, currentModel = getCurrentModel(ctx), currentThinking = pi.getThinkingLevel();
3716
+ let stepEntries2 = getIterationEntries(ctx, stepStartId2);
3717
+ delegated.changed && (iterationChanged = !0), chainStepSummaries.push(generateChainStepSummary(stepEntries2, stepLabel, stepNumber));
3718
+ continue;
3719
+ }
3720
+ let singleStep = stepTemplate.singleStep, stepLoopTotal = singleStep.stepLoop, stepLoopMax = stepLoopTotal ?? UNLIMITED_LOOP_CAP, isStepLooping = stepLoopMax > 1, effectiveArgs = singleStep.stepArgs.length > 0 ? singleStep.stepArgs : sharedArgs, shouldInjectSummary = shouldDelegatePrompt(singleStep.prompt, subagentOverride) && singleStep.prompt.inheritContext !== !0 && (chainContextEnabled || singleStep.stepWithContext === !0), outerLoopState = loopState ? { ...loopState } : null, stepStartId = ctx.sessionManager.getLeafId();
3721
+ isStepLooping && (loopState = { currentIteration: 1, totalIterations: stepLoopTotal }, updateLoopStatus(ctx));
3722
+ try {
3723
+ for (let stepIteration = 0; stepIteration < stepLoopMax; stepIteration++) {
3724
+ isStepLooping && (loopState = { currentIteration: stepIteration + 1, totalIterations: stepLoopTotal }, updateLoopStatus(ctx));
3725
+ let iterSuffix = isStepLooping ? stepLoopTotal !== null ? ` (iter ${stepIteration + 1}/${stepLoopTotal})` : ` (iter ${stepIteration + 1})` : "";
3726
+ notify(ctx, `${loopPrefix}Step ${stepNumber}/${templates.length}: ${singleStep.prompt.name}${iterSuffix} ${buildPromptCommandDescription(singleStep.prompt)}`, "info"), ctx.hasUI && ctx.ui.setStatus("prompt-chain", ctx.ui.theme.fg("warning", `step ${stepNumber}/${templates.length}: ${singleStep.prompt.name}`));
3727
+ let taskPreamble = shouldInjectSummary && chainStepSummaries.length > 0 ? `[Previous chain steps]
3728
+
3729
+ ${chainStepSummaries.join(`
3730
+
3731
+ `)}` : void 0, stepLoopContext = isStepLooping ? `Step ${stepNumber}/${templates.length}: ${singleStep.prompt.name}${iterSuffix}` : void 0, stepIterationStartId = ctx.sessionManager.getLeafId(), stepResult = await executePromptStep(singleStep.prompt, effectiveArgs, ctx, currentModel, subagentOverride, chainInheritedModel, taskPreamble, stepLoopContext);
3732
+ if (stepResult === "aborted") {
3733
+ chainAborted = !0, aborted = !0;
3734
+ break;
3735
+ }
3736
+ shouldDelegatePrompt(singleStep.prompt, subagentOverride) && (lastDelegatedText = stepResult.text), currentModel = getCurrentModel(ctx), currentThinking = pi.getThinkingLevel();
3737
+ let stepIterationEntries = getIterationEntries(ctx, stepIterationStartId), stepIterationChanged = didIterationMakeChanges(stepIterationEntries);
3738
+ if (isStepLooping && singleStep.prompt.converge !== !1 && !stepIterationChanged)
3739
+ break;
3740
+ }
3741
+ } finally {
3742
+ isStepLooping && (loopState = outerLoopState ? { ...outerLoopState } : null, updateLoopStatus(ctx));
3743
+ }
3744
+ if (aborted)
3745
+ break;
3746
+ let stepEntries = getIterationEntries(ctx, stepStartId);
3747
+ didIterationMakeChanges(stepEntries) && (iterationChanged = !0), chainStepSummaries.push(generateChainStepSummary(stepEntries, singleStep.prompt.name, stepNumber));
3748
+ }
3749
+ if (aborted) {
3750
+ chainAborted = !0;
3751
+ break;
3752
+ }
3753
+ if (completedIterations++, useConverge && (isUnlimited || effectiveMax > 1) && !iterationChanged) {
3754
+ converged = !0;
3755
+ break;
3756
+ }
3757
+ if (anchorId && iteration < effectiveMax - 1) {
3758
+ freshCollapse = { targetId: anchorId, task: chainStepNames, iteration: iteration + 1, totalIterations };
3759
+ let result = await ctx.navigateTree(anchorId, { summarize: !0 });
3760
+ if (freshCollapse = null, result.cancelled) {
3761
+ chainAborted = !0, notify(ctx, "Loop cancelled", "warning");
3762
+ break;
3763
+ }
3764
+ }
3765
+ }
3766
+ } catch (error) {
3767
+ chainErrorState = { hasError: !0, error };
3768
+ } finally {
3769
+ chainErrorState = await restoreAfterExecution(ctx, shouldRestore, originalModel, originalThinking, getCurrentModel(ctx), pi.getThinkingLevel(), chainErrorState, "chain"), pendingSkillMessage = void 0, chainActive = !1, loopState = null, freshCollapse = null, boomerangCollapse = null, accumulatedSummaries = [], updateLoopStatus(ctx), ctx.hasUI && ctx.ui.setStatus("prompt-chain", void 0), chainErrorState.hasError || notifyLoopCompletion(ctx, completedIterations, totalIterations, effectiveMax, converged, !0);
3770
+ }
3771
+ if (lastDelegatedText && !chainErrorState.hasError && !chainAborted && (pi.sendUserMessage(`[Delegated chain complete: ${chainStepNames}]
3772
+
3773
+ ${lastDelegatedText}`), await waitForTurnStart(ctx), await ctx.waitForIdle()), chainErrorState.hasError)
3774
+ throw chainErrorState.error;
3775
+ }
3776
+ async function runPromptCommand(name, args, ctx) {
3777
+ storedCommandCtx = ctx, refreshPrompts(ctx.cwd, ctx);
3778
+ let prompt = prompts.get(name);
3779
+ if (!prompt) {
3780
+ notify(ctx, `Prompt "${name}" no longer exists`, "error");
3781
+ return;
3782
+ }
3783
+ let subagent = extractSubagentOverride(args), runtimeCwd = subagent.cwd ? expandCwdPath(subagent.cwd) : void 0;
3784
+ if (subagent.cwd && !runtimeCwd) {
3785
+ notify(ctx, "Invalid --cwd path: must be absolute", "error");
3786
+ return;
3787
+ }
3788
+ let argsWithoutSubagent = subagent.args;
3789
+ if (prompt.deterministic) {
3790
+ if (subagent.override || subagent.fork) {
3791
+ notify(ctx, "Deterministic prompts do not support runtime --subagent/--fork in v1", "error");
3792
+ return;
3793
+ }
3794
+ if (extractLoopCount(argsWithoutSubagent)) {
3795
+ notify(ctx, "Deterministic prompts do not support runtime --loop in v1", "error");
3796
+ return;
3797
+ }
3798
+ }
3799
+ if (prompt.workers !== void 0 || prompt.reviewers !== void 0 || prompt.finalApplier !== void 0) {
3800
+ await runComparePrompt(name, prompt, argsWithoutSubagent, ctx, getCurrentModel(ctx), {
3801
+ cwd: runtimeCwd,
3802
+ model: subagent.model,
3803
+ subagentOverride: subagent.override,
3804
+ fork: subagent.fork
3805
+ });
3806
+ return;
3807
+ }
3808
+ if (prompt.chain) {
3809
+ subagent.model && notify(ctx, "--model is not supported on chain prompts (ignored)", "warning"), subagent.fork && notify(ctx, "--fork is not supported on chain prompts (ignored)", "warning");
3810
+ let worktreeExtraction = extractWorktreeFlag(argsWithoutSubagent), extracted = extractChainContextFlag(worktreeExtraction.args), chainContextEnabled = extracted.chainContext || prompt.chainContext === "summary", cliWorktree = worktreeExtraction.worktree, loop2 = extractLoopCount(extracted.args), totalIterations = prompt.loop !== void 0 ? prompt.loop : 1, fresh = !1, converge = !0, cleanedArgs = extracted.args;
3811
+ if (loop2)
3812
+ totalIterations = loop2.loopCount, fresh = loop2.fresh, converge = loop2.converge, cleanedArgs = loop2.args;
3813
+ else if (prompt.loop !== void 0) {
3814
+ let flags = extractLoopFlags(extracted.args);
3815
+ fresh = flags.fresh, converge = flags.converge, cleanedArgs = flags.args;
3816
+ }
3817
+ let { steps, invalidSegments } = parseChainDeclaration(prompt.chain);
3818
+ if (invalidSegments.length > 0) {
3819
+ notify(ctx, `Invalid chain step: ${invalidSegments[0]}`, "error");
3820
+ return;
3821
+ }
3822
+ if (steps.length === 0) {
3823
+ notify(ctx, "No templates specified", "error");
3824
+ return;
3825
+ }
3826
+ let cwdOverride = runtimeCwd ?? prompt.cwd;
3827
+ await runSharedChainExecution(steps, parseCommandArgs(cleanedArgs), totalIterations, fresh || prompt.fresh === !0, converge && prompt.converge !== !1, prompt.restore, ctx, subagent.override, cwdOverride, chainContextEnabled, prompt.worktree === !0, cliWorktree);
3828
+ return;
3829
+ }
3830
+ let promptOverrides = {
3831
+ ...subagent.model ? { models: [subagent.model] } : {},
3832
+ ...subagent.fork ? { inheritContext: !0 } : {}
3833
+ }, loop = extractLoopCount(argsWithoutSubagent);
3834
+ if (loop) {
3835
+ await runPromptLoop(name, loop.args, loop.loopCount, loop.fresh, loop.converge, ctx, subagent.override, runtimeCwd, promptOverrides);
3836
+ return;
3837
+ }
3838
+ if (prompt.loop !== void 0) {
3839
+ let flags = extractLoopFlags(argsWithoutSubagent);
3840
+ await runPromptLoop(name, flags.args, prompt.loop, flags.fresh, flags.converge, ctx, subagent.override, runtimeCwd, promptOverrides);
3841
+ return;
3842
+ }
3843
+ let effectivePrompt = {
3844
+ ...prompt,
3845
+ ...runtimeCwd ? {
3846
+ cwd: runtimeCwd,
3847
+ ...prompt.deterministic ? { deterministic: { ...prompt.deterministic, cwd: runtimeCwd } } : {}
3848
+ } : {},
3849
+ ...promptOverrides
3850
+ }, savedModel = getCurrentModel(ctx), savedThinking = pi.getThinkingLevel(), isDelegatedPrompt = shouldDelegatePrompt(effectivePrompt, subagent.override), promptTurnRestore = !isDelegatedPrompt && prompt.restore ? { originalModel: savedModel, originalThinking: savedThinking } : void 0, boomerangTargetId = effectivePrompt.boomerang ? ctx.sessionManager.getLeafId() : null, stepResult = await executePromptStep(effectivePrompt, parseCommandArgs(argsWithoutSubagent), ctx, savedModel, subagent.override, void 0, void 0, void 0, promptTurnRestore);
3851
+ stepResult !== "aborted" && (isDelegatedPrompt && stepResult.text && (pi.sendUserMessage(`[Delegated result: ${name}]
3852
+
3853
+ ${stepResult.text}`), await waitForTurnStart(ctx), await ctx.waitForIdle()), effectivePrompt.boomerang && await collapseBoomerangPrompt(ctx, name, boomerangTargetId));
3854
+ }
3855
+ function resetSessionScopedState(ctx) {
3856
+ storedCommandCtx = null, pendingSkillMessage = void 0, previousModel = void 0, previousThinking = void 0, runtimeModel = ctx.model, boomerangCollapse = null, toolManager.clearQueue(), refreshPrompts(ctx.cwd, ctx);
3857
+ }
3858
+ pi.on("session_start", async (_event, ctx) => {
3859
+ resetSessionScopedState(ctx);
3860
+ }), pi.on("model_select", async (event) => {
3861
+ runtimeModel = event.model;
3862
+ }), pi.on("before_agent_start", async (event) => {
3863
+ let systemPrompt = event.systemPrompt;
3864
+ if (toolManager.isEnabled() && !loopState && !chainActive) {
3865
+ let toolGuidance = toolManager.getGuidance(), guidance = toolGuidance ? `The run-prompt tool is available for running prompt template commands. ${toolGuidance}` : "The run-prompt tool is available for running prompt template commands.";
3866
+ systemPrompt += `
3867
+
3868
+ ${guidance}`;
3869
+ }
3870
+ if (loopState) {
3871
+ let iterText = loopState.totalIterations !== null ? `iteration ${loopState.currentIteration} of ${loopState.totalIterations}` : `iteration ${loopState.currentIteration}`;
3872
+ systemPrompt += `
3873
+
3874
+ You are on ${iterText} of the same prompt. Previous iterations and their results are visible in the conversation above. Build on that work \u2014 focus on what remains to improve.`;
3875
+ }
3876
+ let skillMessage = consumePendingSkillMessage(), hasSystemPromptOverride = systemPrompt !== event.systemPrompt;
3877
+ if (!(!hasSystemPromptOverride && !skillMessage))
3878
+ return {
3879
+ ...hasSystemPromptOverride ? { systemPrompt } : {},
3880
+ ...skillMessage ? { message: skillMessage } : {}
3881
+ };
3882
+ }), pi.on("agent_end", async (_event, ctx) => {
3883
+ if (chainActive || loopState)
3884
+ return;
3885
+ let restoreModel = previousModel, restoreThinking = previousThinking;
3886
+ if (!restoreModel && restoreThinking === void 0 && !toolManager.hasQueuedCommand())
3887
+ return;
3888
+ runtimeModel = ctx.model, previousModel = void 0, previousThinking = void 0;
3889
+ let restoreFn = async () => {
3890
+ (restoreModel || restoreThinking !== void 0) && await restoreSessionState(ctx, restoreModel, restoreThinking, getCurrentModel(ctx), pi.getThinkingLevel());
3891
+ };
3892
+ await toolManager.processQueue(ctx, restoreFn) || await restoreFn();
3893
+ }), pi.on("session_before_tree", async (event) => {
3894
+ if (boomerangCollapse && event.preparation.targetId === boomerangCollapse.targetId) {
3895
+ let summary2 = generateBoomerangSummary(event.preparation.entriesToSummarize, boomerangCollapse.task);
3896
+ return {
3897
+ summary: {
3898
+ summary: [...boomerangCollapse.previousSummaries, summary2].join(`
3899
+
3900
+ ---
3901
+
3902
+ `)
3903
+ }
3904
+ };
3905
+ }
3906
+ if (!freshCollapse || event.preparation.targetId !== freshCollapse.targetId)
3907
+ return;
3908
+ let summary = generateIterationSummary(event.preparation.entriesToSummarize, freshCollapse.task, freshCollapse.iteration, freshCollapse.totalIterations);
3909
+ return accumulatedSummaries.push(summary), {
3910
+ summary: {
3911
+ summary: accumulatedSummaries.join(`
3912
+
3913
+ ---
3914
+
3915
+ `)
3916
+ }
3917
+ };
3918
+ });
3919
+ async function runChainCommand(args, ctx) {
3920
+ storedCommandCtx = ctx, refreshPrompts(ctx.cwd, ctx);
3921
+ let subagent = extractSubagentOverride(args), runtimeCwd = subagent.cwd ? expandCwdPath(subagent.cwd) : void 0;
3922
+ if (subagent.cwd && !runtimeCwd) {
3923
+ notify(ctx, "Invalid --cwd path: must be absolute", "error");
3924
+ return;
3925
+ }
3926
+ let worktreeExtraction = extractWorktreeFlag(subagent.args), extracted = extractChainContextFlag(worktreeExtraction.args), loop = extractLoopCount(extracted.args), cleanedArgs = loop ? loop.args : extracted.args, { steps, sharedArgs, invalidSegments } = parseChainSteps(cleanedArgs);
3927
+ if (invalidSegments.length > 0) {
3928
+ notify(ctx, `Invalid chain step: ${invalidSegments[0]}`, "error");
3929
+ return;
3930
+ }
3931
+ if (steps.length === 0) {
3932
+ notify(ctx, "No templates specified", "error");
3933
+ return;
3934
+ }
3935
+ await runSharedChainExecution(steps, sharedArgs, loop ? loop.loopCount : 1, loop?.fresh === !0, loop?.converge ?? !0, !0, ctx, subagent.override, runtimeCwd, extracted.chainContext, !1, worktreeExtraction.worktree);
3936
+ }
3937
+ toolManager.isEnabled() && toolManager.ensureRegistered(), pi.registerCommand("chain-prompts", {
3938
+ description: "Chain prompt templates sequentially [template -> template -> ...]",
3939
+ handler: async (args, ctx) => {
3940
+ await runChainCommand(args, ctx);
3941
+ }
3942
+ }), toolManager.registerCommand();
3943
+ }
3944
+ export {
3945
+ promptModelExtension as default
3946
+ };