@ai-zen/cli 1.0.0-alpha.20 → 1.0.0-alpha.23

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 (261) hide show
  1. package/CHANGELOG.md +205 -0
  2. package/README.md +45 -17
  3. package/README.zh.md +45 -17
  4. package/dist/agent-creator.d.ts.map +1 -1
  5. package/dist/agent-creator.js +32 -10
  6. package/dist/agent-creator.js.map +1 -1
  7. package/dist/agent-switch.d.ts +61 -0
  8. package/dist/agent-switch.d.ts.map +1 -0
  9. package/dist/agent-switch.js +83 -0
  10. package/dist/agent-switch.js.map +1 -0
  11. package/dist/agents-store.d.ts +6 -1
  12. package/dist/agents-store.d.ts.map +1 -1
  13. package/dist/agents-store.js +6 -1
  14. package/dist/agents-store.js.map +1 -1
  15. package/dist/auto-migrate-confirm.d.ts.map +1 -1
  16. package/dist/auto-migrate-confirm.js +2 -1
  17. package/dist/auto-migrate-confirm.js.map +1 -1
  18. package/dist/config-editor.d.ts +9 -1
  19. package/dist/config-editor.d.ts.map +1 -1
  20. package/dist/config-editor.js +30 -19
  21. package/dist/config-editor.js.map +1 -1
  22. package/dist/config.d.ts +1 -1
  23. package/dist/config.d.ts.map +1 -1
  24. package/dist/config.js +29 -13
  25. package/dist/config.js.map +1 -1
  26. package/dist/conversation-commands/registry.d.ts +123 -4
  27. package/dist/conversation-commands/registry.d.ts.map +1 -1
  28. package/dist/conversation-commands/registry.js +92 -17
  29. package/dist/conversation-commands/registry.js.map +1 -1
  30. package/dist/conversation-persist-plugin.d.ts.map +1 -1
  31. package/dist/conversation-persist-plugin.js +6 -14
  32. package/dist/conversation-persist-plugin.js.map +1 -1
  33. package/dist/conversation-repository.d.ts +68 -14
  34. package/dist/conversation-repository.d.ts.map +1 -1
  35. package/dist/conversation-repository.js +81 -23
  36. package/dist/conversation-repository.js.map +1 -1
  37. package/dist/cwd-tracker-plugin.d.ts.map +1 -1
  38. package/dist/cwd-tracker-plugin.js +6 -2
  39. package/dist/cwd-tracker-plugin.js.map +1 -1
  40. package/dist/format-time.d.ts +17 -6
  41. package/dist/format-time.d.ts.map +1 -1
  42. package/dist/format-time.js +32 -14
  43. package/dist/format-time.js.map +1 -1
  44. package/dist/handoff-service.d.ts.map +1 -1
  45. package/dist/handoff-service.js +22 -19
  46. package/dist/handoff-service.js.map +1 -1
  47. package/dist/hook.d.ts.map +1 -1
  48. package/dist/hook.js +69 -15
  49. package/dist/hook.js.map +1 -1
  50. package/dist/i18n/en-wizard.d.ts +8 -0
  51. package/dist/i18n/en-wizard.d.ts.map +1 -0
  52. package/dist/i18n/en-wizard.js +290 -0
  53. package/dist/i18n/en-wizard.js.map +1 -0
  54. package/dist/i18n/en.d.ts +7 -0
  55. package/dist/i18n/en.d.ts.map +1 -0
  56. package/dist/i18n/en.js +223 -0
  57. package/dist/i18n/en.js.map +1 -0
  58. package/dist/i18n/index.d.ts +57 -0
  59. package/dist/i18n/index.d.ts.map +1 -0
  60. package/dist/i18n/index.js +109 -0
  61. package/dist/i18n/index.js.map +1 -0
  62. package/dist/i18n/preferences.d.ts +34 -0
  63. package/dist/i18n/preferences.d.ts.map +1 -0
  64. package/dist/i18n/preferences.js +69 -0
  65. package/dist/i18n/preferences.js.map +1 -0
  66. package/dist/i18n/zh-wizard.d.ts +11 -0
  67. package/dist/i18n/zh-wizard.d.ts.map +1 -0
  68. package/dist/i18n/zh-wizard.js +293 -0
  69. package/dist/i18n/zh-wizard.js.map +1 -0
  70. package/dist/i18n/zh.d.ts +10 -0
  71. package/dist/i18n/zh.d.ts.map +1 -0
  72. package/dist/i18n/zh.js +227 -0
  73. package/dist/i18n/zh.js.map +1 -0
  74. package/dist/index.js +41 -23
  75. package/dist/index.js.map +1 -1
  76. package/dist/mcp-command.d.ts +32 -0
  77. package/dist/mcp-command.d.ts.map +1 -0
  78. package/dist/mcp-command.js +37 -0
  79. package/dist/mcp-command.js.map +1 -0
  80. package/dist/mode.d.ts +31 -4
  81. package/dist/mode.d.ts.map +1 -1
  82. package/dist/mode.js +42 -7
  83. package/dist/mode.js.map +1 -1
  84. package/dist/model-switch.d.ts.map +1 -1
  85. package/dist/model-switch.js +5 -4
  86. package/dist/model-switch.js.map +1 -1
  87. package/dist/reasoning-effort.d.ts +23 -4
  88. package/dist/reasoning-effort.d.ts.map +1 -1
  89. package/dist/reasoning-effort.js +51 -24
  90. package/dist/reasoning-effort.js.map +1 -1
  91. package/dist/sdk-log.d.ts +23 -16
  92. package/dist/sdk-log.d.ts.map +1 -1
  93. package/dist/sdk-log.js +43 -19
  94. package/dist/sdk-log.js.map +1 -1
  95. package/dist/stdio-runner.d.ts.map +1 -1
  96. package/dist/stdio-runner.js +19 -19
  97. package/dist/stdio-runner.js.map +1 -1
  98. package/dist/sub-agent-guard-plugin.d.ts +5 -2
  99. package/dist/sub-agent-guard-plugin.d.ts.map +1 -1
  100. package/dist/sub-agent-guard-plugin.js +5 -2
  101. package/dist/sub-agent-guard-plugin.js.map +1 -1
  102. package/dist/tui/chat-session.d.ts +73 -0
  103. package/dist/tui/chat-session.d.ts.map +1 -1
  104. package/dist/tui/chat-session.js +167 -33
  105. package/dist/tui/chat-session.js.map +1 -1
  106. package/dist/tui/components.d.ts +43 -2
  107. package/dist/tui/components.d.ts.map +1 -1
  108. package/dist/tui/components.js +97 -4
  109. package/dist/tui/components.js.map +1 -1
  110. package/dist/tui/config-wizard/detail.d.ts +12 -6
  111. package/dist/tui/config-wizard/detail.d.ts.map +1 -1
  112. package/dist/tui/config-wizard/detail.js +33 -32
  113. package/dist/tui/config-wizard/detail.js.map +1 -1
  114. package/dist/tui/config-wizard/engine.d.ts.map +1 -1
  115. package/dist/tui/config-wizard/engine.js +26 -20
  116. package/dist/tui/config-wizard/engine.js.map +1 -1
  117. package/dist/tui/config-wizard/fields.d.ts.map +1 -1
  118. package/dist/tui/config-wizard/fields.js +176 -164
  119. package/dist/tui/config-wizard/fields.js.map +1 -1
  120. package/dist/tui/config-wizard/kv-editor.d.ts.map +1 -1
  121. package/dist/tui/config-wizard/kv-editor.js +9 -5
  122. package/dist/tui/config-wizard/kv-editor.js.map +1 -1
  123. package/dist/tui/config-wizard/list.d.ts.map +1 -1
  124. package/dist/tui/config-wizard/list.js +2 -1
  125. package/dist/tui/config-wizard/list.js.map +1 -1
  126. package/dist/tui/config-wizard/mcp-helpers.d.ts.map +1 -1
  127. package/dist/tui/config-wizard/mcp-helpers.js +4 -3
  128. package/dist/tui/config-wizard/mcp-helpers.js.map +1 -1
  129. package/dist/tui/config-wizard/menu.d.ts.map +1 -1
  130. package/dist/tui/config-wizard/menu.js +32 -19
  131. package/dist/tui/config-wizard/menu.js.map +1 -1
  132. package/dist/tui/config-wizard/prompt-editor.d.ts.map +1 -1
  133. package/dist/tui/config-wizard/prompt-editor.js +4 -3
  134. package/dist/tui/config-wizard/prompt-editor.js.map +1 -1
  135. package/dist/tui/config-wizard/prompt.d.ts.map +1 -1
  136. package/dist/tui/config-wizard/prompt.js +8 -7
  137. package/dist/tui/config-wizard/prompt.js.map +1 -1
  138. package/dist/tui/config-wizard/step-agents.d.ts.map +1 -1
  139. package/dist/tui/config-wizard/step-agents.js +29 -20
  140. package/dist/tui/config-wizard/step-agents.js.map +1 -1
  141. package/dist/tui/config-wizard/step-defaults.d.ts.map +1 -1
  142. package/dist/tui/config-wizard/step-defaults.js +21 -17
  143. package/dist/tui/config-wizard/step-defaults.js.map +1 -1
  144. package/dist/tui/config-wizard/step-endpoints.d.ts.map +1 -1
  145. package/dist/tui/config-wizard/step-endpoints.js +16 -6
  146. package/dist/tui/config-wizard/step-endpoints.js.map +1 -1
  147. package/dist/tui/config-wizard/step-mcp.d.ts.map +1 -1
  148. package/dist/tui/config-wizard/step-mcp.js +17 -19
  149. package/dist/tui/config-wizard/step-mcp.js.map +1 -1
  150. package/dist/tui/config-wizard/step-models.d.ts.map +1 -1
  151. package/dist/tui/config-wizard/step-models.js +41 -26
  152. package/dist/tui/config-wizard/step-models.js.map +1 -1
  153. package/dist/tui/config-wizard/step-new-endpoint.d.ts.map +1 -1
  154. package/dist/tui/config-wizard/step-new-endpoint.js +16 -12
  155. package/dist/tui/config-wizard/step-new-endpoint.js.map +1 -1
  156. package/dist/tui/config-wizard/step-simple.d.ts.map +1 -1
  157. package/dist/tui/config-wizard/step-simple.js +18 -17
  158. package/dist/tui/config-wizard/step-simple.js.map +1 -1
  159. package/dist/tui/index.d.ts +17 -1
  160. package/dist/tui/index.d.ts.map +1 -1
  161. package/dist/tui/index.js +25 -14
  162. package/dist/tui/index.js.map +1 -1
  163. package/dist/tui/input-editing.d.ts +4 -1
  164. package/dist/tui/input-editing.d.ts.map +1 -1
  165. package/dist/tui/input-editing.js +7 -3
  166. package/dist/tui/input-editing.js.map +1 -1
  167. package/dist/tui/phase.d.ts +64 -0
  168. package/dist/tui/phase.d.ts.map +1 -0
  169. package/dist/tui/phase.js +112 -0
  170. package/dist/tui/phase.js.map +1 -0
  171. package/dist/tui/screens/agent-tabs.d.ts +53 -0
  172. package/dist/tui/screens/agent-tabs.d.ts.map +1 -0
  173. package/dist/tui/screens/agent-tabs.js +81 -0
  174. package/dist/tui/screens/agent-tabs.js.map +1 -0
  175. package/dist/tui/screens/chat-commands.d.ts +54 -3
  176. package/dist/tui/screens/chat-commands.d.ts.map +1 -1
  177. package/dist/tui/screens/chat-commands.js +469 -330
  178. package/dist/tui/screens/chat-commands.js.map +1 -1
  179. package/dist/tui/screens/chat.d.ts +8 -0
  180. package/dist/tui/screens/chat.d.ts.map +1 -1
  181. package/dist/tui/screens/chat.js +263 -406
  182. package/dist/tui/screens/chat.js.map +1 -1
  183. package/dist/tui/screens/common-keys.d.ts +36 -0
  184. package/dist/tui/screens/common-keys.d.ts.map +1 -0
  185. package/dist/tui/screens/common-keys.js +67 -0
  186. package/dist/tui/screens/common-keys.js.map +1 -0
  187. package/dist/tui/screens/handoff-choice.d.ts.map +1 -1
  188. package/dist/tui/screens/handoff-choice.js +4 -3
  189. package/dist/tui/screens/handoff-choice.js.map +1 -1
  190. package/dist/tui/screens/index.d.ts +3 -1
  191. package/dist/tui/screens/index.d.ts.map +1 -1
  192. package/dist/tui/screens/index.js +2 -1
  193. package/dist/tui/screens/index.js.map +1 -1
  194. package/dist/tui/screens/input-row.d.ts +64 -0
  195. package/dist/tui/screens/input-row.d.ts.map +1 -0
  196. package/dist/tui/screens/input-row.js +67 -0
  197. package/dist/tui/screens/input-row.js.map +1 -0
  198. package/dist/tui/screens/input.d.ts +13 -1
  199. package/dist/tui/screens/input.d.ts.map +1 -1
  200. package/dist/tui/screens/input.js +26 -12
  201. package/dist/tui/screens/input.js.map +1 -1
  202. package/dist/tui/screens/layout.d.ts +15 -0
  203. package/dist/tui/screens/layout.d.ts.map +1 -1
  204. package/dist/tui/screens/layout.js +14 -2
  205. package/dist/tui/screens/layout.js.map +1 -1
  206. package/dist/tui/screens/lines.d.ts.map +1 -1
  207. package/dist/tui/screens/lines.js +6 -6
  208. package/dist/tui/screens/lines.js.map +1 -1
  209. package/dist/tui/screens/messages-view.d.ts.map +1 -1
  210. package/dist/tui/screens/messages-view.js +5 -4
  211. package/dist/tui/screens/messages-view.js.map +1 -1
  212. package/dist/tui/screens/notice-bar.d.ts +5 -0
  213. package/dist/tui/screens/notice-bar.d.ts.map +1 -0
  214. package/dist/tui/screens/notice-bar.js +15 -0
  215. package/dist/tui/screens/notice-bar.js.map +1 -0
  216. package/dist/tui/screens/notice.d.ts +40 -8
  217. package/dist/tui/screens/notice.d.ts.map +1 -1
  218. package/dist/tui/screens/notice.js +75 -15
  219. package/dist/tui/screens/notice.js.map +1 -1
  220. package/dist/tui/screens/overlays.d.ts.map +1 -1
  221. package/dist/tui/screens/overlays.js +3 -2
  222. package/dist/tui/screens/overlays.js.map +1 -1
  223. package/dist/tui/screens/splash.d.ts +1 -1
  224. package/dist/tui/screens/splash.d.ts.map +1 -1
  225. package/dist/tui/screens/splash.js +5 -2
  226. package/dist/tui/screens/splash.js.map +1 -1
  227. package/dist/tui/screens/use-chat-viewport.d.ts +22 -0
  228. package/dist/tui/screens/use-chat-viewport.d.ts.map +1 -0
  229. package/dist/tui/screens/use-chat-viewport.js +50 -0
  230. package/dist/tui/screens/use-chat-viewport.js.map +1 -0
  231. package/dist/tui/screens/use-input-editing.d.ts +44 -0
  232. package/dist/tui/screens/use-input-editing.d.ts.map +1 -0
  233. package/dist/tui/screens/use-input-editing.js +192 -0
  234. package/dist/tui/screens/use-input-editing.js.map +1 -0
  235. package/dist/tui/screens/use-overlays.d.ts +25 -0
  236. package/dist/tui/screens/use-overlays.d.ts.map +1 -0
  237. package/dist/tui/screens/use-overlays.js +32 -0
  238. package/dist/tui/screens/use-overlays.js.map +1 -0
  239. package/dist/tui/screens/use-wizard-host.d.ts +35 -0
  240. package/dist/tui/screens/use-wizard-host.d.ts.map +1 -0
  241. package/dist/tui/screens/use-wizard-host.js +103 -0
  242. package/dist/tui/screens/use-wizard-host.js.map +1 -0
  243. package/dist/tui/status-segments.d.ts +37 -0
  244. package/dist/tui/status-segments.d.ts.map +1 -0
  245. package/dist/tui/status-segments.js +166 -0
  246. package/dist/tui/status-segments.js.map +1 -0
  247. package/dist/tui/text.d.ts +8 -5
  248. package/dist/tui/text.d.ts.map +1 -1
  249. package/dist/tui/text.js +95 -35
  250. package/dist/tui/text.js.map +1 -1
  251. package/dist/tui/theme.d.ts +2 -0
  252. package/dist/tui/theme.d.ts.map +1 -1
  253. package/dist/tui/theme.js +2 -0
  254. package/dist/tui/theme.js.map +1 -1
  255. package/dist/tui/token-rate.d.ts +83 -0
  256. package/dist/tui/token-rate.d.ts.map +1 -0
  257. package/dist/tui/token-rate.js +195 -0
  258. package/dist/tui/token-rate.js.map +1 -0
  259. package/dist/types.d.ts +0 -3
  260. package/dist/types.d.ts.map +1 -1
  261. package/package.json +4 -3
@@ -1 +1 @@
1
- {"version":3,"file":"splash.js","sourceRoot":"","sources":["../../../src/tui/screens/splash.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"splash.js","sourceRoot":"","sources":["../../../src/tui/screens/splash.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { type RefObject } from "react";
2
+ import { type ChatLayout } from "./layout.js";
3
+ export interface ChatViewport {
4
+ /** 视口顶部行索引(相对整个对话行);`null` = 贴底(自动跟随最新内容) */
5
+ viewTop: number | null;
6
+ /**
7
+ * 最近一帧的布局。**由渲染体在算完布局后写入**(`viewport.layoutRef.current = layout`):
8
+ * 键盘回调需要的总行数 / 视口高度只有布局算完才知道,而布局又依赖 `viewTop`
9
+ * —— 用 ref 传递可避免两个方向互相等待。
10
+ */
11
+ layoutRef: RefObject<ChatLayout | null>;
12
+ /** 翻页:一页 = 视口高度 - 1 行(留一行上下文,不至于跳得没头没尾) */
13
+ scrollByPage: (dir: -1 | 1) => void;
14
+ /** 按行滚动 */
15
+ scrollByLine: (dir: -1 | 1) => void;
16
+ /** 鼠标滚轮:一格滚 `WHEEL_STEP` 行(与按行滚动共用一个钳制入口) */
17
+ scrollByWheel: (dir: -1 | 1) => void;
18
+ /** 贴底(恢复跟随最新内容) */
19
+ scrollToBottom: () => void;
20
+ }
21
+ export declare function useChatViewport(): ChatViewport;
22
+ //# sourceMappingURL=use-chat-viewport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-chat-viewport.d.ts","sourceRoot":"","sources":["../../../src/tui/screens/use-chat-viewport.ts"],"names":[],"mappings":"AAUA,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtE,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;;OAIG;IACH,SAAS,EAAE,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACxC,2CAA2C;IAC3C,YAAY,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC;IACpC,WAAW;IACX,YAAY,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC;IACpC,6CAA6C;IAC7C,aAAa,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC;IACrC,mBAAmB;IACnB,cAAc,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,wBAAgB,eAAe,IAAI,YAAY,CA8C9C"}
@@ -0,0 +1,50 @@
1
+ // 对话视口 —— 「翻页 / 按行 / 滚轮 / 回底」的唯一入口
2
+ //
3
+ // 从 `chat.tsx` 抽出来的理由:视口是**不依赖会话**的独立状态机(一个 `viewTop` 状态
4
+ // 加一份最近布局的引用),却被塞在 God Component 里,与消息、输入、向导混在一起。
5
+ // 抽出来后,「滚动」这件事只有这一个地方能改。
6
+ //
7
+ // 关键点:所有动作都走 `scrollTo()` → `clampViewTop()`,因此
8
+ // · 越界方向被自然吃掉,不会出现「滚过头回不来」;
9
+ // · 回到底部时 `clampViewTop()` 返回 `null`,视口**自动**恢复「跟随最新内容」,
10
+ // 不需要各处手写「滚到底就清空滚动状态」。
11
+ import { useCallback, useRef, useState } from "react";
12
+ import { WHEEL_STEP } from "../mouse.js";
13
+ import { clampViewTop } from "./layout.js";
14
+ export function useChatViewport() {
15
+ const [viewTop, setViewTop] = useState(null);
16
+ const layoutRef = useRef(null);
17
+ // 下面的回调只读 `layoutRef`(布局每帧更新)与 `setViewTop`,没有闭包捕获的旧状态,
18
+ // 所以依赖数组为空即可保持引用稳定(可安全传给 memo 化的子组件)。
19
+ // `scrollTo` 是下面三个动作的公共实现,**不对外暴露**:调用方只需要「翻页 / 按行 / 滚轮」,
20
+ // 直接设任意顶部值既没必要,也绕过了「以布局实际生效的顶部为基准」这条约束。
21
+ const scrollTo = useCallback((nextTop) => {
22
+ const L = layoutRef.current;
23
+ if (!L)
24
+ return;
25
+ setViewTop(clampViewTop(L.totalLines, L.budget, nextTop));
26
+ }, []);
27
+ const scrollByPage = useCallback((dir) => {
28
+ const L = layoutRef.current;
29
+ if (!L)
30
+ return;
31
+ // 按「布局实际生效的顶部」算,而不是原始 `viewTop`:贴底时 `viewTop` 是
32
+ // `null`,从 `layout.viewTop` 起算才能从底部往上翻一屏。
33
+ scrollTo(L.viewTop + dir * Math.max(1, L.budget - 1));
34
+ }, [scrollTo]);
35
+ const scrollByLine = useCallback((dir) => {
36
+ const L = layoutRef.current;
37
+ if (!L)
38
+ return;
39
+ scrollTo(L.viewTop + dir);
40
+ }, [scrollTo]);
41
+ const scrollByWheel = useCallback((dir) => {
42
+ const L = layoutRef.current;
43
+ if (!L)
44
+ return;
45
+ scrollTo(L.viewTop + dir * WHEEL_STEP);
46
+ }, [scrollTo]);
47
+ const scrollToBottom = useCallback(() => setViewTop(null), []);
48
+ return { viewTop, layoutRef, scrollByPage, scrollByLine, scrollByWheel, scrollToBottom };
49
+ }
50
+ //# sourceMappingURL=use-chat-viewport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-chat-viewport.js","sourceRoot":"","sources":["../../../src/tui/screens/use-chat-viewport.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,EAAE;AACF,yDAAyD;AACzD,kDAAkD;AAClD,yBAAyB;AACzB,EAAE;AACF,gDAAgD;AAChD,8BAA8B;AAC9B,2DAA2D;AAC3D,2BAA2B;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAkB,MAAM,OAAO,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAmB,MAAM,aAAa,CAAC;AAqB5D,MAAM,UAAU,eAAe;IAC7B,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAElD,wDAAwD;IACxD,sCAAsC;IACtC,0DAA0D;IAC1D,wCAAwC;IACxC,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,OAAe,EAAE,EAAE;QAC/C,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,CAAC;YAAE,OAAO;QACf,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5D,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,GAAW,EAAE,EAAE;QACd,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,CAAC;YAAE,OAAO;QACf,gDAAgD;QAChD,0CAA0C;QAC1C,QAAQ,CAAC,CAAC,CAAC,OAAO,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAC;IAEF,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,GAAW,EAAE,EAAE;QACd,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,CAAC;YAAE,OAAO;QACf,QAAQ,CAAC,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC;IAC5B,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAC;IAEF,MAAM,aAAa,GAAG,WAAW,CAC/B,CAAC,GAAW,EAAE,EAAE;QACd,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,CAAC;YAAE,OAAO;QACf,QAAQ,CAAC,CAAC,CAAC,OAAO,GAAG,GAAG,GAAG,UAAU,CAAC,CAAC;IACzC,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAC;IAEF,MAAM,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IAE/D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC;AAC3F,CAAC"}
@@ -0,0 +1,44 @@
1
+ import type { Notice } from "./notice.js";
2
+ export interface InputEditingDeps {
3
+ /** 初始草稿(`/back` 撤回后重挂载用的预填内容),缺省空 */
4
+ initialText?: string;
5
+ /** 通知出口(暂存 / 取回草稿的提示,走通知通道而不是转录) */
6
+ notify: (text: string, tone?: Notice["tone"]) => void;
7
+ }
8
+ export interface InputEditing {
9
+ /** 当前草稿 */
10
+ input: string;
11
+ /** 光标位置:以字素簇计的索引(0..字数),可落在末尾之后一格 */
12
+ cursor: number;
13
+ /** 整体替换草稿(光标移到末尾) */
14
+ setInputText: (text: string) => void;
15
+ insertAtCursor: (text: string) => void;
16
+ deleteBeforeCursor: () => void;
17
+ deleteAfterCursor: () => void;
18
+ deleteWordBeforeCursor: () => void;
19
+ deleteWordAfterCursor: () => void;
20
+ deleteToStartOfLine: () => void;
21
+ deleteToEndOfLine: () => void;
22
+ /** Ctrl+W:删到前一空白(标点不切分) */
23
+ deletePrevWhitespace: () => void;
24
+ /** Ctrl+Y / Alt+Y:取回 kill ring 里的一段;`advance` 为真时循环到更早的一段 */
25
+ yank: (advance: boolean) => void;
26
+ /** Ctrl+_:撤销上一次编辑 */
27
+ undoEdit: () => void;
28
+ /** Ctrl+S:暂存草稿 / 取回草稿 */
29
+ toggleStash: () => void;
30
+ moveCursor: (delta: number) => void;
31
+ moveCursorToLineStart: () => void;
32
+ moveCursorToLineEnd: () => void;
33
+ /** 按词左右移动:`dir` 为 -1 往前、1 往后 */
34
+ moveCursorByWord: (dir: -1 | 1) => void;
35
+ /** 历史:上一条 / 下一条(没有可翻的时候自动空转) */
36
+ historyPrev: () => void;
37
+ historyNext: () => void;
38
+ /** 提交时调用:清空草稿并退出历史浏览(历史游标复位到底部) */
39
+ clearDraft: () => void;
40
+ /** 提交成功时调用:记进历史并把历史游标复位到底部 */
41
+ rememberSubmitted: (text: string) => void;
42
+ }
43
+ export declare function useInputEditing({ initialText, notify }: InputEditingDeps): InputEditing;
44
+ //# sourceMappingURL=use-input-editing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-input-editing.d.ts","sourceRoot":"","sources":["../../../src/tui/screens/use-input-editing.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,gBAAgB;IAC/B,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;CACvD;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW;IACX,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,sBAAsB,EAAE,MAAM,IAAI,CAAC;IACnC,qBAAqB,EAAE,MAAM,IAAI,CAAC;IAClC,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,2BAA2B;IAC3B,oBAAoB,EAAE,MAAM,IAAI,CAAC;IACjC,6DAA6D;IAC7D,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACjC,qBAAqB;IACrB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,yBAAyB;IACzB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,qBAAqB,EAAE,MAAM,IAAI,CAAC;IAClC,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,gCAAgC;IAChC,gBAAgB,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC;IACxC,gCAAgC;IAChC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,mCAAmC;IACnC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,8BAA8B;IAC9B,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAED,wBAAgB,eAAe,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,gBAAgB,GAAG,YAAY,CAoLvF"}
@@ -0,0 +1,192 @@
1
+ // 输入编辑 —— 草稿文本与光标、历史、kill ring、撤销栈、暂存区的唯一实现
2
+ //
3
+ // 从 `chat.tsx` 抽出来的理由:这一整块(`input` / `cursor` / `history` / kill ring /
4
+ // undo / stash + 20 个编辑动作)是**纯编辑器语义**,与「对话屏」毫无关系,却和会话、
5
+ // 向导、渲染挤在同一个组件里 —— 于是既不能单测,也每次都被误认为「对话的一部分」。
6
+ //
7
+ // 两条贯穿全篇的约定:
8
+ //
9
+ // 1. **按字素簇编辑**:所有位置计算都走 `graphemes()`。`❤️` 是 2 个 code point、
10
+ // `👨‍👩‍👧` 是 5 个,但它们都是**一个**字符 —— 按 code point 删会切出半个字素簇。
11
+ // 2. **纯函数算、hook 只套用**:具体「删哪个词、删到哪」在 `input.ts` /
12
+ // `input-editing.ts` 里(有独立测试),这里只负责「拿到结果 → 更新状态 + 记撤销」。
13
+ import { useRef, useState } from "react";
14
+ import { deleteToLineEnd, deleteToLineStart, deleteWordLeft, deleteWordRight, wordLeft, wordRight, } from "./input.js";
15
+ import { deleteToPrevWhitespace, killedText, killAt, popUndo, pushKill, pushUndo, } from "../input-editing.js";
16
+ import { graphemes } from "../text.js";
17
+ import { t } from "../../i18n/index.js";
18
+ export function useInputEditing({ initialText, notify }) {
19
+ const [input, setInput] = useState(initialText ?? "");
20
+ const [cursor, setCursor] = useState(graphemes(initialText ?? "").length);
21
+ const [history, setHistory] = useState([]);
22
+ /** 历史游标:-1 = 不在浏览历史(当前是草稿) */
23
+ const historyIndex = useRef(-1);
24
+ /** kill ring:Ctrl+W/U/K 删掉的文本,Ctrl+Y 取回、Alt+Y 循环 */
25
+ const killRingRef = useRef([]);
26
+ const yankIndexRef = useRef(-1);
27
+ /** 编辑撤销栈(Ctrl+_) */
28
+ const undoStackRef = useRef([]);
29
+ /** 暂存区(Ctrl+S) */
30
+ const stashRef = useRef(null);
31
+ const setInputText = (text) => {
32
+ setInput(text);
33
+ setCursor(graphemes(text).length);
34
+ };
35
+ /**
36
+ * 取「当前文本 + 钳制后的光标」,所有编辑动作的统一起点。
37
+ *
38
+ * 钳制防的**不是**「cursor 越界」——`cursor` 的每个写入点都已保证落在 `[0, len]`;
39
+ * 防的是**文本与光标不同步**:`input` 与 `cursor` 是两个 state,任何一处只改其一
40
+ * (或将来新增编辑动作忘了同步)都会让 `cp > chars.length` 成立,那时 `slice`
41
+ * 会静默切少、`cp - 1` 会变负。钳一下把后果限制在「本次编辑落点不对」。
42
+ */
43
+ const clampCursor = () => {
44
+ const chars = graphemes(input);
45
+ return { chars, cp: Math.max(0, Math.min(cursor, chars.length)) };
46
+ };
47
+ const insertAtCursor = (text) => {
48
+ const { chars, cp } = clampCursor();
49
+ setInput(chars.slice(0, cp).join("") + text + chars.slice(cp).join(""));
50
+ setCursor(cp + graphemes(text).length);
51
+ };
52
+ const deleteBeforeCursor = () => {
53
+ const { chars, cp } = clampCursor();
54
+ if (cp === 0)
55
+ return;
56
+ setInput(chars.slice(0, cp - 1).join("") + chars.slice(cp).join(""));
57
+ setCursor(cp - 1);
58
+ };
59
+ const deleteAfterCursor = () => {
60
+ const { chars, cp } = clampCursor();
61
+ if (cp >= chars.length)
62
+ return;
63
+ setInput(chars.slice(0, cp).join("") + chars.slice(cp + 1).join(""));
64
+ };
65
+ /** 套用纯函数算好的「文本 + 光标」结果(无变化则不触发重渲染,也不进撤销栈) */
66
+ const applyEdit = (r) => {
67
+ if (r.text === input && r.cursor === cursor)
68
+ return;
69
+ undoStackRef.current = pushUndo(undoStackRef.current, { text: input, cursor });
70
+ setInput(r.text);
71
+ setCursor(r.cursor);
72
+ };
73
+ /** 删除类编辑:额外把删掉的文本放进 kill ring(Ctrl+Y 可取回) */
74
+ const applyKill = (r) => {
75
+ if (r.text === input && r.cursor === cursor)
76
+ return;
77
+ killRingRef.current = pushKill(killRingRef.current, killedText(input, r.text));
78
+ yankIndexRef.current = -1;
79
+ applyEdit(r);
80
+ };
81
+ const yank = (advance) => {
82
+ const ring = killRingRef.current;
83
+ if (ring.length === 0)
84
+ return;
85
+ const next = advance ? yankIndexRef.current + 1 : 0;
86
+ // 只用 `killAt` 的 undefined 做越界守卫(环已到头),不再先判一遍 `next >= ring.length`
87
+ const text = killAt(ring, next);
88
+ if (text === undefined)
89
+ return;
90
+ yankIndexRef.current = next;
91
+ insertAtCursor(text);
92
+ };
93
+ const undoEdit = () => {
94
+ const popped = popUndo(undoStackRef.current);
95
+ if (!popped)
96
+ return;
97
+ undoStackRef.current = popped.rest;
98
+ setInput(popped.state.text);
99
+ setCursor(popped.state.cursor);
100
+ };
101
+ const toggleStash = () => {
102
+ if (input.length > 0) {
103
+ stashRef.current = { text: input, cursor };
104
+ setInputText("");
105
+ notify(t("notice.draftSaved"));
106
+ return;
107
+ }
108
+ const stashed = stashRef.current;
109
+ if (!stashed)
110
+ return;
111
+ stashRef.current = null;
112
+ setInput(stashed.text);
113
+ setCursor(stashed.cursor);
114
+ notify(t("notice.draftRestored"));
115
+ };
116
+ const moveCursor = (delta) => {
117
+ const len = graphemes(input).length;
118
+ setCursor((c) => Math.max(0, Math.min(len, c + delta)));
119
+ };
120
+ const moveCursorByWord = (dir) => {
121
+ setCursor(dir === -1 ? wordLeft(input, cursor) : wordRight(input, cursor));
122
+ };
123
+ const moveCursorToLineStart = () => {
124
+ const { chars, cp } = clampCursor();
125
+ let i = cp;
126
+ while (i > 0 && chars[i - 1] !== "\n")
127
+ i -= 1;
128
+ setCursor(i);
129
+ };
130
+ const moveCursorToLineEnd = () => {
131
+ const { chars, cp } = clampCursor();
132
+ let i = cp;
133
+ while (i < chars.length && chars[i] !== "\n")
134
+ i += 1;
135
+ setCursor(i);
136
+ };
137
+ // 历史浏览:「上一条」从最新开始往回走,「下一条」走到底就回到空草稿。
138
+ // 上下两处按键(Ctrl+P/N 与 ↑/↓)共用这一对,不再各写一遍。
139
+ const historyPrev = () => {
140
+ if (history.length === 0)
141
+ return;
142
+ const idx = historyIndex.current < 0 ? history.length - 1 : Math.max(0, historyIndex.current - 1);
143
+ historyIndex.current = idx;
144
+ setInputText(history[idx]);
145
+ };
146
+ const historyNext = () => {
147
+ if (historyIndex.current < 0)
148
+ return;
149
+ const idx = historyIndex.current + 1;
150
+ if (idx >= history.length) {
151
+ historyIndex.current = -1;
152
+ setInputText("");
153
+ return;
154
+ }
155
+ historyIndex.current = idx;
156
+ setInputText(history[idx]);
157
+ };
158
+ const clearDraft = () => {
159
+ setInput("");
160
+ setCursor(0);
161
+ historyIndex.current = -1;
162
+ };
163
+ const rememberSubmitted = (text) => {
164
+ setHistory((h) => [...h, text]);
165
+ historyIndex.current = -1;
166
+ };
167
+ return {
168
+ input,
169
+ cursor,
170
+ setInputText,
171
+ insertAtCursor,
172
+ deleteBeforeCursor,
173
+ deleteAfterCursor,
174
+ deleteWordBeforeCursor: () => applyKill(deleteWordLeft(input, cursor)),
175
+ deleteWordAfterCursor: () => applyKill(deleteWordRight(input, cursor)),
176
+ deleteToStartOfLine: () => applyKill(deleteToLineStart(input, cursor)),
177
+ deleteToEndOfLine: () => applyKill(deleteToLineEnd(input, cursor)),
178
+ deletePrevWhitespace: () => applyKill(deleteToPrevWhitespace(input, cursor)),
179
+ yank,
180
+ undoEdit,
181
+ toggleStash,
182
+ moveCursor,
183
+ moveCursorToLineStart,
184
+ moveCursorToLineEnd,
185
+ moveCursorByWord,
186
+ historyPrev,
187
+ historyNext,
188
+ clearDraft,
189
+ rememberSubmitted,
190
+ };
191
+ }
192
+ //# sourceMappingURL=use-input-editing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-input-editing.js","sourceRoot":"","sources":["../../../src/tui/screens/use-input-editing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { type Dispatch, type SetStateAction } from "react";
2
+ import type { SelectItem } from "../components.js";
3
+ /** 确认框请求:`question` 上屏,用户作答后由 `resolve` 结算 */
4
+ export interface ConfirmState {
5
+ question: string;
6
+ resolve: (value: boolean) => void;
7
+ }
8
+ /** 选择器请求:`items` 上屏,用户选中 / 取消后由 `resolve` 结算(取消为 `null`) */
9
+ export interface PickerState {
10
+ title: string;
11
+ items: SelectItem<string>[];
12
+ resolve: (value: string | null) => void;
13
+ }
14
+ export interface ChatOverlays {
15
+ confirmState: ConfirmState | null;
16
+ pickerState: PickerState | null;
17
+ /** 命令层推送覆盖层用(`runCommand` / `chooseHandoffMode` 的入参类型) */
18
+ setConfirmState: Dispatch<SetStateAction<ConfirmState | null>>;
19
+ setPickerState: Dispatch<SetStateAction<PickerState | null>>;
20
+ /** 作答:结算 Promise 并关掉覆盖层(无覆盖层时为空操作) */
21
+ resolveConfirm: (value: boolean) => void;
22
+ resolvePicker: (value: string | null) => void;
23
+ }
24
+ export declare function useChatOverlays(): ChatOverlays;
25
+ //# sourceMappingURL=use-overlays.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-overlays.d.ts","sourceRoot":"","sources":["../../../src/tui/screens/use-overlays.ts"],"names":[],"mappings":"AAWA,OAAO,EAAyB,KAAK,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AAClF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,8CAA8C;AAC9C,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACnC;AAED,4DAA4D;AAC5D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;IAC5B,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,0DAA0D;IAC1D,eAAe,EAAE,QAAQ,CAAC,cAAc,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC;IAC/D,cAAc,EAAE,QAAQ,CAAC,cAAc,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC;IAC7D,sCAAsC;IACtC,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAC/C;AAED,wBAAgB,eAAe,IAAI,YAAY,CAqB9C"}
@@ -0,0 +1,32 @@
1
+ // 覆盖层(确认框 / 选择器)—— 「弹一个、答一个、再关掉」的唯一实现
2
+ //
3
+ // 两种覆盖层共用同一套契约:调用方给一个 `resolve` 回调,拿到一个 Promise,
4
+ // **用户在覆盖层上作答后 Promise 才结算**。这正是命令处理器能写成
5
+ // `const ok = await confirm(...)` 的原因。
6
+ //
7
+ // 从 `chat.tsx` 抽出来的理由:这套 `resolve` 生命周期被埋在 God Component 里,
8
+ // 既没法单测(要从键盘打到命令层才能碰到),也容易被下一个人的 `setState` 写出
9
+ // 「先清状态、后调 resolve」的竞态。抽出来后:
10
+ // · 关状态与调 resolve 在**同一次**函数式更新里完成,不会读到过期状态;
11
+ // · 已经是 `null` 时重复 resolve 是安全空操作(Esc 连按不会炸)。
12
+ import { useCallback, useState } from "react";
13
+ export function useChatOverlays() {
14
+ const [confirmState, setConfirmState] = useState(null);
15
+ const [pickerState, setPickerState] = useState(null);
16
+ // 用函数式更新而不是闭包里的 `confirmState`:连按两下 Esc / 两个键同一帧到达时,
17
+ // 第二次更新仍能看到「已被第一次清掉」的真实状态,不会重复 resolve。
18
+ const resolveConfirm = useCallback((value) => {
19
+ setConfirmState((cs) => {
20
+ cs?.resolve(value);
21
+ return null;
22
+ });
23
+ }, []);
24
+ const resolvePicker = useCallback((value) => {
25
+ setPickerState((ps) => {
26
+ ps?.resolve(value);
27
+ return null;
28
+ });
29
+ }, []);
30
+ return { confirmState, pickerState, setConfirmState, setPickerState, resolveConfirm, resolvePicker };
31
+ }
32
+ //# sourceMappingURL=use-overlays.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-overlays.js","sourceRoot":"","sources":["../../../src/tui/screens/use-overlays.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,EAAE;AACF,iDAAiD;AACjD,yCAAyC;AACzC,uCAAuC;AACvC,EAAE;AACF,4DAA4D;AAC5D,+CAA+C;AAC/C,6BAA6B;AAC7B,+CAA+C;AAC/C,gDAAgD;AAChD,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAsC,MAAM,OAAO,CAAC;AA2BlF,MAAM,UAAU,eAAe;IAC7B,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAsB,IAAI,CAAC,CAAC;IAC5E,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAqB,IAAI,CAAC,CAAC;IAEzE,qDAAqD;IACrD,wCAAwC;IACxC,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,KAAc,EAAE,EAAE;QACpD,eAAe,CAAC,CAAC,EAAE,EAAE,EAAE;YACrB,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;YACnB,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,aAAa,GAAG,WAAW,CAAC,CAAC,KAAoB,EAAE,EAAE;QACzD,cAAc,CAAC,CAAC,EAAE,EAAE,EAAE;YACpB,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;YACnB,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC;AACvG,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { AppConfig, ReasoningPresets } from "@ai-zen/agents-sdk";
2
+ import { type AgentStore } from "../../agents-store.js";
3
+ import type { McpSnapshot, WizardCloseResult, WizardStep } from "../config-wizard/index.js";
4
+ import type { Notice } from "./notice.js";
5
+ export interface WizardHostDeps {
6
+ /** 当前模型 id:`/key` 直达它所用端点的密钥;也是「当前端点是否被改动」的比较基准 */
7
+ modelId: string;
8
+ /** 通知出口(读写失败、变更摘要都从这里出去,不进食转录) */
9
+ notify: (text: string, tone?: Notice["tone"]) => void;
10
+ /** 会话是否已建好(未建好时改配置只能重启) */
11
+ hasSession: () => boolean;
12
+ /** 会话还没建好就改了配置 → 只能重启进程让新配置生效 */
13
+ restart: () => void;
14
+ /** 改了当前端点 / MCP / Agent 定义 → 重载会话(消息保留) */
15
+ reloadSession: () => void;
16
+ }
17
+ export interface WizardHost {
18
+ wizardStep: WizardStep | null;
19
+ wizardConfig: AppConfig | null;
20
+ wizardPresets: ReasoningPresets;
21
+ wizardAgents: {
22
+ id: string;
23
+ name: string;
24
+ }[];
25
+ wizardMcp: McpSnapshot | null;
26
+ wizardAgentStore: AgentStore | null;
27
+ /** 打开向导:先读齐快照再接管整屏(读失败则只报错、不进向导) */
28
+ openWizard: (step: WizardStep) => Promise<void>;
29
+ /** `/key`:直达当前模型所用端点的 API Key 编辑步骤 */
30
+ openKeyEditor: () => Promise<void>;
31
+ /** 向导关闭:渲染变更摘要,并让改动生效 */
32
+ closeWizard: (result: WizardCloseResult) => void;
33
+ }
34
+ export declare function useWizardHost({ modelId, notify, hasSession, restart, reloadSession, }: WizardHostDeps): WizardHost;
35
+ //# sourceMappingURL=use-wizard-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-wizard-host.d.ts","sourceRoot":"","sources":["../../../src/tui/screens/use-wizard-host.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtE,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExE,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;IACtD,2BAA2B;IAC3B,UAAU,EAAE,MAAM,OAAO,CAAC;IAC1B,iCAAiC;IACjC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,2CAA2C;IAC3C,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,SAAS,GAAG,IAAI,CAAC;IAC/B,aAAa,EAAE,gBAAgB,CAAC;IAChC,YAAY,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC7C,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B,gBAAgB,EAAE,UAAU,GAAG,IAAI,CAAC;IACpC,oCAAoC;IACpC,UAAU,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,sCAAsC;IACtC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,yBAAyB;IACzB,WAAW,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAClD;AAED,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,MAAM,EACN,UAAU,EACV,OAAO,EACP,aAAa,GACd,EAAE,cAAc,GAAG,UAAU,CA0F7B"}
@@ -0,0 +1,103 @@
1
+ // 配置向导宿主 —— 「打开向导 / 读齐快照 / 关闭后让改动生效」的唯一实现
2
+ //
3
+ // 从 `chat.tsx` 抽出来的理由:向导本身(`config-wizard/`)是独立状态机,但**宿主**
4
+ // 的活儿散落在对话屏里 —— 6 个 `useState`、3 个入口函数,还要顺手记「当前模型用的是
5
+ // 哪个端点」以便关闭时判断要不要重建会话。这些既不属于「对话」,也没法单测(要一路
6
+ // 从键盘打到向导关闭才能碰到)。
7
+ //
8
+ // 依赖方向是**注入**而非 import 会话:宿主要做的事(通知、重启、重载会话)都通过
9
+ // `WizardHostDeps` 传进来,于是 hook 可以在测试里用假依赖跑完整生命周期。
10
+ import { useRef, useState } from "react";
11
+ import { readConfig, readMcpConfig, readReasoningPresets } from "../../config.js";
12
+ import { readAgentStore } from "../../agents-store.js";
13
+ import { resolveCredential } from "../../config-editor.js";
14
+ import { t } from "../../i18n/index.js";
15
+ export function useWizardHost({ modelId, notify, hasSession, restart, reloadSession, }) {
16
+ const [wizardStep, setWizardStep] = useState(null);
17
+ const [wizardConfig, setWizardConfig] = useState(null);
18
+ const [wizardPresets, setWizardPresets] = useState({});
19
+ const [wizardAgents, setWizardAgents] = useState([]);
20
+ const [wizardMcp, setWizardMcp] = useState(null);
21
+ const [wizardAgentStore, setWizardAgentStore] = useState(null);
22
+ /**
23
+ * 打开向导时当前模型所用的端点 id —— 关闭时据此判断「当前端点有没有被改」。
24
+ *
25
+ * 用 ref 而不是 state:它只在 `openWizard` / `closeWizard` 之间传递,不上屏,
26
+ * 放 state 会多一次无意义渲染。
27
+ */
28
+ const currentEndpointRef = useRef(null);
29
+ const openWizard = async (step) => {
30
+ try {
31
+ const config = await readConfig();
32
+ currentEndpointRef.current = resolveCredential(config, modelId)?.endpointId ?? null;
33
+ const agentStore = await readAgentStore();
34
+ setWizardConfig(config);
35
+ setWizardPresets(await readReasoningPresets());
36
+ setWizardAgents(agentStore.agents.map((agent) => ({ id: agent.id, name: agent.name || agent.id })));
37
+ setWizardAgentStore(agentStore);
38
+ setWizardMcp({ global: await readMcpConfig("global"), project: await readMcpConfig("project") });
39
+ setWizardStep(step);
40
+ }
41
+ catch (error) {
42
+ notify(t("chat.configReadFailed", { error: error?.message ?? error }), "error");
43
+ }
44
+ };
45
+ const openKeyEditor = async () => {
46
+ try {
47
+ const config = await readConfig();
48
+ const credential = resolveCredential(config, modelId);
49
+ if (!credential) {
50
+ notify(t("chat.modelNoEndpoint", { id: modelId }), "error");
51
+ return;
52
+ }
53
+ currentEndpointRef.current = credential.endpointId;
54
+ setWizardConfig(config);
55
+ setWizardStep({ kind: "edit", field: "apiKey", endpointId: credential.endpointId });
56
+ }
57
+ catch (error) {
58
+ notify(t("chat.configReadFailed", { error: error?.message ?? error }), "error");
59
+ }
60
+ };
61
+ /** 向导关闭:渲染变更摘要;若改到当前端点 / MCP / Agent 定义则重建会话(消息保留) */
62
+ const closeWizard = (result) => {
63
+ setWizardStep(null);
64
+ setWizardConfig(null);
65
+ setWizardMcp(null);
66
+ setWizardAgentStore(null);
67
+ // 同一批摘要合成**一条**(多行):既能全部显示,又只占通知队列的一个槽位。
68
+ // 逐条 push 在单槽时代只剩最后一条,在队列时代则会挤掉更早的进度提示。
69
+ const { summary } = result;
70
+ if (summary.length === 1) {
71
+ notify(t("chat.configUpdated", { line: summary[0] }));
72
+ }
73
+ else if (summary.length > 1) {
74
+ // 子项缩进 = 一个汉字宽度(两个半角空格),不加 `·` 之类的项目符号:
75
+ // 通知正文本身就左对齐于行首,子项只需要一点层级差,符号是多余装饰。
76
+ notify(t("chat.configUpdatedMulti", { lines: summary.map((line) => ` ${line}`).join("\n") }));
77
+ }
78
+ if (!result.dirty)
79
+ return;
80
+ // 会话都没建好 → 只能重启让新配置生效。
81
+ if (!hasSession()) {
82
+ restart();
83
+ return;
84
+ }
85
+ // 只有「当前端点 / MCP / Agent 定义」变了才需要重建会话;改的是别的模型、
86
+ // 别的端点的参数,当前会话不受影响,不该白重连一次。
87
+ const endpointChanged = !!currentEndpointRef.current && result.changedEndpointIds.includes(currentEndpointRef.current);
88
+ if (endpointChanged || result.mcpChanged || result.agentsChanged)
89
+ reloadSession();
90
+ };
91
+ return {
92
+ wizardStep,
93
+ wizardConfig,
94
+ wizardPresets,
95
+ wizardAgents,
96
+ wizardMcp,
97
+ wizardAgentStore,
98
+ openWizard,
99
+ openKeyEditor,
100
+ closeWizard,
101
+ };
102
+ }
103
+ //# sourceMappingURL=use-wizard-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-wizard-host.js","sourceRoot":"","sources":["../../../src/tui/screens/use-wizard-host.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * 状态栏的折行 —— 输入是「按优先级排好的信息块」,输出是「确定的若干行」
3
+ *
4
+ * 为什么不用 Ink 自己的 wrap:状态栏高度必须是**确定值**,`computeChatLayout` 要靠它
5
+ * 算出对话区还能占几行(整帧高度恒等于终端行数,输入框才吸得住底)。让 Ink 在渲染时
6
+ * 折行,行数只有渲染完才知道,布局预算就会算错——轻则顶部留白多一行,重则把输入框
7
+ * 顶出屏幕。所以这里先在纯逻辑里折好,渲染层只负责按行铺颜色。
8
+ *
9
+ * 折行以「块」为单位(见 `packSegments`):身份、用量、快捷键各是一块,窄屏时整块
10
+ * 顺延到下一行,而不是把一块劈成两半——也不再用 `justify-content: space-between` 把
11
+ * 两侧各切一半(左边「思考 高」被吃掉、右边提示只剩半截)。
12
+ */
13
+ /** 一段带样式的文本(颜色由调用方给,这里只管切分) */
14
+ export interface StatusSegment {
15
+ text: string;
16
+ color?: string;
17
+ bold?: boolean;
18
+ }
19
+ /**
20
+ * 把片段流按显示宽度折成若干行。
21
+ *
22
+ * 断行策略与 `wrapText` 一致:优先在**空格**处断(英文单词不被劈开),没有空格可断
23
+ * 时按字符硬断(CJK 本来就能任意断行)。折行后的行首空格会被吃掉,避免出现
24
+ * 「第二行无故缩进两格」。
25
+ */
26
+ export declare function wrapSegments(segments: StatusSegment[], width: number): StatusSegment[][];
27
+ /** 片段流的总显示宽度(宽字符算 2 列) */
28
+ export declare function segmentsWidth(segments: StatusSegment[]): number;
29
+ /**
30
+ * 以**块**为单位装行:能塞进当前行剩余宽度就并排(用 `separator` 连起来),
31
+ * 塞不下就整块挪到下一行;只有单块本身就比一整行还宽时,才退化成块内折行
32
+ * (`wrapSegments`),此时优先在空格 / CJK 边界断,尽量不劈开英文单词。
33
+ *
34
+ * 这样「换行时一块占一行」是默认行为:块是原子的排版单位,行的边界只会落在块边界上。
35
+ */
36
+ export declare function packSegments(blocks: StatusSegment[][], width: number, separator?: StatusSegment[]): StatusSegment[][];
37
+ //# sourceMappingURL=status-segments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-segments.d.ts","sourceRoot":"","sources":["../../src/tui/status-segments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,+BAA+B;AAC/B,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAwCD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,EAAE,EAAE,CAyDxF;AAED,0BAA0B;AAC1B,wBAAgB,aAAa,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,CAM/D;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,aAAa,EAAE,EAAE,EACzB,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,aAAa,EAAsB,GAC7C,aAAa,EAAE,EAAE,CAwCnB"}