@caupulican/pi-adaptative 0.81.40 → 0.81.42

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 (599) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -1
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +1 -0
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -1
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +1 -0
  6. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/text.py +5 -1
  7. package/dist/bundled-resources/runtimes/pi-shell-engine/context.py +3 -3
  8. package/dist/bundled-resources/runtimes/pi-shell-engine/errors.py +8 -0
  9. package/dist/bundled-resources/runtimes/pi-shell-engine/exec.py +26 -3
  10. package/dist/bundled-resources/runtimes/pi-shell-engine/expand.py +3 -0
  11. package/dist/bundled-resources/runtimes/pi-shell-engine/main.py +4 -1
  12. package/dist/bundled-resources/runtimes/pi-shell-engine/state.py +2 -1
  13. package/dist/bundled-resources/runtimes/pi-shell-engine/tokens.py +2 -0
  14. package/dist/cli/args.d.ts +2 -0
  15. package/dist/cli/args.d.ts.map +1 -1
  16. package/dist/cli/args.js +22 -1
  17. package/dist/cli/args.js.map +1 -1
  18. package/dist/core/agent-paths.d.ts +38 -0
  19. package/dist/core/agent-paths.d.ts.map +1 -1
  20. package/dist/core/agent-paths.js +77 -0
  21. package/dist/core/agent-paths.js.map +1 -1
  22. package/dist/core/agent-session-contracts.d.ts +311 -0
  23. package/dist/core/agent-session-contracts.d.ts.map +1 -0
  24. package/dist/core/agent-session-contracts.js +26 -0
  25. package/dist/core/agent-session-contracts.js.map +1 -0
  26. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  27. package/dist/core/agent-session-runtime.js +3 -0
  28. package/dist/core/agent-session-runtime.js.map +1 -1
  29. package/dist/core/agent-session.d.ts +26 -405
  30. package/dist/core/agent-session.d.ts.map +1 -1
  31. package/dist/core/agent-session.js +90 -316
  32. package/dist/core/agent-session.js.map +1 -1
  33. package/dist/core/auth-storage.d.ts.map +1 -1
  34. package/dist/core/auth-storage.js +3 -1
  35. package/dist/core/auth-storage.js.map +1 -1
  36. package/dist/core/autonomy/contracts.d.ts +2 -0
  37. package/dist/core/autonomy/contracts.d.ts.map +1 -1
  38. package/dist/core/autonomy/contracts.js.map +1 -1
  39. package/dist/core/autonomy/envelope-enforcement.d.ts.map +1 -1
  40. package/dist/core/autonomy/envelope-enforcement.js +4 -9
  41. package/dist/core/autonomy/envelope-enforcement.js.map +1 -1
  42. package/dist/core/autonomy/lane-tool-surface.d.ts +3 -1
  43. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  44. package/dist/core/autonomy/lane-tool-surface.js +19 -5
  45. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  46. package/dist/core/autonomy/path-scope.d.ts +14 -0
  47. package/dist/core/autonomy/path-scope.d.ts.map +1 -1
  48. package/dist/core/autonomy/path-scope.js +37 -6
  49. package/dist/core/autonomy/path-scope.js.map +1 -1
  50. package/dist/core/background-lane-controller.d.ts +30 -2
  51. package/dist/core/background-lane-controller.d.ts.map +1 -1
  52. package/dist/core/background-lane-controller.js +33 -1
  53. package/dist/core/background-lane-controller.js.map +1 -1
  54. package/dist/core/bedrock-sso-login.d.ts +16 -0
  55. package/dist/core/bedrock-sso-login.d.ts.map +1 -0
  56. package/dist/core/bedrock-sso-login.js +98 -0
  57. package/dist/core/bedrock-sso-login.js.map +1 -0
  58. package/dist/core/compaction-controller.d.ts.map +1 -1
  59. package/dist/core/compaction-controller.js +1 -1
  60. package/dist/core/compaction-controller.js.map +1 -1
  61. package/dist/core/compaction-support.d.ts +3 -8
  62. package/dist/core/compaction-support.d.ts.map +1 -1
  63. package/dist/core/compaction-support.js +3 -3
  64. package/dist/core/compaction-support.js.map +1 -1
  65. package/dist/core/context-pipeline.d.ts +1 -1
  66. package/dist/core/context-pipeline.d.ts.map +1 -1
  67. package/dist/core/context-pipeline.js +7 -33
  68. package/dist/core/context-pipeline.js.map +1 -1
  69. package/dist/core/cost/cost-summary.d.ts.map +1 -1
  70. package/dist/core/cost/cost-summary.js +5 -3
  71. package/dist/core/cost/cost-summary.js.map +1 -1
  72. package/dist/core/cost/daily-usage.d.ts.map +1 -1
  73. package/dist/core/cost/daily-usage.js +4 -5
  74. package/dist/core/cost/daily-usage.js.map +1 -1
  75. package/dist/core/default-tool-surface.d.ts.map +1 -1
  76. package/dist/core/default-tool-surface.js +1 -0
  77. package/dist/core/default-tool-surface.js.map +1 -1
  78. package/dist/core/delegation/managed-lane-controller.d.ts +11 -1
  79. package/dist/core/delegation/managed-lane-controller.d.ts.map +1 -1
  80. package/dist/core/delegation/managed-lane-controller.js +84 -41
  81. package/dist/core/delegation/managed-lane-controller.js.map +1 -1
  82. package/dist/core/delegation/session-worker-claim.d.ts.map +1 -1
  83. package/dist/core/delegation/session-worker-claim.js +4 -3
  84. package/dist/core/delegation/session-worker-claim.js.map +1 -1
  85. package/dist/core/delegation/worker-action-journal.d.ts +73 -0
  86. package/dist/core/delegation/worker-action-journal.d.ts.map +1 -0
  87. package/dist/core/delegation/worker-action-journal.js +297 -0
  88. package/dist/core/delegation/worker-action-journal.js.map +1 -0
  89. package/dist/core/delegation/worker-actions.d.ts +36 -1
  90. package/dist/core/delegation/worker-actions.d.ts.map +1 -1
  91. package/dist/core/delegation/worker-actions.js +171 -46
  92. package/dist/core/delegation/worker-actions.js.map +1 -1
  93. package/dist/core/delegation/worker-agent-control-coordinator.d.ts +75 -0
  94. package/dist/core/delegation/worker-agent-control-coordinator.d.ts.map +1 -0
  95. package/dist/core/delegation/worker-agent-control-coordinator.js +218 -0
  96. package/dist/core/delegation/worker-agent-control-coordinator.js.map +1 -0
  97. package/dist/core/delegation/worker-agent-control.d.ts +66 -0
  98. package/dist/core/delegation/worker-agent-control.d.ts.map +1 -0
  99. package/dist/core/delegation/worker-agent-control.js +163 -0
  100. package/dist/core/delegation/worker-agent-control.js.map +1 -0
  101. package/dist/core/delegation/worker-attempt-executor.d.ts +80 -0
  102. package/dist/core/delegation/worker-attempt-executor.d.ts.map +1 -0
  103. package/dist/core/delegation/worker-attempt-executor.js +343 -0
  104. package/dist/core/delegation/worker-attempt-executor.js.map +1 -0
  105. package/dist/core/delegation/worker-claim.d.ts +30 -0
  106. package/dist/core/delegation/worker-claim.d.ts.map +1 -1
  107. package/dist/core/delegation/worker-claim.js +205 -53
  108. package/dist/core/delegation/worker-claim.js.map +1 -1
  109. package/dist/core/delegation/worker-conversation-store.d.ts +116 -0
  110. package/dist/core/delegation/worker-conversation-store.d.ts.map +1 -0
  111. package/dist/core/delegation/worker-conversation-store.js +442 -0
  112. package/dist/core/delegation/worker-conversation-store.js.map +1 -0
  113. package/dist/core/delegation/worker-delegation-controller.d.ts +21 -5
  114. package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -1
  115. package/dist/core/delegation/worker-delegation-controller.js +386 -251
  116. package/dist/core/delegation/worker-delegation-controller.js.map +1 -1
  117. package/dist/core/delegation/worker-delegation-request.d.ts +14 -0
  118. package/dist/core/delegation/worker-delegation-request.d.ts.map +1 -1
  119. package/dist/core/delegation/worker-delegation-request.js.map +1 -1
  120. package/dist/core/delegation/worker-dispatch-scheduler.d.ts +4 -2
  121. package/dist/core/delegation/worker-dispatch-scheduler.d.ts.map +1 -1
  122. package/dist/core/delegation/worker-dispatch-scheduler.js +16 -6
  123. package/dist/core/delegation/worker-dispatch-scheduler.js.map +1 -1
  124. package/dist/core/delegation/worker-execution-policy.d.ts +2 -1
  125. package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -1
  126. package/dist/core/delegation/worker-execution-policy.js +5 -7
  127. package/dist/core/delegation/worker-execution-policy.js.map +1 -1
  128. package/dist/core/delegation/worker-lifecycle.d.ts +44 -1
  129. package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -1
  130. package/dist/core/delegation/worker-lifecycle.js +120 -0
  131. package/dist/core/delegation/worker-lifecycle.js.map +1 -1
  132. package/dist/core/delegation/worker-process-owner.d.ts +18 -0
  133. package/dist/core/delegation/worker-process-owner.d.ts.map +1 -0
  134. package/dist/core/delegation/worker-process-owner.js +54 -0
  135. package/dist/core/delegation/worker-process-owner.js.map +1 -0
  136. package/dist/core/delegation/worker-profile-resolver.d.ts +5 -1
  137. package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -1
  138. package/dist/core/delegation/worker-profile-resolver.js +8 -0
  139. package/dist/core/delegation/worker-profile-resolver.js.map +1 -1
  140. package/dist/core/delegation/worker-recovery-coordinator.d.ts +54 -0
  141. package/dist/core/delegation/worker-recovery-coordinator.d.ts.map +1 -0
  142. package/dist/core/delegation/worker-recovery-coordinator.js +181 -0
  143. package/dist/core/delegation/worker-recovery-coordinator.js.map +1 -0
  144. package/dist/core/delegation/worker-resource-catalog.d.ts +32 -0
  145. package/dist/core/delegation/worker-resource-catalog.d.ts.map +1 -0
  146. package/dist/core/delegation/worker-resource-catalog.js +116 -0
  147. package/dist/core/delegation/worker-resource-catalog.js.map +1 -0
  148. package/dist/core/delegation/worker-resource-materializer.d.ts +47 -0
  149. package/dist/core/delegation/worker-resource-materializer.d.ts.map +1 -0
  150. package/dist/core/delegation/worker-resource-materializer.js +137 -0
  151. package/dist/core/delegation/worker-resource-materializer.js.map +1 -0
  152. package/dist/core/delegation/worker-runner.d.ts +3 -1
  153. package/dist/core/delegation/worker-runner.d.ts.map +1 -1
  154. package/dist/core/delegation/worker-runner.js +189 -54
  155. package/dist/core/delegation/worker-runner.js.map +1 -1
  156. package/dist/core/delegation/worker-terminal-finalizer.d.ts +23 -0
  157. package/dist/core/delegation/worker-terminal-finalizer.d.ts.map +1 -0
  158. package/dist/core/delegation/worker-terminal-finalizer.js +12 -0
  159. package/dist/core/delegation/worker-terminal-finalizer.js.map +1 -0
  160. package/dist/core/delegation/worker-write-reservation-coordinator.d.ts +38 -0
  161. package/dist/core/delegation/worker-write-reservation-coordinator.d.ts.map +1 -0
  162. package/dist/core/delegation/worker-write-reservation-coordinator.js +107 -0
  163. package/dist/core/delegation/worker-write-reservation-coordinator.js.map +1 -0
  164. package/dist/core/delegation/worker-write-reservation.d.ts +90 -0
  165. package/dist/core/delegation/worker-write-reservation.d.ts.map +1 -0
  166. package/dist/core/delegation/worker-write-reservation.js +348 -0
  167. package/dist/core/delegation/worker-write-reservation.js.map +1 -0
  168. package/dist/core/extension-import-authority.d.ts +6 -0
  169. package/dist/core/extension-import-authority.d.ts.map +1 -0
  170. package/dist/core/extension-import-authority.js +10 -0
  171. package/dist/core/extension-import-authority.js.map +1 -0
  172. package/dist/core/extensions/loader.d.ts.map +1 -1
  173. package/dist/core/extensions/loader.js +2 -3
  174. package/dist/core/extensions/loader.js.map +1 -1
  175. package/dist/core/extensions/runner.d.ts +3 -0
  176. package/dist/core/extensions/runner.d.ts.map +1 -1
  177. package/dist/core/extensions/runner.js +14 -5
  178. package/dist/core/extensions/runner.js.map +1 -1
  179. package/dist/core/extensions/stale-context.d.ts +2 -0
  180. package/dist/core/extensions/stale-context.d.ts.map +1 -0
  181. package/dist/core/extensions/stale-context.js +2 -0
  182. package/dist/core/extensions/stale-context.js.map +1 -0
  183. package/dist/core/extensions/types.d.ts +8 -0
  184. package/dist/core/extensions/types.d.ts.map +1 -1
  185. package/dist/core/extensions/types.js.map +1 -1
  186. package/dist/core/foreground-recovery-controller.d.ts +1 -0
  187. package/dist/core/foreground-recovery-controller.d.ts.map +1 -1
  188. package/dist/core/foreground-recovery-controller.js +13 -13
  189. package/dist/core/foreground-recovery-controller.js.map +1 -1
  190. package/dist/core/goal-loop-controller.d.ts +14 -9
  191. package/dist/core/goal-loop-controller.d.ts.map +1 -1
  192. package/dist/core/goal-loop-controller.js +47 -75
  193. package/dist/core/goal-loop-controller.js.map +1 -1
  194. package/dist/core/goals/compact-goal-context.d.ts +11 -0
  195. package/dist/core/goals/compact-goal-context.d.ts.map +1 -0
  196. package/dist/core/goals/compact-goal-context.js +59 -0
  197. package/dist/core/goals/compact-goal-context.js.map +1 -0
  198. package/dist/core/goals/goal-acceptance.d.ts.map +1 -1
  199. package/dist/core/goals/goal-acceptance.js +2 -0
  200. package/dist/core/goals/goal-acceptance.js.map +1 -1
  201. package/dist/core/goals/goal-auto-continue-controller.d.ts +2 -1
  202. package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -1
  203. package/dist/core/goals/goal-auto-continue-controller.js +5 -8
  204. package/dist/core/goals/goal-auto-continue-controller.js.map +1 -1
  205. package/dist/core/goals/goal-continuation-controller.d.ts +2 -2
  206. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  207. package/dist/core/goals/goal-continuation-controller.js +42 -11
  208. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  209. package/dist/core/goals/goal-continuation-defaults.d.ts +4 -29
  210. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
  211. package/dist/core/goals/goal-continuation-defaults.js +4 -32
  212. package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
  213. package/dist/core/goals/goal-continuation-prompt.d.ts +8 -18
  214. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  215. package/dist/core/goals/goal-continuation-prompt.js +9 -179
  216. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  217. package/dist/core/goals/goal-lifecycle.d.ts +35 -12
  218. package/dist/core/goals/goal-lifecycle.d.ts.map +1 -1
  219. package/dist/core/goals/goal-lifecycle.js +98 -13
  220. package/dist/core/goals/goal-lifecycle.js.map +1 -1
  221. package/dist/core/goals/goal-record.d.ts +17 -0
  222. package/dist/core/goals/goal-record.d.ts.map +1 -0
  223. package/dist/core/goals/goal-record.js +31 -0
  224. package/dist/core/goals/goal-record.js.map +1 -0
  225. package/dist/core/goals/goal-session-controller.d.ts +42 -0
  226. package/dist/core/goals/goal-session-controller.d.ts.map +1 -0
  227. package/dist/core/goals/goal-session-controller.js +128 -0
  228. package/dist/core/goals/goal-session-controller.js.map +1 -0
  229. package/dist/core/goals/goal-state.d.ts +45 -25
  230. package/dist/core/goals/goal-state.d.ts.map +1 -1
  231. package/dist/core/goals/goal-state.js +85 -15
  232. package/dist/core/goals/goal-state.js.map +1 -1
  233. package/dist/core/goals/goal-tool-core.d.ts +1 -4
  234. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  235. package/dist/core/goals/goal-tool-core.js +49 -34
  236. package/dist/core/goals/goal-tool-core.js.map +1 -1
  237. package/dist/core/goals/session-goal-state.d.ts +18 -8
  238. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  239. package/dist/core/goals/session-goal-state.js +134 -11
  240. package/dist/core/goals/session-goal-state.js.map +1 -1
  241. package/dist/core/human-input-controller.d.ts +47 -0
  242. package/dist/core/human-input-controller.d.ts.map +1 -0
  243. package/dist/core/human-input-controller.js +181 -0
  244. package/dist/core/human-input-controller.js.map +1 -0
  245. package/dist/core/local-runtime-controller.d.ts +1 -1
  246. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  247. package/dist/core/local-runtime-controller.js.map +1 -1
  248. package/dist/core/model-capability.d.ts +0 -19
  249. package/dist/core/model-capability.d.ts.map +1 -1
  250. package/dist/core/model-capability.js +0 -19
  251. package/dist/core/model-capability.js.map +1 -1
  252. package/dist/core/model-registry.d.ts +6 -1
  253. package/dist/core/model-registry.d.ts.map +1 -1
  254. package/dist/core/model-registry.js +13 -5
  255. package/dist/core/model-registry.js.map +1 -1
  256. package/dist/core/model-resolver.d.ts +16 -1
  257. package/dist/core/model-resolver.d.ts.map +1 -1
  258. package/dist/core/model-resolver.js +32 -16
  259. package/dist/core/model-resolver.js.map +1 -1
  260. package/dist/core/model-router-controller.d.ts +1 -1
  261. package/dist/core/model-router-controller.d.ts.map +1 -1
  262. package/dist/core/model-router-controller.js.map +1 -1
  263. package/dist/core/model-selection-controller.d.ts +1 -1
  264. package/dist/core/model-selection-controller.d.ts.map +1 -1
  265. package/dist/core/model-selection-controller.js.map +1 -1
  266. package/dist/core/models/model-endpoint.d.ts +3 -0
  267. package/dist/core/models/model-endpoint.d.ts.map +1 -0
  268. package/dist/core/models/model-endpoint.js +11 -0
  269. package/dist/core/models/model-endpoint.js.map +1 -0
  270. package/dist/core/orchestration/agent-resume.d.ts +2 -0
  271. package/dist/core/orchestration/agent-resume.d.ts.map +1 -1
  272. package/dist/core/orchestration/agent-resume.js +7 -0
  273. package/dist/core/orchestration/agent-resume.js.map +1 -1
  274. package/dist/core/orchestration/attempt-usage.d.ts +28 -0
  275. package/dist/core/orchestration/attempt-usage.d.ts.map +1 -0
  276. package/dist/core/orchestration/attempt-usage.js +168 -0
  277. package/dist/core/orchestration/attempt-usage.js.map +1 -0
  278. package/dist/core/orchestration/capability-gateway.d.ts +19 -1
  279. package/dist/core/orchestration/capability-gateway.d.ts.map +1 -1
  280. package/dist/core/orchestration/capability-gateway.js +128 -28
  281. package/dist/core/orchestration/capability-gateway.js.map +1 -1
  282. package/dist/core/orchestration/contracts.d.ts +35 -0
  283. package/dist/core/orchestration/contracts.d.ts.map +1 -1
  284. package/dist/core/orchestration/contracts.js +17 -0
  285. package/dist/core/orchestration/contracts.js.map +1 -1
  286. package/dist/core/orchestration/delegation-ledger.d.ts +17 -2
  287. package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -1
  288. package/dist/core/orchestration/delegation-ledger.js +81 -3
  289. package/dist/core/orchestration/delegation-ledger.js.map +1 -1
  290. package/dist/core/orchestration/event-store.d.ts +1 -0
  291. package/dist/core/orchestration/event-store.d.ts.map +1 -1
  292. package/dist/core/orchestration/event-store.js +78 -38
  293. package/dist/core/orchestration/event-store.js.map +1 -1
  294. package/dist/core/orchestration/profile-registry.d.ts.map +1 -1
  295. package/dist/core/orchestration/profile-registry.js +81 -41
  296. package/dist/core/orchestration/profile-registry.js.map +1 -1
  297. package/dist/core/orchestration/profile-store.d.ts.map +1 -1
  298. package/dist/core/orchestration/profile-store.js +18 -4
  299. package/dist/core/orchestration/profile-store.js.map +1 -1
  300. package/dist/core/orchestration/risk-budget.d.ts +2 -0
  301. package/dist/core/orchestration/risk-budget.d.ts.map +1 -1
  302. package/dist/core/orchestration/risk-budget.js +26 -0
  303. package/dist/core/orchestration/risk-budget.js.map +1 -1
  304. package/dist/core/orchestration/task-runtime.d.ts +13 -1
  305. package/dist/core/orchestration/task-runtime.d.ts.map +1 -1
  306. package/dist/core/orchestration/task-runtime.js +127 -16
  307. package/dist/core/orchestration/task-runtime.js.map +1 -1
  308. package/dist/core/orchestration/work-state-projection.d.ts.map +1 -1
  309. package/dist/core/orchestration/work-state-projection.js +1 -1
  310. package/dist/core/orchestration/work-state-projection.js.map +1 -1
  311. package/dist/core/orchestration/worker-execution-contract.d.ts +3 -1
  312. package/dist/core/orchestration/worker-execution-contract.d.ts.map +1 -1
  313. package/dist/core/orchestration/worker-execution-contract.js +75 -23
  314. package/dist/core/orchestration/worker-execution-contract.js.map +1 -1
  315. package/dist/core/orchestration/worker-result-adapter.d.ts +9 -3
  316. package/dist/core/orchestration/worker-result-adapter.d.ts.map +1 -1
  317. package/dist/core/orchestration/worker-result-adapter.js +167 -14
  318. package/dist/core/orchestration/worker-result-adapter.js.map +1 -1
  319. package/dist/core/package-manager.d.ts.map +1 -1
  320. package/dist/core/package-manager.js +20 -3
  321. package/dist/core/package-manager.js.map +1 -1
  322. package/dist/core/profile-filter-controller.d.ts +8 -1
  323. package/dist/core/profile-filter-controller.d.ts.map +1 -1
  324. package/dist/core/profile-filter-controller.js +23 -5
  325. package/dist/core/profile-filter-controller.js.map +1 -1
  326. package/dist/core/prompt-templates.d.ts +1 -0
  327. package/dist/core/prompt-templates.d.ts.map +1 -1
  328. package/dist/core/prompt-templates.js +18 -29
  329. package/dist/core/prompt-templates.js.map +1 -1
  330. package/dist/core/reflection-controller.d.ts +2 -2
  331. package/dist/core/reflection-controller.d.ts.map +1 -1
  332. package/dist/core/reflection-controller.js +92 -54
  333. package/dist/core/reflection-controller.js.map +1 -1
  334. package/dist/core/request-auth.d.ts +7 -0
  335. package/dist/core/request-auth.d.ts.map +1 -0
  336. package/dist/core/request-auth.js +8 -0
  337. package/dist/core/request-auth.js.map +1 -0
  338. package/dist/core/research/evidence-bundle.d.ts +20 -0
  339. package/dist/core/research/evidence-bundle.d.ts.map +1 -1
  340. package/dist/core/research/evidence-bundle.js +173 -69
  341. package/dist/core/research/evidence-bundle.js.map +1 -1
  342. package/dist/core/resource-loader.d.ts.map +1 -1
  343. package/dist/core/resource-loader.js +16 -6
  344. package/dist/core/resource-loader.js.map +1 -1
  345. package/dist/core/risk-classifier.d.ts.map +1 -1
  346. package/dist/core/risk-classifier.js +8 -0
  347. package/dist/core/risk-classifier.js.map +1 -1
  348. package/dist/core/runtime-builder.d.ts +22 -3
  349. package/dist/core/runtime-builder.d.ts.map +1 -1
  350. package/dist/core/runtime-builder.js +147 -80
  351. package/dist/core/runtime-builder.js.map +1 -1
  352. package/dist/core/sdk.d.ts.map +1 -1
  353. package/dist/core/sdk.js +7 -1
  354. package/dist/core/sdk.js.map +1 -1
  355. package/dist/core/secrets/credential-exposure-guard.d.ts +9 -0
  356. package/dist/core/secrets/credential-exposure-guard.d.ts.map +1 -0
  357. package/dist/core/secrets/credential-exposure-guard.js +241 -0
  358. package/dist/core/secrets/credential-exposure-guard.js.map +1 -0
  359. package/dist/core/secrets/secret-dotenv.d.ts +27 -0
  360. package/dist/core/secrets/secret-dotenv.d.ts.map +1 -0
  361. package/dist/core/secrets/secret-dotenv.js +183 -0
  362. package/dist/core/secrets/secret-dotenv.js.map +1 -0
  363. package/dist/core/secrets/secret-vault-format.d.ts +112 -0
  364. package/dist/core/secrets/secret-vault-format.d.ts.map +1 -0
  365. package/dist/core/secrets/secret-vault-format.js +397 -0
  366. package/dist/core/secrets/secret-vault-format.js.map +1 -0
  367. package/dist/core/secrets/secret-vault.d.ts +72 -0
  368. package/dist/core/secrets/secret-vault.d.ts.map +1 -0
  369. package/dist/core/secrets/secret-vault.js +671 -0
  370. package/dist/core/secrets/secret-vault.js.map +1 -0
  371. package/dist/core/session-analytics.d.ts +4 -23
  372. package/dist/core/session-analytics.d.ts.map +1 -1
  373. package/dist/core/session-analytics.js +39 -69
  374. package/dist/core/session-analytics.js.map +1 -1
  375. package/dist/core/session-artifact-bundle.d.ts +35 -0
  376. package/dist/core/session-artifact-bundle.d.ts.map +1 -0
  377. package/dist/core/session-artifact-bundle.js +61 -0
  378. package/dist/core/session-artifact-bundle.js.map +1 -0
  379. package/dist/core/session-role.d.ts +5 -0
  380. package/dist/core/session-role.d.ts.map +1 -1
  381. package/dist/core/session-role.js +14 -1
  382. package/dist/core/session-role.js.map +1 -1
  383. package/dist/core/session-tree-navigator.d.ts +4 -6
  384. package/dist/core/session-tree-navigator.d.ts.map +1 -1
  385. package/dist/core/session-tree-navigator.js +4 -1
  386. package/dist/core/session-tree-navigator.js.map +1 -1
  387. package/dist/core/settings-manager.d.ts +1 -1
  388. package/dist/core/settings-manager.d.ts.map +1 -1
  389. package/dist/core/settings-manager.js +1 -1
  390. package/dist/core/settings-manager.js.map +1 -1
  391. package/dist/core/slash-commands.d.ts.map +1 -1
  392. package/dist/core/slash-commands.js +2 -2
  393. package/dist/core/slash-commands.js.map +1 -1
  394. package/dist/core/tool-capability-policy.d.ts.map +1 -1
  395. package/dist/core/tool-capability-policy.js +1 -0
  396. package/dist/core/tool-capability-policy.js.map +1 -1
  397. package/dist/core/tool-gate-controller.d.ts.map +1 -1
  398. package/dist/core/tool-gate-controller.js +8 -2
  399. package/dist/core/tool-gate-controller.js.map +1 -1
  400. package/dist/core/tool-protocol-controller.d.ts +2 -4
  401. package/dist/core/tool-protocol-controller.d.ts.map +1 -1
  402. package/dist/core/tool-protocol-controller.js.map +1 -1
  403. package/dist/core/tool-recovery-stats.d.ts +21 -1
  404. package/dist/core/tool-recovery-stats.d.ts.map +1 -1
  405. package/dist/core/tool-recovery-stats.js.map +1 -1
  406. package/dist/core/tools/bash.d.ts +5 -0
  407. package/dist/core/tools/bash.d.ts.map +1 -1
  408. package/dist/core/tools/bash.js +59 -5
  409. package/dist/core/tools/bash.js.map +1 -1
  410. package/dist/core/tools/delegate-status.d.ts +6 -1
  411. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  412. package/dist/core/tools/delegate-status.js +106 -25
  413. package/dist/core/tools/delegate-status.js.map +1 -1
  414. package/dist/core/tools/delegate.d.ts +9 -1
  415. package/dist/core/tools/delegate.d.ts.map +1 -1
  416. package/dist/core/tools/delegate.js +329 -69
  417. package/dist/core/tools/delegate.js.map +1 -1
  418. package/dist/core/tools/git-filter.d.ts +1 -8
  419. package/dist/core/tools/git-filter.d.ts.map +1 -1
  420. package/dist/core/tools/git-filter.js +2 -63
  421. package/dist/core/tools/git-filter.js.map +1 -1
  422. package/dist/core/tools/goal.d.ts +5 -3
  423. package/dist/core/tools/goal.d.ts.map +1 -1
  424. package/dist/core/tools/goal.js +97 -19
  425. package/dist/core/tools/goal.js.map +1 -1
  426. package/dist/core/tools/index.d.ts +1 -0
  427. package/dist/core/tools/index.d.ts.map +1 -1
  428. package/dist/core/tools/index.js +1 -0
  429. package/dist/core/tools/index.js.map +1 -1
  430. package/dist/core/tools/orchestration-panel.d.ts +1 -4
  431. package/dist/core/tools/orchestration-panel.d.ts.map +1 -1
  432. package/dist/core/tools/orchestration-panel.js +0 -44
  433. package/dist/core/tools/orchestration-panel.js.map +1 -1
  434. package/dist/core/tools/output-accumulator.d.ts +11 -0
  435. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  436. package/dist/core/tools/output-accumulator.js +36 -3
  437. package/dist/core/tools/output-accumulator.js.map +1 -1
  438. package/dist/core/tools/python.d.ts +2 -0
  439. package/dist/core/tools/python.d.ts.map +1 -1
  440. package/dist/core/tools/python.js +3 -1
  441. package/dist/core/tools/python.js.map +1 -1
  442. package/dist/core/tools/read.d.ts.map +1 -1
  443. package/dist/core/tools/read.js +1 -1
  444. package/dist/core/tools/read.js.map +1 -1
  445. package/dist/core/tools/run-process.d.ts +1 -1
  446. package/dist/core/tools/run-process.d.ts.map +1 -1
  447. package/dist/core/tools/run-process.js +69 -9
  448. package/dist/core/tools/run-process.js.map +1 -1
  449. package/dist/core/tools/search-command-guard.d.ts +14 -0
  450. package/dist/core/tools/search-command-guard.d.ts.map +1 -0
  451. package/dist/core/tools/search-command-guard.js +333 -0
  452. package/dist/core/tools/search-command-guard.js.map +1 -0
  453. package/dist/core/tools/secret-store.d.ts +38 -0
  454. package/dist/core/tools/secret-store.d.ts.map +1 -0
  455. package/dist/core/tools/secret-store.js +412 -0
  456. package/dist/core/tools/secret-store.js.map +1 -0
  457. package/dist/core/tools/shell-command-parser.d.ts +16 -0
  458. package/dist/core/tools/shell-command-parser.d.ts.map +1 -0
  459. package/dist/core/tools/shell-command-parser.js +113 -0
  460. package/dist/core/tools/shell-command-parser.js.map +1 -0
  461. package/dist/core/tools/shell-contract-router.d.ts.map +1 -1
  462. package/dist/core/tools/shell-contract-router.js +12 -5
  463. package/dist/core/tools/shell-contract-router.js.map +1 -1
  464. package/dist/core/tools/task-steps.d.ts.map +1 -1
  465. package/dist/core/tools/task-steps.js +4 -7
  466. package/dist/core/tools/task-steps.js.map +1 -1
  467. package/dist/core/util/atomic-file.d.ts +6 -2
  468. package/dist/core/util/atomic-file.d.ts.map +1 -1
  469. package/dist/core/util/atomic-file.js +4 -4
  470. package/dist/core/util/atomic-file.js.map +1 -1
  471. package/dist/core/util/bounded-file.d.ts +15 -0
  472. package/dist/core/util/bounded-file.d.ts.map +1 -0
  473. package/dist/core/util/bounded-file.js +120 -0
  474. package/dist/core/util/bounded-file.js.map +1 -0
  475. package/dist/core/util/bounded-jsonl.d.ts.map +1 -1
  476. package/dist/core/util/bounded-jsonl.js +119 -9
  477. package/dist/core/util/bounded-jsonl.js.map +1 -1
  478. package/dist/core/util/bounded-value.d.ts +3 -0
  479. package/dist/core/util/bounded-value.d.ts.map +1 -0
  480. package/dist/core/util/bounded-value.js +12 -0
  481. package/dist/core/util/bounded-value.js.map +1 -0
  482. package/dist/core/util/value-guards.d.ts +2 -0
  483. package/dist/core/util/value-guards.d.ts.map +1 -1
  484. package/dist/core/util/value-guards.js +5 -0
  485. package/dist/core/util/value-guards.js.map +1 -1
  486. package/dist/index.d.ts +3 -2
  487. package/dist/index.d.ts.map +1 -1
  488. package/dist/index.js +2 -1
  489. package/dist/index.js.map +1 -1
  490. package/dist/main.d.ts.map +1 -1
  491. package/dist/main.js +25 -11
  492. package/dist/main.js.map +1 -1
  493. package/dist/modes/interactive/auth-dialogs-controller.d.ts +4 -0
  494. package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -1
  495. package/dist/modes/interactive/auth-dialogs-controller.js +60 -1
  496. package/dist/modes/interactive/auth-dialogs-controller.js.map +1 -1
  497. package/dist/modes/interactive/components/activity-lane.d.ts +55 -0
  498. package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -0
  499. package/dist/modes/interactive/components/activity-lane.js +304 -0
  500. package/dist/modes/interactive/components/activity-lane.js.map +1 -0
  501. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  502. package/dist/modes/interactive/components/assistant-message.js +19 -10
  503. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  504. package/dist/modes/interactive/components/expandable-text.d.ts +12 -0
  505. package/dist/modes/interactive/components/expandable-text.d.ts.map +1 -0
  506. package/dist/modes/interactive/components/expandable-text.js +17 -0
  507. package/dist/modes/interactive/components/expandable-text.js.map +1 -0
  508. package/dist/modes/interactive/components/extension-editor.d.ts +15 -1
  509. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  510. package/dist/modes/interactive/components/extension-editor.js +30 -21
  511. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  512. package/dist/modes/interactive/components/extension-input.d.ts +1 -0
  513. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  514. package/dist/modes/interactive/components/extension-input.js +6 -1
  515. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  516. package/dist/modes/interactive/components/scoped-models-selector.d.ts +2 -2
  517. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  518. package/dist/modes/interactive/components/scoped-models-selector.js +23 -14
  519. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  520. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  521. package/dist/modes/interactive/components/session-selector.js +27 -44
  522. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  523. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  524. package/dist/modes/interactive/components/settings-selector.js +4 -4
  525. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  526. package/dist/modes/interactive/components/tool-execution.d.ts +19 -11
  527. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  528. package/dist/modes/interactive/components/tool-execution.js +53 -20
  529. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  530. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  531. package/dist/modes/interactive/components/tool-group.js +3 -0
  532. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  533. package/dist/modes/interactive/components/usage-action-selector.d.ts +16 -0
  534. package/dist/modes/interactive/components/usage-action-selector.d.ts.map +1 -0
  535. package/dist/modes/interactive/components/usage-action-selector.js +46 -0
  536. package/dist/modes/interactive/components/usage-action-selector.js.map +1 -0
  537. package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
  538. package/dist/modes/interactive/extension-ui-host.js +1 -0
  539. package/dist/modes/interactive/extension-ui-host.js.map +1 -1
  540. package/dist/modes/interactive/external-editor.d.ts +15 -0
  541. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  542. package/dist/modes/interactive/external-editor.js +27 -19
  543. package/dist/modes/interactive/external-editor.js.map +1 -1
  544. package/dist/modes/interactive/history-reload-math.d.ts +6 -2
  545. package/dist/modes/interactive/history-reload-math.d.ts.map +1 -1
  546. package/dist/modes/interactive/history-reload-math.js +10 -5
  547. package/dist/modes/interactive/history-reload-math.js.map +1 -1
  548. package/dist/modes/interactive/interactive-event-controller.d.ts +74 -0
  549. package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -0
  550. package/dist/modes/interactive/interactive-event-controller.js +328 -0
  551. package/dist/modes/interactive/interactive-event-controller.js.map +1 -0
  552. package/dist/modes/interactive/interactive-mode.d.ts +20 -25
  553. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  554. package/dist/modes/interactive/interactive-mode.js +196 -608
  555. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  556. package/dist/modes/interactive/loaded-resources-view.d.ts +20 -0
  557. package/dist/modes/interactive/loaded-resources-view.d.ts.map +1 -0
  558. package/dist/modes/interactive/loaded-resources-view.js +147 -0
  559. package/dist/modes/interactive/loaded-resources-view.js.map +1 -0
  560. package/dist/modes/interactive/resource-display.d.ts.map +1 -1
  561. package/dist/modes/interactive/resource-display.js +8 -2
  562. package/dist/modes/interactive/resource-display.js.map +1 -1
  563. package/dist/modes/interactive/resource-shell-commands.d.ts +1 -5
  564. package/dist/modes/interactive/resource-shell-commands.d.ts.map +1 -1
  565. package/dist/modes/interactive/resource-shell-commands.js +0 -5
  566. package/dist/modes/interactive/resource-shell-commands.js.map +1 -1
  567. package/dist/modes/interactive/session-flow-commands.d.ts +10 -6
  568. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  569. package/dist/modes/interactive/session-flow-commands.js +123 -70
  570. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  571. package/dist/modes/interactive/usage-commands.d.ts +34 -0
  572. package/dist/modes/interactive/usage-commands.d.ts.map +1 -0
  573. package/dist/modes/interactive/usage-commands.js +225 -0
  574. package/dist/modes/interactive/usage-commands.js.map +1 -0
  575. package/dist/utils/shell.d.ts.map +1 -1
  576. package/dist/utils/shell.js +5 -3
  577. package/dist/utils/shell.js.map +1 -1
  578. package/dist/utils/version-check.d.ts.map +1 -1
  579. package/dist/utils/version-check.js +3 -1
  580. package/dist/utils/version-check.js.map +1 -1
  581. package/docs/UI_POLISH_ORCHESTRATION.md +25 -31
  582. package/docs/UI_QUALITY_ORCHESTRATION.md +22 -24
  583. package/docs/providers.md +9 -1
  584. package/docs/tool-repair.md +3 -0
  585. package/docs/ui-reference/README.md +6 -6
  586. package/docs/ui-reference/orchestration-after.txt +14 -7
  587. package/docs/ui-reference/orchestration-before.txt +12 -6
  588. package/docs/ui-reference/orchestration-reference.txt +15 -5
  589. package/docs/usage.md +9 -1
  590. package/docs/windows.md +4 -2
  591. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  592. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  593. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  594. package/examples/extensions/sandbox/package-lock.json +2 -2
  595. package/examples/extensions/sandbox/package.json +1 -1
  596. package/examples/extensions/with-deps/package-lock.json +2 -2
  597. package/examples/extensions/with-deps/package.json +1 -1
  598. package/npm-shrinkwrap.json +13 -13
  599. package/package.json +4 -4
@@ -13,6 +13,21 @@ export interface ExternalEditorHost {
13
13
  readonly ui: Pick<TUI, "stop" | "start" | "requestRender">;
14
14
  showWarning(message: string): void;
15
15
  }
16
+ export interface ExternalEditorOptions {
17
+ command: string;
18
+ content: string;
19
+ }
20
+ export type ExternalEditorResult = {
21
+ status: "complete";
22
+ content: string;
23
+ } | {
24
+ status: "failed";
25
+ };
26
+ /**
27
+ * Edit text through the configured external editor while keeping all temporary
28
+ * artifacts inside Pi's bounded user-level work directory.
29
+ */
30
+ export declare function editInExternalEditor(options: ExternalEditorOptions): Promise<ExternalEditorResult>;
16
31
  export declare function openExternalEditor(host: ExternalEditorHost): Promise<void>;
17
32
  export declare function openEditorForPath(host: ExternalEditorHost, filePath: string): Promise<boolean>;
18
33
  //# sourceMappingURL=external-editor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"external-editor.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/external-editor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAK/D,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,eAAe,CAAC,CAAC;IAC3D,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAMD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6ChF;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAkDpG","sourcesContent":["/**\n * External-editor launch flows extracted from interactive-mode.\n *\n * `openExternalEditor` edits the current editor buffer in `$VISUAL`/`$EDITOR`;\n * `openEditorForPath` opens an arbitrary file (falling back to `vi`). Both stop\n * the TUI to release the terminal, spawn the editor, and restart the TUI with a\n * forced full re-render. They operate through a narrow `ExternalEditorHost` seam;\n * interactive-mode keeps thin delegating wrappers.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { EditorComponent, TUI } from \"@caupulican/pi-tui\";\nimport { getAgentDir } from \"../../config.ts\";\nimport { runExternalEditor } from \"../../utils/external-editor-command.ts\";\nimport { getProcessWorkRun } from \"../../utils/work-directory.ts\";\n\nexport interface ExternalEditorHost {\n\treadonly editor: EditorComponent;\n\treadonly ui: Pick<TUI, \"stop\" | \"start\" | \"requestRender\">;\n\tshowWarning(message: string): void;\n}\n\nfunction resolveEditorCommand(): string | undefined {\n\treturn process.env.VISUAL || process.env.EDITOR;\n}\n\nexport async function openExternalEditor(host: ExternalEditorHost): Promise<void> {\n\tconst editorCmd = resolveEditorCommand();\n\tif (!editorCmd) {\n\t\thost.showWarning(\"No editor configured. Set $VISUAL or $EDITOR environment variable.\");\n\t\treturn;\n\t}\n\n\tconst currentText = host.editor.getExpandedText?.() ?? host.editor.getText();\n\tconst tmpFile = path.join(\n\t\tgetProcessWorkRun(getAgentDir(), \"editors\", \"external\").path,\n\t\t`pi-editor-${randomUUID()}.pi.md`,\n\t);\n\n\ttry {\n\t\t// Write current content to temp file\n\t\tfs.writeFileSync(tmpFile, currentText, \"utf-8\");\n\n\t\t// Stop TUI to release terminal\n\t\thost.ui.stop();\n\n\t\tprocess.stdout.write(`Launching external editor: ${editorCmd}\\nPi will resume when the editor exits.\\n`);\n\n\t\t// Cross-platform executable resolution preserves quoted Windows paths without\n\t\t// asking a shell to reinterpret the temporary file path.\n\t\tconst status = await runExternalEditor(editorCmd, tmpFile);\n\n\t\t// On successful exit (status 0), replace editor content\n\t\tif (status === 0) {\n\t\t\tconst newContent = fs.readFileSync(tmpFile, \"utf-8\").replace(/\\n$/, \"\");\n\t\t\thost.editor.setText(newContent);\n\t\t}\n\t\t// On non-zero exit, keep original text (no action needed)\n\t} finally {\n\t\t// Clean up temp file\n\t\ttry {\n\t\t\tfs.unlinkSync(tmpFile);\n\t\t} catch {\n\t\t\t// Ignore cleanup errors\n\t\t}\n\n\t\t// Restart TUI\n\t\thost.ui.start();\n\t\t// Force full re-render since external editor uses alternate screen\n\t\thost.ui.requestRender(true);\n\t}\n}\n\nexport async function openEditorForPath(host: ExternalEditorHost, filePath: string): Promise<boolean> {\n\tlet editorCmd = resolveEditorCommand();\n\tlet isFallback = false;\n\tif (!editorCmd) {\n\t\teditorCmd = \"vi\";\n\t\tisFallback = true;\n\t}\n\n\ttry {\n\t\t// Stop TUI to release terminal\n\t\thost.ui.stop();\n\n\t\tprocess.stdout.write(\n\t\t\t`Launching external editor: ${editorCmd} ${filePath}\\nPi will resume when the editor exits.\\n`,\n\t\t);\n\n\t\tconst status = await runExternalEditor(editorCmd, filePath);\n\n\t\tif (status === null) {\n\t\t\tif (isFallback) {\n\t\t\t\tprocess.stdout.write(`\\nError: Failed to launch fallback editor \"vi\".\\n`);\n\t\t\t} else {\n\t\t\t\tprocess.stdout.write(`\\nError: Failed to launch editor \"${editorCmd}\".\\n`);\n\t\t\t}\n\t\t\tprocess.stdout.write(`Please set the $EDITOR or $VISUAL environment variable to edit inline.\\n`);\n\t\t\tprocess.stdout.write(`Absolute file path: ${filePath}\\n\\nPress Enter to return to Pi...`);\n\t\t\t// Wait for enter, but do not remain pending if stdin closes during shutdown.\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tlet settled = false;\n\t\t\t\tconst finish = () => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tprocess.stdin.removeListener(\"data\", finish);\n\t\t\t\t\tprocess.stdin.removeListener(\"end\", finish);\n\t\t\t\t\tprocess.stdin.removeListener(\"error\", finish);\n\t\t\t\t\tresolve();\n\t\t\t\t};\n\t\t\t\tprocess.stdin.once(\"data\", finish);\n\t\t\t\tprocess.stdin.once(\"end\", finish);\n\t\t\t\tprocess.stdin.once(\"error\", finish);\n\t\t\t});\n\t\t}\n\n\t\treturn status === 0;\n\t} finally {\n\t\t// Restart TUI\n\t\thost.ui.start();\n\t\t// Force full re-render since external editor uses alternate screen\n\t\thost.ui.requestRender(true);\n\t}\n}\n"]}
1
+ {"version":3,"file":"external-editor.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/external-editor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAK/D,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,eAAe,CAAC,CAAC;IAC3D,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,oBAAoB,GAAG;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,CAAC;AAMlG;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAqBxG;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBhF;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAkDpG","sourcesContent":["/**\n * External-editor launch flows extracted from interactive-mode.\n *\n * `openExternalEditor` edits the current editor buffer in `$VISUAL`/`$EDITOR`;\n * `openEditorForPath` opens an arbitrary file (falling back to `vi`). Both stop\n * the TUI to release the terminal, spawn the editor, and restart the TUI with a\n * forced full re-render. They operate through a narrow `ExternalEditorHost` seam;\n * interactive-mode keeps thin delegating wrappers.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { EditorComponent, TUI } from \"@caupulican/pi-tui\";\nimport { getAgentDir } from \"../../config.ts\";\nimport { runExternalEditor } from \"../../utils/external-editor-command.ts\";\nimport { getProcessWorkRun } from \"../../utils/work-directory.ts\";\n\nexport interface ExternalEditorHost {\n\treadonly editor: EditorComponent;\n\treadonly ui: Pick<TUI, \"stop\" | \"start\" | \"requestRender\">;\n\tshowWarning(message: string): void;\n}\n\nexport interface ExternalEditorOptions {\n\tcommand: string;\n\tcontent: string;\n}\n\nexport type ExternalEditorResult = { status: \"complete\"; content: string } | { status: \"failed\" };\n\nfunction resolveEditorCommand(): string | undefined {\n\treturn process.env.VISUAL || process.env.EDITOR;\n}\n\n/**\n * Edit text through the configured external editor while keeping all temporary\n * artifacts inside Pi's bounded user-level work directory.\n */\nexport async function editInExternalEditor(options: ExternalEditorOptions): Promise<ExternalEditorResult> {\n\tconst tmpFile = path.join(\n\t\tgetProcessWorkRun(getAgentDir(), \"editors\", \"external\").path,\n\t\t`pi-editor-${randomUUID()}.pi.md`,\n\t);\n\n\ttry {\n\t\tfs.writeFileSync(tmpFile, options.content, \"utf-8\");\n\t\tprocess.stdout.write(`Launching external editor: ${options.command}\\nPi will resume when the editor exits.\\n`);\n\t\tconst status = await runExternalEditor(options.command, tmpFile);\n\t\tif (status !== 0) {\n\t\t\treturn { status: \"failed\" };\n\t\t}\n\t\treturn { status: \"complete\", content: fs.readFileSync(tmpFile, \"utf-8\").replace(/\\n$/, \"\") };\n\t} finally {\n\t\ttry {\n\t\t\tfs.unlinkSync(tmpFile);\n\t\t} catch {\n\t\t\t// Cleanup is best effort.\n\t\t}\n\t}\n}\n\nexport async function openExternalEditor(host: ExternalEditorHost): Promise<void> {\n\tconst editorCmd = resolveEditorCommand();\n\tif (!editorCmd) {\n\t\thost.showWarning(\"No editor configured. Set $VISUAL or $EDITOR environment variable.\");\n\t\treturn;\n\t}\n\n\tconst currentText = host.editor.getExpandedText?.() ?? host.editor.getText();\n\n\ttry {\n\t\t// Stop TUI to release terminal\n\t\thost.ui.stop();\n\n\t\tconst result = await editInExternalEditor({ command: editorCmd, content: currentText });\n\t\tif (result.status === \"complete\") {\n\t\t\thost.editor.setText(result.content);\n\t\t}\n\t} finally {\n\t\t// Restart TUI\n\t\thost.ui.start();\n\t\t// Force full re-render since external editor uses alternate screen\n\t\thost.ui.requestRender(true);\n\t}\n}\n\nexport async function openEditorForPath(host: ExternalEditorHost, filePath: string): Promise<boolean> {\n\tlet editorCmd = resolveEditorCommand();\n\tlet isFallback = false;\n\tif (!editorCmd) {\n\t\teditorCmd = \"vi\";\n\t\tisFallback = true;\n\t}\n\n\ttry {\n\t\t// Stop TUI to release terminal\n\t\thost.ui.stop();\n\n\t\tprocess.stdout.write(\n\t\t\t`Launching external editor: ${editorCmd} ${filePath}\\nPi will resume when the editor exits.\\n`,\n\t\t);\n\n\t\tconst status = await runExternalEditor(editorCmd, filePath);\n\n\t\tif (status === null) {\n\t\t\tif (isFallback) {\n\t\t\t\tprocess.stdout.write(`\\nError: Failed to launch fallback editor \"vi\".\\n`);\n\t\t\t} else {\n\t\t\t\tprocess.stdout.write(`\\nError: Failed to launch editor \"${editorCmd}\".\\n`);\n\t\t\t}\n\t\t\tprocess.stdout.write(`Please set the $EDITOR or $VISUAL environment variable to edit inline.\\n`);\n\t\t\tprocess.stdout.write(`Absolute file path: ${filePath}\\n\\nPress Enter to return to Pi...`);\n\t\t\t// Wait for enter, but do not remain pending if stdin closes during shutdown.\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tlet settled = false;\n\t\t\t\tconst finish = () => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tprocess.stdin.removeListener(\"data\", finish);\n\t\t\t\t\tprocess.stdin.removeListener(\"end\", finish);\n\t\t\t\t\tprocess.stdin.removeListener(\"error\", finish);\n\t\t\t\t\tresolve();\n\t\t\t\t};\n\t\t\t\tprocess.stdin.once(\"data\", finish);\n\t\t\t\tprocess.stdin.once(\"end\", finish);\n\t\t\t\tprocess.stdin.once(\"error\", finish);\n\t\t\t});\n\t\t}\n\n\t\treturn status === 0;\n\t} finally {\n\t\t// Restart TUI\n\t\thost.ui.start();\n\t\t// Force full re-render since external editor uses alternate screen\n\t\thost.ui.requestRender(true);\n\t}\n}\n"]}
@@ -16,6 +16,30 @@ import { getProcessWorkRun } from "../../utils/work-directory.js";
16
16
  function resolveEditorCommand() {
17
17
  return process.env.VISUAL || process.env.EDITOR;
18
18
  }
19
+ /**
20
+ * Edit text through the configured external editor while keeping all temporary
21
+ * artifacts inside Pi's bounded user-level work directory.
22
+ */
23
+ export async function editInExternalEditor(options) {
24
+ const tmpFile = path.join(getProcessWorkRun(getAgentDir(), "editors", "external").path, `pi-editor-${randomUUID()}.pi.md`);
25
+ try {
26
+ fs.writeFileSync(tmpFile, options.content, "utf-8");
27
+ process.stdout.write(`Launching external editor: ${options.command}\nPi will resume when the editor exits.\n`);
28
+ const status = await runExternalEditor(options.command, tmpFile);
29
+ if (status !== 0) {
30
+ return { status: "failed" };
31
+ }
32
+ return { status: "complete", content: fs.readFileSync(tmpFile, "utf-8").replace(/\n$/, "") };
33
+ }
34
+ finally {
35
+ try {
36
+ fs.unlinkSync(tmpFile);
37
+ }
38
+ catch {
39
+ // Cleanup is best effort.
40
+ }
41
+ }
42
+ }
19
43
  export async function openExternalEditor(host) {
20
44
  const editorCmd = resolveEditorCommand();
21
45
  if (!editorCmd) {
@@ -23,31 +47,15 @@ export async function openExternalEditor(host) {
23
47
  return;
24
48
  }
25
49
  const currentText = host.editor.getExpandedText?.() ?? host.editor.getText();
26
- const tmpFile = path.join(getProcessWorkRun(getAgentDir(), "editors", "external").path, `pi-editor-${randomUUID()}.pi.md`);
27
50
  try {
28
- // Write current content to temp file
29
- fs.writeFileSync(tmpFile, currentText, "utf-8");
30
51
  // Stop TUI to release terminal
31
52
  host.ui.stop();
32
- process.stdout.write(`Launching external editor: ${editorCmd}\nPi will resume when the editor exits.\n`);
33
- // Cross-platform executable resolution preserves quoted Windows paths without
34
- // asking a shell to reinterpret the temporary file path.
35
- const status = await runExternalEditor(editorCmd, tmpFile);
36
- // On successful exit (status 0), replace editor content
37
- if (status === 0) {
38
- const newContent = fs.readFileSync(tmpFile, "utf-8").replace(/\n$/, "");
39
- host.editor.setText(newContent);
53
+ const result = await editInExternalEditor({ command: editorCmd, content: currentText });
54
+ if (result.status === "complete") {
55
+ host.editor.setText(result.content);
40
56
  }
41
- // On non-zero exit, keep original text (no action needed)
42
57
  }
43
58
  finally {
44
- // Clean up temp file
45
- try {
46
- fs.unlinkSync(tmpFile);
47
- }
48
- catch {
49
- // Ignore cleanup errors
50
- }
51
59
  // Restart TUI
52
60
  host.ui.start();
53
61
  // Force full re-render since external editor uses alternate screen
@@ -1 +1 @@
1
- {"version":3,"file":"external-editor.js","sourceRoot":"","sources":["../../../src/modes/interactive/external-editor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * External-editor launch flows extracted from interactive-mode.\n *\n * `openExternalEditor` edits the current editor buffer in `$VISUAL`/`$EDITOR`;\n * `openEditorForPath` opens an arbitrary file (falling back to `vi`). Both stop\n * the TUI to release the terminal, spawn the editor, and restart the TUI with a\n * forced full re-render. They operate through a narrow `ExternalEditorHost` seam;\n * interactive-mode keeps thin delegating wrappers.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { EditorComponent, TUI } from \"@caupulican/pi-tui\";\nimport { getAgentDir } from \"../../config.ts\";\nimport { runExternalEditor } from \"../../utils/external-editor-command.ts\";\nimport { getProcessWorkRun } from \"../../utils/work-directory.ts\";\n\nexport interface ExternalEditorHost {\n\treadonly editor: EditorComponent;\n\treadonly ui: Pick<TUI, \"stop\" | \"start\" | \"requestRender\">;\n\tshowWarning(message: string): void;\n}\n\nfunction resolveEditorCommand(): string | undefined {\n\treturn process.env.VISUAL || process.env.EDITOR;\n}\n\nexport async function openExternalEditor(host: ExternalEditorHost): Promise<void> {\n\tconst editorCmd = resolveEditorCommand();\n\tif (!editorCmd) {\n\t\thost.showWarning(\"No editor configured. Set $VISUAL or $EDITOR environment variable.\");\n\t\treturn;\n\t}\n\n\tconst currentText = host.editor.getExpandedText?.() ?? host.editor.getText();\n\tconst tmpFile = path.join(\n\t\tgetProcessWorkRun(getAgentDir(), \"editors\", \"external\").path,\n\t\t`pi-editor-${randomUUID()}.pi.md`,\n\t);\n\n\ttry {\n\t\t// Write current content to temp file\n\t\tfs.writeFileSync(tmpFile, currentText, \"utf-8\");\n\n\t\t// Stop TUI to release terminal\n\t\thost.ui.stop();\n\n\t\tprocess.stdout.write(`Launching external editor: ${editorCmd}\\nPi will resume when the editor exits.\\n`);\n\n\t\t// Cross-platform executable resolution preserves quoted Windows paths without\n\t\t// asking a shell to reinterpret the temporary file path.\n\t\tconst status = await runExternalEditor(editorCmd, tmpFile);\n\n\t\t// On successful exit (status 0), replace editor content\n\t\tif (status === 0) {\n\t\t\tconst newContent = fs.readFileSync(tmpFile, \"utf-8\").replace(/\\n$/, \"\");\n\t\t\thost.editor.setText(newContent);\n\t\t}\n\t\t// On non-zero exit, keep original text (no action needed)\n\t} finally {\n\t\t// Clean up temp file\n\t\ttry {\n\t\t\tfs.unlinkSync(tmpFile);\n\t\t} catch {\n\t\t\t// Ignore cleanup errors\n\t\t}\n\n\t\t// Restart TUI\n\t\thost.ui.start();\n\t\t// Force full re-render since external editor uses alternate screen\n\t\thost.ui.requestRender(true);\n\t}\n}\n\nexport async function openEditorForPath(host: ExternalEditorHost, filePath: string): Promise<boolean> {\n\tlet editorCmd = resolveEditorCommand();\n\tlet isFallback = false;\n\tif (!editorCmd) {\n\t\teditorCmd = \"vi\";\n\t\tisFallback = true;\n\t}\n\n\ttry {\n\t\t// Stop TUI to release terminal\n\t\thost.ui.stop();\n\n\t\tprocess.stdout.write(\n\t\t\t`Launching external editor: ${editorCmd} ${filePath}\\nPi will resume when the editor exits.\\n`,\n\t\t);\n\n\t\tconst status = await runExternalEditor(editorCmd, filePath);\n\n\t\tif (status === null) {\n\t\t\tif (isFallback) {\n\t\t\t\tprocess.stdout.write(`\\nError: Failed to launch fallback editor \"vi\".\\n`);\n\t\t\t} else {\n\t\t\t\tprocess.stdout.write(`\\nError: Failed to launch editor \"${editorCmd}\".\\n`);\n\t\t\t}\n\t\t\tprocess.stdout.write(`Please set the $EDITOR or $VISUAL environment variable to edit inline.\\n`);\n\t\t\tprocess.stdout.write(`Absolute file path: ${filePath}\\n\\nPress Enter to return to Pi...`);\n\t\t\t// Wait for enter, but do not remain pending if stdin closes during shutdown.\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tlet settled = false;\n\t\t\t\tconst finish = () => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tprocess.stdin.removeListener(\"data\", finish);\n\t\t\t\t\tprocess.stdin.removeListener(\"end\", finish);\n\t\t\t\t\tprocess.stdin.removeListener(\"error\", finish);\n\t\t\t\t\tresolve();\n\t\t\t\t};\n\t\t\t\tprocess.stdin.once(\"data\", finish);\n\t\t\t\tprocess.stdin.once(\"end\", finish);\n\t\t\t\tprocess.stdin.once(\"error\", finish);\n\t\t\t});\n\t\t}\n\n\t\treturn status === 0;\n\t} finally {\n\t\t// Restart TUI\n\t\thost.ui.start();\n\t\t// Force full re-render since external editor uses alternate screen\n\t\thost.ui.requestRender(true);\n\t}\n}\n"]}
1
+ {"version":3,"file":"external-editor.js","sourceRoot":"","sources":["../../../src/modes/interactive/external-editor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * External-editor launch flows extracted from interactive-mode.\n *\n * `openExternalEditor` edits the current editor buffer in `$VISUAL`/`$EDITOR`;\n * `openEditorForPath` opens an arbitrary file (falling back to `vi`). Both stop\n * the TUI to release the terminal, spawn the editor, and restart the TUI with a\n * forced full re-render. They operate through a narrow `ExternalEditorHost` seam;\n * interactive-mode keeps thin delegating wrappers.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { EditorComponent, TUI } from \"@caupulican/pi-tui\";\nimport { getAgentDir } from \"../../config.ts\";\nimport { runExternalEditor } from \"../../utils/external-editor-command.ts\";\nimport { getProcessWorkRun } from \"../../utils/work-directory.ts\";\n\nexport interface ExternalEditorHost {\n\treadonly editor: EditorComponent;\n\treadonly ui: Pick<TUI, \"stop\" | \"start\" | \"requestRender\">;\n\tshowWarning(message: string): void;\n}\n\nexport interface ExternalEditorOptions {\n\tcommand: string;\n\tcontent: string;\n}\n\nexport type ExternalEditorResult = { status: \"complete\"; content: string } | { status: \"failed\" };\n\nfunction resolveEditorCommand(): string | undefined {\n\treturn process.env.VISUAL || process.env.EDITOR;\n}\n\n/**\n * Edit text through the configured external editor while keeping all temporary\n * artifacts inside Pi's bounded user-level work directory.\n */\nexport async function editInExternalEditor(options: ExternalEditorOptions): Promise<ExternalEditorResult> {\n\tconst tmpFile = path.join(\n\t\tgetProcessWorkRun(getAgentDir(), \"editors\", \"external\").path,\n\t\t`pi-editor-${randomUUID()}.pi.md`,\n\t);\n\n\ttry {\n\t\tfs.writeFileSync(tmpFile, options.content, \"utf-8\");\n\t\tprocess.stdout.write(`Launching external editor: ${options.command}\\nPi will resume when the editor exits.\\n`);\n\t\tconst status = await runExternalEditor(options.command, tmpFile);\n\t\tif (status !== 0) {\n\t\t\treturn { status: \"failed\" };\n\t\t}\n\t\treturn { status: \"complete\", content: fs.readFileSync(tmpFile, \"utf-8\").replace(/\\n$/, \"\") };\n\t} finally {\n\t\ttry {\n\t\t\tfs.unlinkSync(tmpFile);\n\t\t} catch {\n\t\t\t// Cleanup is best effort.\n\t\t}\n\t}\n}\n\nexport async function openExternalEditor(host: ExternalEditorHost): Promise<void> {\n\tconst editorCmd = resolveEditorCommand();\n\tif (!editorCmd) {\n\t\thost.showWarning(\"No editor configured. Set $VISUAL or $EDITOR environment variable.\");\n\t\treturn;\n\t}\n\n\tconst currentText = host.editor.getExpandedText?.() ?? host.editor.getText();\n\n\ttry {\n\t\t// Stop TUI to release terminal\n\t\thost.ui.stop();\n\n\t\tconst result = await editInExternalEditor({ command: editorCmd, content: currentText });\n\t\tif (result.status === \"complete\") {\n\t\t\thost.editor.setText(result.content);\n\t\t}\n\t} finally {\n\t\t// Restart TUI\n\t\thost.ui.start();\n\t\t// Force full re-render since external editor uses alternate screen\n\t\thost.ui.requestRender(true);\n\t}\n}\n\nexport async function openEditorForPath(host: ExternalEditorHost, filePath: string): Promise<boolean> {\n\tlet editorCmd = resolveEditorCommand();\n\tlet isFallback = false;\n\tif (!editorCmd) {\n\t\teditorCmd = \"vi\";\n\t\tisFallback = true;\n\t}\n\n\ttry {\n\t\t// Stop TUI to release terminal\n\t\thost.ui.stop();\n\n\t\tprocess.stdout.write(\n\t\t\t`Launching external editor: ${editorCmd} ${filePath}\\nPi will resume when the editor exits.\\n`,\n\t\t);\n\n\t\tconst status = await runExternalEditor(editorCmd, filePath);\n\n\t\tif (status === null) {\n\t\t\tif (isFallback) {\n\t\t\t\tprocess.stdout.write(`\\nError: Failed to launch fallback editor \"vi\".\\n`);\n\t\t\t} else {\n\t\t\t\tprocess.stdout.write(`\\nError: Failed to launch editor \"${editorCmd}\".\\n`);\n\t\t\t}\n\t\t\tprocess.stdout.write(`Please set the $EDITOR or $VISUAL environment variable to edit inline.\\n`);\n\t\t\tprocess.stdout.write(`Absolute file path: ${filePath}\\n\\nPress Enter to return to Pi...`);\n\t\t\t// Wait for enter, but do not remain pending if stdin closes during shutdown.\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tlet settled = false;\n\t\t\t\tconst finish = () => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tprocess.stdin.removeListener(\"data\", finish);\n\t\t\t\t\tprocess.stdin.removeListener(\"end\", finish);\n\t\t\t\t\tprocess.stdin.removeListener(\"error\", finish);\n\t\t\t\t\tresolve();\n\t\t\t\t};\n\t\t\t\tprocess.stdin.once(\"data\", finish);\n\t\t\t\tprocess.stdin.once(\"end\", finish);\n\t\t\t\tprocess.stdin.once(\"error\", finish);\n\t\t\t});\n\t\t}\n\n\t\treturn status === 0;\n\t} finally {\n\t\t// Restart TUI\n\t\thost.ui.start();\n\t\t// Force full re-render since external editor uses alternate screen\n\t\thost.ui.requestRender(true);\n\t}\n}\n"]}
@@ -10,13 +10,17 @@ import type { AgentMessage } from "@caupulican/pi-agent-core";
10
10
  import type { Message } from "@caupulican/pi-ai";
11
11
  export declare const TUI_HISTORY_RELOAD_MAX_LINES = 1000;
12
12
  export declare const TUI_HISTORY_RELOAD_WRAP_WIDTH = 100;
13
+ export interface TuiHistoryReloadOptions {
14
+ /** Read tool-result content while sizing history. False when tool output is collapsed. */
15
+ includeToolResultContent?: boolean;
16
+ }
13
17
  export declare function getContentText(content: unknown): string;
14
18
  export declare function getUserMessageText(message: Message): string;
15
19
  export declare function getTuiHistoryMessageText(message: AgentMessage): string;
16
- export declare function estimateTuiHistoryLines(message: AgentMessage): number;
20
+ export declare function estimateTuiHistoryLines(message: AgentMessage, options?: TuiHistoryReloadOptions): number;
17
21
  export declare function trimTextToTuiHistoryTail(text: string, maxEstimatedLines: number): string;
18
22
  export declare function trimMessageToTuiHistoryTail(message: AgentMessage, maxEstimatedLines: number): AgentMessage;
19
- export declare function messagesForTuiHistoryReload(messages: AgentMessage[]): {
23
+ export declare function messagesForTuiHistoryReload(messages: AgentMessage[], options?: TuiHistoryReloadOptions): {
20
24
  messages: AgentMessage[];
21
25
  omittedMessages: number;
22
26
  estimatedLines: number;
@@ -1 +1 @@
1
- {"version":3,"file":"history-reload-math.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/history-reload-math.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,eAAO,MAAM,4BAA4B,OAAO,CAAC;AACjD,eAAO,MAAM,6BAA6B,MAAM,CAAC;AAEjD,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAWvD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAO3D;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAoBtE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAOrE;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,MAAM,CAaxF;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,GAAG,YAAY,CAgB1G;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG;IACtE,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACvB,CA6BA","sourcesContent":["/**\n * Pure math for capping the TUI transcript that is re-rendered on reload/resume.\n *\n * These functions estimate wrapped line counts for agent messages and select the\n * tail of a message list that fits within the reload budget, trimming an oversized\n * head message when needed. They read only their arguments and hold no UI or session\n * state, so they live outside interactive-mode and are unit-testable in isolation.\n */\n\nimport type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport type { Message } from \"@caupulican/pi-ai\";\n\nexport const TUI_HISTORY_RELOAD_MAX_LINES = 1000;\nexport const TUI_HISTORY_RELOAD_WRAP_WIDTH = 100;\n\nexport function getContentText(content: unknown): string {\n\tif (typeof content === \"string\") return content;\n\tif (Array.isArray(content)) {\n\t\treturn content\n\t\t\t.map((part) => {\n\t\t\t\tconst maybeText = (part as { text?: unknown }).text;\n\t\t\t\treturn typeof maybeText === \"string\" ? maybeText : \"\";\n\t\t\t})\n\t\t\t.join(\"\");\n\t}\n\treturn \"\";\n}\n\nexport function getUserMessageText(message: Message): string {\n\tif (message.role !== \"user\") return \"\";\n\tconst textBlocks =\n\t\ttypeof message.content === \"string\"\n\t\t\t? [{ type: \"text\", text: message.content }]\n\t\t\t: message.content.filter((c: { type: string }) => c.type === \"text\");\n\treturn textBlocks.map((c) => (c as { text: string }).text).join(\"\");\n}\n\nexport function getTuiHistoryMessageText(message: AgentMessage): string {\n\tswitch (message.role) {\n\t\tcase \"bashExecution\":\n\t\t\treturn [message.command, message.output ?? \"\"].filter(Boolean).join(\"\\n\");\n\t\tcase \"user\":\n\t\t\treturn getUserMessageText(message);\n\t\tcase \"assistant\":\n\t\t\treturn getContentText(message.content);\n\t\tcase \"toolResult\":\n\t\t\treturn getContentText(message.content);\n\t\tcase \"custom\":\n\t\t\treturn getContentText(message.content);\n\t\tcase \"compactionSummary\":\n\t\tcase \"branchSummary\":\n\t\t\treturn message.summary;\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = message;\n\t\t\treturn JSON.stringify(_exhaustive);\n\t\t}\n\t}\n}\n\nexport function estimateTuiHistoryLines(message: AgentMessage): number {\n\tconst text = getTuiHistoryMessageText(message);\n\tconst hardLines = text.length > 0 ? text.split(/\\r\\n|\\r|\\n/).length : 1;\n\tconst wrappedLines = Math.ceil(text.length / TUI_HISTORY_RELOAD_WRAP_WIDTH);\n\t// Add one line for role/tool chrome or spacing. Tool-call-only assistant messages\n\t// have little text but still render a component.\n\treturn Math.max(1, hardLines, wrappedLines) + 1;\n}\n\nexport function trimTextToTuiHistoryTail(text: string, maxEstimatedLines: number): string {\n\tconst maxLines = Math.max(1, maxEstimatedLines);\n\tconst lines = text.split(/\\r\\n|\\r|\\n/);\n\tif (lines.length > maxLines) {\n\t\tconst omitted = lines.length - maxLines;\n\t\treturn `[Earlier ${omitted} line${omitted === 1 ? \"\" : \"s\"} omitted from TUI reload history; full session remains available to the model.]\\n${lines.slice(-maxLines).join(\"\\n\")}`;\n\t}\n\tconst maxChars = Math.max(TUI_HISTORY_RELOAD_WRAP_WIDTH, maxLines * TUI_HISTORY_RELOAD_WRAP_WIDTH);\n\tif (text.length > maxChars) {\n\t\tconst omitted = text.length - maxChars;\n\t\treturn `[Earlier ${omitted} character${omitted === 1 ? \"\" : \"s\"} omitted from TUI reload history; full session remains available to the model.]\\n${text.slice(-maxChars)}`;\n\t}\n\treturn text;\n}\n\nexport function trimMessageToTuiHistoryTail(message: AgentMessage, maxEstimatedLines: number): AgentMessage {\n\tconst text = getTuiHistoryMessageText(message);\n\tconst trimmedText = trimTextToTuiHistoryTail(text, maxEstimatedLines);\n\tif (trimmedText === text) return message;\n\tconst clone = JSON.parse(JSON.stringify(message)) as AgentMessage;\n\tconst mutable = clone as unknown as { role?: string; content?: unknown; output?: unknown };\n\tif (mutable.role === \"bashExecution\" && typeof mutable.output === \"string\") {\n\t\tmutable.output = trimmedText;\n\t} else if (mutable.role === \"compactionSummary\" || mutable.role === \"branchSummary\") {\n\t\t(mutable as { summary?: string }).summary = trimmedText;\n\t} else if (typeof mutable.content === \"string\") {\n\t\tmutable.content = trimmedText;\n\t} else {\n\t\tmutable.content = [{ type: \"text\", text: trimmedText }];\n\t}\n\treturn clone;\n}\n\nexport function messagesForTuiHistoryReload(messages: AgentMessage[]): {\n\tmessages: AgentMessage[];\n\tomittedMessages: number;\n\testimatedLines: number;\n} {\n\tlet estimatedLines = 0;\n\tlet start = messages.length;\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst nextLines = estimateTuiHistoryLines(messages[i]);\n\t\tif (start < messages.length && estimatedLines + nextLines > TUI_HISTORY_RELOAD_MAX_LINES) break;\n\t\testimatedLines += nextLines;\n\t\tstart = i;\n\t\tif (estimatedLines >= TUI_HISTORY_RELOAD_MAX_LINES) break;\n\t}\n\tconst selected = messages.slice(start);\n\tif (selected.length > 0 && estimatedLines > TUI_HISTORY_RELOAD_MAX_LINES) {\n\t\tconst tailLines = selected.slice(1).reduce((sum, message) => sum + estimateTuiHistoryLines(message), 0);\n\t\tconst firstAllowance = TUI_HISTORY_RELOAD_MAX_LINES - tailLines;\n\t\tif (firstAllowance <= 4) {\n\t\t\tselected.shift();\n\t\t\tstart += 1;\n\t\t\testimatedLines = tailLines;\n\t\t} else {\n\t\t\t// Reserve room for truncation marker, role chrome, and wrap variance.\n\t\t\tselected[0] = trimMessageToTuiHistoryTail(selected[0], firstAllowance - 4);\n\t\t\testimatedLines = tailLines + estimateTuiHistoryLines(selected[0]);\n\t\t}\n\t}\n\treturn {\n\t\tmessages: selected,\n\t\tomittedMessages: start,\n\t\testimatedLines,\n\t};\n}\n"]}
1
+ {"version":3,"file":"history-reload-math.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/history-reload-math.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,eAAO,MAAM,4BAA4B,OAAO,CAAC;AACjD,eAAO,MAAM,6BAA6B,MAAM,CAAC;AAEjD,MAAM,WAAW,uBAAuB;IACvC,0FAA0F;IAC1F,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAWvD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAO3D;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAoBtE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,uBAA4B,GAAG,MAAM,CAY5G;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,MAAM,CAaxF;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,GAAG,YAAY,CAgB1G;AAED,wBAAgB,2BAA2B,CAC1C,QAAQ,EAAE,YAAY,EAAE,EACxB,OAAO,GAAE,uBAA4B,GACnC;IACF,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACvB,CA6BA","sourcesContent":["/**\n * Pure math for capping the TUI transcript that is re-rendered on reload/resume.\n *\n * These functions estimate wrapped line counts for agent messages and select the\n * tail of a message list that fits within the reload budget, trimming an oversized\n * head message when needed. They read only their arguments and hold no UI or session\n * state, so they live outside interactive-mode and are unit-testable in isolation.\n */\n\nimport type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport type { Message } from \"@caupulican/pi-ai\";\n\nexport const TUI_HISTORY_RELOAD_MAX_LINES = 1000;\nexport const TUI_HISTORY_RELOAD_WRAP_WIDTH = 100;\n\nexport interface TuiHistoryReloadOptions {\n\t/** Read tool-result content while sizing history. False when tool output is collapsed. */\n\tincludeToolResultContent?: boolean;\n}\n\nexport function getContentText(content: unknown): string {\n\tif (typeof content === \"string\") return content;\n\tif (Array.isArray(content)) {\n\t\treturn content\n\t\t\t.map((part) => {\n\t\t\t\tconst maybeText = (part as { text?: unknown }).text;\n\t\t\t\treturn typeof maybeText === \"string\" ? maybeText : \"\";\n\t\t\t})\n\t\t\t.join(\"\");\n\t}\n\treturn \"\";\n}\n\nexport function getUserMessageText(message: Message): string {\n\tif (message.role !== \"user\") return \"\";\n\tconst textBlocks =\n\t\ttypeof message.content === \"string\"\n\t\t\t? [{ type: \"text\", text: message.content }]\n\t\t\t: message.content.filter((c: { type: string }) => c.type === \"text\");\n\treturn textBlocks.map((c) => (c as { text: string }).text).join(\"\");\n}\n\nexport function getTuiHistoryMessageText(message: AgentMessage): string {\n\tswitch (message.role) {\n\t\tcase \"bashExecution\":\n\t\t\treturn [message.command, message.output ?? \"\"].filter(Boolean).join(\"\\n\");\n\t\tcase \"user\":\n\t\t\treturn getUserMessageText(message);\n\t\tcase \"assistant\":\n\t\t\treturn getContentText(message.content);\n\t\tcase \"toolResult\":\n\t\t\treturn getContentText(message.content);\n\t\tcase \"custom\":\n\t\t\treturn getContentText(message.content);\n\t\tcase \"compactionSummary\":\n\t\tcase \"branchSummary\":\n\t\t\treturn message.summary;\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = message;\n\t\t\treturn JSON.stringify(_exhaustive);\n\t\t}\n\t}\n}\n\nexport function estimateTuiHistoryLines(message: AgentMessage, options: TuiHistoryReloadOptions = {}): number {\n\tif (message.role === \"toolResult\" && options.includeToolResultContent === false) {\n\t\t// Tool results render inside their matching tool-call component, not as a separate row.\n\t\t// Retain a one-line accounting floor so orphaned results cannot bypass the reload bound.\n\t\treturn 1;\n\t}\n\tconst text = getTuiHistoryMessageText(message);\n\tconst hardLines = text.length > 0 ? text.split(/\\r\\n|\\r|\\n/).length : 1;\n\tconst wrappedLines = Math.ceil(text.length / TUI_HISTORY_RELOAD_WRAP_WIDTH);\n\t// Add one line for role/tool chrome or spacing. Tool-call-only assistant messages\n\t// have little text but still render a component.\n\treturn Math.max(1, hardLines, wrappedLines) + 1;\n}\n\nexport function trimTextToTuiHistoryTail(text: string, maxEstimatedLines: number): string {\n\tconst maxLines = Math.max(1, maxEstimatedLines);\n\tconst lines = text.split(/\\r\\n|\\r|\\n/);\n\tif (lines.length > maxLines) {\n\t\tconst omitted = lines.length - maxLines;\n\t\treturn `[Earlier ${omitted} line${omitted === 1 ? \"\" : \"s\"} omitted from TUI reload history; full session remains available to the model.]\\n${lines.slice(-maxLines).join(\"\\n\")}`;\n\t}\n\tconst maxChars = Math.max(TUI_HISTORY_RELOAD_WRAP_WIDTH, maxLines * TUI_HISTORY_RELOAD_WRAP_WIDTH);\n\tif (text.length > maxChars) {\n\t\tconst omitted = text.length - maxChars;\n\t\treturn `[Earlier ${omitted} character${omitted === 1 ? \"\" : \"s\"} omitted from TUI reload history; full session remains available to the model.]\\n${text.slice(-maxChars)}`;\n\t}\n\treturn text;\n}\n\nexport function trimMessageToTuiHistoryTail(message: AgentMessage, maxEstimatedLines: number): AgentMessage {\n\tconst text = getTuiHistoryMessageText(message);\n\tconst trimmedText = trimTextToTuiHistoryTail(text, maxEstimatedLines);\n\tif (trimmedText === text) return message;\n\tconst clone = JSON.parse(JSON.stringify(message)) as AgentMessage;\n\tconst mutable = clone as unknown as { role?: string; content?: unknown; output?: unknown };\n\tif (mutable.role === \"bashExecution\" && typeof mutable.output === \"string\") {\n\t\tmutable.output = trimmedText;\n\t} else if (mutable.role === \"compactionSummary\" || mutable.role === \"branchSummary\") {\n\t\t(mutable as { summary?: string }).summary = trimmedText;\n\t} else if (typeof mutable.content === \"string\") {\n\t\tmutable.content = trimmedText;\n\t} else {\n\t\tmutable.content = [{ type: \"text\", text: trimmedText }];\n\t}\n\treturn clone;\n}\n\nexport function messagesForTuiHistoryReload(\n\tmessages: AgentMessage[],\n\toptions: TuiHistoryReloadOptions = {},\n): {\n\tmessages: AgentMessage[];\n\tomittedMessages: number;\n\testimatedLines: number;\n} {\n\tlet estimatedLines = 0;\n\tlet start = messages.length;\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst nextLines = estimateTuiHistoryLines(messages[i], options);\n\t\tif (start < messages.length && estimatedLines + nextLines > TUI_HISTORY_RELOAD_MAX_LINES) break;\n\t\testimatedLines += nextLines;\n\t\tstart = i;\n\t\tif (estimatedLines >= TUI_HISTORY_RELOAD_MAX_LINES) break;\n\t}\n\tconst selected = messages.slice(start);\n\tif (selected.length > 0 && estimatedLines > TUI_HISTORY_RELOAD_MAX_LINES) {\n\t\tconst tailLines = selected.slice(1).reduce((sum, message) => sum + estimateTuiHistoryLines(message, options), 0);\n\t\tconst firstAllowance = TUI_HISTORY_RELOAD_MAX_LINES - tailLines;\n\t\tif (firstAllowance <= 4) {\n\t\t\tselected.shift();\n\t\t\tstart += 1;\n\t\t\testimatedLines = tailLines;\n\t\t} else {\n\t\t\t// Reserve room for truncation marker, role chrome, and wrap variance.\n\t\t\tselected[0] = trimMessageToTuiHistoryTail(selected[0], firstAllowance - 4);\n\t\t\testimatedLines = tailLines + estimateTuiHistoryLines(selected[0], options);\n\t\t}\n\t}\n\treturn {\n\t\tmessages: selected,\n\t\tomittedMessages: start,\n\t\testimatedLines,\n\t};\n}\n"]}
@@ -50,7 +50,12 @@ export function getTuiHistoryMessageText(message) {
50
50
  }
51
51
  }
52
52
  }
53
- export function estimateTuiHistoryLines(message) {
53
+ export function estimateTuiHistoryLines(message, options = {}) {
54
+ if (message.role === "toolResult" && options.includeToolResultContent === false) {
55
+ // Tool results render inside their matching tool-call component, not as a separate row.
56
+ // Retain a one-line accounting floor so orphaned results cannot bypass the reload bound.
57
+ return 1;
58
+ }
54
59
  const text = getTuiHistoryMessageText(message);
55
60
  const hardLines = text.length > 0 ? text.split(/\r\n|\r|\n/).length : 1;
56
61
  const wrappedLines = Math.ceil(text.length / TUI_HISTORY_RELOAD_WRAP_WIDTH);
@@ -93,11 +98,11 @@ export function trimMessageToTuiHistoryTail(message, maxEstimatedLines) {
93
98
  }
94
99
  return clone;
95
100
  }
96
- export function messagesForTuiHistoryReload(messages) {
101
+ export function messagesForTuiHistoryReload(messages, options = {}) {
97
102
  let estimatedLines = 0;
98
103
  let start = messages.length;
99
104
  for (let i = messages.length - 1; i >= 0; i--) {
100
- const nextLines = estimateTuiHistoryLines(messages[i]);
105
+ const nextLines = estimateTuiHistoryLines(messages[i], options);
101
106
  if (start < messages.length && estimatedLines + nextLines > TUI_HISTORY_RELOAD_MAX_LINES)
102
107
  break;
103
108
  estimatedLines += nextLines;
@@ -107,7 +112,7 @@ export function messagesForTuiHistoryReload(messages) {
107
112
  }
108
113
  const selected = messages.slice(start);
109
114
  if (selected.length > 0 && estimatedLines > TUI_HISTORY_RELOAD_MAX_LINES) {
110
- const tailLines = selected.slice(1).reduce((sum, message) => sum + estimateTuiHistoryLines(message), 0);
115
+ const tailLines = selected.slice(1).reduce((sum, message) => sum + estimateTuiHistoryLines(message, options), 0);
111
116
  const firstAllowance = TUI_HISTORY_RELOAD_MAX_LINES - tailLines;
112
117
  if (firstAllowance <= 4) {
113
118
  selected.shift();
@@ -117,7 +122,7 @@ export function messagesForTuiHistoryReload(messages) {
117
122
  else {
118
123
  // Reserve room for truncation marker, role chrome, and wrap variance.
119
124
  selected[0] = trimMessageToTuiHistoryTail(selected[0], firstAllowance - 4);
120
- estimatedLines = tailLines + estimateTuiHistoryLines(selected[0]);
125
+ estimatedLines = tailLines + estimateTuiHistoryLines(selected[0], options);
121
126
  }
122
127
  }
123
128
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"history-reload-math.js","sourceRoot":"","sources":["../../../src/modes/interactive/history-reload-math.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure math for capping the TUI transcript that is re-rendered on reload/resume.\n *\n * These functions estimate wrapped line counts for agent messages and select the\n * tail of a message list that fits within the reload budget, trimming an oversized\n * head message when needed. They read only their arguments and hold no UI or session\n * state, so they live outside interactive-mode and are unit-testable in isolation.\n */\n\nimport type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport type { Message } from \"@caupulican/pi-ai\";\n\nexport const TUI_HISTORY_RELOAD_MAX_LINES = 1000;\nexport const TUI_HISTORY_RELOAD_WRAP_WIDTH = 100;\n\nexport function getContentText(content: unknown): string {\n\tif (typeof content === \"string\") return content;\n\tif (Array.isArray(content)) {\n\t\treturn content\n\t\t\t.map((part) => {\n\t\t\t\tconst maybeText = (part as { text?: unknown }).text;\n\t\t\t\treturn typeof maybeText === \"string\" ? maybeText : \"\";\n\t\t\t})\n\t\t\t.join(\"\");\n\t}\n\treturn \"\";\n}\n\nexport function getUserMessageText(message: Message): string {\n\tif (message.role !== \"user\") return \"\";\n\tconst textBlocks =\n\t\ttypeof message.content === \"string\"\n\t\t\t? [{ type: \"text\", text: message.content }]\n\t\t\t: message.content.filter((c: { type: string }) => c.type === \"text\");\n\treturn textBlocks.map((c) => (c as { text: string }).text).join(\"\");\n}\n\nexport function getTuiHistoryMessageText(message: AgentMessage): string {\n\tswitch (message.role) {\n\t\tcase \"bashExecution\":\n\t\t\treturn [message.command, message.output ?? \"\"].filter(Boolean).join(\"\\n\");\n\t\tcase \"user\":\n\t\t\treturn getUserMessageText(message);\n\t\tcase \"assistant\":\n\t\t\treturn getContentText(message.content);\n\t\tcase \"toolResult\":\n\t\t\treturn getContentText(message.content);\n\t\tcase \"custom\":\n\t\t\treturn getContentText(message.content);\n\t\tcase \"compactionSummary\":\n\t\tcase \"branchSummary\":\n\t\t\treturn message.summary;\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = message;\n\t\t\treturn JSON.stringify(_exhaustive);\n\t\t}\n\t}\n}\n\nexport function estimateTuiHistoryLines(message: AgentMessage): number {\n\tconst text = getTuiHistoryMessageText(message);\n\tconst hardLines = text.length > 0 ? text.split(/\\r\\n|\\r|\\n/).length : 1;\n\tconst wrappedLines = Math.ceil(text.length / TUI_HISTORY_RELOAD_WRAP_WIDTH);\n\t// Add one line for role/tool chrome or spacing. Tool-call-only assistant messages\n\t// have little text but still render a component.\n\treturn Math.max(1, hardLines, wrappedLines) + 1;\n}\n\nexport function trimTextToTuiHistoryTail(text: string, maxEstimatedLines: number): string {\n\tconst maxLines = Math.max(1, maxEstimatedLines);\n\tconst lines = text.split(/\\r\\n|\\r|\\n/);\n\tif (lines.length > maxLines) {\n\t\tconst omitted = lines.length - maxLines;\n\t\treturn `[Earlier ${omitted} line${omitted === 1 ? \"\" : \"s\"} omitted from TUI reload history; full session remains available to the model.]\\n${lines.slice(-maxLines).join(\"\\n\")}`;\n\t}\n\tconst maxChars = Math.max(TUI_HISTORY_RELOAD_WRAP_WIDTH, maxLines * TUI_HISTORY_RELOAD_WRAP_WIDTH);\n\tif (text.length > maxChars) {\n\t\tconst omitted = text.length - maxChars;\n\t\treturn `[Earlier ${omitted} character${omitted === 1 ? \"\" : \"s\"} omitted from TUI reload history; full session remains available to the model.]\\n${text.slice(-maxChars)}`;\n\t}\n\treturn text;\n}\n\nexport function trimMessageToTuiHistoryTail(message: AgentMessage, maxEstimatedLines: number): AgentMessage {\n\tconst text = getTuiHistoryMessageText(message);\n\tconst trimmedText = trimTextToTuiHistoryTail(text, maxEstimatedLines);\n\tif (trimmedText === text) return message;\n\tconst clone = JSON.parse(JSON.stringify(message)) as AgentMessage;\n\tconst mutable = clone as unknown as { role?: string; content?: unknown; output?: unknown };\n\tif (mutable.role === \"bashExecution\" && typeof mutable.output === \"string\") {\n\t\tmutable.output = trimmedText;\n\t} else if (mutable.role === \"compactionSummary\" || mutable.role === \"branchSummary\") {\n\t\t(mutable as { summary?: string }).summary = trimmedText;\n\t} else if (typeof mutable.content === \"string\") {\n\t\tmutable.content = trimmedText;\n\t} else {\n\t\tmutable.content = [{ type: \"text\", text: trimmedText }];\n\t}\n\treturn clone;\n}\n\nexport function messagesForTuiHistoryReload(messages: AgentMessage[]): {\n\tmessages: AgentMessage[];\n\tomittedMessages: number;\n\testimatedLines: number;\n} {\n\tlet estimatedLines = 0;\n\tlet start = messages.length;\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst nextLines = estimateTuiHistoryLines(messages[i]);\n\t\tif (start < messages.length && estimatedLines + nextLines > TUI_HISTORY_RELOAD_MAX_LINES) break;\n\t\testimatedLines += nextLines;\n\t\tstart = i;\n\t\tif (estimatedLines >= TUI_HISTORY_RELOAD_MAX_LINES) break;\n\t}\n\tconst selected = messages.slice(start);\n\tif (selected.length > 0 && estimatedLines > TUI_HISTORY_RELOAD_MAX_LINES) {\n\t\tconst tailLines = selected.slice(1).reduce((sum, message) => sum + estimateTuiHistoryLines(message), 0);\n\t\tconst firstAllowance = TUI_HISTORY_RELOAD_MAX_LINES - tailLines;\n\t\tif (firstAllowance <= 4) {\n\t\t\tselected.shift();\n\t\t\tstart += 1;\n\t\t\testimatedLines = tailLines;\n\t\t} else {\n\t\t\t// Reserve room for truncation marker, role chrome, and wrap variance.\n\t\t\tselected[0] = trimMessageToTuiHistoryTail(selected[0], firstAllowance - 4);\n\t\t\testimatedLines = tailLines + estimateTuiHistoryLines(selected[0]);\n\t\t}\n\t}\n\treturn {\n\t\tmessages: selected,\n\t\tomittedMessages: start,\n\t\testimatedLines,\n\t};\n}\n"]}
1
+ {"version":3,"file":"history-reload-math.js","sourceRoot":"","sources":["../../../src/modes/interactive/history-reload-math.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure math for capping the TUI transcript that is re-rendered on reload/resume.\n *\n * These functions estimate wrapped line counts for agent messages and select the\n * tail of a message list that fits within the reload budget, trimming an oversized\n * head message when needed. They read only their arguments and hold no UI or session\n * state, so they live outside interactive-mode and are unit-testable in isolation.\n */\n\nimport type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport type { Message } from \"@caupulican/pi-ai\";\n\nexport const TUI_HISTORY_RELOAD_MAX_LINES = 1000;\nexport const TUI_HISTORY_RELOAD_WRAP_WIDTH = 100;\n\nexport interface TuiHistoryReloadOptions {\n\t/** Read tool-result content while sizing history. False when tool output is collapsed. */\n\tincludeToolResultContent?: boolean;\n}\n\nexport function getContentText(content: unknown): string {\n\tif (typeof content === \"string\") return content;\n\tif (Array.isArray(content)) {\n\t\treturn content\n\t\t\t.map((part) => {\n\t\t\t\tconst maybeText = (part as { text?: unknown }).text;\n\t\t\t\treturn typeof maybeText === \"string\" ? maybeText : \"\";\n\t\t\t})\n\t\t\t.join(\"\");\n\t}\n\treturn \"\";\n}\n\nexport function getUserMessageText(message: Message): string {\n\tif (message.role !== \"user\") return \"\";\n\tconst textBlocks =\n\t\ttypeof message.content === \"string\"\n\t\t\t? [{ type: \"text\", text: message.content }]\n\t\t\t: message.content.filter((c: { type: string }) => c.type === \"text\");\n\treturn textBlocks.map((c) => (c as { text: string }).text).join(\"\");\n}\n\nexport function getTuiHistoryMessageText(message: AgentMessage): string {\n\tswitch (message.role) {\n\t\tcase \"bashExecution\":\n\t\t\treturn [message.command, message.output ?? \"\"].filter(Boolean).join(\"\\n\");\n\t\tcase \"user\":\n\t\t\treturn getUserMessageText(message);\n\t\tcase \"assistant\":\n\t\t\treturn getContentText(message.content);\n\t\tcase \"toolResult\":\n\t\t\treturn getContentText(message.content);\n\t\tcase \"custom\":\n\t\t\treturn getContentText(message.content);\n\t\tcase \"compactionSummary\":\n\t\tcase \"branchSummary\":\n\t\t\treturn message.summary;\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = message;\n\t\t\treturn JSON.stringify(_exhaustive);\n\t\t}\n\t}\n}\n\nexport function estimateTuiHistoryLines(message: AgentMessage, options: TuiHistoryReloadOptions = {}): number {\n\tif (message.role === \"toolResult\" && options.includeToolResultContent === false) {\n\t\t// Tool results render inside their matching tool-call component, not as a separate row.\n\t\t// Retain a one-line accounting floor so orphaned results cannot bypass the reload bound.\n\t\treturn 1;\n\t}\n\tconst text = getTuiHistoryMessageText(message);\n\tconst hardLines = text.length > 0 ? text.split(/\\r\\n|\\r|\\n/).length : 1;\n\tconst wrappedLines = Math.ceil(text.length / TUI_HISTORY_RELOAD_WRAP_WIDTH);\n\t// Add one line for role/tool chrome or spacing. Tool-call-only assistant messages\n\t// have little text but still render a component.\n\treturn Math.max(1, hardLines, wrappedLines) + 1;\n}\n\nexport function trimTextToTuiHistoryTail(text: string, maxEstimatedLines: number): string {\n\tconst maxLines = Math.max(1, maxEstimatedLines);\n\tconst lines = text.split(/\\r\\n|\\r|\\n/);\n\tif (lines.length > maxLines) {\n\t\tconst omitted = lines.length - maxLines;\n\t\treturn `[Earlier ${omitted} line${omitted === 1 ? \"\" : \"s\"} omitted from TUI reload history; full session remains available to the model.]\\n${lines.slice(-maxLines).join(\"\\n\")}`;\n\t}\n\tconst maxChars = Math.max(TUI_HISTORY_RELOAD_WRAP_WIDTH, maxLines * TUI_HISTORY_RELOAD_WRAP_WIDTH);\n\tif (text.length > maxChars) {\n\t\tconst omitted = text.length - maxChars;\n\t\treturn `[Earlier ${omitted} character${omitted === 1 ? \"\" : \"s\"} omitted from TUI reload history; full session remains available to the model.]\\n${text.slice(-maxChars)}`;\n\t}\n\treturn text;\n}\n\nexport function trimMessageToTuiHistoryTail(message: AgentMessage, maxEstimatedLines: number): AgentMessage {\n\tconst text = getTuiHistoryMessageText(message);\n\tconst trimmedText = trimTextToTuiHistoryTail(text, maxEstimatedLines);\n\tif (trimmedText === text) return message;\n\tconst clone = JSON.parse(JSON.stringify(message)) as AgentMessage;\n\tconst mutable = clone as unknown as { role?: string; content?: unknown; output?: unknown };\n\tif (mutable.role === \"bashExecution\" && typeof mutable.output === \"string\") {\n\t\tmutable.output = trimmedText;\n\t} else if (mutable.role === \"compactionSummary\" || mutable.role === \"branchSummary\") {\n\t\t(mutable as { summary?: string }).summary = trimmedText;\n\t} else if (typeof mutable.content === \"string\") {\n\t\tmutable.content = trimmedText;\n\t} else {\n\t\tmutable.content = [{ type: \"text\", text: trimmedText }];\n\t}\n\treturn clone;\n}\n\nexport function messagesForTuiHistoryReload(\n\tmessages: AgentMessage[],\n\toptions: TuiHistoryReloadOptions = {},\n): {\n\tmessages: AgentMessage[];\n\tomittedMessages: number;\n\testimatedLines: number;\n} {\n\tlet estimatedLines = 0;\n\tlet start = messages.length;\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst nextLines = estimateTuiHistoryLines(messages[i], options);\n\t\tif (start < messages.length && estimatedLines + nextLines > TUI_HISTORY_RELOAD_MAX_LINES) break;\n\t\testimatedLines += nextLines;\n\t\tstart = i;\n\t\tif (estimatedLines >= TUI_HISTORY_RELOAD_MAX_LINES) break;\n\t}\n\tconst selected = messages.slice(start);\n\tif (selected.length > 0 && estimatedLines > TUI_HISTORY_RELOAD_MAX_LINES) {\n\t\tconst tailLines = selected.slice(1).reduce((sum, message) => sum + estimateTuiHistoryLines(message, options), 0);\n\t\tconst firstAllowance = TUI_HISTORY_RELOAD_MAX_LINES - tailLines;\n\t\tif (firstAllowance <= 4) {\n\t\t\tselected.shift();\n\t\t\tstart += 1;\n\t\t\testimatedLines = tailLines;\n\t\t} else {\n\t\t\t// Reserve room for truncation marker, role chrome, and wrap variance.\n\t\t\tselected[0] = trimMessageToTuiHistoryTail(selected[0], firstAllowance - 4);\n\t\t\testimatedLines = tailLines + estimateTuiHistoryLines(selected[0], options);\n\t\t}\n\t}\n\treturn {\n\t\tmessages: selected,\n\t\tomittedMessages: start,\n\t\testimatedLines,\n\t};\n}\n"]}
@@ -0,0 +1,74 @@
1
+ import type { AgentMessage, ToolCallRepairInfo } from "@caupulican/pi-agent-core";
2
+ import type { AssistantMessage } from "@caupulican/pi-ai";
3
+ import { type Container, type Loader, type LoaderIndicatorOptions, type MarkdownTheme, type TUI } from "@caupulican/pi-tui";
4
+ import type { AgentSession } from "../../core/agent-session.ts";
5
+ import type { AgentSessionEvent } from "../../core/agent-session-contracts.ts";
6
+ import type { FooterDataProvider } from "../../core/footer-data-provider.ts";
7
+ import type { SettingsManager } from "../../core/settings-manager.ts";
8
+ import type { ActivityLaneComponent, ActivityLaneKind } from "./components/activity-lane.ts";
9
+ import { AssistantMessageComponent } from "./components/assistant-message.ts";
10
+ import { CountdownTimer } from "./components/countdown-timer.ts";
11
+ import type { CustomEditor } from "./components/custom-editor.ts";
12
+ import type { FooterComponent } from "./components/footer.ts";
13
+ import type { ToolExecutionComponent } from "./components/tool-execution.ts";
14
+ import { type ToolPanelRegistry, type ToolPanelTenantScope } from "./components/tool-panel-registry.ts";
15
+ /** Structural host consumed by the event owner. InteractiveMode deliberately remains a thin facade. */
16
+ export interface InteractiveEventHost {
17
+ isInitialized: boolean;
18
+ session: AgentSession;
19
+ settingsManager: SettingsManager;
20
+ footer: FooterComponent;
21
+ footerDataProvider: FooterDataProvider;
22
+ ui: TUI;
23
+ defaultEditor: CustomEditor;
24
+ statusContainer: Container;
25
+ chatContainer: Container;
26
+ activityLane: ActivityLaneComponent | undefined;
27
+ loadingAnimation: Loader | undefined;
28
+ workingVisible: boolean;
29
+ workingIndicatorOptions: LoaderIndicatorOptions | undefined;
30
+ retryEscapeHandler: (() => void) | undefined;
31
+ retryCountdown: CountdownTimer | undefined;
32
+ autoCompactionEscapeHandler: (() => void) | undefined;
33
+ streamingComponent: AssistantMessageComponent | undefined;
34
+ streamingMessage: AssistantMessage | undefined;
35
+ hideThinkingBlock: boolean;
36
+ hiddenThinkingLabel: string;
37
+ lastStreamingUiUpdateAt: number;
38
+ toolPanels: ToolPanelRegistry;
39
+ init(): Promise<void>;
40
+ createWorkingLoader(): Loader;
41
+ stopWorkingLoader(): void;
42
+ clearActiveToolCalls(): void;
43
+ getWorkingLoaderMessage(): string;
44
+ updatePendingMessagesDisplay(): void;
45
+ updateTerminalTitle(): void;
46
+ refreshActivityLane(): void;
47
+ updateEditorBorderColor(): void;
48
+ showWarning(message: string): void;
49
+ showError(message: string): void;
50
+ addMessageToChat(message: AgentMessage): void;
51
+ clearPendingStreamingUiUpdate(): void;
52
+ getMarkdownThemeWithSettings(): MarkdownTheme;
53
+ applyStreamingMessageUpdate(message: AssistantMessage, options?: {
54
+ force?: boolean;
55
+ }): void;
56
+ trimLiveTuiHistory(): void;
57
+ attachToolExecutionComponent(toolName: string, toolCallId: string, args: unknown, repair?: ToolCallRepairInfo): ToolExecutionComponent;
58
+ toolActivityKind(toolName: string): ActivityLaneKind;
59
+ toolActivityLabel(toolName: string): string;
60
+ toolActivityTerminalStatus(isError: boolean, details: unknown): "success" | "failure" | "neutral";
61
+ getToolPanelScope(): ToolPanelTenantScope;
62
+ isNativeReflectionEnabled(): boolean;
63
+ maybeRunNativeReflection(messages: AgentMessage[]): void;
64
+ maybeStartAutoLearn(): boolean;
65
+ maybeStartAutonomyReview(messages: AgentMessage[]): boolean;
66
+ checkShutdownRequested(): Promise<void>;
67
+ rebuildChatFromMessages(): Promise<void>;
68
+ flushCompactionQueue(options?: {
69
+ willRetry?: boolean;
70
+ }): Promise<void>;
71
+ }
72
+ /** Single owner for AgentSessionEvent -> terminal UI state transitions. */
73
+ export declare function handleInteractiveEvent(host: InteractiveEventHost, event: AgentSessionEvent): Promise<void>;
74
+ //# sourceMappingURL=interactive-event-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive-event-controller.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/interactive-event-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage, ToolCallRepairInfo } from \"@caupulican/pi-agent-core\";\nimport { createCompactionSummaryMessage } from \"@caupulican/pi-agent-core\";\nimport type { AssistantMessage } from \"@caupulican/pi-ai\";\nimport {\n\ttype Container,\n\ttype Loader,\n\ttype LoaderIndicatorOptions,\n\ttype MarkdownTheme,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@caupulican/pi-tui\";\nimport type { AgentSession } from \"../../core/agent-session.ts\";\nimport type { AgentSessionEvent } from \"../../core/agent-session-contracts.ts\";\nimport type { FooterDataProvider } from \"../../core/footer-data-provider.ts\";\nimport type { SettingsManager } from \"../../core/settings-manager.ts\";\nimport type { ActivityLaneComponent, ActivityLaneKind } from \"./components/activity-lane.ts\";\nimport { AssistantMessageComponent } from \"./components/assistant-message.ts\";\nimport { CountdownTimer } from \"./components/countdown-timer.ts\";\nimport type { CustomEditor } from \"./components/custom-editor.ts\";\nimport type { FooterComponent } from \"./components/footer.ts\";\nimport { keyText } from \"./components/keybinding-hints.ts\";\nimport type { ToolExecutionComponent } from \"./components/tool-execution.ts\";\nimport {\n\tgetToolPanelResultActionKeys,\n\ttype ToolPanelRegistry,\n\ttype ToolPanelTenantScope,\n} from \"./components/tool-panel-registry.ts\";\nimport { theme } from \"./theme/theme.ts\";\n\n/** Structural host consumed by the event owner. InteractiveMode deliberately remains a thin facade. */\nexport interface InteractiveEventHost {\n\tisInitialized: boolean;\n\tsession: AgentSession;\n\tsettingsManager: SettingsManager;\n\tfooter: FooterComponent;\n\tfooterDataProvider: FooterDataProvider;\n\tui: TUI;\n\tdefaultEditor: CustomEditor;\n\tstatusContainer: Container;\n\tchatContainer: Container;\n\tactivityLane: ActivityLaneComponent | undefined;\n\tloadingAnimation: Loader | undefined;\n\tworkingVisible: boolean;\n\tworkingIndicatorOptions: LoaderIndicatorOptions | undefined;\n\tretryEscapeHandler: (() => void) | undefined;\n\tretryCountdown: CountdownTimer | undefined;\n\tautoCompactionEscapeHandler: (() => void) | undefined;\n\tstreamingComponent: AssistantMessageComponent | undefined;\n\tstreamingMessage: AssistantMessage | undefined;\n\thideThinkingBlock: boolean;\n\thiddenThinkingLabel: string;\n\tlastStreamingUiUpdateAt: number;\n\ttoolPanels: ToolPanelRegistry;\n\tinit(): Promise<void>;\n\tcreateWorkingLoader(): Loader;\n\tstopWorkingLoader(): void;\n\tclearActiveToolCalls(): void;\n\tgetWorkingLoaderMessage(): string;\n\tupdatePendingMessagesDisplay(): void;\n\tupdateTerminalTitle(): void;\n\trefreshActivityLane(): void;\n\tupdateEditorBorderColor(): void;\n\tshowWarning(message: string): void;\n\tshowError(message: string): void;\n\taddMessageToChat(message: AgentMessage): void;\n\tclearPendingStreamingUiUpdate(): void;\n\tgetMarkdownThemeWithSettings(): MarkdownTheme;\n\tapplyStreamingMessageUpdate(message: AssistantMessage, options?: { force?: boolean }): void;\n\ttrimLiveTuiHistory(): void;\n\tattachToolExecutionComponent(\n\t\ttoolName: string,\n\t\ttoolCallId: string,\n\t\targs: unknown,\n\t\trepair?: ToolCallRepairInfo,\n\t): ToolExecutionComponent;\n\ttoolActivityKind(toolName: string): ActivityLaneKind;\n\ttoolActivityLabel(toolName: string): string;\n\ttoolActivityTerminalStatus(isError: boolean, details: unknown): \"success\" | \"failure\" | \"neutral\";\n\tgetToolPanelScope(): ToolPanelTenantScope;\n\tisNativeReflectionEnabled(): boolean;\n\tmaybeRunNativeReflection(messages: AgentMessage[]): void;\n\tmaybeStartAutoLearn(): boolean;\n\tmaybeStartAutonomyReview(messages: AgentMessage[]): boolean;\n\tcheckShutdownRequested(): Promise<void>;\n\trebuildChatFromMessages(): Promise<void>;\n\tflushCompactionQueue(options?: { willRetry?: boolean }): Promise<void>;\n}\n\n/** Single owner for AgentSessionEvent -> terminal UI state transitions. */\nexport async function handleInteractiveEvent(host: InteractiveEventHost, event: AgentSessionEvent): Promise<void> {\n\tif (!host.isInitialized) await host.init();\n\thost.footer.invalidate();\n\n\tswitch (event.type) {\n\t\tcase \"routing_start\":\n\t\t\tif (!host.session.isStreaming && !host.loadingAnimation && host.workingVisible) {\n\t\t\t\tif (host.workingIndicatorOptions) {\n\t\t\t\t\thost.loadingAnimation = host.createWorkingLoader();\n\t\t\t\t\thost.statusContainer.addChild(host.loadingAnimation);\n\t\t\t\t} else {\n\t\t\t\t\thost.activityLane?.start({ id: \"runtime:routing\", kind: \"runtime\", label: \"Routing\" });\n\t\t\t\t}\n\t\t\t\thost.ui.requestRender();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"routing_end\":\n\t\t\thost.stopWorkingLoader();\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"agent_start\":\n\t\t\thost.clearActiveToolCalls();\n\t\t\tif (host.settingsManager.getShowTerminalProgress()) host.ui.terminal.setProgress(true);\n\t\t\tif (host.retryEscapeHandler) {\n\t\t\t\thost.defaultEditor.onEscape = host.retryEscapeHandler;\n\t\t\t\thost.retryEscapeHandler = undefined;\n\t\t\t}\n\t\t\tif (host.retryCountdown) {\n\t\t\t\thost.retryCountdown.dispose();\n\t\t\t\thost.retryCountdown = undefined;\n\t\t\t}\n\t\t\thost.activityLane?.remove(\"runtime:retry\");\n\t\t\thost.stopWorkingLoader();\n\t\t\tif (host.workingVisible) {\n\t\t\t\tif (host.workingIndicatorOptions) {\n\t\t\t\t\thost.loadingAnimation = host.createWorkingLoader();\n\t\t\t\t\thost.statusContainer.addChild(host.loadingAnimation);\n\t\t\t\t} else {\n\t\t\t\t\thost.activityLane?.start({\n\t\t\t\t\t\tid: \"runtime:turn\",\n\t\t\t\t\t\tkind: \"runtime\",\n\t\t\t\t\t\tlabel: host.getWorkingLoaderMessage(),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"queue_update\":\n\t\t\thost.updatePendingMessagesDisplay();\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"session_info_changed\":\n\t\t\thost.updateTerminalTitle();\n\t\t\thost.refreshActivityLane();\n\t\t\thost.footer.invalidate();\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"thinking_level_changed\":\n\t\t\thost.footer.invalidate();\n\t\t\thost.updateEditorBorderColor();\n\t\t\tbreak;\n\n\t\tcase \"warning\":\n\t\t\thost.showWarning(event.message);\n\t\t\tbreak;\n\n\t\tcase \"delegate_workers\":\n\t\t\thost.footerDataProvider.setExtensionStatus(\"delegate\", undefined);\n\t\t\thost.refreshActivityLane();\n\t\t\thost.footer.invalidate();\n\t\t\tbreak;\n\n\t\tcase \"message_start\":\n\t\t\tif (event.message.role === \"custom\") {\n\t\t\t\thost.addMessageToChat(event.message);\n\t\t\t\thost.ui.requestRender();\n\t\t\t} else if (event.message.role === \"user\") {\n\t\t\t\thost.addMessageToChat(event.message);\n\t\t\t\thost.updatePendingMessagesDisplay();\n\t\t\t\thost.ui.requestRender();\n\t\t\t} else if (event.message.role === \"assistant\") {\n\t\t\t\thost.clearPendingStreamingUiUpdate();\n\t\t\t\thost.lastStreamingUiUpdateAt = 0;\n\t\t\t\thost.streamingComponent = new AssistantMessageComponent(\n\t\t\t\t\tundefined,\n\t\t\t\t\thost.hideThinkingBlock,\n\t\t\t\t\thost.getMarkdownThemeWithSettings(),\n\t\t\t\t\thost.hiddenThinkingLabel,\n\t\t\t\t);\n\t\t\t\thost.streamingMessage = event.message;\n\t\t\t\thost.chatContainer.addChild(host.streamingComponent);\n\t\t\t\thost.applyStreamingMessageUpdate(host.streamingMessage, { force: true });\n\t\t\t\thost.trimLiveTuiHistory();\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"message_update\":\n\t\t\tif (host.streamingComponent && event.message.role === \"assistant\") {\n\t\t\t\thost.applyStreamingMessageUpdate(event.message);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase \"message_end\":\n\t\t\tif (event.message.role === \"user\") break;\n\t\t\tif (host.streamingComponent && event.message.role === \"assistant\") {\n\t\t\t\thost.streamingMessage = event.message;\n\t\t\t\tlet errorMessage: string | undefined;\n\t\t\t\tif (host.streamingMessage.stopReason === \"aborted\") {\n\t\t\t\t\tconst retryAttempt = host.session.retryAttempt;\n\t\t\t\t\terrorMessage =\n\t\t\t\t\t\tretryAttempt > 0\n\t\t\t\t\t\t\t? `Aborted after ${retryAttempt} retry attempt${retryAttempt > 1 ? \"s\" : \"\"}`\n\t\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\t\thost.streamingMessage.errorMessage = errorMessage;\n\t\t\t\t}\n\t\t\t\thost.applyStreamingMessageUpdate(host.streamingMessage, { force: true });\n\t\t\t\tif (host.streamingMessage.stopReason === \"aborted\" || host.streamingMessage.stopReason === \"error\") {\n\t\t\t\t\terrorMessage ??= host.streamingMessage.errorMessage || \"Error\";\n\t\t\t\t\tfor (const [, component] of host.toolPanels.activeEntries()) {\n\t\t\t\t\t\tcomponent.updateResult({ content: [{ type: \"text\", text: errorMessage }], isError: true });\n\t\t\t\t\t}\n\t\t\t\t\thost.clearActiveToolCalls();\n\t\t\t\t} else {\n\t\t\t\t\tfor (const [, component] of host.toolPanels.activeEntries()) component.setArgsComplete();\n\t\t\t\t}\n\t\t\t\thost.streamingComponent = undefined;\n\t\t\t\thost.streamingMessage = undefined;\n\t\t\t\thost.footer.invalidate();\n\t\t\t}\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\n\t\tcase \"tool_execution_start\": {\n\t\t\thost.activityLane?.start({\n\t\t\t\tid: `tool:${event.toolCallId}`,\n\t\t\t\tkind: host.toolActivityKind(event.toolName),\n\t\t\t\tlabel: host.toolActivityLabel(event.toolName),\n\t\t\t});\n\t\t\tlet component = host.toolPanels.getActive(event.toolCallId);\n\t\t\tif (!component) {\n\t\t\t\tcomponent = host.attachToolExecutionComponent(event.toolName, event.toolCallId, event.args, event.repair);\n\t\t\t} else {\n\t\t\t\tcomponent.updateArgs(event.args, event.repair);\n\t\t\t}\n\t\t\tcomponent.markExecutionStarted(event.repair);\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"tool_execution_update\": {\n\t\t\tconst component = host.toolPanels.getActive(event.toolCallId);\n\t\t\tif (component) {\n\t\t\t\tcomponent.updateArgs(event.args, event.repair);\n\t\t\t\tcomponent.updateResult({ ...event.partialResult, isError: false }, true);\n\t\t\t\thost.ui.requestRender();\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"tool_execution_end\": {\n\t\t\tconst toolActivityId = `tool:${event.toolCallId}`;\n\t\t\tif (host.activityLane) {\n\t\t\t\tconst toolKind = host.toolActivityKind(event.toolName);\n\t\t\t\tconst terminalStatus = host.toolActivityTerminalStatus(event.isError, event.result.details);\n\t\t\t\tif (toolKind === \"tool\" || terminalStatus !== \"success\") {\n\t\t\t\t\thost.activityLane.finish(toolActivityId, terminalStatus, {\n\t\t\t\t\t\tid: toolActivityId,\n\t\t\t\t\t\tkind: toolKind,\n\t\t\t\t\t\tlabel: host.toolActivityLabel(event.toolName),\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\thost.activityLane.remove(toolActivityId);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst component = host.toolPanels.getActive(event.toolCallId);\n\t\t\tif (component) {\n\t\t\t\tcomponent.updateResult({ ...event.result, isError: event.isError });\n\t\t\t\thost.toolPanels.registerAliases(\n\t\t\t\t\tcomponent,\n\t\t\t\t\tgetToolPanelResultActionKeys(host.getToolPanelScope(), event.toolName, event.result),\n\t\t\t\t);\n\t\t\t\thost.toolPanels.finish(event.toolCallId);\n\t\t\t\thost.ui.requestRender();\n\t\t\t}\n\t\t\tif ([\"task_steps\", \"goal\", \"delegate\", \"delegate_status\"].includes(event.toolName)) {\n\t\t\t\thost.refreshActivityLane();\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"agent_end\": {\n\t\t\tif (host.isNativeReflectionEnabled()) host.maybeRunNativeReflection(event.messages);\n\t\t\telse if (!host.maybeStartAutoLearn()) host.maybeStartAutonomyReview(event.messages);\n\t\t\tif (host.settingsManager.getShowTerminalProgress()) host.ui.terminal.setProgress(false);\n\t\t\tif (event.willRetry) {\n\t\t\t\thost.activityLane?.remove(\"runtime:turn\");\n\t\t\t} else {\n\t\t\t\tconst finalAssistant = event.messages.findLast(\n\t\t\t\t\t(message): message is AssistantMessage => message.role === \"assistant\",\n\t\t\t\t);\n\t\t\t\tconst failed = finalAssistant?.stopReason === \"error\" || finalAssistant?.stopReason === \"aborted\";\n\t\t\t\thost.activityLane?.finish(\"runtime:turn\", failed ? \"failure\" : \"success\", {\n\t\t\t\t\tid: \"runtime:turn\",\n\t\t\t\t\tkind: \"runtime\",\n\t\t\t\t\tlabel: failed ? \"Turn failed\" : \"Done\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (host.loadingAnimation) {\n\t\t\t\thost.loadingAnimation.stop();\n\t\t\t\thost.loadingAnimation = undefined;\n\t\t\t\thost.statusContainer.clear();\n\t\t\t}\n\t\t\tif (host.streamingComponent) {\n\t\t\t\thost.chatContainer.removeChild(host.streamingComponent);\n\t\t\t\thost.streamingComponent = undefined;\n\t\t\t\thost.streamingMessage = undefined;\n\t\t\t}\n\t\t\thost.clearActiveToolCalls();\n\t\t\thost.activityLane?.removeByPrefix(\"tool:\");\n\t\t\tawait host.checkShutdownRequested();\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"compaction_start\": {\n\t\t\tif (host.settingsManager.getShowTerminalProgress()) host.ui.terminal.setProgress(true);\n\t\t\thost.autoCompactionEscapeHandler = host.defaultEditor.onEscape;\n\t\t\thost.defaultEditor.onEscape = () => host.session.abortCompaction();\n\t\t\thost.stopWorkingLoader();\n\t\t\tconst cancelHint = `(${keyText(\"app.interrupt\")} to cancel)`;\n\t\t\tconst label =\n\t\t\t\tevent.reason === \"manual\"\n\t\t\t\t\t? `Compacting context ${cancelHint}`\n\t\t\t\t\t: `${event.reason === \"overflow\" ? \"Context overflow · \" : \"\"}Auto-compacting ${cancelHint}`;\n\t\t\thost.activityLane?.start({ id: \"runtime:compaction\", kind: \"runtime\", label });\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"compaction_end\": {\n\t\t\tif (host.settingsManager.getShowTerminalProgress()) host.ui.terminal.setProgress(false);\n\t\t\tif (host.autoCompactionEscapeHandler) {\n\t\t\t\thost.defaultEditor.onEscape = host.autoCompactionEscapeHandler;\n\t\t\t\thost.autoCompactionEscapeHandler = undefined;\n\t\t\t}\n\t\t\tif (event.aborted) {\n\t\t\t\thost.activityLane?.finish(\"runtime:compaction\", \"neutral\", {\n\t\t\t\t\tid: \"runtime:compaction\",\n\t\t\t\t\tkind: \"runtime\",\n\t\t\t\t\tlabel: \"Compaction cancelled\",\n\t\t\t\t});\n\t\t\t\tif (event.reason === \"manual\") host.showError(\"Compaction cancelled\");\n\t\t\t} else if (event.result) {\n\t\t\t\thost.activityLane?.finish(\"runtime:compaction\", \"success\", {\n\t\t\t\t\tid: \"runtime:compaction\",\n\t\t\t\t\tkind: \"runtime\",\n\t\t\t\t\tlabel: \"Context compacted\",\n\t\t\t\t});\n\t\t\t\tawait host.rebuildChatFromMessages();\n\t\t\t\thost.addMessageToChat(\n\t\t\t\t\tcreateCompactionSummaryMessage(\n\t\t\t\t\t\tevent.result.summary,\n\t\t\t\t\t\tevent.result.tokensBefore,\n\t\t\t\t\t\tnew Date().toISOString(),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\thost.footer.invalidate();\n\t\t\t} else if (event.errorMessage) {\n\t\t\t\thost.activityLane?.finish(\"runtime:compaction\", \"failure\", {\n\t\t\t\t\tid: \"runtime:compaction\",\n\t\t\t\t\tkind: \"runtime\",\n\t\t\t\t\tlabel: \"Compaction failed\",\n\t\t\t\t});\n\t\t\t\tif (event.reason === \"manual\") host.showError(event.errorMessage);\n\t\t\t\telse {\n\t\t\t\t\thost.chatContainer.addChild(new Spacer(1));\n\t\t\t\t\thost.chatContainer.addChild(new Text(theme.fg(\"error\", event.errorMessage), 1, 0));\n\t\t\t\t}\n\t\t\t} else if (event.skipReason) {\n\t\t\t\thost.activityLane?.finish(\"runtime:compaction\", \"neutral\", {\n\t\t\t\t\tid: \"runtime:compaction\",\n\t\t\t\t\tkind: \"runtime\",\n\t\t\t\t\tlabel: `Compaction skipped · ${event.skipReason}`,\n\t\t\t\t});\n\t\t\t}\n\t\t\tvoid host.flushCompactionQueue({ willRetry: event.willRetry });\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"auto_retry_start\": {\n\t\t\thost.retryEscapeHandler = host.defaultEditor.onEscape;\n\t\t\thost.defaultEditor.onEscape = () => host.session.abortRetry();\n\t\t\thost.retryCountdown?.dispose();\n\t\t\tconst retryMessage = (seconds: number) =>\n\t\t\t\t`Retry ${event.attempt}/${event.maxAttempts} in ${seconds}s · ${keyText(\"app.interrupt\")} cancel`;\n\t\t\thost.activityLane?.wait({\n\t\t\t\tid: \"runtime:retry\",\n\t\t\t\tkind: \"runtime\",\n\t\t\t\tlabel: retryMessage(Math.ceil(event.delayMs / 1000)),\n\t\t\t});\n\t\t\thost.retryCountdown = new CountdownTimer(\n\t\t\t\tevent.delayMs,\n\t\t\t\thost.ui,\n\t\t\t\t(seconds) => host.activityLane?.update(\"runtime:retry\", retryMessage(seconds)),\n\t\t\t\t() => {\n\t\t\t\t\thost.retryCountdown = undefined;\n\t\t\t\t},\n\t\t\t);\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"auto_retry_end\":\n\t\t\tif (host.retryEscapeHandler) {\n\t\t\t\thost.defaultEditor.onEscape = host.retryEscapeHandler;\n\t\t\t\thost.retryEscapeHandler = undefined;\n\t\t\t}\n\t\t\tif (host.retryCountdown) {\n\t\t\t\thost.retryCountdown.dispose();\n\t\t\t\thost.retryCountdown = undefined;\n\t\t\t}\n\t\t\thost.activityLane?.finish(\"runtime:retry\", event.success ? \"success\" : \"failure\", {\n\t\t\t\tid: \"runtime:retry\",\n\t\t\t\tkind: \"runtime\",\n\t\t\t\tlabel: event.success ? \"Retry resumed\" : \"Retry failed\",\n\t\t\t});\n\t\t\tif (!event.success) {\n\t\t\t\thost.showError(`Retry failed after ${event.attempt} attempts: ${event.finalError || \"Unknown error\"}`);\n\t\t\t}\n\t\t\thost.ui.requestRender();\n\t\t\tbreak;\n\t}\n}\n"]}