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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. package/README.md +171 -124
  2. package/bin/dsh-tui.js +748 -22
  3. package/cordis.patch.yml +38 -10
  4. package/cordis.yml +2 -0
  5. package/lib/types/adapter/channel/session-projection.d.ts.map +1 -1
  6. package/lib/types/adapter/channel/session-projection.js +2 -0
  7. package/lib/types/adapter/channel/ui-policy.d.ts +4 -1
  8. package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
  9. package/lib/types/adapter/channel/ui-policy.js +5 -1
  10. package/lib/types/adapter/kernel/host-facade.d.ts.map +1 -1
  11. package/lib/types/adapter/kernel/host-facade.js +1 -0
  12. package/lib/types/adapter/kernel/replay.d.ts.map +1 -1
  13. package/lib/types/adapter/kernel/replay.js +3 -0
  14. package/lib/types/adapter/kernel/runtime.d.ts.map +1 -1
  15. package/lib/types/adapter/kernel/runtime.js +2 -0
  16. package/lib/types/adapter/kernel/slices/workspace.d.ts.map +1 -1
  17. package/lib/types/adapter/kernel/slices/workspace.js +1 -0
  18. package/lib/types/adapter/ports/channel-ui.d.ts +22 -2
  19. package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
  20. package/lib/types/adapter/ports/channel-view.d.ts +66 -0
  21. package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
  22. package/lib/types/adapter/ports/channel-workspace.d.ts +23 -0
  23. package/lib/types/adapter/ports/channel-workspace.d.ts.map +1 -1
  24. package/lib/types/adapter/ports/workspace.d.ts +2 -0
  25. package/lib/types/adapter/ports/workspace.d.ts.map +1 -1
  26. package/lib/types/adapter/upstream/workspace-driver.d.ts.map +1 -1
  27. package/lib/types/adapter/upstream/workspace-driver.js +10 -2
  28. package/lib/types/commands.d.ts.map +1 -1
  29. package/lib/types/commands.js +1 -0
  30. package/lib/types/components/ContextBarView.d.ts +15 -7
  31. package/lib/types/components/ContextBarView.d.ts.map +1 -1
  32. package/lib/types/components/ContextBarView.js +26 -22
  33. package/lib/types/components/ImagePreviewOverlay.d.ts.map +1 -1
  34. package/lib/types/components/ImagePreviewOverlay.js +11 -5
  35. package/lib/types/components/Markdown.d.ts +11 -1
  36. package/lib/types/components/Markdown.d.ts.map +1 -1
  37. package/lib/types/components/Markdown.js +20 -2
  38. package/lib/types/components/MermaidDiagram.d.ts +13 -0
  39. package/lib/types/components/MermaidDiagram.d.ts.map +1 -0
  40. package/lib/types/components/MermaidDiagram.js +61 -0
  41. package/lib/types/components/MessageList.d.ts +26 -1
  42. package/lib/types/components/MessageList.d.ts.map +1 -1
  43. package/lib/types/components/MessageList.js +72 -7
  44. package/lib/types/components/PageMargin.d.ts +1 -1
  45. package/lib/types/components/PromptInput.d.ts +37 -1
  46. package/lib/types/components/PromptInput.d.ts.map +1 -1
  47. package/lib/types/components/PromptInput.js +243 -28
  48. package/lib/types/components/ScrollbarGutter.d.ts +20 -5
  49. package/lib/types/components/ScrollbarGutter.d.ts.map +1 -1
  50. package/lib/types/components/ScrollbarGutter.js +88 -10
  51. package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
  52. package/lib/types/components/StreamingMarkdown.js +30 -28
  53. package/lib/types/components/Tooltip.d.ts.map +1 -1
  54. package/lib/types/components/Tooltip.js +45 -7
  55. package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
  56. package/lib/types/components/messages/UserPromptMessage.js +5 -7
  57. package/lib/types/components/messages/useImageInspection.d.ts.map +1 -1
  58. package/lib/types/components/messages/useImageInspection.js +19 -9
  59. package/lib/types/components/promptDraftCache.d.ts +102 -0
  60. package/lib/types/components/promptDraftCache.d.ts.map +1 -0
  61. package/lib/types/components/promptDraftCache.js +76 -0
  62. package/lib/types/components/questions/AskUserQuestionPanel.d.ts +17 -1
  63. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  64. package/lib/types/components/questions/AskUserQuestionPanel.js +40 -7
  65. package/lib/types/components/questions/QuestionMinimizedBar.d.ts +12 -0
  66. package/lib/types/components/questions/QuestionMinimizedBar.d.ts.map +1 -0
  67. package/lib/types/components/questions/QuestionMinimizedBar.js +43 -0
  68. package/lib/types/components/sessions/SessionListRow.d.ts +23 -1
  69. package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
  70. package/lib/types/components/sessions/SessionListRow.js +52 -5
  71. package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts +49 -0
  72. package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts.map +1 -0
  73. package/lib/types/components/workspaces/HomeWorkspaceRow.js +50 -0
  74. package/lib/types/dsh-adapter/bundled-presets.d.ts +10 -0
  75. package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -0
  76. package/lib/types/dsh-adapter/bundled-presets.js +80 -0
  77. package/lib/types/dsh-adapter/channel/action-readiness.d.ts +1 -1
  78. package/lib/types/dsh-adapter/channel/action-readiness.d.ts.map +1 -1
  79. package/lib/types/dsh-adapter/channel/action-readiness.js +3 -0
  80. package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts +1 -1
  81. package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts.map +1 -1
  82. package/lib/types/dsh-adapter/channel/agent-view-projection.js +19 -2
  83. package/lib/types/dsh-adapter/channel/background-action.d.ts.map +1 -1
  84. package/lib/types/dsh-adapter/channel/background-action.js +52 -29
  85. package/lib/types/dsh-adapter/channel/binding.d.ts +19 -2
  86. package/lib/types/dsh-adapter/channel/binding.d.ts.map +1 -1
  87. package/lib/types/dsh-adapter/channel/binding.js +78 -18
  88. package/lib/types/dsh-adapter/channel/composer-images.d.ts +5 -0
  89. package/lib/types/dsh-adapter/channel/composer-images.d.ts.map +1 -1
  90. package/lib/types/dsh-adapter/channel/composer-images.js +105 -6
  91. package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts +8 -0
  92. package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts.map +1 -1
  93. package/lib/types/dsh-adapter/channel/context-bookkeeping.js +3 -2
  94. package/lib/types/dsh-adapter/channel/ide-selection.d.ts +58 -0
  95. package/lib/types/dsh-adapter/channel/ide-selection.d.ts.map +1 -0
  96. package/lib/types/dsh-adapter/channel/ide-selection.js +226 -0
  97. package/lib/types/dsh-adapter/channel/input-delivery.d.ts +6 -1
  98. package/lib/types/dsh-adapter/channel/input-delivery.d.ts.map +1 -1
  99. package/lib/types/dsh-adapter/channel/input-delivery.js +9 -1
  100. package/lib/types/dsh-adapter/channel/local-actions.d.ts +3 -19
  101. package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
  102. package/lib/types/dsh-adapter/channel/local-actions.js +2 -1
  103. package/lib/types/dsh-adapter/channel/model-actions.d.ts +4 -1
  104. package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
  105. package/lib/types/dsh-adapter/channel/model-actions.js +82 -6
  106. package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
  107. package/lib/types/dsh-adapter/channel/model-switch.js +49 -31
  108. package/lib/types/dsh-adapter/channel/projection.d.ts +4 -0
  109. package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
  110. package/lib/types/dsh-adapter/channel/projection.js +29 -19
  111. package/lib/types/dsh-adapter/channel/reports.d.ts.map +1 -1
  112. package/lib/types/dsh-adapter/channel/reports.js +4 -12
  113. package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
  114. package/lib/types/dsh-adapter/channel/session-fork.js +26 -2
  115. package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts +3 -0
  116. package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts.map +1 -1
  117. package/lib/types/dsh-adapter/channel/session-live-adoption.js +1 -0
  118. package/lib/types/dsh-adapter/channel/session-metadata.d.ts +10 -0
  119. package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
  120. package/lib/types/dsh-adapter/channel/session-metadata.js +2 -2
  121. package/lib/types/dsh-adapter/channel/session-resume.d.ts +11 -2
  122. package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
  123. package/lib/types/dsh-adapter/channel/session-resume.js +291 -94
  124. package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
  125. package/lib/types/dsh-adapter/channel/session-rewind.js +34 -16
  126. package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
  127. package/lib/types/dsh-adapter/channel/session-tree-actions.js +19 -3
  128. package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
  129. package/lib/types/dsh-adapter/channel/settings-host.js +4 -3
  130. package/lib/types/dsh-adapter/channel/state.d.ts +1 -1
  131. package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
  132. package/lib/types/dsh-adapter/channel/state.js +1 -1
  133. package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
  134. package/lib/types/dsh-adapter/channel/transcript.js +6 -12
  135. package/lib/types/dsh-adapter/channel/types.d.ts +6 -1
  136. package/lib/types/dsh-adapter/channel/types.d.ts.map +1 -1
  137. package/lib/types/dsh-adapter/channel/workspace-actions.d.ts +4 -1
  138. package/lib/types/dsh-adapter/channel/workspace-actions.d.ts.map +1 -1
  139. package/lib/types/dsh-adapter/channel/workspace-actions.js +41 -1
  140. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  141. package/lib/types/dsh-adapter/channel.js +67 -6
  142. package/lib/types/dsh-adapter/compat/messages.d.ts +15 -0
  143. package/lib/types/dsh-adapter/compat/messages.d.ts.map +1 -0
  144. package/lib/types/dsh-adapter/compat/messages.js +15 -0
  145. package/lib/types/dsh-adapter/compat/settings.d.ts +33 -0
  146. package/lib/types/dsh-adapter/compat/settings.d.ts.map +1 -0
  147. package/lib/types/dsh-adapter/compat/settings.js +43 -0
  148. package/lib/types/dsh-adapter/compat/shell.d.ts +25 -0
  149. package/lib/types/dsh-adapter/compat/shell.d.ts.map +1 -0
  150. package/lib/types/dsh-adapter/compat/shell.js +11 -0
  151. package/lib/types/dsh-adapter/contract.d.ts +4 -4
  152. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  153. package/lib/types/dsh-adapter/contract.js +15 -6
  154. package/lib/types/dsh-adapter/ide-channel.d.ts +224 -0
  155. package/lib/types/dsh-adapter/ide-channel.d.ts.map +1 -0
  156. package/lib/types/dsh-adapter/ide-channel.js +556 -0
  157. package/lib/types/dsh-adapter/index.d.ts +18 -3
  158. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  159. package/lib/types/dsh-adapter/index.js +32 -5
  160. package/lib/types/dsh-adapter/plugin.d.ts +5 -2
  161. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  162. package/lib/types/dsh-adapter/plugin.js +173 -42
  163. package/lib/types/dsh-adapter/preset-resolution.d.ts +8 -0
  164. package/lib/types/dsh-adapter/preset-resolution.d.ts.map +1 -1
  165. package/lib/types/dsh-adapter/preset-resolution.js +10 -0
  166. package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts +53 -0
  167. package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts.map +1 -0
  168. package/lib/types/dsh-adapter/session-mount-heartbeat.js +100 -0
  169. package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -1
  170. package/lib/types/dsh-adapter/sessionTree.js +3 -2
  171. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  172. package/lib/types/dsh-adapter/subagents.js +6 -5
  173. package/lib/types/dsh-adapter/workspaces.d.ts +46 -3
  174. package/lib/types/dsh-adapter/workspaces.d.ts.map +1 -1
  175. package/lib/types/dsh-adapter/workspaces.js +116 -0
  176. package/lib/types/effortPrefs.d.ts +15 -3
  177. package/lib/types/effortPrefs.d.ts.map +1 -1
  178. package/lib/types/effortPrefs.js +37 -3
  179. package/lib/types/homePrefs.d.ts +15 -0
  180. package/lib/types/homePrefs.d.ts.map +1 -0
  181. package/lib/types/homePrefs.js +53 -0
  182. package/lib/types/i18n.d.ts +257 -296
  183. package/lib/types/i18n.d.ts.map +1 -1
  184. package/lib/types/i18n.js +78 -84
  185. package/lib/types/ink/colorize.d.ts +10 -0
  186. package/lib/types/ink/colorize.d.ts.map +1 -1
  187. package/lib/types/ink/colorize.js +21 -0
  188. package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
  189. package/lib/types/ink/components/ScrollBox.js +12 -1
  190. package/lib/types/ink/dom.d.ts +1 -0
  191. package/lib/types/ink/dom.d.ts.map +1 -1
  192. package/lib/types/ink/hooks/use-copy-on-select.d.ts +5 -1
  193. package/lib/types/ink/hooks/use-copy-on-select.d.ts.map +1 -1
  194. package/lib/types/ink/hooks/use-copy-on-select.js +15 -1
  195. package/lib/types/ink/ink.d.ts.map +1 -1
  196. package/lib/types/ink/ink.js +36 -1
  197. package/lib/types/ink/output.d.ts +10 -1
  198. package/lib/types/ink/output.d.ts.map +1 -1
  199. package/lib/types/ink/output.js +109 -17
  200. package/lib/types/ink/render-border.d.ts +6 -1
  201. package/lib/types/ink/render-border.d.ts.map +1 -1
  202. package/lib/types/ink/render-border.js +25 -9
  203. package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
  204. package/lib/types/ink/render-node-to-output.js +48 -6
  205. package/lib/types/ink/renderer.d.ts +6 -0
  206. package/lib/types/ink/renderer.d.ts.map +1 -1
  207. package/lib/types/ink/renderer.js +2 -1
  208. package/lib/types/ink/selection.d.ts +60 -0
  209. package/lib/types/ink/selection.d.ts.map +1 -1
  210. package/lib/types/ink/selection.js +129 -0
  211. package/lib/types/ink/sixel-graphics.d.ts +19 -1
  212. package/lib/types/ink/sixel-graphics.d.ts.map +1 -1
  213. package/lib/types/ink/sixel-graphics.js +124 -12
  214. package/lib/types/ink/terminal-image.d.ts +18 -1
  215. package/lib/types/ink/terminal-image.d.ts.map +1 -1
  216. package/lib/types/ink/terminal.d.ts +17 -0
  217. package/lib/types/ink/terminal.d.ts.map +1 -1
  218. package/lib/types/ink/terminal.js +20 -1
  219. package/lib/types/screens/Chat.d.ts +17 -1
  220. package/lib/types/screens/Chat.d.ts.map +1 -1
  221. package/lib/types/screens/Chat.js +284 -72
  222. package/lib/types/screens/SessionSupervisor.d.ts +84 -0
  223. package/lib/types/screens/SessionSupervisor.d.ts.map +1 -0
  224. package/lib/types/screens/SessionSupervisor.js +350 -0
  225. package/lib/types/screens/SessionTree.js +2 -2
  226. package/lib/types/screens/Settings.d.ts.map +1 -1
  227. package/lib/types/screens/Settings.js +32 -9
  228. package/lib/types/screens/StatusLine.d.ts +13 -0
  229. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  230. package/lib/types/screens/StatusLine.js +36 -17
  231. package/lib/types/screens/StatusMetrics.d.ts +79 -22
  232. package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
  233. package/lib/types/screens/StatusMetrics.js +153 -88
  234. package/lib/types/screens/sessionSupervisor/model.d.ts +83 -0
  235. package/lib/types/screens/sessionSupervisor/model.d.ts.map +1 -0
  236. package/lib/types/screens/sessionSupervisor/model.js +69 -0
  237. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts +120 -0
  238. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts.map +1 -0
  239. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.js +593 -0
  240. package/lib/types/sessionMounts.d.ts +272 -0
  241. package/lib/types/sessionMounts.d.ts.map +1 -0
  242. package/lib/types/sessionMounts.js +706 -0
  243. package/lib/types/sessions/format.d.ts.map +1 -1
  244. package/lib/types/sessions/format.js +4 -1
  245. package/lib/types/sessions/resumeFailure.d.ts +38 -0
  246. package/lib/types/sessions/resumeFailure.d.ts.map +1 -0
  247. package/lib/types/sessions/resumeFailure.js +58 -0
  248. package/lib/types/terminal-utils/mermaid.d.ts +44 -0
  249. package/lib/types/terminal-utils/mermaid.d.ts.map +1 -0
  250. package/lib/types/terminal-utils/mermaid.js +83 -0
  251. package/lib/types/tips.d.ts.map +1 -1
  252. package/lib/types/tips.js +175 -19
  253. package/lib/types/tuiDisplayPrefs.d.ts +7 -9
  254. package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
  255. package/lib/types/tuiDisplayPrefs.js +31 -28
  256. package/lib/types/update.d.ts +61 -0
  257. package/lib/types/update.d.ts.map +1 -1
  258. package/lib/types/update.js +194 -0
  259. package/lib/types/utils/imageResize.d.ts +90 -0
  260. package/lib/types/utils/imageResize.d.ts.map +1 -0
  261. package/lib/types/utils/imageResize.js +272 -0
  262. package/lib/types/utils/keymap.d.ts +5 -1
  263. package/lib/types/utils/keymap.d.ts.map +1 -1
  264. package/lib/types/utils/keymap.js +23 -0
  265. package/lib/types/workspaces.d.ts +2 -1
  266. package/lib/types/workspaces.d.ts.map +1 -1
  267. package/lib/types/workspaces.js +1 -1
  268. package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +10 -10
  269. package/package.json +120 -103
  270. package/presets/liangshen/.dsh-tui-managed.json +1 -1
  271. package/presets/liangshen/agent.cordis.yml +15 -0
  272. package/lib/types/screens/AgentView.d.ts +0 -23
  273. package/lib/types/screens/AgentView.d.ts.map +0 -1
  274. package/lib/types/screens/AgentView.js +0 -546
  275. package/lib/types/screens/SessionBrowser.d.ts +0 -42
  276. package/lib/types/screens/SessionBrowser.d.ts.map +0 -1
  277. package/lib/types/screens/SessionBrowser.js +0 -911
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Inbound image adaptation for the composer's staging gate.
3
+ *
4
+ * The upstream attachment store admits images by media type, byte budget,
5
+ * pixel budget and a per-side dimension cap (`maxImageDimension`). Two kinds
6
+ * of paste used to fail with no user-side recourse: one that exceeds the
7
+ * dimension cap, and one whose format the deployment does not accept. This
8
+ * module measures the bytes BEFORE staging and produces an admissible pair
9
+ * (bytes + media type) through sharp — an optionalDependency, absent on
10
+ * minimal installs, which must degrade with a clear error, not a crash.
11
+ *
12
+ * Sizing probe is pure byte inspection (PNG/JPEG/WebP/GIF). Formats the
13
+ * probe cannot identify return null and MUST be forced through an actual
14
+ * decode for measurement — the #432 review gap was letting an
15
+ * "unrecognized but under the byte cap" image through, where a
16
+ * large-resolution small-byte WebP/GIF would sail past the probe and be
17
+ * rejected by upstream afterwards.
18
+ *
19
+ * The single entry point is {@link adaptImageForAdmission}: it decides
20
+ * whether anything has to change (resample, re-encode, or both) and reports
21
+ * exactly what it did, so the caller can tell the user instead of silently
22
+ * rewriting their image.
23
+ */
24
+ const PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
25
+ function probePng(b) {
26
+ // IHDR is required to be the first chunk: width/height are big-endian
27
+ // u32 at fixed offsets 16/20.
28
+ if (b.length < 24)
29
+ return null;
30
+ const width = (b[16] << 24) | (b[17] << 16) | (b[18] << 8) | b[19];
31
+ const height = (b[20] << 24) | (b[21] << 16) | (b[22] << 8) | b[23];
32
+ return width > 0 && height > 0 ? { width, height } : null;
33
+ }
34
+ function probeJpeg(b) {
35
+ // Walk the segment chain to the first SOF marker (C0–CF except C4 DHT,
36
+ // C8 JPG, CC DAC); height/width are big-endian u16 at +5/+7 inside it.
37
+ if (b.length < 4 || b[0] !== 0xff || b[1] !== 0xd8)
38
+ return null;
39
+ let i = 2;
40
+ while (i + 9 < b.length) {
41
+ if (b[i] !== 0xff)
42
+ return null;
43
+ const marker = b[i + 1];
44
+ if (marker === 0xd8 || (marker >= 0xd0 && marker <= 0xd9)) {
45
+ i += 2; // standalone markers carry no length
46
+ continue;
47
+ }
48
+ const segLen = (b[i + 2] << 8) | b[i + 3];
49
+ if (segLen < 2)
50
+ return null;
51
+ const isSof = marker >= 0xc0 && marker <= 0xcf
52
+ && marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc;
53
+ if (isSof) {
54
+ const height = (b[i + 5] << 8) | b[i + 6];
55
+ const width = (b[i + 7] << 8) | b[i + 8];
56
+ return width > 0 && height > 0 ? { width, height } : null;
57
+ }
58
+ i += 2 + segLen;
59
+ }
60
+ return null;
61
+ }
62
+ function probeWebp(b) {
63
+ // RIFF....WEBP followed by VP8X (extended) or VP8 (lossy) or VP8L
64
+ // (lossless). VP8X carries the canvas size as 1-subtracted 24-bit LE;
65
+ // VP8 carries u16 LE after the frame tag; VP8L packs 14-bit
66
+ // 1-subtracted fields after the signature byte.
67
+ if (b.length < 30)
68
+ return null;
69
+ if (b[0] !== 0x52 || b[1] !== 0x49 || b[2] !== 0x46 || b[3] !== 0x46)
70
+ return null;
71
+ if (b[8] !== 0x57 || b[9] !== 0x45 || b[10] !== 0x42 || b[11] !== 0x50)
72
+ return null;
73
+ const fourcc = String.fromCharCode(b[12], b[13], b[14], b[15]);
74
+ if (fourcc === 'VP8X') {
75
+ const width = 1 + ((b[24] | (b[25] << 8) | (b[26] << 16)) & 0xffffff);
76
+ const height = 1 + ((b[27] | (b[28] << 8) | (b[29] << 16)) & 0xffffff);
77
+ return { width, height };
78
+ }
79
+ if (fourcc === 'VP8 ') {
80
+ // Uncompressed chunk header (10 bytes) then keyframe tag (3) then the
81
+ // dimensions: 14-bit width/height in the low bits of each u16, with a
82
+ // 2-bit horizontal/vertical scale in the top bits (RFC 6386 §9.1). Mask
83
+ // them off, or an encoder that sets the scale bits is measured up to
84
+ // 49152px too wide and gets shrunk far past the caps.
85
+ const width = (b[26] | (b[27] << 8)) & 0x3fff;
86
+ const height = (b[28] | (b[29] << 8)) & 0x3fff;
87
+ return width > 0 && height > 0 ? { width, height } : null;
88
+ }
89
+ if (fourcc === 'VP8L') {
90
+ const bits = (b[21] | (b[22] << 8) | (b[23] << 16) | (b[24] << 24)) >>> 0;
91
+ const width = (bits & 0x3fff) + 1;
92
+ const height = ((bits >> 14) & 0x3fff) + 1;
93
+ return { width, height };
94
+ }
95
+ return null;
96
+ }
97
+ function probeGif(b) {
98
+ // Logical screen descriptor: u16 LE at fixed offsets 6/8. A truncated header
99
+ // reads as 0×0 and would then look "inside the caps", so the zero check is
100
+ // what keeps an unmeasurable file on the decode path.
101
+ const width = b[6] | (b[7] << 8);
102
+ const height = b[8] | (b[9] << 8);
103
+ return width > 0 && height > 0 ? { width, height } : null;
104
+ }
105
+ /**
106
+ * Measure intrinsic pixel dimensions from the encoded bytes alone — no
107
+ * decode, no dependencies. Recognizes PNG / JPEG / WebP (VP8X, VP8,
108
+ * VP8L) / GIF; anything else returns null, which callers MUST treat as
109
+ * "unknown, force a real decode" — never as "small enough".
110
+ */
111
+ export function probeImageSize(bytes) {
112
+ if (bytes.length >= 8 && PNG_SIGNATURE.every((v, i) => bytes[i] === v)) {
113
+ return probePng(bytes);
114
+ }
115
+ if (bytes.length >= 2 && bytes[0] === 0xff && bytes[1] === 0xd8) {
116
+ return probeJpeg(bytes);
117
+ }
118
+ if (bytes.length >= 30 && bytes[0] === 0x52 && bytes[8] === 0x57) {
119
+ return probeWebp(bytes);
120
+ }
121
+ if (bytes.length >= 10
122
+ && bytes[0] === 0x47 && bytes[1] === 0x49 && bytes[2] === 0x46 && bytes[3] === 0x38) {
123
+ return probeGif(bytes);
124
+ }
125
+ return null;
126
+ }
127
+ /** Whether a measured image already satisfies the dimension/pixel caps. */
128
+ export function withinDimensionLimits(size, limits) {
129
+ return size.width <= limits.maxImageDimension
130
+ && size.height <= limits.maxImageDimension
131
+ && size.width * size.height <= limits.maxImagePixels;
132
+ }
133
+ /**
134
+ * Target dimensions that bring an oversized image inside `limits` while
135
+ * preserving the aspect ratio: scale down by the largest of the three
136
+ * required factors (per-side, per-side, total-pixels).
137
+ */
138
+ export function downscaleTarget(size, limits) {
139
+ const factors = [
140
+ size.width / limits.maxImageDimension,
141
+ size.height / limits.maxImageDimension,
142
+ Math.sqrt((size.width * size.height) / limits.maxImagePixels),
143
+ ];
144
+ const factor = Math.max(1, ...factors);
145
+ return {
146
+ width: Math.max(1, Math.floor(size.width / factor)),
147
+ height: Math.max(1, Math.floor(size.height / factor)),
148
+ };
149
+ }
150
+ /** Re-encode preference for a source format the profile does not accept.
151
+ * Alpha first: never trade transparency away for bytes. For opaque sources
152
+ * JPEG leads because the per-image BYTE cap — not the pixel cap — is what a
153
+ * lossless re-encode of a large photo most often blows; PNG is the last
154
+ * resort there: lossless, and by far the largest wire form. */
155
+ const ALPHA_TARGETS = ['image/png', 'image/webp', 'image/jpeg'];
156
+ const OPAQUE_TARGETS = ['image/jpeg', 'image/webp', 'image/png'];
157
+ /** Background composited under an alpha channel when the only writable
158
+ * target carries no transparency. White matches the screenshots and document
159
+ * captures this gate mostly sees; sharp's default composite is BLACK, which
160
+ * reads as a broken image on any light UI. */
161
+ const OPAQUE_BACKGROUND = { r: 255, g: 255, b: 255 };
162
+ /**
163
+ * The media type one re-encode should produce.
164
+ *
165
+ * 1. A source format the profile already accepts is kept: re-encoding a format
166
+ * nobody objected to costs quality (JPEG) or losslessness (PNG) for
167
+ * nothing.
168
+ * 2. Otherwise the first accepted entry of the alpha/opaque order above. An
169
+ * empty allowlist falls back to the source format, which the caller's own
170
+ * admission check then refuses with the established message.
171
+ */
172
+ function chooseTargetMediaType(input) {
173
+ const { hasAlpha, sourceMediaType, acceptedMediaTypes } = input;
174
+ if (acceptedMediaTypes.includes(sourceMediaType))
175
+ return sourceMediaType;
176
+ return (hasAlpha ? ALPHA_TARGETS : OPAQUE_TARGETS).find(type => acceptedMediaTypes.includes(type))
177
+ ?? sourceMediaType;
178
+ }
179
+ /** Load sharp lazily so a missing optionalDependency stays a typed outcome. */
180
+ async function loadSharp() {
181
+ try {
182
+ // The ESM build exposes the factory as the namespace's default; some
183
+ // bundlers hand the function itself. Handle both without trusting either.
184
+ const mod = await import('sharp');
185
+ if (typeof mod === 'function')
186
+ return mod;
187
+ if (typeof mod === 'object' && mod !== null) {
188
+ const candidate = mod.default;
189
+ if (typeof candidate === 'function')
190
+ return candidate;
191
+ }
192
+ return null;
193
+ }
194
+ catch {
195
+ return null;
196
+ }
197
+ }
198
+ /**
199
+ * Produce bytes the profile can admit, and report what had to change.
200
+ *
201
+ * Both triggers are size-independent by design: a media type the profile does
202
+ * not accept is converted even when it fits the pixel caps (a small PNG must
203
+ * not be refused while a large one succeeds), and an image the byte probe
204
+ * cannot measure is decoded so its real dimensions decide. The probe still
205
+ * short-circuits the common case — bytes it proves to be inside the caps in an
206
+ * accepted format are returned untouched, with no encoder loaded.
207
+ *
208
+ * Aspect ratio is preserved by {@link downscaleTarget}. An animated source is
209
+ * REFUSED whenever this gate would have to touch its bytes: re-encoding a
210
+ * multi-page image here cannot promise frames, delays and loop survive, and
211
+ * silently returning a still is a data loss the store's own refusal (the
212
+ * behaviour without this gate) never inflicted. Animated images that need no
213
+ * change pass through untouched.
214
+ */
215
+ export async function adaptImageForAdmission(bytes, sourceMediaType, limits, acceptedMediaTypes) {
216
+ const probe = probeImageSize(bytes);
217
+ const sharp = await loadSharp();
218
+ if (sharp === null) {
219
+ return { kind: 'unavailable', reason: 'sharp-missing', detail: 'sharp is not installed in this environment' };
220
+ }
221
+ try {
222
+ // One header read drives every decision below: dimensions for a format
223
+ // the byte probe cannot measure (the #432 gap), alpha support, and the
224
+ // frame count that decides whether this gate may touch the bytes at all.
225
+ const image = sharp(bytes);
226
+ const meta = await image.metadata();
227
+ const measured = probe ?? (meta.width !== undefined && meta.height !== undefined
228
+ ? { width: meta.width, height: meta.height }
229
+ : null);
230
+ if (measured === null) {
231
+ return { kind: 'unavailable', reason: 'decode-failed', detail: 'the image decodes without pixel dimensions' };
232
+ }
233
+ const hasAlpha = meta.hasAlpha === true;
234
+ const resized = !withinDimensionLimits(measured, limits);
235
+ if (!resized && acceptedMediaTypes.includes(sourceMediaType))
236
+ return { kind: 'unchanged' };
237
+ if ((meta.pages ?? 1) > 1) {
238
+ return {
239
+ kind: 'unavailable',
240
+ reason: 'animated-unsupported',
241
+ detail: `${meta.pages} frames`,
242
+ };
243
+ }
244
+ const mediaType = chooseTargetMediaType({ hasAlpha, sourceMediaType, acceptedMediaTypes });
245
+ const target = downscaleTarget(measured, limits);
246
+ const flattened = hasAlpha && mediaType === 'image/jpeg';
247
+ let pipeline = image;
248
+ if (resized)
249
+ pipeline = image.resize(target.width, target.height, { fit: 'inside' });
250
+ if (flattened)
251
+ pipeline = pipeline.flatten({ background: OPAQUE_BACKGROUND });
252
+ const data = await pipeline
253
+ .toFormat(mediaType.replace('image/', ''), mediaType === 'image/jpeg' ? { quality: 90 } : {})
254
+ .toBuffer();
255
+ return {
256
+ kind: 'adapted',
257
+ data,
258
+ mediaType,
259
+ width: target.width,
260
+ height: target.height,
261
+ resized,
262
+ flattened,
263
+ };
264
+ }
265
+ catch (error) {
266
+ return {
267
+ kind: 'unavailable',
268
+ reason: 'decode-failed',
269
+ detail: error instanceof Error ? error.message : String(error),
270
+ };
271
+ }
272
+ }
@@ -66,7 +66,7 @@ export declare function canonicalComboString(raw: string): string;
66
66
  */
67
67
  export declare function comboMatchesStrict(combo: ParsedCombo, input: string, key: ComboKeyFlags): boolean;
68
68
  /** Identifiers of every customizable built-in action. */
69
- export type ShortcutActionId = 'paste' | 'history' | 'editor' | 'transcript' | 'trajectory' | 'dashboard' | 'contextPanel' | 'showAll' | 'redraw' | 'todoFold' | 'expandEditor';
69
+ export type ShortcutActionId = 'paste' | 'history' | 'editor' | 'transcript' | 'trajectory' | 'dashboard' | 'contextPanel' | 'showAll' | 'questionFold' | 'redraw' | 'todoFold' | 'expandEditor';
70
70
  export interface ShortcutActionSpec {
71
71
  readonly id: ShortcutActionId;
72
72
  /** Default combos; the FIRST entry is the canonical display form. */
@@ -92,6 +92,10 @@ export declare function resetKeymapOverrides(): void;
92
92
  export declare function effectiveCombos(action: ShortcutActionId): readonly ParsedCombo[];
93
93
  /** Effective combos as display strings (`ctrl+v, alt+v`). */
94
94
  export declare function effectiveComboString(action: ShortcutActionId): string;
95
+ /** One combo in display capitalization ('ctrl+k' → 'Ctrl+K'). */
96
+ export declare function comboDisplay(raw: string): string;
97
+ /** Effective combos as display strings ('Ctrl+K, Alt+V'). */
98
+ export declare function effectiveComboDisplay(action: ShortcutActionId): string;
95
99
  /** Match a keypress against an action's EFFECTIVE combos (platform alias
96
100
  * included). This is the one call site Chat/PromptInput should need. */
97
101
  export declare function actionMatches(action: ShortcutActionId, input: string, key: ComboKeyFlags): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"keymap.d.ts","sourceRoot":"","sources":["../../../src/utils/keymap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"keymap.d.ts","sourceRoot":"","sources":["../../../src/utils/keymap.ts"],"names":[],"mappings":"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"}
@@ -171,6 +171,7 @@ export const SHORTCUT_ACTIONS = [
171
171
  { id: 'showAll', defaults: ['ctrl+e'] },
172
172
  { id: 'redraw', defaults: ['ctrl+l'] },
173
173
  { id: 'todoFold', defaults: ['ctrl+q'] },
174
+ { id: 'questionFold', defaults: ['ctrl+k'] },
174
175
  { id: 'expandEditor', defaults: ['ctrl+shift+e'] },
175
176
  ];
176
177
  const DEFAULT_COMBO_MAP = new Map(SHORTCUT_ACTIONS.map(action => [action.id, action.defaults.map(parseCombo).filter((combo) => combo !== undefined)]));
@@ -211,6 +212,28 @@ export function effectiveCombos(action) {
211
212
  export function effectiveComboString(action) {
212
213
  return effectiveCombos(action).map(combo => combo.raw).join(', ');
213
214
  }
215
+ /** Modifier token → display label ('ctrl' → 'Ctrl'). */
216
+ const COMBO_MODIFIER_LABELS = {
217
+ ctrl: 'Ctrl',
218
+ shift: 'Shift',
219
+ alt: 'Alt',
220
+ meta: 'Meta',
221
+ super: 'Super',
222
+ };
223
+ /** One combo in display capitalization ('ctrl+k' → 'Ctrl+K'). */
224
+ export function comboDisplay(raw) {
225
+ return raw.split('+').map(token => {
226
+ const lower = token.toLowerCase();
227
+ const mod = COMBO_MODIFIER_LABELS[lower];
228
+ if (mod !== undefined)
229
+ return mod;
230
+ return token.length === 1 ? token.toUpperCase() : token[0].toUpperCase() + token.slice(1);
231
+ }).join('+');
232
+ }
233
+ /** Effective combos as display strings ('Ctrl+K, Alt+V'). */
234
+ export function effectiveComboDisplay(action) {
235
+ return effectiveCombos(action).map(combo => comboDisplay(combo.raw)).join(', ');
236
+ }
214
237
  /** Match a keypress against an action's EFFECTIVE combos (platform alias
215
238
  * included). This is the one call site Chat/PromptInput should need. */
216
239
  export function actionMatches(action, input, key) {
@@ -1,4 +1,5 @@
1
- export { name, WORKSPACE_PROVIDER_TIMEOUT_MS, TuiWorkspaceRuntime, createLocalWorkspaceRuntime, localWorkspaceUri, parseLocalWorkspaceReference, } from './dsh-adapter/workspaces.js';
1
+ export { name, WORKSPACE_PROVIDER_TIMEOUT_MS, TuiWorkspaceRuntime, createLocalWorkspaceRuntime, localWorkspaceUri, parseLocalWorkspaceReference, listRegistryWorkspaces, removeRegistryWorkspace, } from './dsh-adapter/workspaces.js';
2
2
  export type { TuiWorkspaceKind, TuiWorkspaceTarget, TuiWorkspaceChoice, TuiWorkspaceCommandResult, TuiWorkspaceCommand, TuiCommandShell, TuiWorkspaceProvider, } from './dsh-adapter/workspaces.js';
3
+ export type { TuiWorkspaceEntry } from './adapter/ports/channel-workspace.js';
3
4
  export { default } from './dsh-adapter/workspaces.js';
4
5
  //# sourceMappingURL=workspaces.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../src/workspaces.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,IAAI,EACJ,6BAA6B,EAC7B,mBAAmB,EACnB,2BAA2B,EAC3B,iBAAiB,EACjB,4BAA4B,GAC7B,MAAM,6BAA6B,CAAA;AACpC,YAAY,EACV,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,EACnB,eAAe,EACf,oBAAoB,GACrB,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA"}
1
+ {"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../src/workspaces.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,IAAI,EACJ,6BAA6B,EAC7B,mBAAmB,EACnB,2BAA2B,EAC3B,iBAAiB,EACjB,4BAA4B,EAC5B,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,6BAA6B,CAAA;AACpC,YAAY,EACV,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,EACnB,eAAe,EACf,oBAAoB,GACrB,MAAM,6BAA6B,CAAA;AACpC,YAAY,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAA;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA"}
@@ -1,4 +1,4 @@
1
1
  // Re-export shim: the Cordis-backed implementation lives behind the adapter
2
2
  // boundary so UI consumers never import official @deepseek-ai/* packages.
3
- export { name, WORKSPACE_PROVIDER_TIMEOUT_MS, TuiWorkspaceRuntime, createLocalWorkspaceRuntime, localWorkspaceUri, parseLocalWorkspaceReference, } from './dsh-adapter/workspaces.js';
3
+ export { name, WORKSPACE_PROVIDER_TIMEOUT_MS, TuiWorkspaceRuntime, createLocalWorkspaceRuntime, localWorkspaceUri, parseLocalWorkspaceReference, listRegistryWorkspaces, removeRegistryWorkspace, } from './dsh-adapter/workspaces.js';
4
4
  export { default } from './dsh-adapter/workspaces.js';
@@ -43,11 +43,11 @@
43
43
  },
44
44
  "peerDependencies": {
45
45
  "@deepseek-ai/cordis": "^4.0.1",
46
- "@deepseek-ai/dsh-attachment": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1",
47
- "@deepseek-ai/dsh-commands": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1",
48
- "@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1",
49
- "@deepseek-ai/dsh-llm-pi-ai": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1",
50
- "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1",
46
+ "@deepseek-ai/dsh-attachment": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
47
+ "@deepseek-ai/dsh-commands": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
48
+ "@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
49
+ "@deepseek-ai/dsh-llm-pi-ai": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
50
+ "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
51
51
  "@deepseek-ai/schemastery": "^3.18.1"
52
52
  },
53
53
  "peerDependenciesMeta": {
@@ -57,11 +57,11 @@
57
57
  },
58
58
  "devDependencies": {
59
59
  "@deepseek-ai/cordis": "^4.0.1",
60
- "@deepseek-ai/dsh-attachment": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1",
61
- "@deepseek-ai/dsh-commands": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1",
62
- "@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1",
63
- "@deepseek-ai/dsh-llm-pi-ai": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1",
64
- "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1",
60
+ "@deepseek-ai/dsh-attachment": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
61
+ "@deepseek-ai/dsh-commands": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
62
+ "@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
63
+ "@deepseek-ai/dsh-llm-pi-ai": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
64
+ "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
65
65
  "@deepseek-ai/schemastery": "^3.18.1",
66
66
  "@types/node": "^22.0.0",
67
67
  "typescript": "^6.0.3"