@ai-zen/cli 1.0.0-alpha.2 → 1.0.0-alpha.22

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 (311) hide show
  1. package/CHANGELOG.md +514 -0
  2. package/README.md +136 -39
  3. package/README.zh.md +136 -39
  4. package/dist/agent-creator.d.ts +11 -0
  5. package/dist/agent-creator.d.ts.map +1 -1
  6. package/dist/agent-creator.js +52 -21
  7. package/dist/agent-creator.js.map +1 -1
  8. package/dist/agent-switch.d.ts +61 -0
  9. package/dist/agent-switch.d.ts.map +1 -0
  10. package/dist/agent-switch.js +83 -0
  11. package/dist/agent-switch.js.map +1 -0
  12. package/dist/agents-store.d.ts +6 -1
  13. package/dist/agents-store.d.ts.map +1 -1
  14. package/dist/agents-store.js +46 -4
  15. package/dist/agents-store.js.map +1 -1
  16. package/dist/auto-migrate-confirm.d.ts +43 -0
  17. package/dist/auto-migrate-confirm.d.ts.map +1 -0
  18. package/dist/auto-migrate-confirm.js +47 -0
  19. package/dist/auto-migrate-confirm.js.map +1 -0
  20. package/dist/config-editor.d.ts +13 -5
  21. package/dist/config-editor.d.ts.map +1 -1
  22. package/dist/config-editor.js +36 -27
  23. package/dist/config-editor.js.map +1 -1
  24. package/dist/config.d.ts +24 -3
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/config.js +55 -15
  27. package/dist/config.js.map +1 -1
  28. package/dist/conversation-commands/registry.d.ts +123 -4
  29. package/dist/conversation-commands/registry.d.ts.map +1 -1
  30. package/dist/conversation-commands/registry.js +92 -14
  31. package/dist/conversation-commands/registry.js.map +1 -1
  32. package/dist/conversation-persist-plugin.d.ts +0 -1
  33. package/dist/conversation-persist-plugin.d.ts.map +1 -1
  34. package/dist/conversation-persist-plugin.js +7 -16
  35. package/dist/conversation-persist-plugin.js.map +1 -1
  36. package/dist/conversation-repository.d.ts +71 -13
  37. package/dist/conversation-repository.d.ts.map +1 -1
  38. package/dist/conversation-repository.js +81 -24
  39. package/dist/conversation-repository.js.map +1 -1
  40. package/dist/cwd-tracker-plugin.d.ts.map +1 -1
  41. package/dist/cwd-tracker-plugin.js +6 -2
  42. package/dist/cwd-tracker-plugin.js.map +1 -1
  43. package/dist/format-time.d.ts +17 -6
  44. package/dist/format-time.d.ts.map +1 -1
  45. package/dist/format-time.js +32 -14
  46. package/dist/format-time.js.map +1 -1
  47. package/dist/handoff-service.d.ts +19 -0
  48. package/dist/handoff-service.d.ts.map +1 -0
  49. package/dist/handoff-service.js +89 -0
  50. package/dist/handoff-service.js.map +1 -0
  51. package/dist/hook.d.ts.map +1 -1
  52. package/dist/hook.js +69 -15
  53. package/dist/hook.js.map +1 -1
  54. package/dist/i18n/en-wizard.d.ts +8 -0
  55. package/dist/i18n/en-wizard.d.ts.map +1 -0
  56. package/dist/i18n/en-wizard.js +290 -0
  57. package/dist/i18n/en-wizard.js.map +1 -0
  58. package/dist/i18n/en.d.ts +7 -0
  59. package/dist/i18n/en.d.ts.map +1 -0
  60. package/dist/i18n/en.js +224 -0
  61. package/dist/i18n/en.js.map +1 -0
  62. package/dist/i18n/index.d.ts +57 -0
  63. package/dist/i18n/index.d.ts.map +1 -0
  64. package/dist/i18n/index.js +109 -0
  65. package/dist/i18n/index.js.map +1 -0
  66. package/dist/i18n/preferences.d.ts +34 -0
  67. package/dist/i18n/preferences.d.ts.map +1 -0
  68. package/dist/i18n/preferences.js +69 -0
  69. package/dist/i18n/preferences.js.map +1 -0
  70. package/dist/i18n/zh-wizard.d.ts +11 -0
  71. package/dist/i18n/zh-wizard.d.ts.map +1 -0
  72. package/dist/i18n/zh-wizard.js +293 -0
  73. package/dist/i18n/zh-wizard.js.map +1 -0
  74. package/dist/i18n/zh.d.ts +10 -0
  75. package/dist/i18n/zh.d.ts.map +1 -0
  76. package/dist/i18n/zh.js +228 -0
  77. package/dist/i18n/zh.js.map +1 -0
  78. package/dist/index.js +61 -25
  79. package/dist/index.js.map +1 -1
  80. package/dist/mcp-command.d.ts +32 -0
  81. package/dist/mcp-command.d.ts.map +1 -0
  82. package/dist/mcp-command.js +37 -0
  83. package/dist/mcp-command.js.map +1 -0
  84. package/dist/mode.d.ts +31 -4
  85. package/dist/mode.d.ts.map +1 -1
  86. package/dist/mode.js +42 -7
  87. package/dist/mode.js.map +1 -1
  88. package/dist/model-switch.d.ts +58 -0
  89. package/dist/model-switch.d.ts.map +1 -0
  90. package/dist/model-switch.js +62 -0
  91. package/dist/model-switch.js.map +1 -0
  92. package/dist/reasoning-effort.d.ts +96 -0
  93. package/dist/reasoning-effort.d.ts.map +1 -0
  94. package/dist/reasoning-effort.js +164 -0
  95. package/dist/reasoning-effort.js.map +1 -0
  96. package/dist/reasoning-presets.d.ts +34 -0
  97. package/dist/reasoning-presets.d.ts.map +1 -0
  98. package/dist/reasoning-presets.js +85 -0
  99. package/dist/reasoning-presets.js.map +1 -0
  100. package/dist/sdk-log.d.ts +55 -0
  101. package/dist/sdk-log.d.ts.map +1 -0
  102. package/dist/sdk-log.js +91 -0
  103. package/dist/sdk-log.js.map +1 -0
  104. package/dist/session-pointer.d.ts +22 -9
  105. package/dist/session-pointer.d.ts.map +1 -1
  106. package/dist/session-pointer.js +55 -23
  107. package/dist/session-pointer.js.map +1 -1
  108. package/dist/stdio-runner.d.ts.map +1 -1
  109. package/dist/stdio-runner.js +32 -30
  110. package/dist/stdio-runner.js.map +1 -1
  111. package/dist/sub-agent-guard-plugin.d.ts +5 -5
  112. package/dist/sub-agent-guard-plugin.d.ts.map +1 -1
  113. package/dist/sub-agent-guard-plugin.js +7 -7
  114. package/dist/sub-agent-guard-plugin.js.map +1 -1
  115. package/dist/tui/chat-session.d.ts +110 -59
  116. package/dist/tui/chat-session.d.ts.map +1 -1
  117. package/dist/tui/chat-session.js +268 -120
  118. package/dist/tui/chat-session.js.map +1 -1
  119. package/dist/tui/components.d.ts +48 -2
  120. package/dist/tui/components.d.ts.map +1 -1
  121. package/dist/tui/components.js +96 -3
  122. package/dist/tui/components.js.map +1 -1
  123. package/dist/tui/config-wizard/detail.d.ts +12 -6
  124. package/dist/tui/config-wizard/detail.d.ts.map +1 -1
  125. package/dist/tui/config-wizard/detail.js +33 -32
  126. package/dist/tui/config-wizard/detail.js.map +1 -1
  127. package/dist/tui/config-wizard/engine.d.ts.map +1 -1
  128. package/dist/tui/config-wizard/engine.js +27 -21
  129. package/dist/tui/config-wizard/engine.js.map +1 -1
  130. package/dist/tui/config-wizard/fields.d.ts +3 -1
  131. package/dist/tui/config-wizard/fields.d.ts.map +1 -1
  132. package/dist/tui/config-wizard/fields.js +216 -152
  133. package/dist/tui/config-wizard/fields.js.map +1 -1
  134. package/dist/tui/config-wizard/kv-editor.d.ts.map +1 -1
  135. package/dist/tui/config-wizard/kv-editor.js +9 -5
  136. package/dist/tui/config-wizard/kv-editor.js.map +1 -1
  137. package/dist/tui/config-wizard/list.d.ts.map +1 -1
  138. package/dist/tui/config-wizard/list.js +2 -1
  139. package/dist/tui/config-wizard/list.js.map +1 -1
  140. package/dist/tui/config-wizard/mcp-helpers.d.ts.map +1 -1
  141. package/dist/tui/config-wizard/mcp-helpers.js +4 -3
  142. package/dist/tui/config-wizard/mcp-helpers.js.map +1 -1
  143. package/dist/tui/config-wizard/menu.d.ts.map +1 -1
  144. package/dist/tui/config-wizard/menu.js +33 -21
  145. package/dist/tui/config-wizard/menu.js.map +1 -1
  146. package/dist/tui/config-wizard/prompt-editor.d.ts.map +1 -1
  147. package/dist/tui/config-wizard/prompt-editor.js +4 -3
  148. package/dist/tui/config-wizard/prompt-editor.js.map +1 -1
  149. package/dist/tui/config-wizard/prompt.d.ts.map +1 -1
  150. package/dist/tui/config-wizard/prompt.js +8 -7
  151. package/dist/tui/config-wizard/prompt.js.map +1 -1
  152. package/dist/tui/config-wizard/step-agents.d.ts.map +1 -1
  153. package/dist/tui/config-wizard/step-agents.js +29 -20
  154. package/dist/tui/config-wizard/step-agents.js.map +1 -1
  155. package/dist/tui/config-wizard/step-defaults.d.ts.map +1 -1
  156. package/dist/tui/config-wizard/step-defaults.js +24 -27
  157. package/dist/tui/config-wizard/step-defaults.js.map +1 -1
  158. package/dist/tui/config-wizard/step-endpoints.d.ts.map +1 -1
  159. package/dist/tui/config-wizard/step-endpoints.js +16 -6
  160. package/dist/tui/config-wizard/step-endpoints.js.map +1 -1
  161. package/dist/tui/config-wizard/step-mcp.d.ts.map +1 -1
  162. package/dist/tui/config-wizard/step-mcp.js +17 -19
  163. package/dist/tui/config-wizard/step-mcp.js.map +1 -1
  164. package/dist/tui/config-wizard/step-models.d.ts.map +1 -1
  165. package/dist/tui/config-wizard/step-models.js +41 -26
  166. package/dist/tui/config-wizard/step-models.js.map +1 -1
  167. package/dist/tui/config-wizard/step-new-endpoint.d.ts.map +1 -1
  168. package/dist/tui/config-wizard/step-new-endpoint.js +16 -12
  169. package/dist/tui/config-wizard/step-new-endpoint.js.map +1 -1
  170. package/dist/tui/config-wizard/step-simple.d.ts.map +1 -1
  171. package/dist/tui/config-wizard/step-simple.js +18 -17
  172. package/dist/tui/config-wizard/step-simple.js.map +1 -1
  173. package/dist/tui/config-wizard/types.d.ts +18 -3
  174. package/dist/tui/config-wizard/types.d.ts.map +1 -1
  175. package/dist/tui/config-wizard/wizard.d.ts.map +1 -1
  176. package/dist/tui/config-wizard/wizard.js +4 -3
  177. package/dist/tui/config-wizard/wizard.js.map +1 -1
  178. package/dist/tui/highlight.d.ts +3 -2
  179. package/dist/tui/highlight.d.ts.map +1 -1
  180. package/dist/tui/highlight.js +3 -2
  181. package/dist/tui/highlight.js.map +1 -1
  182. package/dist/tui/index.d.ts +18 -1
  183. package/dist/tui/index.d.ts.map +1 -1
  184. package/dist/tui/index.js +107 -49
  185. package/dist/tui/index.js.map +1 -1
  186. package/dist/tui/input-editing.d.ts +52 -0
  187. package/dist/tui/input-editing.d.ts.map +1 -0
  188. package/dist/tui/input-editing.js +91 -0
  189. package/dist/tui/input-editing.js.map +1 -0
  190. package/dist/tui/key-debug.d.ts +62 -0
  191. package/dist/tui/key-debug.d.ts.map +1 -0
  192. package/dist/tui/key-debug.js +92 -0
  193. package/dist/tui/key-debug.js.map +1 -0
  194. package/dist/tui/mouse.d.ts +55 -0
  195. package/dist/tui/mouse.d.ts.map +1 -0
  196. package/dist/tui/mouse.js +74 -0
  197. package/dist/tui/mouse.js.map +1 -0
  198. package/dist/tui/phase.d.ts +64 -0
  199. package/dist/tui/phase.d.ts.map +1 -0
  200. package/dist/tui/phase.js +112 -0
  201. package/dist/tui/phase.js.map +1 -0
  202. package/dist/tui/screens/chat-commands.d.ts +64 -3
  203. package/dist/tui/screens/chat-commands.d.ts.map +1 -1
  204. package/dist/tui/screens/chat-commands.js +483 -157
  205. package/dist/tui/screens/chat-commands.js.map +1 -1
  206. package/dist/tui/screens/chat.d.ts +10 -5
  207. package/dist/tui/screens/chat.d.ts.map +1 -1
  208. package/dist/tui/screens/chat.js +464 -301
  209. package/dist/tui/screens/chat.js.map +1 -1
  210. package/dist/tui/screens/common-keys.d.ts +36 -0
  211. package/dist/tui/screens/common-keys.d.ts.map +1 -0
  212. package/dist/tui/screens/common-keys.js +67 -0
  213. package/dist/tui/screens/common-keys.js.map +1 -0
  214. package/dist/tui/screens/frame-buffer.d.ts +47 -0
  215. package/dist/tui/screens/frame-buffer.d.ts.map +1 -0
  216. package/dist/tui/screens/frame-buffer.js +78 -0
  217. package/dist/tui/screens/frame-buffer.js.map +1 -0
  218. package/dist/tui/screens/handoff-choice.d.ts +37 -0
  219. package/dist/tui/screens/handoff-choice.d.ts.map +1 -0
  220. package/dist/tui/screens/handoff-choice.js +42 -0
  221. package/dist/tui/screens/handoff-choice.js.map +1 -0
  222. package/dist/tui/screens/index.d.ts +8 -8
  223. package/dist/tui/screens/index.d.ts.map +1 -1
  224. package/dist/tui/screens/index.js +7 -7
  225. package/dist/tui/screens/index.js.map +1 -1
  226. package/dist/tui/screens/input-row.d.ts +64 -0
  227. package/dist/tui/screens/input-row.d.ts.map +1 -0
  228. package/dist/tui/screens/input-row.js +67 -0
  229. package/dist/tui/screens/input-row.js.map +1 -0
  230. package/dist/tui/screens/input.d.ts +46 -1
  231. package/dist/tui/screens/input.d.ts.map +1 -1
  232. package/dist/tui/screens/input.js +83 -8
  233. package/dist/tui/screens/input.js.map +1 -1
  234. package/dist/tui/screens/layout.d.ts +21 -3
  235. package/dist/tui/screens/layout.d.ts.map +1 -1
  236. package/dist/tui/screens/layout.js +20 -9
  237. package/dist/tui/screens/layout.js.map +1 -1
  238. package/dist/tui/screens/lines.d.ts +12 -41
  239. package/dist/tui/screens/lines.d.ts.map +1 -1
  240. package/dist/tui/screens/lines.js +90 -98
  241. package/dist/tui/screens/lines.js.map +1 -1
  242. package/dist/tui/screens/messages-view.d.ts +10 -0
  243. package/dist/tui/screens/messages-view.d.ts.map +1 -0
  244. package/dist/tui/screens/messages-view.js +116 -0
  245. package/dist/tui/screens/messages-view.js.map +1 -0
  246. package/dist/tui/screens/notice-bar.d.ts +5 -0
  247. package/dist/tui/screens/notice-bar.d.ts.map +1 -0
  248. package/dist/tui/screens/notice-bar.js +15 -0
  249. package/dist/tui/screens/notice-bar.js.map +1 -0
  250. package/dist/tui/screens/notice.d.ts +64 -0
  251. package/dist/tui/screens/notice.d.ts.map +1 -0
  252. package/dist/tui/screens/notice.js +106 -0
  253. package/dist/tui/screens/notice.js.map +1 -0
  254. package/dist/tui/screens/overlays.d.ts.map +1 -1
  255. package/dist/tui/screens/overlays.js +3 -2
  256. package/dist/tui/screens/overlays.js.map +1 -1
  257. package/dist/tui/screens/render.d.ts +2 -4
  258. package/dist/tui/screens/render.d.ts.map +1 -1
  259. package/dist/tui/screens/render.js +7 -43
  260. package/dist/tui/screens/render.js.map +1 -1
  261. package/dist/tui/screens/splash.d.ts +1 -1
  262. package/dist/tui/screens/splash.d.ts.map +1 -1
  263. package/dist/tui/screens/splash.js +12 -3
  264. package/dist/tui/screens/splash.js.map +1 -1
  265. package/dist/tui/screens/use-chat-viewport.d.ts +22 -0
  266. package/dist/tui/screens/use-chat-viewport.d.ts.map +1 -0
  267. package/dist/tui/screens/use-chat-viewport.js +50 -0
  268. package/dist/tui/screens/use-chat-viewport.js.map +1 -0
  269. package/dist/tui/screens/use-input-editing.d.ts +44 -0
  270. package/dist/tui/screens/use-input-editing.d.ts.map +1 -0
  271. package/dist/tui/screens/use-input-editing.js +192 -0
  272. package/dist/tui/screens/use-input-editing.js.map +1 -0
  273. package/dist/tui/screens/use-overlays.d.ts +25 -0
  274. package/dist/tui/screens/use-overlays.d.ts.map +1 -0
  275. package/dist/tui/screens/use-overlays.js +32 -0
  276. package/dist/tui/screens/use-overlays.js.map +1 -0
  277. package/dist/tui/screens/use-wizard-host.d.ts +35 -0
  278. package/dist/tui/screens/use-wizard-host.d.ts.map +1 -0
  279. package/dist/tui/screens/use-wizard-host.js +103 -0
  280. package/dist/tui/screens/use-wizard-host.js.map +1 -0
  281. package/dist/tui/status-segments.d.ts +37 -0
  282. package/dist/tui/status-segments.d.ts.map +1 -0
  283. package/dist/tui/status-segments.js +166 -0
  284. package/dist/tui/status-segments.js.map +1 -0
  285. package/dist/tui/text.d.ts +20 -7
  286. package/dist/tui/text.d.ts.map +1 -1
  287. package/dist/tui/text.js +111 -37
  288. package/dist/tui/text.js.map +1 -1
  289. package/dist/tui/theme.d.ts +7 -1
  290. package/dist/tui/theme.d.ts.map +1 -1
  291. package/dist/tui/theme.js +15 -3
  292. package/dist/tui/theme.js.map +1 -1
  293. package/dist/tui/token-rate.d.ts +83 -0
  294. package/dist/tui/token-rate.d.ts.map +1 -0
  295. package/dist/tui/token-rate.js +195 -0
  296. package/dist/tui/token-rate.js.map +1 -0
  297. package/dist/types.d.ts +7 -8
  298. package/dist/types.d.ts.map +1 -1
  299. package/package.json +4 -3
  300. package/dist/auto-migrate-confirm-plugin.d.ts +0 -58
  301. package/dist/auto-migrate-confirm-plugin.d.ts.map +0 -1
  302. package/dist/auto-migrate-confirm-plugin.js +0 -61
  303. package/dist/auto-migrate-confirm-plugin.js.map +0 -1
  304. package/dist/migration-service.d.ts +0 -15
  305. package/dist/migration-service.d.ts.map +0 -1
  306. package/dist/migration-service.js +0 -59
  307. package/dist/migration-service.js.map +0 -1
  308. package/dist/tui/screens/state.d.ts +0 -13
  309. package/dist/tui/screens/state.d.ts.map +0 -1
  310. package/dist/tui/screens/state.js +0 -75
  311. package/dist/tui/screens/state.js.map +0 -1
@@ -0,0 +1,67 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * 可测量的输入行 —— 让**渲染器自己**告诉我们虚拟光标在第几列、第几行
4
+ *
5
+ * ## 为什么要测量,而不是算
6
+ *
7
+ * 真实光标 = (x, y)。y 是行号,不依赖宽度计算;x 取决于「光标前那段文本占几列」。
8
+ * 而宽度是个陷阱:Ink 排版时用 `string-width`(`ink/build/output.js`),我们手写的
9
+ * `displayWidth` 与它在若干字符上不一致 —— 实测 `⚡` `✅` `✨` `⭐` 这类 East Asian
10
+ * Wide 符号(我们算 1、Ink 算 2)、ZWJ 组合 emoji `👨‍👩‍👧`(我们算 8、Ink 算 2)、
11
+ * keycap `1️⃣`(我们算 3、Ink 算 2)。输入里只要出现这类字符,算出来的 x 就会偏。
12
+ *
13
+ * 既然这一行**已经渲染出来了**,最可靠的来源就是渲染器本身:Ink 7 的
14
+ * `measureElement()` 返回元素的布局坐标 `{ x, y, width, height }`(内部累加所有
15
+ * 祖先 offset),拿到的就是帧内绝对列 / 行。
16
+ *
17
+ * ## 为什么光标块要单独包一个 Box
18
+ *
19
+ * `measureElement()` 只能量**有独立布局节点**(yoga node)的元素。把整行写成
20
+ * 一个 `<Text>` 里嵌套若干片段时,那些片段在排版中被并进父文本节点,对它们调用
21
+ * `measureElement()` 直接返回 `null`(实测)。所以这里把**光标所在的那个字符**
22
+ * 单独包进 `<Box ref>`:它成为真实节点,坐标就能被测出来。
23
+ *
24
+ * ## 拆行之后怎么保住「一行就是一行」
25
+ *
26
+ * 整行拆成多个节点后,原本 `<Text wrap="truncate">` 的整行截断兜底就不存在了:
27
+ * 一旦内容超宽(例如宽度模型把 `⚡` 算成 1 列而 Ink 按 2 列排),这一行会被顶成
28
+ * 两行,整帧高度 +1,底部输入框/状态栏会被顶出屏幕。
29
+ *
30
+ * 解法是让溢出被**可截断的邻段吸收**:`before` / `after` 两段设为
31
+ * `flexShrink={1} minWidth={0}` + `wrap="truncate"`,光标块 `flexShrink={0}`。
32
+ * 实测:容器 40、`before` 60 列时仍是**一行**(行高 1),光标被钳在可用区边缘。
33
+ *
34
+ * ## 时序
35
+ *
36
+ * `measureElement()` 只能在渲染之后(`useEffect`)调用,而 Ink 的 `setCursorPosition`
37
+ * 只在 commit 阶段(`useInsertionEffect`)把位置推给渲染器,所以「测量 → 上报」天然
38
+ * 跨一次 commit:宿主把结果存进 state,下一次 commit 才把硬件光标挪过去(多一趟渲染,
39
+ * Ink 自带节流,肉眼无感)。因此宿主仍保留手算位置作为**首帧兜底**。
40
+ */
41
+ import { useEffect, useRef } from "react";
42
+ import { Box, measureElement, Text } from "ink";
43
+ import { theme } from "../theme.js";
44
+ /**
45
+ * 光标所在的输入行:把光标字符包成可测节点,渲染后上报它的布局坐标。
46
+ *
47
+ * 视觉与「整块 `<Text>`」渲染等价(提示符 / 正文 / 反显光标块 / 后续文本),
48
+ * 区别只是各处成为独立节点,于是可以被 `measureElement()` 量到。
49
+ */
50
+ export function CursorInputRow({ firstLine, before, at, after, onMeasure }) {
51
+ const cursorRef = useRef(null);
52
+ /** 上一次上报的值:相同就不再上报,避免「测量 → setState → 渲染 → 再测量」打转 */
53
+ const lastKeyRef = useRef(null);
54
+ useEffect(() => {
55
+ const node = cursorRef.current;
56
+ if (!node)
57
+ return;
58
+ const { x, y } = measureElement(node);
59
+ const key = `${x}:${y}`;
60
+ if (key === lastKeyRef.current)
61
+ return;
62
+ lastKeyRef.current = key;
63
+ onMeasure({ x, y });
64
+ }, [firstLine, before, at, after, onMeasure]);
65
+ return (_jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { flexShrink: 0, children: firstLine ? (_jsx(Text, { color: theme.brand[0], bold: true, children: "❯ " })) : (_jsx(Text, { children: " " })) }), _jsx(Box, { flexShrink: 1, minWidth: 0, children: _jsx(Text, { wrap: "truncate", children: before }) }), _jsx(Box, { ref: cursorRef, flexShrink: 0, children: _jsx(Text, { inverse: true, color: theme.brand[0], children: at }) }), _jsx(Box, { flexShrink: 1, minWidth: 0, children: _jsx(Text, { wrap: "truncate", children: after }) })] }));
66
+ }
67
+ //# sourceMappingURL=input-row.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-row.js","sourceRoot":"","sources":["../../../src/tui/screens/input-row.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,IAAI,EAAmB,MAAM,KAAK,CAAC;AACjE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAqBpC;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAuB;IAC7F,MAAM,SAAS,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAClD,qDAAqD;IACrD,MAAM,UAAU,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAE/C,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,IAAI,GAAG,KAAK,UAAU,CAAC,OAAO;YAAE,OAAO;QACvC,UAAU,CAAC,OAAO,GAAG,GAAG,CAAC;QACzB,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACtB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;IAE9C,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,KAAK,aACtB,KAAC,GAAG,IAAC,UAAU,EAAE,CAAC,YACf,SAAS,CAAC,CAAC,CAAC,CACX,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,kBAC9B,IAAI,GACA,CACR,CAAC,CAAC,CAAC,CACF,KAAC,IAAI,cAAE,IAAI,GAAQ,CACpB,GACG,EAEN,KAAC,GAAG,IAAC,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,YAC7B,KAAC,IAAI,IAAC,IAAI,EAAC,UAAU,YAAE,MAAM,GAAQ,GACjC,EACN,KAAC,GAAG,IAAC,GAAG,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,YAChC,KAAC,IAAI,IAAC,OAAO,QAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,YAChC,EAAE,GACE,GACH,EACN,KAAC,GAAG,IAAC,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,YAC7B,KAAC,IAAI,IAAC,IAAI,EAAC,UAAU,YAAE,KAAK,GAAQ,GAChC,IACF,CACP,CAAC;AACJ,CAAC"}
@@ -2,11 +2,21 @@
2
2
  export declare function inputLines(text: string, columns: number): string[];
3
3
  /**
4
4
  * 计算终端硬件光标坐标(相对 Ink 输出原点),用于让 IME(输入法)候选框
5
- * 跟随编辑光标。x 为列、y 为行。
5
+ * 跟随编辑光标。x 为列、y 为行(0 起始,从整帧第一行算起)。
6
+ *
7
+ * y 必须把输入行**上方渲染的全部行**算进去,顺序与 `chat.tsx` 的渲染顺序严格一致:
8
+ *
9
+ * 对话区(`layout.lines`)→ 通知栏(`noticeLines`)→ 斜杠菜单(`hints`)→ 分隔线 → 输入行
10
+ *
11
+ * 漏算任何一段,硬件光标就会整体偏移那么多行(Ink 的 `moveUp = 总行数 − y`,
12
+ * 所以 y 少几行,光标就高几行)。历史上「通知栏」就被漏过:`/help` 这类多行通知
13
+ * 一出现,IME 候选框会浮到输入行上方好几行。
6
14
  */
7
15
  export declare function computeInputCursorPosition(input: {
8
16
  /** 对话区行数(输入区之前的行偏移基数) */
9
17
  transcriptLines: number;
18
+ /** 通知栏行数(位于对话区与斜杠菜单之间;不传视为 0) */
19
+ noticeCount?: number;
10
20
  /** 斜杠命令菜单行数 */
11
21
  hintCount: number;
12
22
  /** 光标在输入框内的行 / 列(列以 code point 计) */
@@ -26,4 +36,39 @@ export declare function isWordChar(ch: string): boolean;
26
36
  export declare function wordLeft(text: string, cursor: number): number;
27
37
  /** 向右跨词后的光标位置(跳过单词与分隔符,停在词尾) */
28
38
  export declare function wordRight(text: string, cursor: number): number;
39
+ /**
40
+ * 向左删一个词(Ctrl+W / Alt+Backspace):删掉光标前的分隔符与单词。
41
+ * 返回删除后的文本与光标位置 —— 光标原地不动,只是前面的内容被吃掉。
42
+ */
43
+ export declare function deleteWordLeft(text: string, cursor: number): {
44
+ text: string;
45
+ cursor: number;
46
+ };
47
+ /**
48
+ * 向右删一个词(Alt+D / Ctrl+Delete):删掉光标后的分隔符与单词。
49
+ * 光标不动,后面的内容被吃掉。
50
+ */
51
+ export declare function deleteWordRight(text: string, cursor: number): {
52
+ text: string;
53
+ cursor: number;
54
+ };
55
+ /**
56
+ * 删到行首(Ctrl+U):删掉光标到本行开头(不含换行符)的内容。
57
+ *
58
+ * 语义与 readline 的 unix-line-discard / 主流 TUI 保持一致。注意 macOS 上
59
+ * iTerm2 与 Terminal.app 会把 `Cmd+Backspace` 映射成 `Ctrl+U` —— 若此处做成
60
+ * 「清空整个输入框」,Mac 用户按 ⌘⌫ 会丢掉全部草稿(多行输入时尤其致命)。
61
+ */
62
+ export declare function deleteToLineStart(text: string, cursor: number): {
63
+ text: string;
64
+ cursor: number;
65
+ };
66
+ /**
67
+ * 删到行尾(Ctrl+K):删掉光标到本行末尾(不含换行符)的内容;
68
+ * 若光标已在行尾,则连该换行符一起删掉(与 readline 的 kill-line 一致)。
69
+ */
70
+ export declare function deleteToLineEnd(text: string, cursor: number): {
71
+ text: string;
72
+ cursor: number;
73
+ };
29
74
  //# sourceMappingURL=input.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../src/tui/screens/input.ts"],"names":[],"mappings":"AAKA,2CAA2C;AAC3C,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAIlE;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,yBAAyB;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAS3B;AAID,wDAAwD;AACxD,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAK9C;AAED,gCAAgC;AAChC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAM7D;AAED,gCAAgC;AAChC,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAM9D"}
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../src/tui/screens/input.ts"],"names":[],"mappings":"AAMA,2CAA2C;AAC3C,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAIlE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,yBAAyB;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,iCAAiC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAS3B;AAID,wDAAwD;AACxD,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAK9C;AAED,gCAAgC;AAChC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAM7D;AAED,gCAAgC;AAChC,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAM9D;AASD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAQ7F;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAQ9F;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAShG;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAU9F"}
@@ -1,24 +1,33 @@
1
1
  // 由 src/tui/screens.tsx 拆分而来 —— 输入区折行 / 硬件光标 / 跨词移动
2
- import { displayWidth, layoutInput, INPUT_PREFIX_WIDTH } from "../text.js";
2
+ import { displayWidth, graphemes, layoutInput, INPUT_PREFIX_WIDTH } from "../text.js";
3
+ import { t } from "../../i18n/index.js";
3
4
  // ==================== 对话屏布局(吸底)====================
4
5
  /** 输入区文本折行(不含提示符 `❯ `,交由渲染层补齐);空输入用占位提示 */
5
6
  export function inputLines(text, columns) {
6
7
  const width = Math.max(4, columns - 4);
7
- const body = text.length > 0 ? text : "输入消息,/ 查看命令…";
8
+ const body = text.length > 0 ? text : t("input.placeholder");
8
9
  return layoutInput(body, 0, width).lines;
9
10
  }
10
11
  /**
11
12
  * 计算终端硬件光标坐标(相对 Ink 输出原点),用于让 IME(输入法)候选框
12
- * 跟随编辑光标。x 为列、y 为行。
13
+ * 跟随编辑光标。x 为列、y 为行(0 起始,从整帧第一行算起)。
14
+ *
15
+ * y 必须把输入行**上方渲染的全部行**算进去,顺序与 `chat.tsx` 的渲染顺序严格一致:
16
+ *
17
+ * 对话区(`layout.lines`)→ 通知栏(`noticeLines`)→ 斜杠菜单(`hints`)→ 分隔线 → 输入行
18
+ *
19
+ * 漏算任何一段,硬件光标就会整体偏移那么多行(Ink 的 `moveUp = 总行数 − y`,
20
+ * 所以 y 少几行,光标就高几行)。历史上「通知栏」就被漏过:`/help` 这类多行通知
21
+ * 一出现,IME 候选框会浮到输入行上方好几行。
13
22
  */
14
23
  export function computeInputCursorPosition(input) {
15
24
  const before = input.placeholder
16
25
  ? ""
17
- : Array.from(input.lineText).slice(0, input.cursorCol).join("");
26
+ : graphemes(input.lineText).slice(0, input.cursorCol).join("");
18
27
  return {
19
28
  x: INPUT_PREFIX_WIDTH + displayWidth(before),
20
- // 对话区 + 斜杠菜单 + 分隔线 + 输入行内偏移
21
- y: input.transcriptLines + input.hintCount + 1 + input.cursorRow,
29
+ // 对话区 + 通知栏 + 斜杠菜单 + 分隔线 + 输入行内偏移
30
+ y: input.transcriptLines + (input.noticeCount ?? 0) + input.hintCount + 1 + input.cursorRow,
22
31
  };
23
32
  }
24
33
  // ==================== 跨词移动(Ctrl/Alt + ← →)====================
@@ -33,7 +42,7 @@ export function isWordChar(ch) {
33
42
  }
34
43
  /** 向左跨词后的光标位置(跳过分隔符与单词,停在词首) */
35
44
  export function wordLeft(text, cursor) {
36
- const chars = Array.from(text);
45
+ const chars = graphemes(text);
37
46
  let i = Math.max(0, Math.min(cursor, chars.length));
38
47
  while (i > 0 && !isWordChar(chars[i - 1]))
39
48
  i -= 1;
@@ -43,7 +52,7 @@ export function wordLeft(text, cursor) {
43
52
  }
44
53
  /** 向右跨词后的光标位置(跳过单词与分隔符,停在词尾) */
45
54
  export function wordRight(text, cursor) {
46
- const chars = Array.from(text);
55
+ const chars = graphemes(text);
47
56
  let i = Math.max(0, Math.min(cursor, chars.length));
48
57
  while (i < chars.length && !isWordChar(chars[i]))
49
58
  i += 1;
@@ -51,4 +60,70 @@ export function wordRight(text, cursor) {
51
60
  i += 1;
52
61
  return i;
53
62
  }
63
+ // ==================== 按词删除(Ctrl+W / Alt+Backspace、Alt+D / Ctrl+Delete)====================
64
+ /** 光标钳制到 [0, len](按 code point 计) */
65
+ function clampCursor(chars, cursor) {
66
+ return Math.max(0, Math.min(cursor, chars.length));
67
+ }
68
+ /**
69
+ * 向左删一个词(Ctrl+W / Alt+Backspace):删掉光标前的分隔符与单词。
70
+ * 返回删除后的文本与光标位置 —— 光标原地不动,只是前面的内容被吃掉。
71
+ */
72
+ export function deleteWordLeft(text, cursor) {
73
+ const chars = graphemes(text);
74
+ const cp = clampCursor(chars, cursor);
75
+ const from = wordLeft(text, cp);
76
+ return {
77
+ text: chars.slice(0, from).join("") + chars.slice(cp).join(""),
78
+ cursor: from,
79
+ };
80
+ }
81
+ /**
82
+ * 向右删一个词(Alt+D / Ctrl+Delete):删掉光标后的分隔符与单词。
83
+ * 光标不动,后面的内容被吃掉。
84
+ */
85
+ export function deleteWordRight(text, cursor) {
86
+ const chars = graphemes(text);
87
+ const cp = clampCursor(chars, cursor);
88
+ const to = wordRight(text, cp);
89
+ return {
90
+ text: chars.slice(0, cp).join("") + chars.slice(to).join(""),
91
+ cursor: cp,
92
+ };
93
+ }
94
+ /**
95
+ * 删到行首(Ctrl+U):删掉光标到本行开头(不含换行符)的内容。
96
+ *
97
+ * 语义与 readline 的 unix-line-discard / 主流 TUI 保持一致。注意 macOS 上
98
+ * iTerm2 与 Terminal.app 会把 `Cmd+Backspace` 映射成 `Ctrl+U` —— 若此处做成
99
+ * 「清空整个输入框」,Mac 用户按 ⌘⌫ 会丢掉全部草稿(多行输入时尤其致命)。
100
+ */
101
+ export function deleteToLineStart(text, cursor) {
102
+ const chars = graphemes(text);
103
+ const cp = clampCursor(chars, cursor);
104
+ let from = cp;
105
+ while (from > 0 && chars[from - 1] !== "\n")
106
+ from -= 1;
107
+ return {
108
+ text: chars.slice(0, from).join("") + chars.slice(cp).join(""),
109
+ cursor: from,
110
+ };
111
+ }
112
+ /**
113
+ * 删到行尾(Ctrl+K):删掉光标到本行末尾(不含换行符)的内容;
114
+ * 若光标已在行尾,则连该换行符一起删掉(与 readline 的 kill-line 一致)。
115
+ */
116
+ export function deleteToLineEnd(text, cursor) {
117
+ const chars = graphemes(text);
118
+ const cp = clampCursor(chars, cursor);
119
+ let to = cp;
120
+ while (to < chars.length && chars[to] !== "\n")
121
+ to += 1;
122
+ if (to === cp && chars[cp] === "\n")
123
+ to += 1;
124
+ return {
125
+ text: chars.slice(0, cp).join("") + chars.slice(to).join(""),
126
+ cursor: cp,
127
+ };
128
+ }
54
129
  //# sourceMappingURL=input.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"input.js","sourceRoot":"","sources":["../../../src/tui/screens/input.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE3E,qDAAqD;AAErD,2CAA2C;AAC3C,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,OAAe;IACtD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC;IACrD,OAAO,WAAW,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC;AAC3C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CAAC,KAY1C;IACC,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW;QAC9B,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClE,OAAO;QACL,CAAC,EAAE,kBAAkB,GAAG,YAAY,CAAC,MAAM,CAAC;QAC5C,4BAA4B;QAC5B,CAAC,EAAE,KAAK,CAAC,eAAe,GAAG,KAAK,CAAC,SAAS,GAAG,CAAC,GAAG,KAAK,CAAC,SAAS;KACjE,CAAC;AACJ,CAAC;AAED,gEAAgE;AAEhE,wDAAwD;AACxD,MAAM,UAAU,UAAU,CAAC,EAAU;IACnC,IAAI,CAAC,EAAE;QAAE,OAAO,KAAK,CAAC;IACtB,MAAM,IAAI,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC;IAChC,IAAI,IAAI,GAAG,GAAG;QAAE,OAAO,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxB,CAAC;AAED,gCAAgC;AAChC,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,MAAc;IACnD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAAE,CAAC,IAAI,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAAE,CAAC,IAAI,CAAC,CAAC;IACjD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,gCAAgC;AAChC,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,MAAc;IACpD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAAE,CAAC,IAAI,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAAE,CAAC,IAAI,CAAC,CAAC;IACxD,OAAO,CAAC,CAAC;AACX,CAAC"}
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../../../src/tui/screens/input.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,30 @@
1
- import { RLine, Block, LiveAssistant } from "./lines.js";
1
+ import { RLine } from "./lines.js";
2
2
  /** 确认框固定高度(外 marginTop 1 + 上下边框 2 + 问题 1 + marginTop 1 + 选项 1) */
3
3
  export declare const CONFIRM_LINES = 6;
4
+ /** 底部状态栏行数下限:模型/Agent 一行 + 用量与速率一行(宽度不够时会折成更多行,
5
+ * 实际值由 `statusBarRows()` 量出后传入 `computeChatLayout({ statusBarLines })`) */
6
+ export declare const STATUS_BAR_LINES = 2;
4
7
  /** 选择覆盖层高度(相对条目数) */
5
8
  export declare function pickerLines(itemCount: number): number;
6
9
  export interface ChatLayoutInput {
7
10
  columns: number;
8
11
  rows: number;
9
- blocks: Block[];
10
- live: LiveAssistant | null;
12
+ /** 已折行的对话行(由 messages-view 依 agent.messages 产出) */
13
+ transcript: RLine[];
11
14
  input: string;
12
15
  busy: boolean;
13
16
  hintCount: number;
17
+ /** 通知栏行数(notice / error 独立栏位),缺省 0 */
18
+ noticeCount?: number;
14
19
  overlay: "none" | "confirm" | "picker";
15
20
  pickerItems: number;
16
21
  /** 视口顶部行索引(相对整个对话行);null / undefined = 贴底(自动跟随最新) */
17
22
  viewTop?: number | null;
23
+ /**
24
+ * 状态栏实际占据的行数(由 `statusBarRows()` 实测得出 —— 它会随终端宽度折行)。
25
+ * 缺省用 `STATUS_BAR_LINES`。
26
+ */
27
+ statusBarLines?: number;
18
28
  }
19
29
  export interface ChatLayout {
20
30
  /** 对话区(含顶部补齐空行),行数恒为 `rows - bottomLines` */
@@ -30,6 +40,14 @@ export interface ChatLayout {
30
40
  /** 是否处于滚动状态(视口未贴底,下方仍有更新的内容) */
31
41
  scrolled: boolean;
32
42
  }
43
+ /**
44
+ * 把「想要的视口顶部」钳制成合法值:下限 0、上限 `totalLines - budget`。
45
+ *
46
+ * 返回 `null` 表示**已贴底**(视口顶恰好等于最大顶,或内容不足一屏)—— 调用方据此
47
+ * 清掉滚动状态,让视口重新跟随最新内容。所有滚动动作(翻页 / 按行 / 鼠标滚轮)都
48
+ * 走这一个函数,越界方向自然被吃掉,不会出现「滚过头回不来」。
49
+ */
50
+ export declare function clampViewTop(totalLines: number, budget: number, nextTop: number): number | null;
33
51
  /**
34
52
  * 计算对话屏布局:底部区域高度固定后,把「对话行」按视口截取到可用高度,顶部用空行
35
53
  * 补齐 —— 使整帧高度恒等于传入的 `rows`(调用方以 `usableFrameRows()` 预留末行),
@@ -1 +1 @@
1
- {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/tui/screens/layout.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAA6B,MAAM,YAAY,CAAC;AAGpF,kEAAkE;AAClE,eAAO,MAAM,aAAa,IAAI,CAAC;AAC/B,qBAAqB;AACrB,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,UAAU,CA4BpE"}
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/tui/screens/layout.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,kEAAkE;AAClE,eAAO,MAAM,aAAa,IAAI,CAAC;AAC/B;4EAC4E;AAC5E,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAClC,qBAAqB;AACrB,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,UAAU,EAAE,KAAK,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI/F;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,UAAU,CA4BpE"}
@@ -1,12 +1,25 @@
1
- // 由 src/tui/screens.tsx 拆分而来 —— 吸底布局 computeChatLayout + 覆盖层高度
2
- import { blockToLines, liveToLines } from "./lines.js";
3
1
  import { inputLines } from "./input.js";
4
2
  /** 确认框固定高度(外 marginTop 1 + 上下边框 2 + 问题 1 + marginTop 1 + 选项 1) */
5
3
  export const CONFIRM_LINES = 6;
4
+ /** 底部状态栏行数下限:模型/Agent 一行 + 用量与速率一行(宽度不够时会折成更多行,
5
+ * 实际值由 `statusBarRows()` 量出后传入 `computeChatLayout({ statusBarLines })`) */
6
+ export const STATUS_BAR_LINES = 2;
6
7
  /** 选择覆盖层高度(相对条目数) */
7
8
  export function pickerLines(itemCount) {
8
9
  return 7 + itemCount;
9
10
  }
11
+ /**
12
+ * 把「想要的视口顶部」钳制成合法值:下限 0、上限 `totalLines - budget`。
13
+ *
14
+ * 返回 `null` 表示**已贴底**(视口顶恰好等于最大顶,或内容不足一屏)—— 调用方据此
15
+ * 清掉滚动状态,让视口重新跟随最新内容。所有滚动动作(翻页 / 按行 / 鼠标滚轮)都
16
+ * 走这一个函数,越界方向自然被吃掉,不会出现「滚过头回不来」。
17
+ */
18
+ export function clampViewTop(totalLines, budget, nextTop) {
19
+ const maxTop = Math.max(0, totalLines - budget);
20
+ const clamped = Math.max(0, Math.min(maxTop, nextTop));
21
+ return clamped >= maxTop ? null : clamped;
22
+ }
10
23
  /**
11
24
  * 计算对话屏布局:底部区域高度固定后,把「对话行」按视口截取到可用高度,顶部用空行
12
25
  * 补齐 —— 使整帧高度恒等于传入的 `rows`(调用方以 `usableFrameRows()` 预留末行),
@@ -16,20 +29,18 @@ export function pickerLines(itemCount) {
16
29
  * 传入具体值时按 [0, totalLines - budget] 钳制,用于「应用内翻页」回看更早的历史。
17
30
  */
18
31
  export function computeChatLayout(input) {
19
- const transcript = [];
20
- for (const block of input.blocks)
21
- transcript.push(...blockToLines(block, input.columns));
22
- if (input.live)
23
- transcript.push(...liveToLines(input.live, input.columns));
32
+ const transcript = input.transcript;
24
33
  const inputHeight = input.busy ? 1 : inputLines(input.input, input.columns).length;
25
34
  const overlayHeight = input.overlay === "confirm"
26
35
  ? CONFIRM_LINES
27
36
  : input.overlay === "picker"
28
37
  ? pickerLines(input.pickerItems)
29
38
  : 0;
39
+ const noticeCount = input.noticeCount ?? 0;
40
+ const statusBarLines = Math.max(1, input.statusBarLines ?? STATUS_BAR_LINES);
30
41
  const bottomLines = input.overlay === "none"
31
- ? 1 /* 分隔线 */ + input.hintCount + inputHeight + 1 /* 状态栏 */
32
- : overlayHeight + 1 /* 状态栏 */;
42
+ ? noticeCount /* 通知栏 */ + 1 /* 分隔线 */ + input.hintCount + inputHeight + statusBarLines
43
+ : overlayHeight + statusBarLines;
33
44
  const budget = Math.max(0, input.rows - bottomLines);
34
45
  const totalLines = transcript.length;
35
46
  const maxTop = Math.max(0, totalLines - budget);
@@ -1 +1 @@
1
- {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../../src/tui/screens/layout.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,OAAO,EAA+B,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACpF,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,kEAAkE;AAClE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC;AAC/B,qBAAqB;AACrB,MAAM,UAAU,WAAW,CAAC,SAAiB;IAC3C,OAAO,CAAC,GAAG,SAAS,CAAC;AACvB,CAAC;AA+BD;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAsB;IACtD,MAAM,UAAU,GAAY,EAAE,CAAC;IAC/B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM;QAAE,UAAU,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IACzF,IAAI,KAAK,CAAC,IAAI;QAAE,UAAU,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAE3E,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IACnF,MAAM,aAAa,GACjB,KAAK,CAAC,OAAO,KAAK,SAAS;QACzB,CAAC,CAAC,aAAa;QACf,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,QAAQ;YAC1B,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC;YAChC,CAAC,CAAC,CAAC,CAAC;IACV,MAAM,WAAW,GACf,KAAK,CAAC,OAAO,KAAK,MAAM;QACtB,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,GAAG,WAAW,GAAG,CAAC,CAAC,SAAS;QAC3D,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,SAAS,CAAC;IAElC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,GAAG,WAAW,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC;IACrC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;IAC1F,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IACtD,MAAM,KAAK,GAAY;QACrB,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,KAAc,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACnG,GAAG,SAAS;KACb,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,GAAG,MAAM,EAAE,CAAC;AAC1F,CAAC"}
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../../src/tui/screens/layout.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,kEAAkE;AAClE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC;AAC/B;4EAC4E;AAC5E,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAClC,qBAAqB;AACrB,MAAM,UAAU,WAAW,CAAC,SAAiB;IAC3C,OAAO,CAAC,GAAG,SAAS,CAAC;AACvB,CAAC;AAsCD;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,UAAkB,EAAE,MAAc,EAAE,OAAe;IAC9E,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvD,OAAO,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;AAC5C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAsB;IACtD,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IAEpC,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IACnF,MAAM,aAAa,GACjB,KAAK,CAAC,OAAO,KAAK,SAAS;QACzB,CAAC,CAAC,aAAa;QACf,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,QAAQ;YAC1B,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC;YAChC,CAAC,CAAC,CAAC,CAAC;IACV,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC;IAC3C,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,cAAc,IAAI,gBAAgB,CAAC,CAAC;IAC7E,MAAM,WAAW,GACf,KAAK,CAAC,OAAO,KAAK,MAAM;QACtB,CAAC,CAAC,WAAW,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,GAAG,WAAW,GAAG,cAAc;QACtF,CAAC,CAAC,aAAa,GAAG,cAAc,CAAC;IAErC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,GAAG,WAAW,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC;IACrC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;IAC1F,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IACtD,MAAM,KAAK,GAAY;QACrB,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,KAAc,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACnG,GAAG,SAAS;KACb,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,GAAG,MAAM,EAAE,CAAC;AAC1F,CAAC"}
@@ -14,58 +14,29 @@ export interface RLine {
14
14
  /** 着色分段;`text` 恒为这些分段的纯文本拼接(便于测试与裁剪) */
15
15
  spans?: Span[];
16
16
  }
17
- export interface ToolLine {
18
- name: string;
19
- args: string;
20
- }
21
- export type Block = {
22
- id: number;
23
- kind: "user";
24
- text: string;
25
- } | {
26
- id: number;
27
- kind: "assistant";
28
- reasoning: string;
29
- content: string;
30
- tools: ToolLine[];
31
- } | {
32
- id: number;
33
- kind: "notice";
34
- tone: "info" | "error";
35
- text: string;
36
- };
37
- export interface LiveAssistant {
38
- reasoning: string;
39
- content: string;
40
- tools: ToolLine[];
41
- sub: string | null;
42
- /**
43
- * 本轮(一次 API 请求)工具调用在 `tools` 中的起始下标。
44
- *
45
- * AI 一轮回复里可并行调用多个工具,且**工具执行后会在同一轮对话内继续下一轮**
46
- * (每次请求 SDK 都 `emit("open")`);每轮的 `tool_calls.index` 都会从 `0` 重新
47
- * 计数。用它分段,避免新一轮与上一轮同 index 的工具调用被拼到同一行
48
- * (如 `read` + `edit` → `readedit`)。
49
- */
50
- roundBase?: number;
51
- }
52
17
  /** 缩进 2 列后的可用文本宽度 */
53
18
  export declare function innerWidth(columns: number): number;
54
19
  export declare function indentLines(kind: LineKind, key: string, text: string, width: number): RLine[];
55
20
  /** 按显示宽度把分段裁成**严格单行**,超出补省略号(用于工具调用行) */
56
21
  export declare function clipSpans(spans: Span[], max: number): Span[];
22
+ /** 由分段拼出 RLine(`text` = 分段纯文本拼接) */
23
+ export declare function spanLine(key: string, kind: LineKind, spans: Span[]): RLine;
57
24
  /**
58
25
  * 工具调用行的分段:` ⚙ name(args)`,参数按 **JSON** 高亮。
59
26
  * 无参数时省略括号;调用方用 `clipSpans` 裁成严格单行。
60
27
  */
61
28
  export declare function toolSpans(name: string, args: string): Span[];
62
29
  /**
63
- * 正文 / 思考内容 → 预折行;**围栏代码块**(` ```lang `)按语言高亮,其余按普通文本折行。
64
- * 围栏行本身不显示(见 `splitFences`)。
30
+ * 正文 / 思考内容 → 预折行。
31
+ *
32
+ * - **普通文本段**按 **markdown 源码着色**(`highlightCode(text, "markdown")`):
33
+ * AI 回答本身就是 markdown,交给 highlight.js 的 markdown 词法上色,标记符(`#`/`**`/`` ` `` 等)
34
+ * 原样保留、只染色(不做语义渲染);
35
+ * - **围栏代码块**按标注语言做语法高亮,并**保留围栏行**(` ```lang ` 与 ` ``` `,
36
+ * 以低调的暗灰渲染),不丢弃 —— 便于一眼看出代码块边界与语言。
37
+ * 未标注 / 未知语言则不着色。
38
+ *
39
+ * 正文段用**空格优先**折行,代码段逐字符硬断。
65
40
  */
66
41
  export declare function contentLines(kind: LineKind, key: string, text: string, width: number): RLine[];
67
- /** 单个对话块 → 若干预折行 */
68
- export declare function blockToLines(block: Block, columns: number): RLine[];
69
- /** 流式中的 AI 块 → 若干预折行(与完成态一致:前置一个空行隔开上文) */
70
- export declare function liveToLines(live: LiveAssistant, columns: number): RLine[];
71
42
  //# sourceMappingURL=lines.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lines.d.ts","sourceRoot":"","sources":["../../../src/tui/screens/lines.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,QAAQ,GAChB,KAAK,GACL,aAAa,GACb,WAAW,GACX,WAAW,GACX,WAAW,GACX,MAAM,GACN,SAAS,GACT,QAAQ,GACR,OAAO,CAAC;AAEZ,gDAAgD;AAChD,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,KAAK,GACb;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,QAAQ,EAAE,CAAA;CAAE,GACxF;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAqB;AACrB,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE,CAE7F;AA2DD,yCAAyC;AACzC,wBAAgB,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,CAsB5D;AAOD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,CAS5D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE,CAiB9F;AAED,oBAAoB;AACpB,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,EAAE,CAoCnE;AAED,2CAA2C;AAC3C,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,EAAE,CAqBzE"}
1
+ {"version":3,"file":"lines.d.ts","sourceRoot":"","sources":["../../../src/tui/screens/lines.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,QAAQ,GAChB,KAAK,GACL,aAAa,GACb,WAAW,GACX,WAAW,GACX,WAAW,GACX,MAAM,GACN,SAAS,GACT,QAAQ,GACR,OAAO,CAAC;AAEZ,gDAAgD;AAChD,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;CAChB;AAED,qBAAqB;AACrB,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE,CAE7F;AAuHD,yCAAyC;AACzC,wBAAgB,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,CAsB5D;AAED,oCAAoC;AACpC,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,KAAK,CAE1E;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,CAS5D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE,CAsB9F"}