@xopcai/xopc 0.0.124 → 0.0.125

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 (304) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/Combination-BzaXOLd9.js +41 -0
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-B5uSVAyJ.js → agent-avatar-dicebear-BKDKICZV.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-BnTB7-c5.js +2 -0
  6. package/dist/gateway/static/root/assets/app-management-settings-panel-DI4BqHKW.js +1 -0
  7. package/dist/gateway/static/root/assets/appearance-settings-6_ie3NQ4.js +1 -0
  8. package/dist/gateway/static/root/assets/apps-page-B6bG65SW.js +1 -0
  9. package/dist/gateway/static/root/assets/{archive-plugin-CXUGRp2i.js → archive-plugin-kUHEJ1HK.js} +1 -1
  10. package/dist/gateway/static/root/assets/{attachment-load-Cmiub3Wg.js → attachment-load-Dm-9prpU.js} +1 -1
  11. package/dist/gateway/static/root/assets/automation-suggestion-card-OTxQTPnC.js +1 -0
  12. package/dist/gateway/static/root/assets/automations-page-1lVbo0dS.js +1 -0
  13. package/dist/gateway/static/root/assets/{binary-plugins-0Izz-N3p.js → binary-plugins-DllA_jQ0.js} +1 -1
  14. package/dist/gateway/static/root/assets/{block-editor-C1Kv0IkJ.js → block-editor-Cm6CWNj1.js} +6 -6
  15. package/dist/gateway/static/root/assets/browser-settings-page-CzDBlOK0.js +8 -0
  16. package/dist/gateway/static/root/assets/capability-presets-api-VJ89b6I2.js +1 -0
  17. package/dist/gateway/static/root/assets/capability-presets-settings-panel-BaPj8wC2.js +1 -0
  18. package/dist/gateway/static/root/assets/{channel-recipient-api-BeA2aVor.js → channel-recipient-api-B5PwBEUx.js} +1 -1
  19. package/dist/gateway/static/root/assets/channels-settings-Df4m7p1k.js +1 -0
  20. package/dist/gateway/static/root/assets/code-editor-gbRgS14t.js +1 -0
  21. package/dist/gateway/static/root/assets/connectors-page-BMTphmHS.js +2 -0
  22. package/dist/gateway/static/root/assets/{directory-picker-path-field-2rjzUu57.js → directory-picker-path-field-DySMzOF6.js} +1 -1
  23. package/dist/gateway/static/root/assets/dist-By6Rh2ee.js +1 -0
  24. package/dist/gateway/static/root/assets/dist-CkobR7mk.js +1 -0
  25. package/dist/gateway/static/root/assets/dist-DokQNVMQ.js +1 -0
  26. package/dist/gateway/static/root/assets/dreaming-settings-D_AjSnV_.js +3 -0
  27. package/dist/gateway/static/root/assets/extension-debug-page-BaM0FpW7.js +1 -0
  28. package/dist/gateway/static/root/assets/extension-page-DuZWVOGA.js +1 -0
  29. package/dist/gateway/static/root/assets/extension-settings-page-DarVtbmJ.js +1 -0
  30. package/dist/gateway/static/root/assets/{fetch-BU5S0Sn7.js → fetch-NFKfkqrd.js} +1 -1
  31. package/dist/gateway/static/root/assets/{gateway-config-api-BIPGwrl1.js → gateway-config-api-CFEm9rgy.js} +1 -1
  32. package/dist/gateway/static/root/assets/gateway-settings-BMk2S5td.js +1 -0
  33. package/dist/gateway/static/root/assets/{gateway-startup-retry-Cd0Zz30N.js → gateway-startup-retry-Dtwh_yGg.js} +1 -1
  34. package/dist/gateway/static/root/assets/goal-create-dialog-BKP7ylcG.js +1 -0
  35. package/dist/gateway/static/root/assets/goal-detail-page-C2cTxf71.js +1 -0
  36. package/dist/gateway/static/root/assets/{goals-config-api-B95KdGMj.js → goals-config-api-DTWZNA_Y.js} +1 -1
  37. package/dist/gateway/static/root/assets/goals-page-CTmA3hWK.js +2 -0
  38. package/dist/gateway/static/root/assets/goals-settings-Bhct0ZT-.js +1 -0
  39. package/dist/gateway/static/root/assets/heartbeat-settings-C-UxSU4a.js +1 -0
  40. package/dist/gateway/static/root/assets/{html-workspace-editor-CQLWDiwE.js → html-workspace-editor-DV90ddkE.js} +1 -1
  41. package/dist/gateway/static/root/assets/index-BNHDd2j1.css +1 -0
  42. package/dist/gateway/static/root/assets/index-BPXLPMuY.js +193 -0
  43. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-DCjy2y4d.js +1 -0
  44. package/dist/gateway/static/root/assets/logs-page-CGc3_CQU.js +2 -0
  45. package/dist/gateway/static/root/assets/{markdown-editor-AssmZFx4.js → markdown-editor-BFOjBBla.js} +2 -2
  46. package/dist/gateway/static/root/assets/markdown-split-BaqxP-GQ.js +1 -0
  47. package/dist/gateway/static/root/assets/{media-plugins-BhIQU5yS.js → media-plugins-DQ_EXloK.js} +1 -1
  48. package/dist/gateway/static/root/assets/messages-CjuIJcZl.js +3 -0
  49. package/dist/gateway/static/root/assets/models-hub-panel-Drz4UQMb.js +2 -0
  50. package/dist/gateway/static/root/assets/notes-page-CY1ylng1.js +1 -0
  51. package/dist/gateway/static/root/assets/notes-workbench-X7IaD--t.js +2 -0
  52. package/dist/gateway/static/root/assets/page-tabs-EIZhLppK.js +1 -0
  53. package/dist/gateway/static/root/assets/{preview-open-alternatives-DGzet1d7.js → preview-open-alternatives-r_uB4Epr.js} +1 -1
  54. package/dist/gateway/static/root/assets/project-detail-page-DE5adRBE.js +1 -0
  55. package/dist/gateway/static/root/assets/projects-page-CuOb1k6F.js +1 -0
  56. package/dist/gateway/static/root/assets/remote-access-hub-BOxNrUVA.js +1 -0
  57. package/dist/gateway/static/root/assets/{save-bar-controls-Cqgb-jqa.js → save-bar-controls-B132Uf-2.js} +1 -1
  58. package/dist/gateway/static/root/assets/{schedule-field-DVZcI8Yt.js → schedule-field-B5qshALm.js} +1 -1
  59. package/dist/gateway/static/root/assets/{schema-form-Bj7sOxC8.js → schema-form-CvLmkdS9.js} +1 -1
  60. package/dist/gateway/static/root/assets/sessions-page-CY0IQcGW.js +1 -0
  61. package/dist/gateway/static/root/assets/settings-advanced-gate-D4NBNVCB.js +1 -0
  62. package/dist/gateway/static/root/assets/{settings-collapsible-section-BmXn-8N6.js → settings-collapsible-section-pRlvqsAf.js} +1 -1
  63. package/dist/gateway/static/root/assets/{settings-form-section-BnqYMWHR.js → settings-form-section-BBYUDLVd.js} +1 -1
  64. package/dist/gateway/static/root/assets/settings-page-DaO7zYZM.js +1 -0
  65. package/dist/gateway/static/root/assets/{settings-page-layout-CdWZU1hd.js → settings-page-layout-D8g9PAek.js} +1 -1
  66. package/dist/gateway/static/root/assets/setup-status-panel-Bks0CLLT.js +1 -0
  67. package/dist/gateway/static/root/assets/{share-preview-page-IB1v8i86.js → share-preview-page-v6-IOp8t.js} +1 -1
  68. package/dist/gateway/static/root/assets/shares-settings-CEZsKm9r.js +1 -0
  69. package/dist/gateway/static/root/assets/skill-reload-api-oTkHbb9W.js +1 -0
  70. package/dist/gateway/static/root/assets/skills-page-DigsbZ6K.js +2 -0
  71. package/dist/gateway/static/root/assets/{system-settings-panel-BxQ384RC.js → system-settings-panel-HUU2FFjM.js} +1 -1
  72. package/dist/gateway/static/root/assets/{typed-models-lib-BkcpvFYO.js → typed-models-lib-AH160QHh.js} +1 -1
  73. package/dist/gateway/static/root/assets/{use-channel-catalog-Cd0FaEQ4.js → use-channel-catalog-BXzDmjCQ.js} +1 -1
  74. package/dist/gateway/static/root/assets/{user-profile-settings-panel-DQ7NnRSY.js → user-profile-settings-panel-DxwnQvQ3.js} +1 -1
  75. package/dist/gateway/static/root/assets/{utils-YKhVf7Ka.js → utils-i5POEtqd.js} +1 -1
  76. package/dist/gateway/static/root/assets/{vendor-codemirror-CNP1wPe7.js → vendor-codemirror-BvNgyE1Q.js} +1 -1
  77. package/dist/gateway/static/root/assets/voice-api-key-field-CEJklEgb.js +1 -0
  78. package/dist/gateway/static/root/assets/work-item-detail-page-CD6FL_Rs.js +1 -0
  79. package/dist/gateway/static/root/assets/workflow-run-setup-panel-ClVVMgN-.js +3 -0
  80. package/dist/gateway/static/root/assets/{workflow-start-dialog-BNJVCWoS.js → workflow-start-dialog-Dv4ZA1T0.js} +1 -1
  81. package/dist/gateway/static/root/assets/workflows-page-OLQiUpoW.js +18 -0
  82. package/dist/gateway/static/root/index.html +8 -7
  83. package/dist/package.js +1 -1
  84. package/dist/src/agent/agent-manager.js +6 -2
  85. package/dist/src/agent/agent-manager.js.map +1 -1
  86. package/dist/src/agent/child-agent-factory.d.ts +2 -0
  87. package/dist/src/agent/child-agent-factory.js +2 -0
  88. package/dist/src/agent/child-agent-factory.js.map +1 -1
  89. package/dist/src/agent/coding/index.d.ts +1 -0
  90. package/dist/src/agent/coding/index.js +2 -0
  91. package/dist/src/agent/coding/turn-diff-tracker.d.ts +67 -0
  92. package/dist/src/agent/coding/turn-diff-tracker.js +233 -0
  93. package/dist/src/agent/coding/turn-diff-tracker.js.map +1 -0
  94. package/dist/src/agent/memory/dreaming/config.d.ts +2 -2
  95. package/dist/src/agent/memory/dreaming/config.js +3 -3
  96. package/dist/src/agent/memory/dreaming/config.js.map +1 -1
  97. package/dist/src/agent/memory/dreaming/constants.d.ts +1 -1
  98. package/dist/src/agent/memory/dreaming/constants.js +1 -1
  99. package/dist/src/agent/memory/dreaming/constants.js.map +1 -1
  100. package/dist/src/agent/memory/dreaming/deep-promotion.d.ts +1 -0
  101. package/dist/src/agent/memory/dreaming/deep-promotion.js +11 -20
  102. package/dist/src/agent/memory/dreaming/deep-promotion.js.map +1 -1
  103. package/dist/src/agent/memory/dreaming/events.d.ts +3 -3
  104. package/dist/src/agent/memory/dreaming/events.js +6 -6
  105. package/dist/src/agent/memory/dreaming/events.js.map +1 -1
  106. package/dist/src/agent/memory/dreaming/last-run.d.ts +2 -2
  107. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  108. package/dist/src/agent/memory/dreaming/last-run.js.map +1 -1
  109. package/dist/src/agent/memory/dreaming/light-sweep.d.ts +1 -1
  110. package/dist/src/agent/memory/dreaming/light-sweep.js +3 -3
  111. package/dist/src/agent/memory/dreaming/light-sweep.js.map +1 -1
  112. package/dist/src/agent/memory/dreaming/preview.d.ts +1 -0
  113. package/dist/src/agent/memory/dreaming/preview.js +2 -2
  114. package/dist/src/agent/memory/dreaming/preview.js.map +1 -1
  115. package/dist/src/agent/memory/dreaming/rem-patterns.d.ts +1 -1
  116. package/dist/src/agent/memory/dreaming/rem-patterns.js +13 -13
  117. package/dist/src/agent/memory/dreaming/rem-patterns.js.map +1 -1
  118. package/dist/src/agent/memory/dreaming/scope.d.ts +14 -0
  119. package/dist/src/agent/memory/dreaming/scope.js +27 -0
  120. package/dist/src/agent/memory/dreaming/scope.js.map +1 -0
  121. package/dist/src/agent/memory/dreaming/short-term-store.d.ts +4 -4
  122. package/dist/src/agent/memory/dreaming/short-term-store.js +17 -17
  123. package/dist/src/agent/memory/dreaming/short-term-store.js.map +1 -1
  124. package/dist/src/agent/orchestration/agent-event-handler.d.ts +2 -0
  125. package/dist/src/agent/orchestration/agent-event-handler.js +13 -0
  126. package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
  127. package/dist/src/agent/orchestration/agent-orchestrator.js +22 -12
  128. package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
  129. package/dist/src/agent/sandbox/command-validator.js +12 -0
  130. package/dist/src/agent/sandbox/command-validator.js.map +1 -1
  131. package/dist/src/agent/service.d.ts +2 -1
  132. package/dist/src/agent/service.js +18 -6
  133. package/dist/src/agent/service.js.map +1 -1
  134. package/dist/src/agent/session/session-inspector.d.ts +5 -3
  135. package/dist/src/agent/session/session-inspector.js +16 -7
  136. package/dist/src/agent/session/session-inspector.js.map +1 -1
  137. package/dist/src/agent/source-context/types.d.ts +1 -1
  138. package/dist/src/agent/source-context/types.js +1 -1
  139. package/dist/src/agent/source-context/types.js.map +1 -1
  140. package/dist/src/agent/tools/apply-patch.js +116 -62
  141. package/dist/src/agent/tools/apply-patch.js.map +1 -1
  142. package/dist/src/agent/tools/concurrency.d.ts +8 -0
  143. package/dist/src/agent/tools/concurrency.js +31 -0
  144. package/dist/src/agent/tools/concurrency.js.map +1 -0
  145. package/dist/src/agent/tools/dreaming-tool.d.ts +2 -0
  146. package/dist/src/agent/tools/dreaming-tool.js +13 -10
  147. package/dist/src/agent/tools/dreaming-tool.js.map +1 -1
  148. package/dist/src/agent/tools/exec-command.js +4 -0
  149. package/dist/src/agent/tools/exec-command.js.map +1 -1
  150. package/dist/src/agent/tools/executor.d.ts +6 -4
  151. package/dist/src/agent/tools/executor.js +7 -4
  152. package/dist/src/agent/tools/executor.js.map +1 -1
  153. package/dist/src/agent/tools/factory.d.ts +3 -0
  154. package/dist/src/agent/tools/factory.js +7 -1
  155. package/dist/src/agent/tools/factory.js.map +1 -1
  156. package/dist/src/agent/tools/find.js +2 -0
  157. package/dist/src/agent/tools/find.js.map +1 -1
  158. package/dist/src/agent/tools/grep.js +2 -0
  159. package/dist/src/agent/tools/grep.js.map +1 -1
  160. package/dist/src/agent/tools/index.d.ts +2 -0
  161. package/dist/src/agent/tools/index.js +3 -1
  162. package/dist/src/agent/tools/list-dir.js +2 -0
  163. package/dist/src/agent/tools/list-dir.js.map +1 -1
  164. package/dist/src/agent/tools/memory-tool.d.ts +1 -0
  165. package/dist/src/agent/tools/memory-tool.js +2 -2
  166. package/dist/src/agent/tools/memory-tool.js.map +1 -1
  167. package/dist/src/agent/tools/metadata.d.ts +15 -0
  168. package/dist/src/agent/tools/metadata.js +26 -0
  169. package/dist/src/agent/tools/metadata.js.map +1 -0
  170. package/dist/src/agent/tools/read.js +2 -0
  171. package/dist/src/agent/tools/read.js.map +1 -1
  172. package/dist/src/agent/tools/write.js +6 -0
  173. package/dist/src/agent/tools/write.js.map +1 -1
  174. package/dist/src/agent/workflow/subagent-runner.d.ts +1 -0
  175. package/dist/src/agent/workflow/subagent-runner.js +5 -1
  176. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  177. package/dist/src/agent/workflow/workflow-child-tools.js +5 -0
  178. package/dist/src/agent/workflow/workflow-child-tools.js.map +1 -1
  179. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  180. package/dist/src/connectors/health.d.ts +2 -1
  181. package/dist/src/connectors/health.js +59 -1
  182. package/dist/src/connectors/health.js.map +1 -1
  183. package/dist/src/connectors/install.d.ts +1 -0
  184. package/dist/src/connectors/install.js +28 -1
  185. package/dist/src/connectors/install.js.map +1 -1
  186. package/dist/src/connectors/instances.js +7 -0
  187. package/dist/src/connectors/instances.js.map +1 -1
  188. package/dist/src/connectors/materialize.js +2 -1
  189. package/dist/src/connectors/materialize.js.map +1 -1
  190. package/dist/src/connectors/registries/modelscope.js +38 -13
  191. package/dist/src/connectors/registries/modelscope.js.map +1 -1
  192. package/dist/src/connectors/types.d.ts +2 -0
  193. package/dist/src/gateway/dreaming-automation-reconciler.d.ts +1 -0
  194. package/dist/src/gateway/dreaming-automation-reconciler.js +62 -42
  195. package/dist/src/gateway/dreaming-automation-reconciler.js.map +1 -1
  196. package/dist/src/gateway/hono/app.js +7 -1
  197. package/dist/src/gateway/hono/app.js.map +1 -1
  198. package/dist/src/gateway/hono/routes/connectors.js +46 -2
  199. package/dist/src/gateway/hono/routes/connectors.js.map +1 -1
  200. package/dist/src/gateway/hono/routes/dreaming.js +111 -66
  201. package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
  202. package/dist/src/gateway/hono/routes/projects.js +846 -43
  203. package/dist/src/gateway/hono/routes/projects.js.map +1 -1
  204. package/dist/src/gateway/hono/routes/sessions.js +1 -0
  205. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  206. package/dist/src/gateway/service.js +17 -8
  207. package/dist/src/gateway/service.js.map +1 -1
  208. package/dist/src/media/store.js +1 -1
  209. package/dist/src/media/store.js.map +1 -1
  210. package/dist/src/media/types.d.ts +1 -1
  211. package/dist/src/media/uri.js +2 -1
  212. package/dist/src/media/uri.js.map +1 -1
  213. package/dist/src/session/session-context-for-llm.d.ts +2 -0
  214. package/dist/src/session/session-context-for-llm.js +14 -1
  215. package/dist/src/session/session-context-for-llm.js.map +1 -1
  216. package/dist/src/session/store.js +2 -2
  217. package/dist/src/session/store.js.map +1 -1
  218. package/dist/src/storage/sqlite/migrations/022_work_items.sql +61 -0
  219. package/dist/src/storage/sqlite/migrations/023_work_item_attachments.sql +15 -0
  220. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  221. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  222. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  223. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  224. package/dist/src/storage/sqlite/schema.js +1 -1
  225. package/dist/src/storage/sqlite/schema.sql +78 -0
  226. package/dist/src/tui/components/assistant-message.js +12 -2
  227. package/dist/src/tui/components/assistant-message.js.map +1 -1
  228. package/dist/src/tui/components/tool-execution.d.ts +8 -0
  229. package/dist/src/tui/components/tool-execution.js +87 -77
  230. package/dist/src/tui/components/tool-execution.js.map +1 -1
  231. package/dist/src/tui/components/visual-truncate.d.ts +1 -0
  232. package/dist/src/tui/components/visual-truncate.js +28 -1
  233. package/dist/src/tui/components/visual-truncate.js.map +1 -1
  234. package/dist/src/tui/tool-summary.d.ts +22 -0
  235. package/dist/src/tui/tool-summary.js +212 -0
  236. package/dist/src/tui/tool-summary.js.map +1 -0
  237. package/dist/src/tui/tui-tool-diff.d.ts +15 -0
  238. package/dist/src/tui/tui-tool-diff.js +178 -7
  239. package/dist/src/tui/tui-tool-diff.js.map +1 -1
  240. package/dist/src/work-items/agent-context.d.ts +3 -0
  241. package/dist/src/work-items/agent-context.js +39 -0
  242. package/dist/src/work-items/agent-context.js.map +1 -0
  243. package/dist/src/work-items/index.d.ts +4 -0
  244. package/dist/src/work-items/index.js +4 -0
  245. package/dist/src/work-items/types.d.ts +112 -0
  246. package/dist/src/work-items/types.js +1 -0
  247. package/dist/src/work-items/work-item-service.d.ts +33 -0
  248. package/dist/src/work-items/work-item-service.js +180 -0
  249. package/dist/src/work-items/work-item-service.js.map +1 -0
  250. package/dist/src/work-items/work-item-store.d.ts +21 -0
  251. package/dist/src/work-items/work-item-store.js +302 -0
  252. package/dist/src/work-items/work-item-store.js.map +1 -0
  253. package/dist/src/workflows/service/workflow-run-service.js +4 -3
  254. package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
  255. package/dist/src/workflows/service/workflow-session-bridge.js +3 -0
  256. package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
  257. package/package.json +1 -1
  258. package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +0 -41
  259. package/dist/gateway/static/root/assets/agents-BjIxt67Z.js +0 -2
  260. package/dist/gateway/static/root/assets/app-management-settings-panel-CYCONLIL.js +0 -1
  261. package/dist/gateway/static/root/assets/appearance-settings-Clw3ryKg.js +0 -1
  262. package/dist/gateway/static/root/assets/apps-page-QICTeGjX.js +0 -1
  263. package/dist/gateway/static/root/assets/automation-suggestion-card-CU0-4nQ-.js +0 -1
  264. package/dist/gateway/static/root/assets/automations-page-Car-jtiz.js +0 -1
  265. package/dist/gateway/static/root/assets/browser-settings-page-CMeBJzlS.js +0 -8
  266. package/dist/gateway/static/root/assets/capability-presets-api-BmQTM9Il.js +0 -1
  267. package/dist/gateway/static/root/assets/capability-presets-settings-panel-DZEJEoCF.js +0 -1
  268. package/dist/gateway/static/root/assets/channels-settings-kkW-xFau.js +0 -1
  269. package/dist/gateway/static/root/assets/code-editor-dZTY2dRW.js +0 -1
  270. package/dist/gateway/static/root/assets/connectors-page-BvaQvO5F.js +0 -2
  271. package/dist/gateway/static/root/assets/dist-Mys7eFJ5.js +0 -1
  272. package/dist/gateway/static/root/assets/dist-wO9a2_ID.js +0 -1
  273. package/dist/gateway/static/root/assets/dreaming-settings-DnHO686d.js +0 -1
  274. package/dist/gateway/static/root/assets/extension-debug-page-BGLRuWVN.js +0 -1
  275. package/dist/gateway/static/root/assets/extension-page-D978ePp9.js +0 -1
  276. package/dist/gateway/static/root/assets/extension-settings-page-B6Ih4Swx.js +0 -1
  277. package/dist/gateway/static/root/assets/gateway-settings-CMEA3r5u.js +0 -1
  278. package/dist/gateway/static/root/assets/goal-create-dialog-B-KHKeXN.js +0 -1
  279. package/dist/gateway/static/root/assets/goal-detail-page-BxrSoWdj.js +0 -1
  280. package/dist/gateway/static/root/assets/goals-page-BTJzIl28.js +0 -2
  281. package/dist/gateway/static/root/assets/goals-settings-BJyEuLLm.js +0 -1
  282. package/dist/gateway/static/root/assets/heartbeat-settings-wkOjYNQT.js +0 -1
  283. package/dist/gateway/static/root/assets/index-BLaXr6Ev.css +0 -1
  284. package/dist/gateway/static/root/assets/index-c_9TVr_C.js +0 -191
  285. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-BT8T4DyC.js +0 -1
  286. package/dist/gateway/static/root/assets/logs-page-CrxBJUgI.js +0 -2
  287. package/dist/gateway/static/root/assets/markdown-split-Dv66bO2b.js +0 -1
  288. package/dist/gateway/static/root/assets/messages-O6TAtdFC.js +0 -3
  289. package/dist/gateway/static/root/assets/models-hub-panel-DOOpz6y1.js +0 -2
  290. package/dist/gateway/static/root/assets/notes-page-Br16pK9v.js +0 -1
  291. package/dist/gateway/static/root/assets/notes-workbench-PSJAi0ZC.js +0 -2
  292. package/dist/gateway/static/root/assets/project-detail-page-CIGGgKuw.js +0 -1
  293. package/dist/gateway/static/root/assets/projects-page-B2grhsBt.js +0 -1
  294. package/dist/gateway/static/root/assets/remote-access-hub-CXMORxBD.js +0 -1
  295. package/dist/gateway/static/root/assets/sessions-page-Bi2wkBzU.js +0 -1
  296. package/dist/gateway/static/root/assets/settings-advanced-gate-B1L3G4IA.js +0 -1
  297. package/dist/gateway/static/root/assets/settings-page-BfRSHJmO.js +0 -1
  298. package/dist/gateway/static/root/assets/setup-status-panel-CWtPM7RK.js +0 -1
  299. package/dist/gateway/static/root/assets/shares-settings-ngbsBgij.js +0 -1
  300. package/dist/gateway/static/root/assets/skill-reload-api-BIe442Gv.js +0 -1
  301. package/dist/gateway/static/root/assets/skills-page-BfchZRVa.js +0 -2
  302. package/dist/gateway/static/root/assets/voice-api-key-field-C5Ov8Uk_.js +0 -1
  303. package/dist/gateway/static/root/assets/workflow-run-setup-panel-BYD9BtOq.js +0 -3
  304. package/dist/gateway/static/root/assets/workflows-page-BYF29ANm.js +0 -18
@@ -9,3 +9,4 @@ export interface VisualTruncateResult {
9
9
  * across many terminal rows.
10
10
  */
11
11
  export declare function truncateToVisualLines(text: string, maxVisualLines: number, width: number, paddingX?: number): VisualTruncateResult;
12
+ export declare function truncateToVisualLinesMiddle(text: string, maxVisualLines: number, width: number, paddingX?: number): VisualTruncateResult;
@@ -21,7 +21,34 @@ function truncateToVisualLines(text, maxVisualLines, width, paddingX = 0) {
21
21
  skippedCount: rendered.length - maxVisualLines
22
22
  };
23
23
  }
24
+ function truncateToVisualLinesMiddle(text, maxVisualLines, width, paddingX = 0) {
25
+ if (!text || maxVisualLines <= 0) return {
26
+ visualLines: [],
27
+ skippedCount: 0
28
+ };
29
+ const rendered = new Text(text, paddingX, 0).render(width);
30
+ if (rendered.length <= maxVisualLines) return {
31
+ visualLines: rendered,
32
+ skippedCount: 0
33
+ };
34
+ if (maxVisualLines === 1) return {
35
+ visualLines: ["..."],
36
+ skippedCount: rendered.length - 1
37
+ };
38
+ const visibleWithoutMarker = maxVisualLines - 1;
39
+ const headCount = Math.ceil(visibleWithoutMarker / 2);
40
+ const tailCount = Math.floor(visibleWithoutMarker / 2);
41
+ const skippedCount = rendered.length - headCount - tailCount;
42
+ return {
43
+ visualLines: [
44
+ ...rendered.slice(0, headCount),
45
+ `... ${skippedCount} rows hidden ...`,
46
+ ...rendered.slice(rendered.length - tailCount)
47
+ ],
48
+ skippedCount
49
+ };
50
+ }
24
51
  //#endregion
25
- export { truncateToVisualLines };
52
+ export { truncateToVisualLines, truncateToVisualLinesMiddle };
26
53
 
27
54
  //# sourceMappingURL=visual-truncate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"visual-truncate.js","names":[],"sources":["../../../../src/tui/components/visual-truncate.ts"],"sourcesContent":["import { Text } from '@earendil-works/pi-tui';\n\nexport interface VisualTruncateResult {\n visualLines: string[];\n skippedCount: number;\n}\n\n/**\n * Truncate text by rendered terminal rows, not source lines.\n *\n * This keeps collapsed previews bounded when one very long logical line wraps\n * across many terminal rows.\n */\nexport function truncateToVisualLines(\n text: string,\n maxVisualLines: number,\n width: number,\n paddingX = 0,\n): VisualTruncateResult {\n if (!text || maxVisualLines <= 0) {\n return { visualLines: [], skippedCount: 0 };\n }\n\n const rendered = new Text(text, paddingX, 0).render(width);\n if (rendered.length <= maxVisualLines) {\n return { visualLines: rendered, skippedCount: 0 };\n }\n\n return {\n visualLines: rendered.slice(-maxVisualLines),\n skippedCount: rendered.length - maxVisualLines,\n };\n}\n"],"mappings":";;;;;;;;AAaA,SAAgB,sBACd,MACA,gBACA,OACA,WAAW,GACW;AACtB,KAAI,CAAC,QAAQ,kBAAkB,EAC7B,QAAO;EAAE,aAAa,EAAE;EAAE,cAAc;EAAG;CAG7C,MAAM,WAAW,IAAI,KAAK,MAAM,UAAU,EAAE,CAAC,OAAO,MAAM;AAC1D,KAAI,SAAS,UAAU,eACrB,QAAO;EAAE,aAAa;EAAU,cAAc;EAAG;AAGnD,QAAO;EACL,aAAa,SAAS,MAAM,CAAC,eAAe;EAC5C,cAAc,SAAS,SAAS;EACjC"}
1
+ {"version":3,"file":"visual-truncate.js","names":[],"sources":["../../../../src/tui/components/visual-truncate.ts"],"sourcesContent":["import { Text } from '@earendil-works/pi-tui';\n\nexport interface VisualTruncateResult {\n visualLines: string[];\n skippedCount: number;\n}\n\n/**\n * Truncate text by rendered terminal rows, not source lines.\n *\n * This keeps collapsed previews bounded when one very long logical line wraps\n * across many terminal rows.\n */\nexport function truncateToVisualLines(\n text: string,\n maxVisualLines: number,\n width: number,\n paddingX = 0,\n): VisualTruncateResult {\n if (!text || maxVisualLines <= 0) {\n return { visualLines: [], skippedCount: 0 };\n }\n\n const rendered = new Text(text, paddingX, 0).render(width);\n if (rendered.length <= maxVisualLines) {\n return { visualLines: rendered, skippedCount: 0 };\n }\n\n return {\n visualLines: rendered.slice(-maxVisualLines),\n skippedCount: rendered.length - maxVisualLines,\n };\n}\n\nexport function truncateToVisualLinesMiddle(\n text: string,\n maxVisualLines: number,\n width: number,\n paddingX = 0,\n): VisualTruncateResult {\n if (!text || maxVisualLines <= 0) {\n return { visualLines: [], skippedCount: 0 };\n }\n\n const rendered = new Text(text, paddingX, 0).render(width);\n if (rendered.length <= maxVisualLines) {\n return { visualLines: rendered, skippedCount: 0 };\n }\n\n if (maxVisualLines === 1) {\n return {\n visualLines: ['...'],\n skippedCount: rendered.length - 1,\n };\n }\n\n const visibleWithoutMarker = maxVisualLines - 1;\n const headCount = Math.ceil(visibleWithoutMarker / 2);\n const tailCount = Math.floor(visibleWithoutMarker / 2);\n const skippedCount = rendered.length - headCount - tailCount;\n return {\n visualLines: [\n ...rendered.slice(0, headCount),\n `... ${skippedCount} rows hidden ...`,\n ...rendered.slice(rendered.length - tailCount),\n ],\n skippedCount,\n };\n}\n"],"mappings":";;;;;;;;AAaA,SAAgB,sBACd,MACA,gBACA,OACA,WAAW,GACW;AACtB,KAAI,CAAC,QAAQ,kBAAkB,EAC7B,QAAO;EAAE,aAAa,EAAE;EAAE,cAAc;EAAG;CAG7C,MAAM,WAAW,IAAI,KAAK,MAAM,UAAU,EAAE,CAAC,OAAO,MAAM;AAC1D,KAAI,SAAS,UAAU,eACrB,QAAO;EAAE,aAAa;EAAU,cAAc;EAAG;AAGnD,QAAO;EACL,aAAa,SAAS,MAAM,CAAC,eAAe;EAC5C,cAAc,SAAS,SAAS;EACjC;;AAGH,SAAgB,4BACd,MACA,gBACA,OACA,WAAW,GACW;AACtB,KAAI,CAAC,QAAQ,kBAAkB,EAC7B,QAAO;EAAE,aAAa,EAAE;EAAE,cAAc;EAAG;CAG7C,MAAM,WAAW,IAAI,KAAK,MAAM,UAAU,EAAE,CAAC,OAAO,MAAM;AAC1D,KAAI,SAAS,UAAU,eACrB,QAAO;EAAE,aAAa;EAAU,cAAc;EAAG;AAGnD,KAAI,mBAAmB,EACrB,QAAO;EACL,aAAa,CAAC,MAAM;EACpB,cAAc,SAAS,SAAS;EACjC;CAGH,MAAM,uBAAuB,iBAAiB;CAC9C,MAAM,YAAY,KAAK,KAAK,uBAAuB,EAAE;CACrD,MAAM,YAAY,KAAK,MAAM,uBAAuB,EAAE;CACtD,MAAM,eAAe,SAAS,SAAS,YAAY;AACnD,QAAO;EACL,aAAa;GACX,GAAG,SAAS,MAAM,GAAG,UAAU;GAC/B,OAAO,aAAa;GACpB,GAAG,SAAS,MAAM,SAAS,SAAS,UAAU;GAC/C;EACD;EACD"}
@@ -0,0 +1,22 @@
1
+ import type { TuiToolContentBlock } from './tui-tool-result.js';
2
+ export type ToolSummaryKind = 'read' | 'search' | 'exec' | 'mcp' | 'generic';
3
+ export interface ToolSummaryContext {
4
+ toolName: string;
5
+ args: unknown;
6
+ output: string;
7
+ content?: TuiToolContentBlock[];
8
+ details: unknown;
9
+ isError: boolean;
10
+ expandKey: string;
11
+ }
12
+ export declare function formatArgsSummary(args: unknown, toolName: string): string;
13
+ export declare function getToolSummaryKind(toolName: string): ToolSummaryKind;
14
+ export declare function isReadStyleTool(toolName: string): boolean;
15
+ export declare function isSearchStyleTool(toolName: string): boolean;
16
+ export declare function isExecStyleTool(toolName: string): boolean;
17
+ export declare function isMcpStyleTool(toolName: string): boolean;
18
+ export declare function displayToolName(toolName: string): string;
19
+ export declare function compactPath(path: string, maxLength?: number): string;
20
+ export declare function formatCollapsedToolSummary(ctx: ToolSummaryContext): string;
21
+ export declare function formatExecExpandedOutput(output: string, details: unknown): string;
22
+ export declare function extractExitCode(details: unknown): number | undefined;
@@ -0,0 +1,212 @@
1
+ import { basename, dirname } from "node:path";
2
+ import { Text } from "@earendil-works/pi-tui";
3
+ //#region src/tui/tool-summary.ts
4
+ const MAX_ARG_VALUE_LENGTH = 120;
5
+ const MAX_PATH_LABEL_LENGTH = 72;
6
+ function formatArgsSummary(args, toolName) {
7
+ if (!args || typeof args !== "object") return "";
8
+ const compactRead = isReadStyleTool(toolName) ? formatCompactReadArgs(args) : null;
9
+ if (compactRead) return compactRead;
10
+ const command = isExecStyleTool(toolName) ? commandFromArgs(args) : null;
11
+ if (command) return command;
12
+ const entries = Object.entries(args);
13
+ if (entries.length === 0) return "";
14
+ return entries.map(([key, value]) => {
15
+ const stringValue = formatArgValue(value);
16
+ return `${key}=${stringValue.length > MAX_ARG_VALUE_LENGTH ? `${stringValue.slice(0, MAX_ARG_VALUE_LENGTH - 3)}...` : stringValue}`;
17
+ }).join(", ");
18
+ }
19
+ function getToolSummaryKind(toolName) {
20
+ if (isReadStyleTool(toolName)) return "read";
21
+ if (isSearchStyleTool(toolName)) return "search";
22
+ if (isExecStyleTool(toolName)) return "exec";
23
+ if (isMcpStyleTool(toolName)) return "mcp";
24
+ return "generic";
25
+ }
26
+ function isReadStyleTool(toolName) {
27
+ const base = baseToolName(toolName);
28
+ return [
29
+ "read",
30
+ "read_file",
31
+ "memory_get"
32
+ ].includes(base);
33
+ }
34
+ function isSearchStyleTool(toolName) {
35
+ const base = baseToolName(toolName);
36
+ return [
37
+ "search",
38
+ "grep",
39
+ "rg",
40
+ "ripgrep",
41
+ "search_code",
42
+ "file_search",
43
+ "list_files"
44
+ ].includes(base);
45
+ }
46
+ function isExecStyleTool(toolName) {
47
+ const base = baseToolName(toolName);
48
+ return [
49
+ "bash",
50
+ "shell",
51
+ "exec",
52
+ "run_command",
53
+ "exec_command",
54
+ "terminal"
55
+ ].includes(base);
56
+ }
57
+ function isMcpStyleTool(toolName) {
58
+ return toolName.includes("__");
59
+ }
60
+ function displayToolName(toolName) {
61
+ const parts = toolName.split("__");
62
+ if (parts.length === 2 && parts[0] && parts[1]) return `${parts[0]}.${parts[1]}`;
63
+ return toolName;
64
+ }
65
+ function compactPath(path, maxLength = MAX_PATH_LABEL_LENGTH) {
66
+ const normalized = path.replace(/\\/g, "/");
67
+ if (normalized.length <= maxLength) return normalized;
68
+ const base = basename(normalized);
69
+ const parent = basename(dirname(normalized));
70
+ const suffix = parent ? `${parent}/${base}` : base;
71
+ if (suffix.length + 2 <= maxLength) return `.../${suffix}`;
72
+ return `.../${base.slice(Math.max(0, base.length - maxLength + 3))}`;
73
+ }
74
+ function formatCollapsedToolSummary(ctx) {
75
+ if (ctx.isError) {
76
+ const rows = nonBlankLines(ctx.output).length;
77
+ return `error; ${rows === 1 ? "1 error line" : `${rows} error lines`}; ${ctx.expandKey} to expand`;
78
+ }
79
+ switch (getToolSummaryKind(ctx.toolName)) {
80
+ case "read": {
81
+ const rows = new Text(ctx.output, 1, 0).render(80).length;
82
+ return ` ${rows} ${rows === 1 ? "row" : "rows"}; ${ctx.expandKey} to expand`;
83
+ }
84
+ case "search": return formatSearchSummary(ctx.output, ctx.expandKey);
85
+ case "exec": return formatExecSummary(ctx.output, ctx.details, ctx.isError, ctx.expandKey);
86
+ case "mcp": return formatMcpSummary(ctx.output, ctx.content, ctx.expandKey);
87
+ case "generic": return "";
88
+ }
89
+ }
90
+ function formatExecExpandedOutput(output, details) {
91
+ const parsed = parseExecDetails(details);
92
+ const sections = [];
93
+ const stdout = parsed.stdout ?? output;
94
+ if (stdout.trim()) sections.push(`stdout\n${stdout}`);
95
+ if (parsed.stderr?.trim()) sections.push(`stderr\n${parsed.stderr}`);
96
+ if (parsed.exitCode !== void 0) sections.push(`exit ${parsed.exitCode}`);
97
+ return sections.join("\n");
98
+ }
99
+ function extractExitCode(details) {
100
+ return parseExecDetails(details).exitCode;
101
+ }
102
+ function formatCompactReadArgs(args) {
103
+ if (!args || typeof args !== "object") return null;
104
+ const record = args;
105
+ const rawPath = typeof record.path === "string" ? record.path : typeof record.file_path === "string" ? record.file_path : void 0;
106
+ if (!rawPath) return null;
107
+ const normalized = rawPath.replace(/\\/g, "/");
108
+ const base = basename(normalized);
109
+ let label;
110
+ if (base === "SKILL.md") {
111
+ const parent = basename(dirname(normalized));
112
+ label = parent ? `[skill] ${parent}` : "[skill]";
113
+ } else if (base === "AGENTS.md") label = `read resource ${compactPath(normalized)}`;
114
+ else label = compactPath(normalized);
115
+ const start = firstFiniteNumber(record.offset, record.from, record.start, record.line);
116
+ const count = firstFiniteNumber(record.limit, record.lines, record.count);
117
+ if (start != null && count != null && count > 0) label += `:${start}-${start + count - 1}`;
118
+ return label;
119
+ }
120
+ function commandFromArgs(args) {
121
+ if (!args || typeof args !== "object") return null;
122
+ const record = args;
123
+ const raw = record.command ?? record.cmd ?? record.script;
124
+ if (Array.isArray(raw)) return raw.map(String).join(" ");
125
+ if (typeof raw === "string" && raw.trim()) return raw.trim();
126
+ return null;
127
+ }
128
+ function baseToolName(toolName) {
129
+ return toolName.split("__").pop()?.toLowerCase() ?? toolName.toLowerCase();
130
+ }
131
+ function firstFiniteNumber(...values) {
132
+ for (const value of values) {
133
+ if (typeof value === "number" && Number.isFinite(value)) return Math.floor(value);
134
+ if (typeof value === "string" && value.trim()) {
135
+ const parsed = Number(value);
136
+ if (Number.isFinite(parsed)) return Math.floor(parsed);
137
+ }
138
+ }
139
+ return null;
140
+ }
141
+ function formatArgValue(value) {
142
+ if (typeof value === "string") return value;
143
+ if (typeof value === "bigint") return `${value.toString()}n`;
144
+ if (typeof value === "function") return "[function]";
145
+ if (typeof value === "symbol") return String(value);
146
+ if (value instanceof Error) return value.message || value.name;
147
+ try {
148
+ const json = JSON.stringify(value);
149
+ return json === void 0 ? String(value) : json;
150
+ } catch {
151
+ return String(value);
152
+ }
153
+ }
154
+ function formatSearchSummary(output, expandKey) {
155
+ const lines = nonBlankLines(output);
156
+ const paths = /* @__PURE__ */ new Set();
157
+ let matchCount = 0;
158
+ for (const line of lines) {
159
+ const path = extractResultPath(line);
160
+ if (path) paths.add(compactPath(path, 48));
161
+ if (line.trim()) matchCount += 1;
162
+ }
163
+ const matchLabel = matchCount === 1 ? "1 result" : `${matchCount} results`;
164
+ const fileLabel = paths.size === 0 ? "" : paths.size === 1 ? ` in ${[...paths][0]}` : ` in ${paths.size} files`;
165
+ const samples = [...paths].slice(0, 3).join(", ");
166
+ return `${matchLabel}${fileLabel}${samples && paths.size > 1 ? `: ${samples}` : ""}; ${expandKey} to expand`;
167
+ }
168
+ function formatExecSummary(output, details, isError, expandKey) {
169
+ const parsed = parseExecDetails(details);
170
+ const rows = nonBlankLines([parsed.stdout, parsed.stderr].filter(Boolean).join("\n") || output).length;
171
+ return `${parsed.exitCode === void 0 ? isError ? "failed" : "completed" : `exit ${parsed.exitCode}`}; ${rows === 1 ? "1 output line" : `${rows} output lines`}; ${expandKey} to expand`;
172
+ }
173
+ function formatMcpSummary(output, content, expandKey) {
174
+ if (content?.length) {
175
+ const counts = /* @__PURE__ */ new Map();
176
+ for (const block of content) counts.set(block.type, (counts.get(block.type) ?? 0) + 1);
177
+ return `${[...counts.entries()].map(([type, count]) => `${count} ${type}`).join(", ")}; ${expandKey} to expand`;
178
+ }
179
+ const rows = nonBlankLines(output).length;
180
+ return `${rows === 1 ? "1 result line" : `${rows} result lines`}; ${expandKey} to expand`;
181
+ }
182
+ function parseExecDetails(details) {
183
+ if (!details || typeof details !== "object") return {};
184
+ const record = details;
185
+ return {
186
+ exitCode: numberValue(record.exitCode ?? record.exit_code ?? record.code ?? record.status),
187
+ stdout: stringValue(record.stdout ?? record.output),
188
+ stderr: stringValue(record.stderr ?? record.errorOutput ?? record.error_output)
189
+ };
190
+ }
191
+ function numberValue(value) {
192
+ if (typeof value === "number" && Number.isFinite(value)) return Math.trunc(value);
193
+ if (typeof value === "string" && /^-?\d+$/.test(value)) return Number(value);
194
+ }
195
+ function stringValue(value) {
196
+ return typeof value === "string" ? value : void 0;
197
+ }
198
+ function nonBlankLines(text) {
199
+ return text.split("\n").filter((line) => line.trim().length > 0);
200
+ }
201
+ function extractResultPath(line) {
202
+ const trimmed = line.trim();
203
+ const colonPath = trimmed.match(/^(.+?):\d+(?::\d+)?:/);
204
+ if (colonPath?.[1]) return colonPath[1];
205
+ const jsonPath = trimmed.match(/"?(?:path|file|file_path)"?\s*[:=]\s*"([^"]+)"/i);
206
+ if (jsonPath?.[1]) return jsonPath[1];
207
+ return null;
208
+ }
209
+ //#endregion
210
+ export { compactPath, displayToolName, extractExitCode, formatArgsSummary, formatCollapsedToolSummary, formatExecExpandedOutput, getToolSummaryKind, isExecStyleTool, isMcpStyleTool, isReadStyleTool, isSearchStyleTool };
211
+
212
+ //# sourceMappingURL=tool-summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-summary.js","names":[],"sources":["../../../src/tui/tool-summary.ts"],"sourcesContent":["import { basename, dirname } from 'node:path';\n\nimport { Text } from '@earendil-works/pi-tui';\n\nimport type { TuiToolContentBlock } from './tui-tool-result.js';\n\nconst MAX_ARG_VALUE_LENGTH = 120;\nconst MAX_PATH_LABEL_LENGTH = 72;\n\nexport type ToolSummaryKind = 'read' | 'search' | 'exec' | 'mcp' | 'generic';\n\nexport interface ToolSummaryContext {\n toolName: string;\n args: unknown;\n output: string;\n content?: TuiToolContentBlock[];\n details: unknown;\n isError: boolean;\n expandKey: string;\n}\n\nexport function formatArgsSummary(args: unknown, toolName: string): string {\n if (!args || typeof args !== 'object') return '';\n const compactRead = isReadStyleTool(toolName) ? formatCompactReadArgs(args) : null;\n if (compactRead) return compactRead;\n const command = isExecStyleTool(toolName) ? commandFromArgs(args) : null;\n if (command) return command;\n const entries = Object.entries(args as Record<string, unknown>);\n if (entries.length === 0) return '';\n return entries\n .map(([key, value]) => {\n const stringValue = formatArgValue(value);\n const truncated =\n stringValue.length > MAX_ARG_VALUE_LENGTH\n ? `${stringValue.slice(0, MAX_ARG_VALUE_LENGTH - 3)}...`\n : stringValue;\n return `${key}=${truncated}`;\n })\n .join(', ');\n}\n\nexport function getToolSummaryKind(toolName: string): ToolSummaryKind {\n if (isReadStyleTool(toolName)) return 'read';\n if (isSearchStyleTool(toolName)) return 'search';\n if (isExecStyleTool(toolName)) return 'exec';\n if (isMcpStyleTool(toolName)) return 'mcp';\n return 'generic';\n}\n\nexport function isReadStyleTool(toolName: string): boolean {\n const base = baseToolName(toolName);\n return ['read', 'read_file', 'memory_get'].includes(base);\n}\n\nexport function isSearchStyleTool(toolName: string): boolean {\n const base = baseToolName(toolName);\n return [\n 'search',\n 'grep',\n 'rg',\n 'ripgrep',\n 'search_code',\n 'file_search',\n 'list_files',\n ].includes(base);\n}\n\nexport function isExecStyleTool(toolName: string): boolean {\n const base = baseToolName(toolName);\n return [\n 'bash',\n 'shell',\n 'exec',\n 'run_command',\n 'exec_command',\n 'terminal',\n ].includes(base);\n}\n\nexport function isMcpStyleTool(toolName: string): boolean {\n return toolName.includes('__');\n}\n\nexport function displayToolName(toolName: string): string {\n const parts = toolName.split('__');\n if (parts.length === 2 && parts[0] && parts[1]) {\n return `${parts[0]}.${parts[1]}`;\n }\n return toolName;\n}\n\nexport function compactPath(path: string, maxLength = MAX_PATH_LABEL_LENGTH): string {\n const normalized = path.replace(/\\\\/g, '/');\n if (normalized.length <= maxLength) return normalized;\n const base = basename(normalized);\n const parent = basename(dirname(normalized));\n const suffix = parent ? `${parent}/${base}` : base;\n if (suffix.length + 2 <= maxLength) return `.../${suffix}`;\n return `.../${base.slice(Math.max(0, base.length - maxLength + 3))}`;\n}\n\nexport function formatCollapsedToolSummary(ctx: ToolSummaryContext): string {\n if (ctx.isError) {\n const rows = nonBlankLines(ctx.output).length;\n const rowLabel = rows === 1 ? '1 error line' : `${rows} error lines`;\n return `error; ${rowLabel}; ${ctx.expandKey} to expand`;\n }\n\n switch (getToolSummaryKind(ctx.toolName)) {\n case 'read': {\n const rows = new Text(ctx.output, 1, 0).render(80).length;\n const plural = rows === 1 ? 'row' : 'rows';\n return ` ${rows} ${plural}; ${ctx.expandKey} to expand`;\n }\n case 'search':\n return formatSearchSummary(ctx.output, ctx.expandKey);\n case 'exec':\n return formatExecSummary(ctx.output, ctx.details, ctx.isError, ctx.expandKey);\n case 'mcp':\n return formatMcpSummary(ctx.output, ctx.content, ctx.expandKey);\n case 'generic':\n return '';\n }\n}\n\nexport function formatExecExpandedOutput(output: string, details: unknown): string {\n const parsed = parseExecDetails(details);\n const sections: string[] = [];\n const stdout = parsed.stdout ?? output;\n if (stdout.trim()) {\n sections.push(`stdout\\n${stdout}`);\n }\n if (parsed.stderr?.trim()) {\n sections.push(`stderr\\n${parsed.stderr}`);\n }\n if (parsed.exitCode !== undefined) {\n sections.push(`exit ${parsed.exitCode}`);\n }\n return sections.join('\\n');\n}\n\nexport function extractExitCode(details: unknown): number | undefined {\n return parseExecDetails(details).exitCode;\n}\n\nfunction formatCompactReadArgs(args: unknown): string | null {\n if (!args || typeof args !== 'object') return null;\n const record = args as Record<string, unknown>;\n const rawPath = typeof record.path === 'string'\n ? record.path\n : typeof record.file_path === 'string'\n ? record.file_path\n : undefined;\n if (!rawPath) return null;\n\n const normalized = rawPath.replace(/\\\\/g, '/');\n const base = basename(normalized);\n let label: string;\n if (base === 'SKILL.md') {\n const parent = basename(dirname(normalized));\n label = parent ? `[skill] ${parent}` : '[skill]';\n } else if (base === 'AGENTS.md') {\n label = `read resource ${compactPath(normalized)}`;\n } else {\n label = compactPath(normalized);\n }\n\n const start = firstFiniteNumber(record.offset, record.from, record.start, record.line);\n const count = firstFiniteNumber(record.limit, record.lines, record.count);\n if (start != null && count != null && count > 0) {\n label += `:${start}-${start + count - 1}`;\n }\n return label;\n}\n\nfunction commandFromArgs(args: unknown): string | null {\n if (!args || typeof args !== 'object') return null;\n const record = args as Record<string, unknown>;\n const raw = record.command ?? record.cmd ?? record.script;\n if (Array.isArray(raw)) return raw.map(String).join(' ');\n if (typeof raw === 'string' && raw.trim()) return raw.trim();\n return null;\n}\n\nfunction baseToolName(toolName: string): string {\n return toolName.split('__').pop()?.toLowerCase() ?? toolName.toLowerCase();\n}\n\nfunction firstFiniteNumber(...values: unknown[]): number | null {\n for (const value of values) {\n if (typeof value === 'number' && Number.isFinite(value)) return Math.floor(value);\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value);\n if (Number.isFinite(parsed)) return Math.floor(parsed);\n }\n }\n return null;\n}\n\nfunction formatArgValue(value: unknown): string {\n if (typeof value === 'string') return value;\n if (typeof value === 'bigint') return `${value.toString()}n`;\n if (typeof value === 'function') return '[function]';\n if (typeof value === 'symbol') return String(value);\n if (value instanceof Error) return value.message || value.name;\n try {\n const json = JSON.stringify(value);\n return json === undefined ? String(value) : json;\n } catch {\n return String(value);\n }\n}\n\nfunction formatSearchSummary(output: string, expandKey: string): string {\n const lines = nonBlankLines(output);\n const paths = new Set<string>();\n let matchCount = 0;\n for (const line of lines) {\n const path = extractResultPath(line);\n if (path) paths.add(compactPath(path, 48));\n if (line.trim()) matchCount += 1;\n }\n\n const matchLabel = matchCount === 1 ? '1 result' : `${matchCount} results`;\n const fileLabel = paths.size === 0\n ? ''\n : paths.size === 1\n ? ` in ${[...paths][0]}`\n : ` in ${paths.size} files`;\n const samples = [...paths].slice(0, 3).join(', ');\n const sampleSuffix = samples && paths.size > 1 ? `: ${samples}` : '';\n return `${matchLabel}${fileLabel}${sampleSuffix}; ${expandKey} to expand`;\n}\n\nfunction formatExecSummary(\n output: string,\n details: unknown,\n isError: boolean,\n expandKey: string,\n): string {\n const parsed = parseExecDetails(details);\n const outputText = [parsed.stdout, parsed.stderr].filter(Boolean).join('\\n') || output;\n const rows = nonBlankLines(outputText).length;\n const exit = parsed.exitCode === undefined\n ? isError ? 'failed' : 'completed'\n : `exit ${parsed.exitCode}`;\n const rowLabel = rows === 1 ? '1 output line' : `${rows} output lines`;\n return `${exit}; ${rowLabel}; ${expandKey} to expand`;\n}\n\nfunction formatMcpSummary(\n output: string,\n content: TuiToolContentBlock[] | undefined,\n expandKey: string,\n): string {\n if (content?.length) {\n const counts = new Map<string, number>();\n for (const block of content) {\n counts.set(block.type, (counts.get(block.type) ?? 0) + 1);\n }\n const label = [...counts.entries()]\n .map(([type, count]) => `${count} ${type}`)\n .join(', ');\n return `${label}; ${expandKey} to expand`;\n }\n const rows = nonBlankLines(output).length;\n const rowLabel = rows === 1 ? '1 result line' : `${rows} result lines`;\n return `${rowLabel}; ${expandKey} to expand`;\n}\n\nfunction parseExecDetails(details: unknown): {\n exitCode?: number;\n stdout?: string;\n stderr?: string;\n} {\n if (!details || typeof details !== 'object') return {};\n const record = details as Record<string, unknown>;\n return {\n exitCode: numberValue(record.exitCode ?? record.exit_code ?? record.code ?? record.status),\n stdout: stringValue(record.stdout ?? record.output),\n stderr: stringValue(record.stderr ?? record.errorOutput ?? record.error_output),\n };\n}\n\nfunction numberValue(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return Math.trunc(value);\n if (typeof value === 'string' && /^-?\\d+$/.test(value)) return Number(value);\n return undefined;\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction nonBlankLines(text: string): string[] {\n return text.split('\\n').filter((line) => line.trim().length > 0);\n}\n\nfunction extractResultPath(line: string): string | null {\n const trimmed = line.trim();\n const colonPath = trimmed.match(/^(.+?):\\d+(?::\\d+)?:/);\n if (colonPath?.[1]) return colonPath[1];\n const jsonPath = trimmed.match(/\"?(?:path|file|file_path)\"?\\s*[:=]\\s*\"([^\"]+)\"/i);\n if (jsonPath?.[1]) return jsonPath[1];\n return null;\n}\n"],"mappings":"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"}
@@ -1,4 +1,19 @@
1
+ export type TuiFileChange = {
2
+ kind: 'add' | 'delete' | 'update';
3
+ path: string;
4
+ movePath?: string;
5
+ unifiedDiff: string;
6
+ added: number;
7
+ removed: number;
8
+ };
9
+ export type TuiPatchSummary = {
10
+ files: TuiFileChange[];
11
+ added: number;
12
+ removed: number;
13
+ };
1
14
  export declare function isDiffFriendlyTool(toolName: string): boolean;
2
15
  export declare function looksLikeUnifiedDiff(text: string): boolean;
3
16
  /** Colorize unified diff lines for terminal display. */
4
17
  export declare function renderUnifiedDiff(text: string, maxLines?: number): string;
18
+ export declare function parseUnifiedPatch(text: string): TuiPatchSummary | null;
19
+ export declare function renderPatchSummary(text: string, maxLines?: number): string | null;
@@ -31,26 +31,145 @@ function renderUnifiedDiff(text, maxLines = 80) {
31
31
  const inverse = (value) => `\x1b[7m${value}\x1b[27m`;
32
32
  const lines = text.split("\n");
33
33
  const capped = lines.length > maxLines ? [...lines.slice(0, maxLines), "…"] : lines;
34
+ const lineNumberWidth = getLineNumberWidth(lines);
34
35
  const rendered = [];
36
+ let oldLine = 0;
37
+ let newLine = 0;
35
38
  for (let index = 0; index < capped.length; index += 1) {
36
39
  const line = capped[index] ?? "";
37
40
  const next = capped[index + 1] ?? "";
41
+ const hunk = parseHunkHeader(line);
42
+ if (hunk) {
43
+ oldLine = hunk.oldStart;
44
+ newLine = hunk.newStart;
45
+ rendered.push(header(line));
46
+ continue;
47
+ }
38
48
  if (isRemovedDiffLine(line) && isAddedDiffLine(next)) {
39
49
  const pair = renderReplacementPair(line, next, inverse);
40
- rendered.push(removed(pair.removedLine));
41
- rendered.push(added(pair.addedLine));
50
+ rendered.push(removed(renderDiffBodyLine(oldLine, "delete", pair.removedLine, lineNumberWidth)));
51
+ rendered.push(added(renderDiffBodyLine(newLine, "add", pair.addedLine, lineNumberWidth)));
52
+ oldLine += 1;
53
+ newLine += 1;
42
54
  index += 1;
43
55
  continue;
44
56
  }
45
57
  if (isDiffHeaderLine(line)) rendered.push(header(line));
46
- else if (line.startsWith("+")) rendered.push(added(replaceTabs(line)));
47
- else if (line.startsWith("-")) rendered.push(removed(replaceTabs(line)));
48
- else rendered.push(context(replaceTabs(line)));
58
+ else if (line.startsWith("+")) {
59
+ rendered.push(added(renderDiffBodyLine(newLine, "add", replaceTabs(line), lineNumberWidth)));
60
+ newLine += 1;
61
+ } else if (line.startsWith("-")) {
62
+ rendered.push(removed(renderDiffBodyLine(oldLine, "delete", replaceTabs(line), lineNumberWidth)));
63
+ oldLine += 1;
64
+ } else if (line === "…") rendered.push(context(line));
65
+ else {
66
+ rendered.push(context(renderDiffBodyLine(newLine, "context", replaceTabs(line), lineNumberWidth)));
67
+ oldLine += 1;
68
+ newLine += 1;
69
+ }
70
+ }
71
+ return rendered.join("\n");
72
+ }
73
+ function parseUnifiedPatch(text) {
74
+ if (!looksLikeUnifiedDiff(text)) return null;
75
+ const files = [];
76
+ let current = null;
77
+ const finish = () => {
78
+ if (!current || current.hunks.length === 0) return;
79
+ const oldPath = normalizeDiffPath(current.oldPath);
80
+ const newPath = normalizeDiffPath(current.newPath);
81
+ const path = newPath && newPath !== "/dev/null" ? newPath : oldPath && oldPath !== "/dev/null" ? oldPath : "unknown";
82
+ const kind = oldPath === "/dev/null" ? "add" : newPath === "/dev/null" ? "delete" : "update";
83
+ files.push({
84
+ kind,
85
+ path,
86
+ unifiedDiff: current.hunks.join("\n"),
87
+ added: current.added,
88
+ removed: current.removed
89
+ });
90
+ };
91
+ for (const rawLine of text.split("\n")) {
92
+ const gitMatch = rawLine.match(/^diff --git a\/(.+?) b\/(.+)$/);
93
+ if (gitMatch) {
94
+ finish();
95
+ current = {
96
+ oldPath: gitMatch[1],
97
+ newPath: gitMatch[2],
98
+ hunks: [rawLine],
99
+ added: 0,
100
+ removed: 0
101
+ };
102
+ continue;
103
+ }
104
+ if (rawLine.startsWith("--- ")) {
105
+ if (!current) current = {
106
+ hunks: [],
107
+ added: 0,
108
+ removed: 0
109
+ };
110
+ current.oldPath = rawLine.slice(4).trim();
111
+ current.hunks.push(rawLine);
112
+ continue;
113
+ }
114
+ if (rawLine.startsWith("+++ ")) {
115
+ if (!current) current = {
116
+ hunks: [],
117
+ added: 0,
118
+ removed: 0
119
+ };
120
+ current.newPath = rawLine.slice(4).trim();
121
+ current.hunks.push(rawLine);
122
+ continue;
123
+ }
124
+ if (!current && rawLine.startsWith("@@")) current = {
125
+ hunks: [],
126
+ added: 0,
127
+ removed: 0
128
+ };
129
+ if (!current) continue;
130
+ current.hunks.push(rawLine);
131
+ if (isAddedDiffLine(rawLine)) current.added += 1;
132
+ else if (isRemovedDiffLine(rawLine)) current.removed += 1;
133
+ }
134
+ finish();
135
+ if (files.length === 0) return null;
136
+ return {
137
+ files,
138
+ added: files.reduce((sum, file) => sum + file.added, 0),
139
+ removed: files.reduce((sum, file) => sum + file.removed, 0)
140
+ };
141
+ }
142
+ function renderPatchSummary(text, maxLines = 120) {
143
+ const summary = parseUnifiedPatch(text);
144
+ if (!summary) return null;
145
+ const { theme } = getThemeExports();
146
+ const fileCount = summary.files.length;
147
+ const header = fileCount === 1 ? `${changeVerb(summary.files[0])} ${summary.files[0].path} ${lineCountSummary(summary.files[0])}` : `Edited ${fileCount} files ${lineCountSummary(summary)}`;
148
+ const rendered = [theme.accentSoft("• ") + theme.bold(header)];
149
+ let remainingLines = Math.max(1, maxLines - 1);
150
+ let omitted = false;
151
+ for (const [index, file] of summary.files.entries()) {
152
+ if (remainingLines <= 0) {
153
+ omitted = true;
154
+ break;
155
+ }
156
+ if (index > 0) {
157
+ rendered.push("");
158
+ remainingLines -= 1;
159
+ }
160
+ if (fileCount > 1) {
161
+ rendered.push(theme.dim(` ${changeVerb(file)} ${file.path} ${lineCountSummary(file)}`));
162
+ remainingLines -= 1;
163
+ }
164
+ const diff = renderUnifiedDiff(file.unifiedDiff, Math.max(1, remainingLines)).split("\n").map((line) => ` ${line}`).join("\n");
165
+ rendered.push(diff);
166
+ remainingLines -= diff.split("\n").length;
49
167
  }
168
+ if (omitted) rendered.push(theme.dim(" …"));
50
169
  return rendered.join("\n");
51
170
  }
52
171
  function isDiffHeaderLine(line) {
53
- return line.startsWith("+++") || line.startsWith("---") || line.startsWith("@@") || line.startsWith("diff --git");
172
+ return line.startsWith("+++") || line.startsWith("---") || line.startsWith("@@") || line.startsWith("diff --git") || line.startsWith("index ") || line.startsWith("new file mode ") || line.startsWith("deleted file mode ") || line.startsWith("similarity index ") || line.startsWith("rename from ") || line.startsWith("rename to ");
54
173
  }
55
174
  function isRemovedDiffLine(line) {
56
175
  return line.startsWith("-") && !line.startsWith("---");
@@ -61,6 +180,9 @@ function isAddedDiffLine(line) {
61
180
  function replaceTabs(text) {
62
181
  return text.replace(/\t/g, " ");
63
182
  }
183
+ function renderDiffBodyLine(lineNumber, kind, line, lineNumberWidth) {
184
+ return `${lineNumber > 0 ? String(lineNumber).padStart(lineNumberWidth, " ") : "".padStart(lineNumberWidth, " ")} ${kind === "add" ? "+" : kind === "delete" ? "-" : " "}${kind === "context" ? line.startsWith(" ") ? line.slice(1) : line : line.slice(1)}`;
185
+ }
64
186
  function renderReplacementPair(removedLine, addedLine, inverse) {
65
187
  const removedContent = replaceTabs(removedLine.slice(1));
66
188
  const addedContent = replaceTabs(addedLine.slice(1));
@@ -79,6 +201,55 @@ function highlightChangedSpan(text, start, end, inverse) {
79
201
  if (highlightStart >= end) return text;
80
202
  return `${text.slice(0, highlightStart)}${inverse(text.slice(highlightStart, end))}${text.slice(end)}`;
81
203
  }
204
+ function parseHunkHeader(line) {
205
+ const match = line.match(/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
206
+ if (!match) return null;
207
+ return {
208
+ oldStart: Number(match[1]),
209
+ newStart: Number(match[2])
210
+ };
211
+ }
212
+ function getLineNumberWidth(lines) {
213
+ let oldLine = 0;
214
+ let newLine = 0;
215
+ let maxLine = 0;
216
+ for (const line of lines) {
217
+ const hunk = parseHunkHeader(line);
218
+ if (hunk) {
219
+ oldLine = hunk.oldStart;
220
+ newLine = hunk.newStart;
221
+ maxLine = Math.max(maxLine, oldLine, newLine);
222
+ continue;
223
+ }
224
+ if (isAddedDiffLine(line)) {
225
+ maxLine = Math.max(maxLine, newLine);
226
+ newLine += 1;
227
+ } else if (isRemovedDiffLine(line)) {
228
+ maxLine = Math.max(maxLine, oldLine);
229
+ oldLine += 1;
230
+ } else if (!isDiffHeaderLine(line)) {
231
+ maxLine = Math.max(maxLine, newLine);
232
+ oldLine += 1;
233
+ newLine += 1;
234
+ }
235
+ }
236
+ return Math.max(1, String(maxLine).length);
237
+ }
238
+ function normalizeDiffPath(path) {
239
+ if (!path) return void 0;
240
+ const [first] = path.split(/\s+/);
241
+ if (!first) return void 0;
242
+ if (first === "/dev/null") return first;
243
+ return first.replace(/^[ab]\//, "");
244
+ }
245
+ function changeVerb(file) {
246
+ if (file.kind === "add") return "Added";
247
+ if (file.kind === "delete") return "Deleted";
248
+ return "Edited";
249
+ }
250
+ function lineCountSummary(change) {
251
+ return `(+${change.added} -${change.removed})`;
252
+ }
82
253
  function commonPrefixLength(a, b) {
83
254
  const max = Math.min(a.length, b.length);
84
255
  let index = 0;
@@ -96,6 +267,6 @@ function hexToRgb(hex) {
96
267
  return `${Number.parseInt(h.slice(0, 2), 16)};${Number.parseInt(h.slice(2, 4), 16)};${Number.parseInt(h.slice(4, 6), 16)}`;
97
268
  }
98
269
  //#endregion
99
- export { isDiffFriendlyTool, looksLikeUnifiedDiff, renderUnifiedDiff };
270
+ export { isDiffFriendlyTool, looksLikeUnifiedDiff, parseUnifiedPatch, renderPatchSummary, renderUnifiedDiff };
100
271
 
101
272
  //# sourceMappingURL=tui-tool-diff.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tui-tool-diff.js","names":[],"sources":["../../../src/tui/tui-tool-diff.ts"],"sourcesContent":["import { getThemeExports } from './theme-manager.js';\n\nconst DIFF_TOOLS = new Set([\n 'edit',\n 'write',\n 'apply_patch',\n 'patch',\n 'search_replace',\n 'str_replace',\n]);\n\nexport function isDiffFriendlyTool(toolName: string): boolean {\n const base = toolName.split('__').pop()?.toLowerCase() ?? toolName.toLowerCase();\n return DIFF_TOOLS.has(base);\n}\n\nexport function looksLikeUnifiedDiff(text: string): boolean {\n const sample = text.trimStart();\n if (sample.startsWith('@@')) return true;\n const lines = sample.split('\\n').slice(0, 20);\n let diffLines = 0;\n for (const line of lines) {\n if (/^(\\+\\+\\+|---|@@|[+-] |diff --git)/.test(line)) diffLines += 1;\n }\n return diffLines >= 2;\n}\n\n/** Colorize unified diff lines for terminal display. */\nexport function renderUnifiedDiff(text: string, maxLines = 80): string {\n const palette = getThemeExports().palette;\n const fg = (hex: string) => (line: string) => `\\x1b[38;2;${hexToRgb(hex)}m${line}\\x1b[0m`;\n const added = fg(palette.success);\n const removed = fg(palette.error);\n const context = fg(palette.dim);\n const header = fg(palette.accentSoft);\n const inverse = (value: string) => `\\x1b[7m${value}\\x1b[27m`;\n\n const lines = text.split('\\n');\n const capped = lines.length > maxLines ? [...lines.slice(0, maxLines), '…'] : lines;\n\n const rendered: string[] = [];\n for (let index = 0; index < capped.length; index += 1) {\n const line = capped[index] ?? '';\n const next = capped[index + 1] ?? '';\n\n if (isRemovedDiffLine(line) && isAddedDiffLine(next)) {\n const pair = renderReplacementPair(line, next, inverse);\n rendered.push(removed(pair.removedLine));\n rendered.push(added(pair.addedLine));\n index += 1;\n continue;\n }\n\n if (isDiffHeaderLine(line)) {\n rendered.push(header(line));\n } else if (line.startsWith('+')) {\n rendered.push(added(replaceTabs(line)));\n } else if (line.startsWith('-')) {\n rendered.push(removed(replaceTabs(line)));\n } else {\n rendered.push(context(replaceTabs(line)));\n }\n }\n\n return rendered.join('\\n');\n}\n\nfunction isDiffHeaderLine(line: string): boolean {\n return line.startsWith('+++') || line.startsWith('---') || line.startsWith('@@') || line.startsWith('diff --git');\n}\n\nfunction isRemovedDiffLine(line: string): boolean {\n return line.startsWith('-') && !line.startsWith('---');\n}\n\nfunction isAddedDiffLine(line: string): boolean {\n return line.startsWith('+') && !line.startsWith('+++');\n}\n\nfunction replaceTabs(text: string): string {\n return text.replace(/\\t/g, ' ');\n}\n\nfunction renderReplacementPair(\n removedLine: string,\n addedLine: string,\n inverse: (value: string) => string,\n): { removedLine: string; addedLine: string } {\n const removedContent = replaceTabs(removedLine.slice(1));\n const addedContent = replaceTabs(addedLine.slice(1));\n const commonPrefix = commonPrefixLength(removedContent, addedContent);\n const commonSuffix = commonSuffixLength(\n removedContent.slice(commonPrefix),\n addedContent.slice(commonPrefix),\n );\n\n const removedChangedEnd = removedContent.length - commonSuffix;\n const addedChangedEnd = addedContent.length - commonSuffix;\n return {\n removedLine: `-${highlightChangedSpan(removedContent, commonPrefix, removedChangedEnd, inverse)}`,\n addedLine: `+${highlightChangedSpan(addedContent, commonPrefix, addedChangedEnd, inverse)}`,\n };\n}\n\nfunction highlightChangedSpan(\n text: string,\n start: number,\n end: number,\n inverse: (value: string) => string,\n): string {\n if (end <= start) return text;\n const changed = text.slice(start, end);\n const leadingWhitespace = changed.match(/^\\s*/)?.[0] ?? '';\n const highlightStart = start + leadingWhitespace.length;\n if (highlightStart >= end) return text;\n return `${text.slice(0, highlightStart)}${inverse(text.slice(highlightStart, end))}${text.slice(end)}`;\n}\n\nfunction commonPrefixLength(a: string, b: string): number {\n const max = Math.min(a.length, b.length);\n let index = 0;\n while (index < max && a[index] === b[index]) {\n index += 1;\n }\n return index;\n}\n\nfunction commonSuffixLength(a: string, b: string): number {\n const max = Math.min(a.length, b.length);\n let index = 0;\n while (index < max && a[a.length - index - 1] === b[b.length - index - 1]) {\n index += 1;\n }\n return index;\n}\n\nfunction hexToRgb(hex: string): string {\n const h = hex.replace('#', '');\n const r = Number.parseInt(h.slice(0, 2), 16);\n const g = Number.parseInt(h.slice(2, 4), 16);\n const b = Number.parseInt(h.slice(4, 6), 16);\n return `${r};${g};${b}`;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tui-tool-diff.js","names":[],"sources":["../../../src/tui/tui-tool-diff.ts"],"sourcesContent":["import { getThemeExports } from './theme-manager.js';\n\ntype DiffLineKind = 'context' | 'add' | 'delete';\n\ntype HunkHeader = {\n oldStart: number;\n newStart: number;\n};\n\nexport type TuiFileChange = {\n kind: 'add' | 'delete' | 'update';\n path: string;\n movePath?: string;\n unifiedDiff: string;\n added: number;\n removed: number;\n};\n\nexport type TuiPatchSummary = {\n files: TuiFileChange[];\n added: number;\n removed: number;\n};\n\nconst DIFF_TOOLS = new Set([\n 'edit',\n 'write',\n 'apply_patch',\n 'patch',\n 'search_replace',\n 'str_replace',\n]);\n\nexport function isDiffFriendlyTool(toolName: string): boolean {\n const base = toolName.split('__').pop()?.toLowerCase() ?? toolName.toLowerCase();\n return DIFF_TOOLS.has(base);\n}\n\nexport function looksLikeUnifiedDiff(text: string): boolean {\n const sample = text.trimStart();\n if (sample.startsWith('@@')) return true;\n const lines = sample.split('\\n').slice(0, 20);\n let diffLines = 0;\n for (const line of lines) {\n if (/^(\\+\\+\\+|---|@@|[+-] |diff --git)/.test(line)) diffLines += 1;\n }\n return diffLines >= 2;\n}\n\n/** Colorize unified diff lines for terminal display. */\nexport function renderUnifiedDiff(text: string, maxLines = 80): string {\n const palette = getThemeExports().palette;\n const fg = (hex: string) => (line: string) => `\\x1b[38;2;${hexToRgb(hex)}m${line}\\x1b[0m`;\n const added = fg(palette.success);\n const removed = fg(palette.error);\n const context = fg(palette.dim);\n const header = fg(palette.accentSoft);\n const inverse = (value: string) => `\\x1b[7m${value}\\x1b[27m`;\n\n const lines = text.split('\\n');\n const capped = lines.length > maxLines ? [...lines.slice(0, maxLines), '…'] : lines;\n const lineNumberWidth = getLineNumberWidth(lines);\n\n const rendered: string[] = [];\n let oldLine = 0;\n let newLine = 0;\n for (let index = 0; index < capped.length; index += 1) {\n const line = capped[index] ?? '';\n const next = capped[index + 1] ?? '';\n\n const hunk = parseHunkHeader(line);\n if (hunk) {\n oldLine = hunk.oldStart;\n newLine = hunk.newStart;\n rendered.push(header(line));\n continue;\n }\n\n if (isRemovedDiffLine(line) && isAddedDiffLine(next)) {\n const pair = renderReplacementPair(line, next, inverse);\n rendered.push(removed(renderDiffBodyLine(oldLine, 'delete', pair.removedLine, lineNumberWidth)));\n rendered.push(added(renderDiffBodyLine(newLine, 'add', pair.addedLine, lineNumberWidth)));\n oldLine += 1;\n newLine += 1;\n index += 1;\n continue;\n }\n\n if (isDiffHeaderLine(line)) {\n rendered.push(header(line));\n } else if (line.startsWith('+')) {\n rendered.push(added(renderDiffBodyLine(newLine, 'add', replaceTabs(line), lineNumberWidth)));\n newLine += 1;\n } else if (line.startsWith('-')) {\n rendered.push(removed(renderDiffBodyLine(oldLine, 'delete', replaceTabs(line), lineNumberWidth)));\n oldLine += 1;\n } else if (line === '…') {\n rendered.push(context(line));\n } else {\n rendered.push(context(renderDiffBodyLine(newLine, 'context', replaceTabs(line), lineNumberWidth)));\n oldLine += 1;\n newLine += 1;\n }\n }\n\n return rendered.join('\\n');\n}\n\nexport function parseUnifiedPatch(text: string): TuiPatchSummary | null {\n if (!looksLikeUnifiedDiff(text)) return null;\n\n const files: TuiFileChange[] = [];\n let current: {\n oldPath?: string;\n newPath?: string;\n hunks: string[];\n added: number;\n removed: number;\n } | null = null;\n\n const finish = () => {\n if (!current || current.hunks.length === 0) return;\n const oldPath = normalizeDiffPath(current.oldPath);\n const newPath = normalizeDiffPath(current.newPath);\n const path = newPath && newPath !== '/dev/null'\n ? newPath\n : oldPath && oldPath !== '/dev/null'\n ? oldPath\n : 'unknown';\n const kind = oldPath === '/dev/null'\n ? 'add'\n : newPath === '/dev/null'\n ? 'delete'\n : 'update';\n files.push({\n kind,\n path,\n unifiedDiff: current.hunks.join('\\n'),\n added: current.added,\n removed: current.removed,\n });\n };\n\n for (const rawLine of text.split('\\n')) {\n const gitMatch = rawLine.match(/^diff --git a\\/(.+?) b\\/(.+)$/);\n if (gitMatch) {\n finish();\n current = {\n oldPath: gitMatch[1],\n newPath: gitMatch[2],\n hunks: [rawLine],\n added: 0,\n removed: 0,\n };\n continue;\n }\n\n if (rawLine.startsWith('--- ')) {\n if (!current) {\n current = { hunks: [], added: 0, removed: 0 };\n }\n current.oldPath = rawLine.slice(4).trim();\n current.hunks.push(rawLine);\n continue;\n }\n\n if (rawLine.startsWith('+++ ')) {\n if (!current) {\n current = { hunks: [], added: 0, removed: 0 };\n }\n current.newPath = rawLine.slice(4).trim();\n current.hunks.push(rawLine);\n continue;\n }\n\n if (!current && rawLine.startsWith('@@')) {\n current = { hunks: [], added: 0, removed: 0 };\n }\n if (!current) continue;\n\n current.hunks.push(rawLine);\n if (isAddedDiffLine(rawLine)) {\n current.added += 1;\n } else if (isRemovedDiffLine(rawLine)) {\n current.removed += 1;\n }\n }\n finish();\n\n if (files.length === 0) return null;\n return {\n files,\n added: files.reduce((sum, file) => sum + file.added, 0),\n removed: files.reduce((sum, file) => sum + file.removed, 0),\n };\n}\n\nexport function renderPatchSummary(text: string, maxLines = 120): string | null {\n const summary = parseUnifiedPatch(text);\n if (!summary) return null;\n\n const { theme } = getThemeExports();\n const fileCount = summary.files.length;\n const header = fileCount === 1\n ? `${changeVerb(summary.files[0]!)} ${summary.files[0]!.path} ${lineCountSummary(summary.files[0]!)}`\n : `Edited ${fileCount} files ${lineCountSummary(summary)}`;\n const rendered: string[] = [theme.accentSoft('• ') + theme.bold(header)];\n\n let remainingLines = Math.max(1, maxLines - 1);\n let omitted = false;\n for (const [index, file] of summary.files.entries()) {\n if (remainingLines <= 0) {\n omitted = true;\n break;\n }\n if (index > 0) {\n rendered.push('');\n remainingLines -= 1;\n }\n if (fileCount > 1) {\n rendered.push(theme.dim(` ${changeVerb(file)} ${file.path} ${lineCountSummary(file)}`));\n remainingLines -= 1;\n }\n\n const diff = renderUnifiedDiff(file.unifiedDiff, Math.max(1, remainingLines))\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n rendered.push(diff);\n remainingLines -= diff.split('\\n').length;\n }\n\n if (omitted) {\n rendered.push(theme.dim(' …'));\n }\n\n return rendered.join('\\n');\n}\n\nfunction isDiffHeaderLine(line: string): boolean {\n return (\n line.startsWith('+++') ||\n line.startsWith('---') ||\n line.startsWith('@@') ||\n line.startsWith('diff --git') ||\n line.startsWith('index ') ||\n line.startsWith('new file mode ') ||\n line.startsWith('deleted file mode ') ||\n line.startsWith('similarity index ') ||\n line.startsWith('rename from ') ||\n line.startsWith('rename to ')\n );\n}\n\nfunction isRemovedDiffLine(line: string): boolean {\n return line.startsWith('-') && !line.startsWith('---');\n}\n\nfunction isAddedDiffLine(line: string): boolean {\n return line.startsWith('+') && !line.startsWith('+++');\n}\n\nfunction replaceTabs(text: string): string {\n return text.replace(/\\t/g, ' ');\n}\n\nfunction renderDiffBodyLine(\n lineNumber: number,\n kind: DiffLineKind,\n line: string,\n lineNumberWidth: number,\n): string {\n const gutter = lineNumber > 0 ? String(lineNumber).padStart(lineNumberWidth, ' ') : ''.padStart(lineNumberWidth, ' ');\n const marker = kind === 'add' ? '+' : kind === 'delete' ? '-' : ' ';\n const content = kind === 'context'\n ? line.startsWith(' ') ? line.slice(1) : line\n : line.slice(1);\n return `${gutter} ${marker}${content}`;\n}\n\nfunction renderReplacementPair(\n removedLine: string,\n addedLine: string,\n inverse: (value: string) => string,\n): { removedLine: string; addedLine: string } {\n const removedContent = replaceTabs(removedLine.slice(1));\n const addedContent = replaceTabs(addedLine.slice(1));\n const commonPrefix = commonPrefixLength(removedContent, addedContent);\n const commonSuffix = commonSuffixLength(\n removedContent.slice(commonPrefix),\n addedContent.slice(commonPrefix),\n );\n\n const removedChangedEnd = removedContent.length - commonSuffix;\n const addedChangedEnd = addedContent.length - commonSuffix;\n return {\n removedLine: `-${highlightChangedSpan(removedContent, commonPrefix, removedChangedEnd, inverse)}`,\n addedLine: `+${highlightChangedSpan(addedContent, commonPrefix, addedChangedEnd, inverse)}`,\n };\n}\n\nfunction highlightChangedSpan(\n text: string,\n start: number,\n end: number,\n inverse: (value: string) => string,\n): string {\n if (end <= start) return text;\n const changed = text.slice(start, end);\n const leadingWhitespace = changed.match(/^\\s*/)?.[0] ?? '';\n const highlightStart = start + leadingWhitespace.length;\n if (highlightStart >= end) return text;\n return `${text.slice(0, highlightStart)}${inverse(text.slice(highlightStart, end))}${text.slice(end)}`;\n}\n\nfunction parseHunkHeader(line: string): HunkHeader | null {\n const match = line.match(/^@@ -(\\d+)(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/);\n if (!match) return null;\n return {\n oldStart: Number(match[1]),\n newStart: Number(match[2]),\n };\n}\n\nfunction getLineNumberWidth(lines: string[]): number {\n let oldLine = 0;\n let newLine = 0;\n let maxLine = 0;\n for (const line of lines) {\n const hunk = parseHunkHeader(line);\n if (hunk) {\n oldLine = hunk.oldStart;\n newLine = hunk.newStart;\n maxLine = Math.max(maxLine, oldLine, newLine);\n continue;\n }\n if (isAddedDiffLine(line)) {\n maxLine = Math.max(maxLine, newLine);\n newLine += 1;\n } else if (isRemovedDiffLine(line)) {\n maxLine = Math.max(maxLine, oldLine);\n oldLine += 1;\n } else if (!isDiffHeaderLine(line)) {\n maxLine = Math.max(maxLine, newLine);\n oldLine += 1;\n newLine += 1;\n }\n }\n return Math.max(1, String(maxLine).length);\n}\n\nfunction normalizeDiffPath(path: string | undefined): string | undefined {\n if (!path) return undefined;\n const [first] = path.split(/\\s+/);\n if (!first) return undefined;\n if (first === '/dev/null') return first;\n return first.replace(/^[ab]\\//, '');\n}\n\nfunction changeVerb(file: Pick<TuiFileChange, 'kind'>): string {\n if (file.kind === 'add') return 'Added';\n if (file.kind === 'delete') return 'Deleted';\n return 'Edited';\n}\n\nfunction lineCountSummary(change: Pick<TuiFileChange | TuiPatchSummary, 'added' | 'removed'>): string {\n return `(+${change.added} -${change.removed})`;\n}\n\nfunction commonPrefixLength(a: string, b: string): number {\n const max = Math.min(a.length, b.length);\n let index = 0;\n while (index < max && a[index] === b[index]) {\n index += 1;\n }\n return index;\n}\n\nfunction commonSuffixLength(a: string, b: string): number {\n const max = Math.min(a.length, b.length);\n let index = 0;\n while (index < max && a[a.length - index - 1] === b[b.length - index - 1]) {\n index += 1;\n }\n return index;\n}\n\nfunction hexToRgb(hex: string): string {\n const h = hex.replace('#', '');\n const r = Number.parseInt(h.slice(0, 2), 16);\n const g = Number.parseInt(h.slice(2, 4), 16);\n const b = Number.parseInt(h.slice(4, 6), 16);\n return `${r};${g};${b}`;\n}\n"],"mappings":";;AAwBA,MAAM,aAAa,IAAI,IAAI;CACzB;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAgB,mBAAmB,UAA2B;CAC5D,MAAM,OAAO,SAAS,MAAM,KAAK,CAAC,KAAK,EAAE,aAAa,IAAI,SAAS,aAAa;AAChF,QAAO,WAAW,IAAI,KAAK;;AAG7B,SAAgB,qBAAqB,MAAuB;CAC1D,MAAM,SAAS,KAAK,WAAW;AAC/B,KAAI,OAAO,WAAW,KAAK,CAAE,QAAO;CACpC,MAAM,QAAQ,OAAO,MAAM,KAAK,CAAC,MAAM,GAAG,GAAG;CAC7C,IAAI,YAAY;AAChB,MAAK,MAAM,QAAQ,MACjB,KAAI,oCAAoC,KAAK,KAAK,CAAE,cAAa;AAEnE,QAAO,aAAa;;;AAItB,SAAgB,kBAAkB,MAAc,WAAW,IAAY;CACrE,MAAM,UAAU,iBAAiB,CAAC;CAClC,MAAM,MAAM,SAAiB,SAAiB,aAAa,SAAS,IAAI,CAAC,GAAG,KAAK;CACjF,MAAM,QAAQ,GAAG,QAAQ,QAAQ;CACjC,MAAM,UAAU,GAAG,QAAQ,MAAM;CACjC,MAAM,UAAU,GAAG,QAAQ,IAAI;CAC/B,MAAM,SAAS,GAAG,QAAQ,WAAW;CACrC,MAAM,WAAW,UAAkB,UAAU,MAAM;CAEnD,MAAM,QAAQ,KAAK,MAAM,KAAK;CAC9B,MAAM,SAAS,MAAM,SAAS,WAAW,CAAC,GAAG,MAAM,MAAM,GAAG,SAAS,EAAE,IAAI,GAAG;CAC9E,MAAM,kBAAkB,mBAAmB,MAAM;CAEjD,MAAM,WAAqB,EAAE;CAC7B,IAAI,UAAU;CACd,IAAI,UAAU;AACd,MAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS,GAAG;EACrD,MAAM,OAAO,OAAO,UAAU;EAC9B,MAAM,OAAO,OAAO,QAAQ,MAAM;EAElC,MAAM,OAAO,gBAAgB,KAAK;AAClC,MAAI,MAAM;AACR,aAAU,KAAK;AACf,aAAU,KAAK;AACf,YAAS,KAAK,OAAO,KAAK,CAAC;AAC3B;;AAGF,MAAI,kBAAkB,KAAK,IAAI,gBAAgB,KAAK,EAAE;GACpD,MAAM,OAAO,sBAAsB,MAAM,MAAM,QAAQ;AACvD,YAAS,KAAK,QAAQ,mBAAmB,SAAS,UAAU,KAAK,aAAa,gBAAgB,CAAC,CAAC;AAChG,YAAS,KAAK,MAAM,mBAAmB,SAAS,OAAO,KAAK,WAAW,gBAAgB,CAAC,CAAC;AACzF,cAAW;AACX,cAAW;AACX,YAAS;AACT;;AAGF,MAAI,iBAAiB,KAAK,CACxB,UAAS,KAAK,OAAO,KAAK,CAAC;WAClB,KAAK,WAAW,IAAI,EAAE;AAC/B,YAAS,KAAK,MAAM,mBAAmB,SAAS,OAAO,YAAY,KAAK,EAAE,gBAAgB,CAAC,CAAC;AAC5F,cAAW;aACF,KAAK,WAAW,IAAI,EAAE;AAC/B,YAAS,KAAK,QAAQ,mBAAmB,SAAS,UAAU,YAAY,KAAK,EAAE,gBAAgB,CAAC,CAAC;AACjG,cAAW;aACF,SAAS,IAClB,UAAS,KAAK,QAAQ,KAAK,CAAC;OACvB;AACL,YAAS,KAAK,QAAQ,mBAAmB,SAAS,WAAW,YAAY,KAAK,EAAE,gBAAgB,CAAC,CAAC;AAClG,cAAW;AACX,cAAW;;;AAIf,QAAO,SAAS,KAAK,KAAK;;AAG5B,SAAgB,kBAAkB,MAAsC;AACtE,KAAI,CAAC,qBAAqB,KAAK,CAAE,QAAO;CAExC,MAAM,QAAyB,EAAE;CACjC,IAAI,UAMO;CAEX,MAAM,eAAe;AACnB,MAAI,CAAC,WAAW,QAAQ,MAAM,WAAW,EAAG;EAC5C,MAAM,UAAU,kBAAkB,QAAQ,QAAQ;EAClD,MAAM,UAAU,kBAAkB,QAAQ,QAAQ;EAClD,MAAM,OAAO,WAAW,YAAY,cAChC,UACA,WAAW,YAAY,cACrB,UACA;EACN,MAAM,OAAO,YAAY,cACrB,QACA,YAAY,cACV,WACA;AACN,QAAM,KAAK;GACT;GACA;GACA,aAAa,QAAQ,MAAM,KAAK,KAAK;GACrC,OAAO,QAAQ;GACf,SAAS,QAAQ;GAClB,CAAC;;AAGJ,MAAK,MAAM,WAAW,KAAK,MAAM,KAAK,EAAE;EACtC,MAAM,WAAW,QAAQ,MAAM,gCAAgC;AAC/D,MAAI,UAAU;AACZ,WAAQ;AACR,aAAU;IACR,SAAS,SAAS;IAClB,SAAS,SAAS;IAClB,OAAO,CAAC,QAAQ;IAChB,OAAO;IACP,SAAS;IACV;AACD;;AAGF,MAAI,QAAQ,WAAW,OAAO,EAAE;AAC9B,OAAI,CAAC,QACH,WAAU;IAAE,OAAO,EAAE;IAAE,OAAO;IAAG,SAAS;IAAG;AAE/C,WAAQ,UAAU,QAAQ,MAAM,EAAE,CAAC,MAAM;AACzC,WAAQ,MAAM,KAAK,QAAQ;AAC3B;;AAGF,MAAI,QAAQ,WAAW,OAAO,EAAE;AAC9B,OAAI,CAAC,QACH,WAAU;IAAE,OAAO,EAAE;IAAE,OAAO;IAAG,SAAS;IAAG;AAE/C,WAAQ,UAAU,QAAQ,MAAM,EAAE,CAAC,MAAM;AACzC,WAAQ,MAAM,KAAK,QAAQ;AAC3B;;AAGF,MAAI,CAAC,WAAW,QAAQ,WAAW,KAAK,CACtC,WAAU;GAAE,OAAO,EAAE;GAAE,OAAO;GAAG,SAAS;GAAG;AAE/C,MAAI,CAAC,QAAS;AAEd,UAAQ,MAAM,KAAK,QAAQ;AAC3B,MAAI,gBAAgB,QAAQ,CAC1B,SAAQ,SAAS;WACR,kBAAkB,QAAQ,CACnC,SAAQ,WAAW;;AAGvB,SAAQ;AAER,KAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAO;EACL;EACA,OAAO,MAAM,QAAQ,KAAK,SAAS,MAAM,KAAK,OAAO,EAAE;EACvD,SAAS,MAAM,QAAQ,KAAK,SAAS,MAAM,KAAK,SAAS,EAAE;EAC5D;;AAGH,SAAgB,mBAAmB,MAAc,WAAW,KAAoB;CAC9E,MAAM,UAAU,kBAAkB,KAAK;AACvC,KAAI,CAAC,QAAS,QAAO;CAErB,MAAM,EAAE,UAAU,iBAAiB;CACnC,MAAM,YAAY,QAAQ,MAAM;CAChC,MAAM,SAAS,cAAc,IACzB,GAAG,WAAW,QAAQ,MAAM,GAAI,CAAC,GAAG,QAAQ,MAAM,GAAI,KAAK,GAAG,iBAAiB,QAAQ,MAAM,GAAI,KACjG,UAAU,UAAU,SAAS,iBAAiB,QAAQ;CAC1D,MAAM,WAAqB,CAAC,MAAM,WAAW,KAAK,GAAG,MAAM,KAAK,OAAO,CAAC;CAExE,IAAI,iBAAiB,KAAK,IAAI,GAAG,WAAW,EAAE;CAC9C,IAAI,UAAU;AACd,MAAK,MAAM,CAAC,OAAO,SAAS,QAAQ,MAAM,SAAS,EAAE;AACnD,MAAI,kBAAkB,GAAG;AACvB,aAAU;AACV;;AAEF,MAAI,QAAQ,GAAG;AACb,YAAS,KAAK,GAAG;AACjB,qBAAkB;;AAEpB,MAAI,YAAY,GAAG;AACjB,YAAS,KAAK,MAAM,IAAI,KAAK,WAAW,KAAK,CAAC,GAAG,KAAK,KAAK,GAAG,iBAAiB,KAAK,GAAG,CAAC;AACxF,qBAAkB;;EAGpB,MAAM,OAAO,kBAAkB,KAAK,aAAa,KAAK,IAAI,GAAG,eAAe,CAAC,CAC1E,MAAM,KAAK,CACX,KAAK,SAAS,KAAK,OAAO,CAC1B,KAAK,KAAK;AACb,WAAS,KAAK,KAAK;AACnB,oBAAkB,KAAK,MAAM,KAAK,CAAC;;AAGrC,KAAI,QACF,UAAS,KAAK,MAAM,IAAI,MAAM,CAAC;AAGjC,QAAO,SAAS,KAAK,KAAK;;AAG5B,SAAS,iBAAiB,MAAuB;AAC/C,QACE,KAAK,WAAW,MAAM,IACtB,KAAK,WAAW,MAAM,IACtB,KAAK,WAAW,KAAK,IACrB,KAAK,WAAW,aAAa,IAC7B,KAAK,WAAW,SAAS,IACzB,KAAK,WAAW,iBAAiB,IACjC,KAAK,WAAW,qBAAqB,IACrC,KAAK,WAAW,oBAAoB,IACpC,KAAK,WAAW,eAAe,IAC/B,KAAK,WAAW,aAAa;;AAIjC,SAAS,kBAAkB,MAAuB;AAChD,QAAO,KAAK,WAAW,IAAI,IAAI,CAAC,KAAK,WAAW,MAAM;;AAGxD,SAAS,gBAAgB,MAAuB;AAC9C,QAAO,KAAK,WAAW,IAAI,IAAI,CAAC,KAAK,WAAW,MAAM;;AAGxD,SAAS,YAAY,MAAsB;AACzC,QAAO,KAAK,QAAQ,OAAO,MAAM;;AAGnC,SAAS,mBACP,YACA,MACA,MACA,iBACQ;AAMR,QAAO,GALQ,aAAa,IAAI,OAAO,WAAW,CAAC,SAAS,iBAAiB,IAAI,GAAG,GAAG,SAAS,iBAAiB,IAAI,CAKpG,GAJF,SAAS,QAAQ,MAAM,SAAS,WAAW,MAAM,MAChD,SAAS,YACrB,KAAK,WAAW,IAAI,GAAG,KAAK,MAAM,EAAE,GAAG,OACvC,KAAK,MAAM,EAAE;;AAInB,SAAS,sBACP,aACA,WACA,SAC4C;CAC5C,MAAM,iBAAiB,YAAY,YAAY,MAAM,EAAE,CAAC;CACxD,MAAM,eAAe,YAAY,UAAU,MAAM,EAAE,CAAC;CACpD,MAAM,eAAe,mBAAmB,gBAAgB,aAAa;CACrE,MAAM,eAAe,mBACnB,eAAe,MAAM,aAAa,EAClC,aAAa,MAAM,aAAa,CACjC;CAED,MAAM,oBAAoB,eAAe,SAAS;CAClD,MAAM,kBAAkB,aAAa,SAAS;AAC9C,QAAO;EACL,aAAa,IAAI,qBAAqB,gBAAgB,cAAc,mBAAmB,QAAQ;EAC/F,WAAW,IAAI,qBAAqB,cAAc,cAAc,iBAAiB,QAAQ;EAC1F;;AAGH,SAAS,qBACP,MACA,OACA,KACA,SACQ;AACR,KAAI,OAAO,MAAO,QAAO;CAGzB,MAAM,iBAAiB,SAFP,KAAK,MAAM,OAAO,IACD,CAAC,MAAM,OAAO,GAAG,MAAM,IACP;AACjD,KAAI,kBAAkB,IAAK,QAAO;AAClC,QAAO,GAAG,KAAK,MAAM,GAAG,eAAe,GAAG,QAAQ,KAAK,MAAM,gBAAgB,IAAI,CAAC,GAAG,KAAK,MAAM,IAAI;;AAGtG,SAAS,gBAAgB,MAAiC;CACxD,MAAM,QAAQ,KAAK,MAAM,0CAA0C;AACnE,KAAI,CAAC,MAAO,QAAO;AACnB,QAAO;EACL,UAAU,OAAO,MAAM,GAAG;EAC1B,UAAU,OAAO,MAAM,GAAG;EAC3B;;AAGH,SAAS,mBAAmB,OAAyB;CACnD,IAAI,UAAU;CACd,IAAI,UAAU;CACd,IAAI,UAAU;AACd,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,OAAO,gBAAgB,KAAK;AAClC,MAAI,MAAM;AACR,aAAU,KAAK;AACf,aAAU,KAAK;AACf,aAAU,KAAK,IAAI,SAAS,SAAS,QAAQ;AAC7C;;AAEF,MAAI,gBAAgB,KAAK,EAAE;AACzB,aAAU,KAAK,IAAI,SAAS,QAAQ;AACpC,cAAW;aACF,kBAAkB,KAAK,EAAE;AAClC,aAAU,KAAK,IAAI,SAAS,QAAQ;AACpC,cAAW;aACF,CAAC,iBAAiB,KAAK,EAAE;AAClC,aAAU,KAAK,IAAI,SAAS,QAAQ;AACpC,cAAW;AACX,cAAW;;;AAGf,QAAO,KAAK,IAAI,GAAG,OAAO,QAAQ,CAAC,OAAO;;AAG5C,SAAS,kBAAkB,MAA8C;AACvE,KAAI,CAAC,KAAM,QAAO,KAAA;CAClB,MAAM,CAAC,SAAS,KAAK,MAAM,MAAM;AACjC,KAAI,CAAC,MAAO,QAAO,KAAA;AACnB,KAAI,UAAU,YAAa,QAAO;AAClC,QAAO,MAAM,QAAQ,WAAW,GAAG;;AAGrC,SAAS,WAAW,MAA2C;AAC7D,KAAI,KAAK,SAAS,MAAO,QAAO;AAChC,KAAI,KAAK,SAAS,SAAU,QAAO;AACnC,QAAO;;AAGT,SAAS,iBAAiB,QAA4E;AACpG,QAAO,KAAK,OAAO,MAAM,IAAI,OAAO,QAAQ;;AAG9C,SAAS,mBAAmB,GAAW,GAAmB;CACxD,MAAM,MAAM,KAAK,IAAI,EAAE,QAAQ,EAAE,OAAO;CACxC,IAAI,QAAQ;AACZ,QAAO,QAAQ,OAAO,EAAE,WAAW,EAAE,OACnC,UAAS;AAEX,QAAO;;AAGT,SAAS,mBAAmB,GAAW,GAAmB;CACxD,MAAM,MAAM,KAAK,IAAI,EAAE,QAAQ,EAAE,OAAO;CACxC,IAAI,QAAQ;AACZ,QAAO,QAAQ,OAAO,EAAE,EAAE,SAAS,QAAQ,OAAO,EAAE,EAAE,SAAS,QAAQ,GACrE,UAAS;AAEX,QAAO;;AAGT,SAAS,SAAS,KAAqB;CACrC,MAAM,IAAI,IAAI,QAAQ,KAAK,GAAG;AAI9B,QAAO,GAHG,OAAO,SAAS,EAAE,MAAM,GAAG,EAAE,EAAE,GAG9B,CAAC,GAFF,OAAO,SAAS,EAAE,MAAM,GAAG,EAAE,EAAE,GAEzB,CAAC,GADP,OAAO,SAAS,EAAE,MAAM,GAAG,EAAE,EAAE,GACpB"}
@@ -0,0 +1,3 @@
1
+ import type { AgentSourceContext } from '../agent/source-context/types.js';
2
+ import type { WorkItem } from './types.js';
3
+ export declare function buildWorkItemAgentContext(item: WorkItem): AgentSourceContext;