@deepseek-harness-tui/dsh-tui 0.8.1 → 0.8.2

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 (240) hide show
  1. package/README.md +22 -13
  2. package/dsh-ecosystem-spec/protocols/profile-definitions.d.ts +13 -0
  3. package/dsh-ecosystem-spec/protocols/profile-definitions.js +59 -0
  4. package/dsh-ecosystem-spec/protocols/tui-channel-http.d.ts +15 -0
  5. package/dsh-ecosystem-spec/protocols/tui-channel-http.js +32 -0
  6. package/dsh-ecosystem-spec/protocols/tui-channel.d.ts +59 -0
  7. package/dsh-ecosystem-spec/protocols/tui-channel.js +166 -0
  8. package/dsh-ecosystem-spec/protocols/tui-contributions.d.ts +42 -0
  9. package/dsh-ecosystem-spec/protocols/tui-contributions.js +143 -0
  10. package/dsh-ecosystem-spec/registry/README.md +14 -0
  11. package/dsh-ecosystem-spec/registry/contracts/scene-v1alpha1.json +13 -0
  12. package/dsh-ecosystem-spec/registry/contracts/settings-section-v1alpha1.json +13 -0
  13. package/dsh-ecosystem-spec/registry/contracts/tui-channel-v1alpha1.json +30 -0
  14. package/dsh-ecosystem-spec/registry/contracts/workspace-provider-v1alpha1.json +6 -0
  15. package/{ecosystem-spec → dsh-ecosystem-spec}/registry/permissions-0.1.json +1 -1
  16. package/dsh-ecosystem-spec/registry/registry-0.15.json +149 -0
  17. package/lib/types/command-trees.d.ts +2 -1
  18. package/lib/types/command-trees.d.ts.map +1 -1
  19. package/lib/types/command-trees.js +1 -1
  20. package/lib/types/components/LoadedContextPanel.d.ts +10 -5
  21. package/lib/types/components/LoadedContextPanel.d.ts.map +1 -1
  22. package/lib/types/components/LoadedContextPanel.js +18 -7
  23. package/lib/types/components/LogoV2.d.ts.map +1 -1
  24. package/lib/types/components/LogoV2.js +16 -7
  25. package/lib/types/components/Markdown.d.ts +13 -1
  26. package/lib/types/components/Markdown.d.ts.map +1 -1
  27. package/lib/types/components/Markdown.js +15 -1
  28. package/lib/types/components/MessageList.d.ts +3 -1
  29. package/lib/types/components/MessageList.d.ts.map +1 -1
  30. package/lib/types/components/MessageList.js +90 -9
  31. package/lib/types/components/PromptInput.d.ts.map +1 -1
  32. package/lib/types/components/PromptInput.js +26 -12
  33. package/lib/types/components/StreamingMarkdown.d.ts +2 -8
  34. package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
  35. package/lib/types/components/StreamingMarkdown.js +51 -9
  36. package/lib/types/components/activityFrames.d.ts +1 -1
  37. package/lib/types/components/activityFrames.d.ts.map +1 -1
  38. package/lib/types/components/activityFrames.js +4 -1
  39. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +5 -1
  40. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  41. package/lib/types/components/messages/AssistantThinkingMessage.js +26 -3
  42. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  43. package/lib/types/components/messages/AssistantToolUseMessage.js +12 -1
  44. package/lib/types/dsh-adapter/channel.d.ts +31 -4
  45. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  46. package/lib/types/dsh-adapter/channel.js +267 -102
  47. package/lib/types/dsh-adapter/childStderr.d.ts.map +1 -1
  48. package/lib/types/dsh-adapter/childStderr.js +10 -0
  49. package/lib/types/dsh-adapter/command-attribution.d.ts.map +1 -1
  50. package/lib/types/dsh-adapter/command-attribution.js +2 -2
  51. package/lib/types/dsh-adapter/command-trees.d.ts +7 -1
  52. package/lib/types/dsh-adapter/command-trees.d.ts.map +1 -1
  53. package/lib/types/dsh-adapter/command-trees.js +70 -20
  54. package/lib/types/dsh-adapter/component-identity.d.ts +5 -0
  55. package/lib/types/dsh-adapter/component-identity.d.ts.map +1 -1
  56. package/lib/types/dsh-adapter/component-identity.js +14 -14
  57. package/lib/types/dsh-adapter/decision-guard.d.ts.map +1 -1
  58. package/lib/types/dsh-adapter/decision-guard.js +10 -16
  59. package/lib/types/dsh-adapter/dialogs.d.ts +2 -3
  60. package/lib/types/dsh-adapter/dialogs.d.ts.map +1 -1
  61. package/lib/types/dsh-adapter/dialogs.js +114 -60
  62. package/lib/types/dsh-adapter/effect-ledger.d.ts +0 -8
  63. package/lib/types/dsh-adapter/effect-ledger.d.ts.map +1 -1
  64. package/lib/types/dsh-adapter/effect-ledger.js +73 -53
  65. package/lib/types/dsh-adapter/extension-events.d.ts.map +1 -1
  66. package/lib/types/dsh-adapter/extension-events.js +39 -1
  67. package/lib/types/dsh-adapter/grants.d.ts.map +1 -1
  68. package/lib/types/dsh-adapter/grants.js +43 -14
  69. package/lib/types/dsh-adapter/host-access.d.ts +37 -0
  70. package/lib/types/dsh-adapter/host-access.d.ts.map +1 -0
  71. package/lib/types/dsh-adapter/host-access.js +652 -0
  72. package/lib/types/dsh-adapter/host-descriptor.d.ts +2 -2
  73. package/lib/types/dsh-adapter/host-descriptor.d.ts.map +1 -1
  74. package/lib/types/dsh-adapter/host-descriptor.js +31 -8
  75. package/lib/types/dsh-adapter/index.d.ts +4 -0
  76. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  77. package/lib/types/dsh-adapter/index.js +1 -0
  78. package/lib/types/dsh-adapter/message-observer.d.ts +10 -15
  79. package/lib/types/dsh-adapter/message-observer.d.ts.map +1 -1
  80. package/lib/types/dsh-adapter/message-observer.js +114 -70
  81. package/lib/types/dsh-adapter/plugin-host.d.ts +39 -6
  82. package/lib/types/dsh-adapter/plugin-host.d.ts.map +1 -1
  83. package/lib/types/dsh-adapter/plugin-host.js +139 -44
  84. package/lib/types/dsh-adapter/plugin-storage.d.ts +0 -5
  85. package/lib/types/dsh-adapter/plugin-storage.d.ts.map +1 -1
  86. package/lib/types/dsh-adapter/plugin-storage.js +48 -36
  87. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  88. package/lib/types/dsh-adapter/plugin.js +80 -16
  89. package/lib/types/dsh-adapter/promptDebug.d.ts +0 -6
  90. package/lib/types/dsh-adapter/promptDebug.d.ts.map +1 -1
  91. package/lib/types/dsh-adapter/promptDebug.js +13 -4
  92. package/lib/types/dsh-adapter/renderers.d.ts +6 -14
  93. package/lib/types/dsh-adapter/renderers.d.ts.map +1 -1
  94. package/lib/types/dsh-adapter/renderers.js +81 -46
  95. package/lib/types/dsh-adapter/scenes.d.ts +8 -4
  96. package/lib/types/dsh-adapter/scenes.d.ts.map +1 -1
  97. package/lib/types/dsh-adapter/scenes.js +136 -37
  98. package/lib/types/dsh-adapter/settings-sections.d.ts +7 -3
  99. package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
  100. package/lib/types/dsh-adapter/settings-sections.js +106 -26
  101. package/lib/types/dsh-adapter/shortcuts.d.ts +8 -10
  102. package/lib/types/dsh-adapter/shortcuts.d.ts.map +1 -1
  103. package/lib/types/dsh-adapter/shortcuts.js +108 -36
  104. package/lib/types/dsh-adapter/status.d.ts +6 -7
  105. package/lib/types/dsh-adapter/status.d.ts.map +1 -1
  106. package/lib/types/dsh-adapter/status.js +88 -22
  107. package/lib/types/dsh-adapter/workspaces.d.ts +16 -5
  108. package/lib/types/dsh-adapter/workspaces.d.ts.map +1 -1
  109. package/lib/types/dsh-adapter/workspaces.js +287 -170
  110. package/lib/types/extensions.d.ts +10 -5
  111. package/lib/types/extensions.d.ts.map +1 -1
  112. package/lib/types/extensions.js +11 -5
  113. package/lib/types/force-production-react.d.ts +1 -0
  114. package/lib/types/force-production-react.d.ts.map +1 -0
  115. package/lib/types/force-production-react.js +12 -0
  116. package/lib/types/i18n.d.ts +14 -6
  117. package/lib/types/i18n.d.ts.map +1 -1
  118. package/lib/types/i18n.js +4 -2
  119. package/lib/types/index.d.ts +1 -0
  120. package/lib/types/index.d.ts.map +1 -1
  121. package/lib/types/index.js +1 -0
  122. package/lib/types/ink/components/App.d.ts +2 -0
  123. package/lib/types/ink/components/App.d.ts.map +1 -1
  124. package/lib/types/ink/components/App.js +4 -0
  125. package/lib/types/ink/ink.d.ts +20 -3
  126. package/lib/types/ink/ink.d.ts.map +1 -1
  127. package/lib/types/ink/ink.js +57 -5
  128. package/lib/types/ink/log-update.d.ts.map +1 -1
  129. package/lib/types/ink/log-update.js +128 -9
  130. package/lib/types/ink/output.d.ts +28 -2
  131. package/lib/types/ink/output.d.ts.map +1 -1
  132. package/lib/types/ink/output.js +158 -12
  133. package/lib/types/ink/screen.d.ts +39 -0
  134. package/lib/types/ink/screen.d.ts.map +1 -1
  135. package/lib/types/ink/screen.js +117 -0
  136. package/lib/types/ink/terminal.d.ts.map +1 -1
  137. package/lib/types/ink/terminal.js +10 -2
  138. package/lib/types/ink/wrapAnsi.d.ts +1 -1
  139. package/lib/types/ink/wrapAnsi.d.ts.map +1 -1
  140. package/lib/types/ink/wrapAnsi.js +29 -2
  141. package/lib/types/plugin-host.d.ts +13 -11
  142. package/lib/types/plugin-host.d.ts.map +1 -1
  143. package/lib/types/plugin-host.js +16 -16
  144. package/lib/types/plugin-spec/registry.d.ts +2 -2
  145. package/lib/types/plugin-spec/registry.d.ts.map +1 -1
  146. package/lib/types/plugin-spec/registry.js +113 -18
  147. package/lib/types/plugin-spec/tui-extension.d.ts.map +1 -1
  148. package/lib/types/plugin-spec/tui-extension.js +2 -0
  149. package/lib/types/plugin-spec/validate.d.ts.map +1 -1
  150. package/lib/types/plugin-spec/validate.js +20 -1
  151. package/lib/types/scenes.d.ts +2 -1
  152. package/lib/types/scenes.d.ts.map +1 -1
  153. package/lib/types/scenes.js +1 -1
  154. package/lib/types/screens/Chat.d.ts +3 -3
  155. package/lib/types/screens/Chat.d.ts.map +1 -1
  156. package/lib/types/screens/Chat.js +38 -17
  157. package/lib/types/screens/SessionBrowser.d.ts.map +1 -1
  158. package/lib/types/screens/SessionBrowser.js +10 -3
  159. package/lib/types/sessions/view.d.ts +3 -2
  160. package/lib/types/sessions/view.d.ts.map +1 -1
  161. package/lib/types/sessions/view.js +18 -0
  162. package/lib/types/settings-sections.d.ts +2 -1
  163. package/lib/types/settings-sections.d.ts.map +1 -1
  164. package/lib/types/settings-sections.js +1 -1
  165. package/lib/types/utils/execFileNoThrow.d.ts.map +1 -1
  166. package/lib/types/utils/execFileNoThrow.js +3 -0
  167. package/lib/types/workspaces.d.ts +2 -1
  168. package/lib/types/workspaces.d.ts.map +1 -1
  169. package/lib/types/workspaces.js +1 -1
  170. package/node_modules/@dsh-std/command/CHANGELOG.md +8 -0
  171. package/node_modules/@dsh-std/command/package.json +1 -1
  172. package/node_modules/@dsh-std/connection/CHANGELOG.md +8 -0
  173. package/node_modules/@dsh-std/connection/lib/memory.d.ts +1 -1
  174. package/node_modules/@dsh-std/connection/lib/memory.d.ts.map +1 -1
  175. package/node_modules/@dsh-std/connection/lib/memory.js +1 -0
  176. package/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  177. package/node_modules/@dsh-std/connection/package.json +1 -1
  178. package/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
  179. package/node_modules/@dsh-std/core/package.json +1 -1
  180. package/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -0
  181. package/node_modules/@dsh-std/manifest/package.json +1 -1
  182. package/node_modules/@dsh-std/messages/CHANGELOG.md +8 -0
  183. package/node_modules/@dsh-std/messages/package.json +1 -1
  184. package/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -0
  185. package/node_modules/@dsh-std/presentation/README.md +2 -1
  186. package/node_modules/@dsh-std/presentation/README.zh.md +2 -1
  187. package/node_modules/@dsh-std/presentation/lib/callback.d.ts +2 -0
  188. package/node_modules/@dsh-std/presentation/lib/callback.js +179 -0
  189. package/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -0
  190. package/node_modules/@dsh-std/presentation/lib/index.d.ts +44 -1
  191. package/node_modules/@dsh-std/presentation/lib/index.d.ts.map +1 -1
  192. package/node_modules/@dsh-std/presentation/lib/index.js +6 -3
  193. package/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
  194. package/node_modules/@dsh-std/presentation/package.json +7 -3
  195. package/node_modules/@dsh-std/storage/CHANGELOG.md +8 -0
  196. package/node_modules/@dsh-std/storage/package.json +1 -1
  197. package/package.json +10 -5
  198. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/CHANGELOG.md +8 -0
  199. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.d.ts +1 -1
  200. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.d.ts.map +1 -1
  201. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js +1 -0
  202. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  203. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/package.json +1 -1
  204. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
  205. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/package.json +1 -1
  206. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -0
  207. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/package.json +1 -1
  208. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -0
  209. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.md +2 -1
  210. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.zh.md +2 -1
  211. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.d.ts +2 -0
  212. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js +179 -0
  213. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -0
  214. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.d.ts +44 -1
  215. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.d.ts.map +1 -1
  216. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js +6 -3
  217. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
  218. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/package.json +7 -3
  219. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
  220. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/package.json +1 -1
  221. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
  222. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/package.json +1 -1
  223. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
  224. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/package.json +1 -1
  225. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/CHANGELOG.md +8 -0
  226. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.d.ts +1 -1
  227. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.d.ts.map +1 -1
  228. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js +1 -0
  229. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  230. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/package.json +1 -1
  231. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
  232. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/package.json +1 -1
  233. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
  234. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/package.json +1 -1
  235. package/ecosystem-spec/registry/registry-0.15.json +0 -57
  236. /package/{ecosystem-spec → dsh-ecosystem-spec}/registry/contracts/decision-events-v1alpha1.json +0 -0
  237. /package/{ecosystem-spec → dsh-ecosystem-spec}/registry/host-descriptor.tui.example.json +0 -0
  238. /package/{ecosystem-spec → dsh-ecosystem-spec}/schemas/conformance-claim.schema.json +0 -0
  239. /package/{ecosystem-spec → dsh-ecosystem-spec}/schemas/effect-ledger-record.schema.json +0 -0
  240. /package/{ecosystem-spec → dsh-ecosystem-spec}/schemas/host-descriptor.schema.json +0 -0
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "tui.channel",
3
+ "version": "v1alpha1",
4
+ "coordinates": {
5
+ "apiVersion": "tui.dsh/v1alpha1",
6
+ "kind": "Channel"
7
+ },
8
+ "kind": "capability",
9
+ "caller": "a negotiated TUI endpoint",
10
+ "permissions": [],
11
+ "operations": [
12
+ {"name": "open", "input": "workspace/session selector", "output": "complete channel snapshot"},
13
+ {"name": "subscribe", "input": "channel id and last observed version", "output": "snapshot progress stream"},
14
+ {"name": "invoke", "input": "channel method and JSON arguments", "output": "method progress, JSON result and optional snapshot"},
15
+ {"name": "close", "input": "channel id", "output": "closed acknowledgement"}
16
+ ],
17
+ "wireRevision": 6,
18
+ "features": [
19
+ "commands", "credentials", "diagnostics", "files", "models", "modes",
20
+ "presets", "presentation", "provider-setup", "scenes", "session-history", "session-input",
21
+ "session-lifecycle", "session-state", "settings", "skills", "subagents",
22
+ "trace", "workspaces"
23
+ ],
24
+ "errors": ["CHANNEL_NOT_FOUND", "FEATURE_UNAVAILABLE", "INVALID_ARGUMENT", "PERMISSION_DENIED", "REVISION_MISMATCH", "PROVIDER_FAILURE"],
25
+ "concurrency": "state mutations are serialized per channel; independent read operations may run concurrently",
26
+ "timeout": "the caller supplies connection invocation cancellation; subscriptions remain open until cancelled or closed",
27
+ "cleanup": "connection close or facet deactivate releases subscriptions, uploads and channel attachments",
28
+ "privacyClass": "sensitive",
29
+ "securityBoundary": false
30
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "status": "superseded",
3
+ "coordinates": {"apiVersion": "workspace.dsh/v1alpha1", "kind": "WorkspaceProvider"},
4
+ "package": "@dsh-std/workspace",
5
+ "proposal": "vendor/dsh-std/docs/proposals/workspace.zh.md"
6
+ }
@@ -5,7 +5,7 @@
5
5
  {"name":"storage.local.write","default":"deny","revocable":true,"scope":"plugin namespace"},
6
6
  {"name":"commands.invoke","default":"allow","revocable":true,"scope":"declared command id","rationale":"调用由宿主或用户通过一次 invocation 主动发起,不同于数据访问类权限——插件无法仅凭此权限被动读取任何数据,故默认允许;撤销只关闭该 command ID 的调用入口"},
7
7
  {"name":"messages.observe.read","default":"deny","revocable":true,"scope":"message observation scope"},
8
- {"name":"session.input.intercept","default":"deny","revocable":true,"scope":"decision event subscription","rationale":"拦截类订阅(RFC 0005 D-7):能否决/改写用户输入,严格强于观察,故默认拒绝;TUI 实验实现见 tui.dsh/v1alpha1#DecisionEvents"},
8
+ {"name":"session.input.intercept","default":"deny","revocable":true,"scope":"decision event subscription","rationale":"拦截类订阅(RFC 0005 D-7):能否决/改写用户输入,严格强于观察,故默认拒绝;TUI 实验实现见 tui.dsh.decision-events"},
9
9
  {"name":"session.rewind.intercept","default":"deny","revocable":true,"scope":"decision event subscription","rationale":"同 session.input.intercept——可否决会话回退或注入回退模式"},
10
10
  {"name":"session.switch.intercept","default":"deny","revocable":true,"scope":"decision event subscription","rationale":"同 session.input.intercept——可否决会话切换"},
11
11
  {"name":"session.compact.intercept","default":"deny","revocable":true,"scope":"decision event subscription","rationale":"同 session.input.intercept——可否决手动压缩"}
@@ -0,0 +1,149 @@
1
+ {
2
+ "profileVersion": "tui-admission/0.15",
3
+ "std": {
4
+ "repository": "https://github.com/Yan-Zero/dsh-std",
5
+ "submodule": "vendor/dsh-std",
6
+ "manifestVersion": "0.15"
7
+ },
8
+ "imports": [
9
+ {
10
+ "name": "commands",
11
+ "coordinates": {
12
+ "apiVersion": "commands.dsh/v1alpha1",
13
+ "kind": "Command"
14
+ },
15
+ "package": "@dsh-std/command",
16
+ "kind": "capability",
17
+ "permissions": [
18
+ "commands.invoke"
19
+ ]
20
+ },
21
+ {
22
+ "name": "storage.local",
23
+ "coordinates": {
24
+ "apiVersion": "storage.dsh/v1alpha1",
25
+ "kind": "LocalStorage"
26
+ },
27
+ "package": "@dsh-std/storage",
28
+ "kind": "capability",
29
+ "permissions": [
30
+ "storage.local.read",
31
+ "storage.local.write"
32
+ ]
33
+ },
34
+ {
35
+ "name": "messages.observe",
36
+ "coordinates": {
37
+ "apiVersion": "messages.dsh/v1alpha1",
38
+ "kind": "MessageObserver"
39
+ },
40
+ "package": "@dsh-std/messages",
41
+ "kind": "event",
42
+ "permissions": [
43
+ "messages.observe.read"
44
+ ],
45
+ "eventEnvelope": "@dsh-std/messages/schema/message-observer-envelope-0.15.json"
46
+ },
47
+ {
48
+ "name": "presentation.open-external",
49
+ "coordinates": {
50
+ "apiVersion": "presentation.dsh/v1alpha1",
51
+ "kind": "OpenExternal"
52
+ },
53
+ "package": "@dsh-std/presentation",
54
+ "kind": "capability",
55
+ "permissions": []
56
+ },
57
+ {
58
+ "name": "presentation.user-interaction",
59
+ "coordinates": {
60
+ "apiVersion": "presentation.dsh/v1alpha1",
61
+ "kind": "UserInteraction"
62
+ },
63
+ "package": "@dsh-std/presentation",
64
+ "kind": "capability",
65
+ "permissions": []
66
+ },
67
+ {
68
+ "name": "presentation.external-redirect",
69
+ "coordinates": {
70
+ "apiVersion": "presentation.dsh/v1alpha1",
71
+ "kind": "ExternalRedirect"
72
+ },
73
+ "package": "@dsh-std/presentation",
74
+ "kind": "capability",
75
+ "permissions": []
76
+ }
77
+ ],
78
+ "definitions": [
79
+ {
80
+ "name": "tui.decision-events",
81
+ "authority": "dsh-tui",
82
+ "coordinates": {
83
+ "apiVersion": "tui.dsh/v1alpha1",
84
+ "kind": "DecisionEvents"
85
+ },
86
+ "kind": "capability",
87
+ "profile": "registry/contracts/decision-events-v1alpha1.json",
88
+ "profileHash": "sha256:56440dde1b00c210b22761a0cba139ce0a20207330567777cebe1e48b494ceb0",
89
+ "permissions": [
90
+ "session.input.intercept",
91
+ "session.rewind.intercept",
92
+ "session.switch.intercept",
93
+ "session.compact.intercept"
94
+ ]
95
+ },
96
+ {
97
+ "name": "tui.channel",
98
+ "authority": "dsh-tui",
99
+ "coordinates": {
100
+ "apiVersion": "tui.dsh/v1alpha1",
101
+ "kind": "Channel"
102
+ },
103
+ "kind": "capability",
104
+ "profile": "registry/contracts/tui-channel-v1alpha1.json",
105
+ "profileHash": "sha256:2d0668656d999a8cacd363cd3c76207f9392118be8a83e6dd5f81b54ae063fe6",
106
+ "permissions": []
107
+ }
108
+ ],
109
+ "extensions": [
110
+ {
111
+ "name": "workspace.provider",
112
+ "authority": "dsh-std",
113
+ "coordinates": {
114
+ "apiVersion": "workspace.dsh/v1alpha1",
115
+ "kind": "WorkspaceProvider"
116
+ },
117
+ "kind": "extension",
118
+ "package": "@dsh-std/workspace",
119
+ "permissions": []
120
+ },
121
+ {
122
+ "name": "tui.settings-section",
123
+ "authority": "dsh-tui",
124
+ "coordinates": {
125
+ "apiVersion": "tui.dsh/v1alpha1",
126
+ "kind": "SettingsSection"
127
+ },
128
+ "kind": "extension",
129
+ "profile": "registry/contracts/settings-section-v1alpha1.json",
130
+ "profileHash": "sha256:685b0f17fe489f458e9b799811f61c42b858330584e95ecb97e7216b5be100ac",
131
+ "permissions": []
132
+ },
133
+ {
134
+ "name": "tui.scene",
135
+ "authority": "dsh-tui",
136
+ "coordinates": {
137
+ "apiVersion": "tui.dsh/v1alpha1",
138
+ "kind": "Scene"
139
+ },
140
+ "kind": "extension",
141
+ "profile": "registry/contracts/scene-v1alpha1.json",
142
+ "profileHash": "sha256:69ce3ae26d60dea2ed170376db8a1fb5860c94bd192c62681423c1d848ec2b26",
143
+ "permissions": []
144
+ }
145
+ ],
146
+ "facetApiVersions": [
147
+ "v1alpha1"
148
+ ]
149
+ }
@@ -1,3 +1,4 @@
1
- export * from './dsh-adapter/command-trees.js';
1
+ export { name, TuiCommandTreeRuntime } from './dsh-adapter/command-trees.js';
2
+ export type { TuiCommandTreeProvider } from './dsh-adapter/command-trees.js';
2
3
  export { default } from './dsh-adapter/command-trees.js';
3
4
  //# sourceMappingURL=command-trees.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"command-trees.d.ts","sourceRoot":"","sources":["../../src/command-trees.ts"],"names":[],"mappings":"AAEA,cAAc,gCAAgC,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA"}
1
+ {"version":3,"file":"command-trees.d.ts","sourceRoot":"","sources":["../../src/command-trees.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAA;AAC5E,YAAY,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,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 * from './dsh-adapter/command-trees.js';
3
+ export { name, TuiCommandTreeRuntime } from './dsh-adapter/command-trees.js';
4
4
  export { default } from './dsh-adapter/command-trees.js';
@@ -1,15 +1,20 @@
1
1
  import React from 'react';
2
2
  import type { LoadedContext } from '../dsh-adapter/channel.js';
3
3
  /**
4
- * The startup context summary: a one-line inventory of what a
4
+ * The startup context panel: a collapsed one-line summary of what a
5
5
  * fresh conversation will load for the current agent (system prompt
6
6
  * sections, workspace instruction files, dynamic context, skill catalog,
7
- * tools). `/context` renders the existing details as a local report; the
8
- * summary itself disappears once the transcript has rows. Renders nothing
9
- * for an empty snapshot.
7
+ * tools), expandable to the grouped details with Ctrl+P. The `/context`
8
+ * local command still prints the same details as a transcript report.
9
+ * The panel renders only while the transcript is still empty — the first
10
+ * message's rows take over. Renders nothing for an empty snapshot.
10
11
  * @param context - the channel's loaded-context snapshot.
12
+ * @param open - whether the grouped details are shown.
13
+ * @param onToggle - flips `open`; fired by the Ctrl+P keybinding.
11
14
  */
12
- export declare function LoadedContextPanel({ context }: {
15
+ export declare function LoadedContextPanel({ context, open, onToggle, }: {
13
16
  context: LoadedContext;
17
+ open: boolean;
18
+ onToggle: () => void;
14
19
  }): React.ReactNode;
15
20
  //# sourceMappingURL=LoadedContextPanel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LoadedContextPanel.d.ts","sourceRoot":"","sources":["../../../src/components/LoadedContextPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAG9D;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,aAAa,CAAA;CAAE,GAAG,KAAK,CAAC,SAAS,CAW3F"}
1
+ {"version":3,"file":"LoadedContextPanel.d.ts","sourceRoot":"","sources":["../../../src/components/LoadedContextPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,aAAa,EAAsB,MAAM,2BAA2B,CAAA;AA+BlF;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,OAAO,EACP,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,aAAa,CAAA;IACtB,IAAI,EAAE,OAAO,CAAA;IACb,QAAQ,EAAE,MAAM,IAAI,CAAA;CACrB,GAAG,KAAK,CAAC,SAAS,CAoElB"}
@@ -1,19 +1,30 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { t } from '../i18n.js';
3
3
  import { Box, Text } from '../ui.js';
4
- import { summarizeLoadedContext } from '../utils/loaded-context.js';
4
+ import { summarizeLoadedContext, truncateContextText } from '../utils/loaded-context.js';
5
+ /** One named entry (section or dynamic context) with its full text. */
6
+ function Entry({ entry }) {
7
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, dimColor: true, children: entry.name }), _jsx(Text, { dimColor: true, wrap: "wrap", children: truncateContextText(entry.text) })] }));
8
+ }
9
+ /** A titled group of rows inside the expanded panel. */
10
+ function Group({ title, children }) {
11
+ return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { bold: true, color: "subtle", children: title }), _jsx(Box, { flexDirection: "column", paddingLeft: 2, children: children })] }));
12
+ }
5
13
  /**
6
- * The startup context summary: a one-line inventory of what a
14
+ * The startup context panel: a collapsed one-line summary of what a
7
15
  * fresh conversation will load for the current agent (system prompt
8
16
  * sections, workspace instruction files, dynamic context, skill catalog,
9
- * tools). `/context` renders the existing details as a local report; the
10
- * summary itself disappears once the transcript has rows. Renders nothing
11
- * for an empty snapshot.
17
+ * tools), expandable to the grouped details with Ctrl+P. The `/context`
18
+ * local command still prints the same details as a transcript report.
19
+ * The panel renders only while the transcript is still empty — the first
20
+ * message's rows take over. Renders nothing for an empty snapshot.
12
21
  * @param context - the channel's loaded-context snapshot.
22
+ * @param open - whether the grouped details are shown.
23
+ * @param onToggle - flips `open`; fired by the Ctrl+P keybinding.
13
24
  */
14
- export function LoadedContextPanel({ context }) {
25
+ export function LoadedContextPanel({ context, open, onToggle, }) {
15
26
  const summary = summarizeLoadedContext(context);
16
27
  if (summary === '')
17
28
  return null;
18
- return (_jsx(Box, { marginTop: 1, marginBottom: 1, paddingX: 1, children: _jsxs(Text, { wrap: "truncate", children: [t('context-loaded'), " \u00B7 ", summary, _jsx(Text, { dimColor: true, children: " \u00B7 /context" })] }) }));
29
+ return (_jsxs(Box, { flexDirection: "column", marginTop: 1, marginBottom: 1, children: [_jsx(Box, { paddingX: 1, backgroundColor: open ? 'userMessageBackground' : undefined, children: _jsxs(Text, { bold: open, wrap: "truncate", children: [open ? '▼' : '▶', " ", _jsxs(Text, { dimColor: true, children: ["\uFF08Ctrl+P", open ? t('context-panel-collapse') : t('context-panel-expand'), "\uFF09"] }), " ", t('context-loaded'), " \u00B7 ", summary] }) }), open && (_jsxs(Box, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [context.sections.length > 0 && (_jsx(Group, { title: t('context-panel-sections', { n: context.sections.length }), children: context.sections.map(section => (_jsx(Entry, { entry: section }, section.name))) })), context.files.length > 0 && (_jsx(Group, { title: t('context-panel-files', { n: context.files.length }), children: context.files.map(file => (_jsx(Text, { dimColor: true, children: file.displayPath }, file.displayPath))) })), context.contexts.length > 0 && (_jsx(Group, { title: t('context-panel-runtime', { n: context.contexts.length }), children: context.contexts.map(entry => (_jsx(Entry, { entry: entry }, entry.name))) })), context.skills.length > 0 && (_jsx(Group, { title: t('context-panel-skills', { n: context.skills.length }), children: context.skills.map(skill => (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, dimColor: true, children: skill.name }), _jsx(Text, { dimColor: true, wrap: "wrap", children: skill.description })] }, skill.name))) })), context.tools.length > 0 && (_jsx(Group, { title: t('context-panel-tools', { n: context.tools.length }), children: context.tools.map(tool => (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, dimColor: true, children: tool.name }), _jsx(Text, { dimColor: true, wrap: "wrap", children: truncateContextText(tool.description, 160) })] }, tool.name))) })), _jsx(Text, { dimColor: true, children: "\u00B7 /context" })] }))] }));
19
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"LogoV2.d.ts","sourceRoot":"","sources":["../../../src/components/LogoV2.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAoDzB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAK,EACL,MAAM,EACN,GAAG,EACH,SAAiB,GAClB,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,GAAG,EAAE,MAAM,CAAA;IACX,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,GAAG,KAAK,CAAC,SAAS,CA+ElB"}
1
+ {"version":3,"file":"LogoV2.d.ts","sourceRoot":"","sources":["../../../src/components/LogoV2.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAwDzB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAK,EACL,MAAM,EACN,GAAG,EACH,SAAiB,GAClB,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,GAAG,EAAE,MAAM,CAAA;IACX,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,GAAG,KAAK,CAAC,SAAS,CAqFlB"}
@@ -9,6 +9,7 @@ import { getTheme } from '../theme.js';
9
9
  import { useTheme } from './design-system/ThemeProvider.js';
10
10
  import { parseRGB } from './Spinner/spinnerUtils.js';
11
11
  import { renderBigText } from './bigfont.js';
12
+ import { stringWidth } from '../ink/stringWidth.js';
12
13
  import { BRAND, FLASH, ICE, PALE, sweep } from './shimmer.js';
13
14
  import { STANDARD_FRAME_INDEX, WhaleArt } from './Whale.js';
14
15
  import { OPENING_SEQUENCE } from './whaleFrames.js';
@@ -35,13 +36,16 @@ const WHALE_MIN_COLUMNS = 64;
35
36
  */
36
37
  const FULL_WHALE_WIDTH = 40;
37
38
  /**
38
- * Leading spaces that center the welcome line under the drawn whale: the
39
- * art's bounding box spans sprite columns 3..34 (center 18.5) of the
40
- * 40-wide box, and the tagline measure 14
41
- * columns — 18.5 − 7 = 11.5 → 12. Centered on the full 40-column box
42
- * instead would need 13, which reads one column right of the whale body.
39
+ * Center of the whale art's bounding box: sprite columns 3..34 (center
40
+ * 18.5) of the 40-wide box. The welcome tagline is indented so its own
41
+ * center lands on this column — for the 14-column Chinese tagline that is
42
+ * 18.5 − 7 = 11.5 → 12 leading spaces. (Centering on the full 40-column
43
+ * box would need 13, which reads one column right of the whale body.)
44
+ * The pad is recomputed from the rendered tagline's display width so
45
+ * longer locales — e.g. the 21-column English tagline → 8 — stay
46
+ * centered under the art too.
43
47
  */
44
- const WELCOME_PAD = 12;
48
+ const WHALE_CENTER = 18.5;
45
49
  /** `max` → `Max` (effort levels arrive lower-case from the adapter). */
46
50
  function capitalize(text) {
47
51
  return text.length === 0 ? text : text[0].toUpperCase() + text.slice(1);
@@ -89,7 +93,12 @@ export function LogoV2({ model, effort, cwd, skipIntro = false, }) {
89
93
  // Frozen clock for the settled header: t=0 parks every sweep highlight
90
94
  // off-screen, leaving the static gradient behind.
91
95
  const t = settled ? 0 : time;
96
+ const tagline = tr('logo-tagline');
97
+ // Indent that centers the tagline under the whale art's bounding box.
98
+ const welcomePad = showWhale
99
+ ? Math.max(0, Math.round(WHALE_CENTER - stringWidth(tagline) / 2))
100
+ : 2;
92
101
  const bigDeepSeek = renderBigText('DEEPSEEK', t, wordmarkRGB, taglineRGB, FLASH, 60);
93
102
  const bigHarness = renderBigText('HARNESS', t, taglineRGB, PALE, FLASH, 60);
94
- return (_jsxs(Box, { ref: ref, flexDirection: "column", marginTop: 1, children: [_jsxs(Box, { flexDirection: "row", gap: 2, width: "100%", alignItems: "center", children: [showWhale && _jsx(WhaleArt, { frameIndex: frameIndex, width: FULL_WHALE_WIDTH }), _jsxs(Box, { flexDirection: "column", flexShrink: 1, children: [_jsxs(Text, { wrap: "truncate-end", children: [sweep('✦ dsh-TUI', t, wordmarkRGB, wordmarkShimmerRGB, 60), _jsx(Text, { dimColor: true, children: ' v' + VERSION })] }), bigDeepSeek.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row }, `ds-${index}`))), bigHarness.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row }, `h-${index}`))), _jsxs(Text, { wrap: "truncate-end", children: [model, effort !== undefined && _jsx(Text, { dimColor: true, children: ' · ' + capitalize(effort) + ' effort' })] }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: cwd }), _jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { dimColor: true, children: tr('logo-tip-prefix') }), "/model", _jsxs(Text, { dimColor: true, children: [" ", tr('logo-tip-model'), " \u00B7 "] }), "/help", _jsxs(Text, { dimColor: true, children: [" ", tr('logo-tip-help'), " \u00B7 "] }), "Tab", _jsxs(Text, { dimColor: true, children: [" ", tr('logo-tip-tab')] })] })] })] }), _jsx(Box, { marginTop: 1, paddingLeft: showWhale ? WELCOME_PAD : 2, children: _jsx(Text, { children: sweep(tr('logo-tagline'), t, taglineRGB, FLASH, 60) }) })] }));
103
+ return (_jsxs(Box, { ref: ref, flexDirection: "column", marginTop: 1, children: [_jsxs(Box, { flexDirection: "row", gap: 2, width: "100%", alignItems: "center", children: [showWhale && _jsx(WhaleArt, { frameIndex: frameIndex, width: FULL_WHALE_WIDTH }), _jsxs(Box, { flexDirection: "column", flexShrink: 1, children: [_jsxs(Text, { wrap: "truncate-end", children: [sweep('✦ dsh-TUI', t, wordmarkRGB, wordmarkShimmerRGB, 60), _jsx(Text, { dimColor: true, children: ' v' + VERSION })] }), bigDeepSeek.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row }, `ds-${index}`))), bigHarness.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row }, `h-${index}`))), _jsxs(Text, { wrap: "truncate-end", children: [model, effort !== undefined && _jsx(Text, { dimColor: true, children: ' · ' + capitalize(effort) + ' effort' })] }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: cwd }), _jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { dimColor: true, children: tr('logo-tip-prefix') }), "/model", _jsxs(Text, { dimColor: true, children: [" ", tr('logo-tip-model'), " \u00B7 "] }), "/help", _jsxs(Text, { dimColor: true, children: [" ", tr('logo-tip-help'), " \u00B7 "] }), "Tab", _jsxs(Text, { dimColor: true, children: [" ", tr('logo-tip-tab')] })] })] })] }), _jsx(Box, { marginTop: 1, paddingLeft: welcomePad, children: _jsx(Text, { children: sweep(tagline, t, taglineRGB, FLASH, 60) }) })] }));
95
104
  }
@@ -18,7 +18,19 @@ type Props = {
18
18
  /**
19
19
  * 混合渲染 Markdown 内容:表格用带边框的 flexbox 组件,其余内容由
20
20
  * formatToken 生成 ANSI 字符串放入 Text。高亮对象异步就绪后自动刷新。
21
+ *
22
+ * memo by content: finished transcript blocks render with the SAME string
23
+ * identity for the whole session (StreamingMarkdown keeps its stable prefix
24
+ * identity-stable precisely to hit this); without the memo every parent
25
+ * re-render re-ran the full token→ANSI→yoga pipeline for every settled
26
+ * block — the dominant long-output stall (string-width via wrap-ansi, 60%+
27
+ * of CPU in streaming profiles).
28
+ */
29
+ declare function MarkdownImpl({ children, dimColor, cacheTokens }: Props): React.ReactNode;
30
+ /**
31
+ * Memoized Markdown: skips the whole token→ANSI→layout pipeline when the
32
+ * content string is the same reference (see MarkdownImpl's doc comment).
21
33
  */
22
- export declare function Markdown({ children, dimColor, cacheTokens }: Props): React.ReactNode;
34
+ export declare const Markdown: React.MemoExoticComponent<typeof MarkdownImpl>;
23
35
  export {};
24
36
  //# sourceMappingURL=Markdown.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Markdown.d.ts","sourceRoot":"","sources":["../../../src/components/Markdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB;;;;;;;;GAQG;AAEH,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB,CAAA;AA4GD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EAAE,QAAQ,EAAE,QAAgB,EAAE,WAAkB,EAAE,EAAE,KAAK,GAAG,KAAK,CAAC,SAAS,CA6BnG"}
1
+ {"version":3,"file":"Markdown.d.ts","sourceRoot":"","sources":["../../../src/components/Markdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB;;;;;;;;GAQG;AAEH,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB,CAAA;AA4GD;;;;;;;;;;GAUG;AACH,iBAAS,YAAY,CAAC,EAAE,QAAQ,EAAE,QAAgB,EAAE,WAAkB,EAAE,EAAE,KAAK,GAAG,KAAK,CAAC,SAAS,CA6BhG;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,gDAMpB,CAAA"}
@@ -90,8 +90,15 @@ function renderTokensToNodes(tokens, highlight, dimColor) {
90
90
  /**
91
91
  * 混合渲染 Markdown 内容:表格用带边框的 flexbox 组件,其余内容由
92
92
  * formatToken 生成 ANSI 字符串放入 Text。高亮对象异步就绪后自动刷新。
93
+ *
94
+ * memo by content: finished transcript blocks render with the SAME string
95
+ * identity for the whole session (StreamingMarkdown keeps its stable prefix
96
+ * identity-stable precisely to hit this); without the memo every parent
97
+ * re-render re-ran the full token→ANSI→yoga pipeline for every settled
98
+ * block — the dominant long-output stall (string-width via wrap-ansi, 60%+
99
+ * of CPU in streaming profiles).
93
100
  */
94
- export function Markdown({ children, dimColor = false, cacheTokens = true }) {
101
+ function MarkdownImpl({ children, dimColor = false, cacheTokens = true }) {
95
102
  const [highlight, setHighlight] = React.useState(null);
96
103
  React.useEffect(() => {
97
104
  let mounted = true;
@@ -110,3 +117,10 @@ export function Markdown({ children, dimColor = false, cacheTokens = true }) {
110
117
  }, [children, dimColor, highlight, cacheTokens]);
111
118
  return (_jsx(Box, { flexDirection: "column", gap: 1, children: renderedNodes }));
112
119
  }
120
+ /**
121
+ * Memoized Markdown: skips the whole token→ANSI→layout pipeline when the
122
+ * content string is the same reference (see MarkdownImpl's doc comment).
123
+ */
124
+ export const Markdown = React.memo(MarkdownImpl, (prev, next) => prev.children === next.children &&
125
+ prev.dimColor === next.dimColor &&
126
+ prev.cacheTokens === next.cacheTokens);
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { type ScrollBoxHandle } from '../ui.js';
3
3
  import type { ChatRow } from '../dsh-adapter/channel.js';
4
4
  import type { DOMElement } from '../ink/dom.js';
5
- export declare function MessageList({ rows, expanded, expandedRows, selectedId, onToggleRow, model, diffLayout, showAll, onToggleAll, onLoadOlder, thinkingVisible, registerRowRef, scrollHandle, forceMountRowId, newSinceRowId, onUnseenCount, failureHintRowId, failureHint, }: {
5
+ export declare function MessageList({ rows, expanded, expandedRows, selectedId, onToggleRow, model, diffLayout, thinkingFold, showAll, onToggleAll, onLoadOlder, thinkingVisible, registerRowRef, scrollHandle, forceMountRowId, newSinceRowId, onUnseenCount, failureHintRowId, failureHint, }: {
6
6
  rows: readonly ChatRow[];
7
7
  expanded: boolean;
8
8
  expandedRows: ReadonlySet<number>;
@@ -11,6 +11,8 @@ export declare function MessageList({ rows, expanded, expandedRows, selectedId,
11
11
  model: string;
12
12
  /** Edit/Write diff presentation preference (forwarded to tool cards). */
13
13
  diffLayout?: 'auto' | 'split' | 'unified';
14
+ /** Thinking-block display mode from channel (`preview`/`full`). */
15
+ thinkingFold?: 'preview' | 'full';
14
16
  showAll: boolean;
15
17
  onToggleAll: () => void;
16
18
  /** Restore folded-away older rows from the session log (CC-style "load
@@ -1 +1 @@
1
- {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAA8B,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAC3E,OAAO,KAAK,EAAE,OAAO,EAAyC,MAAM,2BAA2B,CAAA;AAC/F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAuC/C,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,WAAW,EACX,KAAK,EACL,UAAmB,EACnB,OAAO,EACP,WAAW,EACX,WAAW,EACX,eAAsB,EACtB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,WAAW,GACZ,EAAE;IACD,IAAI,EAAE,SAAS,OAAO,EAAE,CAAA;IACxB,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACjC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;IACzC,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB;2EACuE;IACvE,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAA;IAC/D,oDAAoD;IACpD,YAAY,CAAC,EAAE,eAAe,GAAG,IAAI,CAAA;IACrC,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B;8EAC0E;IAC1E,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,0EAA0E;IAC1E,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,qBAiRA;AA2QD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,MAAM,EACN,GAAG,GACJ,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,GAAG,EAAE,MAAM,CAAA;CACZ,GAAG,KAAK,CAAC,SAAS,CAMlB"}
1
+ {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAA8B,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAC3E,OAAO,KAAK,EAAE,OAAO,EAAyC,MAAM,2BAA2B,CAAA;AAC/F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAuC/C,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,WAAW,EACX,KAAK,EACL,UAAmB,EACnB,YAAwB,EACxB,OAAO,EACP,WAAW,EACX,WAAW,EACX,eAAsB,EACtB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,WAAW,GACZ,EAAE;IACD,IAAI,EAAE,SAAS,OAAO,EAAE,CAAA;IACxB,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACjC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;IACzC,mEAAmE;IACnE,YAAY,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IACjC,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB;2EACuE;IACvE,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAA;IAC/D,oDAAoD;IACpD,YAAY,CAAC,EAAE,eAAe,GAAG,IAAI,CAAA;IACrC,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B;8EAC0E;IAC1E,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,0EAA0E;IAC1E,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,qBA6VA;AAmRD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,MAAM,EACN,GAAG,GACJ,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,GAAG,EAAE,MAAM,CAAA;CACZ,GAAG,KAAK,CAAC,SAAS,CAMlB"}
@@ -37,7 +37,7 @@ const DEFAULT_ROW_HEIGHT = 2;
37
37
  /** Cold-start estimate of the header block above the rows; corrected by the
38
38
  * first layout measurement. */
39
39
  const DEFAULT_HEADER_LINES = 14;
40
- export function MessageList({ rows, expanded, expandedRows, selectedId, onToggleRow, model, diffLayout = 'auto', showAll, onToggleAll, onLoadOlder, thinkingVisible = true, registerRowRef, scrollHandle, forceMountRowId, newSinceRowId, onUnseenCount, failureHintRowId, failureHint, }) {
40
+ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggleRow, model, diffLayout = 'auto', thinkingFold = 'preview', showAll, onToggleAll, onLoadOlder, thinkingVisible = true, registerRowRef, scrollHandle, forceMountRowId, newSinceRowId, onUnseenCount, failureHintRowId, failureHint, }) {
41
41
  const hiddenCount = rows.length - MAX_RENDERED_ROWS;
42
42
  // The thinking filter runs BEFORE virtualization so window indices line up.
43
43
  const visibleRows = (showAll || hiddenCount <= 0
@@ -65,7 +65,7 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
65
65
  return undefined;
66
66
  };
67
67
  // --- layout virtualization ---------------------------------------------
68
- const { columns } = useTerminalSize();
68
+ const { columns, rows: termRows } = useTerminalSize();
69
69
  // Measured row heights, remembered after a row unmounts so virtualization
70
70
  // can compute total content height. Bounded: row ids grow monotonically
71
71
  // and rows are never removed from the transcript (foldRows keeps the
@@ -75,6 +75,31 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
75
75
  const HEIGHTS_CACHE_MAX = 5000;
76
76
  const heightsRef = React.useRef(new Map());
77
77
  const localRefs = React.useRef(new Map());
78
+ /** Row ids that have been mounted (and therefore painted into the
79
+ * terminal) at least once. The sticky window may skip a row ONLY after
80
+ * this: an unpainted row above the window has no scrollback copy, so
81
+ * skipping it would erase it from the user's history entirely — preset
82
+ * history at boot (session resume) landed exactly there. Cleared when
83
+ * the list head changes identity (rewind / new session / loadOlder
84
+ * prepends restored rows that must paint again). */
85
+ const paintedOnceRef = React.useRef(new Set());
86
+ const paintedBaseRef = React.useRef(undefined);
87
+ /** Window-expansion hold: after the window WIDENS (new rows mounted),
88
+ * refuse to tighten for a short hold so the mounted rows actually reach
89
+ * the terminal. React commits within one ink frame coalesce — a render
90
+ * that mounts rows followed by the measure-tick re-render that drops
91
+ * them paints only the DROPPED layout, and never-mounted rows have no
92
+ * scrollback copy (preset history at boot vanished — CI
93
+ * repro-inline-scrollback). After the hold, tightening is visually
94
+ * free: those rows sit in scrollback and the diff skips them. */
95
+ const lastStartRef = React.useRef(-1);
96
+ const holdUntilRef = React.useRef(0);
97
+ const listHeadId = visibleRows[0]?.id;
98
+ if (listHeadId !== undefined && paintedBaseRef.current !== undefined && listHeadId !== paintedBaseRef.current) {
99
+ paintedOnceRef.current = new Set();
100
+ }
101
+ if (listHeadId !== undefined)
102
+ paintedBaseRef.current = listHeadId;
78
103
  /** Content-space offset of visibleRows[0] (header + dividers), measured. */
79
104
  const baseRef = React.useRef(null);
80
105
  const measureQueuedRef = React.useRef(false);
@@ -128,6 +153,15 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
128
153
  // back to the real bottom: a self-sustaining ping-pong that blanks the
129
154
  // transcript mid-stream.
130
155
  if (sticky && visibleRows.length > 0) {
156
+ // Sticky (follow-bottom): the viewport shows the TAIL of the content —
157
+ // mount exactly the tail window the floor walk covers, not everything
158
+ // from the scrollTop scan. Main-screen ScrollBox reports its viewport
159
+ // as the CONTENT height (the terminal itself is the scroller), so both
160
+ // the scan and an unclamped floor walk mount EVERY row in long
161
+ // sessions — and React's commit traverses every fiber of every mounted
162
+ // row per frame (measured as the dominant long-session stall). The
163
+ // user only ever sees terminal rows: clamp the walk-back coverage to
164
+ // the TERMINAL viewport plus overscan.
131
165
  start = Math.min(start, visibleRows.length - 1);
132
166
  // Blank-band guard: sticky scrollTop tracks the renderer's FRESH Yoga
133
167
  // scrollHeight, while these offsets use per-row heights measured one to
@@ -135,15 +169,44 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
135
169
  // deeper through the underestimated offsets than the real viewport does,
136
170
  // unmounting rows that are still on screen (visible spacer band). Walk
137
171
  // backwards from the tail with the known heights and mount at least one
138
- // viewport plus overscan of content above it, so the window can never
139
- // open a gap inside what the user is looking at.
140
- let covered = viewport + OVERSCAN_LINES;
172
+ // terminal viewport plus overscan of content above it, so the window
173
+ // can never open a gap inside what the user is looking at.
174
+ let covered = Math.min(viewport, termRows) + OVERSCAN_LINES;
141
175
  let floor = visibleRows.length - 1;
142
176
  while (floor > 0 && covered > 0) {
143
177
  covered -= heightOf(visibleRows[floor]);
144
178
  floor--;
145
179
  }
146
- start = Math.min(start, floor + 1);
180
+ // The walk exhausted the whole list: every row is within coverage —
181
+ // floor+1 here would drop row 0 (its content then has no terminal copy
182
+ // anywhere; preset history lost its head — CI repro-inline-scrollback).
183
+ start = floor === 0 && covered > 0 ? 0 : floor + 1;
184
+ // Paint-at-least-once: extend the window over any row that has never
185
+ // been mounted. A row the window skips keeps only its terminal/scrollback
186
+ // copy — a row that was never painted has NO copy anywhere, so preset
187
+ // history (session resume, repro-inline-scrollback's #39 family) would
188
+ // vanish from the user's scrollback. Extending mounts everything above
189
+ // on the first frame (topPad 0, full paint), then the set fills and the
190
+ // window tightens to the tail.
191
+ const paintedOnce = paintedOnceRef.current;
192
+ for (let i = 0; i < start; i++) {
193
+ if (!paintedOnce.has(visibleRows[i].id)) {
194
+ start = i;
195
+ break;
196
+ }
197
+ }
198
+ // Expansion hold — AFTER the extension so it tracks the FINAL window:
199
+ // never tighten within the hold window after a widen. React commits
200
+ // inside one ink frame coalesce; a mount followed by the measure-tick
201
+ // re-render that drops the row paints only the DROPPED layout, and the
202
+ // row's painted-once mark (set at the first commit) is a lie.
203
+ if (lastStartRef.current >= 0 && start > lastStartRef.current && performance.now() < holdUntilRef.current) {
204
+ start = lastStartRef.current;
205
+ }
206
+ if (lastStartRef.current < 0 || start < lastStartRef.current) {
207
+ holdUntilRef.current = performance.now() + 120;
208
+ }
209
+ lastStartRef.current = start;
147
210
  }
148
211
  if (forceMountRowId !== undefined && forceMountRowId !== null) {
149
212
  const idx = visibleRows.findIndex(row => row.id === forceMountRowId);
@@ -152,6 +215,15 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
152
215
  end = Math.max(end, idx + 1);
153
216
  }
154
217
  }
218
+ // The newest failed tool call carries the trajectory footnote
219
+ // (failureHint). Virtualization must not unmount it: before the window
220
+ // clamp the row was always mounted, now keep mounting it explicitly while
221
+ // the hint is live (verify-trace-scene's footnote check).
222
+ if (failureHintRowId !== undefined && failureHintRowId !== null) {
223
+ const idx = visibleRows.findIndex(row => row.id === failureHintRowId);
224
+ if (idx !== -1)
225
+ start = Math.min(start, idx);
226
+ }
155
227
  const topPad = offsets[start] ?? 0;
156
228
  const mountedBottom = end < visibleRows.length ? offsets[end] : total;
157
229
  const bottomPad = total - mountedBottom;
@@ -185,6 +257,12 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
185
257
  // mounted coverage so burst scrolls never show blank spacer.
186
258
  React.useLayoutEffect(() => {
187
259
  let changed = false;
260
+ // Mounted ⇒ painted: record rows eligible for window skipping.
261
+ const paintedOnce = paintedOnceRef.current;
262
+ for (const id of localRefs.current.keys()) {
263
+ if (!paintedOnce.has(id))
264
+ paintedOnce.add(id);
265
+ }
188
266
  for (const [id, el] of localRefs.current) {
189
267
  const h = el.yogaNode?.getComputedHeight();
190
268
  if (h !== undefined && h > 0 && heightsRef.current.get(id) !== h) {
@@ -256,10 +334,10 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
256
334
  // spacing; only the very first row of the whole list has none.
257
335
  const addMargin = margins.get(row.id) === true;
258
336
  const tool = row.tool;
259
- return (_jsx(MemoRow, { rowId: row.id, kind: row.kind, text: row.text, executionTarget: row.executionTarget, streaming: row.streaming === true, durationMs: row.durationMs, time: row.time, addMargin: addMargin, isSelected: selectedId === row.id, isExpanded: expandedRows.has(row.id), expanded: expanded, model: model, diffLayout: diffLayout, background: rowBackground(row.id), toolCallId: tool?.callId, toolName: tool?.name, toolArgsText: tool?.argsText, toolArgsFull: tool?.argsFull, toolStatus: tool?.status, toolResultText: tool?.resultText, toolResultFull: tool?.resultFull, toolErrorText: tool?.errorText, toolFootnote: failureHintRowId === row.id ? failureHint : undefined, toolCallView: tool?.callView, toolResultView: tool?.resultView, toolStartedAt: tool?.startedAt, toolDurationMs: tool?.durationMs, nowSec: tool?.status === 'running' ? nowSec : undefined, onToggleRow: onToggleRow, setRowRef: setRowRef }, row.id));
337
+ return (_jsx(MemoRow, { rowId: row.id, kind: row.kind, text: row.text, executionTarget: row.executionTarget, streaming: row.streaming === true, durationMs: row.durationMs, time: row.time, addMargin: addMargin, isSelected: selectedId === row.id, isExpanded: expandedRows.has(row.id), expanded: expanded, model: model, diffLayout: diffLayout, thinkingFold: thinkingFold, background: rowBackground(row.id), toolCallId: tool?.callId, toolName: tool?.name, toolArgsText: tool?.argsText, toolArgsFull: tool?.argsFull, toolStatus: tool?.status, toolResultText: tool?.resultText, toolResultFull: tool?.resultFull, toolErrorText: tool?.errorText, toolFootnote: failureHintRowId === row.id ? failureHint : undefined, toolCallView: tool?.callView, toolResultView: tool?.resultView, toolStartedAt: tool?.startedAt, toolDurationMs: tool?.durationMs, nowSec: tool?.status === 'running' ? nowSec : undefined, onToggleRow: onToggleRow, setRowRef: setRowRef }, row.id));
260
338
  }), bottomPad > 0 && _jsx(Box, { height: bottomPad, flexShrink: 0 })] }));
261
339
  }
262
- function TranscriptRow({ rowId, kind, text, executionTarget, streaming, durationMs, time, addMargin, isSelected, isExpanded, expanded, model, diffLayout, background, toolCallId, toolName, toolArgsText, toolArgsFull, toolStatus, toolResultText, toolResultFull, toolErrorText, toolFootnote, toolCallView, toolResultView, toolStartedAt, toolDurationMs, onToggleRow, setRowRef, }) {
340
+ function TranscriptRow({ rowId, kind, text, executionTarget, streaming, durationMs, time, addMargin, isSelected, isExpanded, expanded, model, diffLayout, thinkingFold, background, toolCallId, toolName, toolArgsText, toolArgsFull, toolStatus, toolResultText, toolResultFull, toolErrorText, toolFootnote, toolCallView, toolResultView, toolStartedAt, toolDurationMs, onToggleRow, setRowRef, }) {
263
341
  const ref = React.useCallback((el) => {
264
342
  setRowRef(rowId, el);
265
343
  }, [setRowRef, rowId]);
@@ -272,7 +350,10 @@ function TranscriptRow({ rowId, kind, text, executionTarget, streaming, duration
272
350
  case 'assistant':
273
351
  return streaming ? (_jsxs(Box, { alignItems: "flex-start", flexDirection: "row", marginTop: addMargin ? 1 : 0, width: "100%", backgroundColor: background, children: [_jsx(Box, { minWidth: 2, children: _jsx(Text, { color: "text", children: "\u25CF" }) }), _jsx(Box, { flexDirection: "column", children: _jsx(StreamingMarkdown, { children: stripNarration(text) }) })] })) : (_jsxs(Box, { width: "100%", flexDirection: "column", backgroundColor: background, ref: ref, children: [expanded && (_jsx(Box, { flexDirection: "row", justifyContent: "flex-end", gap: 1, marginTop: 1, children: _jsx(MessageMetadata, { timestamp: time, model: model }) })), _jsx(AssistantTextMessage, { text: stripNarration(text), addMargin: addMargin, isSelected: isSelected, isExpanded: isExpanded, onClick: onClick })] }));
274
352
  case 'reasoning':
275
- return (_jsx(Box, { flexDirection: "column", ref: ref, children: _jsx(AssistantThinkingMessage, { thinking: text, addMargin: addMargin,
353
+ return (_jsx(Box, { flexDirection: "column", ref: ref, children: _jsx(AssistantThinkingMessage, { thinking: text, addMargin: addMargin, preview: streaming &&
354
+ thinkingFold === 'preview' &&
355
+ !expanded &&
356
+ !isExpanded,
276
357
  // Streaming reasoning shows expanded live, then folds
277
358
  // automatically once the turn settles (unless Ctrl+O or a
278
359
  // single-row expansion keeps it open).
@@ -1 +1 @@
1
- {"version":3,"file":"PromptInput.d.ts","sourceRoot":"","sources":["../../../src/components/PromptInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AASzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAkDxD;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,IAAI,OAAO,CAAA;IAClB,KAAK,IAAI,IAAI,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAA;IAChB,0EAA0E;IAC1E,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,IAAI,IAAI,CAAA;IACpB;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IACrD,6EAA6E;IAC7E,eAAe,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,cAAc,CAAC,IAAI,IAAI,CAAA;IACvB,8EAA8E;IAC9E,eAAe,CAAC,IAAI,IAAI,CAAA;IACxB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;CACzD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,cAAc,EACd,eAAe,EACf,aAAa,GACd,EAAE,gBAAgB,qBAg5BlB"}
1
+ {"version":3,"file":"PromptInput.d.ts","sourceRoot":"","sources":["../../../src/components/PromptInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AASzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAkDxD;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,IAAI,OAAO,CAAA;IAClB,KAAK,IAAI,IAAI,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAA;IAChB,0EAA0E;IAC1E,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,IAAI,IAAI,CAAA;IACpB;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IACrD,6EAA6E;IAC7E,eAAe,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,cAAc,CAAC,IAAI,IAAI,CAAA;IACvB,8EAA8E;IAC9E,eAAe,CAAC,IAAI,IAAI,CAAA;IACxB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;CACzD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,cAAc,EACd,eAAe,EACf,aAAa,GACd,EAAE,gBAAgB,qBA65BlB"}