@deepseek-harness-tui/dsh-tui 0.10.2 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (351) hide show
  1. package/README.md +175 -123
  2. package/bin/dsh-tui.js +748 -22
  3. package/cordis.patch.yml +42 -13
  4. package/cordis.yml +5 -2
  5. package/lib/types/activityPrefs.d.ts +24 -0
  6. package/lib/types/activityPrefs.d.ts.map +1 -1
  7. package/lib/types/activityPrefs.js +50 -1
  8. package/lib/types/adapter/channel/session-projection.d.ts.map +1 -1
  9. package/lib/types/adapter/channel/session-projection.js +2 -0
  10. package/lib/types/adapter/channel/state.d.ts.map +1 -1
  11. package/lib/types/adapter/channel/state.js +3 -1
  12. package/lib/types/adapter/channel/ui-policy.d.ts +4 -1
  13. package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
  14. package/lib/types/adapter/channel/ui-policy.js +6 -2
  15. package/lib/types/adapter/kernel/host-facade.d.ts.map +1 -1
  16. package/lib/types/adapter/kernel/host-facade.js +1 -0
  17. package/lib/types/adapter/kernel/replay.d.ts.map +1 -1
  18. package/lib/types/adapter/kernel/replay.js +3 -0
  19. package/lib/types/adapter/kernel/runtime.d.ts.map +1 -1
  20. package/lib/types/adapter/kernel/runtime.js +2 -0
  21. package/lib/types/adapter/kernel/slices/workspace.d.ts.map +1 -1
  22. package/lib/types/adapter/kernel/slices/workspace.js +1 -0
  23. package/lib/types/adapter/ports/channel-ui.d.ts +29 -5
  24. package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
  25. package/lib/types/adapter/ports/channel-view.d.ts +66 -12
  26. package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
  27. package/lib/types/adapter/ports/channel-workspace.d.ts +23 -0
  28. package/lib/types/adapter/ports/channel-workspace.d.ts.map +1 -1
  29. package/lib/types/adapter/ports/channel.d.ts +4 -1
  30. package/lib/types/adapter/ports/channel.d.ts.map +1 -1
  31. package/lib/types/adapter/ports/workspace.d.ts +2 -0
  32. package/lib/types/adapter/ports/workspace.d.ts.map +1 -1
  33. package/lib/types/adapter/upstream/workspace-driver.d.ts.map +1 -1
  34. package/lib/types/adapter/upstream/workspace-driver.js +10 -2
  35. package/lib/types/commands.d.ts.map +1 -1
  36. package/lib/types/commands.js +1 -0
  37. package/lib/types/components/ActivityLine.d.ts +7 -2
  38. package/lib/types/components/ActivityLine.d.ts.map +1 -1
  39. package/lib/types/components/ActivityLine.js +0 -8
  40. package/lib/types/components/ContextBarView.d.ts +15 -7
  41. package/lib/types/components/ContextBarView.d.ts.map +1 -1
  42. package/lib/types/components/ContextBarView.js +26 -22
  43. package/lib/types/components/ImagePreviewOverlay.d.ts.map +1 -1
  44. package/lib/types/components/ImagePreviewOverlay.js +11 -5
  45. package/lib/types/components/Markdown.d.ts +11 -1
  46. package/lib/types/components/Markdown.d.ts.map +1 -1
  47. package/lib/types/components/Markdown.js +20 -2
  48. package/lib/types/components/MermaidDiagram.d.ts +13 -0
  49. package/lib/types/components/MermaidDiagram.d.ts.map +1 -0
  50. package/lib/types/components/MermaidDiagram.js +61 -0
  51. package/lib/types/components/MessageList.d.ts +26 -1
  52. package/lib/types/components/MessageList.d.ts.map +1 -1
  53. package/lib/types/components/MessageList.js +74 -8
  54. package/lib/types/components/PageMargin.d.ts +1 -1
  55. package/lib/types/components/PromptInput.d.ts +37 -1
  56. package/lib/types/components/PromptInput.d.ts.map +1 -1
  57. package/lib/types/components/PromptInput.js +291 -30
  58. package/lib/types/components/ScrollbarGutter.d.ts +20 -5
  59. package/lib/types/components/ScrollbarGutter.d.ts.map +1 -1
  60. package/lib/types/components/ScrollbarGutter.js +88 -10
  61. package/lib/types/components/SplitDiffView.d.ts.map +1 -1
  62. package/lib/types/components/SplitDiffView.js +2 -1
  63. package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
  64. package/lib/types/components/StreamingMarkdown.js +30 -28
  65. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  66. package/lib/types/components/SubagentCard.js +12 -6
  67. package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
  68. package/lib/types/components/SubagentDetailScene.js +8 -3
  69. package/lib/types/components/Tooltip.d.ts.map +1 -1
  70. package/lib/types/components/Tooltip.js +45 -7
  71. package/lib/types/components/design-system/HintLine.d.ts +1 -2
  72. package/lib/types/components/design-system/HintLine.d.ts.map +1 -1
  73. package/lib/types/components/design-system/HintLine.js +1 -2
  74. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +2 -1
  75. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  76. package/lib/types/components/messages/AssistantThinkingMessage.js +2 -1
  77. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +2 -2
  78. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  79. package/lib/types/components/messages/AssistantToolUseMessage.js +30 -26
  80. package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
  81. package/lib/types/components/messages/UserPromptMessage.js +5 -7
  82. package/lib/types/components/messages/useImageInspection.d.ts.map +1 -1
  83. package/lib/types/components/messages/useImageInspection.js +19 -9
  84. package/lib/types/components/promptDraftCache.d.ts +102 -0
  85. package/lib/types/components/promptDraftCache.d.ts.map +1 -0
  86. package/lib/types/components/promptDraftCache.js +76 -0
  87. package/lib/types/components/questions/AskUserQuestionPanel.d.ts +17 -1
  88. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  89. package/lib/types/components/questions/AskUserQuestionPanel.js +40 -7
  90. package/lib/types/components/questions/QuestionMinimizedBar.d.ts +12 -0
  91. package/lib/types/components/questions/QuestionMinimizedBar.d.ts.map +1 -0
  92. package/lib/types/components/questions/QuestionMinimizedBar.js +43 -0
  93. package/lib/types/components/sessions/SessionListRow.d.ts +23 -1
  94. package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
  95. package/lib/types/components/sessions/SessionListRow.js +52 -5
  96. package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts +49 -0
  97. package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts.map +1 -0
  98. package/lib/types/components/workspaces/HomeWorkspaceRow.js +50 -0
  99. package/lib/types/dsh-adapter/activity-store.d.ts +221 -0
  100. package/lib/types/dsh-adapter/activity-store.d.ts.map +1 -0
  101. package/lib/types/dsh-adapter/activity-store.js +359 -0
  102. package/lib/types/dsh-adapter/bundled-presets.d.ts +10 -0
  103. package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -0
  104. package/lib/types/dsh-adapter/bundled-presets.js +80 -0
  105. package/lib/types/dsh-adapter/channel/action-readiness.d.ts +1 -1
  106. package/lib/types/dsh-adapter/channel/action-readiness.d.ts.map +1 -1
  107. package/lib/types/dsh-adapter/channel/action-readiness.js +3 -0
  108. package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts +1 -1
  109. package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts.map +1 -1
  110. package/lib/types/dsh-adapter/channel/agent-view-projection.js +19 -2
  111. package/lib/types/dsh-adapter/channel/background-action.d.ts +1 -1
  112. package/lib/types/dsh-adapter/channel/background-action.d.ts.map +1 -1
  113. package/lib/types/dsh-adapter/channel/background-action.js +53 -29
  114. package/lib/types/dsh-adapter/channel/binding-events.d.ts +8 -6
  115. package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
  116. package/lib/types/dsh-adapter/channel/binding-events.js +5 -4
  117. package/lib/types/dsh-adapter/channel/binding.d.ts +19 -2
  118. package/lib/types/dsh-adapter/channel/binding.d.ts.map +1 -1
  119. package/lib/types/dsh-adapter/channel/binding.js +78 -18
  120. package/lib/types/dsh-adapter/channel/compaction.d.ts +0 -1
  121. package/lib/types/dsh-adapter/channel/compaction.d.ts.map +1 -1
  122. package/lib/types/dsh-adapter/channel/compaction.js +0 -2
  123. package/lib/types/dsh-adapter/channel/composer-images.d.ts +5 -0
  124. package/lib/types/dsh-adapter/channel/composer-images.d.ts.map +1 -1
  125. package/lib/types/dsh-adapter/channel/composer-images.js +105 -6
  126. package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts +8 -0
  127. package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts.map +1 -1
  128. package/lib/types/dsh-adapter/channel/context-bookkeeping.js +3 -2
  129. package/lib/types/dsh-adapter/channel/ide-selection.d.ts +58 -0
  130. package/lib/types/dsh-adapter/channel/ide-selection.d.ts.map +1 -0
  131. package/lib/types/dsh-adapter/channel/ide-selection.js +226 -0
  132. package/lib/types/dsh-adapter/channel/input-delivery.d.ts +6 -1
  133. package/lib/types/dsh-adapter/channel/input-delivery.d.ts.map +1 -1
  134. package/lib/types/dsh-adapter/channel/input-delivery.js +9 -1
  135. package/lib/types/dsh-adapter/channel/local-actions.d.ts +3 -19
  136. package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
  137. package/lib/types/dsh-adapter/channel/local-actions.js +2 -1
  138. package/lib/types/dsh-adapter/channel/model-actions.d.ts +4 -1
  139. package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
  140. package/lib/types/dsh-adapter/channel/model-actions.js +82 -6
  141. package/lib/types/dsh-adapter/channel/model-switch.d.ts +1 -2
  142. package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
  143. package/lib/types/dsh-adapter/channel/model-switch.js +49 -31
  144. package/lib/types/dsh-adapter/channel/projection.d.ts +4 -0
  145. package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
  146. package/lib/types/dsh-adapter/channel/projection.js +29 -19
  147. package/lib/types/dsh-adapter/channel/reports.d.ts.map +1 -1
  148. package/lib/types/dsh-adapter/channel/reports.js +4 -12
  149. package/lib/types/dsh-adapter/channel/session-adoption.d.ts +1 -1
  150. package/lib/types/dsh-adapter/channel/session-adoption.d.ts.map +1 -1
  151. package/lib/types/dsh-adapter/channel/session-adoption.js +1 -0
  152. package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
  153. package/lib/types/dsh-adapter/channel/session-fork.js +26 -2
  154. package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts +4 -1
  155. package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts.map +1 -1
  156. package/lib/types/dsh-adapter/channel/session-live-adoption.js +2 -0
  157. package/lib/types/dsh-adapter/channel/session-metadata.d.ts +10 -0
  158. package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
  159. package/lib/types/dsh-adapter/channel/session-metadata.js +6 -4
  160. package/lib/types/dsh-adapter/channel/session-reset.d.ts +1 -1
  161. package/lib/types/dsh-adapter/channel/session-reset.d.ts.map +1 -1
  162. package/lib/types/dsh-adapter/channel/session-reset.js +0 -1
  163. package/lib/types/dsh-adapter/channel/session-resume.d.ts +12 -3
  164. package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
  165. package/lib/types/dsh-adapter/channel/session-resume.js +292 -94
  166. package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
  167. package/lib/types/dsh-adapter/channel/session-rewind.js +34 -16
  168. package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
  169. package/lib/types/dsh-adapter/channel/session-tree-actions.js +19 -3
  170. package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
  171. package/lib/types/dsh-adapter/channel/settings-host.js +4 -3
  172. package/lib/types/dsh-adapter/channel/state.d.ts +6 -1
  173. package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
  174. package/lib/types/dsh-adapter/channel/state.js +3 -3
  175. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts +21 -1
  176. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
  177. package/lib/types/dsh-adapter/channel/subagent-projection.js +173 -6
  178. package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
  179. package/lib/types/dsh-adapter/channel/transcript.js +6 -12
  180. package/lib/types/dsh-adapter/channel/types.d.ts +6 -1
  181. package/lib/types/dsh-adapter/channel/types.d.ts.map +1 -1
  182. package/lib/types/dsh-adapter/channel/workspace-actions.d.ts +4 -1
  183. package/lib/types/dsh-adapter/channel/workspace-actions.d.ts.map +1 -1
  184. package/lib/types/dsh-adapter/channel/workspace-actions.js +41 -1
  185. package/lib/types/dsh-adapter/channel.d.ts +1 -1
  186. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  187. package/lib/types/dsh-adapter/channel.js +82 -20
  188. package/lib/types/dsh-adapter/compat/index.d.ts +1 -1
  189. package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
  190. package/lib/types/dsh-adapter/compat/index.js +1 -1
  191. package/lib/types/dsh-adapter/compat/messages.d.ts +15 -0
  192. package/lib/types/dsh-adapter/compat/messages.d.ts.map +1 -0
  193. package/lib/types/dsh-adapter/compat/messages.js +15 -0
  194. package/lib/types/dsh-adapter/compat/sessionLog.d.ts +18 -0
  195. package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
  196. package/lib/types/dsh-adapter/compat/sessionLog.js +18 -3
  197. package/lib/types/dsh-adapter/compat/settings.d.ts +35 -0
  198. package/lib/types/dsh-adapter/compat/settings.d.ts.map +1 -0
  199. package/lib/types/dsh-adapter/compat/settings.js +57 -0
  200. package/lib/types/dsh-adapter/compat/shell.d.ts +25 -0
  201. package/lib/types/dsh-adapter/compat/shell.d.ts.map +1 -0
  202. package/lib/types/dsh-adapter/compat/shell.js +11 -0
  203. package/lib/types/dsh-adapter/contract.d.ts +5 -4
  204. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  205. package/lib/types/dsh-adapter/contract.js +17 -6
  206. package/lib/types/dsh-adapter/ide-channel.d.ts +224 -0
  207. package/lib/types/dsh-adapter/ide-channel.d.ts.map +1 -0
  208. package/lib/types/dsh-adapter/ide-channel.js +556 -0
  209. package/lib/types/dsh-adapter/index.d.ts +18 -3
  210. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  211. package/lib/types/dsh-adapter/index.js +32 -5
  212. package/lib/types/dsh-adapter/plugin.d.ts +4 -1
  213. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  214. package/lib/types/dsh-adapter/plugin.js +197 -49
  215. package/lib/types/dsh-adapter/preset-resolution.d.ts +8 -0
  216. package/lib/types/dsh-adapter/preset-resolution.d.ts.map +1 -1
  217. package/lib/types/dsh-adapter/preset-resolution.js +10 -0
  218. package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts +53 -0
  219. package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts.map +1 -0
  220. package/lib/types/dsh-adapter/session-mount-heartbeat.js +100 -0
  221. package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -1
  222. package/lib/types/dsh-adapter/sessionTree.js +3 -2
  223. package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
  224. package/lib/types/dsh-adapter/settings-sections.js +7 -4
  225. package/lib/types/dsh-adapter/subagents.d.ts +16 -3
  226. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  227. package/lib/types/dsh-adapter/subagents.js +92 -29
  228. package/lib/types/dsh-adapter/workspaces.d.ts +46 -3
  229. package/lib/types/dsh-adapter/workspaces.d.ts.map +1 -1
  230. package/lib/types/dsh-adapter/workspaces.js +116 -0
  231. package/lib/types/effortPrefs.d.ts +15 -3
  232. package/lib/types/effortPrefs.d.ts.map +1 -1
  233. package/lib/types/effortPrefs.js +37 -3
  234. package/lib/types/history.d.ts +13 -1
  235. package/lib/types/history.d.ts.map +1 -1
  236. package/lib/types/history.js +15 -2
  237. package/lib/types/homePrefs.d.ts +15 -0
  238. package/lib/types/homePrefs.d.ts.map +1 -0
  239. package/lib/types/homePrefs.js +53 -0
  240. package/lib/types/i18n.d.ts +347 -297
  241. package/lib/types/i18n.d.ts.map +1 -1
  242. package/lib/types/i18n.js +133 -85
  243. package/lib/types/ink/colorize.d.ts +10 -0
  244. package/lib/types/ink/colorize.d.ts.map +1 -1
  245. package/lib/types/ink/colorize.js +21 -0
  246. package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
  247. package/lib/types/ink/components/ScrollBox.js +12 -1
  248. package/lib/types/ink/dom.d.ts +1 -0
  249. package/lib/types/ink/dom.d.ts.map +1 -1
  250. package/lib/types/ink/hooks/use-copy-on-select.d.ts +5 -1
  251. package/lib/types/ink/hooks/use-copy-on-select.d.ts.map +1 -1
  252. package/lib/types/ink/hooks/use-copy-on-select.js +15 -1
  253. package/lib/types/ink/ink.d.ts.map +1 -1
  254. package/lib/types/ink/ink.js +36 -1
  255. package/lib/types/ink/log-update.d.ts.map +1 -1
  256. package/lib/types/ink/log-update.js +19 -1
  257. package/lib/types/ink/output.d.ts +10 -1
  258. package/lib/types/ink/output.d.ts.map +1 -1
  259. package/lib/types/ink/output.js +109 -17
  260. package/lib/types/ink/render-border.d.ts +6 -1
  261. package/lib/types/ink/render-border.d.ts.map +1 -1
  262. package/lib/types/ink/render-border.js +25 -9
  263. package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
  264. package/lib/types/ink/render-node-to-output.js +48 -6
  265. package/lib/types/ink/renderer.d.ts +6 -0
  266. package/lib/types/ink/renderer.d.ts.map +1 -1
  267. package/lib/types/ink/renderer.js +2 -1
  268. package/lib/types/ink/selection.d.ts +88 -0
  269. package/lib/types/ink/selection.d.ts.map +1 -1
  270. package/lib/types/ink/selection.js +164 -0
  271. package/lib/types/ink/sixel-graphics.d.ts +19 -1
  272. package/lib/types/ink/sixel-graphics.d.ts.map +1 -1
  273. package/lib/types/ink/sixel-graphics.js +124 -12
  274. package/lib/types/ink/terminal-image.d.ts +18 -1
  275. package/lib/types/ink/terminal-image.d.ts.map +1 -1
  276. package/lib/types/ink/terminal.d.ts +17 -0
  277. package/lib/types/ink/terminal.d.ts.map +1 -1
  278. package/lib/types/ink/terminal.js +20 -1
  279. package/lib/types/screens/Chat.d.ts +20 -1
  280. package/lib/types/screens/Chat.d.ts.map +1 -1
  281. package/lib/types/screens/Chat.js +296 -76
  282. package/lib/types/screens/SessionSupervisor.d.ts +84 -0
  283. package/lib/types/screens/SessionSupervisor.d.ts.map +1 -0
  284. package/lib/types/screens/SessionSupervisor.js +350 -0
  285. package/lib/types/screens/SessionTree.js +2 -2
  286. package/lib/types/screens/Settings.d.ts.map +1 -1
  287. package/lib/types/screens/Settings.js +32 -9
  288. package/lib/types/screens/StatusLine.d.ts +18 -1
  289. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  290. package/lib/types/screens/StatusLine.js +38 -19
  291. package/lib/types/screens/StatusMetrics.d.ts +79 -22
  292. package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
  293. package/lib/types/screens/StatusMetrics.js +153 -88
  294. package/lib/types/screens/sessionSupervisor/model.d.ts +83 -0
  295. package/lib/types/screens/sessionSupervisor/model.d.ts.map +1 -0
  296. package/lib/types/screens/sessionSupervisor/model.js +69 -0
  297. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts +120 -0
  298. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts.map +1 -0
  299. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.js +593 -0
  300. package/lib/types/sessionMounts.d.ts +272 -0
  301. package/lib/types/sessionMounts.d.ts.map +1 -0
  302. package/lib/types/sessionMounts.js +706 -0
  303. package/lib/types/sessions/format.d.ts.map +1 -1
  304. package/lib/types/sessions/format.js +4 -1
  305. package/lib/types/sessions/resumeFailure.d.ts +38 -0
  306. package/lib/types/sessions/resumeFailure.d.ts.map +1 -0
  307. package/lib/types/sessions/resumeFailure.js +58 -0
  308. package/lib/types/terminal-utils/mermaid.d.ts +44 -0
  309. package/lib/types/terminal-utils/mermaid.d.ts.map +1 -0
  310. package/lib/types/terminal-utils/mermaid.js +83 -0
  311. package/lib/types/tips.d.ts.map +1 -1
  312. package/lib/types/tips.js +175 -19
  313. package/lib/types/tuiDisplayPrefs.d.ts +7 -9
  314. package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
  315. package/lib/types/tuiDisplayPrefs.js +31 -28
  316. package/lib/types/update.d.ts +61 -0
  317. package/lib/types/update.d.ts.map +1 -1
  318. package/lib/types/update.js +194 -0
  319. package/lib/types/utils/fold-long-lines.d.ts +1 -1
  320. package/lib/types/utils/fold-long-lines.js +1 -1
  321. package/lib/types/utils/imageResize.d.ts +90 -0
  322. package/lib/types/utils/imageResize.d.ts.map +1 -0
  323. package/lib/types/utils/imageResize.js +272 -0
  324. package/lib/types/utils/keymap.d.ts +5 -1
  325. package/lib/types/utils/keymap.d.ts.map +1 -1
  326. package/lib/types/utils/keymap.js +23 -0
  327. package/lib/types/working-activity.d.ts +10 -9
  328. package/lib/types/working-activity.d.ts.map +1 -1
  329. package/lib/types/working-activity.js +17 -10
  330. package/lib/types/workspaces.d.ts +2 -1
  331. package/lib/types/workspaces.d.ts.map +1 -1
  332. package/lib/types/workspaces.js +1 -1
  333. package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +10 -10
  334. package/package.json +126 -105
  335. package/presets/liangshen/.dsh-tui-managed.json +1 -1
  336. package/presets/liangshen/agent.cordis.yml +15 -0
  337. package/lib/types/components/design-system/KeyboardShortcutHint.d.ts +0 -19
  338. package/lib/types/components/design-system/KeyboardShortcutHint.d.ts.map +0 -1
  339. package/lib/types/components/design-system/KeyboardShortcutHint.js +0 -14
  340. package/lib/types/dsh-adapter/channel/activity.d.ts +0 -20
  341. package/lib/types/dsh-adapter/channel/activity.d.ts.map +0 -1
  342. package/lib/types/dsh-adapter/channel/activity.js +0 -113
  343. package/lib/types/screens/AgentView.d.ts +0 -23
  344. package/lib/types/screens/AgentView.d.ts.map +0 -1
  345. package/lib/types/screens/AgentView.js +0 -546
  346. package/lib/types/screens/SessionBrowser.d.ts +0 -42
  347. package/lib/types/screens/SessionBrowser.d.ts.map +0 -1
  348. package/lib/types/screens/SessionBrowser.js +0 -911
  349. package/lib/types/terminal-utils/terminal.d.ts +0 -18
  350. package/lib/types/terminal-utils/terminal.d.ts.map +0 -1
  351. package/lib/types/terminal-utils/terminal.js +0 -96
@@ -5,6 +5,8 @@ import { readModelPref } from '../../modelPrefs.js';
5
5
  import { readPresetPref } from '../../presetPrefs.js';
6
6
  import { clearResumeTarget, touchAgentViewSession, touchSession } from '../../sessionHistory.js';
7
7
  import { t } from '../../i18n.js';
8
+ import { reserveMount } from '../../sessionMounts.js';
9
+ import { mountFailureText } from '../../sessions/resumeFailure.js';
8
10
  import { composePreset } from '../presets.js';
9
11
  import { attachSessionToWorkspace } from '../workspace.js';
10
12
  import { resetSessionProjection } from './session-reset.js';
@@ -19,6 +21,13 @@ export function createBackgroundCurrentAction(ctx, state, options, deps) {
19
21
  return { ok: false, reason: 'unavailable' };
20
22
  }
21
23
  const sessionId = SessionId(randomUUID());
24
+ // Reserve before the factory: from the moment `agents.create` returns this
25
+ // process holds the only write handle on a log the publisher has not named
26
+ // yet, and a peer listing sessions in that gap would be told it is free.
27
+ const reserved = await reserveMount(sessionId);
28
+ if (!reserved.ok && reserved.reason !== 'occupied')
29
+ deps.notify(mountFailureText(reserved), { color: 'warning', timeoutMs: 8000 });
30
+ const reservation = reserved.ok ? reserved.reservation : { settle: () => { }, abandon: () => { } };
22
31
  try {
23
32
  const composed = await composePreset(ctx, options.configuredPreset ?? readPresetPref());
24
33
  const route = await validateModelRoute(ctx.get('llm'), resolveModelRoute({ provider: options.configuredProvider, model: options.configuredModel }, readModelPref(), { provider: options.provider, model: options.model }), { provider: options.provider, model: options.model });
@@ -30,6 +39,7 @@ export function createBackgroundCurrentAction(ctx, state, options, deps) {
30
39
  }));
31
40
  if (!deps.binding.isCurrent(adoption)) {
32
41
  await deps.binding.abandon(handle);
42
+ reservation.abandon();
33
43
  return { ok: false, reason: 'failed', error: 'Channel lifetime ended' };
34
44
  }
35
45
  try {
@@ -45,39 +55,53 @@ export function createBackgroundCurrentAction(ctx, state, options, deps) {
45
55
  // agent; the prepared candidate is abandoned instead.
46
56
  if (!deps.binding.isCurrent(adoption)) {
47
57
  await deps.binding.abandon(handle);
58
+ reservation.abandon();
48
59
  return { ok: false, reason: 'failed', error: 'Channel lifetime ended' };
49
60
  }
50
- return deps.binding.adopt(handle, adoption, (previous, disposePrevious) => {
51
- const previousSessionId = String(previous.agent.session.id);
52
- if (previous.handle !== undefined) {
53
- deps.backgroundHandles.set(previousSessionId, previous.handle);
54
- disposePrevious('park');
55
- }
56
- resetSessionProjection(state, deps.rowIds, deps.resetProjector, deps.resetSubagents, deps.resetJobs);
57
- state.status = handle.agent.status;
58
- state.agentId = handle.agent.id;
59
- state.loadedContext = undefined;
60
- state.contextWindow = undefined;
61
- state.effortLevels = undefined;
62
- state.reasoningEffort = undefined;
63
- deps.refreshEffortLevels();
64
- // Reset the input FIFO and pending-decision indicators BEFORE the first
65
- // emit (main's bind → clear → refresh order).
66
- deps.clearStagedImages();
67
- deps.bindAgent();
68
- deps.refreshCommands();
69
- void deps.refreshLoadedContext();
70
- void deps.refreshSkillCommands();
71
- clearResumeTarget();
72
- touchSession(handle.agent.id);
73
- touchAgentViewSession(previousSessionId);
74
- touchAgentViewSession(String(handle.agent.id));
75
- deps.notifySessionSwitched('background', String(handle.agent.id), previousSessionId);
76
- deps.notifyAgentView();
77
- return { ok: true, backgroundedSessionId: previousSessionId };
78
- });
61
+ let committed = false;
62
+ try {
63
+ const result = deps.binding.adopt(handle, adoption, (previous, disposePrevious) => {
64
+ const previousSessionId = String(previous.agent.session.id);
65
+ if (previous.handle !== undefined) {
66
+ deps.backgroundHandles.set(previousSessionId, previous.handle);
67
+ disposePrevious('park');
68
+ }
69
+ resetSessionProjection(state, deps.rowIds, deps.resetProjector, deps.resetSubagents, deps.resetJobs);
70
+ state.status = handle.agent.status;
71
+ state.agentId = handle.agent.id;
72
+ state.sessionId = handle.agent.session.id;
73
+ state.loadedContext = undefined;
74
+ state.contextWindow = undefined;
75
+ state.effortLevels = undefined;
76
+ state.reasoningEffort = undefined;
77
+ deps.refreshEffortLevels();
78
+ // Reset the input FIFO and pending-decision indicators BEFORE the first
79
+ // emit (main's bind → clear → refresh order).
80
+ deps.clearStagedImages();
81
+ deps.bindAgent();
82
+ deps.refreshCommands();
83
+ void deps.refreshLoadedContext();
84
+ void deps.refreshSkillCommands();
85
+ clearResumeTarget();
86
+ touchSession(handle.agent.id);
87
+ touchAgentViewSession(previousSessionId);
88
+ touchAgentViewSession(String(handle.agent.id));
89
+ deps.notifySessionSwitched('background', String(handle.agent.id), previousSessionId);
90
+ deps.notifyAgentView();
91
+ return { ok: true, backgroundedSessionId: previousSessionId };
92
+ });
93
+ committed = true;
94
+ return result;
95
+ }
96
+ finally {
97
+ if (committed)
98
+ reservation.settle();
99
+ else
100
+ reservation.abandon();
101
+ }
79
102
  }
80
103
  catch (error) {
104
+ reservation.abandon();
81
105
  const message = error instanceof Error ? error.message : String(error);
82
106
  deps.notify(t('agentview-dispatch-failed', { err: message }), { color: 'error', timeoutMs: 8000 });
83
107
  return { ok: false, reason: 'failed', error: message };
@@ -16,12 +16,12 @@ export declare function createBindingEvents(ctx: Context, deps: {
16
16
  owner: ChannelOwner;
17
17
  binding: ChannelBinding;
18
18
  state: ChannelState;
19
- activity: {
20
- start(agent: ChannelBinding['agent']): void;
21
- stop(): void;
22
- onAgentStatus(status: ChannelBinding['agent']['status']): unknown;
23
- onSessionEvent(event: unknown): unknown;
24
- };
19
+ /** Read the activity projection's current value for a freshly bound session.
20
+ * A projection value only arrives when it changes, so a resumed or
21
+ * reattached session needs this read to show its line before the next event.
22
+ * The line's semantics live in the working-activity plugin: this app folds
23
+ * nothing itself and forwards no events. */
24
+ seedActivity?(session: unknown): void;
25
25
  inputConvergence: InputConvergence;
26
26
  selection: ModelSelectionRef;
27
27
  modelActions: {
@@ -36,6 +36,7 @@ export declare function createBindingEvents(ctx: Context, deps: {
36
36
  subagents: {
37
37
  onSessionEvent(session: unknown, event: unknown): boolean;
38
38
  onStreamFrame?(agent: unknown, frame: AssistantStreamFrame): boolean;
39
+ onParentEvent?(event: unknown): void;
39
40
  onStart(info: {
40
41
  id: string;
41
42
  runId?: string;
@@ -44,6 +45,7 @@ export declare function createBindingEvents(ctx: Context, deps: {
44
45
  }): void;
45
46
  onEnd(info: {
46
47
  id: string;
48
+ runId?: string;
47
49
  stopReason: string;
48
50
  lastAssistantMessage?: unknown[];
49
51
  }): void;
@@ -1 +1 @@
1
- {"version":3,"file":"binding-events.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/binding-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AACrF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE;IACtD,KAAK,EAAE,YAAY,CAAA;IACnB,OAAO,EAAE,cAAc,CAAA;IACvB,KAAK,EAAE,YAAY,CAAA;IACnB,QAAQ,EAAE;QACR,KAAK,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;QAC3C,IAAI,IAAI,IAAI,CAAA;QACZ,aAAa,CAAC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAA;QACjE,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAA;KACxC,CAAA;IACD,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,SAAS,EAAE,iBAAiB,CAAA;IAC5B,YAAY,EAAE;QAAE,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,SAAS,EAAE,iBAAiB,CAAA;KAAE,CAAA;IACrF,WAAW,EAAE;QAAE,WAAW,IAAI,IAAI,CAAC;QAAC,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;KAAE,CAAA;IAC5F,SAAS,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAA;IACrD,SAAS,EAAE;QAAE,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;QAAC,aAAa,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC;QAAC,OAAO,CAAC,IAAI,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,OAAO,CAAA;SAAE,GAAG,IAAI,CAAC;QAAC,KAAK,CAAC,IAAI,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAC;YAAC,oBAAoB,CAAC,EAAE,OAAO,EAAE,CAAA;SAAE,GAAG,IAAI,CAAA;KAAE,CAAA;IAC/T,SAAS,EAAE;QAAE,QAAQ,IAAI,IAAI,CAAA;KAAE,CAAA;IAC/B,eAAe,CAAC,EAAE;QAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;KAAE,CAAA;IACrE;;;sCAGkC;IAClC,gBAAgB,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3C;gBAYkB,IAAI;EAgItB"}
1
+ {"version":3,"file":"binding-events.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/binding-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AACrF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE;IACtD,KAAK,EAAE,YAAY,CAAA;IACnB,OAAO,EAAE,cAAc,CAAA;IACvB,KAAK,EAAE,YAAY,CAAA;IACnB;;;;iDAI6C;IAC7C,YAAY,CAAC,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IACrC,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,SAAS,EAAE,iBAAiB,CAAA;IAC5B,YAAY,EAAE;QAAE,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,SAAS,EAAE,iBAAiB,CAAA;KAAE,CAAA;IACrF,WAAW,EAAE;QAAE,WAAW,IAAI,IAAI,CAAC;QAAC,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;KAAE,CAAA;IAC5F,SAAS,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAA;IACrD,SAAS,EAAE;QAAE,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;QAAC,aAAa,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC;QAAC,aAAa,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;QAAC,OAAO,CAAC,IAAI,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,OAAO,CAAA;SAAE,GAAG,IAAI,CAAC;QAAC,KAAK,CAAC,IAAI,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAC;YAAC,oBAAoB,CAAC,EAAE,OAAO,EAAE,CAAA;SAAE,GAAG,IAAI,CAAA;KAAE,CAAA;IACrX,SAAS,EAAE;QAAE,QAAQ,IAAI,IAAI,CAAA;KAAE,CAAA;IAC/B,eAAe,CAAC,EAAE;QAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;KAAE,CAAA;IACrE;;;sCAGkC;IAClC,gBAAgB,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3C;gBAYkB,IAAI;EAiItB"}
@@ -22,7 +22,7 @@ export function createBindingEvents(ctx, deps) {
22
22
  deps.state.agentBindingGeneration = deps.binding.bind();
23
23
  deps.inputConvergence.cancelInFlight = false;
24
24
  deps.inputConvergence.interruptSeq += 1;
25
- deps.activity.start(deps.binding.agent);
25
+ deps.seedActivity?.(deps.binding.agent.session);
26
26
  deps.modelActions.selection.current = undefined;
27
27
  deps.modelActions.selection.assembled = undefined;
28
28
  if (deps.binding.agent.options?.model === undefined && deps.state.provider !== '' && deps.state.model !== '') {
@@ -80,7 +80,6 @@ export function createBindingEvents(ctx, deps) {
80
80
  if (!current() || subject !== capture.agent)
81
81
  return;
82
82
  deps.state.status = status;
83
- deps.activity.onAgentStatus(status);
84
83
  if (status === 'idle')
85
84
  reconcileRetiredProjection('idle');
86
85
  deps.state.emit();
@@ -89,7 +88,6 @@ export function createBindingEvents(ctx, deps) {
89
88
  if (!current() || subject !== capture.agent)
90
89
  return;
91
90
  deps.state.status = 'disposed';
92
- deps.activity.stop();
93
91
  reconcileRetiredProjection('disposed');
94
92
  deps.state.emit();
95
93
  });
@@ -125,7 +123,10 @@ export function createBindingEvents(ctx, deps) {
125
123
  if (!isMainSession)
126
124
  return;
127
125
  deps.messageObserver?.publish(subject, event);
128
- deps.activity.onSessionEvent(event);
126
+ // Parent-log discovery events (`subagent/catalog`, workflow member
127
+ // edges) reach the dashboard through the same firehose; they are not
128
+ // transcript rows and render below remains untouched by them.
129
+ deps.subagents.onParentEvent?.(event);
129
130
  deps.modeActions.onSessionEvent(subject, event);
130
131
  deps.projector.renderEvent(event);
131
132
  if (event.type === 'assistant/chunk')
@@ -24,10 +24,27 @@ export declare function createChannelBinding(initial: Agent, handle: AgentHandle
24
24
  readonly generation: number;
25
25
  capture(): BindingCapture;
26
26
  isCurrent(capture: BindingCapture): boolean;
27
- /** Create a candidate without giving it authority over the live binding. */
27
+ /**
28
+ * Create a candidate without giving it authority over the live binding.
29
+ *
30
+ * When the capture went stale the candidate is closed and the rejection
31
+ * WAITS for that close. The caller's `abandon(handle)` can no longer see the
32
+ * handle — it was never in `pending` — so waiting here is the only way the
33
+ * handle is known to have stopped writing before the caller gives its
34
+ * ledger reservation back.
35
+ */
28
36
  prepare(capture: BindingCapture, create: () => Promise<AgentHandle>): Promise<AgentHandle>;
29
- /** Dispose an uncommitted candidate exactly once. Live handles are inert. */
37
+ /**
38
+ * Dispose an uncommitted candidate exactly once and WAIT for the close.
39
+ *
40
+ * Waiting is the point: callers use this on the path where they are about
41
+ * to give a cross-process ledger reservation back, and that reservation may
42
+ * only be released once the handle has actually stopped writing. A live
43
+ * handle that this cell never owned is inert here.
44
+ */
30
45
  abandon(candidate: AgentHandle): Promise<void>;
46
+ /** A registry may retain an agent while its async handle close drains. */
47
+ waitForDisposal(sessionId: string): Promise<void>;
31
48
  /** Perform one explicit synchronous prepared-handle adoption transaction. */
32
49
  adopt: <T>(candidate: AgentHandle, capture: BindingCapture, tail: (previous: BindingCommit, disposition: (next: PreviousDisposition) => void) => T) => T;
33
50
  /** Perform one explicit synchronous already-live-agent adoption transaction. */
@@ -1 +1 @@
1
- {"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/binding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;AAED,KAAK,mBAAmB,GAAG,SAAS,GAAG,MAAM,CAAA;AAE7C;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,GAAG,SAAS,EAAE,KAAK,EAAE,YAAY;;;;eAiK1F,cAAc;uBACN,cAAc;IAEjC,4EAA4E;qBACrD,cAAc,UAAU,MAAM,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;IAkBhG,6EAA6E;uBACpD,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAEpD,6EAA6E;YAvIhE,CAAC,aACH,WAAW,WACb,cAAc,QACjB,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,KAAK,CAAC,KACrF,CAAC;IAqIF,gFAAgF;eA5EhE,CAAC,SACV,KAAK,cACA,WAAW,GAAG,SAAS,QAC7B,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,KAAK,CAAC,KACrF,CAAC;;uBAsFiB,MAAM,IAAI;qCAvLS,MAAM,IAAI,KAAG,OAAO;EA0L7D;AAED,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAA"}
1
+ {"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/binding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;AAED,KAAK,mBAAmB,GAAG,SAAS,GAAG,MAAM,CAAA;AAE7C;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,GAAG,SAAS,EAAE,KAAK,EAAE,YAAY;;;;eAsM1F,cAAc;uBACN,cAAc;IAEjC;;;;;;;;OAQG;qBACoB,cAAc,UAAU,MAAM,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;IAkBhG;;;;;;;OAOG;uBACsB,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpD,0EAA0E;+BACzC,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,6EAA6E;YA7JhE,CAAC,aACH,WAAW,WACb,cAAc,QACjB,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,KAAK,CAAC,KACrF,CAAC;IA2JF,gFAAgF;eAlGhE,CAAC,SACV,KAAK,cACA,WAAW,GAAG,SAAS,QAC7B,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,KAAK,CAAC,KACrF,CAAC;;uBA4GiB,MAAM,IAAI;qCAvNS,MAAM,IAAI,KAAG,OAAO;EA0N7D;AAED,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAA"}
@@ -14,17 +14,46 @@ export function createChannelBinding(initial, handle, owner) {
14
14
  let subscriptions = [];
15
15
  let handoff;
16
16
  const pending = new Map();
17
- const disposed = new WeakSet();
17
+ /**
18
+ * The in-flight (or finished) close of a handle this cell owns, keyed by the
19
+ * handle. A Promise rather than a "has it started" flag, because the callers
20
+ * that matter need to know when the handle has actually STOPPED writing: a
21
+ * ledger reservation is only safe to give back after that, and a second
22
+ * `dispose()` must not start a parallel close.
23
+ */
24
+ const closing = new WeakMap();
25
+ const closingSessions = new Map();
26
+ /** Close `candidate` exactly once; the result resolves however it ends. */
18
27
  const dispose = (candidate) => {
19
- if (disposed.has(candidate))
20
- return;
21
- disposed.add(candidate);
22
- void candidate.dispose().catch(() => undefined);
28
+ const started = closing.get(candidate);
29
+ if (started !== undefined)
30
+ return started;
31
+ // Kicked off SYNCHRONOUSLY: revocation is part of a synchronous transaction
32
+ // boundary, and a caller that abandons a candidate may check it right away.
33
+ // Only the waiting is deferred, never the call.
34
+ let close;
35
+ try {
36
+ close = Promise.resolve(candidate.dispose()).catch(() => undefined);
37
+ }
38
+ catch {
39
+ close = Promise.resolve();
40
+ }
41
+ closing.set(candidate, close);
42
+ const id = String(candidate.agent.session.id);
43
+ closingSessions.set(id, close);
44
+ void close.then(() => {
45
+ if (closingSessions.get(id) === close)
46
+ closingSessions.delete(id);
47
+ });
48
+ return close;
23
49
  };
24
50
  const disposePending = (candidate) => {
25
- if (!pending.delete(candidate))
26
- return;
27
- dispose(candidate);
51
+ if (pending.delete(candidate))
52
+ return dispose(candidate);
53
+ // Already un-pended (a revocation path took it out from under the caller):
54
+ // hand back the close that is already running, so a caller that HAS to
55
+ // wait — one about to give a ledger reservation back — still can.
56
+ return closing.get(candidate);
28
57
  };
29
58
  const clearSubscriptions = (afterEach) => {
30
59
  const active = subscriptions.splice(0);
@@ -49,23 +78,33 @@ export function createChannelBinding(initial, handle, owner) {
49
78
  return failure;
50
79
  };
51
80
  const isCaptureCurrent = (capture) => owner.current() && capture.agent === currentAgent && capture.generation === generation;
81
+ /**
82
+ * Start a close without waiting for it. The callers below are synchronous
83
+ * transaction boundaries — they must not turn into awaits — but the close
84
+ * itself stays observable through {@link dispose}, so a caller that DOES have
85
+ * to wait (an `abandon` handing a ledger reservation back) still can.
86
+ */
87
+ const startClose = (close) => {
88
+ void close;
89
+ };
52
90
  const assertPrepared = (candidate, capture) => {
53
91
  if (pending.get(candidate) !== capture || !isCaptureCurrent(capture)) {
54
- disposePending(candidate);
92
+ startClose(disposePending(candidate));
55
93
  throw new Error('dsh-tui: Channel binding changed before adoption');
56
94
  }
57
95
  };
58
96
  const settlePrevious = (previous, disposition) => {
59
97
  // Parking deliberately transfers ownership to the caller's background
60
98
  // ledger. Disposal is centralised here so no adoption tail can double-call
61
- // an old handle while its transaction is being revoked.
99
+ // an old handle while its transaction is being revoked. Neither path waits:
100
+ // an ordinary session switch must not block on the handle it just left.
62
101
  if (disposition === 'dispose' && previous.handle !== undefined && previous.handle !== currentHandle) {
63
- dispose(previous.handle);
102
+ startClose(dispose(previous.handle));
64
103
  }
65
104
  };
66
105
  owner.own(clearSubscriptions);
67
106
  owner.own(() => { for (const candidate of [...pending.keys()])
68
- disposePending(candidate); });
107
+ startClose(disposePending(candidate)); });
69
108
  const adopt = (candidate, capture, tail) => {
70
109
  if (handoff !== undefined) {
71
110
  // Mark the outer transaction superseded as well as rejecting this one;
@@ -120,7 +159,7 @@ export function createChannelBinding(initial, handle, owner) {
120
159
  if (currentHandle === candidate) {
121
160
  currentHandle = undefined;
122
161
  }
123
- dispose(candidate);
162
+ startClose(dispose(candidate));
124
163
  owner.dispose();
125
164
  throw error;
126
165
  }
@@ -185,27 +224,48 @@ export function createChannelBinding(initial, handle, owner) {
185
224
  get generation() { return generation; },
186
225
  capture() { return { agent: currentAgent, generation }; },
187
226
  isCurrent(capture) { return isCaptureCurrent(capture); },
188
- /** Create a candidate without giving it authority over the live binding. */
227
+ /**
228
+ * Create a candidate without giving it authority over the live binding.
229
+ *
230
+ * When the capture went stale the candidate is closed and the rejection
231
+ * WAITS for that close. The caller's `abandon(handle)` can no longer see the
232
+ * handle — it was never in `pending` — so waiting here is the only way the
233
+ * handle is known to have stopped writing before the caller gives its
234
+ * ledger reservation back.
235
+ */
189
236
  async prepare(capture, create) {
190
237
  owner.assertActive();
191
238
  if (!isCaptureCurrent(capture))
192
239
  throw new Error('dsh-tui: Channel binding changed before preparation');
193
240
  const candidate = await create();
194
241
  if (!isCaptureCurrent(capture)) {
195
- dispose(candidate);
242
+ await dispose(candidate);
196
243
  throw new Error('dsh-tui: Channel binding changed during preparation');
197
244
  }
198
245
  pending.set(candidate, capture);
199
246
  // Owner disposal may synchronously occur through embedding hooks while
200
247
  // ownership is registered; verify the pending entry itself as well.
201
248
  if (!isCaptureCurrent(capture) || pending.get(candidate) !== capture) {
202
- disposePending(candidate);
249
+ await disposePending(candidate);
203
250
  throw new Error('dsh-tui: Channel binding changed during preparation');
204
251
  }
205
252
  return candidate;
206
253
  },
207
- /** Dispose an uncommitted candidate exactly once. Live handles are inert. */
208
- async abandon(candidate) { disposePending(candidate); },
254
+ /**
255
+ * Dispose an uncommitted candidate exactly once and WAIT for the close.
256
+ *
257
+ * Waiting is the point: callers use this on the path where they are about
258
+ * to give a cross-process ledger reservation back, and that reservation may
259
+ * only be released once the handle has actually stopped writing. A live
260
+ * handle that this cell never owned is inert here.
261
+ */
262
+ async abandon(candidate) {
263
+ await disposePending(candidate);
264
+ },
265
+ /** A registry may retain an agent while its async handle close drains. */
266
+ async waitForDisposal(sessionId) {
267
+ await closingSessions.get(sessionId);
268
+ },
209
269
  /** Perform one explicit synchronous prepared-handle adoption transaction. */
210
270
  adopt,
211
271
  /** Perform one explicit synchronous already-live-agent adoption transaction. */
@@ -10,7 +10,6 @@ export declare function createManualCompaction(ctx: Context, state: CompactionSt
10
10
  agent(): Agent;
11
11
  withDecisionPending<T>(name: string, pending: Promise<T>): Promise<T>;
12
12
  notify: Notify;
13
- onComplete(): void;
14
13
  }): {
15
14
  compact: () => void;
16
15
  settle: () => Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/compaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAIlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAO9C,KAAK,eAAe,GAAG,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,KAAK,GAAG,SAAS,CAAC,CAAA;AACxE,KAAK,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;AAEpC,mFAAmF;AACnF,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE;IACJ,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,QAAQ,GAAG,KAAK,CAAC,CAAA;IACvD,KAAK,IAAI,KAAK,CAAA;IACd,mBAAmB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IACrE,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,IAAI,IAAI,CAAA;CACnB;mBAuBmB,IAAI;kBAlBC,OAAO,CAAC,IAAI,CAAC;EAwGvC"}
1
+ {"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/compaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAIlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAO9C,KAAK,eAAe,GAAG,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,KAAK,GAAG,SAAS,CAAC,CAAA;AACxE,KAAK,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;AAEpC,mFAAmF;AACnF,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE;IACJ,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,QAAQ,GAAG,KAAK,CAAC,CAAA;IACvD,KAAK,IAAI,KAAK,CAAA;IACd,mBAAmB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IACrE,MAAM,EAAE,MAAM,CAAA;CACf;mBAuBmB,IAAI;kBAlBC,OAAO,CAAC,IAAI,CAAC;EAuGvC"}
@@ -78,8 +78,6 @@ export function createManualCompaction(ctx, state, deps) {
78
78
  if (!isCurrent())
79
79
  return;
80
80
  deps.notify(result ? t('compact-done') : t('compact-nothing'));
81
- if (result)
82
- deps.onComplete();
83
81
  }
84
82
  catch (error) {
85
83
  if (!isCurrent() || cancelled.has(controller))
@@ -19,6 +19,11 @@ export declare function firstStaleComposerToken(text: string, ordered: ReadonlyM
19
19
  export interface ComposerImageLimits {
20
20
  readonly maxImageBytes: number;
21
21
  readonly maxImagesPerMessage: number;
22
+ /** Per-side intrinsic pixel cap mirrored from the upstream store so the
23
+ * ingress gate can resample before staging (issue #938). */
24
+ readonly maxImageDimension: number;
25
+ /** Total-pixel cap ditto. */
26
+ readonly maxImagePixels: number;
22
27
  }
23
28
  /** The composer's staged-image capability store plus its draft-binding rules. */
24
29
  export interface ComposerImages {
@@ -1 +1 @@
1
- {"version":3,"file":"composer-images.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/composer-images.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAIlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EAChB,MAAM,YAAY,CAAA;AAEnB,iEAAiE;AACjE,eAAO,MAAM,oBAAoB,QAAqB,CAAA;AAEtD;6EAC6E;AAC7E,eAAO,MAAM,0BAA0B,QAAsB,CAAA;AAE7D,eAAO,MAAM,sBAAsB,GAAI,WAAW,MAAM,KAAG,MACe,CAAA;AAE1E;;;2EAG2E;AAC3E,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,gBAAgB,EAAE,EACjC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,GAC7B,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAehB;AAED;;4EAE4E;AAC5E,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GACpC,MAAM,GAAG,SAAS,CAKpB;AAOD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;CACrC;AAED,iFAAiF;AACjF,MAAM,WAAW,cAAc;IAC7B;sEACkE;IAClE,qBAAqB,IAAI,MAAM,CAAA;IAC/B;yEACqE;IACrE,UAAU,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACpD;iFAC6E;IAC7E,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;IAC3F,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAA;IACxC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACzC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAA;IACzD,iBAAiB,IAAI,mBAAmB,GAAG,SAAS,CAAA;IACpD;0EACsE;IACtE,iBAAiB,IAAI,IAAI,CAAA;IACzB,6EAA6E;IAC7E,QAAQ,IAAI,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAA;IAChE;4DACwD;IACxD,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,SAAS,gBAAgB,EAAE,CAAA;IACtG,wEAAwE;IACxE,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,SAAS,gBAAgB,EAAE,CAAA;CACnG;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE;IAAE,UAAU,IAAI,MAAM,CAAA;CAAE,GAC7B,cAAc,CAsKhB"}
1
+ {"version":3,"file":"composer-images.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/composer-images.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAMlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAEhB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EAChB,MAAM,YAAY,CAAA;AAEnB,iEAAiE;AACjE,eAAO,MAAM,oBAAoB,QAAqB,CAAA;AAEtD;6EAC6E;AAC7E,eAAO,MAAM,0BAA0B,QAAsB,CAAA;AAE7D,eAAO,MAAM,sBAAsB,GAAI,WAAW,MAAM,KAAG,MACe,CAAA;AAE1E;;;2EAG2E;AAC3E,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,gBAAgB,EAAE,EACjC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,GAC7B,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAehB;AAED;;4EAE4E;AAC5E,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GACpC,MAAM,GAAG,SAAS,CAKpB;AAOD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;IACpC;iEAC6D;IAC7D,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;IAClC,6BAA6B;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAChC;AAED,iFAAiF;AACjF,MAAM,WAAW,cAAc;IAC7B;sEACkE;IAClE,qBAAqB,IAAI,MAAM,CAAA;IAC/B;yEACqE;IACrE,UAAU,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACpD;iFAC6E;IAC7E,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;IAC3F,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAA;IACxC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACzC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAA;IACzD,iBAAiB,IAAI,mBAAmB,GAAG,SAAS,CAAA;IACpD;0EACsE;IACtE,iBAAiB,IAAI,IAAI,CAAA;IACzB,6EAA6E;IAC7E,QAAQ,IAAI,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAA;IAChE;4DACwD;IACxD,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,SAAS,gBAAgB,EAAE,CAAA;IACtG,wEAAwE;IACxE,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,SAAS,gBAAgB,EAAE,CAAA;CACnG;AA0BD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE;IAAE,UAAU,IAAI,MAAM,CAAA;CAAE,GAC7B,cAAc,CAyPhB"}
@@ -1,5 +1,6 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { rememberImagePath, transcriptImageFromAttachment } from '../transcript-images.js';
3
+ import { probeImageSize, adaptImageForAdmission, withinDimensionLimits } from '../../utils/imageResize.js';
3
4
  import { mentionAttachments } from './mentions.js';
4
5
  /** Every visible composer placeholder token, in source order. */
5
6
  export const COMPOSER_IMAGE_TOKEN = /\[Image #\d+\]/gu;
@@ -45,6 +46,24 @@ export function firstStaleComposerToken(text, ordered) {
45
46
  * content-addressed and durable; this map only connects editable
46
47
  * placeholders to them. */
47
48
  const STAGED_IMAGE_LIMIT = 128;
49
+ /** Failure text for a refusal the ingress gate can state before the store:
50
+ * every reason except a missing sharp describes an image the deployment
51
+ * would reject anyway, so the paste is refused with the cause named. */
52
+ function admissionFailure(outcome, context) {
53
+ switch (outcome.reason) {
54
+ case 'sharp-missing':
55
+ return context.probe !== null
56
+ ? `image is ${context.probe.width}×${context.probe.height} (over ${context.limits.maxImageDimension}px) and sharp is unavailable to resample it`
57
+ : `${context.mediaType} is not accepted by this profile and sharp is unavailable to convert it`;
58
+ case 'animated-unsupported':
59
+ return `resizing or converting this animated image cannot keep its frames (${outcome.detail})`;
60
+ default:
61
+ return `image could not be decoded to resize or convert it (${outcome.detail})`;
62
+ }
63
+ }
64
+ /** A store-reported pixel dimension, or the gate's own value when the store
65
+ * reported none (lean attachment fakes in the verify scripts). */
66
+ const positiveOr = (value, fallback) => typeof value === 'number' && value > 0 ? value : fallback;
48
67
  /**
49
68
  * Owns the editable-composer image capabilities: the session epoch, the
50
69
  * capability map, its preview facades and the `[Image #N]` compatibility
@@ -121,16 +140,78 @@ export function createComposerImages(ctx, owner, deps) {
121
140
  if (generation !== stagedImageEpoch) {
122
141
  throw new Error('the session changed while the image was being staged');
123
142
  }
124
- if (!attachments.imageLimits.mediaTypes.includes(input.mediaType)) {
125
- throw new Error(`${input.mediaType} images are not accepted by this profile`);
126
- }
127
143
  if (input.data.byteLength > attachments.imageLimits.maxImageBytes) {
128
144
  throw new Error(`image exceeds this profile's per-image size limit`);
129
145
  }
146
+ // Ingress adaptation (issue #938): the store admits by media type, byte
147
+ // budget and the per-side / total pixel caps, and refuses on all of them
148
+ // when the bytes reach it. Measure and re-encode HERE instead, while the
149
+ // paste can still be explained to the user. Admission is judged against
150
+ // the pair this gate HANDS OVER (the store may normalize further on its
151
+ // own — that step is outside this feature), and both triggers are
152
+ // size-independent:
153
+ // * a source media type the profile does not accept is converted, so a
154
+ // small PNG is never refused while a large one succeeds;
155
+ // * a probe-recognized image inside the caps skips sharp entirely;
156
+ // * an unrecognized format is decoded for measurement (never trusted by
157
+ // byte budget alone — the #432 gap);
158
+ // * with sharp absent the image goes to the store unchanged ONLY while
159
+ // it is still admissible as-is — an accepted format whose size the
160
+ // probe could not prove fits (upstream stays the backstop); a measured
161
+ // oversize, a decode failure, an unaccepted format or a multi-frame
162
+ // image this gate would have to re-encode is reported now instead of
163
+ // becoming a token that dies at save time.
164
+ // The runtime guards keep older attachment fakes (whose imageLimits
165
+ // predate the dimension fields) on the legacy synchronous path.
166
+ const dimensionCap = attachments.imageLimits.maxImageDimension;
167
+ const pixelCap = attachments.imageLimits.maxImagePixels;
168
+ let mediaType = input.mediaType;
169
+ let data = input.data;
170
+ let adapted;
171
+ if (typeof dimensionCap === 'number' && typeof pixelCap === 'number'
172
+ && Number.isFinite(dimensionCap) && Number.isFinite(pixelCap)) {
173
+ const dimensionLimits = { maxImageDimension: dimensionCap, maxImagePixels: pixelCap };
174
+ const probe = probeImageSize(data);
175
+ const sourceAccepted = attachments.imageLimits.mediaTypes.includes(mediaType);
176
+ // Only a probe-measured oversize is *known* to be refused by the store;
177
+ // an unmeasurable image may well be admissible, which is what keeps the
178
+ // sharp-less degradation a degradation rather than a guess.
179
+ const knownOversize = probe !== null && !withinDimensionLimits(probe, dimensionLimits);
180
+ if (!sourceAccepted || probe === null || knownOversize) {
181
+ const outcome = await adaptImageForAdmission(data, mediaType, dimensionLimits, attachments.imageLimits.mediaTypes);
182
+ if (outcome.kind === 'adapted') {
183
+ // outcome.mediaType comes from the accepted list inside the gate, so
184
+ // it is one of the profile's media types at runtime — narrowing,
185
+ // not trusting.
186
+ mediaType = outcome.mediaType;
187
+ data = outcome.data;
188
+ adapted = outcome;
189
+ if (data.byteLength > attachments.imageLimits.maxImageBytes) {
190
+ throw new Error(`image still exceeds this profile's per-image size limit after resampling`);
191
+ }
192
+ }
193
+ else if (outcome.kind === 'unavailable') {
194
+ // Degrade ONLY when the paste is still admissible as-is: an accepted
195
+ // format whose size the probe could not prove fits. Everything else
196
+ // (measured oversize, unaccepted format, decode failure, animation
197
+ // that cannot survive) is a refusal we can state now.
198
+ const degraded = outcome.reason === 'sharp-missing' && sourceAccepted && !knownOversize;
199
+ if (!degraded)
200
+ throw new Error(admissionFailure(outcome, { probe, mediaType, limits: dimensionLimits }));
201
+ }
202
+ }
203
+ }
204
+ // What the store will actually see: an accepted media type, inside the
205
+ // byte cap. A media type can still be unaccepted here only when the
206
+ // adaptation did not run (legacy limits) or could not produce one.
207
+ if (!attachments.imageLimits.mediaTypes.includes(mediaType)) {
208
+ throw new Error(`${mediaType} images are not accepted by this profile`);
209
+ }
130
210
  // The source path is TUI-side display metadata; the store only sees the
131
- // fields its contract names.
211
+ // fields its contract names. mediaType/data may be the adapted pair from
212
+ // the ingress gate above.
132
213
  const { path, ...stored } = input;
133
- const attachment = await attachments.saveImage(stored);
214
+ const attachment = await attachments.saveImage({ ...stored, mediaType, data });
134
215
  // A session change (/new, resume, rewind, model switch, background)
135
216
  // cleared the maps while the save was in flight: the durable object is
136
217
  // harmless, but the OLD session's capability must not reach the new one.
@@ -151,7 +232,23 @@ export function createComposerImages(ctx, owner, deps) {
151
232
  break;
152
233
  deleteStagedImage(oldest);
153
234
  }
154
- return { stageId };
235
+ // The adjustment travels with the capability so the composer can say what
236
+ // happened instead of letting a rewritten image reach the store silently.
237
+ // Its numbers come from the STORE's own report, not from what this gate
238
+ // handed over: the store normalizes further (dimensions, and the media type
239
+ // too), and a notice quoting the gate's numbers would contradict the
240
+ // preview card the user is looking at.
241
+ const adjustment = adapted === undefined ? undefined : {
242
+ sourceMediaType: input.mediaType,
243
+ mediaType: attachment.mediaType,
244
+ width: positiveOr(attachment.width, adapted.width),
245
+ height: positiveOr(attachment.height, adapted.height),
246
+ resized: adapted.resized
247
+ || positiveOr(attachment.width, adapted.width) !== adapted.width
248
+ || positiveOr(attachment.height, adapted.height) !== adapted.height,
249
+ flattened: adapted.flattened,
250
+ };
251
+ return adjustment === undefined ? { stageId } : { stageId, adjustment };
155
252
  };
156
253
  return {
157
254
  stagedImageGeneration() {
@@ -195,6 +292,8 @@ export function createComposerImages(ctx, owner, deps) {
195
292
  return {
196
293
  maxImageBytes: limits.maxImageBytes,
197
294
  maxImagesPerMessage: limits.maxImagesPerMessage,
295
+ maxImageDimension: limits.maxImageDimension,
296
+ maxImagePixels: limits.maxImagePixels,
198
297
  };
199
298
  },
200
299
  clearStagedImages() {
@@ -5,6 +5,14 @@ export declare function createContextBookkeeping(state: () => {
5
5
  tokens: {
6
6
  input: number;
7
7
  };
8
+ /** Last turn's billed token shape; the honest numerator for the
9
+ * context-low warning (input alone misses cached reads/writes, which
10
+ * resumed sessions replay back at full size). */
11
+ lastUsage: {
12
+ input: number;
13
+ cacheRead: number;
14
+ cacheWrite: number;
15
+ } | undefined;
8
16
  pending: PendingMessage[];
9
17
  emit(): void;
10
18
  }, notify: (text: string, options: {
@@ -1 +1 @@
1
- {"version":3,"file":"context-bookkeeping.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/context-bookkeeping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAElE,+EAA+E;AAC/E,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM;IACX,aAAa,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IACzB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,IAAI,IAAI,IAAI,CAAA;CACb,EACD,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,EACnF,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,EAC3C,mBAAmB,EAAE,MAAM;;;;+BAwBK,IAAI;+BArBJ,IAAI;4BAUL;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAA;KAAE,aAAa,cAAc,CAAC,WAAW,CAAC,KAAG,IAAI;gCAK7G,MAAM,KAAG,IAAI;EAQjD"}
1
+ {"version":3,"file":"context-bookkeeping.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/context-bookkeeping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAElE,+EAA+E;AAC/E,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM;IACX,aAAa,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IACzB;;qDAEiD;IACjD,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAA;IAC/E,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,IAAI,IAAI,IAAI,CAAA;CACb,EACD,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,EACnF,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,EAC3C,mBAAmB,EAAE,MAAM;;;;+BAyBK,IAAI;+BAtBJ,IAAI;4BAWL;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAA;KAAE,aAAa,cAAc,CAAC,WAAW,CAAC,KAAG,IAAI;gCAK7G,MAAM,KAAG,IAAI;EAQjD"}
@@ -3,9 +3,10 @@ export function createContextBookkeeping(state, notify, lowContextText, warningB
3
3
  const warning = { value: false };
4
4
  const checkContextWarning = () => {
5
5
  const channel = state();
6
- if (warning.value || channel.contextWindow === undefined)
6
+ if (warning.value || channel.contextWindow === undefined || channel.lastUsage === undefined)
7
7
  return;
8
- const remaining = channel.contextWindow - channel.tokens.input;
8
+ const used = channel.lastUsage.input + channel.lastUsage.cacheRead + channel.lastUsage.cacheWrite;
9
+ const remaining = channel.contextWindow - used;
9
10
  if (remaining >= warningBufferTokens)
10
11
  return;
11
12
  warning.value = true;