@namzu/cli 36.6.0 → 37.0.0

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 (338) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/dist/bin.js +1 -1
  3. package/dist/boot-narrative.d.ts.map +1 -1
  4. package/dist/chunks/{acp-VF7NQ6JH.js → acp-NJUDAWEV.js} +54 -49
  5. package/dist/chunks/acp-NJUDAWEV.js.map +6 -0
  6. package/dist/chunks/{activity-command-NKR6S6K6.js → activity-command-YUENOVUC.js} +13 -13
  7. package/dist/chunks/{add-26SZOQLU.js → add-3F3PRHZ5.js} +23 -24
  8. package/dist/chunks/add-3F3PRHZ5.js.map +6 -0
  9. package/dist/chunks/{agent-CHDTE6PN.js → agent-KYILQUOP.js} +26 -23
  10. package/dist/chunks/agent-session-2YMHOAKF.js +49 -0
  11. package/dist/chunks/{archive-LYS5QLIY.js → archive-VXAYIALI.js} +8 -8
  12. package/dist/chunks/{bin-main-SXTF5LOX.js → bin-main-7CCZXZ53.js} +7 -7
  13. package/dist/chunks/{browser-4VQULFC5.js → browser-LAZRYCOJ.js} +6 -6
  14. package/dist/chunks/{chat-AYQUXC4H.js → chat-RI2TEONK.js} +20 -19
  15. package/dist/chunks/{chat-AYQUXC4H.js.map → chat-RI2TEONK.js.map} +1 -1
  16. package/dist/chunks/{chunk-V6WLAAXC.js → chunk-2IWFTP44.js} +2 -2
  17. package/dist/chunks/{chunk-Z6GVIPO2.js → chunk-2K4A2MVQ.js} +4 -4
  18. package/dist/chunks/{chunk-QMDN7FIB.js → chunk-2KSXZBZK.js} +3 -2
  19. package/dist/chunks/{chunk-QMDN7FIB.js.map → chunk-2KSXZBZK.js.map} +1 -1
  20. package/dist/chunks/{chunk-MIIWBGGM.js → chunk-34CCZWJM.js} +6 -6
  21. package/dist/chunks/{chunk-7QVXN3FK.js → chunk-3M5GHYIX.js} +4 -4
  22. package/dist/chunks/{chunk-AY6EUCML.js → chunk-3RGJ3AC7.js} +2 -2
  23. package/dist/chunks/{chunk-2EUHQ3UU.js → chunk-4DDYSIB2.js} +4 -2
  24. package/dist/chunks/chunk-4DDYSIB2.js.map +6 -0
  25. package/dist/chunks/{chunk-DZEWXEUN.js → chunk-4JQ2VCTQ.js} +6 -6
  26. package/dist/chunks/{chunk-GZHWOIKT.js → chunk-5GUMVF2I.js} +2 -2
  27. package/dist/chunks/{chunk-2JVVUMXC.js → chunk-5J3T7DNL.js} +5143 -1137
  28. package/dist/chunks/chunk-5J3T7DNL.js.map +6 -0
  29. package/dist/chunks/{chunk-TC55VVWF.js → chunk-5RTONMXP.js} +11 -11
  30. package/dist/chunks/{chunk-PH72277Q.js → chunk-5Y2HRYPF.js} +2 -2
  31. package/dist/chunks/{chunk-OTG2DGSA.js → chunk-6V3D6JMG.js} +2 -2
  32. package/dist/chunks/{chunk-BUORNM3L.js → chunk-7BXRAEQU.js} +23 -18
  33. package/dist/chunks/chunk-7BXRAEQU.js.map +6 -0
  34. package/dist/chunks/{chunk-G2DJRAN7.js → chunk-AHKD4XSH.js} +3 -3
  35. package/dist/chunks/{chunk-VE322URM.js → chunk-BPGADECQ.js} +3 -3
  36. package/dist/chunks/{chunk-IKGTBMN2.js → chunk-BXJ7G5XN.js} +1059 -136
  37. package/dist/chunks/chunk-BXJ7G5XN.js.map +6 -0
  38. package/dist/chunks/{chunk-RPRM4YIC.js → chunk-DEYX6OXI.js} +3 -3
  39. package/dist/chunks/{chunk-DII3AAD5.js → chunk-DFLYRMHP.js} +2 -2
  40. package/dist/chunks/{chunk-3APO4D7I.js → chunk-EHEEEVWJ.js} +3 -3
  41. package/dist/chunks/{chunk-SMUEQ5RA.js → chunk-EIMWVYBK.js} +3 -3
  42. package/dist/chunks/{chunk-AO3RYELY.js → chunk-EV57ARS2.js} +23 -9
  43. package/dist/chunks/chunk-EV57ARS2.js.map +6 -0
  44. package/dist/chunks/{chunk-3Z24K6SK.js → chunk-I7GFMQGF.js} +2 -2
  45. package/dist/chunks/{chunk-ZU4YCZVG.js → chunk-IOGROWMG.js} +3 -3
  46. package/dist/chunks/{chunk-ZNAE3DVS.js → chunk-JAPAPPNH.js} +89 -4
  47. package/dist/chunks/{chunk-ZNAE3DVS.js.map → chunk-JAPAPPNH.js.map} +2 -2
  48. package/dist/chunks/{chunk-77VH3G4M.js → chunk-K7ADP5FF.js} +6 -6
  49. package/dist/chunks/{chunk-ODSPUOYW.js → chunk-KF7KR67Z.js} +17 -17
  50. package/dist/chunks/{chunk-BN5A2MAB.js → chunk-KXRBZ2IT.js} +80 -39
  51. package/dist/chunks/chunk-KXRBZ2IT.js.map +6 -0
  52. package/dist/chunks/{chunk-XQWG6PQN.js → chunk-LSMOWOWC.js} +39 -4
  53. package/dist/chunks/{chunk-XQWG6PQN.js.map → chunk-LSMOWOWC.js.map} +1 -1
  54. package/dist/chunks/{chunk-ODWFH233.js → chunk-MK4U26GZ.js} +2 -2
  55. package/dist/chunks/{chunk-X6SYXGAY.js → chunk-MR34S4AM.js} +4 -4
  56. package/dist/chunks/{chunk-4WM5CKTI.js → chunk-NADDUQSP.js} +182 -18
  57. package/dist/chunks/chunk-NADDUQSP.js.map +6 -0
  58. package/dist/chunks/{chunk-QQFWOGD2.js → chunk-NQGVXNXO.js} +6 -6
  59. package/dist/chunks/{chunk-WFAZLQ5N.js → chunk-O3XQA4ZZ.js} +4 -4
  60. package/dist/chunks/{chunk-5X6ADRCM.js → chunk-OEI64DLJ.js} +2 -2
  61. package/dist/chunks/{chunk-LFHTKWQ5.js → chunk-PGPL6KIS.js} +3 -3
  62. package/dist/chunks/{chunk-5SVMKOEG.js → chunk-PSZ6GS75.js} +2 -2
  63. package/dist/chunks/{chunk-EOPRQEHH.js → chunk-PXLJT6YH.js} +13 -13
  64. package/dist/chunks/{chunk-HO4QVXVW.js → chunk-QEWQONLW.js} +2 -2
  65. package/dist/chunks/{chunk-GGCPLAQF.js → chunk-QXSIBEFU.js} +3 -3
  66. package/dist/chunks/{chunk-YUIZ3I52.js → chunk-SDHJ2YUN.js} +7 -3
  67. package/dist/chunks/chunk-SDHJ2YUN.js.map +6 -0
  68. package/dist/chunks/{chunk-TUN5WPEN.js → chunk-SJW2UYTK.js} +2 -2
  69. package/dist/chunks/{chunk-2NUNK4JI.js → chunk-STHNLNY5.js} +4 -4
  70. package/dist/chunks/{chunk-6XVYUSCD.js → chunk-T5D5HHTY.js} +24 -16
  71. package/dist/chunks/{chunk-6XVYUSCD.js.map → chunk-T5D5HHTY.js.map} +1 -1
  72. package/dist/chunks/{chunk-2LBM3V3N.js → chunk-TCXO5WZX.js} +2 -2
  73. package/dist/chunks/{chunk-P7NKAQ6I.js → chunk-UMVFXQYE.js} +4 -4
  74. package/dist/chunks/{chunk-MMCTEOXA.js → chunk-UY74BJBW.js} +2 -2
  75. package/dist/chunks/{chunk-UVAY5ESO.js → chunk-VA63RY7U.js} +4 -4
  76. package/dist/chunks/{chunk-VU7JHAR6.js → chunk-VHEMDWNA.js} +19 -18
  77. package/dist/chunks/{chunk-VU7JHAR6.js.map → chunk-VHEMDWNA.js.map} +1 -1
  78. package/dist/chunks/chunk-VNGFBD26.js +108 -0
  79. package/dist/chunks/chunk-VNGFBD26.js.map +6 -0
  80. package/dist/chunks/{chunk-BVJQ5NVZ.js → chunk-W5PML5BG.js} +2 -2
  81. package/dist/chunks/{chunk-PQOGAHD5.js → chunk-XAFTUVN7.js} +5 -5
  82. package/dist/chunks/{chunk-KWYQCOJA.js → chunk-YJVLERBF.js} +2 -2
  83. package/dist/chunks/{chunk-GKEBBQ3Z.js → chunk-YQHHGBOR.js} +5 -3
  84. package/dist/chunks/chunk-YQHHGBOR.js.map +6 -0
  85. package/dist/chunks/{cli-runtime-TQIXSGNJ.js → cli-runtime-KH73NP4C.js} +15 -11
  86. package/dist/chunks/cli-runtime-KH73NP4C.js.map +6 -0
  87. package/dist/chunks/{commands-YCYR4OO7.js → commands-IMV24FMR.js} +5 -5
  88. package/dist/chunks/{crash-report-3STEQBVJ.js → crash-report-VQBUHKGL.js} +6 -6
  89. package/dist/chunks/{dist-H4O3BALK.js → dist-7Y7RRIE5.js} +2 -2
  90. package/dist/chunks/{dist-ITGC4C5H.js → dist-CQLUZMPF.js} +2 -2
  91. package/dist/chunks/{dist-Z33PLHVL.js → dist-E6HO2DY4.js} +2 -2
  92. package/dist/chunks/{dist-FDUMWWP6.js → dist-EZYJPZFW.js} +2 -2
  93. package/dist/chunks/{dist-G2ZZ3OAU.js → dist-LNY6YOW7.js} +2 -2
  94. package/dist/chunks/{dist-XJYPRLMT.js → dist-WAEUJUZL.js} +2 -2
  95. package/dist/chunks/{dist-LCPSN2KU.js → dist-ZNBV3COW.js} +2 -2
  96. package/dist/chunks/{doctor-YCV7KO72.js → doctor-DEG3FKDC.js} +7 -7
  97. package/dist/chunks/{drain-B6NE7ECX.js → drain-NPWQOBUJ.js} +21 -16
  98. package/dist/chunks/drain-NPWQOBUJ.js.map +6 -0
  99. package/dist/chunks/{eval-HKVQPXKR.js → eval-GI6JQAOX.js} +2 -2
  100. package/dist/chunks/{exec-MOJSMH4D.js → exec-RP67LSL5.js} +57 -105
  101. package/dist/chunks/exec-RP67LSL5.js.map +6 -0
  102. package/dist/chunks/{home-XWVKZPVH.js → home-7EKRNFWG.js} +3 -3
  103. package/dist/chunks/{host-queries-FZZJCBO7.js → host-queries-YN42AIUD.js} +17 -17
  104. package/dist/chunks/{lifecycle-4R4ZRWRI.js → lifecycle-T7GDJRCI.js} +28 -29
  105. package/dist/chunks/{list-7V5HNSRV.js → list-FQZJ3GDF.js} +21 -22
  106. package/dist/chunks/list-FQZJ3GDF.js.map +6 -0
  107. package/dist/chunks/{login-MSFPVB2R.js → login-NO23T6HC.js} +9 -9
  108. package/dist/chunks/{logs-EGCWVNBU.js → logs-LJVTOGXE.js} +4 -4
  109. package/dist/chunks/{mcp-DWCVUDXK.js → mcp-NBWL73J5.js} +23 -22
  110. package/dist/chunks/mcp-NBWL73J5.js.map +6 -0
  111. package/dist/chunks/{message-command-K3GFQCZU.js → message-command-YIURBF2Q.js} +40 -39
  112. package/dist/chunks/message-command-YIURBF2Q.js.map +6 -0
  113. package/dist/chunks/{operator-tools-JRMP2OHZ.js → operator-tools-MQXMUQLG.js} +12 -12
  114. package/dist/chunks/{output-schema-XVJ3XUMN.js → output-schema-2BCRDYWG.js} +3 -3
  115. package/dist/chunks/{pal-Y5K4PJF7.js → pal-PTOFIOCI.js} +14 -14
  116. package/dist/chunks/{providers-MNU4KDEW.js → providers-YRNXCZW5.js} +6 -6
  117. package/dist/chunks/{resident-BI4VV6F4.js → resident-QI33LA6J.js} +29 -28
  118. package/dist/chunks/resident-QI33LA6J.js.map +6 -0
  119. package/dist/chunks/resume-3R5VLEIS.js +21 -0
  120. package/dist/chunks/{resume-command-XBFDMRUK.js → resume-command-7SGSPKXV.js} +4 -4
  121. package/dist/chunks/{schedule-XEU5OSKW.js → schedule-YOMKA5IF.js} +8 -8
  122. package/dist/chunks/{service-YOZ6GUL5.js → service-A4YKUMRI.js} +37 -38
  123. package/dist/chunks/service-A4YKUMRI.js.map +6 -0
  124. package/dist/chunks/session-step-N5EWWZ4K.js +26 -0
  125. package/dist/chunks/{skills-ZKC4GGY6.js → skills-BARULYB3.js} +11 -11
  126. package/dist/chunks/{state-RV3YXV6V.js → state-ZD6WF2PZ.js} +2 -2
  127. package/dist/chunks/{store-7X5FJMKH.js → store-HEOMPNER.js} +4 -4
  128. package/dist/chunks/{store-PJQ65VLY.js → store-RD7EX5RD.js} +12 -8
  129. package/dist/chunks/{store-QLMY3B43.js → store-YWZ6SY2M.js} +6 -6
  130. package/dist/chunks/store-YWZ6SY2M.js.map +6 -0
  131. package/dist/chunks/{tui-FZJ37KG2.js → tui-JLOFXK7O.js} +2324 -827
  132. package/dist/chunks/tui-JLOFXK7O.js.map +6 -0
  133. package/dist/chunks/turndown.cjs-2NVZBL7F.js +17615 -0
  134. package/dist/chunks/turndown.cjs-2NVZBL7F.js.map +6 -0
  135. package/dist/chunks/{upgrade-KJRSVGA3.js → upgrade-FLMI5ZYW.js} +2 -2
  136. package/dist/chunks/{worktree-JLK5Z6DS.js → worktree-GUWRR5KY.js} +10 -10
  137. package/dist/cli-runtime.d.ts +1 -1
  138. package/dist/cli-runtime.d.ts.map +1 -1
  139. package/dist/cli.d.ts.map +1 -1
  140. package/dist/commands/acp.d.ts.map +1 -1
  141. package/dist/commands/desktop-host.d.ts.map +1 -1
  142. package/dist/commands/drain.d.ts.map +1 -1
  143. package/dist/commands/exec-json.d.ts.map +1 -1
  144. package/dist/commands/exec.d.ts.map +1 -1
  145. package/dist/commands/resume.d.ts +31 -0
  146. package/dist/commands/resume.d.ts.map +1 -1
  147. package/dist/config/debug.d.ts.map +1 -1
  148. package/dist/config/load.d.ts +21 -6
  149. package/dist/config/load.d.ts.map +1 -1
  150. package/dist/config/schema.d.ts +48 -4
  151. package/dist/config/schema.d.ts.map +1 -1
  152. package/dist/context/doctrine.d.ts +9 -0
  153. package/dist/context/doctrine.d.ts.map +1 -1
  154. package/dist/context/runtime-message.d.ts.map +1 -1
  155. package/dist/index.d.ts +1 -1
  156. package/dist/index.d.ts.map +1 -1
  157. package/dist/index.js +16 -15
  158. package/dist/integrations/notifications/idle.d.ts +48 -0
  159. package/dist/integrations/notifications/idle.d.ts.map +1 -0
  160. package/dist/integrations/notifications/terminal.d.ts +4 -0
  161. package/dist/integrations/notifications/terminal.d.ts.map +1 -1
  162. package/dist/integrations/resident/runner-worker.js +24 -24
  163. package/dist/integrations/resident/session-step.d.ts.map +1 -1
  164. package/dist/integrations/sessions/ai-title.d.ts +45 -0
  165. package/dist/integrations/sessions/ai-title.d.ts.map +1 -0
  166. package/dist/integrations/sessions/store.d.ts +16 -0
  167. package/dist/integrations/sessions/store.d.ts.map +1 -1
  168. package/dist/integrations/small-model/route.d.ts +44 -0
  169. package/dist/integrations/small-model/route.d.ts.map +1 -0
  170. package/dist/integrations/small-model/side-model.d.ts +89 -0
  171. package/dist/integrations/small-model/side-model.d.ts.map +1 -0
  172. package/dist/integrations/subagents/runtime.d.ts +6 -0
  173. package/dist/integrations/subagents/runtime.d.ts.map +1 -1
  174. package/dist/pals/chat.d.ts.map +1 -1
  175. package/dist/pals/review.d.ts.map +1 -1
  176. package/dist/permissions/local-settings.d.ts +57 -0
  177. package/dist/permissions/local-settings.d.ts.map +1 -0
  178. package/dist/permissions/rules.d.ts +32 -0
  179. package/dist/permissions/rules.d.ts.map +1 -1
  180. package/dist/permissions/session-allow.d.ts +71 -17
  181. package/dist/permissions/session-allow.d.ts.map +1 -1
  182. package/dist/plan/approval.d.ts +43 -0
  183. package/dist/plan/approval.d.ts.map +1 -0
  184. package/dist/plan/exit-plan-mode-tool.d.ts +24 -0
  185. package/dist/plan/exit-plan-mode-tool.d.ts.map +1 -0
  186. package/dist/plan/plan-file.d.ts +10 -0
  187. package/dist/plan/plan-file.d.ts.map +1 -0
  188. package/dist/reminders/frame.d.ts +20 -0
  189. package/dist/reminders/frame.d.ts.map +1 -0
  190. package/dist/reminders/index.d.ts +24 -0
  191. package/dist/reminders/index.d.ts.map +1 -0
  192. package/dist/reminders/plan-mode.d.ts +25 -0
  193. package/dist/reminders/plan-mode.d.ts.map +1 -0
  194. package/dist/reminders/task-nudge.d.ts +18 -0
  195. package/dist/reminders/task-nudge.d.ts.map +1 -0
  196. package/dist/schedule/fire/fire.d.ts.map +1 -1
  197. package/dist/tui/App.d.ts.map +1 -1
  198. package/dist/tui/Composer.d.ts.map +1 -1
  199. package/dist/tui/LiveActivity.d.ts.map +1 -1
  200. package/dist/tui/PermissionOverlay.d.ts +5 -1
  201. package/dist/tui/PermissionOverlay.d.ts.map +1 -1
  202. package/dist/tui/PlanApprovalOverlay.d.ts +32 -0
  203. package/dist/tui/PlanApprovalOverlay.d.ts.map +1 -0
  204. package/dist/tui/QuestionDialog.d.ts +22 -0
  205. package/dist/tui/QuestionDialog.d.ts.map +1 -0
  206. package/dist/tui/StatusBar.d.ts +16 -3
  207. package/dist/tui/StatusBar.d.ts.map +1 -1
  208. package/dist/tui/agent.d.ts +72 -8
  209. package/dist/tui/agent.d.ts.map +1 -1
  210. package/dist/tui/context-meter.d.ts +33 -0
  211. package/dist/tui/context-meter.d.ts.map +1 -0
  212. package/dist/tui/mentions.d.ts +9 -1
  213. package/dist/tui/mentions.d.ts.map +1 -1
  214. package/dist/tui/plain-interruption.d.ts +7 -4
  215. package/dist/tui/plain-interruption.d.ts.map +1 -1
  216. package/dist/tui/question-dialog.d.ts +34 -0
  217. package/dist/tui/question-dialog.d.ts.map +1 -0
  218. package/dist/tui/slashCommands.d.ts +4 -3
  219. package/dist/tui/slashCommands.d.ts.map +1 -1
  220. package/dist/tui/status-line/StatusLineRows.d.ts +11 -0
  221. package/dist/tui/status-line/StatusLineRows.d.ts.map +1 -0
  222. package/dist/tui/status-line/controller.d.ts +55 -0
  223. package/dist/tui/status-line/controller.d.ts.map +1 -0
  224. package/dist/tui/status-line/output.d.ts +18 -0
  225. package/dist/tui/status-line/output.d.ts.map +1 -0
  226. package/dist/tui/status-line/payload.d.ts +43 -0
  227. package/dist/tui/status-line/payload.d.ts.map +1 -0
  228. package/dist/tui/status-line/run-command.d.ts +24 -0
  229. package/dist/tui/status-line/run-command.d.ts.map +1 -0
  230. package/dist/tui/status-line/useStatusLine.d.ts +22 -0
  231. package/dist/tui/status-line/useStatusLine.d.ts.map +1 -0
  232. package/dist/tui/status-line/workspace-git.d.ts +17 -0
  233. package/dist/tui/status-line/workspace-git.d.ts.map +1 -0
  234. package/dist/tui/terminal-title.d.ts +33 -0
  235. package/dist/tui/terminal-title.d.ts.map +1 -0
  236. package/dist/tui/turn-interruption.d.ts.map +1 -1
  237. package/dist/tui/types.d.ts +12 -1
  238. package/dist/tui/types.d.ts.map +1 -1
  239. package/package.json +3 -3
  240. package/dist/chunks/acp-VF7NQ6JH.js.map +0 -6
  241. package/dist/chunks/add-26SZOQLU.js.map +0 -6
  242. package/dist/chunks/agent-session-F5XU36CE.js +0 -46
  243. package/dist/chunks/chunk-2EUHQ3UU.js.map +0 -6
  244. package/dist/chunks/chunk-2JVVUMXC.js.map +0 -6
  245. package/dist/chunks/chunk-4WM5CKTI.js.map +0 -6
  246. package/dist/chunks/chunk-AO3RYELY.js.map +0 -6
  247. package/dist/chunks/chunk-BN5A2MAB.js.map +0 -6
  248. package/dist/chunks/chunk-BUORNM3L.js.map +0 -6
  249. package/dist/chunks/chunk-GKEBBQ3Z.js.map +0 -6
  250. package/dist/chunks/chunk-IKGTBMN2.js.map +0 -6
  251. package/dist/chunks/chunk-UFPOA63T.js +0 -71
  252. package/dist/chunks/chunk-UFPOA63T.js.map +0 -6
  253. package/dist/chunks/chunk-YUIZ3I52.js.map +0 -6
  254. package/dist/chunks/cli-runtime-TQIXSGNJ.js.map +0 -6
  255. package/dist/chunks/drain-B6NE7ECX.js.map +0 -6
  256. package/dist/chunks/exec-MOJSMH4D.js.map +0 -6
  257. package/dist/chunks/list-7V5HNSRV.js.map +0 -6
  258. package/dist/chunks/mcp-DWCVUDXK.js.map +0 -6
  259. package/dist/chunks/message-command-K3GFQCZU.js.map +0 -6
  260. package/dist/chunks/resident-BI4VV6F4.js.map +0 -6
  261. package/dist/chunks/service-YOZ6GUL5.js.map +0 -6
  262. package/dist/chunks/session-step-RLSIZ3S2.js +0 -26
  263. package/dist/chunks/tui-FZJ37KG2.js.map +0 -6
  264. /package/dist/chunks/{activity-command-NKR6S6K6.js.map → activity-command-YUENOVUC.js.map} +0 -0
  265. /package/dist/chunks/{agent-CHDTE6PN.js.map → agent-KYILQUOP.js.map} +0 -0
  266. /package/dist/chunks/{agent-session-F5XU36CE.js.map → agent-session-2YMHOAKF.js.map} +0 -0
  267. /package/dist/chunks/{archive-LYS5QLIY.js.map → archive-VXAYIALI.js.map} +0 -0
  268. /package/dist/chunks/{bin-main-SXTF5LOX.js.map → bin-main-7CCZXZ53.js.map} +0 -0
  269. /package/dist/chunks/{browser-4VQULFC5.js.map → browser-LAZRYCOJ.js.map} +0 -0
  270. /package/dist/chunks/{chunk-V6WLAAXC.js.map → chunk-2IWFTP44.js.map} +0 -0
  271. /package/dist/chunks/{chunk-Z6GVIPO2.js.map → chunk-2K4A2MVQ.js.map} +0 -0
  272. /package/dist/chunks/{chunk-MIIWBGGM.js.map → chunk-34CCZWJM.js.map} +0 -0
  273. /package/dist/chunks/{chunk-7QVXN3FK.js.map → chunk-3M5GHYIX.js.map} +0 -0
  274. /package/dist/chunks/{chunk-AY6EUCML.js.map → chunk-3RGJ3AC7.js.map} +0 -0
  275. /package/dist/chunks/{chunk-DZEWXEUN.js.map → chunk-4JQ2VCTQ.js.map} +0 -0
  276. /package/dist/chunks/{chunk-GZHWOIKT.js.map → chunk-5GUMVF2I.js.map} +0 -0
  277. /package/dist/chunks/{chunk-TC55VVWF.js.map → chunk-5RTONMXP.js.map} +0 -0
  278. /package/dist/chunks/{chunk-PH72277Q.js.map → chunk-5Y2HRYPF.js.map} +0 -0
  279. /package/dist/chunks/{chunk-OTG2DGSA.js.map → chunk-6V3D6JMG.js.map} +0 -0
  280. /package/dist/chunks/{chunk-G2DJRAN7.js.map → chunk-AHKD4XSH.js.map} +0 -0
  281. /package/dist/chunks/{chunk-VE322URM.js.map → chunk-BPGADECQ.js.map} +0 -0
  282. /package/dist/chunks/{chunk-RPRM4YIC.js.map → chunk-DEYX6OXI.js.map} +0 -0
  283. /package/dist/chunks/{chunk-DII3AAD5.js.map → chunk-DFLYRMHP.js.map} +0 -0
  284. /package/dist/chunks/{chunk-3APO4D7I.js.map → chunk-EHEEEVWJ.js.map} +0 -0
  285. /package/dist/chunks/{chunk-SMUEQ5RA.js.map → chunk-EIMWVYBK.js.map} +0 -0
  286. /package/dist/chunks/{chunk-3Z24K6SK.js.map → chunk-I7GFMQGF.js.map} +0 -0
  287. /package/dist/chunks/{chunk-ZU4YCZVG.js.map → chunk-IOGROWMG.js.map} +0 -0
  288. /package/dist/chunks/{chunk-77VH3G4M.js.map → chunk-K7ADP5FF.js.map} +0 -0
  289. /package/dist/chunks/{chunk-ODSPUOYW.js.map → chunk-KF7KR67Z.js.map} +0 -0
  290. /package/dist/chunks/{chunk-ODWFH233.js.map → chunk-MK4U26GZ.js.map} +0 -0
  291. /package/dist/chunks/{chunk-X6SYXGAY.js.map → chunk-MR34S4AM.js.map} +0 -0
  292. /package/dist/chunks/{chunk-QQFWOGD2.js.map → chunk-NQGVXNXO.js.map} +0 -0
  293. /package/dist/chunks/{chunk-WFAZLQ5N.js.map → chunk-O3XQA4ZZ.js.map} +0 -0
  294. /package/dist/chunks/{chunk-5X6ADRCM.js.map → chunk-OEI64DLJ.js.map} +0 -0
  295. /package/dist/chunks/{chunk-LFHTKWQ5.js.map → chunk-PGPL6KIS.js.map} +0 -0
  296. /package/dist/chunks/{chunk-5SVMKOEG.js.map → chunk-PSZ6GS75.js.map} +0 -0
  297. /package/dist/chunks/{chunk-EOPRQEHH.js.map → chunk-PXLJT6YH.js.map} +0 -0
  298. /package/dist/chunks/{chunk-HO4QVXVW.js.map → chunk-QEWQONLW.js.map} +0 -0
  299. /package/dist/chunks/{chunk-GGCPLAQF.js.map → chunk-QXSIBEFU.js.map} +0 -0
  300. /package/dist/chunks/{chunk-TUN5WPEN.js.map → chunk-SJW2UYTK.js.map} +0 -0
  301. /package/dist/chunks/{chunk-2NUNK4JI.js.map → chunk-STHNLNY5.js.map} +0 -0
  302. /package/dist/chunks/{chunk-2LBM3V3N.js.map → chunk-TCXO5WZX.js.map} +0 -0
  303. /package/dist/chunks/{chunk-P7NKAQ6I.js.map → chunk-UMVFXQYE.js.map} +0 -0
  304. /package/dist/chunks/{chunk-MMCTEOXA.js.map → chunk-UY74BJBW.js.map} +0 -0
  305. /package/dist/chunks/{chunk-UVAY5ESO.js.map → chunk-VA63RY7U.js.map} +0 -0
  306. /package/dist/chunks/{chunk-BVJQ5NVZ.js.map → chunk-W5PML5BG.js.map} +0 -0
  307. /package/dist/chunks/{chunk-PQOGAHD5.js.map → chunk-XAFTUVN7.js.map} +0 -0
  308. /package/dist/chunks/{chunk-KWYQCOJA.js.map → chunk-YJVLERBF.js.map} +0 -0
  309. /package/dist/chunks/{commands-YCYR4OO7.js.map → commands-IMV24FMR.js.map} +0 -0
  310. /package/dist/chunks/{crash-report-3STEQBVJ.js.map → crash-report-VQBUHKGL.js.map} +0 -0
  311. /package/dist/chunks/{dist-H4O3BALK.js.map → dist-7Y7RRIE5.js.map} +0 -0
  312. /package/dist/chunks/{dist-ITGC4C5H.js.map → dist-CQLUZMPF.js.map} +0 -0
  313. /package/dist/chunks/{dist-Z33PLHVL.js.map → dist-E6HO2DY4.js.map} +0 -0
  314. /package/dist/chunks/{dist-FDUMWWP6.js.map → dist-EZYJPZFW.js.map} +0 -0
  315. /package/dist/chunks/{dist-G2ZZ3OAU.js.map → dist-LNY6YOW7.js.map} +0 -0
  316. /package/dist/chunks/{dist-XJYPRLMT.js.map → dist-WAEUJUZL.js.map} +0 -0
  317. /package/dist/chunks/{dist-LCPSN2KU.js.map → dist-ZNBV3COW.js.map} +0 -0
  318. /package/dist/chunks/{doctor-YCV7KO72.js.map → doctor-DEG3FKDC.js.map} +0 -0
  319. /package/dist/chunks/{eval-HKVQPXKR.js.map → eval-GI6JQAOX.js.map} +0 -0
  320. /package/dist/chunks/{home-XWVKZPVH.js.map → home-7EKRNFWG.js.map} +0 -0
  321. /package/dist/chunks/{host-queries-FZZJCBO7.js.map → host-queries-YN42AIUD.js.map} +0 -0
  322. /package/dist/chunks/{lifecycle-4R4ZRWRI.js.map → lifecycle-T7GDJRCI.js.map} +0 -0
  323. /package/dist/chunks/{login-MSFPVB2R.js.map → login-NO23T6HC.js.map} +0 -0
  324. /package/dist/chunks/{logs-EGCWVNBU.js.map → logs-LJVTOGXE.js.map} +0 -0
  325. /package/dist/chunks/{operator-tools-JRMP2OHZ.js.map → operator-tools-MQXMUQLG.js.map} +0 -0
  326. /package/dist/chunks/{output-schema-XVJ3XUMN.js.map → output-schema-2BCRDYWG.js.map} +0 -0
  327. /package/dist/chunks/{pal-Y5K4PJF7.js.map → pal-PTOFIOCI.js.map} +0 -0
  328. /package/dist/chunks/{providers-MNU4KDEW.js.map → providers-YRNXCZW5.js.map} +0 -0
  329. /package/dist/chunks/{resume-command-XBFDMRUK.js.map → resume-3R5VLEIS.js.map} +0 -0
  330. /package/dist/chunks/{session-step-RLSIZ3S2.js.map → resume-command-7SGSPKXV.js.map} +0 -0
  331. /package/dist/chunks/{schedule-XEU5OSKW.js.map → schedule-YOMKA5IF.js.map} +0 -0
  332. /package/dist/chunks/{store-7X5FJMKH.js.map → session-step-N5EWWZ4K.js.map} +0 -0
  333. /package/dist/chunks/{skills-ZKC4GGY6.js.map → skills-BARULYB3.js.map} +0 -0
  334. /package/dist/chunks/{state-RV3YXV6V.js.map → state-ZD6WF2PZ.js.map} +0 -0
  335. /package/dist/chunks/{store-PJQ65VLY.js.map → store-HEOMPNER.js.map} +0 -0
  336. /package/dist/chunks/{store-QLMY3B43.js.map → store-RD7EX5RD.js.map} +0 -0
  337. /package/dist/chunks/{upgrade-KJRSVGA3.js.map → upgrade-FLMI5ZYW.js.map} +0 -0
  338. /package/dist/chunks/{worktree-JLK5Z6DS.js.map → worktree-GUWRR5KY.js.map} +0 -0
@@ -2,16 +2,19 @@ import { createRequire as __namzuCreateRequire } from 'node:module';
2
2
  const require = __namzuCreateRequire(import.meta.url);
3
3
  import {
4
4
  openManagedWorktrees
5
- } from "./chunk-DZEWXEUN.js";
5
+ } from "./chunk-4JQ2VCTQ.js";
6
6
  import {
7
7
  createBrowserControl
8
8
  } from "./chunk-WHODOMXA.js";
9
9
  import {
10
10
  connectMcpServers
11
- } from "./chunk-Z6GVIPO2.js";
11
+ } from "./chunk-2K4A2MVQ.js";
12
+ import {
13
+ openInBrowser
14
+ } from "./chunk-2IWFTP44.js";
12
15
  import {
13
16
  createSessionSkillCatalog
14
- } from "./chunk-VE322URM.js";
17
+ } from "./chunk-BPGADECQ.js";
15
18
  import {
16
19
  SAVE_SKILL_TOOL_NAME,
17
20
  WORKFLOW_TOOL_DESCRIPTION,
@@ -27,10 +30,7 @@ import {
27
30
  viewFromJournal,
28
31
  workflowOffered,
29
32
  workflowRefusal
30
- } from "./chunk-LFHTKWQ5.js";
31
- import {
32
- openInBrowser
33
- } from "./chunk-V6WLAAXC.js";
33
+ } from "./chunk-PGPL6KIS.js";
34
34
  import {
35
35
  CredentialRefreshRejectedError,
36
36
  CredentialWithdrawnError,
@@ -38,15 +38,16 @@ import {
38
38
  ensureFreshStoredCodexCredential,
39
39
  readSubscriptionCredential,
40
40
  sameOAuthCredential
41
- } from "./chunk-P7NKAQ6I.js";
41
+ } from "./chunk-UMVFXQYE.js";
42
42
  import {
43
43
  debugRequested
44
44
  } from "./chunk-GNBMKISG.js";
45
45
  import {
46
+ LOCAL_CONFIG_FILE,
46
47
  configuredPassthroughTools,
47
48
  resolveToolResultScreens,
48
49
  unmatchedPassthroughTools
49
- } from "./chunk-UFPOA63T.js";
50
+ } from "./chunk-NADDUQSP.js";
50
51
  import {
51
52
  formatSize,
52
53
  homePath,
@@ -74,30 +75,20 @@ import {
74
75
  requiresCredentialForModel,
75
76
  resolveChainCapabilities,
76
77
  unresolvedMembers
77
- } from "./chunk-EOPRQEHH.js";
78
+ } from "./chunk-PXLJT6YH.js";
78
79
  import {
79
80
  PROVIDER_REGISTRY,
80
81
  missingCredentialMessage,
81
82
  unsupportedProviderMessage
82
83
  } from "./chunk-6LLJQ3KY.js";
83
- import {
84
- cliLogger
85
- } from "./chunk-TUN5WPEN.js";
86
84
  import {
87
85
  isPermissionMode,
88
86
  permissionModeLabel
89
- } from "./chunk-OTG2DGSA.js";
90
- import {
91
- probeCapabilities
92
- } from "./chunk-OH6TB27S.js";
93
- import {
94
- activeZenCatalogue,
95
- isOfferableModel
96
- } from "./chunk-U3JIZFOS.js";
87
+ } from "./chunk-6V3D6JMG.js";
97
88
  import {
98
89
  conversationLogPath,
99
90
  ensureSessionStarted
100
- } from "./chunk-XQWG6PQN.js";
91
+ } from "./chunk-LSMOWOWC.js";
101
92
  import {
102
93
  INSTRUCTIONS_FILENAME,
103
94
  MAX_CHARS_PER_FILE,
@@ -107,16 +98,31 @@ import {
107
98
  } from "./chunk-H6B6AROX.js";
108
99
  import {
109
100
  ensurePrivateStateDirectory
110
- } from "./chunk-GZHWOIKT.js";
101
+ } from "./chunk-5GUMVF2I.js";
102
+ import {
103
+ compilePermissions,
104
+ isPermissionEffect
105
+ } from "./chunk-JAPAPPNH.js";
106
+ import {
107
+ cliLogger
108
+ } from "./chunk-SJW2UYTK.js";
109
+ import {
110
+ probeCapabilities
111
+ } from "./chunk-OH6TB27S.js";
112
+ import {
113
+ activeZenCatalogue,
114
+ isOfferableModel
115
+ } from "./chunk-U3JIZFOS.js";
111
116
  import {
112
117
  restrictToOwner
113
- } from "./chunk-AY6EUCML.js";
118
+ } from "./chunk-3RGJ3AC7.js";
114
119
  import {
115
120
  namzuHomePath
116
- } from "./chunk-PH72277Q.js";
121
+ } from "./chunk-5Y2HRYPF.js";
117
122
  import {
118
123
  AgentManager,
119
124
  AgentRegistry,
125
+ AuthorizationGate,
120
126
  BOOT_EVENT_NAMES,
121
127
  BackgroundJobRegistry,
122
128
  CODING_AGENT_DELEGATION_DOCTRINE,
@@ -148,6 +154,7 @@ import {
148
154
  MarkdownMemoryStore,
149
155
  MemoryContentRejectedError,
150
156
  MemoryNameConflictError,
157
+ NOOP_LOGGER,
151
158
  PLAN_MODE_DOCTRINE,
152
159
  PluginLifecycleManager,
153
160
  PluginRegistry,
@@ -221,6 +228,7 @@ import {
221
228
  isCompactionMessage,
222
229
  isEntityId,
223
230
  isProjectInstructionMessageSource,
231
+ isReminderMessage,
224
232
  isReviewExempt,
225
233
  isTerminalAgentTaskState,
226
234
  isTerminalStatus,
@@ -228,6 +236,7 @@ import {
228
236
  isTrustedReadOnly,
229
237
  isTurnInProgressError,
230
238
  isolationOf,
239
+ lexShellCommandLine,
231
240
  mapTools,
232
241
  mcpJsonSchemaToZod,
233
242
  openSessionTokenBudget,
@@ -238,6 +247,7 @@ import {
238
247
  refineEvidenceRecallTerms,
239
248
  requireOpenProject,
240
249
  resolveContextWindow,
250
+ resolveModelPricing,
241
251
  resolveNamzuHome,
242
252
  resolveWithinReal,
243
253
  resumeSession,
@@ -252,7 +262,7 @@ import {
252
262
  windowsShellNotice,
253
263
  withProviderFallback,
254
264
  wrapUntrusted
255
- } from "./chunk-2JVVUMXC.js";
265
+ } from "./chunk-5J3T7DNL.js";
256
266
  import {
257
267
  __name
258
268
  } from "./chunk-76FLAFCG.js";
@@ -367,10 +377,10 @@ var tail = Promise.resolve();
367
377
  var nextStart = 0;
368
378
  function cancelled(promise, signal) {
369
379
  signal.throwIfAborted();
370
- return new Promise((resolve9, reject) => {
380
+ return new Promise((resolve11, reject) => {
371
381
  const abort = /* @__PURE__ */ __name(() => reject(signal.reason), "abort");
372
382
  signal.addEventListener("abort", abort, { once: true });
373
- promise.then(resolve9, reject).finally(() => signal.removeEventListener("abort", abort));
383
+ promise.then(resolve11, reject).finally(() => signal.removeEventListener("abort", abort));
374
384
  });
375
385
  }
376
386
  __name(cancelled, "cancelled");
@@ -411,8 +421,8 @@ async function searchExa(query2, limit, context) {
411
421
  const deadline = Date.now() + DEADLINE_MS;
412
422
  const previous = tail;
413
423
  let release;
414
- tail = new Promise((resolve9) => {
415
- release = resolve9;
424
+ tail = new Promise((resolve11) => {
425
+ release = resolve11;
416
426
  });
417
427
  let acquired = false;
418
428
  try {
@@ -929,7 +939,7 @@ __name(oneLine, "oneLine");
929
939
  // src/tui/agent.ts
930
940
  import { SubprocessComputerUseHost } from "@namzu/computer-use";
931
941
  import { realpath as realpath4, stat as stat4 } from "node:fs/promises";
932
- import { join as join13, parse, resolve as resolve8 } from "node:path";
942
+ import { join as join14, parse, resolve as resolve10 } from "node:path";
933
943
 
934
944
  // src/checkpoints/store.ts
935
945
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -2334,6 +2344,11 @@ function createSessionDirectories(cwd, directories) {
2334
2344
  }
2335
2345
  __name(createSessionDirectories, "createSessionDirectories");
2336
2346
 
2347
+ // src/context/doctrine.ts
2348
+ var NAMZU_PLAN_FILE_DOCTRINE = `## Plan mode
2349
+
2350
+ You are in plan mode. Read, search and think; the only file you may change is the plan file named in the plan-mode reminder. Any other \`edit\`, \`write\` or shell command that changes state will be refused. Write the plan into the plan file, then call \`exit_plan_mode\` so the user can approve it; do not ask for approval in plain text. If the user sends you back with feedback, revise the plan file and call it again.`;
2351
+
2337
2352
  // src/context/project-tracker.ts
2338
2353
  import { realpathSync } from "node:fs";
2339
2354
  import { dirname as dirname2, isAbsolute as isAbsolute3, join as join3, relative as relative3, resolve as resolve3, sep as sep2 } from "node:path";
@@ -3943,7 +3958,7 @@ async function searchConversationCore(sessions, sessionId, request, signal, acti
3943
3958
  result.excludedToolResults = (result.excludedToolResults ?? 0) + page.excludedToolResults;
3944
3959
  if (page.excludedSummaries)
3945
3960
  result.excludedSummaries = (result.excludedSummaries ?? 0) + page.excludedSummaries;
3946
- const matches2 = page.matches.map(
3961
+ const matches = page.matches.map(
3947
3962
  (match) => ({
3948
3963
  seq: match.seq,
3949
3964
  recordedAt: match.recordedAt,
@@ -3958,11 +3973,11 @@ async function searchConversationCore(sessions, sessionId, request, signal, acti
3958
3973
  ...match.characterOffset === void 0 ? {} : { byteOffset: match.byteOffset }
3959
3974
  })
3960
3975
  );
3961
- const bytes = Buffer.byteLength(JSON.stringify(matches2));
3976
+ const bytes = Buffer.byteLength(JSON.stringify(matches));
3962
3977
  if (outputBytes + bytes > OUTPUT_BYTES)
3963
3978
  throw new Error("Evidence exceeded its output allowance.");
3964
3979
  outputBytes += bytes;
3965
- result.matches.push(...matches2);
3980
+ result.matches.push(...matches);
3966
3981
  result.unavailable += page.unavailable.length;
3967
3982
  result.incomplete ||= page.incomplete || page.unavailable.length > 0;
3968
3983
  state.omitted ||= page.incomplete || page.unavailable.length > 0;
@@ -4235,15 +4250,15 @@ function newScan(terms) {
4235
4250
  return { terms, started: false };
4236
4251
  }
4237
4252
  __name(newScan, "newScan");
4238
- function advanceScan(scans, scan, nextCursor, excerpts, hasDerivedSummaries, canRefine) {
4239
- scan.started = true;
4240
- scan.cursor = nextCursor;
4253
+ function advanceScan(scans, scan2, nextCursor, excerpts, hasDerivedSummaries, canRefine) {
4254
+ scan2.started = true;
4255
+ scan2.cursor = nextCursor;
4241
4256
  if (!canRefine || scans.length !== 1 || !nextCursor) return;
4242
4257
  if (hasDerivedSummaries) {
4243
- scans.push({ ...newScan(scan.terms), excludeDerivedSummaries: true });
4258
+ scans.push({ ...newScan(scan2.terms), excludeDerivedSummaries: true });
4244
4259
  return;
4245
4260
  }
4246
- const focused = refineEvidenceRecallTerms(scan.terms, excerpts);
4261
+ const focused = refineEvidenceRecallTerms(scan2.terms, excerpts);
4247
4262
  if (focused) scans.push(newScan(focused));
4248
4263
  }
4249
4264
  __name(advanceScan, "advanceScan");
@@ -4268,8 +4283,8 @@ function createConversationEvidenceRecall(sessions, sessionId, assertOwner, reso
4268
4283
  let excludedSummaries = 0;
4269
4284
  const scans = [newScan(terms)];
4270
4285
  for (let pages = 0; pages < RECALL_PAGES; pages++) {
4271
- const scan = [...scans].reverse().find((s) => !s.started || s.cursor);
4272
- if (!scan) break;
4286
+ const scan2 = [...scans].reverse().find((s) => !s.started || s.cursor);
4287
+ if (!scan2) break;
4273
4288
  signal.throwIfAborted();
4274
4289
  const remaining = maxReadBytes - scannedBytes;
4275
4290
  if (remaining < 1024 * 1024) {
@@ -4280,12 +4295,12 @@ function createConversationEvidenceRecall(sessions, sessionId, assertOwner, reso
4280
4295
  sessions,
4281
4296
  sessionId,
4282
4297
  {
4283
- terms: scan.terms,
4298
+ terms: scan2.terms,
4284
4299
  matchMode: "token",
4285
4300
  excludeSuccessfulTools: CONVERSATION_RETRIEVAL_TOOLS,
4286
- excludeDerivedSummaries: scan.excludeDerivedSummaries ?? false,
4301
+ excludeDerivedSummaries: scan2.excludeDerivedSummaries ?? false,
4287
4302
  maxReadBytes: remaining,
4288
- ...scan.cursor ? { cursor: scan.cursor } : {}
4303
+ ...scan2.cursor ? { cursor: scan2.cursor } : {}
4289
4304
  },
4290
4305
  signal,
4291
4306
  active
@@ -4316,7 +4331,7 @@ function createConversationEvidenceRecall(sessions, sessionId, assertOwner, reso
4316
4331
  }
4317
4332
  advanceScan(
4318
4333
  scans,
4319
- scan,
4334
+ scan2,
4320
4335
  page.nextCursor,
4321
4336
  page.matches.map((match) => match.text),
4322
4337
  page.matches.some((match) => match.source === "compaction_shed:summary"),
@@ -4326,9 +4341,9 @@ function createConversationEvidenceRecall(sessions, sessionId, assertOwner, reso
4326
4341
  }
4327
4342
  assertOwner(turnId);
4328
4343
  signal.throwIfAborted();
4329
- const continuations = [...scans].reverse().filter((scan) => scan.cursor !== void 0).map((scan) => ({
4344
+ const continuations = [...scans].reverse().filter((scan2) => scan2.cursor !== void 0).map((scan2) => ({
4330
4345
  toolName: "search_conversation",
4331
- input: { cursor: scan.cursor }
4346
+ input: { cursor: scan2.cursor }
4332
4347
  }));
4333
4348
  return {
4334
4349
  candidates,
@@ -4433,6 +4448,150 @@ function createTaskContextStep(store, tenantId, now = Date.now) {
4433
4448
  }
4434
4449
  __name(createTaskContextStep, "createTaskContextStep");
4435
4450
 
4451
+ // src/integrations/small-model/route.ts
4452
+ function parseSmallModel(value, activeProviderId, isKnownProvider) {
4453
+ const slash = value.indexOf("/");
4454
+ if (slash > 0 && slash < value.length - 1) {
4455
+ const head = value.slice(0, slash);
4456
+ if (isKnownProvider(head)) return { providerId: head, model: value.slice(slash + 1) };
4457
+ }
4458
+ return { providerId: activeProviderId, model: value };
4459
+ }
4460
+ __name(parseSmallModel, "parseSmallModel");
4461
+ var NOT_A_CHAT_MODEL = /embed|moderat|whisper|transcri|tts|speech|image|dall-?e|realtime|audio/iu;
4462
+ function price(providerId, model) {
4463
+ if (model.inputPrice !== void 0 && model.outputPrice !== void 0) {
4464
+ return model.inputPrice + model.outputPrice;
4465
+ }
4466
+ const rates = resolveModelPricing(providerId, model.id);
4467
+ return rates === void 0 ? void 0 : rates.inputCostPer1M + rates.outputCostPer1M;
4468
+ }
4469
+ __name(price, "price");
4470
+ function cheapestTextModel(providerId, models, offerable = () => true) {
4471
+ let best;
4472
+ for (const model of models) {
4473
+ if (!model.supportsStreaming) continue;
4474
+ if (model.inputModalities !== void 0 && !model.inputModalities.includes("text")) continue;
4475
+ if (NOT_A_CHAT_MODEL.test(model.id)) continue;
4476
+ if (!offerable(model)) continue;
4477
+ const cost = price(providerId, model);
4478
+ if (cost === void 0) continue;
4479
+ if (best === void 0) {
4480
+ best = { model, cost };
4481
+ continue;
4482
+ }
4483
+ if (cost !== best.cost) {
4484
+ if (cost < best.cost) best = { model, cost };
4485
+ continue;
4486
+ }
4487
+ const window = model.contextWindow ?? 0;
4488
+ const bestWindow = best.model.contextWindow ?? 0;
4489
+ if (window > bestWindow || window === bestWindow && model.id.length < best.model.id.length) {
4490
+ best = { model, cost };
4491
+ }
4492
+ }
4493
+ return best?.model;
4494
+ }
4495
+ __name(cheapestTextModel, "cheapestTextModel");
4496
+
4497
+ // src/integrations/small-model/side-model.ts
4498
+ function estimateTokens(text) {
4499
+ return Math.ceil(text.length / 4);
4500
+ }
4501
+ __name(estimateTokens, "estimateTokens");
4502
+ function createSideModel(deps) {
4503
+ const routes = /* @__PURE__ */ new Map();
4504
+ const resolve11 = /* @__PURE__ */ __name(async (sessionId, signal) => {
4505
+ const active = deps.active();
4506
+ if (deps.configured !== void 0) {
4507
+ const target = parseSmallModel(deps.configured, active.providerId, deps.isKnownProvider);
4508
+ return { ...target, source: "configured" };
4509
+ }
4510
+ try {
4511
+ const provider = await deps.buildProvider(sessionId, active);
4512
+ if (provider.listModels === void 0) return { ...active, source: "main" };
4513
+ const listing = await runPickerProviderOperation(
4514
+ signal,
4515
+ (operationSignal) => provider.listModels(operationSignal)
4516
+ );
4517
+ const cheapest = cheapestTextModel(
4518
+ active.providerId,
4519
+ listing,
4520
+ (model) => deps.offerable ? deps.offerable(active.providerId, model) : true
4521
+ );
4522
+ if (cheapest !== void 0) {
4523
+ return {
4524
+ providerId: active.providerId,
4525
+ model: cheapest.id,
4526
+ source: "cheapest"
4527
+ };
4528
+ }
4529
+ } catch (error) {
4530
+ deps.debug?.("side model: listing failed, using the conversation model", error);
4531
+ }
4532
+ return { ...active, source: "main" };
4533
+ }, "resolve");
4534
+ const route = /* @__PURE__ */ __name((sessionId, signal) => {
4535
+ const active = deps.active();
4536
+ const key = `${active.providerId}
4537
+ ${active.model}
4538
+ ${deps.configured ?? ""}`;
4539
+ let pending = routes.get(key);
4540
+ if (pending === void 0) {
4541
+ pending = resolve11(sessionId, signal);
4542
+ routes.set(key, pending);
4543
+ void pending.then((value) => {
4544
+ if (signal.aborted && value.source === "main" && routes.get(key) === pending) {
4545
+ routes.delete(key);
4546
+ }
4547
+ });
4548
+ }
4549
+ return pending;
4550
+ }, "route");
4551
+ const ask = /* @__PURE__ */ __name(async (request) => {
4552
+ try {
4553
+ request.signal.throwIfAborted();
4554
+ const chosen = await route(request.sessionId, request.signal);
4555
+ const provider = await deps.buildProvider(request.sessionId, chosen);
4556
+ const estimatedPromptTokens = estimateTokens(request.instruction) + estimateTokens(request.body);
4557
+ const send = /* @__PURE__ */ __name(async () => {
4558
+ const response = await collectChatCompletion(
4559
+ provider.chatStream({
4560
+ model: chosen.model,
4561
+ messages: [createSystemMessage(request.instruction), createUserMessage(request.body)],
4562
+ maxTokens: request.maxTokens,
4563
+ signal: request.signal
4564
+ })
4565
+ );
4566
+ return { value: response.message.content ?? "", usage: response.usage };
4567
+ }, "send");
4568
+ if (request.timing === "in-turn") {
4569
+ const text = await deps.ledger.chargeNow({
4570
+ turnId: request.turnId,
4571
+ sessionId: request.sessionId,
4572
+ estimatedPromptTokens,
4573
+ signal: request.signal,
4574
+ request: send
4575
+ });
4576
+ return text?.trim() ? text : void 0;
4577
+ }
4578
+ const result = await send();
4579
+ void deps.ledger.chargeLater({
4580
+ turnId: request.turnId,
4581
+ sessionId: request.sessionId,
4582
+ estimatedPromptTokens,
4583
+ usage: result.usage
4584
+ });
4585
+ return result.value.trim() ? result.value : void 0;
4586
+ } catch (error) {
4587
+ deps.debug?.("side model: request failed", error);
4588
+ return void 0;
4589
+ }
4590
+ }, "ask");
4591
+ return { route, ask };
4592
+ }
4593
+ __name(createSideModel, "createSideModel");
4594
+
4436
4595
  // src/integrations/state/retention.ts
4437
4596
  var CLI_CHECKPOINT_RETENTION = 10;
4438
4597
 
@@ -6275,9 +6434,68 @@ async function createSubagentRuntime(input) {
6275
6434
  throw error;
6276
6435
  }
6277
6436
  }, "gatewayForTurn");
6437
+ const queuedSideSpend = /* @__PURE__ */ new Map();
6438
+ const releasedTurns = /* @__PURE__ */ new Set();
6439
+ const countSideSpend = /* @__PURE__ */ __name(async (budget, spend) => {
6440
+ const controller = new AbortController();
6441
+ await chargeLabelRequest({
6442
+ budget,
6443
+ sessionId: spend.sessionId,
6444
+ estimatedPromptTokens: spend.estimatedPromptTokens,
6445
+ signal: controller.signal,
6446
+ request: /* @__PURE__ */ __name(async () => ({ value: true, usage: spend.usage }), "request")
6447
+ }).catch(() => void 0);
6448
+ }, "countSideSpend");
6449
+ const countQueuedSideSpend = /* @__PURE__ */ __name(async (turnId, pending) => {
6450
+ const queued = queuedSideSpend.get(turnId);
6451
+ if (queued === void 0) return;
6452
+ queuedSideSpend.delete(turnId);
6453
+ const runtime = await pending.catch(() => void 0);
6454
+ if (runtime === void 0) return;
6455
+ for (const spend of queued) await countSideSpend(runtime.budget, spend);
6456
+ }, "countQueuedSideSpend");
6457
+ const sideLedger = {
6458
+ async chargeNow(input2) {
6459
+ const turn = await parents.get(input2.turnId)?.catch(() => void 0);
6460
+ if (!turn || closed) return void 0;
6461
+ return chargeLabelRequest({
6462
+ budget: turn.budget,
6463
+ sessionId: input2.sessionId,
6464
+ estimatedPromptTokens: input2.estimatedPromptTokens,
6465
+ signal: input2.signal,
6466
+ request: input2.request
6467
+ });
6468
+ },
6469
+ async chargeLater(input2) {
6470
+ const spend = {
6471
+ sessionId: input2.sessionId,
6472
+ estimatedPromptTokens: input2.estimatedPromptTokens,
6473
+ usage: input2.usage
6474
+ };
6475
+ if (!releasedTurns.has(input2.turnId)) {
6476
+ const queue = queuedSideSpend.get(input2.turnId) ?? [];
6477
+ queue.push(spend);
6478
+ queuedSideSpend.set(input2.turnId, queue);
6479
+ return;
6480
+ }
6481
+ await openSessionTokenBudget({
6482
+ store: tokenBudgetStore,
6483
+ scope: { rootSessionId: input2.sessionId, rootTurnId: input2.turnId }
6484
+ }).then(
6485
+ (budget) => countSideSpend(budget, spend),
6486
+ () => void 0
6487
+ );
6488
+ }
6489
+ };
6278
6490
  const releaseTurn = /* @__PURE__ */ __name(async (turnId) => {
6279
6491
  const pending = parents.get(turnId);
6280
6492
  if (!pending) return;
6493
+ await countQueuedSideSpend(turnId, pending);
6494
+ releasedTurns.add(turnId);
6495
+ if (releasedTurns.size > 256) {
6496
+ const oldest = releasedTurns.values().next().value;
6497
+ if (oldest !== void 0) releasedTurns.delete(oldest);
6498
+ }
6281
6499
  parents.delete(turnId);
6282
6500
  await pending.then(
6283
6501
  (runtime) => runtime.close(),
@@ -7335,6 +7553,7 @@ ${JSON.stringify(launch.schema)}`;
7335
7553
  gatewayForTurn,
7336
7554
  completionInboxForTurn,
7337
7555
  releaseTurn,
7556
+ sideLedger,
7338
7557
  agentTool,
7339
7558
  waitForTaskTool,
7340
7559
  agentTaskListTool,
@@ -7732,11 +7951,11 @@ var WorkflowRunRegistry = class {
7732
7951
  whenIdle(signal) {
7733
7952
  const going = /* @__PURE__ */ __name(() => [...this.runs.values()].some((run2) => !run2.finalized), "going");
7734
7953
  if (!going() || signal?.aborted) return Promise.resolve();
7735
- return new Promise((resolve9) => {
7954
+ return new Promise((resolve11) => {
7736
7955
  const done = /* @__PURE__ */ __name(() => {
7737
7956
  off();
7738
7957
  signal?.removeEventListener("abort", done);
7739
- resolve9();
7958
+ resolve11();
7740
7959
  }, "done");
7741
7960
  const off = this.subscribe(() => {
7742
7961
  if (!going()) done();
@@ -7933,8 +8152,8 @@ function createWorkflowHost(options) {
7933
8152
  let launching = true;
7934
8153
  let settleLaunch = /* @__PURE__ */ __name(() => {
7935
8154
  }, "settleLaunch");
7936
- const launch = new Promise((resolve9) => {
7937
- settleLaunch = resolve9;
8155
+ const launch = new Promise((resolve11) => {
8156
+ settleLaunch = resolve11;
7938
8157
  });
7939
8158
  const detach = /* @__PURE__ */ __name(() => {
7940
8159
  if (!launching) return;
@@ -8743,28 +8962,249 @@ function createLiveModeControl(options) {
8743
8962
  }
8744
8963
  __name(createLiveModeControl, "createLiveModeControl");
8745
8964
 
8965
+ // src/permissions/local-settings.ts
8966
+ import { execFile as execFile3 } from "node:child_process";
8967
+ import { existsSync, readFileSync, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
8968
+ import { appendFile as appendFile3, mkdir as mkdir5, readFile as readFile5, writeFile as writeFile3 } from "node:fs/promises";
8969
+ import { homedir } from "node:os";
8970
+ import { dirname as dirname3, isAbsolute as isAbsolute6, join as join13, resolve as resolve8 } from "node:path";
8971
+ function localConfigPath(cwd) {
8972
+ return resolve8(cwd, LOCAL_CONFIG_FILE);
8973
+ }
8974
+ __name(localConfigPath, "localConfigPath");
8975
+ function isRecord2(value) {
8976
+ return typeof value === "object" && value !== null && !Array.isArray(value);
8977
+ }
8978
+ __name(isRecord2, "isRecord");
8979
+ function addAllowRules(permissions, additions) {
8980
+ const out = { ...permissions };
8981
+ for (const [tool, wanted] of Object.entries(additions)) {
8982
+ const existing = out[tool];
8983
+ if (existing === void 0) {
8984
+ out[tool] = wanted;
8985
+ continue;
8986
+ }
8987
+ if (isPermissionEffect(existing)) continue;
8988
+ if (!isRecord2(existing)) continue;
8989
+ if (isPermissionEffect(wanted)) {
8990
+ continue;
8991
+ }
8992
+ const table = { ...existing };
8993
+ for (const [pattern, effect] of Object.entries(wanted)) {
8994
+ if (table[pattern] === void 0) table[pattern] = effect;
8995
+ }
8996
+ out[tool] = table;
8997
+ }
8998
+ return out;
8999
+ }
9000
+ __name(addAllowRules, "addAllowRules");
9001
+ function writeLocalAllows(cwd, additions) {
9002
+ const path = localConfigPath(cwd);
9003
+ let document = {};
9004
+ if (existsSync(path)) {
9005
+ let parsed;
9006
+ try {
9007
+ parsed = JSON.parse(readFileSync(path, "utf-8"));
9008
+ } catch (cause) {
9009
+ return {
9010
+ path,
9011
+ error: `${LOCAL_CONFIG_FILE} is not valid JSON (${cause instanceof Error ? cause.message : String(cause)})`
9012
+ };
9013
+ }
9014
+ if (!isRecord2(parsed)) return { path, error: `${LOCAL_CONFIG_FILE} is not a JSON object` };
9015
+ document = parsed;
9016
+ }
9017
+ const permissions = isRecord2(document.permissions) ? document.permissions : {};
9018
+ if (document.permissions !== void 0 && !isRecord2(document.permissions)) {
9019
+ return { path, error: `${LOCAL_CONFIG_FILE} has a permissions value that is not a table` };
9020
+ }
9021
+ document = { ...document, permissions: addAllowRules(permissions, additions) };
9022
+ try {
9023
+ const staging = `${path}.${process.pid}.tmp`;
9024
+ writeFileSync2(staging, `${JSON.stringify(document, null, " ")}
9025
+ `, { mode: 384 });
9026
+ renameSync2(staging, path);
9027
+ } catch (cause) {
9028
+ return { path, error: cause instanceof Error ? cause.message : String(cause) };
9029
+ }
9030
+ return { path };
9031
+ }
9032
+ __name(writeLocalAllows, "writeLocalAllows");
9033
+ function git2(args, cwd, env) {
9034
+ return new Promise((done) => {
9035
+ execFile3(
9036
+ "git",
9037
+ [...args],
9038
+ { cwd, env, timeout: 15e3, windowsHide: true },
9039
+ (error, stdout) => {
9040
+ const code = error === null ? 0 : typeof error.code === "number" ? error.code : 1;
9041
+ done({ code, stdout: String(stdout ?? "") });
9042
+ }
9043
+ );
9044
+ });
9045
+ }
9046
+ __name(git2, "git");
9047
+ function globalIgnorePath(configured, env) {
9048
+ const home = env.HOME ?? env.USERPROFILE ?? homedir();
9049
+ const value = configured.trim();
9050
+ if (value === "~" || value.startsWith("~/")) return join13(home, value.slice(2));
9051
+ if (value !== "" && isAbsolute6(value)) return value;
9052
+ const xdg = env.XDG_CONFIG_HOME;
9053
+ if (xdg && isAbsolute6(xdg)) return join13(xdg, "git", "ignore");
9054
+ return join13(home, ".config", "git", "ignore");
9055
+ }
9056
+ __name(globalIgnorePath, "globalIgnorePath");
9057
+ async function ensureLocalConfigIgnored(cwd, env = process.env) {
9058
+ try {
9059
+ const inside = await git2(["rev-parse", "--is-inside-work-tree"], cwd, env);
9060
+ if (inside.code !== 0 || inside.stdout.trim() !== "true") return { state: "not-a-repository" };
9061
+ const ignored = /* @__PURE__ */ __name(async () => (await git2(["check-ignore", "--", LOCAL_CONFIG_FILE], cwd, env)).code === 0, "ignored");
9062
+ if (await ignored()) return { state: "ignored", written: false };
9063
+ const configured = await git2(["config", "--global", "--get", "core.excludesfile"], cwd, env);
9064
+ const file = globalIgnorePath(configured.code === 0 ? configured.stdout : "", env);
9065
+ const line = `**/${LOCAL_CONFIG_FILE}`;
9066
+ await mkdir5(dirname3(file), { recursive: true });
9067
+ let existing = "";
9068
+ try {
9069
+ existing = await readFile5(file, "utf-8");
9070
+ } catch {
9071
+ }
9072
+ const why = /* @__PURE__ */ __name(async () => (await git2(["ls-files", "--error-unmatch", "--", LOCAL_CONFIG_FILE], cwd, env)).code === 0 ? "tracked" : "not-read", "why");
9073
+ if (existing.includes(line)) {
9074
+ const reason = await why();
9075
+ return { state: reason, reason: `${line} is in ${file} but git does not ignore the file` };
9076
+ }
9077
+ if (existing === "") await writeFile3(file, `${line}
9078
+ `, "utf-8");
9079
+ else await appendFile3(file, `${existing.endsWith("\n") ? "" : "\n"}${line}
9080
+ `, "utf-8");
9081
+ if (!await ignored()) {
9082
+ const reason = await why();
9083
+ return { state: reason, reason: `wrote ${line} to ${file} but git still does not ignore it` };
9084
+ }
9085
+ return { state: "ignored", written: true };
9086
+ } catch (cause) {
9087
+ return { state: "failed", reason: cause instanceof Error ? cause.message : String(cause) };
9088
+ }
9089
+ }
9090
+ __name(ensureLocalConfigIgnored, "ensureLocalConfigIgnored");
9091
+ function logIgnoreOutcome(outcome) {
9092
+ if (outcome.state === "ignored" || outcome.state === "not-a-repository") return;
9093
+ cliLogger().warn("The local config may be tracked by git", {
9094
+ "namzu.config.local.state": outcome.state,
9095
+ "namzu.config.local.reason": outcome.reason
9096
+ });
9097
+ }
9098
+ __name(logIgnoreOutcome, "logIgnoreOutcome");
9099
+
8746
9100
  // src/permissions/session-allow.ts
8747
9101
  var WEB_FETCH_TOOL = "web_fetch";
8748
9102
  var MAX_LABEL_COMMAND = 60;
8749
- function isRecord2(value) {
9103
+ var MAX_RULES_PER_ANSWER = 5;
9104
+ function isRecord3(value) {
8750
9105
  return typeof value === "object" && value !== null && !Array.isArray(value);
8751
9106
  }
8752
- __name(isRecord2, "isRecord");
9107
+ __name(isRecord3, "isRecord");
8753
9108
  function alwaysAsked(call) {
8754
9109
  return call.escalation !== void 0 || call.requiresApproval === true || call.authorization?.explicitReview === true || call.isDestructive === true;
8755
9110
  }
8756
9111
  __name(alwaysAsked, "alwaysAsked");
8757
- function allowFor(call, commands) {
9112
+ var NO_PREFIX_PROGRAMS = /* @__PURE__ */ new Set([
9113
+ "sh",
9114
+ "bash",
9115
+ "zsh",
9116
+ "fish",
9117
+ "csh",
9118
+ "tcsh",
9119
+ "ksh",
9120
+ "dash",
9121
+ "cmd",
9122
+ "powershell",
9123
+ "pwsh",
9124
+ "env",
9125
+ "xargs",
9126
+ "command",
9127
+ "builtin",
9128
+ "noglob",
9129
+ "nice",
9130
+ "stdbuf",
9131
+ "nohup",
9132
+ "timeout",
9133
+ "time",
9134
+ "watch",
9135
+ "ionice",
9136
+ "chrt",
9137
+ "setsid",
9138
+ "taskset",
9139
+ "strace",
9140
+ "ltrace",
9141
+ "script",
9142
+ "flock",
9143
+ "unshare",
9144
+ "nsenter",
9145
+ "sudo",
9146
+ "doas",
9147
+ "pkexec",
9148
+ "su",
9149
+ "runuser"
9150
+ ]);
9151
+ var SUBCOMMAND = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
9152
+ var ASSIGNMENT = /^[A-Za-z_]\w*=/;
9153
+ var PLAIN_PROGRAM = /^[\w./+@:-]+$/;
9154
+ var NOT_EXACT = /[\n\r;&|<>`$()*?{}\\]/;
9155
+ function programName(word) {
9156
+ return word.slice(word.lastIndexOf("/") + 1);
9157
+ }
9158
+ __name(programName, "programName");
9159
+ function twoWordPrefix(command) {
9160
+ const words = command.trim().split(/\s+/).filter(Boolean);
9161
+ const [program, subcommand] = words;
9162
+ if (words.length < 2 || program === void 0 || subcommand === void 0) return void 0;
9163
+ if (ASSIGNMENT.test(program)) return void 0;
9164
+ if (!PLAIN_PROGRAM.test(program) || NO_PREFIX_PROGRAMS.has(programName(program))) return void 0;
9165
+ if (!SUBCOMMAND.test(subcommand)) return void 0;
9166
+ return `${program} ${subcommand}`;
9167
+ }
9168
+ __name(twoWordPrefix, "twoWordPrefix");
9169
+ function allowForCommand(tool, command) {
9170
+ if (NOT_EXACT.test(command)) return void 0;
9171
+ const prefix = programName(command.split(/\s+/)[0] ?? "") === "cd" ? void 0 : twoWordPrefix(command);
9172
+ if (prefix !== void 0) return { kind: "prefix", tool, prefix };
9173
+ return { kind: "command", tool, command };
9174
+ }
9175
+ __name(allowForCommand, "allowForCommand");
9176
+ function plainCommands(line) {
9177
+ const lexed = lexShellCommandLine(line, { dialect: "bash" });
9178
+ if (!lexed.complete || lexed.opaque || lexed.commands.length === 0) return void 0;
9179
+ if (lexed.redirections.length > 0 || lexed.compoundWords.length > 0) return void 0;
9180
+ const out = [];
9181
+ for (const command of lexed.commands) {
9182
+ if (command.origin !== "line" || command.redirections.length > 0) return void 0;
9183
+ const text = command.text.trim();
9184
+ if (text === "") return void 0;
9185
+ out.push(text);
9186
+ }
9187
+ return out;
9188
+ }
9189
+ __name(plainCommands, "plainCommands");
9190
+ function allowsFor(call, commands) {
8758
9191
  if (alwaysAsked(call)) return void 0;
8759
- const input = isRecord2(call.input) ? call.input : void 0;
9192
+ const input = isRecord3(call.input) ? call.input : void 0;
8760
9193
  const commandArgument = commands.get(call.name);
8761
9194
  if (commandArgument !== void 0) {
8762
9195
  const line = input?.[commandArgument];
8763
9196
  if (typeof line !== "string") return void 0;
8764
- const command = line.trim();
8765
- if (command === "" || /[\n\r;&|<>`$()*?{}\\]/.test(command)) return void 0;
8766
9197
  if (input?.dangerously_disable_sandbox === true) return void 0;
8767
- return { kind: "command", tool: call.name, command };
9198
+ if (line.trim() === "" || /[\n\r]/.test(line.trim())) return void 0;
9199
+ const parts = plainCommands(line);
9200
+ if (parts === void 0) return void 0;
9201
+ const out = [];
9202
+ for (const part of parts) {
9203
+ const allow = allowForCommand(call.name, part);
9204
+ if (allow === void 0) return void 0;
9205
+ if (!out.some((existing) => sameAllow(existing, allow))) out.push(allow);
9206
+ }
9207
+ return out.length > 0 && out.length <= MAX_RULES_PER_ANSWER ? out : void 0;
8768
9208
  }
8769
9209
  if (call.name === WEB_FETCH_TOOL) {
8770
9210
  const url = input?.url;
@@ -8772,29 +9212,32 @@ function allowFor(call, commands) {
8772
9212
  try {
8773
9213
  const host = new URL(url).hostname;
8774
9214
  if (host === "" || host.includes("*")) return void 0;
8775
- return { kind: "host", tool: call.name, host };
9215
+ return [{ kind: "host", tool: call.name, host }];
8776
9216
  } catch {
8777
9217
  return void 0;
8778
9218
  }
8779
9219
  }
8780
- if (call.name.startsWith("mcp__")) return { kind: "tool", tool: call.name };
9220
+ if (call.name.startsWith("mcp__")) return [{ kind: "tool", tool: call.name }];
8781
9221
  return void 0;
8782
9222
  }
8783
- __name(allowFor, "allowFor");
9223
+ __name(allowsFor, "allowsFor");
8784
9224
  function allowsForBatch(calls, commands) {
8785
9225
  if (calls.length === 0) return void 0;
8786
9226
  const out = [];
8787
9227
  for (const call of calls) {
8788
- const allow = allowFor(call, commands);
8789
- if (!allow) return void 0;
8790
- if (!out.some((existing) => sameAllow(existing, allow))) out.push(allow);
9228
+ const allows = allowsFor(call, commands);
9229
+ if (!allows) return void 0;
9230
+ for (const allow of allows) {
9231
+ if (!out.some((existing) => sameAllow(existing, allow))) out.push(allow);
9232
+ }
8791
9233
  }
8792
- return out;
9234
+ return out.length <= MAX_RULES_PER_ANSWER ? out : void 0;
8793
9235
  }
8794
9236
  __name(allowsForBatch, "allowsForBatch");
8795
9237
  function sameAllow(a, b) {
8796
9238
  if (a.kind !== b.kind || a.tool !== b.tool) return false;
8797
9239
  if (a.kind === "command" && b.kind === "command") return a.command === b.command;
9240
+ if (a.kind === "prefix" && b.kind === "prefix") return a.prefix === b.prefix;
8798
9241
  if (a.kind === "host" && b.kind === "host") return a.host === b.host;
8799
9242
  return true;
8800
9243
  }
@@ -8808,6 +9251,8 @@ function describeAllows(allows) {
8808
9251
  switch (allow.kind) {
8809
9252
  case "command":
8810
9253
  return `${shorten(allow.command)} commands`;
9254
+ case "prefix":
9255
+ return `${shorten(allow.prefix)} * commands`;
8811
9256
  case "host":
8812
9257
  return allow.host;
8813
9258
  case "tool":
@@ -8817,47 +9262,237 @@ function describeAllows(allows) {
8817
9262
  return parts.length <= 1 ? parts[0] ?? "" : `${parts.slice(0, -1).join(", ")} and ${parts.at(-1)}`;
8818
9263
  }
8819
9264
  __name(describeAllows, "describeAllows");
8820
- function matches(allow, toolName2, toolInput, commands) {
8821
- if (allow.tool !== toolName2) return false;
8822
- switch (allow.kind) {
8823
- case "tool":
8824
- return true;
8825
- case "host": {
8826
- const url = isRecord2(toolInput) ? toolInput.url : void 0;
8827
- if (typeof url !== "string") return false;
8828
- try {
8829
- return new URL(url).hostname === allow.host;
8830
- } catch {
8831
- return false;
8832
- }
8833
- }
8834
- case "command": {
8835
- const argument = commands.get(toolName2);
8836
- if (argument === void 0 || !isRecord2(toolInput)) return false;
8837
- const line = toolInput[argument];
8838
- return typeof line === "string" && line.trim() === allow.command && toolInput.dangerously_disable_sandbox !== true;
9265
+ function permissionsForAllows(allows) {
9266
+ const table = {};
9267
+ const pattern = /* @__PURE__ */ __name((tool, glob) => {
9268
+ const existing = table[tool];
9269
+ const patterns = typeof existing === "object" ? existing : {};
9270
+ patterns[glob] = "allow";
9271
+ table[tool] = patterns;
9272
+ }, "pattern");
9273
+ for (const allow of allows) {
9274
+ switch (allow.kind) {
9275
+ case "command":
9276
+ pattern(allow.tool, allow.command);
9277
+ break;
9278
+ case "prefix":
9279
+ pattern(allow.tool, `${allow.prefix} *`);
9280
+ break;
9281
+ case "host":
9282
+ pattern(allow.tool, `http://${allow.host}/*`);
9283
+ pattern(allow.tool, `https://${allow.host}/*`);
9284
+ break;
9285
+ case "tool":
9286
+ table[allow.tool] = "allow";
9287
+ break;
8839
9288
  }
8840
9289
  }
9290
+ return table;
8841
9291
  }
8842
- __name(matches, "matches");
8843
- function createSessionAllows(commands) {
9292
+ __name(permissionsForAllows, "permissionsForAllows");
9293
+ function createSessionAllows(_commands, options = {}) {
8844
9294
  const entries = [];
9295
+ let gate;
9296
+ const rebuild = /* @__PURE__ */ __name(() => {
9297
+ const { rules } = compilePermissions(permissionsForAllows(entries));
9298
+ gate = rules.length === 0 ? void 0 : new AuthorizationGate(
9299
+ {
9300
+ enabled: true,
9301
+ rules: [...rules],
9302
+ allowReadOnlyTools: false,
9303
+ denyDangerousPatterns: false,
9304
+ logDecisions: false
9305
+ },
9306
+ NOOP_LOGGER
9307
+ );
9308
+ }, "rebuild");
9309
+ const allowed = /* @__PURE__ */ __name((call) => {
9310
+ if (isRecord3(call.toolInput) && call.toolInput.dangerously_disable_sandbox === true)
9311
+ return false;
9312
+ const result = gate?.evaluate(call);
9313
+ return result !== void 0 && result.matchedRule !== null && result.decision === "allow";
9314
+ }, "allowed");
8845
9315
  return {
8846
9316
  add(allows) {
8847
- for (const allow of allows) {
8848
- if (!entries.some((existing) => sameAllow(existing, allow))) entries.push(allow);
9317
+ const fresh = allows.filter(
9318
+ (allow) => !entries.some((existing) => sameAllow(existing, allow))
9319
+ );
9320
+ entries.push(...fresh);
9321
+ if (fresh.length > 0) rebuild();
9322
+ const cwd = typeof options.cwd === "function" ? options.cwd() : options.cwd;
9323
+ if (cwd === void 0) return void 0;
9324
+ const write = (options.persist ?? writeLocalAllows)(cwd, permissionsForAllows(allows));
9325
+ if (write.error !== void 0) {
9326
+ cliLogger().warn("Could not save a remembered answer", {
9327
+ "namzu.config.local.path": write.path,
9328
+ "namzu.config.local.error": write.error
9329
+ });
9330
+ return `Could not save this answer to ${LOCAL_CONFIG_FILE}: ${write.error}. It holds for this session only.`;
8849
9331
  }
9332
+ void (options.keepIgnored ?? ensureLocalConfigIgnored)(cwd).then(logIgnoreOutcome);
9333
+ return void 0;
8850
9334
  },
8851
9335
  list: /* @__PURE__ */ __name(() => [...entries], "list"),
8852
9336
  rule: {
8853
9337
  type: "predicate",
8854
- description: "allowed for this session by an answer at a prompt",
8855
- decide: /* @__PURE__ */ __name((call) => entries.some((allow) => matches(allow, call.toolName, call.toolInput, commands)) ? "allow" : null, "decide")
9338
+ description: "allowed by an answer at a prompt",
9339
+ decide: /* @__PURE__ */ __name((call) => allowed(call) ? "allow" : null, "decide")
8856
9340
  }
8857
9341
  };
8858
9342
  }
8859
9343
  __name(createSessionAllows, "createSessionAllows");
8860
9344
 
9345
+ // src/plan/approval.ts
9346
+ var KEEP_PLANNING_PLACEHOLDER = "Tell namzu what to change";
9347
+ function planApprovalRows(bypassAvailable) {
9348
+ return [
9349
+ bypassAvailable ? {
9350
+ id: "approve-auto",
9351
+ label: "Yes, and approve every tool without asking",
9352
+ mode: "auto"
9353
+ } : {
9354
+ id: "approve-accept-edits",
9355
+ label: "Yes, and auto-approve edits",
9356
+ mode: "accept-edits"
9357
+ },
9358
+ {
9359
+ id: "approve-ask",
9360
+ label: "Yes, and ask before each edit",
9361
+ mode: "prompt"
9362
+ },
9363
+ { id: "keep-planning", label: "No, keep planning" }
9364
+ ];
9365
+ }
9366
+ __name(planApprovalRows, "planApprovalRows");
9367
+ var EXIT_PLAN_MODE_TOOL_NAME = "exit_plan_mode";
9368
+
9369
+ // src/plan/plan-file.ts
9370
+ import { readFile as readFile6 } from "node:fs/promises";
9371
+ import { isAbsolute as isAbsolute7, resolve as resolve9 } from "node:path";
9372
+ var WRITERS = /* @__PURE__ */ new Set(["write", "edit"]);
9373
+ function isPlanFileWrite(planPath, cwd) {
9374
+ const target = resolve9(planPath);
9375
+ return (call) => {
9376
+ if (!WRITERS.has(call.name)) return false;
9377
+ const input = call.input;
9378
+ if (input === null || typeof input !== "object") return false;
9379
+ const path = input.path;
9380
+ if (typeof path !== "string" || path.length === 0 || path.includes("\0")) return false;
9381
+ return resolve9(isAbsolute7(path) ? path : resolve9(cwd, path)) === target;
9382
+ };
9383
+ }
9384
+ __name(isPlanFileWrite, "isPlanFileWrite");
9385
+ async function readPlan(planPath) {
9386
+ try {
9387
+ const text = await readFile6(planPath, "utf8");
9388
+ return text.trim().length > 0 ? text : void 0;
9389
+ } catch {
9390
+ return void 0;
9391
+ }
9392
+ }
9393
+ __name(readPlan, "readPlan");
9394
+
9395
+ // src/plan/exit-plan-mode-tool.ts
9396
+ function approvedPlanText(plan, planPath, answer) {
9397
+ return [
9398
+ `The user approved your plan and moved this session to "${permissionModeLabel(answer.mode)}". You can start the work now; if a task list fits it, open one first.`,
9399
+ "",
9400
+ `The plan is saved at ${planPath} if you need to refer back to it.`,
9401
+ ...answer.feedback ? ["", `The user added: ${answer.feedback}`] : [],
9402
+ "",
9403
+ "## Approved plan",
9404
+ plan
9405
+ ].join("\n");
9406
+ }
9407
+ __name(approvedPlanText, "approvedPlanText");
9408
+ function buildExitPlanModeTool(host) {
9409
+ return defineTool({
9410
+ name: EXIT_PLAN_MODE_TOOL_NAME,
9411
+ description: "Present the finished plan for the user to approve and leave plan mode. Write the plan to the plan file first; this tool reads it from there and takes no arguments. The user picks how to continue (auto-approve edits, or ask before each edit) or sends you back to planning with feedback. Call it only while in plan mode, only when the plan is ready, and never ask for approval of a plan any other way.",
9412
+ inputSchema: mcpJsonSchemaToZod({
9413
+ type: "object",
9414
+ properties: {},
9415
+ additionalProperties: false
9416
+ }),
9417
+ category: "custom",
9418
+ permissions: [],
9419
+ // Asks the person, changes nothing itself: the mode switch is theirs.
9420
+ readOnly: true,
9421
+ destructive: false,
9422
+ concurrencySafe: false,
9423
+ // A person reads a whole plan before answering.
9424
+ timeoutMs: 30 * 6e4,
9425
+ presentCall: /* @__PURE__ */ __name(() => ({
9426
+ kind: "generic",
9427
+ label: "Present plan for approval",
9428
+ presentation: "activity"
9429
+ }), "presentCall"),
9430
+ // The transcript already shows the approved plan (the host writes it when the
9431
+ // person approves); the tool's own result is for the model.
9432
+ presentResult: /* @__PURE__ */ __name((_input, result) => {
9433
+ if (result.success)
9434
+ return {
9435
+ kind: "generic",
9436
+ label: "Plan approved",
9437
+ visibility: "hidden"
9438
+ };
9439
+ const outcome = result.data?.outcome;
9440
+ return outcome === "keep-planning" ? { kind: "generic", label: "Kept planning", outcome: "cancelled" } : void 0;
9441
+ }, "presentResult"),
9442
+ async execute(_input, context) {
9443
+ context.abortSignal?.throwIfAborted();
9444
+ if (host.mode() !== "plan") {
9445
+ return {
9446
+ success: false,
9447
+ output: "",
9448
+ error: "You are not in plan mode, so there is no plan to put up for approval. If your plan was already approved, carry on with the work."
9449
+ };
9450
+ }
9451
+ const planPath = host.planPath();
9452
+ const plan = await readPlan(planPath);
9453
+ if (plan === void 0) {
9454
+ return {
9455
+ success: false,
9456
+ output: "",
9457
+ error: `There is no plan to approve: ${planPath} is missing or empty. Write the plan to that file first, then call ${EXIT_PLAN_MODE_TOOL_NAME}.`
9458
+ };
9459
+ }
9460
+ const ask = host.approval();
9461
+ if (!ask) {
9462
+ return {
9463
+ success: false,
9464
+ output: "",
9465
+ error: "Nobody can approve a plan in this session, and you cannot leave plan mode yourself. End your reply with the plan and tell the user to switch the permission mode when they want it carried out."
9466
+ };
9467
+ }
9468
+ let answer;
9469
+ try {
9470
+ answer = await ask(
9471
+ { plan, planPath, bypassAvailable: host.bypassAvailable() },
9472
+ context.abortSignal
9473
+ );
9474
+ } catch {
9475
+ answer = { kind: "keep-planning" };
9476
+ }
9477
+ context.abortSignal?.throwIfAborted();
9478
+ if (answer.kind === "approve") {
9479
+ return {
9480
+ success: true,
9481
+ output: approvedPlanText(plan, planPath, answer),
9482
+ data: { outcome: "approved", mode: answer.mode }
9483
+ };
9484
+ }
9485
+ return {
9486
+ success: false,
9487
+ output: "",
9488
+ error: answer.feedback ? `The user did not approve the plan and wants you to keep planning. What they said: ${answer.feedback}` : "The user did not approve the plan yet and has not said what to change. Stay in plan mode and ask what they want different, or refine the plan.",
9489
+ data: { outcome: "keep-planning" }
9490
+ };
9491
+ }
9492
+ });
9493
+ }
9494
+ __name(buildExitPlanModeTool, "buildExitPlanModeTool");
9495
+
8861
9496
  // src/provider-retry.ts
8862
9497
  var TERMINAL_PROVIDER_RETRY = {
8863
9498
  maxRetries: 10,
@@ -8872,6 +9507,175 @@ function terminalProviderRetry(restartableOutput) {
8872
9507
  }
8873
9508
  __name(terminalProviderRetry, "terminalProviderRetry");
8874
9509
 
9510
+ // src/reminders/index.ts
9511
+ import { existsSync as existsSync2 } from "node:fs";
9512
+
9513
+ // src/reminders/frame.ts
9514
+ var TAG = /^<system-reminder kind="([a-z-]+)"(?: form="([a-z]+)")?>/;
9515
+ function frameReminder(kind, text, form) {
9516
+ const open3 = form ? `<system-reminder kind="${kind}" form="${form}">` : `<system-reminder kind="${kind}">`;
9517
+ return `${open3}
9518
+ ${text.trim()}
9519
+ </system-reminder>`;
9520
+ }
9521
+ __name(frameReminder, "frameReminder");
9522
+ function reminderKindOf(message2) {
9523
+ if (!isReminderMessage(message2) || typeof message2.content !== "string") return void 0;
9524
+ const kind = TAG.exec(message2.content)?.[1];
9525
+ return kind === "plan-mode" || kind === "plan-reentry" || kind === "plan-exit" || kind === "task-nudge" ? kind : void 0;
9526
+ }
9527
+ __name(reminderKindOf, "reminderKindOf");
9528
+ function isOperatorTurn(message2) {
9529
+ if (message2.role !== "user") return false;
9530
+ const source = message2.source;
9531
+ return source === void 0 || source.type === "goal-round" || source.type === "runtime-context" && source.kind === "steering";
9532
+ }
9533
+ __name(isOperatorTurn, "isOperatorTurn");
9534
+
9535
+ // src/reminders/plan-mode.ts
9536
+ var PLAN_REMINDER_EVERY_N_TURNS = 5;
9537
+ var PLAN_REMINDER_FULL_EVERY_N = 5;
9538
+ function scan(messages) {
9539
+ let turns = 0;
9540
+ let hasReminder = false;
9541
+ let sent = 0;
9542
+ let hasExited = false;
9543
+ let inStretch = true;
9544
+ for (let i = messages.length - 1; i >= 0; i--) {
9545
+ const message2 = messages[i];
9546
+ const kind = reminderKindOf(message2);
9547
+ if (kind === "plan-exit") {
9548
+ hasExited = true;
9549
+ if (!hasReminder) inStretch = false;
9550
+ break;
9551
+ }
9552
+ if (kind === "plan-mode" || kind === "plan-reentry") {
9553
+ if (inStretch) hasReminder = true;
9554
+ if (kind === "plan-mode") sent++;
9555
+ continue;
9556
+ }
9557
+ if (!hasReminder && isOperatorTurn(message2)) turns++;
9558
+ }
9559
+ return { turnsSinceReminder: turns, hasReminder, sent, hasExited };
9560
+ }
9561
+ __name(scan, "scan");
9562
+ function fullText(input) {
9563
+ const file = input.planExists ? `A plan already exists at ${input.planPath}. Read it, then revise it in place with the edit tool.` : `No plan exists yet. Create it at ${input.planPath} with the write tool.`;
9564
+ const ending = input.canAsk ? "Your turn ends in exactly one of two ways: you ask the user a question with ask_user_question to settle something you cannot decide yourself, or you call exit_plan_mode once the plan file is ready for approval." : "Your turn ends by calling exit_plan_mode once the plan file is ready for approval.";
9565
+ return `Plan mode is on. Change nothing except the plan file: no edits, no commands that change state, no commits. This overrides every other instruction you have.
9566
+
9567
+ ${file} It is the only file you may write; build the plan up in it as you learn.
9568
+
9569
+ How to plan:
9570
+ 1. Understand the request. Read the code it touches and look for existing functions and patterns to reuse before proposing new ones. For wide questions, send read-only explore agents; one is usually enough.
9571
+ 2. Decide on one approach. Weigh alternatives briefly and keep only the one you recommend.
9572
+ 3. Write the plan file: why the change is needed, the recommended approach, the files to change, what existing code it reuses, and how to verify the result end to end.
9573
+ 4. Finish. ${ending} Never ask for approval in plain text ("does this look right?"); exit_plan_mode is how the user is asked.`;
9574
+ }
9575
+ __name(fullText, "fullText");
9576
+ function sparseText(input) {
9577
+ return `Plan mode is still on (full rules above). Only ${input.planPath} may be written. End the turn by ${input.canAsk ? "asking the user a question or " : ""}calling exit_plan_mode.`;
9578
+ }
9579
+ __name(sparseText, "sparseText");
9580
+ function reentryText(input) {
9581
+ return `You are back in plan mode after leaving it earlier. A plan from that session is at ${input.planPath}. Before planning anything new, read it and compare it with the current request: if this is a different task, start over and overwrite it; if it continues the same task, revise it and drop what no longer applies. Edit the plan file one way or the other before you call exit_plan_mode.`;
9582
+ }
9583
+ __name(reentryText, "reentryText");
9584
+ function exitText(input) {
9585
+ return `You have left plan mode. You can edit files and run tools again.${input.planExists ? ` The plan is at ${input.planPath} if you need to refer to it.` : ""}`;
9586
+ }
9587
+ __name(exitText, "exitText");
9588
+ function planModeReminders(input) {
9589
+ const stretch = scan(input.messages);
9590
+ if (input.mode !== "plan") {
9591
+ return stretch.hasReminder ? [frameReminder("plan-exit", exitText(input))] : [];
9592
+ }
9593
+ if (stretch.hasReminder && stretch.turnsSinceReminder < PLAN_REMINDER_EVERY_N_TURNS) return [];
9594
+ const full = (stretch.sent + 1) % PLAN_REMINDER_FULL_EVERY_N === 1;
9595
+ const out = [
9596
+ frameReminder(
9597
+ "plan-mode",
9598
+ full ? fullText(input) : sparseText(input),
9599
+ full ? "full" : "sparse"
9600
+ )
9601
+ ];
9602
+ if (!stretch.hasReminder && stretch.hasExited && input.planExists) {
9603
+ out.push(frameReminder("plan-reentry", reentryText(input)));
9604
+ }
9605
+ return out;
9606
+ }
9607
+ __name(planModeReminders, "planModeReminders");
9608
+
9609
+ // src/reminders/task-nudge.ts
9610
+ var TASK_NUDGE_AFTER_TURNS = 10;
9611
+ var TASK_NUDGE_EVERY_TURNS = 10;
9612
+ var TASK_TOOLS = /* @__PURE__ */ new Set(["task_create", "task_update"]);
9613
+ function taskNudgeCounts(messages) {
9614
+ let sinceTaskTool = 0;
9615
+ let sinceNudge = 0;
9616
+ let sawTool = false;
9617
+ let sawNudge = false;
9618
+ for (let i = messages.length - 1; i >= 0 && !(sawTool && sawNudge); i--) {
9619
+ const message2 = messages[i];
9620
+ if (message2.role === "assistant") {
9621
+ if (!sawTool && message2.toolCalls?.some((call) => TASK_TOOLS.has(call.function.name))) {
9622
+ sawTool = true;
9623
+ }
9624
+ if (!sawTool) sinceTaskTool++;
9625
+ if (!sawNudge) sinceNudge++;
9626
+ } else if (!sawNudge && reminderKindOf(message2) === "task-nudge") {
9627
+ sawNudge = true;
9628
+ }
9629
+ }
9630
+ return { sinceTaskTool, sinceNudge };
9631
+ }
9632
+ __name(taskNudgeCounts, "taskNudgeCounts");
9633
+ function listText(tasks) {
9634
+ return tasks.map((task) => `#${task.id}. [${task.status}] ${task.subject}`).join("\n");
9635
+ }
9636
+ __name(listText, "listText");
9637
+ function taskNudge(messages, tasks) {
9638
+ if (messages.length === 0) return [];
9639
+ const { sinceTaskTool, sinceNudge } = taskNudgeCounts(messages);
9640
+ if (sinceTaskTool < TASK_NUDGE_AFTER_TURNS || sinceNudge < TASK_NUDGE_EVERY_TURNS) return [];
9641
+ const head = "You have not used the task tools for a while. If this work has steps worth tracking, add them with task_create and keep their status current with task_update (in_progress when you start one, completed when it is done); if the list has gone stale, tidy it. Only do so if it fits the work; otherwise ignore this note.";
9642
+ return [
9643
+ frameReminder(
9644
+ "task-nudge",
9645
+ tasks.length > 0 ? `${head}
9646
+
9647
+ The task list now:
9648
+ ${listText(tasks)}` : head
9649
+ )
9650
+ ];
9651
+ }
9652
+ __name(taskNudge, "taskNudge");
9653
+
9654
+ // src/reminders/index.ts
9655
+ function createCliReminderSource(options) {
9656
+ return async ({ messages }) => {
9657
+ const out = [];
9658
+ if (options.planPath) {
9659
+ const planPath = options.planPath();
9660
+ out.push(
9661
+ ...planModeReminders({
9662
+ messages,
9663
+ mode: options.mode(),
9664
+ planPath,
9665
+ planExists: (options.planExists ?? existsSync2)(planPath),
9666
+ canAsk: options.canAsk === true
9667
+ })
9668
+ );
9669
+ }
9670
+ if (options.tasks) {
9671
+ const nudge = taskNudge(messages, []);
9672
+ if (nudge.length > 0) out.push(...taskNudge(messages, await options.tasks()));
9673
+ }
9674
+ return out;
9675
+ };
9676
+ }
9677
+ __name(createCliReminderSource, "createCliReminderSource");
9678
+
8875
9679
  // src/skills/directory.ts
8876
9680
  function createSkillDirectoryResolver(options) {
8877
9681
  return async (skill, context) => {
@@ -9021,24 +9825,24 @@ async function resolveModelSwitch(request, options) {
9021
9825
  listed.set(detected.entry.id, listing);
9022
9826
  return listing.kind === "ok" && listing.models.some((candidate) => candidate.id === model);
9023
9827
  }, "inspect");
9024
- const resolve9 = /* @__PURE__ */ __name((detected) => ({
9828
+ const resolve11 = /* @__PURE__ */ __name((detected) => ({
9025
9829
  kind: "resolved",
9026
9830
  selection: { id: detected.entry.id, model }
9027
9831
  }), "resolve");
9028
9832
  const first = selected ?? usable.find(({ entry }) => entry.id === options.currentProvider);
9029
- if (first && await inspect(first)) return resolve9(first);
9833
+ if (first && await inspect(first)) return resolve11(first);
9030
9834
  const candidates = selected ? [selected] : usable;
9031
- const matches2 = selected ? [] : (await Promise.all(
9835
+ const matches = selected ? [] : (await Promise.all(
9032
9836
  candidates.filter((candidate) => candidate !== first).map(async (candidate) => await inspect(candidate) ? candidate : void 0)
9033
9837
  )).filter((candidate) => candidate !== void 0);
9034
9838
  signal?.throwIfAborted();
9035
- const uniqueMatch = matches2.length === 1 ? matches2[0] : void 0;
9036
- if (uniqueMatch) return resolve9(uniqueMatch);
9037
- if (matches2.length > 1) {
9839
+ const uniqueMatch = matches.length === 1 ? matches[0] : void 0;
9840
+ if (uniqueMatch) return resolve11(uniqueMatch);
9841
+ if (matches.length > 1) {
9038
9842
  return {
9039
9843
  kind: "rejected",
9040
- reason: `Model "${model}" is available from multiple providers. Specify one: ${matches2.map(({ entry }) => entry.id).join(", ")}.`,
9041
- choices: matches2.map(({ entry }) => ({ provider: entry.id, model }))
9844
+ reason: `Model "${model}" is available from multiple providers. Specify one: ${matches.map(({ entry }) => entry.id).join(", ")}.`,
9845
+ choices: matches.map(({ entry }) => ({ provider: entry.id, model }))
9042
9846
  };
9043
9847
  }
9044
9848
  const choices = candidates.flatMap((candidate) => {
@@ -9109,6 +9913,8 @@ function createCliToolPresenter(registry) {
9109
9913
  __name(createCliToolPresenter, "createCliToolPresenter");
9110
9914
 
9111
9915
  // src/tui/agent.ts
9916
+ var WEB_FETCH_MAX_BYTES = 10 * 1024 * 1024;
9917
+ var WEB_EXTRACT_MAX_TOKENS = 8192;
9112
9918
  async function observeWithSignal(operation, signal) {
9113
9919
  signal.throwIfAborted();
9114
9920
  let rejectAbort = /* @__PURE__ */ __name(() => {
@@ -9187,8 +9993,8 @@ var SessionOperationOwner = class {
9187
9993
  })()[Symbol.asyncIterator]();
9188
9994
  let settled = false;
9189
9995
  let settle;
9190
- const settlement = new Promise((resolve9) => {
9191
- settle = resolve9;
9996
+ const settlement = new Promise((resolve11) => {
9997
+ settle = resolve11;
9192
9998
  });
9193
9999
  let operationTail = Promise.resolve();
9194
10000
  let returnStarted = false;
@@ -9457,14 +10263,14 @@ function clipRequestContext(prompt, limit, kind) {
9457
10263
  __name(clipRequestContext, "clipRequestContext");
9458
10264
  async function createAgentSession(prefs, detected, options = {}) {
9459
10265
  if (options.palEnvironment) {
9460
- const { createPalAgentSession } = await import("./agent-session-F5XU36CE.js");
10266
+ const { createPalAgentSession } = await import("./agent-session-2YMHOAKF.js");
9461
10267
  return createPalAgentSession(prefs, detected, options);
9462
10268
  }
9463
- const { palAtWorkspace } = await import("./store-QLMY3B43.js");
10269
+ const { palAtWorkspace } = await import("./store-YWZ6SY2M.js");
9464
10270
  if (palAtWorkspace(options.cwd ?? process.cwd()))
9465
10271
  throw new Error("This Pal requires its owned virtual computer. Open it with namzu pal chat.");
9466
10272
  const commandArguments = builtinCommandArguments();
9467
- const sessionAllows = createSessionAllows(commandArguments);
10273
+ const sessionAllows = createSessionAllows(commandArguments, { cwd: /* @__PURE__ */ __name(() => cwd, "cwd") });
9468
10274
  const sessionRules = [...options.rules ?? [], sessionAllows.rule];
9469
10275
  const fileObservations = /* @__PURE__ */ new Map();
9470
10276
  const observationsFor = /* @__PURE__ */ __name((id, prior) => {
@@ -9494,7 +10300,7 @@ async function createAgentSession(prefs, detected, options = {}) {
9494
10300
  }
9495
10301
  return seeded;
9496
10302
  }, "observationsFor");
9497
- const requestedCwd = resolve8(options.cwd ?? process.cwd());
10303
+ const requestedCwd = resolve10(options.cwd ?? process.cwd());
9498
10304
  let cwd;
9499
10305
  try {
9500
10306
  const entry2 = await stat4(requestedCwd);
@@ -9526,13 +10332,13 @@ async function createAgentSession(prefs, detected, options = {}) {
9526
10332
  paths = options.conversationSessions.paths;
9527
10333
  projectId = options.conversationSessions.projectId;
9528
10334
  } else {
9529
- const home = resolve8(options.stateRoot ?? resolveNamzuHome());
10335
+ const home = resolve10(options.stateRoot ?? resolveNamzuHome());
9530
10336
  ensurePrivateStateDirectory(home, "projects");
9531
10337
  const project = await ensureProject({ home, cwd: cliProjectRoot(cwd) });
9532
10338
  paths = new SessionPaths({ home, slug: project.slug });
9533
10339
  projectId = project.projectId;
9534
10340
  }
9535
- ensurePrivateStateDirectory(resolve8(paths.projectDir(), ".."), paths.slug);
10341
+ ensurePrivateStateDirectory(resolve10(paths.projectDir(), ".."), paths.slug);
9536
10342
  ensurePrivateStateDirectory(paths.projectDir(), "memory");
9537
10343
  } catch (error) {
9538
10344
  return emptySession(
@@ -9801,8 +10607,8 @@ async function createAgentSession(prefs, detected, options = {}) {
9801
10607
  const ownedJobs = jobRegistry ? bindOwner(jobRegistry, jobOwner) : void 0;
9802
10608
  const directories = [];
9803
10609
  for (const dir of options.additionalDirectories ?? []) {
9804
- const absolute = resolve8(cwd, dir);
9805
- if (absolute !== resolve8(cwd) && !directories.includes(absolute)) directories.push(absolute);
10610
+ const absolute = resolve10(cwd, dir);
10611
+ if (absolute !== resolve10(cwd) && !directories.includes(absolute)) directories.push(absolute);
9806
10612
  }
9807
10613
  const sessionDirectories = createSessionDirectories(cwd, directories);
9808
10614
  const checkpoints = new FileCheckpointStore(
@@ -10002,7 +10808,26 @@ async function createAgentSession(prefs, detected, options = {}) {
10002
10808
  webSearchTool = createWebSearchTool();
10003
10809
  toolsets.push(toolset("web-search", [webSearchTool]));
10004
10810
  }
10005
- const webCapability = options.web?.fetch ? { fetch: new GuardedFetchProvider() } : void 0;
10811
+ let sideModel;
10812
+ const webCapability = options.web?.fetch ? {
10813
+ // A page may be ten mebibytes, as in the reference; the guard's own
10814
+ // default is two.
10815
+ fetch: new GuardedFetchProvider({ maxBytes: WEB_FETCH_MAX_BYTES }),
10816
+ // The answer to a prompt about a page comes from the small model. It is
10817
+ // read at call time: the model exists once the delegation runtime does,
10818
+ // and a page fetched without one is returned as markdown instead.
10819
+ extract: {
10820
+ extract: /* @__PURE__ */ __name(async (request) => sideModel?.ask({
10821
+ sessionId: request.sessionId,
10822
+ turnId: request.turnId,
10823
+ instruction: request.instruction,
10824
+ body: request.body,
10825
+ maxTokens: WEB_EXTRACT_MAX_TOKENS,
10826
+ signal: request.signal ?? new AbortController().signal,
10827
+ timing: "in-turn"
10828
+ }), "extract")
10829
+ }
10830
+ } : void 0;
10006
10831
  if (webCapability) toolsets.push(toolset("web-fetch", [WebFetchTool]));
10007
10832
  const delegationScopes = /* @__PURE__ */ new Map();
10008
10833
  const delegationLimits = /* @__PURE__ */ new Map();
@@ -10086,6 +10911,18 @@ async function createAgentSession(prefs, detected, options = {}) {
10086
10911
  )
10087
10912
  ] : [], "savedAgentsSteps");
10088
10913
  const directChildReports = /* @__PURE__ */ new Set();
10914
+ const providerForModel = /* @__PURE__ */ __name(async (invokingSessionId, providerId, selectedModel) => {
10915
+ if (!invokingSessionId && (providerId === "zen" || providerId === "zen-go"))
10916
+ throw new Error("A delegated provider requires its invoking conversation.");
10917
+ await ensureRegistered(providerId);
10918
+ const credential = await currentCredentialFor(providerId);
10919
+ return constructProvider(
10920
+ providerId,
10921
+ providerId === primary.id && credential ? { ...credential, apiKey: currentToken ?? credential.apiKey } : credential,
10922
+ selectedModel,
10923
+ { sessionId: invokingSessionId }
10924
+ );
10925
+ }, "providerForModel");
10089
10926
  let subagentRuntime;
10090
10927
  let allowedAgentIds = [];
10091
10928
  try {
@@ -10200,26 +11037,17 @@ async function createAgentSession(prefs, detected, options = {}) {
10200
11037
  }
10201
11038
  })
10202
11039
  );
10203
- const matches2 = catalogues.flat();
11040
+ const matches = catalogues.flat();
10204
11041
  return JSON.stringify({
10205
- models: matches2.slice(0, 40),
10206
- omitted: Math.max(0, matches2.length - 40),
11042
+ models: matches.slice(0, 40),
11043
+ omitted: Math.max(0, matches.length - 40),
10207
11044
  guidance: "Use exact IDs. Omitted capability fields are unknown, not unsupported. Narrow query when results are omitted."
10208
11045
  });
10209
11046
  }, "listModels"),
10210
11047
  buildProvider: /* @__PURE__ */ __name(async (invokingSessionId, selection) => {
10211
11048
  const providerId = selection ? selection.provider : turnRouteTarget?.provider ?? primary.id;
10212
11049
  const selectedModel = selection?.model ?? turnRouteTarget?.model ?? model;
10213
- if (!invokingSessionId && (providerId === "zen" || providerId === "zen-go"))
10214
- throw new Error("A delegated provider requires its invoking conversation.");
10215
- await ensureRegistered(providerId);
10216
- const credential = await currentCredentialFor(providerId);
10217
- const childProvider = constructProvider(
10218
- providerId,
10219
- providerId === primary.id && credential ? { ...credential, apiKey: currentToken ?? credential.apiKey } : credential,
10220
- selectedModel,
10221
- { sessionId: invokingSessionId }
10222
- );
11050
+ const childProvider = await providerForModel(invokingSessionId, providerId, selectedModel);
10223
11051
  if (selection?.effort) await prepareDelegatedEffort(childProvider, selectedModel);
10224
11052
  return childProvider;
10225
11053
  }, "buildProvider"),
@@ -10242,6 +11070,21 @@ async function createAgentSession(prefs, detected, options = {}) {
10242
11070
  authorizationGate: gateFor(sessionRules)
10243
11071
  });
10244
11072
  subagentRuntime = sub;
11073
+ sideModel = createSideModel({
11074
+ active: /* @__PURE__ */ __name(() => ({
11075
+ providerId: turnRouteTarget?.provider ?? primary.id,
11076
+ model: turnRouteTarget?.model ?? model
11077
+ }), "active"),
11078
+ configured: options.smallModel,
11079
+ isKnownProvider: /* @__PURE__ */ __name((id) => findDetected(detected, id) != null, "isKnownProvider"),
11080
+ buildProvider: /* @__PURE__ */ __name((sessionId, target) => providerForModel(sessionId, target.providerId, target.model), "buildProvider"),
11081
+ offerable: /* @__PURE__ */ __name((providerId, listed) => {
11082
+ const found = findDetected(detected, providerId);
11083
+ return found != null && canSelectModel(found.entry, found.apiKey, listed.id) && isOfferableModel(providerId, listed.id);
11084
+ }, "offerable"),
11085
+ ledger: sub.sideLedger,
11086
+ debug: /* @__PURE__ */ __name((message2, error) => cliLogger().debug(message2, exceptionAttributes(error)), "debug")
11087
+ });
10245
11088
  const agentToolsets = [toolset("agents", [sub.agentTool, sub.waitForTaskTool])];
10246
11089
  if (sub.modelCatalogueTool)
10247
11090
  agentToolsets.push(toolset("agents:model-catalogue", [sub.modelCatalogueTool]));
@@ -10260,7 +11103,7 @@ async function createAgentSession(prefs, detected, options = {}) {
10260
11103
  runsDirectory: /* @__PURE__ */ __name((turnId) => {
10261
11104
  if (options.ephemeral) return void 0;
10262
11105
  const owner = delegationScopes.get(turnId) ?? scope;
10263
- return join13(paths.sessionDir({ sessionId: owner.sessionId }), "runs");
11106
+ return join14(paths.sessionDir({ sessionId: owner.sessionId }), "runs");
10264
11107
  }, "runsDirectory"),
10265
11108
  refusal: /* @__PURE__ */ __name((turnId) => {
10266
11109
  const auth = delegatedWorkflowAuth.get(turnId);
@@ -10343,6 +11186,7 @@ async function createAgentSession(prefs, detected, options = {}) {
10343
11186
  );
10344
11187
  }
10345
11188
  subagentRuntime = void 0;
11189
+ sideModel = void 0;
10346
11190
  cliLogger().warn("sub-agent runtime unavailable this session", exceptionAttributes(err));
10347
11191
  }
10348
11192
  const modelSwitchHandlers = /* @__PURE__ */ new Map();
@@ -10375,6 +11219,13 @@ async function createAgentSession(prefs, detected, options = {}) {
10375
11219
  action: "answer_question",
10376
11220
  selectedOptionIds: [...answer.selectedOptionIds],
10377
11221
  ...answer.freeText !== void 0 ? { freeText: answer.freeText } : {},
11222
+ ...answer.answers ? {
11223
+ answers: answer.answers.map((entry2) => ({
11224
+ questionId: entry2.questionId,
11225
+ selectedOptionIds: [...entry2.selectedOptionIds],
11226
+ ...entry2.freeText !== void 0 ? { freeText: entry2.freeText } : {}
11227
+ }))
11228
+ } : {},
10378
11229
  questionId: request.question.questionId
10379
11230
  };
10380
11231
  case "abort":
@@ -10387,13 +11238,26 @@ async function createAgentSession(prefs, detected, options = {}) {
10387
11238
  toolset("ask-user-question", [buildAskUserQuestionTool({ resumeHandler: parkQuestion })])
10388
11239
  );
10389
11240
  }
11241
+ let currentPlanHost;
11242
+ if (options.planApproval && !options.ephemeral) {
11243
+ toolsets.push(
11244
+ toolset("plan-mode", [
11245
+ buildExitPlanModeTool({
11246
+ mode: /* @__PURE__ */ __name(() => currentPlanHost?.mode() ?? "prompt", "mode"),
11247
+ planPath: /* @__PURE__ */ __name(() => currentPlanHost?.planPath ?? paths.planFile({ sessionId: scope.sessionId }), "planPath"),
11248
+ bypassAvailable: /* @__PURE__ */ __name(() => currentPlanHost?.bypassAvailable() ?? false, "bypassAvailable"),
11249
+ approval: /* @__PURE__ */ __name(() => currentPlanHost?.approval, "approval")
11250
+ })
11251
+ ])
11252
+ );
11253
+ }
10390
11254
  if (options.extraTools && options.extraTools.length > 0) {
10391
11255
  toolsets.push(toolset("extra", options.extraTools));
10392
11256
  }
10393
11257
  if (options.openUrl) toolsets.push(toolset("open-url", [createOpenUrlTool()]));
10394
11258
  const decisionTool = maybeCreateDecisionTool(options.decision, process.env);
10395
11259
  if (decisionTool) toolsets.push(toolset("decide", [decisionTool]));
10396
- const operatorPals = await import("./operator-tools-JRMP2OHZ.js");
11260
+ const operatorPals = await import("./operator-tools-MQXMUQLG.js");
10397
11261
  toolsets.push(
10398
11262
  readyWhen(
10399
11263
  toolset(
@@ -10712,7 +11576,8 @@ async function createAgentSession(prefs, detected, options = {}) {
10712
11576
  (input) => subagentRuntime?.launchesReadOnlyAgent(input) === true
10713
11577
  ),
10714
11578
  { unattendedSandboxEscape },
10715
- screenPolicyFor(() => liveManager())
11579
+ screenPolicyFor(() => liveManager()),
11580
+ options.planApproval && !options.ephemeral ? isPlanFileWrite(paths.planFile({ sessionId: entry2.sessionId }), cwd) : void 0
10716
11581
  ), "handlerFor")
10717
11582
  });
10718
11583
  const resumeHandler = modeControl.handler;
@@ -10905,8 +11770,8 @@ async function createAgentSession(prefs, detected, options = {}) {
10905
11770
  if (mapped) yield mapped;
10906
11771
  }
10907
11772
  if (settled) break;
10908
- await new Promise((resolve9) => {
10909
- wake = resolve9;
11773
+ await new Promise((resolve11) => {
11774
+ wake = resolve11;
10910
11775
  });
10911
11776
  wake = void 0;
10912
11777
  }
@@ -10941,7 +11806,7 @@ async function createAgentSession(prefs, detected, options = {}) {
10941
11806
  return reasoningEffortDefault;
10942
11807
  },
10943
11808
  ...reasoningSettled ? { reasoningSettled } : {},
10944
- compact: /* @__PURE__ */ __name((messages) => operations.promise(void 0, async (signal) => {
11809
+ compact: /* @__PURE__ */ __name((messages, instructions) => operations.promise(void 0, async (signal) => {
10945
11810
  const sessionId = scope.sessionId;
10946
11811
  const sessions = options.conversationSessions;
10947
11812
  await prepareProviderCredential(signal);
@@ -10949,7 +11814,8 @@ async function createAgentSession(prefs, detected, options = {}) {
10949
11814
  config: compactionConfigFor(options.compaction),
10950
11815
  provider: providerForSession(sessionId),
10951
11816
  model,
10952
- signal
11817
+ signal,
11818
+ ...instructions ? { instructions } : {}
10953
11819
  };
10954
11820
  if (sessions && !options.ephemeral) {
10955
11821
  if (sessions.projectId !== scope.projectId || sessions.tenantId !== scope.tenantId)
@@ -11010,7 +11876,7 @@ async function createAgentSession(prefs, detected, options = {}) {
11010
11876
  const live = host.registry.list();
11011
11877
  const known = new Set(live.map((view) => view.runId));
11012
11878
  const saved = options.ephemeral ? [] : await listWorkflowRuns(
11013
- join13(paths.sessionDir({ sessionId: scope.sessionId }), "runs")
11879
+ join14(paths.sessionDir({ sessionId: scope.sessionId }), "runs")
11014
11880
  ).catch(() => []);
11015
11881
  return [
11016
11882
  ...[...live].sort((a, b) => b.startedAt - a.startedAt),
@@ -11025,6 +11891,7 @@ async function createAgentSession(prefs, detected, options = {}) {
11025
11891
  reset: /* @__PURE__ */ __name(() => host.registry.reset(), "reset")
11026
11892
  }))(workflowHost)
11027
11893
  } : {},
11894
+ ...sideModel ? { sideModel } : {},
11028
11895
  ...subagentRuntime ? {
11029
11896
  subagents: subagentRuntime.activity,
11030
11897
  onSubagentReport: /* @__PURE__ */ __name((listener) => {
@@ -11219,6 +12086,13 @@ async function createAgentSession(prefs, detected, options = {}) {
11219
12086
  errorKind: null,
11220
12087
  // Reads the same object the handler mutates, at call time.
11221
12088
  allowForSession: /* @__PURE__ */ __name((allows) => sessionAllows.add(allows), "allowForSession"),
12089
+ notifyHooks: /* @__PURE__ */ __name((info) => {
12090
+ if (!sessionPlugins) return;
12091
+ void sessionPlugins.manager.executeHooks("notification", {
12092
+ sessionId: scope.sessionId,
12093
+ notification: info
12094
+ }).catch(() => []);
12095
+ }, "notifyHooks"),
11222
12096
  commandArguments,
11223
12097
  setPermissionMode: /* @__PURE__ */ __name(async (mode, reason) => {
11224
12098
  await Promise.all(
@@ -11239,6 +12113,8 @@ async function createAgentSession(prefs, detected, options = {}) {
11239
12113
  let runManager = manager;
11240
12114
  lastSendInteractive = opts?.onPermission !== void 0;
11241
12115
  const turnScope = { ...scope };
12116
+ const planPath = options.planApproval && !options.ephemeral ? paths.planFile({ sessionId: turnScope.sessionId }) : void 0;
12117
+ const planModeWrite = planPath ? isPlanFileWrite(planPath, cwd) : void 0;
11242
12118
  const initialMode = opts?.permissionMode ?? options.permissionMode ?? (opts?.onPermission || opts?.reviewHold ? "prompt" : "auto");
11243
12119
  const modeControl = createLiveModeControl({
11244
12120
  initial: initialMode,
@@ -11264,7 +12140,8 @@ async function createAgentSession(prefs, detected, options = {}) {
11264
12140
  (input) => subagentRuntime?.launchesReadOnlyAgent(input) === true
11265
12141
  ),
11266
12142
  { unattendedSandboxEscape },
11267
- screenPolicyFor(() => runManager)
12143
+ screenPolicyFor(() => runManager),
12144
+ planModeWrite
11268
12145
  ), "handlerFor")
11269
12146
  });
11270
12147
  const resumeHandler = modeControl.handler;
@@ -11315,6 +12192,12 @@ async function createAgentSession(prefs, detected, options = {}) {
11315
12192
  }
11316
12193
  const curatedMemoryPrompt = composeMemoryPrompt(curatedMemory);
11317
12194
  currentOnQuestion = opts?.onQuestion;
12195
+ currentPlanHost = planPath ? {
12196
+ mode: /* @__PURE__ */ __name(() => modeControl.current(), "mode"),
12197
+ planPath,
12198
+ approval: opts?.onPlanExit,
12199
+ bypassAvailable: opts?.bypassAvailable ?? (() => false)
12200
+ } : void 0;
11318
12201
  const [environmentFacts, turnSnapshot] = await Promise.all([
11319
12202
  readEnvironmentFacts(cwd),
11320
12203
  readTurnSnapshot(cwd)
@@ -11432,7 +12315,7 @@ async function createAgentSession(prefs, detected, options = {}) {
11432
12315
  // Present only while the turn runs under `plan`. A mode change
11433
12316
  // is rare, so the cached prefix it re-keys is a price paid once
11434
12317
  // per switch rather than once per turn.
11435
- !residentContext && opts?.permissionMode === "plan" ? PLAN_MODE_DOCTRINE : void 0,
12318
+ !residentContext && opts?.permissionMode === "plan" ? planPath ? NAMZU_PLAN_FILE_DOCTRINE : PLAN_MODE_DOCTRINE : void 0,
11436
12319
  residentContext ? void 0 : environmentPrompt,
11437
12320
  residentContext ? void 0 : opts?.extraSystem,
11438
12321
  residentContext ? void 0 : opts?.systemNote,
@@ -11453,6 +12336,14 @@ async function createAgentSession(prefs, detected, options = {}) {
11453
12336
  }
11454
12337
  claimTurn(turnId);
11455
12338
  const turnTaskStore = selectTaskStore(turnScope);
12339
+ const reminderSource = options.reminders ? createCliReminderSource({
12340
+ mode: /* @__PURE__ */ __name(() => modeControl.current(), "mode"),
12341
+ ...planPath ? {
12342
+ planPath: /* @__PURE__ */ __name(() => planPath, "planPath"),
12343
+ canAsk: Boolean(options.askUser && subagentRuntime)
12344
+ } : {},
12345
+ tasks: /* @__PURE__ */ __name(() => turnTaskStore.list({ sessionId: turnScope.sessionId }), "tasks")
12346
+ }) : void 0;
11456
12347
  let ephemeralLog;
11457
12348
  if (options.ephemeral) {
11458
12349
  ephemeralLog = new InMemorySessionLog({
@@ -11535,6 +12426,7 @@ async function createAgentSession(prefs, detected, options = {}) {
11535
12426
  ...memoryContextSteps(curatedMemoryPrompt, storedMemory.prompt)
11536
12427
  ],
11537
12428
  taskStore: turnTaskStore,
12429
+ ...reminderSource ? { reminders: reminderSource } : {},
11538
12430
  systemPrompt,
11539
12431
  messages,
11540
12432
  projectInstructionContext: projectInstructions.createTurnContext(),
@@ -11975,13 +12867,17 @@ function gateFor(rules) {
11975
12867
  return { ...VERIFICATION_GATE, rules: [...rules ?? []] };
11976
12868
  }
11977
12869
  __name(gateFor, "gateFor");
12870
+ var MAX_OUTPUT_CONTINUATIONS = 3;
11978
12871
  var COMPACTION_CONFIG = {
11979
12872
  strategy: "salience",
12873
+ // Give up on compaction that keeps failing or keeps refilling, and say so
12874
+ // once. The kernel leaves this off, so the CLI asks.
12875
+ circuitBreaker: true,
11980
12876
  // On, and this is the CLI making a choice rather than taking a default.
11981
12877
  // A session's transcript is the only record of what was compacted away;
11982
12878
  // the size trade this costs is the operator's to see and turn off.
11983
12879
  recordShedHistory: true,
11984
- triggerThreshold: 0.7,
12880
+ // No `triggerThreshold`: the kernel derives it from the model's window.
11985
12881
  resetThreshold: 0.4,
11986
12882
  keepRecentMessages: 6,
11987
12883
  // Reclaim from stale tool output before summarizing. A CLI session is
@@ -12049,6 +12945,7 @@ async function* runTurn({
12049
12945
  onApprovalPolicy,
12050
12946
  reviewAllowedCalls,
12051
12947
  taskStore,
12948
+ reminders,
12052
12949
  systemPrompt,
12053
12950
  messages,
12054
12951
  projectInstructionContext,
@@ -12073,6 +12970,7 @@ async function* runTurn({
12073
12970
  const readsOnly = declaredReadOnly(turnManager);
12074
12971
  try {
12075
12972
  const events = query({
12973
+ maxOutputContinuations: MAX_OUTPUT_CONTINUATIONS,
12076
12974
  ...retainedToolPreviewChars !== void 0 ? { retainedToolPreviewChars } : {},
12077
12975
  ...fileReadTracker ? { fileReadTracker } : {},
12078
12976
  ...structuredOutput ? { structuredOutput } : {},
@@ -12133,6 +13031,7 @@ async function* runTurn({
12133
13031
  ...systemPrompt ? { systemPrompt } : {},
12134
13032
  projectInstructionContext,
12135
13033
  messages: [...messages],
13034
+ ...reminders ? { reminders } : {},
12136
13035
  ...opts?.inboundMessages ? { inboundMessages: opts.inboundMessages } : {},
12137
13036
  ...opts?.waitForInbound ? { waitForInbound: opts.waitForInbound } : {},
12138
13037
  ...opts?.durableInbound ? { durableInbound: opts.durableInbound } : {},
@@ -12206,12 +13105,13 @@ async function* runTurn({
12206
13105
  }
12207
13106
  }
12208
13107
  __name(runTurn, "runTurn");
12209
- function makeResumeHandler(approval, onPermission, mode = onPermission ? "prompt" : "auto", exempt = () => false, escapePolicy = {}, screen) {
13108
+ function makeResumeHandler(approval, onPermission, mode = onPermission ? "prompt" : "auto", exempt = () => false, escapePolicy = {}, screen, planModeWrite) {
12210
13109
  return createReviewHandler({
12211
13110
  mode,
12212
13111
  prompt: onPermission,
12213
13112
  exempt,
12214
13113
  remembered: approval,
13114
+ ...planModeWrite ? { planModeWrite } : {},
12215
13115
  ...screen ? { screenConsent: screen.consent, capturesScreen: screen.capturesScreen } : {},
12216
13116
  // Refused unless the operator wrote `sandbox.allowUnattendedEscape`: a
12217
13117
  // session with nobody to ask has nobody to consent to leaving the
@@ -12270,7 +13170,9 @@ function withRuntimeMountedTools(manager) {
12270
13170
  __name(withRuntimeMountedTools, "withRuntimeMountedTools");
12271
13171
  function reviewExemptionFor(mode, manager, launchesReadOnlyAgent) {
12272
13172
  const exemptLookup = withRuntimeMountedTools(manager);
12273
- return (name, input) => isPromptExempt(exemptLookup, name, input) || mode !== "strict" && name === AGENT_LAUNCH_TOOL && launchesReadOnlyAgent(input) || mode !== "strict" && mode !== "plan" && confirmsItself(name, input) || mode !== "strict" && mode !== "plan" && name === SAVE_SKILL_TOOL_NAME && manager.has(SAVE_SKILL_TOOL_NAME);
13173
+ return (name, input) => isPromptExempt(exemptLookup, name, input) || // Presenting a plan asks the person on its own screen and changes nothing;
13174
+ // `plan` is the one mode it is for. Outside it the tool refuses by itself.
13175
+ name === EXIT_PLAN_MODE_TOOL_NAME && manager.has(EXIT_PLAN_MODE_TOOL_NAME) || mode !== "strict" && name === AGENT_LAUNCH_TOOL && launchesReadOnlyAgent(input) || mode !== "strict" && mode !== "plan" && confirmsItself(name, input) || mode !== "strict" && mode !== "plan" && name === SAVE_SKILL_TOOL_NAME && manager.has(SAVE_SKILL_TOOL_NAME);
12274
13176
  }
12275
13177
  __name(reviewExemptionFor, "reviewExemptionFor");
12276
13178
  function confirmsItself(name, input) {
@@ -12335,6 +13237,21 @@ function toAgentEvent(event, presenter, readsOnly) {
12335
13237
  ...event.messageId ? { messageId: event.messageId } : {},
12336
13238
  ...event.turnId ? { turnId: event.turnId } : {}
12337
13239
  };
13240
+ case "plugin_hook_completed": {
13241
+ const result = event.result;
13242
+ if ((result.action === "continue" || result.action === "skip") && result.halt) {
13243
+ return {
13244
+ kind: "hook-notice",
13245
+ text: `A hook stopped this turn: ${result.halt.reason}`
13246
+ };
13247
+ }
13248
+ if ((result.action === "continue" || result.action === "skip") && result.notice) {
13249
+ return { kind: "hook-notice", text: `A hook says: ${result.notice}` };
13250
+ }
13251
+ return null;
13252
+ }
13253
+ case "plugin_hook_executing":
13254
+ return event.statusMessage ? { kind: "hook-status", text: event.statusMessage } : null;
12338
13255
  case "reasoning_started":
12339
13256
  return { kind: "reasoning", text: "" };
12340
13257
  case "reasoning_delta":
@@ -12585,6 +13502,10 @@ function describeCompactionFailure(event) {
12585
13502
  return `context could not be reduced further \u2014 nothing left to shed. ${held}; later passes will answer the same`;
12586
13503
  case "split_tool_pair":
12587
13504
  return `context not compacted \u2014 the reducer produced a history splitting a tool call from its result, so it was refused. ${held}; this is a bug in the reducer`;
13505
+ case "breaker_open":
13506
+ return event.error ?? "Automatic compaction stopped after three failed attempts. Run /compact yourself, or start fresh with /clear.";
13507
+ case "refilling":
13508
+ return event.error ?? "The context filled up again right after being compacted, three times in a row. Read big files in smaller parts, or start fresh with /clear.";
12588
13509
  }
12589
13510
  }
12590
13511
  __name(describeCompactionFailure, "describeCompactionFailure");
@@ -12882,6 +13803,8 @@ export {
12882
13803
  renderStoredMemorySection,
12883
13804
  allowsForBatch,
12884
13805
  describeAllows,
13806
+ KEEP_PLANNING_PLACEHOLDER,
13807
+ planApprovalRows,
12885
13808
  assistantTranscriptTexts,
12886
13809
  projectTurnConversation,
12887
13810
  resolveModelSwitch,
@@ -12911,4 +13834,4 @@ export {
12911
13834
  RESULT_SUMMARY_WHOLE_MAX,
12912
13835
  resultSummaryLine
12913
13836
  };
12914
- //# sourceMappingURL=chunk-IKGTBMN2.js.map
13837
+ //# sourceMappingURL=chunk-BXJ7G5XN.js.map