@ashx-j/lunr 0.2.22 → 0.2.24

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 (277) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/README.md +15 -13
  3. package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
  4. package/dist/builtin-extensions/ashxj-tui.js +2 -2
  5. package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
  6. package/dist/builtin-extensions/lunr-browser.d.ts +7 -1
  7. package/dist/builtin-extensions/lunr-browser.d.ts.map +1 -1
  8. package/dist/builtin-extensions/lunr-browser.js +116 -3
  9. package/dist/builtin-extensions/lunr-browser.js.map +1 -1
  10. package/dist/builtin-extensions/lunr-plan-tools.d.ts +7 -7
  11. package/dist/builtin-extensions/lunr-plan-tools.d.ts.map +1 -1
  12. package/dist/builtin-extensions/lunr-plan-tools.js +12 -12
  13. package/dist/builtin-extensions/lunr-plan-tools.js.map +1 -1
  14. package/dist/builtin-extensions/pi-intercom/index.d.ts.map +1 -1
  15. package/dist/builtin-extensions/pi-intercom/index.js +2 -0
  16. package/dist/builtin-extensions/pi-intercom/index.js.map +1 -1
  17. package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.d.ts.map +1 -1
  18. package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.js +1 -0
  19. package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.js.map +1 -1
  20. package/dist/builtin-extensions/pi-mcp-adapter/index.d.ts.map +1 -1
  21. package/dist/builtin-extensions/pi-mcp-adapter/index.js +1 -1
  22. package/dist/builtin-extensions/pi-mcp-adapter/index.js.map +1 -1
  23. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  24. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +1 -1
  25. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  26. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
  27. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +1 -1
  28. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
  29. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +4 -4
  30. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
  31. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +6 -4
  32. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
  33. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.d.ts +2 -0
  34. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.d.ts.map +1 -1
  35. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.js +6 -3
  36. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.js.map +1 -1
  37. package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.d.ts.map +1 -1
  38. package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js +7 -2
  39. package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js.map +1 -1
  40. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts +2 -0
  41. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts.map +1 -1
  42. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js +4 -0
  43. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js.map +1 -1
  44. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts.map +1 -1
  45. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js +1 -1
  46. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js.map +1 -1
  47. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts +2 -0
  48. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts.map +1 -1
  49. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js +9 -0
  50. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js.map +1 -1
  51. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.d.ts.map +1 -1
  52. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js +41 -3
  53. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js.map +1 -1
  54. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts +1 -0
  55. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
  56. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +5 -1
  57. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
  58. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
  59. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +3 -2
  60. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
  61. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  62. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +23 -0
  63. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
  64. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts +1 -1
  65. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts.map +1 -1
  66. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js +1 -1
  67. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js.map +1 -1
  68. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts +2 -0
  69. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts.map +1 -1
  70. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js +17 -15
  71. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js.map +1 -1
  72. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
  73. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js +3 -1
  74. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
  75. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts.map +1 -1
  76. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js +2 -2
  77. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js.map +1 -1
  78. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +1 -0
  79. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
  80. package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
  81. package/dist/builtin-extensions/pi-subagents/src/tui/communication.d.ts +1 -1
  82. package/dist/builtin-extensions/pi-subagents/src/tui/communication.d.ts.map +1 -1
  83. package/dist/builtin-extensions/pi-subagents/src/tui/communication.js +3 -2
  84. package/dist/builtin-extensions/pi-subagents/src/tui/communication.js.map +1 -1
  85. package/dist/core/agent-session.d.ts +20 -1
  86. package/dist/core/agent-session.d.ts.map +1 -1
  87. package/dist/core/agent-session.js +235 -107
  88. package/dist/core/agent-session.js.map +1 -1
  89. package/dist/core/browser/schema.d.ts +1 -1
  90. package/dist/core/browser/schema.d.ts.map +1 -1
  91. package/dist/core/browser/schema.js +1 -1
  92. package/dist/core/browser/schema.js.map +1 -1
  93. package/dist/core/catalog-cache-scope.d.ts.map +1 -1
  94. package/dist/core/catalog-cache-scope.js +3 -1
  95. package/dist/core/catalog-cache-scope.js.map +1 -1
  96. package/dist/core/model-runtime.d.ts.map +1 -1
  97. package/dist/core/model-runtime.js +3 -2
  98. package/dist/core/model-runtime.js.map +1 -1
  99. package/dist/core/permissions.d.ts +16 -23
  100. package/dist/core/permissions.d.ts.map +1 -1
  101. package/dist/core/permissions.js +66 -141
  102. package/dist/core/permissions.js.map +1 -1
  103. package/dist/core/plan-mode.d.ts +10 -12
  104. package/dist/core/plan-mode.d.ts.map +1 -1
  105. package/dist/core/plan-mode.js +16 -18
  106. package/dist/core/plan-mode.js.map +1 -1
  107. package/dist/core/runtime-bridges.d.ts.map +1 -1
  108. package/dist/core/runtime-bridges.js +2 -0
  109. package/dist/core/runtime-bridges.js.map +1 -1
  110. package/dist/core/sdk.d.ts.map +1 -1
  111. package/dist/core/sdk.js +13 -6
  112. package/dist/core/sdk.js.map +1 -1
  113. package/dist/core/session-manager.d.ts.map +1 -1
  114. package/dist/core/session-manager.js +9 -2
  115. package/dist/core/session-manager.js.map +1 -1
  116. package/dist/core/settings-manager.d.ts +13 -1
  117. package/dist/core/settings-manager.d.ts.map +1 -1
  118. package/dist/core/settings-manager.js +49 -1
  119. package/dist/core/settings-manager.js.map +1 -1
  120. package/dist/core/slash-commands.d.ts.map +1 -1
  121. package/dist/core/slash-commands.js +4 -4
  122. package/dist/core/slash-commands.js.map +1 -1
  123. package/dist/core/subagent-permission-inherit.d.ts +6 -10
  124. package/dist/core/subagent-permission-inherit.d.ts.map +1 -1
  125. package/dist/core/subagent-permission-inherit.js +14 -14
  126. package/dist/core/subagent-permission-inherit.js.map +1 -1
  127. package/dist/core/subagent-wait-interruption.d.ts +11 -0
  128. package/dist/core/subagent-wait-interruption.d.ts.map +1 -0
  129. package/dist/core/subagent-wait-interruption.js +19 -0
  130. package/dist/core/subagent-wait-interruption.js.map +1 -0
  131. package/dist/core/system-prompt.d.ts +2 -0
  132. package/dist/core/system-prompt.d.ts.map +1 -1
  133. package/dist/core/system-prompt.js +11 -4
  134. package/dist/core/system-prompt.js.map +1 -1
  135. package/dist/core/tools/render-utils.d.ts +3 -3
  136. package/dist/core/tools/render-utils.d.ts.map +1 -1
  137. package/dist/core/tools/render-utils.js +3 -3
  138. package/dist/core/tools/render-utils.js.map +1 -1
  139. package/dist/gateway/adapters/discord.d.ts.map +1 -1
  140. package/dist/gateway/adapters/discord.js +1 -1
  141. package/dist/gateway/adapters/discord.js.map +1 -1
  142. package/dist/gateway/approval.d.ts +2 -6
  143. package/dist/gateway/approval.d.ts.map +1 -1
  144. package/dist/gateway/approval.js +3 -7
  145. package/dist/gateway/approval.js.map +1 -1
  146. package/dist/gateway/mobile-commands.d.ts.map +1 -1
  147. package/dist/gateway/mobile-commands.js +12 -11
  148. package/dist/gateway/mobile-commands.js.map +1 -1
  149. package/dist/gateway/router.d.ts.map +1 -1
  150. package/dist/gateway/router.js +1 -1
  151. package/dist/gateway/router.js.map +1 -1
  152. package/dist/main.d.ts.map +1 -1
  153. package/dist/main.js +1 -2
  154. package/dist/main.js.map +1 -1
  155. package/dist/modes/interactive/components/assistant-message.d.ts +10 -2
  156. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  157. package/dist/modes/interactive/components/assistant-message.js +29 -5
  158. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  159. package/dist/modes/interactive/components/copyable-text.d.ts +2 -6
  160. package/dist/modes/interactive/components/copyable-text.d.ts.map +1 -1
  161. package/dist/modes/interactive/components/copyable-text.js +26 -35
  162. package/dist/modes/interactive/components/copyable-text.js.map +1 -1
  163. package/dist/modes/interactive/components/settings-selector.d.ts +7 -1
  164. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  165. package/dist/modes/interactive/components/settings-selector.js +36 -3
  166. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  167. package/dist/modes/interactive/components/thinking-tail.d.ts +9 -2
  168. package/dist/modes/interactive/components/thinking-tail.d.ts.map +1 -1
  169. package/dist/modes/interactive/components/thinking-tail.js +43 -1
  170. package/dist/modes/interactive/components/thinking-tail.js.map +1 -1
  171. package/dist/modes/interactive/components/tool-execution.d.ts +5 -3
  172. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  173. package/dist/modes/interactive/components/tool-execution.js +44 -45
  174. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  175. package/dist/modes/interactive/interactive-mode.d.ts +7 -2
  176. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  177. package/dist/modes/interactive/interactive-mode.js +194 -129
  178. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  179. package/dist/modes/interactive/theme/theme.d.ts +1 -0
  180. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  181. package/dist/modes/interactive/theme/theme.js +23 -0
  182. package/dist/modes/interactive/theme/theme.js.map +1 -1
  183. package/dist/node-runtime/{agent-session-services-NQ6GKOIK.js → agent-session-services-IEF7LQWD.js} +12 -13
  184. package/dist/node-runtime/{builtin-extensions-GVC6IFDU.js → builtin-extensions-EBAWTH4M.js} +5 -5
  185. package/dist/node-runtime/{chunk-XLTL257W.js → chunk-2KIPT4HJ.js} +5 -1
  186. package/dist/node-runtime/{chunk-IWOWXRWU.js → chunk-5Q3EHOHI.js} +21 -21
  187. package/dist/node-runtime/{chunk-6B2POMK7.js → chunk-6VYZ5UFP.js} +1 -1
  188. package/dist/node-runtime/{chunk-TQGPP4SC.js → chunk-CDVHZOOK.js} +1 -1
  189. package/dist/node-runtime/{chunk-TDL7UWJ7.js → chunk-DE2JB6J5.js} +189 -70
  190. package/dist/node-runtime/{chunk-YJMMG7C6.js → chunk-DSIKTUPW.js} +1 -1
  191. package/dist/node-runtime/{chunk-IQIEU7SB.js → chunk-F4FLTQKV.js} +2 -2
  192. package/dist/node-runtime/{chunk-GMHJCCEN.js → chunk-FU6OODRZ.js} +4 -1
  193. package/dist/node-runtime/{chunk-5BNJ4JUH.js → chunk-GJ2RDBRL.js} +1 -1
  194. package/dist/node-runtime/{chunk-GNN7H3B7.js → chunk-GS42T6MX.js} +1 -1
  195. package/dist/node-runtime/{chunk-OFKSVRV7.js → chunk-GYIXXQAO.js} +1 -1
  196. package/dist/node-runtime/{chunk-BX2RB477.js → chunk-HFVZUPFJ.js} +1 -1
  197. package/dist/node-runtime/{chunk-PC2Z5TKZ.js → chunk-HMBGROQK.js} +3 -3
  198. package/dist/node-runtime/{chunk-AZJHNQKQ.js → chunk-I54LGHWM.js} +1 -1
  199. package/dist/node-runtime/{chunk-IVXYUAJE.js → chunk-IF24A3FH.js} +1 -1
  200. package/dist/node-runtime/{chunk-VJPTNWAP.js → chunk-IGV54Q5V.js} +3 -3
  201. package/dist/node-runtime/{chunk-QDGKKKUM.js → chunk-K5AGHH57.js} +18 -13
  202. package/dist/node-runtime/{chunk-GS66LV4M.js → chunk-KJ6DWS3K.js} +4 -4
  203. package/dist/node-runtime/{chunk-EQ63ANHL.js → chunk-L3LX4SNR.js} +310 -192
  204. package/dist/node-runtime/{chunk-VSELYKWU.js → chunk-LWYIVUGV.js} +2 -1
  205. package/dist/node-runtime/{chunk-JHYKXIMM.js → chunk-MPKSOJBT.js} +1 -1
  206. package/dist/node-runtime/{chunk-UAFLNHSH.js → chunk-OF7PWMG4.js} +8 -8
  207. package/dist/node-runtime/{chunk-CSUZVNYE.js → chunk-OVX6X377.js} +10 -6
  208. package/dist/node-runtime/{chunk-ORH324EP.js → chunk-PCEW76PM.js} +3 -3
  209. package/dist/node-runtime/{chunk-6427XAWG.js → chunk-QH6YL7VK.js} +3 -3
  210. package/dist/node-runtime/{chunk-LMBNLFXQ.js → chunk-QM43FEAE.js} +15 -15
  211. package/dist/node-runtime/{chunk-7QWNYZDI.js → chunk-RDDAZOMU.js} +16 -0
  212. package/dist/node-runtime/{chunk-WADV2VDS.js → chunk-RORY2HMJ.js} +46 -5
  213. package/dist/node-runtime/{chunk-H3XF4UVQ.js → chunk-RWTKOC3B.js} +1 -1
  214. package/dist/node-runtime/{chunk-V2A7CEXK.js → chunk-WHLRAGUQ.js} +13 -12
  215. package/dist/node-runtime/{chunk-GJSAD4AB.js → chunk-Y73WPE6S.js} +17 -17
  216. package/dist/node-runtime/{chunk-VSSXXL36.js → chunk-YDO2F2IA.js} +2 -2
  217. package/dist/node-runtime/{chunk-BFNXONG3.js → chunk-YVI6L6LU.js} +5 -5
  218. package/dist/node-runtime/{chunk-5D7LC2ZQ.js → chunk-ZXSGTGJ6.js} +54 -85
  219. package/dist/node-runtime/cli-runtime.js +1 -1
  220. package/dist/node-runtime/{command-3JHHXOPX.js → command-7BG7VVTS.js} +3 -3
  221. package/dist/node-runtime/{commands-KAMO2T6P.js → commands-NZLSOHPE.js} +2 -2
  222. package/dist/node-runtime/{commands-2JVNFGMQ.js → commands-QFDKNQTL.js} +9 -9
  223. package/dist/node-runtime/{direct-tool-executor-YAVOLDFY.js → direct-tool-executor-77GW4F5P.js} +3 -3
  224. package/dist/node-runtime/{export-html-KBFVV63J.js → export-html-VM4J2MNR.js} +2 -2
  225. package/dist/node-runtime/{extension-input-K24TVKVW.js → extension-input-E7BJZ35H.js} +4 -4
  226. package/dist/node-runtime/{extension-selector-SPNF7EDR.js → extension-selector-WU42XDTU.js} +4 -4
  227. package/dist/node-runtime/{gateway-VFO6SFKK.js → gateway-TWR3N65G.js} +14 -14
  228. package/dist/node-runtime/index.js +26 -27
  229. package/dist/node-runtime/{init-X2LIUB2H.js → init-HS6NQXSK.js} +2 -2
  230. package/dist/node-runtime/{install-cli-C3CF7O7N.js → install-cli-VAP6KBFN.js} +1 -1
  231. package/dist/node-runtime/{interactive-mode-LOM6AIF6.js → interactive-mode-6J5VZ2TT.js} +19 -20
  232. package/dist/node-runtime/{interactive-view-IDSCPPK7.js → interactive-view-NGFAMHPW.js} +7 -7
  233. package/dist/node-runtime/lunr-browser-J5ZZYVGM.js +174 -0
  234. package/dist/node-runtime/{lunr-cron-BKHGNBKT.js → lunr-cron-CXOL37AL.js} +7 -7
  235. package/dist/node-runtime/main.js +22 -23
  236. package/dist/node-runtime/{mobile-commands-HMP25WBC.js → mobile-commands-VTBM5DSZ.js} +6 -6
  237. package/dist/node-runtime/{model-runtime-PLQKAG4B.js → model-runtime-OO5HFLWE.js} +1 -1
  238. package/dist/node-runtime/{package-manager-cli-VCK4E2RC.js → package-manager-cli-ZLW5DZXF.js} +9 -10
  239. package/dist/node-runtime/{pi-intercom-HBPK5HSJ.js → pi-intercom-QM53RLTS.js} +2 -0
  240. package/dist/node-runtime/{pi-mcp-adapter-E6WULBKF.js → pi-mcp-adapter-5UKBZP44.js} +7 -6
  241. package/dist/node-runtime/{pi-subagents-FEUDLJOE.js → pi-subagents-XPCLLKIM.js} +65 -21
  242. package/dist/node-runtime/{proxy-modes-OSQCWRBI.js → proxy-modes-LGEUYD7R.js} +3 -3
  243. package/dist/node-runtime/rpc-entry.js +22 -23
  244. package/dist/node-runtime/{rpc-mode-P5ODXPEG.js → rpc-mode-O3XV4SID.js} +2 -2
  245. package/dist/node-runtime/{runtime-bridges-3XUQ46XW.js → runtime-bridges-QYXUX2TG.js} +8 -1
  246. package/dist/node-runtime/{session-handoff-HC7R5E24.js → session-handoff-GWARVEWT.js} +2 -2
  247. package/dist/node-runtime/{session-manager-CFN4UFM2.js → session-manager-JB5J6XBN.js} +1 -1
  248. package/dist/node-runtime/{session-selector-LHRMJOKT.js → session-selector-GIM4DHQ2.js} +4 -4
  249. package/dist/node-runtime/{settings-manager-UUZ6NUXI.js → settings-manager-WCQDUVQB.js} +7 -4
  250. package/dist/node-runtime/{setup-NRXVZBLJ.js → setup-YRBKH2LD.js} +2 -2
  251. package/dist/node-runtime/{subagent-executor-MLUMBWCP.js → subagent-executor-OTNISDQU.js} +47 -10
  252. package/dist/node-runtime/{theme-U7IGOA7O.js → theme-UOO5RVFN.js} +1 -1
  253. package/dist/node-runtime/{update-cli-4TP25CNW.js → update-cli-VBR2777K.js} +1 -2
  254. package/dist/startup/interactive-view.d.ts.map +1 -1
  255. package/dist/startup/interactive-view.js +5 -1
  256. package/dist/startup/interactive-view.js.map +1 -1
  257. package/docs/browser.md +1 -1
  258. package/docs/features.md +17 -14
  259. package/docs/index.md +1 -1
  260. package/docs/keybindings.md +1 -1
  261. package/docs/providers.md +6 -2
  262. package/docs/quickstart.md +2 -2
  263. package/docs/settings.md +2 -1
  264. package/docs/usage.md +6 -6
  265. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  266. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  267. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  268. package/examples/extensions/gondolin/package-lock.json +2 -2
  269. package/examples/extensions/gondolin/package.json +1 -1
  270. package/examples/extensions/plan-mode/README.md +1 -1
  271. package/examples/extensions/sandbox/package-lock.json +2 -2
  272. package/examples/extensions/sandbox/package.json +1 -1
  273. package/examples/extensions/with-deps/package-lock.json +2 -2
  274. package/examples/extensions/with-deps/package.json +1 -1
  275. package/package.json +4 -4
  276. package/dist/node-runtime/chunk-LISUTZS3.js +0 -19
  277. package/dist/node-runtime/lunr-browser-YNW7FTYX.js +0 -87
@@ -2,10 +2,7 @@
2
2
  * lunR: parent-delegated children inherit an explicit permission level, not a
3
3
  * named agent role. The parent process resolves the requested level against
4
4
  * its own mode, then snapshots that resolved child permission into the child
5
- * environment. Full maps to child runtime Auto; read-only maps to Plan.
6
- *
7
- * Ordinary `lunr -p`, cron, and gateway headless sessions are not children and
8
- * stay fail-closed.
5
+ * environment. Full maps to child runtime Auto; read-only maps to Read-only.
9
6
  */
10
7
  import { type PermissionMode } from "./permissions.ts";
11
8
  export declare const SUBAGENT_CHILD_ENV = "PI_SUBAGENT_CHILD";
@@ -13,7 +10,7 @@ export declare const SUBAGENT_CHILD_PERMISSION_ENV = "PI_SUBAGENT_CHILD_PERMISSI
13
10
  /** @deprecated Replaced by SUBAGENT_CHILD_PERMISSION_ENV. Kept so leftover env is ignored. */
14
11
  export declare const SUBAGENT_PARENT_PERMISSION_MODE_ENV = "PI_SUBAGENT_PARENT_PERMISSION_MODE";
15
12
  export type ChildPermission = "full" | "read-only";
16
- export declare const PLAN_MODE_WRITE_SPAWN_ERROR = "Cannot launch a full-access child in plan mode. Relaunch with permissions: \"read-only\".";
13
+ export declare const READ_ONLY_WRITE_SPAWN_ERROR = "Cannot launch a full-access child in read-only mode. Relaunch with permissions: \"read-only\".";
17
14
  export declare function isSubagentChildProcess(env?: NodeJS.ProcessEnv): boolean;
18
15
  export declare function parseParentPermissionMode(value: string | undefined): PermissionMode | undefined;
19
16
  export declare function parseChildPermission(value: string | undefined): ChildPermission | undefined;
@@ -35,11 +32,10 @@ export interface RejectedChildPermissions {
35
32
  * Resolve the child's permission level before spawn.
36
33
  *
37
34
  * Parent mode Requested Result
38
- * Manual/YOLO/Auto omitted Full
39
- * Manual/YOLO/Auto full Full
40
- * Manual/YOLO/Auto read-only Read-only
41
- * Plan read-only Read-only
42
- * Plan full / omitted Reject (omission resolves to full)
35
+ * YOLO/Auto omitted/full Full
36
+ * YOLO/Auto read-only Read-only
37
+ * Read-only read-only Read-only
38
+ * Read-only full / omitted Reject (omission resolves to full)
43
39
  */
44
40
  export declare function resolveChildPermissions(parentMode: string | undefined, requested?: string): ResolvedChildPermissions | RejectedChildPermissions;
45
41
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"subagent-permission-inherit.d.ts","sourceRoot":"","sources":["../../src/core/subagent-permission-inherit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAqB,KAAK,cAAc,EAAoB,MAAM,kBAAkB,CAAC;AAE5F,eAAO,MAAM,kBAAkB,sBAAsB,CAAC;AACtD,eAAO,MAAM,6BAA6B,iCAAiC,CAAC;AAC5E,8FAA8F;AAC9F,eAAO,MAAM,mCAAmC,uCAAuC,CAAC;AAExF,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,WAAW,CAAC;AAEnD,eAAO,MAAM,2BAA2B,8FACkD,CAAC;AAE3F,wBAAgB,sBAAsB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAEpF;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,GAAG,SAAS,CAG/F;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,CAG3F;AAED,+FAA+F;AAC/F,wBAAgB,+BAA+B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CAEnF;AAED,wBAAgB,iCAAiC,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,CAErG;AAED,wBAAgB,4BAA4B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,cAAc,CAE/E;AAED,MAAM,WAAW,wBAAwB;IACxC,EAAE,EAAE,IAAI,CAAC;IACT,SAAS,EAAE,eAAe,CAAC;IAC3B,SAAS,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,wBAAwB;IACxC,EAAE,EAAE,KAAK,CAAC;IACV,SAAS,EAAE,eAAe,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACtC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,SAAS,CAAC,EAAE,MAAM,GAChB,wBAAwB,GAAG,wBAAwB,CAMrD;AAED;;;GAGG;AACH,wBAAgB,iCAAiC,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,cAAc,GAAG,SAAS,CAKlH","sourcesContent":["/**\n * lunR: parent-delegated children inherit an explicit permission level, not a\n * named agent role. The parent process resolves the requested level against\n * its own mode, then snapshots that resolved child permission into the child\n * environment. Full maps to child runtime Auto; read-only maps to Plan.\n *\n * Ordinary `lunr -p`, cron, and gateway headless sessions are not children and\n * stay fail-closed.\n */\n\nimport { getPermissionMode, type PermissionMode, resetPermissions } from \"./permissions.ts\";\n\nexport const SUBAGENT_CHILD_ENV = \"PI_SUBAGENT_CHILD\";\nexport const SUBAGENT_CHILD_PERMISSION_ENV = \"PI_SUBAGENT_CHILD_PERMISSION\";\n/** @deprecated Replaced by SUBAGENT_CHILD_PERMISSION_ENV. Kept so leftover env is ignored. */\nexport const SUBAGENT_PARENT_PERMISSION_MODE_ENV = \"PI_SUBAGENT_PARENT_PERMISSION_MODE\";\n\nexport type ChildPermission = \"full\" | \"read-only\";\n\nexport const PLAN_MODE_WRITE_SPAWN_ERROR =\n\t'Cannot launch a full-access child in plan mode. Relaunch with permissions: \"read-only\".';\n\nexport function isSubagentChildProcess(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn env[SUBAGENT_CHILD_ENV] === \"1\";\n}\n\nexport function parseParentPermissionMode(value: string | undefined): PermissionMode | undefined {\n\tif (value === \"manual\" || value === \"yolo\" || value === \"plan\" || value === \"auto\") return value;\n\treturn undefined;\n}\n\nexport function parseChildPermission(value: string | undefined): ChildPermission | undefined {\n\tif (value === \"full\" || value === \"read-only\") return value;\n\treturn undefined;\n}\n\n/** Omitted permissions resolve to full. Unknown values are rejected by the schema/executor. */\nexport function resolveRequestedChildPermission(requested?: string): ChildPermission {\n\treturn requested === \"read-only\" ? \"read-only\" : \"full\";\n}\n\nexport function resolveChildRuntimePermissionMode(childPermission: string | undefined): PermissionMode {\n\treturn parseChildPermission(childPermission) === \"read-only\" ? \"plan\" : \"auto\";\n}\n\nexport function snapshotParentPermissionMode(sessionId?: string): PermissionMode {\n\treturn getPermissionMode(sessionId);\n}\n\nexport interface ResolvedChildPermissions {\n\tok: true;\n\trequested: ChildPermission;\n\teffective: ChildPermission;\n}\n\nexport interface RejectedChildPermissions {\n\tok: false;\n\trequested: ChildPermission;\n\terror: string;\n}\n\n/**\n * Resolve the child's permission level before spawn.\n *\n * Parent mode Requested Result\n * Manual/YOLO/Auto omitted Full\n * Manual/YOLO/Auto full Full\n * Manual/YOLO/Auto read-only Read-only\n * Plan read-only Read-only\n * Plan full / omitted Reject (omission resolves to full)\n */\nexport function resolveChildPermissions(\n\tparentMode: string | undefined,\n\trequested?: string,\n): ResolvedChildPermissions | RejectedChildPermissions {\n\tconst requestedPermission = resolveRequestedChildPermission(requested);\n\tif (parseParentPermissionMode(parentMode) === \"plan\" && requestedPermission === \"full\") {\n\t\treturn { ok: false, requested: requestedPermission, error: PLAN_MODE_WRITE_SPAWN_ERROR };\n\t}\n\treturn { ok: true, requested: requestedPermission, effective: requestedPermission };\n}\n\n/**\n * Apply the resolved child permission before any tool call. No-op for non-child\n * processes so `lunr -p` stays fail-closed.\n */\nexport function applyInheritedSubagentPermissions(env: NodeJS.ProcessEnv = process.env): PermissionMode | undefined {\n\tif (!isSubagentChildProcess(env)) return undefined;\n\tconst childMode = resolveChildRuntimePermissionMode(env[SUBAGENT_CHILD_PERMISSION_ENV]);\n\tresetPermissions(childMode);\n\treturn childMode;\n}\n"]}
1
+ {"version":3,"file":"subagent-permission-inherit.d.ts","sourceRoot":"","sources":["../../src/core/subagent-permission-inherit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAqB,KAAK,cAAc,EAAoB,MAAM,kBAAkB,CAAC;AAE5F,eAAO,MAAM,kBAAkB,sBAAsB,CAAC;AACtD,eAAO,MAAM,6BAA6B,iCAAiC,CAAC;AAC5E,8FAA8F;AAC9F,eAAO,MAAM,mCAAmC,uCAAuC,CAAC;AAExF,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,WAAW,CAAC;AAEnD,eAAO,MAAM,2BAA2B,mGACuD,CAAC;AAEhG,wBAAgB,sBAAsB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAEpF;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,GAAG,SAAS,CAK/F;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,CAG3F;AAED,+FAA+F;AAC/F,wBAAgB,+BAA+B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CAEnF;AAED,wBAAgB,iCAAiC,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,CAErG;AAED,wBAAgB,4BAA4B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,cAAc,CAE/E;AAED,MAAM,WAAW,wBAAwB;IACxC,EAAE,EAAE,IAAI,CAAC;IACT,SAAS,EAAE,eAAe,CAAC;IAC3B,SAAS,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,wBAAwB;IACxC,EAAE,EAAE,KAAK,CAAC;IACV,SAAS,EAAE,eAAe,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACtC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,SAAS,CAAC,EAAE,MAAM,GAChB,wBAAwB,GAAG,wBAAwB,CAMrD;AAED;;;GAGG;AACH,wBAAgB,iCAAiC,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,cAAc,GAAG,SAAS,CAKlH","sourcesContent":["/**\n * lunR: parent-delegated children inherit an explicit permission level, not a\n * named agent role. The parent process resolves the requested level against\n * its own mode, then snapshots that resolved child permission into the child\n * environment. Full maps to child runtime Auto; read-only maps to Read-only.\n */\n\nimport { getPermissionMode, type PermissionMode, resetPermissions } from \"./permissions.ts\";\n\nexport const SUBAGENT_CHILD_ENV = \"PI_SUBAGENT_CHILD\";\nexport const SUBAGENT_CHILD_PERMISSION_ENV = \"PI_SUBAGENT_CHILD_PERMISSION\";\n/** @deprecated Replaced by SUBAGENT_CHILD_PERMISSION_ENV. Kept so leftover env is ignored. */\nexport const SUBAGENT_PARENT_PERMISSION_MODE_ENV = \"PI_SUBAGENT_PARENT_PERMISSION_MODE\";\n\nexport type ChildPermission = \"full\" | \"read-only\";\n\nexport const READ_ONLY_WRITE_SPAWN_ERROR =\n\t'Cannot launch a full-access child in read-only mode. Relaunch with permissions: \"read-only\".';\n\nexport function isSubagentChildProcess(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn env[SUBAGENT_CHILD_ENV] === \"1\";\n}\n\nexport function parseParentPermissionMode(value: string | undefined): PermissionMode | undefined {\n\tif (value === \"yolo\" || value === \"auto\" || value === \"read-only\") return value;\n\tif (value === \"plan\") return \"read-only\";\n\tif (value === \"manual\") return \"yolo\";\n\treturn undefined;\n}\n\nexport function parseChildPermission(value: string | undefined): ChildPermission | undefined {\n\tif (value === \"full\" || value === \"read-only\") return value;\n\treturn undefined;\n}\n\n/** Omitted permissions resolve to full. Unknown values are rejected by the schema/executor. */\nexport function resolveRequestedChildPermission(requested?: string): ChildPermission {\n\treturn requested === \"read-only\" ? \"read-only\" : \"full\";\n}\n\nexport function resolveChildRuntimePermissionMode(childPermission: string | undefined): PermissionMode {\n\treturn parseChildPermission(childPermission) === \"read-only\" ? \"read-only\" : \"auto\";\n}\n\nexport function snapshotParentPermissionMode(sessionId?: string): PermissionMode {\n\treturn getPermissionMode(sessionId);\n}\n\nexport interface ResolvedChildPermissions {\n\tok: true;\n\trequested: ChildPermission;\n\teffective: ChildPermission;\n}\n\nexport interface RejectedChildPermissions {\n\tok: false;\n\trequested: ChildPermission;\n\terror: string;\n}\n\n/**\n * Resolve the child's permission level before spawn.\n *\n * Parent mode Requested Result\n * YOLO/Auto omitted/full Full\n * YOLO/Auto read-only Read-only\n * Read-only read-only Read-only\n * Read-only full / omitted Reject (omission resolves to full)\n */\nexport function resolveChildPermissions(\n\tparentMode: string | undefined,\n\trequested?: string,\n): ResolvedChildPermissions | RejectedChildPermissions {\n\tconst requestedPermission = resolveRequestedChildPermission(requested);\n\tif (parseParentPermissionMode(parentMode) === \"read-only\" && requestedPermission === \"full\") {\n\t\treturn { ok: false, requested: requestedPermission, error: READ_ONLY_WRITE_SPAWN_ERROR };\n\t}\n\treturn { ok: true, requested: requestedPermission, effective: requestedPermission };\n}\n\n/**\n * Apply the resolved child permission before any tool call. No-op for non-child\n * processes so `lunr -p` stays fail-closed.\n */\nexport function applyInheritedSubagentPermissions(env: NodeJS.ProcessEnv = process.env): PermissionMode | undefined {\n\tif (!isSubagentChildProcess(env)) return undefined;\n\tconst childMode = resolveChildRuntimePermissionMode(env[SUBAGENT_CHILD_PERMISSION_ENV]);\n\tresetPermissions(childMode);\n\treturn childMode;\n}\n"]}
@@ -2,23 +2,24 @@
2
2
  * lunR: parent-delegated children inherit an explicit permission level, not a
3
3
  * named agent role. The parent process resolves the requested level against
4
4
  * its own mode, then snapshots that resolved child permission into the child
5
- * environment. Full maps to child runtime Auto; read-only maps to Plan.
6
- *
7
- * Ordinary `lunr -p`, cron, and gateway headless sessions are not children and
8
- * stay fail-closed.
5
+ * environment. Full maps to child runtime Auto; read-only maps to Read-only.
9
6
  */
10
7
  import { getPermissionMode, resetPermissions } from "./permissions.js";
11
8
  export const SUBAGENT_CHILD_ENV = "PI_SUBAGENT_CHILD";
12
9
  export const SUBAGENT_CHILD_PERMISSION_ENV = "PI_SUBAGENT_CHILD_PERMISSION";
13
10
  /** @deprecated Replaced by SUBAGENT_CHILD_PERMISSION_ENV. Kept so leftover env is ignored. */
14
11
  export const SUBAGENT_PARENT_PERMISSION_MODE_ENV = "PI_SUBAGENT_PARENT_PERMISSION_MODE";
15
- export const PLAN_MODE_WRITE_SPAWN_ERROR = 'Cannot launch a full-access child in plan mode. Relaunch with permissions: "read-only".';
12
+ export const READ_ONLY_WRITE_SPAWN_ERROR = 'Cannot launch a full-access child in read-only mode. Relaunch with permissions: "read-only".';
16
13
  export function isSubagentChildProcess(env = process.env) {
17
14
  return env[SUBAGENT_CHILD_ENV] === "1";
18
15
  }
19
16
  export function parseParentPermissionMode(value) {
20
- if (value === "manual" || value === "yolo" || value === "plan" || value === "auto")
17
+ if (value === "yolo" || value === "auto" || value === "read-only")
21
18
  return value;
19
+ if (value === "plan")
20
+ return "read-only";
21
+ if (value === "manual")
22
+ return "yolo";
22
23
  return undefined;
23
24
  }
24
25
  export function parseChildPermission(value) {
@@ -31,7 +32,7 @@ export function resolveRequestedChildPermission(requested) {
31
32
  return requested === "read-only" ? "read-only" : "full";
32
33
  }
33
34
  export function resolveChildRuntimePermissionMode(childPermission) {
34
- return parseChildPermission(childPermission) === "read-only" ? "plan" : "auto";
35
+ return parseChildPermission(childPermission) === "read-only" ? "read-only" : "auto";
35
36
  }
36
37
  export function snapshotParentPermissionMode(sessionId) {
37
38
  return getPermissionMode(sessionId);
@@ -40,16 +41,15 @@ export function snapshotParentPermissionMode(sessionId) {
40
41
  * Resolve the child's permission level before spawn.
41
42
  *
42
43
  * Parent mode Requested Result
43
- * Manual/YOLO/Auto omitted Full
44
- * Manual/YOLO/Auto full Full
45
- * Manual/YOLO/Auto read-only Read-only
46
- * Plan read-only Read-only
47
- * Plan full / omitted Reject (omission resolves to full)
44
+ * YOLO/Auto omitted/full Full
45
+ * YOLO/Auto read-only Read-only
46
+ * Read-only read-only Read-only
47
+ * Read-only full / omitted Reject (omission resolves to full)
48
48
  */
49
49
  export function resolveChildPermissions(parentMode, requested) {
50
50
  const requestedPermission = resolveRequestedChildPermission(requested);
51
- if (parseParentPermissionMode(parentMode) === "plan" && requestedPermission === "full") {
52
- return { ok: false, requested: requestedPermission, error: PLAN_MODE_WRITE_SPAWN_ERROR };
51
+ if (parseParentPermissionMode(parentMode) === "read-only" && requestedPermission === "full") {
52
+ return { ok: false, requested: requestedPermission, error: READ_ONLY_WRITE_SPAWN_ERROR };
53
53
  }
54
54
  return { ok: true, requested: requestedPermission, effective: requestedPermission };
55
55
  }
@@ -1 +1 @@
1
- {"version":3,"file":"subagent-permission-inherit.js","sourceRoot":"","sources":["../../src/core/subagent-permission-inherit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,iBAAiB,EAAuB,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAE5F,MAAM,CAAC,MAAM,kBAAkB,GAAG,mBAAmB,CAAC;AACtD,MAAM,CAAC,MAAM,6BAA6B,GAAG,8BAA8B,CAAC;AAC5E,8FAA8F;AAC9F,MAAM,CAAC,MAAM,mCAAmC,GAAG,oCAAoC,CAAC;AAIxF,MAAM,CAAC,MAAM,2BAA2B,GACvC,yFAAyF,CAAC;AAE3F,MAAM,UAAU,sBAAsB,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG,EAAW;IACrF,OAAO,GAAG,CAAC,kBAAkB,CAAC,KAAK,GAAG,CAAC;AAAA,CACvC;AAED,MAAM,UAAU,yBAAyB,CAAC,KAAyB,EAA8B;IAChG,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IACjG,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAyB,EAA+B;IAC5F,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,WAAW;QAAE,OAAO,KAAK,CAAC;IAC5D,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,+FAA+F;AAC/F,MAAM,UAAU,+BAA+B,CAAC,SAAkB,EAAmB;IACpF,OAAO,SAAS,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC;AAAA,CACxD;AAED,MAAM,UAAU,iCAAiC,CAAC,eAAmC,EAAkB;IACtG,OAAO,oBAAoB,CAAC,eAAe,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;AAAA,CAC/E;AAED,MAAM,UAAU,4BAA4B,CAAC,SAAkB,EAAkB;IAChF,OAAO,iBAAiB,CAAC,SAAS,CAAC,CAAC;AAAA,CACpC;AAcD;;;;;;;;;GASG;AACH,MAAM,UAAU,uBAAuB,CACtC,UAA8B,EAC9B,SAAkB,EACoC;IACtD,MAAM,mBAAmB,GAAG,+BAA+B,CAAC,SAAS,CAAC,CAAC;IACvE,IAAI,yBAAyB,CAAC,UAAU,CAAC,KAAK,MAAM,IAAI,mBAAmB,KAAK,MAAM,EAAE,CAAC;QACxF,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,KAAK,EAAE,2BAA2B,EAAE,CAAC;IAC1F,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,mBAAmB,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC;AAAA,CACpF;AAED;;;GAGG;AACH,MAAM,UAAU,iCAAiC,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG,EAA8B;IACnH,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACnD,MAAM,SAAS,GAAG,iCAAiC,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC,CAAC;IACxF,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAC5B,OAAO,SAAS,CAAC;AAAA,CACjB","sourcesContent":["/**\n * lunR: parent-delegated children inherit an explicit permission level, not a\n * named agent role. The parent process resolves the requested level against\n * its own mode, then snapshots that resolved child permission into the child\n * environment. Full maps to child runtime Auto; read-only maps to Plan.\n *\n * Ordinary `lunr -p`, cron, and gateway headless sessions are not children and\n * stay fail-closed.\n */\n\nimport { getPermissionMode, type PermissionMode, resetPermissions } from \"./permissions.ts\";\n\nexport const SUBAGENT_CHILD_ENV = \"PI_SUBAGENT_CHILD\";\nexport const SUBAGENT_CHILD_PERMISSION_ENV = \"PI_SUBAGENT_CHILD_PERMISSION\";\n/** @deprecated Replaced by SUBAGENT_CHILD_PERMISSION_ENV. Kept so leftover env is ignored. */\nexport const SUBAGENT_PARENT_PERMISSION_MODE_ENV = \"PI_SUBAGENT_PARENT_PERMISSION_MODE\";\n\nexport type ChildPermission = \"full\" | \"read-only\";\n\nexport const PLAN_MODE_WRITE_SPAWN_ERROR =\n\t'Cannot launch a full-access child in plan mode. Relaunch with permissions: \"read-only\".';\n\nexport function isSubagentChildProcess(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn env[SUBAGENT_CHILD_ENV] === \"1\";\n}\n\nexport function parseParentPermissionMode(value: string | undefined): PermissionMode | undefined {\n\tif (value === \"manual\" || value === \"yolo\" || value === \"plan\" || value === \"auto\") return value;\n\treturn undefined;\n}\n\nexport function parseChildPermission(value: string | undefined): ChildPermission | undefined {\n\tif (value === \"full\" || value === \"read-only\") return value;\n\treturn undefined;\n}\n\n/** Omitted permissions resolve to full. Unknown values are rejected by the schema/executor. */\nexport function resolveRequestedChildPermission(requested?: string): ChildPermission {\n\treturn requested === \"read-only\" ? \"read-only\" : \"full\";\n}\n\nexport function resolveChildRuntimePermissionMode(childPermission: string | undefined): PermissionMode {\n\treturn parseChildPermission(childPermission) === \"read-only\" ? \"plan\" : \"auto\";\n}\n\nexport function snapshotParentPermissionMode(sessionId?: string): PermissionMode {\n\treturn getPermissionMode(sessionId);\n}\n\nexport interface ResolvedChildPermissions {\n\tok: true;\n\trequested: ChildPermission;\n\teffective: ChildPermission;\n}\n\nexport interface RejectedChildPermissions {\n\tok: false;\n\trequested: ChildPermission;\n\terror: string;\n}\n\n/**\n * Resolve the child's permission level before spawn.\n *\n * Parent mode Requested Result\n * Manual/YOLO/Auto omitted Full\n * Manual/YOLO/Auto full Full\n * Manual/YOLO/Auto read-only Read-only\n * Plan read-only Read-only\n * Plan full / omitted Reject (omission resolves to full)\n */\nexport function resolveChildPermissions(\n\tparentMode: string | undefined,\n\trequested?: string,\n): ResolvedChildPermissions | RejectedChildPermissions {\n\tconst requestedPermission = resolveRequestedChildPermission(requested);\n\tif (parseParentPermissionMode(parentMode) === \"plan\" && requestedPermission === \"full\") {\n\t\treturn { ok: false, requested: requestedPermission, error: PLAN_MODE_WRITE_SPAWN_ERROR };\n\t}\n\treturn { ok: true, requested: requestedPermission, effective: requestedPermission };\n}\n\n/**\n * Apply the resolved child permission before any tool call. No-op for non-child\n * processes so `lunr -p` stays fail-closed.\n */\nexport function applyInheritedSubagentPermissions(env: NodeJS.ProcessEnv = process.env): PermissionMode | undefined {\n\tif (!isSubagentChildProcess(env)) return undefined;\n\tconst childMode = resolveChildRuntimePermissionMode(env[SUBAGENT_CHILD_PERMISSION_ENV]);\n\tresetPermissions(childMode);\n\treturn childMode;\n}\n"]}
1
+ {"version":3,"file":"subagent-permission-inherit.js","sourceRoot":"","sources":["../../src/core/subagent-permission-inherit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,iBAAiB,EAAuB,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAE5F,MAAM,CAAC,MAAM,kBAAkB,GAAG,mBAAmB,CAAC;AACtD,MAAM,CAAC,MAAM,6BAA6B,GAAG,8BAA8B,CAAC;AAC5E,8FAA8F;AAC9F,MAAM,CAAC,MAAM,mCAAmC,GAAG,oCAAoC,CAAC;AAIxF,MAAM,CAAC,MAAM,2BAA2B,GACvC,8FAA8F,CAAC;AAEhG,MAAM,UAAU,sBAAsB,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG,EAAW;IACrF,OAAO,GAAG,CAAC,kBAAkB,CAAC,KAAK,GAAG,CAAC;AAAA,CACvC;AAED,MAAM,UAAU,yBAAyB,CAAC,KAAyB,EAA8B;IAChG,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,WAAW;QAAE,OAAO,KAAK,CAAC;IAChF,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,WAAW,CAAC;IACzC,IAAI,KAAK,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IACtC,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAyB,EAA+B;IAC5F,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,WAAW;QAAE,OAAO,KAAK,CAAC;IAC5D,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,+FAA+F;AAC/F,MAAM,UAAU,+BAA+B,CAAC,SAAkB,EAAmB;IACpF,OAAO,SAAS,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC;AAAA,CACxD;AAED,MAAM,UAAU,iCAAiC,CAAC,eAAmC,EAAkB;IACtG,OAAO,oBAAoB,CAAC,eAAe,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC;AAAA,CACpF;AAED,MAAM,UAAU,4BAA4B,CAAC,SAAkB,EAAkB;IAChF,OAAO,iBAAiB,CAAC,SAAS,CAAC,CAAC;AAAA,CACpC;AAcD;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CACtC,UAA8B,EAC9B,SAAkB,EACoC;IACtD,MAAM,mBAAmB,GAAG,+BAA+B,CAAC,SAAS,CAAC,CAAC;IACvE,IAAI,yBAAyB,CAAC,UAAU,CAAC,KAAK,WAAW,IAAI,mBAAmB,KAAK,MAAM,EAAE,CAAC;QAC7F,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,KAAK,EAAE,2BAA2B,EAAE,CAAC;IAC1F,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,mBAAmB,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC;AAAA,CACpF;AAED;;;GAGG;AACH,MAAM,UAAU,iCAAiC,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG,EAA8B;IACnH,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACnD,MAAM,SAAS,GAAG,iCAAiC,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC,CAAC;IACxF,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAC5B,OAAO,SAAS,CAAC;AAAA,CACjB","sourcesContent":["/**\n * lunR: parent-delegated children inherit an explicit permission level, not a\n * named agent role. The parent process resolves the requested level against\n * its own mode, then snapshots that resolved child permission into the child\n * environment. Full maps to child runtime Auto; read-only maps to Read-only.\n */\n\nimport { getPermissionMode, type PermissionMode, resetPermissions } from \"./permissions.ts\";\n\nexport const SUBAGENT_CHILD_ENV = \"PI_SUBAGENT_CHILD\";\nexport const SUBAGENT_CHILD_PERMISSION_ENV = \"PI_SUBAGENT_CHILD_PERMISSION\";\n/** @deprecated Replaced by SUBAGENT_CHILD_PERMISSION_ENV. Kept so leftover env is ignored. */\nexport const SUBAGENT_PARENT_PERMISSION_MODE_ENV = \"PI_SUBAGENT_PARENT_PERMISSION_MODE\";\n\nexport type ChildPermission = \"full\" | \"read-only\";\n\nexport const READ_ONLY_WRITE_SPAWN_ERROR =\n\t'Cannot launch a full-access child in read-only mode. Relaunch with permissions: \"read-only\".';\n\nexport function isSubagentChildProcess(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn env[SUBAGENT_CHILD_ENV] === \"1\";\n}\n\nexport function parseParentPermissionMode(value: string | undefined): PermissionMode | undefined {\n\tif (value === \"yolo\" || value === \"auto\" || value === \"read-only\") return value;\n\tif (value === \"plan\") return \"read-only\";\n\tif (value === \"manual\") return \"yolo\";\n\treturn undefined;\n}\n\nexport function parseChildPermission(value: string | undefined): ChildPermission | undefined {\n\tif (value === \"full\" || value === \"read-only\") return value;\n\treturn undefined;\n}\n\n/** Omitted permissions resolve to full. Unknown values are rejected by the schema/executor. */\nexport function resolveRequestedChildPermission(requested?: string): ChildPermission {\n\treturn requested === \"read-only\" ? \"read-only\" : \"full\";\n}\n\nexport function resolveChildRuntimePermissionMode(childPermission: string | undefined): PermissionMode {\n\treturn parseChildPermission(childPermission) === \"read-only\" ? \"read-only\" : \"auto\";\n}\n\nexport function snapshotParentPermissionMode(sessionId?: string): PermissionMode {\n\treturn getPermissionMode(sessionId);\n}\n\nexport interface ResolvedChildPermissions {\n\tok: true;\n\trequested: ChildPermission;\n\teffective: ChildPermission;\n}\n\nexport interface RejectedChildPermissions {\n\tok: false;\n\trequested: ChildPermission;\n\terror: string;\n}\n\n/**\n * Resolve the child's permission level before spawn.\n *\n * Parent mode Requested Result\n * YOLO/Auto omitted/full Full\n * YOLO/Auto read-only Read-only\n * Read-only read-only Read-only\n * Read-only full / omitted Reject (omission resolves to full)\n */\nexport function resolveChildPermissions(\n\tparentMode: string | undefined,\n\trequested?: string,\n): ResolvedChildPermissions | RejectedChildPermissions {\n\tconst requestedPermission = resolveRequestedChildPermission(requested);\n\tif (parseParentPermissionMode(parentMode) === \"read-only\" && requestedPermission === \"full\") {\n\t\treturn { ok: false, requested: requestedPermission, error: READ_ONLY_WRITE_SPAWN_ERROR };\n\t}\n\treturn { ok: true, requested: requestedPermission, effective: requestedPermission };\n}\n\n/**\n * Apply the resolved child permission before any tool call. No-op for non-child\n * processes so `lunr -p` stays fail-closed.\n */\nexport function applyInheritedSubagentPermissions(env: NodeJS.ProcessEnv = process.env): PermissionMode | undefined {\n\tif (!isSubagentChildProcess(env)) return undefined;\n\tconst childMode = resolveChildRuntimePermissionMode(env[SUBAGENT_CHILD_PERMISSION_ENV]);\n\tresetPermissions(childMode);\n\treturn childMode;\n}\n"]}
@@ -0,0 +1,11 @@
1
+ export declare const SUBAGENT_WAIT_INTERRUPTION_SYMBOL: unique symbol;
2
+ export interface SubagentWaitInterruptionRegistration {
3
+ signal: AbortSignal;
4
+ wasInterrupted(): boolean;
5
+ unregister(): void;
6
+ }
7
+ export interface SubagentWaitInterruptionOwner {
8
+ register(): SubagentWaitInterruptionRegistration;
9
+ }
10
+ export declare function registerSubagentWaitInterruptionOwner(sessionId: string, owner: SubagentWaitInterruptionOwner): () => void;
11
+ //# sourceMappingURL=subagent-wait-interruption.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagent-wait-interruption.d.ts","sourceRoot":"","sources":["../../src/core/subagent-wait-interruption.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iCAAiC,eAAiD,CAAC;AAEhG,MAAM,WAAW,oCAAoC;IACpD,MAAM,EAAE,WAAW,CAAC;IACpB,cAAc,IAAI,OAAO,CAAC;IAC1B,UAAU,IAAI,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,IAAI,oCAAoC,CAAC;CACjD;AAeD,wBAAgB,qCAAqC,CACpD,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,6BAA6B,GAClC,MAAM,IAAI,CAMZ","sourcesContent":["export const SUBAGENT_WAIT_INTERRUPTION_SYMBOL = Symbol.for(\"@lunr/subagent-wait-interruption\");\n\nexport interface SubagentWaitInterruptionRegistration {\n\tsignal: AbortSignal;\n\twasInterrupted(): boolean;\n\tunregister(): void;\n}\n\nexport interface SubagentWaitInterruptionOwner {\n\tregister(): SubagentWaitInterruptionRegistration;\n}\n\ninterface SubagentWaitInterruptionBridge {\n\towners: Map<string, SubagentWaitInterruptionOwner>;\n}\n\nfunction getBridge(): SubagentWaitInterruptionBridge {\n\tconst globals = globalThis as Record<symbol, unknown>;\n\tconst existing = globals[SUBAGENT_WAIT_INTERRUPTION_SYMBOL] as SubagentWaitInterruptionBridge | undefined;\n\tif (existing) return existing;\n\tconst bridge: SubagentWaitInterruptionBridge = { owners: new Map() };\n\tglobals[SUBAGENT_WAIT_INTERRUPTION_SYMBOL] = bridge;\n\treturn bridge;\n}\n\nexport function registerSubagentWaitInterruptionOwner(\n\tsessionId: string,\n\towner: SubagentWaitInterruptionOwner,\n): () => void {\n\tconst owners = getBridge().owners;\n\towners.set(sessionId, owner);\n\treturn () => {\n\t\tif (owners.get(sessionId) === owner) owners.delete(sessionId);\n\t};\n}\n"]}
@@ -0,0 +1,19 @@
1
+ export const SUBAGENT_WAIT_INTERRUPTION_SYMBOL = Symbol.for("@lunr/subagent-wait-interruption");
2
+ function getBridge() {
3
+ const globals = globalThis;
4
+ const existing = globals[SUBAGENT_WAIT_INTERRUPTION_SYMBOL];
5
+ if (existing)
6
+ return existing;
7
+ const bridge = { owners: new Map() };
8
+ globals[SUBAGENT_WAIT_INTERRUPTION_SYMBOL] = bridge;
9
+ return bridge;
10
+ }
11
+ export function registerSubagentWaitInterruptionOwner(sessionId, owner) {
12
+ const owners = getBridge().owners;
13
+ owners.set(sessionId, owner);
14
+ return () => {
15
+ if (owners.get(sessionId) === owner)
16
+ owners.delete(sessionId);
17
+ };
18
+ }
19
+ //# sourceMappingURL=subagent-wait-interruption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagent-wait-interruption.js","sourceRoot":"","sources":["../../src/core/subagent-wait-interruption.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iCAAiC,GAAG,MAAM,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;AAgBhG,SAAS,SAAS,GAAmC;IACpD,MAAM,OAAO,GAAG,UAAqC,CAAC;IACtD,MAAM,QAAQ,GAAG,OAAO,CAAC,iCAAiC,CAA+C,CAAC;IAC1G,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,MAAM,GAAmC,EAAE,MAAM,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;IACrE,OAAO,CAAC,iCAAiC,CAAC,GAAG,MAAM,CAAC;IACpD,OAAO,MAAM,CAAC;AAAA,CACd;AAED,MAAM,UAAU,qCAAqC,CACpD,SAAiB,EACjB,KAAoC,EACvB;IACb,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC,MAAM,CAAC;IAClC,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC7B,OAAO,GAAG,EAAE,CAAC;QACZ,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,KAAK;YAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAAA,CAC9D,CAAC;AAAA,CACF","sourcesContent":["export const SUBAGENT_WAIT_INTERRUPTION_SYMBOL = Symbol.for(\"@lunr/subagent-wait-interruption\");\n\nexport interface SubagentWaitInterruptionRegistration {\n\tsignal: AbortSignal;\n\twasInterrupted(): boolean;\n\tunregister(): void;\n}\n\nexport interface SubagentWaitInterruptionOwner {\n\tregister(): SubagentWaitInterruptionRegistration;\n}\n\ninterface SubagentWaitInterruptionBridge {\n\towners: Map<string, SubagentWaitInterruptionOwner>;\n}\n\nfunction getBridge(): SubagentWaitInterruptionBridge {\n\tconst globals = globalThis as Record<symbol, unknown>;\n\tconst existing = globals[SUBAGENT_WAIT_INTERRUPTION_SYMBOL] as SubagentWaitInterruptionBridge | undefined;\n\tif (existing) return existing;\n\tconst bridge: SubagentWaitInterruptionBridge = { owners: new Map() };\n\tglobals[SUBAGENT_WAIT_INTERRUPTION_SYMBOL] = bridge;\n\treturn bridge;\n}\n\nexport function registerSubagentWaitInterruptionOwner(\n\tsessionId: string,\n\towner: SubagentWaitInterruptionOwner,\n): () => void {\n\tconst owners = getBridge().owners;\n\towners.set(sessionId, owner);\n\treturn () => {\n\t\tif (owners.get(sessionId) === owner) owners.delete(sessionId);\n\t};\n}\n"]}
@@ -7,6 +7,8 @@ export interface BuildSystemPromptOptions {
7
7
  customPrompt?: string;
8
8
  /** Current model in provider/id form. */
9
9
  modelSlug?: string;
10
+ /** Whether the default prompt encourages autonomous delegation. */
11
+ automaticSubagentDelegation?: boolean;
10
12
  /** Active tools; used to decide whether read-dependent skill metadata is visible. */
11
13
  selectedTools?: string[];
12
14
  /** Legacy extension metadata retained for API compatibility; tool definitions are sent separately. */
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qFAAqF;IACrF,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,sGAAsG;IACtG,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,oGAAoG;IACpG,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CAoH3E","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.ts\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.ts\";\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Current model in provider/id form. */\n\tmodelSlug?: string;\n\t/** Active tools; used to decide whether read-dependent skill metadata is visible. */\n\tselectedTools?: string[];\n\t/** Legacy extension metadata retained for API compatibility; tool definitions are sent separately. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Legacy extension metadata retained for API compatibility; not appended to the default prompt. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. */\n\tcwd: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n}\n\n/** Build the base system prompt and append configured context. */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tmodelSlug,\n\t\tselectedTools,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst promptCwd = cwd.replace(/\\\\/g, \"/\");\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t\t}\n\t\t\tprompt += \"</project_context>\\n\";\n\t\t}\n\n\t\t// Append skills section (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\tconst currentModel = modelSlug?.trim() || \"no model selected\";\n\tconst hasRead = !selectedTools || selectedTools.includes(\"read\");\n\tconst todoGuideline =\n\t\t!selectedTools || selectedTools.includes(\"todo\")\n\t\t\t? \"- Use todo for meaningful multi-step work. Every update must send the complete list, with exactly one item in progress at a time.\\n\"\n\t\t\t: \"\";\n\n\tlet prompt = `You are an expert coding assistant currently running ''${currentModel}'', operating inside lunR, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\nCurrent working directory: ''${promptCwd}''\n\nBehavior guidelines:\n- Default to writing no comments. Only add one if the why is non-obvious: a hidden constraint, a subtle invariant, a workaround for a specific bug, something that would surprise the reader. If removing the comment wouldn't confuse a future reader, don't write it.\n- Keep comments up to date! When making changes, it's important to keep things in sync. An outdated comment is worse than no comment at all.\n- Carefully consider the reversibility and blast radius of actions. Generally you can freely take local, reversible actions like editing files or running tests. But for actions that are hard to reverse, affect shared systems beyond your local environment, or could otherwise be risky or destructive, check with the user before proceeding.\n- Orchestrate subagents with intent! Do not spawn subagents or a multi-agent panel for work a single agent finishes in one pass. Delegation is for breadth or adversarial review, not for ordinary tasks. Use subagents as a tool when there is genuine benefit to it or the user explicitly asks for it.\n- When several agents work in parallel, state file ownership up front so they do not collide.\n- Tests are good! Endless smoke tests, regressions tests for feature deletions, etc, much less good. Tests should be focused, not slop.\n- Prefer editing existing files to creating new ones.\n- When a reusable excerpt, prompt, or code fragment should have its own Copy button, wrap only that payload in a fenced Markdown block with the info string \\`lunr-copy\\`. Keep explanation outside the block. Use a longer backtick or tilde fence when the payload contains fenced code.\n- Only use emojis if the user explicitly requests it.\n- Never exfil private data on public platforms like github or any other services under any circumstances.\n\n\nGuidelines:\n- Use bash for file operations like ls, rg, find\n- Use read to examine files instead of cat or sed.\n- Use edit for precise changes (edits[].oldText must match exactly)\n- When changing multiple separate locations in one file, use one edit call with multiple entries in edits[] instead of multiple edit calls\n- Each edits[].oldText is matched against the original file, not after earlier edits are applied. Do not emit overlapping or nested edits. Merge nearby changes into one edit.\n- Keep edits[].oldText as small as possible while still being unique in the file. Do not pad with large unchanged regions.\n- Use write only for new files or complete rewrites.\n${todoGuideline}- Use subagents for independent parallel work, specialist analysis, or substantial research. Subagents start with fresh sessions. Use intercom instead to coordinate with an existing lunR session.\n- Use ast_search for structural code matches.\n- Use cron only when the user asks to schedule or manage unattended prompts.\n- Memory stores established, durable facts and stable preferences. Do not store behavior instructions, transient task details, transcripts, guesses, or secrets. Change memory only with the memory tools.\n- ~/.lunr/agent/agents/ contains optional global and per-model AGENTS.md instructions written by the user. Never modify this tree, including through shell commands.\n- Use web search when information is current, uncertain, externally referenced, or research-heavy, and cite the sources used.\n- Use MCP only for capabilities exposed by configured MCP servers. Call native lunR tools directly.\n\n\nlunR documentation (read only when the user asks about lunR itself, or the task concerns lunR itself, its SDK, extensions, themes, skills, or TUI):\n- README: ${readmePath}\n- Documentation: ${docsPath}\n- Examples: ${examplesPath}\n- Always read lunR .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t}\n\t\tprompt += \"</project_context>\\n\";\n\t}\n\n\t// Append skills section (only if read tool is available)\n\tif (hasRead && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\treturn prompt;\n}\n"]}
1
+ {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,qFAAqF;IACrF,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,sGAAsG;IACtG,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,oGAAoG;IACpG,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CA4H3E","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.ts\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.ts\";\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Current model in provider/id form. */\n\tmodelSlug?: string;\n\t/** Whether the default prompt encourages autonomous delegation. */\n\tautomaticSubagentDelegation?: boolean;\n\t/** Active tools; used to decide whether read-dependent skill metadata is visible. */\n\tselectedTools?: string[];\n\t/** Legacy extension metadata retained for API compatibility; tool definitions are sent separately. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Legacy extension metadata retained for API compatibility; not appended to the default prompt. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. */\n\tcwd: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n}\n\n/** Build the base system prompt and append configured context. */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tmodelSlug,\n\t\tautomaticSubagentDelegation = true,\n\t\tselectedTools,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst promptCwd = cwd.replace(/\\\\/g, \"/\");\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t\t}\n\t\t\tprompt += \"</project_context>\\n\";\n\t\t}\n\n\t\t// Append skills section (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\tconst currentModel = modelSlug?.trim() || \"no model selected\";\n\tconst hasRead = !selectedTools || selectedTools.includes(\"read\");\n\tconst todoGuideline =\n\t\t!selectedTools || selectedTools.includes(\"todo\")\n\t\t\t? \"- Use todo for meaningful multi-step work. Every update must send the complete list, with exactly one item in progress at a time.\\n\"\n\t\t\t: \"\";\n\tconst delegationBehavior = automaticSubagentDelegation\n\t\t? \"- Orchestrate subagents with intent! Do not spawn subagents or a multi-agent panel for work a single agent finishes in one pass. Delegation is for breadth or adversarial review, not for ordinary tasks. Use subagents as a tool when there is genuine benefit to it or the user explicitly asks for it.\"\n\t\t: \"- Work on tasks directly. Launch subagents only when the user specifically instructs you to delegate work.\";\n\tconst delegationGuideline = automaticSubagentDelegation\n\t\t? \"- Use subagents for independent parallel work, specialist analysis, or substantial research. Subagents start with fresh sessions. Use intercom instead to coordinate with an existing lunR session.\\n\"\n\t\t: \"\";\n\n\tlet prompt = `You are an expert coding assistant currently running ''${currentModel}'', operating inside lunR, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\nCurrent working directory: ''${promptCwd}''\n\nBehavior guidelines:\n- Default to writing no comments. Only add one if the why is non-obvious: a hidden constraint, a subtle invariant, a workaround for a specific bug, something that would surprise the reader. If removing the comment wouldn't confuse a future reader, don't write it.\n- Keep comments up to date! When making changes, it's important to keep things in sync. An outdated comment is worse than no comment at all.\n- Carefully consider the reversibility and blast radius of actions. Generally you can freely take local, reversible actions like editing files or running tests. But for actions that are hard to reverse, affect shared systems beyond your local environment, or could otherwise be risky or destructive, check with the user before proceeding.\n${delegationBehavior}\n- When several agents work in parallel, state file ownership up front so they do not collide.\n- Tests are good! Endless smoke tests, regressions tests for feature deletions, etc, much less good. Tests should be focused, not slop.\n- Prefer editing existing files to creating new ones.\n- When a reusable excerpt, prompt, or code fragment should be click-to-copy, wrap only that payload in a fenced Markdown block with the info string \\`lunr-copy\\`. Keep explanation outside the block. Use a longer backtick or tilde fence when the payload contains fenced code.\n- Only use emojis if the user explicitly requests it.\n- Never exfil private data on public platforms like github or any other services under any circumstances.\n\n\nGuidelines:\n- Use bash for file operations like ls, rg, find\n- Use read to examine files instead of cat or sed.\n- Use edit for precise changes (edits[].oldText must match exactly)\n- When changing multiple separate locations in one file, use one edit call with multiple entries in edits[] instead of multiple edit calls\n- Each edits[].oldText is matched against the original file, not after earlier edits are applied. Do not emit overlapping or nested edits. Merge nearby changes into one edit.\n- Keep edits[].oldText as small as possible while still being unique in the file. Do not pad with large unchanged regions.\n- Use write only for new files or complete rewrites.\n${todoGuideline}${delegationGuideline}- Resume a subagent only when its work is unfinished or the next task genuinely needs the context it built up. Otherwise launch a new subagent.\n- Use ast_search for structural code matches.\n- Use cron only when the user asks to schedule or manage unattended prompts.\n- For gateway work, inspect with \\`lunr gateway status\\` or \\`lunr gateway doctor\\`, configure with \\`lunr gateway setup\\`, and run \\`lunr gateway start\\` or \\`lunr gateway stop\\` only with user approval. Test by asking the user to send \\`/whoami\\` or a normal message to the bot; there is no arbitrary outbound send command. Keep bot tokens out of commands and output. See ${docsPath}/features.md for pairing, logs, and service details.\n- Memory stores established, durable facts and stable preferences. Do not store behavior instructions, transient task details, transcripts, guesses, or secrets. Change memory only with the memory tools.\n- ~/.lunr/agent/agents/ contains optional global and per-model AGENTS.md instructions written by the user. Never modify this tree, including through shell commands.\n- Use web search when information is current, uncertain, externally referenced, or research-heavy, and cite the sources used.\n- Use MCP only for capabilities exposed by configured MCP servers. Call native lunR tools directly.\n\n\nlunR documentation (read only when the user asks about lunR itself, or the task concerns lunR itself, its SDK, extensions, themes, skills, or TUI):\n- README: ${readmePath}\n- Documentation: ${docsPath}\n- Examples: ${examplesPath}\n- Always read lunR .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t}\n\t\tprompt += \"</project_context>\\n\";\n\t}\n\n\t// Append skills section (only if read tool is available)\n\tif (hasRead && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\treturn prompt;\n}\n"]}
@@ -5,7 +5,7 @@ import { getDocsPath, getExamplesPath, getReadmePath } from "../config.js";
5
5
  import { formatSkillsForPrompt } from "./skills.js";
6
6
  /** Build the base system prompt and append configured context. */
7
7
  export function buildSystemPrompt(options) {
8
- const { customPrompt, modelSlug, selectedTools, appendSystemPrompt, cwd, contextFiles: providedContextFiles, skills: providedSkills, } = options;
8
+ const { customPrompt, modelSlug, automaticSubagentDelegation = true, selectedTools, appendSystemPrompt, cwd, contextFiles: providedContextFiles, skills: providedSkills, } = options;
9
9
  const promptCwd = cwd.replace(/\\/g, "/");
10
10
  const appendSection = appendSystemPrompt ? `\n\n${appendSystemPrompt}` : "";
11
11
  const contextFiles = providedContextFiles ?? [];
@@ -41,6 +41,12 @@ export function buildSystemPrompt(options) {
41
41
  const todoGuideline = !selectedTools || selectedTools.includes("todo")
42
42
  ? "- Use todo for meaningful multi-step work. Every update must send the complete list, with exactly one item in progress at a time.\n"
43
43
  : "";
44
+ const delegationBehavior = automaticSubagentDelegation
45
+ ? "- Orchestrate subagents with intent! Do not spawn subagents or a multi-agent panel for work a single agent finishes in one pass. Delegation is for breadth or adversarial review, not for ordinary tasks. Use subagents as a tool when there is genuine benefit to it or the user explicitly asks for it."
46
+ : "- Work on tasks directly. Launch subagents only when the user specifically instructs you to delegate work.";
47
+ const delegationGuideline = automaticSubagentDelegation
48
+ ? "- Use subagents for independent parallel work, specialist analysis, or substantial research. Subagents start with fresh sessions. Use intercom instead to coordinate with an existing lunR session.\n"
49
+ : "";
44
50
  let prompt = `You are an expert coding assistant currently running ''${currentModel}'', operating inside lunR, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.
45
51
  Current working directory: ''${promptCwd}''
46
52
 
@@ -48,11 +54,11 @@ Behavior guidelines:
48
54
  - Default to writing no comments. Only add one if the why is non-obvious: a hidden constraint, a subtle invariant, a workaround for a specific bug, something that would surprise the reader. If removing the comment wouldn't confuse a future reader, don't write it.
49
55
  - Keep comments up to date! When making changes, it's important to keep things in sync. An outdated comment is worse than no comment at all.
50
56
  - Carefully consider the reversibility and blast radius of actions. Generally you can freely take local, reversible actions like editing files or running tests. But for actions that are hard to reverse, affect shared systems beyond your local environment, or could otherwise be risky or destructive, check with the user before proceeding.
51
- - Orchestrate subagents with intent! Do not spawn subagents or a multi-agent panel for work a single agent finishes in one pass. Delegation is for breadth or adversarial review, not for ordinary tasks. Use subagents as a tool when there is genuine benefit to it or the user explicitly asks for it.
57
+ ${delegationBehavior}
52
58
  - When several agents work in parallel, state file ownership up front so they do not collide.
53
59
  - Tests are good! Endless smoke tests, regressions tests for feature deletions, etc, much less good. Tests should be focused, not slop.
54
60
  - Prefer editing existing files to creating new ones.
55
- - When a reusable excerpt, prompt, or code fragment should have its own Copy button, wrap only that payload in a fenced Markdown block with the info string \`lunr-copy\`. Keep explanation outside the block. Use a longer backtick or tilde fence when the payload contains fenced code.
61
+ - When a reusable excerpt, prompt, or code fragment should be click-to-copy, wrap only that payload in a fenced Markdown block with the info string \`lunr-copy\`. Keep explanation outside the block. Use a longer backtick or tilde fence when the payload contains fenced code.
56
62
  - Only use emojis if the user explicitly requests it.
57
63
  - Never exfil private data on public platforms like github or any other services under any circumstances.
58
64
 
@@ -65,9 +71,10 @@ Guidelines:
65
71
  - Each edits[].oldText is matched against the original file, not after earlier edits are applied. Do not emit overlapping or nested edits. Merge nearby changes into one edit.
66
72
  - Keep edits[].oldText as small as possible while still being unique in the file. Do not pad with large unchanged regions.
67
73
  - Use write only for new files or complete rewrites.
68
- ${todoGuideline}- Use subagents for independent parallel work, specialist analysis, or substantial research. Subagents start with fresh sessions. Use intercom instead to coordinate with an existing lunR session.
74
+ ${todoGuideline}${delegationGuideline}- Resume a subagent only when its work is unfinished or the next task genuinely needs the context it built up. Otherwise launch a new subagent.
69
75
  - Use ast_search for structural code matches.
70
76
  - Use cron only when the user asks to schedule or manage unattended prompts.
77
+ - For gateway work, inspect with \`lunr gateway status\` or \`lunr gateway doctor\`, configure with \`lunr gateway setup\`, and run \`lunr gateway start\` or \`lunr gateway stop\` only with user approval. Test by asking the user to send \`/whoami\` or a normal message to the bot; there is no arbitrary outbound send command. Keep bot tokens out of commands and output. See ${docsPath}/features.md for pairing, logs, and service details.
71
78
  - Memory stores established, durable facts and stable preferences. Do not store behavior instructions, transient task details, transcripts, guesses, or secrets. Change memory only with the memory tools.
72
79
  - ~/.lunr/agent/agents/ contains optional global and per-model AGENTS.md instructions written by the user. Never modify this tree, including through shell commands.
73
80
  - Use web search when information is current, uncertain, externally referenced, or research-heavy, and cite the sources used.
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.ts\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.ts\";\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Current model in provider/id form. */\n\tmodelSlug?: string;\n\t/** Active tools; used to decide whether read-dependent skill metadata is visible. */\n\tselectedTools?: string[];\n\t/** Legacy extension metadata retained for API compatibility; tool definitions are sent separately. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Legacy extension metadata retained for API compatibility; not appended to the default prompt. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. */\n\tcwd: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n}\n\n/** Build the base system prompt and append configured context. */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tmodelSlug,\n\t\tselectedTools,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst promptCwd = cwd.replace(/\\\\/g, \"/\");\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t\t}\n\t\t\tprompt += \"</project_context>\\n\";\n\t\t}\n\n\t\t// Append skills section (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\tconst currentModel = modelSlug?.trim() || \"no model selected\";\n\tconst hasRead = !selectedTools || selectedTools.includes(\"read\");\n\tconst todoGuideline =\n\t\t!selectedTools || selectedTools.includes(\"todo\")\n\t\t\t? \"- Use todo for meaningful multi-step work. Every update must send the complete list, with exactly one item in progress at a time.\\n\"\n\t\t\t: \"\";\n\n\tlet prompt = `You are an expert coding assistant currently running ''${currentModel}'', operating inside lunR, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\nCurrent working directory: ''${promptCwd}''\n\nBehavior guidelines:\n- Default to writing no comments. Only add one if the why is non-obvious: a hidden constraint, a subtle invariant, a workaround for a specific bug, something that would surprise the reader. If removing the comment wouldn't confuse a future reader, don't write it.\n- Keep comments up to date! When making changes, it's important to keep things in sync. An outdated comment is worse than no comment at all.\n- Carefully consider the reversibility and blast radius of actions. Generally you can freely take local, reversible actions like editing files or running tests. But for actions that are hard to reverse, affect shared systems beyond your local environment, or could otherwise be risky or destructive, check with the user before proceeding.\n- Orchestrate subagents with intent! Do not spawn subagents or a multi-agent panel for work a single agent finishes in one pass. Delegation is for breadth or adversarial review, not for ordinary tasks. Use subagents as a tool when there is genuine benefit to it or the user explicitly asks for it.\n- When several agents work in parallel, state file ownership up front so they do not collide.\n- Tests are good! Endless smoke tests, regressions tests for feature deletions, etc, much less good. Tests should be focused, not slop.\n- Prefer editing existing files to creating new ones.\n- When a reusable excerpt, prompt, or code fragment should have its own Copy button, wrap only that payload in a fenced Markdown block with the info string \\`lunr-copy\\`. Keep explanation outside the block. Use a longer backtick or tilde fence when the payload contains fenced code.\n- Only use emojis if the user explicitly requests it.\n- Never exfil private data on public platforms like github or any other services under any circumstances.\n\n\nGuidelines:\n- Use bash for file operations like ls, rg, find\n- Use read to examine files instead of cat or sed.\n- Use edit for precise changes (edits[].oldText must match exactly)\n- When changing multiple separate locations in one file, use one edit call with multiple entries in edits[] instead of multiple edit calls\n- Each edits[].oldText is matched against the original file, not after earlier edits are applied. Do not emit overlapping or nested edits. Merge nearby changes into one edit.\n- Keep edits[].oldText as small as possible while still being unique in the file. Do not pad with large unchanged regions.\n- Use write only for new files or complete rewrites.\n${todoGuideline}- Use subagents for independent parallel work, specialist analysis, or substantial research. Subagents start with fresh sessions. Use intercom instead to coordinate with an existing lunR session.\n- Use ast_search for structural code matches.\n- Use cron only when the user asks to schedule or manage unattended prompts.\n- Memory stores established, durable facts and stable preferences. Do not store behavior instructions, transient task details, transcripts, guesses, or secrets. Change memory only with the memory tools.\n- ~/.lunr/agent/agents/ contains optional global and per-model AGENTS.md instructions written by the user. Never modify this tree, including through shell commands.\n- Use web search when information is current, uncertain, externally referenced, or research-heavy, and cite the sources used.\n- Use MCP only for capabilities exposed by configured MCP servers. Call native lunR tools directly.\n\n\nlunR documentation (read only when the user asks about lunR itself, or the task concerns lunR itself, its SDK, extensions, themes, skills, or TUI):\n- README: ${readmePath}\n- Documentation: ${docsPath}\n- Examples: ${examplesPath}\n- Always read lunR .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t}\n\t\tprompt += \"</project_context>\\n\";\n\t}\n\n\t// Append skills section (only if read tool is available)\n\tif (hasRead && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\treturn prompt;\n}\n"]}
1
+ {"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.ts\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.ts\";\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Current model in provider/id form. */\n\tmodelSlug?: string;\n\t/** Whether the default prompt encourages autonomous delegation. */\n\tautomaticSubagentDelegation?: boolean;\n\t/** Active tools; used to decide whether read-dependent skill metadata is visible. */\n\tselectedTools?: string[];\n\t/** Legacy extension metadata retained for API compatibility; tool definitions are sent separately. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Legacy extension metadata retained for API compatibility; not appended to the default prompt. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. */\n\tcwd: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n}\n\n/** Build the base system prompt and append configured context. */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tmodelSlug,\n\t\tautomaticSubagentDelegation = true,\n\t\tselectedTools,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst promptCwd = cwd.replace(/\\\\/g, \"/\");\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t\t}\n\t\t\tprompt += \"</project_context>\\n\";\n\t\t}\n\n\t\t// Append skills section (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\tconst currentModel = modelSlug?.trim() || \"no model selected\";\n\tconst hasRead = !selectedTools || selectedTools.includes(\"read\");\n\tconst todoGuideline =\n\t\t!selectedTools || selectedTools.includes(\"todo\")\n\t\t\t? \"- Use todo for meaningful multi-step work. Every update must send the complete list, with exactly one item in progress at a time.\\n\"\n\t\t\t: \"\";\n\tconst delegationBehavior = automaticSubagentDelegation\n\t\t? \"- Orchestrate subagents with intent! Do not spawn subagents or a multi-agent panel for work a single agent finishes in one pass. Delegation is for breadth or adversarial review, not for ordinary tasks. Use subagents as a tool when there is genuine benefit to it or the user explicitly asks for it.\"\n\t\t: \"- Work on tasks directly. Launch subagents only when the user specifically instructs you to delegate work.\";\n\tconst delegationGuideline = automaticSubagentDelegation\n\t\t? \"- Use subagents for independent parallel work, specialist analysis, or substantial research. Subagents start with fresh sessions. Use intercom instead to coordinate with an existing lunR session.\\n\"\n\t\t: \"\";\n\n\tlet prompt = `You are an expert coding assistant currently running ''${currentModel}'', operating inside lunR, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\nCurrent working directory: ''${promptCwd}''\n\nBehavior guidelines:\n- Default to writing no comments. Only add one if the why is non-obvious: a hidden constraint, a subtle invariant, a workaround for a specific bug, something that would surprise the reader. If removing the comment wouldn't confuse a future reader, don't write it.\n- Keep comments up to date! When making changes, it's important to keep things in sync. An outdated comment is worse than no comment at all.\n- Carefully consider the reversibility and blast radius of actions. Generally you can freely take local, reversible actions like editing files or running tests. But for actions that are hard to reverse, affect shared systems beyond your local environment, or could otherwise be risky or destructive, check with the user before proceeding.\n${delegationBehavior}\n- When several agents work in parallel, state file ownership up front so they do not collide.\n- Tests are good! Endless smoke tests, regressions tests for feature deletions, etc, much less good. Tests should be focused, not slop.\n- Prefer editing existing files to creating new ones.\n- When a reusable excerpt, prompt, or code fragment should be click-to-copy, wrap only that payload in a fenced Markdown block with the info string \\`lunr-copy\\`. Keep explanation outside the block. Use a longer backtick or tilde fence when the payload contains fenced code.\n- Only use emojis if the user explicitly requests it.\n- Never exfil private data on public platforms like github or any other services under any circumstances.\n\n\nGuidelines:\n- Use bash for file operations like ls, rg, find\n- Use read to examine files instead of cat or sed.\n- Use edit for precise changes (edits[].oldText must match exactly)\n- When changing multiple separate locations in one file, use one edit call with multiple entries in edits[] instead of multiple edit calls\n- Each edits[].oldText is matched against the original file, not after earlier edits are applied. Do not emit overlapping or nested edits. Merge nearby changes into one edit.\n- Keep edits[].oldText as small as possible while still being unique in the file. Do not pad with large unchanged regions.\n- Use write only for new files or complete rewrites.\n${todoGuideline}${delegationGuideline}- Resume a subagent only when its work is unfinished or the next task genuinely needs the context it built up. Otherwise launch a new subagent.\n- Use ast_search for structural code matches.\n- Use cron only when the user asks to schedule or manage unattended prompts.\n- For gateway work, inspect with \\`lunr gateway status\\` or \\`lunr gateway doctor\\`, configure with \\`lunr gateway setup\\`, and run \\`lunr gateway start\\` or \\`lunr gateway stop\\` only with user approval. Test by asking the user to send \\`/whoami\\` or a normal message to the bot; there is no arbitrary outbound send command. Keep bot tokens out of commands and output. See ${docsPath}/features.md for pairing, logs, and service details.\n- Memory stores established, durable facts and stable preferences. Do not store behavior instructions, transient task details, transcripts, guesses, or secrets. Change memory only with the memory tools.\n- ~/.lunr/agent/agents/ contains optional global and per-model AGENTS.md instructions written by the user. Never modify this tree, including through shell commands.\n- Use web search when information is current, uncertain, externally referenced, or research-heavy, and cite the sources used.\n- Use MCP only for capabilities exposed by configured MCP servers. Call native lunR tools directly.\n\n\nlunR documentation (read only when the user asks about lunR itself, or the task concerns lunR itself, its SDK, extensions, themes, skills, or TUI):\n- README: ${readmePath}\n- Documentation: ${docsPath}\n- Examples: ${examplesPath}\n- Always read lunR .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t}\n\t\tprompt += \"</project_context>\\n\";\n\t}\n\n\t// Append skills section (only if read tool is available)\n\tif (hasRead && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\treturn prompt;\n}\n"]}
@@ -34,9 +34,9 @@ export declare function toolGroupRole(continuation: boolean, followed: boolean):
34
34
  * ```
35
35
  *
36
36
  * Singletons and expanded rows keep `● title detail` on one line.
37
- * Collapsed errors stay in the same-name tree; the error body is hoisted
38
- * under the last leaf so it does not split the file list. Grouped still-running
39
- * cards share the same tree as finished ones. `compact` is header-only body
37
+ * Collapsed errors stay in the same-name tree with a red status dot; details
38
+ * remain available on expansion. Grouped still-running cards share the same
39
+ * tree as finished ones. `compact` is header-only body
40
40
  * hiding at the caller; pass `tree` for chrome. `isError` is accepted so
41
41
  * callers can keep passing it, but it does not drop tree chrome.
42
42
  */
@@ -1 +1 @@
1
- {"version":3,"file":"render-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tools/render-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import * as os from \"node:os\";\nimport { basename } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type { ImageContent, TextContent } from \"@ashx-j/lunr-ai\";\nimport {\n\tgetCapabilities,\n\tgetImageDimensions,\n\thyperlink,\n\timageFallback,\n\tText,\n\ttruncateToWidth,\n\twrapTextWithAnsi,\n} from \"@ashx-j/lunr-tui\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { stripAnsi } from \"../../utils/ansi.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\nimport type { ToolGroupRole } from \"../extensions/types.ts\";\n\nexport function shortenPath(path: unknown): string {\n\tif (typeof path !== \"string\") return \"\";\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\treturn `~${path.slice(home.length)}`;\n\t}\n\treturn path;\n}\n\nexport function linkPath(styledText: string, rawPath: string, cwd: string): string {\n\tif (!getCapabilities().hyperlinks) return styledText;\n\tconst absolutePath = resolvePath(rawPath, cwd);\n\treturn hyperlink(styledText, pathToFileURL(absolutePath).href);\n}\n\nexport function str(value: unknown): string | null {\n\tif (typeof value === \"string\") return value;\n\tif (value == null) return \"\";\n\treturn null;\n}\n\nexport function replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport function normalizeDisplayText(text: string): string {\n\treturn text.replace(/\\r/g, \"\");\n}\n\nexport function getTextOutput(\n\tresult: { content: Array<{ type: string; text?: string; data?: string; mimeType?: string }> } | undefined,\n\tshowImages: boolean,\n): string {\n\tif (!result) return \"\";\n\n\tconst textBlocks = result.content.filter((c) => c.type === \"text\");\n\tconst imageBlocks = result.content.filter((c) => c.type === \"image\");\n\n\tlet output = textBlocks.map((c) => sanitizeBinaryOutput(stripAnsi(c.text || \"\")).replace(/\\r/g, \"\")).join(\"\\n\");\n\n\tconst caps = getCapabilities();\n\tif (imageBlocks.length > 0 && (!caps.images || !showImages)) {\n\t\tconst imageIndicators = imageBlocks\n\t\t\t.map((img) => {\n\t\t\t\tconst mimeType = img.mimeType ?? \"image/unknown\";\n\t\t\t\tconst dims =\n\t\t\t\t\timg.data && img.mimeType ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\treturn imageFallback(mimeType, dims);\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t}\n\n\treturn output;\n}\n\nexport type ToolRenderResultLike<TDetails> = {\n\tcontent: (TextContent | ImageContent)[];\n\tdetails: TDetails;\n};\n\nexport function invalidArgText(theme: Theme): string {\n\treturn theme.fg(\"error\", \"[invalid arg]\");\n}\n\n// lunr: compact-by-default — tool execute() paths append truncation/limit notices\n// as a trailing \"\\n\\n[...]\" block. Compact (header-only) results blank the body,\n// so this extracts that notice to keep it visible without the full output.\nexport function extractTrailingNotice(text: string): string | undefined {\n\tconst trimmed = text.trimEnd();\n\tif (!trimmed.endsWith(\"]\")) return undefined;\n\tconst start = trimmed.lastIndexOf(\"\\n\\n[\");\n\tif (start === -1) return undefined;\n\treturn trimmed.slice(start + 2);\n}\n\nexport type ToolStatusDotState = \"pending\" | \"success\" | \"error\";\n\nexport type { ToolGroupRole };\n\nexport function toolGroupRole(continuation: boolean, followed: boolean): ToolGroupRole {\n\tif (!continuation && followed) return \"first\";\n\tif (continuation && followed) return \"middle\";\n\tif (continuation && !followed) return \"last\";\n\treturn \"singleton\";\n}\n\n/**\n * Quieter same-name chrome: the verb is printed once, then files hang off a tree.\n *\n * ```\n * ● read\n * ├─ resolve.ts\n * └─ usage-service.ts\n * ```\n *\n * Singletons and expanded rows keep `● title detail` on one line.\n * Collapsed errors stay in the same-name tree; the error body is hoisted\n * under the last leaf so it does not split the file list. Grouped still-running\n * cards share the same tree as finished ones. `compact` is header-only body\n * hiding at the caller; pass `tree` for chrome. `isError` is accepted so\n * callers can keep passing it, but it does not drop tree chrome.\n */\nexport function toolGroupTree(context: { expanded?: boolean; isError?: boolean }): boolean {\n\treturn !context.expanded;\n}\n\ninterface GroupedCallOptions {\n\trole: ToolGroupRole;\n\tcompact?: boolean;\n\ttree?: boolean;\n\tdot: string;\n\ttitle: string;\n\tdetail?: string;\n}\n\nexport class GroupedCallText extends Text {\n\tprivate call?: GroupedCallOptions;\n\tprivate formattedWidth?: number;\n\n\tsetCall(call: GroupedCallOptions): void {\n\t\tthis.setText(formatGroupedCall(call));\n\t\tthis.call = call;\n\t}\n\n\toverride setText(text: string): void {\n\t\tthis.call = undefined;\n\t\tthis.formattedWidth = undefined;\n\t\tsuper.setText(text);\n\t}\n\n\toverride render(width: number): string[] {\n\t\tif (this.call && this.formattedWidth !== width) {\n\t\t\tsuper.setText(formatGroupedCall(this.call, width));\n\t\t\tthis.formattedWidth = width;\n\t\t}\n\t\treturn super.render(width);\n\t}\n}\n\nexport function formatGroupedCall(opts: GroupedCallOptions, width?: number): string {\n\tconst detail = opts.detail?.trim() ? opts.detail : \"\";\n\tconst useTree = (opts.tree ?? opts.compact === true) && opts.role !== \"singleton\" && detail.length > 0;\n\tif (!useTree) {\n\t\treturn detail ? `${opts.dot} ${opts.title} ${detail}` : `${opts.dot} ${opts.title}`;\n\t}\n\tconst branch = opts.role === \"last\" ? \"└─\" : \"├─\";\n\tconst prefix = ` ${branch} `;\n\tconst continuation = opts.role === \"last\" ? \" \" : \" │ \";\n\tconst leaf =\n\t\twidth === undefined\n\t\t\t? `${prefix}${detail}`\n\t\t\t: wrapTextWithAnsi(replaceTabs(detail), Math.max(1, width - prefix.length))\n\t\t\t\t\t.map((line, index) => truncateToWidth(`${index === 0 ? prefix : continuation}${line}`, width, \"\"))\n\t\t\t\t\t.join(\"\\n\");\n\tif (opts.role === \"first\") {\n\t\treturn `${opts.dot} ${opts.title}\\n${leaf}`;\n\t}\n\treturn leaf;\n}\n\n/**\n * Colored status dot used as the sole state indicator on tool titles (moon theme:\n * backgrounds stay neutral). Pending = muted, success = green, error = red.\n */\nexport function toolStatusDot(state: ToolStatusDotState, theme: Theme): string {\n\treturn theme.fg(state === \"pending\" ? \"muted\" : state, \"●\");\n}\n\n/** Derive the status dot from a render context (partial → pending, error → error, else success). */\nexport function toolStatusDotFromContext(context: { isPartial: boolean; isError: boolean }, theme: Theme): string {\n\treturn toolStatusDot(context.isPartial ? \"pending\" : context.isError ? \"error\" : \"success\", theme);\n}\n\nexport function renderToolPath(\n\trawPath: string | null,\n\ttheme: Theme,\n\tcwd: string,\n\toptions?: { emptyFallback?: string },\n): string {\n\tif (rawPath === null) return invalidArgText(theme);\n\tconst value = rawPath || options?.emptyFallback;\n\tif (!value) return theme.fg(\"toolOutput\", \"...\");\n\treturn linkPath(theme.fg(\"accent\", shortenPath(value)), value, cwd);\n}\n\n/** Basename-only path for compact tool headers. Still hyperlinked to the absolute file. */\nexport function renderToolFileName(rawPath: string | null, theme: Theme, cwd: string): string {\n\tif (rawPath === null) return invalidArgText(theme);\n\tif (!rawPath) return theme.fg(\"toolOutput\", \"...\");\n\tconst name = basename(rawPath) || rawPath;\n\treturn linkPath(theme.fg(\"accent\", name), rawPath, cwd);\n}\n\n/**\n * Collapsed grep/find path. Omits cwd (`.` / empty) so the header stays one line.\n * Other paths are basename-only and hyperlinked.\n */\nexport function renderCollapsedSearchPath(rawPath: string | null, theme: Theme, cwd: string): string | undefined {\n\tif (rawPath === null) return invalidArgText(theme);\n\tconst value = rawPath.trim();\n\tif (!value || value === \".\" || value === \"./\") return undefined;\n\treturn renderToolFileName(value, theme, cwd);\n}\n"]}
1
+ {"version":3,"file":"render-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tools/render-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import * as os from \"node:os\";\nimport { basename } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type { ImageContent, TextContent } from \"@ashx-j/lunr-ai\";\nimport {\n\tgetCapabilities,\n\tgetImageDimensions,\n\thyperlink,\n\timageFallback,\n\tText,\n\ttruncateToWidth,\n\twrapTextWithAnsi,\n} from \"@ashx-j/lunr-tui\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { stripAnsi } from \"../../utils/ansi.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\nimport type { ToolGroupRole } from \"../extensions/types.ts\";\n\nexport function shortenPath(path: unknown): string {\n\tif (typeof path !== \"string\") return \"\";\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\treturn `~${path.slice(home.length)}`;\n\t}\n\treturn path;\n}\n\nexport function linkPath(styledText: string, rawPath: string, cwd: string): string {\n\tif (!getCapabilities().hyperlinks) return styledText;\n\tconst absolutePath = resolvePath(rawPath, cwd);\n\treturn hyperlink(styledText, pathToFileURL(absolutePath).href);\n}\n\nexport function str(value: unknown): string | null {\n\tif (typeof value === \"string\") return value;\n\tif (value == null) return \"\";\n\treturn null;\n}\n\nexport function replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport function normalizeDisplayText(text: string): string {\n\treturn text.replace(/\\r/g, \"\");\n}\n\nexport function getTextOutput(\n\tresult: { content: Array<{ type: string; text?: string; data?: string; mimeType?: string }> } | undefined,\n\tshowImages: boolean,\n): string {\n\tif (!result) return \"\";\n\n\tconst textBlocks = result.content.filter((c) => c.type === \"text\");\n\tconst imageBlocks = result.content.filter((c) => c.type === \"image\");\n\n\tlet output = textBlocks.map((c) => sanitizeBinaryOutput(stripAnsi(c.text || \"\")).replace(/\\r/g, \"\")).join(\"\\n\");\n\n\tconst caps = getCapabilities();\n\tif (imageBlocks.length > 0 && (!caps.images || !showImages)) {\n\t\tconst imageIndicators = imageBlocks\n\t\t\t.map((img) => {\n\t\t\t\tconst mimeType = img.mimeType ?? \"image/unknown\";\n\t\t\t\tconst dims =\n\t\t\t\t\timg.data && img.mimeType ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\treturn imageFallback(mimeType, dims);\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t}\n\n\treturn output;\n}\n\nexport type ToolRenderResultLike<TDetails> = {\n\tcontent: (TextContent | ImageContent)[];\n\tdetails: TDetails;\n};\n\nexport function invalidArgText(theme: Theme): string {\n\treturn theme.fg(\"error\", \"[invalid arg]\");\n}\n\n// lunr: compact-by-default — tool execute() paths append truncation/limit notices\n// as a trailing \"\\n\\n[...]\" block. Compact (header-only) results blank the body,\n// so this extracts that notice to keep it visible without the full output.\nexport function extractTrailingNotice(text: string): string | undefined {\n\tconst trimmed = text.trimEnd();\n\tif (!trimmed.endsWith(\"]\")) return undefined;\n\tconst start = trimmed.lastIndexOf(\"\\n\\n[\");\n\tif (start === -1) return undefined;\n\treturn trimmed.slice(start + 2);\n}\n\nexport type ToolStatusDotState = \"pending\" | \"success\" | \"error\";\n\nexport type { ToolGroupRole };\n\nexport function toolGroupRole(continuation: boolean, followed: boolean): ToolGroupRole {\n\tif (!continuation && followed) return \"first\";\n\tif (continuation && followed) return \"middle\";\n\tif (continuation && !followed) return \"last\";\n\treturn \"singleton\";\n}\n\n/**\n * Quieter same-name chrome: the verb is printed once, then files hang off a tree.\n *\n * ```\n * ● read\n * ├─ resolve.ts\n * └─ usage-service.ts\n * ```\n *\n * Singletons and expanded rows keep `● title detail` on one line.\n * Collapsed errors stay in the same-name tree with a red status dot; details\n * remain available on expansion. Grouped still-running cards share the same\n * tree as finished ones. `compact` is header-only body\n * hiding at the caller; pass `tree` for chrome. `isError` is accepted so\n * callers can keep passing it, but it does not drop tree chrome.\n */\nexport function toolGroupTree(context: { expanded?: boolean; isError?: boolean }): boolean {\n\treturn !context.expanded;\n}\n\ninterface GroupedCallOptions {\n\trole: ToolGroupRole;\n\tcompact?: boolean;\n\ttree?: boolean;\n\tdot: string;\n\ttitle: string;\n\tdetail?: string;\n}\n\nexport class GroupedCallText extends Text {\n\tprivate call?: GroupedCallOptions;\n\tprivate formattedWidth?: number;\n\n\tsetCall(call: GroupedCallOptions): void {\n\t\tthis.setText(formatGroupedCall(call));\n\t\tthis.call = call;\n\t}\n\n\toverride setText(text: string): void {\n\t\tthis.call = undefined;\n\t\tthis.formattedWidth = undefined;\n\t\tsuper.setText(text);\n\t}\n\n\toverride render(width: number): string[] {\n\t\tif (this.call && this.formattedWidth !== width) {\n\t\t\tsuper.setText(formatGroupedCall(this.call, width));\n\t\t\tthis.formattedWidth = width;\n\t\t}\n\t\treturn super.render(width);\n\t}\n}\n\nexport function formatGroupedCall(opts: GroupedCallOptions, width?: number): string {\n\tconst detail = opts.detail?.trim() ? opts.detail : \"\";\n\tconst useTree = (opts.tree ?? opts.compact === true) && opts.role !== \"singleton\" && detail.length > 0;\n\tif (!useTree) {\n\t\treturn detail ? `${opts.dot} ${opts.title} ${detail}` : `${opts.dot} ${opts.title}`;\n\t}\n\tconst branch = opts.role === \"last\" ? \"└─\" : \"├─\";\n\tconst prefix = ` ${branch} `;\n\tconst continuation = opts.role === \"last\" ? \" \" : \" │ \";\n\tconst leaf =\n\t\twidth === undefined\n\t\t\t? `${prefix}${detail}`\n\t\t\t: wrapTextWithAnsi(replaceTabs(detail), Math.max(1, width - prefix.length))\n\t\t\t\t\t.map((line, index) => truncateToWidth(`${index === 0 ? prefix : continuation}${line}`, width, \"\"))\n\t\t\t\t\t.join(\"\\n\");\n\tif (opts.role === \"first\") {\n\t\treturn `${opts.dot} ${opts.title}\\n${leaf}`;\n\t}\n\treturn leaf;\n}\n\n/**\n * Colored status dot used as the sole state indicator on tool titles (moon theme:\n * backgrounds stay neutral). Pending = muted, success = green, error = red.\n */\nexport function toolStatusDot(state: ToolStatusDotState, theme: Theme): string {\n\treturn theme.fg(state === \"pending\" ? \"muted\" : state, \"●\");\n}\n\n/** Derive the status dot from a render context (partial → pending, error → error, else success). */\nexport function toolStatusDotFromContext(context: { isPartial: boolean; isError: boolean }, theme: Theme): string {\n\treturn toolStatusDot(context.isPartial ? \"pending\" : context.isError ? \"error\" : \"success\", theme);\n}\n\nexport function renderToolPath(\n\trawPath: string | null,\n\ttheme: Theme,\n\tcwd: string,\n\toptions?: { emptyFallback?: string },\n): string {\n\tif (rawPath === null) return invalidArgText(theme);\n\tconst value = rawPath || options?.emptyFallback;\n\tif (!value) return theme.fg(\"toolOutput\", \"...\");\n\treturn linkPath(theme.fg(\"accent\", shortenPath(value)), value, cwd);\n}\n\n/** Basename-only path for compact tool headers. Still hyperlinked to the absolute file. */\nexport function renderToolFileName(rawPath: string | null, theme: Theme, cwd: string): string {\n\tif (rawPath === null) return invalidArgText(theme);\n\tif (!rawPath) return theme.fg(\"toolOutput\", \"...\");\n\tconst name = basename(rawPath) || rawPath;\n\treturn linkPath(theme.fg(\"accent\", name), rawPath, cwd);\n}\n\n/**\n * Collapsed grep/find path. Omits cwd (`.` / empty) so the header stays one line.\n * Other paths are basename-only and hyperlinked.\n */\nexport function renderCollapsedSearchPath(rawPath: string | null, theme: Theme, cwd: string): string | undefined {\n\tif (rawPath === null) return invalidArgText(theme);\n\tconst value = rawPath.trim();\n\tif (!value || value === \".\" || value === \"./\") return undefined;\n\treturn renderToolFileName(value, theme, cwd);\n}\n"]}
@@ -86,9 +86,9 @@ export function toolGroupRole(continuation, followed) {
86
86
  * ```
87
87
  *
88
88
  * Singletons and expanded rows keep `● title detail` on one line.
89
- * Collapsed errors stay in the same-name tree; the error body is hoisted
90
- * under the last leaf so it does not split the file list. Grouped still-running
91
- * cards share the same tree as finished ones. `compact` is header-only body
89
+ * Collapsed errors stay in the same-name tree with a red status dot; details
90
+ * remain available on expansion. Grouped still-running cards share the same
91
+ * tree as finished ones. `compact` is header-only body
92
92
  * hiding at the caller; pass `tree` for chrome. `isError` is accepted so
93
93
  * callers can keep passing it, but it does not drop tree chrome.
94
94
  */
@@ -1 +1 @@
1
- {"version":3,"file":"render-utils.js","sourceRoot":"","sources":["../../../src/core/tools/render-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import * as os from \"node:os\";\nimport { basename } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type { ImageContent, TextContent } from \"@ashx-j/lunr-ai\";\nimport {\n\tgetCapabilities,\n\tgetImageDimensions,\n\thyperlink,\n\timageFallback,\n\tText,\n\ttruncateToWidth,\n\twrapTextWithAnsi,\n} from \"@ashx-j/lunr-tui\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { stripAnsi } from \"../../utils/ansi.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\nimport type { ToolGroupRole } from \"../extensions/types.ts\";\n\nexport function shortenPath(path: unknown): string {\n\tif (typeof path !== \"string\") return \"\";\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\treturn `~${path.slice(home.length)}`;\n\t}\n\treturn path;\n}\n\nexport function linkPath(styledText: string, rawPath: string, cwd: string): string {\n\tif (!getCapabilities().hyperlinks) return styledText;\n\tconst absolutePath = resolvePath(rawPath, cwd);\n\treturn hyperlink(styledText, pathToFileURL(absolutePath).href);\n}\n\nexport function str(value: unknown): string | null {\n\tif (typeof value === \"string\") return value;\n\tif (value == null) return \"\";\n\treturn null;\n}\n\nexport function replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport function normalizeDisplayText(text: string): string {\n\treturn text.replace(/\\r/g, \"\");\n}\n\nexport function getTextOutput(\n\tresult: { content: Array<{ type: string; text?: string; data?: string; mimeType?: string }> } | undefined,\n\tshowImages: boolean,\n): string {\n\tif (!result) return \"\";\n\n\tconst textBlocks = result.content.filter((c) => c.type === \"text\");\n\tconst imageBlocks = result.content.filter((c) => c.type === \"image\");\n\n\tlet output = textBlocks.map((c) => sanitizeBinaryOutput(stripAnsi(c.text || \"\")).replace(/\\r/g, \"\")).join(\"\\n\");\n\n\tconst caps = getCapabilities();\n\tif (imageBlocks.length > 0 && (!caps.images || !showImages)) {\n\t\tconst imageIndicators = imageBlocks\n\t\t\t.map((img) => {\n\t\t\t\tconst mimeType = img.mimeType ?? \"image/unknown\";\n\t\t\t\tconst dims =\n\t\t\t\t\timg.data && img.mimeType ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\treturn imageFallback(mimeType, dims);\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t}\n\n\treturn output;\n}\n\nexport type ToolRenderResultLike<TDetails> = {\n\tcontent: (TextContent | ImageContent)[];\n\tdetails: TDetails;\n};\n\nexport function invalidArgText(theme: Theme): string {\n\treturn theme.fg(\"error\", \"[invalid arg]\");\n}\n\n// lunr: compact-by-default — tool execute() paths append truncation/limit notices\n// as a trailing \"\\n\\n[...]\" block. Compact (header-only) results blank the body,\n// so this extracts that notice to keep it visible without the full output.\nexport function extractTrailingNotice(text: string): string | undefined {\n\tconst trimmed = text.trimEnd();\n\tif (!trimmed.endsWith(\"]\")) return undefined;\n\tconst start = trimmed.lastIndexOf(\"\\n\\n[\");\n\tif (start === -1) return undefined;\n\treturn trimmed.slice(start + 2);\n}\n\nexport type ToolStatusDotState = \"pending\" | \"success\" | \"error\";\n\nexport type { ToolGroupRole };\n\nexport function toolGroupRole(continuation: boolean, followed: boolean): ToolGroupRole {\n\tif (!continuation && followed) return \"first\";\n\tif (continuation && followed) return \"middle\";\n\tif (continuation && !followed) return \"last\";\n\treturn \"singleton\";\n}\n\n/**\n * Quieter same-name chrome: the verb is printed once, then files hang off a tree.\n *\n * ```\n * ● read\n * ├─ resolve.ts\n * └─ usage-service.ts\n * ```\n *\n * Singletons and expanded rows keep `● title detail` on one line.\n * Collapsed errors stay in the same-name tree; the error body is hoisted\n * under the last leaf so it does not split the file list. Grouped still-running\n * cards share the same tree as finished ones. `compact` is header-only body\n * hiding at the caller; pass `tree` for chrome. `isError` is accepted so\n * callers can keep passing it, but it does not drop tree chrome.\n */\nexport function toolGroupTree(context: { expanded?: boolean; isError?: boolean }): boolean {\n\treturn !context.expanded;\n}\n\ninterface GroupedCallOptions {\n\trole: ToolGroupRole;\n\tcompact?: boolean;\n\ttree?: boolean;\n\tdot: string;\n\ttitle: string;\n\tdetail?: string;\n}\n\nexport class GroupedCallText extends Text {\n\tprivate call?: GroupedCallOptions;\n\tprivate formattedWidth?: number;\n\n\tsetCall(call: GroupedCallOptions): void {\n\t\tthis.setText(formatGroupedCall(call));\n\t\tthis.call = call;\n\t}\n\n\toverride setText(text: string): void {\n\t\tthis.call = undefined;\n\t\tthis.formattedWidth = undefined;\n\t\tsuper.setText(text);\n\t}\n\n\toverride render(width: number): string[] {\n\t\tif (this.call && this.formattedWidth !== width) {\n\t\t\tsuper.setText(formatGroupedCall(this.call, width));\n\t\t\tthis.formattedWidth = width;\n\t\t}\n\t\treturn super.render(width);\n\t}\n}\n\nexport function formatGroupedCall(opts: GroupedCallOptions, width?: number): string {\n\tconst detail = opts.detail?.trim() ? opts.detail : \"\";\n\tconst useTree = (opts.tree ?? opts.compact === true) && opts.role !== \"singleton\" && detail.length > 0;\n\tif (!useTree) {\n\t\treturn detail ? `${opts.dot} ${opts.title} ${detail}` : `${opts.dot} ${opts.title}`;\n\t}\n\tconst branch = opts.role === \"last\" ? \"└─\" : \"├─\";\n\tconst prefix = ` ${branch} `;\n\tconst continuation = opts.role === \"last\" ? \" \" : \" │ \";\n\tconst leaf =\n\t\twidth === undefined\n\t\t\t? `${prefix}${detail}`\n\t\t\t: wrapTextWithAnsi(replaceTabs(detail), Math.max(1, width - prefix.length))\n\t\t\t\t\t.map((line, index) => truncateToWidth(`${index === 0 ? prefix : continuation}${line}`, width, \"\"))\n\t\t\t\t\t.join(\"\\n\");\n\tif (opts.role === \"first\") {\n\t\treturn `${opts.dot} ${opts.title}\\n${leaf}`;\n\t}\n\treturn leaf;\n}\n\n/**\n * Colored status dot used as the sole state indicator on tool titles (moon theme:\n * backgrounds stay neutral). Pending = muted, success = green, error = red.\n */\nexport function toolStatusDot(state: ToolStatusDotState, theme: Theme): string {\n\treturn theme.fg(state === \"pending\" ? \"muted\" : state, \"●\");\n}\n\n/** Derive the status dot from a render context (partial → pending, error → error, else success). */\nexport function toolStatusDotFromContext(context: { isPartial: boolean; isError: boolean }, theme: Theme): string {\n\treturn toolStatusDot(context.isPartial ? \"pending\" : context.isError ? \"error\" : \"success\", theme);\n}\n\nexport function renderToolPath(\n\trawPath: string | null,\n\ttheme: Theme,\n\tcwd: string,\n\toptions?: { emptyFallback?: string },\n): string {\n\tif (rawPath === null) return invalidArgText(theme);\n\tconst value = rawPath || options?.emptyFallback;\n\tif (!value) return theme.fg(\"toolOutput\", \"...\");\n\treturn linkPath(theme.fg(\"accent\", shortenPath(value)), value, cwd);\n}\n\n/** Basename-only path for compact tool headers. Still hyperlinked to the absolute file. */\nexport function renderToolFileName(rawPath: string | null, theme: Theme, cwd: string): string {\n\tif (rawPath === null) return invalidArgText(theme);\n\tif (!rawPath) return theme.fg(\"toolOutput\", \"...\");\n\tconst name = basename(rawPath) || rawPath;\n\treturn linkPath(theme.fg(\"accent\", name), rawPath, cwd);\n}\n\n/**\n * Collapsed grep/find path. Omits cwd (`.` / empty) so the header stays one line.\n * Other paths are basename-only and hyperlinked.\n */\nexport function renderCollapsedSearchPath(rawPath: string | null, theme: Theme, cwd: string): string | undefined {\n\tif (rawPath === null) return invalidArgText(theme);\n\tconst value = rawPath.trim();\n\tif (!value || value === \".\" || value === \"./\") return undefined;\n\treturn renderToolFileName(value, theme, cwd);\n}\n"]}
1
+ {"version":3,"file":"render-utils.js","sourceRoot":"","sources":["../../../src/core/tools/render-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import * as os from \"node:os\";\nimport { basename } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type { ImageContent, TextContent } from \"@ashx-j/lunr-ai\";\nimport {\n\tgetCapabilities,\n\tgetImageDimensions,\n\thyperlink,\n\timageFallback,\n\tText,\n\ttruncateToWidth,\n\twrapTextWithAnsi,\n} from \"@ashx-j/lunr-tui\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { stripAnsi } from \"../../utils/ansi.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\nimport type { ToolGroupRole } from \"../extensions/types.ts\";\n\nexport function shortenPath(path: unknown): string {\n\tif (typeof path !== \"string\") return \"\";\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\treturn `~${path.slice(home.length)}`;\n\t}\n\treturn path;\n}\n\nexport function linkPath(styledText: string, rawPath: string, cwd: string): string {\n\tif (!getCapabilities().hyperlinks) return styledText;\n\tconst absolutePath = resolvePath(rawPath, cwd);\n\treturn hyperlink(styledText, pathToFileURL(absolutePath).href);\n}\n\nexport function str(value: unknown): string | null {\n\tif (typeof value === \"string\") return value;\n\tif (value == null) return \"\";\n\treturn null;\n}\n\nexport function replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport function normalizeDisplayText(text: string): string {\n\treturn text.replace(/\\r/g, \"\");\n}\n\nexport function getTextOutput(\n\tresult: { content: Array<{ type: string; text?: string; data?: string; mimeType?: string }> } | undefined,\n\tshowImages: boolean,\n): string {\n\tif (!result) return \"\";\n\n\tconst textBlocks = result.content.filter((c) => c.type === \"text\");\n\tconst imageBlocks = result.content.filter((c) => c.type === \"image\");\n\n\tlet output = textBlocks.map((c) => sanitizeBinaryOutput(stripAnsi(c.text || \"\")).replace(/\\r/g, \"\")).join(\"\\n\");\n\n\tconst caps = getCapabilities();\n\tif (imageBlocks.length > 0 && (!caps.images || !showImages)) {\n\t\tconst imageIndicators = imageBlocks\n\t\t\t.map((img) => {\n\t\t\t\tconst mimeType = img.mimeType ?? \"image/unknown\";\n\t\t\t\tconst dims =\n\t\t\t\t\timg.data && img.mimeType ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\treturn imageFallback(mimeType, dims);\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t}\n\n\treturn output;\n}\n\nexport type ToolRenderResultLike<TDetails> = {\n\tcontent: (TextContent | ImageContent)[];\n\tdetails: TDetails;\n};\n\nexport function invalidArgText(theme: Theme): string {\n\treturn theme.fg(\"error\", \"[invalid arg]\");\n}\n\n// lunr: compact-by-default — tool execute() paths append truncation/limit notices\n// as a trailing \"\\n\\n[...]\" block. Compact (header-only) results blank the body,\n// so this extracts that notice to keep it visible without the full output.\nexport function extractTrailingNotice(text: string): string | undefined {\n\tconst trimmed = text.trimEnd();\n\tif (!trimmed.endsWith(\"]\")) return undefined;\n\tconst start = trimmed.lastIndexOf(\"\\n\\n[\");\n\tif (start === -1) return undefined;\n\treturn trimmed.slice(start + 2);\n}\n\nexport type ToolStatusDotState = \"pending\" | \"success\" | \"error\";\n\nexport type { ToolGroupRole };\n\nexport function toolGroupRole(continuation: boolean, followed: boolean): ToolGroupRole {\n\tif (!continuation && followed) return \"first\";\n\tif (continuation && followed) return \"middle\";\n\tif (continuation && !followed) return \"last\";\n\treturn \"singleton\";\n}\n\n/**\n * Quieter same-name chrome: the verb is printed once, then files hang off a tree.\n *\n * ```\n * ● read\n * ├─ resolve.ts\n * └─ usage-service.ts\n * ```\n *\n * Singletons and expanded rows keep `● title detail` on one line.\n * Collapsed errors stay in the same-name tree with a red status dot; details\n * remain available on expansion. Grouped still-running cards share the same\n * tree as finished ones. `compact` is header-only body\n * hiding at the caller; pass `tree` for chrome. `isError` is accepted so\n * callers can keep passing it, but it does not drop tree chrome.\n */\nexport function toolGroupTree(context: { expanded?: boolean; isError?: boolean }): boolean {\n\treturn !context.expanded;\n}\n\ninterface GroupedCallOptions {\n\trole: ToolGroupRole;\n\tcompact?: boolean;\n\ttree?: boolean;\n\tdot: string;\n\ttitle: string;\n\tdetail?: string;\n}\n\nexport class GroupedCallText extends Text {\n\tprivate call?: GroupedCallOptions;\n\tprivate formattedWidth?: number;\n\n\tsetCall(call: GroupedCallOptions): void {\n\t\tthis.setText(formatGroupedCall(call));\n\t\tthis.call = call;\n\t}\n\n\toverride setText(text: string): void {\n\t\tthis.call = undefined;\n\t\tthis.formattedWidth = undefined;\n\t\tsuper.setText(text);\n\t}\n\n\toverride render(width: number): string[] {\n\t\tif (this.call && this.formattedWidth !== width) {\n\t\t\tsuper.setText(formatGroupedCall(this.call, width));\n\t\t\tthis.formattedWidth = width;\n\t\t}\n\t\treturn super.render(width);\n\t}\n}\n\nexport function formatGroupedCall(opts: GroupedCallOptions, width?: number): string {\n\tconst detail = opts.detail?.trim() ? opts.detail : \"\";\n\tconst useTree = (opts.tree ?? opts.compact === true) && opts.role !== \"singleton\" && detail.length > 0;\n\tif (!useTree) {\n\t\treturn detail ? `${opts.dot} ${opts.title} ${detail}` : `${opts.dot} ${opts.title}`;\n\t}\n\tconst branch = opts.role === \"last\" ? \"└─\" : \"├─\";\n\tconst prefix = ` ${branch} `;\n\tconst continuation = opts.role === \"last\" ? \" \" : \" │ \";\n\tconst leaf =\n\t\twidth === undefined\n\t\t\t? `${prefix}${detail}`\n\t\t\t: wrapTextWithAnsi(replaceTabs(detail), Math.max(1, width - prefix.length))\n\t\t\t\t\t.map((line, index) => truncateToWidth(`${index === 0 ? prefix : continuation}${line}`, width, \"\"))\n\t\t\t\t\t.join(\"\\n\");\n\tif (opts.role === \"first\") {\n\t\treturn `${opts.dot} ${opts.title}\\n${leaf}`;\n\t}\n\treturn leaf;\n}\n\n/**\n * Colored status dot used as the sole state indicator on tool titles (moon theme:\n * backgrounds stay neutral). Pending = muted, success = green, error = red.\n */\nexport function toolStatusDot(state: ToolStatusDotState, theme: Theme): string {\n\treturn theme.fg(state === \"pending\" ? \"muted\" : state, \"●\");\n}\n\n/** Derive the status dot from a render context (partial → pending, error → error, else success). */\nexport function toolStatusDotFromContext(context: { isPartial: boolean; isError: boolean }, theme: Theme): string {\n\treturn toolStatusDot(context.isPartial ? \"pending\" : context.isError ? \"error\" : \"success\", theme);\n}\n\nexport function renderToolPath(\n\trawPath: string | null,\n\ttheme: Theme,\n\tcwd: string,\n\toptions?: { emptyFallback?: string },\n): string {\n\tif (rawPath === null) return invalidArgText(theme);\n\tconst value = rawPath || options?.emptyFallback;\n\tif (!value) return theme.fg(\"toolOutput\", \"...\");\n\treturn linkPath(theme.fg(\"accent\", shortenPath(value)), value, cwd);\n}\n\n/** Basename-only path for compact tool headers. Still hyperlinked to the absolute file. */\nexport function renderToolFileName(rawPath: string | null, theme: Theme, cwd: string): string {\n\tif (rawPath === null) return invalidArgText(theme);\n\tif (!rawPath) return theme.fg(\"toolOutput\", \"...\");\n\tconst name = basename(rawPath) || rawPath;\n\treturn linkPath(theme.fg(\"accent\", name), rawPath, cwd);\n}\n\n/**\n * Collapsed grep/find path. Omits cwd (`.` / empty) so the header stays one line.\n * Other paths are basename-only and hyperlinked.\n */\nexport function renderCollapsedSearchPath(rawPath: string | null, theme: Theme, cwd: string): string | undefined {\n\tif (rawPath === null) return invalidArgText(theme);\n\tconst value = rawPath.trim();\n\tif (!value || value === \".\" || value === \"./\") return undefined;\n\treturn renderToolFileName(value, theme, cwd);\n}\n"]}